示例#1
0
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()
示例#2
0
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()
示例#3
0
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)
示例#4
0
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)
示例#5
0
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
示例#6
0
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
示例#7
0
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'
示例#9
0
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'