From 3489e949e30e75d1f93610b2c6015b4ff95aefa2 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sun, 19 May 2013 18:19:42 +0000 Subject: universal plugin downloader for the PluginUpdater plugin git-svn-id: http://svn.miranda-ng.org/main/trunk@4745 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/PluginUpdater/PluginUpdater_11.vcxproj | 10 + .../PluginUpdater/PluginUpdater_11.vcxproj.filters | 14 + plugins/PluginUpdater/res/Resource.rc | 25 +- plugins/PluginUpdater/res/info.ico | Bin 0 -> 1150 bytes plugins/PluginUpdater/src/Common.h | 6 +- plugins/PluginUpdater/src/Events.cpp | 7 + plugins/PluginUpdater/src/Notifications.cpp | 345 +++++++++++++++++++++ plugins/PluginUpdater/src/PluginUpdater.cpp | 20 +- plugins/PluginUpdater/src/Scanner.cpp | 190 ++++++++++++ plugins/PluginUpdater/src/Utils.cpp | 15 +- plugins/PluginUpdater/src/resource.h | 12 +- 11 files changed, 631 insertions(+), 13 deletions(-) create mode 100644 plugins/PluginUpdater/res/info.ico diff --git a/plugins/PluginUpdater/PluginUpdater_11.vcxproj b/plugins/PluginUpdater/PluginUpdater_11.vcxproj index c66da3da88..88241dbec3 100644 --- a/plugins/PluginUpdater/PluginUpdater_11.vcxproj +++ b/plugins/PluginUpdater/PluginUpdater_11.vcxproj @@ -92,6 +92,7 @@ $(IntDir)$(TargetName).lib $(ProfileDir)..\..\bin11\lib false + comctl32.lib;%(AdditionalDependencies) ..\..\include\msapi @@ -115,6 +116,7 @@ false $(IntDir)$(TargetName).lib $(ProfileDir)..\..\bin11\lib + comctl32.lib;%(AdditionalDependencies) ..\..\include\msapi @@ -140,6 +142,7 @@ $(IntDir)$(TargetName).lib true $(ProfileDir)..\..\bin11\lib + comctl32.lib;%(AdditionalDependencies) ..\..\include\msapi @@ -165,6 +168,7 @@ $(IntDir)$(TargetName).lib true $(ProfileDir)..\..\bin11\lib + comctl32.lib;%(AdditionalDependencies) ..\..\include\msapi @@ -224,6 +228,12 @@ {e2a369cd-eda3-414f-8ad0-e732cd7ee68c} + + + + + + diff --git a/plugins/PluginUpdater/PluginUpdater_11.vcxproj.filters b/plugins/PluginUpdater/PluginUpdater_11.vcxproj.filters index 8f5a421d1a..4f6cd1a2b0 100644 --- a/plugins/PluginUpdater/PluginUpdater_11.vcxproj.filters +++ b/plugins/PluginUpdater/PluginUpdater_11.vcxproj.filters @@ -98,4 +98,18 @@ Source Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + \ No newline at end of file diff --git a/plugins/PluginUpdater/res/Resource.rc b/plugins/PluginUpdater/res/Resource.rc index b4b0271a75..36884c96c5 100644 --- a/plugins/PluginUpdater/res/Resource.rc +++ b/plugins/PluginUpdater/res/Resource.rc @@ -29,6 +29,7 @@ LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT IDI_MENU ICON "menu.ico" IDI_OK ICON "btnOk.ico" IDI_CANCEL ICON "btnClose.ico" +IDI_INFO ICON "info.ico" ///////////////////////////////////////////////////////////////////////////// // @@ -76,7 +77,7 @@ BEGIN CONTROL "Stable version",IDC_STABLE,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,11,106,236,10 CONTROL "Development version (less stable)",IDC_TRUNK,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,11,121,236,10 CONTROL "Custom version",IDC_CUSTOM,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,11,136,236,10 - EDITTEXT IDC_CUSTOMURL,11,150,234,16,ES_AUTOHSCROLL | WS_TABSTOP + EDITTEXT IDC_CUSTOMURL,11,150,234,16,ES_AUTOHSCROLL END IDD_POPUP DIALOGEX 0, 0, 316, 182 @@ -125,6 +126,20 @@ BEGIN CTEXT "Popups",IDC_STATIC,7,9,79,8 END +IDD_LIST DIALOGEX 0, 0, 240, 236 +STYLE DS_SETFONT | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME +EXSTYLE WS_EX_CONTROLPARENT +CAPTION "Component list" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CTEXT "Here is the complete list of missing Miranda NG components. \nCheck components that you want to download. \n\nClick on info icon to view component info page.",IDC_UPDATETEXT,9,9,223,44 + DEFPUSHBUTTON "Download",IDOK,185,218,50,14 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,1,58,236,1 + CONTROL "",IDC_LIST_UPDATES,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,6,64,229,149 + PUSHBUTTON "Select &all",IDC_SELALL,6,218,50,14,NOT WS_TABSTOP + PUSHBUTTON "Select &none",IDC_SELNONE,59,218,50,14,NOT WS_TABSTOP +END + #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -169,6 +184,14 @@ BEGIN BEGIN BOTTOMMARGIN, 180 END + + IDD_LIST, DIALOG + BEGIN + VERTGUIDE, 6 + VERTGUIDE, 235 + BOTTOMMARGIN, 234 + HORZGUIDE, 232 + END END #endif // APSTUDIO_INVOKED diff --git a/plugins/PluginUpdater/res/info.ico b/plugins/PluginUpdater/res/info.ico new file mode 100644 index 0000000000..296d8f8f3e Binary files /dev/null and b/plugins/PluginUpdater/res/info.ico differ diff --git a/plugins/PluginUpdater/src/Common.h b/plugins/PluginUpdater/src/Common.h index 9a54f61846..8c101c5e84 100644 --- a/plugins/PluginUpdater/src/Common.h +++ b/plugins/PluginUpdater/src/Common.h @@ -114,7 +114,7 @@ extern HINSTANCE hInst; extern TCHAR tszRoot[MAX_PATH], tszDialogMsg[2048], tszTempPath[MAX_PATH]; extern FILEINFO *pFileInfo; -extern HANDLE hCheckThread, hPluginUpdaterFolder; +extern HANDLE hCheckThread, hListThread, hPluginUpdaterFolder; extern PlugOptions opts; extern POPUP_OPTIONS PopupOptions; extern aPopups PopupsList[POPUPS]; @@ -135,16 +135,20 @@ int OptInit(WPARAM, LPARAM); void BackupFile(TCHAR *ptszSrcFileName, TCHAR *ptszBackFileName); void DoCheck(int iFlag); +void DoGetList(int iFlag); BOOL DownloadFile(LPCTSTR tszURL, LPCTSTR tszLocal, int CRCsum); void ShowPopup(HWND hDlg, LPCTSTR Title, LPCTSTR Text, int Number, int ActType); void __stdcall RestartMe(void*); +void __stdcall OpenPluginOptions(void*); BOOL AllowUpdateOnStartup(); void InitTimer(); INT_PTR MenuCommand(WPARAM wParam,LPARAM lParam); +INT_PTR ShowListCommand(WPARAM wParam,LPARAM lParam); INT_PTR EmptyFolder(WPARAM wParam,LPARAM lParam); INT_PTR CALLBACK DlgUpdate(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); +INT_PTR CALLBACK DlgList(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK DlgMsgPop(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); bool unzip(const TCHAR *ptszZipFile, TCHAR *ptszDestPath, TCHAR *ptszBackPath); diff --git a/plugins/PluginUpdater/src/Events.cpp b/plugins/PluginUpdater/src/Events.cpp index a82e0261b8..d55ce08022 100644 --- a/plugins/PluginUpdater/src/Events.cpp +++ b/plugins/PluginUpdater/src/Events.cpp @@ -58,6 +58,13 @@ INT_PTR MenuCommand(WPARAM wParam,LPARAM lParam) return 0; } +INT_PTR ShowListCommand(WPARAM wParam,LPARAM lParam) +{ + opts.bSilent = false; + DoGetList(1); + return 0; +} + INT_PTR EmptyFolder(WPARAM wParam,LPARAM lParam) { SHFILEOPSTRUCT file_op = { diff --git a/plugins/PluginUpdater/src/Notifications.cpp b/plugins/PluginUpdater/src/Notifications.cpp index 94a93d5e43..746449a735 100644 --- a/plugins/PluginUpdater/src/Notifications.cpp +++ b/plugins/PluginUpdater/src/Notifications.cpp @@ -377,6 +377,97 @@ LBL_Exit: goto LBL_Exit; } +static void ApplyDownloads(void *param) +{ + HWND hDlg = (HWND)param; + + ////////////////////////////////////////////////////////////////////////////////////// + // if we need to escalate priviledges, launch a atub + + if ( !PrepareEscalation()) { + DestroyWindow(hDlg); + return; + } + + ////////////////////////////////////////////////////////////////////////////////////// + // ok, let's unpack all zips + + HWND hwndList = GetDlgItem(hDlg, IDC_LIST_UPDATES); + OBJLIST &todo = *(OBJLIST *)GetWindowLongPtr(hDlg, GWLP_USERDATA); + TCHAR tszBuff[2048], tszFileTemp[MAX_PATH], tszFileBack[MAX_PATH]; + + mir_sntprintf(tszFileBack, SIZEOF(tszFileBack), _T("%s\\Backups"), tszRoot); + SafeCreateDirectory(tszFileBack); + + mir_sntprintf(tszFileTemp, SIZEOF(tszFileTemp), _T("%s\\Temp"), tszRoot); + SafeCreateDirectory(tszFileTemp); + + for (int i=0; i < todo.getCount(); ++i) { + ListView_EnsureVisible(hwndList, i, FALSE); + if ( !todo[i].bEnabled) { + ListView_SetItemText(hwndList, i, 2, TranslateT("Skipped.")); + continue; + } + + // download update + ListView_SetItemText(hwndList, i, 2, TranslateT("Downloading...")); + + FILEURL *pFileUrl = &todo[i].File; + if ( !DownloadFile(pFileUrl->tszDownloadURL, pFileUrl->tszDiskPath, pFileUrl->CRCsum)){ + ListView_SetItemText(hwndList, i, 2, TranslateT("Failed!")); + } + else + ListView_SetItemText(hwndList, i, 2, TranslateT("Succeeded.")); + } + + if (todo.getCount() > 0) { + ShowPopup(0, LPGENT("Plugin Updater"), TranslateT("Download complete"), 2, 0); + + TCHAR *tszMirandaPath = Utils_ReplaceVarsT(_T("%miranda_path%")); + + for (int i = 0; i < todo.getCount(); i++) { + if ( !todo[i].bEnabled) + continue; + + TCHAR tszBackFile[MAX_PATH]; + FILEINFO& p = todo[i]; + if (p.bDeleteOnly) { // we need only to backup the old file + TCHAR *ptszRelPath = p.tszNewName + _tcslen(tszMirandaPath) + 1; + mir_sntprintf(tszBackFile, SIZEOF(tszBackFile), _T("%s\\%s"), tszFileBack, ptszRelPath); + BackupFile(p.tszNewName, tszBackFile); + continue; + } + + // if file name differs, we also need to backup the old file here + // otherwise it would be replaced by unzip + if ( _tcsicmp(p.tszOldName, p.tszNewName)) { + TCHAR tszSrcPath[MAX_PATH]; + mir_sntprintf(tszSrcPath, SIZEOF(tszSrcPath), _T("%s\\%s"), tszMirandaPath, p.tszOldName); + mir_sntprintf(tszBackFile, SIZEOF(tszBackFile), _T("%s\\%s"), tszFileBack, p.tszOldName); + BackupFile(tszSrcPath, tszBackFile); + } + + if ( unzip(p.File.tszDiskPath, tszMirandaPath, tszFileBack)) + SafeDeleteFile(p.File.tszDiskPath); // remove .zip after successful update + } + } + + PopupDataText temp; + temp.Title = TranslateT("Plugin Updater"); + temp.Text = tszBuff; + lstrcpyn(tszBuff, TranslateT("Download complete. Do you want go to plugins option page?"), SIZEOF(tszBuff)); + int rc = MessageBox(NULL, temp.Text, temp.Title, MB_YESNO | MB_ICONQUESTION); + if (rc == IDYES) + CallFunctionAsync(OpenPluginOptions, 0); + + if (hPipe) + CloseHandle(hPipe); + CloseWindow(hDlg); + DestroyWindow(hDlg); + hwndDialog = NULL; + return; +} + static void ResizeVert(HWND hDlg, int yy) { RECT r = { 0, 0, 244, yy }; @@ -385,6 +476,14 @@ static void ResizeVert(HWND hDlg, int yy) SetWindowPos(hDlg, 0, 0, 0, r.right, r.bottom, SWP_NOMOVE | SWP_NOZORDER); } +int ImageList_AddIconFromIconLib(HIMAGELIST hIml, const char *name) +{ + HICON icon = Skin_GetIconByHandle(Skin_GetIconHandle(name)); + int res = ImageList_AddIcon(hIml, icon); + Skin_ReleaseIcon(icon); + return res; +} + INT_PTR CALLBACK DlgUpdate(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { HWND hwndList = GetDlgItem(hDlg, IDC_LIST_UPDATES); @@ -545,6 +644,252 @@ INT_PTR CALLBACK DlgUpdate(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam return FALSE; } +///////////////////////////////////////////////////////////////////////////////////////// + +static LRESULT CALLBACK PluginListWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_LBUTTONDOWN) { + LVHITTESTINFO hi; + hi.pt.x = LOWORD(lParam); hi.pt.y = HIWORD(lParam); + ListView_SubItemHitTest(hwnd, &hi); + if (hi.iSubItem == 1) { + LVITEM lvi = {0}; + lvi.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_GROUPID; + lvi.stateMask = -1; + lvi.iItem = hi.iItem; + if (ListView_GetItem(hwnd, &lvi) && lvi.iGroupId == 1) { + TCHAR link[MAX_PATH]; + FILEINFO *info = (FILEINFO *)lvi.lParam; + + TCHAR tszFileName[MAX_PATH]; + _tcscpy(tszFileName, _tcsrchr(info->tszNewName, L'\\') + 1); + TCHAR *p = _tcschr(tszFileName, L'.'); *p = 0; + + mir_sntprintf(link, MAX_PATH, L"http://wiki.miranda-ng.org/index.php?title=Plugin:%s", tszFileName); + CallService(MS_UTILS_OPENURL, OUF_TCHAR, (LPARAM) link); + } + } + } + + return mir_callNextSubclass(hwnd, PluginListWndProc, msg, wParam, lParam); +} + +static int ListDlg_Resize(HWND, LPARAM, UTILRESIZECONTROL *urc) +{ + switch (urc->wId) { + case IDC_SELALL: + case IDC_SELNONE: + return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM; + + case IDOK: + return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM; + } + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT; +} + +INT_PTR CALLBACK DlgList(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND hwndList = GetDlgItem(hDlg, IDC_LIST_UPDATES); + + switch (message) { + case WM_INITDIALOG: + hwndDialog = hDlg; + TranslateDialogDefault( hDlg ); + mir_subclassWindow(hwndList, PluginListWndProc); + + SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadSkinnedIconBig(SKINICON_OTHER_OPTIONS)); + SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadSkinnedIcon(SKINICON_OTHER_OPTIONS)); + { + HIMAGELIST hIml = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, 4, 0); + ImageList_AddIconFromIconLib(hIml, "info"); + ListView_SetImageList(hwndList, hIml, LVSIL_SMALL); + + OSVERSIONINFO osver = { sizeof(osver) }; + if (GetVersionEx(&osver) && osver.dwMajorVersion >= 6) { + wchar_t szPath[MAX_PATH]; + GetModuleFileName(NULL, szPath, SIZEOF(szPath)); + TCHAR *ext = _tcsrchr(szPath, '.'); + if (ext != NULL) + *ext = '\0'; + _tcscat(szPath, _T(".test")); + HANDLE hFile = CreateFile(szPath, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + // Running Windows Vista or later (major version >= 6). + Button_SetElevationRequiredState(GetDlgItem(hDlg, IDOK), !IsProcessElevated()); + else { + CloseHandle(hFile); + DeleteFile(szPath); + } + } + RECT r; + GetClientRect(hwndList, &r); + + /// + LVCOLUMN lvc = {0}; + lvc.mask = LVCF_WIDTH | LVCF_TEXT; + //lvc.fmt = LVCFMT_LEFT; + + lvc.pszText = TranslateT("Component Name"); + lvc.cx = 220; // width of column in pixels + ListView_InsertColumn(hwndList, 0, &lvc); + + lvc.pszText = L""; + lvc.cx = 32 - GetSystemMetrics(SM_CXVSCROLL); // width of column in pixels + ListView_InsertColumn(hwndList, 1, &lvc); + + lvc.pszText = L"State"; + lvc.cx = 100 - GetSystemMetrics(SM_CXVSCROLL); // width of column in pixels + ListView_InsertColumn(hwndList, 2, &lvc); + + /// + LVGROUP lvg; + lvg.cbSize = sizeof(LVGROUP); + lvg.mask = LVGF_HEADER | LVGF_GROUPID; + + lvg.pszHeader = LPGENT("Plugins"); + lvg.iGroupId = 1; + ListView_InsertGroup(hwndList, 0, &lvg); + + lvg.pszHeader = LPGENT("Icons"); + lvg.iGroupId = 2; + ListView_InsertGroup(hwndList, 0, &lvg); + + lvg.pszHeader = LPGENT("Other"); + lvg.iGroupId = 3; + ListView_InsertGroup(hwndList, 0, &lvg); + + ListView_EnableGroupView(hwndList, TRUE); + + /// + SendMessage(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES | LVS_EX_CHECKBOXES | LVS_EX_LABELTIP); + ListView_DeleteAllItems(hwndList); + + /// + OBJLIST &todo = *(OBJLIST *)lParam; + for (int i = 0; i < todo.getCount(); ++i) { + int groupId = 3; + LVITEM lvi = {0}; + lvi.mask = LVIF_PARAM | LVIF_GROUPID | LVIF_TEXT | LVIF_IMAGE; + + if (_tcschr(todo[i].tszOldName, L'\\') != NULL) + groupId = _tcsstr(todo[i].tszOldName, L"Plugins") != NULL ? 1 : 2; + + lvi.iItem = i; + lvi.lParam = (LPARAM)&todo[i]; + lvi.iGroupId = groupId; + lvi.iImage = -1; + lvi.pszText = todo[i].tszOldName; + int iRow = ListView_InsertItem(hwndList, &lvi); + + + if (iRow != -1) { + lvi.iItem = iRow; + if (groupId == 1) { + lvi.mask = LVIF_IMAGE; + lvi.iSubItem = 1; + lvi.iImage = 0; + ListView_SetItem(hwndList, &lvi); + } + } + todo[i].bEnabled = false; + } + HWND hwOk = GetDlgItem(hDlg, IDOK); + EnableWindow(hwOk, false); + } + + // do this after filling list - enables 'ITEMCHANGED' below + SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam); + Utils_RestoreWindowPosition(hDlg, 0, MODNAME, "ListWindow"); + return TRUE; + + case WM_NOTIFY: + if (((LPNMHDR) lParam)->hwndFrom == hwndList) { + switch (((LPNMHDR) lParam)->code) { + case LVN_ITEMCHANGED: + if (GetWindowLongPtr(hDlg, GWLP_USERDATA)) { + NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam; + + LVITEM lvI = {0}; + lvI.iItem = nmlv->iItem; + lvI.iSubItem = 0; + lvI.mask = LVIF_PARAM; + ListView_GetItem(hwndList, &lvI); + + OBJLIST &todo = *(OBJLIST *)GetWindowLongPtr(hDlg, GWLP_USERDATA); + if ((nmlv->uNewState ^ nmlv->uOldState) & LVIS_STATEIMAGEMASK) { + todo[lvI.iItem].bEnabled = ListView_GetCheckState(hwndList, nmlv->iItem); + + bool enableOk = false; + for (int i=0; i < todo.getCount(); ++i) { + if (todo[i].bEnabled) { + enableOk = true; + break; + } + } + HWND hwOk = GetDlgItem(hDlg, IDOK); + EnableWindow(hwOk, enableOk ? TRUE : FALSE); + } + } + break; + } + } + break; + + case WM_COMMAND: + if (HIWORD( wParam ) == BN_CLICKED) { + switch(LOWORD(wParam)) { + case IDOK: + EnableWindow( GetDlgItem(hDlg, IDOK), FALSE); + EnableWindow( GetDlgItem(hDlg, IDC_SELALL), FALSE); + EnableWindow( GetDlgItem(hDlg, IDC_SELNONE), FALSE); + + mir_forkthread(ApplyDownloads, hDlg); + return TRUE; + + case IDC_DETAILS: + bShowDetails = !bShowDetails; + ResizeVert(hDlg, bShowDetails ? 242 : 60); + break; + + case IDC_SELALL: + SelectAll(hDlg, true); + break; + + case IDC_SELNONE: + SelectAll(hDlg, false); + break; + + case IDCANCEL: + DestroyWindow(hDlg); + return TRUE; + } + } + break; + + case WM_SIZE: // make the dlg resizeable + if ( !IsIconic(hDlg)) { + UTILRESIZEDIALOG urd = { sizeof(urd) }; + urd.hInstance = hInst; + urd.hwndDlg = hDlg; + urd.lpTemplate = MAKEINTRESOURCEA(IDD_LIST); + urd.pfnResizer = ListDlg_Resize; + CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); + } + break; + + case WM_DESTROY: + Utils_SaveWindowPosition(hDlg, NULL, MODNAME, "ListWindow"); + Skin_ReleaseIcon((HICON)SendMessage(hDlg, WM_SETICON, ICON_BIG, 0)); + Skin_ReleaseIcon((HICON)SendMessage(hDlg, WM_SETICON, ICON_SMALL, 0)); + hwndDialog = NULL; + delete (OBJLIST *)GetWindowLongPtr(hDlg, GWLP_USERDATA); + SetWindowLongPtr(hDlg, GWLP_USERDATA, 0); + break; + } + + return FALSE; +} + INT_PTR CALLBACK DlgMsgPop(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { diff --git a/plugins/PluginUpdater/src/PluginUpdater.cpp b/plugins/PluginUpdater/src/PluginUpdater.cpp index fbd28aa8af..bf914fb48b 100644 --- a/plugins/PluginUpdater/src/PluginUpdater.cpp +++ b/plugins/PluginUpdater/src/PluginUpdater.cpp @@ -29,7 +29,7 @@ Boston, MA 02111-1307, USA. UTF8_INTERFACE utfi; #endif -HANDLE hPluginUpdaterFolder = NULL, hCheckUpdates = NULL, hEmptyFolder = NULL; +HANDLE hPluginUpdaterFolder = NULL, hEmptyFolder = NULL; HINSTANCE hInst = NULL; TCHAR tszRoot[MAX_PATH] = {0}, tszTempPath[MAX_PATH]; int hLangpack; @@ -101,18 +101,24 @@ extern "C" __declspec(dllexport) int Load(void) IcoLibInit(); // Add cheking update menu item - hCheckUpdates = CreateServiceFunction(MODNAME"/CheckUpdates", MenuCommand); + CreateServiceFunction(MODNAME"/CheckUpdates", MenuCommand); + CreateServiceFunction(MODNAME"/ShowList", ShowListCommand); CLISTMENUITEM mi = { sizeof(mi) }; - mi.position = -0x7FFFFFFF; + mi.position = 400010000; mi.icolibItem = Skin_GetIconHandle("check_update"); mi.pszName = LPGEN("Check for plugin updates"); mi.pszService = MODNAME"/CheckUpdates"; Menu_AddMainMenuItem(&mi); + mi.position++; + mi.icolibItem = LoadSkinnedIconHandle(SKINICON_OTHER_OPTIONS); + mi.pszName = LPGEN("Show full plugin list"); + mi.pszService = MODNAME"/ShowList"; + Menu_AddMainMenuItem(&mi); + // Add hotkey - HOTKEYDESC hkd = {0}; - hkd.cbSize = sizeof(hkd); + HOTKEYDESC hkd = { sizeof(hkd) }; hkd.pszName = "Check for plugin updates"; hkd.pszDescription = "Check for plugin updates"; hkd.pszSection = "Plugin Updater"; @@ -133,7 +139,9 @@ extern "C" __declspec(dllexport) int Unload(void) if (hCheckThread) hCheckThread = NULL; + if (hListThread) + hListThread = NULL; + NetlibUnInit(); - DestroyServiceFunction(hCheckUpdates); return 0; } diff --git a/plugins/PluginUpdater/src/Scanner.cpp b/plugins/PluginUpdater/src/Scanner.cpp index 3653adfd2f..c3659a6275 100644 --- a/plugins/PluginUpdater/src/Scanner.cpp +++ b/plugins/PluginUpdater/src/Scanner.cpp @@ -247,6 +247,7 @@ static void ScanFolder(const TCHAR *tszFolder, size_t cbBaseLen, int level, cons mir_sntprintf(FileInfo->File.tszDownloadURL, SIZEOF(FileInfo->File.tszDownloadURL), _T("%s/%s.zip"), tszBaseUrl, tszBuf); for (p = _tcschr(FileInfo->File.tszDownloadURL, '\\'); p != 0; p = _tcschr(p, '\\')) *p++ = '/'; + FileInfo->File.CRCsum = MyCRC; UpdateFiles->insert(FileInfo); } // end compare versions @@ -256,11 +257,62 @@ static void ScanFolder(const TCHAR *tszFolder, size_t cbBaseLen, int level, cons FindClose(hFind); } +static void GetFullComponent(const TCHAR *tszFolder, const TCHAR *tszBaseUrl, SERVLIST& hashes, OBJLIST *UpdateFiles) +{ + // skip updater's own folder + if ( !_tcsicmp(tszFolder, tszRoot)) + return; + + TCHAR tszPath[MAX_PATH]; + for (int i = 0 ; i < hashes.getCount(); i++) + { + mir_sntprintf(tszPath, SIZEOF(tszPath), _T("%s\\%s"), tszFolder, hashes[i].m_name); + + // this file exist on disk + if (GetFileAttributes(tszPath) != DWORD(-1)) + continue; + + { + ServListEntry tmp(hashes[i].m_name); + ServListEntry *item = hashes.find(&tmp); + + FILEINFO *FileInfo = new FILEINFO; + FileInfo->bDeleteOnly = FALSE; + _tcscpy(FileInfo->tszOldName, item->m_name); // copy the relative old name + _tcscpy(FileInfo->tszNewName, item->m_name); + + TCHAR tszFileName[MAX_PATH]; + _tcscpy(tszFileName, _tcsrchr(tszPath, L'\\') + 1); + TCHAR *p = _tcschr(tszFileName, L'.'); *p = 0; + + TCHAR tszRelFileName[MAX_PATH]; + _tcscpy(tszRelFileName, item->m_name); + p = _tcschr(tszRelFileName, L'.'); *p = 0; + p = _tcschr(tszRelFileName, L'\\'); + p = (p) ? p+1 : tszRelFileName; + _tcslwr(p); + + + mir_sntprintf(FileInfo->File.tszDiskPath, SIZEOF(FileInfo->File.tszDiskPath), _T("%s\\Temp\\%s.zip"), tszRoot, tszFileName); + mir_sntprintf(FileInfo->File.tszDownloadURL, SIZEOF(FileInfo->File.tszDownloadURL), _T("%s/%s.zip"), tszBaseUrl, tszRelFileName); + for (p = _tcschr(FileInfo->File.tszDownloadURL, '\\'); p != 0; p = _tcschr(p, '\\')) + *p++ = '/'; + FileInfo->File.CRCsum = item->m_crc; + UpdateFiles->insert(FileInfo); + } // end compare versions + } +} + static void __stdcall LaunchDialog(void *param) { CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_UPDATE), GetDesktopWindow(), DlgUpdate, (LPARAM)param); } +static void __stdcall LaunchListDialog(void *param) +{ + CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_LIST), GetDesktopWindow(), DlgList, (LPARAM)param); +} + static void CheckUpdates(void *) { char szKey[64] = {0}; @@ -357,6 +409,131 @@ static void CheckUpdates(void *) hCheckThread = NULL; } +static void GetList(void *) +{ + char szKey[64] = {0}; + DBVARIANT dbVar = {0}; + + TCHAR tszTempPath[MAX_PATH]; + DWORD dwLen = GetTempPath(SIZEOF(tszTempPath), tszTempPath); + if (tszTempPath[dwLen-1] == '\\') + tszTempPath[dwLen-1] = 0; + + // Load files info + if (db_get_ts(NULL, MODNAME, "UpdateURL", &dbVar)) { // URL is not set + db_set_ts(NULL, MODNAME, "UpdateURL", _T(DEFAULT_UPDATE_URL)); + db_get_ts(NULL, MODNAME, "UpdateURL", &dbVar); + } + + REPLACEVARSARRAY vars[2]; + vars[0].lptzKey = _T("platform"); + #ifdef WIN64 + vars[0].lptzValue = _T("64"); + #else + vars[0].lptzValue = _T("32"); + #endif + vars[1].lptzKey = vars[1].lptzValue = 0; + + REPLACEVARSDATA dat = { sizeof(REPLACEVARSDATA) }; + dat.dwFlags = RVF_TCHAR; + dat.variables = vars; + mir_ptr tszBaseUrl((TCHAR*)CallService(MS_UTILS_REPLACEVARS, (WPARAM)dbVar.ptszVal, (LPARAM)&dat)); + db_free(&dbVar); + + // Download version info + ShowPopup(NULL, TranslateT("Plugin Updater"), TranslateT("Downloading version info..."), 4, 0); + + FILEURL pFileUrl; + mir_sntprintf(pFileUrl.tszDownloadURL, SIZEOF(pFileUrl.tszDownloadURL), _T("%s/hashes.zip"), (TCHAR*)tszBaseUrl); + mir_sntprintf(pFileUrl.tszDiskPath, SIZEOF(pFileUrl.tszDiskPath), _T("%s\\hashes.zip"), tszTempPath); + if (!DownloadFile(pFileUrl.tszDownloadURL, pFileUrl.tszDiskPath, 0)) { + ShowPopup(0, LPGENT("Plugin Updater"), LPGENT("An error occured while downloading the update."), 1, 0); + hListThread = NULL; + return; + } + + unzip(pFileUrl.tszDiskPath, tszTempPath, NULL); + DeleteFile(pFileUrl.tszDiskPath); + + TCHAR tszTmpIni[MAX_PATH] = {0}; + mir_sntprintf(tszTmpIni, SIZEOF(tszTmpIni), _T("%s\\hashes.txt"), tszTempPath); + FILE *fp = _tfopen(tszTmpIni, _T("r")); + if (!fp) { + hListThread = NULL; + return; + } + + //SERVLIST hashes(50, CompareHashes); + FILELIST *UpdateFiles = new FILELIST(20); + char str[200]; + TCHAR *dirname = Utils_ReplaceVarsT(_T("%miranda_path%")); + while(fgets(str, SIZEOF(str), fp) != NULL) { + rtrim(str); + char *p = strchr(str, ' '); + if (p == NULL) + continue; + + *p++ = 0; + /*if ( !opts.bUpdateIcons && !_strnicmp(str, "icons\\", 6)) + continue;*/ + + _strlwr(p); + + int dwCrc32; + char *p1 = strchr(p, ' '); + if (p1 == NULL) + dwCrc32 = 0; + else { + *p1++ = 0; + sscanf(p1, "%08x", &dwCrc32); + } + ServListEntry hash(str, p, dwCrc32); + + TCHAR tszPath[MAX_PATH]; + mir_sntprintf(tszPath, SIZEOF(tszPath), _T("%s\\%s"), dirname, hash.m_name); + + if (GetFileAttributes(tszPath) != DWORD(-1)) + continue; + + FILEINFO *FileInfo = new FILEINFO; + FileInfo->bDeleteOnly = FALSE; + _tcscpy(FileInfo->tszOldName, hash.m_name); // copy the relative old name + _tcscpy(FileInfo->tszNewName, hash.m_name); + + TCHAR tszFileName[MAX_PATH]; + _tcscpy(tszFileName, _tcsrchr(tszPath, L'\\') + 1); + TCHAR *tp = _tcschr(tszFileName, L'.'); *tp = 0; + + TCHAR tszRelFileName[MAX_PATH]; + _tcscpy(tszRelFileName, hash.m_name); + tp = _tcschr(tszRelFileName, L'.'); *tp = 0; + tp = _tcschr(tszRelFileName, L'\\'); + tp = (p) ? tp+1 : tszRelFileName; + _tcslwr(tp); + + + mir_sntprintf(FileInfo->File.tszDiskPath, SIZEOF(FileInfo->File.tszDiskPath), _T("%s\\Temp\\%s.zip"), tszRoot, tszFileName); + mir_sntprintf(FileInfo->File.tszDownloadURL, SIZEOF(FileInfo->File.tszDownloadURL), _T("%s/%s.zip"), tszBaseUrl, tszRelFileName); + for (tp = _tcschr(FileInfo->File.tszDownloadURL, '\\'); tp != 0; tp = _tcschr(tp, '\\')) + *tp++ = '/'; + FileInfo->File.CRCsum = hash.m_crc; + UpdateFiles->insert(FileInfo); + } + fclose(fp); + DeleteFile(tszTmpIni); + + mir_free(dirname); + + // Show dialog + if (UpdateFiles->getCount() == 0) { + if ( !opts.bSilent) + ShowPopup(0, LPGENT("Plugin Updater"), LPGENT("List is emply."), 2, 0); + } + else CallFunctionAsync(LaunchListDialog, UpdateFiles); + + hListThread = NULL; +} + void DoCheck(int iFlag) { if (hCheckThread) @@ -371,3 +548,16 @@ void DoCheck(int iFlag) db_set_dw(NULL, MODNAME, "LastUpdate", time(NULL)); } } + +void DoGetList(int iFlag) +{ + if (hListThread) + ShowPopup(0, LPGENT("Plugin Updater"), LPGENT("List loading already started!"), 2, 0); + else if (hwndDialog) { + ShowWindow(hwndDialog, SW_SHOW); + SetForegroundWindow(hwndDialog); + SetFocus(hwndDialog); + } + else if (iFlag) + hListThread = mir_forkthread(GetList, 0); +} diff --git a/plugins/PluginUpdater/src/Utils.cpp b/plugins/PluginUpdater/src/Utils.cpp index 87f7cbedb7..43f27180de 100644 --- a/plugins/PluginUpdater/src/Utils.cpp +++ b/plugins/PluginUpdater/src/Utils.cpp @@ -23,7 +23,7 @@ BOOL DlgDld; int Number = 0; TCHAR tszDialogMsg[2048] = {0}; FILEINFO *pFileInfo = NULL; -HANDLE hCheckThread = NULL, hNetlibUser = NULL; +HANDLE hCheckThread = NULL, hListThread = NULL, hNetlibUser = NULL; POPUP_OPTIONS PopupOptions = {0}; aPopups PopupsList[POPUPS]; @@ -39,8 +39,9 @@ struct static iconList[] = { { "check_update", LPGEN("Check for plugin updates"), IDI_MENU }, - { "btn_ok", LPGEN("'Yes' Button"), IDI_OK }, - { "btn_cancel", LPGEN("'No' Button"), IDI_CANCEL } + { "btn_ok", LPGEN("'Yes' Button"), IDI_OK }, + { "btn_cancel", LPGEN("'No' Button"), IDI_CANCEL }, + { "info", LPGEN("Plugin info"), IDI_INFO }, }; void IcoLibInit() @@ -361,6 +362,14 @@ void __stdcall RestartMe(void*) CallService(MS_SYSTEM_RESTART, db_get_b(NULL,MODNAME,"RestartCurrentProfile",1) ? 1 : 0, 0); } +void __stdcall OpenPluginOptions(void*) +{ + OPENOPTIONSDIALOG ood = {0}; + ood.cbSize = sizeof(ood); + ood.pszPage = "Plugins"; + Options_Open(&ood); +} + #endif // FUNCTION: IsRunAsAdmin() diff --git a/plugins/PluginUpdater/src/resource.h b/plugins/PluginUpdater/src/resource.h index 2f940e3fee..57416edb3e 100644 --- a/plugins/PluginUpdater/src/resource.h +++ b/plugins/PluginUpdater/src/resource.h @@ -1,14 +1,22 @@ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. -// Used by C:\Myranda\plugins\PluginUpdater\res\Resource.rc +// Used by e:\Projects\C++\MirandaNG\plugins\PluginUpdater\res\Resource.rc // #define IDI_MENU 101 #define IDD_UPDATE 102 #define IDD_OPT_UPDATENOTIFY 104 #define IDD_POPUP 105 #define IDD_POPUPDUMMI 106 +#define IDD_LIST 107 #define IDI_OK 108 #define IDI_CANCEL 109 +#define IDI_INFO 111 +#define IDI_DOWN_DEL 112 +#define IDI_DOWN_FAIL 113 +#define IDI_DOWN_LOAD 114 +#define IDI_DOWN_OK 115 +#define IDI_ICON5 116 +#define IDI_DOWN_SKIP 116 #define IDC_UPDATETEXT 1001 #define IDC_CURVER 1002 #define IDC_NEWVER 1003 @@ -69,7 +77,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 110 +#define _APS_NEXT_RESOURCE_VALUE 117 #define _APS_NEXT_COMMAND_VALUE 40075 #define _APS_NEXT_CONTROL_VALUE 1044 #define _APS_NEXT_SYMED_VALUE 101 -- cgit v1.2.3