ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

dwnl.c
Go to the documentation of this file.
00001 #include <stdio.h>
00002 #define COBJMACROS
00003 #include <urlmon.h>
00004 #include <wininet.h>
00005 #include <tchar.h>
00006 
00007 /* FIXME: add correct definitions to urlmon.idl */
00008 #ifdef UNICODE
00009 #define URLDownloadToFile URLDownloadToFileW
00010 #else
00011 #define URLDownloadToFile URLDownloadToFileA
00012 #endif
00013 
00014 #define DWNL_E_LASTERROR    0
00015 #define DWNL_E_NEEDTARGETFILENAME   -1
00016 #define DWNL_E_UNSUPPORTEDSCHEME    -2
00017 
00018 typedef struct
00019 {
00020     const IBindStatusCallbackVtbl* lpIBindStatusCallbackVtbl;
00021     LONG ref;
00022     TCHAR szHostName[INTERNET_MAX_HOST_NAME_LENGTH + 1];
00023     TCHAR szMimeType[128];
00024     UINT64 Size;
00025     UINT64 Progress;
00026     UINT bResolving : 1;
00027     UINT bConnecting : 1;
00028     UINT bSendingReq : 1;
00029     UINT bBeginTransfer : 1;
00030 } CBindStatusCallback;
00031 
00032 #define impl_to_interface(impl,iface) (struct iface *)(&(impl)->lp##iface##Vtbl)
00033 #define interface_to_impl(instance,iface) ((CBindStatusCallback*)((ULONG_PTR)instance - FIELD_OFFSET(CBindStatusCallback,lp##iface##Vtbl)))
00034 
00035 static void
00036 CBindStatusCallback_Destroy(CBindStatusCallback *This)
00037 {
00038     return;
00039 }
00040 
00041 static void
00042 write_status(LPCTSTR lpFmt, ...)
00043 {
00044     va_list args;
00045 
00046     /* FIXME: Determine line length! */
00047     TCHAR szTxt[80];
00048     int c;
00049 
00050     va_start(args, lpFmt);
00051     _vstprintf(szTxt, lpFmt, args);
00052     va_end(args);
00053 
00054     c = _tcslen(szTxt);
00055     while (c < (sizeof(szTxt) / sizeof(szTxt[0])) - 1)
00056         szTxt[c++] = _T(' ');
00057     szTxt[c] = _T('\0');
00058 
00059     _tprintf(_T("\r%.79s"), szTxt);
00060 }
00061 
00062 static void
00063 CBindStatusCallback_UpdateProgress(CBindStatusCallback *This)
00064 {
00065     /* FIXME: better output */
00066     if (This->Size != 0)
00067     {
00068         UINT Percentage;
00069 
00070         Percentage = (UINT)((This->Progress * 100) / This->Size);
00071         if (Percentage > 99)
00072             Percentage = 99;
00073 
00074         write_status(_T("%2d%% (%I64u bytes downloaded)"), Percentage, This->Progress);
00075     }
00076     else
00077     {
00078         /* Unknown size */
00079         write_status(_T("%I64u bytes downloaded"), This->Progress);
00080     }
00081 }
00082 
00083 static ULONG STDMETHODCALLTYPE
00084 CBindStatusCallback_AddRef(IBindStatusCallback *iface)
00085 {
00086     CBindStatusCallback *This = interface_to_impl(iface, IBindStatusCallback);
00087     ULONG ret;
00088 
00089     ret = InterlockedIncrement((PLONG)&This->ref);
00090     return ret;
00091 }
00092 
00093 static ULONG STDMETHODCALLTYPE
00094 CBindStatusCallback_Release(IBindStatusCallback *iface)
00095 {
00096     CBindStatusCallback *This = interface_to_impl(iface, IBindStatusCallback);
00097     ULONG ret;
00098 
00099     ret = InterlockedDecrement((PLONG)&This->ref);
00100     if (ret == 0)
00101     {
00102         CBindStatusCallback_Destroy(This);
00103 
00104         HeapFree(GetProcessHeap(),
00105                  0,
00106                  This);
00107     }
00108 
00109     return ret;
00110 }
00111 
00112 static HRESULT STDMETHODCALLTYPE
00113 CBindStatusCallback_QueryInterface(IBindStatusCallback *iface,
00114                                    REFIID iid,
00115                                    PVOID *pvObject)
00116 {
00117     CBindStatusCallback *This = interface_to_impl(iface, IBindStatusCallback);
00118 
00119     *pvObject = NULL;
00120 
00121     if (IsEqualIID(iid,
00122                    &IID_IBindStatusCallback) ||
00123         IsEqualIID(iid,
00124                    &IID_IUnknown))
00125     {
00126         *pvObject = impl_to_interface(This, IBindStatusCallback);
00127     }
00128     else
00129         return E_NOINTERFACE;
00130 
00131     CBindStatusCallback_AddRef(iface);
00132     return S_OK;
00133 }
00134 
00135 static HRESULT STDMETHODCALLTYPE
00136 CBindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
00137                                    DWORD dwReserved,
00138                                    IBinding* pib)
00139 {
00140     return E_NOTIMPL;
00141 }
00142 
00143 static HRESULT STDMETHODCALLTYPE
00144 CBindStatusCallback_GetPriority(IBindStatusCallback *iface,
00145                                 LONG* pnPriority)
00146 {
00147     return E_NOTIMPL;
00148 }
00149 
00150 static HRESULT STDMETHODCALLTYPE
00151 CBindStatusCallback_OnLowResource(IBindStatusCallback *iface,
00152                                   DWORD reserved)
00153 {
00154     return E_NOTIMPL;
00155 }
00156 
00157 static HRESULT STDMETHODCALLTYPE
00158 CBindStatusCallback_OnProgress(IBindStatusCallback *iface,
00159                                ULONG ulProgress,
00160                                ULONG ulProgressMax,
00161                                ULONG ulStatusCode,
00162                                LPCWSTR szStatusText)
00163 {
00164     CBindStatusCallback *This = interface_to_impl(iface, IBindStatusCallback);
00165 
00166     switch (ulStatusCode)
00167     {
00168         case BINDSTATUS_FINDINGRESOURCE:
00169             if (!This->bResolving)
00170             {
00171                 _tcscpy(This->szHostName, szStatusText);
00172                 This->bResolving = TRUE;
00173 
00174                 _tprintf(_T("Resolving %s... "), This->szHostName);
00175             }
00176             break;
00177 
00178         case BINDSTATUS_CONNECTING:
00179             This->bConnecting = TRUE;
00180             This->bSendingReq = FALSE;
00181             This->bBeginTransfer = FALSE;
00182             This->szMimeType[0] = _T('\0');
00183             if (This->bResolving)
00184             {
00185                 _tprintf(_T("done.\n"));
00186                 _tprintf(_T("Connecting to %s[%s]... "), This->szHostName, szStatusText);
00187             }
00188             else
00189                 _tprintf(_T("Connecting to %s... "), szStatusText);
00190             break;
00191 
00192         case BINDSTATUS_REDIRECTING:
00193             This->bResolving = FALSE;
00194             This->bConnecting = FALSE;
00195             This->bSendingReq = FALSE;
00196             This->bBeginTransfer = FALSE;
00197             This->szMimeType[0] = _T('\0');
00198             _tprintf(_T("Redirecting to %s... "), szStatusText);
00199             break;
00200 
00201         case BINDSTATUS_SENDINGREQUEST:
00202             This->bBeginTransfer = FALSE;
00203             This->szMimeType[0] = _T('\0');
00204             if (This->bResolving || This->bConnecting)
00205                 _tprintf(_T("done.\n"));
00206 
00207             if (!This->bSendingReq)
00208                 _tprintf(_T("Sending request... "));
00209 
00210             This->bSendingReq = TRUE;
00211             break;
00212 
00213         case BINDSTATUS_MIMETYPEAVAILABLE:
00214             _tcscpy(This->szMimeType, szStatusText);
00215             break;
00216 
00217         case BINDSTATUS_BEGINDOWNLOADDATA:
00218             This->Progress = (UINT64)ulProgress;
00219             This->Size = (UINT64)ulProgressMax;
00220 
00221             if (This->bSendingReq)
00222                 _tprintf(_T("done.\n"));
00223 
00224             if (!This->bBeginTransfer && This->Size != 0)
00225             {
00226                 if (This->szMimeType[0] != _T('\0'))
00227                     _tprintf(_T("Length: %I64u [%s]\n"), This->Size, This->szMimeType);
00228                 else
00229                     _tprintf(_T("Length: %ull\n"), This->Size);
00230             }
00231 
00232             _tprintf(_T("\n"));
00233 
00234             This->bBeginTransfer = TRUE;
00235             break;
00236 
00237         case BINDSTATUS_ENDDOWNLOADDATA:
00238             write_status(_T("File saved."));
00239             _tprintf(_T("\n"));
00240             break;
00241 
00242         case BINDSTATUS_DOWNLOADINGDATA:
00243             This->Progress = (UINT64)ulProgress;
00244             This->Size = (UINT64)ulProgressMax;
00245 
00246             CBindStatusCallback_UpdateProgress(This);
00247             break;
00248     }
00249 
00250     return S_OK;
00251 }
00252 
00253 static HRESULT STDMETHODCALLTYPE
00254 CBindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
00255                                   HRESULT hresult,
00256                                   LPCWSTR szError)
00257 {
00258     return E_NOTIMPL;
00259 }
00260 
00261 static HRESULT STDMETHODCALLTYPE
00262 CBindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
00263                                 DWORD* grfBINDF,
00264                                 BINDINFO* pbindinfo)
00265 {
00266     return E_NOTIMPL;
00267 }
00268 
00269 static HRESULT STDMETHODCALLTYPE
00270 CBindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
00271                                     DWORD grfBSCF,
00272                                     DWORD dwSize,
00273                                     FORMATETC* pformatetc,
00274                                     STGMEDIUM* pstgmed)
00275 {
00276     return E_NOTIMPL;
00277 }
00278 
00279 static HRESULT STDMETHODCALLTYPE
00280 CBindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
00281                                       REFIID riid,
00282                                       IUnknown* punk)
00283 {
00284     return E_NOTIMPL;
00285 }
00286 
00287 static const struct IBindStatusCallbackVtbl vtblIBindStatusCallback =
00288 {
00289     CBindStatusCallback_QueryInterface,
00290     CBindStatusCallback_AddRef,
00291     CBindStatusCallback_Release,
00292     CBindStatusCallback_OnStartBinding,
00293     CBindStatusCallback_GetPriority,
00294     CBindStatusCallback_OnLowResource,
00295     CBindStatusCallback_OnProgress,
00296     CBindStatusCallback_OnStopBinding,
00297     CBindStatusCallback_GetBindInfo,
00298     CBindStatusCallback_OnDataAvailable,
00299     CBindStatusCallback_OnObjectAvailable,
00300 };
00301 
00302 static IBindStatusCallback *
00303 CreateBindStatusCallback(void)
00304 {
00305     CBindStatusCallback *This;
00306 
00307     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
00308     if (This == NULL)
00309         return NULL;
00310 
00311     This->lpIBindStatusCallbackVtbl = &vtblIBindStatusCallback;
00312     This->ref = 1;
00313 
00314     return impl_to_interface(This, IBindStatusCallback);
00315 }
00316 
00317 
00318 // ToDo: Show status, get file name from webserver, better error reporting
00319 
00320 static int
00321 get_display_url(IN LPURL_COMPONENTS purl,
00322                 OUT TCHAR *szBuffer,
00323                 IN PDWORD pdwBufferSize)
00324 {
00325     URL_COMPONENTS urlc;
00326 
00327     /* Hide the password */
00328     urlc = *purl;
00329     urlc.lpszPassword = NULL;
00330     urlc.dwPasswordLength = 0;
00331 
00332     if (!InternetCreateUrl(&urlc, ICU_ESCAPE, szBuffer, pdwBufferSize))
00333         return DWNL_E_LASTERROR;
00334 
00335     return 1;
00336 }
00337 
00338 static int
00339 download_file(IN LPCTSTR pszUrl,
00340               IN LPCTSTR pszFile  OPTIONAL)
00341 {
00342     TCHAR szScheme[INTERNET_MAX_SCHEME_LENGTH + 1];
00343     TCHAR szHostName[INTERNET_MAX_HOST_NAME_LENGTH + 1];
00344     TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH + 1];
00345     TCHAR szPassWord[INTERNET_MAX_PASSWORD_LENGTH + 1];
00346     TCHAR szUrlPath[INTERNET_MAX_PATH_LENGTH + 1];
00347     TCHAR szExtraInfo[INTERNET_MAX_PATH_LENGTH + 1];
00348     TCHAR szUrl[INTERNET_MAX_URL_LENGTH + 1];
00349     DWORD dwUrlLen;
00350     LPTSTR pszFilePart;
00351     URL_COMPONENTS urlc;
00352     IBindStatusCallback *pbsc;
00353     int iRet;
00354 
00355     if (pszFile != NULL && pszFile[0] == _T('\0'))
00356         pszFile = NULL;
00357 
00358     urlc.dwStructSize = sizeof(urlc);
00359     urlc.lpszScheme = szScheme;
00360     urlc.dwSchemeLength = sizeof(szScheme) / sizeof(szScheme[0]);
00361     urlc.lpszHostName = szHostName;
00362     urlc.dwHostNameLength = sizeof(szHostName) / sizeof(szHostName[0]);
00363     urlc.lpszUserName = szUserName;
00364     urlc.dwUserNameLength = sizeof(szUserName) / sizeof(szUserName[0]);
00365     urlc.lpszPassword = szPassWord;
00366     urlc.dwPasswordLength = sizeof(szPassWord) / sizeof(szPassWord[0]);
00367     urlc.lpszUrlPath = szUrlPath;
00368     urlc.dwUrlPathLength = sizeof(szUrlPath) / sizeof(szUrlPath[0]);
00369     urlc.lpszExtraInfo = szExtraInfo;
00370     urlc.dwExtraInfoLength = sizeof(szExtraInfo) / sizeof(szExtraInfo[0]);
00371     if (!InternetCrackUrl(pszUrl, _tcslen(pszUrl), ICU_ESCAPE, &urlc))
00372         return DWNL_E_LASTERROR;
00373 
00374     if (urlc.nScheme != INTERNET_SCHEME_FTP &&
00375         urlc.nScheme != INTERNET_SCHEME_GOPHER &&
00376         urlc.nScheme != INTERNET_SCHEME_HTTP &&
00377         urlc.nScheme != INTERNET_SCHEME_HTTPS)
00378     {
00379         return DWNL_E_UNSUPPORTEDSCHEME;
00380     }
00381 
00382     if (urlc.nScheme == INTERNET_SCHEME_FTP && urlc.dwUserNameLength == 0 && urlc.dwPasswordLength == 0)
00383     {
00384         _tcscpy(szUserName, _T("anonymous"));
00385         urlc.dwUserNameLength = _tcslen(szUserName);
00386     }
00387 
00388     /* FIXME: Get file name from server */
00389     if (urlc.dwUrlPathLength == 0 && pszFile == NULL)
00390         return DWNL_E_NEEDTARGETFILENAME;
00391 
00392     pszFilePart = _tcsrchr(szUrlPath, _T('/'));
00393     if (pszFilePart != NULL)
00394         pszFilePart++;
00395 
00396     if (pszFilePart == NULL && pszFile == NULL)
00397         return DWNL_E_NEEDTARGETFILENAME;
00398 
00399     if (pszFile == NULL)
00400         pszFile = pszFilePart;
00401 
00402     if (urlc.dwUserNameLength == 0)
00403         urlc.lpszUserName = NULL;
00404 
00405     if (urlc.dwPasswordLength == 0)
00406         urlc.lpszPassword = NULL;
00407 
00408     /* Generate the URL to be displayed (without a password) */
00409     dwUrlLen = sizeof(szUrl) / sizeof(szUrl[0]);
00410     iRet = get_display_url(&urlc, szUrl, &dwUrlLen);
00411     if (iRet <= 0)
00412         return iRet;
00413 
00414     _tprintf(_T("Download `%s\'\n\t=> `%s\'\n"), szUrl, pszFile);
00415 
00416     /* Generate the URL to download */
00417     dwUrlLen = sizeof(szUrl) / sizeof(szUrl[0]);
00418     if (!InternetCreateUrl(&urlc, ICU_ESCAPE, szUrl, &dwUrlLen))
00419         return DWNL_E_LASTERROR;
00420 
00421     pbsc = CreateBindStatusCallback();
00422     if (pbsc == NULL)
00423         return DWNL_E_LASTERROR;
00424 
00425     if(!SUCCEEDED(URLDownloadToFile(NULL, szUrl, pszFile, 0, pbsc)))
00426     {
00427         IBindStatusCallback_Release(pbsc);
00428         return DWNL_E_LASTERROR; /* FIXME */
00429     }
00430 
00431     IBindStatusCallback_Release(pbsc);
00432     return 1;
00433 }
00434 
00435 static int
00436 print_err(int iErr)
00437 {
00438     write_status(_T(""));
00439 
00440     if (iErr == DWNL_E_LASTERROR)
00441     {
00442         if (GetLastError() == ERROR_SUCCESS)
00443         {
00444             /* File not found */
00445             _ftprintf(stderr, _T("\nERROR: Download failed.\n"));
00446         }
00447         else
00448         {
00449             /* Display last error code */
00450             _ftprintf(stderr, _T("\nERROR: %u\n"), GetLastError());
00451         }
00452     }
00453     else
00454     {
00455         switch (iErr)
00456         {
00457             case DWNL_E_NEEDTARGETFILENAME:
00458                 _ftprintf(stderr, _T("\nERROR: Cannot determine filename, please specify a destination file name.\n"));
00459                 break;
00460 
00461             case DWNL_E_UNSUPPORTEDSCHEME:
00462                 _ftprintf(stderr, _T("\nERROR: Unsupported protocol.\n"));
00463                 break;
00464         }
00465     }
00466 
00467     return 1;
00468 }
00469 
00470 int _tmain(int argc, TCHAR **argv)
00471 {
00472     int iErr, iRet = 0;
00473 
00474     if(argc != 2 && argc != 3)
00475     {
00476         _tprintf(_T("Usage: dwnl URL [DESTINATION]"));
00477         return 2;
00478     }
00479 
00480     iErr = download_file(argv[1], argc == 3 ? argv[2] : NULL);
00481     if (iErr <= 0)
00482         iRet = print_err(iErr);
00483 
00484     return iRet;
00485 }

Generated on Sun May 27 2012 04:17:12 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.