summaryrefslogtreecommitdiff
path: root/plugins/PluginUpdater/src/DlgUpdate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/PluginUpdater/src/DlgUpdate.cpp')
-rw-r--r--plugins/PluginUpdater/src/DlgUpdate.cpp1527
1 files changed, 763 insertions, 764 deletions
diff --git a/plugins/PluginUpdater/src/DlgUpdate.cpp b/plugins/PluginUpdater/src/DlgUpdate.cpp
index c7f02157ce..711bfcd57b 100644
--- a/plugins/PluginUpdater/src/DlgUpdate.cpp
+++ b/plugins/PluginUpdater/src/DlgUpdate.cpp
@@ -1,765 +1,764 @@
-/*
-Copyright (C) 2010 Mataes
-
-This is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public
-License as published by the Free Software Foundation; either
-version 2 of the License, or (at your option) any later version.
-
-This is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Library General Public License for more details.
-
-You should have received a copy of the GNU Library General Public
-License along with this file; see the file license.txt. If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
-*/
-
-#include "common.h"
-
-#define UM_ERROR (WM_USER+1)
-
-static bool bShowDetails;
-static HWND hwndDialog;
-HANDLE hCheckThread;
-
-static void SelectAll(HWND hDlg, bool bEnable)
-{
- OBJLIST<FILEINFO> &todo = *(OBJLIST<FILEINFO> *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
- HWND hwndList = GetDlgItem(hDlg, IDC_LIST_UPDATES);
-
- for (int i=0; i < todo.getCount(); i++) {
- ListView_SetCheckState(hwndList, i, bEnable);
- db_set_b(NULL, MODNAME "Files", StrToLower(_T2A(todo[i].tszOldName)), todo[i].bEnabled = bEnable);
- }
-}
-
-static void SetStringText(HWND hWnd, size_t i, TCHAR *ptszText)
-{
- ListView_SetItemText(hWnd, i, 1, ptszText);
-}
-
-static void ApplyUpdates(void *param)
-{
- HWND hDlg = (HWND)param;
- OBJLIST<FILEINFO> &todo = *(OBJLIST<FILEINFO> *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
- if (todo.getCount() == 0) {
- return;
- }
-
- // 1) If we need to escalate priviledges, launch a stub
- if (!PrepareEscalation()) {
- EndDialog(hDlg, 0);
- return;
- }
-
- AutoHandle pipe(hPipe);
- HWND hwndList = GetDlgItem(hDlg, IDC_LIST_UPDATES);
- TCHAR 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);
-
- // 2) Download all plugins
- HANDLE nlc = NULL;
- for (int i=0; i < todo.getCount(); i++) {
- ListView_EnsureVisible(hwndList, i, FALSE);
- if (!todo[i].bEnabled) {
- SetStringText(hwndList, i, TranslateT("Skipped."));
- }
- else if (todo[i].bDeleteOnly) {
- SetStringText(hwndList, i, TranslateT("Will be deleted!"));
- }
- else {
- // download update
- SetStringText(hwndList, i, TranslateT("Downloading..."));
-
- FILEURL *pFileUrl = &todo[i].File;
- if (!DownloadFile(pFileUrl, nlc)) {
- SetStringText(hwndList, i, TranslateT("Failed!"));
-
- // interrupt update as we require all components to be updated
- Netlib_CloseHandle(nlc);
- PostMessage(hDlg, UM_ERROR, 0, 0);
- SkinPlaySound("updatefailed");
- return;
- }
- SetStringText(hwndList, i, TranslateT("Succeeded."));
- }
- }
- Netlib_CloseHandle(nlc);
-
- // 3) Unpack all zips
- TCHAR *tszMirandaPath = Utils_ReplaceVarsT(_T("%miranda_path%"));
- for (int i = 0; i < todo.getCount(); i++) {
- if (todo[i].bEnabled) {
- 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);
- }
- else {
- // 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,true))
- SafeDeleteFile(p.File.tszDiskPath); // remove .zip after successful update
- }
- }
- }
- SkinPlaySound("updatecompleted");
-
-#if MIRANDA_VER < 0x0A00
- // 4) Change title of clist
- ptrT title = db_get_tsa(NULL, "CList", "TitleText");
- if (!_tcsicmp(title, _T("Miranda IM")))
- db_set_ts(NULL, "CList", "TitleText", _T("Miranda NG"));
-#endif
-
- opts.bForceRedownload = false;
- db_unset(NULL, MODNAME, "ForceRedownload");
-
- db_set_b(NULL, MODNAME, "RestartCount", 5);
-
- // 5) Prepare Restart
- int rc = MessageBox(hDlg, TranslateT("Update complete. Press Yes to restart Miranda now or No to postpone a restart until the exit."), TranslateT("Plugin Updater"), MB_YESNO | MB_ICONQUESTION);
- EndDialog(hDlg, 0);
- PostMessage(hDlg, WM_DESTROY, 0, 0); // why do we have to call this manually?
- if (rc == IDYES)
- CallFunctionAsync(RestartMe, 0);
-}
-
-static void ResizeVert(HWND hDlg, int yy)
-{
- RECT r = { 0, 0, 244, yy };
- MapDialogRect(hDlg, &r);
- r.bottom += GetSystemMetrics(SM_CYSMCAPTION);
- SetWindowPos(hDlg, 0, 0, 0, r.right, r.bottom, SWP_NOMOVE | SWP_NOZORDER);
-}
-
-static INT_PTR CALLBACK DlgUpdate(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- HWND hwndList = GetDlgItem(hDlg, IDC_LIST_UPDATES);
-
- switch (message) {
- case WM_INITDIALOG:
- TranslateDialogDefault(hDlg);
- SendMessage(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
- SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)Skin_GetIcon("check_update"));
- SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM)Skin_GetIcon("check_update", 1));
- {
- 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};
- // Initialize the LVCOLUMN structure.
- // The mask specifies that the format, width, text, and
- // subitem members of the structure are valid.
- lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
- lvc.fmt = LVCFMT_LEFT;
-
- lvc.iSubItem = 0;
- lvc.pszText = TranslateT("Component Name");
- lvc.cx = 220; // width of column in pixels
- ListView_InsertColumn(hwndList, 0, &lvc);
-
- lvc.iSubItem = 1;
- lvc.pszText = TranslateT("State");
- lvc.cx = 120 - GetSystemMetrics(SM_CXVSCROLL); // width of column in pixels
- ListView_InsertColumn(hwndList, 1, &lvc);
-
- //enumerate plugins, fill in list
- //bool one_enabled = false;
- ListView_DeleteAllItems(hwndList);
-
- // Some code to create the list-view control.
- // Initialize LVITEM members that are common to all items.
- LVITEM lvI = {0};
- lvI.mask = LVIF_TEXT | LVIF_PARAM | LVIF_NORECOMPUTE;// | LVIF_IMAGE;
-
- bool enableOk = false;
- OBJLIST<FILEINFO> &todo = *(OBJLIST<FILEINFO> *)lParam;
- for (int i = 0; i < todo.getCount(); ++i) {
- lvI.mask = LVIF_TEXT | LVIF_PARAM;// | LVIF_IMAGE;
- lvI.iSubItem = 0;
- lvI.lParam = (LPARAM)&todo[i];
- lvI.pszText = todo[i].tszOldName;
- lvI.iItem = i;
- ListView_InsertItem(hwndList, &lvI);
-
- // remember whether the user has decided not to update this component with this particular new version
- todo[i].bEnabled = db_get_b(NULL, MODNAME "Files", StrToLower(_T2A(todo[i].tszOldName)), true);
- ListView_SetCheckState(hwndList, lvI.iItem, todo[i].bEnabled);
- if (todo[i].bEnabled)
- enableOk = true;
- }
- HWND hwOk = GetDlgItem(hDlg, IDOK);
- EnableWindow(hwOk, enableOk);
- }
-
- bShowDetails = false;
- ResizeVert(hDlg, 60);
-
- // do this after filling list - enables 'ITEMCHANGED' below
- SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam);
- Utils_RestoreWindowPositionNoSize(hDlg, 0, MODNAME, "ConfirmWindow");
- 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<FILEINFO> &todo = *(OBJLIST<FILEINFO> *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
- if ((nmlv->uNewState ^ nmlv->uOldState) & LVIS_STATEIMAGEMASK) {
- todo[lvI.iItem].bEnabled = ListView_GetCheckState(hwndList, nmlv->iItem);
- db_set_b(NULL, MODNAME "Files", StrToLower(_T2A(todo[lvI.iItem].tszOldName)), todo[lvI.iItem].bEnabled);
-
- 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(ApplyUpdates, hDlg);
- return TRUE;
-
- case IDC_DETAILS:
- bShowDetails = !bShowDetails;
- ResizeVert(hDlg, bShowDetails ? 242 : 60);
- SetDlgItemText(hDlg, IDC_DETAILS, (bShowDetails ? TranslateT("<< Details") : TranslateT("Details >>")));
- break;
-
- case IDC_SELALL:
- SelectAll(hDlg, true);
- break;
-
- case IDC_SELNONE:
- SelectAll(hDlg, false);
- break;
-
- case IDCANCEL:
- DestroyWindow(hDlg);
- return TRUE;
- }
- }
- break;
-
- case UM_ERROR:
- MessageBox(hDlg, TranslateT("Update failed! One of the components wasn't downloaded correctly. Try it again later."), TranslateT("Plugin Updater"), MB_OK | MB_ICONERROR);
- DestroyWindow(hDlg);
- break;
-
- case WM_CLOSE:
- DestroyWindow(hDlg);
- break;
-
- case WM_DESTROY:
- Skin_ReleaseIcon((HICON)SendMessage(hDlg, WM_SETICON, ICON_SMALL, 0));
- Utils_SaveWindowPosition(hDlg, NULL, MODNAME, "ConfirmWindow");
- hwndDialog = NULL;
- opts.bSilent = true;
- delete (OBJLIST<FILEINFO> *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
- SetWindowLongPtr(hDlg, GWLP_USERDATA, 0);
- #if MIRANDA_VER >= 0x0A00
- db_set_dw(NULL, MODNAME, "LastUpdate", time(NULL));
- #endif
- mir_forkthread(InitTimer, (void*)0);
- break;
- }
-
- return FALSE;
-}
-
-static LRESULT CALLBACK PopupDlgProcRestart(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- switch (uMsg) {
- case WM_COMMAND:
- case WM_CONTEXTMENU:
- PUDeletePopup(hDlg);
-
- if (uMsg == WM_COMMAND) {
- TCHAR tszText[200];
- mir_sntprintf(tszText, SIZEOF(tszText), _T("%s\n\n%s"), TranslateT("You need to restart your Miranda to apply installed updates."), TranslateT("Would you like to restart it now?"));
-
- if (MessageBox(hDlg, tszText, TranslateT("Plugin Updater"), MB_YESNO | MB_ICONQUESTION) == IDYES)
- CallFunctionAsync(RestartMe, 0);
- }
-
- return TRUE;
- }
-
- return DefWindowProc(hDlg, uMsg, wParam, lParam);
-}
-
-static void DlgUpdateSilent(void *lParam)
-{
- OBJLIST<FILEINFO> &UpdateFiles = *(OBJLIST<FILEINFO> *)lParam;
- if (UpdateFiles.getCount() == 0) {
- delete &UpdateFiles;
- return;
- }
-
- // 1) If we need to escalate priviledges, launch a stub
- if (!PrepareEscalation()) {
- delete &UpdateFiles;
- return;
- }
-
- AutoHandle pipe(hPipe);
- TCHAR 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);
-
- // 2) Download all plugins
- HANDLE nlc = NULL;
- // Count all updates that have been enabled
- int count = 0;
- for (int i = 0; i < UpdateFiles.getCount(); i++) {
- if (db_get_b(NULL, MODNAME "Files", StrToLower(_T2A(UpdateFiles[i].tszOldName)), 1) && !UpdateFiles[i].bDeleteOnly) {
- // download update
- FILEURL *pFileUrl = &UpdateFiles[i].File;
- if (!DownloadFile(pFileUrl, nlc)) {
- // interrupt update as we require all components to be updated
- Netlib_CloseHandle(nlc);
- SkinPlaySound("updatefailed");
- delete &UpdateFiles;
- return;
- }
- count++;
- }
-
- }
- Netlib_CloseHandle(nlc);
-
- if (count == 0) {
- delete &UpdateFiles;
- return;
- }
-
- // 3) Unpack all zips
- TCHAR *tszMirandaPath = Utils_ReplaceVarsT(_T("%miranda_path%"));
- for (int i = 0; i < UpdateFiles.getCount(); i++) {
- if (db_get_b(NULL, MODNAME "Files", StrToLower(_T2A(UpdateFiles[i].tszOldName)), 1)) {
- TCHAR tszBackFile[MAX_PATH];
- FILEINFO& p = UpdateFiles[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);
- }
- else {
- // 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, true))
- SafeDeleteFile(p.File.tszDiskPath); // remove .zip after successful update
- }
- }
- }
- delete &UpdateFiles;
- SkinPlaySound("updatecompleted");
-
-#if MIRANDA_VER < 0x0A00
- // 4) Change title of clist
- ptrT title = db_get_tsa(NULL, "CList", "TitleText");
- if (!_tcsicmp(title, _T("Miranda IM")))
- db_set_ts(NULL, "CList", "TitleText", _T("Miranda NG"));
-#endif
-
- opts.bForceRedownload = false;
- db_unset(NULL, MODNAME, "ForceRedownload");
-
- db_set_b(NULL, MODNAME, "RestartCount", 5);
- db_set_b(NULL, MODNAME, "NeedRestart", 1);
-
- // 5) Prepare Restart
- TCHAR tszTitle[100];
- mir_sntprintf(tszTitle, SIZEOF(tszTitle), TranslateT("%d component(s) was updated"), count);
-
- if (ServiceExists(MS_POPUP_ADDPOPUPT) && db_get_b(NULL, "Popup", "ModuleIsEnabled", 1)) {
- POPUPDATAT_V2 pd = { 0 };
- pd.cbSize = sizeof(pd);
- pd.lchContact = NULL;
- pd.lchIcon = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
- pd.colorBack = pd.colorText = 0;
- pd.iSeconds = -1;
- pd.PluginWindowProc = PopupDlgProcRestart;
-
- lstrcpyn(pd.lptzText, TranslateT("You need to restart your Miranda to apply installed updates."), MAX_SECONDLINE);
- lstrcpyn(pd.lptzContactName, tszTitle, MAX_CONTACTNAME);
-
- CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&pd, APF_NEWDATA);
- } else {
- bool notified = false;
-
- if (ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) {
- MIRANDASYSTRAYNOTIFY err;
- err.szProto = MODULEA;
- err.cbSize = sizeof(err);
- err.dwInfoFlags = NIIF_INTERN_UNICODE | NIIF_INFO;
- err.tszInfoTitle = tszTitle;
- err.tszInfo = TranslateT("You need to restart your Miranda to apply installed updates.");
- err.uTimeout = 30000;
-
- notified = !CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&err);
- }
-
- if (!notified) {
- // Error, let's try to show MessageBox as last way to inform user about successful update
- TCHAR tszText[200];
- mir_sntprintf(tszText, SIZEOF(tszText), _T("%s\n\n%s"), TranslateT("You need to restart your Miranda to apply installed updates."), TranslateT("Would you like to restart it now?"));
-
- if (MessageBox(NULL, tszText, tszTitle, MB_ICONINFORMATION | MB_YESNO) == IDYES)
- CallFunctionAsync(RestartMe, 0);
- }
- }
-}
-
-static void __stdcall LaunchDialog(void *param)
-{
- if (opts.bSilentMode && opts.bSilent)
- mir_forkthread(DlgUpdateSilent, param);
- else
- hwndDialog = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_UPDATE), GetDesktopWindow(), DlgUpdate, (LPARAM)param);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// building file list in the separate thread
-
-struct
-{
- TCHAR *oldName, *newName;
-}
-static renameTable[] =
-{
- { _T("svc_dbepp.dll"), _T("Plugins\\dbeditorpp.dll") },
- { _T("svc_crshdmp.dll"), _T("Plugins\\crashdumper.dll") },
- { _T("svc_vi.dll"), _T("Plugins\\versioninfo.dll") },
- { _T("crashrpt.dll"), _T("Plugins\\crashdumper.dll") },
- { _T("advsplashscreen.dll"), _T("Plugins\\splashscreen.dll") },
- { _T("import_sa.dll"), _T("Plugins\\import.dll") },
- { _T("newnr.dll"), _T("Plugins\\notesreminders.dll") },
- { _T("dbtool.exe"), _T("Plugins\\dbchecker.dll") },
- { _T("dbtool_sa.exe"), _T("Plugins\\dbchecker.dll") },
- { _T("bclist.dll"), _T("Plugins\\clist_blind.dll") },
- { _T("otr.dll"), _T("Plugins\\mirotr.dll") },
- { _T("ttnotify.dll"), _T("Plugins\\tooltipnotify.dll") },
- { _T("newstatusnotify.dll"), _T("Plugins\\newxstatusnotify.dll") },
- { _T("rss.dll"), _T("Plugins\\newsaggregator.dll") },
- { _T("dbx_3x.dll"), _T("Plugins\\dbx_mmap.dll") },
-
- #if MIRANDA_VER >= 0x0A00
- { _T("dbx_mmap_sa.dll"), _T("Plugins\\dbx_mmap.dll") },
- { _T("dbx_tree.dll"), _T("Plugins\\dbx_mmap.dll") },
- { _T("rc4.dll"), NULL },
- { _T("athena.dll"), NULL },
- #endif
-
- { _T("proto_newsaggr.dll"), _T("Icons\\proto_newsaggregator.dll") },
- { _T("clienticons_*.dll"), _T("Icons\\fp_icons.dll") },
- { _T("fp_*.dll"), _T("Icons\\fp_icons.dll") },
-
- { _T("langpack_*.txt"), _T("Languages\\*") },
-
- { _T("clist_classic.dll"), NULL },
- { _T("chat.dll"), NULL },
- { _T("gender.dll"), NULL },
- { _T("srmm.dll"), NULL },
- { _T("extraicons.dll"), NULL },
- { _T("langman.dll"), NULL },
- { _T("metacontacts.dll"), NULL },
-};
-
-static bool CheckFileRename(const TCHAR *ptszOldName, TCHAR *pNewName)
-{
- for (int i = 0; i < SIZEOF(renameTable); i++) {
- if (!wildcmpit(ptszOldName, renameTable[i].oldName))
- continue;
-
- TCHAR *ptszDest = renameTable[i].newName;
- if (ptszDest == NULL)
- *pNewName = 0;
- else {
- _tcsncpy_s(pNewName, MAX_PATH, ptszDest, _TRUNCATE);
- size_t cbLen = _tcslen(ptszDest) - 1;
- if (pNewName[cbLen] == '*')
- _tcsncpy_s(pNewName + cbLen, MAX_PATH - cbLen, ptszOldName, _TRUNCATE);
- }
- return true;
- }
-
- return false;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-static bool isValidExtension(const TCHAR *ptszFileName)
-{
- const TCHAR *pExt = _tcsrchr(ptszFileName, '.');
-
- return (pExt != NULL) && (!_tcsicmp(pExt, _T(".dll")) || !_tcsicmp(pExt, _T(".exe")) || !_tcsicmp(pExt, _T(".txt")));
-}
-
-static int ScanFolder(const TCHAR *tszFolder, size_t cbBaseLen, int level, const TCHAR *tszBaseUrl, SERVLIST& hashes, OBJLIST<FILEINFO> *UpdateFiles)
-{
- int count = 0;
-
- // skip updater's own folder
- if (!_tcsicmp(tszFolder, tszRoot))
- return count;
-
- TCHAR tszBuf[MAX_PATH];
- mir_sntprintf(tszBuf, SIZEOF(tszBuf), _T("%s\\*"), tszFolder);
-
- WIN32_FIND_DATA ffd;
- HANDLE hFind = FindFirstFile(tszBuf, &ffd);
- if (hFind == INVALID_HANDLE_VALUE)
- return count;
-
- do {
- if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- if (_tcscmp(ffd.cFileName, _T(".")) && _tcscmp(ffd.cFileName, _T(".."))) {
- // we need to skip profile folder
- TCHAR tszProfilePath[MAX_PATH];
- CallService(MS_DB_GETPROFILEPATHT, SIZEOF(tszProfilePath), (LPARAM)tszProfilePath);
-
- mir_sntprintf(tszBuf, SIZEOF(tszBuf), _T("%s\\%s"), tszFolder, ffd.cFileName);
- if (0 != _tcsicmp(tszBuf, tszProfilePath))
- count += ScanFolder(tszBuf, cbBaseLen, level+1, tszBaseUrl, hashes, UpdateFiles);
- }
- }
- else if (isValidExtension(ffd.cFileName)) {
- // calculate the current file's relative name and store it into tszNewName
- TCHAR tszNewName[MAX_PATH];
- if (!CheckFileRename(ffd.cFileName, tszNewName)) {
- if (level == 0)
- _tcsncpy(tszNewName, ffd.cFileName, MAX_PATH);
- else
- mir_sntprintf(tszNewName, SIZEOF(tszNewName), _T("%s\\%s"), tszFolder+cbBaseLen, ffd.cFileName);
- }
-
- bool bHasNewVersion = true;
- TCHAR *ptszUrl;
- int MyCRC = 0;
- mir_sntprintf(tszBuf, SIZEOF(tszBuf), _T("%s\\%s"), tszFolder, ffd.cFileName);
-
- // this file is not marked for deletion
- if (tszNewName[0]) {
- TCHAR *pName = tszNewName;
- ServListEntry *item = hashes.find((ServListEntry*)&pName);
- if (item == NULL) {
- TCHAR *p = _tcsrchr(tszNewName, '.');
- if (p[-1] != 'w' && p[-1] != 'W')
- continue;
-
- int iPos = int(p - tszNewName)-1;
- strdel(p-1, 1);
- if ((item = hashes.find((ServListEntry*)&pName)) == NULL)
- continue;
-
- strdel(tszNewName+iPos, 1);
- }
-
- ptszUrl = item->m_name;
- // No need to hash a file if we are forcing a redownload anyway
- if (!opts.bForceRedownload) {
- // try to hash the file
- char szMyHash[33];
- __try {
- CalculateModuleHash(tszBuf, szMyHash);
- bHasNewVersion = strcmp(szMyHash, item->m_szHash) != 0;
- }
- __except(EXCEPTION_EXECUTE_HANDLER) {
- ZeroMemory(szMyHash, 0);
- // smth went wrong, reload a file from scratch
- }
- }
-
- MyCRC = item->m_crc;
- }
- else // file was marked for deletion, add it to the list anyway
- ptszUrl = _T("");
-
- // Compare versions
- if (bHasNewVersion) { // Yeah, we've got new version.
- FILEINFO *FileInfo = new FILEINFO;
- _tcscpy(FileInfo->tszOldName, tszBuf+cbBaseLen); // copy the relative old name
- if (tszNewName[0] == 0) {
- FileInfo->bDeleteOnly = TRUE;
- _tcscpy(FileInfo->tszNewName, tszBuf); // save the full old name for deletion
- }
- else {
- FileInfo->bDeleteOnly = FALSE;
- _tcsncpy(FileInfo->tszNewName, ptszUrl, SIZEOF(FileInfo->tszNewName));
- }
-
- _tcscpy(tszBuf, ptszUrl);
- TCHAR *p = _tcsrchr(tszBuf, '.');
- if (p) *p = 0;
- p = _tcsrchr(tszBuf, '\\');
- p = (p) ? p+1 : tszBuf;
- _tcslwr(p);
-
- mir_sntprintf(FileInfo->File.tszDiskPath, SIZEOF(FileInfo->File.tszDiskPath), _T("%s\\Temp\\%s.zip"), tszRoot, p);
- 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);
-
- if (!opts.bSilent || db_get_b(NULL, MODNAME "Files", StrToLower(_T2A(FileInfo->tszNewName)), true))
- count++;
- } // end compare versions
- }
- }
- while (FindNextFile(hFind, &ffd) != 0);
-
- FindClose(hFind);
- return count;
-}
-
-static void CheckUpdates(void *)
-{
- char szKey[64] = {0};
-
- TCHAR tszTempPath[MAX_PATH];
- DWORD dwLen = GetTempPath(SIZEOF(tszTempPath), tszTempPath);
- if (tszTempPath[dwLen-1] == '\\')
- tszTempPath[dwLen-1] = 0;
-
- ptrT updateUrl(GetDefaultUrl()), baseUrl;
-
- SERVLIST hashes(50, CompareHashes);
- bool success = ParseHashes(updateUrl, baseUrl, hashes);
- if (success) {
- FILELIST *UpdateFiles = new FILELIST(20);
- VARST dirname( _T("%miranda_path%"));
- int count = ScanFolder(dirname, lstrlen(dirname)+1, 0, baseUrl, hashes, UpdateFiles);
-
- // Show dialog
- if (count == 0) {
- if (!opts.bSilent)
- ShowPopup(0, LPGENT("Plugin Updater"), LPGENT("No updates found."), 2, 0);
- delete UpdateFiles;
- opts.bSilent = true;
- }
- else CallFunctionAsync(LaunchDialog, UpdateFiles);
- }
- else opts.bSilent = true;
-
- mir_forkthread(InitTimer, (void*)(success ? 0 : 2));
-
- hashes.destroy();
- hCheckThread = NULL;
-}
-
-void DoCheck()
-{
- if (hCheckThread)
- ShowPopup(0, LPGENT("Plugin Updater"), LPGENT("Update checking already started!"), 2, 0);
- else if (hwndDialog) {
- ShowWindow(hwndDialog, SW_SHOW);
- SetForegroundWindow(hwndDialog);
- SetFocus(hwndDialog);
- } else {
- #if MIRANDA_VER >= 0x0A00
- db_set_dw(NULL, MODNAME, "LastUpdate", time(NULL));
- #endif
- hCheckThread = mir_forkthread(CheckUpdates, 0);
- }
-}
-
-void UninitCheck()
-{
- if (hwndDialog != NULL)
- DestroyWindow(hwndDialog);
-}
-
-INT_PTR MenuCommand(WPARAM,LPARAM)
-{
- opts.bSilent = false;
- DoCheck();
- return 0;
-}
-
-void InitCheck()
-{
- CreateServiceFunction(MODNAME"/CheckUpdates", MenuCommand);
-}
-
-void UnloadCheck()
-{
- if (hCheckThread)
- hCheckThread = NULL;
+/*
+Copyright (C) 2010 Mataes
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include "common.h"
+
+#define UM_ERROR (WM_USER+1)
+
+static bool bShowDetails;
+static HWND hwndDialog;
+HANDLE hCheckThread;
+
+static void SelectAll(HWND hDlg, bool bEnable)
+{
+ OBJLIST<FILEINFO> &todo = *(OBJLIST<FILEINFO> *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
+ HWND hwndList = GetDlgItem(hDlg, IDC_LIST_UPDATES);
+
+ for (int i=0; i < todo.getCount(); i++) {
+ ListView_SetCheckState(hwndList, i, bEnable);
+ db_set_b(NULL, MODNAME "Files", StrToLower(_T2A(todo[i].tszOldName)), todo[i].bEnabled = bEnable);
+ }
+}
+
+static void SetStringText(HWND hWnd, size_t i, TCHAR *ptszText)
+{
+ ListView_SetItemText(hWnd, i, 1, ptszText);
+}
+
+static void ApplyUpdates(void *param)
+{
+ HWND hDlg = (HWND)param;
+ OBJLIST<FILEINFO> &todo = *(OBJLIST<FILEINFO> *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
+ if (todo.getCount() == 0) {
+ return;
+ }
+
+ // 1) If we need to escalate priviledges, launch a stub
+ if (!PrepareEscalation()) {
+ SendMessage(hDlg, WM_CLOSE, 0, 0);
+ return;
+ }
+
+ AutoHandle pipe(hPipe);
+ HWND hwndList = GetDlgItem(hDlg, IDC_LIST_UPDATES);
+ TCHAR 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);
+
+ // 2) Download all plugins
+ HANDLE nlc = NULL;
+ for (int i=0; i < todo.getCount(); i++) {
+ ListView_EnsureVisible(hwndList, i, FALSE);
+ if (!todo[i].bEnabled) {
+ SetStringText(hwndList, i, TranslateT("Skipped."));
+ }
+ else if (todo[i].bDeleteOnly) {
+ SetStringText(hwndList, i, TranslateT("Will be deleted!"));
+ }
+ else {
+ // download update
+ SetStringText(hwndList, i, TranslateT("Downloading..."));
+
+ FILEURL *pFileUrl = &todo[i].File;
+ if (!DownloadFile(pFileUrl, nlc)) {
+ SetStringText(hwndList, i, TranslateT("Failed!"));
+
+ // interrupt update as we require all components to be updated
+ Netlib_CloseHandle(nlc);
+ PostMessage(hDlg, UM_ERROR, 0, 0);
+ SkinPlaySound("updatefailed");
+ return;
+ }
+ SetStringText(hwndList, i, TranslateT("Succeeded."));
+ }
+ }
+ Netlib_CloseHandle(nlc);
+
+ // 3) Unpack all zips
+ TCHAR *tszMirandaPath = Utils_ReplaceVarsT(_T("%miranda_path%"));
+ for (int i = 0; i < todo.getCount(); i++) {
+ if (todo[i].bEnabled) {
+ 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);
+ }
+ else {
+ // 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,true))
+ SafeDeleteFile(p.File.tszDiskPath); // remove .zip after successful update
+ }
+ }
+ }
+ SkinPlaySound("updatecompleted");
+
+#if MIRANDA_VER < 0x0A00
+ // 4) Change title of clist
+ ptrT title = db_get_tsa(NULL, "CList", "TitleText");
+ if (!_tcsicmp(title, _T("Miranda IM")))
+ db_set_ts(NULL, "CList", "TitleText", _T("Miranda NG"));
+#endif
+
+ opts.bForceRedownload = false;
+ db_unset(NULL, MODNAME, "ForceRedownload");
+
+ db_set_b(NULL, MODNAME, "RestartCount", 5);
+
+ // 5) Prepare Restart
+ int rc = MessageBox(hDlg, TranslateT("Update complete. Press Yes to restart Miranda now or No to postpone a restart until the exit."), TranslateT("Plugin Updater"), MB_YESNO | MB_ICONQUESTION);
+ SendMessage(hDlg, WM_CLOSE, 0, 0);
+ if (rc == IDYES)
+ CallFunctionAsync(RestartMe, 0);
+}
+
+static void ResizeVert(HWND hDlg, int yy)
+{
+ RECT r = { 0, 0, 244, yy };
+ MapDialogRect(hDlg, &r);
+ r.bottom += GetSystemMetrics(SM_CYSMCAPTION);
+ SetWindowPos(hDlg, 0, 0, 0, r.right, r.bottom, SWP_NOMOVE | SWP_NOZORDER);
+}
+
+static INT_PTR CALLBACK DlgUpdate(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndList = GetDlgItem(hDlg, IDC_LIST_UPDATES);
+
+ switch (message) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hDlg);
+ SendMessage(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
+ SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)Skin_GetIcon("check_update"));
+ SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM)Skin_GetIcon("check_update", 1));
+ {
+ 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};
+ // Initialize the LVCOLUMN structure.
+ // The mask specifies that the format, width, text, and
+ // subitem members of the structure are valid.
+ lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
+ lvc.fmt = LVCFMT_LEFT;
+
+ lvc.iSubItem = 0;
+ lvc.pszText = TranslateT("Component Name");
+ lvc.cx = 220; // width of column in pixels
+ ListView_InsertColumn(hwndList, 0, &lvc);
+
+ lvc.iSubItem = 1;
+ lvc.pszText = TranslateT("State");
+ lvc.cx = 120 - GetSystemMetrics(SM_CXVSCROLL); // width of column in pixels
+ ListView_InsertColumn(hwndList, 1, &lvc);
+
+ //enumerate plugins, fill in list
+ //bool one_enabled = false;
+ ListView_DeleteAllItems(hwndList);
+
+ // Some code to create the list-view control.
+ // Initialize LVITEM members that are common to all items.
+ LVITEM lvI = {0};
+ lvI.mask = LVIF_TEXT | LVIF_PARAM | LVIF_NORECOMPUTE;// | LVIF_IMAGE;
+
+ bool enableOk = false;
+ OBJLIST<FILEINFO> &todo = *(OBJLIST<FILEINFO> *)lParam;
+ for (int i = 0; i < todo.getCount(); ++i) {
+ lvI.mask = LVIF_TEXT | LVIF_PARAM;// | LVIF_IMAGE;
+ lvI.iSubItem = 0;
+ lvI.lParam = (LPARAM)&todo[i];
+ lvI.pszText = todo[i].tszOldName;
+ lvI.iItem = i;
+ ListView_InsertItem(hwndList, &lvI);
+
+ // remember whether the user has decided not to update this component with this particular new version
+ todo[i].bEnabled = db_get_b(NULL, MODNAME "Files", StrToLower(_T2A(todo[i].tszOldName)), true);
+ ListView_SetCheckState(hwndList, lvI.iItem, todo[i].bEnabled);
+ if (todo[i].bEnabled)
+ enableOk = true;
+ }
+ HWND hwOk = GetDlgItem(hDlg, IDOK);
+ EnableWindow(hwOk, enableOk);
+ }
+
+ bShowDetails = false;
+ ResizeVert(hDlg, 60);
+
+ // do this after filling list - enables 'ITEMCHANGED' below
+ SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam);
+ Utils_RestoreWindowPositionNoSize(hDlg, 0, MODNAME, "ConfirmWindow");
+ 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<FILEINFO> &todo = *(OBJLIST<FILEINFO> *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
+ if ((nmlv->uNewState ^ nmlv->uOldState) & LVIS_STATEIMAGEMASK) {
+ todo[lvI.iItem].bEnabled = ListView_GetCheckState(hwndList, nmlv->iItem);
+ db_set_b(NULL, MODNAME "Files", StrToLower(_T2A(todo[lvI.iItem].tszOldName)), todo[lvI.iItem].bEnabled);
+
+ 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(ApplyUpdates, hDlg);
+ return TRUE;
+
+ case IDC_DETAILS:
+ bShowDetails = !bShowDetails;
+ ResizeVert(hDlg, bShowDetails ? 242 : 60);
+ SetDlgItemText(hDlg, IDC_DETAILS, (bShowDetails ? TranslateT("<< Details") : TranslateT("Details >>")));
+ break;
+
+ case IDC_SELALL:
+ SelectAll(hDlg, true);
+ break;
+
+ case IDC_SELNONE:
+ SelectAll(hDlg, false);
+ break;
+
+ case IDCANCEL:
+ DestroyWindow(hDlg);
+ return TRUE;
+ }
+ }
+ break;
+
+ case UM_ERROR:
+ MessageBox(hDlg, TranslateT("Update failed! One of the components wasn't downloaded correctly. Try it again later."), TranslateT("Plugin Updater"), MB_OK | MB_ICONERROR);
+ DestroyWindow(hDlg);
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow(hDlg);
+ break;
+
+ case WM_DESTROY:
+ Skin_ReleaseIcon((HICON)SendMessage(hDlg, WM_SETICON, ICON_SMALL, 0));
+ Utils_SaveWindowPosition(hDlg, NULL, MODNAME, "ConfirmWindow");
+ hwndDialog = NULL;
+ opts.bSilent = true;
+ delete (OBJLIST<FILEINFO> *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
+ SetWindowLongPtr(hDlg, GWLP_USERDATA, 0);
+ #if MIRANDA_VER >= 0x0A00
+ db_set_dw(NULL, MODNAME, "LastUpdate", time(NULL));
+ #endif
+ mir_forkthread(InitTimer, (void*)0);
+ break;
+ }
+
+ return FALSE;
+}
+
+static LRESULT CALLBACK PopupDlgProcRestart(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg) {
+ case WM_COMMAND:
+ case WM_CONTEXTMENU:
+ PUDeletePopup(hDlg);
+
+ if (uMsg == WM_COMMAND) {
+ TCHAR tszText[200];
+ mir_sntprintf(tszText, SIZEOF(tszText), _T("%s\n\n%s"), TranslateT("You need to restart your Miranda to apply installed updates."), TranslateT("Would you like to restart it now?"));
+
+ if (MessageBox(hDlg, tszText, TranslateT("Plugin Updater"), MB_YESNO | MB_ICONQUESTION) == IDYES)
+ CallFunctionAsync(RestartMe, 0);
+ }
+
+ return TRUE;
+ }
+
+ return DefWindowProc(hDlg, uMsg, wParam, lParam);
+}
+
+static void DlgUpdateSilent(void *lParam)
+{
+ OBJLIST<FILEINFO> &UpdateFiles = *(OBJLIST<FILEINFO> *)lParam;
+ if (UpdateFiles.getCount() == 0) {
+ delete &UpdateFiles;
+ return;
+ }
+
+ // 1) If we need to escalate priviledges, launch a stub
+ if (!PrepareEscalation()) {
+ delete &UpdateFiles;
+ return;
+ }
+
+ AutoHandle pipe(hPipe);
+ TCHAR 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);
+
+ // 2) Download all plugins
+ HANDLE nlc = NULL;
+ // Count all updates that have been enabled
+ int count = 0;
+ for (int i = 0; i < UpdateFiles.getCount(); i++) {
+ if (db_get_b(NULL, MODNAME "Files", StrToLower(_T2A(UpdateFiles[i].tszOldName)), 1) && !UpdateFiles[i].bDeleteOnly) {
+ // download update
+ FILEURL *pFileUrl = &UpdateFiles[i].File;
+ if (!DownloadFile(pFileUrl, nlc)) {
+ // interrupt update as we require all components to be updated
+ Netlib_CloseHandle(nlc);
+ SkinPlaySound("updatefailed");
+ delete &UpdateFiles;
+ return;
+ }
+ count++;
+ }
+
+ }
+ Netlib_CloseHandle(nlc);
+
+ if (count == 0) {
+ delete &UpdateFiles;
+ return;
+ }
+
+ // 3) Unpack all zips
+ TCHAR *tszMirandaPath = Utils_ReplaceVarsT(_T("%miranda_path%"));
+ for (int i = 0; i < UpdateFiles.getCount(); i++) {
+ if (db_get_b(NULL, MODNAME "Files", StrToLower(_T2A(UpdateFiles[i].tszOldName)), 1)) {
+ TCHAR tszBackFile[MAX_PATH];
+ FILEINFO& p = UpdateFiles[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);
+ }
+ else {
+ // 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, true))
+ SafeDeleteFile(p.File.tszDiskPath); // remove .zip after successful update
+ }
+ }
+ }
+ delete &UpdateFiles;
+ SkinPlaySound("updatecompleted");
+
+#if MIRANDA_VER < 0x0A00
+ // 4) Change title of clist
+ ptrT title = db_get_tsa(NULL, "CList", "TitleText");
+ if (!_tcsicmp(title, _T("Miranda IM")))
+ db_set_ts(NULL, "CList", "TitleText", _T("Miranda NG"));
+#endif
+
+ opts.bForceRedownload = false;
+ db_unset(NULL, MODNAME, "ForceRedownload");
+
+ db_set_b(NULL, MODNAME, "RestartCount", 5);
+ db_set_b(NULL, MODNAME, "NeedRestart", 1);
+
+ // 5) Prepare Restart
+ TCHAR tszTitle[100];
+ mir_sntprintf(tszTitle, SIZEOF(tszTitle), TranslateT("%d component(s) was updated"), count);
+
+ if (ServiceExists(MS_POPUP_ADDPOPUPT) && db_get_b(NULL, "Popup", "ModuleIsEnabled", 1)) {
+ POPUPDATAT_V2 pd = { 0 };
+ pd.cbSize = sizeof(pd);
+ pd.lchContact = NULL;
+ pd.lchIcon = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
+ pd.colorBack = pd.colorText = 0;
+ pd.iSeconds = -1;
+ pd.PluginWindowProc = PopupDlgProcRestart;
+
+ lstrcpyn(pd.lptzText, TranslateT("You need to restart your Miranda to apply installed updates."), MAX_SECONDLINE);
+ lstrcpyn(pd.lptzContactName, tszTitle, MAX_CONTACTNAME);
+
+ CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&pd, APF_NEWDATA);
+ } else {
+ bool notified = false;
+
+ if (ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) {
+ MIRANDASYSTRAYNOTIFY err;
+ err.szProto = MODULEA;
+ err.cbSize = sizeof(err);
+ err.dwInfoFlags = NIIF_INTERN_UNICODE | NIIF_INFO;
+ err.tszInfoTitle = tszTitle;
+ err.tszInfo = TranslateT("You need to restart your Miranda to apply installed updates.");
+ err.uTimeout = 30000;
+
+ notified = !CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&err);
+ }
+
+ if (!notified) {
+ // Error, let's try to show MessageBox as last way to inform user about successful update
+ TCHAR tszText[200];
+ mir_sntprintf(tszText, SIZEOF(tszText), _T("%s\n\n%s"), TranslateT("You need to restart your Miranda to apply installed updates."), TranslateT("Would you like to restart it now?"));
+
+ if (MessageBox(NULL, tszText, tszTitle, MB_ICONINFORMATION | MB_YESNO) == IDYES)
+ CallFunctionAsync(RestartMe, 0);
+ }
+ }
+}
+
+static void __stdcall LaunchDialog(void *param)
+{
+ if (opts.bSilentMode && opts.bSilent)
+ mir_forkthread(DlgUpdateSilent, param);
+ else
+ hwndDialog = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_UPDATE), GetDesktopWindow(), DlgUpdate, (LPARAM)param);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// building file list in the separate thread
+
+struct
+{
+ TCHAR *oldName, *newName;
+}
+static renameTable[] =
+{
+ { _T("svc_dbepp.dll"), _T("Plugins\\dbeditorpp.dll") },
+ { _T("svc_crshdmp.dll"), _T("Plugins\\crashdumper.dll") },
+ { _T("svc_vi.dll"), _T("Plugins\\versioninfo.dll") },
+ { _T("crashrpt.dll"), _T("Plugins\\crashdumper.dll") },
+ { _T("advsplashscreen.dll"), _T("Plugins\\splashscreen.dll") },
+ { _T("import_sa.dll"), _T("Plugins\\import.dll") },
+ { _T("newnr.dll"), _T("Plugins\\notesreminders.dll") },
+ { _T("dbtool.exe"), _T("Plugins\\dbchecker.dll") },
+ { _T("dbtool_sa.exe"), _T("Plugins\\dbchecker.dll") },
+ { _T("bclist.dll"), _T("Plugins\\clist_blind.dll") },
+ { _T("otr.dll"), _T("Plugins\\mirotr.dll") },
+ { _T("ttnotify.dll"), _T("Plugins\\tooltipnotify.dll") },
+ { _T("newstatusnotify.dll"), _T("Plugins\\newxstatusnotify.dll") },
+ { _T("rss.dll"), _T("Plugins\\newsaggregator.dll") },
+ { _T("dbx_3x.dll"), _T("Plugins\\dbx_mmap.dll") },
+
+ #if MIRANDA_VER >= 0x0A00
+ { _T("dbx_mmap_sa.dll"), _T("Plugins\\dbx_mmap.dll") },
+ { _T("dbx_tree.dll"), _T("Plugins\\dbx_mmap.dll") },
+ { _T("rc4.dll"), NULL },
+ { _T("athena.dll"), NULL },
+ #endif
+
+ { _T("proto_newsaggr.dll"), _T("Icons\\proto_newsaggregator.dll") },
+ { _T("clienticons_*.dll"), _T("Icons\\fp_icons.dll") },
+ { _T("fp_*.dll"), _T("Icons\\fp_icons.dll") },
+
+ { _T("langpack_*.txt"), _T("Languages\\*") },
+
+ { _T("clist_classic.dll"), NULL },
+ { _T("chat.dll"), NULL },
+ { _T("gender.dll"), NULL },
+ { _T("srmm.dll"), NULL },
+ { _T("extraicons.dll"), NULL },
+ { _T("langman.dll"), NULL },
+ { _T("metacontacts.dll"), NULL },
+};
+
+static bool CheckFileRename(const TCHAR *ptszOldName, TCHAR *pNewName)
+{
+ for (int i = 0; i < SIZEOF(renameTable); i++) {
+ if (!wildcmpit(ptszOldName, renameTable[i].oldName))
+ continue;
+
+ TCHAR *ptszDest = renameTable[i].newName;
+ if (ptszDest == NULL)
+ *pNewName = 0;
+ else {
+ _tcsncpy_s(pNewName, MAX_PATH, ptszDest, _TRUNCATE);
+ size_t cbLen = _tcslen(ptszDest) - 1;
+ if (pNewName[cbLen] == '*')
+ _tcsncpy_s(pNewName + cbLen, MAX_PATH - cbLen, ptszOldName, _TRUNCATE);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static bool isValidExtension(const TCHAR *ptszFileName)
+{
+ const TCHAR *pExt = _tcsrchr(ptszFileName, '.');
+
+ return (pExt != NULL) && (!_tcsicmp(pExt, _T(".dll")) || !_tcsicmp(pExt, _T(".exe")) || !_tcsicmp(pExt, _T(".txt")));
+}
+
+static int ScanFolder(const TCHAR *tszFolder, size_t cbBaseLen, int level, const TCHAR *tszBaseUrl, SERVLIST& hashes, OBJLIST<FILEINFO> *UpdateFiles)
+{
+ int count = 0;
+
+ // skip updater's own folder
+ if (!_tcsicmp(tszFolder, tszRoot))
+ return count;
+
+ TCHAR tszBuf[MAX_PATH];
+ mir_sntprintf(tszBuf, SIZEOF(tszBuf), _T("%s\\*"), tszFolder);
+
+ WIN32_FIND_DATA ffd;
+ HANDLE hFind = FindFirstFile(tszBuf, &ffd);
+ if (hFind == INVALID_HANDLE_VALUE)
+ return count;
+
+ do {
+ if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ if (_tcscmp(ffd.cFileName, _T(".")) && _tcscmp(ffd.cFileName, _T(".."))) {
+ // we need to skip profile folder
+ TCHAR tszProfilePath[MAX_PATH];
+ CallService(MS_DB_GETPROFILEPATHT, SIZEOF(tszProfilePath), (LPARAM)tszProfilePath);
+
+ mir_sntprintf(tszBuf, SIZEOF(tszBuf), _T("%s\\%s"), tszFolder, ffd.cFileName);
+ if (0 != _tcsicmp(tszBuf, tszProfilePath))
+ count += ScanFolder(tszBuf, cbBaseLen, level+1, tszBaseUrl, hashes, UpdateFiles);
+ }
+ }
+ else if (isValidExtension(ffd.cFileName)) {
+ // calculate the current file's relative name and store it into tszNewName
+ TCHAR tszNewName[MAX_PATH];
+ if (!CheckFileRename(ffd.cFileName, tszNewName)) {
+ if (level == 0)
+ _tcsncpy(tszNewName, ffd.cFileName, MAX_PATH);
+ else
+ mir_sntprintf(tszNewName, SIZEOF(tszNewName), _T("%s\\%s"), tszFolder+cbBaseLen, ffd.cFileName);
+ }
+
+ bool bHasNewVersion = true;
+ TCHAR *ptszUrl;
+ int MyCRC = 0;
+ mir_sntprintf(tszBuf, SIZEOF(tszBuf), _T("%s\\%s"), tszFolder, ffd.cFileName);
+
+ // this file is not marked for deletion
+ if (tszNewName[0]) {
+ TCHAR *pName = tszNewName;
+ ServListEntry *item = hashes.find((ServListEntry*)&pName);
+ if (item == NULL) {
+ TCHAR *p = _tcsrchr(tszNewName, '.');
+ if (p[-1] != 'w' && p[-1] != 'W')
+ continue;
+
+ int iPos = int(p - tszNewName)-1;
+ strdel(p-1, 1);
+ if ((item = hashes.find((ServListEntry*)&pName)) == NULL)
+ continue;
+
+ strdel(tszNewName+iPos, 1);
+ }
+
+ ptszUrl = item->m_name;
+ // No need to hash a file if we are forcing a redownload anyway
+ if (!opts.bForceRedownload) {
+ // try to hash the file
+ char szMyHash[33];
+ __try {
+ CalculateModuleHash(tszBuf, szMyHash);
+ bHasNewVersion = strcmp(szMyHash, item->m_szHash) != 0;
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER) {
+ ZeroMemory(szMyHash, 0);
+ // smth went wrong, reload a file from scratch
+ }
+ }
+
+ MyCRC = item->m_crc;
+ }
+ else // file was marked for deletion, add it to the list anyway
+ ptszUrl = _T("");
+
+ // Compare versions
+ if (bHasNewVersion) { // Yeah, we've got new version.
+ FILEINFO *FileInfo = new FILEINFO;
+ _tcscpy(FileInfo->tszOldName, tszBuf+cbBaseLen); // copy the relative old name
+ if (tszNewName[0] == 0) {
+ FileInfo->bDeleteOnly = TRUE;
+ _tcscpy(FileInfo->tszNewName, tszBuf); // save the full old name for deletion
+ }
+ else {
+ FileInfo->bDeleteOnly = FALSE;
+ _tcsncpy(FileInfo->tszNewName, ptszUrl, SIZEOF(FileInfo->tszNewName));
+ }
+
+ _tcscpy(tszBuf, ptszUrl);
+ TCHAR *p = _tcsrchr(tszBuf, '.');
+ if (p) *p = 0;
+ p = _tcsrchr(tszBuf, '\\');
+ p = (p) ? p+1 : tszBuf;
+ _tcslwr(p);
+
+ mir_sntprintf(FileInfo->File.tszDiskPath, SIZEOF(FileInfo->File.tszDiskPath), _T("%s\\Temp\\%s.zip"), tszRoot, p);
+ 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);
+
+ if (!opts.bSilent || db_get_b(NULL, MODNAME "Files", StrToLower(_T2A(FileInfo->tszNewName)), true))
+ count++;
+ } // end compare versions
+ }
+ }
+ while (FindNextFile(hFind, &ffd) != 0);
+
+ FindClose(hFind);
+ return count;
+}
+
+static void CheckUpdates(void *)
+{
+ char szKey[64] = {0};
+
+ TCHAR tszTempPath[MAX_PATH];
+ DWORD dwLen = GetTempPath(SIZEOF(tszTempPath), tszTempPath);
+ if (tszTempPath[dwLen-1] == '\\')
+ tszTempPath[dwLen-1] = 0;
+
+ ptrT updateUrl(GetDefaultUrl()), baseUrl;
+
+ SERVLIST hashes(50, CompareHashes);
+ bool success = ParseHashes(updateUrl, baseUrl, hashes);
+ if (success) {
+ FILELIST *UpdateFiles = new FILELIST(20);
+ VARST dirname( _T("%miranda_path%"));
+ int count = ScanFolder(dirname, lstrlen(dirname)+1, 0, baseUrl, hashes, UpdateFiles);
+
+ // Show dialog
+ if (count == 0) {
+ if (!opts.bSilent)
+ ShowPopup(0, LPGENT("Plugin Updater"), LPGENT("No updates found."), 2, 0);
+ delete UpdateFiles;
+ opts.bSilent = true;
+ }
+ else CallFunctionAsync(LaunchDialog, UpdateFiles);
+ }
+ else opts.bSilent = true;
+
+ mir_forkthread(InitTimer, (void*)(success ? 0 : 2));
+
+ hashes.destroy();
+ hCheckThread = NULL;
+}
+
+void DoCheck()
+{
+ if (hCheckThread)
+ ShowPopup(0, LPGENT("Plugin Updater"), LPGENT("Update checking already started!"), 2, 0);
+ else if (hwndDialog) {
+ ShowWindow(hwndDialog, SW_SHOW);
+ SetForegroundWindow(hwndDialog);
+ SetFocus(hwndDialog);
+ } else {
+ #if MIRANDA_VER >= 0x0A00
+ db_set_dw(NULL, MODNAME, "LastUpdate", time(NULL));
+ #endif
+ hCheckThread = mir_forkthread(CheckUpdates, 0);
+ }
+}
+
+void UninitCheck()
+{
+ if (hwndDialog != NULL)
+ DestroyWindow(hwndDialog);
+}
+
+INT_PTR MenuCommand(WPARAM,LPARAM)
+{
+ opts.bSilent = false;
+ DoCheck();
+ return 0;
+}
+
+void InitCheck()
+{
+ CreateServiceFunction(MODNAME"/CheckUpdates", MenuCommand);
+}
+
+void UnloadCheck()
+{
+ if (hCheckThread)
+ hCheckThread = NULL;
} \ No newline at end of file