diff --git a/main.c b/main.c index 13c09b2..be3a63c 100644 --- a/main.c +++ b/main.c @@ -55,6 +55,10 @@ #include #endif +#define OVPN_EXITCODE_ERROR 1 +#define OVPN_EXITCODE_TIMEOUT 2 +#define OVPN_EXITCODE_NOTREADY 3 + /* Declare Windows procedure */ LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); static void ShowSettingsDialog(); @@ -75,21 +79,10 @@ static int VerifyAutoConnections() { int i; - BOOL match; for (i = 0; i < MAX_CONFIGS && o.auto_connect[i] != 0; i++) { - int j; - match = FALSE; - for (j = 0; j < MAX_CONFIGS; j++) - { - if (_tcsicmp(o.conn[j].config_file, o.auto_connect[i]) == 0) - { - match = TRUE; - break; - } - } - if (match == FALSE) + if (GetConnByName(o.auto_connect[i]) == NULL) { /* autostart config not found */ ShowLocalizedMsg(IDS_ERR_AUTOSTART_CONF, o.auto_connect[i]); @@ -100,6 +93,49 @@ VerifyAutoConnections() return TRUE; } +/* + * Send a copydata message corresponding to any --command action option specified + * to the running instance and return success or error. + */ +static int +NotifyRunningInstance() +{ + /* Check if a previous instance has a window initialized + * Even if we are not the first instance this may return null + * if the previous instance has not fully started up + */ + HANDLE hwnd_master = FindWindow (szClassName, NULL); + int exit_code = 0; + if (hwnd_master) + { + /* GUI up and running -- send a message if any action is pecified, + else show the balloon */ + COPYDATASTRUCT config_data = {0}; + int timeout = 30*1000; /* 30 seconds */ + if (!o.action) + { + o.action = WM_OVPN_NOTIFY; + o.action_arg = LoadLocalizedString(IDS_NFO_CLICK_HERE_TO_START); + } + config_data.dwData = o.action; + if (o.action_arg) + { + config_data.cbData = (wcslen(o.action_arg)+1)*sizeof(o.action_arg[0]); + config_data.lpData = (void *) o.action_arg; + } + PrintDebug(L"Instance 2: called with action %d : %s", o.action, o.action_arg); + if (!SendMessageTimeout (hwnd_master, WM_COPYDATA, 0, + (LPARAM) &config_data, 0, timeout, NULL)) + exit_code = OVPN_EXITCODE_TIMEOUT; + } + else + { + PrintDebug(L"Instance 2: Previous instance not yet ready to accept comamnds"); + exit_code = OVPN_EXITCODE_NOTREADY; + } + PrintDebug(L"Instance 2: Returning exit code %d", exit_code); + return exit_code; +} int WINAPI _tWinMain (HINSTANCE hThisInstance, UNUSED HINSTANCE hPrevInstance, @@ -109,6 +145,16 @@ int WINAPI _tWinMain (HINSTANCE hThisInstance, MSG messages; /* Here messages to the application are saved */ WNDCLASSEX wincl; /* Data structure for the windowclass */ DWORD shell32_version; + BOOL first_instance = TRUE; + /* a session local semaphore to detect second instance */ + HANDLE session_semaphore = InitSemaphore(L"Local\\"PACKAGE_NAME); + + /* try to lock the semaphore, else we are not the first instance */ + if (session_semaphore && + WaitForSingleObject(session_semaphore, 0) != WAIT_OBJECT_0) + { + first_instance = FALSE; + } /* Initialize handlers for manangement interface notifications */ mgmt_rtmsg_handler handler[] = { @@ -166,16 +212,8 @@ int WINAPI _tWinMain (HINSTANCE hThisInstance, PrintDebug(_T("Shell32.dll version: 0x%lx"), shell32_version); #endif - - /* Check if a previous instance is already running. */ - if ((FindWindow (szClassName, NULL)) != NULL) - { - /* GUI already running */ - ShowLocalizedMsg(IDS_ERR_GUI_ALREADY_RUNNING); - exit(1); - } - - UpdateRegistry(); /* Checks version change and update keys/values */ + if (first_instance) + UpdateRegistry(); /* Checks version change and update keys/values */ GetRegistryKeys(); /* Parse command-line options */ @@ -183,6 +221,21 @@ int WINAPI _tWinMain (HINSTANCE hThisInstance, EnsureDirExists(o.config_dir); + if (!first_instance) + { + int res = NotifyRunningInstance(); + exit(res); + } + else if (o.action == WM_OVPN_START) + { + PrintDebug(L"Instance 1: Called with --command connect xxx. Treating it as --connect xxx"); + } + else if (o.action) + { + PrintDebug(L"Instance 1: Called with --command when no previous instance available"); + exit(OVPN_EXITCODE_ERROR); + } + if (!CheckVersion()) { exit(1); } @@ -200,6 +253,7 @@ int WINAPI _tWinMain (HINSTANCE hThisInstance, if (!VerifyAutoConnections()) { exit(1); } + GetProxyRegistrySettings(); #ifndef DISABLE_CHANGE_PASSWORD @@ -350,6 +404,68 @@ dpi_initialize(void) dpi_setscale(dpix); } +static int +HandleCopyDataMessage(const COPYDATASTRUCT *copy_data) +{ + WCHAR *str = NULL; + connection_t *c = NULL; + PrintDebug (L"WM_COPYDATA message received. (dwData: %lu, cbData: %lu, lpData: %s)", + copy_data->dwData, copy_data->cbData, copy_data->lpData); + if (copy_data->cbData >= sizeof(WCHAR) && copy_data->lpData) + { + str = (WCHAR*) copy_data->lpData; + str[copy_data->cbData/sizeof(WCHAR)-1] = L'\0'; /* in case not nul-terminated */ + c = GetConnByName(str); + } + if(copy_data->dwData == WM_OVPN_START && c) + { + if (!o.silent_connection) + ForceForegroundWindow(o.hWnd); + StartOpenVPN(c); + } + else if(copy_data->dwData == WM_OVPN_STOP && c) + StopOpenVPN(c); + else if(copy_data->dwData == WM_OVPN_RESTART && c) + { + if (!o.silent_connection) + ForceForegroundWindow(o.hWnd); + RestartOpenVPN(c); + } + else if(copy_data->dwData == WM_OVPN_SHOWSTATUS && c->hwndStatus && c) + { + ForceForegroundWindow(o.hWnd); + ShowWindow(c->hwndStatus, SW_SHOW); + } + else if(copy_data->dwData == WM_OVPN_STOPALL) + StopAllOpenVPN(); + else if(copy_data->dwData == WM_OVPN_SILENT && str) + { + if (_wtoi(str) == 0) + o.silent_connection = 0; + else + o.silent_connection = 1; + } + else if(copy_data->dwData == WM_OVPN_EXIT) + { + CloseApplication(o.hWnd); + } + /* Not yet implemented + else if(copy_data->dwData == WM_OVPN_IMPORT) + { + } + */ + else if (copy_data->dwData == WM_OVPN_NOTIFY) + { + ShowTrayBalloon(L"", copy_data->lpData); + } + else + { + PrintDebug (L"WM_COPYDATA message ignored. (dwData: %lu, cbData: %lu)", + copy_data->dwData, copy_data->cbData); + } + return TRUE; /* indicate we handled the message */ +} + /* This function is called by the Windows function DispatchMessage() */ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -373,6 +489,11 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM SendMessage(hwnd, WM_SETICON, (WPARAM) (ICON_BIG), (LPARAM) (hIcon)); } + /* Enable next line to accept WM_COPYDATA messages from lower level processes */ +#if 0 + ChangeWindowMessageFilterEx(hwnd, WM_COPYDATA, MSGFLT_ALLOW, NULL); +#endif + CreatePopupMenus(); /* Create popup menus */ ShowTrayIcon(); if (o.service_only) @@ -387,6 +508,10 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM OnNotifyTray(lParam); // Manages message from tray break; + case WM_COPYDATA: // custom messages with data from other processes + HandleCopyDataMessage((COPYDATASTRUCT*) lParam); + return TRUE; /* lets the sender free copy_data */ + case WM_COMMAND: if ( (LOWORD(wParam) >= IDM_CONNECTMENU) && (LOWORD(wParam) < IDM_CONNECTMENU + MAX_CONFIGS) ) { StartOpenVPN(&o.conn[LOWORD(wParam) - IDM_CONNECTMENU]); @@ -394,6 +519,9 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM if ( (LOWORD(wParam) >= IDM_DISCONNECTMENU) && (LOWORD(wParam) < IDM_DISCONNECTMENU + MAX_CONFIGS) ) { StopOpenVPN(&o.conn[LOWORD(wParam) - IDM_DISCONNECTMENU]); } + if ( (LOWORD(wParam) >= IDM_RECONNECTMENU) && (LOWORD(wParam) < IDM_RECONNECTMENU + MAX_CONFIGS) ) { + RestartOpenVPN(&o.conn[LOWORD(wParam) - IDM_RECONNECTMENU]); + } if ( (LOWORD(wParam) >= IDM_STATUSMENU) && (LOWORD(wParam) < IDM_STATUSMENU + MAX_CONFIGS) ) { ShowWindow(o.conn[LOWORD(wParam) - IDM_STATUSMENU].hwndStatus, SW_SHOW); } diff --git a/main.h b/main.h index 1b2f61e..ba17e45 100644 --- a/main.h +++ b/main.h @@ -45,6 +45,21 @@ /* Authorized group who can use any options and config locations */ #define OVPN_ADMIN_GROUP TEXT("OpenVPN Administrators") /* May be reset in registry */ +/* Application defined message IDs */ +#define WM_NOTIFYICONTRAY (WM_APP + 1) +#define WM_MANAGEMENT (WM_APP + 2) + +#define WM_OVPN_STOP (WM_APP + 10) +#define WM_OVPN_SUSPEND (WM_APP + 11) +#define WM_OVPN_RESTART (WM_APP + 12) +#define WM_OVPN_START (WM_APP + 13) +#define WM_OVPN_STOPALL (WM_APP + 14) +#define WM_OVPN_SHOWSTATUS (WM_APP + 15) +#define WM_OVPN_NOTIFY (WM_APP + 16) +#define WM_OVPN_EXIT (WM_APP + 17) +#define WM_OVPN_SILENT (WM_APP + 18) +#define WM_OVPN_IMPORT (WM_APP + 20) + /* bool definitions */ #define bool int #define true 1 diff --git a/manage.h b/manage.h index 1b89f41..94632bd 100644 --- a/manage.h +++ b/manage.h @@ -24,8 +24,6 @@ #include -#define WM_MANAGEMENT (WM_APP + 2) - typedef enum { ready, stop, diff --git a/misc.c b/misc.c index fb1e5d9..ec36fad 100644 --- a/misc.c +++ b/misc.c @@ -396,10 +396,10 @@ BOOL IsUserAdmin(VOID) } HANDLE -InitSemaphore (void) +InitSemaphore (WCHAR *name) { HANDLE semaphore = NULL; - semaphore = CreateSemaphore (NULL, 1, 1, NULL); + semaphore = CreateSemaphore (NULL, 1, 1, name); if (!semaphore) { MessageBoxW (NULL, L"Error creating semaphore", TEXT(PACKAGE_NAME), MB_OK); diff --git a/misc.h b/misc.h index f7f43cc..0480eeb 100644 --- a/misc.h +++ b/misc.h @@ -33,7 +33,7 @@ BOOL wcsbegins(LPCWSTR, LPCWSTR); BOOL ForceForegroundWindow(HWND); BOOL IsUserAdmin(VOID); -HANDLE InitSemaphore (void); +HANDLE InitSemaphore (WCHAR *); BOOL CheckFileAccess (const TCHAR *path, int access); BOOL Base64Encode(const char *input, int input_len, char **output); diff --git a/openvpn-gui-res.h b/openvpn-gui-res.h index a46b263..cce2457 100644 --- a/openvpn-gui-res.h +++ b/openvpn-gui-res.h @@ -149,6 +149,7 @@ #define IDS_MENU_ASK_STOP_SERVICE 1022 #define IDS_MENU_IMPORT 1023 #define IDS_MENU_CLEARPASS 1024 +#define IDS_MENU_RECONNECT 1025 /* LogViewer Dialog */ #define IDS_ERR_START_LOG_VIEWER 1101 @@ -215,6 +216,7 @@ #define IDS_NFO_ACTIVE_CONN_EXIT 1307 #define IDS_NFO_SERVICE_ACTIVE_EXIT 1308 #define IDS_ERR_CREATE_PATH 1309 +#define IDS_NFO_CLICK_HERE_TO_START 1310 /* Program Options Related */ #define IDS_NFO_USAGE 1401 diff --git a/openvpn.c b/openvpn.c index 030c4c9..e6155fe 100644 --- a/openvpn.c +++ b/openvpn.c @@ -50,9 +50,6 @@ #include "access.h" #include "save_pass.h" -#define WM_OVPN_STOP (WM_APP + 10) -#define WM_OVPN_SUSPEND (WM_APP + 11) - extern options_t o; static BOOL @@ -1565,7 +1562,7 @@ StatusDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) case ID_RESTART: c->state = reconnecting; SetFocus(GetDlgItem(c->hwndStatus, ID_EDT_LOG)); - ManagementCommand(c, "signal SIGHUP", NULL, regular); + RestartOpenVPN(c); return TRUE; } break; @@ -1597,6 +1594,9 @@ StatusDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) case WM_OVPN_STOP: c = (connection_t *) GetProp(hwndDlg, cfgProp); + /* external messages can trigger when we are not ready -- check the state */ + if (!IsWindowEnabled(GetDlgItem(c->hwndStatus, ID_DISCONNECT))) + break; c->state = disconnecting; RunDisconnectScript(c, false); EnableWindow(GetDlgItem(c->hwndStatus, ID_DISCONNECT), FALSE); @@ -1604,7 +1604,7 @@ StatusDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) SetMenuStatus(c, disconnecting); SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_WAIT_TERM)); SetEvent(c->exit_event); - SetTimer(hwndDlg, IDT_STOP_TIMER, 3000, NULL); + SetTimer(hwndDlg, IDT_STOP_TIMER, 15000, NULL); break; case WM_OVPN_SUSPEND: @@ -1615,7 +1615,7 @@ StatusDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) SetMenuStatus(c, disconnecting); SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_WAIT_TERM)); SetEvent(c->exit_event); - SetTimer(hwndDlg, IDT_STOP_TIMER, 3000, NULL); + SetTimer(hwndDlg, IDT_STOP_TIMER, 15000, NULL); break; case WM_TIMER: @@ -1628,6 +1628,18 @@ StatusDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) KillTimer (hwndDlg, IDT_STOP_TIMER); } break; + + case WM_OVPN_RESTART: + c = (connection_t *) GetProp(hwndDlg, cfgProp); + /* external messages can trigger when we are not ready -- check the state */ + if (IsWindowEnabled(GetDlgItem(c->hwndStatus, ID_RESTART))) + ManagementCommand(c, "signal SIGHUP", NULL, regular); + if (!o.silent_connection) + { + SetForegroundWindow(c->hwndStatus); + ShowWindow(c->hwndStatus, SW_SHOW); + } + break; } return FALSE; } @@ -1749,12 +1761,19 @@ StartOpenVPN(connection_t *c) if (c->hwndStatus) { - PrintDebug(L"Connection request when previous status window is still open -- ignored"); - WriteStatusLog(c, L"OpenVPN GUI> ", - L"Complete the pending dialog before starting a new connection", false); - SetForegroundWindow(c->hwndStatus); + PrintDebug(L"Connection request when already started -- ignored"); + /* the tread can hang around after disconnect if user has not dismissed any popups */ + if (c->state == disconnected) + WriteStatusLog(c, L"OpenVPN GUI> ", + L"Complete any pending dialog before starting a new connection", false); + if (!o.silent_connection) + { + SetForegroundWindow(c->hwndStatus); + ShowWindow(c->hwndStatus, SW_SHOW); + } return FALSE; } + PrintDebug(L"Starting openvpn on config %s", c->config_name); RunPreconnectScript(c); @@ -1955,6 +1974,14 @@ SuspendOpenVPN(int config) PostMessage(o.conn[config].hwndStatus, WM_OVPN_SUSPEND, 0, 0); } +void +RestartOpenVPN(connection_t *c) +{ + if (c->hwndStatus) + PostMessage(c->hwndStatus, WM_OVPN_RESTART, 0, 0); + else /* Not started: treat this as a request to connect */ + StartOpenVPN(c); +} void SetStatusWinIcon(HWND hwndDlg, int iconId) diff --git a/openvpn.h b/openvpn.h index 2bfa1d2..f1d6860 100644 --- a/openvpn.h +++ b/openvpn.h @@ -26,6 +26,7 @@ BOOL StartOpenVPN(connection_t *); void StopOpenVPN(connection_t *); void SuspendOpenVPN(int config); +void RestartOpenVPN(connection_t *); BOOL CheckVersion(); void SetStatusWinIcon(HWND hwndDlg, int IconID); diff --git a/openvpn_config.c b/openvpn_config.c index e1a02dc..5580adb 100644 --- a/openvpn_config.c +++ b/openvpn_config.c @@ -114,7 +114,8 @@ AddConfigFileToList(int config, const TCHAR *filename, const TCHAR *config_dir) /* Check if connection should be autostarted */ for (i = 0; i < MAX_CONFIGS && o.auto_connect[i]; ++i) { - if (_tcsicmp(c->config_file, o.auto_connect[i]) == 0) + if (_tcsicmp(c->config_file, o.auto_connect[i]) == 0 + || _tcsicmp(c->config_name, o.auto_connect[i]) == 0) { c->auto_connect = true; break; diff --git a/options.c b/options.c index cf3cf15..bfbd371 100644 --- a/options.c +++ b/options.c @@ -101,6 +101,14 @@ add_option(options_t *options, int i, TCHAR **p) exit(1); } options->auto_connect[auto_connect_nr++] = p[1]; + /* Treat the first connect option to also mean --command connect profile. + * This gets used if we are not the first instance. + */ + if (auto_connect_nr == 1) + { + options->action = WM_OVPN_START; + options->action_arg = p[1]; + } } else if (streq(p[0], _T("exe_path")) && p[1]) { @@ -203,6 +211,56 @@ add_option(options_t *options, int i, TCHAR **p) ++i; options->preconnectscript_timeout = _ttoi(p[1]); } + else if (streq(p[0], _T("command")) && p[1]) + { + ++i; + /* command to be sent to a running instance */ + if (streq(p[1], _T("connect")) && p[2]) + { + /* Treat this as "--connect profile" in case this is the first instance */ + add_option(options, i, &p[1]); + ++i; + options->action = WM_OVPN_START; + options->action_arg = p[2]; + } + else if (streq(p[1], _T("disconnect")) && p[2]) + { + ++i; + options->action = WM_OVPN_STOP; + options->action_arg = p[2]; + } + else if (streq(p[1], _T("reconnect")) && p[2]) + { + ++i; + options->action = WM_OVPN_RESTART; + options->action_arg = p[2]; + } + else if (streq(p[1], _T("status")) && p[2]) + { + ++i; + options->action = WM_OVPN_SHOWSTATUS; + options->action_arg = p[2]; + } + else if (streq(p[1], _T("silent_connection"))) + { + ++i; + options->action = WM_OVPN_SILENT; + options->action_arg = p[2] ? p[2] : _T("1"); + } + else if (streq(p[1], _T("disconnect_all"))) + { + options->action = WM_OVPN_STOPALL; + } + else if (streq(p[1], _T("exit"))) + { + options->action = WM_OVPN_EXIT; + } + else + { + ShowLocalizedMsg(IDS_ERR_BAD_OPTION, p[0]); + exit(1); + } + } else { /* Unrecognized option or missing parameter */ @@ -252,7 +310,7 @@ void InitOptions(options_t *opt) { CLEAR(*opt); - opt->netcmd_semaphore = InitSemaphore (); + opt->netcmd_semaphore = InitSemaphore (NULL); opt->version = MakeVersion (PACKAGE_VERSION_RESOURCE); opt->clr_warning = RGB(0xff, 0, 0); opt->clr_error = RGB(0xff, 0, 0); @@ -354,6 +412,18 @@ GetConnByManagement(SOCKET sk) return NULL; } +connection_t* +GetConnByName(const WCHAR *name) +{ + for (int i = 0; i < o.num_configs; ++i) + { + if (wcsicmp (o.conn[i].config_file, name) == 0 + || wcsicmp(o.conn[i].config_name, name) == 0) + return &o.conn[i]; + } + return NULL; +} + /* callback to set the initial value of folder browse selection */ static int CALLBACK BrowseCallback (HWND h, UINT msg, UNUSED LPARAM l, LPARAM data) diff --git a/options.h b/options.h index 5cae976..85468be 100644 --- a/options.h +++ b/options.h @@ -180,12 +180,15 @@ typedef struct { unsigned int dpi_scale; COLORREF clr_warning; COLORREF clr_error; + int action; /* action to send to a running instance */ + TCHAR *action_arg; } options_t; void InitOptions(options_t *); void ProcessCommandLine(options_t *, TCHAR *); int CountConnState(conn_state_t); connection_t* GetConnByManagement(SOCKET); +connection_t* GetConnByName(const WCHAR *config_name); INT_PTR CALLBACK ScriptSettingsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK ConnectionSettingsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK AdvancedSettingsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); diff --git a/res/openvpn-gui-res-en.rc b/res/openvpn-gui-res-en.rc index 7f521e4..a528cd2 100644 --- a/res/openvpn-gui-res-en.rc +++ b/res/openvpn-gui-res-en.rc @@ -247,6 +247,7 @@ BEGIN IDS_MENU_CLOSE "Exit" IDS_MENU_CONNECT "Connect" IDS_MENU_DISCONNECT "Disconnect" + IDS_MENU_RECONNECT "Reconnect" IDS_MENU_STATUS "Show Status" IDS_MENU_VIEWLOG "View Log" IDS_MENU_EDITCONFIG "Edit Config" @@ -342,6 +343,16 @@ BEGIN IDS_NFO_USAGE "--help\t\t\t: Show this message.\n" \ "--connect cnn \t\t: Connect to ""cnn"" at startup. (extension must be included)\n" \ "\t\t\t Example: openvpn-gui --connect office.ovpn\n" \ + "--command cmd [args]\t: Send a command to a running instance of the GUI\n" \ + "Supported commands:\n"\ + " connect cnn \t: connect the config named ""cnn""\n"\ + " disconnect cnn \t: disconnect the config named ""cnn""\n"\ + " reconnect cnn \t: reconnect the config named ""cnn""\n"\ + " disconnect_all \t: disconnect all connected configs\n"\ + " exit \t\t: terminate the running GUI instance (may ask for confirmation)\n"\ + " status cnn \t\t: show the status window of config ""cnn"" if connected\n"\ + " silent_connection [0|1]\t: set the silent_connection flag on (1) or off (0)\n"\ + "\t\t\tExample: openvpn-gui.exe --command disconnect myconfig\n"\ "\n" \ "Options to override registry settings:\n" \ "--exe_path\t\t: Path to openvpn.exe.\n" \ @@ -461,4 +472,6 @@ BEGIN IDS_ERR_INVALID_PASSWORD_INPUT "Invalid character in password" IDS_ERR_INVALID_USERNAME_INPUT "Invalid character in username" IDS_NFO_AUTO_CONNECT "Connecting automatically in %u seconds..." + IDS_NFO_CLICK_HERE_TO_START "OpenVPN GUI is already running. Right click on the tray icon to start." + END diff --git a/tray.c b/tray.c index ffbf3f3..7227e5d 100644 --- a/tray.c +++ b/tray.c @@ -63,6 +63,7 @@ CreatePopupMenus() if (o.service_only == 0) { AppendMenu(hMenu, MF_STRING, IDM_CONNECTMENU, LoadLocalizedString(IDS_MENU_CONNECT)); AppendMenu(hMenu, MF_STRING, IDM_DISCONNECTMENU, LoadLocalizedString(IDS_MENU_DISCONNECT)); + AppendMenu(hMenu, MF_STRING, IDM_RECONNECTMENU, LoadLocalizedString(IDS_MENU_RECONNECT)); AppendMenu(hMenu, MF_STRING, IDM_STATUSMENU, LoadLocalizedString(IDS_MENU_STATUS)); AppendMenu(hMenu, MF_SEPARATOR, 0, 0); } @@ -117,6 +118,7 @@ CreatePopupMenus() if (o.service_only == 0) { AppendMenu(hMenuConn[i], MF_STRING, IDM_CONNECTMENU + i, LoadLocalizedString(IDS_MENU_CONNECT)); AppendMenu(hMenuConn[i], MF_STRING, IDM_DISCONNECTMENU + i, LoadLocalizedString(IDS_MENU_DISCONNECT)); + AppendMenu(hMenuConn[i], MF_STRING, IDM_RECONNECTMENU + i, LoadLocalizedString(IDS_MENU_RECONNECT)); AppendMenu(hMenuConn[i], MF_STRING, IDM_STATUSMENU + i, LoadLocalizedString(IDS_MENU_STATUS)); AppendMenu(hMenuConn[i], MF_SEPARATOR, 0, 0); } @@ -349,18 +351,21 @@ SetMenuStatus(connection_t *c, conn_state_t state) { EnableMenuItem(hMenu, IDM_CONNECTMENU, MF_ENABLED); EnableMenuItem(hMenu, IDM_DISCONNECTMENU, MF_GRAYED); + EnableMenuItem(hMenu, IDM_RECONNECTMENU, MF_GRAYED); EnableMenuItem(hMenu, IDM_STATUSMENU, MF_GRAYED); } else if (state == connecting || state == resuming || state == connected) { EnableMenuItem(hMenu, IDM_CONNECTMENU, MF_GRAYED); EnableMenuItem(hMenu, IDM_DISCONNECTMENU, MF_ENABLED); + EnableMenuItem(hMenu, IDM_RECONNECTMENU, MF_ENABLED); EnableMenuItem(hMenu, IDM_STATUSMENU, MF_ENABLED); } else if (state == disconnecting) { EnableMenuItem(hMenu, IDM_CONNECTMENU, MF_GRAYED); EnableMenuItem(hMenu, IDM_DISCONNECTMENU, MF_GRAYED); + EnableMenuItem(hMenu, IDM_RECONNECTMENU, MF_GRAYED); EnableMenuItem(hMenu, IDM_STATUSMENU, MF_ENABLED); } if (c->flags & (FLAG_SAVE_AUTH_PASS | FLAG_SAVE_KEY_PASS)) @@ -384,18 +389,21 @@ SetMenuStatus(connection_t *c, conn_state_t state) { EnableMenuItem(hMenuConn[i], IDM_CONNECTMENU + i, MF_ENABLED); EnableMenuItem(hMenuConn[i], IDM_DISCONNECTMENU + i, MF_GRAYED); + EnableMenuItem(hMenuConn[i], IDM_RECONNECTMENU + i, MF_GRAYED); EnableMenuItem(hMenuConn[i], IDM_STATUSMENU + i, MF_GRAYED); } else if (state == connecting || state == resuming || state == connected) { EnableMenuItem(hMenuConn[i], IDM_CONNECTMENU + i, MF_GRAYED); EnableMenuItem(hMenuConn[i], IDM_DISCONNECTMENU + i, MF_ENABLED); + EnableMenuItem(hMenuConn[i], IDM_RECONNECTMENU + i, MF_ENABLED); EnableMenuItem(hMenuConn[i], IDM_STATUSMENU + i, MF_ENABLED); } else if (state == disconnecting) { EnableMenuItem(hMenuConn[i], IDM_CONNECTMENU + i, MF_GRAYED); EnableMenuItem(hMenuConn[i], IDM_DISCONNECTMENU + i, MF_GRAYED); + EnableMenuItem(hMenuConn[i], IDM_RECONNECTMENU + i, MF_GRAYED); EnableMenuItem(hMenuConn[i], IDM_STATUSMENU + i, MF_ENABLED); } if (c->flags & (FLAG_SAVE_AUTH_PASS | FLAG_SAVE_KEY_PASS)) diff --git a/tray.h b/tray.h index 88ee852..1ce5e07 100644 --- a/tray.h +++ b/tray.h @@ -25,8 +25,6 @@ #include "options.h" -#define WM_NOTIFYICONTRAY (WM_APP + 1) - #define IDM_SERVICE_START 100 #define IDM_SERVICE_STOP 101 #define IDM_SERVICE_RESTART 102 @@ -42,6 +40,7 @@ #define IDM_EDITMENU (MAX_CONFIGS + IDM_VIEWLOGMENU) #define IDM_PASSPHRASEMENU (MAX_CONFIGS + IDM_EDITMENU) #define IDM_CLEARPASSMENU (MAX_CONFIGS + IDM_PASSPHRASEMENU) +#define IDM_RECONNECTMENU (MAX_CONFIGS + IDM_CLEARPASSMENU) void CreatePopupMenus(); void OnNotifyTray(LPARAM);