Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendwnl.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
1.7.6.1
|