Merge pull request #188 from selvanair/already-running-v2

Support sending commands to a running instance of the GUI
pull/199/merge
Selva Nair 2018-01-24 07:38:07 -05:00 committed by GitHub
commit c87c7387b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 306 additions and 41 deletions

172
main.c
View File

@ -55,6 +55,10 @@
#include <openssl/err.h>
#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);
}

15
main.h
View File

@ -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

View File

@ -24,8 +24,6 @@
#include <winsock2.h>
#define WM_MANAGEMENT (WM_APP + 2)
typedef enum {
ready,
stop,

4
misc.c
View File

@ -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);

2
misc.h
View File

@ -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);

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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

8
tray.c
View File

@ -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))

3
tray.h
View File

@ -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);