class OP2Daemon(object): __metaclass__ = Singleton implements(IObserver) def __init__(self): self.application = SIPApplication() self.stopping = False self.stop_event = Event() Account.register_extension(AccountExtension) BonjourAccount.register_extension(BonjourAccountExtension) SIPSimpleSettings.register_extension(SIPSimpleSettingsExtension) self.account_model = AccountModel() self.bonjour_services = BonjourServices() self.hal = HardwareAbstractionLayer() self.session_manager = SessionManager() self.web_handler = WebHandler() def start(self): self.account_model.start() self.bonjour_services.start() self.hal.start() self.session_manager.start() notification_center = NotificationCenter() notification_center.add_observer(self) notification_center.add_observer(self, sender=self.application) self.application.start(FileStorage(ApplicationData.directory)) def stop(self): if self.stopping: return self.stopping = True self.session_manager.stop() self.hal.stop() self.bonjour_services.stop() self.account_model.stop() self.application.stop() def handle_notification(self, notification): handler = getattr(self, '_NH_%s' % notification.name, Null) handler(notification) def _NH_SIPApplicationDidStart(self, notification): log.msg('SIP application started') self.web_handler.start() def _NH_SIPApplicationWillEnd(self, notification): self.web_handler.stop() def _NH_SIPApplicationDidEnd(self, notification): log.msg('SIP application ended') self.stop_event.set()
class SIPManager(object): __metaclass__ = Singleton implements(IObserver) def __init__(self): BlinkLogger().log_info(u"Loading SIP SIMPLE Client SDK %s" % sdk_version) BlinkLogger().log_info(u"Starting core version %s" % core_version) self._app = SIPApplication() self._delegate = None self._selected_account = None self.ip_address_monitor = IPAddressMonitor() self.bonjour_disabled_on_sleep = False self.bonjour_conference_services = BonjourConferenceServices() self.notification_center = NotificationCenter() self.notification_center.add_observer(self, sender=self._app) self.notification_center.add_observer(self, sender=self._app.engine) self.notification_center.add_observer(self, name='CFGSettingsObjectDidChange') self.notification_center.add_observer(self, name='SIPAccountDidActivate') self.notification_center.add_observer(self, name='SIPAccountDidDeactivate') self.notification_center.add_observer(self, name='SIPAccountRegistrationDidSucceed') self.notification_center.add_observer(self, name='SIPAccountRegistrationDidEnd') self.notification_center.add_observer(self, name='SIPAccountRegistrationDidFail') self.notification_center.add_observer(self, name='SIPAccountRegistrationGotAnswer') self.notification_center.add_observer(self, name='SIPAccountGotMessageSummary') self.notification_center.add_observer(self, name='XCAPManagerDidDiscoverServerCapabilities') self.notification_center.add_observer(self, name='SystemWillSleep') self.notification_center.add_observer(self, name='SystemDidWakeUpFromSleep') def set_delegate(self, delegate): self._delegate = delegate def migratePasswordsToKeychain(self): if NSApp.delegate().applicationName == 'SIP2SIP': return account_manager = AccountManager() configuration_manager = ConfigurationManager() bonjour_account = BonjourAccount() for account in (account for account in account_manager.iter_accounts() if account is not bonjour_account): try: stored_auth_password = configuration_manager.get(account.__key__ + ['auth', 'password']) except ObjectNotFoundError: stored_auth_password = None try: stored_ldap_password = configuration_manager.get(account.__key__ + ['ldap', 'password']) except ObjectNotFoundError: stored_ldap_password = None try: stored_web_password = configuration_manager.get(account.__key__ + ['server', 'web_password']) except ObjectNotFoundError: stored_web_password = None if (stored_auth_password, stored_ldap_password, stored_web_password) != ('keychain', 'keychain', 'keychain'): Account.auth.password.dirty[account.auth] = True Account.ldap.password.dirty[account.ldap] = True Account.server.web_password.dirty[account.server] = True account.save() def cleanupIcons(self): save = False configuration_manager = ConfigurationManager() try: contacts = configuration_manager.get(['Addressbook', 'Contacts']) except Exception: return for data in contacts.itervalues(): if 'icon' in data: del data['icon'] save = True if save: configuration_manager.save() def init(self): Account.register_extension(AccountExtension) BonjourAccount.register_extension(BonjourAccountExtension) Contact.register_extension(BlinkContactExtension) Group.register_extension(BlinkGroupExtension) SIPSimpleSettings.register_extension(SIPSimpleSettingsExtension) self._app.start(FileStorage(ApplicationData.directory)) # start session mgr SessionManager() def init_configurations(self): account_manager = AccountManager() settings = SIPSimpleSettings() # fixup default account self._selected_account = account_manager.default_account if self._selected_account is None: self._selected_account = account_manager.get_accounts()[0] # save default ca if needed ca = open(Resources.get('ca.crt'), "r").read().strip() try: X509Certificate(ca) except GNUTLSError, e: BlinkLogger().log_error(u"Invalid Certificate Authority: %s" % e) return tls_folder = ApplicationData.get('tls') if not os.path.exists(tls_folder): os.mkdir(tls_folder, 0700) ca_path = os.path.join(tls_folder, 'ca.crt') try: existing_cas = open(ca_path, "r").read().strip() except Exception: existing_cas = None if ca == existing_cas: return with open(ca_path, "w") as f: os.chmod(ca_path, 0600) f.write(ca) BlinkLogger().log_debug(u"Added default Certificate Authority to %s" % ca_path) settings.tls.ca_list = ca_path settings.save()
class Blink(QApplication, metaclass=QSingleton): def __init__(self): super(Blink, self).__init__(sys.argv) self.setAttribute(Qt.AA_DontShowIconsInMenus, False) self.sip_application = SIPApplication() self.first_run = False self.setOrganizationDomain("ag-projects.com") self.setOrganizationName("AG Projects") self.setApplicationName("Blink") self.setApplicationVersion(__version__) self.main_window = MainWindow() self.chat_window = ChatWindow() self.main_window.__closed__ = True self.chat_window.__closed__ = True self.main_window.installEventFilter(self) self.chat_window.installEventFilter(self) self.main_window.addAction( self.chat_window.control_button.actions.main_window) self.chat_window.addAction(self.main_window.quit_action) self.chat_window.addAction(self.main_window.help_action) self.chat_window.addAction(self.main_window.redial_action) self.chat_window.addAction(self.main_window.join_conference_action) self.chat_window.addAction(self.main_window.mute_action) self.chat_window.addAction(self.main_window.silent_action) self.chat_window.addAction(self.main_window.preferences_action) self.chat_window.addAction(self.main_window.transfers_window_action) self.chat_window.addAction(self.main_window.logs_window_action) self.chat_window.addAction( self.main_window.received_files_window_action) self.chat_window.addAction(self.main_window.screenshots_window_action) self.ip_address_monitor = IPAddressMonitor() self.log_manager = LogManager() self.presence_manager = PresenceManager() self.session_manager = SessionManager() self.update_manager = UpdateManager() # Prevent application from exiting after last window is closed if system tray was initialized if self.main_window.system_tray_icon: self.setQuitOnLastWindowClosed(False) self.main_window.check_for_updates_action.triggered.connect( self.update_manager.check_for_updates) self.main_window.check_for_updates_action.setVisible( self.update_manager != Null) if getattr(sys, 'frozen', False): XMLDocument.schema_path = Resources.get('xml-schemas') Account.register_extension(AccountExtension) BonjourAccount.register_extension(BonjourAccountExtension) Contact.register_extension(ContactExtension) Group.register_extension(GroupExtension) SIPSimpleSettings.register_extension(SIPSimpleSettingsExtension) notification_center = NotificationCenter() notification_center.add_observer(self, sender=self.sip_application) branding.setup(self) def run(self): self.first_run = not os.path.exists(ApplicationData.get('config')) self.sip_application.start(FileStorage(ApplicationData.directory)) self.exec_() self.update_manager.shutdown() self.sip_application.stop() self.sip_application.thread.join() self.log_manager.stop() def quit(self): self.chat_window.close() self.main_window.close() super(Blink, self).quit() def eventFilter(self, watched, event): if watched in (self.main_window, self.chat_window): if event.type() == QEvent.Show: watched.__closed__ = False elif event.type() == QEvent.Close: watched.__closed__ = True if self.main_window.__closed__ and self.chat_window.__closed__: # close auxiliary windows self.main_window.conference_dialog.close() self.main_window.filetransfer_window.close() self.main_window.preferences_window.close() return False def customEvent(self, event): handler = getattr(self, '_EH_%s' % event.name, Null) handler(event) def _EH_CallFunctionEvent(self, event): try: event.function(*event.args, **event.kw) except: log.exception( 'Exception occurred while calling function %s in the GUI thread' % event.function.__name__) def handle_notification(self, notification): handler = getattr(self, '_NH_%s' % notification.name, Null) handler(notification) def _NH_SIPApplicationWillStart(self, notification): self.log_manager.start() self.presence_manager.start() @run_in_gui_thread def _NH_SIPApplicationDidStart(self, notification): self.ip_address_monitor.start() self.main_window.show() accounts = AccountManager().get_accounts() if not accounts or (self.first_run and accounts == [BonjourAccount()]): self.main_window.preferences_window.show_create_account_dialog() self.update_manager.initialize() def _NH_SIPApplicationWillEnd(self, notification): self.ip_address_monitor.stop() def _NH_SIPApplicationDidEnd(self, notification): self.presence_manager.stop() @run_in_gui_thread def _NH_SIPApplicationGotFatalError(self, notification): log.error('Fatal error:\n{}'.format(notification.data.traceback)) QMessageBox.critical( self.main_window, "Fatal Error", "A fatal error occurred, {} will now exit.".format( self.applicationName())) sys.exit(1)
class Blink(QApplication): __metaclass__ = QSingleton implements(IObserver) def __init__(self): super(Blink, self).__init__(sys.argv) self.setAttribute(Qt.AA_DontShowIconsInMenus, False) self.sip_application = SIPApplication() self.first_run = False self.setOrganizationDomain("ag-projects.com") self.setOrganizationName("AG Projects") self.setApplicationName("Blink") self.setApplicationVersion(__version__) self.main_window = MainWindow() self.chat_window = ChatWindow() self.main_window.__closed__ = True self.chat_window.__closed__ = True self.main_window.installEventFilter(self) self.chat_window.installEventFilter(self) self.main_window.addAction(self.chat_window.control_button.actions.main_window) self.chat_window.addAction(self.main_window.quit_action) self.chat_window.addAction(self.main_window.help_action) self.chat_window.addAction(self.main_window.redial_action) self.chat_window.addAction(self.main_window.join_conference_action) self.chat_window.addAction(self.main_window.mute_action) self.chat_window.addAction(self.main_window.silent_action) self.chat_window.addAction(self.main_window.preferences_action) self.chat_window.addAction(self.main_window.transfers_window_action) self.chat_window.addAction(self.main_window.logs_window_action) self.chat_window.addAction(self.main_window.received_files_window_action) self.chat_window.addAction(self.main_window.screenshots_window_action) self.ip_address_monitor = IPAddressMonitor() self.log_manager = LogManager() self.presence_manager = PresenceManager() self.session_manager = SessionManager() self.update_manager = UpdateManager() # Prevent application from exiting after last window is closed if system tray was initialized if self.main_window.system_tray_icon: self.setQuitOnLastWindowClosed(False) self.main_window.check_for_updates_action.triggered.connect(self.update_manager.check_for_updates) self.main_window.check_for_updates_action.setVisible(self.update_manager != Null) if getattr(sys, "frozen", False): XMLDocument.schema_path = Resources.get("xml-schemas") Account.register_extension(AccountExtension) BonjourAccount.register_extension(BonjourAccountExtension) Contact.register_extension(ContactExtension) Group.register_extension(GroupExtension) SIPSimpleSettings.register_extension(SIPSimpleSettingsExtension) notification_center = NotificationCenter() notification_center.add_observer(self, sender=self.sip_application) branding.setup(self) def run(self): self.first_run = not os.path.exists(ApplicationData.get("config")) self.sip_application.start(FileStorage(ApplicationData.directory)) self.exec_() self.update_manager.shutdown() self.sip_application.stop() self.sip_application.thread.join() self.log_manager.stop() def quit(self): self.chat_window.close() self.main_window.close() super(Blink, self).quit() def eventFilter(self, watched, event): if watched in (self.main_window, self.chat_window): if event.type() == QEvent.Show: watched.__closed__ = False elif event.type() == QEvent.Close: watched.__closed__ = True if self.main_window.__closed__ and self.chat_window.__closed__: # close auxiliary windows self.main_window.conference_dialog.close() self.main_window.filetransfer_window.close() self.main_window.preferences_window.close() return False def customEvent(self, event): handler = getattr(self, "_EH_%s" % event.name, Null) handler(event) def _EH_CallFunctionEvent(self, event): try: event.function(*event.args, **event.kw) except: log.exception("Exception occurred while calling function %s in the GUI thread" % event.function.__name__) def handle_notification(self, notification): handler = getattr(self, "_NH_%s" % notification.name, Null) handler(notification) def _NH_SIPApplicationWillStart(self, notification): self.log_manager.start() self.presence_manager.start() @run_in_gui_thread def _NH_SIPApplicationDidStart(self, notification): self.ip_address_monitor.start() self.main_window.show() accounts = AccountManager().get_accounts() if not accounts or (self.first_run and accounts == [BonjourAccount()]): self.main_window.preferences_window.show_create_account_dialog() self.update_manager.initialize() def _NH_SIPApplicationWillEnd(self, notification): self.ip_address_monitor.stop() def _NH_SIPApplicationDidEnd(self, notification): self.presence_manager.stop() @run_in_gui_thread def _NH_SIPApplicationGotFatalError(self, notification): log.error("Fatal error:\n{}".format(notification.data.traceback)) QMessageBox.critical( self.main_window, u"Fatal Error", u"A fatal error occurred, {} will now exit.".format(self.applicationName()), ) sys.exit(1)
class SIPManager(object): __metaclass__ = Singleton implements(IObserver) def __init__(self): self._app = SIPApplication() self._delegate = None self._selected_account = None self._version = None self.ip_address_monitor = IPAddressMonitor() self.bonjour_disabled_on_sleep = False self.bonjour_conference_services = BonjourConferenceServices() self.notification_center = NotificationCenter() self.notification_center.add_observer(self, sender=self._app) self.notification_center.add_observer(self, sender=self._app.engine) self.notification_center.add_observer(self, name='CFGSettingsObjectDidChange') self.notification_center.add_observer(self, name='SIPAccountDidActivate') self.notification_center.add_observer(self, name='SIPAccountDidDeactivate') self.notification_center.add_observer(self, name='SIPAccountRegistrationDidSucceed') self.notification_center.add_observer(self, name='SIPAccountRegistrationDidEnd') self.notification_center.add_observer(self, name='SIPAccountRegistrationDidFail') self.notification_center.add_observer(self, name='SIPAccountRegistrationGotAnswer') self.notification_center.add_observer(self, name='SIPAccountMWIDidGetSummary') self.notification_center.add_observer(self, name='XCAPManagerDidDiscoverServerCapabilities') self.notification_center.add_observer(self, name='SystemWillSleep') self.notification_center.add_observer(self, name='SystemDidWakeUpFromSleep') def set_delegate(self, delegate): self._delegate = delegate def migratePasswordsToKeychain(self): account_manager = AccountManager() configuration_manager = ConfigurationManager() bonjour_account = BonjourAccount() for account in (account for account in account_manager.iter_accounts() if account is not bonjour_account): try: stored_auth_password = configuration_manager.get(account.__key__ + ['auth', 'password']) except ObjectNotFoundError: stored_auth_password = None try: stored_ldap_password = configuration_manager.get(account.__key__ + ['ldap', 'password']) except ObjectNotFoundError: stored_ldap_password = None try: stored_web_password = configuration_manager.get(account.__key__ + ['server', 'web_password']) except ObjectNotFoundError: stored_web_password = None if (stored_auth_password, stored_ldap_password, stored_web_password) != ('keychain', 'keychain', 'keychain'): Account.auth.password.dirty[account.auth] = True Account.ldap.password.dirty[account.ldap] = True Account.server.web_password.dirty[account.server] = True account.save() def init(self): self._version = str(NSBundle.mainBundle().infoDictionary().objectForKey_("CFBundleShortVersionString")) #first_start = not os.path.exists(ApplicationData.get('config')) Account.register_extension(AccountExtension) BonjourAccount.register_extension(BonjourAccountExtension) Contact.register_extension(BlinkContactExtension) ContactGroup.register_extension(BlinkContactGroupExtension) SIPSimpleSettings.register_extension(SIPSimpleSettingsExtension) self._app.start(FileStorage(ApplicationData.directory)) self.init_configurations() # start session mgr SessionManager() def init_configurations(self): account_manager = AccountManager() settings = SIPSimpleSettings() self.notification_center.add_observer(self, sender=settings) # fixup default account self._selected_account = account_manager.default_account if self._selected_account is None: self._selected_account = account_manager.get_accounts()[0] default_ca = open(Resources.get('ca.crt'), "r").read().strip() self.set_default_certificate_authority(default_ca) def set_default_certificate_authority(self, ca): try: X509Certificate(ca) except GNUTLSError, e: BlinkLogger().log_error(u"Invalid Certificate Authority: %s" % e) return False settings = SIPSimpleSettings() must_save_ca = False tls_folder = ApplicationData.get('tls') if not os.path.exists(tls_folder): os.mkdir(tls_folder, 0700) ca_path = os.path.join(tls_folder, 'ca.crt') try: existing_cas = open(ca_path, "r").read().strip() except: existing_cas = None if ca != existing_cas: f = open(ca_path, "w") os.chmod(ca_path, 0600) f.write(ca) f.close() BlinkLogger().log_info(u"Added default Certificate Authority to %s" % ca_path) must_save_ca = True if must_save_ca: settings.tls.ca_list = ca_path settings.save() return True
class Blink(QApplication): __metaclass__ = QSingleton implements(IObserver) def __init__(self): super(Blink, self).__init__(sys.argv) self.setAttribute(Qt.AA_DontShowIconsInMenus, False) self.sip_application = SIPApplication() self.first_run = False self.setOrganizationDomain("ag-projects.com") self.setOrganizationName("AG Projects") self.setApplicationName("Blink") self.setApplicationVersion(__version__) self.main_window = MainWindow() self.chat_window = ChatWindow() self.main_window.__closed__ = True self.chat_window.__closed__ = True self.main_window.installEventFilter(self) self.chat_window.installEventFilter(self) self.main_window.addAction(self.chat_window.control_button.actions.main_window) self.chat_window.addAction(self.main_window.quit_action) self.chat_window.addAction(self.main_window.help_action) self.chat_window.addAction(self.main_window.redial_action) self.chat_window.addAction(self.main_window.join_conference_action) self.chat_window.addAction(self.main_window.mute_action) self.chat_window.addAction(self.main_window.silent_action) self.chat_window.addAction(self.main_window.preferences_action) self.chat_window.addAction(self.main_window.transfers_window_action) self.chat_window.addAction(self.main_window.logs_window_action) self.chat_window.addAction(self.main_window.received_files_window_action) self.chat_window.addAction(self.main_window.screenshots_window_action) self.ip_address_monitor = IPAddressMonitor() self.log_manager = LogManager() self.presence_manager = PresenceManager() self.session_manager = SessionManager() self.update_manager = UpdateManager() # Prevent application from exiting after last window is closed if system tray was initialized if self.main_window.system_tray_icon: self.setQuitOnLastWindowClosed(False) self.main_window.check_for_updates_action.triggered.connect(self.update_manager.check_for_updates) self.main_window.check_for_updates_action.setVisible(self.update_manager != Null) if getattr(sys, 'frozen', False): XMLDocument.schema_path = Resources.get('xml-schemas') Account.register_extension(AccountExtension) BonjourAccount.register_extension(BonjourAccountExtension) Contact.register_extension(ContactExtension) Group.register_extension(GroupExtension) SIPSimpleSettings.register_extension(SIPSimpleSettingsExtension) notification_center = NotificationCenter() notification_center.add_observer(self, sender=self.sip_application) branding.setup(self) def run(self): self.first_run = not os.path.exists(ApplicationData.get('config')) self.sip_application.start(FileStorage(ApplicationData.directory)) self.exec_() self.update_manager.shutdown() self.sip_application.stop() self.sip_application.thread.join() self.log_manager.stop() def quit(self): self.chat_window.close() self.main_window.close() super(Blink, self).quit() def fetch_account(self): filename = os.path.expanduser('~/.blink_account') if not os.path.exists(filename): return try: data = open(filename).read() data = cjson.decode(data.replace(r'\/', '/')) except (OSError, IOError), e: print "Failed to read json data from ~/.blink_account: %s" % e return except cjson.DecodeError, e: print "Failed to decode json data from ~/.blink_account: %s" % e return
class SIPManager(object): __metaclass__ = Singleton implements(IObserver) def __init__(self): self._app = SIPApplication() self._delegate = None self._selected_account = None self._version = None self.ip_address_monitor = IPAddressMonitor() self.bonjour_disabled_on_sleep = False self.bonjour_conference_services = BonjourConferenceServices() self.notification_center = NotificationCenter() self.notification_center.add_observer(self, sender=self._app) self.notification_center.add_observer(self, sender=self._app.engine) self.notification_center.add_observer( self, name='CFGSettingsObjectDidChange') self.notification_center.add_observer(self, name='SIPAccountDidActivate') self.notification_center.add_observer(self, name='SIPAccountDidDeactivate') self.notification_center.add_observer( self, name='SIPAccountRegistrationDidSucceed') self.notification_center.add_observer( self, name='SIPAccountRegistrationDidEnd') self.notification_center.add_observer( self, name='SIPAccountRegistrationDidFail') self.notification_center.add_observer( self, name='SIPAccountRegistrationGotAnswer') self.notification_center.add_observer( self, name='SIPAccountMWIDidGetSummary') self.notification_center.add_observer( self, name='XCAPManagerDidDiscoverServerCapabilities') self.notification_center.add_observer(self, name='SystemWillSleep') self.notification_center.add_observer(self, name='SystemDidWakeUpFromSleep') def set_delegate(self, delegate): self._delegate = delegate def migratePasswordsToKeychain(self): account_manager = AccountManager() configuration_manager = ConfigurationManager() bonjour_account = BonjourAccount() for account in (account for account in account_manager.iter_accounts() if account is not bonjour_account): try: stored_auth_password = configuration_manager.get( account.__key__ + ['auth', 'password']) except ObjectNotFoundError: stored_auth_password = None try: stored_ldap_password = configuration_manager.get( account.__key__ + ['ldap', 'password']) except ObjectNotFoundError: stored_ldap_password = None try: stored_web_password = configuration_manager.get( account.__key__ + ['server', 'web_password']) except ObjectNotFoundError: stored_web_password = None if (stored_auth_password, stored_ldap_password, stored_web_password) != ('keychain', 'keychain', 'keychain'): Account.auth.password.dirty[account.auth] = True Account.ldap.password.dirty[account.ldap] = True Account.server.web_password.dirty[account.server] = True account.save() def init(self): self._version = str( NSBundle.mainBundle().infoDictionary().objectForKey_( "CFBundleShortVersionString")) #first_start = not os.path.exists(ApplicationData.get('config')) Account.register_extension(AccountExtension) BonjourAccount.register_extension(BonjourAccountExtension) Contact.register_extension(BlinkContactExtension) ContactGroup.register_extension(BlinkContactGroupExtension) SIPSimpleSettings.register_extension(SIPSimpleSettingsExtension) self._app.start(FileStorage(ApplicationData.directory)) self.init_configurations() # start session mgr SessionManager() def init_configurations(self): account_manager = AccountManager() settings = SIPSimpleSettings() self.notification_center.add_observer(self, sender=settings) # fixup default account self._selected_account = account_manager.default_account if self._selected_account is None: self._selected_account = account_manager.get_accounts()[0] default_ca = open(Resources.get('ca.crt'), "r").read().strip() self.set_default_certificate_authority(default_ca) def set_default_certificate_authority(self, ca): try: X509Certificate(ca) except GNUTLSError, e: BlinkLogger().log_error(u"Invalid Certificate Authority: %s" % e) return False settings = SIPSimpleSettings() must_save_ca = False tls_folder = ApplicationData.get('tls') if not os.path.exists(tls_folder): os.mkdir(tls_folder, 0700) ca_path = os.path.join(tls_folder, 'ca.crt') try: existing_cas = open(ca_path, "r").read().strip() except: existing_cas = None if ca != existing_cas: f = open(ca_path, "w") os.chmod(ca_path, 0600) f.write(ca) f.close() BlinkLogger().log_info( u"Added default Certificate Authority to %s" % ca_path) must_save_ca = True if must_save_ca: settings.tls.ca_list = ca_path settings.save() return True
class XCAPApplication(object): __metaclass__ = Singleton implements(IObserver) def __init__(self): self.application = SIPApplication() self.xcap_manager = None self.quit_event = Event() notification_center = NotificationCenter() notification_center.add_observer(self, sender=self.application) def start(self): self.application.start(FileBackend(os.path.realpath('test-config'))) @run_in_green_thread def stop(self): self.xcap_manager.stop() self.application.stop() def handle_notification(self, notification): handler = getattr(self, '_NH_%s' % notification.name, Null) handler(notification) @run_in_green_thread def _NH_SIPApplicationDidStart(self, notification): account_manager = AccountManager() self.xcap_manager = XCAPManager(account_manager.default_account) notification_center = NotificationCenter() notification_center.add_observer(self, sender=self.xcap_manager) self.xcap_manager.load(os.path.realpath('xcap-cache')) self.xcap_manager.start() def _NH_SIPApplicationDidEnd(self, notification): self.quit_event.set() def _NH_XCAPManagerDidChangeState(self, notification): print 'XCAP Manager state %s -> %s' % (notification.data.prev_state, notification.data.state) def _NH_XCAPManagerWillStart(self, notification): print 'XCAP Manager will start' def _NH_XCAPManagerDidStart(self, notification): print 'XCAP Manager did start' def _NH_XCAPManagerDidDiscoverServerCapabilities(self, notification): print ' contact list supported: %s' % notification.data.contactlist_supported print ' presence policies supported: %s' % notification.data.presence_policies_supported print ' dialoginfo policies supported: %s' % notification.data.dialoginfo_policies_supported print ' status icon supported: %s' % notification.data.status_icon_supported print ' offline status supported: %s' % notification.data.offline_status_supported def _NH_XCAPManagerWillEnd(self, notification): print 'XCAP Manager will end' def _NH_XCAPManagerDidEnd(self, notification): print 'XCAP Manager did end' def _NH_XCAPManagerDidReloadData(self, notification): print 'XCAP Manager reloaded data:' groups = dict.fromkeys(notification.data.groups) for group in groups: groups[group] = [] for contact in notification.data.contacts: if contact.group is not None: groups[contact.group].append(contact) print 'Buddies:' for group, contacts in groups.iteritems(): print ' %s:' % group for contact in contacts: if contact.name: print ' %s <%s>' % (contact.name, contact.uri) else: print ' %s' % contact.uri print ' subscribe-to-presence = %s' % contact.subscribe_to_presence print ' subscribe-to-dialoginfo = %s' % contact.subscribe_to_dialoginfo print ' presence-policies = %s' % (', '.join(p.id for p in contact.presence_policies) if contact.presence_policies else None) print ' dialoginfo-policies = %s' % (', '.join(p.id for p in contact.dialoginfo_policies) if contact.dialoginfo_policies else None) for attr, value in contact.attributes.iteritems(): print ' x: %s = %s' % (attr, value) print print 'Presence policies:' for policy in notification.data.presence_policies: print ' %s -> %s' % (policy.id, policy.action) if policy.sphere: print ' sphere = %s' % policy.sphere if policy.validity: print ' valid between:' for from_timestamp, until_timestamp in policy.validity: print ' %s - %s' % (from_timestamp, until_timestamp) if policy.multi_identity_conditions: print ' multi identity conditions:' for multi_condition in policy.multi_identity_conditions: if isinstance(multi_condition, CatchAllCondition) and multi_condition.exceptions: print ' anyone except' for exception in multi_condition.exceptions: if isinstance(exception, DomainException): print ' users from domain %s' % exception.domain elif isinstance(exception, UserException): print ' user %s' % exception.uri elif isinstance(multi_condition, CatchAllCondition): print ' anyone' elif isinstance(multi_condition, DomainCondition) and multi_condition.exceptions: print ' anyone from domain %s except' % multi_condition.domain for exception in multi_condition.exceptions: if isinstance(exception, UserException): print ' user %s' % exception.uri elif isinstance(multi_condition, DomainCondition): print ' anyone from domain %s' % multi_condition.domain if policy.provide_devices is All: print ' provide-devices = All' elif policy.provide_devices: print ' provide-devices:' for prv in policy.provide_devices: if isinstance(prv, Class): print ' class = %s' % prv elif isinstance(prv, OccurenceID): print ' occurence-id = %s' % prv elif isinstance(prv, DeviceID): print ' device-id = %s' % prv else: print ' unknown = %s(%r)' % (prv, type(prv).__name__) if policy.provide_persons is All: print ' provide-persons = All' elif policy.provide_persons: print ' provide-persons:' for prv in policy.provide_persons: if isinstance(prv, Class): print ' class = %s' % prv elif isinstance(prv, OccurenceID): print ' occurence-id = %s' % prv else: print ' unknown = %s(%r)' % (prv, type(prv).__name__) if policy.provide_services is All: print ' provide-services = All' elif policy.provide_services: print ' provide-services:' for prv in policy.provide_services: if isinstance(prv, Class): print ' class = %s' % prv elif isinstance(prv, OccurenceID): print ' occurence-id = %s' % prv elif isinstance(prv, ServiceURI): print ' service-uri = %s' % prv elif isinstance(prv, ServiceURIScheme): print ' service-uri-scheme = %s' % prv else: print ' unknown = %s(%r)' % (prv, type(prv).__name__) print ' provide-activities = %s' % policy.provide_activities print ' provide-class = %s' % policy.provide_class print ' provide-device-id = %s' % policy.provide_device_id print ' provide-mood = %s' % policy.provide_mood print ' provide-place-is = %s' % policy.provide_place_is print ' provide-place-type = %s' % policy.provide_place_type print ' provide-privacy = %s' % policy.provide_privacy print ' provide-relationship = %s' % policy.provide_relationship print ' provide-status-icon = %s' % policy.provide_status_icon print ' provide-sphere = %s' % policy.provide_sphere print ' provide-time-offset = %s' % policy.provide_time_offset print ' provide-user-input = %s' % policy.provide_user_input print ' provide-unknown-attributes = %s' % policy.provide_unknown_attributes print ' provide-all-attributes = %s' % policy.provide_all_attributes print print 'Dialog-info policies:' for policy in notification.data.dialoginfo_policies: print ' %s -> %s' % (policy.id, policy.action) if policy.sphere: print ' sphere = %s' % policy.sphere if policy.validity: print ' valid between:' for from_timestamp, until_timestamp in policy.validity: print ' %s - %s' % (from_timestamp, until_timestamp) print print 'RLS services:' for service in notification.data.services: print ' %s -> %s' % (service.uri, ', '.join(service.packages)) for entry in service.entries: print ' %s' % entry print print 'Offline status:' if notification.data.offline_status: print ' Note: %s' % notification.data.offline_status.note print ' Activity: %s' % notification.data.offline_status.activity else: print ' Missing'
class SIPManager(object, metaclass=Singleton): def __init__(self): BlinkLogger().log_info("Using SIP SIMPLE client SDK version %s" % sdk_version) self._app = SIPApplication() self._delegate = None self._selected_account = None self.ip_address_monitor = IPAddressMonitor() self.bonjour_disabled_on_sleep = False self.bonjour_conference_services = BonjourConferenceServices() self.notification_center = NotificationCenter() self.notification_center.add_observer(self, sender=self._app) self.notification_center.add_observer(self, sender=self._app.engine) self.notification_center.add_observer(self, name='CFGSettingsObjectDidChange') self.notification_center.add_observer(self, name='SIPAccountDidActivate') self.notification_center.add_observer(self, name='SIPAccountDidDeactivate') self.notification_center.add_observer(self, name='SIPAccountRegistrationDidSucceed') self.notification_center.add_observer(self, name='SIPAccountRegistrationDidEnd') self.notification_center.add_observer(self, name='SIPAccountGotMessageSummary') self.notification_center.add_observer(self, name='XCAPManagerDidDiscoverServerCapabilities') self.notification_center.add_observer(self, name='XCAPManagerClientError') self.notification_center.add_observer(self, name='SystemWillSleep') self.notification_center.add_observer(self, name='SystemDidWakeUpFromSleep') self.notification_center.add_observer(self, name='SIPEngineGotException') self.registrar_addresses = {} self.contact_addresses = {} def set_delegate(self, delegate): self._delegate = delegate def migratePasswordsToKeychain(self): if not NSApp.delegate().migrate_passwords_to_keychain: return account_manager = AccountManager() configuration_manager = ConfigurationManager() bonjour_account = BonjourAccount() for account in (account for account in account_manager.iter_accounts() if account is not bonjour_account): try: stored_auth_password = configuration_manager.get(account.__key__ + ['auth', 'password']) except ObjectNotFoundError: stored_auth_password = None try: stored_ldap_password = configuration_manager.get(account.__key__ + ['ldap', 'password']) except ObjectNotFoundError: stored_ldap_password = None try: stored_web_password = configuration_manager.get(account.__key__ + ['server', 'web_password']) except ObjectNotFoundError: stored_web_password = None if (stored_auth_password, stored_ldap_password, stored_web_password) != ('keychain', 'keychain', 'keychain'): Account.auth.password.dirty[account.auth] = True Account.ldap.password.dirty[account.ldap] = True Account.server.web_password.dirty[account.server] = True account.save() def cleanupIcons(self): save = False configuration_manager = ConfigurationManager() try: contacts = configuration_manager.get(['Addressbook', 'Contacts']) except Exception: return for data in contacts.values(): if 'icon' in data: del data['icon'] save = True if save: configuration_manager.save() def init(self): if NSApp.delegate().account_extension: Account.register_extension(NSApp.delegate().account_extension) else: Account.register_extension(AccountExtension) BonjourAccount.register_extension(BonjourAccountExtension) Contact.register_extension(BlinkContactExtension) Group.register_extension(BlinkGroupExtension) ContactURI.register_extension(BlinkContactURIExtension) if NSApp.delegate().general_extension: SIPSimpleSettings.register_extension(NSApp.delegate().general_extension) else: SIPSimpleSettings.register_extension(SIPSimpleSettingsExtension) app = AppKit.NSApplication.sharedApplication() self._app.start(FileStorage(ApplicationData.directory)) # start session mgr SessionManager() def init_configurations(self): account_manager = AccountManager() settings = SIPSimpleSettings() # fixup default account self._selected_account = account_manager.default_account if self._selected_account is None: self._selected_account = account_manager.get_accounts()[0] # save default ca if needed ca = open(Resources.get('ca.crt'), "r").read().strip() try: X509Certificate(ca) except GNUTLSError as e: BlinkLogger().log_error("Invalid Certificate Authority: %s" % e) return tls_folder = ApplicationData.get('tls') if not os.path.exists(tls_folder): os.mkdir(tls_folder, 0o700) ca_path = os.path.join(tls_folder, 'ca.crt') try: existing_cas = open(ca_path, "r").read().strip() except Exception: existing_cas = None if ca == existing_cas: return with open(ca_path, "wb") as f: os.chmod(ca_path, 0o600) f.write(ca.encode()) BlinkLogger().log_debug("Added default Certificate Authority to %s" % ca_path) settings.tls.ca_list = ca_path settings.save() def add_certificate_authority(self, ca): # not used anymore, let users add CAs in keychain instead try: X509Certificate(ca) except GNUTLSError as e: BlinkLogger().log_error("Invalid Certificate Authority: %s" % e) return False settings = SIPSimpleSettings() must_save_ca = False if settings.tls.ca_list is not None: ca_path = settings.tls.ca_list.normalized else: tls_folder = ApplicationData.get('tls') if not os.path.exists(tls_folder): os.mkdir(tls_folder, 0o700) ca_path = os.path.join(tls_folder, 'ca.crt') must_save_ca = True try: existing_cas = open(ca_path, "r").read().strip() + os.linesep except: existing_cas = None ca_list = ca else: ca_list = existing_cas if ca in existing_cas else existing_cas + ca if ca_list != existing_cas: f = open(ca_path, "w") os.chmod(ca_path, 0o600) f.write(ca_list) f.close() BlinkLogger().log_debug("Added new Certificate Authority to %s" % ca_path) must_save_ca = True if must_save_ca: settings.tls.ca_list = ca_path settings.save() return True def save_certificates(self, response): passport = response["passport"] address = response["sip_address"] tls_folder = ApplicationData.get('tls') if not os.path.exists(tls_folder): os.mkdir(tls_folder, 0o700) ca = passport["ca"].strip() + os.linesep self.add_certificate_authority(ca) crt = passport["crt"].strip() + os.linesep try: X509Certificate(crt) except GNUTLSError as e: BlinkLogger().log_error("Invalid TLS certificate: %s" % e) return None key = passport["key"].strip() + os.linesep try: X509PrivateKey(key) except GNUTLSError as e: BlinkLogger().log_error("Invalid Private Key: %s" % e) return None crt_path = os.path.join(tls_folder, address + ".crt") f = open(crt_path, "w") os.chmod(crt_path, 0o600) f.write(crt) f.write(key) f.close() BlinkLogger().log_info("Saved new TLS Certificate and Private Key to %s" % crt_path) return crt_path def fetch_account(self): """Fetch the SIP account from ~/.blink_account and create/update it as needed""" filename = os.path.expanduser('~/.blink_account') if not os.path.exists(filename): return try: data = open(filename).read() data = json.loads(data.decode().replace('\\/', '/')) except (OSError, IOError) as e: BlinkLogger().log_error("Failed to read json data from ~/.blink_account: %s" % e) return except ValueError as e: BlinkLogger().log_error("Failed to decode json data from ~/.blink_account: %s" % e) return finally: unlink(filename) data = defaultdict(lambda: None, data) account_id = data['sip_address'] if account_id is None: return account_manager = AccountManager() try: account = account_manager.get_account(account_id) except KeyError: account = Account(account_id) account.display_name = data['display_name'] default_account = account else: default_account = account_manager.default_account account.auth.username = data['auth_username'] account.auth.password = data['password'] or '' account.sip.outbound_proxy = data['outbound_proxy'] account.xcap.xcap_root = data['xcap_root'] account.nat_traversal.msrp_relay = data['msrp_relay'] account.server.settings_url = data['settings_url'] account.web_alert.alert_url = data['web_alert_url'] account.server.web_password = data['web_password'] account.conference.server_address = data['conference_server'] if data['ldap_hostname']: account.ldap.enabled = True account.ldap.hostname = data['ldap_hostname'] account.ldap.dn = data['ldap_dn'] account.ldap.username = data['ldap_username'] if data['ldap_password']: account.ldap.password = data['ldap_password'] if data['ldap_transport']: account.ldap.transport = data['ldap_transport'] if data['ldap_port']: account.ldap.port = data['ldap_port'] if data['passport'] is not None: cert_path = self.save_certificates(data) if cert_path: account.tls.certificate = cert_path account.enabled = True account.save() account_manager.default_account = default_account settings = SIPSimpleSettings() settings.service_provider.name = data['service_provider_name'] settings.service_provider.help_url = data['service_provider_help_url'] settings.service_provider.about_url = data['service_provider_about_url'] settings.save() def get_recordings_directory(self): return ApplicationData.get('history') def get_contacts_backup_directory(self): path = ApplicationData.get('contacts_backup') makedirs(path) return path def get_recordings(self, filter_uris=[]): result = [] historydir = self.get_recordings_directory() for acct in os.listdir(historydir): dirname = historydir + "/" + acct if not os.path.isdir(dirname): continue files = [dirname+"/"+f for f in os.listdir(dirname)] for file in files: try: recording_type = "audio" if file.endswith(".wav") else "video" stat = os.stat(file) toks = file.split("/")[-1].split("-", 2) if len(toks) == 3: date, time, rest = toks timestamp = date[:4]+"/"+date[4:6]+"/"+date[6:8]+" "+time[:2]+":"+time[2:4] pos = rest.rfind(".") if pos >= 0: remote = rest[:pos] else: remote = rest try: identity = SIPURI.parse('sip:'+str(remote)) remote_party = format_identity_to_string(identity, check_contact=True) except SIPCoreError: remote_party = "%s" % (remote) else: try: identity = SIPURI.parse('sip:'+str(file[:-4])) remote_party = format_identity_to_string(identity, check_contact=True) except SIPCoreError: remote_party = file[:-4] timestamp = datetime.fromtimestamp(int(stat.st_ctime)).strftime("%E %T") if filter_uris and remote_party not in filter_uris: continue result.append((timestamp, remote_party, file, recording_type)) except Exception: pass sorted(result, key=lambda x: x[0]) return result def get_contact_backups(self): result = [] dirname = self.get_contacts_backup_directory() if not os.path.isdir(dirname): return files = [dirname+"/"+f for f in os.listdir(dirname) if f.endswith(".pickle")] for file in files: try: os.stat(file) date = file.split("/")[-1].split('-')[0] time = file.split("/")[-1].split('-')[1].split('.')[0] timestamp = date[:4]+"/"+date[4:6]+"/"+date[6:8]+" "+time[:2]+":"+time[2:4] result.append((timestamp, file)) except Exception: pass result.sort(lambda a,b: cmp(a[0],b[0])) return result def is_muted(self): return self._app.voice_audio_mixer and self._app.voice_audio_mixer.muted def mute(self, flag): self._app.voice_audio_mixer.muted = flag self.notification_center.post_notification("BlinkMuteChangedState", sender=self) def is_silent(self): return SIPSimpleSettings().audio.silent def silent(self, flag): SIPSimpleSettings().audio.silent = flag SIPSimpleSettings().save() @run_in_gui_thread def handle_notification(self, notification): handler = getattr(self, '_NH_%s' % notification.name, Null) handler(notification.sender, notification.data) def _NH_SIPApplicationFailedToStartTLS(self, sender, data): BlinkLogger().log_info('Failed to start TLS transport: %s' % data.error) def _NH_SIPApplicationWillStart(self, sender, data): settings = SIPSimpleSettings() _version = str(NSBundle.mainBundle().infoDictionary().objectForKey_("CFBundleShortVersionString")) settings.user_agent = "%s %s (MacOSX)" % (NSApp.delegate().applicationName, _version) BlinkLogger().log_debug("SIP User Agent: %s" % settings.user_agent) settings.save() self.migratePasswordsToKeychain() self.cleanupIcons() # Set audio settings compatible with AEC and Noise Suppression settings.audio.sample_rate = 32000 if settings.audio.echo_canceller.enabled else 48000 if NSApp.delegate().service_provider_help_url and settings.service_provider.help_url != NSApp.delegate().service_provider_help_url: settings.service_provider.help_url = NSApp.delegate().service_provider_help_url settings.save() if NSApp.delegate().service_provider_name and settings.service_provider.name != NSApp.delegate().service_provider_name: settings.service_provider.name = NSApp.delegate().service_provider_name settings.save() BlinkLogger().log_debug("Audio engine sampling rate %dKHz covering 0-%dKHz spectrum" % (settings.audio.sample_rate/1000, settings.audio.sample_rate/1000/2)) BlinkLogger().log_debug("Acoustic Echo Canceller is %s" % ('enabled' if settings.audio.echo_canceller.enabled else 'disabled')) account_manager = AccountManager() for account in account_manager.iter_accounts(): must_save = False if account is not BonjourAccount() and account.sip.primary_proxy is None and account.sip.outbound_proxy and not account.sip.selected_proxy: account.sip.primary_proxy = account.sip.outbound_proxy if account is not BonjourAccount() and settings.tls.verify_server != account.tls.verify_server: account.tls.verify_server = settings.tls.verify_server if account.tls.certificate and os.path.basename(account.tls.certificate.normalized) != 'default.crt': account.tls.certificate = DefaultValue if account.rtp.encryption_type == '': account.rtp.encryption.enabled = False elif account.rtp.encryption_type == 'opportunistic': account.rtp.encryption.enabled = True account.rtp.encryption.key_negotiation = 'opportunistic' elif account.rtp.encryption_type == 'sdes_optional': account.rtp.encryption.enabled = True account.rtp.encryption.key_negotiation = 'sdes_optional' elif account.rtp.encryption_type == 'sdes_mandatory': account.rtp.encryption.enabled = True account.rtp.encryption.key_negotiation = 'sdes_mandatory' elif account.rtp.encryption_type == 'zrtp': account.rtp.encryption.enabled = True account.rtp.encryption.key_negotiation = 'zrtp' account.save() logger = FileLogger() logger.start() self.ip_address_monitor.start() def _NH_SIPApplicationDidStart(self, sender, data): settings = SIPSimpleSettings() settings.audio.enable_aec = settings.audio.echo_canceller.enabled settings.audio.sound_card_delay = settings.audio.echo_canceller.tail_length #self._app.engine.enable_colorbar_device = True BlinkLogger().log_debug("SDK loaded") BlinkLogger().log_debug("SIP device ID: %s" % settings.instance_id) codecs_print = [] for codec in settings.rtp.audio_codec_list: codecs_print.append(beautify_audio_codec(codec)) BlinkLogger().log_info("Enabled audio codecs: %s" % ", ".join(codecs_print)) if settings.audio.input_device is None: BlinkLogger().log_info("Switching audio input device to system default") settings.audio.input_device = 'system_default' if settings.audio.output_device is None: BlinkLogger().log_info("Switching audio output device to system default") settings.audio.output_device = 'system_default' if settings.audio.alert_device is None: BlinkLogger().log_info("Switching audio alert device to system default") settings.audio.alert_device = 'system_default' try: from VideoController import VideoController except ImportError: pass else: if settings.video.max_bitrate is not None and settings.video.max_bitrate > 10000: settings.video.max_bitrate = 4.0 codecs_print = [] for codec in settings.rtp.video_codec_list: codecs_print.append(beautify_video_codec(codec)) #BlinkLogger().log_info(u"Enabled video codecs: %s" % ", ".join(codecs_print)) #BlinkLogger().log_debug(u"Available video cameras: %s" % ", ".join((camera for camera in self._app.engine.video_devices))) if settings.video.device != "system_default" and settings.video.device != self._app.video_device.real_name and self._app.video_device.real_name != None: settings.video.device = self._app.video_device.real_name #BlinkLogger().log_info(u"Using video camera %s" % self._app.video_device.real_name) elif settings.video.device is None: devices = list(device for device in self._app.engine.video_devices if device not in ('system_default', None)) if devices: BlinkLogger().log_info("Switching video camera to %s" % devices[0]) settings.video.device = devices[0] else: BlinkLogger().log_debug("Using video camera %s" % self._app.video_device.real_name) settings.save() bonjour_account = BonjourAccount() if bonjour_account.enabled: for transport in settings.sip.transport_list: try: BlinkLogger().log_debug('Bonjour Account listens on %s' % bonjour_account.contact[transport]) except KeyError: pass self.init_configurations() def _NH_SIPApplicationWillEnd(self, sender, data): self.ip_address_monitor.stop() def _NH_SIPEngineGotException(self, sender, data): BlinkLogger().log_info("SIP Engine Exception", data) NSRunAlertPanel(NSLocalizedString("Error", "Window title"), NSLocalizedString("There was a critical error of core functionality:\n%s", "Label") % data.traceback, NSLocalizedString("Quit", "Button title"), None, None) NSApp.terminate_(None) return def _NH_SIPEngineDidFail(self, sender, data): NSRunAlertPanel(NSLocalizedString("Fatal Error Encountered", "Window title"), NSLocalizedString("There was a fatal error affecting Blink core functionality. The program cannot continue and will be shut down. Information about the cause of the error can be found by opening the Console application and searching for 'Blink'.", "Label"), NSLocalizedString("Shut Down", "Button title"), None, None) import signal BlinkLogger().log_info("A fatal error occurred, forcing termination of Blink") os.kill(os.getpid(), signal.SIGTERM) def _NH_SIPAccountDidActivate(self, account, data): BlinkLogger().log_info("Account %s activated" % account.id) # Activate BonjourConferenceServer discovery if account is BonjourAccount(): call_in_green_thread(self.bonjour_conference_services.start) else: BlinkLogger().log_info("Account %s loaded %d CAs from %s" % (account.id, len(account.tls_credentials._trusted), account.ca_list)) def _NH_SIPAccountDidDeactivate(self, account, data): BlinkLogger().log_info("Account %s deactivated" % account.id) MWIData.remove(account) # Deactivate BonjourConferenceServer discovery if account is BonjourAccount(): call_in_green_thread(self.bonjour_conference_services.stop) def _NH_SIPAccountRegistrationDidSucceed(self, account, data): #contact_header_list = data.contact_header_list #if len(contact_header_list) > 1: # message += u'Other registered Contact Addresses:\n%s\n' % '\n'.join(' %s (expires in %s seconds)' % (other_contact_header.uri, other_contact_header.expires) for other_contact_header in contact_header_list if other_contact_header.uri!=data.contact_header.uri) _address = "%s:%s;transport=%s" % (data.registrar.address, data.registrar.port, data.registrar.transport) _contact = data.contact_header.uri registrar_changed = False contact_changed = False try: old_address = self.registrar_addresses[account.id] except KeyError: registrar_changed = True else: if old_address != _address: registrar_changed = True try: old_contact = self.contact_addresses[account.id] except KeyError: contact_changed = True else: if old_contact != _contact: contact_changed = True if contact_changed and registrar_changed: message = 'Account %s registered contact %s at %s:%d;transport=%s for %d seconds' % (account.id, data.contact_header.uri, data.registrar.address, data.registrar.port, data.registrar.transport, data.expires) BlinkLogger().log_info(message) elif contact_changed: message = 'Account %s changed contact to %s' % (account.id, data.contact_header.uri) BlinkLogger().log_debug(message) elif registrar_changed: message = 'Account %s changed registrar to %s:%d;transport=%s' % (account.id, data.registrar.address, data.registrar.port, data.registrar.transport) BlinkLogger().log_debug(message) self.registrar_addresses[account.id] = _address self.contact_addresses[account.id] = data.contact_header.uri if account.contact.public_gruu is not None: message = 'Account %s has public SIP GRUU %s' % (account.id, account.contact.public_gruu) BlinkLogger().log_debug(message) if account.contact.temporary_gruu is not None: message = 'Account %s has temporary SIP GRUU %s' % (account.id, account.contact.temporary_gruu) BlinkLogger().log_debug(message) def _NH_SIPAccountRegistrationDidEnd(self, account, data): BlinkLogger().log_info("Account %s was unregistered" % account.id) try: del self.registrar_addresses[account.id] except KeyError: pass try: del self.contact_addresses[account.id] except KeyError: pass def _NH_SIPAccountGotMessageSummary(self, account, data): BlinkLogger().log_debug("Received voicemail notification for account %s" % account.id) summary = data.message_summary if summary.summaries.get('voice-message') is None: return voice_messages = summary.summaries['voice-message'] new_messages = int(voice_messages['new_messages']) old_messages = int(voice_messages['old_messages']) MWIData.store(account, summary) if summary.messages_waiting and new_messages > 0: nc_title = NSLocalizedString("New Voicemail Message", "System notification title") if new_messages == 1 else NSLocalizedString("New Voicemail Messages", "System notification title") nc_subtitle = NSLocalizedString("On Voicemail Server", "System notification subtitle") if old_messages > 0: nc_body = NSLocalizedString("You have %d new and ", "System notification body") % new_messages + NSLocalizedString("%d old voicemail messages", "System notification body") % old_messages else: nc_body = NSLocalizedString("You have %d new voicemail messages", "System notification body") % new_messages NSApp.delegate().gui_notify(nc_title, nc_body, nc_subtitle) self.notification_center.post_notification('BlinkAccountGotMessageSummary', sender=account, data=data) def _NH_CFGSettingsObjectDidChange(self, account, data): if isinstance(account, Account): if 'message_summary.enabled' in data.modified: if not account.message_summary.enabled: MWIData.remove(account) if 'audio.echo_canceller.enabled' in data.modified: settings = SIPSimpleSettings() settings.audio.sample_rate = 32000 if settings.audio.echo_canceller.enabled and settings.audio.sample_rate not in ('16000', '32000') else 48000 spectrum = settings.audio.sample_rate/1000/2 if settings.audio.sample_rate/1000/2 < 20 else 20 BlinkLogger().log_info("Audio sample rate is set to %dkHz covering 0-%dkHz spectrum" % (settings.audio.sample_rate/1000, spectrum)) BlinkLogger().log_debug("Acoustic Echo Canceller is %s" % ('enabled' if settings.audio.echo_canceller.enabled else 'disabled')) if spectrum >=20: BlinkLogger().log_debug("For studio quality disable the option 'Use ambient noise reduction' in System Preferences > Sound > Input section.") settings.save() elif 'audio.sample_rate' in data.modified: settings = SIPSimpleSettings() spectrum = settings.audio.sample_rate/1000/2 if settings.audio.sample_rate/1000/2 < 20 else 20 if settings.audio.sample_rate == 48000: settings.audio.echo_canceller.enabled = False settings.audio.enable_aec = False settings.save() else: settings.audio.echo_canceller.enabled = True settings.audio.enable_aec = True settings.save() def _NH_SystemWillSleep(self, sender, data): bonjour_account = BonjourAccount() if bonjour_account.enabled: BlinkLogger().log_info("Computer will go to sleep") BlinkLogger().log_debug("Disabling Bonjour discovery during sleep") bonjour_account.enabled=False self.bonjour_disabled_on_sleep=True def _NH_SystemDidWakeUpFromSleep(self, sender, data): BlinkLogger().log_info("Computer wake up from sleep") bonjour_account = BonjourAccount() if not bonjour_account.enabled and self.bonjour_disabled_on_sleep: BlinkLogger().log_debug("Enabling Bonjour discovery after wakeup from sleep") bonjour_account.enabled=True self.bonjour_disabled_on_sleep=False def _NH_XCAPManagerDidDiscoverServerCapabilities(self, sender, data): account = sender.account xcap_root = sender.xcap_root if xcap_root is None: # The XCAP manager might be stopped because this notification is processed in a different # thread from which it was posted return BlinkLogger().log_debug("Using XCAP root %s for account %s" % (xcap_root, account.id)) BlinkLogger().log_debug("XCAP server capabilities: %s" % ", ".join(data.auids)) def _NH_XCAPManagerClientError(self, sender, data): account = sender.account BlinkLogger().log_info("XCAP error for account %s (%s): %s" % (account.id, sender.xcap_root, data.error)) def _NH_SIPEngineGotException(self, sender, data): BlinkLogger().log_info("SIP Engine got fatal error: %s" % data.traceback) NSRunAlertPanel(NSLocalizedString("Error", "Window title"), NSLocalizedString("There was a critical error of core functionality:\n%s", "Label") % data.traceback, NSLocalizedString("Quit", "Button title"), None, None) NSApp.terminate_(None) return def validateAddAccountAction(self): if NSApp.delegate().maximum_accounts: return len([account for account in AccountManager().iter_accounts() if not isinstance(account, BonjourAccount)]) <= NSApp.delegate().maximum_accounts return True
class XCAPApplication(object): __metaclass__ = Singleton implements(IObserver) def __init__(self): self.application = SIPApplication() self.xcap_manager = None self.quit_event = Event() notification_center = NotificationCenter() notification_center.add_observer(self, sender=self.application) def start(self): self.application.start(FileBackend(os.path.realpath('test-config'))) @run_in_green_thread def stop(self): self.xcap_manager.stop() self.application.stop() def handle_notification(self, notification): handler = getattr(self, '_NH_%s' % notification.name, Null) handler(notification) @run_in_green_thread def _NH_SIPApplicationDidStart(self, notification): account_manager = AccountManager() self.xcap_manager = XCAPManager(account_manager.default_account) notification_center = NotificationCenter() notification_center.add_observer(self, sender=self.xcap_manager) self.xcap_manager.load(os.path.realpath('xcap-cache')) self.xcap_manager.start() def _NH_SIPApplicationDidEnd(self, notification): self.quit_event.set() def _NH_XCAPManagerDidChangeState(self, notification): print 'XCAP Manager state %s -> %s' % (notification.data.prev_state, notification.data.state) def _NH_XCAPManagerWillStart(self, notification): print 'XCAP Manager will start' def _NH_XCAPManagerDidStart(self, notification): print 'XCAP Manager did start' def _NH_XCAPManagerDidDiscoverServerCapabilities(self, notification): print ' contact list supported: %s' % notification.data.contactlist_supported print ' presence policies supported: %s' % notification.data.presence_policies_supported print ' dialoginfo policies supported: %s' % notification.data.dialoginfo_policies_supported print ' status icon supported: %s' % notification.data.status_icon_supported print ' offline status supported: %s' % notification.data.offline_status_supported def _NH_XCAPManagerWillEnd(self, notification): print 'XCAP Manager will end' def _NH_XCAPManagerDidEnd(self, notification): print 'XCAP Manager did end' def _NH_XCAPManagerDidReloadData(self, notification): print 'XCAP Manager reloaded data:' groups = dict.fromkeys(notification.data.groups) for group in groups: groups[group] = [] for contact in notification.data.contacts: if contact.group is not None: groups[contact.group].append(contact) print 'Buddies:' for group, contacts in groups.iteritems(): print ' %s:' % group for contact in contacts: if contact.name: print ' %s <%s>' % (contact.name, contact.uri) else: print ' %s' % contact.uri print ' subscribe-to-presence = %s' % contact.subscribe_to_presence print ' subscribe-to-dialoginfo = %s' % contact.subscribe_to_dialoginfo print ' presence-policies = %s' % ( ', '.join(p.id for p in contact.presence_policies) if contact.presence_policies else None) print ' dialoginfo-policies = %s' % ( ', '.join(p.id for p in contact.dialoginfo_policies) if contact.dialoginfo_policies else None) for attr, value in contact.attributes.iteritems(): print ' x: %s = %s' % (attr, value) print print 'Presence policies:' for policy in notification.data.presence_policies: print ' %s -> %s' % (policy.id, policy.action) if policy.sphere: print ' sphere = %s' % policy.sphere if policy.validity: print ' valid between:' for from_timestamp, until_timestamp in policy.validity: print ' %s - %s' % (from_timestamp, until_timestamp) if policy.multi_identity_conditions: print ' multi identity conditions:' for multi_condition in policy.multi_identity_conditions: if isinstance( multi_condition, CatchAllCondition) and multi_condition.exceptions: print ' anyone except' for exception in multi_condition.exceptions: if isinstance(exception, DomainException): print ' users from domain %s' % exception.domain elif isinstance(exception, UserException): print ' user %s' % exception.uri elif isinstance(multi_condition, CatchAllCondition): print ' anyone' elif isinstance( multi_condition, DomainCondition) and multi_condition.exceptions: print ' anyone from domain %s except' % multi_condition.domain for exception in multi_condition.exceptions: if isinstance(exception, UserException): print ' user %s' % exception.uri elif isinstance(multi_condition, DomainCondition): print ' anyone from domain %s' % multi_condition.domain if policy.provide_devices is All: print ' provide-devices = All' elif policy.provide_devices: print ' provide-devices:' for prv in policy.provide_devices: if isinstance(prv, Class): print ' class = %s' % prv elif isinstance(prv, OccurenceID): print ' occurence-id = %s' % prv elif isinstance(prv, DeviceID): print ' device-id = %s' % prv else: print ' unknown = %s(%r)' % ( prv, type(prv).__name__) if policy.provide_persons is All: print ' provide-persons = All' elif policy.provide_persons: print ' provide-persons:' for prv in policy.provide_persons: if isinstance(prv, Class): print ' class = %s' % prv elif isinstance(prv, OccurenceID): print ' occurence-id = %s' % prv else: print ' unknown = %s(%r)' % ( prv, type(prv).__name__) if policy.provide_services is All: print ' provide-services = All' elif policy.provide_services: print ' provide-services:' for prv in policy.provide_services: if isinstance(prv, Class): print ' class = %s' % prv elif isinstance(prv, OccurenceID): print ' occurence-id = %s' % prv elif isinstance(prv, ServiceURI): print ' service-uri = %s' % prv elif isinstance(prv, ServiceURIScheme): print ' service-uri-scheme = %s' % prv else: print ' unknown = %s(%r)' % ( prv, type(prv).__name__) print ' provide-activities = %s' % policy.provide_activities print ' provide-class = %s' % policy.provide_class print ' provide-device-id = %s' % policy.provide_device_id print ' provide-mood = %s' % policy.provide_mood print ' provide-place-is = %s' % policy.provide_place_is print ' provide-place-type = %s' % policy.provide_place_type print ' provide-privacy = %s' % policy.provide_privacy print ' provide-relationship = %s' % policy.provide_relationship print ' provide-status-icon = %s' % policy.provide_status_icon print ' provide-sphere = %s' % policy.provide_sphere print ' provide-time-offset = %s' % policy.provide_time_offset print ' provide-user-input = %s' % policy.provide_user_input print ' provide-unknown-attributes = %s' % policy.provide_unknown_attributes print ' provide-all-attributes = %s' % policy.provide_all_attributes print print 'Dialog-info policies:' for policy in notification.data.dialoginfo_policies: print ' %s -> %s' % (policy.id, policy.action) if policy.sphere: print ' sphere = %s' % policy.sphere if policy.validity: print ' valid between:' for from_timestamp, until_timestamp in policy.validity: print ' %s - %s' % (from_timestamp, until_timestamp) print print 'RLS services:' for service in notification.data.services: print ' %s -> %s' % (service.uri, ', '.join(service.packages)) for entry in service.entries: print ' %s' % entry print print 'Offline status:' if notification.data.offline_status: print ' Note: %s' % notification.data.offline_status.note print ' Activity: %s' % notification.data.offline_status.activity else: print ' Missing'