diff --git a/src/g4wihelp.c b/src/g4wihelp.c index 3fc742ef..12b859a3 100644 --- a/src/g4wihelp.c +++ b/src/g4wihelp.c @@ -1,1204 +1,1029 @@ /* g4wihelp.c - NSIS Helper DLL used with gpg4win. -*- coding: latin-1; -*- * Copyright (C) 2005 g10 Code GmbH * Copyright (C) 2001 Justin Frankel * Copyright (C) 2016 Intevation GmbH * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any * damages arising from the use of this software. * * Permission is granted to anyone to use this software for any * purpose, including commercial applications, and to alter it and * redistribute it freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must * not claim that you wrote the original software. If you use this * software in a product, an acknowledgment in the product * documentation would be appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must * not be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source * distribution. ************************************************************ * The code for the splash screen has been taken from the Splash * plugin of the NSIS 2.04 distribution. That code comes without * explicit copyright notices in tyhe source files or author names, it * seems that it has been written by Justin Frankel; not sure about * the year, though. [wk 2005-11-28] */ #include #include #include #include #include "exdll.h" static HINSTANCE g_hInstance; /* Our Instance. */ static HWND g_hwndParent; /* Handle of parent window or NULL. */ static HBITMAP g_hbm; /* Handle of the splash image. */ static int sleepint; /* Milliseconds to show the spals image. */ void slide_stop(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop); /* Standard entry point for DLLs. */ int WINAPI DllMain (HANDLE hinst, DWORD reason, LPVOID reserved) { if (reason == DLL_PROCESS_ATTACH) g_hInstance = hinst; else if (reason == DLL_PROCESS_DETACH) slide_stop(NULL, 0, NULL, NULL); return TRUE; } /* Dummy function for testing. */ void __declspec(dllexport) dummy (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { g_hwndParent = hwndParent; EXDLL_INIT(); // note if you want parameters from the stack, pop them off in order. // i.e. if you are called via exdll::myFunction file.dat poop.dat // calling popstring() the first time would give you file.dat, // and the second time would give you poop.dat. // you should empty the stack of your parameters, and ONLY your // parameters. // do your stuff here { char buf[1024]; sprintf(buf,"$R0=%s\r\n$R1=%s\r\n", getuservariable(INST_R0), getuservariable(INST_R1)); MessageBox(g_hwndParent,buf,0,MB_OK); sprintf (buf, "autoclose =%d\r\n" "all_user_var =%d\r\n" "exec_error =%d\r\n" "abort =%d\r\n" "exec_reboot =%d\r\n" "reboot_called=%d\r\n" "silent =%d\r\n" "instdir_error=%d\r\n" "rtl =%d\r\n" "errlvl =%d\r\n", extra->exec_flags->autoclose, extra->exec_flags->all_user_var, extra->exec_flags->exec_error, extra->exec_flags->abort, extra->exec_flags->exec_reboot, extra->exec_flags->reboot_called, extra->exec_flags->silent, extra->exec_flags->instdir_error, extra->exec_flags->rtl, extra->exec_flags->errlvl); MessageBox(g_hwndParent,buf,0,MB_OK); } } void __declspec(dllexport) runonce (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { const char *result; g_hwndParent = hwndParent; EXDLL_INIT(); CreateMutexA (NULL, 0, getuservariable(INST_R0)); result = GetLastError ()? "1":"0"; setuservariable (INST_R0, result); } void __declspec(dllexport) playsound (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { char fname[MAX_PATH]; g_hwndParent = hwndParent; EXDLL_INIT(); if (popstring(fname, sizeof fname)) return; PlaySound (fname, NULL, SND_ASYNC|SND_FILENAME|SND_NODEFAULT); } void __declspec(dllexport) stopsound (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { g_hwndParent = hwndParent; EXDLL_INIT(); PlaySound (NULL, NULL, 0); } /* Windows procedure to control the splashimage. This one pauses the execution until the sleep time is over or the user closes this windows. */ static LRESULT CALLBACK splash_wndproc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT result = 0; switch (uMsg) { case WM_CREATE: { BITMAP bm; RECT vp; GetObject(g_hbm, sizeof(bm), (LPSTR)&bm); SystemParametersInfo(SPI_GETWORKAREA, 0, &vp, 0); SetWindowLong(hwnd,GWL_STYLE,0); SetWindowPos(hwnd,NULL, vp.left+(vp.right-vp.left-bm.bmWidth)/2, vp.top+(vp.bottom-vp.top-bm.bmHeight)/2, bm.bmWidth,bm.bmHeight, SWP_NOZORDER); ShowWindow(hwnd,SW_SHOW); SetTimer(hwnd,1,sleepint,NULL); } break; case WM_PAINT: { PAINTSTRUCT ps; RECT r; HDC curdc=BeginPaint(hwnd,&ps); HDC hdc=CreateCompatibleDC(curdc); HBITMAP oldbm; GetClientRect(hwnd,&r); oldbm=(HBITMAP)SelectObject(hdc,g_hbm); BitBlt(curdc,r.left,r.top,r.right-r.left,r.bottom-r.top, hdc,0,0,SRCCOPY); SelectObject(hdc,oldbm); DeleteDC(hdc); EndPaint(hwnd,&ps); } break; case WM_CLOSE: break; case WM_TIMER: case WM_LBUTTONDOWN: DestroyWindow(hwnd); /*(fall through)*/ default: result = DefWindowProc (hwnd, uMsg, wParam, lParam); } return result; } /* Display a splash screen. Call as g4wihelp::showsplash SLEEP FNAME With SLEEP being the time in milliseconds to show the splashscreen and FNAME the complete filename of the image. As of now only BMP is supported. */ void __declspec(dllexport) showsplash (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { static WNDCLASS wc; char sleepstr[30]; char fname[MAX_PATH]; int err = 0; char *p; char classname[] = "_sp"; g_hwndParent = hwndParent; EXDLL_INIT(); if (popstring(sleepstr, sizeof sleepstr)) err = 1; if (popstring(fname, sizeof fname)) err = 1; if (err) return; if (!*fname) return; /* Nothing to do. */ for (sleepint=0, p=sleepstr; *p >= '0' && *p <= '9'; p++) { sleepint *= 10; sleepint += *p - '0'; } if (sleepint <= 0) return; /* Nothing to do. */ wc.lpfnWndProc = splash_wndproc; wc.hInstance = g_hInstance; wc.hCursor = LoadCursor(NULL,IDC_ARROW); wc.lpszClassName = classname; if (!RegisterClass(&wc)) return; /* Error. */ g_hbm = LoadImage (NULL, fname, IMAGE_BITMAP, 0, 0 , LR_CREATEDIBSECTION|LR_LOADFROMFILE); if (g_hbm) { MSG msg; HWND hwnd; hwnd = CreateWindowEx (WS_EX_TOOLWINDOW, classname, classname, 0, 0, 0, 0, 0, (HWND)hwndParent, NULL, g_hInstance, NULL); while (IsWindow(hwnd) && GetMessage ( &msg, hwnd, 0, 0)) { DispatchMessage (&msg); } DeleteObject (g_hbm); g_hbm = NULL; } UnregisterClass (classname, g_hInstance); } /* Service Management. */ /* Use this to report unexpected errors. FIXME: This is really not very descriptive. */ void service_error (const char *str) { char buf[1024]; snprintf (buf, sizeof (buf) - 1, "error: %s: ec=%d\r\n", str, GetLastError ()); MessageBox(g_hwndParent, buf, 0, MB_OK); setuservariable (INST_R0, "1"); } void __declspec(dllexport) service_create (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { SC_HANDLE sc; SC_HANDLE service; const char *result = NULL; char service_name[256]; char display_name[256]; char program[256]; int err = 0; g_hwndParent = hwndParent; EXDLL_INIT(); /* The expected stack layout: service_name, display_name, program. */ if (popstring (service_name, sizeof (service_name))) err = 1; if (!err && popstring (display_name, sizeof (display_name))) err = 1; if (!err && popstring (program, sizeof (program))) err = 1; if (err) { setuservariable (INST_R0, "1"); return; } sc = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); if (sc == NULL) { service_error ("OpenSCManager"); return; } service = CreateService (sc, service_name, display_name, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, /* Use SERVICE_DEMAND_START for testing. FIXME: Currently not configurable by caller. */ SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, program, NULL, NULL, NULL, /* FIXME: Currently not configurable by caller. */ /* FIXME: LocalService or NetworkService don't work for dirmngr right now. NOTE! If you change it here, you also should adjust make-msi.pl for the msi installer. In the future, this should be an argument to the function and then the make-msi.pl script can extract it from the invocation. */ NULL /* "NT AUTHORITY\\LocalService" */, NULL); if (service == NULL) { service_error ("CreateService"); CloseServiceHandle (sc); return; } CloseServiceHandle (service); result = GetLastError () ? "1":"0"; setuservariable (INST_R0, result); return; } /* Requires g_hwndParent to be set! */ SC_HANDLE service_lookup (char *service_name) { SC_HANDLE sc; SC_HANDLE service; sc = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); if (sc == NULL) { service_error ("OpenSCManager"); return NULL; } service = OpenService (sc, service_name, SC_MANAGER_ALL_ACCESS); if (service == NULL) { /* Fail silently here. */ CloseServiceHandle (sc); return NULL; } CloseServiceHandle (sc); return service; } /* Returns status. */ void __declspec(dllexport) service_query (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { SC_HANDLE service; const char *result = NULL; char service_name[256]; int err = 0; SERVICE_STATUS status; g_hwndParent = hwndParent; EXDLL_INIT(); /* The expected stack layout: service_name argc [argv]. */ if (popstring (service_name, sizeof (service_name))) err = 1; if (err) { setuservariable (INST_R0, "ERROR"); return; } service = service_lookup (service_name); if (service == NULL) if (err == 0) { setuservariable (INST_R0, "MISSING"); return; } err = QueryServiceStatus (service, &status); if (err == 0) { setuservariable (INST_R0, "ERROR"); CloseServiceHandle (service); return; } CloseServiceHandle (service); switch (status.dwCurrentState) { case SERVICE_START_PENDING: result = "START_PENDING"; break; case SERVICE_RUNNING: result = "RUNNING"; break; case SERVICE_PAUSE_PENDING: result = "PAUSE_PENDING"; break; case SERVICE_PAUSED: result = "PAUSED"; break; case SERVICE_CONTINUE_PENDING: result = "CONTINUE_PENDING"; break; case SERVICE_STOP_PENDING: result = "STOP_PENDING"; break; case SERVICE_STOPPED: result = "STOPPED"; break; default: result = "UNKNOWN"; } setuservariable (INST_R0, result); return; } void __declspec(dllexport) service_start (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { SC_HANDLE service; const char *result = NULL; char service_name[256]; char argc_str[256]; #define NR_ARGS 10 #define ARG_MAX 256 char argv_str[NR_ARGS][ARG_MAX]; char *argv[NR_ARGS + 1]; int argc; int i; int err = 0; g_hwndParent = hwndParent; EXDLL_INIT(); /* The expected stack layout: service_name argc [argv]. */ if (popstring (service_name, sizeof (service_name))) err = 1; if (!err && popstring (argc_str, sizeof (argc_str))) err = 1; if (!err) { argc = atoi (argc_str); for (i = 0; i < argc; i++) { if (popstring (argv_str[i], ARG_MAX)) { err = 1; break; } argv[i] = argv_str[i]; } argv[i] = NULL; } if (err) { setuservariable (INST_R0, "1"); return; } service = service_lookup (service_name); if (service == NULL) return; err = StartService (service, argc, argc == 0 ? NULL : argv); if (err == 0) { service_error ("StartService"); CloseServiceHandle (service); return; } CloseServiceHandle (service); setuservariable (INST_R0, "0"); return; } void __declspec(dllexport) service_stop (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { SC_HANDLE service; const char *result = NULL; char service_name[256]; int err = 0; SERVICE_STATUS status; DWORD timeout = 10000; /* 10 seconds. */ DWORD start_time; g_hwndParent = hwndParent; EXDLL_INIT(); /* The expected stack layout: service_name argc [argv]. */ if (popstring (service_name, sizeof (service_name))) err = 1; if (err) { setuservariable (INST_R0, "1"); return; } service = service_lookup (service_name); if (service == NULL) return; err = QueryServiceStatus (service, &status); if (err == 0) { service_error ("QueryService"); CloseServiceHandle (service); return; } if (status.dwCurrentState != SERVICE_STOPPED && status.dwCurrentState != SERVICE_STOP_PENDING) { err = ControlService (service, SERVICE_CONTROL_STOP, &status); if (err == 0) { service_error ("ControlService"); CloseServiceHandle (service); return; } } start_time = GetTickCount (); while (status.dwCurrentState != SERVICE_STOPPED) { Sleep (1000); /* One second. */ if (!QueryServiceStatus (service, &status)) { service_error ("QueryService"); CloseServiceHandle (service); return; } if (status.dwCurrentState == SERVICE_STOPPED) break; if (GetTickCount () - start_time > timeout) { char buf[1024]; snprintf (buf, sizeof (buf) - 1, "time out waiting for service %s to stop\r\n", service_name); MessageBox (g_hwndParent, buf, 0, MB_OK); setuservariable (INST_R0, "1"); return; } } CloseServiceHandle (service); setuservariable (INST_R0, "0"); return; } void __declspec(dllexport) service_delete (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { SC_HANDLE service; const char *result = NULL; char service_name[256]; int err = 0; g_hwndParent = hwndParent; EXDLL_INIT(); /* The expected stack layout: service_name argc [argv]. */ if (popstring (service_name, sizeof (service_name))) err = 1; if (err) { setuservariable (INST_R0, "1"); return; } service = service_lookup (service_name); if (service == NULL) return; err = DeleteService (service); if (err == 0) { service_error ("DeleteService"); CloseServiceHandle (service); return; } CloseServiceHandle (service); setuservariable (INST_R0, "0"); return; } #include /* Extract config file parameters. FIXME: Not particularly robust. We expect some reasonable formatting. The parser below is very limited. It expects a command line option /c=FILE or /C=FILE, where FILE must be enclosed in double-quotes if it contains spaces. That file should contain a single section [gpg4win] and KEY=VALUE pairs for each additional configuration file to install. Comments are supported only on lines by themselves. VALUE can be quoted in double-quotes, but does not need to be, unless it has whitespace at the beginning or end. KEY can, for example, be "gpg.conf" (without the quotes). */ void config_init (char **keys, char **values, int max) { /* First, parse the command line. */ char *cmdline; char *begin = NULL; char *end = NULL; char mark; char *fname; char *ptr; FILE *conf; *keys = NULL; *values = NULL; cmdline = getuservariable (INST_CMDLINE); mark = (*cmdline == '"') ? (cmdline++, '"') : ' '; while (*cmdline && *cmdline != mark) cmdline++; if (mark == '"' && *cmdline) cmdline++; while (*cmdline && *cmdline == ' ') cmdline++; while (*cmdline) { /* We are at the beginning of a new argument. */ if (cmdline[0] == '/' && (cmdline[1] == 'C' || cmdline[1] == 'c') && cmdline[2] == '=') { cmdline += 3; begin = cmdline; } while (*cmdline && *cmdline != ' ') { /* Skip over quoted parts. */ if (*cmdline == '"') { cmdline++; while (*cmdline && *cmdline != '"') cmdline++; if (*cmdline) cmdline++; } else cmdline++; } if (begin && !end) { end = cmdline - 1; break; } while (*cmdline && *cmdline == ' ') cmdline++; } if (!begin || begin > end) return; /* Strip quotes. */ if (*begin == '"' && *end == '"') { begin++; end--; } if (begin > end) return; fname = malloc (end - begin + 2); if (!fname) return; ptr = fname; while (begin <= end) *(ptr++) = *(begin++); *ptr = '\0'; conf = fopen (fname, "r"); free (fname); if (!conf) return; while (max - 1 > 0) { char line[256]; char *ptr2; if (fgets (line, sizeof (line), conf) == NULL) break; ptr = &line[strlen (line)]; while (ptr > line && (ptr[-1] == '\n' || ptr[-1] == '\r' || ptr[-1] == ' ' || ptr[-1] == '\t')) ptr--; *ptr = '\0'; ptr = line; while (*ptr && (*ptr == ' ' || *ptr == '\t')) ptr++; /* Ignore comment lines. */ /* FIXME: Ignore section markers. */ if (*ptr == '\0' || *ptr == ';' || *ptr == '[') continue; begin = ptr; while (*ptr && *ptr != '=' && *ptr != ' ' && *ptr != '\t') ptr++; end = ptr - 1; while (*ptr && (*ptr == ' ' || *ptr == '\t')) ptr++; if (*ptr != '=') continue; ptr++; if (begin > end) continue; /* We found a key. */ *keys = malloc (end - begin + 2); if (!keys) return; ptr2 = *keys; while (begin <= end) *(ptr2++) = *(begin++); *ptr2 = '\0'; *values = NULL; while (*ptr && (*ptr == ' ' || *ptr == '\t')) ptr++; begin = ptr; /* In this case, end points to the byte after the value, which is OK because that is '\0'. */ end = &line[strlen (line)]; if (begin > end) begin = end; /* Strip quotes. */ if (*begin == '"' && end[-1] == '"') { begin++; end--; *end = '\0'; } if (begin > end) return; *values = malloc (end - begin + 1); ptr2 = *values; while (begin <= end) *(ptr2++) = *(begin++); keys++; values++; max--; } fclose (conf); *keys = NULL; *values = NULL; } char * config_lookup (char *key) { #define MAX_KEYS 128 static int initialised = 0; static char *keys[MAX_KEYS]; static char *values[MAX_KEYS]; int i; if (initialised == 0) { initialised = 1; config_init (keys, values, MAX_KEYS); #if 0 MessageBox(g_hwndParent, "Configuration File:", 0, MB_OK); i = 0; while (keys[i]) { char buf[256]; sprintf (buf, "%s=%s\r\n", keys[i], values[i]); MessageBox (g_hwndParent, buf, 0, MB_OK); i++; } #endif } i = 0; while (keys[i]) { if (!strcmp (keys[i], key)) return values[i]; i++; } return NULL; } void __declspec(dllexport) config_fetch (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { char key[256]; int err = 0; char *value; g_hwndParent = hwndParent; EXDLL_INIT(); /* The expected stack layout: key. */ if (popstring (key, sizeof (key))) err = 1; if (err) { setuservariable (INST_R0, ""); return; } value = config_lookup (key); setuservariable (INST_R0, value == NULL ? "" : value); return; } void __declspec(dllexport) config_fetch_bool (HWND hwndParent, int string_size, char *variables, stack_t **stacktop, extra_parameters_t *extra) { char key[256]; int err = 0; char *value; int result; g_hwndParent = hwndParent; EXDLL_INIT(); /* The expected stack layout: key. */ if (popstring (key, sizeof (key))) err = 1; if (err) { setuservariable (INST_R0, ""); return; } value = config_lookup (key); if (value == NULL || *value == '\0') { setuservariable (INST_R0, ""); return; } result = 0; if (!strcasecmp (value, "true") || !strcasecmp (value, "yes") || atoi (value) != 0) result = 1; setuservariable (INST_R0, result == 0 ? "0" : "1"); return; } /* Return a string from the Win32 Registry or NULL in case of error. Caller must release the return value. A NULL for root is an alias for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */ char * read_w32_registry_string (HKEY root, const char *dir, const char *name) { HKEY root_key; HKEY key_handle; DWORD n1, nbytes, type; char *result = NULL; root_key = root; if (! root_key) root_key = HKEY_CURRENT_USER; if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) ) { if (root) return NULL; /* no need for a RegClose, so return direct */ /* It seems to be common practise to fall back to HKLM. */ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) ) return NULL; /* still no need for a RegClose, so return direct */ } nbytes = 1; if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) { if (root) goto leave; /* Try to fallback to HKLM also vor a missing value. */ RegCloseKey (key_handle); if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) ) return NULL; /* Nope. */ if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes)) goto leave; } result = malloc( (n1=nbytes+1) ); if( !result ) goto leave; if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) { free(result); result = NULL; goto leave; } result[nbytes] = 0; /* make sure it is really a string */ leave: RegCloseKey( key_handle ); return result; } -#define ENV_HK HKEY_LOCAL_MACHINE -#define ENV_REG "SYSTEM\\CurrentControlSet\\Control\\" \ - "Session Manager\\Environment" - /* The following setting can be used for a per-user setting. */ -#if 0 -#define ENV_HK HKEY_CURRENT_USER -#define ENV_REG "Environment" -#endif -/* Due to a bug in Windows7 (kb 2685893) we better but a lower limit - than 8191 on the maximum length of the PATH variable. Note, that - depending on the used toolchain we used to have a 259 byte limit in - the past. */ -#define PATH_LENGTH_LIMIT 2047 - -void __declspec(dllexport) -path_add (HWND hwndParent, int string_size, char *variables, - stack_t **stacktop, extra_parameters_t *extra) -{ - char dir[PATH_LENGTH_LIMIT]; - char *path; - char *path_new; - int path_new_size; - char *comp; - const char delims[] = ";"; - HKEY key_handle = 0; - - g_hwndParent = hwndParent; - EXDLL_INIT(); - - setuservariable (INST_R0, "0"); - -/* MessageBox (g_hwndParent, "XXX 1", 0, MB_OK); */ - - /* The expected stack layout: path component. */ - if (popstring (dir, sizeof (dir))) - return; - -/* MessageBox (g_hwndParent, "XXX 2", 0, MB_OK); */ - - path = read_w32_registry_string (ENV_HK, ENV_REG, "Path"); - if (! path) - { - MessageBox (g_hwndParent, "No PATH variable found", 0, MB_OK); - return; - } - -/* MessageBox (g_hwndParent, "XXX 3", 0, MB_OK); */ - - /* Old path plus semicolon plus dir plus terminating nul. */ - path_new_size = strlen (path) + 1 + strlen (dir) + 1; - if (path_new_size > PATH_LENGTH_LIMIT) - { - MessageBox (g_hwndParent, "PATH env variable too big", 0, MB_OK); - free (path); - return; - } - -/* MessageBox (g_hwndParent, "XXX 4", 0, MB_OK); */ - - path_new = malloc (path_new_size); - if (!path_new) - { - free (path); - return; - } - -/* MessageBox (g_hwndParent, "XXX 5", 0, MB_OK); */ - - strcpy (path_new, path); - strcat (path_new, ";"); - strcat (path_new, dir); - -/* MessageBox (g_hwndParent, "XXX 6", 0, MB_OK); */ -/* MessageBox (g_hwndParent, dir, 0, MB_OK); */ -/* MessageBox (g_hwndParent, "XXX 7", 0, MB_OK); */ - - /* Check if the directory already exists in the path. */ - comp = strtok (path, delims); - do - { -/* MessageBox (g_hwndParent, comp, 0, MB_OK); */ - - if (!strcmp (comp, dir)) - { - free (path); - free (path_new); - return; - } - comp = strtok (NULL, delims); - } - while (comp); - free (path); - -/* MessageBox (g_hwndParent, "XXX 8", 0, MB_OK); */ - - /* Set a key for our CLSID. */ - RegCreateKey (ENV_HK, ENV_REG, &key_handle); - RegSetValueEx (key_handle, "Path", 0, REG_EXPAND_SZ, - path_new, path_new_size); - RegCloseKey (key_handle); - SetEnvironmentVariable("PATH", path_new); - free (path_new); - -/* MessageBox (g_hwndParent, "XXX 9", 0, MB_OK); */ - - setuservariable (INST_R0, "1"); -} - - -void __declspec(dllexport) -path_remove (HWND hwndParent, int string_size, char *variables, - stack_t **stacktop, extra_parameters_t *extra) -{ - char dir[PATH_LENGTH_LIMIT]; - char *path; - char *path_new; - int path_new_size; - char *comp; - const char delims[] = ";"; - HKEY key_handle = 0; - int changed = 0; - int count = 0; - - g_hwndParent = hwndParent; - EXDLL_INIT(); - - setuservariable (INST_R0, "0"); - - /* The expected stack layout: path component. */ - if (popstring (dir, sizeof (dir))) - return; - - path = read_w32_registry_string (ENV_HK, ENV_REG, "Path"); - /* Old path plus semicolon plus dir plus terminating nul. */ - path_new_size = strlen (path) + 1; - path_new = malloc (path_new_size); - if (!path_new) - { - free (path); - return; - } - path_new[0] = '\0'; - - /* Compose the new path. */ - comp = strtok (path, delims); - do - { - if (strcmp (comp, dir)) - { - if (count != 0) - strcat (path_new, ";"); - strcat (path_new, comp); - count++; - } - else - changed = 1; - - comp = strtok (NULL, delims); - } - while (comp); - free (path); - - if (! changed) - return; - - /* Set a key for our CLSID. */ - RegCreateKey (ENV_HK, ENV_REG, &key_handle); - RegSetValueEx (key_handle, "Path", 0, REG_EXPAND_SZ, - path_new, path_new_size); - RegCloseKey (key_handle); - free (path_new); - - setuservariable (INST_R0, "1"); -} - /** @brief Kill processes with the name name. * * This function tries to kill a process using ExitProcess. * * If it does not work it does not work. No return values. * The intention is to make an effort to kill something during * installation / uninstallation. * * The function signature is explained by NSIS. */ void __declspec(dllexport) __cdecl KillProc(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) { HANDLE h; PROCESSENTRY32 pe32; if (!stacktop || !*stacktop || !(*stacktop)->text) { ERRORPRINTF ("Invalid call to KillProc."); return; } h = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0); if (h == INVALID_HANDLE_VALUE) { ERRORPRINTF ("Failed to create Toolhelp snapshot"); return; } pe32.dwSize = sizeof (PROCESSENTRY32); if (!Process32First (h, &pe32)) { ERRORPRINTF ("Failed to get first process"); CloseHandle (h); return; } do { if (!strcmp ((*stacktop)->text, pe32.szExeFile)) { HANDLE hProc = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID); if (!hProc) { ERRORPRINTF ("Failed to open process handle."); continue; } if (!TerminateProcess (hProc, 1)) { ERRORPRINTF ("Failed to terminate process."); } CloseHandle (hProc); } } while (Process32Next (h, &pe32)); CloseHandle (h); } diff --git a/src/installer.nsi b/src/installer.nsi index 20b6e344..59663c47 100644 --- a/src/installer.nsi +++ b/src/installer.nsi @@ -1,774 +1,729 @@ # installer.nsi - Installer for GnuPG 4 Windows. -*- coding: latin-1; -*- # Copyright (C) 2005, 2007 g10 Code GmbH # # This file is part of GPG4Win. # # GPG4Win is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPG4Win 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA # No servicable parts beyond this line. Stay clear :) !ifdef REQUIRE_W32_NSIS !ifdef PACKAGE_LIBRARY !include "Library.nsh" !endif !else !macro InstallLib libtype shared install localfile destfile tempbasedir File "${localfile}" !macroend !endif !include "WinMessages.nsh" -# Define for the registry key to change the environment. The -# commented one may be used if the setting should affect only the -# current user. -!define Regkey_for_Env \ - 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' -# !define Regkey_for_Env 'HKCU "Environment"' - - # We use the modern UI 2. !ifdef DEBUG !include "MUI2.nsh" !else !include "MUI2.nsh" # MUI2 defines debug !undef DEBUG !endif # Set the package name. Note that this name should not be sufficed # with the version because this would get displayed in the start menu. Name "${PRETTY_PACKAGE}" - - -# Set the output filename. -!ifdef GPG4WIN_VANILLA -OutFile "${PACKAGE}-vanilla-${VERSION}.exe" -BrandingText "${PRETTY_PACKAGE}-vanilla-${VERSION}" -!else -!ifdef GPG4WIN_LIGHT -OutFile "${PACKAGE}-light-${VERSION}.exe" -BrandingText "${PRETTY_PACKAGE}-light-${VERSION}" -!else OutFile "${PACKAGE}-${VERSION}.exe" BrandingText "${PRETTY_PACKAGE}-${VERSION}" -!endif -!endif # Details button conflicts with splashscreen ShowInstDetails nevershow # Set the installation directory. !ifndef INSTALL_DIR !define INSTALL_DIR "${PACKAGE}" !endif InstallDir "$PROGRAMFILES\${INSTALL_DIR}" InstallDirRegKey HKLM "Software\${PRETTY_PACKAGE_SHORT}" \ "Install Directory" # Add version information to the file properties. VIProductVersion "${PROD_VERSION}" VIAddVersionKey "ProductName" "${PRETTY_PACKAGE_SHORT} (${VERSION})" !ifdef LICENSE_GPL VIAddVersionKey "Comments" \ "${PRETTY_PACKAGE_SHORT} is Free Software; you can redistribute it \ and/or modify it under the terms of the GNU General Public License. \ You should have received a copy of the GNU General Public License \ along with this software; if not, write to the Free Software \ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, \ MA 02110-1301, USA" !else VIAddVersionKey "Comments" \ "${PRETTY_PACKAGE_SHORT} is Free Software; you can redistribute it \ and/or modify it under the terms of the GNU Lesser General Public \ License. You should have received a copy of the GNU Lesser General \ Public License along with this software; if not, write to the Free \ Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, \ MA 02110-1301, USA" !endif VIAddVersionKey "CompanyName" "${COMPANY}" VIAddVersionKey "LegalTrademarks" "" VIAddVersionKey "LegalCopyright" "${COPYRIGHT}" VIAddVersionKey "FileDescription" "${DESCRIPTION}" VIAddVersionKey "FileVersion" "${PROD_VERSION}" # Set to the name of another GnuPG installation if one has been detected Var OtherGnuPGDetected # Interface Settings # !define MUI_ABORTWARNING !define MUI_FINISHPAGE_NOAUTOCLOSE !define MUI_UNFINISHPAGE_NOAUTOCLOSE !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_BITMAP \ "${TOP_SRCDIR}/doc/logo/gpg4win-nsis-header-install-150x57.bmp" !define MUI_HEADERIMAGE_UNBITMAP \ "${TOP_SRCDIR}/doc/logo/gpg4win-nsis-header-uninstall-150x57.bmp" !define MUI_WELCOMEFINISHPAGE_BITMAP \ "${TOP_SRCDIR}/doc/logo/gpg4win-nsis-wizard-install-164x314.bmp" !define MUI_UNWELCOMEFINISHPAGE_BITMAP \ "${TOP_SRCDIR}/doc/logo/gpg4win-nsis-wizard-uninstall-164x314.bmp" !define MUI_ICON "${TOP_SRCDIR}/doc/logo/gpg4win-nsis-install.ico" !define MUI_UNICON "${TOP_SRCDIR}/doc/logo/gpg4win-nsis-uninstall.ico" # Remember the installer language !define MUI_LANGDLL_REGISTRY_ROOT "HKLM" !define MUI_LANGDLL_REGISTRY_KEY "Software\${PRETTY_PACKAGE_SHORT}" !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language" # No Umlaute, please! !define MUI_LANGDLL_INFO "Please choose a language for the setup.$\r$\n\ Bitte die Sprache des Installations-Vorgangs angeben." # The list of wizard pages. !define MUI_WELCOMEPAGE_TITLE "${WELCOME_TITLE_STR}" !define MUI_WELCOMEPAGE_TEXT "${ABOUT_STR}" !insertmacro MUI_PAGE_WELCOME #!define MUI_LICENSEPAGE_BUTTON "$(^NextBtn)" #!define MUI_PAGE_HEADER_SUBTEXT "$(T_GPLHeader)" #!insertmacro MUI_PAGE_LICENSE "license.blurb" !define MUI_PAGE_CUSTOMFUNCTION_SHOW PrintNonAdminWarning !insertmacro MUI_PAGE_COMPONENTS !define MUI_PAGE_CUSTOMFUNCTION_LEAVE CheckExistingVersion !insertmacro MUI_PAGE_DIRECTORY !define MUI_PAGE_CUSTOMFUNCTION_PRE BeforeInstallHooks !insertmacro MUI_PAGE_INSTFILES # Finish page !ifndef SOURCES !define MUI_PAGE_CUSTOMFUNCTION_PRE ShowFinalWarnings !define MUI_PAGE_CUSTOMFUNCTION_SHOW FinishFunction !define MUI_FINISHPAGE_RUN !define MUI_FINISHPAGE_RUN_FUNCTION RunAsUser !define MUI_FINISHPAGE_SHOWREADME "share\gpg4win\README.$(T_LangCode).txt" !define MUI_FINISHPAGE_SHOWREADME_TEXT "$(T_ShowReadme)" !define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED !define MUI_FINISHPAGE_LINK "$(T_MoreInfo)" !define MUI_FINISHPAGE_LINK_LOCATION "$(T_MoreInfoURL)" !insertmacro MUI_PAGE_FINISH Function FinishFunction IfSilent leave Var /GLOBAL gpa_or_kleopatra !insertmacro SectionFlagIsSet ${SEC_kleopatra} \ ${SF_SELECTED} have_kleo 0 !insertmacro SectionFlagIsSet ${SEC_gpa} \ ${SF_SELECTED} have_gpa 0 ShowWindow $mui.FinishPage.Run ${SW_HIDE} goto leave have_kleo: SendMessage $mui.FinishPage.Run.Text ${WM_SETTEXT} 0 "STR:$(T_RunKleopatra)" goto leave have_gpa: SendMessage $mui.FinishPage.Run.Text ${WM_SETTEXT} 0 "STR:$(T_RunGPA)" StrCpy $gpa_or_kleopatra "GPA" leave: FunctionEnd Function RunAsUser !insertmacro SectionFlagIsSet ${SEC_kleopatra} \ ${SF_SELECTED} 0 skip_kleo g4wihelp::DesktopShellRun "$INSTDIR\bin\kleopatra.exe" goto leave skip_kleo: !insertmacro SectionFlagIsSet ${SEC_gpa} \ ${SF_SELECTED} 0 leave g4wihelp::DesktopShellRun "$INSTDIR\bin\gpa.exe" leave: FunctionEnd LangString T_RunKleopatra ${LANG_ENGLISH} \ "Run Kleopatra" LangString T_RunGPA ${LANG_ENGLISH} \ "Run GPA" # /SOURCES !endif # Uninstaller pages. !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !ifndef SOURCES !define MUI_PAGE_CUSTOMFUNCTION_PRE un.CloseApps !endif !insertmacro MUI_UNPAGE_INSTFILES #!insertmacro MUI_UNPAGE_FINISH #Page license #Page components #Page directory #Page instfiles #UninstPage uninstConfirm #UninstPage instfiles # Language support. This has to be done after defining the pages, but # before defining the translation strings. Confusing. # Enable this to not filter languages for the current code page. Note # that languages which are then not filtered out may not be displayed # correctly in the Windows version the user is using. Not recommended, # but can be useful for testing. !ifdef DEBUG !define MUI_LANGDLL_ALLLANGUAGES !endif !insertmacro MUI_LANGUAGE "English" !define PO_HEADER !include "../po/catalogs.nsi" !undef PO_HEADER !insertmacro MUI_RESERVEFILE_LANGDLL ReserveFile "${BUILD_DIR}\g4wihelp.dll" !ifdef SOURCES ReserveFile "${TOP_SRCDIR}\doc\logo\gpg4win-logo-400px.bmp" ReserveFile "${TOP_SRCDIR}\src\gpg4win-splash.wav" !endif ReserveFile "${TOP_SRCDIR}\COPYING" ReserveFile "${TOP_SRCDIR}\doc\logo\gpg4win-logo-164x314.bmp" # Language support LangString T_LangCode ${LANG_ENGLISH} "en" # Startup page LangString T_GPLHeader ${LANG_ENGLISH} \ "This software is licensed under the terms of the GNU General Public \ License (GPL)." LangString T_GPLShort ${LANG_ENGLISH} \ "In short: You are allowed to run this software for any purpose. \ You may distribute it as long as you give the recipients the same \ rights you have received." LangString T_MoreInfo ${LANG_ENGLISH} \ "Click here for the project's homepage" LangString T_MoreInfoURL ${LANG_ENGLISH} "http://www.gpg4win.org" LangString T_ShowReadme ${LANG_ENGLISH} \ "Show the README file" LangString T_NoKeyManager ${LANG_ENGLISH} \ "No key manager has been installed, thus we can't run one now." # Used as subdirectory name in Start Menu. LangString DESC_Menu_manuals ${LANG_ENGLISH} \ "Documentation" LangString DESC_Menu_uninstall ${LANG_ENGLISH} \ "Uninstall" # Used as subdirectory name on Desktop. LangString DESC_Desktop_manuals ${LANG_ENGLISH} \ "Gpg4win Documentation" # Functions # Custom functions and macros for gpg4win. !include "g4wihelp.nsi" # Display a warning if this is a Beta version. #Function PrintBetaWarning # MessageBox MB_OK "$(T_BetaWarning)" #FunctionEnd # Display a warning if GnuPP has been detected and allow the user to abort # the installation. Function PrintGnuPPWarning MessageBox MB_YESNO "$(T_FoundOldGnuPP)" IDYES cont Abort cont: StrCpy $OtherGnuPGDetected "GnuPP" FunctionEnd # Display a warning if GnuPT has been detected and allow the user to abort # the installation. Function PrintGnuPTWarning MessageBox MB_YESNO "$(T_FoundOldGnuPT)" IDYES cont Abort cont: StrCpy $OtherGnuPGDetected "GnuPT" FunctionEnd # Display a warning if the Sourceforge WinPT has been detected and # allow the user to abort the installation. Function PrintWinPTSFWarning MessageBox MB_YESNO "$(T_FoundOldWinPTSF)" IDYES cont Abort cont: StrCpy $OtherGnuPGDetected "WinPT-SF" FunctionEnd # Display a warning if GnuPG Pack has been detected and abort the # the installation. This one clobbers our own Registry space. Function PrintGnuPackWarning MessageBox MB_OK "$(T_FoundOldGnuPack)" Abort FunctionEnd # Check whether one of the other GnuPG systems has already been # installed. We do this by looking at the registry. Function CheckOtherGnuPGApps StrCpy $OtherGnuPGDetected "" ClearErrors ReadRegStr $0 HKLM "Software\GNU\GnuPP\Settings" "Path" IfErrors +2 0 Call PrintGnuPPWarning EnumRegKey $0 HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\MenuOrder\Start Menu\Programs\GnuPT" 0 StrCmp $0 "" +2 Call PrintGnuPTWarning ClearErrors ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Windows Privacy Tools" "DisplayVersion" IfErrors +2 0 Call PrintWinPTSFWarning ReadRegStr $0 HKLM "Software\GNU\GnuPG" "Install Directory" Push $0 Push "GnuPG-Pack" Call StrStr Pop $0 StrCmp $0 "" +2 Call PrintGnuPackWarning FunctionEnd # Check whether gpg4win has already been installed. This is called as # a leave function from the directory page. A call to abort will get # back to the directory selection. Function CheckExistingVersion ClearErrors FileOpen $0 "$INSTDIR\VERSION" r IfErrors leave FileRead $0 $R0 FileRead $0 $R1 FileClose $0 Push $R1 Call TrimNewLines Pop $R1 # Extract major version. StrCpy $0 $R1 2 StrCmp $0 "1." 0 leave MessageBox MB_YESNO "$(T_FoundExistingOldVersion)" IDYES leave Abort leave: FunctionEnd # PrintNonAdminWarning # Check whether the current user is in the Administrator group or an # OS version without the need for an Administrator is in use. Print a # diagnostic if this is not the case and abort installation. Function PrintNonAdminWarning #Call PrintBetaWarning ClearErrors UserInfo::GetName IfErrors leave Pop $0 UserInfo::GetAccountType Pop $1 StrCmp $1 "Admin" leave +1 MessageBox MB_OK "$(T_AdminNeeded)" Quit leave: FunctionEnd # Check for claws mail installation which was shipped in Gpg4win # versions < 2.2.6 Function CheckClawsUninstall IfFileExists $INSTDIR\claws-mail.exe 0 leave MessageBox MB_YESNO "$(T_FoundOldClaws)" IDYES uninstall IDNO leave uninstall: !insertmacro SelectSection ${SecUninstClawsMail} leave: FunctionEnd # Check whether this is a reinstall and popup a message box to explain # that it is better to close other apps before continuing Function PrintCloseOtherApps g4wihelp::KillProc "kleopatra.exe" g4wihelp::KillProc "gpa.exe" goto leave # TODO check for running outlook and offer to kill it. print_warning: MessageBox MB_OK|MB_ICONEXCLAMATION "$(T_CloseOtherApps)" leave: FunctionEnd Function un.CloseApps g4wihelp::KillProc "kleopatra.exe" g4wihelp::KillProc "gpa.exe" FunctionEnd # Called right before installation Function BeforeInstallHooks Call PrintCloseOtherApps -!ifndef GPG4WIN_VANILLA Call CheckClawsUninstall -!endif FunctionEnd # Called right before the final page to show more warnings. Function ShowFinalWarnings StrCmp $OtherGnupgDetected "" +2 MessageBox MB_OK "$(T_FoundOldSeeManual)" leave: FunctionEnd #----------------------------------------------- # Strings pertaining to the install options page #----------------------------------------------- # Installation options title LangString T_InstallOptions ${LANG_ENGLISH} "Install Options" # Installation options subtitle 1 LangString T_InstallOptLinks ${LANG_ENGLISH} "Start links" LangString T_InstOptLabelA ${LANG_ENGLISH} \ "Please select where Gpg4win shall install links:" LangString T_InstOptLabelB ${LANG_ENGLISH} \ "(Only programs will be linked into the quick launch bar.)" LangString T_InstOptFieldA ${LANG_ENGLISH} \ "Start Menu" LangString T_InstOptFieldB ${LANG_ENGLISH} \ "Desktop" LangString T_InstOptFieldC ${LANG_ENGLISH} \ "Quick Launch Bar" #------------------------------------------------ # String pertaining to the existing version check #------------------------------------------------ LangString T_FoundExistingVersion ${LANG_ENGLISH} \ "Version $R1 has already been installed. $\r$\n\ Do you want to overwrite it with version ${VERSION}?" LangString T_FoundExistingOldVersion ${LANG_ENGLISH} \ "An old version $R1 has already been installed. It is \ strongly recommended to deinstall previous versions on \ major upgrades. $\r$\n\ Do you want to continue installing Gpg4win ${VERSION} anyway?" LangString T_UninstallingOldVersion ${LANG_ENGLISH} \ "Uninstalling Gpg4win-" #--------------------------------------------- # From the old installation checking functions #--------------------------------------------- LangString T_FoundOldSeeManual ${LANG_ENGLISH} \ "Please see the Gpg4win user manual to learn how to migrate existing \ keys from other GnuPG based installations to Gpg4win." #--------- LangString T_FoundOldGnuPP ${LANG_ENGLISH} \ "An old installation of GnuPP (GNU Privacy Project) has been been \ detected. That software is not maintained anymore and thus should \ be removed. $\r$\n\ $\r$\n\ Do you want to continue installing Gpg4win and take care of the old \ installation later?" #--------- LangString T_FoundOldGnuPT ${LANG_ENGLISH} \ "An installation of GnuPT has been been detected. This may cause \ problems when used along with Gpg4win. $\r$\n\ $\r$\n\ Do you want to continue installing Gpg4win?" #--------- LangString T_FoundOldWinPTSF ${LANG_ENGLISH} \ "An old installation of the Sourceforge hosted WinPT has been been \ detected. That software is not maintained anymore and should \ be removed. $\r$\n\ $\r$\n\ Do you want to continue installing Gpg4win and take care of the old \ installation later?" #-------- LangString T_FoundOldGnuPack ${LANG_ENGLISH} \ "An installation of GnuPG-Pack has been been detected. You need to \ uninstall it before you can continue with Gpg4win installation. $\r$\n\ $\r$\n\ The installation will be aborted now!" # From Function PrintBetaWarning LangString T_BetaWarning ${LANG_ENGLISH} \ "Note: This is a BETA version of Gpg4win. $\r$\n\ $\r$\n\ Beta versions are only intended for testing and \ shall not be used in a production environment." # From Function PrintNonAdminWarning LangString T_AdminNeeded ${LANG_ENGLISH} \ "Warning: Administrator permissions required for a successful installation" # From Function PrintCloseOtherApps LangString T_CloseOtherApps ${LANG_ENGLISH} \ "Please make sure that other applications are not running. \ In particular you should close Outlook and all Explorer \ windows. Gpg4win will try to install anyway but a reboot \ will be required then." LangString T_ShuttingDownWinPT ${LANG_ENGLISH} \ "Trying to shutdown a possible running instance of WinPT." # From Function CheckClawsUninstall LangString T_FoundOldClaws ${LANG_ENGLISH} \ "An old version of Claws Mail was found in your Installation directory. \ $\r$\nPlease note that Claws Mail is no longer bundled with Gpg4win \ and is now available as a standalone package.$\r$\n\ You should uninstall Claws Mail now, and if you wish to \ continue to use it, install an up-to-date version from:$\r$\n\ http://www.claws-mail.org/win32 $\r$\n$\r$\n\ Uninstall Claws Mail from Gpg4win now?" # FIXME: The GetAfterChar function comes from the NSIS wiki. Function un.GetAfterChar Exch $0 ; chop char Exch Exch $1 ; input string Push $2 Push $3 StrCpy $2 0 loop: IntOp $2 $2 - 1 StrCpy $3 $1 1 $2 StrCmp $3 "" 0 +3 StrCpy $0 "" Goto exit2 StrCmp $3 $0 exit1 Goto loop exit1: IntOp $2 $2 + 1 StrCpy $0 $1 "" $2 exit2: Pop $3 Pop $2 Pop $1 Exch $0 ; output FunctionEnd Function un.SourceDelete Push "/" Call un.GetAfterChar Pop $R0 Delete "$INSTDIR\$R0" FunctionEnd # StrStr - taken from the NSIS reference # input, top of stack = string to search for # top of stack-1 = string to search in # output, top of stack (replaces with the portion of the string remaining) # modifies no other variables. # # Usage: # Push "this is a long ass string" # Push "ass" # Call StrStr # Pop $R0 # ($R0 at this point is "ass string") # !macro StrStr un Function ${un}StrStr Exch $R1 # st=haystack,old$R1, $R1=needle Exch # st=old$R1,haystack Exch $R2 # st=old$R1,old$R2, $R2=haystack Push $R3 Push $R4 Push $R5 StrLen $R3 $R1 StrCpy $R4 0 # $R1=needle # $R2=haystack # $R3=len(needle) # $R4=cnt # $R5=tmp loop: StrCpy $R5 $R2 $R3 $R4 StrCmp $R5 $R1 done StrCmp $R5 "" done IntOp $R4 $R4 + 1 Goto loop done: StrCpy $R1 $R2 "" $R4 Pop $R5 Pop $R4 Pop $R3 Pop $R2 Exch $R1 FunctionEnd !macroend !insertmacro StrStr "" !insertmacro StrStr "un." # TrimNewlines - taken from the NSIS reference # input, top of stack (e.g. whatever$\r$\n) # output, top of stack (replaces, with e.g. whatever) # modifies no other variables. Function TrimNewlines Exch $R0 Push $R1 Push $R2 StrCpy $R1 0 loop: IntOp $R1 $R1 - 1 StrCpy $R2 $R0 1 $R1 StrCmp $R2 "$\r" loop StrCmp $R2 "$\n" loop IntOp $R1 $R1 + 1 IntCmp $R1 0 no_trim_needed StrCpy $R0 $R0 $R1 no_trim_needed: Pop $R2 Pop $R1 Exch $R0 FunctionEnd -# AddToPath - Adds the given dir to the search path. -# Input - head of the stack -Function AddToPath - Exch $0 - g4wihelp::path_add "$0" - StrCmp $R5 "0" add_to_path_done - SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 - add_to_path_done: - Pop $0 -FunctionEnd - -# RemoveFromPath - Remove a given dir from the path -# Input: head of the stack -Function un.RemoveFromPath - Exch $0 - g4wihelp::path_remove "$0" - StrCmp $R5 "0" remove_from_path_done - SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 - remove_from_path_done: - Pop $0 -FunctionEnd - Function .onInit Call G4wRunOnce SetOutPath $TEMP !ifdef SOURCES File /oname=gpgspltmp.bmp "${TOP_SRCDIR}/doc/logo/gpg4win-logo-400px.bmp" # We play the tune only for the source installer File /oname=gpgspltmp.wav "${TOP_SRCDIR}/src/gpg4win-splash.wav" g4wihelp::playsound $TEMP\gpgspltmp.wav g4wihelp::showsplash 2500 $TEMP\gpgspltmp.bmp Delete $TEMP\gpgspltmp.bmp # Note that we delete gpgspltmp.wav in .onInst{Failed,Success} !endif # Enable this to force a language selection dialog on every run (the # preferred language is the default). Otherwise, the preferred # language is stored in the registry, and the installer does not ask # on upgrades. !ifdef DEBUG !define MUI_LANGDLL_ALWAYSSHOW !endif !insertmacro MUI_LANGDLL_DISPLAY ${MementoSectionRestore} Call CalcDefaults Call CalcDepends Call CheckOtherGnuPGApps FunctionEnd Function un.onInit # Remove the language preference. !insertmacro MUI_UNGETLANGUAGE FunctionEnd # This must be in a central place. Urgs. !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !ifdef HAVE_PKG_GNUPG_W32 !insertmacro MUI_DESCRIPTION_TEXT ${SEC_gnupg_w32} $(DESC_SEC_gnupg_w32) !endif !ifdef HAVE_PKG_GPGOL !insertmacro MUI_DESCRIPTION_TEXT ${SEC_gpgol} $(DESC_SEC_gpgol) !endif !ifdef HAVE_PKG_GPGEX !insertmacro MUI_DESCRIPTION_TEXT ${SEC_gpgex} $(DESC_SEC_gpgex) !endif !ifdef HAVE_PKG_PAPERKEY !insertmacro MUI_DESCRIPTION_TEXT ${SEC_paperkey} $(DESC_SEC_paperkey) !endif !ifdef HAVE_PKG_GPA !insertmacro MUI_DESCRIPTION_TEXT ${SEC_gpa} $(DESC_SEC_gpa) !endif !ifdef HAVE_PKG_KLEOPATRA !insertmacro MUI_DESCRIPTION_TEXT ${SEC_kleopatra} $(DESC_SEC_kleopatra) !endif !ifdef HAVE_PKG_MAN_NOVICE_EN !insertmacro MUI_DESCRIPTION_TEXT ${SEC_man_novice_en} $(DESC_SEC_man_novice_en) !endif !ifdef HAVE_PKG_MAN_ADVANCED_EN !insertmacro MUI_DESCRIPTION_TEXT ${SEC_man_advanced_en} $(DESC_SEC_man_advanced_en) !endif !ifdef HAVE_PKG_COMPENDIUM !insertmacro MUI_DESCRIPTION_TEXT ${SEC_compendium} $(DESC_SEC_compendium) !endif !ifdef HAVE_PKG_MAN_NOVICE_DE !insertmacro MUI_DESCRIPTION_TEXT ${SEC_man_novice_de} $(DESC_SEC_man_novice_de) !endif !ifdef HAVE_PKG_MAN_ADVANCED_DE !insertmacro MUI_DESCRIPTION_TEXT ${SEC_man_advanced_de} $(DESC_SEC_man_advanced_de) !endif !insertmacro MUI_FUNCTION_DESCRIPTION_END diff --git a/src/uninst-gpg4win.nsi b/src/uninst-gpg4win.nsi index 22820e78..80e77d6b 100644 --- a/src/uninst-gpg4win.nsi +++ b/src/uninst-gpg4win.nsi @@ -1,146 +1,142 @@ # uninst-gpg4win.nsi - Hidden uninstaller. -*- coding: latin-1; -*- # Copyright (C) 2005 g10 Code GmbH # # This file is part of GPG4Win. # # GPG4Win is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GPG4Win 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA # This is the very last section of the uninstaller. Section "-un.gpg4win" !ifdef SOURCES Delete "gpg4win-${VERSION}.tar.bz2" !else DeleteRegValue HKLM "Software\GNU\GnuPG" "Install Directory" - # Remove the public directory from the PATH - Push "$INSTDIR\pub" - Call un.RemoveFromPath - # Delete gpg4win included tools Delete "$INSTDIR\bin\sha1sum.exe" Delete "$INSTDIR\bin\sha256sum.exe" Delete "$INSTDIR\bin\md5sum.exe" Delete "$INSTDIR\bin\mkportable.exe" # Delete the runtime libaries Delete "$INSTDIR\bin\libstdc++-6.dll" Delete "$INSTDIR\bin\libgcc_s_sjlj-1.dll" Delete "$INSTDIR\bin\libwinpthread-1.dll" # Delete standard stuff. Delete "$INSTDIR\share\gpg4win\README.*.txt" Delete "$INSTDIR\share\gpg4win\HOWTO-SMIME.*.txt" Delete "$INSTDIR\share\gpg4win\versioninfo.txt" Delete "$INSTDIR\VERSION" RMDir "$INSTDIR\share\gpg4win" # Remove the locale directories. RMDir "$INSTDIR\share\locale\ar\LC_MESSAGES" RMDir "$INSTDIR\share\locale\ar" RMDir "$INSTDIR\share\locale\be\LC_MESSAGES" RMDir "$INSTDIR\share\locale\be" RMDir "$INSTDIR\share\locale\bg\LC_MESSAGES" RMDir "$INSTDIR\share\locale\bg" RMDir "$INSTDIR\share\locale\ca\LC_MESSAGES" RMDir "$INSTDIR\share\locale\ca" RMDir "$INSTDIR\share\locale\cs\LC_MESSAGES" RMDir "$INSTDIR\share\locale\cs" RMDir "$INSTDIR\share\locale\da\LC_MESSAGES" RMDir "$INSTDIR\share\locale\da" RMDir "$INSTDIR\share\locale\de\LC_MESSAGES" RMDir "$INSTDIR\share\locale\de" RMDir "$INSTDIR\share\locale\el\LC_MESSAGES" RMDir "$INSTDIR\share\locale\el" RMDir "$INSTDIR\share\locale\en@boldquot\LC_MESSAGES" RMDir "$INSTDIR\share\locale\en@boldquot" RMDir "$INSTDIR\share\locale\en@quot\LC_MESSAGES" RMDir "$INSTDIR\share\locale\en@quot" RMDir "$INSTDIR\share\locale\en_GB\LC_MESSAGES" RMDir "$INSTDIR\share\locale\en_GB" RMDir "$INSTDIR\share\locale\eo\LC_MESSAGES" RMDir "$INSTDIR\share\locale\eo" RMDir "$INSTDIR\share\locale\es\LC_MESSAGES" RMDir "$INSTDIR\share\locale\es" RMDir "$INSTDIR\share\locale\et\LC_MESSAGES" RMDir "$INSTDIR\share\locale\et" RMDir "$INSTDIR\share\locale\fi\LC_MESSAGES" RMDir "$INSTDIR\share\locale\fi" RMDir "$INSTDIR\share\locale\fr\LC_MESSAGES" RMDir "$INSTDIR\share\locale\fr" RMDir "$INSTDIR\share\locale\gl\LC_MESSAGES" RMDir "$INSTDIR\share\locale\gl" RMDir "$INSTDIR\share\locale\hu\LC_MESSAGES" RMDir "$INSTDIR\share\locale\hu" RMDir "$INSTDIR\share\locale\id\LC_MESSAGES" RMDir "$INSTDIR\share\locale\id" RMDir "$INSTDIR\share\locale\id_ID\LC_MESSAGES" RMDir "$INSTDIR\share\locale\id_ID" RMDir "$INSTDIR\share\locale\it\LC_MESSAGES" RMDir "$INSTDIR\share\locale\it" RMDir "$INSTDIR\share\locale\ja\LC_MESSAGES" RMDir "$INSTDIR\share\locale\ja" RMDir "$INSTDIR\share\locale\nb\LC_MESSAGES" RMDir "$INSTDIR\share\locale\nb" RMDir "$INSTDIR\share\locale\nl\LC_MESSAGES" RMDir "$INSTDIR\share\locale\nl" RMDir "$INSTDIR\share\locale\pl\LC_MESSAGES" RMDir "$INSTDIR\share\locale\pl" RMDir "$INSTDIR\share\locale\pt_BR\LC_MESSAGES" RMDir "$INSTDIR\share\locale\pt_BR" RMDir "$INSTDIR\share\locale\pt_PT\LC_MESSAGES" RMDir "$INSTDIR\share\locale\pt_PT" RMDir "$INSTDIR\share\locale\pt\LC_MESSAGES" RMDir "$INSTDIR\share\locale\pt" RMDir "$INSTDIR\share\locale\ro\LC_MESSAGES" RMDir "$INSTDIR\share\locale\ro" RMDir "$INSTDIR\share\locale\ru\LC_MESSAGES" RMDir "$INSTDIR\share\locale\ru" RMDir "$INSTDIR\share\locale\sk\LC_MESSAGES" RMDir "$INSTDIR\share\locale\sk" RMDir "$INSTDIR\share\locale\sv\LC_MESSAGES" RMDir "$INSTDIR\share\locale\sv" RMDir "$INSTDIR\share\locale\sr\LC_MESSAGES" RMDir "$INSTDIR\share\locale\sr" RMDir "$INSTDIR\share\locale\tr\LC_MESSAGES" RMDir "$INSTDIR\share\locale\tr" RMDir "$INSTDIR\share\locale\uk\LC_MESSAGES" RMDir "$INSTDIR\share\locale\uk" RMDir "$INSTDIR\share\locale\zh_CN\LC_MESSAGES" RMDir "$INSTDIR\share\locale\zh_CN" RMDir "$INSTDIR\share\locale\zh_TW\LC_MESSAGES" RMDir "$INSTDIR\share\locale\zh_TW" RMDir "$INSTDIR\share\locale" # Try again to remove the scdaemon. This is useful because scdaemon # needs some time to stop after gpg-agent has been stopped. Delete "$INSTDIR\bin\scdaemon.exe" # Try to remove other top directories. RMDir "$INSTDIR\lib" RMDir "$INSTDIR\include" RMDir "$INSTDIR\share" RMDir "$INSTDIR\pub" RMDir "$INSTDIR\etc" RMDir "$INSTDIR" !endif SectionEnd