/* * OpenVPN-GUI -- A Windows GUI for OpenVPN. * * Copyright (C) 2004 Mathias Sundman * * This program 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. * * This program 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 (see the file COPYING included with this * distribution); if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define _WIN32_IE 0x0500 #define NIF_INFO 0x00000010 // Notify Icon Infotip flags #define NIIF_NONE 0x00000000 // icon flags are mutually exclusive // and take only the lowest 2 bits #define NIIF_INFO 0x00000001 #define NIIF_WARNING 0x00000002 #define NIIF_ERROR 0x00000003 #define NIIF_ICON_MASK 0x0000000F #include #include #include "tray.h" #include "service.h" #include "shellapi.h" #include "main.h" #include "options.h" #include "openvpn.h" #include "openvpn_config.h" #include "openvpn-gui-res.h" //POPUP MENU HMENU hMenu; HMENU hMenuConn[MAX_CONFIGS]; HMENU hMenuService; NOTIFYICONDATA ni; extern struct options o; // Mouse clicks on tray void OnNotifyTray(LPARAM lParam) { POINT pt; // point structure int connected_config; int i; TCHAR buf[1000]; // Right click, show the menu switch(lParam) { case WM_RBUTTONDOWN: /* Re-read configs and re-create menus if no connection is running */ if (CountConnectedState(DISCONNECTED) == o.num_configs) { DestroyPopupMenus(); BuildFileList(); CreatePopupMenus(); } GetCursorPos(&pt); // get the cursors position SetForegroundWindow(o.hWnd); // set the foreground window TrackPopupMenu(hMenu,TPM_RIGHTALIGN,pt.x,pt.y,0,o.hWnd,NULL);// track the popup break; case WM_LBUTTONDOWN: break; case WM_LBUTTONDBLCLK: if (o.service_only[0]=='1') { /* Start OpenVPN Service */ if (o.service_running == SERVICE_DISCONNECTED) { MyStartService(); } else if (o.service_running == SERVICE_CONNECTED) { /* Stop OpenVPN service */ myLoadString(IDM_TEXT_ASK_STOP_SERVICE); if (MessageBox(NULL, buf, GUI_NAME, MB_YESNO | MB_SETFOREGROUND) == IDYES) { MyStopService(); } } } else { /* Open Status window if only one connection is running */ connected_config = -1; for (i=0; i < o.num_configs; i++) { if(o.cnn[i].connect_status != DISCONNECTED) { if (connected_config == -1) { connected_config = i; } else { connected_config = -1; break; } } } if (connected_config != -1) { ShowWindow(o.cnn[connected_config].hwndStatus, SW_SHOW); SetForegroundWindow(o.cnn[connected_config].hwndStatus); } /* Re-read configs and re-create menus if no connection is running */ if (CountConnectedState(DISCONNECTED) == o.num_configs) { DestroyPopupMenus(); BuildFileList(); CreatePopupMenus(); /* Start connection if only one config exist */ if ((o.num_configs == 1) && (o.cnn[0].connect_status == DISCONNECTED)) StartOpenVPN(0); } } break; } PostMessage(o.hWnd,WM_NULL,0,0);// post a null message } void OnDestroyTray() { //Destroy popup menu DestroyMenu(hMenu); //Remove Icon from Tray Shell_NotifyIcon(NIM_DELETE, &ni); } /* Create Popup Menus */ void CreatePopupMenus() { int i; //extern struct options o; /* Create Main menu */ hMenu=CreatePopupMenu(); /* Create a menu for every config */ for (i=0; i < o.num_configs; i++) hMenuConn[i]=CreatePopupMenu(); /* Create the Service Menu */ hMenuService=CreatePopupMenu(); /* Put something on the menus */ CreateItemList(hMenu); } /* Destroy Popup Menus */ void DestroyPopupMenus() { int i; /* Destroy Main menu */ DestroyMenu(hMenu); /* Destroy all config submenus */ for (i=0; i < o.num_configs; i++) DestroyMenu(hMenuConn[i]); /* Destroy the Service Menu */ DestroyMenu(hMenuService); } void CreateItemList() { extern char ext_string[]; extern char allow_edit[2]; extern char allow_service[2]; int i; TCHAR buf[1000]; if (o.num_configs == 1) { /* Create Main menu with actions */ if (o.service_only[0]=='0') { myLoadString(IDM_TEXT_CONNECT); AppendMenu(hMenu,MF_STRING, IDM_CONNECTMENU, buf); myLoadString(IDM_TEXT_DISCONNECT); AppendMenu(hMenu,MF_STRING, IDM_DISCONNECTMENU, buf); myLoadString(IDM_TEXT_STATUS); AppendMenu(hMenu,MF_STRING, IDM_STATUSMENU, buf); AppendMenu(hMenu,MF_SEPARATOR,0,0); } else { myLoadString(IDM_TEXT_SERVICEONLY_START); AppendMenu(hMenu,MF_STRING, IDM_SERVICE_START, buf); myLoadString(IDM_TEXT_SERVICEONLY_STOP); AppendMenu(hMenu,MF_STRING, IDM_SERVICE_STOP, buf); myLoadString(IDM_TEXT_SERVICEONLY_RESTART); AppendMenu(hMenu,MF_STRING, IDM_SERVICE_RESTART, buf); AppendMenu(hMenu,MF_SEPARATOR,0,0); } myLoadString(IDM_TEXT_VIEWLOG); AppendMenu(hMenu,MF_STRING, IDM_VIEWLOGMENU, buf); if (o.allow_edit[0]=='1') { myLoadString(IDM_TEXT_EDITCONFIG); AppendMenu(hMenu,MF_STRING, IDM_EDITMENU, buf); } #ifndef DISABLE_CHANGE_PASSWORD if (o.allow_password[0]=='1') { myLoadString(IDM_TEXT_PASSPHRASE); AppendMenu(hMenu,MF_STRING, IDM_PASSPHRASEMENU, buf); } #endif AppendMenu(hMenu,MF_SEPARATOR,0,0); if (o.allow_service[0]=='1' && o.service_only[0]=='0') { myLoadString(IDM_TEXT_SERVICE); AppendMenu(hMenu,MF_POPUP,(UINT) hMenuService, buf); AppendMenu(hMenu,MF_SEPARATOR,0,0); } if (o.allow_proxy[0]=='1' && o.service_only[0]=='0') { myLoadString(IDM_TEXT_PROXY); AppendMenu(hMenu,MF_STRING ,IDM_PROXY, buf); AppendMenu(hMenu,MF_SEPARATOR,0,0); } myLoadString(IDM_TEXT_ABOUT); AppendMenu(hMenu,MF_STRING ,IDM_ABOUT, buf); myLoadString(IDM_TEXT_CLOSE); AppendMenu(hMenu,MF_STRING ,IDM_CLOSE, buf); SetMenuStatus(0, DISCONNECTED); } else { /* Create Main menu with all connections */ for (i=0; i < o.num_configs; i++) AppendMenu(hMenu,MF_POPUP,(UINT) hMenuConn[i],o.cnn[i].config_name); if (o.num_configs > 0) AppendMenu(hMenu,MF_SEPARATOR,0,0); if (o.allow_service[0]=='1' && o.service_only[0]=='0') { myLoadString(IDM_TEXT_SERVICE); AppendMenu(hMenu,MF_POPUP,(UINT) hMenuService, buf); AppendMenu(hMenu,MF_SEPARATOR,0,0); } if (o.service_only[0]=='1') { myLoadString(IDM_TEXT_SERVICEONLY_START); AppendMenu(hMenu,MF_STRING, IDM_SERVICE_START, buf); myLoadString(IDM_TEXT_SERVICEONLY_STOP); AppendMenu(hMenu,MF_STRING, IDM_SERVICE_STOP, buf); myLoadString(IDM_TEXT_SERVICEONLY_RESTART); AppendMenu(hMenu,MF_STRING, IDM_SERVICE_RESTART, buf); AppendMenu(hMenu,MF_SEPARATOR,0,0); } if (o.allow_proxy[0]=='1' && o.service_only[0]=='0') { myLoadString(IDM_TEXT_PROXY); AppendMenu(hMenu,MF_STRING ,IDM_PROXY, buf); AppendMenu(hMenu,MF_SEPARATOR,0,0); } myLoadString(IDM_TEXT_ABOUT); AppendMenu(hMenu,MF_STRING ,IDM_ABOUT, buf); myLoadString(IDM_TEXT_CLOSE); AppendMenu(hMenu,MF_STRING ,IDM_CLOSE, buf); /* Create PopUp menus for every connection */ for (i=0; i < o.num_configs; i++) { if (o.service_only[0]=='0') { myLoadString(IDM_TEXT_CONNECT); AppendMenu(hMenuConn[i],MF_STRING, (UINT_PTR)IDM_CONNECTMENU+i, buf); myLoadString(IDM_TEXT_DISCONNECT); AppendMenu(hMenuConn[i],MF_STRING, (UINT_PTR)IDM_DISCONNECTMENU+i, buf); myLoadString(IDM_TEXT_STATUS); AppendMenu(hMenuConn[i],MF_STRING, (UINT_PTR)IDM_STATUSMENU+i, buf); AppendMenu(hMenuConn[i],MF_SEPARATOR,0,0); } myLoadString(IDM_TEXT_VIEWLOG); AppendMenu(hMenuConn[i],MF_STRING, (UINT_PTR)IDM_VIEWLOGMENU+i, buf); if (o.allow_edit[0]=='1') { myLoadString(IDM_TEXT_EDITCONFIG); AppendMenu(hMenuConn[i],MF_STRING, (UINT_PTR)IDM_EDITMENU+i, buf); } #ifndef DISABLE_CHANGE_PASSWORD if (o.allow_password[0]=='1') { myLoadString(IDM_TEXT_PASSPHRASE); AppendMenu(hMenuConn[i],MF_STRING, (UINT_PTR)IDM_PASSPHRASEMENU+i, buf); } #endif SetMenuStatus(i, DISCONNECTED); } } /* Create Service menu */ if (o.allow_service[0]=='1' && o.service_only[0]=='0') { myLoadString(IDM_TEXT_SERVICE_START); AppendMenu(hMenuService,MF_STRING, IDM_SERVICE_START, buf); myLoadString(IDM_TEXT_SERVICE_STOP); AppendMenu(hMenuService,MF_STRING, IDM_SERVICE_STOP, buf); myLoadString(IDM_TEXT_SERVICE_RESTART); AppendMenu(hMenuService,MF_STRING, IDM_SERVICE_RESTART, buf); } SetServiceMenuStatus(); } BOOL LoadAppIcon() { // Load icon from resource HICON hIcon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(APP_ICON), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR); if (hIcon) { SendMessage(o.hWnd, WM_SETICON, (WPARAM) (ICON_SMALL), (LPARAM) (hIcon)); SendMessage(o.hWnd, WM_SETICON, (WPARAM) (ICON_BIG), (LPARAM) (hIcon)); //ALT+TAB icon return TRUE; } return FALSE; } void ShowTrayIcon() { TCHAR buf[1000]; ni.cbSize = sizeof(ni); ni.uID = 0; myLoadString(MSG_TIP); lstrcpyn(ni.szTip, buf, sizeof(ni.szTip)); ni.hWnd = o.hWnd; ni.uFlags = NIF_MESSAGE | NIF_TIP | NIF_ICON; // We want to use icon, tip, and callback message ni.uCallbackMessage = WM_NOTIFYICONTRAY; // Our custom callback message (WM_APP + 1) //Load selected icon ni.hIcon = (HICON)LoadIcon(o.hInstance, MAKEINTRESOURCE(APP_ICON_DISCONNECTED)); Shell_NotifyIcon(NIM_ADD, &ni); } /* SetTrayIcon(int connected) * connected=0 -> DisConnected * connected=1 -> Connecting * connected=2 -> Connected */ void SetTrayIcon(int connected) { char msg[500]; char msg_connected[100]; char msg_connecting[100]; char conn_name[200]; char connected_since[50]; int i, first_conn; int config=0; TCHAR buf[1000]; ni.cbSize = sizeof(ni); ni.uID = 0; ni.hWnd = o.hWnd; ni.uFlags = NIF_MESSAGE | NIF_TIP | NIF_ICON; // We want to use icon, tip, and callback message ni.uCallbackMessage = WM_NOTIFYICONTRAY; // Our custom callback message (WM_APP + 1) myLoadString(MSG_TIP); strncpy(msg, buf, sizeof(ni.szTip)); myLoadString(MSG_TIP_CONNECTED); strncpy(msg_connected, buf, sizeof(msg_connected)); myLoadString(MSG_TIP_CONNECTING); strncpy(msg_connecting, buf, sizeof(msg_connecting)); first_conn=1; for (i=0; i < o.num_configs; i++) { if(o.cnn[i].connect_status == CONNECTED) { /* Append connection name to Icon Tip Msg */ if (first_conn) strncat(msg, msg_connected, sizeof(msg) - strlen(msg) - 1); else strncat(msg, ", ", sizeof(msg) - strlen(msg) - 1); strncat(msg, o.cnn[i].config_name, sizeof(msg) - strlen(msg) - 1); first_conn=0; config=i; } } first_conn=1; for (i=0; i < o.num_configs; i++) { if((o.cnn[i].connect_status == CONNECTING) || (o.cnn[i].connect_status == RECONNECTING)) { /* Append connection name to Icon Tip Msg */ if (first_conn) strncat(msg, msg_connecting, sizeof(msg) - strlen(msg) - 1); else strncat(msg, ", ", sizeof(msg) - strlen(msg) - 1); strncat(msg, o.cnn[i].config_name, sizeof(msg) - strlen(msg) - 1); first_conn=0; } } if (CountConnectedState(CONNECTED) == 1) { /* Append "Connected Since and Assigned IP msg" */ time_t con_time; con_time=time(NULL); strftime(connected_since, sizeof(connected_since), "%b %d, %H:%M", localtime(&o.cnn[config].connected_since)); myLoadString(MSG_TIP_CONNECTED_SINCE); strncat(msg, buf, sizeof(msg) - strlen(msg) - 1); strncat(msg, connected_since, sizeof(msg) - strlen(msg) - 1); if (strlen(o.cnn[config].ip) > 0) { char assigned_ip[100]; myLoadString(MSG_TIP_ASSIGNED_IP); mysnprintf(assigned_ip, buf, o.cnn[config].ip); strncat(msg, assigned_ip, sizeof(msg) - strlen(msg) - 1); } } strncpy(ni.szTip, msg, sizeof(ni.szTip)); //Load selected icon if (connected==2) ni.hIcon = (HICON)LoadIcon(o.hInstance, MAKEINTRESOURCE(APP_ICON_CONNECTED)); else if (connected==1) ni.hIcon = (HICON)LoadIcon(o.hInstance, MAKEINTRESOURCE(APP_ICON_CONNECTING)); else if (connected==0) ni.hIcon = (HICON)LoadIcon(o.hInstance, MAKEINTRESOURCE(APP_ICON_DISCONNECTED)); Shell_NotifyIcon(NIM_MODIFY, &ni); } void ShowTrayBalloon(char *infotitle_msg, char *info_msg) { ni.cbSize = sizeof(ni); ni.uID = 0; ni.hWnd = o.hWnd; ni.uFlags = NIF_INFO; /* We want to show a balloon */ ni.uTimeout = 5000; ni.dwInfoFlags = NIIF_INFO; /* Show an Info Icon */ strncpy(ni.szInfo, info_msg, sizeof(ni.szInfo)); strncpy(ni.szInfoTitle, infotitle_msg, sizeof(ni.szInfoTitle)); Shell_NotifyIcon(NIM_MODIFY, &ni); } void SetMenuStatus (int config, int bCheck) { /* bCheck values: * 0 - Not Connected * 1 - Connecting * 2 - Connected * 4 - Disconnecting */ unsigned int iState; if (o.num_configs == 1) { if (bCheck == DISCONNECTED) { EnableMenuItem(hMenu, IDM_CONNECTMENU, MF_ENABLED); EnableMenuItem(hMenu, IDM_DISCONNECTMENU, MF_GRAYED); EnableMenuItem(hMenu, IDM_STATUSMENU, MF_GRAYED); } if (bCheck == CONNECTING) { EnableMenuItem(hMenu, IDM_CONNECTMENU, MF_GRAYED); EnableMenuItem(hMenu, IDM_DISCONNECTMENU, MF_ENABLED); EnableMenuItem(hMenu, IDM_STATUSMENU, MF_ENABLED); } if (bCheck == CONNECTED) { EnableMenuItem(hMenu, IDM_CONNECTMENU, MF_GRAYED); EnableMenuItem(hMenu, IDM_DISCONNECTMENU, MF_ENABLED); EnableMenuItem(hMenu, IDM_STATUSMENU, MF_ENABLED); } if (bCheck == DISCONNECTING) { EnableMenuItem(hMenu, IDM_CONNECTMENU, MF_GRAYED); EnableMenuItem(hMenu, IDM_DISCONNECTMENU, MF_GRAYED); EnableMenuItem(hMenu, IDM_STATUSMENU, MF_ENABLED); } } else { iState = ((bCheck == CONNECTED) || (bCheck == DISCONNECTING)) ? MF_CHECKED : MF_UNCHECKED ; CheckMenuItem (hMenu, (UINT) hMenuConn[config], iState) ; if (bCheck == DISCONNECTED) { EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_CONNECTMENU + config, MF_ENABLED); EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_DISCONNECTMENU + config, MF_GRAYED); EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_STATUSMENU + config, MF_GRAYED); } if (bCheck == CONNECTING) { EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_CONNECTMENU + config, MF_GRAYED); EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_DISCONNECTMENU + config, MF_ENABLED); EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_STATUSMENU + config, MF_ENABLED); } if (bCheck == CONNECTED) { EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_CONNECTMENU + config, MF_GRAYED); EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_DISCONNECTMENU + config, MF_ENABLED); EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_STATUSMENU + config, MF_ENABLED); } if (bCheck == DISCONNECTING) { EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_CONNECTMENU + config, MF_GRAYED); EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_DISCONNECTMENU + config, MF_GRAYED); EnableMenuItem(hMenuConn[config], (UINT_PTR)IDM_STATUSMENU + config, MF_ENABLED); } } } void SetServiceMenuStatus() { HMENU hMenuHandle; if (o.allow_service[0]=='0' && o.service_only[0]=='0') return; if (o.service_only[0]=='1') hMenuHandle = hMenu; else hMenuHandle = hMenuService; if ((o.service_running == SERVICE_NOACCESS) || (o.service_running == SERVICE_CONNECTING)) { /* Service is disabled */ EnableMenuItem(hMenuHandle, IDM_SERVICE_START, MF_GRAYED); EnableMenuItem(hMenuHandle, IDM_SERVICE_STOP, MF_GRAYED); EnableMenuItem(hMenuHandle, IDM_SERVICE_RESTART, MF_GRAYED); } else if (o.service_running == SERVICE_CONNECTED) { /* Service is running */ EnableMenuItem(hMenuHandle, IDM_SERVICE_START, MF_GRAYED); EnableMenuItem(hMenuHandle, IDM_SERVICE_STOP, MF_ENABLED); EnableMenuItem(hMenuHandle, IDM_SERVICE_RESTART, MF_ENABLED); } else { /* Service is not running */ EnableMenuItem(hMenuHandle, IDM_SERVICE_START, MF_ENABLED); EnableMenuItem(hMenuHandle, IDM_SERVICE_STOP, MF_GRAYED); EnableMenuItem(hMenuHandle, IDM_SERVICE_RESTART, MF_GRAYED); } }