#include "common.h" #include "services.h" UpdateList update_list; CRITICAL_SECTION list_cs; DWORD daily_timer_id = 0, startup_timer_id = 0; HANDLE hMainMenuItem, hGroupMenuItem; HANDLE hStartupDone = 0; bool checking = false; HANDLE hUpdateThread = 0; #define NUM_SERVICES 13 HANDLE hService[NUM_SERVICES] = {0}; VOID CALLBACK CheckTimerProcDaily(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { if(options.check_daily) CallService(MS_UPDATE_CHECKFORUPDATES, (WPARAM)(is_idle && options.no_conf_idle), 0); } // returns true if any downloaded dll is active bool DownloadUpdates(UpdateList *todo, FilenameMap *map, bool dlls_only) { bool dll_enabled_or_langpack = false; bool use_popup = options.popup_notify && ArePopupsEnabled(); // iterate through the updates we need to check if(use_popup) { ShowPopup(0, TranslateT("Downloading Updates"), _T(""), POPFLAG_SAVEHWND, -1); } else { CreateProgressWindow(); PostMessage(hwndProgress, WM_SETTEXT, 0, (LPARAM)TranslateT("Progress - Downloading updates...")); PostMessage(hwndProgress, WMU_SETMESSAGE, (WPARAM)TranslateT("Downloading"), 0); } int count = todo->size(), index = 0; TCHAR msg[512]; TCHAR *temp_str; bool a_download_succeeded = false; for(todo->reset(); todo->current(); todo->next(), index++) { // remember if the user has decided not to install this version char stored_setting[256]; mir_snprintf(stored_setting, 256, "DisabledVer%s", todo->current()->update.szComponentName); DBVARIANT dbv; bool download = todo->current()->update_options.enabled; if(!DBGetContactSetting(0, "Updater", stored_setting, &dbv)) { if(dbv.pszVal && strcmp(dbv.pszVal, todo->current()->newVersion) == 0) download = false; else DBDeleteContactSetting(0, "Updater", stored_setting); DBFreeVariant(&dbv); } if(download) { _stprintf(msg, TranslateT("Downloading plugin: %s"), TranslateTS(temp_str = GetTString(todo->current()->update.szComponentName))); free(temp_str); } else { _stprintf(msg, TranslateT("Skipping plugin: %s"), TranslateTS(temp_str = GetTString(todo->current()->update.szComponentName))); free(temp_str); } if(!use_popup) { PostMessage(hwndProgress, WMU_SETMESSAGE, (WPARAM)msg, 0); PostMessage(hwndProgress, WMU_SETPROGRESS, (WPARAM)(int)(index * 100.0 / count), 0); } //else if(hwndPop) // disabled - just annoying //ChangePopupText(hwndPop, msg); if(download) { bool got_file = false; if(todo->current()->update_options.use_beta) { // download from i->update.szBetaUpdateURL to temp folder got_file = GetFile(todo->current()->update.szBetaUpdateURL, options.temp_folder, todo->current()->update.szComponentName, todo->current()->newVersion, dlls_only); } else { got_file = GetFile(todo->current()->update.szUpdateURL, options.temp_folder, todo->current()->update.szComponentName, todo->current()->newVersion, dlls_only); } if(got_file) { a_download_succeeded = true; if(todo->current()->file_id != -1) { if(todo->current()->cat == MC_PLUGINS) dll_enabled_or_langpack |= RearrangeDlls(todo->current()->shortName, (*map)[todo->current()->file_id]); else if(todo->current()->cat == MC_LOCALIZATION) { RearrangeLangpacks(todo->current()->shortName, (*map)[todo->current()->file_id]); dll_enabled_or_langpack = true; } } else { dll_enabled_or_langpack = true; } } } if(use_popup == false && hwndProgress == 0) { RemoveFolder(options.temp_folder); break; // user closed progress window - cancel } } if(!use_popup && hwndProgress) ProgressWindowDone(); // postmessage here causes a lockup on exit! bah popups!! //if(hwndPop) PostMessage(hwndPop, WMU_CLOSEPOP, 0, 0); if(hwndPop) SendMessage(hwndPop, WMU_CLOSEPOP, 0, 0); if(!a_download_succeeded) { for(todo->reset(); todo->current(); todo->next()) free(todo->current()->newVersion); todo->clear(); } return dll_enabled_or_langpack; } void __stdcall sttNotifyStartup( ULONG dwParam ) { NotifyEventHooks(hStartupDone, 0, 0); } void RestoreStatus() { //NotifyEventHooks(hStartupDone, 0, 0); // do this in a seperate thread, in case we're called from an event hook to prevent double-lock on core hook critical section (csHooks) QueueUserAPC(sttNotifyStartup, mainThread, 0); if(options.start_offline) { // restore global status - only works on startup since we remove the SavedGlobalStatus parameter WORD clist_status = DBGetContactSettingWord(0, "CList", "Status", ID_STATUS_OFFLINE), saved_global_status = DBGetContactSettingWord(0, MODULE, "SavedGlobalStatus", clist_status); if(clist_status == ID_STATUS_OFFLINE && saved_global_status != clist_status) { #ifdef DEBUG_POPUPS PUShowMessage("Updater: restoring status", SM_NOTIFY); #endif CallService(MS_CLIST_SETSTATUSMODE, (WPARAM)saved_global_status, 0); } } DBDeleteContactSetting(0, MODULE, "SavedGlobalStatus"); } bool WriteLastCheckTime() { SYSTEMTIME now; GetSystemTime(&now); DBWriteContactSettingWord(0, MODULE, "LastUpdateDay", now.wDay); DBWriteContactSettingWord(0, MODULE, "LastUpdateMonth", now.wMonth); DBWriteContactSettingWord(0, MODULE, "LastUpdateYear", now.wYear); return true; } //DWORD CALLBACK CheckForUpdatesWorker(LPVOID param) { unsigned int CALLBACK CheckForUpdatesWorker(void *param) { if(checking) return 1; if(!(GetSystemMetrics(SM_NETWORK) & 1)) { ShowError(TranslateT("No network - aborting update check")); NLog("worker thread aborting - no network"); return 1; // no network } NLog("CheckForUpdatesWorker thread starting"); checking = true; WriteLastCheckTime(); bool confirm = !(((DWORD)param & 1) == 1); bool restart = !(((DWORD)param & 2) == 2); // if restart is false, then we're doing an 'update and shutdown' if(hwndOptions) PostMessage(hwndOptions, WMU_CHECKING, 0, 0); bool use_popup = options.popup_notify && ArePopupsEnabled(); FilenameMap fn_map; if(use_popup) { ShowPopup(0, TranslateT("Checking for Updates"), _T(""), POPFLAG_SAVEHWND, -1); } else { CreateProgressWindow(); PostMessage(hwndProgress, WM_SETTEXT, 0, (LPARAM)TranslateT("Progress - Checking for updates...")); if(options.use_xml_backend) PostMessage(hwndProgress, WMU_SETMESSAGE, (WPARAM)TranslateT("Downloading XML data"), 0); else PostMessage(hwndProgress, WMU_SETMESSAGE, (WPARAM)TranslateT("Checking for updates"), 0); } EnterCriticalSection(&list_cs); if(options.use_xml_backend) { if(UpdateXMLData(MC_PLUGINS)) {// prevent double error messages (in some cases) // iterate through the registered plugins if(!use_popup) PostMessage(hwndProgress, WMU_SETMESSAGE, (WPARAM)TranslateT("Scanning plugins folder"), 0); ScanPlugins(&fn_map, &update_list); if(UpdateXMLData(MC_LOCALIZATION)) { if(!use_popup) PostMessage(hwndProgress, WMU_SETMESSAGE, (WPARAM)TranslateT("Scanning language packs"), 0); ScanLangpacks(&fn_map, &update_list); } if(!use_popup) PostMessage(hwndProgress, WMU_SETMESSAGE, (WPARAM)TranslateT("Updating component file listing ids"), 0); UpdateFLIDs(update_list); } if(!use_popup) PostMessage(hwndProgress, WMU_SETMESSAGE, (WPARAM)TranslateT("Checking for updates"), 0); } UpdateList update_list2(update_list); LeaveCriticalSection(&list_cs); int count = update_list2.size(), index = 0; TCHAR msg[512]; TCHAR *temp_str; UpdateList todo; for(update_list2.reset(); update_list2.current(); update_list2.next(), index++) { if(update_list2.current()->update_options.enabled) { _stprintf(msg, TranslateT("Checking plugin: %s"), TranslateTS(temp_str = GetTString(update_list2.current()->update.szComponentName))); free(temp_str); } else { _stprintf(msg, TranslateT("Skipping plugin: %s"), TranslateTS(temp_str = GetTString(update_list2.current()->update.szComponentName))); free(temp_str); } if(!use_popup) { PostMessage(hwndProgress, WMU_SETMESSAGE, (WPARAM)msg, 0); PostMessage(hwndProgress, WMU_SETPROGRESS, (WPARAM)(int)(index * 100.0 / count), 0); } //else if(hwndPop) // disabled - just annoying //ChangePopupText(hwndPop, msg); if(update_list2.current()->update_options.enabled) { char *nv; bool beta; if(nv = UpdateRequired(update_list2.current(), &beta)) { todo.push_back(*update_list2.current()); todo.back().newVersion = nv; todo.back().update_options.use_beta = beta; } } if(use_popup == false && hwndProgress == 0) { RemoveFolder(options.temp_folder); break; // user closed progress window - cancel } } if(!use_popup && hwndProgress) ProgressWindowDone(); if(hwndPop) PostMessage(hwndPop, WMU_CLOSEPOP, 0, 0); if(options.use_xml_backend) { FreeXMLData(MC_PLUGINS); FreeXMLData(MC_LOCALIZATION); } bool restore_status = true; if(todo.size()) { int cd_ret = CD_OK; if(confirm) { if(use_popup) { ShowPopup(0, TranslateT("Updates Available"), TranslateT("Click here to install"), POPFLAG_SAVEHWND, -1); DWORD ret; while((ret = WaitForSingleObject(hEventPop, 200)) == WAIT_TIMEOUT && !Miranda_Terminated()); if(!pop_cancelled && ret == WAIT_OBJECT_0 && !Miranda_Terminated()) { cd_ret = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_CONFIRMUPDATES), GetDesktopWindow(), DlgProcConfirm, (LPARAM)&todo); } else { if(hwndOptions) PostMessage(hwndOptions, WMU_DONECHECKING, 0, 0); RestoreStatus(); for(todo.reset(); todo.current(); todo.next()) free(todo.current()->newVersion); checking = false; return 1; } } else cd_ret = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_CONFIRMUPDATES), GetDesktopWindow(), DlgProcConfirm, (LPARAM)&todo); } if(!confirm || cd_ret == CD_CONFALL || cd_ret == CD_NOINSTALL || cd_ret == CD_OK) { bool conf_all = (cd_ret == CD_CONFALL), no_install = (cd_ret == CD_NOINSTALL); // ensure the backup folder exists (either create it or return non-zero signifying error) if(options.backup && !CreatePath(options.backup_folder)) { //MessageBox(0, Translate("Could not create backup folder"), Translate("Error"), MB_OK | MB_ICONERROR); ShowError(TranslateT("Could not create backup folder")); if(hwndOptions) PostMessage(hwndOptions, WMU_DONECHECKING, 0, 0); RestoreStatus(); for(todo.reset(); todo.current(); todo.next()) free(todo.current()->newVersion); checking = false; return 1; } bool dll_enabled_or_langpack = DownloadUpdates(&todo, &fn_map, confirm ? false : options.auto_dll_only); if(todo.size() && !no_install) { if(!conf_all || DialogBox(hInst, MAKEINTRESOURCE(IDD_CONFIRMCOMPONENTS), GetDesktopWindow(), DlgProcConfirmComponents) == IDOK) { if(!dll_enabled_or_langpack && restart) { // we're not doing an 'update and shutdown', and we're not updating any active dlls...so just install // get folders TCHAR root_folder[MAX_PATH], plugins_folder[MAX_PATH], *p; GetModuleFileName(0, root_folder, MAX_PATH); _tcscpy(plugins_folder, root_folder); p = _tcsrchr(plugins_folder, '\\'); if(p) *p = 0; _tcscat(plugins_folder, _T("\\Plugins")); p = _tcsrchr(root_folder, _T('\\')); if(p) *p = 0; // move files MoveFiles(0, options.temp_folder, plugins_folder, options.backup_folder, root_folder); // rescan to get correct version numbers ScanPlugins(0, 0); } else { if(ExternProcess(restart) == 0) // if restarting, don't restore status restore_status = false; } } } } for(todo.reset(); todo.current(); todo.next()) free(todo.current()->newVersion); } else if(!restart) { HWND hWndMiranda = (HWND)CallService(MS_CLUI_GETHWND, 0, 0); PostMessage(hWndMiranda, WM_COMMAND, ID_ICQ_EXIT, 0); } if(restore_status && restart) { // restore status if we're not doing an 'update and shutdown', and the update was unsuccessful (or there was nothing to update, or no need to shutdown) checking = false; if(hwndOptions) PostMessage(hwndOptions, WMU_DONECHECKING, 0, 0); RestoreStatus(); } return 0; } int Restart(WPARAM wParam, LPARAM lParam) { ExternProcess(true); return 0; } int UpdateAndExit(WPARAM wParam, LPARAM lParam) { return CallService(MS_UPDATE_CHECKFORUPDATES, 0, 1); } // if wParam, don't confirm // if lParam, install and shutdown but don't restart int CheckForUpdates(WPARAM wParam, LPARAM lParam) { if(daily_timer_id) KillTimer(0, daily_timer_id); daily_timer_id = SetTimer(0, 0, 24 * 60 * 60 * 1000, CheckTimerProcDaily); DWORD param = ((wParam ? 1 : 0) | (lParam ? 2 : 0)); if(hUpdateThread) CloseHandle(hUpdateThread); //hUpdateThread = CreateThread(0, 0, CheckForUpdatesWorker, (void *)param, 0, 0); hUpdateThread = (HANDLE)_beginthreadex(0, 0, CheckForUpdatesWorker, (void *)param, 0, 0); NLog("CheckForUpdates service called"); return 0; } int EnumerateUpdates(WPARAM wParam, LPARAM lParam) { UpdateEnumerateFunc func = (UpdateEnumerateFunc)wParam; EnterCriticalSection(&list_cs); for(update_list.reset(); update_list.current(); update_list.next()) { func(update_list.current()->update.szComponentName, &(update_list.current()->update_options), lParam); } LeaveCriticalSection(&list_cs); return 0; } void LoadUpdateOptions(char *szComponentName, UpdateOptions *update_options) { char buff[256]; sprintf(buff, "Enable%s", szComponentName); update_options->enabled = (DBGetContactSettingByte(0, MODULE, buff, 1) == 1); if(!update_options->fixed) { sprintf(buff, "UseBeta%s", szComponentName); update_options->use_beta = (DBGetContactSettingByte(0, MODULE, buff, 0) == 1); } } void SaveUpdateOptions(char *szComponentName, UpdateOptions *update_options) { char buff[256]; sprintf(buff, "Enable%s", szComponentName); DBWriteContactSettingByte(0, MODULE, buff, update_options->enabled ? 1 : 0); if(!update_options->fixed) { sprintf(buff, "UseBeta%s", szComponentName); DBWriteContactSettingByte(0, MODULE, buff, update_options->use_beta ? 1 : 0); } } int SetUpdateOptions(WPARAM wParam, LPARAM lParam) { char *szComponentName = (char *)wParam; UpdateOptions *uo = (UpdateOptions *)lParam; TCHAR *temp1 = 0, *temp2 = 0; bool found = false; EnterCriticalSection(&list_cs); for(update_list.reset(); update_list.current(); update_list.next()) { if(strcmp(update_list.current()->update.szComponentName, szComponentName) == 0 || _tcscmp(TranslateTS(temp1 = GetTString(update_list.current()->update.szComponentName)), (TCHAR *)szComponentName) == 0) // when set via options, szComponentName is translated and potentially already converted to unicode { found = true; update_list.current()->update_options = *uo; SaveUpdateOptions(update_list.current()->update.szComponentName, &update_list.current()->update_options); if(update_list.current()->file_id == -1 && !uo->use_beta) { update_list.current()->file_id = CheckForFileID(update_list.current()->update.szUpdateURL, update_list.current()->update.szVersionURL, update_list.current()->update.szComponentName); } break; } } LeaveCriticalSection(&list_cs); if(temp1) free(temp1); if(temp2) free(temp2); return found ? 0 : 1; } int GetUpdateOptions(WPARAM wParam, LPARAM lParam) { char *szComponentName = (char *)wParam; UpdateOptions *uo = (UpdateOptions *)lParam; TCHAR *temp1 = 0, *temp2 = 0; bool found = false; EnterCriticalSection(&list_cs); for(update_list.reset(); update_list.current(); update_list.next()) { if(strcmp(update_list.current()->update.szComponentName, szComponentName) == 0 || _tcscmp(TranslateTS(temp1 = GetTString(update_list.current()->update.szComponentName)), (TCHAR *)szComponentName) == 0) // when set via options, szComponentName is translated and potentially already converted to unicode { found = true; *uo = update_list.current()->update_options; break; } } LeaveCriticalSection(&list_cs); if(temp1) free(temp1); if(temp2) free(temp2); return found ? 0 : 1; } bool RegisterForFileListing(int file_id, PLUGININFO *pluginInfo, bool auto_register) { return RegisterForFileListing(file_id, pluginInfo->shortName, pluginInfo->version, auto_register, MC_PLUGINS); } bool IsRegistered(int file_id) { EnterCriticalSection(&list_cs); for(update_list.reset(); update_list.current(); update_list.next()) { if(update_list.current()->file_id == file_id) { LeaveCriticalSection(&list_cs); return true; // plugin already registered } } LeaveCriticalSection(&list_cs); return false; } bool RegisterForFileListing(int file_id, const char *fl_name, DWORD version, bool auto_register, const Category cat) { // allow multiple registration of same plugin only if new plugin not automatically registered // if multiple registration of an auto registered plugin occurs, use newest file id and version EnterCriticalSection(&list_cs); for(update_list.reset(); update_list.current(); update_list.next()) { if(strcmp(update_list.current()->update.szComponentName, fl_name) == 0) { if(!auto_register) { update_list.erase(); break; } if(update_list.current()->auto_register) { update_list.current()->file_id = file_id; // in case plugin file id changes (i.e. scan from xml data will overwrite settings read from db on startup) char version_str[16]; update_list.current()->update.pbVersion = (BYTE *)safe_strdup(CreateVersionString(version, version_str)); update_list.current()->update.cpbVersion = strlen(version_str); } LeaveCriticalSection(&list_cs); // plugin already registered - set file id if AUTOREGISTER if(update_list.current()->update.szUpdateURL && strcmp(update_list.current()->update.szUpdateURL, UPDATER_AUTOREGISTER) == 0) { update_list.current()->file_id = file_id; char *buff = (char *)safe_alloc(strlen(MIM_DOWNLOAD_URL_PREFIX) + 9); sprintf(buff, MIM_DOWNLOAD_URL_PREFIX "%d", file_id); update_list.current()->update.szUpdateURL = buff; update_list.current()->shortName = safe_strdup(update_list.current()->update.szComponentName); if(update_list.current()->update.szBetaVersionURL) { update_list.current()->update_options.fixed = false; LoadUpdateOptions(update_list.current()->update.szComponentName, &update_list.current()->update_options); } } return false; } } LeaveCriticalSection(&list_cs); UpdateInternal update_internal = {0}; char version_str[16]; char *buff; update_internal.cat = cat; update_internal.shortName = safe_strdup(fl_name); update_internal.update.szComponentName = safe_strdup(fl_name); update_internal.update.pbVersion = (BYTE *)safe_strdup(CreateVersionString(version, version_str)); update_internal.update.cpbVersion = strlen(version_str); buff = (char *)safe_alloc(strlen(MIM_DOWNLOAD_URL_PREFIX) + 9); sprintf(buff, MIM_DOWNLOAD_URL_PREFIX "%d", file_id); update_internal.update.szUpdateURL = buff; ///////// only used when not using the xml backend //////////// buff = (char *)safe_alloc(strlen("class=\"fileNameHeader\">") + strlen(fl_name) + 2); sprintf(buff, "class=\"fileNameHeader\">%s ", fl_name); update_internal.update.pbVersionPrefix = (BYTE *)buff; update_internal.update.cpbVersionPrefix = strlen(buff); buff = (char *)safe_alloc(strlen(MIM_VIEW_URL_PREFIX) + 9); sprintf(buff, MIM_VIEW_URL_PREFIX "%d", file_id); update_internal.update.szVersionURL = buff; /////////////////////////////////////////////////////////////// // same as register, except for fileID update_internal.file_id = file_id; update_internal.auto_register = auto_register; update_internal.update_options.fixed = true; update_internal.update_options.use_beta = false; LoadUpdateOptions(update_internal.update.szComponentName, &update_internal.update_options); EnterCriticalSection(&list_cs); update_list.push_back(update_internal); LeaveCriticalSection(&list_cs); return true; } void DoStartupProcess() { if(checking) return; if(OldXMLDataExists(MC_PLUGINS) && OldXMLDataExists(MC_LOCALIZATION)) { if(options.check_on_startup) { SYSTEMTIME now; GetSystemTime(&now); if(options.check_once) { if(DBGetContactSettingWord(0, MODULE, "LastUpdateDay", 32) == 32) { CallService(MS_UPDATE_CHECKFORUPDATES, 0, 0); } else { if(now.wDay != DBGetContactSettingWord(0, MODULE, "LastUpdateDay", now.wDay) || now.wMonth != DBGetContactSettingWord(0, MODULE, "LastUpdateMonth", now.wMonth) || now.wYear != DBGetContactSettingWord(0, MODULE, "LastUpdateYear", now.wYear)) { CallService(MS_UPDATE_CHECKFORUPDATES, 0, 0); } else { if(LoadOldXMLData(MC_PLUGINS, false)) { ScanPlugins(0, 0); FreeXMLData(MC_PLUGINS); } if(LoadOldXMLData(MC_LOCALIZATION, false)) { ScanLangpacks(0, 0); FreeXMLData(MC_LOCALIZATION); } RestoreStatus(); } } } else { CallService(MS_UPDATE_CHECKFORUPDATES, 0, 0); } } else { if(LoadOldXMLData(MC_PLUGINS, false)) { ScanPlugins(0, 0); FreeXMLData(MC_PLUGINS); } if(LoadOldXMLData(MC_LOCALIZATION, false)) { ScanLangpacks(0, 0); FreeXMLData(MC_LOCALIZATION); } RestoreStatus(); } } else { if(options.check_on_startup) CallService(MS_UPDATE_CHECKFORUPDATES, 0, 0); else RestoreStatus(); } } int Register(WPARAM wParam, LPARAM lParam) { Update *update = (Update *)lParam; UpdateInternal update_internal = {0}; // remove registered plugin if already there EnterCriticalSection(&list_cs); for(update_list.reset(); update_list.current(); update_list.next()) { if(strcmp(update_list.current()->update.szComponentName, update->szComponentName) == 0) { update_list.erase(); break; } } LeaveCriticalSection(&list_cs); if(update->szComponentName == 0 || update->pbVersion == 0) return 1; if(update->szVersionURL == 0 && (update->szUpdateURL == 0 || strcmp(update->szUpdateURL, UPDATER_AUTOREGISTER) != 0) && update->szBetaVersionURL == 0) // both betas and normal updates disabled - complain return 1; update_internal.cat = MC_UNKNOWN; // duplicate all the data...sigh update_internal.update.szComponentName = safe_strdup(update->szComponentName); if(update->szVersionURL) update_internal.update.szVersionURL = safe_strdup(update->szVersionURL); if(update->szUpdateURL) update_internal.update.szUpdateURL = safe_strdup(update->szUpdateURL); // if revision update url is from the fl, and we can find the file_id, use xml data if available // otherwise set this to -1 to check url's specified if(update_internal.update.szUpdateURL) update_internal.file_id = CheckForFileID(update_internal.update.szUpdateURL, update_internal.update.szVersionURL, update_internal.update.szComponentName); else update_internal.file_id = -1; if(update_internal.file_id != -1) { // ensure correct format for file listing version string search data char *buff = (char *)safe_alloc(strlen("class=\"fileNameHeader\">") + strlen(update->szComponentName) + 2); sprintf(buff, "class=\"fileNameHeader\">%s ", update->szComponentName); update_internal.update.pbVersionPrefix = (BYTE *)buff; update_internal.update.cpbVersionPrefix = strlen(buff); update_internal.shortName = safe_strdup(update->szComponentName); } else { if(update->pbVersionPrefix) update_internal.update.pbVersionPrefix = safe_bytedup(update->pbVersionPrefix, update->cpbVersionPrefix); update_internal.update.cpbVersionPrefix = update->cpbVersionPrefix; } // leave beta alone if(update->szBetaVersionURL) update_internal.update.szBetaVersionURL = safe_strdup(update->szBetaVersionURL); if(update->pbBetaVersionPrefix) update_internal.update.pbBetaVersionPrefix = safe_bytedup(update->pbBetaVersionPrefix, update->cpbBetaVersionPrefix); update_internal.update.cpbBetaVersionPrefix = update->cpbBetaVersionPrefix; if(update->szBetaUpdateURL) update_internal.update.szBetaUpdateURL = safe_strdup(update->szBetaUpdateURL); update_internal.update.pbVersion = safe_bytedup(update->pbVersion, update->cpbVersion); update_internal.update.cpbVersion = update->cpbVersion; if(update->cbSize > UPDATE_V1_SIZE && update->szBetaChangelogURL) update_internal.update.szBetaChangelogURL = safe_strdup(update->szBetaChangelogURL); update_internal.update_options.fixed = (update->szVersionURL == 0 || strcmp(update->szUpdateURL, UPDATER_AUTOREGISTER) == 0 || update->szBetaVersionURL == 0); // set 'fixed' flag update_internal.update_options.use_beta = (update->szVersionURL == 0 || strcmp(update->szUpdateURL, UPDATER_AUTOREGISTER) == 0); LoadUpdateOptions(update_internal.update.szComponentName, &update_internal.update_options); EnterCriticalSection(&list_cs); update_list.push_back(update_internal); LeaveCriticalSection(&list_cs); //if(strcmp(update_internal.update.szComponentName, "My Details") == 0) { // MessageBox(0, "My Details registered", "msg", MB_OK); //} return 0; } int RegisterFL(WPARAM wParam, LPARAM lParam) { int file_id = (int)wParam; PLUGININFO *pluginInfo = (PLUGININFO *)lParam; // remove registered plugin if already there EnterCriticalSection(&list_cs); for(update_list.reset(); update_list.current(); update_list.next()) { if(strcmp(update_list.current()->update.szComponentName, pluginInfo->shortName) == 0) { update_list.erase(); break; } } LeaveCriticalSection(&list_cs); RegisterForFileListing(file_id, pluginInfo, false); return 0; } int Unregister(WPARAM wParam, LPARAM lParam) { char *szComponentName = (char *)lParam; // remove registered plugin if found EnterCriticalSection(&list_cs); for(update_list.reset(); update_list.current(); update_list.next()) { if(strcmp(update_list.current()->update.szComponentName, szComponentName) == 0) { update_list.erase(); break; } } LeaveCriticalSection(&list_cs); return 0; } int CheckForUpdatesTrgr(WPARAM wParam, LPARAM lParam) { if(wParam & ACT_PERFORM) { #ifdef DEBUG_POPUPS PUShowMessage("Updater: triggered check", SM_NOTIFY); #endif CallService(MS_UPDATE_CHECKFORUPDATES, (WPARAM)(is_idle && options.no_conf_idle), 0); } return 0; } int ServicesModulesLoaded2(WPARAM wParam, LPARAM lParam) { // do initial update etc. depending on options and time KillTimer(0, startup_timer_id); DoStartupProcess(); return 0; } VOID CALLBACK StartupTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { KillTimer(0, startup_timer_id); ServicesModulesLoaded2(0, 0); } HANDLE hEventServicesModulesLoaded2; int ServicesModulesLoaded(WPARAM wParam, LPARAM lParam) { // add main menu item CLISTMENUITEM menu = {0}; menu.cbSize=sizeof(menu); menu.flags = CMIM_ALL; menu.hIcon = hIconCheck; menu.pszName = Translate("Check for updates"); menu.pszService= MS_UPDATE_CHECKFORUPDATES; menu.position = 500010000; #ifdef MS_CLIST_ADDGROUPMENUITEM if (ServiceExists(MS_CLIST_ADDGROUPMENUITEM)) { GroupMenuParam gmp = {0}; hGroupMenuItem = (HANDLE)CallService(MS_CLIST_ADDGROUPMENUITEM,(WPARAM)&gmp,(LPARAM)&menu); } #endif hMainMenuItem = (HANDLE)CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&menu); hEventServicesModulesLoaded2 = HookEvent(ME_SYSTEM_MODULESLOADED, ServicesModulesLoaded2); startup_timer_id = SetTimer(0, 0, 5000, StartupTimerProc); return 0; } int EnableStatusControl(WPARAM wParam, LPARAM lParam) { BOOL enable = (BOOL)wParam; options.start_offline = (enable == TRUE); return 0; } int IsUpdateSupported(WPARAM wParam, LPARAM lParam) { char *szComponentName = (char *)lParam; EnterCriticalSection(&list_cs); for(update_list.reset(); update_list.current(); update_list.next()) { if(strcmp(update_list.current()->update.szComponentName, szComponentName) == 0) { return TRUE; } } LeaveCriticalSection(&list_cs); return FALSE; } int ServicesPreShutdown(WPARAM wParam, LPARAM lParam) { KillProgressWindowThread(); return 0; } HANDLE hEventPreShutDown, hEventServicesModulesLoaded; void InitServices() { InitAlternateShortNameMap(); InitializeCriticalSection(&list_cs); int i = 0; hService[i++] = CreateServiceFunction(MS_UPDATE_REGISTER, Register); hService[i++] = CreateServiceFunction(MS_UPDATE_REGISTERFL, RegisterFL); hService[i++] = CreateServiceFunction(MS_UPDATE_UNREGISTER, Unregister); hService[i++] = CreateServiceFunction(MS_UPDATE_CHECKFORUPDATESTRGR, CheckForUpdatesTrgr); hService[i++] = CreateServiceFunction(MS_UPDATE_CHECKFORUPDATES, CheckForUpdates); hService[i++] = CreateServiceFunction(MS_UPDATE_SETUPDATEOPTIONS, SetUpdateOptions); hService[i++] = CreateServiceFunction(MS_UPDATE_GETUPDATEOPTIONS, GetUpdateOptions); hService[i++] = CreateServiceFunction(MS_UPDATE_ENUMERATE, EnumerateUpdates); hService[i++] = CreateServiceFunction(MS_UPDATE_ENABLESTATUSCONTROL, EnableStatusControl); hService[i++] = CreateServiceFunction(MS_UPDATE_MENURESTART, Restart); hService[i++] = CreateServiceFunction(MS_UPDATE_MENUUPDATEANDEXIT, UpdateAndExit); hService[i++] = CreateServiceFunction(MS_UPDATE_MENUCHECKFORUPDATES, CheckForUpdates); hService[i++] = CreateServiceFunction(MS_UPDATE_ISUPDATESUPPORTED, IsUpdateSupported); hStartupDone = CreateHookableEvent(ME_UPDATE_STARTUPDONE); hEventPreShutDown = HookEvent(ME_SYSTEM_PRESHUTDOWN, ServicesPreShutdown); daily_timer_id = SetTimer(0, 0, 24 * 60 * 60 * 1000, CheckTimerProcDaily); MakeProgressWindowThread(); hEventServicesModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ServicesModulesLoaded); } void DeinitServices() { UnhookEvent(hEventPreShutDown); UnhookEvent(hEventServicesModulesLoaded); UnhookEvent(hEventServicesModulesLoaded2); if(daily_timer_id) KillTimer(0, daily_timer_id); if(hUpdateThread) { WaitForSingleObject(hUpdateThread, INFINITE); CloseHandle(hUpdateThread); } DestroyHookableEvent(hStartupDone); for(int i = 0; i < NUM_SERVICES; i++) if(hService[i]) DestroyServiceFunction(hService[i]); DeleteCriticalSection(&list_cs); update_list.clear(); }