00001
00002
00003
00004
00005
00006 #include "fsInternetFile2.h"
00007 #include <curl/curl.h>
00008
00009 fsInternetFile2::fsInternetFile2()
00010 {
00011 m_curl = NULL;
00012 m_bDownloading = false;
00013 m_bNeedStop = false;
00014 m_irLastError = IR_SUCCESS;
00015
00016 m_hevReadDataReq = m_hevReadDataDone = NULL;
00017
00018 m_fileTime = -1;
00019 m_uFileSize = _UI64_MAX;
00020
00021 m_bDoPause = FALSE;
00022
00023 m_uStartPos = 0;
00024
00025 m_enRST = RST_UNKNOWN;
00026 }
00027
00028 fsInternetFile2::~fsInternetFile2()
00029 {
00030 StopDownloading ();
00031 for (int i = 0; m_bDownloading && i < 33; i++)
00032 Sleep (33 * 3);
00033
00034 if (m_hevReadDataReq)
00035 CloseHandle (m_hevReadDataReq);
00036 if (m_hevReadDataDone)
00037 CloseHandle (m_hevReadDataDone);
00038 }
00039
00040 fsInternetResult fsInternetFile2::Initialize()
00041 {
00042 if (m_curl == NULL)
00043 {
00044
00045 m_curl = curl_easy_init ();
00046
00047 if (m_curl)
00048 {
00049
00050 if (m_hevReadDataReq == NULL)
00051 {
00052 m_hevReadDataReq = CreateEvent (NULL, TRUE, FALSE, NULL);
00053 m_hevReadDataDone = CreateEvent (NULL, TRUE, FALSE, NULL);
00054 }
00055
00056
00057 curl_easy_setopt (m_curl, CURLOPT_WRITEFUNCTION, _WriteData);
00058 curl_easy_setopt (m_curl, CURLOPT_WRITEDATA, this);
00059
00060 curl_easy_setopt (m_curl, CURLOPT_HEADERFUNCTION, _WriteHeader);
00061 curl_easy_setopt (m_curl, CURLOPT_HEADERDATA, this);
00062
00063 curl_easy_setopt (m_curl, CURLOPT_FOLLOWLOCATION, TRUE);
00064 }
00065 }
00066
00067 return m_curl == NULL ? IR_ERROR : IR_SUCCESS;
00068 }
00069
00070 size_t fsInternetFile2::_WriteData(void *ptr, size_t size, size_t nmemb, void *stream)
00071 {
00072 fsInternetFile2* pthis = (fsInternetFile2*) stream;
00073 return pthis->OnWriteData ((LPBYTE)ptr, size * nmemb);
00074 }
00075
00076 void fsInternetFile2::set_URL(LPCSTR pszURL)
00077 {
00078 curl_easy_setopt (m_curl, CURLOPT_URL, pszURL);
00079
00080 if (strstr (pszURL, ".megashares.com/") != NULL)
00081 m_bDoPause = TRUE;
00082 }
00083
00084 fsInternetResult fsInternetFile2::StartDownloading()
00085 {
00086 if (m_bDownloading == false)
00087 {
00088 m_bDownloading = true;
00089 m_bNeedStop = false;
00090 m_bAnswrFromServRcvd = false;
00091 m_irLastError = IR_SUCCESS;
00092 m_strHttpHeader = "";
00093 m_enRST = RST_UNKNOWN;
00094
00095
00096 ResetEvent (m_hevReadDataReq);
00097
00098 ResetEvent (m_hevReadDataDone);
00099
00100 DWORD dw;
00101 CloseHandle (
00102 CreateThread (NULL, 0, _threadDownload, this, 0, &dw));
00103
00104
00105 while (m_bAnswrFromServRcvd == false)
00106 Sleep (10);
00107
00108 if (m_irLastError == IR_SUCCESS)
00109 ExtractFileInfoFromResponse ();
00110
00111 if (m_strHttpHeader.IsEmpty () == FALSE)
00112 Dialog (IFDD_FROMSERVER, m_strHttpHeader);
00113
00114
00115 return m_irLastError;
00116 }
00117
00118 return IR_S_FALSE;
00119 }
00120
00121 DWORD WINAPI fsInternetFile2::_threadDownload(LPVOID lp)
00122 {
00123 fsInternetFile2* pthis = (fsInternetFile2*)lp;
00124
00125 try{
00126
00127 if (pthis->m_bDoPause)
00128 Sleep (1500);
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 CURLcode res = curl_easy_perform (pthis->m_curl);
00141
00142
00143 pthis->m_irLastError = CURLcodeToIR (res);
00144
00145 if (pthis->m_irLastError == IR_SUCCESS)
00146 {
00147 long nRespCode = 200;
00148 curl_easy_getinfo (pthis->m_curl, CURLINFO_RESPONSE_CODE, &nRespCode);
00149 pthis->m_irLastError = fsHttpStatusCodeToIR (nRespCode);
00150 }
00151
00152
00153 curl_easy_cleanup (pthis->m_curl);
00154 pthis->m_curl = NULL;
00155
00156
00157 pthis->m_bAnswrFromServRcvd = true;
00158
00159 pthis->m_bDownloading = false;
00160
00161
00162 SetEvent (pthis->m_hevReadDataReq);
00163 SetEvent (pthis->m_hevReadDataDone);
00164
00165 }catch (...) {}
00166
00167 return 0;
00168 }
00169
00170 fsInternetResult fsInternetFile2::CURLcodeToIR(int code)
00171 {
00172 switch (code)
00173 {
00174 case CURLE_OK:
00175 return IR_SUCCESS;
00176
00177 case CURLE_COULDNT_RESOLVE_HOST:
00178 return IR_NAMENOTRESOLVED;
00179
00180 case CURLE_COULDNT_CONNECT:
00181 return IR_CANTCONNECT;
00182
00183 case CURLE_FTP_USER_PASSWORD_INCORRECT:
00184 return IR_LOGINFAILURE;
00185
00186 case CURLE_OPERATION_TIMEOUTED:
00187 return IR_TIMEOUT;
00188
00189 case CURLE_HTTP_RANGE_ERROR:
00190 return IR_RANGESNOTAVAIL;
00191
00192
00193 default:
00194 return IR_ERROR;
00195 }
00196 }
00197
00198 fsInternetResult fsInternetFile2::Read(LPBYTE pBuffer, DWORD dwToRead, DWORD *pdwRead)
00199 {
00200 if (pdwRead)
00201 *pdwRead = 0;
00202
00203 if (dwToRead == 0)
00204 return IR_SUCCESS;
00205
00206 if (m_bDownloading == false)
00207 return m_irLastError;
00208
00209
00210 m_ReadReq.abData.clear ();
00211 m_ReadReq.nDataLeft = dwToRead;
00212
00213
00214 SetEvent (m_hevReadDataReq);
00215
00216 while (WAIT_TIMEOUT == WaitForSingleObject (m_hevReadDataDone, 1000))
00217 {
00218 if (m_bNeedStop)
00219 return IR_S_FALSE;
00220 }
00221
00222 ResetEvent (m_hevReadDataDone);
00223
00224 if (m_bNeedStop)
00225 return IR_S_FALSE;
00226
00227 if (m_ReadReq.nDataLeft == dwToRead)
00228 return m_irLastError != IR_SUCCESS ? m_irLastError : IR_ERROR;
00229
00230
00231
00232 DWORD dwRead = dwToRead - m_ReadReq.nDataLeft;
00233
00234 CopyMemory (pBuffer, m_ReadReq.abData, dwRead);
00235 if (pdwRead)
00236 *pdwRead = dwRead;
00237
00238 return m_ReadReq.nDataLeft ? m_irLastError : IR_SUCCESS;
00239 }
00240
00241 size_t fsInternetFile2::OnWriteData(LPBYTE ptr, size_t size)
00242 {
00243
00244 m_bAnswrFromServRcvd = true;
00245 size_t sizeRcvd = size;
00246
00247 _lReadData:
00248
00249
00250 while (WAIT_TIMEOUT == WaitForSingleObject (m_hevReadDataReq, 1000))
00251 {
00252 if (m_bNeedStop)
00253 return 0;
00254 }
00255
00256 if (m_bNeedStop || m_bDownloading == false)
00257 return 0;
00258
00259
00260 int n; n = min (m_ReadReq.nDataLeft, size);
00261
00262 m_ReadReq.abData.add ((LPBYTE)ptr, n);
00263
00264 m_ReadReq.nDataLeft -= n;
00265 size -= n;
00266 ptr += n;
00267
00268 if (m_ReadReq.nDataLeft == 0) {
00269
00270
00271 ResetEvent (m_hevReadDataReq);
00272
00273 SetEvent (m_hevReadDataDone);
00274 }
00275
00276 if (size == 0)
00277
00278
00279 return sizeRcvd;
00280
00281
00282
00283
00284 goto _lReadData;
00285 }
00286
00287 void fsInternetFile2::StopDownloading()
00288 {
00289 m_bNeedStop = true;
00290
00291
00292 SetEvent (m_hevReadDataReq);
00293 SetEvent (m_hevReadDataDone);
00294 }
00295
00296 void fsInternetFile2::set_ResumeFrom (UINT64 uStart)
00297 {
00298 curl_easy_setopt (m_curl, CURLOPT_RESUME_FROM_LARGE, (curl_off_t)uStart);
00299 m_uStartPos = uStart;
00300 }
00301
00302 void fsInternetFile2::set_UserAgent(LPCSTR psz)
00303 {
00304 curl_easy_setopt (m_curl, CURLOPT_USERAGENT, psz);
00305 }
00306
00307 void fsInternetFile2::set_UseHttp11(BOOL bUse)
00308 {
00309 curl_easy_setopt (m_curl, CURLOPT_HTTP_VERSION,
00310 bUse ? CURL_HTTP_VERSION_1_1 : CURL_HTTP_VERSION_1_0);
00311 }
00312
00313 void fsInternetFile2::set_Referer(LPCSTR psz)
00314 {
00315 curl_easy_setopt (m_curl, CURLOPT_REFERER, psz);
00316 }
00317
00318 void fsInternetFile2::set_Cookie(LPCSTR psz)
00319 {
00320 curl_easy_setopt (m_curl, CURLOPT_COOKIE, psz);
00321 }
00322
00323 void fsInternetFile2::set_Auth(LPCSTR pszUser, LPCSTR pszPwd)
00324 {
00325 char sz [1000];
00326 sprintf (sz, "%s:%s", pszUser, pszPwd);
00327 curl_easy_setopt (m_curl, CURLOPT_USERPWD, sz);
00328 }
00329
00330 void fsInternetFile2::set_Proxy(LPCSTR pszProxy, LPCSTR pszUser, LPCSTR pszPwd)
00331 {
00332 curl_easy_setopt (m_curl, CURLOPT_PROXY, pszProxy);
00333
00334 if (pszUser && *pszUser)
00335 {
00336 char sz [1000];
00337 sprintf (sz, "%s:%s", pszUser, pszPwd);
00338 curl_easy_setopt (m_curl, CURLOPT_PROXYUSERPWD, sz);
00339 }
00340 }
00341
00342 void fsInternetFile2::set_PostData(LPCSTR psz)
00343 {
00344 BOOL bPost = psz != NULL && *psz != 0;
00345 curl_easy_setopt (m_curl, CURLOPT_POST, bPost);
00346 if (bPost)
00347 {
00348 curl_easy_setopt (m_curl, CURLOPT_POSTFIELDS, psz);
00349 curl_easy_setopt (m_curl, CURLOPT_POSTFIELDSIZE, lstrlen (psz));
00350 }
00351 }
00352
00353 void fsInternetFile2::ExtractFileInfoFromResponse()
00354 {
00355 if (m_curl != NULL)
00356 {
00357 LPSTR psz = NULL;
00358 curl_easy_getinfo (m_curl, CURLINFO_CONTENT_TYPE, &psz);
00359 m_strContentType = psz ? psz : "";
00360
00361 curl_easy_getinfo (m_curl, CURLINFO_FILETIME, &m_fileTime);
00362
00363 double f;
00364 curl_easy_getinfo (m_curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &f);
00365 m_uFileSize = (UINT64)f + m_uStartPos;
00366
00367 if (m_uStartPos != 0)
00368 m_enRST = RST_PRESENT;
00369 }
00370 else
00371 {
00372 m_uFileSize = 0;
00373 }
00374 }
00375
00376 LPCSTR fsInternetFile2::get_ContentType()
00377 {
00378 return m_strContentType;
00379 }
00380
00381 void UnixTimeToFileTime(time_t t, LPFILETIME pft)
00382 {
00383
00384 LONGLONG ll;
00385
00386 ll = Int32x32To64(t, 10000000) + 116444736000000000;
00387 pft->dwLowDateTime = (DWORD)ll;
00388 pft->dwHighDateTime = (DWORD) (ll >> 32);
00389 }
00390
00391 BOOL fsInternetFile2::GetLastModifiedDate(FILETIME *pTime)
00392 {
00393 if (m_fileTime == -1)
00394 return FALSE;
00395
00396 UnixTimeToFileTime (m_fileTime, pTime);
00397
00398 return TRUE;
00399 }
00400
00401 fsResumeSupportType fsInternetFile2::IsResumeSupported()
00402 {
00403 return m_enRST;
00404 }
00405
00406 size_t fsInternetFile2::_WriteHeader(void *ptr, size_t size, size_t nmemb, void *stream)
00407 {
00408 fsInternetFile2* pthis = (fsInternetFile2*) stream;
00409 char sz [10000];
00410 strncpy (sz, (LPCSTR)ptr, size * nmemb);
00411 sz [size * nmemb] = 0;
00412 pthis->m_strHttpHeader += sz;
00413 return size * nmemb;
00414 }
00415
00416 LPCSTR fsInternetFile2::get_SuggestedFileName()
00417 {
00418 return m_strSuggestedFileName;
00419 }
00420
00421 UINT64 fsInternetFile2::GetFileSize()
00422 {
00423 return m_uFileSize;
00424 }