|
- #!/usr/bin/env python
-
- from Foundation import *
- from AppKit import *
- from SystemConfiguration import *
- import commands, re
-
- class ToggleProxy(NSObject):
-
- # This is a dictionary of the proxy-types we support, each with a
- # dictionary of some unique attributes for each, namely:
- #
- # 'pref' : This is a constant defining which preference itemmarks if this proxy is enabled
- # 'title' : This is what will appear in the menu
- # 'action' : This is the method that will be called if the user toggles this proxies menuitem
- # 'keyEquivalent' : Self-explanatory, but unused
- # 'menuitem' : This will store the menu item for this proxy once it is created
-
- 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.active_image = NSImage.imageNamed_("active")
- self.inactive_image = NSImage.imageNamed_("inactive")
-
- # make status bar item
- self.statusitem = NSStatusBar.systemStatusBar().statusItemWithLength_(NSVariableStatusItemLength)
- self.statusitem.retain()
- self.statusitem.setHighlightMode_(False)
- self.statusitem.setEnabled_(True)
-
- # insert a menu into the status bar item
- self.menu = NSMenu.alloc().init()
- self.statusitem.setMenu_(self.menu)
-
- # open connection to the dynamic (configuration) store
- self.store = SCDynamicStoreCreate(None, "name.klep.toggleproxy", self.dynamicStoreCallback, None)
-
- proxyRef = SCNetworkServiceCopyProtocol(self.service, kSCNetworkProtocolTypeProxies)
- prefDict = SCNetworkProtocolGetConfiguration(proxyRef)
-
- separatorRequired = False
-
- # For each of the proxies we are concerned with, check to see if any
- # are configured. If so (even if not enabled), create a menuitem for
- # that proxy type.
-
- 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:
- proxy['menuitem'] = None
-
- if separatorRequired:
- self.menu.addItem_(NSMenuItem.separatorItem())
-
- # Need a way to quit
- self.menu.addItemWithTitle_action_keyEquivalent_("Quit", "quitApp:", "")
-
- # Start working
- # self.loadNetworkServices()
- self.watchForProxyChanges()
- self.updateProxyStatus()
-
- @property
- def interface(self):
- # 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)
- if self.interface == SCNetworkInterfaceGetBSDName(interface):
- return serviceRef
- return None
-
- def watchForProxyChanges(self):
- """ install a watcher for proxy changes """
- SCDynamicStoreSetNotificationKeys(self.store, None, [ 'State:/Network/Global/Proxies' ])
-
- source = SCDynamicStoreCreateRunLoopSource(None, self.store, 0)
- loop = NSRunLoop.currentRunLoop().getCFRunLoop()
- CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes)
-
- def dynamicStoreCallback(self, store, keys, info):
- """ callback for watcher """
- self.updateProxyStatus()
-
- def updateProxyStatus(self):
- """ update proxy status """
- # load proxy dictionary
- proxydict = SCDynamicStoreCopyProxies(None)
-
- # get status for primary interface
- status = proxydict['__SCOPED__'][self.interface]
-
- # Are any proxies active now?
- anyProxyEnabled = False
-
- # update menu items according to their related proxy state
- for proxy in self.proxies.values():
- if proxy['menuitem']:
- proxy['menuitem'].setState_(status.get(proxy['pref'], False) and NSOnState or NSOffState)
- if status.get(proxy['pref'], False):
- anyProxyEnabled = True
-
- # set image
- self.statusitem.setImage_(anyProxyEnabled and self.active_image or self.inactive_image)
-
- 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.proxies['http']['menuitem'], 'webproxy')
-
- def toggleHttpsProxy_(self, sender):
- 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.proxies['socks']['menuitem'], 'socksfirewallproxy')
-
- def toggleProxy(self, item, target):
- """ callback for clicks on menu item """
- servicename = SCNetworkServiceGetName(self.service)
- if not servicename:
- NSLog("interface '%s' not found in services?" % self.interface)
- return
- newstate = item.state() == NSOffState and 'on' or 'off'
- commands.getoutput("/usr/sbin/networksetup -set%sstate '%s' %s" % (
- target,
- servicename,
- newstate
- ))
- self.updateProxyStatus()
-
- if __name__ == '__main__':
- sharedapp = NSApplication.sharedApplication()
- toggler = ToggleProxy.alloc().init()
- sharedapp.setDelegate_(toggler)
- sharedapp.run()
|