├── MANIFEST.in ├── NEWS ├── README ├── data ├── icons │ ├── 128x128 │ │ └── apps │ │ │ └── vpn-indicator.png │ ├── 16x16 │ │ └── apps │ │ │ └── vpn-indicator.png │ ├── 22x22 │ │ └── apps │ │ │ └── vpn-indicator.png │ ├── 24x24 │ │ └── apps │ │ │ └── vpn-indicator.png │ ├── 32x32 │ │ └── apps │ │ │ └── vpn-indicator.png │ ├── 48x48 │ │ └── apps │ │ │ └── vpn-indicator.png │ ├── 64x64 │ │ └── apps │ │ │ └── vpn-indicator.png │ └── scalable │ │ └── vpn-indicator.svg ├── me.imtx.vpndaemon.service ├── vpn-indicator-daemon.conf ├── vpn-indicator.desktop └── vpn-indicator.ui ├── debian ├── changelog ├── compat ├── control ├── pycompat └── rules ├── gnome-shell └── vpn-indicator@imtx.me │ ├── extension.js │ ├── metadata.json │ └── stylesheet.css ├── setup.cfg ├── setup.py ├── vpn-indicator └── vpn-indicator-daemon /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.in README 2 | include data/* 3 | recursive-include data *.png *.in *.conf *.desktop *.service 4 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | vpn-indicator 1.0.1 2 | =================== 3 | 4 | * Overview of Changes: 5 | - Show notify when the connection status changes 6 | - Improve the do_start_vpn method, so start menu will call this too 7 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | An easy to use vpn indicator for Ubuntu 2 | -------------------------------------------------------------------------------- /data/icons/128x128/apps/vpn-indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tualatrix/vpn-indicator/a41323f361f20d88587f9d4ceae625a7680b077b/data/icons/128x128/apps/vpn-indicator.png -------------------------------------------------------------------------------- /data/icons/16x16/apps/vpn-indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tualatrix/vpn-indicator/a41323f361f20d88587f9d4ceae625a7680b077b/data/icons/16x16/apps/vpn-indicator.png -------------------------------------------------------------------------------- /data/icons/22x22/apps/vpn-indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tualatrix/vpn-indicator/a41323f361f20d88587f9d4ceae625a7680b077b/data/icons/22x22/apps/vpn-indicator.png -------------------------------------------------------------------------------- /data/icons/24x24/apps/vpn-indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tualatrix/vpn-indicator/a41323f361f20d88587f9d4ceae625a7680b077b/data/icons/24x24/apps/vpn-indicator.png -------------------------------------------------------------------------------- /data/icons/32x32/apps/vpn-indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tualatrix/vpn-indicator/a41323f361f20d88587f9d4ceae625a7680b077b/data/icons/32x32/apps/vpn-indicator.png -------------------------------------------------------------------------------- /data/icons/48x48/apps/vpn-indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tualatrix/vpn-indicator/a41323f361f20d88587f9d4ceae625a7680b077b/data/icons/48x48/apps/vpn-indicator.png -------------------------------------------------------------------------------- /data/icons/64x64/apps/vpn-indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tualatrix/vpn-indicator/a41323f361f20d88587f9d4ceae625a7680b077b/data/icons/64x64/apps/vpn-indicator.png -------------------------------------------------------------------------------- /data/icons/scalable/vpn-indicator.svg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tualatrix/vpn-indicator/a41323f361f20d88587f9d4ceae625a7680b077b/data/icons/scalable/vpn-indicator.svg -------------------------------------------------------------------------------- /data/me.imtx.vpndaemon.service: -------------------------------------------------------------------------------- 1 | [D-BUS Service] 2 | Name=me.imtx.vpndaemon 3 | Exec=/usr/bin/vpn-indicator-daemon 4 | User=root 5 | -------------------------------------------------------------------------------- /data/vpn-indicator-daemon.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 18 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /data/vpn-indicator.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Version=1.0 4 | Type=Application 5 | Terminal=false 6 | Exec=vpn-indicator 7 | Name=VPN Indicator 8 | Comment=VPN Indicator for Ubuntu 9 | Icon=vpn-indicator 10 | Categories=Application;Network 11 | -------------------------------------------------------------------------------- /data/vpn-indicator.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | False 16 | 17 | 18 | True 19 | True 20 | 21 | 22 | True 23 | False 24 | 25 | 26 | True 27 | True 28 | config_model 29 | False 30 | 31 | 32 | column 33 | 34 | 35 | 36 | 1 37 | 1 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | False 47 | True 48 | 49 | 50 | 51 | 52 | True 53 | True 54 | automatic 55 | automatic 56 | 57 | 58 | True 59 | True 60 | log_buffer 61 | 62 | 63 | 64 | 65 | True 66 | True 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | vpn-indicator (1.0.3-1~oneiric1) oneiric; urgency=low 2 | 3 | * Set the current config when activate vpn menu 4 | 5 | -- Tualatrix Chou Fri, 27 Jan 2012 19:06:18 +0800 6 | 7 | vpn-indicator (1.0.2-1~natty1) natty; urgency=low 8 | 9 | * Only show notify when the current_config is exist 10 | 11 | -- Tualatrix Chou Fri, 27 Jan 2012 19:06:08 +0800 12 | 13 | vpn-indicator (1.0.1-1~natty1) natty; urgency=low 14 | 15 | * Overview of Changes: 16 | - Show notify when the connection status changes 17 | - Improve the do_start_vpn method, so start menu will call this too 18 | 19 | -- Tualatrix Chou Mon, 23 May 2011 17:22:26 +0800 20 | 21 | vpn-indicator (1.0.0-2~natty1) natty; urgency=low 22 | 23 | * New upstream release 24 | 25 | -- Tualatrix Chou Fri, 13 May 2011 21:07:06 +0800 26 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 7 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: vpn-indicator 2 | Section: net 3 | Priority: optional 4 | Maintainer: Tualatrix Chou 5 | Build-Depends: debhelper (>= 7.0.50~), 6 | intltool, 7 | python-central (>= 0.5.6), 8 | python-dev, 9 | python-setuptools, 10 | python-distutils-extra 11 | Standards-Version: 3.9.1 12 | Homepage: http://imtx.me 13 | 14 | Package: vpn-indicator 15 | Architecture: all 16 | Depends: python-gtk2, 17 | python-dbus, 18 | python-appindicator, 19 | ${python:Depends} 20 | Description: VPN Indicator for Ubuntu 21 | Website: http://imtx.me 22 | -------------------------------------------------------------------------------- /debian/pycompat: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | %: 3 | dh --with python-central $@ 4 | 5 | override_dh_auto_clean: 6 | rm -rf $(CURDIR)/debian/python-module-stampdir 7 | rm -rf $(CURDIR)/debian/stamp-patched 8 | rm -rf $(CURDIR)/build 9 | rm -rf $(CURDIR)/dist 10 | -------------------------------------------------------------------------------- /gnome-shell/vpn-indicator@imtx.me/extension.js: -------------------------------------------------------------------------------- 1 | const St = imports.gi.St; 2 | const Main = imports.ui.main; 3 | const DBus = imports.dbus; 4 | const Mainloop = imports.mainloop; 5 | const PopupMenu = imports.ui.popupMenu; 6 | const PanelMenu = imports.ui.panelMenu; 7 | const Shell = imports.gi.Shell; 8 | const Lang = imports.lang; 9 | const GLib = imports.gi.GLib; 10 | const Gio = imports.gi.Gio; 11 | 12 | const Gettext = imports.gettext; 13 | const _ = Gettext.gettext; 14 | 15 | const BUS_NAME = 'me.imtx.vpndaemon' 16 | const OBJECT_PATH = '/Daemon'; 17 | const VpnDaemonInterface = { 18 | name: BUS_NAME, 19 | methods: [ 20 | { name: 'stop_vpn', inSignature: '' }, 21 | { name: 'start_vpn', inSignature: '' }, 22 | { name: 'load_config', inSignature: 's' }, 23 | { name: 'is_running', inSignature: 'b' }, 24 | { name: 'is_connected', inSignature: 'b' } 25 | ] 26 | }; 27 | 28 | let VpnDaemonProxy = DBus.makeProxyClass(VpnDaemonInterface); 29 | 30 | function VpnIndicator() { 31 | this._init.apply(this, arguments); 32 | 33 | } 34 | 35 | VpnIndicator.prototype = { 36 | 37 | __proto__: PanelMenu.Button.prototype, 38 | 39 | _init: function(mode) { 40 | PanelMenu.Button.prototype._init.call(this, 0.0); 41 | 42 | this._icon = new St.Icon({ icon_name: 'changes-allow-symbolic', 43 | icon_type: St.IconType.FULLCOLOR, 44 | icon_size: Main.panel.button.height }); 45 | this.actor.set_child(this._icon); 46 | 47 | this._vpnDaemonProxy = new VpnDaemonProxy(DBus.system, BUS_NAME, OBJECT_PATH); 48 | 49 | item = new PopupMenu.PopupSeparatorMenuItem(); 50 | this._vpnSwitch = new PopupMenu.PopupSwitchMenuItem(_("OpenVPN"), false); 51 | this._vpnSwitch.connect('toggled', Lang.bind(this, function() { 52 | global.log("the switch state is " + this._vpnSwitch.state); 53 | if ( this._vpnSwitch.state ) { 54 | let status = this._vpnDaemonProxy.start_vpnRemote(); 55 | global.log("start_vpn result: ", status); 56 | } else { 57 | let status = this._vpnDaemonProxy.stop_vpnRemote(); 58 | global.log("stop_vpn result: ", status); 59 | } 60 | })); 61 | this.menu.addMenuItem(this._vpnSwitch); 62 | 63 | item = new PopupMenu.PopupSeparatorMenuItem(); 64 | this.menu.addMenuItem(item); 65 | 66 | this._createSubMenu(); 67 | 68 | Main.panel._rightBox.insert_actor(this.actor, 1); 69 | Main.panel._menus.addMenu(this.menu); 70 | 71 | Mainloop.timeout_add(1000, Lang.bind(this, this._checkVpnStatus)); 72 | }, 73 | 74 | _checkVpnStatus: function() { 75 | vpn_status = this._vpnDaemonProxy.is_connectedRemote(); 76 | global.log("_checkVpnStatus: " + vpn_status); 77 | if (vpn_status) { 78 | this._icon.set_property('icon_name', 'nm-vpn-standalone-lock'); 79 | } else { 80 | this._icon.set_property('icon_name', 'changes-allow-symbolic'); 81 | } 82 | }, 83 | 84 | _createSubMenu: function() { 85 | let item; 86 | let dir = Gio.file_new_for_path("/etc/openvpn/"); 87 | fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null); 88 | 89 | let vpnConfig = Gio.file_new_for_path("/etc/openvpn/openvpn.conf"); 90 | let fileType = vpnConfig.query_info('standard::*', Gio.FileQueryInfoFlags.NONE, null); 91 | 92 | let target = fileType.get_symlink_target(); 93 | global.log("The vpn config real path is: " + target); 94 | 95 | while ((info = fileEnum.next_file(null)) != null) { 96 | let fileType = info.get_file_type(); 97 | let name = info.get_name(); 98 | 99 | match = name.match(/([\w\d-]+)(.ovpn$)/); 100 | if (match != null) { 101 | item = new PopupMenu.PopupMenuItem(match[1]); 102 | item.connect('activate', Lang.bind(this, this._onVpnMenuActivate, name)); 103 | this.menu.addMenuItem(item); 104 | 105 | if (name == target || target.search(name) != -1) { 106 | item.setShowDot(true); 107 | } 108 | } 109 | } 110 | }, 111 | 112 | _onVpnMenuActivate: function(item, event, name) { 113 | }, 114 | }; 115 | 116 | function main(extensionMeta) { 117 | 118 | let userExtensionLocalePath = extensionMeta.path + '/locale'; 119 | Gettext.bindtextdomain("vpn-indicator", userExtensionLocalePath); 120 | Gettext.textdomain("vpn-indicator"); 121 | 122 | new VpnIndicator(false); 123 | } 124 | 125 | -------------------------------------------------------------------------------- /gnome-shell/vpn-indicator@imtx.me/metadata.json: -------------------------------------------------------------------------------- 1 | {"shell-version": ["3.0.2"], "uuid": "vpn-indicator@imtx.me", "name": "VPN Indicator", "description": "To show the vpn connection"} -------------------------------------------------------------------------------- /gnome-shell/vpn-indicator@imtx.me/stylesheet.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tualatrix/vpn-indicator/a41323f361f20d88587f9d4ceae625a7680b077b/gnome-shell/vpn-indicator@imtx.me/stylesheet.css -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [build] 2 | icons=True 3 | 4 | [build_i18n] 5 | domain=vpn-indicator 6 | desktop_files=[ ("share/applications",("data/vpn-indicator.desktop",)) ] 7 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import glob 2 | from setuptools import setup, find_packages 3 | 4 | setup(name='vpn-indicator', 5 | version='1.0.3', 6 | description='VPN Indicator for Ubuntu', 7 | author='Tualatrix Chou', 8 | author_email='tualatrix@gmail.com', 9 | url='http://imtx.me/', 10 | scripts=['vpn-indicator', 'vpn-indicator-daemon'], 11 | packages=find_packages(), 12 | data_files=[ 13 | ('../etc/dbus-1/system.d/', ['data/vpn-indicator-daemon.conf']), 14 | ('../etc/xdg/autostart/', ['data/vpn-indicator.desktop']), 15 | ('share/vpn-indicator/', glob.glob('data/*.ui')), 16 | ('share/dbus-1/system-services', ['data/me.imtx.vpndaemon.service']), 17 | ('share/applications', ['data/vpn-indicator.desktop']), 18 | ], 19 | license='GNU GPL', 20 | platforms='linux', 21 | test_suite='tests', 22 | ) 23 | -------------------------------------------------------------------------------- /vpn-indicator: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import os 4 | import glob 5 | import time 6 | 7 | import dbus 8 | import gobject 9 | import gtk 10 | import pynotify 11 | import appindicator 12 | 13 | 14 | class GuiBuilder(object): 15 | def __init__(self, path): 16 | file_path = os.path.join(path) 17 | 18 | self.builder = gtk.Builder() 19 | self.builder.set_translation_domain('ubuntu-tweak') 20 | self.builder.add_from_file(file_path) 21 | self.builder.connect_signals(self) 22 | 23 | for o in self.builder.get_objects(): 24 | if issubclass(type(o), gtk.Buildable): 25 | name = gtk.Buildable.get_name(o) 26 | setattr(self, name, o) 27 | else: 28 | print("WARNING: can not set name for non Buildable object: %s" % o) 29 | 30 | def get_object(self, name): 31 | return self.builder.get_object(name) 32 | 33 | 34 | class LogWindow(gtk.Window, GuiBuilder): 35 | def __init__(self): 36 | gtk.Window.__init__(self) 37 | if __file__ == '/usr/bin/vpn-indicator': 38 | GuiBuilder.__init__(self, '/usr/share/vpn-indicator/vpn-indicator.ui') 39 | else: 40 | GuiBuilder.__init__(self, 'data/vpn-indicator.ui') 41 | 42 | self.set_position(gtk.WIN_POS_CENTER) 43 | self.set_size_request(800, 600) 44 | self.set_title('VPN Indicator') 45 | 46 | self.hpaned1.reparent(self) 47 | 48 | self._update_model() 49 | self.connect('delete-event', self.on_delete_event) 50 | 51 | def on_delete_event(self, widget, event): 52 | self.hide() 53 | return True 54 | 55 | def _update_model(self): 56 | configs = glob.glob('/etc/openvpn/*.ovpn') 57 | configs.sort() 58 | 59 | for f in configs: 60 | iter = self.config_model.append((f, os.path.splitext(os.path.basename(f))[0])) 61 | 62 | # if it is the current config, select it 63 | if os.path.realpath('/etc/openvpn/openvpn.conf') == f: 64 | self.config_view.get_selection().select_iter(iter) 65 | self.show_log() 66 | 67 | def show_log(self): 68 | data = os.popen('cat /var/log/syslog|grep "openvpn"').read() 69 | text_buffer = self.log_view.get_buffer() 70 | text_buffer.set_text(data) 71 | 72 | iter_start, iter_end = text_buffer.get_bounds() 73 | 74 | mark = text_buffer.create_mark(None, iter_end, False) 75 | self.log_view.scroll_mark_onscreen(mark) 76 | text_buffer.delete_mark(mark) 77 | 78 | 79 | class VpnIndicator(appindicator.Indicator): 80 | INTERFACE = "me.imtx.vpndaemon" 81 | 82 | (STATUS_CONNECTING, 83 | STATUS_CONNECTED, 84 | STATUS_DISCONNECTED) = range(3) 85 | 86 | _window = None 87 | _current_config = None 88 | _current_status = None 89 | # animate_seq = ['changes-allow-symbolic', 'nm-vpn-standalone-lock'] 90 | animate_seq = ['nm-signal-00-secure', 'nm-signal-25-secure', 'nm-signal-50-secure', 'nm-signal-75-secure', 'nm-signal-100-secure'] 91 | 92 | def __init__(self): 93 | appindicator.Indicator.__init__(self, 94 | "vpn-indicator", 95 | "changes-allow-symbolic", 96 | appindicator.CATEGORY_APPLICATION_STATUS) 97 | self.set_status(appindicator.STATUS_ACTIVE) 98 | self.set_attention_icon("indicatr-messages-new") 99 | 100 | self._init_daemon() 101 | self._create_menu() 102 | self._current_status = self.STATUS_CONNECTING 103 | 104 | gobject.timeout_add(1000, self.checkvpn_status) 105 | 106 | def checkvpn_status(self): 107 | if self._current_config: 108 | if not self.is_vpn_connected() and self.is_vpn_runned(): 109 | animate_icon = self.animate_seq[0] 110 | self.animate_seq.append(self.animate_seq.pop(0)) 111 | self.set_icon(animate_icon) 112 | elif not self.is_vpn_connected() and not self.is_vpn_runned(): 113 | self.set_icon("changes-allow-symbolic") 114 | if self._current_status != self.STATUS_DISCONNECTED: 115 | pynotify.Notification(self._current_config, 'VPN disconnected', 'vpn-indicator').show() 116 | self._current_status = self.STATUS_DISCONNECTED 117 | elif self.is_vpn_connected() and self.is_vpn_runned(): 118 | if self._current_status != self.STATUS_CONNECTED: 119 | pynotify.Notification(self._current_config, 'VPN Connection Established', 'vpn-indicator').show() 120 | self.set_icon('nm-vpn-standalone-lock') 121 | self._current_status = self.STATUS_CONNECTED 122 | return True 123 | 124 | def is_vpn_connected(self): 125 | return 'tun' in os.popen('ifconfig -s').read() 126 | 127 | def is_vpn_runned(self): 128 | return 'is running' in os.popen('service openvpn status').read() 129 | 130 | def _create_menu(self): 131 | menu = gtk.Menu() 132 | 133 | first_item = None 134 | configs = glob.glob('/etc/openvpn/*.ovpn') 135 | configs.sort() 136 | 137 | for f in configs: 138 | short_name = os.path.splitext(os.path.basename(f))[0] 139 | menu_items = gtk.RadioMenuItem(first_item, 140 | short_name) 141 | 142 | if first_item == None: 143 | first_item = menu_items 144 | 145 | if os.path.realpath('/etc/openvpn/openvpn.conf') == f: 146 | self._current_config = short_name 147 | menu_items.set_active(True) 148 | 149 | menu.append(menu_items) 150 | 151 | menu_items.connect("activate", self.on_vpnmenu_activated, f) 152 | 153 | menu.append(gtk.SeparatorMenuItem()) 154 | 155 | start_menu = gtk.MenuItem('Start VPN') 156 | start_menu.connect('activate', self.on_start_menu_activated) 157 | menu.append(start_menu) 158 | 159 | stop_menu = gtk.MenuItem('Stop VPN') 160 | stop_menu.connect('activate', self.on_stop_menu_activated) 161 | menu.append(stop_menu) 162 | 163 | menu.append(gtk.SeparatorMenuItem()) 164 | 165 | log_menu = gtk.MenuItem('VPN Status...') 166 | log_menu.connect('activate', self.on_log_menu_activated) 167 | menu.append(log_menu) 168 | 169 | quit_menu = gtk.MenuItem('Quit') 170 | quit_menu.connect('activate', self.on_quit_menu_activated) 171 | menu.append(quit_menu) 172 | 173 | menu.show_all() 174 | self.set_menu(menu) 175 | 176 | def on_log_menu_activated(self, widget): 177 | if self._window: 178 | self._window.present() 179 | else: 180 | self._window = LogWindow() 181 | self._window.show_all() 182 | 183 | def on_quit_menu_activated(self, widget): 184 | gtk.main_quit() 185 | 186 | def on_start_menu_activated(self, widget): 187 | self.do_start_vpn() 188 | 189 | def on_stop_menu_activated(self, widget): 190 | self.daemon.stop_vpn(dbus_interface='me.imtx.vpndaemon') 191 | 192 | def on_vpnmenu_activated(self, widget, config_path): 193 | if widget.get_active(): 194 | short_name = os.path.splitext(os.path.basename(config_path))[0] 195 | self._current_config = short_name 196 | 197 | if self.is_vpn_connected(): 198 | dialog = gtk.MessageDialog(buttons=gtk.BUTTONS_YES_NO) 199 | dialog.set_markup('VPN "%s" is connected\n\nWould you like to turn off it, then connect to "%s"?' % ( 200 | self._current_config, short_name)) 201 | response = dialog.run() 202 | dialog.destroy() 203 | if response == gtk.RESPONSE_YES: 204 | self.do_start_vpn(config_path) 205 | return True 206 | else: 207 | self.do_start_vpn(config_path) 208 | 209 | def do_start_vpn(self, config_path=None): 210 | if config_path: 211 | print 'load config: %s' % config_path 212 | self.daemon.load_config(config_path, dbus_interface='me.imtx.vpndaemon') 213 | self.daemon.stop_vpn(dbus_interface='me.imtx.vpndaemon') 214 | while True: 215 | if not self.is_vpn_runned(): 216 | print 'do_start_vpn' 217 | self.daemon.start_vpn(dbus_interface='me.imtx.vpndaemon') 218 | break 219 | else: 220 | print 'vpn is running, check status' 221 | time.sleep(1) 222 | 223 | def _init_daemon(self): 224 | try: 225 | systembus = dbus.SystemBus() 226 | self.daemon = systembus.get_object('me.imtx.vpndaemon', '/Daemon') 227 | except Exception, e: 228 | print e 229 | self.daemon = None 230 | 231 | 232 | if __name__ == "__main__": 233 | pynotify.init('vpn-indicator') 234 | VpnIndicator() 235 | gtk.main() 236 | -------------------------------------------------------------------------------- /vpn-indicator-daemon: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import os 4 | import dbus 5 | import dbus.service 6 | import dbus.mainloop.glib 7 | import gobject 8 | import subprocess 9 | 10 | class Daemon(dbus.service.Object): 11 | INTERFACE = "me.imtx.vpndaemon" 12 | ENV = {'PATH': '/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin'} 13 | 14 | @dbus.service.method(INTERFACE, 15 | in_signature='s', out_signature='') 16 | def load_config(self, path): 17 | os.system('ln -sf %s /etc/openvpn/openvpn.conf' % path) 18 | 19 | @dbus.service.method(INTERFACE, 20 | in_signature='', out_signature='ss') 21 | def stop_vpn(self): 22 | return subprocess.Popen(['service', 'openvpn', 'stop'], 23 | stdout=subprocess.PIPE, 24 | stderr=subprocess.PIPE, 25 | env=self.ENV).communicate() 26 | 27 | @dbus.service.method(INTERFACE, 28 | in_signature='', out_signature='ss') 29 | def start_vpn(self): 30 | return subprocess.Popen(['service', 'openvpn', 'start'], 31 | stdout=subprocess.PIPE, 32 | stderr=subprocess.PIPE, 33 | env=self.ENV).communicate() 34 | 35 | @dbus.service.method(INTERFACE, 36 | in_signature='', out_signature='b') 37 | def is_running(self): 38 | # Fedora/GNOME Shell use this 39 | output = ''.join(subprocess.Popen(['service', 'openvpn', 'status'], 40 | stdout=subprocess.PIPE, 41 | stderr=subprocess.PIPE, 42 | env=self.ENV).communicate()) 43 | if 'not started' in output: 44 | return False 45 | else: 46 | return True 47 | 48 | @dbus.service.method(INTERFACE, 49 | in_signature='', out_signature='b') 50 | def is_connected(self): 51 | # Fedora/GNOME Shell use this 52 | output = ''.join(subprocess.Popen(['ifconfig', '-s'], 53 | stdout=subprocess.PIPE, 54 | stderr=subprocess.PIPE, 55 | env=self.ENV).communicate()) 56 | if 'tun' in output: 57 | return True 58 | else: 59 | return False 60 | 61 | @dbus.service.method(INTERFACE, 62 | in_signature='', out_signature='') 63 | def exit(self): 64 | mainloop.quit() 65 | 66 | if __name__ == '__main__': 67 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 68 | 69 | system_bus = dbus.SystemBus() 70 | name = dbus.service.BusName(Daemon.INTERFACE, system_bus) 71 | object = Daemon(system_bus, '/Daemon') 72 | 73 | mainloop = gobject.MainLoop() 74 | mainloop.run() 75 | --------------------------------------------------------------------------------