00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 #include "camtypes.h"
00099 #include <fstream.h>
00100 #include <io.h>
00101 #include <stdlib.h>
00102 #include <direct.h>
00103 #include <stdio.h>
00104 #include <errno.h>
00105 #include <string.h>
00106 #include <process.h>
00107 #include "sglcart.h"
00108 #include "pathnmex.h"
00109 #include "camnet.h"
00110 #include "sgliboil.h"
00111
00112
00113 #include "registry.h"
00114
00115
00116
00117
00118
00119
00120 using namespace InetUtils;
00121
00122 CC_IMPLEMENT_DYNAMIC(AsynchDownload, CCObject);
00123 CC_IMPLEMENT_MEMDUMP(DownloadQueue, CCObject);
00124 CC_IMPLEMENT_MEMDUMP(DownloadCache, CCObject);
00125 CC_IMPLEMENT_MEMDUMP(InternetManager, CCObject);
00126
00127 #define new CAM_DEBUG_NEW
00128
00129 #define MAX_ATTEMPTS 5 // maximum no. of attempts made to download a file
00130 #define ICON_ANIMATION 101 // timer event for icon animation
00131 #define ICON_UPDATE_INTERVAL 300
00132
00133
00134
00135 CTypedPtrMap<CMapPtrToPtr, HWND, AsynchDownload::AsynchBindStatusCallback*> AsynchDownload::AsynchBindStatusCallback::m_CallbackTable;
00136 HWND AsynchDownload::AsynchBindStatusCallback::m_hNormalPriorityProgressDlg = NULL;
00137 UINT32 AsynchDownload::AsynchBindStatusCallback::m_nNormalPriorityIconID = _R(IDI_DOWNLOADING);
00138 INT32 AsynchDownload::m_nNormalPriorityInstanceCount = 0;
00139 INT32 AsynchDownload::m_nHighPriorityInstanceCount = 0;
00140 HICON AsynchDownload::AsynchBindStatusCallback::m_hiconProgress = 0;
00141
00142
00143 typedef BOOL (WINAPI *P_GDFSE)(LPCTSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
00144
00145
00147
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166 AsynchDownload::AsynchDownload(DOWNLOAD_HANDLE hDownload, LPDOWNLOADINFO pDownloadInfo)
00167 {
00168 m_Handle = hDownload;
00169 m_bSuccess = FALSE;
00170 m_ulFileSize = 0;
00171 m_ulDownloaded = 0;
00172 m_nPercentageDownloaded = 0;
00173 m_bAbort = FALSE;
00174 m_pMoniker = NULL;
00175 m_pBindContext = NULL;
00176 m_pCallback = NULL;
00177 m_strTargetURL = pDownloadInfo->strURL;
00178 m_strLocalFilePath = pDownloadInfo->strLocalFile;
00179 m_nFileType = (FileType) pDownloadInfo->nFileType;
00180 m_nAttempts = 0;
00181 m_Priority = (Priority) pDownloadInfo->nPriority;
00182 m_bHasProgressDlg = pDownloadInfo->bHasProgressDlg;
00183 if (m_bHasProgressDlg = pDownloadInfo->bHasProgressDlg)
00184 m_strDescription = pDownloadInfo->strDescription;
00185 if (m_Priority == PRIORITY_NORMAL)
00186 m_nNormalPriorityInstanceCount++;
00187 else if (m_Priority == PRIORITY_HIGH)
00188 m_nHighPriorityInstanceCount++;
00189
00190 m_hwndNotifyWindow = pDownloadInfo->hwndNotifyWindow;
00191 m_lNotifyToken = pDownloadInfo->lNotifyToken;
00192
00193 AfxOleLockApp();
00194 }
00195
00196 AsynchDownload::~AsynchDownload()
00197 {
00198
00199 Cleanup();
00200 if (m_Priority == PRIORITY_NORMAL)
00201 m_nNormalPriorityInstanceCount--;
00202 else if (m_Priority == PRIORITY_HIGH)
00203 m_nHighPriorityInstanceCount--;
00204 AfxOleUnlockApp();
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227 HRESULT AsynchDownload::DoBind()
00228 {
00229 if (m_strTargetURL.IsEmpty() || m_strLocalFilePath.IsEmpty())
00230 {
00231 ERROR3("Invalid (empty) URL or file path");
00232 return E_FAIL;
00233 }
00234 #ifdef _DEBUG
00235 String_256 strErrorMsg(m_strTargetURL);
00236 #endif
00237 WCHAR wchURL[INTERNET_MAX_PATH_LENGTH];
00238 MultiByteToWideChar(CP_ACP, 0, (TCHAR*) m_strTargetURL, -1, wchURL, INTERNET_MAX_PATH_LENGTH);
00239 if (IsValidURL(NULL, wchURL, 0) == S_FALSE)
00240 {
00241 #ifdef _DEBUG
00242 strErrorMsg += _T(" is not a valid URL");
00243 ERROR3(strErrorMsg);
00244 #endif
00245 return E_FAIL;
00246 }
00247 IStream* pStream = NULL;
00248 m_pCallback = new AsynchBindStatusCallback(this);
00249 if (!m_pCallback)
00250 {
00251 ERROR3("Memory allocation error");
00252 return E_OUTOFMEMORY;
00253 }
00254 HRESULT hr = CreateURLMoniker(NULL, wchURL, &m_pMoniker);
00255 if (FAILED(hr))
00256 {
00257 ERROR3("Could not create URL Moniker");
00258 Cleanup();
00259 return hr;
00260 }
00261 hr = CreateBindCtx(0, &m_pBindContext);
00262 if (FAILED(hr))
00263 {
00264 ERROR3("Could not create bind context");
00265 Cleanup();
00266 return hr;
00267 }
00268 hr = RegisterBindStatusCallback(m_pBindContext, m_pCallback, 0, 0L);
00269 if (FAILED(hr))
00270 {
00271 ERROR3("Failed to register callback object");
00272 Cleanup();
00273 return hr;
00274 }
00275 hr = m_pMoniker->BindToStorage(m_pBindContext, 0, IID_IStream, (void**)&pStream);
00276 m_nAttempts++;
00277 return hr;
00278 }
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 void AsynchDownload::Cleanup()
00294 {
00295 if (m_pCallback)
00296 {
00297 m_pCallback->Release();
00298 m_pCallback = NULL;
00299 }
00300 if (m_pMoniker)
00301 {
00302 m_pMoniker->Release();
00303 m_pMoniker = NULL;
00304 }
00305 if (m_pBindContext)
00306 {
00307 m_pBindContext->Release();
00308 m_pBindContext = NULL;
00309 }
00310 }
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 HRESULT AsynchDownload::Retry()
00324 {
00325 if (m_nAttempts <= MAX_ATTEMPTS)
00326 {
00327 TRACEUSER( "adrian", _T("\n\nRetrying the %d time to download %s\n\n"), m_nAttempts, (TCHAR*) m_strTargetURL);
00328 Cleanup();
00329 DoBind();
00330 }
00331 else
00332 {
00333 TRACEUSER( "adrian", _T("\n\nGiving up on %s\n\n"), (TCHAR*) m_strTargetURL);
00334 InternetManager::OnDownloadComplete(this);
00335 }
00336 return S_OK;
00337 }
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356 HRESULT AsynchDownload::AbortDownload()
00357 {
00358 if (m_bAbort)
00359 return S_FALSE;
00360 else
00361 m_bAbort = TRUE;
00362 if (m_pCallback)
00363 {
00364 if (m_pCallback->m_pBinding)
00365 return m_pCallback->m_pBinding->Abort();
00366 else
00367 return E_FAIL;
00368 }
00369 return E_FAIL;
00370 }
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387 void AsynchDownload::Release()
00388 {
00389 if (m_pCallback && m_pCallback->m_pBinding)
00390 m_pCallback->m_pBinding->Abort();
00391 else
00392 delete this;
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409 AsynchDownload::AsynchBindStatusCallback::AsynchBindStatusCallback(AsynchDownload* pDownload)
00410 {
00411 m_dwRef = 1;
00412 m_pDownload = pDownload;
00413 m_pBinding = NULL;
00414 m_hProgressDlg = NULL;
00415 m_nIconID = _R(IDI_DOWNLOADING);
00416 }
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430 AsynchDownload::AsynchBindStatusCallback::~AsynchBindStatusCallback()
00431 {
00432 if (m_pBinding)
00433 {
00434
00435 ERROR3("AsynchDownload deleted while still in progress");
00436 }
00437 }
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450 HRESULT _stdcall AsynchDownload::AsynchBindStatusCallback::QueryInterface(REFIID riid,void ** ppv)
00451 {
00452 *ppv = NULL;
00453
00454 if (riid==IID_IUnknown || riid==IID_IBindStatusCallback)
00455 {
00456 *ppv = this;
00457 AddRef();
00458 return S_OK;
00459 }
00460 else if (riid == IID_IAuthenticate)
00461 {
00462 *ppv = (IAuthenticate *)this;
00463 AddRef();
00464 return S_OK;
00465 }
00466
00467 return E_NOINTERFACE;
00468 }
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481 HRESULT _stdcall AsynchDownload::AsynchBindStatusCallback::OnStartBinding(DWORD dwReserved, IBinding* pbinding)
00482 {
00483 m_pDownload->m_ulFileSize = 0;
00484 m_pDownload->m_ulDownloaded = 0;
00485
00486 m_pBinding = pbinding;
00487 if (m_pBinding != NULL)
00488 m_pBinding->AddRef();
00489
00490 if (m_pDownload->m_bHasProgressDlg)
00491 {
00492 HWND hProgressDlg;
00493 BOOL bNeedsPositioning = (m_pDownload->m_Priority != PRIORITY_NORMAL) ||
00494 (m_pDownload->m_Priority == PRIORITY_NORMAL && !m_hNormalPriorityProgressDlg);
00495 if (!AttachProgressDlg())
00496 {
00497 ERROR3("Could not create progress dialog");
00498 goto END;
00499 }
00500 if (m_pDownload->m_Priority == PRIORITY_NORMAL)
00501 hProgressDlg = m_hNormalPriorityProgressDlg;
00502 else
00503 hProgressDlg = m_hProgressDlg;
00504 if (hProgressDlg)
00505 {
00506 HWND hProgressBar = GetDlgItem(hProgressDlg, _R(IDC_PROGRESSBAR));
00507 HWND hPercentage = GetDlgItem(hProgressDlg, _R(IDC_PERCENTAGE));
00508 ERROR3IF(!(hProgressBar && hPercentage), "Cannot find control");
00509
00510 ::SendMessage(hProgressBar, PBM_SETPOS, (WPARAM) 0, 0);
00511
00512 String_256 strPercentage = _T("0%");
00513
00514 String_256 strURL = m_pDownload->m_strTargetURL;
00515 strtok(strURL, _T(":/"));
00516 String_256 strCaption;
00517 strCaption.MakeMsg(_R(IDS_CONTACTING_HOST), strtok(NULL, _T(":/")));
00518 ::SetWindowText(hProgressDlg, (TCHAR*) strCaption);
00519 ::SetWindowText(hPercentage, (TCHAR*) strPercentage);
00520
00521 if (bNeedsPositioning)
00522 {
00523 CRect rcDialog;
00524 ::GetWindowRect(hProgressDlg, &rcDialog);
00525
00526 ::SetWindowPos(hProgressDlg, HWND_TOPMOST, ::GetSystemMetrics(SM_CXSCREEN) - rcDialog.Width(), 0,
00527 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW);
00528 }
00529 else
00530 ::SetWindowPos(hProgressDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
00531
00532 ::UpdateWindow(hProgressBar);
00533 ::UpdateWindow(hPercentage);
00534 ::UpdateWindow(hProgressDlg);
00535 }
00536 }
00537 END:
00538 return S_OK;
00539 }
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556 HRESULT _stdcall AsynchDownload::AsynchBindStatusCallback::OnProgress(UINT32 ulProgress, UINT32 ulProgressMax, UINT32 ulStateCode,
00557 LPCWSTR pwzStateText)
00558 {
00559 if (m_pDownload->m_bAbort)
00560 {
00561 return E_ABORT;
00562 }
00563 TCHAR sz[256];
00564 if(pwzStateText != NULL)
00565 WideCharToMultiByte(CP_ACP, 0, pwzStateText, -1, sz, sizeof(sz)/sizeof(TCHAR), 0, 0);
00566
00567
00568
00569 m_pDownload->m_ulFileSize = (ulProgress > ulProgressMax) ? ulProgress : ulProgressMax;
00570 m_pDownload->m_ulDownloaded = ulProgress;
00571 INT32 nPercentage = (ulProgress && ulProgressMax) ? (100 * ulProgress/ulProgressMax) : 0;
00572
00573 if (nPercentage!=m_pDownload->m_nPercentageDownloaded)
00574 {
00575
00576 InternetManager::SetState(m_pDownload->m_Handle, AsynchDownload::STATE_PENDING);
00577 }
00578
00579 m_pDownload->m_nPercentageDownloaded = nPercentage;
00580 if (m_pDownload->m_bHasProgressDlg)
00581 {
00582 HWND hProgressDlg;
00583 if (m_pDownload->m_Priority == PRIORITY_NORMAL)
00584 hProgressDlg = m_hNormalPriorityProgressDlg;
00585 else
00586 hProgressDlg = m_hProgressDlg;
00587
00588 if (hProgressDlg && ::IsWindow(hProgressDlg))
00589 {
00590 HWND hPercentage = GetDlgItem(hProgressDlg, _R(IDC_PERCENTAGE));
00591 HWND hProgressBar = GetDlgItem(hProgressDlg, _R(IDC_PROGRESSBAR));
00592 if (!(hPercentage && hProgressBar))
00593 {
00594 ERROR3("Cannot find control");
00595 }
00596 else
00597 {
00598 String_256 strCaption, strPercentage;
00599 switch (ulStateCode)
00600 {
00601 case BINDSTATUS_FINDINGRESOURCE:
00602 case BINDSTATUS_CONNECTING:
00603 case BINDSTATUS_SENDINGREQUEST:
00604 break;
00605
00606 case BINDSTATUS_DOWNLOADINGDATA:
00607 {
00608 strCaption = String_256(_R(IDS_DOWNLOAD));
00609 if (m_pDownload->m_strDescription.IsEmpty())
00610 {
00611 strCaption+= _T("'");
00612 strCaption += strrchr(m_pDownload->m_strTargetURL, _T('/')) + 1;
00613 strCaption+= _T("'");
00614 }
00615 else
00616 {
00617 strCaption += m_pDownload->m_strDescription;
00618 }
00619 if (!ulProgressMax)
00620 {
00621 strPercentage = "N/A";
00622 m_pDownload->m_nPercentageDownloaded = 0;
00623 }
00624 else
00625 {
00626 wsprintf(strPercentage, "%d%%", nPercentage);
00627 ::SendMessage(hProgressBar, PBM_SETPOS, (WPARAM) nPercentage, 0);
00628
00629 ::UpdateWindow(hProgressBar);
00630 }
00631 }
00632 break;
00633 case BINDSTATUS_ENDDOWNLOADDATA:
00634 strPercentage = _T("100%");
00635 ::SendMessage(hProgressBar, PBM_SETPOS, (WPARAM) 100, 0);
00636
00637 ::UpdateWindow(hProgressBar);
00638 strCaption = String_256(_R(IDS_ENDDOWNLOAD));
00639 break;
00640 }
00641
00642
00643 TCHAR tchBuff[96];
00644 ::GetWindowText(hPercentage, tchBuff, sizeof(tchBuff)/sizeof(TCHAR));
00645 if (strPercentage != String_256(tchBuff))
00646 {
00647 ::SetWindowText(hPercentage, (TCHAR*) strPercentage);
00648 ::UpdateWindow(hPercentage);
00649 }
00650 ::GetWindowText(hProgressDlg, tchBuff, sizeof(tchBuff)/sizeof(TCHAR));
00651 if (strCaption.Length() && strCaption != String_256(tchBuff))
00652 {
00653 ::SetWindowText(hProgressDlg, (TCHAR*) strCaption);
00654 ::UpdateWindow(hProgressDlg);
00655 }
00656 }
00657 }
00658 }
00659
00660 if (ulStateCode == BINDSTATUS_CACHEFILENAMEAVAILABLE)
00661 m_pDownload->m_strCacheFileName = sz;
00662
00663 return (NOERROR);
00664 }
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679 HRESULT _stdcall AsynchDownload::AsynchBindStatusCallback::OnStopBinding(HRESULT hrState, LPCWSTR szError)
00680 {
00681 #ifdef _DEBUG
00682 if (hrState)
00683 {
00684 TCHAR szErrorMsg[256];
00685 if (hrState == 0x800C0006)
00686 wsprintf(szErrorMsg, "%s %s\n", (TCHAR*) (String_256) m_pDownload->m_strTargetURL, _T("not found on the server"));
00687 else
00688 wsprintf(szErrorMsg, "%s %s\n", _T("Got network error (possibly host not found) downloading"), (TCHAR*) (String_256) m_pDownload->m_strTargetURL);
00689 if (hrState != 0x80004004)
00690 TRACE(szErrorMsg);
00691
00692
00693 String_256 strAppDataPath;
00694 GetAppDataPath(&strAppDataPath);
00695 PathName logPath(strAppDataPath);
00696 String_256 strLogName("errlog.txt");
00697 logPath.SetFileNameAndType(strLogName);
00698 static BOOL bShouldOverwrite = TRUE;
00699 INT32 iFlags = bShouldOverwrite ? ios::out | ios::trunc : ios::out | ios::app;
00700 bShouldOverwrite = FALSE;
00701 ofstream logFile((TCHAR*) (String_256) logPath.GetPath(), iFlags);
00702 if (!logFile.bad())
00703 logFile << szErrorMsg;
00704 logFile.close();
00705 }
00706 #endif
00707
00708
00709 if (m_pBinding)
00710 {
00711 m_pBinding->Release();
00712 m_pBinding = NULL;
00713 }
00714 if (m_pDownload->m_bHasProgressDlg)
00715 DetachProgressDlg();
00716
00717 if (!hrState && !m_pDownload->m_bAbort)
00718 {
00719
00720 PathNameEx path(m_pDownload->m_strLocalFilePath);
00721 BOOL bIsCacheFile = DownloadCache::IsCachePath(m_pDownload->m_strLocalFilePath);
00722 if (!path.CreateLocation())
00723 {
00724 InformError(_R(IDS_DIRCREATEFAIL), _R(IDS_OK));
00725 m_pDownload->m_bSuccess = FALSE;
00726 goto COMPLETE;
00727 }
00728 ifstream stmCache((TCHAR*) m_pDownload->m_strCacheFileName, ios::in | ios::nocreate | ios::binary);
00729
00730 DownloadCache::RemoveFile(m_pDownload->m_strLocalFilePath);
00731 if (bIsCacheFile)
00732 DownloadCache::m_CacheMonitor.IgnoreEvents(1);
00733 ofstream stmFile((TCHAR*) m_pDownload->m_strLocalFilePath, ios::out | ios::binary | ios::trunc);
00734 if (stmCache.bad() || stmFile.bad())
00735 {
00736 String_256 strTemp;
00737 PathName path(m_pDownload->m_strLocalFilePath);
00738 strTemp.MakeMsg(_R(IDS_FILEIOERROR), (TCHAR*) String_256(path.GetFileName()));
00739 Error::SetError(0, strTemp, 0);
00740 InformError();
00741 stmFile.close();
00742 stmCache.close();
00743 goto COMPLETE;
00744 }
00745 stmFile << stmCache.rdbuf();
00746 if (stmFile.bad() || stmCache.bad())
00747 {
00748 String_256 strTemp;
00749 PathName path(m_pDownload->m_strLocalFilePath);
00750 strTemp.MakeMsg(_R(IDS_FILEIOERROR), (TCHAR*) String_256(path.GetFileName()));
00751 Error::SetError(0,strTemp, 0);
00752 InformError();
00753 }
00754 else
00755 m_pDownload->m_bSuccess = TRUE;
00756 stmFile.close();
00757 stmCache.close();
00758 }
00759 else if (hrState == 0x800C0007)
00760 {
00761 return m_pDownload->Retry();
00762 }
00763
00764 COMPLETE:
00765 InternetManager::OnDownloadComplete(m_pDownload);
00766 return S_OK;
00767 }
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780 HRESULT _stdcall AsynchDownload::AsynchBindStatusCallback::GetBindInfo(DWORD* pgrfBINDF, BINDINFO* pbindInfo)
00781 {
00782 *pgrfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_GETNEWESTVERSION;
00783 pbindInfo->cbSize = sizeof(BINDINFO);
00784 pbindInfo->szExtraInfo = NULL;
00785 memset(&pbindInfo->stgmedData, 0, sizeof(STGMEDIUM));
00786 pbindInfo->grfBindInfoF = 0;
00787 pbindInfo->dwBindVerb = BINDVERB_GET;
00788 pbindInfo->szCustomVerb = NULL;
00789 return S_OK;
00790 }
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806 HRESULT _stdcall AsynchDownload::AsynchBindStatusCallback::OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pfmtetc,
00807 STGMEDIUM* pstgmed)
00808 {
00809
00810 return S_OK;
00811 }
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823 STDMETHODIMP AsynchDownload::AsynchBindStatusCallback::Authenticate(HWND *phwnd, LPWSTR *pszUserName, LPWSTR *pszPassword)
00824 {
00825 *phwnd = AfxGetMainWnd()->m_hWnd;
00826 *pszUserName = 0;
00827 *pszPassword = 0;
00828
00829 return S_OK;
00830 }
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847 BOOL CALLBACK AsynchDownload::AsynchBindStatusCallback::DialogProc(HWND hDlg, UINT32 message, WPARAM wParam, LPARAM lParam)
00848 {
00849 switch (message)
00850 {
00851 case WM_TIMER:
00852 {
00853 if (wParam == ICON_ANIMATION)
00854 {
00855 UINT32* pIconID = NULL;
00856 if (hDlg == m_hNormalPriorityProgressDlg)
00857 pIconID = &m_nNormalPriorityIconID;
00858 else
00859 {
00860 AsynchBindStatusCallback* pCallback = NULL;
00861 if (!m_CallbackTable.Lookup(hDlg, pCallback))
00862 {
00863 ERROR3("Callback not found in the lookup table");
00864 }
00865 else if (pCallback)
00866 pIconID = &pCallback->m_nIconID;
00867 }
00868 if (*pIconID == _R(IDI_DOWNLOADING6))
00869 *pIconID = _R(IDI_DOWNLOADING);
00870 else
00871 (*pIconID)++;
00872
00873 HICON hiconPrev = m_hiconProgress;
00874 m_hiconProgress = (HICON)::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(*pIconID), IMAGE_ICON, 16, 16, 0);
00875 ::SendMessage(hDlg, WM_SETICON, (WPARAM) FALSE, (LPARAM) m_hiconProgress );
00876 ::DestroyIcon(hiconPrev);
00877 return TRUE;
00878 }
00879 }
00880 break;
00881 case WM_COMMAND:
00882 {
00883 switch (LOWORD(wParam))
00884 {
00885 case IDCANCEL:
00886 {
00887 CANCEL:
00888 if (m_hiconProgress)
00889 {
00890 ::DestroyIcon(m_hiconProgress);
00891 m_hiconProgress = 0;
00892 }
00893
00894
00895 if (hDlg == m_hNormalPriorityProgressDlg)
00896 {
00897 AsynchDownload* pDownload = InternetManager::GetCurrentNormalPriorityDownload();
00898 if (pDownload)
00899 pDownload->AbortDownload();
00900 return TRUE;
00901 }
00902 AsynchBindStatusCallback* pCallback = NULL;
00903 if (!m_CallbackTable.Lookup(hDlg, pCallback))
00904 {
00905 ERROR3("Callback not found in the lookup table");
00906 }
00907 else
00908 {
00909 if (pCallback && pCallback->m_pDownload)
00910 {
00911
00912
00913
00914
00915
00916
00917 HRESULT result = pCallback->m_pDownload->AbortDownload();
00918 ERROR3IF(result == E_FAIL, "Could not abort download");
00919 }
00920 }
00921 return TRUE;
00922 }
00923 break;
00924 }
00925 }
00926 break;
00927 case WM_CLOSE:
00928 goto CANCEL;
00929 }
00930 return FALSE;
00931 }
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946 BOOL AsynchDownload::AsynchBindStatusCallback::AttachProgressDlg()
00947 {
00948 static BOOL bShouldRegisterClass = TRUE;
00949 if (bShouldRegisterClass)
00950 {
00951 WNDCLASSEX wndClass;
00952 static char szClassName[] = "DownloadProgressDlg";
00953 if (!::GetClassInfoEx(NULL, MAKEINTRESOURCE(32770), &wndClass))
00954 {
00955 ERROR3("Failed to get class info");
00956 }
00957 wndClass.lpszClassName = szClassName;
00958 wndClass.hInstance = AfxGetResourceHandle();
00959 wndClass.hIcon = NULL;
00960 wndClass.hIconSm = (HICON) ::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(_R(IDI_DOWNLOADING)), IMAGE_ICON, 16, 16, 0);
00961 wndClass.cbSize = sizeof(wndClass);
00962 ERROR3IF(!wndClass.hIconSm, "Failed to load icon");
00963 if (!::RegisterClassEx(&wndClass))
00964 {
00965 ERROR3("Failed to register progress dlg class");
00966 }
00967 else
00968 bShouldRegisterClass = FALSE;
00969 }
00970 if (m_pDownload->m_Priority == PRIORITY_HIGH)
00971 {
00972 m_hProgressDlg = ::CreateDialogParam(AfxGetResourceHandle(), MAKEINTRESOURCE(_R(IDD_PROGRESS)),
00973 HWND_DESKTOP, (DLGPROC) &DialogProc, NULL);
00974 if (!m_hProgressDlg)
00975 {
00976 ERROR3("Could not create progress dialog");
00977 return FALSE;
00978 }
00979 else
00980 {
00981
00982 m_CallbackTable[m_hProgressDlg] = this;
00983 ::SetTimer(m_hProgressDlg, ICON_ANIMATION, ICON_UPDATE_INTERVAL, NULL);
00984 }
00985 }
00986 else if (!m_hNormalPriorityProgressDlg)
00987 {
00988 m_hNormalPriorityProgressDlg = ::CreateDialogParam(AfxGetResourceHandle(), MAKEINTRESOURCE(_R(IDD_PROGRESS)),
00989 HWND_DESKTOP, (DLGPROC) &DialogProc, NULL);
00990 if (!m_hNormalPriorityProgressDlg)
00991 {
00992 ERROR3("Could not create progress dialog");
00993 return FALSE;
00994 }
00995 else
00996 ::SetTimer(m_hNormalPriorityProgressDlg, ICON_ANIMATION, ICON_UPDATE_INTERVAL, NULL);
00997 }
00998 return TRUE;
00999 }
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014 void AsynchDownload::AsynchBindStatusCallback::DetachProgressDlg()
01015 {
01016 if (m_hProgressDlg && m_pDownload->m_Priority == PRIORITY_HIGH)
01017 {
01018 BOOL bDestroyed = FALSE;
01019
01020 bDestroyed = ::KillTimer(m_hProgressDlg, ICON_ANIMATION);
01021 ERROR3IF(!bDestroyed, "Warning: timer not destroyed");
01022
01023 if (::IsWindow(m_hProgressDlg))
01024 bDestroyed = ::DestroyWindow(m_hProgressDlg);
01025 ERROR3IF(!bDestroyed, "Warning: progress dialog not destroyed");
01026
01027
01028 m_CallbackTable[m_hProgressDlg] = NULL;
01029 m_hProgressDlg = NULL;
01030 }
01031 else if (m_hNormalPriorityProgressDlg && m_pDownload->m_Priority == PRIORITY_NORMAL)
01032 {
01033 if (m_pDownload->m_nNormalPriorityInstanceCount == 1)
01034 {
01035
01036 BOOL bDestroyed = ::KillTimer(m_hNormalPriorityProgressDlg, ICON_ANIMATION);
01037 ERROR3IF(!bDestroyed, "Warning: timer not destroyed");
01038 ::DestroyWindow(m_hNormalPriorityProgressDlg);
01039 m_hNormalPriorityProgressDlg = NULL;
01040 }
01041 }
01042 }
01043
01044
01045
01047
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061 DownloadQueue::~DownloadQueue()
01062 {
01063 if (!IsEmpty())
01064 Flush();
01065 }
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080 BOOL DownloadQueue::Queue(AsynchDownload* pDownload)
01081 {
01082 if (!pDownload)
01083 {
01084 ERROR3("Unexpected NULL pointer");
01085 return FALSE;
01086 }
01087 if (m_enType != LIFO && m_enType != FIFO)
01088 {
01089 ERROR3("Invalid queue type");
01090 return FALSE;
01091 }
01092 try
01093 {
01094 if (m_enType == FIFO)
01095 m_List.AddTail(pDownload);
01096 else
01097 m_List.AddHead(pDownload);
01098 }
01099 catch (CMemoryException* pxMem)
01100 {
01101 pxMem->Delete();
01102 ERROR2(FALSE, "Could not queue download - memory problems");
01103 }
01104 return TRUE;
01105 }
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119 BOOL DownloadQueue::Remove(AsynchDownload* pDownload)
01120 {
01121 if (!pDownload)
01122 {
01123 ERROR3("Unexpected NULL pointer");
01124 return FALSE;
01125 }
01126 POSITION pos = m_List.Find(pDownload);
01127 if (!pos)
01128 return FALSE;
01129 m_List.RemoveAt(pos);
01130 pDownload->Release();
01131 return TRUE;
01132 }
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145 void DownloadQueue::Flush()
01146 {
01147 if (IsEmpty())
01148 return;
01149 POSITION pos = m_List.GetHeadPosition();
01150 while (pos)
01151 {
01152 AsynchDownload* pDownload = m_List.GetNext(pos);
01153 if (pDownload)
01154 pDownload->Release();
01155 }
01156 m_List.RemoveAll();
01157 }
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171 AsynchDownload* DownloadQueue::FindDownload(const String_256& strFileName)
01172 {
01173 if (IsEmpty())
01174 return NULL;
01175 String_256 strLocalFileName(strFileName);
01176 AsynchDownload* pIterator = NULL;
01177 POSITION pos = m_List.GetHeadPosition();
01178 while (pos)
01179 {
01180 pIterator = m_List.GetNext(pos);
01181 if (!strLocalFileName.CompareTo(pIterator->GetLocalFileName(), FALSE))
01182 return pIterator;
01183 }
01184 return NULL;
01185 }
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200 AsynchDownload* DownloadQueue::FindDownload(DOWNLOAD_HANDLE hDownload)
01201 {
01202 AsynchDownload* pDownload = NULL;
01203 if (IsEmpty())
01204 return pDownload;
01205 AsynchDownload* pIterator = NULL;
01206 POSITION pos = m_List.GetHeadPosition();
01207 while (pos && !pDownload)
01208 {
01209 pIterator = m_List.GetNext(pos);
01210 if (pIterator->GetHandle() == hDownload)
01211 pDownload = pIterator;
01212 }
01213 return pDownload;
01214 }
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231 AsynchDownload* DownloadQueue::GetNextDownload()
01232 {
01233 AsynchDownload* pDownload = NULL;
01234 if (m_List.IsEmpty())
01235 return pDownload;
01236 POSITION pos = m_List.GetHeadPosition();
01237 pDownload = m_List.GetAt(pos);
01238 m_List.RemoveAt(pos);
01239 return pDownload;
01240 }
01241
01242
01243
01245
01247
01248 UINT32 DownloadCache::m_lMaxSize = 5000 * SIZEOFKILOBYTE;
01249 STL::priority_queue< CacheEntry, stl::vector<CacheEntry>, CacheRemovalAlgorithm> DownloadCache::m_CacheData;
01250 STL::priority_queue< CacheEntry, stl::vector<CacheEntry>, CacheRemovalAlgorithm> DownloadCache::m_TemporaryCacheData;
01251 INT32 DownloadCache::m_nInstanceCount = 0;
01252 UINT32 DownloadCache::m_lCurrentSize = 0;
01253 String_256 DownloadCache::m_strCachePath;
01254 DownloadCache::CacheMonitor DownloadCache::m_CacheMonitor;
01255 HANDLE DownloadCache::CacheMonitor::rgEvents[2];
01256 volatile INT32 DownloadCache::CacheMonitor::m_nIgnoreCount;
01257 CRITICAL_SECTION DownloadCache::CacheMonitor::m_CacheDataCriticalSection;
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273 BOOL DownloadCache::SetPath(const String_256& rCachePath)
01274 {
01275 m_strCachePath = rCachePath;
01276
01277 if (_taccess(m_strCachePath, 0) == -1)
01278 {
01279 PathNameEx cachePath(m_strCachePath);
01280 if (!cachePath.CreateLocation())
01281 return FALSE;
01282 else
01283 {
01284 while (!m_CacheData.empty())
01285 m_CacheData.pop();
01286 m_lCurrentSize = 0;
01287 return TRUE;
01288 }
01289 }
01290 else
01291 {
01292 Refresh();
01293 return TRUE;
01294 }
01295 #ifdef _DEBUG
01296 AssertCacheDataValid();
01297 #endif
01298 }
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313 BOOL DownloadCache::SetSize(UINT32 lSize)
01314 {
01315 ERROR2IF(m_strCachePath.IsEmpty(), FALSE, "Invalid cache path");
01316
01317
01318
01319
01320
01321
01322 TCHAR szDrive[_MAX_DRIVE + 1];
01323 _tsplitpath(m_strCachePath, szDrive, NULL, NULL, NULL);
01324 camStrcat(szDrive, _T("\\"));
01325
01326
01327 BOOL fResult = FALSE;
01328 P_GDFSE pGetDiskFreeSpaceEx = NULL;
01329 pGetDiskFreeSpaceEx = (P_GDFSE)GetProcAddress(GetModuleHandle ("kernel32.dll"), "GetDiskFreeSpaceExA");
01330
01331 unsigned __int64 i64FreeBytesToCaller, i64TotalBytes, i64FreeBytes;
01332 DWORD dwSectorsPerCluster, dwBytesPerSector, dwNumberOfFreeClusters, dwTotalNumberOfClusters;
01333
01334 if (pGetDiskFreeSpaceEx)
01335 {
01336 fResult = pGetDiskFreeSpaceEx(szDrive, (PULARGE_INTEGER)&i64FreeBytesToCaller, (PULARGE_INTEGER)&i64TotalBytes, (PULARGE_INTEGER)&i64FreeBytes);
01337
01338
01339 if (((__int64)lSize >= i64FreeBytesToCaller) || (lSize < 500 * SIZEOFKILOBYTE)) { return FALSE; }
01340 }
01341 else
01342 {
01343 fResult = GetDiskFreeSpace (szDrive, &dwSectorsPerCluster, &dwBytesPerSector, &dwNumberOfFreeClusters, &dwTotalNumberOfClusters);
01344 if (fResult)
01345 {
01346
01347 i64FreeBytes = (__int64)dwNumberOfFreeClusters * dwSectorsPerCluster * dwBytesPerSector;
01348
01349
01350 if (((__int64)lSize >= i64FreeBytes) || (lSize < 500 * SIZEOFKILOBYTE)) { return FALSE; }
01351 }
01352 }
01353
01354
01355 if (!fResult) { ERROR3("Can't GetDiskFreeSpace()!"); return FALSE; }
01356
01357
01358 InternetManager::g_CacheSize = lSize;
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376 m_lMaxSize = lSize;
01377 while (m_lCurrentSize > m_lMaxSize && m_CacheData.size())
01378 {
01379 if (!_tremove(m_CacheData.top().szFilePath))
01380 {
01381 m_lCurrentSize -= m_CacheData.top().Size();
01382 TRACEUSER( "adrian", _T("Discarded %s - new cache size is %u bytes\n"), m_CacheData.top().szFilePath, m_lCurrentSize);
01383 TRACEUSER( "adrian", _T("New cache usage is %d percent\n"), GetUsage());
01384 }
01385 m_CacheData.pop();
01386 }
01387 #ifdef _DEBUG
01388 AssertCacheDataValid();
01389 #endif
01390 return TRUE;
01391 }
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406 void DownloadCache::Flush()
01407 {
01408 if (m_strCachePath.IsEmpty())
01409 return;
01410 Traverse(m_strCachePath, TRUE);
01411 }
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428 void DownloadCache::Refresh()
01429 {
01430 if (m_strCachePath.IsEmpty())
01431 {
01432 ERROR3("Invalid cache path!");
01433 return;
01434 }
01435 ::EnterCriticalSection(&m_CacheMonitor.m_CacheDataCriticalSection);
01436 __try
01437 {
01438 while (!m_CacheData.empty())
01439 m_CacheData.pop();
01440 m_lCurrentSize = 0;
01441 if (!Traverse(m_strCachePath))
01442 {
01443 ERROR3("Unknown cache error");
01444 __leave;
01445 }
01446 TRACEUSER( "adrian", _T("Current cache size is %u bytes\n"), m_lCurrentSize);
01447 TRACEUSER( "adrian", _T("Cache usage is %d percent\n"), GetUsage());
01448 if (!m_lMaxSize)
01449 {
01450 ERROR3("Cache size is 0!");
01451 __leave;
01452 }
01453 while (m_lCurrentSize > m_lMaxSize && m_CacheData.size())
01454 {
01455 m_CacheMonitor.IgnoreEvents(1);
01456 if (!_tremove(m_CacheData.top().szFilePath))
01457 {
01458 m_lCurrentSize -= m_CacheData.top().Size();
01459 TRACEUSER( "adrian", _T("Discarded %s - new cache size is %u bytes\n"), m_CacheData.top().szFilePath, m_lCurrentSize);
01460 TRACEUSER( "adrian", _T("New cache usage is %d percent\n"), GetUsage());
01461 }
01462 else
01463 m_CacheMonitor.IgnoreEvents(-1);
01464 m_CacheData.pop();
01465 }
01466 #ifdef _DEBUG
01467 AssertCacheDataValid();
01468 #endif
01469 }
01470 __finally
01471 {
01472 ::LeaveCriticalSection(&m_CacheMonitor.m_CacheDataCriticalSection);
01473 }
01474 }
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488 BOOL DownloadCache::Traverse(const String_256& strDirPath, BOOL bFlush)
01489 {
01490 ::EnterCriticalSection(&m_CacheMonitor.m_CacheDataCriticalSection);
01491 _finddata_t findData;
01492 String_256 strSearchPattern(strDirPath);
01493 if (strSearchPattern[strSearchPattern.Length() -1] == _T('\\'))
01494 strSearchPattern += _T('*');
01495 else
01496 strSearchPattern += _T("\\*");
01497 INT32 hSearch = _tfindfirst(strSearchPattern, &findData);
01498 if (hSearch == -1)
01499 return TRUE;
01500 do
01501 {
01502 if (!(camStrcmp(findData.name, _T(".")) && camStrcmp(findData.name, _T(".."))))
01503 continue;
01504 String_256 strFilePath(strDirPath);
01505 if (strFilePath[strFilePath.Length() -1] != _T('\\'))
01506 strFilePath += _T('\\');
01507 strFilePath += findData.name;
01508 strFilePath.toLower();
01509 CacheEntry entry(strFilePath);
01510 if (!entry.IsValid())
01511 {
01512 ERROR3("Invalid cache entry");
01513 ::LeaveCriticalSection(&m_CacheMonitor.m_CacheDataCriticalSection);
01514 return FALSE;
01515 }
01516 BOOL bIsFolder = entry.IsFolder();
01517 BOOL bIsFile = entry.IsFile();
01518 if (entry.IsFolder())
01519 Traverse(strFilePath, bFlush);
01520 else if (entry.IsFile())
01521 {
01522 if (!bFlush)
01523 {
01524 m_CacheData.push(entry);
01525 m_lCurrentSize += entry.Size();
01526 }
01527 else if (!camStrstr(strFilePath, _T(".txt")))
01528 RemoveFile(strFilePath);
01529 }
01530 }
01531 while (_tfindnext(hSearch, &findData) == 0);
01532 _findclose(hSearch);
01533 ::LeaveCriticalSection(&m_CacheMonitor.m_CacheDataCriticalSection);
01534 return TRUE;
01535 }
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549 BOOL DownloadCache::IsCachePath(const TCHAR* szPath)
01550 {
01551 String_256 strPath(szPath);
01552 strPath.toLower();
01553 String_256 cachePath(m_strCachePath);
01554 cachePath.toLower();
01555 return (camStrstr(strPath, cachePath)) ? TRUE : FALSE;
01556 }
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572 void DownloadCache::InsertFile(const TCHAR* szPath)
01573 {
01574
01575 if (!IsCachePath(szPath))
01576 return;
01577 CacheEntry entry(szPath);
01578 if (!entry.IsValid())
01579 {
01580 #ifdef _DEBUG
01581 TCHAR szMsg[256];
01582 TCHAR szError[128];
01583 switch (errno)
01584 {
01585 case ENOENT:
01586 camStrcpy(szError, "path not found (ENOENT)");
01587 break;
01588 default:
01589 wsprintf(szError, "errno = %d", errno);
01590 }
01591 wsprintf(szMsg, "Invalid cache entry: %s, %s", szPath, szError);
01592 ERROR3(szMsg);
01593 #endif
01594 return;
01595 }
01596 if (!entry.IsFile())
01597 return;
01598 TRACEUSER( "adrian", _T("Cache size before inserting %s is %u bytes\n"), entry.szFilePath, m_lCurrentSize);
01599 ::EnterCriticalSection(&m_CacheMonitor.m_CacheDataCriticalSection);
01600 m_CacheData.push(entry);
01601 m_lCurrentSize += entry.Size();
01602 TRACEUSER( "adrian", _T("Cache size after inserting %s is %u bytes\n"), entry.szFilePath, m_lCurrentSize);
01603 TRACEUSER( "adrian", _T("Cache usage is %d percent\n"), GetUsage());
01604
01605 while (m_lCurrentSize > m_lMaxSize && m_CacheData.size() && entry != m_CacheData.top())
01606 {
01607 m_CacheMonitor.IgnoreEvents(1);
01608 if (!_tremove(m_CacheData.top().szFilePath))
01609 {
01610 m_lCurrentSize -= m_CacheData.top().Size();
01611 TRACEUSER( "adrian", _T("Discarded %s - new cache size is %u bytes\n"), m_CacheData.top().szFilePath, m_lCurrentSize);
01612 TRACEUSER( "adrian", _T("New cache usage is %d percent\n"), GetUsage());
01613 }
01614 else
01615 m_CacheMonitor.IgnoreEvents(-1);
01616 m_CacheData.pop();
01617 }
01618 #ifdef _DEBUG
01619 AssertCacheDataValid();
01620 #endif
01621 ::LeaveCriticalSection(&m_CacheMonitor.m_CacheDataCriticalSection);
01622 }
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640 INT32 DownloadCache::RemoveFile(const TCHAR* szPath)
01641 {
01642 ::EnterCriticalSection(&m_CacheMonitor.m_CacheDataCriticalSection);
01643 __try
01644 {
01645
01646 if (!IsCachePath(szPath))
01647 return _tremove(szPath);
01648 CacheEntry entry(szPath);
01649 INT32 nRet;
01650 if (!entry.IsValid())
01651 {
01652 if (errno != ENOENT)
01653 {
01654 ERROR3("Invalid cache entry");
01655 m_CacheMonitor.IgnoreEvents(1);
01656 nRet = _tremove(szPath);
01657 if (nRet)
01658 m_CacheMonitor.IgnoreEvents(-1);
01659 }
01660 else
01661 nRet = -1;
01662 return nRet;
01663
01664 }
01665 if (!entry.IsFile())
01666 {
01667 errno = ENOENT;
01668 return -1;
01669 }
01670 m_CacheMonitor.IgnoreEvents(1);
01671 nRet =_tremove(szPath);
01672 if (!nRet)
01673 {
01674 RemoveEntry(entry);
01675 m_lCurrentSize -= entry.Size();
01676 }
01677 else
01678 {
01679 m_CacheMonitor.IgnoreEvents(-1);
01680 #ifdef _DEBUG
01681 TCHAR szMsg[256];
01682 TCHAR szError[128];
01683 switch (errno)
01684 {
01685 case EACCES:
01686 camStrcpy(szError, "access denied (EACCES)");
01687 break;
01688 case ENOENT:
01689 camStrcpy(szError, "path not found (ENOENT)");
01690 break;
01691 default:
01692 wsprintf(szError, "errno = %d", errno);
01693 }
01694 wsprintf(szMsg, "Failed to delete %s , %s", szPath, szError);
01695 ERROR3(szMsg);
01696 #endif
01697 }
01698 #ifdef _DEBUG
01699 AssertCacheDataValid();
01700 #endif
01701 return nRet;
01702 }
01703 __finally
01704 {
01705 ::LeaveCriticalSection(&m_CacheMonitor.m_CacheDataCriticalSection);
01706 }
01707
01708 return 0;
01709 }
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727 INT32 DownloadCache::RenameFile(const TCHAR* szOldName, const TCHAR* szNewName)
01728 {
01729 String_256 strOldName(szOldName), strNewName(szNewName);
01730 BOOL bIsCachePath = IsCachePath(szOldName);
01731 if (bIsCachePath)
01732 m_CacheMonitor.IgnoreEvents(1);
01733 INT32 nRetValue = _trename(strOldName, strNewName);
01734 if (nRetValue && bIsCachePath)
01735 m_CacheMonitor.IgnoreEvents(-1);
01736
01737 if (!bIsCachePath)
01738 return nRetValue;
01739 ::EnterCriticalSection(&m_CacheMonitor.m_CacheDataCriticalSection);
01740 if (!nRetValue)
01741 {
01742 CacheEntry entry(strNewName);
01743 if (!entry.IsValid())
01744 {
01745 ERROR3("Invalid cache entry");
01746 ::LeaveCriticalSection(&m_CacheMonitor.m_CacheDataCriticalSection);
01747 return nRetValue;
01748 }
01749 if (!entry.IsFile())
01750 {
01751 ::LeaveCriticalSection(&m_CacheMonitor.m_CacheDataCriticalSection);
01752 return nRetValue;
01753 }
01754 m_CacheData.push(entry);
01755 camStrcpy(entry.szFilePath, strOldName);
01756 RemoveEntry(entry);
01757 }
01758 #ifdef _DEBUG
01759 else
01760 {
01761 TCHAR szMsg[256];
01762 TCHAR szError[128];
01763 switch (errno)
01764 {
01765 case EACCES:
01766 camStrcpy(szError, "file already exists or could not be created (EACCES)");
01767 break;
01768 case ENOENT:
01769 camStrcpy(szError, "path not found (ENOENT)");
01770 break;
01771 default:
01772 wsprintf(szError, "errno = %d", errno);
01773 }
01774 wsprintf(szMsg, "Failed to rename %s to %s, %s", strOldName, strNewName, szError);
01775 ERROR3(szMsg);
01776 }
01777 AssertCacheDataValid();
01778 #endif
01779 ::LeaveCriticalSection(&m_CacheMonitor.m_CacheDataCriticalSection);
01780 return nRetValue;
01781 }
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794 DownloadCache::CacheMonitor::CacheMonitor()
01795 {
01796 m_hMonitorThread = NULL;
01797 m_dwMonitorThreadID = 0;
01798 ::InitializeCriticalSection(&m_CacheDataCriticalSection);
01799 }
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812 DownloadCache::CacheMonitor::~CacheMonitor()
01813 {
01814 if (m_hMonitorThread && m_dwMonitorThreadID)
01815 Deactivate();
01816 ::DeleteCriticalSection(&m_CacheDataCriticalSection);
01817 }
01818
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828
01829
01830
01831 BOOL DownloadCache::CacheMonitor::Activate(String_256& strCachePath)
01832 {
01833 if (rgEvents[EVENT_DEACTIVATE] || rgEvents[EVENT_CHANGE])
01834 return FALSE;
01835 if (!(rgEvents[EVENT_DEACTIVATE] = ::CreateEvent(NULL, TRUE, FALSE, NULL)))
01836 return FALSE;
01837 if ((rgEvents[EVENT_CHANGE] = ::FindFirstChangeNotification(strCachePath, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME)) == INVALID_HANDLE_VALUE)
01838 return FALSE;
01839 if (!(m_hMonitorThread = (HANDLE) ::_beginthreadex(NULL, 0, &Monitor, (LPVOID) rgEvents, 0, &m_dwMonitorThreadID)))
01840 return FALSE;
01841 return TRUE;
01842 }
01843
01844
01845
01846
01847
01848
01849
01850
01851
01852
01853
01854
01855 unsigned __stdcall DownloadCache::CacheMonitor::Monitor(LPVOID pParam)
01856 {
01857 TRACEUSER( "adrian", _T("Entering monitor thread\n"));
01858 HANDLE* lpEvents = (HANDLE*) pParam;
01859 while (::WaitForMultipleObjects(2, lpEvents, FALSE, INFINITE) != WAIT_OBJECT_0)
01860 {
01861 TRACEUSER( "adrian", _T("\n\n\nCache event detected\n"));
01862 if (m_nIgnoreCount > 0)
01863 {
01864 m_nIgnoreCount--;
01865 #ifdef _DEBUG
01866 TCHAR szMsg[96];
01867 wsprintf(szMsg, "Cache ignore count decremented to %d\n\n\n", m_nIgnoreCount);
01868 TRACEUSER("adrian", szMsg);
01869 #endif
01870 }
01871 else
01872 OnCacheEvent();
01873 if (!::FindNextChangeNotification(*(lpEvents + 1)))
01874 ::_endthreadex(0xFFFFFFFF);
01875 }
01876 TRACEUSER( "adrian", _T("Exiting monitor thread\n"));
01877 return 0;
01878 }
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889
01890
01891 BOOL DownloadCache::CacheMonitor::Deactivate()
01892 {
01893 BOOL bRet = TRUE;
01894 if (!m_hMonitorThread)
01895 return bRet;
01896 if (!::SetEvent(rgEvents[0]))
01897 goto TERMINATE;
01898 if (::WaitForSingleObject(m_hMonitorThread, 1000) == WAIT_TIMEOUT)
01899 {
01900 TERMINATE:
01901 bRet = FALSE;
01902 ERROR3("Warning: monitor thread not released - will attempt to terminate it");
01903 if (!::TerminateThread(m_hMonitorThread, 0xFFFFFFFF))
01904 {
01905 TCHAR szErrorMsg[96];
01906 wsprintf(szErrorMsg, "Cannot kill zombie thread, thread ID = %lx", m_dwMonitorThreadID);
01907 ERROR3(szErrorMsg);
01908 }
01909 }
01910 ::CloseHandle(m_hMonitorThread);
01911 m_hMonitorThread = NULL;
01912 m_dwMonitorThreadID = 0;
01913 ::CloseHandle(rgEvents[0]);
01914 ::FindCloseChangeNotification(rgEvents[1]);
01915 memset(rgEvents, 0x00, sizeof(rgEvents));
01916 return bRet;
01917 }
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927
01928
01929
01930
01931 void DownloadCache::CacheMonitor::OnCacheEvent()
01932 {
01933 String_256 strErrorMsg(_R(IDS_CACHEMODIFIED));
01934 String_256 strCaption(_R(IDS_ERRORBOX_WARNING));
01935 ::MessageBox(NULL, strErrorMsg, strCaption, MB_ICONEXCLAMATION | MB_SETFOREGROUND | MB_OK);
01936 ::EnterCriticalSection(&m_CacheDataCriticalSection);
01937 DownloadCache::Refresh();
01938 ::LeaveCriticalSection(&m_CacheDataCriticalSection);
01939 }
01940
01941
01942
01943
01944
01945
01946
01947
01948
01949
01950
01951
01952 CacheEntry::CacheEntry(const String_256& strPath)
01953 {
01954 camStrcpy(szFilePath, strPath);
01955 if (m_bIsValid = (!_tstat(szFilePath, &m_FileStat)))
01956 {
01957 String_256 strFilePath(strPath);
01958 strFilePath.toLower();
01959 PathName filePath(strFilePath);
01960 if (filePath.GetType() == _T("txt"))
01961 m_nPriority = PRIORITY_CURRENT_CATALOG_FILE;
01962 else if (filePath.GetType() == _T("old"))
01963 m_nPriority = PRIORITY_OLD_CATALOG_FILE;
01964 else
01965 {
01966
01967 INT32 rgTypes[5] = {SGLib_ClipArt, SGLib_Font, SGLib_Fractal, SGLib_ClipArt_WebThemes, SGLib_Blank};
01968 INT32 nLibType;
01969 String_256 strAppDataPath;
01970 GetAppDataPath(&strAppDataPath);
01971 PathName appDataPath(strAppDataPath);
01972 for (INT32 i = 0; i < 5; i++)
01973 {
01974 nLibType = rgTypes[i];
01975 if (nLibType == SGLib_Blank)
01976 break;
01977 String_256 strCacheSubdir = GetStringField(rgTypes[i], _R(IDS_CACHEDIR));
01978 String_256 strTypePath(appDataPath.GetLocation(TRUE));
01979 strTypePath += strCacheSubdir;
01980 strTypePath.toLower();
01981 if (camStrstr(strFilePath, strTypePath))
01982 break;
01983 }
01984
01985 BOOL bIsThumb = (camStrstr(strFilePath, _T("xarainfo"))) && (filePath.GetType() == _T("png"));
01986 switch (nLibType)
01987 {
01988 case SGLib_ClipArt:
01989 case SGLib_ClipArt_WebThemes:
01990 m_nPriority = bIsThumb ? PRIORITY_CLIPART_THUMBNAIL : PRIORITY_CLIPART_FILE;
01991 break;
01992 case SGLib_Font:
01993 m_nPriority = bIsThumb ? PRIORITY_FONT_THUMBNAIL : PRIORITY_FONT_FILE;
01994 break;
01995 case SGLib_Fractal:
01996 m_nPriority = bIsThumb ? PRIORITY_FILL_THUMBNAIL : PRIORITY_FILL_FILE;
01997 break;
01998 default:
01999 m_nPriority = PRIORITY_OTHER;
02000 }
02001 }
02002 }
02003 }
02004
02005
02006
02008
02010
02011
02012 INT32 InternetManager::nMaxConnections = 32;
02013 CTypedPtrArray<CPtrArray, AsynchDownload*> InternetManager::m_CurrentDownloads;
02014 DownloadQueue InternetManager::m_NormalPriorityQueue;
02015 DownloadQueue InternetManager::m_HighPriorityQueue;
02016 DOWNLOAD_HANDLE InternetManager::m_NextHandle = 1L;
02017 AsynchDownload::State InternetManager::m_StateTable[1000];
02018 String_256 InternetManager::strTempFileURL;
02019 BOOL InternetManager::m_bIsSuspended = FALSE;
02020 INT32 InternetManager::rgConnections[4] = {4, 8, 20, 64};
02021
02022
02023 UINT32 InternetManager::g_ConnectionType = CONNECTION_SLOWMODEM;
02024 UINT32 InternetManager::g_CacheSize = 5000;
02025
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035
02036 void InternetManager::Initialize()
02037 {
02038 WORD wVersionRequested;
02039 WSADATA wsaData;
02040 wVersionRequested = MAKEWORD(1, 1);
02041 if (::WSAStartup(wVersionRequested, &wsaData))
02042 InformError(_R(IDS_SOCKETNOTINITIALIZED));
02043 m_HighPriorityQueue.SetType(DownloadQueue::LIFO);
02044 String_256 strCachePath;
02045 GetAppCachePath(&strCachePath);
02046 DownloadCache::SetPath(strCachePath);
02047
02048
02049
02050
02051
02052
02053
02054
02055
02056
02057
02058
02059
02060
02061
02062
02063
02064
02065
02066
02067
02068
02069
02070
02071
02072
02073
02074
02075
02076
02077
02078 if (Camelot.DeclareSection(TEXT("Internet"), 4))
02079 {
02080 Camelot.DeclarePref(NULL, TEXT("Connection Type"), &g_ConnectionType, 0, 3);
02081 Camelot.DeclarePref(NULL, TEXT("Cache Size"), &g_CacheSize, 64 * SIZEOFKILOBYTE);
02082 }
02083 nMaxConnections = rgConnections[g_ConnectionType];
02084 DownloadCache::SetSize(g_CacheSize);
02085 }
02086
02087
02088
02089
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099 void InternetManager::OnExitInstance()
02100 {
02101 ::WSACleanup();
02102
02103
02104
02105
02106
02107
02108 if (HasDownloadsPending())
02109 {
02110 m_HighPriorityQueue.Flush();
02111 m_NormalPriorityQueue.Flush();
02112 for (INT32 i = 0; i < m_CurrentDownloads.GetSize(); i++)
02113 {
02114 if (m_CurrentDownloads[i])
02115 m_CurrentDownloads[i]->Release();
02116 }
02117 }
02118
02119 if (!strTempFileURL.IsEmpty())
02120 {
02121 UnlockUrlCacheEntryFile((TCHAR*) strTempFileURL, 0);
02122 DeleteUrlCacheEntry((TCHAR*) strTempFileURL);
02123 }
02124 }
02125
02126
02127
02128
02129
02130
02131
02132
02133
02134
02135
02136
02137
02138
02139
02140
02141
02142
02143
02144
02145
02146
02147
02148
02149
02150
02151
02152
02153
02154
02155
02156
02157
02158 DOWNLOAD_HANDLE InternetManager::RegisterDownload(LPDOWNLOADINFO pDownloadInfo)
02159 {
02160 if (m_NextHandle == 1L)
02161 memset(m_StateTable, 0, sizeof(m_StateTable));
02162
02163
02164 AsynchDownload* pPreviousDownload = GetPendingDownload(pDownloadInfo->strLocalFile);
02165 if (pPreviousDownload)
02166 return pPreviousDownload->GetHandle();
02167
02168 DOWNLOAD_HANDLE handle = m_NextHandle;
02169 m_NextHandle++;
02170 if (camStrstr((TCHAR*) pDownloadInfo->strURL, _T("file://")))
02171 {
02172 PathNameEx(pDownloadInfo->strLocalFile).CreateLocation();
02173 #ifdef UNICODE
02174 WCHAR wchURL[INTERNET_MAX_PATH_LENGTH];
02175 MultiByteToWideChar(CP_ACP, 0, (TCHAR*) pDownloadInfo->strURL, -1, wchURL, INTERNET_MAX_PATH_LENGTH);
02176 if (SUCCEEDED(::URLDownloadToFile(NULL, wchURL, (TCHAR*) pDownloadInfo->strLocalFile, 0, NULL)))
02177 #else
02178 if (SUCCEEDED(::URLDownloadToFile(NULL, (TCHAR*) pDownloadInfo->strURL, (TCHAR*) pDownloadInfo->strLocalFile, 0, NULL)))
02179 #endif
02180
02181 SetState(handle, AsynchDownload::STATE_SUCCEEDED);
02182 else
02183
02184 SetState(handle, AsynchDownload::STATE_FAILED);
02185 return handle;
02186 }
02187 AsynchDownload* pDownload = new AsynchDownload(handle, pDownloadInfo);
02188 if (!pDownload)
02189 {
02190 ERROR3("Memory allocation error");
02191 return (DOWNLOAD_HANDLE) INVALID_HANDLE_VALUE;
02192 }
02193
02194 SetState(handle, AsynchDownload::STATE_PENDING);
02195 if (m_CurrentDownloads.GetSize() < nMaxConnections && !m_bIsSuspended)
02196 {
02197 if (pDownloadInfo->nPriority == AsynchDownload::PRIORITY_NORMAL && GetOpenConnections(AsynchDownload::PRIORITY_NORMAL))
02198 goto QUEUE;
02199 if (!SUCCEEDED(pDownload->StartDownload()))
02200 {
02201
02202 SetState(handle, AsynchDownload::STATE_FAILED);
02203 pDownload->Release();
02204 }
02205 else
02206 {
02207
02208 m_CurrentDownloads.Add(pDownload);
02209 if (pDownloadInfo->nPriority == AsynchDownload::PRIORITY_NORMAL)
02210 TRACEUSER( "adrian", _T("Download fired up for %s\n"), (TCHAR*) String_256(pDownload->GetLocalFileName()));
02211 }
02212 }
02213 else
02214 {
02215 QUEUE:
02216
02217 if (pDownloadInfo->nPriority == AsynchDownload::PRIORITY_NORMAL)
02218 m_NormalPriorityQueue.Queue(pDownload);
02219 else
02220 {
02221
02222 if (pDownloadInfo->nFileType == TYPE_THUMBNAIL)
02223 m_HighPriorityQueue.SetType(DownloadQueue::FIFO);
02224 m_HighPriorityQueue.Queue(pDownload);
02225 if (pDownloadInfo->nFileType == TYPE_THUMBNAIL)
02226 m_HighPriorityQueue.SetType(DownloadQueue::LIFO);
02227 }
02228 }
02229 return handle;
02230 }
02231
02232
02233
02234
02235
02236
02237
02238
02239
02240
02241
02242
02243
02244
02245
02246
02247
02248
02249
02250 BOOL InternetManager::UnregisterDownload(DOWNLOAD_HANDLE hDownload)
02251 {
02252 AsynchDownload::State downloadState = GetDownloadState(hDownload);
02253 if (downloadState == AsynchDownload::STATE_PENDING)
02254 {
02255 AsynchDownload* pDownload = GetPendingDownload(hDownload);
02256 if (!pDownload)
02257 {
02258 ERROR3("Unexpected NULL pointer");
02259 return FALSE;
02260 }
02261
02262 m_StateTable[pDownload->GetHandle()] = AsynchDownload::STATE_ABORTED;
02263
02264
02265 BOOL bIsExecuting = FALSE;
02266 for (INT32 i = 0; i < m_CurrentDownloads.GetSize(); i++)
02267 {
02268 if (m_CurrentDownloads[i] == pDownload)
02269 bIsExecuting = TRUE;
02270 }
02271 if (bIsExecuting)
02272 {
02273
02274
02275
02276
02277 HRESULT result = pDownload->AbortDownload();
02278 ERROR3IF(result == E_FAIL, "Could not abort download");
02279 }
02280 else
02281 {
02282 if (m_NormalPriorityQueue.Remove(pDownload) || m_HighPriorityQueue.Remove(pDownload))
02283 return TRUE;
02284 else
02285 {
02286 ERROR3("Failed to unregister download");
02287 return FALSE;
02288 }
02289 }
02290 }
02291 return TRUE;
02292 }
02293
02294
02295
02296
02297
02298
02299
02300
02301
02302
02303
02304
02305
02306
02307
02308 AsynchDownload* InternetManager::GetPendingDownload(const String_256& strFileName)
02309 {
02310 AsynchDownload* pDownload = NULL;
02311 String_256 strLocalFileName(strFileName);
02312
02313 for (INT32 i = 0; i < m_CurrentDownloads.GetSize(); i++)
02314 if (!strLocalFileName.CompareTo(m_CurrentDownloads[i]->GetLocalFileName(), FALSE))
02315 return m_CurrentDownloads[i];
02316
02317 if (pDownload = m_NormalPriorityQueue.FindDownload(strLocalFileName))
02318 return pDownload;
02319 pDownload = m_HighPriorityQueue.FindDownload(strLocalFileName);
02320 return pDownload;
02321 }
02322
02323
02324
02325
02326
02327
02328
02329
02330
02331
02332
02333
02334
02335 INT32 InternetManager::GetPercentageDownloaded(DOWNLOAD_HANDLE hDownload)
02336 {
02337 AsynchDownload* pDownload = GetPendingDownload(hDownload);
02338 if (pDownload)
02339 return pDownload->GetPercentageDownloaded();
02340 else
02341 return -1;
02342 }
02343
02344
02345
02346
02347
02348
02349
02350
02351
02352
02353
02354
02355
02356 AsynchDownload* InternetManager::GetPendingDownload(DOWNLOAD_HANDLE hDownload)
02357 {
02358 AsynchDownload* pDownload = NULL;
02359 AsynchDownload::State downloadState = GetDownloadState(hDownload);
02360 if (downloadState != AsynchDownload::STATE_PENDING)
02361 return pDownload;
02362
02363 for (INT32 i = 0; i < m_CurrentDownloads.GetSize(); i++)
02364 {
02365 if (m_CurrentDownloads[i]->GetHandle() == hDownload)
02366 return m_CurrentDownloads[i];
02367 }
02368
02369 if (pDownload = m_NormalPriorityQueue.FindDownload(hDownload))
02370 return pDownload;
02371 pDownload = m_HighPriorityQueue.FindDownload(hDownload);
02372 return pDownload;
02373 }
02374
02375
02376
02377
02378
02379
02380
02381
02382
02383
02384
02385
02386
02387 AsynchDownload* InternetManager::GetDownload(DOWNLOAD_HANDLE hDownload)
02388 {
02389 AsynchDownload* pDownload = NULL;
02390
02391
02392 for (INT32 i = 0; i < m_CurrentDownloads.GetSize(); i++)
02393 {
02394 if (m_CurrentDownloads[i]->GetHandle() == hDownload)
02395 return m_CurrentDownloads[i];
02396 }
02397
02398 if (pDownload = m_NormalPriorityQueue.FindDownload(hDownload))
02399 return pDownload;
02400 pDownload = m_HighPriorityQueue.FindDownload(hDownload);
02401 return pDownload;
02402 }
02403
02404
02405
02406
02407
02408
02409
02410
02411
02412
02413
02414
02415
02416
02417
02418
02419
02420
02421
02422
02423 AsynchDownload::State InternetManager::GetDownloadState(DOWNLOAD_HANDLE hDownload)
02424 {
02425
02426 if ((hDownload < 1) || (hDownload >= MAX_HANDLE))
02427 return AsynchDownload::STATE_ERROR;
02428 else
02429 return m_StateTable[hDownload];
02430 }
02431
02432
02433
02434
02435
02436
02437
02438
02439
02440
02441
02442
02443
02444
02445
02446 void InternetManager::OnDownloadComplete(AsynchDownload* pDownload)
02447 {
02448 if (!pDownload)
02449 {
02450 ERROR3("Unexpected NULL pointer");
02451 return;
02452 }
02453 if (pDownload->HasSucceeded())
02454 {
02455
02456 DownloadCache::InsertFile(pDownload->GetLocalFileName());
02457 SetState(pDownload->GetHandle(), AsynchDownload::STATE_SUCCEEDED);
02458 }
02459 else
02460 {
02461 if (pDownload->WasAborted())
02462
02463 SetState(pDownload->GetHandle(), AsynchDownload::STATE_ABORTED);
02464 else
02465
02466 SetState(pDownload->GetHandle(), AsynchDownload::STATE_FAILED);
02467 }
02468
02469
02470 INT32 nSlot = -1;
02471 for (INT32 i = 0; i < m_CurrentDownloads.GetSize(); i++)
02472 {
02473 if (m_CurrentDownloads[i] == pDownload)
02474 nSlot = i;
02475 }
02476 ERROR3IF(nSlot == -1, "Download terminated without being executed");
02477 if (nSlot != -1)
02478 m_CurrentDownloads.RemoveAt(nSlot);
02479 if (!strTempFileURL.IsEmpty())
02480 {
02481 UnlockUrlCacheEntryFile((TCHAR*) strTempFileURL, 0);
02482 DeleteUrlCacheEntry((TCHAR*) strTempFileURL);
02483 }
02484 strTempFileURL = pDownload->GetTargetURL();
02485 if (nSlot != -1)
02486 pDownload->Release();
02487 if (m_bIsSuspended)
02488 return;
02489
02490 while ((!m_HighPriorityQueue.IsEmpty() || !m_NormalPriorityQueue.IsEmpty()) && m_CurrentDownloads.GetSize() < nMaxConnections)
02491 {
02492 AsynchDownload* pNextDownload = m_HighPriorityQueue.GetNextDownload();
02493 if (!pNextDownload)
02494 {
02495
02496
02497 if (!GetOpenConnections(AsynchDownload::PRIORITY_NORMAL))
02498 pNextDownload = m_NormalPriorityQueue.GetNextDownload();
02499 }
02500 if (!pNextDownload)
02501 return;
02502 if (!SUCCEEDED(pNextDownload->StartDownload()))
02503 {
02504
02505 SetState(pNextDownload->GetHandle(), AsynchDownload::STATE_FAILED);
02506 pNextDownload->Release();
02507 }
02508 else
02509 {
02510
02511 m_CurrentDownloads.Add(pNextDownload);
02512 TRACEUSER( "adrian", _T("Download fired up for %s\n"), (TCHAR*) String_256(pNextDownload->GetLocalFileName()));
02513 }
02514 }
02515 }
02516
02517
02518
02519
02520
02521
02522
02523
02524
02525
02526
02527
02528
02529
02530
02531 void InternetManager::CancelAllDownloads()
02532 {
02533
02534 while (!m_HighPriorityQueue.IsEmpty())
02535 {
02536 AsynchDownload* pDownload = m_HighPriorityQueue.GetNextDownload();
02537 if (pDownload)
02538 UnregisterDownload(pDownload->GetHandle());
02539 }
02540 while (!m_NormalPriorityQueue.IsEmpty())
02541 {
02542 AsynchDownload* pDownload = m_NormalPriorityQueue.GetNextDownload();
02543 if (pDownload)
02544 UnregisterDownload(pDownload->GetHandle());
02545 }
02546
02547
02548
02549 for (INT32 i = 0; i < m_CurrentDownloads.GetSize(); i++)
02550 {
02551 HRESULT result = m_CurrentDownloads[i]->AbortDownload();
02552 ERROR3IF(result == E_FAIL , "Could not abort download");
02553 }
02554 }
02555
02556
02557
02558
02559
02560
02561
02562
02563
02564
02565
02566
02567
02568
02569 INT32 InternetManager::GetOpenConnections(AsynchDownload::Priority priority)
02570 {
02571 INT32 nDownloads = 0;
02572 for (INT32 i = 0; i < m_CurrentDownloads.GetSize(); i++)
02573 {
02574 if (m_CurrentDownloads[i]->GetPriority() == priority)
02575 nDownloads++;
02576 }
02577 return nDownloads;
02578 }
02579
02580
02581
02582
02583
02584
02585
02586
02587
02588
02589
02590
02591
02592
02593
02594
02595 void InternetManager::Resume()
02596 {
02597 m_bIsSuspended = FALSE;
02598 while ((!m_HighPriorityQueue.IsEmpty() || !m_NormalPriorityQueue.IsEmpty()) && m_CurrentDownloads.GetSize() < nMaxConnections)
02599 {
02600 AsynchDownload* pNextDownload = m_HighPriorityQueue.GetNextDownload();
02601 if (!pNextDownload)
02602 {
02603
02604
02605 if (!GetOpenConnections(AsynchDownload::PRIORITY_NORMAL))
02606 pNextDownload = m_NormalPriorityQueue.GetNextDownload();
02607 }
02608 if (!pNextDownload)
02609 return;
02610 if (!SUCCEEDED(pNextDownload->StartDownload()))
02611 {
02612
02613 SetState(pNextDownload->GetHandle(), AsynchDownload::STATE_FAILED);
02614 pNextDownload->Release();
02615 }
02616 else
02617 {
02618
02619 m_CurrentDownloads.Add(pNextDownload);
02620 TRACEUSER( "adrian", _T("Download fired up for %s\n"), (TCHAR*) String_256(pNextDownload->GetLocalFileName()));
02621 }
02622 }
02623 }
02624
02625
02626
02627
02628
02629
02630
02631
02632
02633
02634
02635
02636 AsynchDownload* InternetManager::GetCurrentNormalPriorityDownload()
02637 {
02638 AsynchDownload* pDownload = NULL;
02639 for (INT32 i = 0; i < m_CurrentDownloads.GetSize(); i++)
02640 {
02641 if (m_CurrentDownloads[i]->GetPriority() == AsynchDownload::PRIORITY_NORMAL)
02642 pDownload = m_CurrentDownloads[i];
02643 }
02644 return pDownload;
02645 }
02646
02647
02648
02649
02650
02651
02652
02653
02654
02655
02656
02657
02658
02659
02660
02661
02662 void InternetManager::SetConnectionType(ConnectionType type)
02663 {
02664
02665 g_ConnectionType = type;
02666
02667 nMaxConnections = rgConnections[type];
02668
02669
02670
02671 if (type==CONNECTION_ISDN)
02672 HelpDownloadOp::HighBandwidth = TRUE;
02673 else
02674 HelpDownloadOp::HighBandwidth = FALSE;
02675
02676
02677
02678
02679
02680
02681
02682
02683
02684
02685
02686
02687
02688
02689
02690
02691
02692
02693 }
02694
02695
02696
02697
02698
02699
02700
02701
02702
02703
02704
02705
02706
02707
02708
02709 ConnectionType InternetManager::GetConnectionType()
02710 {
02711 for (INT32 type = (INT32) CONNECTION_SLOWMODEM; type <= (INT32) CONNECTION_ISDN; type++)
02712 {
02713 if (rgConnections[type] == nMaxConnections)
02714 break;
02715 }
02716 return (ConnectionType) type;
02717 }
02718
02719
02720
02721
02722
02723
02724
02725
02726
02727
02728 bool InternetManager::GetProxyServer(SERVENT* pProxyEntry, bool* pbProxyEnabled)
02729 {
02730
02731 TCHAR szProxy[_MAX_PATH];
02732 String_256 KeySectionName(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"));
02733 HKEY hKey = OpenRegKey(HKEY_CURRENT_USER, KeySectionName);
02734 if (hKey)
02735 {
02736 String_256 ProxyServer;
02737 BOOL ok = GetRegString(hKey, TEXT("ProxyServer"), &ProxyServer);
02738 if (ok)
02739 camStrcpy(szProxy, (TCHAR*)ProxyServer);
02740 *pbProxyEnabled = GetRegBool(hKey, TEXT("ProxyEnable")) == TRUE;
02741 CloseRegKey(hKey);
02742 }
02743
02744
02745 if (!camStrlen(szProxy))
02746 {
02747 *pbProxyEnabled = false;
02748 return true;
02749 }
02750
02751 String_256 strHost, strPort;
02752 TCHAR tchBuff[_MAX_PATH];
02753 camStrcpy(tchBuff, szProxy);
02754 TCHAR* lpszTemp = NULL;
02755 lpszTemp = camStrstr(tchBuff, _T("http="));
02756 if (lpszTemp != NULL)
02757 {
02758 strHost = _tcstok((lpszTemp + 5), _T(":"));
02759 strPort = _tcstok(NULL, _T(";"));
02760 }
02761 else
02762 {
02763 strHost = _tcstok(tchBuff, _T(":"));
02764 strPort = _tcstok(NULL, _T(";"));
02765 }
02766 if (!camStrlen(strHost) || !camStrlen(strPort))
02767 {
02768 *pbProxyEnabled = false;
02769 return true;
02770 }
02771
02772 camStrcpy(pProxyEntry->s_name, strHost);
02773 pProxyEntry->s_port = (unsigned short) atoi(strPort);
02774 return true;
02775 }
02776
02777
02778
02779
02780
02781
02782
02783
02784
02785
02786
02787
02788 void InternetManager::SetState(DOWNLOAD_HANDLE hDownload, AsynchDownload::State state)
02789 {
02790 m_StateTable[hDownload] = state;
02791
02792
02793
02794 AsynchDownload* pDownload = GetDownload(hDownload);
02795
02796
02797
02798 if (pDownload)
02799 {
02800 HWND hwndNotify = pDownload->GetNotifyHWND();
02801 INT32 lNotifyToken = pDownload->GetNotifyToken();
02802 if (hwndNotify && lNotifyToken)
02803 {
02804
02805 ::PostMessage(hwndNotify, WM_USER_DOWNLOADSTATUS, state, lNotifyToken);
02806 }
02807 }
02808 }
02809