From 6787306b165d16854d1776f99742bfdf78ba0b38 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Mon, 23 May 2022 14:42:53 -0400 Subject: [PATCH] Support sending multiple actions to a running instance Currently we support only one --command action arg type of option. Extend it to allow multiple such commands in one invocation. Trac #498 Signed-off-by: Selva Nair --- main.c | 72 +++++++++++++++++++++++++++++++++---------------------- options.c | 61 +++++++++++++++++++++++++++------------------- options.h | 14 +++++++++-- 3 files changed, 91 insertions(+), 56 deletions(-) diff --git a/main.c b/main.c index 6b7f44e5..ba71d5c1 100644 --- a/main.c +++ b/main.c @@ -100,7 +100,7 @@ VerifyAutoConnections() * to the running instance and return success or error. */ static int -NotifyRunningInstance() +NotifyRunningInstance(int action_type, wchar_t *action_arg) { /* Check if a previous instance has a window initialized * Even if we are not the first instance this may return null @@ -110,22 +110,16 @@ NotifyRunningInstance() int exit_code = 0; if (hwnd_master) { - /* GUI up and running -- send a message if any action is pecified, - else show the balloon */ + /* GUI up and running -- send a message for the specified action */ COPYDATASTRUCT config_data = {0}; int timeout = 30*1000; /* 30 seconds */ - if (!o.action) + config_data.dwData = action_type; + if (action_arg) { - o.action = WM_OVPN_NOTIFY; - o.action_arg = LoadLocalizedString(IDS_NFO_CLICK_HERE_TO_START); + config_data.cbData = (wcslen(action_arg)+1)*sizeof(action_arg[0]); + config_data.lpData = (void *) action_arg; } - 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 : %ls", o.action, o.action_arg); + PrintDebug(L"Instance 2: called with action %d : %ls", action_type, action_arg); if (!SendMessageTimeout (hwnd_master, WM_COPYDATA, 0, (LPARAM) &config_data, 0, timeout, NULL)) { @@ -245,23 +239,40 @@ int WINAPI _tWinMain (HINSTANCE hThisInstance, 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 == WM_OVPN_IMPORT) - { - ; /* pass -- import is handled after Window initialization */ + int exit_code = 0; + struct action *a = o.action_list.head; + if (!a) /* no actions -- send a balloon notification */ + { + exit_code = NotifyRunningInstance(WM_OVPN_NOTIFY, + LoadLocalizedString(IDS_NFO_CLICK_HERE_TO_START)); + } + else while (a) + { + int res = NotifyRunningInstance(a->type, a->arg); + exit_code = res > exit_code ? res : exit_code; + a = a->next; + } + exit(exit_code); } - else if (o.action) + else { - MsgToEventLog(EVENTLOG_ERROR_TYPE, L"Called with --command when no previous instance available"); - exit(OVPN_EXITCODE_ERROR); + for (struct action *a = o.action_list.head; a; a = a->next) + { + if (a->type == WM_OVPN_START) + { + PrintDebug(L"Instance 1: Called with --command connect xxx. Treating it as --connect xxx"); + } + else if (a->type == WM_OVPN_IMPORT) + { + ; /* pass -- import is handled after Window initialization */ + } + else + { + MsgToEventLog(EVENTLOG_ERROR_TYPE, L"Called with --command when no previous instance available (action type = %d arg = %s", a->type, a->arg ? a->arg : L""); + exit(OVPN_EXITCODE_ERROR); + } + } } - if (!CheckVersion()) { exit(1); } @@ -528,9 +539,12 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM CheckServiceStatus(); // Check if service is running or not /* if '--import' was specified, do it now */ - if (o.action == WM_OVPN_IMPORT && o.action_arg) + for (struct action *a = o.action_list.head; a ; a = a->next) { - ImportConfigFile(o.action_arg, true); /* prompt user */ + if (a->type == WM_OVPN_IMPORT && a->arg) + { + ImportConfigFile(a->arg, true); /* prompt user */ + } } if (!AutoStartConnections()) { diff --git a/options.c b/options.c index 41af25c9..07c26d15 100644 --- a/options.c +++ b/options.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "options.h" #include "main.h" @@ -81,9 +82,32 @@ ExpandOptions (void) ExpandString (o.install_path, _countof(o.install_path)); } +static void +add_action(struct action_list *al, DWORD type, wchar_t *arg) +{ + struct action *a = calloc(sizeof(*a), 1); + if (!a) + { + ErrorExit(1, L"Out of memory while parsing command line"); + } + a->type = type; + a->arg = arg; + if (!al->head) /* first entry */ + { + al->head = a; + } + else + { + assert(al->tail); + al->tail->next = a; + } + al->tail = a; +} + static int add_option(options_t *options, int i, TCHAR **p) { + struct action_list *al = &options->action_list; if (streq(p[0], _T("help"))) { TCHAR caption[200]; @@ -112,14 +136,10 @@ add_option(options_t *options, int i, TCHAR **p) options->auto_connect = tmp; } options->auto_connect[options->num_auto_connect++] = p[1]; - /* Treat the first connect option to also mean --command connect profile. + /* Treat connect option to also mean --command connect profile. * This gets used if we are not the first instance. */ - if (options->num_auto_connect == 1) - { - options->action = WM_OVPN_START; - options->action_arg = p[1]; - } + add_action(al, WM_OVPN_START, p[1]); } else if (streq(p[0], L"import") && p[1]) { @@ -127,8 +147,7 @@ add_option(options_t *options, int i, TCHAR **p) /* This is interpreted directly or as a command depending * on we are the first instance or not. So, set as an action. */ - options->action = WM_OVPN_IMPORT; - options->action_arg = p[1]; + add_action(al, WM_OVPN_IMPORT, p[1]); } else if (streq(p[0], _T("exe_path")) && p[1]) { @@ -248,52 +267,44 @@ add_option(options_t *options, int i, TCHAR **p) 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]; + i = add_option(options, i, &p[1]); } else if (streq(p[1], _T("disconnect")) && p[2]) { ++i; - options->action = WM_OVPN_STOP; - options->action_arg = p[2]; + add_action(al, WM_OVPN_STOP, p[2]); } else if (streq(p[1], _T("reconnect")) && p[2]) { ++i; - options->action = WM_OVPN_RESTART; - options->action_arg = p[2]; + add_action(al, WM_OVPN_RESTART, p[2]); } else if (streq(p[1], _T("status")) && p[2]) { ++i; - options->action = WM_OVPN_SHOWSTATUS; - options->action_arg = p[2]; + add_action(al, WM_OVPN_SHOWSTATUS, p[2]); } else if (streq(p[1], L"import") && p[2]) { ++i; - options->action = WM_OVPN_IMPORT; - options->action_arg = p[2]; + add_action(al, WM_OVPN_IMPORT, 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"); + add_action(al, WM_OVPN_SILENT, p[2] ? p[2] : L"1"); } else if (streq(p[1], _T("disconnect_all"))) { - options->action = WM_OVPN_STOPALL; + add_action(al, WM_OVPN_STOPALL, NULL); } else if (streq(p[1], _T("exit"))) { - options->action = WM_OVPN_EXIT; + add_action(al, WM_OVPN_EXIT, NULL); } else if (streq(p[1], _T("rescan"))) { - options->action = WM_OVPN_RESCAN; + add_action(al, WM_OVPN_RESCAN, NULL); } else { diff --git a/options.h b/options.h index 5166d121..492127e4 100644 --- a/options.h +++ b/options.h @@ -158,6 +158,17 @@ struct connection { struct echo_msg echo_msg; /* Message echo-ed from server or client config and related data */ }; +/* Command actions to be send to running instance */ +struct action { + int type; + wchar_t *arg; + struct action *next; +}; + +struct action_list { + struct action *head, *tail; +}; + /* All options used within OpenVPN GUI */ typedef struct { /* Array of configs to autostart */ @@ -223,8 +234,7 @@ typedef struct { unsigned int dpi_scale; COLORREF clr_warning; COLORREF clr_error; - int action; /* action to send to a running instance */ - TCHAR *action_arg; + struct action_list action_list; /* list of actions to send to a running instance */ HANDLE session_semaphore; HANDLE event_log; } options_t;