1c2c66affSColin Finck /* 2c2c66affSColin Finck * PROJECT: ReactOS Applications Manager 336870a02S赫杨 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4c2c66affSColin Finck * PURPOSE: Displaying a download dialog 5c2c66affSColin Finck * COPYRIGHT: Copyright 2001 John R. Sheets (for CodeWeavers) 6c2c66affSColin Finck * Copyright 2004 Mike McCormack (for CodeWeavers) 7c2c66affSColin Finck * Copyright 2005 Ge van Geldorp (gvg@reactos.org) 8c2c66affSColin Finck * Copyright 2009 Dmitry Chapyshev (dmitry@reactos.org) 9c2c66affSColin Finck * Copyright 2015 Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com) 10c2c66affSColin Finck * Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org) 11c2c66affSColin Finck */ 12c2c66affSColin Finck 13c2c66affSColin Finck /* 14c2c66affSColin Finck * Based on Wine dlls/shdocvw/shdocvw_main.c 15c2c66affSColin Finck * 16c2c66affSColin Finck * This library is free software; you can redistribute it and/or 17c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public 18c2c66affSColin Finck * License as published by the Free Software Foundation; either 19c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version. 20c2c66affSColin Finck * 21c2c66affSColin Finck * This library is distributed in the hope that it will be useful, 22c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of 23c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24c2c66affSColin Finck * Lesser General Public License for more details. 25c2c66affSColin Finck * 26c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public 27c2c66affSColin Finck * License along with this library; if not, write to the Free Software 28c2c66affSColin Finck * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 29c2c66affSColin Finck */ 30c2c66affSColin Finck #include "rapps.h" 31c2c66affSColin Finck 32c2c66affSColin Finck #include <shlobj_undoc.h> 33c2c66affSColin Finck #include <shlguid_undoc.h> 34c2c66affSColin Finck 35c2c66affSColin Finck #include <atlbase.h> 36c2c66affSColin Finck #include <atlcom.h> 37c2c66affSColin Finck #include <atlwin.h> 38c2c66affSColin Finck #include <wininet.h> 39c2c66affSColin Finck #include <shellutils.h> 40c2c66affSColin Finck 41fb1582d3SKyle Katarn #include <debug.h> 42fb1582d3SKyle Katarn 43a6bf77e7SHermès Bélusca-Maïto #include <ui/rosctrls.h> 44c2c66affSColin Finck #include <windowsx.h> 452ac13afeSHe Yang #include <process.h> 466803490aSGiannis Adamopoulos #undef SubclassWindow 47c2c66affSColin Finck 48c2c66affSColin Finck #include "rosui.h" 49c2c66affSColin Finck #include "dialogs.h" 50c2c66affSColin Finck #include "misc.h" 51c2c66affSColin Finck 52c2c66affSColin Finck #ifdef USE_CERT_PINNING 53f77f5a30SStanislav Motylkov #define CERT_ISSUER_INFO_OLD "US\r\nLet's Encrypt\r\nLet's Encrypt Authority X3" 54f77f5a30SStanislav Motylkov #define CERT_ISSUER_INFO_NEW "US\r\nLet's Encrypt\r\nR3" 55bb819f15SAlexander Shaposhnikov #define CERT_SUBJECT_INFO "rapps.reactos.org" 56c2c66affSColin Finck #endif 57c2c66affSColin Finck 58a21d959eSHe Yang enum DownloadType 59a21d959eSHe Yang { 60a21d959eSHe Yang DLTYPE_APPLICATION, 61a21d959eSHe Yang DLTYPE_DBUPDATE, 62a21d959eSHe Yang DLTYPE_DBUPDATE_UNOFFICIAL 63a21d959eSHe Yang }; 64a21d959eSHe Yang 65c2c66affSColin Finck enum DownloadStatus 66c2c66affSColin Finck { 67c2c66affSColin Finck DLSTATUS_WAITING = IDS_STATUS_WAITING, 68c2c66affSColin Finck DLSTATUS_DOWNLOADING = IDS_STATUS_DOWNLOADING, 69c2c66affSColin Finck DLSTATUS_WAITING_INSTALL = IDS_STATUS_DOWNLOADED, 70c2c66affSColin Finck DLSTATUS_INSTALLING = IDS_STATUS_INSTALLING, 71c2c66affSColin Finck DLSTATUS_INSTALLED = IDS_STATUS_INSTALLED, 72c2c66affSColin Finck DLSTATUS_FINISHED = IDS_STATUS_FINISHED 73c2c66affSColin Finck }; 74c2c66affSColin Finck 75*33c2903eSMark Jansen CStringW 76*33c2903eSMark Jansen LoadStatusString(DownloadStatus StatusParam) 77c2c66affSColin Finck { 78*33c2903eSMark Jansen CStringW szString; 79c2c66affSColin Finck szString.LoadStringW(StatusParam); 80c2c66affSColin Finck return szString; 81c2c66affSColin Finck } 82c2c66affSColin Finck 83c2c66affSColin Finck struct DownloadInfo 84c2c66affSColin Finck { 85*33c2903eSMark Jansen DownloadInfo() 86c2c66affSColin Finck { 87c2c66affSColin Finck } 88*33c2903eSMark Jansen DownloadInfo(const CApplicationInfo &AppInfo) : DLType(DLTYPE_APPLICATION) 89*33c2903eSMark Jansen { 90*33c2903eSMark Jansen AppInfo.GetDownloadInfo(szUrl, szSHA1, SizeInBytes); 91*33c2903eSMark Jansen szName = AppInfo.szDisplayName; 92*33c2903eSMark Jansen } 93c2c66affSColin Finck 94a21d959eSHe Yang DownloadType DLType; 95*33c2903eSMark Jansen CStringW szUrl; 96*33c2903eSMark Jansen CStringW szName; 97*33c2903eSMark Jansen CStringW szSHA1; 984439b538SMark Jansen ULONG SizeInBytes; 99c2c66affSColin Finck }; 100c2c66affSColin Finck 101c2c66affSColin Finck struct DownloadParam 102c2c66affSColin Finck { 103*33c2903eSMark Jansen DownloadParam() : Dialog(NULL), AppInfo(), szCaption(NULL) 104*33c2903eSMark Jansen { 105*33c2903eSMark Jansen } 106c2c66affSColin Finck DownloadParam(HWND dlg, const ATL::CSimpleArray<DownloadInfo> &info, LPCWSTR caption) 107c2c66affSColin Finck : Dialog(dlg), AppInfo(info), szCaption(caption) 108c2c66affSColin Finck { 109c2c66affSColin Finck } 110c2c66affSColin Finck 111c2c66affSColin Finck HWND Dialog; 112c2c66affSColin Finck ATL::CSimpleArray<DownloadInfo> AppInfo; 113c2c66affSColin Finck LPCWSTR szCaption; 114c2c66affSColin Finck }; 115c2c66affSColin Finck 116*33c2903eSMark Jansen class CDownloaderProgress : public CWindowImpl<CDownloaderProgress, CWindow, CControlWinTraits> 1176803490aSGiannis Adamopoulos { 118*33c2903eSMark Jansen CStringW m_szProgressText; 1196803490aSGiannis Adamopoulos 1206803490aSGiannis Adamopoulos public: 1216803490aSGiannis Adamopoulos CDownloaderProgress() 1226803490aSGiannis Adamopoulos { 1236803490aSGiannis Adamopoulos } 1246803490aSGiannis Adamopoulos 125*33c2903eSMark Jansen VOID 126*33c2903eSMark Jansen SetMarquee(BOOL Enable) 1276803490aSGiannis Adamopoulos { 1286803490aSGiannis Adamopoulos if (Enable) 1296803490aSGiannis Adamopoulos ModifyStyle(0, PBS_MARQUEE, 0); 1306803490aSGiannis Adamopoulos else 1316803490aSGiannis Adamopoulos ModifyStyle(PBS_MARQUEE, 0, 0); 1326803490aSGiannis Adamopoulos 1336803490aSGiannis Adamopoulos SendMessage(PBM_SETMARQUEE, Enable, 0); 1346803490aSGiannis Adamopoulos } 1356803490aSGiannis Adamopoulos 136*33c2903eSMark Jansen VOID 137*33c2903eSMark Jansen SetProgress(ULONG ulProgress, ULONG ulProgressMax) 1386803490aSGiannis Adamopoulos { 1396803490aSGiannis Adamopoulos WCHAR szProgress[100]; 1406803490aSGiannis Adamopoulos 1416803490aSGiannis Adamopoulos /* format the bits and bytes into pretty and accessible units... */ 1426803490aSGiannis Adamopoulos StrFormatByteSizeW(ulProgress, szProgress, _countof(szProgress)); 1436803490aSGiannis Adamopoulos 1446803490aSGiannis Adamopoulos /* use our subclassed progress bar text subroutine */ 145*33c2903eSMark Jansen CStringW ProgressText; 1466803490aSGiannis Adamopoulos 1476803490aSGiannis Adamopoulos if (ulProgressMax) 1486803490aSGiannis Adamopoulos { 1496803490aSGiannis Adamopoulos /* total size is known */ 1506803490aSGiannis Adamopoulos WCHAR szProgressMax[100]; 1516803490aSGiannis Adamopoulos UINT uiPercentage = ((ULONGLONG)ulProgress * 100) / ulProgressMax; 1526803490aSGiannis Adamopoulos 1536803490aSGiannis Adamopoulos /* send the current progress to the progress bar */ 154*33c2903eSMark Jansen if (!IsWindow()) 155*33c2903eSMark Jansen return; 1566803490aSGiannis Adamopoulos SendMessage(PBM_SETPOS, uiPercentage, 0); 1576803490aSGiannis Adamopoulos 1586803490aSGiannis Adamopoulos /* format total download size */ 1596803490aSGiannis Adamopoulos StrFormatByteSizeW(ulProgressMax, szProgressMax, _countof(szProgressMax)); 1606803490aSGiannis Adamopoulos 1616803490aSGiannis Adamopoulos /* generate the text on progress bar */ 162*33c2903eSMark Jansen ProgressText.Format(L"%u%% \x2014 %ls / %ls", uiPercentage, szProgress, szProgressMax); 1636803490aSGiannis Adamopoulos } 1646803490aSGiannis Adamopoulos else 1656803490aSGiannis Adamopoulos { 1666803490aSGiannis Adamopoulos /* send the current progress to the progress bar */ 167*33c2903eSMark Jansen if (!IsWindow()) 168*33c2903eSMark Jansen return; 1696803490aSGiannis Adamopoulos SendMessage(PBM_SETPOS, 0, 0); 1706803490aSGiannis Adamopoulos 1716803490aSGiannis Adamopoulos /* total size is not known, display only current size */ 1726803490aSGiannis Adamopoulos ProgressText.Format(L"%ls...", szProgress); 1736803490aSGiannis Adamopoulos } 1746803490aSGiannis Adamopoulos 1756803490aSGiannis Adamopoulos /* and finally display it */ 176*33c2903eSMark Jansen if (!IsWindow()) 177*33c2903eSMark Jansen return; 178844d447eSKatayama Hirofumi MZ SetWindowText(ProgressText.GetString()); 1796803490aSGiannis Adamopoulos } 1806803490aSGiannis Adamopoulos 181*33c2903eSMark Jansen LRESULT 182*33c2903eSMark Jansen OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 183b4114030SKatayama Hirofumi MZ { 184b4114030SKatayama Hirofumi MZ return TRUE; 185b4114030SKatayama Hirofumi MZ } 186b4114030SKatayama Hirofumi MZ 187*33c2903eSMark Jansen LRESULT 188*33c2903eSMark Jansen OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 1896803490aSGiannis Adamopoulos { 1906803490aSGiannis Adamopoulos PAINTSTRUCT ps; 1916803490aSGiannis Adamopoulos HDC hDC = BeginPaint(&ps), hdcMem; 1926803490aSGiannis Adamopoulos HBITMAP hbmMem; 1936803490aSGiannis Adamopoulos HANDLE hOld; 1946803490aSGiannis Adamopoulos RECT myRect; 1956803490aSGiannis Adamopoulos UINT win_width, win_height; 1966803490aSGiannis Adamopoulos 1976803490aSGiannis Adamopoulos GetClientRect(&myRect); 1986803490aSGiannis Adamopoulos 1996803490aSGiannis Adamopoulos /* grab the progress bar rect size */ 2006803490aSGiannis Adamopoulos win_width = myRect.right - myRect.left; 2016803490aSGiannis Adamopoulos win_height = myRect.bottom - myRect.top; 2026803490aSGiannis Adamopoulos 2036803490aSGiannis Adamopoulos /* create an off-screen DC for double-buffering */ 2046803490aSGiannis Adamopoulos hdcMem = CreateCompatibleDC(hDC); 2056803490aSGiannis Adamopoulos hbmMem = CreateCompatibleBitmap(hDC, win_width, win_height); 2066803490aSGiannis Adamopoulos 2076803490aSGiannis Adamopoulos hOld = SelectObject(hdcMem, hbmMem); 2086803490aSGiannis Adamopoulos 2096803490aSGiannis Adamopoulos /* call the original draw code and redirect it to our memory buffer */ 2106803490aSGiannis Adamopoulos DefWindowProc(uMsg, (WPARAM)hdcMem, lParam); 2116803490aSGiannis Adamopoulos 2126803490aSGiannis Adamopoulos /* draw our nifty progress text over it */ 2136803490aSGiannis Adamopoulos SelectFont(hdcMem, GetStockFont(DEFAULT_GUI_FONT)); 214*33c2903eSMark Jansen DrawShadowText( 215*33c2903eSMark Jansen hdcMem, m_szProgressText.GetString(), m_szProgressText.GetLength(), &myRect, 216*33c2903eSMark Jansen DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE, GetSysColor(COLOR_CAPTIONTEXT), 217*33c2903eSMark Jansen GetSysColor(COLOR_3DDKSHADOW), 1, 1); 2186803490aSGiannis Adamopoulos 2196803490aSGiannis Adamopoulos /* transfer the off-screen DC to the screen */ 2206803490aSGiannis Adamopoulos BitBlt(hDC, 0, 0, win_width, win_height, hdcMem, 0, 0, SRCCOPY); 2216803490aSGiannis Adamopoulos 2226803490aSGiannis Adamopoulos /* free the off-screen DC */ 2236803490aSGiannis Adamopoulos SelectObject(hdcMem, hOld); 2246803490aSGiannis Adamopoulos DeleteObject(hbmMem); 2256803490aSGiannis Adamopoulos DeleteDC(hdcMem); 2266803490aSGiannis Adamopoulos 2276803490aSGiannis Adamopoulos EndPaint(&ps); 2286803490aSGiannis Adamopoulos return 0; 2296803490aSGiannis Adamopoulos } 2306803490aSGiannis Adamopoulos 231*33c2903eSMark Jansen LRESULT 232*33c2903eSMark Jansen OnSetText(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 2336803490aSGiannis Adamopoulos { 234b4114030SKatayama Hirofumi MZ PCWSTR pszText = (PCWSTR)lParam; 235b4114030SKatayama Hirofumi MZ if (pszText) 2366803490aSGiannis Adamopoulos { 237b4114030SKatayama Hirofumi MZ if (m_szProgressText != pszText) 238b4114030SKatayama Hirofumi MZ { 239b4114030SKatayama Hirofumi MZ m_szProgressText = pszText; 240b4114030SKatayama Hirofumi MZ InvalidateRect(NULL, TRUE); 2416803490aSGiannis Adamopoulos } 242b4114030SKatayama Hirofumi MZ } 243b4114030SKatayama Hirofumi MZ else 244b4114030SKatayama Hirofumi MZ { 245b4114030SKatayama Hirofumi MZ if (!m_szProgressText.IsEmpty()) 246b4114030SKatayama Hirofumi MZ { 247b4114030SKatayama Hirofumi MZ m_szProgressText.Empty(); 248b4114030SKatayama Hirofumi MZ InvalidateRect(NULL, TRUE); 249b4114030SKatayama Hirofumi MZ } 250b4114030SKatayama Hirofumi MZ } 251b4114030SKatayama Hirofumi MZ return TRUE; 2526803490aSGiannis Adamopoulos } 2536803490aSGiannis Adamopoulos 2546803490aSGiannis Adamopoulos BEGIN_MSG_MAP(CDownloaderProgress) 255b4114030SKatayama Hirofumi MZ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) 2566803490aSGiannis Adamopoulos MESSAGE_HANDLER(WM_PAINT, OnPaint) 2576803490aSGiannis Adamopoulos MESSAGE_HANDLER(WM_SETTEXT, OnSetText) 2586803490aSGiannis Adamopoulos END_MSG_MAP() 2596803490aSGiannis Adamopoulos }; 2606803490aSGiannis Adamopoulos 261*33c2903eSMark Jansen class CDowloadingAppsListView : public CListView 262c2c66affSColin Finck { 263c2c66affSColin Finck public: 264*33c2903eSMark Jansen HWND 265*33c2903eSMark Jansen Create(HWND hwndParent) 266c2c66affSColin Finck { 267c2c66affSColin Finck RECT r = {10, 150, 320, 350}; 268*33c2903eSMark Jansen const DWORD style = WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | 269*33c2903eSMark Jansen LVS_NOCOLUMNHEADER; 270c2c66affSColin Finck 271c2c66affSColin Finck HWND hwnd = CListView::Create(hwndParent, r, NULL, style, WS_EX_CLIENTEDGE); 272c2c66affSColin Finck 273c2c66affSColin Finck AddColumn(0, 150, LVCFMT_LEFT); 274c2c66affSColin Finck AddColumn(1, 120, LVCFMT_LEFT); 275c2c66affSColin Finck 276c2c66affSColin Finck return hwnd; 277c2c66affSColin Finck } 278c2c66affSColin Finck 279*33c2903eSMark Jansen VOID 280*33c2903eSMark Jansen LoadList(ATL::CSimpleArray<DownloadInfo> arrInfo) 281c2c66affSColin Finck { 282c2c66affSColin Finck for (INT i = 0; i < arrInfo.GetSize(); ++i) 283c2c66affSColin Finck { 284c2c66affSColin Finck AddRow(i, arrInfo[i].szName.GetString(), DLSTATUS_WAITING); 285c2c66affSColin Finck } 286c2c66affSColin Finck } 287c2c66affSColin Finck 288*33c2903eSMark Jansen VOID 289*33c2903eSMark Jansen SetDownloadStatus(INT ItemIndex, DownloadStatus Status) 290c2c66affSColin Finck { 291*33c2903eSMark Jansen CStringW szBuffer = LoadStatusString(Status); 29296fba571SGiannis Adamopoulos SetItemText(ItemIndex, 1, szBuffer.GetString()); 293c2c66affSColin Finck } 294c2c66affSColin Finck 295*33c2903eSMark Jansen BOOL 296*33c2903eSMark Jansen AddItem(INT ItemIndex, LPWSTR lpText) 297c2c66affSColin Finck { 298c2c66affSColin Finck LVITEMW Item; 299c2c66affSColin Finck 300c2c66affSColin Finck ZeroMemory(&Item, sizeof(Item)); 301c2c66affSColin Finck 302c2c66affSColin Finck Item.mask = LVIF_TEXT | LVIF_STATE; 303c2c66affSColin Finck Item.pszText = lpText; 304c2c66affSColin Finck Item.iItem = ItemIndex; 305c2c66affSColin Finck 306c2c66affSColin Finck return InsertItem(&Item); 307c2c66affSColin Finck } 308c2c66affSColin Finck 309*33c2903eSMark Jansen VOID 310*33c2903eSMark Jansen AddRow(INT RowIndex, LPCWSTR szAppName, const DownloadStatus Status) 311c2c66affSColin Finck { 312*33c2903eSMark Jansen CStringW szStatus = LoadStatusString(Status); 313*33c2903eSMark Jansen AddItem(RowIndex, const_cast<LPWSTR>(szAppName)); 314c2c66affSColin Finck SetDownloadStatus(RowIndex, Status); 315c2c66affSColin Finck } 316c2c66affSColin Finck 317*33c2903eSMark Jansen BOOL 318*33c2903eSMark Jansen AddColumn(INT Index, INT Width, INT Format) 319c2c66affSColin Finck { 320c2c66affSColin Finck LVCOLUMNW Column; 321c2c66affSColin Finck ZeroMemory(&Column, sizeof(Column)); 322c2c66affSColin Finck 323c2c66affSColin Finck Column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM; 324c2c66affSColin Finck Column.iSubItem = Index; 325c2c66affSColin Finck Column.cx = Width; 326c2c66affSColin Finck Column.fmt = Format; 327c2c66affSColin Finck 328c2c66affSColin Finck return (InsertColumn(Index, &Column) == -1) ? FALSE : TRUE; 329c2c66affSColin Finck } 330c2c66affSColin Finck }; 331c2c66affSColin Finck 332c2c66affSColin Finck #ifdef USE_CERT_PINNING 333*33c2903eSMark Jansen static BOOL 334*33c2903eSMark Jansen CertGetSubjectAndIssuer(HINTERNET hFile, CLocalPtr<char> &subjectInfo, CLocalPtr<char> &issuerInfo) 335c2c66affSColin Finck { 336c2c66affSColin Finck DWORD certInfoLength; 337b56193a2SMark Jansen INTERNET_CERTIFICATE_INFOA certInfo; 33807f3691cSMark Jansen DWORD size, flags; 33907f3691cSMark Jansen 34007f3691cSMark Jansen size = sizeof(flags); 34107f3691cSMark Jansen if (!InternetQueryOptionA(hFile, INTERNET_OPTION_SECURITY_FLAGS, &flags, &size)) 34207f3691cSMark Jansen { 34307f3691cSMark Jansen return FALSE; 34407f3691cSMark Jansen } 34507f3691cSMark Jansen 34607f3691cSMark Jansen if (!flags & SECURITY_FLAG_SECURE) 34707f3691cSMark Jansen { 34807f3691cSMark Jansen return FALSE; 34907f3691cSMark Jansen } 350c2c66affSColin Finck 351b56193a2SMark Jansen /* Despite what the header indicates, the implementation of INTERNET_CERTIFICATE_INFO is not Unicode-aware. */ 352c2c66affSColin Finck certInfoLength = sizeof(certInfo); 353*33c2903eSMark Jansen if (!InternetQueryOptionA(hFile, INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT, &certInfo, &certInfoLength)) 354c2c66affSColin Finck { 355b56193a2SMark Jansen return FALSE; 356b56193a2SMark Jansen } 357b56193a2SMark Jansen 35807f3691cSMark Jansen subjectInfo.Attach(certInfo.lpszSubjectInfo); 35907f3691cSMark Jansen issuerInfo.Attach(certInfo.lpszIssuerInfo); 36007f3691cSMark Jansen 361c2c66affSColin Finck if (certInfo.lpszProtocolName) 362c2c66affSColin Finck LocalFree(certInfo.lpszProtocolName); 363c2c66affSColin Finck if (certInfo.lpszSignatureAlgName) 364c2c66affSColin Finck LocalFree(certInfo.lpszSignatureAlgName); 365b56193a2SMark Jansen if (certInfo.lpszEncryptionAlgName) 366b56193a2SMark Jansen LocalFree(certInfo.lpszEncryptionAlgName); 367b56193a2SMark Jansen 36807f3691cSMark Jansen return certInfo.lpszSubjectInfo && certInfo.lpszIssuerInfo; 369c2c66affSColin Finck } 370c2c66affSColin Finck #endif 371c2c66affSColin Finck 372*33c2903eSMark Jansen inline VOID 373*33c2903eSMark Jansen MessageBox_LoadString(HWND hMainWnd, INT StringID) 374c2c66affSColin Finck { 375*33c2903eSMark Jansen CStringW szMsgText; 376c2c66affSColin Finck if (szMsgText.LoadStringW(StringID)) 377c2c66affSColin Finck { 378c2c66affSColin Finck MessageBoxW(hMainWnd, szMsgText.GetString(), NULL, MB_OK | MB_ICONERROR); 379c2c66affSColin Finck } 380c2c66affSColin Finck } 381c2c66affSColin Finck 3821807dbfdSGiannis Adamopoulos // Download dialog (loaddlg.cpp) 3831807dbfdSGiannis Adamopoulos class CDownloadManager 3841807dbfdSGiannis Adamopoulos { 3854c524ee3S赫杨 static ATL::CSimpleArray<DownloadInfo> AppsDownloadList; 3861807dbfdSGiannis Adamopoulos static CDowloadingAppsListView DownloadsListView; 3876803490aSGiannis Adamopoulos static CDownloaderProgress ProgressBar; 388db8f1d6fSGiannis Adamopoulos static BOOL bCancelled; 389946ee611SMark Jansen static BOOL bModal; 390*33c2903eSMark Jansen static VOID 391*33c2903eSMark Jansen UpdateProgress(HWND hDlg, ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText); 392*33c2903eSMark Jansen 3931807dbfdSGiannis Adamopoulos public: 394*33c2903eSMark Jansen static VOID 395*33c2903eSMark Jansen Add(DownloadInfo info); 396*33c2903eSMark Jansen static VOID 397*33c2903eSMark Jansen Download(const DownloadInfo &DLInfo, BOOL bIsModal = FALSE); 398*33c2903eSMark Jansen static INT_PTR CALLBACK 399*33c2903eSMark Jansen DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wParam, LPARAM lParam); 400*33c2903eSMark Jansen static unsigned int WINAPI 401*33c2903eSMark Jansen ThreadFunc(LPVOID Context); 4021807dbfdSGiannis Adamopoulos static VOID LaunchDownloadDialog(BOOL); 4031807dbfdSGiannis Adamopoulos }; 4041807dbfdSGiannis Adamopoulos 405c2c66affSColin Finck // CDownloadManager 4064c524ee3S赫杨 ATL::CSimpleArray<DownloadInfo> CDownloadManager::AppsDownloadList; 407c2c66affSColin Finck CDowloadingAppsListView CDownloadManager::DownloadsListView; 4086803490aSGiannis Adamopoulos CDownloaderProgress CDownloadManager::ProgressBar; 409946ee611SMark Jansen BOOL CDownloadManager::bCancelled = FALSE; 410946ee611SMark Jansen BOOL CDownloadManager::bModal = FALSE; 411c2c66affSColin Finck 412*33c2903eSMark Jansen VOID 413*33c2903eSMark Jansen CDownloadManager::Add(DownloadInfo info) 4141807dbfdSGiannis Adamopoulos { 4154c524ee3S赫杨 AppsDownloadList.Add(info); 4161807dbfdSGiannis Adamopoulos } 4171807dbfdSGiannis Adamopoulos 418*33c2903eSMark Jansen VOID 419*33c2903eSMark Jansen CDownloadManager::Download(const DownloadInfo &DLInfo, BOOL bIsModal) 420c2c66affSColin Finck { 4214c524ee3S赫杨 AppsDownloadList.RemoveAll(); 4224c524ee3S赫杨 AppsDownloadList.Add(DLInfo); 423c2c66affSColin Finck LaunchDownloadDialog(bIsModal); 424c2c66affSColin Finck } 425c2c66affSColin Finck 426*33c2903eSMark Jansen INT_PTR CALLBACK 427*33c2903eSMark Jansen CDownloadManager::DownloadDlgProc(HWND Dlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 428c2c66affSColin Finck { 429c2c66affSColin Finck static WCHAR szCaption[MAX_PATH]; 430c2c66affSColin Finck 431c2c66affSColin Finck switch (uMsg) 432c2c66affSColin Finck { 433c2c66affSColin Finck case WM_INITDIALOG: 434c2c66affSColin Finck { 435c2c66affSColin Finck HICON hIconSm, hIconBg; 436*33c2903eSMark Jansen CStringW szTempCaption; 437c2c66affSColin Finck 438db8f1d6fSGiannis Adamopoulos bCancelled = FALSE; 439db8f1d6fSGiannis Adamopoulos 440a84d2959SHermès Bélusca-Maïto if (hMainWnd) 441a84d2959SHermès Bélusca-Maïto { 4426f130666STimo Kreuzer hIconBg = (HICON)GetClassLongPtrW(hMainWnd, GCLP_HICON); 4436f130666STimo Kreuzer hIconSm = (HICON)GetClassLongPtrW(hMainWnd, GCLP_HICONSM); 444a84d2959SHermès Bélusca-Maïto } 445a84d2959SHermès Bélusca-Maïto if (!hMainWnd || (!hIconBg || !hIconSm)) 446a84d2959SHermès Bélusca-Maïto { 447a84d2959SHermès Bélusca-Maïto /* Load the default icon */ 448a84d2959SHermès Bélusca-Maïto hIconBg = hIconSm = LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN)); 449a84d2959SHermès Bélusca-Maïto } 450c2c66affSColin Finck 451c2c66affSColin Finck if (hIconBg && hIconSm) 452c2c66affSColin Finck { 453c2c66affSColin Finck SendMessageW(Dlg, WM_SETICON, ICON_BIG, (LPARAM)hIconBg); 454c2c66affSColin Finck SendMessageW(Dlg, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm); 455c2c66affSColin Finck } 456c2c66affSColin Finck 457c2c66affSColin Finck HWND Item = GetDlgItem(Dlg, IDC_DOWNLOAD_PROGRESS); 458c2c66affSColin Finck if (Item) 459c2c66affSColin Finck { 460c2c66affSColin Finck // initialize the default values for our nifty progress bar 461c2c66affSColin Finck // and subclass it so that it learns to print a status text 4626803490aSGiannis Adamopoulos ProgressBar.SubclassWindow(Item); 4636803490aSGiannis Adamopoulos ProgressBar.SendMessage(PBM_SETRANGE, 0, MAKELPARAM(0, 100)); 4646803490aSGiannis Adamopoulos ProgressBar.SendMessage(PBM_SETPOS, 0, 0); 465b4114030SKatayama Hirofumi MZ if (AppsDownloadList.GetSize() > 0) 466b4114030SKatayama Hirofumi MZ ProgressBar.SetProgress(0, AppsDownloadList[0].SizeInBytes); 467c2c66affSColin Finck } 468c2c66affSColin Finck 469c2c66affSColin Finck // Add a ListView 470c2c66affSColin Finck HWND hListView = DownloadsListView.Create(Dlg); 471c2c66affSColin Finck if (!hListView) 472c2c66affSColin Finck { 473c2c66affSColin Finck return FALSE; 474c2c66affSColin Finck } 4754c524ee3S赫杨 DownloadsListView.LoadList(AppsDownloadList); 476c2c66affSColin Finck 477c2c66affSColin Finck // Get a dlg string for later use 47826ac8ac8SHermès Bélusca-Maïto GetWindowTextW(Dlg, szCaption, _countof(szCaption)); 479c2c66affSColin Finck 480ee019e12SAlexander Shaposhnikov // Hide a placeholder from displaying 481ee019e12SAlexander Shaposhnikov szTempCaption = szCaption; 482ee019e12SAlexander Shaposhnikov szTempCaption.Replace(L"%ls", L""); 483ee019e12SAlexander Shaposhnikov SetWindowText(Dlg, szTempCaption.GetString()); 484ee019e12SAlexander Shaposhnikov 485ee019e12SAlexander Shaposhnikov ShowWindow(Dlg, SW_SHOW); 486ee019e12SAlexander Shaposhnikov 487c2c66affSColin Finck // Start download process 4884c524ee3S赫杨 DownloadParam *param = new DownloadParam(Dlg, AppsDownloadList, szCaption); 4892ac13afeSHe Yang unsigned int ThreadId; 4902ac13afeSHe Yang HANDLE Thread = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (void *)param, 0, &ThreadId); 491c2c66affSColin Finck if (!Thread) 492c2c66affSColin Finck { 493c2c66affSColin Finck return FALSE; 494c2c66affSColin Finck } 495c2c66affSColin Finck 496c2c66affSColin Finck CloseHandle(Thread); 4974c524ee3S赫杨 AppsDownloadList.RemoveAll(); 498c2c66affSColin Finck return TRUE; 499c2c66affSColin Finck } 500c2c66affSColin Finck 501c2c66affSColin Finck case WM_COMMAND: 502c2c66affSColin Finck if (wParam == IDCANCEL) 503c2c66affSColin Finck { 504db8f1d6fSGiannis Adamopoulos bCancelled = TRUE; 505c2c66affSColin Finck PostMessageW(Dlg, WM_CLOSE, 0, 0); 506c2c66affSColin Finck } 507c2c66affSColin Finck return FALSE; 508c2c66affSColin Finck 509c2c66affSColin Finck case WM_CLOSE: 510b4114030SKatayama Hirofumi MZ if (ProgressBar) 511b4114030SKatayama Hirofumi MZ ProgressBar.UnsubclassWindow(TRUE); 512946ee611SMark Jansen if (CDownloadManager::bModal) 513946ee611SMark Jansen { 514946ee611SMark Jansen ::EndDialog(Dlg, 0); 515946ee611SMark Jansen } 516946ee611SMark Jansen else 517946ee611SMark Jansen { 518946ee611SMark Jansen ::DestroyWindow(Dlg); 519946ee611SMark Jansen } 520c2c66affSColin Finck return TRUE; 521c2c66affSColin Finck 522c2c66affSColin Finck default: 523c2c66affSColin Finck return FALSE; 524c2c66affSColin Finck } 525c2c66affSColin Finck } 526c2c66affSColin Finck 5271e201d70SGiannis Adamopoulos BOOL UrlHasBeenCopied; 5281e201d70SGiannis Adamopoulos 529*33c2903eSMark Jansen VOID 530*33c2903eSMark Jansen CDownloadManager::UpdateProgress( 5311e201d70SGiannis Adamopoulos HWND hDlg, 5321e201d70SGiannis Adamopoulos ULONG ulProgress, 5331e201d70SGiannis Adamopoulos ULONG ulProgressMax, 5341e201d70SGiannis Adamopoulos ULONG ulStatusCode, 5351e201d70SGiannis Adamopoulos LPCWSTR szStatusText) 5361e201d70SGiannis Adamopoulos { 5371e201d70SGiannis Adamopoulos HWND Item; 5381e201d70SGiannis Adamopoulos 539*33c2903eSMark Jansen if (!IsWindow(hDlg)) 540*33c2903eSMark Jansen return; 5411e201d70SGiannis Adamopoulos ProgressBar.SetProgress(ulProgress, ulProgressMax); 5421e201d70SGiannis Adamopoulos 543*33c2903eSMark Jansen if (!IsWindow(hDlg)) 544*33c2903eSMark Jansen return; 5451e201d70SGiannis Adamopoulos Item = GetDlgItem(hDlg, IDC_DOWNLOAD_STATUS); 5461e201d70SGiannis Adamopoulos if (Item && szStatusText && wcslen(szStatusText) > 0 && UrlHasBeenCopied == FALSE) 5471e201d70SGiannis Adamopoulos { 5481e201d70SGiannis Adamopoulos SIZE_T len = wcslen(szStatusText) + 1; 549*33c2903eSMark Jansen CStringW buf; 5501e201d70SGiannis Adamopoulos DWORD dummyLen; 5511e201d70SGiannis Adamopoulos 5521e201d70SGiannis Adamopoulos /* beautify our url for display purposes */ 5531e201d70SGiannis Adamopoulos if (!InternetCanonicalizeUrlW(szStatusText, buf.GetBuffer(len), &dummyLen, ICU_DECODE | ICU_NO_ENCODE)) 5541e201d70SGiannis Adamopoulos { 5551e201d70SGiannis Adamopoulos /* just use the original */ 5561e201d70SGiannis Adamopoulos buf.ReleaseBuffer(); 5571e201d70SGiannis Adamopoulos buf = szStatusText; 5581e201d70SGiannis Adamopoulos } 5591e201d70SGiannis Adamopoulos else 5601e201d70SGiannis Adamopoulos { 5611e201d70SGiannis Adamopoulos buf.ReleaseBuffer(); 5621e201d70SGiannis Adamopoulos } 5631e201d70SGiannis Adamopoulos 5641e201d70SGiannis Adamopoulos /* paste it into our dialog and don't do it again in this instance */ 565844d447eSKatayama Hirofumi MZ ::SetWindowText(Item, buf.GetString()); 5661e201d70SGiannis Adamopoulos UrlHasBeenCopied = TRUE; 5671e201d70SGiannis Adamopoulos } 5681e201d70SGiannis Adamopoulos } 5691e201d70SGiannis Adamopoulos 570*33c2903eSMark Jansen BOOL 571*33c2903eSMark Jansen ShowLastError(HWND hWndOwner, BOOL bInetError, DWORD dwLastError) 572fb1582d3SKyle Katarn { 5734f25a476SMark Jansen CLocalPtr<WCHAR> lpMsg; 574fb1582d3SKyle Katarn 575*33c2903eSMark Jansen if (!FormatMessageW( 576*33c2903eSMark Jansen FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | 577059ba9b0SStanislav Motylkov (bInetError ? FORMAT_MESSAGE_FROM_HMODULE : FORMAT_MESSAGE_FROM_SYSTEM), 578*33c2903eSMark Jansen (bInetError ? GetModuleHandleW(L"wininet.dll") : NULL), dwLastError, LANG_USER_DEFAULT, (LPWSTR)&lpMsg, 0, 579*33c2903eSMark Jansen NULL)) 580fb1582d3SKyle Katarn { 581059ba9b0SStanislav Motylkov DPRINT1("FormatMessageW unexpected failure (err %d)\n", GetLastError()); 582059ba9b0SStanislav Motylkov return FALSE; 583fb1582d3SKyle Katarn } 584fb1582d3SKyle Katarn 585fb1582d3SKyle Katarn MessageBoxW(hWndOwner, lpMsg, NULL, MB_OK | MB_ICONERROR); 586059ba9b0SStanislav Motylkov return TRUE; 587fb1582d3SKyle Katarn } 588fb1582d3SKyle Katarn 589*33c2903eSMark Jansen unsigned int WINAPI 590*33c2903eSMark Jansen CDownloadManager::ThreadFunc(LPVOID param) 591c2c66affSColin Finck { 592*33c2903eSMark Jansen CPathW Path; 593c2c66affSColin Finck PWSTR p, q; 594c2c66affSColin Finck 595c2c66affSColin Finck HWND hDlg = static_cast<DownloadParam *>(param)->Dialog; 596c2c66affSColin Finck HWND Item; 597c2c66affSColin Finck INT iAppId; 598c2c66affSColin Finck 599c2c66affSColin Finck ULONG dwContentLen, dwBytesWritten, dwBytesRead, dwStatus; 600c2c66affSColin Finck ULONG dwCurrentBytesRead = 0; 601c2c66affSColin Finck ULONG dwStatusLen = sizeof(dwStatus); 602c2c66affSColin Finck 603c2c66affSColin Finck BOOL bTempfile = FALSE; 604c2c66affSColin Finck 605c2c66affSColin Finck HINTERNET hOpen = NULL; 606c2c66affSColin Finck HINTERNET hFile = NULL; 607c2c66affSColin Finck HANDLE hOut = INVALID_HANDLE_VALUE; 608c2c66affSColin Finck 609c2c66affSColin Finck unsigned char lpBuffer[4096]; 61012489f69SMark Jansen LPCWSTR lpszAgent = L"RApps/1.1"; 611e5336bd2SHe Yang URL_COMPONENTSW urlComponents; 612c2c66affSColin Finck size_t urlLength, filenameLength; 613c2c66affSColin Finck 614c2c66affSColin Finck const ATL::CSimpleArray<DownloadInfo> &InfoArray = static_cast<DownloadParam *>(param)->AppInfo; 615c2c66affSColin Finck LPCWSTR szCaption = static_cast<DownloadParam *>(param)->szCaption; 616*33c2903eSMark Jansen CStringW szNewCaption; 617c2c66affSColin Finck 618*33c2903eSMark Jansen const DWORD dwUrlConnectFlags = 619*33c2903eSMark Jansen INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_KEEP_CONNECTION; 620a6d2172cSAlexander Shaposhnikov 621c2c66affSColin Finck if (InfoArray.GetSize() <= 0) 622c2c66affSColin Finck { 623c2c66affSColin Finck MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_DOWNLOAD); 624c2c66affSColin Finck goto end; 625c2c66affSColin Finck } 626c2c66affSColin Finck 627c2c66affSColin Finck for (iAppId = 0; iAppId < InfoArray.GetSize(); ++iAppId) 628c2c66affSColin Finck { 629ee019e12SAlexander Shaposhnikov // Reset progress bar 630*33c2903eSMark Jansen if (!IsWindow(hDlg)) 631*33c2903eSMark Jansen break; 632ee019e12SAlexander Shaposhnikov Item = GetDlgItem(hDlg, IDC_DOWNLOAD_PROGRESS); 633ee019e12SAlexander Shaposhnikov if (Item) 634ee019e12SAlexander Shaposhnikov { 6356803490aSGiannis Adamopoulos ProgressBar.SetMarquee(FALSE); 6366803490aSGiannis Adamopoulos ProgressBar.SendMessage(PBM_SETPOS, 0, 0); 637b4114030SKatayama Hirofumi MZ ProgressBar.SetProgress(0, InfoArray[iAppId].SizeInBytes); 638ee019e12SAlexander Shaposhnikov } 639ee019e12SAlexander Shaposhnikov 64007f3691cSMark Jansen // is this URL an update package for RAPPS? if so store it in a different place 641a21d959eSHe Yang if (InfoArray[iAppId].DLType != DLTYPE_APPLICATION) 64207f3691cSMark Jansen { 64307f3691cSMark Jansen if (!GetStorageDirectory(Path)) 644fb1582d3SKyle Katarn { 645059ba9b0SStanislav Motylkov ShowLastError(hMainWnd, FALSE, GetLastError()); 64607f3691cSMark Jansen goto end; 64707f3691cSMark Jansen } 648fb1582d3SKyle Katarn } 64907f3691cSMark Jansen else 65007f3691cSMark Jansen { 65107f3691cSMark Jansen Path = SettingsInfo.szDownloadDir; 65207f3691cSMark Jansen } 65307f3691cSMark Jansen 654ee019e12SAlexander Shaposhnikov // Change caption to show the currently downloaded app 655a21d959eSHe Yang switch (InfoArray[iAppId].DLType) 656ee019e12SAlexander Shaposhnikov { 657a21d959eSHe Yang case DLTYPE_APPLICATION: 658ee019e12SAlexander Shaposhnikov szNewCaption.Format(szCaption, InfoArray[iAppId].szName.GetString()); 659a21d959eSHe Yang break; 660a21d959eSHe Yang case DLTYPE_DBUPDATE: 661ee019e12SAlexander Shaposhnikov szNewCaption.LoadStringW(IDS_DL_DIALOG_DB_DOWNLOAD_DISP); 662a21d959eSHe Yang break; 663a21d959eSHe Yang case DLTYPE_DBUPDATE_UNOFFICIAL: 664a21d959eSHe Yang szNewCaption.LoadStringW(IDS_DL_DIALOG_DB_UNOFFICIAL_DOWNLOAD_DISP); 665a21d959eSHe Yang break; 666ee019e12SAlexander Shaposhnikov } 667ee019e12SAlexander Shaposhnikov 668*33c2903eSMark Jansen if (!IsWindow(hDlg)) 669*33c2903eSMark Jansen goto end; 670ee019e12SAlexander Shaposhnikov SetWindowTextW(hDlg, szNewCaption.GetString()); 671ee019e12SAlexander Shaposhnikov 672c2c66affSColin Finck // build the path for the download 673c2c66affSColin Finck p = wcsrchr(InfoArray[iAppId].szUrl.GetString(), L'/'); 674c2c66affSColin Finck q = wcsrchr(InfoArray[iAppId].szUrl.GetString(), L'?'); 675c2c66affSColin Finck 676c2c66affSColin Finck // do we have a final slash separator? 677c2c66affSColin Finck if (!p) 678fb1582d3SKyle Katarn { 679fb1582d3SKyle Katarn MessageBox_LoadString(hMainWnd, IDS_UNABLE_PATH); 680c2c66affSColin Finck goto end; 681fb1582d3SKyle Katarn } 682c2c66affSColin Finck 683c2c66affSColin Finck // prepare the tentative length of the filename, maybe we've to remove part of it later on 684c2c66affSColin Finck filenameLength = wcslen(p) * sizeof(WCHAR); 685c2c66affSColin Finck 686c2c66affSColin Finck /* do we have query arguments in the target URL after the filename? account for them 687c2c66affSColin Finck (e.g. https://example.org/myfile.exe?no_adware_plz) */ 688c2c66affSColin Finck if (q && q > p && (q - p) > 0) 689c2c66affSColin Finck filenameLength -= wcslen(q - 1) * sizeof(WCHAR); 690c2c66affSColin Finck 691c2c66affSColin Finck // is the path valid? can we access it? 692*33c2903eSMark Jansen if (GetFileAttributesW(Path) == INVALID_FILE_ATTRIBUTES) 693c2c66affSColin Finck { 694*33c2903eSMark Jansen if (!CreateDirectoryW(Path, NULL)) 695fb1582d3SKyle Katarn { 696059ba9b0SStanislav Motylkov ShowLastError(hMainWnd, FALSE, GetLastError()); 697c2c66affSColin Finck goto end; 698c2c66affSColin Finck } 699fb1582d3SKyle Katarn } 700c2c66affSColin Finck 701fbf119fdSHe Yang switch (InfoArray[iAppId].DLType) 702fbf119fdSHe Yang { 703fbf119fdSHe Yang case DLTYPE_DBUPDATE: 704fbf119fdSHe Yang case DLTYPE_DBUPDATE_UNOFFICIAL: 705*33c2903eSMark Jansen Path += APPLICATION_DATABASE_NAME; 706fbf119fdSHe Yang break; 707fbf119fdSHe Yang case DLTYPE_APPLICATION: 708*33c2903eSMark Jansen Path += (LPWSTR)(p + 1); // use the filename retrieved from URL 709fbf119fdSHe Yang break; 710fbf119fdSHe Yang } 711c2c66affSColin Finck 712*33c2903eSMark Jansen if ((InfoArray[iAppId].DLType == DLTYPE_APPLICATION) && InfoArray[iAppId].szSHA1[0] && 713*33c2903eSMark Jansen GetFileAttributesW(Path) != INVALID_FILE_ATTRIBUTES) 714c2c66affSColin Finck { 715c2c66affSColin Finck // only open it in case of total correctness 716c2c66affSColin Finck if (VerifyInteg(InfoArray[iAppId].szSHA1.GetString(), Path)) 717c2c66affSColin Finck goto run; 718c2c66affSColin Finck } 719c2c66affSColin Finck 720c2c66affSColin Finck // Add the download URL 721*33c2903eSMark Jansen if (!IsWindow(hDlg)) 722*33c2903eSMark Jansen goto end; 723c2c66affSColin Finck SetDlgItemTextW(hDlg, IDC_DOWNLOAD_STATUS, InfoArray[iAppId].szUrl.GetString()); 724c2c66affSColin Finck 725c2c66affSColin Finck DownloadsListView.SetDownloadStatus(iAppId, DLSTATUS_DOWNLOADING); 726c2c66affSColin Finck 727c2c66affSColin Finck // download it 7281e201d70SGiannis Adamopoulos UrlHasBeenCopied = FALSE; 729c2c66affSColin Finck bTempfile = TRUE; 730c2c66affSColin Finck 731c2c66affSColin Finck /* FIXME: this should just be using the system-wide proxy settings */ 732c2c66affSColin Finck switch (SettingsInfo.Proxy) 733c2c66affSColin Finck { 734c2c66affSColin Finck case 0: // preconfig 73507f3691cSMark Jansen default: 736c2c66affSColin Finck hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); 737c2c66affSColin Finck break; 738c2c66affSColin Finck case 1: // direct (no proxy) 739c2c66affSColin Finck hOpen = InternetOpenW(lpszAgent, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); 740c2c66affSColin Finck break; 741c2c66affSColin Finck case 2: // use proxy 742*33c2903eSMark Jansen hOpen = InternetOpenW( 743*33c2903eSMark Jansen lpszAgent, INTERNET_OPEN_TYPE_PROXY, SettingsInfo.szProxyServer, SettingsInfo.szNoProxyFor, 0); 744c2c66affSColin Finck break; 745c2c66affSColin Finck } 746c2c66affSColin Finck 747c2c66affSColin Finck if (!hOpen) 748fb1582d3SKyle Katarn { 749059ba9b0SStanislav Motylkov ShowLastError(hMainWnd, TRUE, GetLastError()); 750c2c66affSColin Finck goto end; 751fb1582d3SKyle Katarn } 752c2c66affSColin Finck 753c2c66affSColin Finck dwStatusLen = sizeof(dwStatus); 754c2c66affSColin Finck 755c2c66affSColin Finck memset(&urlComponents, 0, sizeof(urlComponents)); 756c2c66affSColin Finck urlComponents.dwStructSize = sizeof(urlComponents); 757c2c66affSColin Finck 758c2c66affSColin Finck urlLength = InfoArray[iAppId].szUrl.GetLength(); 759c2c66affSColin Finck urlComponents.dwSchemeLength = urlLength + 1; 760c2c66affSColin Finck urlComponents.lpszScheme = (LPWSTR)malloc(urlComponents.dwSchemeLength * sizeof(WCHAR)); 761c2c66affSColin Finck 762c2c66affSColin Finck if (!InternetCrackUrlW(InfoArray[iAppId].szUrl, urlLength + 1, ICU_DECODE | ICU_ESCAPE, &urlComponents)) 763fb1582d3SKyle Katarn { 764059ba9b0SStanislav Motylkov ShowLastError(hMainWnd, TRUE, GetLastError()); 765c2c66affSColin Finck goto end; 766fb1582d3SKyle Katarn } 767c2c66affSColin Finck 76866e3c1f7SStanislav Motylkov dwContentLen = 0; 76966e3c1f7SStanislav Motylkov 770*33c2903eSMark Jansen if (urlComponents.nScheme == INTERNET_SCHEME_HTTP || urlComponents.nScheme == INTERNET_SCHEME_HTTPS) 7713261bbb7SAlexander Shaposhnikov { 772*33c2903eSMark Jansen hFile = InternetOpenUrlW(hOpen, InfoArray[iAppId].szUrl.GetString(), NULL, 0, dwUrlConnectFlags, 0); 773a6d2172cSAlexander Shaposhnikov if (!hFile) 774a6d2172cSAlexander Shaposhnikov { 775059ba9b0SStanislav Motylkov if (!ShowLastError(hMainWnd, TRUE, GetLastError())) 776059ba9b0SStanislav Motylkov { 777059ba9b0SStanislav Motylkov /* Workaround for CORE-17377 */ 778059ba9b0SStanislav Motylkov MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_DOWNLOAD2); 779059ba9b0SStanislav Motylkov } 780a6d2172cSAlexander Shaposhnikov goto end; 781a6d2172cSAlexander Shaposhnikov } 782a6d2172cSAlexander Shaposhnikov 7833261bbb7SAlexander Shaposhnikov // query connection 7843261bbb7SAlexander Shaposhnikov if (!HttpQueryInfoW(hFile, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwStatus, &dwStatusLen, NULL)) 785fb1582d3SKyle Katarn { 786059ba9b0SStanislav Motylkov ShowLastError(hMainWnd, TRUE, GetLastError()); 7873261bbb7SAlexander Shaposhnikov goto end; 788fb1582d3SKyle Katarn } 7893261bbb7SAlexander Shaposhnikov 7903261bbb7SAlexander Shaposhnikov if (dwStatus != HTTP_STATUS_OK) 7913261bbb7SAlexander Shaposhnikov { 7923261bbb7SAlexander Shaposhnikov MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_DOWNLOAD); 7933261bbb7SAlexander Shaposhnikov goto end; 7943261bbb7SAlexander Shaposhnikov } 7953261bbb7SAlexander Shaposhnikov 7963261bbb7SAlexander Shaposhnikov // query content length 797*33c2903eSMark Jansen HttpQueryInfoW( 798*33c2903eSMark Jansen hFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwContentLen, &dwStatusLen, NULL); 7993261bbb7SAlexander Shaposhnikov } 8004439b538SMark Jansen else if (urlComponents.nScheme == INTERNET_SCHEME_FTP) 8013261bbb7SAlexander Shaposhnikov { 802a6d2172cSAlexander Shaposhnikov // force passive mode on FTP 803*33c2903eSMark Jansen hFile = 804*33c2903eSMark Jansen InternetOpenUrlW(hOpen, InfoArray[iAppId].szUrl, NULL, 0, dwUrlConnectFlags | INTERNET_FLAG_PASSIVE, 0); 805a6d2172cSAlexander Shaposhnikov if (!hFile) 806a6d2172cSAlexander Shaposhnikov { 807059ba9b0SStanislav Motylkov if (!ShowLastError(hMainWnd, TRUE, GetLastError())) 808059ba9b0SStanislav Motylkov { 809059ba9b0SStanislav Motylkov /* Workaround for CORE-17377 */ 810059ba9b0SStanislav Motylkov MessageBox_LoadString(hMainWnd, IDS_UNABLE_TO_DOWNLOAD2); 811059ba9b0SStanislav Motylkov } 812a6d2172cSAlexander Shaposhnikov goto end; 813a6d2172cSAlexander Shaposhnikov } 814a6d2172cSAlexander Shaposhnikov 815c2c66affSColin Finck dwContentLen = FtpGetFileSize(hFile, &dwStatus); 8163261bbb7SAlexander Shaposhnikov } 8174f25a476SMark Jansen else if (urlComponents.nScheme == INTERNET_SCHEME_FILE) 8184f25a476SMark Jansen { 8194f25a476SMark Jansen // Add support for the file scheme so testing locally is simpler 8204f25a476SMark Jansen WCHAR LocalFilePath[MAX_PATH]; 8214f25a476SMark Jansen DWORD cchPath = _countof(LocalFilePath); 8224f25a476SMark Jansen // Ideally we would use PathCreateFromUrlAlloc here, but that is not exported (yet) 8234f25a476SMark Jansen HRESULT hr = PathCreateFromUrlW(InfoArray[iAppId].szUrl, LocalFilePath, &cchPath, 0); 8244f25a476SMark Jansen if (SUCCEEDED(hr)) 8254f25a476SMark Jansen { 8264f25a476SMark Jansen if (CopyFileW(LocalFilePath, Path, FALSE)) 8274f25a476SMark Jansen { 8284f25a476SMark Jansen goto run; 8294f25a476SMark Jansen } 8304f25a476SMark Jansen else 8314f25a476SMark Jansen { 832059ba9b0SStanislav Motylkov ShowLastError(hMainWnd, FALSE, GetLastError()); 8334f25a476SMark Jansen goto end; 8344f25a476SMark Jansen } 8354f25a476SMark Jansen } 8364f25a476SMark Jansen else 8374f25a476SMark Jansen { 838059ba9b0SStanislav Motylkov ShowLastError(hMainWnd, FALSE, hr); 8394f25a476SMark Jansen goto end; 8404f25a476SMark Jansen } 8414f25a476SMark Jansen } 842c2c66affSColin Finck 84366e3c1f7SStanislav Motylkov if (!dwContentLen) 84466e3c1f7SStanislav Motylkov { 8454439b538SMark Jansen // Someone was nice enough to add this, let's use it 8464439b538SMark Jansen if (InfoArray[iAppId].SizeInBytes) 8474439b538SMark Jansen { 8484439b538SMark Jansen dwContentLen = InfoArray[iAppId].SizeInBytes; 8494439b538SMark Jansen } 8504439b538SMark Jansen else 8514439b538SMark Jansen { 85266e3c1f7SStanislav Motylkov // content-length is not known, enable marquee mode 8536803490aSGiannis Adamopoulos ProgressBar.SetMarquee(TRUE); 85466e3c1f7SStanislav Motylkov } 8554439b538SMark Jansen } 85666e3c1f7SStanislav Motylkov 85707f3691cSMark Jansen free(urlComponents.lpszScheme); 85807f3691cSMark Jansen 859c2c66affSColin Finck #ifdef USE_CERT_PINNING 860c2c66affSColin Finck // are we using HTTPS to download the RAPPS update package? check if the certificate is original 861*33c2903eSMark Jansen if ((urlComponents.nScheme == INTERNET_SCHEME_HTTPS) && (InfoArray[iAppId].DLType == DLTYPE_DBUPDATE)) 862c2c66affSColin Finck { 8634f25a476SMark Jansen CLocalPtr<char> subjectName, issuerName; 86412caaeceSMark Jansen CStringA szMsgText; 86507f3691cSMark Jansen bool bAskQuestion = false; 86607f3691cSMark Jansen if (!CertGetSubjectAndIssuer(hFile, subjectName, issuerName)) 86707f3691cSMark Jansen { 86807f3691cSMark Jansen szMsgText.LoadStringW(IDS_UNABLE_TO_QUERY_CERT); 86907f3691cSMark Jansen bAskQuestion = true; 87007f3691cSMark Jansen } 87107f3691cSMark Jansen else 87207f3691cSMark Jansen { 87307f3691cSMark Jansen if (strcmp(subjectName, CERT_SUBJECT_INFO) || 874*33c2903eSMark Jansen (strcmp(issuerName, CERT_ISSUER_INFO_OLD) && strcmp(issuerName, CERT_ISSUER_INFO_NEW))) 87507f3691cSMark Jansen { 87607f3691cSMark Jansen szMsgText.Format(IDS_MISMATCH_CERT_INFO, (char *)subjectName, (const char *)issuerName); 87707f3691cSMark Jansen bAskQuestion = true; 87807f3691cSMark Jansen } 87907f3691cSMark Jansen } 88007f3691cSMark Jansen 88107f3691cSMark Jansen if (bAskQuestion) 88207f3691cSMark Jansen { 88312caaeceSMark Jansen if (MessageBoxA(hMainWnd, szMsgText.GetString(), NULL, MB_YESNO | MB_ICONERROR) != IDYES) 88407f3691cSMark Jansen { 885c2c66affSColin Finck goto end; 886c2c66affSColin Finck } 88707f3691cSMark Jansen } 88807f3691cSMark Jansen } 889c2c66affSColin Finck #endif 890c2c66affSColin Finck 891*33c2903eSMark Jansen hOut = CreateFileW(Path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL); 892c2c66affSColin Finck 893c2c66affSColin Finck if (hOut == INVALID_HANDLE_VALUE) 894fb1582d3SKyle Katarn { 895059ba9b0SStanislav Motylkov ShowLastError(hMainWnd, FALSE, GetLastError()); 896c2c66affSColin Finck goto end; 897fb1582d3SKyle Katarn } 898c2c66affSColin Finck 899c2c66affSColin Finck dwCurrentBytesRead = 0; 900c2c66affSColin Finck do 901c2c66affSColin Finck { 902c2c66affSColin Finck if (!InternetReadFile(hFile, lpBuffer, _countof(lpBuffer), &dwBytesRead)) 903c2c66affSColin Finck { 904059ba9b0SStanislav Motylkov ShowLastError(hMainWnd, TRUE, GetLastError()); 905c2c66affSColin Finck goto end; 906c2c66affSColin Finck } 907c2c66affSColin Finck 908c2c66affSColin Finck if (!WriteFile(hOut, &lpBuffer[0], dwBytesRead, &dwBytesWritten, NULL)) 909c2c66affSColin Finck { 910059ba9b0SStanislav Motylkov ShowLastError(hMainWnd, FALSE, GetLastError()); 911c2c66affSColin Finck goto end; 912c2c66affSColin Finck } 913c2c66affSColin Finck 914c2c66affSColin Finck dwCurrentBytesRead += dwBytesRead; 915*33c2903eSMark Jansen if (!IsWindow(hDlg)) 916*33c2903eSMark Jansen goto end; 9171e201d70SGiannis Adamopoulos UpdateProgress(hDlg, dwCurrentBytesRead, dwContentLen, 0, InfoArray[iAppId].szUrl.GetString()); 918c2c66affSColin Finck } while (dwBytesRead && !bCancelled); 919c2c66affSColin Finck 920c2c66affSColin Finck CloseHandle(hOut); 921c2c66affSColin Finck hOut = INVALID_HANDLE_VALUE; 922c2c66affSColin Finck 923c2c66affSColin Finck if (bCancelled) 924fb1582d3SKyle Katarn { 925fb1582d3SKyle Katarn DPRINT1("Operation cancelled\n"); 926c2c66affSColin Finck goto end; 927fb1582d3SKyle Katarn } 928c2c66affSColin Finck 92966e3c1f7SStanislav Motylkov if (!dwContentLen) 93066e3c1f7SStanislav Motylkov { 93166e3c1f7SStanislav Motylkov // set progress bar to 100% 9326803490aSGiannis Adamopoulos ProgressBar.SetMarquee(FALSE); 93366e3c1f7SStanislav Motylkov 93466e3c1f7SStanislav Motylkov dwContentLen = dwCurrentBytesRead; 935*33c2903eSMark Jansen if (!IsWindow(hDlg)) 936*33c2903eSMark Jansen goto end; 9371e201d70SGiannis Adamopoulos UpdateProgress(hDlg, dwCurrentBytesRead, dwContentLen, 0, InfoArray[iAppId].szUrl.GetString()); 93866e3c1f7SStanislav Motylkov } 93966e3c1f7SStanislav Motylkov 940c2c66affSColin Finck /* if this thing isn't a RAPPS update and it has a SHA-1 checksum 941c2c66affSColin Finck verify its integrity by using the native advapi32.A_SHA1 functions */ 942a21d959eSHe Yang if ((InfoArray[iAppId].DLType == DLTYPE_APPLICATION) && InfoArray[iAppId].szSHA1[0] != 0) 943c2c66affSColin Finck { 944*33c2903eSMark Jansen CStringW szMsgText; 945c2c66affSColin Finck 946c2c66affSColin Finck // change a few strings in the download dialog to reflect the verification process 947c2c66affSColin Finck if (!szMsgText.LoadStringW(IDS_INTEG_CHECK_TITLE)) 948fb1582d3SKyle Katarn { 949fb1582d3SKyle Katarn DPRINT1("Unable to load string\n"); 950c2c66affSColin Finck goto end; 951fb1582d3SKyle Katarn } 952c2c66affSColin Finck 953*33c2903eSMark Jansen if (!IsWindow(hDlg)) 954*33c2903eSMark Jansen goto end; 955c2c66affSColin Finck SetWindowTextW(hDlg, szMsgText.GetString()); 956*33c2903eSMark Jansen ::SetDlgItemTextW(hDlg, IDC_DOWNLOAD_STATUS, Path); 957c2c66affSColin Finck 958c2c66affSColin Finck // this may take a while, depending on the file size 959*33c2903eSMark Jansen if (!VerifyInteg(InfoArray[iAppId].szSHA1.GetString(), Path)) 960c2c66affSColin Finck { 961c2c66affSColin Finck if (!szMsgText.LoadStringW(IDS_INTEG_CHECK_FAIL)) 962fb1582d3SKyle Katarn { 963fb1582d3SKyle Katarn DPRINT1("Unable to load string\n"); 964c2c66affSColin Finck goto end; 965fb1582d3SKyle Katarn } 966c2c66affSColin Finck 967*33c2903eSMark Jansen if (!IsWindow(hDlg)) 968*33c2903eSMark Jansen goto end; 969c2c66affSColin Finck MessageBoxW(hDlg, szMsgText.GetString(), NULL, MB_OK | MB_ICONERROR); 970c2c66affSColin Finck goto end; 971c2c66affSColin Finck } 972c2c66affSColin Finck } 973c2c66affSColin Finck 974c2c66affSColin Finck run: 975c2c66affSColin Finck DownloadsListView.SetDownloadStatus(iAppId, DLSTATUS_WAITING_INSTALL); 976c2c66affSColin Finck 977c2c66affSColin Finck // run it 978a21d959eSHe Yang if (InfoArray[iAppId].DLType == DLTYPE_APPLICATION) 979c2c66affSColin Finck { 980c2c66affSColin Finck SHELLEXECUTEINFOW shExInfo = {0}; 981c2c66affSColin Finck shExInfo.cbSize = sizeof(shExInfo); 982c2c66affSColin Finck shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS; 983c2c66affSColin Finck shExInfo.lpVerb = L"open"; 984*33c2903eSMark Jansen shExInfo.lpFile = Path; 985c2c66affSColin Finck shExInfo.lpParameters = L""; 986c2c66affSColin Finck shExInfo.nShow = SW_SHOW; 987c2c66affSColin Finck 988ae426744SMark Jansen /* FIXME: Do we want to log installer status? */ 989ae426744SMark Jansen WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_INSTALL, InfoArray[iAppId].szName); 990ae426744SMark Jansen 991c2c66affSColin Finck if (ShellExecuteExW(&shExInfo)) 992c2c66affSColin Finck { 99347bbd637SAlexander Shaposhnikov // reflect installation progress in the titlebar 99447bbd637SAlexander Shaposhnikov // TODO: make a separate string with a placeholder to include app name? 995*33c2903eSMark Jansen CStringW szMsgText = LoadStatusString(DLSTATUS_INSTALLING); 996*33c2903eSMark Jansen if (!IsWindow(hDlg)) 997*33c2903eSMark Jansen goto end; 99847bbd637SAlexander Shaposhnikov SetWindowTextW(hDlg, szMsgText.GetString()); 99947bbd637SAlexander Shaposhnikov 1000c2c66affSColin Finck DownloadsListView.SetDownloadStatus(iAppId, DLSTATUS_INSTALLING); 100147bbd637SAlexander Shaposhnikov 1002c2c66affSColin Finck // TODO: issue an install operation separately so that the apps could be downloaded in the background 1003c2c66affSColin Finck WaitForSingleObject(shExInfo.hProcess, INFINITE); 1004c2c66affSColin Finck CloseHandle(shExInfo.hProcess); 1005c2c66affSColin Finck } 1006c2c66affSColin Finck else 1007c2c66affSColin Finck { 1008059ba9b0SStanislav Motylkov ShowLastError(hMainWnd, FALSE, GetLastError()); 1009c2c66affSColin Finck } 1010c2c66affSColin Finck } 1011c2c66affSColin Finck 1012c2c66affSColin Finck end: 1013c2c66affSColin Finck if (hOut != INVALID_HANDLE_VALUE) 1014c2c66affSColin Finck CloseHandle(hOut); 1015c2c66affSColin Finck 10164f25a476SMark Jansen if (hFile) 1017c2c66affSColin Finck InternetCloseHandle(hFile); 1018c2c66affSColin Finck InternetCloseHandle(hOpen); 1019c2c66affSColin Finck 1020c2c66affSColin Finck if (bTempfile) 1021c2c66affSColin Finck { 1022a21d959eSHe Yang if (bCancelled || (SettingsInfo.bDelInstaller && (InfoArray[iAppId].DLType == DLTYPE_APPLICATION))) 1023*33c2903eSMark Jansen DeleteFileW(Path); 1024c2c66affSColin Finck } 1025c2c66affSColin Finck 1026*33c2903eSMark Jansen if (!IsWindow(hDlg)) 1027*33c2903eSMark Jansen return 0; 1028c2c66affSColin Finck DownloadsListView.SetDownloadStatus(iAppId, DLSTATUS_FINISHED); 1029c2c66affSColin Finck } 1030c2c66affSColin Finck 1031c2c66affSColin Finck delete static_cast<DownloadParam *>(param); 1032*33c2903eSMark Jansen if (!IsWindow(hDlg)) 1033*33c2903eSMark Jansen return 0; 1034c2c66affSColin Finck SendMessageW(hDlg, WM_CLOSE, 0, 0); 1035c2c66affSColin Finck return 0; 1036c2c66affSColin Finck } 1037c2c66affSColin Finck 1038c2c66affSColin Finck // TODO: Reuse the dialog 1039*33c2903eSMark Jansen VOID 1040*33c2903eSMark Jansen CDownloadManager::LaunchDownloadDialog(BOOL bIsModal) 1041c2c66affSColin Finck { 1042946ee611SMark Jansen CDownloadManager::bModal = bIsModal; 1043c2c66affSColin Finck if (bIsModal) 1044c2c66affSColin Finck { 1045*33c2903eSMark Jansen DialogBoxW(hInst, MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG), hMainWnd, DownloadDlgProc); 1046c2c66affSColin Finck } 1047c2c66affSColin Finck else 1048c2c66affSColin Finck { 1049*33c2903eSMark Jansen CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_DOWNLOAD_DIALOG), hMainWnd, DownloadDlgProc); 1050c2c66affSColin Finck } 1051c2c66affSColin Finck } 1052c2c66affSColin Finck // CDownloadManager 10531807dbfdSGiannis Adamopoulos 1054*33c2903eSMark Jansen BOOL 1055*33c2903eSMark Jansen DownloadListOfApplications(const CAtlList<CApplicationInfo *> &AppsList, BOOL bIsModal) 10561807dbfdSGiannis Adamopoulos { 1057*33c2903eSMark Jansen if (AppsList.IsEmpty()) 10581807dbfdSGiannis Adamopoulos return FALSE; 10591807dbfdSGiannis Adamopoulos 1060*33c2903eSMark Jansen POSITION CurrentListPosition = AppsList.GetHeadPosition(); 1061*33c2903eSMark Jansen while (CurrentListPosition) 10621807dbfdSGiannis Adamopoulos { 1063*33c2903eSMark Jansen const CApplicationInfo *Info = AppsList.GetNext(CurrentListPosition); 1064*33c2903eSMark Jansen CDownloadManager::Add(DownloadInfo(*Info)); 10651807dbfdSGiannis Adamopoulos } 10661807dbfdSGiannis Adamopoulos 10671807dbfdSGiannis Adamopoulos // Create a dialog and issue a download process 10681807dbfdSGiannis Adamopoulos CDownloadManager::LaunchDownloadDialog(bIsModal); 10691807dbfdSGiannis Adamopoulos 10701807dbfdSGiannis Adamopoulos return TRUE; 10711807dbfdSGiannis Adamopoulos } 10721807dbfdSGiannis Adamopoulos 1073*33c2903eSMark Jansen BOOL 1074*33c2903eSMark Jansen DownloadApplication(CApplicationInfo *pAppInfo) 10751807dbfdSGiannis Adamopoulos { 10761807dbfdSGiannis Adamopoulos if (!pAppInfo) 10771807dbfdSGiannis Adamopoulos return FALSE; 10781807dbfdSGiannis Adamopoulos 1079143b2a50SMark Jansen CDownloadManager::Download(*pAppInfo, FALSE); 10801807dbfdSGiannis Adamopoulos return TRUE; 10811807dbfdSGiannis Adamopoulos } 10821807dbfdSGiannis Adamopoulos 1083*33c2903eSMark Jansen VOID 1084*33c2903eSMark Jansen DownloadApplicationsDB(LPCWSTR lpUrl, BOOL IsOfficial) 10851807dbfdSGiannis Adamopoulos { 10861807dbfdSGiannis Adamopoulos static DownloadInfo DatabaseDLInfo; 10871807dbfdSGiannis Adamopoulos DatabaseDLInfo.szUrl = lpUrl; 10881807dbfdSGiannis Adamopoulos DatabaseDLInfo.szName.LoadStringW(IDS_DL_DIALOG_DB_DISP); 1089a21d959eSHe Yang DatabaseDLInfo.DLType = IsOfficial ? DLTYPE_DBUPDATE : DLTYPE_DBUPDATE_UNOFFICIAL; 10901807dbfdSGiannis Adamopoulos CDownloadManager::Download(DatabaseDLInfo, TRUE); 10911807dbfdSGiannis Adamopoulos } 1092