diff options
Diffstat (limited to 'updater/extern.cpp')
-rw-r--r-- | updater/extern.cpp | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/updater/extern.cpp b/updater/extern.cpp new file mode 100644 index 0000000..2d220df --- /dev/null +++ b/updater/extern.cpp @@ -0,0 +1,440 @@ +#include "common.h"
+#include "extern.h"
+
+// write data needed by the external process, and restart miranda
+// returns 1 if any error, 0 if shutdown is imminent
+int ExternProcess(bool restart) {
+ //HWND hWndMiranda = (HWND)CallService(MS_CLUI_GETHWND, 0, 0);
+
+ // spawn a process that will:
+ // -- wait for miranda to exit
+ // -- move downloaded plugins from the temp folder to the Plugins folder, possibly backing up old ones
+ // -- restart miranda
+
+ char msg[1024];
+ mir_snprintf(msg, 1024, "spawning external process, restart = %s", restart ? "true" : "false");
+ NLog(msg);
+
+ TCHAR data_filename[MAX_PATH];
+
+ _tcscpy(data_filename, options.data_folder);
+ _tcscat(data_filename, _T("\\ud_data.txt"));
+
+ // write data to file for external process to use
+ HANDLE hDatFile = CreateFile(data_filename, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0);
+ if(hDatFile == INVALID_HANDLE_VALUE) {
+ //MessageBox(0, Translate("Could not create data file for restart."), Translate("Error"), MB_OK | MB_ICONERROR);
+ ShowError(TranslateT("Could not create data file for restart"));
+ return 1;
+ }
+
+ TCHAR *mir_exe = (TCHAR *)malloc(MAX_PATH * sizeof(TCHAR)),
+ *plugins_folder = (TCHAR *)malloc(MAX_PATH * sizeof(TCHAR));
+ char *db_name = (char *)malloc(MAX_PATH),
+ *db_path = (char *)malloc(MAX_PATH);
+
+ // Get Miranda exe path and profile
+ CallService(MS_DB_GETPROFILENAME, MAX_PATH, (WPARAM)(char*) db_name);
+ CallService(MS_DB_GETPROFILEPATH, MAX_PATH, (WPARAM)(char*) db_path);
+ strcat(db_path, "\\");
+ strcat(db_path, db_name);
+ //lstrcpyn(db_path+lstrlen(db_path), db_name, lstrlen(db_name)-3); // Pointer arithmetic
+ //*(db_path + lstrlen(db_name) - 3) = 0;
+
+ // get plugin folder
+ GetModuleFileName(0, mir_exe, MAX_PATH);
+ _tcscpy(plugins_folder, mir_exe);
+ TCHAR *p = _tcsrchr(plugins_folder, _T('\\'));
+ if(p) *p = 0;
+ _tcscat(plugins_folder, _T("\\Plugins"));
+
+ unsigned long bytes_written;
+ char *nl = "\r\n";
+ TCHAR *tnl = _T("\r\n");
+ char buf[64];
+ WriteFile(hDatFile, mir_exe, _tcslen(mir_exe) * sizeof(TCHAR), &bytes_written, FALSE);
+ WriteFile(hDatFile, tnl, 2 * sizeof(TCHAR), &bytes_written, FALSE);
+ WriteFile(hDatFile, plugins_folder, _tcslen(plugins_folder) * sizeof(TCHAR), &bytes_written, FALSE);
+ WriteFile(hDatFile, tnl, 2 * sizeof(TCHAR), &bytes_written, FALSE);
+ WriteFile(hDatFile, db_name, strlen(db_name), &bytes_written, FALSE);
+ WriteFile(hDatFile, nl, 2, &bytes_written, FALSE);
+ WriteFile(hDatFile, db_path, strlen(db_path), &bytes_written, FALSE);
+ WriteFile(hDatFile, nl, 2, &bytes_written, FALSE);
+ WriteFile(hDatFile, options.temp_folder, _tcslen(options.temp_folder) * sizeof(TCHAR), &bytes_written, FALSE);
+ WriteFile(hDatFile, tnl, 2 * sizeof(TCHAR), &bytes_written, FALSE);
+ if(options.backup) {
+ WriteFile(hDatFile, options.backup_folder, _tcslen(options.backup_folder) * sizeof(TCHAR), &bytes_written, FALSE);
+ WriteFile(hDatFile, tnl, 2 * sizeof(TCHAR), &bytes_written, FALSE);
+ } else {
+ WriteFile(hDatFile, _T("no backups"), _tcslen(_T("no backups")) * sizeof(TCHAR), &bytes_written, FALSE);
+ WriteFile(hDatFile, tnl, 2 * sizeof(TCHAR), &bytes_written, FALSE);
+ }
+ sprintf(buf, "%d", (unsigned int)GetCurrentProcessId());
+ //MessageBox(0, buf, "Writing process id", MB_OK);
+ WriteFile(hDatFile, buf, strlen(buf), &bytes_written, FALSE);
+ WriteFile(hDatFile, nl, 2, &bytes_written, FALSE);
+
+ sprintf(buf, (restart ? "restart" : "no_restart"));
+ WriteFile(hDatFile, buf, strlen(buf), &bytes_written, FALSE);
+ WriteFile(hDatFile, nl, 2, &bytes_written, FALSE);
+
+ CloseHandle(hDatFile);
+
+ free(mir_exe);
+ free(plugins_folder);
+ free(db_name);
+ free(db_path);
+
+ /*
+ if(!CallService(MS_SYSTEM_OKTOEXIT,0,0)) {
+ DeleteFile(data_filename);
+ MessageBox(0, Translate("Miranda's not 'OK TO EXIT'."), Translate("Error"), MB_OK | MB_ICONERROR);
+ return;
+ }
+ */
+
+ TCHAR szParams[MAX_PATH], szBuf[MAX_PATH];
+
+ // try to fire up external process from new dll (if present), so we can overwrite the old one
+ _tcscpy(szBuf, options.temp_folder);
+#ifdef PLUGDIR
+ _tcscat(szBuf, _T("\\plugins\\updater.dll"));
+#else
+ _tcscat(szBuf, _T("\\updater.dll"));
+#endif
+
+ HANDLE hFile = CreateFile(szBuf, 0, 0, 0, OPEN_EXISTING, 0, 0);
+ if(hFile == INVALID_HANDLE_VALUE) {
+ // try with short path name...(for win98)
+ TCHAR szShortBuf[MAX_PATH];
+ GetShortPathName(szBuf, szShortBuf, MAX_PATH);
+ hFile = CreateFile(szShortBuf, 0, 0, 0, OPEN_EXISTING, 0, 0);
+ }
+
+ if(hFile != INVALID_HANDLE_VALUE) {
+ // new dll exists
+ CloseHandle(hFile);
+ } else {
+ // can't find new updater dll - restart using this dll
+ GetModuleFileName(hInst, szBuf, MAX_PATH);
+ }
+
+ p = _tcsrchr(szBuf, _T('\\'));
+ if(p) *p = 0;
+
+ // rundll32 hates spaces in the <dll name> arg, but quotes aren't allowed in earlier versions...
+ // GetShortPath can return paths with spaces (at least on XP with 8.3 filenames disabled)...
+ // so we must 'CreateProcess' with the updater.dll location as the startup directory and pass only updater.dll as the arg
+
+#ifdef _MSC_VER
+ // MSVC exports differently than gcc/mingw
+ _stprintf(szParams, _T("RUNDLL32.EXE .\\updater.dll,_ExternalUpdate@16 %s"), data_filename);
+#else
+ _stprintf(szParams, _T("RUNDLL32.EXE .\\updater.dll,ExternalUpdate@16 %s"), data_filename);
+#endif
+
+ PROCESS_INFORMATION pi = {0};
+ STARTUPINFO si = {0};
+ si.cb = sizeof(si);
+
+ if(!CreateProcess(0, szParams, 0, 0, 0,
+ CREATE_NO_WINDOW|DETACHED_PROCESS|NORMAL_PRIORITY_CLASS,
+ 0, szBuf, &si, &pi))
+ {
+ int err = GetLastError();
+ TCHAR msg[256];
+ _stprintf(msg, _T("Error code: %d"), err);
+ MessageBox(0, msg, TranslateT("CreateProcess"), MB_OK | MB_ICONERROR);
+
+ return 1;
+ } else {
+ //PostMessage(hWndMiranda, WM_DESTROY, 0, 0);
+ //PostThreadMessage(mainThreadId, WM_QUIT, 0, 0);
+ //PostThreadMessage(mainThreadId, WM_COMMAND, ID_ICQ_EXIT, 0);
+ PostMessage((HWND)CallService(MS_CLUI_GETHWND, 0, 0), WM_COMMAND, ID_ICQ_EXIT, 0);
+ return 0;
+ }
+
+ return 1;
+}
+
+#ifdef _UD_LOGGING
+void mWriteFile(HANDLE hFile, char *line) {
+ unsigned long bytes_written;
+ char *nl = "\r\n";
+
+ WriteFile(hFile, line, strlen(line), &bytes_written, FALSE);
+ WriteFile(hFile, nl, 2, &bytes_written, FALSE);
+}
+#endif
+
+// move all files in src_folder to dst_folder - put replaced files in backup folder
+// if a file in src_folder is a directory, copy it's contents to the same dir in the root folder and
+// set that dir as the new root (so that dirs in dirs go in the right place)
+void MoveFiles(HANDLE hLogFile, TCHAR *src_folder, TCHAR *dst_folder, TCHAR *backup_folder, TCHAR *root_folder) {
+ // move files from src_folder to dst_folder
+
+ if(!src_folder || _tcslen(src_folder) == 0) {
+ MessageBox(0, _T("Your 'temporary files' folder is set to NULL. Install aborted."), _T("Updater Error"), MB_OK | MB_ICONERROR);
+ return;
+ }
+
+ TCHAR szFilesPath[MAX_PATH], szOldFileName[MAX_PATH], szNewFileName[MAX_PATH], szBackupFileName[MAX_PATH];
+
+ bool do_backups = backup_folder ? (_tcscmp(backup_folder, _T("no backups")) != 0) : false;
+
+ // ensure the destination folder exists
+ if(!CreatePath(dst_folder)) {
+ return;
+ }
+
+ _tcscpy(szFilesPath, src_folder);
+ _tcscat(szFilesPath, _T("\\*.*"));
+
+ bool move_file;
+
+ WIN32_FIND_DATA findData;
+ HANDLE hFileSearch = FindFirstFile(szFilesPath, &findData);
+ if(hFileSearch != INVALID_HANDLE_VALUE) {
+ do {
+ if(findData.cFileName[0] != _T('.')) {
+ _tcslwr(findData.cFileName);
+
+ _tcscpy(szOldFileName, src_folder);
+ _tcscat(szOldFileName, _T("\\"));
+ _tcscat(szOldFileName, findData.cFileName);
+
+ if(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ // use szNewFileName as destination and new root folder
+ _tcscpy(szNewFileName, root_folder);
+ if(_tcslen(findData.cFileName) < _tcslen(ROOT_FILES_FOLDER) || _tcscmp(findData.cFileName, ROOT_FILES_FOLDER)) {
+ _tcscat(szNewFileName, _T("\\"));
+ _tcscat(szNewFileName, findData.cFileName);
+ }
+
+ // recurse
+ MoveFiles(hLogFile, szOldFileName, szNewFileName, backup_folder, szNewFileName);
+
+ } else {
+ _tcscpy(szNewFileName, dst_folder);
+
+ // exception for langpack files - move to root_folder
+ // exception for dbtool.exe (e.g. translated) - move to root_folder
+ if((_tcsncmp(findData.cFileName, _T("dbtool.exe"), _tcslen(_T("dbtool.exe"))) == 0)
+ || (_tcsncmp(findData.cFileName, _T("langpack_"), _tcslen(_T("langpack_"))) == 0))
+ {
+ _tcscpy(szNewFileName, root_folder);
+ }
+
+ _tcscat(szNewFileName, _T("\\"));
+ _tcscat(szNewFileName, findData.cFileName);
+
+ move_file = false;
+ if(do_backups) {
+ _tcscpy(szBackupFileName, backup_folder);
+ _tcscat(szBackupFileName, _T("\\"));
+ _tcscat(szBackupFileName, findData.cFileName);
+
+ move_file = true;
+ DeleteFile(szBackupFileName);
+ if(!MoveFile(szNewFileName, szBackupFileName)) {
+ // MessageBox(0, szNewFileName, "Could not backup!", MB_OK | MB_ICONWARNING);
+ }
+ } else {
+ move_file = true;
+ if(!DeleteFile(szNewFileName)) {
+ // MessageBox(0, szNewFileName, "Could not delete!", MB_OK | MB_ICONWARNING);
+ }
+ }
+
+ if(move_file) {
+ if(!MoveFile(szOldFileName, szNewFileName)) {
+ //MessageBox(0, szOldFileName, "Could not move!", MB_OK | MB_ICONWARNING);
+
+ // try a copy - possibly win98 etc. will not move the updater.dll when it is being used by this process
+ CopyFile(szOldFileName, szNewFileName, TRUE);
+ DeleteFile(szOldFileName); // docs say it is marked for delete and actually removed when the last handle is closed...hmm
+ }
+ } else {
+ DeleteFile(szOldFileName);
+ }
+ }
+ }
+ } while(FindNextFile(hFileSearch, &findData));
+ FindClose(hFileSearch);
+ }
+
+ RemoveDirectory(src_folder);
+}
+
+extern "C" void __declspec(dllexport) CALLBACK ExternalUpdate(HWND hwnd, HINSTANCE hInstance, LPSTR lpszCmdLine, int nCmdShow) {
+ HANDLE hDatFile = CreateFileA(lpszCmdLine, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+ if(hDatFile == INVALID_HANDLE_VALUE) {
+ char msg[1024];
+ sprintf(msg, "Could not read data file:\n%s", lpszCmdLine);
+ MessageBoxA(0, msg, "Updater Error", MB_OK | MB_ICONERROR);
+ } else {
+
+ TCHAR *mir_exe = (TCHAR *)malloc(MAX_PATH * sizeof(TCHAR)),
+ *plugins_folder = (TCHAR *)malloc(MAX_PATH * sizeof(TCHAR)),
+ *temp_folder = (TCHAR *)malloc(MAX_PATH * sizeof(TCHAR)),
+ *backup_folder = (TCHAR *)malloc(MAX_PATH * sizeof(TCHAR)),
+ *root_folder = (TCHAR *)malloc(MAX_PATH * sizeof(TCHAR));
+ char *db_name = (char *)malloc(MAX_PATH),
+ *db_path = (char *)malloc(MAX_PATH),
+ *pid = (char *)malloc(64);
+
+ bool restart = true;
+
+ {
+ int i = 0, offset;
+ unsigned long bytes_read;
+ char ans_line[MAX_PATH];
+ TCHAR line[MAX_PATH];
+ BOOL bResult = TRUE;
+ do {
+ offset = 0;
+ if(i == 2 || i == 3 || i == 6 || i == 7) {
+ while((bResult = ReadFile(hDatFile, ans_line + offset, 1, &bytes_read, 0)) && offset < MAX_PATH && bytes_read == 1 && offset < MAX_PATH && ans_line[offset] && (ans_line[offset] != '\n' || (offset > 0 && ans_line[offset - 1] != '\r'))) offset++;
+ if(offset > 0) ans_line[offset - 1] = 0; // cut off /r/n
+ //MessageBoxA(0, ans_line, "Read ANSI text line", MB_OK);
+ } else {
+ while((bResult = ReadFile(hDatFile, line + offset, sizeof(TCHAR), &bytes_read, 0)) && offset < MAX_PATH && bytes_read == sizeof(TCHAR) && offset < MAX_PATH && line[offset] && (line[offset] != _T('\n') || (offset > 0 && line[offset - 1] != _T('\r')))) offset++;
+ if(offset > 0) line[offset - 1] = 0; // cut off /r/n
+ //MessageBox(0, line, _T("Read Unicode text line"), MB_OK);
+ }
+ switch(i) {
+ case 0: _tcsncpy(mir_exe, line, MAX_PATH); break;
+ case 1: _tcsncpy(plugins_folder, line, MAX_PATH); break;
+ case 2: strncpy(db_name, ans_line, MAX_PATH); break;
+ case 3: strncpy(db_path, ans_line, MAX_PATH); break;
+ case 4: _tcsncpy(temp_folder, line, MAX_PATH); break;
+ case 5: _tcsncpy(backup_folder, line, MAX_PATH); break;
+ case 6: strncpy(pid, ans_line, 64); break;
+ case 7:
+ restart = (strncmp(ans_line, "restart", strlen("restart")) == 0);
+ offset = 0; // end loop
+ break;
+ default:
+ offset = 0; // end loop
+ }
+ i++;
+ } while(offset > 0);
+ }
+ CloseHandle(hDatFile);
+// use data file to log to
+#ifndef _UD_LOGGING
+ DeleteFileA(lpszCmdLine);
+#else
+ HANDLE hDatFile = CreateFileA(lpszCmdLine, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0);
+#endif
+
+#ifdef _UD_LOGGING
+ mWriteFile(hDatFile, "Inside external process...");
+#endif
+
+ _tcscpy(root_folder, mir_exe);
+ TCHAR *p = _tcsrchr(root_folder, _T('\\'));
+ if(p) *p = 0;
+
+ // ensure miranda has exited
+ DWORD mpi = (DWORD)atol(pid);
+
+ bool exited = false;
+
+#ifdef _UD_LOGGING
+ char logmsg[1024];
+ sprintf(logmsg, "Opening process #%d...", mpi);
+ mWriteFile(hDatFile, logmsg);
+#endif
+
+ HANDLE hMiranda = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, mpi);
+ if(hMiranda) {
+ if(WaitForSingleObjectEx(hMiranda, 20 * 1000, FALSE) == WAIT_TIMEOUT) {
+
+ if(MessageBox(0, _T("Miranda did not exit - cannot install or restart.\n")
+ _T("Press OK to kill the process, ")
+ _T("or press Cancel to abort."), _T("Updater Error"), MB_OKCANCEL | MB_ICONERROR) == IDOK)
+ {
+ TerminateProcess(hMiranda, 1);
+
+ if(WaitForSingleObjectEx(hMiranda, 5 * 1000, FALSE) == WAIT_TIMEOUT) {
+ //hMiranda = OpenProcess(SYNCHRONIZE, FALSE, mpi);
+ //if(hMiranda) {
+ //CloseHandle(hMiranda);
+ MessageBox(0, _T("It seems Miranda is still running. Aborting update."), _T("Updater Error"), MB_OK | MB_ICONERROR);
+ } else {
+#ifdef _UD_LOGGING
+ mWriteFile(hDatFile, "Wait for miranda processs to 'Terminate' interrupted - assuming it exited");
+#endif
+ exited = true;
+ }
+ }
+ CloseHandle(hMiranda);
+ } else {
+#ifdef _UD_LOGGING
+ mWriteFile(hDatFile, "Wait for miranda processs interrupted - assuming it exited");
+#endif
+ exited = true;
+ CloseHandle(hMiranda);
+ }
+ } else {
+#ifdef _UD_LOGGING
+ mWriteFile(hDatFile, "Could not open miranda processs - assuming it exited");
+#endif
+ //MessageBox(0, "Could not open Miranda process", "Update Error", MB_OK | MB_ICONERROR);
+ exited = true;
+ }
+
+ if(exited) {
+#ifdef _UD_LOGGING
+ mWriteFile(hDatFile, "Miranda exited - moving files");
+ MoveFiles(hDatFile, temp_folder, plugins_folder, backup_folder, root_folder);
+#else
+ MoveFiles(0, temp_folder, plugins_folder, backup_folder, root_folder);
+ RemoveDirectory(temp_folder);
+#endif
+ // move files
+
+ // restart miranda
+ if(restart) {
+#ifdef _UD_LOGGING
+ mWriteFile(hDatFile, "Restarting");
+#endif
+ TCHAR szArgs[MAX_PATH], *temp_str;
+ //wsprintf(szArgs, "\"%s\" \"%s\"", db_path, db_name);
+ _stprintf(szArgs, _T("\"%s\" \"%s\""), mir_exe, temp_str = GetTStringACP(db_path)); // includes name, dummy instead of executable?
+ free(temp_str);
+ //wsprintf(szArgs, "\"%s\"", db_name);
+
+
+ PROCESS_INFORMATION pi = {0};
+ STARTUPINFO si = {0};
+ si.cb = sizeof(si);
+
+ if(!CreateProcess(mir_exe, szArgs, 0, 0, 0, DETACHED_PROCESS|NORMAL_PRIORITY_CLASS, 0, 0, &si, &pi)) {
+ MessageBox(0, _T("Failed to restart Miranda"), _T("Updater Error"), MB_OK | MB_ICONERROR);
+ //MessageBox(0, szArgs, mir_exe, MB_OK);
+ }
+ //ShellExecute(0, 0, mir_exe, szArgs, 0, SW_NORMAL);
+ }
+ }
+#ifdef _UD_LOGGING
+ else mWriteFile(hDatFile, "Miranda did not exit");
+#endif
+
+ free(plugins_folder);
+ free(db_name);
+ free(db_path);
+ free(temp_folder);
+ free(backup_folder);
+ free(root_folder);
+ free(mir_exe);
+
+#ifdef _UD_LOGGING
+ CloseHandle(hDatFile);
+#endif
+ }
+
+ FreeLibraryAndExitThread(hInstance, TRUE);
+}
|