From 05aac311a538e4da399a8575be8fc479e16afeba Mon Sep 17 00:00:00 2001 From: Martin Koistinen Date: Sat, 16 Feb 2013 02:41:25 +0200 Subject: [PATCH] Menu dynamically shows only those proxies which are configured. Support for FTP and RTSP proxies. Signed-off-by: Martin Koistinen --- ToggleProxy.py | 96 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 28 deletions(-) diff --git a/ToggleProxy.py b/ToggleProxy.py index 51594b5..1b4cfb0 100644 --- a/ToggleProxy.py +++ b/ToggleProxy.py @@ -3,10 +3,19 @@ from Foundation import * from AppKit import * from SystemConfiguration import * +# from pprint import pprint import commands, re class ToggleProxy(NSObject): + proxies = { + 'ftp' : { 'pref': kSCPropNetProxiesFTPEnable, 'title': 'FTP Proxy', 'action': 'toggleFtpProxy:', 'keyEquivalent': "", 'menuitem': None }, + 'http' : { 'pref': kSCPropNetProxiesHTTPEnable, 'title': 'HTTP Proxy', 'action': 'toggleHttpProxy:', 'keyEquivalent': "", 'menuitem': None }, + 'https': { 'pref': kSCPropNetProxiesHTTPSEnable, 'title': 'HTTPS Proxy', 'action': 'toggleHttpsProxy:', 'keyEquivalent': "", 'menuitem': None }, + 'rtsp': { 'pref': kSCPropNetProxiesRTSPEnable, 'title': 'RTSP Proxy', 'action': 'toggleRtspProxy:', 'keyEquivalent': "", 'menuitem': None }, + 'socks': { 'pref': kSCPropNetProxiesSOCKSEnable, 'title': 'SOCKS Proxy', 'action': 'toggleSocksProxy:', 'keyEquivalent': "", 'menuitem': None }, + } + def applicationDidFinishLaunching_(self, notification): # load icon files self.icons = { @@ -30,28 +39,40 @@ class ToggleProxy(NSObject): self.menu = NSMenu.alloc().init() self.statusitem.setMenu_(self.menu) - # add items to menu - self.httpMenuItem = self.menu.addItemWithTitle_action_keyEquivalent_( - "HTTP proxy", - "toggleHttpProxy:", - "") - self.httpsMenuItem = self.menu.addItemWithTitle_action_keyEquivalent_( - "HTTPS proxy", - "toggleHttpsProxy:", - "") - self.socksMenuItem = self.menu.addItemWithTitle_action_keyEquivalent_( - "SOCKS proxy", - "toggleSocksProxy:", - "") - self.menu.addItem_(NSMenuItem.separatorItem()) + # open connection to the dynamic (configuration) store + self.store = SCDynamicStoreCreate(None, "name.klep.toggleproxy", self.dynamicStoreCallback, None) + + service = self.service + + proxyRef = SCNetworkServiceCopyProtocol(service, kSCNetworkProtocolTypeProxies) + prefDict = SCNetworkProtocolGetConfiguration(proxyRef) + # pprint(prefDict) + + separatorRequired = False + + for proxy in self.proxies.values(): + enabled = CFDictionaryGetValue(prefDict, proxy['pref']) + if enabled is not None: + proxy['menuitem'] = self.menu.addItemWithTitle_action_keyEquivalent_( + proxy['title'], + proxy['action'], + proxy['keyEquivalent'] + ) + separatorRequired = True + else: + # NSLog("%s does not appear to be configured" % proxy['title']) + proxy['menuitem'] = None + + # pprint(self.proxies) + + if separatorRequired: + self.menu.addItem_(NSMenuItem.separatorItem()) + self.menu.addItemWithTitle_action_keyEquivalent_( "Quit", "quitApp:", "") - # open connection to the dynamic (configuration) store - self.store = SCDynamicStoreCreate(None, "name.klep.toggleproxy", self.dynamicStoreCallback, None) - # start working self.loadNetworkServices() self.watchForProxyChanges() @@ -62,6 +83,19 @@ class ToggleProxy(NSObject): # get primary interface return SCDynamicStoreCopyValue(self.store, 'State:/Network/Global/IPv4')['PrimaryInterface'] + @property + def service(self): + """ Returns the service relating to self.interface """ + prefs = SCPreferencesCreate(kCFAllocatorDefault, 'PRG', None) + + # Fetch the list of services + for serviceRef in SCNetworkServiceCopyAll(prefs): + interface = SCNetworkServiceGetInterface(serviceRef) + bsdname = SCNetworkInterfaceGetBSDName(interface) + if self.interface == bsdname: + return serviceRef + return None + def loadNetworkServices(self): """ Load and store a list of network services indexed by their BSDName """ self.services = {} @@ -92,36 +126,42 @@ class ToggleProxy(NSObject): def updateProxyStatus(self): """ update proxy status """ # load proxy dictionary - proxydict = SCDynamicStoreCopyProxies(None) + proxydict = SCDynamicStoreCopyProxies(None) # get status for primary interface - status = proxydict['__SCOPED__'][self.interface] + status = proxydict['__SCOPED__'][self.interface] # update menu items according to their related proxy state - self.httpMenuItem.setState_( status.get('HTTPEnable', False) and NSOnState or NSOffState ) - self.httpsMenuItem.setState_( status.get('HTTPSEnable', False) and NSOnState or NSOffState ) - self.socksMenuItem.setState_( status.get('SOCKSEnable', False) and NSOnState or NSOffState ) + for proxy in self.proxies.values(): + if proxy['menuitem']: + proxy['menuitem'].setState_( status.get(proxy['pref'], False) and NSOnState or NSOffState) # update icon self.statusitem.setImage_( self.icons['%d-%d-%d' % ( - status.get('HTTPEnable', False) and 1 or 0, - status.get('HTTPSEnable', False) and 1 or 0, - status.get('SOCKSEnable', False) and 1 or 0 + status.get(self.proxies['http']['pref'], False) and 1 or 0, + status.get(self.proxies['https']['pref'], False) and 1 or 0, + status.get(self.proxies['socks']['pref'], False) and 1 or 0 )] ) def quitApp_(self, sender): NSApp.terminate_(self) + def toggleFtpProxy_(self, sender): + self.toggleProxy(self.proxies['ftp']['menuitem'], 'ftpproxy') + def toggleHttpProxy_(self, sender): - self.toggleProxy(self.httpMenuItem, 'webproxy') + self.toggleProxy(self.proxies['http']['menuitem'], 'webproxy') def toggleHttpsProxy_(self, sender): - self.toggleProxy(self.httpsMenuItem, 'securewebproxy') + self.toggleProxy(self.proxies['https']['menuitem'], 'securewebproxy') + + def toggleRtspProxy_(self, sender): + self.toggleProxy(self.proxies['socks']['menuitem'], 'streamingproxy') def toggleSocksProxy_(self, sender): - self.toggleProxy(self.socksMenuItem, 'socksfirewallproxy') + self.toggleProxy(self.proxies['socks']['menuitem'], 'socksfirewallproxy') def toggleProxy(self, item, target): """ callback for clicks on menu item """