Use a list instead of array for connections list

Currently we use an array of connection pointers which needs
to be reallocated when space runs out. But, that happens from
the main thread while the status thread may be referring to those
pointers. Its very hard to fence against possible invalid memory
access. Instead, use a list so that connection pointer never
changes once created.

The connection list is no longer recreated from scratch even when
no connections are active. This means configs added while GUI is
running will always appear at the bottom of the root group listing
until the GUI is restarted.

TODO: This behaviour could be improved by scanning through the groups to
graft new configs at the right branch in the config-group tree.

v2: removed unused references to SetMenuStatusById()

Signed-off-by: Selva Nair <selva.nair@gmail.com>
pull/589/head
Selva Nair 2023-01-14 10:34:11 -05:00
parent 8a4fec9d13
commit 9417991168
11 changed files with 165 additions and 191 deletions

109
main.c
View File

@ -358,17 +358,17 @@ StopAllOpenVPN()
* at their current state. Use the disconnect menu to put them into
* hold state before exit, if desired.
*/
for (i = 0; i < o.num_configs; i++)
for (connection_t *c = o.chead; c; c = c->next)
{
if (o.conn[i].state != disconnected && o.conn[i].state != detached)
if (c->state != disconnected && c->state != detached)
{
if (o.conn[i].flags & FLAG_DAEMON_PERSISTENT)
if (c->flags & FLAG_DAEMON_PERSISTENT)
{
DetachOpenVPN(&o.conn[i]);
DetachOpenVPN(c);
}
else
{
StopOpenVPN(&o.conn[i]);
StopOpenVPN(c);
}
}
}
@ -385,12 +385,10 @@ StopAllOpenVPN()
static int
AutoStartConnections()
{
int i;
for (i = 0; i < o.num_configs; i++)
for (connection_t *c = o.chead; c; c = c->next)
{
if (o.conn[i].auto_connect && !(o.conn[i].flags & FLAG_DAEMON_PERSISTENT))
StartOpenVPN(&o.conn[i]);
if (c->auto_connect && !(c->flags & FLAG_DAEMON_PERSISTENT))
StartOpenVPN(c);
}
return TRUE;
@ -400,15 +398,15 @@ AutoStartConnections()
static void
ResumeConnections()
{
int i;
for (i = 0; i < o.num_configs; i++) {
for (connection_t *c = o.chead; c; c = c->next)
{
/* Restart suspend connections */
if (o.conn[i].state == suspended)
StartOpenVPN(&o.conn[i]);
if (c->state == suspended)
StartOpenVPN(c);
/* If some connection never reached SUSPENDED state */
if (o.conn[i].state == suspending)
StopOpenVPN(&o.conn[i]);
if (c->state == suspending)
StopOpenVPN(c);
}
}
@ -492,19 +490,19 @@ ManagePersistent(HWND hwnd, UINT UNUSED msg, UINT_PTR id, DWORD UNUSED now)
CheckServiceStatus();
if (o.service_state == service_connected)
{
for (int i = 0; i < o.num_configs; i++)
for (connection_t *c = o.chead; c; c = c->next)
{
if (o.conn[i].flags & FLAG_DAEMON_PERSISTENT
&& o.conn[i].auto_connect
&& (o.conn[i].state == disconnected || o.conn[i].state == detached))
if (c->flags & FLAG_DAEMON_PERSISTENT
&& c->auto_connect
&& (c->state == disconnected || c->state == detached))
{
/* disable auto-connect to avoid repeated re-connect
* after unrecoverable errors. Re-enabled on successful
* connect.
*/
o.conn[i].auto_connect = false;
o.conn[i].state = detached; /* this is required to retain management-hold on re-attach */
StartOpenVPN(&o.conn[i]); /* attach to the management i/f */
c->auto_connect = false;
c->state = detached; /* this is required to retain management-hold on re-attach */
StartOpenVPN(c); /* attach to the management i/f */
}
}
}
@ -519,14 +517,14 @@ ManagePersistent(HWND hwnd, UINT UNUSED msg, UINT_PTR id, DWORD UNUSED now)
static void
HandleSessionLock(void)
{
for (int i = 0; i < o.num_configs; i++)
for (connection_t *c = o.chead; c; c = c->next)
{
if (o.conn[i].flags & FLAG_DAEMON_PERSISTENT
&& (o.conn[i].state != disconnected && o.conn[i].state != detached))
if (c->flags & FLAG_DAEMON_PERSISTENT
&& (c->state != disconnected && c->state != detached))
{
o.conn[i].auto_connect = false;
DetachOpenVPN(&o.conn[i]);
o.conn[i].flags |= FLAG_WAIT_UNLOCK;
c->auto_connect = false;
DetachOpenVPN(c);
c->flags |= FLAG_WAIT_UNLOCK;
}
}
}
@ -536,12 +534,12 @@ HandleSessionLock(void)
void
HandleSessionUnlock(void)
{
for (int i = 0; i < o.num_configs; i++)
for (connection_t *c = o.chead; c; c = c->next)
{
if (o.conn[i].flags & FLAG_WAIT_UNLOCK)
if (c->flags & FLAG_WAIT_UNLOCK)
{
o.conn[i].auto_connect = true; /* so that ManagePersistent will trigger attach */
o.conn[i].flags &= ~ FLAG_WAIT_UNLOCK;
c->auto_connect = true; /* so that ManagePersistent will trigger attach */
c->flags &= ~ FLAG_WAIT_UNLOCK;
}
}
}
@ -550,8 +548,8 @@ HandleSessionUnlock(void)
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static UINT s_uTaskbarRestart;
int conn_id = 0;
MENUINFO minfo = {.cbSize = sizeof(MENUINFO)};
connection_t *c = NULL;
switch (message) {
case WM_CREATE:
@ -633,36 +631,37 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
else {
minfo.fMask = MIM_MENUDATA;
GetMenuInfo((HMENU) lParam, &minfo);
conn_id = (INT) minfo.dwMenuData;
if (conn_id < 0 || conn_id >= o.num_configs) break; /* ignore invalid connection id */
c = (connection_t *) minfo.dwMenuData;
if (!c)
break; /* ignore invalid connection */
}
/* reach here only if the command did not match any global items and a valid connection id is available */
if (LOWORD(wParam) == IDM_CONNECTMENU) {
StartOpenVPN(&o.conn[conn_id]);
StartOpenVPN(c);
}
else if (LOWORD(wParam) == IDM_DISCONNECTMENU) {
StopOpenVPN(&o.conn[conn_id]);
StopOpenVPN(c);
}
else if (LOWORD(wParam) == IDM_RECONNECTMENU) {
RestartOpenVPN(&o.conn[conn_id]);
RestartOpenVPN(c);
}
else if (LOWORD(wParam) == IDM_STATUSMENU) {
ShowWindow(o.conn[conn_id].hwndStatus, SW_SHOW);
ShowWindow(c->hwndStatus, SW_SHOW);
}
else if (LOWORD(wParam) == IDM_VIEWLOGMENU) {
ViewLog(conn_id);
ViewLog(c);
}
else if (LOWORD(wParam) == IDM_EDITMENU) {
EditConfig(conn_id);
EditConfig(c);
}
else if (LOWORD(wParam) == IDM_CLEARPASSMENU) {
ResetSavePasswords(&o.conn[conn_id]);
ResetSavePasswords(c);
}
#ifndef DISABLE_CHANGE_PASSWORD
else if (LOWORD(wParam) == IDM_PASSPHRASEMENU) {
ShowChangePassphraseDialog(&o.conn[conn_id]);
ShowChangePassphraseDialog(c);
}
#endif
break;
@ -825,13 +824,11 @@ ShowSettingsDialog()
void
CloseApplication(HWND hwnd)
{
int i;
/* Show a message if any non-persistent connections are active */
for (i = 0; i < o.num_configs; i++)
for (connection_t *c = o.chead; c; c = c->next)
{
if (o.conn[i].state == disconnected
|| o.conn[i].flags & FLAG_DAEMON_PERSISTENT)
if (c->state == disconnected
|| c->flags & FLAG_DAEMON_PERSISTENT)
{
continue;
}
@ -980,7 +977,7 @@ SaveAutoRestartList()
return;
}
int *active_conns = malloc((size_t) max_active*sizeof(int));
connection_t **active_conns = malloc((size_t) max_active*sizeof(connection_t *));
if (!active_conns)
{
@ -988,16 +985,16 @@ SaveAutoRestartList()
return;
}
for (int i = 0; i < o.num_configs; i++)
for (connection_t *c = o.chead; c && nactive < max_active; c = c->next)
{
if (o.conn[i].state == disconnected
|| o.conn[i].flags & FLAG_DAEMON_PERSISTENT)
if (c->state == disconnected
|| c->flags & FLAG_DAEMON_PERSISTENT)
{
continue;
}
/* accumulate space needed for list of active connections */
len += wcslen(o.conn[i].config_name) + 1;
active_conns[nactive++] = i;
len += wcslen(c->config_name) + 1;
active_conns[nactive++] = c;
}
len++; /* for double nul termination */
@ -1015,7 +1012,7 @@ SaveAutoRestartList()
wchar_t *p = list;
for (int i = 0; i < nactive; i++)
{
connection_t *c = &o.conn[active_conns[i]];
connection_t *c = active_conns[i];
wcscpy(p, c->config_name); /* wcscpy is safe here */
p += wcslen(c->config_name) + 1;
}

View File

@ -2681,12 +2681,6 @@ TerminateOpenVPN (connection_t *c)
return retval;
}
void
SuspendOpenVPN(int config)
{
PostMessage(o.conn[config].hwndStatus, WM_OVPN_SUSPEND, 0, 0);
}
void
RestartOpenVPN(connection_t *c)
{

View File

@ -79,22 +79,36 @@ CheckReadAccess (const TCHAR *dir, const TCHAR *file)
static int
ConfigAlreadyExists(TCHAR *newconfig)
{
int i;
for (i = 0; i < o.num_configs; ++i)
for (connection_t *c = o.chead; c; c = c->next)
{
if (_tcsicmp(o.conn[i].config_file, newconfig) == 0)
if (_tcsicmp(c->config_file, newconfig) == 0)
return true;
}
return false;
}
static void
AddConfigFileToList(int config, const TCHAR *filename, const TCHAR *config_dir)
AddConfigFileToList(int group, const TCHAR *filename, const TCHAR *config_dir)
{
connection_t *c = &o.conn[config];
int i;
connection_t *c = calloc(1, sizeof(connection_t));
memset(c, 0, sizeof(*c));
if (!c)
{
ErrorExit(1, L"Out of memory in AddConfigFileToList");
}
if (o.ctail)
{
o.ctail->next = c;
o.ctail = c;
}
else
{
o.chead = o.ctail = c;
}
c->id = o.num_configs++;
c->group = group;
_tcsncpy(c->config_file, filename, _countof(c->config_file) - 1);
_tcsncpy(c->config_dir, config_dir, _countof(c->config_dir) - 1);
@ -105,7 +119,7 @@ AddConfigFileToList(int config, const TCHAR *filename, const TCHAR *config_dir)
c->manage.sk = INVALID_SOCKET;
c->manage.skaddr.sin_family = AF_INET;
c->manage.skaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
c->manage.skaddr.sin_port = htons(o.mgmt_port_offset + config);
c->manage.skaddr.sin_port = htons(o.mgmt_port_offset + c->id);
#ifndef DISABLE_CHANGE_PASSWORD
if (CheckKeyFileWriteAccess (c))
@ -123,7 +137,7 @@ AddConfigFileToList(int config, const TCHAR *filename, const TCHAR *config_dir)
}
/* Check if connection should be autostarted */
for (i = 0; i < o.num_auto_connect; ++i)
for (int i = 0; i < o.num_auto_connect; ++i)
{
if (_tcsicmp(c->config_file, o.auto_connect[i]) == 0
|| _tcsicmp(c->config_name, o.auto_connect[i]) == 0)
@ -211,9 +225,9 @@ ActivateConfigGroups(void)
/* count children of each group -- this includes groups
* and configs which have it as parent
*/
for (int i = 0; i < o.num_configs; i++)
for (connection_t *c = o.chead; c; c = c->next)
{
CONFIG_GROUP(&o.conn[i])->children++;
CONFIG_GROUP(c)->children++;
}
for (int i = 1; i < o.num_groups; i++)
@ -235,23 +249,23 @@ ActivateConfigGroups(void)
* script etc.) in a separate directory, without making the menu structure
* too deeply nested.
*/
for (int i = 0; i < o.num_configs; i++)
for (connection_t *c = o.chead; c; c = c->next)
{
config_group_t *cg = CONFIG_GROUP(&o.conn[i]);
config_group_t *cg = CONFIG_GROUP(c);
/* if not root and has only this config as child -- squash it */
if (PARENT_GROUP(cg) && cg->children == 1
&& !wcscmp(cg->name, o.conn[i].config_name))
&& !wcscmp(cg->name, c->config_name))
{
cg->children--;
o.conn[i].group = cg->parent;
c->group = cg->parent;
}
}
/* activate all groups that connect a config to the root */
for (int i = 0; i < o.num_configs; i++)
for (connection_t *c = o.chead; c; c = c->next)
{
config_group_t *cg = CONFIG_GROUP(&o.conn[i]);
config_group_t *cg = CONFIG_GROUP(c);
while (cg)
{
@ -287,19 +301,6 @@ BuildFileList0(const TCHAR *config_dir, int recurse_depth, int group, int flags)
/* Loop over each config file in config dir */
do
{
if (!o.conn || o.num_configs == o.max_configs)
{
o.max_configs += 50;
void *tmp = realloc(o.conn, sizeof(*o.conn)*o.max_configs);
if (!tmp)
{
o.max_configs -= 50;
FindClose(find_handle);
ErrorExit(1, L"Out of memory while scanning configs");
}
o.conn = tmp;
}
match_t match_type = match(&find_obj, o.ext_string);
if (match_type == match_file)
{
@ -312,8 +313,7 @@ BuildFileList0(const TCHAR *config_dir, int recurse_depth, int group, int flags)
if (CheckReadAccess (config_dir, find_obj.cFileName))
{
AddConfigFileToList(o.num_configs, find_obj.cFileName, config_dir);
o.conn[o.num_configs++].group = group;
AddConfigFileToList(group, find_obj.cFileName, config_dir);
}
}
} while (FindNextFile(find_handle, &find_obj));
@ -419,17 +419,12 @@ BuildFileList()
issue_warnings = false;
/*
* If no connections are active reset num_configs and rescan
* If first time or no entries in the connection list reset groups and rescan
* to make a new list. Else we keep all current configs and
* rescan to add any new one's found.
* Do the same when persistent connections are in auto-attach mode,
* to avoid over-writing their status info such as auto_connect=false
* after manual detach.
*/
if (!o.num_groups
|| (CountConnState(disconnected) == o.num_configs && o.enable_persistent != 2))
if (!o.num_configs)
{
o.num_configs = 0;
o.num_groups = 0;
flags |= FLAG_ADD_CONFIG_GROUPS;
root_gp = NewConfigGroup(L"ROOT", -1, flags); /* -1 indicates no parent */

View File

@ -453,12 +453,11 @@ ProcessCommandLine(options_t *options, TCHAR *command_line)
int
CountConnState(conn_state_t check)
{
int i;
int count = 0;
for (i = 0; i < o.num_configs; ++i)
for (connection_t *c = o.chead; c; c = c->next)
{
if (o.conn[i].state == check)
if (c->state == check)
++count;
}
@ -468,11 +467,10 @@ CountConnState(conn_state_t check)
connection_t*
GetConnByManagement(SOCKET sk)
{
int i;
for (i = 0; i < o.num_configs; ++i)
for (connection_t *c = o.chead; c; c = c->next)
{
if (o.conn[i].manage.sk == sk)
return &o.conn[i];
if (c->manage.sk == sk)
return c;
}
return NULL;
}
@ -480,11 +478,11 @@ GetConnByManagement(SOCKET sk)
connection_t*
GetConnByName(const WCHAR *name)
{
for (int i = 0; i < o.num_configs; ++i)
for (connection_t *c = o.chead; c; c = c->next)
{
if (wcsicmp (o.conn[i].config_file, name) == 0
|| wcsicmp(o.conn[i].config_name, name) == 0)
return &o.conn[i];
if (wcsicmp (c->config_file, name) == 0
|| wcsicmp(c->config_name, name) == 0)
return c;
}
return NULL;
}

View File

@ -167,6 +167,8 @@ struct connection {
struct echo_msg echo_msg; /* Message echo-ed from server or client config and related data */
struct pkcs11_list pkcs11_list;
char daemon_state[20]; /* state of openvpn.ex: WAIT, AUTH, GET_CONFIG etc.. */
int id; /* index of config -- treat as immutable once assigned */
connection_t *next;
};
/* All options used within OpenVPN GUI */
@ -175,7 +177,8 @@ typedef struct {
const TCHAR **auto_connect;
/* Connection parameters */
connection_t *conn; /* Array of connection structure */
connection_t *chead; /* Head of connection list */
connection_t *ctail; /* Tail of connection list */
config_group_t *groups; /* Array of nodes defining the config groups tree */
int num_configs; /* Number of configs */
int num_auto_connect; /* Number of auto-connect configs */

View File

@ -76,10 +76,6 @@ void SetMenuStatus(UNUSED connection_t *c, UNUSED conn_state_t state)
{
return;
}
void SetMenuStatusById(UNUSED int id, UNUSED conn_state_t state)
{
return;
}
void SetServiceMenuStatus(void)
{
return;

View File

@ -265,8 +265,9 @@ InitializeUI(HINSTANCE hinstance)
CheckServiceStatus();
int num_persistent = 0;
for (int i = 0; i < o.num_configs; i++) {
if (o.conn[i].flags & FLAG_DAEMON_PERSISTENT) num_persistent++;
for (connection_t *c = o.chead; c; c = c->next)
{
if (c->flags & FLAG_DAEMON_PERSISTENT) num_persistent++;
}
if (o.service_state == service_disconnected && num_persistent > 0) {
@ -281,15 +282,14 @@ InitializeUI(HINSTANCE hinstance)
/* Returns number of PLAP enabled configs -- for now
* same as autostarted (persistent) connections.
* The corresponding connection pointers are set in
* the conn[] array.
* the conn[] array
*/
DWORD
FindPLAPConnections(connection_t *conn[], size_t max_count)
{
DWORD count = 0;
for (int i = 0; i < o.num_configs && count < max_count; i++)
for (connection_t *c = o.chead; c && count < max_count; c = c->next)
{
connection_t *c = &o.conn[i];
if (!(c->flags & FLAG_DAEMON_PERSISTENT)
|| !ParseManagementAddress(c))
{
@ -390,11 +390,11 @@ DetachAllOpenVPN()
int i;
/* Detach from the mgmt i/f of all connections */
for (i = 0; i < o.num_configs; i++)
for (connection_t *c = o.chead; c; c = c->next)
{
if (o.conn[i].state != disconnected)
if (c->state != disconnected)
{
DetachOpenVPN(&o.conn[i]);
DetachOpenVPN(c);
}
}
@ -408,12 +408,12 @@ DetachAllOpenVPN()
Sleep(100);
}
for (i = 0; i < o.num_configs; i++)
for (connection_t *c = o.chead; c; c = c->next)
{
if (o.conn[i].hwndStatus)
if (c->hwndStatus)
{
/* Status thread still running? kill it */
WaitOnThread(&o.conn[i], 0);
WaitOnThread(c, 0);
}
}
}

90
tray.c
View File

@ -161,13 +161,13 @@ CreatePopupMenus()
CreateMenuBitmaps();
MENUINFO minfo = {.cbSize = sizeof(MENUINFO)};
for (int i = 0; i < o.num_configs; i++)
for (connection_t *c = o.chead; c; c = c->next)
{
hMenuConn[i] = CreatePopupMenu();
hMenuConn[c->id] = CreatePopupMenu();
/* Save the connection index in the menu.*/
minfo.fMask = MIM_MENUDATA;
minfo.dwMenuData = i;
SetMenuInfo(hMenuConn[i], &minfo);
minfo.dwMenuData = (UINT_PTR) c;
SetMenuInfo(hMenuConn[c->id], &minfo);
}
for (int i = 0; i < o.num_groups; i++)
{
@ -185,7 +185,7 @@ CreatePopupMenus()
minfo.dwStyle |= MNS_NOTIFYBYPOS;
SetMenuInfo(hMenu, &minfo);
if (o.num_configs == 1) {
if (o.num_configs == 1 && o.chead) {
/* Create Main menu with actions */
AppendMenu(hMenu, MF_STRING, IDM_CONNECTMENU, LoadLocalizedString(IDS_MENU_CONNECT));
AppendMenu(hMenu, MF_STRING, IDM_DISCONNECTMENU, LoadLocalizedString(IDS_MENU_DISCONNECT));
@ -199,7 +199,7 @@ CreatePopupMenus()
AppendMenu(hMenu, MF_STRING, IDM_CLEARPASSMENU, LoadLocalizedString(IDS_MENU_CLEARPASS));
#ifndef DISABLE_CHANGE_PASSWORD
if (o.conn[0].flags & FLAG_ALLOW_CHANGE_PASSPHRASE)
if (o.chead->flags & FLAG_ALLOW_CHANGE_PASSPHRASE)
AppendMenu(hMenu, MF_STRING, IDM_PASSPHRASEMENU, LoadLocalizedString(IDS_MENU_PASSPHRASE));
#endif
@ -214,7 +214,7 @@ CreatePopupMenus()
AppendMenu(hMenu, MF_STRING ,IDM_SETTINGS, LoadLocalizedString(IDS_MENU_SETTINGS));
AppendMenu(hMenu, MF_STRING ,IDM_CLOSE, LoadLocalizedString(IDS_MENU_CLOSE));
SetMenuStatusById(0, o.conn[0].state);
SetMenuStatus(o.chead, o.chead->state);
}
else {
/* construct the submenu tree first */
@ -240,9 +240,8 @@ CreatePopupMenus()
}
/* add config file (connection) entries */
for (int i = 0; i < o.num_configs; i++)
for (connection_t *c = o.chead; c; c = c->next)
{
connection_t *c = &o.conn[i];
config_group_t *parent = &o.groups[0]; /* by default config is added to the root */
if (USE_NESTED_CONFIG_MENU)
@ -257,11 +256,11 @@ CreatePopupMenus()
assert(parent);
/* Add config to the current sub menu */
AppendMenu(parent->menu, MF_POPUP, (UINT_PTR) hMenuConn[i], c->config_name);
AppendMenu(parent->menu, MF_POPUP, (UINT_PTR) hMenuConn[c->id], c->config_name);
c->pos = parent->children++;
PrintDebug(L"Config %d named %ls added to submenu %ls with position %d",
i, c->config_name, parent->name, c->pos);
c->id, c->config_name, parent->name, c->pos);
}
if (o.num_configs > 0)
@ -277,7 +276,9 @@ CreatePopupMenus()
AppendMenu(hMenu, MF_STRING, IDM_CLOSE, LoadLocalizedString(IDS_MENU_CLOSE));
/* Create popup menus for every connection */
for (int i = 0; i < o.num_configs; i++) {
for (connection_t *c = o.chead; c; c = c->next)
{
int i = c->id;
AppendMenu(hMenuConn[i], MF_STRING, IDM_CONNECTMENU, LoadLocalizedString(IDS_MENU_CONNECT));
AppendMenu(hMenuConn[i], MF_STRING, IDM_DISCONNECTMENU, LoadLocalizedString(IDS_MENU_DISCONNECT));
AppendMenu(hMenuConn[i], MF_STRING, IDM_RECONNECTMENU, LoadLocalizedString(IDS_MENU_RECONNECT));
@ -290,11 +291,11 @@ CreatePopupMenus()
AppendMenu(hMenuConn[i], MF_STRING, IDM_CLEARPASSMENU, LoadLocalizedString(IDS_MENU_CLEARPASS));
#ifndef DISABLE_CHANGE_PASSWORD
if (o.conn[i].flags & FLAG_ALLOW_CHANGE_PASSPHRASE)
if (c->flags & FLAG_ALLOW_CHANGE_PASSPHRASE)
AppendMenu(hMenuConn[i], MF_STRING, IDM_PASSPHRASEMENU, LoadLocalizedString(IDS_MENU_PASSPHRASE));
#endif
SetMenuStatusById(i, o.conn[i].state);
SetMenuStatus(c, c->state);
}
}
}
@ -304,9 +305,10 @@ CreatePopupMenus()
static void
DestroyPopupMenus()
{
int i;
for (i = 0; i < o.num_configs; i++)
DestroyMenu(hMenuConn[i]);
for (connection_t *c = o.chead; c; c = c->next)
{
DestroyMenu(hMenuConn[c->id]);
}
DestroyMenu(hMenuImport);
DestroyMenu(hMenu);
@ -349,16 +351,16 @@ OnNotifyTray(LPARAM lParam)
RecreatePopupMenus();
/* Start connection if only one config exist */
if (o.num_configs == 1 && o.conn[0].state == disconnected)
StartOpenVPN(&o.conn[0]);
if (o.num_configs == 1 && o.chead->state == disconnected)
StartOpenVPN(o.chead);
/* show the status window of all connected/connecting profiles upto a max of 10 */
else if (disconnected_conns < o.num_configs) {
int i;
int num_shown = 0;
for (i = 0; i < o.num_configs; i++) {
if (o.conn[i].state != disconnected) {
ShowWindow(o.conn[i].hwndStatus, SW_SHOW);
SetForegroundWindow(o.conn[i].hwndStatus);
for (connection_t *c = o.chead; c; c = c->next)
{
if (c->state != disconnected && c->hwndStatus) {
ShowWindow(c->hwndStatus, SW_SHOW);
SetForegroundWindow(c->hwndStatus);
if (++num_shown >= 10) break;
}
}
@ -402,47 +404,48 @@ SetTrayIcon(conn_state_t state)
TCHAR msg[500];
TCHAR msg_connected[100];
TCHAR msg_connecting[100];
int i, config = 0;
BOOL first_conn;
UINT icon_id;
connection_t *cc = NULL; /* a connected config */
_tcsncpy(msg, LoadLocalizedString(IDS_TIP_DEFAULT), _countof(ni.szTip));
_tcsncpy(msg_connected, LoadLocalizedString(IDS_TIP_CONNECTED), _countof(msg_connected));
_tcsncpy(msg_connecting, LoadLocalizedString(IDS_TIP_CONNECTING), _countof(msg_connecting));
first_conn = TRUE;
for (i = 0; i < o.num_configs; i++) {
if (o.conn[i].state == connected) {
for (connection_t *c = o.chead; c; c = c->next)
{
if (c->state == connected) {
/* Append connection name to Icon Tip Msg */
_tcsncat(msg, (first_conn ? msg_connected : _T(", ")), _countof(msg) - _tcslen(msg) - 1);
_tcsncat(msg, o.conn[i].config_name, _countof(msg) - _tcslen(msg) - 1);
_tcsncat(msg, c->config_name, _countof(msg) - _tcslen(msg) - 1);
first_conn = FALSE;
config = i;
cc = c;
}
}
first_conn = TRUE;
for (i = 0; i < o.num_configs; i++) {
if (o.conn[i].state == connecting || o.conn[i].state == resuming || o.conn[i].state == reconnecting) {
for (connection_t *c = o.chead; c; c = c->next)
{
if (c->state == connecting || c->state == resuming || c->state == reconnecting) {
/* Append connection name to Icon Tip Msg */
_tcsncat(msg, (first_conn ? msg_connecting : _T(", ")), _countof(msg) - _tcslen(msg) - 1);
_tcsncat(msg, o.conn[i].config_name, _countof(msg) - _tcslen(msg) - 1);
_tcsncat(msg, c->config_name, _countof(msg) - _tcslen(msg) - 1);
first_conn = FALSE;
}
}
if (CountConnState(connected) == 1) {
if (CountConnState(connected) == 1 && cc) {
/* Append "Connected since and assigned IP" to message */
const connection_t *c = &o.conn[config];
TCHAR time[50];
LocalizedTime(o.conn[config].connected_since, time, _countof(time));
LocalizedTime(cc->connected_since, time, _countof(time));
_tcsncat(msg, LoadLocalizedString(IDS_TIP_CONNECTED_SINCE), _countof(msg) - _tcslen(msg) - 1);
_tcsncat(msg, time, _countof(msg) - _tcslen(msg) - 1);
/* concatenate ipv4 and ipv6 addresses into one string */
WCHAR ip[64];
wcs_concat2(ip, _countof(ip), c->ip, c->ipv6, L", ");
wcs_concat2(ip, _countof(ip), cc->ip, cc->ipv6, L", ");
WCHAR *assigned_ip = LoadLocalizedString(IDS_TIP_ASSIGNED_IP, ip);
_tcsncat(msg, assigned_ip, _countof(msg) - _tcslen(msg) - 1);
}
@ -502,21 +505,8 @@ ShowTrayBalloon(TCHAR *infotitle_msg, TCHAR *info_msg)
void
SetMenuStatus(connection_t *c, conn_state_t state)
{
int i;
for (i = 0; i < o.num_configs; ++i)
{
if (c == &o.conn[i])
break;
}
SetMenuStatusById(i, state);
}
void
SetMenuStatusById(int i, conn_state_t state)
{
connection_t *c = &o.conn[i];
int checked = 0;
int i = c->id;
if (state == connected || state == disconnecting) checked = 1;
else if (state != disconnected && state != detached && state != onhold) checked = 2;

1
tray.h
View File

@ -52,7 +52,6 @@ void OnDestroyTray(void);
void ShowTrayIcon();
void SetTrayIcon(conn_state_t);
void SetMenuStatus(connection_t *, conn_state_t);
void SetMenuStatusById(int, conn_state_t);
void SetServiceMenuStatus();
void ShowTrayBalloon(TCHAR *, TCHAR *);
void CheckAndSetTrayIcon();

View File

@ -37,7 +37,7 @@
extern options_t o;
void ViewLog(int config)
void ViewLog(connection_t *c)
{
TCHAR filename[2*MAX_PATH];
@ -54,15 +54,15 @@ void ViewLog(int config)
/* Try first using file association */
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); /* Safe to init COM multiple times */
status = ShellExecuteW (o.hWnd, L"open", o.conn[config].log_path, NULL, o.log_dir, SW_SHOWNORMAL);
status = ShellExecuteW (o.hWnd, L"open", c->log_path, NULL, o.log_dir, SW_SHOWNORMAL);
if (status > (HINSTANCE) 32) /* Success */
return;
else
PrintDebug (L"Opening log file using ShellExecute with verb = open failed"
" for config '%ls' (status = %lu)", o.conn[config].config_name, status);
" for config '%ls' (status = %lu)", c->config_name, status);
_sntprintf_0(filename, _T("%ls \"%ls\""), o.log_viewer, o.conn[config].log_path);
_sntprintf_0(filename, _T("%ls \"%ls\""), o.log_viewer, c->log_path);
/* fill in STARTUPINFO struct */
GetStartupInfo(&start_info);
@ -92,7 +92,7 @@ void ViewLog(int config)
}
void EditConfig(int config)
void EditConfig(connection_t *c)
{
TCHAR filename[2*MAX_PATH];
@ -108,17 +108,17 @@ void EditConfig(int config)
CLEAR (sd);
/* Try first using file association */
_sntprintf_0(filename, L"%ls\\%ls", o.conn[config].config_dir, o.conn[config].config_file);
_sntprintf_0(filename, L"%ls\\%ls", c->config_dir, c->config_file);
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); /* Safe to init COM multiple times */
status = ShellExecuteW (o.hWnd, L"open", filename, NULL, o.conn[config].config_dir, SW_SHOWNORMAL);
status = ShellExecuteW (o.hWnd, L"open", filename, NULL, c->config_dir, SW_SHOWNORMAL);
if (status > (HINSTANCE) 32)
return;
else
PrintDebug (L"Opening config file using ShellExecute with verb = open failed"
" for config '%ls' (status = %lu)", o.conn[config].config_name, status);
" for config '%ls' (status = %lu)", c->config_name, status);
_sntprintf_0(filename, _T("%ls \"%ls\\%ls\""), o.editor, o.conn[config].config_dir, o.conn[config].config_file);
_sntprintf_0(filename, _T("%ls \"%ls\\%ls\""), o.editor, c->config_dir, c->config_file);
/* fill in STARTUPINFO struct */
GetStartupInfo(&start_info);
@ -135,7 +135,7 @@ void EditConfig(int config)
TRUE,
CREATE_NEW_CONSOLE,
NULL,
o.conn[config].config_dir, //start-up dir
c->config_dir, //start-up dir
&start_info,
&proc_info))
{

View File

@ -19,5 +19,7 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
void ViewLog(int config);
void EditConfig(int config);
struct connection;
void ViewLog(struct connection *c);
void EditConfig(struct connection *c);