示例#1
0
    def __init__(self,
                 sip_to_stdout=False,
                 msrp_to_stdout=False,
                 pjsip_to_stdout=False,
                 notifications_to_stdout=False,
                 msrp_level=log.level.ERROR):
        self.sip_to_stdout = sip_to_stdout
        self.msrp_to_stdout = msrp_to_stdout
        self.pjsip_to_stdout = pjsip_to_stdout
        self.notifications_to_stdout = notifications_to_stdout
        self.msrp_level = msrp_level

        self._siptrace_filename = None
        self._siptrace_file = None
        self._siptrace_error = False
        self._siptrace_start_time = None
        self._siptrace_packet_count = 0

        self._msrptrace_filename = None
        self._msrptrace_file = None
        self._msrptrace_error = False

        self._pjsiptrace_filename = None
        self._pjsiptrace_file = None
        self._pjsiptrace_error = False

        self._notifications_filename = None
        self._notifications_file = None
        self._notifications_error = False

        self._event_queue = EventQueue(handler=self._process_notification,
                                       name='Log handling')
        self._log_directory_error = False
示例#2
0
 def start(self):
     settings = SIPSimpleSettings()
     notification_center = NotificationCenter()
     notification_center.add_observer(self)
     if settings.logs.trace_sip:
         self.siptrace_file = LogFile(
             os.path.join(ApplicationData.directory, 'logs',
                          'sip_trace.txt'))
     if settings.logs.trace_msrp:
         self.msrptrace_file = LogFile(
             os.path.join(ApplicationData.directory, 'logs',
                          'msrp_trace.txt'))
     if settings.logs.trace_pjsip:
         self.pjsiptrace_file = LogFile(
             os.path.join(ApplicationData.directory, 'logs',
                          'pjsip_trace.txt'))
     if settings.logs.trace_notifications:
         self.notifications_file = LogFile(
             os.path.join(ApplicationData.directory, 'logs',
                          'notifications_trace.txt'))
     self._siptrace_start_time = datetime.now()
     self._siptrace_packet_count = 0
     self.event_queue = EventQueue(handler=self._process_notification,
                                   name='Blink LogManager')
     self.event_queue.start()
     while settings.logs.trace_notifications and self.notification_queue and self.notification_queue.notifications:
         notification = self.notification_queue.notifications.popleft()
         self.handle_notification(notification)
     self.notification_queue = None
示例#3
0
 def __init__(self):
     main_config_file = process.config_file(RadiusConfig.config_file)
     if main_config_file is None:
         raise RuntimeError("Cannot find the radius configuration file: `%s'" % RadiusConfig.config_file)
     try:
         config = dict(line.rstrip("\n").split(None, 1) for line in open(main_config_file) if len(line.split(None, 1)) == 2 and not line.startswith("#"))
         secrets = dict(line.rstrip("\n").split(None, 1) for line in open(config["servers"]) if len(line.split(None, 1)) == 2 and not line.startswith("#"))
         server = config["acctserver"]
         try:
             server, acctport = server.split(":")
             acctport = int(acctport)
         except ValueError:
             acctport = 1813
         secret = secrets[server]
         dicts = [RadiusDictionaryFile(config["dictionary"])]
         if RadiusConfig.additional_dictionary:
             additional_dictionary = process.config_file(RadiusConfig.additional_dictionary)
             if additional_dictionary:
                 dicts.append(RadiusDictionaryFile(additional_dictionary))
             else:
                 log.warn("Could not load additional RADIUS dictionary file: `%s'" % RadiusConfig.additional_dictionary)
         raddict = pyrad.dictionary.Dictionary(*dicts)
         timeout = int(config["radius_timeout"])
         retries = int(config["radius_retries"])
     except Exception:
         log.fatal("cannot read the RADIUS configuration file")
         raise
     pyrad.client.Client.__init__(self, server, 1812, acctport, secret, raddict)
     self.timeout = timeout
     self.retries = retries
     if "bindaddr" in config and config["bindaddr"] != "*":
         self.bind((config["bindaddr"], 0))
     EventQueue.__init__(self, self.do_accounting)
示例#4
0
    def __init__(self):
        self.queue = EventQueue(handler=self._handle_task, name='RadiusQueue')
        self.queue.start()

        credentials = RadiusDatabaseConfig.user and (
            "%s%s@" % (RadiusDatabaseConfig.user,
                       RadiusDatabaseConfig.password and ":%s" %
                       (RadiusDatabaseConfig.password) or '')) or ''
        self.conn = sqlobject.connectionForURI(
            "mysql://%s%s/%s" % (credentials, RadiusDatabaseConfig.host,
                                 RadiusDatabaseConfig.database))
示例#5
0
 def __init__(self):
     main_config_file = process.configuration.file(RadiusConfig.config_file)
     if main_config_file is None:
         raise RuntimeError(
             'Cannot find the radius configuration file: %r' %
             RadiusConfig.config_file)
     try:
         config = dict(
             line.rstrip('\n').split(None, 1)
             for line in open(main_config_file)
             if len(line.split(None, 1)) == 2 and not line.startswith('#'))
         secrets = dict(
             line.rstrip('\n').split(None, 1)
             for line in open(config['servers'])
             if len(line.split(None, 1)) == 2 and not line.startswith('#'))
         server = config['acctserver']
         try:
             server, acctport = server.split(':')
             acctport = int(acctport)
         except ValueError:
             log.info(
                 'Could not load additional RADIUS dictionary file: %r' %
                 RadiusConfig.additional_dictionary)
             acctport = 1813
         log.info('Using RADIUS server at %s:%d' % (server, acctport))
         secret = secrets[server]
         log.info("Using RADIUS dictionary file %s" % config['dictionary'])
         dicts = [RadiusDictionaryFile(config['dictionary'])]
         if RadiusConfig.additional_dictionary:
             additional_dictionary = process.configuration.file(
                 RadiusConfig.additional_dictionary)
             if additional_dictionary:
                 log.info("Using additional RADIUS dictionary file %s" %
                          RadiusConfig.additional_dictionary)
                 dicts.append(RadiusDictionaryFile(additional_dictionary))
             else:
                 log.warning(
                     'Could not load additional RADIUS dictionary file: %r'
                     % RadiusConfig.additional_dictionary)
         raddict = pyrad.dictionary.Dictionary(*dicts)
         timeout = int(config['radius_timeout'])
         retries = int(config['radius_retries'])
     except Exception:
         log.critical('cannot read the RADIUS configuration file %s' %
                      RadiusConfig.config_file)
         raise
     pyrad.client.Client.__init__(self, server, 1812, acctport, 3799,
                                  secret, raddict)
     self.timeout = timeout
     self.retries = retries
     if 'bindaddr' in config and config['bindaddr'] != '*':
         self.bind((config['bindaddr'], 0))
     EventQueue.__init__(self, self.do_accounting)
示例#6
0
    def start(self):
        # try to create the log directory
        try:
            self._init_log_directory()
        except Exception:
            pass

        # register to receive log notifications
        notification_center = NotificationCenter()
        notification_center.add_observer(self)

        # start the thread processing the notifications
        self._event_queue = EventQueue(handler=self._process_notification,
                                       name='Log handling')
        self._event_queue.start()
示例#7
0
    def __init__(
        self,
        sip_to_stdout=False,
        msrp_to_stdout=False,
        pjsip_to_stdout=False,
        notifications_to_stdout=False,
        msrp_level=log.level.ERROR,
    ):
        self.sip_to_stdout = sip_to_stdout
        self.msrp_to_stdout = msrp_to_stdout
        self.pjsip_to_stdout = pjsip_to_stdout
        self.notifications_to_stdout = notifications_to_stdout
        self.msrp_level = msrp_level

        self._siptrace_filename = None
        self._siptrace_file = None
        self._siptrace_error = False
        self._siptrace_start_time = None
        self._siptrace_packet_count = 0

        self._msrptrace_filename = None
        self._msrptrace_file = None
        self._msrptrace_error = False

        self._pjsiptrace_filename = None
        self._pjsiptrace_file = None
        self._pjsiptrace_error = False

        self._notifications_filename = None
        self._notifications_file = None
        self._notifications_error = False

        self._event_queue = EventQueue(handler=self._process_notification, name="Log handling")
        self._log_directory_error = False
示例#8
0
    def initWithAccount_target_name_(self, account, target, display_name):
        self = objc.super(SMSViewController, self).init()
        if self:
            self.session_id = str(uuid.uuid1())

            self.notification_center = NotificationCenter()
            self.account = account
            self.target_uri = target
            self.display_name = display_name
            self.messages = {}

            self.encryption = OTREncryption(self)

            self.message_queue = EventQueue(self._send_message)

            self.history = ChatHistory()

            self.local_uri = '%s@%s' % (account.id.username, account.id.domain)
            self.remote_uri = '%s@%s' % (self.target_uri.user.decode(),
                                         self.target_uri.host.decode())
            self.contact = NSApp.delegate(
            ).contactsWindowController.getFirstContactFromAllContactsGroupMatchingURI(
                self.remote_uri)

            NSBundle.loadNibNamed_owner_("SMSView", self)

            self.chatViewController.setContentFile_(
                NSBundle.mainBundle().pathForResource_ofType_(
                    "ChatView", "html"))
            self.chatViewController.setAccount_(self.account)
            self.chatViewController.resetRenderedMessages()

            self.chatViewController.inputText.unregisterDraggedTypes()
            self.chatViewController.inputText.setMaxLength_(MAX_MESSAGE_LENGTH)
            self.splitView.setText_(
                NSLocalizedString("%i chars left", "Label") %
                MAX_MESSAGE_LENGTH)

            self.enableIsComposing = True

            self.log_info('Using local account %s' % self.local_uri)

            self.notification_center.add_observer(
                self, name='ChatStreamOTREncryptionStateChanged')
            self.started = False

        return self
示例#9
0
 def __init__(self, name):
     self.name = name
     self.secret = None
     self.private_key = DSAPrivateKey.generate()
     self.otr_session = OTRSession(self.private_key, transport=self)
     self.peer = None
     self.send_queue = EventQueue(handler=self._send_handler)
     self.send_queue.start()
     self.ake_done = Event()
     self.smp_done = Event()
     self.all_done = Event()
     self.otr_done = Event()
     self.smp_status = None
     self.same_secrets = None
     self.sent_message = None
     self.received_message = None
     NotificationCenter().add_observer(self, sender=self.otr_session)
示例#10
0
 def __init__(self):
     main_config_file = process.config_file(RadiusConfig.config_file)
     if main_config_file is None:
         raise RuntimeError(
             "Cannot find the radius configuration file: `%s'" %
             RadiusConfig.config_file)
     try:
         config = dict(
             line.rstrip("\n").split(None, 1)
             for line in open(main_config_file)
             if len(line.split(None, 1)) == 2 and not line.startswith("#"))
         secrets = dict(
             line.rstrip("\n").split(None, 1)
             for line in open(config["servers"])
             if len(line.split(None, 1)) == 2 and not line.startswith("#"))
         server = config["acctserver"]
         try:
             server, acctport = server.split(":")
             acctport = int(acctport)
         except ValueError:
             acctport = 1813
         secret = secrets[server]
         dicts = [RadiusDictionaryFile(config["dictionary"])]
         if RadiusConfig.additional_dictionary:
             additional_dictionary = process.config_file(
                 RadiusConfig.additional_dictionary)
             if additional_dictionary:
                 dicts.append(RadiusDictionaryFile(additional_dictionary))
             else:
                 log.warn(
                     "Could not load additional RADIUS dictionary file: `%s'"
                     % RadiusConfig.additional_dictionary)
         raddict = pyrad.dictionary.Dictionary(*dicts)
         timeout = int(config["radius_timeout"])
         retries = int(config["radius_retries"])
     except Exception:
         log.fatal("cannot read the RADIUS configuration file")
         raise
     pyrad.client.Client.__init__(self, server, 1812, acctport, secret,
                                  raddict)
     self.timeout = timeout
     self.retries = retries
     if "bindaddr" in config and config["bindaddr"] != "*":
         self.bind((config["bindaddr"], 0))
     EventQueue.__init__(self, self.do_accounting)
示例#11
0
 def get_thread(self, thread_id):
     with self.lock:
         try:
             thread = self.threads[thread_id]
         except KeyError:
             self.threads[thread_id] = thread = EventQueue(
                 handler=self._event_handler, name=thread_id)
             thread.start()
         return thread
示例#12
0
    def __init__(self):
        Thread.__init__(self, target=self._run, name='UI-Thread')
        self.setDaemon(True)

        self.__dict__['prompt'] = Prompt('')
        self.__dict__['status'] = None
        self.command_sequence = '/'
        self.application_control_char = '\x18' # ctrl-X
        self.application_control_bindings = {}
        self.display_commands = True
        self.display_text = True

        self.cursor_x = None
        self.cursor_y = None
        self.displaying_question = False
        self.input = Input()
        self.last_window_size = None
        self.prompt_y = None
        self.questions = deque()
        self.stopping = False
        self.lock = RLock()
        self.event_queue = EventQueue(handler=lambda (function, self, args, kwargs): function(self, *args, **kwargs), name='UI operation handling')
示例#13
0
    def start(self):
        # try to create the log directory
        try:
            self._init_log_directory()
        except Exception:
            pass

        # register to receive log notifications
        notification_center = NotificationCenter()
        notification_center.add_observer(self)

        # start the thread processing the notifications
        self._event_queue = EventQueue(handler=self._process_notification, name='Log handling')
        self._event_queue.start()
示例#14
0
    def __init__(self, msrp_level=log.level.INFO):
        self.msrp_level = msrp_level

        self._siptrace_filename = None
        self._siptrace_file = None
        self._siptrace_error = False
        self._siptrace_start_time = None
        self._siptrace_packet_count = 0

        self._msrptrace_filename = None
        self._msrptrace_file = None
        self._msrptrace_error = False

        self._pjsiptrace_filename = None
        self._pjsiptrace_file = None
        self._pjsiptrace_error = False

        self._notifications_filename = None
        self._notifications_file = None
        self._notifications_error = False

        self._event_queue = EventQueue(handler=self._process_notification,
                                       name='Log handling')
        self._log_directory_error = False
示例#15
0
    def __init__(self):
        # Loads the config file
        config = configparser.ConfigParser()
        try:
            config.read('config.ini')
        except Exception as e:
            print("ERROR: " + e)
            return
        self.account_name = config["SIPCONFIG"]["account_name"]
        self.target = None
        self.input = InputThread(self)
        self.output = EventQueue(self._write)
        self.logger = Logger(sip_to_stdout=False,
                             pjsip_to_stdout=False,
                             notifications_to_stdout=False)
        self.account = None
        self.subscriptions = []
        self.subscriptionqueue = []
        self.statusdict = {}
        self.stopping = False
        self.lastmessage = None
        self.commandsystemenabled = bool(config['SIPCONFIG']['commands'])

        self._subscription_routes = None
        self._subscription_timeout = 0.0
        self._subscription_wait = 0.5

        account_manager = AccountManager()
        engine = Engine()
        notification_center = NotificationCenter()
        notification_center.add_observer(self, sender=account_manager)
        notification_center.add_observer(self, sender=engine)
        notification_center.add_observer(self, sender=self.input)
        notification_center.add_observer(self, name='SIPEngineGotMessage')

        log.level.current = log.level.WARNING
示例#16
0
 def start(self):
     settings = SIPSimpleSettings()
     notification_center = NotificationCenter()
     notification_center.add_observer(self)
     self.siptrace_file = LogFile(os.path.join(ApplicationData.directory, 'logs', 'sip.log'))
     self.msrptrace_file = LogFile(os.path.join(ApplicationData.directory, 'logs', 'msrp.log'))
     self.pjsiptrace_file = LogFile(os.path.join(ApplicationData.directory, 'logs', 'pjsip.log'))
     self.notifications_file = LogFile(os.path.join(ApplicationData.directory, 'logs', 'notifications.log'))
     self._siptrace_start_time = datetime.now()
     self._siptrace_packet_count = 0
     self.event_queue = EventQueue(handler=self._process_notification, name='Log handling')
     self.event_queue.start()
     while settings.logs.trace_notifications and self.notification_queue and self.notification_queue.notifications:
         notification = self.notification_queue.notifications.popleft()
         self.handle_notification(notification)
     self.notification_queue = None
示例#17
0
 def __init__(self, name):
     self.name = name
     self.secret = None
     self.private_key = DSAPrivateKey.generate()
     self.otr_session = OTRSession(self.private_key, transport=self)
     self.peer = None
     self.send_queue = EventQueue(handler=self._send_handler)
     self.send_queue.start()
     self.ake_done = Event()
     self.smp_done = Event()
     self.all_done = Event()
     self.otr_done = Event()
     self.smp_status = None
     self.same_secrets = None
     self.sent_message = None
     self.received_message = None
     NotificationCenter().add_observer(self, sender=self.otr_session)
示例#18
0
    def __init__(self):
        Thread.__init__(self, target=self._run, name='UI-Thread')
        self.setDaemon(True)

        self.__dict__['prompt'] = Prompt('')
        self.__dict__['status'] = None
        self.command_sequence = '/'
        self.application_control_char = '\x18' # ctrl-X
        self.application_control_bindings = {}
        self.display_commands = True
        self.display_text = True

        self.cursor_x = None
        self.cursor_y = None
        self.displaying_question = False
        self.input = Input()
        self.last_window_size = None
        self.prompt_y = None
        self.questions = deque()
        self.stopping = False
        self.lock = RLock()
        self.event_queue = EventQueue(handler=lambda (function, self, args, kwargs): function(self, *args, **kwargs), name='UI operation handling')
示例#19
0
    def __init__(self, msrp_level=log.level.INFO):
        self.msrp_level = msrp_level

        self._siptrace_filename = None
        self._siptrace_file = None
        self._siptrace_error = False
        self._siptrace_start_time = None
        self._siptrace_packet_count = 0

        self._msrptrace_filename = None
        self._msrptrace_file = None
        self._msrptrace_error = False

        self._pjsiptrace_filename = None
        self._pjsiptrace_file = None
        self._pjsiptrace_error = False

        self._notifications_filename = None
        self._notifications_file = None
        self._notifications_error = False

        self._event_queue = EventQueue(handler=self._process_notification, name='Log handling')
        self._log_directory_error = False
示例#20
0
class FileLogger(object, metaclass=Singleton):

    # public methods
    #

    def __init__(self, msrp_level=log.level.INFO):
        self.msrp_level = msrp_level

        self._siptrace_filename = None
        self._siptrace_file = None
        self._siptrace_error = False
        self._siptrace_start_time = None
        self._siptrace_packet_count = 0

        self._msrptrace_filename = None
        self._msrptrace_file = None
        self._msrptrace_error = False

        self._pjsiptrace_filename = None
        self._pjsiptrace_file = None
        self._pjsiptrace_error = False

        self._notifications_filename = None
        self._notifications_file = None
        self._notifications_error = False

        self._log_directory_error = False

        self._event_queue = None

    def start(self):
        # try to create the log directory
        try:
            self._init_log_directory()
        except Exception:
            pass

        # register to receive log notifications
        notification_center = NotificationCenter()
        notification_center.add_observer(self)

        # start the thread processing the notifications
        self._event_queue = EventQueue(handler=self._process_notification,
                                       name='Log handling')
        self._event_queue.start()

    def stop(self):
        # stop the thread processing the notifications
        self._event_queue.stop()
        self._event_queue.join()

        # close sip trace file
        if self._siptrace_file is not None:
            self._siptrace_file.close()
            self._siptrace_file = None

        # close msrp trace file
        if self._msrptrace_file is not None:
            self._msrptrace_file.close()
            self._msrptrace_file = None

        # close pjsip trace file
        if self._pjsiptrace_file is not None:
            self._pjsiptrace_file.close()
            self._pjsiptrace_file = None

        # close notifications trace file
        if self._notifications_file is not None:
            self._notifications_file.close()
            self._notifications_file = None

        # unregister from receiving notifications
        notification_center = NotificationCenter()
        notification_center.remove_observer(self)

    def handle_notification(self, notification):
        self._event_queue.put(notification)

    def _process_notification(self, notification):
        settings = SIPSimpleSettings()
        handler = getattr(self, '_NH_%s' % notification.name, None)
        if handler is not None:
            handler(notification)

        handler = getattr(self, '_LH_%s' % notification.name, None)
        if handler is not None:
            handler(notification)

        if notification.name not in (
                'SIPEngineLog', 'SIPEngineSIPTrace'
        ) and settings.logs.trace_notifications and settings.logs.trace_notifications_to_file:
            try:
                self._init_log_file('notifications')
            except Exception:
                pass
            else:
                message = 'Notification name=%s sender=%s data=%s' % (
                    notification.name, notification.sender,
                    pformat(notification.data))
                try:
                    self._notifications_file.write(
                        '%s: %s\n' % (datetime.datetime.now(), message))
                    self._notifications_file.flush()
                except Exception as e:
                    print('Write message failed: %s' % message)

    # notification handlers
    #

    def _NH_CFGSettingsObjectDidChange(self, notification):
        settings = SIPSimpleSettings()
        if notification.sender is settings:
            if 'logs.directory' in notification.data.modified:
                # sip trace
                if self._siptrace_file is not None:
                    self._siptrace_file.close()
                    self._siptrace_file = None
                # pjsip trace
                if self._pjsiptrace_file is not None:
                    self._pjsiptrace_file.close()
                    self._pjsiptrace_file = None
                # notifications trace
                if self._notifications_file is not None:
                    self._notifications_file.close()
                    self._notifications_file = None
                # try to create the log directory
                try:
                    self._init_log_directory()
                except Exception:
                    pass

    # log handlers
    #

    def _LH_SIPEngineSIPTrace(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_sip or not settings.logs.trace_sip_to_file:
            return
        if self._siptrace_start_time is None:
            self._siptrace_start_time = notification.datetime
        self._siptrace_packet_count += 1
        if notification.data.received:
            direction = "RECEIVED"
        else:
            direction = "SENDING"
        buf = [
            "%s: Packet %d, +%s" %
            (direction, self._siptrace_packet_count,
             (notification.datetime - self._siptrace_start_time))
        ]
        buf.append(
            "%(source_ip)s:%(source_port)d -(SIP over %(transport)s)-> %(destination_ip)s:%(destination_port)d"
            % notification.data.__dict__)
        buf.append(notification.data.data)
        buf.append('--')
        message = '\n'.join(buf)
        try:
            self._init_log_file('siptrace')
        except Exception:
            pass
        else:
            self._siptrace_file.write(
                '%s [%s %d]: %s\n' %
                (notification.datetime, os.path.basename(
                    sys.argv[0]).rstrip('.py'), os.getpid(), message))
            self._siptrace_file.flush()

    def _LH_SIPEngineLog(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_pjsip or not settings.logs.trace_pjsip_to_file:
            return
        message = "(%(level)d) %(message)s" % notification.data.__dict__
        try:
            self._init_log_file('pjsiptrace')
        except Exception:
            pass
        else:
            self._pjsiptrace_file.write('[%s %d] %s\n' % (os.path.basename(
                sys.argv[0]).rstrip('.py'), os.getpid(), message))
            self._pjsiptrace_file.flush()

    def _LH_DNSLookupTrace(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_sip or not settings.logs.trace_sip_to_file:
            return
        message = 'DNS lookup %(query_type)s %(query_name)s' % notification.data.__dict__
        if notification.data.error is None:
            message += ' succeeded, ttl=%d: ' % notification.data.answer.ttl
            if notification.data.query_type == 'A':
                message += ", ".join(record.address
                                     for record in notification.data.answer)
            elif notification.data.query_type == 'SRV':
                message += ", ".join('%d %d %d %s' %
                                     (record.priority, record.weight,
                                      record.port, record.target)
                                     for record in notification.data.answer)
            elif notification.data.query_type == 'NAPTR':
                message += ", ".join(
                    '%d %d "%s" "%s" "%s" %s' %
                    (record.order, record.preference, record.flags,
                     record.service, record.regexp, record.replacement)
                    for record in notification.data.answer)
        else:
            import dns.resolver
            message_map = {
                dns.resolver.NXDOMAIN:
                'DNS record does not exist',
                dns.resolver.NoAnswer:
                'DNS response contains no answer',
                dns.resolver.NoNameservers:
                'no DNS name servers could be reached',
                dns.resolver.Timeout:
                'no DNS response received, the query has timed out'
            }
            message += ' failed: %s' % message_map.get(
                notification.data.error.__class__, '')
        try:
            self._init_log_file('siptrace')
        except Exception:
            pass
        else:
            self._siptrace_file.write(
                '%s [%s %d]: %s\n' %
                (notification.datetime, os.path.basename(
                    sys.argv[0]).rstrip('.py'), os.getpid(), message))
            self._siptrace_file.flush()

    def _LH_MSRPTransportTrace(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_msrp or not settings.logs.trace_msrp_to_file:
            return
        arrow = {
            'incoming': '<--',
            'outgoing': '-->'
        }[notification.data.direction]
        local_address = notification.sender.getHost()
        local_address = '%s:%d' % (local_address.host, local_address.port)
        remote_address = notification.sender.getPeer()
        remote_address = '%s:%d' % (remote_address.host, remote_address.port)
        message = '%s %s %s\n' % (local_address, arrow,
                                  remote_address) + notification.data.data
        try:
            self._init_log_file('msrptrace')
        except Exception:
            pass
        else:
            self._msrptrace_file.write(
                '%s [%s %d]: %s\n' %
                (notification.datetime, os.path.basename(
                    sys.argv[0]).rstrip('.py'), os.getpid(), message))
            self._msrptrace_file.flush()

    def _LH_MSRPLibraryLog(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_msrp or not settings.logs.trace_msrp_to_file:
            return
        if notification.data.level < self.msrp_level:
            return
        message = '%s%s' % (notification.data.level.prefix,
                            notification.data.message)
        try:
            self._init_log_file('msrptrace')
        except Exception:
            pass
        else:
            self._msrptrace_file.write(
                '%s [%s %d]: %s\n' %
                (notification.datetime, os.path.basename(
                    sys.argv[0]).rstrip('.py'), os.getpid(), message))
            self._msrptrace_file.flush()

    # private methods
    #

    def _init_log_directory(self):
        settings = SIPSimpleSettings()
        log_directory = settings.logs.directory.normalized
        try:
            makedirs(log_directory)
        except Exception as e:
            if not self._log_directory_error:
                print("failed to create logs directory '%s': %s" %
                      (log_directory, e))
                self._log_directory_error = True
            self._siptrace_error = True
            self._pjsiptrace_error = True
            self._notifications_error = True
            raise
        else:
            self._log_directory_error = False
            # sip trace
            if self._siptrace_filename is None:
                self._siptrace_filename = os.path.join(log_directory,
                                                       'sip_trace.txt')
                self._siptrace_error = False

            # msrp trace
            if self._msrptrace_filename is None:
                self._msrptrace_filename = os.path.join(
                    log_directory, 'msrp_trace.txt')
                self._msrptrace_error = False

            # pjsip trace
            if self._pjsiptrace_filename is None:
                self._pjsiptrace_filename = os.path.join(
                    log_directory, 'pjsip_trace.txt')
                self._pjsiptrace_error = False

            # notifications trace
            if self._notifications_filename is None:
                self._notifications_filename = os.path.join(
                    log_directory, 'notifications_trace.txt')
                self._notifications_error = False

    def _init_log_file(self, type):
        if getattr(self, '_%s_file' % type) is None:
            self._init_log_directory()
            filename = getattr(self, '_%s_filename' % type)
            try:
                setattr(self, '_%s_file' % type, open(filename, 'a'))
            except Exception as e:
                if not getattr(self, '_%s_error' % type):
                    print("failed to create log file '%s': %s" % (filename, e))
                    setattr(self, '_%s_error' % type, True)
                raise
            else:
                setattr(self, '_%s_error' % type, False)
示例#21
0
class LogManager(object):
    __metaclass__ = Singleton

    implements(IObserver)

    def __init__(self):
        self.name = os.path.basename(sys.argv[0]).rsplit('.py', 1)[0]
        self.pid = os.getpid()
        self.msrp_level = log.level.INFO
        self.siptrace_file = Null
        self.msrptrace_file = Null
        self.pjsiptrace_file = Null
        self.notifications_file = Null
        self.event_queue = Null
        self.notification_queue = NotificationQueue()
        self._siptrace_start_time = None
        self._siptrace_packet_count = None

    def start(self):
        settings = SIPSimpleSettings()
        notification_center = NotificationCenter()
        notification_center.add_observer(self)
        if settings.logs.trace_sip:
            self.siptrace_file = LogFile(
                os.path.join(ApplicationData.directory, 'logs',
                             'sip_trace.txt'))
        if settings.logs.trace_msrp:
            self.msrptrace_file = LogFile(
                os.path.join(ApplicationData.directory, 'logs',
                             'msrp_trace.txt'))
        if settings.logs.trace_pjsip:
            self.pjsiptrace_file = LogFile(
                os.path.join(ApplicationData.directory, 'logs',
                             'pjsip_trace.txt'))
        if settings.logs.trace_notifications:
            self.notifications_file = LogFile(
                os.path.join(ApplicationData.directory, 'logs',
                             'notifications_trace.txt'))
        self._siptrace_start_time = datetime.now()
        self._siptrace_packet_count = 0
        self.event_queue = EventQueue(handler=self._process_notification,
                                      name='Blink LogManager')
        self.event_queue.start()
        while settings.logs.trace_notifications and self.notification_queue and self.notification_queue.notifications:
            notification = self.notification_queue.notifications.popleft()
            self.handle_notification(notification)
        self.notification_queue = None

    def stop(self):
        notification_center = NotificationCenter()
        notification_center.remove_observer(self)

        self.event_queue.stop()
        self.event_queue.join()
        self.event_queue = Null

        self.siptrace_file = Null
        self.msrptrace_file = Null
        self.pjsiptrace_file = Null
        self.notifications_file = Null

    def handle_notification(self, notification):
        self.event_queue.put(notification)

    def _process_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification)

        handler = getattr(self, '_LH_%s' % notification.name, Null)
        handler(notification)

        settings = SIPSimpleSettings()
        if notification.name not in ('SIPEngineLog', 'SIPEngineSIPTrace'
                                     ) and settings.logs.trace_notifications:
            message = 'Notification name=%s sender=%s data=%s' % (
                notification.name, notification.sender,
                pformat(notification.data))
            try:
                self.notifications_file.write(
                    '%s [%s %d]: %s\n' %
                    (datetime.now(), self.name, self.pid, message))
                self.notifications_file.flush()
            except Exception:
                pass

    def _NH_CFGSettingsObjectDidChange(self, notification):
        settings = SIPSimpleSettings()
        if notification.sender is settings:
            if 'logs.trace_sip' in notification.data.modified:
                self.siptrace_file = LogFile(
                    os.path.join(
                        ApplicationData.directory, 'logs',
                        'sip_trace.txt')) if settings.logs.trace_sip else Null
            if 'logs.trace_msrp' in notification.data.modified:
                self.msrptrace_file = LogFile(
                    os.path.join(ApplicationData.directory, 'logs',
                                 'msrp_trace.txt')
                ) if settings.logs.trace_msrp else Null
            if 'logs.trace_pjsip' in notification.data.modified:
                self.pjsiptrace_file = LogFile(
                    os.path.join(ApplicationData.directory, 'logs',
                                 'pjsip_trace.txt')
                ) if settings.logs.trace_pjsip else Null
            if 'logs.trace_notifications' in notification.data.modified:
                self.notifications_file = LogFile(
                    os.path.join(ApplicationData.directory, 'logs',
                                 'notifications_trace.txt')
                ) if settings.logs.trace_notifications else Null

    def _LH_SIPEngineSIPTrace(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_sip:
            return
        self._siptrace_packet_count += 1
        if notification.data.received:
            direction = "RECEIVED"
        else:
            direction = "SENDING"
        buf = [
            "%s: Packet %d, +%s" %
            (direction, self._siptrace_packet_count,
             (notification.datetime - self._siptrace_start_time)),
            "%(source_ip)s:%(source_port)d -(SIP over %(transport)s)-> %(destination_ip)s:%(destination_port)d"
            % notification.data.__dict__, notification.data.data, '--'
        ]
        message = '\n'.join(buf)
        try:
            self.siptrace_file.write(
                '%s [%s %d]: %s\n' %
                (notification.datetime, self.name, self.pid, message))
            self.siptrace_file.flush()
        except Exception:
            pass

    def _LH_SIPEngineLog(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_pjsip:
            return
        message = "(%(level)d) %(message)s" % notification.data.__dict__
        try:
            self.pjsiptrace_file.write('[%s %d] %s\n' %
                                       (self.name, self.pid, message))
            self.pjsiptrace_file.flush()
        except Exception:
            pass

    def _LH_DNSLookupTrace(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_sip:
            return
        message = 'DNS lookup %(query_type)s %(query_name)s' % notification.data.__dict__
        if notification.data.error is None:
            message += ' succeeded, ttl=%d: ' % notification.data.answer.ttl
            if notification.data.query_type == 'A':
                message += ", ".join(record.address
                                     for record in notification.data.answer)
            elif notification.data.query_type == 'SRV':
                message += ", ".join('%d %d %d %s' %
                                     (record.priority, record.weight,
                                      record.port, record.target)
                                     for record in notification.data.answer)
            elif notification.data.query_type == 'NAPTR':
                message += ", ".join(
                    '%d %d "%s" "%s" "%s" %s' %
                    (record.order, record.preference, record.flags,
                     record.service, record.regexp, record.replacement)
                    for record in notification.data.answer)
        else:
            import dns.resolver
            message_map = {
                dns.resolver.NXDOMAIN:
                'DNS record does not exist',
                dns.resolver.NoAnswer:
                'DNS response contains no answer',
                dns.resolver.NoNameservers:
                'no DNS name servers could be reached',
                dns.resolver.Timeout:
                'no DNS response received, the query has timed out'
            }
            message += ' failed: %s' % message_map.get(
                notification.data.error.__class__, '')
        try:
            self.siptrace_file.write(
                '%s [%s %d]: %s\n' %
                (notification.datetime, self.name, self.pid, message))
            self.siptrace_file.flush()
        except Exception:
            pass

    def _LH_MSRPTransportTrace(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_msrp:
            return
        arrow = {
            'incoming': '<--',
            'outgoing': '-->'
        }[notification.data.direction]
        local_address = '%s:%d' % (notification.data.local_address.host,
                                   notification.data.local_address.port)
        remote_address = '%s:%d' % (notification.data.remote_address.host,
                                    notification.data.remote_address.port)
        message = '%s %s %s\n' % (local_address, arrow,
                                  remote_address) + notification.data.data
        prefix = '[Illegal request!] ' if notification.data.illegal else ''
        try:
            self.msrptrace_file.write(
                '%s [%s %d]: %s%s\n' %
                (notification.datetime, self.name, self.pid, prefix, message))
            self.msrptrace_file.flush()
        except Exception:
            pass

    def _LH_MSRPLibraryLog(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_msrp:
            return
        if notification.data.level < self.msrp_level:
            return
        message = '%s %s' % (notification.data.level,
                             notification.data.message)
        try:
            self.msrptrace_file.write(
                '%s [%s %d]: %s\n' %
                (notification.datetime, self.name, self.pid, message))
            self.msrptrace_file.flush()
        except Exception:
            pass
示例#22
0
 def __init__(self):
     EventQueue.__init__(self, self.do_accounting)
示例#23
0
class FileLogger(object):
    implements(IObserver)

    # public methods
    #

    def __init__(self, msrp_level=log.level.INFO):
        self.msrp_level = msrp_level

        self._siptrace_filename = None
        self._siptrace_file = None
        self._siptrace_error = False
        self._siptrace_start_time = None
        self._siptrace_packet_count = 0

        self._msrptrace_filename = None
        self._msrptrace_file = None
        self._msrptrace_error = False

        self._pjsiptrace_filename = None
        self._pjsiptrace_file = None
        self._pjsiptrace_error = False

        self._notifications_filename = None
        self._notifications_file = None
        self._notifications_error = False

        self._event_queue = EventQueue(handler=self._process_notification, name='Log handling')
        self._log_directory_error = False

    def start(self):
        # try to create the log directory
        try:
            self._init_log_directory()
        except Exception:
            pass

        # register to receive log notifications
        notification_center = NotificationCenter()
        notification_center.add_observer(self)

        # start the thread processing the notifications
        self._event_queue.start()

    def stop(self):
        # stop the thread processing the notifications
        self._event_queue.stop()
        self._event_queue.join()

        # close sip trace file
        if self._siptrace_file is not None:
            self._siptrace_file.close()
            self._siptrace_file = None

        # close msrp trace file
        if self._msrptrace_file is not None:
            self._msrptrace_file.close()
            self._msrptrace_file = None

        # close pjsip trace file
        if self._pjsiptrace_file is not None:
            self._pjsiptrace_file.close()
            self._pjsiptrace_file = None

        # close notifications trace file
        if self._notifications_file is not None:
            self._notifications_file.close()
            self._notifications_file = None

        # unregister from receiving notifications
        notification_center = NotificationCenter()
        notification_center.remove_observer(self)

    def handle_notification(self, notification):
        self._event_queue.put(notification)

    @allocate_autorelease_pool
    def _process_notification(self, notification):
        settings = SIPSimpleSettings()
        handler = getattr(self, '_NH_%s' % notification.name, None)
        if handler is not None:
            handler(notification)

        handler = getattr(self, '_LH_%s' % notification.name, None)
        if handler is not None:
            handler(notification)

        if notification.name not in ('SIPEngineLog', 'SIPEngineSIPTrace') and settings.logs.trace_notifications:
            try:
                self._init_log_file('notifications')
            except Exception:
                pass
            else:
                message = 'Notification name=%s sender=%s data=%s' % (notification.name, notification.sender, pformat(notification.data))
                self._notifications_file.write('%s: %s\n' % (datetime.datetime.now(), message))
                self._notifications_file.flush()

    # notification handlers
    #

    def _NH_CFGSettingsObjectDidChange(self, notification):
        settings = SIPSimpleSettings()
        if notification.sender is settings:
            if 'logs.directory' in notification.data.modified:
                # sip trace
                if self._siptrace_file is not None:
                    self._siptrace_file.close()
                    self._siptrace_file = None
                # pjsip trace
                if self._pjsiptrace_file is not None:
                    self._pjsiptrace_file.close()
                    self._pjsiptrace_file = None
                # notifications trace
                if self._notifications_file is not None:
                    self._notifications_file.close()
                    self._notifications_file = None
                # try to create the log directory
                try:
                    self._init_log_directory()
                except Exception:
                    pass

    # log handlers
    #

    def _LH_SIPEngineSIPTrace(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_sip:
            return
        if self._siptrace_start_time is None:
            self._siptrace_start_time = notification.data.timestamp
        self._siptrace_packet_count += 1
        if notification.data.received:
            direction = "RECEIVED"
        else:
            direction = "SENDING"
        buf = ["%s: Packet %d, +%s" % (direction, self._siptrace_packet_count, (notification.data.timestamp - self._siptrace_start_time))]
        buf.append("%(source_ip)s:%(source_port)d -(SIP over %(transport)s)-> %(destination_ip)s:%(destination_port)d" % notification.data.__dict__)
        buf.append(notification.data.data)
        buf.append('--')
        message = '\n'.join(buf)
        try:
            self._init_log_file('siptrace')
        except Exception:
            pass
        else:
            self._siptrace_file.write('%s [%s %d]: %s\n' % (notification.data.timestamp, os.path.basename(sys.argv[0]).rstrip('.py'), os.getpid(), message))
            self._siptrace_file.flush()

    def _LH_SIPEngineLog(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_pjsip:
            return
        message = "(%(level)d) %(sender)14s: %(message)s" % notification.data.__dict__
        try:
            self._init_log_file('pjsiptrace')
        except Exception:
            pass
        else:
            self._pjsiptrace_file.write('%s [%s %d] %s\n' % (notification.data.timestamp, os.path.basename(sys.argv[0]).rstrip('.py'), os.getpid(), message))
            self._pjsiptrace_file.flush()

    def _LH_DNSLookupTrace(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_sip:
            return
        message = 'DNS lookup %(query_type)s %(query_name)s' % notification.data.__dict__
        if notification.data.error is None:
            message += ' succeeded, ttl=%d: ' % notification.data.answer.ttl
            if notification.data.query_type == 'A':
                message += ", ".join(record.address for record in notification.data.answer)
            elif notification.data.query_type == 'SRV':
                message += ", ".join('%d %d %d %s' % (record.priority, record.weight, record.port, record.target) for record in notification.data.answer)
            elif notification.data.query_type == 'NAPTR':
                message += ", ".join('%d %d "%s" "%s" "%s" %s' % (record.order, record.preference, record.flags, record.service, record.regexp, record.replacement) for record in notification.data.answer)
        else:
            import dns.resolver
            message_map = {dns.resolver.NXDOMAIN: 'DNS record does not exist',
                           dns.resolver.NoAnswer: 'DNS response contains no answer',
                           dns.resolver.NoNameservers: 'no DNS name servers could be reached',
                           dns.resolver.Timeout: 'no DNS response received, the query has timed out'}
            message += ' failed: %s' % message_map.get(notification.data.error.__class__, '')
        try:
            self._init_log_file('siptrace')
        except Exception:
            pass
        else:
            self._siptrace_file.write('%s [%s %d]: %s\n' % (notification.data.timestamp, os.path.basename(sys.argv[0]).rstrip('.py'), os.getpid(), message))
            self._siptrace_file.flush()

    def _LH_MSRPTransportTrace(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_msrp:
            return
        arrow = {'incoming': '<--', 'outgoing': '-->'}[notification.data.direction]
        local_address = notification.sender.getHost()
        local_address = '%s:%d' % (local_address.host, local_address.port)
        remote_address = notification.sender.getPeer()
        remote_address = '%s:%d' % (remote_address.host, remote_address.port)
        message = '%s %s %s\n' % (local_address, arrow, remote_address) + notification.data.data
        try:
            self._init_log_file('msrptrace')
        except Exception:
            pass
        else:
            self._msrptrace_file.write('%s [%s %d]: %s\n' % (notification.data.timestamp, os.path.basename(sys.argv[0]).rstrip('.py'), os.getpid(), message))
            self._msrptrace_file.flush()

    def _LH_MSRPLibraryLog(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_msrp:
            return
        if notification.data.level < self.msrp_level:
            return
        message = '%s%s' % (notification.data.level.prefix, notification.data.message)
        try:
            self._init_log_file('msrptrace')
        except Exception:
            pass
        else:
            self._msrptrace_file.write('%s [%s %d]: %s\n' % (notification.data.timestamp, os.path.basename(sys.argv[0]).rstrip('.py'), os.getpid(), message))
            self._msrptrace_file.flush()

    # private methods
    #

    def _init_log_directory(self):
        settings = SIPSimpleSettings()
        log_directory = settings.logs.directory.normalized
        try:
            makedirs(log_directory)
        except Exception, e:
            if not self._log_directory_error:
                print "failed to create logs directory '%s': %s" % (log_directory, e)
                self._log_directory_error = True
            self._siptrace_error = True
            self._pjsiptrace_error = True
            self._notifications_error = True
            raise
        else:
示例#24
0
class DataConnection(object):
    implements(IObserver)

    def __init__(self, name):
        self.name = name
        self.secret = None
        self.private_key = DSAPrivateKey.generate()
        self.otr_session = OTRSession(self.private_key, transport=self)
        self.peer = None
        self.send_queue = EventQueue(handler=self._send_handler)
        self.send_queue.start()
        self.ake_done = Event()
        self.smp_done = Event()
        self.all_done = Event()
        self.otr_done = Event()
        self.smp_status = None
        self.same_secrets = None
        self.sent_message = None
        self.received_message = None
        NotificationCenter().add_observer(self, sender=self.otr_session)

    def _send_handler(self, message):
        time.sleep(0.01)
        self.peer.receive(message)

    def connect(self, peer):
        self.peer = peer

    def disconnect(self):
        self.send_queue.stop()
        self.send_queue = None

    def start_otr(self, secret=None):
        self.secret = secret
        self.otr_session.start()

    def stop_otr(self):
        self.otr_session.stop()

    def inject_otr_message(self, message):
        log.debug("{0.name} sending: {1!r}".format(self, message))
        self.send_queue.put(message)

    def send(self, content, content_type='text/plain'):
        log.debug("{0.name} encoding: {1!r}".format(self, content))
        self.sent_message = content
        content = self.otr_session.handle_output(content, content_type)
        log.debug("{0.name} sending: {1!r}".format(self, content))
        self.send_queue.put(content)

    def receive(self, message):
        # log.debug("{0.name} received: {1!r}".format(self, message))
        try:
            message = self.otr_session.handle_input(message, 'text/plain')
        except IgnoreMessage:
            return
        else:
            log.debug("{0.name} decoded:  {1!r}".format(self, message))
            self.received_message = message
            self.all_done.set()

    def handle_notification(self, notification):
        handler = getattr(self, '_NH_{0.name}'.format(notification), Null)
        handler(notification)

    def _NH_OTRSessionStateChanged(self, notification):
        if notification.data.new_state is OTRState.Encrypted:
            self.ake_done.set()
            if self.secret is None:
                self.smp_done.set()
            elif self.name < self.peer.name:
                self.otr_session.smp_verify(secret=self.secret)
        elif notification.data.old_state is OTRState.Encrypted:
            self.otr_done.set()

    def _NH_OTRSessionSMPVerificationDidStart(self, notification):
        if notification.data.originator == 'remote':
            if self.secret:
                self.otr_session.smp_answer(secret=self.secret)
            else:
                self.otr_session.smp_abort()

    def _NH_OTRSessionSMPVerificationDidNotStart(self, notification):
        self.smp_status = notification.data.reason
        self.smp_done.set()

    def _NH_OTRSessionSMPVerificationDidEnd(self, notification):
        self.same_secrets = notification.data.same_secrets
        self.smp_status = notification.data.status
        self.smp_done.set()
示例#25
0
class TraceManager(object):
    __metaclass__ = Singleton

    implements(IObserver)

    def __init__(self):
        self.name = os.path.basename(sys.argv[0]).rsplit('.py', 1)[0]
        self.pid = os.getpid()
        self.msrp_level = log.level.INFO
        self.siptrace_file = Null
        self.msrptrace_file = Null
        self.pjsiptrace_file = Null
        self.notifications_file = Null
        self.event_queue = Null
        self.notification_queue = NotificationQueue()
        self._siptrace_start_time = None
        self._siptrace_packet_count = None

    def start(self):
        settings = SIPSimpleSettings()
        notification_center = NotificationCenter()
        notification_center.add_observer(self)
        self.siptrace_file = LogFile(os.path.join(ApplicationData.directory, 'logs', 'sip.log'))
        self.msrptrace_file = LogFile(os.path.join(ApplicationData.directory, 'logs', 'msrp.log'))
        self.pjsiptrace_file = LogFile(os.path.join(ApplicationData.directory, 'logs', 'pjsip.log'))
        self.notifications_file = LogFile(os.path.join(ApplicationData.directory, 'logs', 'notifications.log'))
        self._siptrace_start_time = datetime.now()
        self._siptrace_packet_count = 0
        self.event_queue = EventQueue(handler=self._process_notification, name='Log handling')
        self.event_queue.start()
        while settings.logs.trace_notifications and self.notification_queue and self.notification_queue.notifications:
            notification = self.notification_queue.notifications.popleft()
            self.handle_notification(notification)
        self.notification_queue = None

    def stop(self):
        notification_center = NotificationCenter()
        notification_center.remove_observer(self)

        self.event_queue.stop()
        self.event_queue.join()
        self.event_queue = Null

        self.siptrace_file = Null
        self.msrptrace_file = Null
        self.pjsiptrace_file = Null
        self.notifications_file = Null

    def handle_notification(self, notification):
        self.event_queue.put(notification)

    def _process_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification)

        handler = getattr(self, '_LH_%s' % notification.name, Null)
        handler(notification)

        settings = SIPSimpleSettings()
        if notification.name not in ('SIPEngineLog', 'SIPEngineSIPTrace') and settings.logs.trace_notifications:
            message = 'Notification name=%s sender=%s data=%s' % (notification.name, notification.sender, pformat(notification.data))
            try:
                self.notifications_file.write('%s [%s %d]: %s\n' % (datetime.now(), self.name, self.pid, message))
            except Exception:
                pass

    def _LH_SIPEngineSIPTrace(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_sip:
            return
        self._siptrace_packet_count += 1
        if notification.data.received:
            direction = "RECEIVED"
        else:
            direction = "SENDING"
        buf = ["%s: Packet %d, +%s" % (direction, self._siptrace_packet_count, (notification.datetime - self._siptrace_start_time))]
        buf.append("%(source_ip)s:%(source_port)d -(SIP over %(transport)s)-> %(destination_ip)s:%(destination_port)d" % notification.data.__dict__)
        buf.append(notification.data.data)
        buf.append('--')
        message = '\n'.join(buf)
        try:
            self.siptrace_file.write('%s [%s %d]: %s\n' % (notification.datetime, self.name, self.pid, message))
        except Exception:
            pass

    def _LH_SIPEngineLog(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_pjsip:
            return
        message = "(%(level)d) %(message)s" % notification.data.__dict__
        try:
            self.pjsiptrace_file.write('[%s %d] %s\n' % (self.name, self.pid, message))
        except Exception:
            pass

    def _LH_DNSLookupTrace(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_sip:
            return
        message = 'DNS lookup %(query_type)s %(query_name)s' % notification.data.__dict__
        if notification.data.error is None:
            message += ' succeeded, ttl=%d: ' % notification.data.answer.ttl
            if notification.data.query_type == 'A':
                message += ", ".join(record.address for record in notification.data.answer)
            elif notification.data.query_type == 'SRV':
                message += ", ".join('%d %d %d %s' % (record.priority, record.weight, record.port, record.target) for record in notification.data.answer)
            elif notification.data.query_type == 'NAPTR':
                message += ", ".join('%d %d "%s" "%s" "%s" %s' % (record.order, record.preference, record.flags, record.service, record.regexp, record.replacement) for record in notification.data.answer)
        else:
            import dns.resolver
            message_map = {dns.resolver.NXDOMAIN: 'DNS record does not exist',
                           dns.resolver.NoAnswer: 'DNS response contains no answer',
                           dns.resolver.NoNameservers: 'no DNS name servers could be reached',
                           dns.resolver.Timeout: 'no DNS response received, the query has timed out'}
            message += ' failed: %s' % message_map.get(notification.data.error.__class__, '')
        try:
            self.siptrace_file.write('%s [%s %d]: %s\n' % (notification.datetime, self.name, self.pid, message))
        except Exception:
            pass

    def _LH_MSRPTransportTrace(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_msrp:
            return
        arrow = {'incoming': '<--', 'outgoing': '-->'}[notification.data.direction]
        local_address = notification.data.local_address
        local_address = '%s:%d' % (local_address.host, local_address.port)
        remote_address = notification.data.remote_address
        remote_address = '%s:%d' % (remote_address.host, remote_address.port)
        message = '%s %s %s\n' % (local_address, arrow, remote_address) + notification.data.data
        try:
            self.msrptrace_file.write('%s [%s %d]: %s\n' % (notification.datetime, self.name, self.pid, message))
        except Exception:
            pass

    def _LH_MSRPLibraryLog(self, notification):
        settings = SIPSimpleSettings()
        if not settings.logs.trace_msrp:
            return
        if notification.data.level < self.msrp_level:
            return
        message = '%s%s' % (notification.data.level.prefix, notification.data.message)
        try:
            self.msrptrace_file.write('%s [%s %d]: %s\n' % (notification.datetime, self.name, self.pid, message))
        except Exception:
            pass
示例#26
0
class RadiusDatabase(object):
    """Interface with the Radius database"""
    class RadiusTask(object):
        def __init__(self, deferred, tasktype, **kwargs):
            self.deferred = deferred
            self.tasktype = tasktype
            self.args = kwargs

    def __init__(self):
        self.queue = EventQueue(handler=self._handle_task, name='RadiusQueue')
        self.queue.start()

        credentials = RadiusDatabaseConfig.user and (
            "%s%s@" % (RadiusDatabaseConfig.user,
                       RadiusDatabaseConfig.password and ":%s" %
                       (RadiusDatabaseConfig.password) or '')) or ''
        self.conn = sqlobject.connectionForURI(
            "mysql://%s%s/%s" % (credentials, RadiusDatabaseConfig.host,
                                 RadiusDatabaseConfig.database))

    def close(self):
        return threads.deferToThread(self._close)

    def _close(self):
        self.queue.stop()
        self.queue.join()
        self.conn.close()

    def getTerminatedCalls(self, calls):
        """
        Retrieve those calls from the ones in progress that were already terminated by caller/called.

        Returns a Deferred. Callback will be called with list of call ids.
        """
        deferred = defer.Deferred()
        self.queue.put(
            RadiusDatabase.RadiusTask(deferred, 'terminated', calls=calls))
        return deferred

    def getTimedoutCalls(self, calls):
        """
        Retrieve those calls from the ones in progress that did timeout and were closed by mediaproxy.

        Returns a Deferred. Callback will be called with list of call ids.
        """
        deferred = defer.Deferred()
        self.queue.put(
            RadiusDatabase.RadiusTask(deferred, 'timedout', calls=calls))
        return deferred

    def query(self, task):
        def _unknown_task(task):
            raise RadiusDatabaseError("Got unknown task to handle: %s" %
                                      task.tasktype)

        return getattr(self, '_RD_%s' % task.tasktype, _unknown_task)(task)

    def _handle_task(self, task):
        try:
            reactor.callFromThread(task.deferred.callback, self.query(task))
        except Exception, e:
            reactor.callFromThread(task.deferred.errback, failure.Failure(e))
示例#27
0
class UI(Thread):
    __metaclass__ = Singleton

    control_chars = {'\x01': 'home',
                     '\x04': 'eof',
                     '\x05': 'end',
                     '\x0a': 'newline',
                     '\x0d': 'newline',
                     '\x1b[A': 'cursorup',
                     '\x1b[B': 'cursordown',
                     '\x1b[C': 'cursorright',
                     '\x1b[D': 'cursorleft',
                     '\x1b[F': 'end',
                     '\x1b[H': 'home',
                     '\x7f': 'delete'}

    # public functions
    #

    def __init__(self):
        Thread.__init__(self, target=self._run, name='UI-Thread')
        self.setDaemon(True)

        self.__dict__['prompt'] = Prompt('')
        self.__dict__['status'] = None
        self.command_sequence = '/'
        self.application_control_char = '\x18' # ctrl-X
        self.application_control_bindings = {}
        self.display_commands = True
        self.display_text = True

        self.cursor_x = None
        self.cursor_y = None
        self.displaying_question = False
        self.input = Input()
        self.last_window_size = None
        self.prompt_y = None
        self.questions = deque()
        self.stopping = False
        self.lock = RLock()
        self.event_queue = EventQueue(handler=lambda (function, self, args, kwargs): function(self, *args, **kwargs), name='UI operation handling')

    def start(self, prompt='', command_sequence='/', control_char='\x18', control_bindings={}, display_commands=True, display_text=True):
        with self.lock:
            if self.isAlive():
                raise RuntimeError('UI already active')
            if not sys.stdin.isatty():
                raise RuntimeError('UI cannot be used on a non-TTY')
            if not sys.stdout.isatty():
                raise RuntimeError('UI cannot be used on a non-TTY')
            stdin_fd = sys.stdin.fileno()

            self.command_sequence = command_sequence
            self.application_control_char = control_char
            self.application_control_bindings = control_bindings
            self.display_commands = display_commands
            self.display_text = display_text

            # wrap sys.stdout
            sys.stdout = TTYFileWrapper(sys.stdout)
            # and possibly sys.stderr
            if sys.stderr.isatty():
                sys.stderr = TTYFileWrapper(sys.stderr)

            # change input to character-mode
            old_settings = termios.tcgetattr(stdin_fd)
            new_settings = termios.tcgetattr(stdin_fd)
            new_settings[3] &= ~termios.ECHO & ~termios.ICANON
            new_settings[6][termios.VMIN] = '\000'
            termios.tcsetattr(stdin_fd, termios.TCSADRAIN, new_settings)
            atexit.register(termios.tcsetattr, stdin_fd, termios.TCSADRAIN, old_settings)

            # find out cursor position in terminal
            self._raw_write('\x1b[6n')
            if select.select([stdin_fd], [], [], None)[0]:
                line, col = os.read(stdin_fd, 10)[2:-1].split(';')
                line = int(line)
                col = int(col)

            # scroll down the terminal until everything goes up
            self._scroll_up(line-1)
            # move the cursor to the upper left side corner
            self._raw_write('\x1b[H')
            self.cursor_x = 1
            self.cursor_y = 1
            # display the prompt
            self.prompt_y = 1
            self.input.add_line()
            self._update_prompt()
            # make sure we know when the window gets resized
            self.last_window_size = self.window_size
            signal.signal(signal.SIGWINCH, lambda signum, frame: self._window_resized())

            self.event_queue.start()
            Thread.start(self)

            # this will trigger the update of the prompt
            self.prompt = prompt

    @run_in_ui_thread
    def stop(self):
        with self.lock:
            self.stopping = True
            self.status = None
            sys.stdout.send_to_file()
            if isinstance(sys.stderr, TTYFileWrapper):
                sys.stderr.send_to_file()
            self._raw_write('\n\x1b[2K')

    def write(self, text):
        self.writelines([text])

    @run_in_ui_thread
    def writelines(self, text_lines):
        with self.lock:
            if not text_lines:
                return
            # go to beginning of prompt line
            self._raw_write('\x1b[%d;%dH' % (self.prompt_y, 1))
            # erase everything beneath it
            self._raw_write('\x1b[0J')
            # start writing lines
            window_size = self.window_size
            for text in text_lines:
                # write the line
                self._raw_write('%s\n' % text)
                # calculate the number of lines the text will produce
                text_lines = (len(text)-1)/window_size.x + 1
                # calculate how much the text will automatically scroll the window
                window_height = struct.unpack('HHHH', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0)))[0]
                auto_scroll_amount = max(0, (self.prompt_y+text_lines-1) - (window_height-1))
                # calculate the new position of the prompt
                self.prompt_y += text_lines - auto_scroll_amount
                # we might need to scroll up to make the prompt position visible again
                scroll_up = self.prompt_y - window_height
                if scroll_up > 0:
                    self.prompt_y -= scroll_up
                    self._scroll_up(scroll_up)
            # redraw the prompt
            self._update_prompt()

    @run_in_ui_thread
    def add_question(self, question):
        with self.lock:
            self.questions.append(question)
            if len(self.questions) == 1:
                self._update_prompt()

    @run_in_ui_thread
    def remove_question(self, question):
        with self.lock:
            first_question = (question == self.questions[0])
            self.questions.remove(question)
            if not self.questions or first_question:
                self.displaying_question = False
                self._update_prompt()

    # properties
    #

    @property
    def window_size(self):
        class WindowSize(tuple):
            def __init__(ws_self, (y, x)):
                ws_self.x = x
                ws_self.y = y if self.status is None else y-1
        return WindowSize(struct.unpack('HHHH', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0)))[:2])
示例#28
0
 def __init__(self):
     EventQueue.__init__(self, self.do_accounting)
示例#29
0
class SMSViewController(NSObject):

    chatViewController = objc.IBOutlet()
    splitView = objc.IBOutlet()
    smileyButton = objc.IBOutlet()
    outputContainer = objc.IBOutlet()
    addContactView = objc.IBOutlet()
    addContactLabel = objc.IBOutlet()
    zoom_period_label = ''

    showHistoryEntries = 50
    remoteTypingTimer = None
    enableIsComposing = False
    handle_scrolling = True
    scrollingTimer = None
    scrolling_back = False
    message_count_from_history = 0

    contact = None

    account = None
    target_uri = None
    routes = None
    queue = None
    queued_serial = 0

    windowController = None
    last_route = None

    def initWithAccount_target_name_(self, account, target, display_name):
        self = objc.super(SMSViewController, self).init()
        if self:
            self.session_id = str(uuid.uuid1())

            self.notification_center = NotificationCenter()
            self.account = account
            self.target_uri = target
            self.display_name = display_name
            self.messages = {}

            self.encryption = OTREncryption(self)

            self.message_queue = EventQueue(self._send_message)

            self.history = ChatHistory()

            self.local_uri = '%s@%s' % (account.id.username, account.id.domain)
            self.remote_uri = '%s@%s' % (self.target_uri.user.decode(),
                                         self.target_uri.host.decode())
            self.contact = NSApp.delegate(
            ).contactsWindowController.getFirstContactFromAllContactsGroupMatchingURI(
                self.remote_uri)

            NSBundle.loadNibNamed_owner_("SMSView", self)

            self.chatViewController.setContentFile_(
                NSBundle.mainBundle().pathForResource_ofType_(
                    "ChatView", "html"))
            self.chatViewController.setAccount_(self.account)
            self.chatViewController.resetRenderedMessages()

            self.chatViewController.inputText.unregisterDraggedTypes()
            self.chatViewController.inputText.setMaxLength_(MAX_MESSAGE_LENGTH)
            self.splitView.setText_(
                NSLocalizedString("%i chars left", "Label") %
                MAX_MESSAGE_LENGTH)

            self.enableIsComposing = True

            self.log_info('Using local account %s' % self.local_uri)

            self.notification_center.add_observer(
                self, name='ChatStreamOTREncryptionStateChanged')
            self.started = False

        return self

    def dealloc(self):
        if self.remoteTypingTimer:
            self.remoteTypingTimer.invalidate()
        self.chatViewController.close()
        objc.super(SMSViewController, self).dealloc()

    def awakeFromNib(self):
        # setup smiley popup
        smileys = SmileyManager().get_smiley_list()

        menu = self.smileyButton.menu()
        while menu.numberOfItems() > 0:
            menu.removeItemAtIndex_(0)

        bigText = NSAttributedString.alloc().initWithString_attributes_(
            " ",
            NSDictionary.dictionaryWithObject_forKey_(
                NSFont.systemFontOfSize_(16), NSFontAttributeName))
        for text, file in smileys:
            image = NSImage.alloc().initWithContentsOfFile_(file)
            if not image:
                print("Can't load %s" % file)
                continue
            image.setScalesWhenResized_(True)
            image.setSize_(NSMakeSize(16, 16))
            atext = bigText.mutableCopy()
            atext.appendAttributedString_(
                NSAttributedString.alloc().initWithString_(text))
            item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
                text, "insertSmiley:", "")
            menu.addItem_(item)
            item.setTarget_(self)
            item.setAttributedTitle_(atext)
            item.setRepresentedObject_(
                NSAttributedString.alloc().initWithString_(text))
            item.setImage_(image)

    @objc.python_method
    def revalidateToolbar(self):
        pass

    @objc.python_method
    def isOutputFrameVisible(self):
        return True

    @objc.python_method
    def log_info(self, text):
        BlinkLogger().log_info("[SMS with %s] %s" % (self.remote_uri, text))

    @objc.IBAction
    def addContactPanelClicked_(self, sender):
        if sender.tag() == 1:
            NSApp.delegate().contactsWindowController.addContact(
                uris=[(self.target_uri, 'sip')])

        self.addContactView.removeFromSuperview()
        frame = self.chatViewController.outputView.frame()
        frame.origin.y = 0
        frame.size = self.outputContainer.frame().size
        self.chatViewController.outputView.setFrame_(frame)

    @objc.python_method
    def insertSmiley_(self, sender):
        smiley = sender.representedObject()
        self.chatViewController.appendAttributedString_(smiley)

    @objc.python_method
    def matchesTargetAccount(self, target, account):
        that_contact = NSApp.delegate(
        ).contactsWindowController.getFirstContactMatchingURI(target)
        this_contact = NSApp.delegate(
        ).contactsWindowController.getFirstContactMatchingURI(self.target_uri)
        return (self.target_uri == target or
                (this_contact and that_contact
                 and this_contact == that_contact)) and self.account == account

    @objc.python_method
    def gotMessage(self,
                   sender,
                   call_id,
                   content,
                   content_type,
                   is_replication_message=False,
                   timestamp=None,
                   window=None):
        is_html = content_type == 'text/html'
        encrypted = False
        try:
            content = self.encryption.otr_session.handle_input(
                content, content_type)
        except IgnoreMessage:
            return None
        except UnencryptedMessage:
            encrypted = False
            encryption_active = True
        except EncryptedMessageError as e:
            self.log_info('OTP encrypted message error: %s' % str(e))
            return None
        except OTRError as e:
            self.log_info('OTP error: %s' % str(e))
            return None
        else:
            encrypted = encryption_active = self.encryption.active

        content = content.decode() if isinstance(content, bytes) else content

        if content.startswith('?OTR:'):
            self.log_info('Dropped OTR message that could not be decoded')
            return None

        self.enableIsComposing = True

        icon = NSApp.delegate().contactsWindowController.iconPathForURI(
            format_identity_to_string(sender))
        timestamp = timestamp or ISOTimestamp.now()

        hash = hashlib.sha1()
        hash.update((content + str(timestamp) + str(sender)).encode('utf-8'))
        id = hash.hexdigest()

        encryption = ''
        if encrypted:
            encryption = 'verified' if self.encryption.verified else 'unverified'

        if not is_replication_message and not window.isKeyWindow():
            nc_body = html2txt(content) if is_html else content
            nc_title = NSLocalizedString("SMS Message Received", "Label")
            nc_subtitle = format_identity_to_string(sender, format='full')
            NSApp.delegate().gui_notify(nc_title, nc_body, nc_subtitle)

        self.log_info("Incoming message %s received" % call_id)

        self.chatViewController.showMessage(call_id,
                                            id,
                                            'incoming',
                                            format_identity_to_string(sender),
                                            icon,
                                            content,
                                            timestamp,
                                            is_html=is_html,
                                            state="delivered",
                                            media_type='sms',
                                            encryption=encryption)

        self.notification_center.post_notification(
            'ChatViewControllerDidDisplayMessage',
            sender=self,
            data=NotificationData(
                direction='incoming',
                history_entry=False,
                remote_party=format_identity_to_string(sender),
                local_party=format_identity_to_string(self.account)
                if self.account is not BonjourAccount() else 'bonjour.local',
                check_contact=True))

        # save to history
        if not is_replication_message or (is_replication_message and
                                          self.local_uri == self.account.id):
            message = MessageInfo(id,
                                  call_id=call_id,
                                  direction='incoming',
                                  sender=sender,
                                  recipient=self.account,
                                  timestamp=timestamp,
                                  content=content,
                                  content_type=content_type,
                                  status="delivered",
                                  encryption=encryption)
            self.add_to_history(message)

    def remoteBecameIdle_(self, timer):
        window = timer.userInfo()
        if window:
            window.noteView_isComposing_(self, False)

        if self.remoteTypingTimer:
            self.remoteTypingTimer.invalidate()
        self.remoteTypingTimer = None

    @objc.python_method
    def gotIsComposing(self, window, state, refresh, last_active):
        self.enableIsComposing = True

        flag = state == "active"
        if flag:
            if refresh is None:
                refresh = 120

            if last_active is not None and (
                    last_active - ISOTimestamp.now() >
                    datetime.timedelta(seconds=refresh)):
                # message is old, discard it
                return

            if self.remoteTypingTimer:
                # if we don't get any indications in the request refresh, then we assume remote to be idle
                self.remoteTypingTimer.setFireDate_(
                    NSDate.dateWithTimeIntervalSinceNow_(refresh))
            else:
                self.remoteTypingTimer = NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(
                    refresh, self, "remoteBecameIdle:", window, False)
        else:
            if self.remoteTypingTimer:
                self.remoteTypingTimer.invalidate()
                self.remoteTypingTimer = None

        window.noteView_isComposing_(self, flag)

    @objc.python_method
    @run_in_gui_thread
    def handle_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification.sender, notification.data)

    @objc.python_method
    def inject_otr_message(self, data):
        if not self.encryption.active:
            self.log_info('Negotiating OTR encryption...')
        messageObject = OTRInternalMessage(data)
        self.sendMessage(messageObject)

    @objc.python_method
    def _NH_DNSLookupDidFail(self, lookup, data):
        self.notification_center.remove_observer(self, sender=lookup)
        message = "DNS lookup of SIP proxies for %s failed: %s" % (str(
            self.target_uri.host), data.error)
        self.setRoutesFailed(message)

    @objc.python_method
    def _NH_DNSLookupDidSucceed(self, lookup, data):
        self.notification_center.remove_observer(self, sender=lookup)
        result_text = ', '.join(
            ('%s:%s (%s)' %
             (result.address, result.port, result.transport.upper())
             for result in data.result))
        self.log_info("DNS lookup for %s succeeded: %s" %
                      (self.target_uri.host.decode(), result_text))
        routes = data.result
        if not routes:
            self.setRoutesFailed("No routes found to SIP Proxy")
        else:
            self.setRoutesResolved(routes)

    @objc.python_method
    def _NH_ChatStreamOTREncryptionStateChanged(self, stream, data):
        if data.new_state is OTRState.Encrypted:
            local_fingerprint = stream.encryption.key_fingerprint
            remote_fingerprint = stream.encryption.peer_fingerprint
            self.log_info("Chat encryption activated using OTR protocol")
            self.log_info("OTR local fingerprint %s" % local_fingerprint)
            self.log_info("OTR remote fingerprint %s" % remote_fingerprint)
            self.chatViewController.showSystemMessage("0",
                                                      "Encryption enabled",
                                                      ISOTimestamp.now())
            self.showSystemMessage("Encryption enabled", ISOTimestamp.now())
        elif data.new_state is OTRState.Finished:
            self.log_info("Chat encryption deactivated")
            self.chatViewController.showSystemMessage("0",
                                                      "Encryption deactivated",
                                                      ISOTimestamp.now(),
                                                      is_error=True)
        elif data.new_state is OTRState.Plaintext:
            self.log_info("Chat encryption deactivated")
            self.chatViewController.showSystemMessage("0",
                                                      "Encryption deactivated",
                                                      ISOTimestamp.now(),
                                                      is_error=True)

    @objc.python_method
    def _NH_SIPMessageDidSucceed(self, sender, data):
        try:
            message = self.messages.pop(str(sender))
        except KeyError:
            pass
        else:
            call_id = data.headers['Call-ID'].body
            self.composeReplicationMessage(message, data.code)
            if message.content_type != "application/im-iscomposing+xml":
                self.log_info("Outgoing %s message %s delivered" %
                              (message.content_type, call_id))
                if data.code == 202:
                    self.chatViewController.markMessage(
                        message.id, MSG_STATE_DEFERRED)
                    message.status = 'deferred'
                else:
                    self.chatViewController.markMessage(
                        message.id, MSG_STATE_DELIVERED)
                    message.status = 'delivered'
                message.call_id = call_id
                self.add_to_history(message)

        self.notification_center.remove_observer(self, sender=sender)

    @objc.python_method
    def _NH_SIPMessageDidFail(self, sender, data):
        try:
            message = self.messages.pop(str(sender))
        except KeyError:
            pass
        else:
            if data.code == 408:
                self.last_route = None

            call_id = message.call_id
            self.composeReplicationMessage(message, data.code)
            if message.content_type != "application/im-iscomposing+xml":
                self.chatViewController.markMessage(message.id,
                                                    MSG_STATE_FAILED)
                message.status = 'failed'
                self.add_to_history(message)
                self.log_info("Outgoing message %s delivery failed: %s" %
                              (call_id.decode(), data.reason))
        self.notification_center.remove_observer(self, sender=sender)

    @objc.python_method
    def add_to_history(self, message):
        # writes the record to the sql database
        cpim_to = format_identity_to_string(
            message.recipient) if message.recipient else ''
        cpim_from = format_identity_to_string(
            message.sender) if message.sender else ''
        cpim_timestamp = str(message.timestamp)
        content_type = "html" if "html" in message.content_type else "text"

        self.history.add_message(message.id,
                                 'sms',
                                 self.local_uri,
                                 self.remote_uri,
                                 message.direction,
                                 cpim_from,
                                 cpim_to,
                                 cpim_timestamp,
                                 message.content,
                                 content_type,
                                 "0",
                                 message.status,
                                 call_id=message.call_id)

    @objc.python_method
    def composeReplicationMessage(self, sent_message, response_code):
        if sent_message.content_type == "application/im-iscomposing+xml":
            return

        if isinstance(self.account, Account):
            if not self.account.sms.disable_replication:
                contact = NSApp.delegate(
                ).contactsWindowController.getFirstContactMatchingURI(
                    self.target_uri)
                msg = CPIMPayload(
                    sent_message.content,
                    sent_message.content_type,
                    charset='utf-8',
                    sender=ChatIdentity(self.account.uri,
                                        self.account.display_name),
                    recipients=[
                        ChatIdentity(self.target_uri,
                                     contact.name if contact else None)
                    ])
                self.sendReplicationMessage(response_code,
                                            msg.encode()[0],
                                            content_type='message/cpim')

    @objc.python_method
    @run_in_green_thread
    def sendReplicationMessage(self,
                               response_code,
                               content,
                               content_type="message/cpim",
                               timestamp=None):
        timestamp = timestamp or ISOTimestamp.now()
        # Lookup routes
        if self.account.sip.outbound_proxy is not None:
            uri = SIPURI(host=self.account.sip.outbound_proxy.host,
                         port=self.account.sip.outbound_proxy.port,
                         parameters={
                             'transport':
                             self.account.sip.outbound_proxy.transport
                         })
        else:
            uri = SIPURI(host=self.account.id.domain)

        route = None
        if self.last_route is None:
            lookup = DNSLookup()
            settings = SIPSimpleSettings()
            try:
                routes = lookup.lookup_sip_proxy(
                    uri, settings.sip.transport_list).wait()
            except DNSLookupError:
                pass
            else:
                route = routes[0]
        else:
            route = self.last_route

        if route:
            extra_headers = [
                Header("X-Offline-Storage", "no"),
                Header("X-Replication-Code", str(response_code)),
                Header("X-Replication-Timestamp", str(ISOTimestamp.now()))
            ]
            message_request = Message(FromHeader(self.account.uri,
                                                 self.account.display_name),
                                      ToHeader(self.account.uri),
                                      RouteHeader(route.uri),
                                      content_type,
                                      content,
                                      credentials=self.account.credentials,
                                      extra_headers=extra_headers)
            message_request.send(
                15 if content_type != "application/im-iscomposing+xml" else 5)

    @objc.python_method
    @run_in_gui_thread
    def setRoutesResolved(self, routes):
        self.routes = routes
        self.last_route = self.routes[0]
        self.log_info('Proceed using route: %s' % self.last_route)

        if not self.started:
            self.message_queue.start()

        if not self.encryption.active and not self.started:
            self.encryption.start()

        self.started = True

    @objc.python_method
    @run_in_gui_thread
    def setRoutesFailed(self, reason):
        self.message_queue.stop()
        self.started = False

        for msgObject in self.message_queue:
            id = msgObject.id

            try:
                message = self.messages.pop(id)
            except KeyError:
                pass
            else:
                if content_type not in ('application/im-iscomposing+xml',
                                        'message/cpim'):
                    self.chatViewController.markMessage(
                        message.id, MSG_STATE_FAILED)
                    message.status = 'failed'
                    self.add_to_history(message)
                    log_text = NSLocalizedString("Routing failure: %s",
                                                 "Label") % msg
                    self.chatViewController.showSystemMessage(
                        '0', reason, ISOTimestamp.now(), True)
                    self.log_info(log_text)

    @objc.python_method
    def _send_message(self, message):
        if (not self.last_route):
            self.log_info('No route found')
            return

        message.timestamp = ISOTimestamp.now()

        if not isinstance(message, OTRInternalMessage):
            try:
                content = self.encryption.otr_session.handle_output(
                    message.content, message.content_type)
            except OTRError as e:
                if 'has ended the private conversation' in str(e):
                    self.log_info(
                        'Encryption has been disabled by remote party, please resend the message again'
                    )
                    self.encryption.stop()
                else:
                    self.log_info('Failed to encrypt outgoing message: %s' %
                                  str(e))
                return

        timeout = 5
        if message.content_type != "application/im-iscomposing+xml":
            self.enableIsComposing = True
            timeout = 15

        message_request = Message(FromHeader(self.account.uri,
                                             self.account.display_name),
                                  ToHeader(self.target_uri),
                                  RouteHeader(self.last_route.uri),
                                  message.content_type,
                                  message.content,
                                  credentials=self.account.credentials)

        self.notification_center.add_observer(self, sender=message_request)

        message_request.send(timeout)
        message.status = 'sent'
        message.call_id = message_request._request.call_id.decode()

        if not isinstance(message, OTRInternalMessage):
            if self.encryption.active:
                self.log_info(
                    'Sending encrypted %s message %s to %s' %
                    (message.content_type, message.id, self.last_route.uri))
            else:
                self.log_info(
                    'Sending %s message %s to %s' %
                    (message.content_type, message.id, self.last_route.uri))

        id = str(message_request)
        self.messages[id] = message

    @objc.python_method
    def lookup_destination(self, target_uri):
        assert isinstance(target_uri, SIPURI)

        lookup = DNSLookup()
        self.notification_center.add_observer(self, sender=lookup)
        settings = SIPSimpleSettings()

        if isinstance(self.account,
                      Account) and self.account.sip.outbound_proxy is not None:
            uri = SIPURI(host=self.account.sip.outbound_proxy.host,
                         port=self.account.sip.outbound_proxy.port,
                         parameters={
                             'transport':
                             self.account.sip.outbound_proxy.transport
                         })
            self.log_info("Starting DNS lookup for %s through proxy %s" %
                          (target_uri.host.decode(), uri))
        elif isinstance(self.account,
                        Account) and self.account.sip.always_use_my_proxy:
            uri = SIPURI(host=self.account.id.domain)
            self.log_info(
                "Starting DNS lookup for %s via proxy of account %s" %
                (target_uri.host.decode(), self.account.id))
        else:
            uri = target_uri
            self.log_info("Starting DNS lookup for %s" %
                          target_uri.host.decode())

        lookup.lookup_sip_proxy(uri, settings.sip.transport_list)

    @objc.python_method
    def sendMessage(self, content, content_type="text/plain"):
        # entry point for sending messages, they will be added to self.message_queue
        if content_type != "application/im-iscomposing+xml":
            icon = NSApp.delegate().contactsWindowController.iconPathForSelf()

            if not isinstance(content, OTRInternalMessage):
                timestamp = ISOTimestamp.now()
                hash = hashlib.sha1()
                content = content.decode() if isinstance(content,
                                                         bytes) else content
                hash.update((content + str(timestamp)).encode("utf-8"))
                id = hash.hexdigest()
                call_id = ''

                encryption = ''
                if self.encryption.active:
                    encryption = 'verified' if self.encryption.verified else 'unverified'

                self.chatViewController.showMessage(call_id,
                                                    id,
                                                    'outgoing',
                                                    None,
                                                    icon,
                                                    content,
                                                    timestamp,
                                                    state="sent",
                                                    media_type='sms',
                                                    encryption=encryption)

                recipient = ChatIdentity(self.target_uri, self.display_name)
                mInfo = MessageInfo(id,
                                    sender=self.account,
                                    recipient=recipient,
                                    timestamp=timestamp,
                                    content_type=content_type,
                                    content=content,
                                    status="queued",
                                    encryption=encryption)

                self.messages[id] = mInfo
                self.message_queue.put(mInfo)
            else:
                self.message_queue.put(content)

        # Async DNS lookup
        if host is None or host.default_ip is None:
            self.setRoutesFailed(
                NSLocalizedString("No Internet connection", "Label"))
            return

        if self.last_route is None:
            self.lookup_destination(self.target_uri)
        else:
            self.setRoutesResolved([self.last_route])

    def textView_doCommandBySelector_(self, textView, selector):
        if selector == "insertNewline:" and self.chatViewController.inputText == textView:
            content = str(textView.string())
            textView.setString_("")
            textView.didChangeText()

            if content:
                self.sendMessage(content)

            self.chatViewController.resetTyping()

            recipient = ChatIdentity(self.target_uri, self.display_name)
            self.notification_center.post_notification(
                'ChatViewControllerDidDisplayMessage',
                sender=self,
                data=NotificationData(
                    direction='outgoing',
                    history_entry=False,
                    remote_party=format_identity_to_string(recipient),
                    local_party=format_identity_to_string(self.account) if
                    self.account is not BonjourAccount() else 'bonjour.local',
                    check_contact=True))

            return True

        return False

    def textDidChange_(self, notif):
        chars_left = MAX_MESSAGE_LENGTH - self.chatViewController.inputText.textStorage(
        ).length()
        self.splitView.setText_(
            NSLocalizedString("%i chars left", "Label") % chars_left)

    @objc.python_method
    def getContentView(self):
        return self.chatViewController.view

    def chatView_becameIdle_(self, chatView, last_active):
        if self.enableIsComposing:
            content = IsComposingMessage(
                state=State("idle"),
                refresh=Refresh(60),
                last_active=LastActive(last_active or ISOTimestamp.now()),
                content_type=ContentType('text')).toxml()
            self.sendMessage(content, IsComposingDocument.content_type)

    def chatView_becameActive_(self, chatView, last_active):
        if self.enableIsComposing:
            content = IsComposingMessage(
                state=State("active"),
                refresh=Refresh(60),
                last_active=LastActive(last_active or ISOTimestamp.now()),
                content_type=ContentType('text')).toxml()
            self.sendMessage(content, IsComposingDocument.content_type)

    def chatViewDidLoad_(self, chatView):
        self.replay_history()

    @objc.python_method
    def scroll_back_in_time(self):
        self.chatViewController.clear()
        self.chatViewController.resetRenderedMessages()
        self.replay_history()

    @objc.python_method
    @run_in_green_thread
    def replay_history(self):
        blink_contact = NSApp.delegate(
        ).contactsWindowController.getFirstContactMatchingURI(self.target_uri)
        if not blink_contact:
            remote_uris = self.remote_uri
        else:
            remote_uris = list(
                str(uri.uri) for uri in blink_contact.uris if '@' in uri.uri)

        zoom_factor = self.chatViewController.scrolling_zoom_factor

        if zoom_factor:
            period_array = {
                1: datetime.datetime.now() - datetime.timedelta(days=2),
                2: datetime.datetime.now() - datetime.timedelta(days=7),
                3: datetime.datetime.now() - datetime.timedelta(days=31),
                4: datetime.datetime.now() - datetime.timedelta(days=90),
                5: datetime.datetime.now() - datetime.timedelta(days=180),
                6: datetime.datetime.now() - datetime.timedelta(days=365),
                7: datetime.datetime.now() - datetime.timedelta(days=3650)
            }

            after_date = period_array[zoom_factor].strftime("%Y-%m-%d")

            if zoom_factor == 1:
                self.zoom_period_label = NSLocalizedString(
                    "Displaying messages from last day", "Label")
            elif zoom_factor == 2:
                self.zoom_period_label = NSLocalizedString(
                    "Displaying messages from last week", "Label")
            elif zoom_factor == 3:
                self.zoom_period_label = NSLocalizedString(
                    "Displaying messages from last month", "Label")
            elif zoom_factor == 4:
                self.zoom_period_label = NSLocalizedString(
                    "Displaying messages from last three months", "Label")
            elif zoom_factor == 5:
                self.zoom_period_label = NSLocalizedString(
                    "Displaying messages from last six months", "Label")
            elif zoom_factor == 6:
                self.zoom_period_label = NSLocalizedString(
                    "Displaying messages from last year", "Label")
            elif zoom_factor == 7:
                self.zoom_period_label = NSLocalizedString(
                    "Displaying all messages", "Label")
                self.chatViewController.setHandleScrolling_(False)

            results = self.history.get_messages(
                remote_uri=remote_uris,
                media_type=('chat', 'sms'),
                after_date=after_date,
                count=10000,
                search_text=self.chatViewController.search_text)
        else:
            results = self.history.get_messages(
                remote_uri=remote_uris,
                media_type=('chat', 'sms'),
                count=self.showHistoryEntries,
                search_text=self.chatViewController.search_text)

        messages = [row for row in reversed(results)]
        self.render_history_messages(messages)

    @objc.python_method
    @run_in_gui_thread
    def render_history_messages(self, messages):
        if self.chatViewController.scrolling_zoom_factor:
            if not self.message_count_from_history:
                self.message_count_from_history = len(messages)
                self.chatViewController.lastMessagesLabel.setStringValue_(
                    self.zoom_period_label)
            else:
                if self.message_count_from_history == len(messages):
                    self.chatViewController.setHandleScrolling_(False)
                    self.chatViewController.lastMessagesLabel.setStringValue_(
                        NSLocalizedString(
                            "%s. There are no previous messages.", "Label") %
                        self.zoom_period_label)
                    self.chatViewController.setHandleScrolling_(False)
                else:
                    self.chatViewController.lastMessagesLabel.setStringValue_(
                        self.zoom_period_label)
        else:
            self.message_count_from_history = len(messages)
            if len(messages):
                self.chatViewController.lastMessagesLabel.setStringValue_(
                    NSLocalizedString("Scroll up for going back in time",
                                      "Label"))
            else:
                self.chatViewController.setHandleScrolling_(False)
                self.chatViewController.lastMessagesLabel.setStringValue_(
                    NSLocalizedString("There are no previous messages",
                                      "Label"))

        if len(messages):
            message = messages[0]
            delta = datetime.date.today() - message.date

            if not self.chatViewController.scrolling_zoom_factor:
                if delta.days <= 2:
                    self.chatViewController.scrolling_zoom_factor = 1
                elif delta.days <= 7:
                    self.chatViewController.scrolling_zoom_factor = 2
                elif delta.days <= 31:
                    self.chatViewController.scrolling_zoom_factor = 3
                elif delta.days <= 90:
                    self.chatViewController.scrolling_zoom_factor = 4
                elif delta.days <= 180:
                    self.chatViewController.scrolling_zoom_factor = 5
                elif delta.days <= 365:
                    self.chatViewController.scrolling_zoom_factor = 6
                elif delta.days <= 3650:
                    self.chatViewController.scrolling_zoom_factor = 7

        call_id = None
        seen_sms = {}
        last_media_type = 'sms'
        last_chat_timestamp = None
        for message in messages:
            if message.status == 'failed':
                continue

            if message.sip_callid != '' and message.media_type == 'sms':
                try:
                    seen = seen_sms[message.sip_callid]
                except KeyError:
                    seen_sms[message.sip_callid] = True
                else:
                    continue

            if message.direction == 'outgoing':
                icon = NSApp.delegate(
                ).contactsWindowController.iconPathForSelf()
            else:
                sender_uri = sipuri_components_from_string(
                    message.cpim_from)[0]
                icon = NSApp.delegate(
                ).contactsWindowController.iconPathForURI(sender_uri)

            timestamp = ISOTimestamp(message.cpim_timestamp)
            is_html = False if message.content_type == 'text' else True

            #if call_id is not None and call_id != message.sip_callid and message.media_type == 'chat':
            #   self.chatViewController.showSystemMessage(message.sip_callid, 'Chat session established', timestamp, False)

            #if message.media_type == 'sms' and last_media_type == 'chat':
            #   self.chatViewController.showSystemMessage(message.sip_callid, 'Short messages', timestamp, False)

            self.chatViewController.showMessage(message.sip_callid,
                                                message.id,
                                                message.direction,
                                                message.cpim_from,
                                                icon,
                                                message.body,
                                                timestamp,
                                                recipient=message.cpim_to,
                                                state=message.status,
                                                is_html=is_html,
                                                history_entry=True,
                                                media_type=message.media_type,
                                                encryption=message.encryption)

            call_id = message.sip_callid
            last_media_type = 'chat' if message.media_type == 'chat' else 'sms'
            if message.media_type == 'chat':
                last_chat_timestamp = timestamp

        self.chatViewController.loadingProgressIndicator.stopAnimation_(None)
        self.chatViewController.loadingTextIndicator.setStringValue_("")

    def webviewFinishedLoading_(self, notification):
        self.document = self.outputView.mainFrameDocument()
        self.finishedLoading = True
        for script in self.messageQueue:
            self.outputView.stringByEvaluatingJavaScriptFromString_(script)
        self.messageQueue = []

        if hasattr(self.delegate, "chatViewDidLoad_"):
            self.delegate.chatViewDidLoad_(self)

    def webView_decidePolicyForNavigationAction_request_frame_decisionListener_(
            self, webView, info, request, frame, listener):
        # intercept link clicks so that they are opened in Safari
        theURL = info[WebActionOriginalURLKey]
        if theURL.scheme() == "file":
            listener.use()
        else:
            listener.ignore()
            NSWorkspace.sharedWorkspace().openURL_(theURL)
示例#30
0
class UI(Thread):
    __metaclass__ = Singleton

    control_chars = {'\x01': 'home',
                     '\x04': 'eof',
                     '\x05': 'end',
                     '\x0a': 'newline',
                     '\x0d': 'newline',
                     '\x1b[A': 'cursorup',
                     '\x1b[B': 'cursordown',
                     '\x1b[C': 'cursorright',
                     '\x1b[D': 'cursorleft',
                     '\x1b[F': 'end',
                     '\x1b[H': 'home',
                     '\x7f': 'delete'}

    # public functions
    #

    def __init__(self):
        Thread.__init__(self, target=self._run, name='UI-Thread')
        self.setDaemon(True)

        self.__dict__['prompt'] = Prompt('')
        self.__dict__['status'] = None
        self.command_sequence = '/'
        self.application_control_char = '\x18' # ctrl-X
        self.application_control_bindings = {}
        self.display_commands = True
        self.display_text = True

        self.cursor_x = None
        self.cursor_y = None
        self.displaying_question = False
        self.input = Input()
        self.last_window_size = None
        self.prompt_y = None
        self.questions = deque()
        self.stopping = False
        self.lock = RLock()
        self.event_queue = EventQueue(handler=lambda (function, self, args, kwargs): function(self, *args, **kwargs), name='UI operation handling')

    def start(self, prompt='', command_sequence='/', control_char='\x18', control_bindings={}, display_commands=True, display_text=True):
        with self.lock:
            if self.isAlive():
                raise RuntimeError('UI already active')
            if not sys.stdin.isatty():
                raise RuntimeError('UI cannot be used on a non-TTY')
            if not sys.stdout.isatty():
                raise RuntimeError('UI cannot be used on a non-TTY')
            stdin_fd = sys.stdin.fileno()

            self.command_sequence = command_sequence
            self.application_control_char = control_char
            self.application_control_bindings = control_bindings
            self.display_commands = display_commands
            self.display_text = display_text

            # wrap sys.stdout
            sys.stdout = TTYFileWrapper(sys.stdout)
            # and possibly sys.stderr
            if sys.stderr.isatty():
                sys.stderr = TTYFileWrapper(sys.stderr)

            # change input to character-mode
            old_settings = termios.tcgetattr(stdin_fd)
            new_settings = termios.tcgetattr(stdin_fd)
            new_settings[3] &= ~termios.ECHO & ~termios.ICANON
            new_settings[6][termios.VMIN] = '\000'
            termios.tcsetattr(stdin_fd, termios.TCSADRAIN, new_settings)
            atexit.register(termios.tcsetattr, stdin_fd, termios.TCSADRAIN, old_settings)

            # find out cursor position in terminal
            self._raw_write('\x1b[6n')
            if select.select([stdin_fd], [], [], None)[0]:
                line, col = os.read(stdin_fd, 10)[2:-1].split(';')
                line = int(line)
                col = int(col)

            # scroll down the terminal until everything goes up
            self._scroll_up(line-1)
            # move the cursor to the upper left side corner
            self._raw_write('\x1b[H')
            self.cursor_x = 1
            self.cursor_y = 1
            # display the prompt
            self.prompt_y = 1
            self.input.add_line()
            self._update_prompt()
            # make sure we know when the window gets resized
            self.last_window_size = self.window_size
            signal.signal(signal.SIGWINCH, lambda signum, frame: self._window_resized())

            self.event_queue.start()
            Thread.start(self)

            # this will trigger the update of the prompt
            self.prompt = prompt

    @run_in_ui_thread
    def stop(self):
        with self.lock:
            self.stopping = True
            self.status = None
            sys.stdout.send_to_file()
            if isinstance(sys.stderr, TTYFileWrapper):
                sys.stderr.send_to_file()
            self._raw_write('\n\x1b[2K')

    def write(self, text):
        self.writelines([text])

    @run_in_ui_thread
    def writelines(self, text_lines):
        with self.lock:
            if not text_lines:
                return
            # go to beginning of prompt line
            self._raw_write('\x1b[%d;%dH' % (self.prompt_y, 1))
            # erase everything beneath it
            self._raw_write('\x1b[0J')
            # start writing lines
            window_size = self.window_size
            for text in text_lines:
                # write the line
                self._raw_write('%s\n' % text)
                # calculate the number of lines the text will produce
                text_lines = (len(text)-1)/window_size.x + 1
                # calculate how much the text will automatically scroll the window
                window_height = struct.unpack('HHHH', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0)))[0]
                auto_scroll_amount = max(0, (self.prompt_y+text_lines-1) - (window_height-1))
                # calculate the new position of the prompt
                self.prompt_y += text_lines - auto_scroll_amount
                # we might need to scroll up to make the prompt position visible again
                scroll_up = self.prompt_y - window_height
                if scroll_up > 0:
                    self.prompt_y -= scroll_up
                    self._scroll_up(scroll_up)
            # redraw the prompt
            self._update_prompt()

    @run_in_ui_thread
    def add_question(self, question):
        with self.lock:
            self.questions.append(question)
            if len(self.questions) == 1:
                self._update_prompt()

    @run_in_ui_thread
    def remove_question(self, question):
        with self.lock:
            first_question = (question == self.questions[0])
            self.questions.remove(question)
            if not self.questions or first_question:
                self.displaying_question = False
                self._update_prompt()

    # properties
    #

    @property
    def window_size(self):
        class WindowSize(tuple):
            def __init__(ws_self, (y, x)):
                ws_self.x = x
                ws_self.y = y if self.status is None else y-1
        return WindowSize(struct.unpack('HHHH', fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0)))[:2])
示例#31
0
class Logger(object):
    implements(IObserver)

    # public methods
    #

    def __init__(
        self,
        sip_to_stdout=False,
        msrp_to_stdout=False,
        pjsip_to_stdout=False,
        notifications_to_stdout=False,
        msrp_level=log.level.ERROR,
    ):
        self.sip_to_stdout = sip_to_stdout
        self.msrp_to_stdout = msrp_to_stdout
        self.pjsip_to_stdout = pjsip_to_stdout
        self.notifications_to_stdout = notifications_to_stdout
        self.msrp_level = msrp_level

        self._siptrace_filename = None
        self._siptrace_file = None
        self._siptrace_error = False
        self._siptrace_start_time = None
        self._siptrace_packet_count = 0

        self._msrptrace_filename = None
        self._msrptrace_file = None
        self._msrptrace_error = False

        self._pjsiptrace_filename = None
        self._pjsiptrace_file = None
        self._pjsiptrace_error = False

        self._notifications_filename = None
        self._notifications_file = None
        self._notifications_error = False

        self._event_queue = EventQueue(handler=self._process_notification, name="Log handling")
        self._log_directory_error = False

    def start(self):
        # try to create the log directory
        try:
            self._init_log_directory()
        except Exception:
            pass

        # register to receive log notifications
        notification_center = NotificationCenter()
        notification_center.add_observer(self)

        # start the thread processing the notifications
        self._event_queue.start()

    def stop(self):
        # stop the thread processing the notifications
        self._event_queue.stop()
        self._event_queue.join()

        # close sip trace file
        if self._siptrace_file is not None:
            self._siptrace_file.close()
            self._siptrace_file = None

        # close msrp trace file
        if self._msrptrace_file is not None:
            self._msrptrace_file.close()
            self._msrptrace_file = None

        # close pjsip trace file
        if self._pjsiptrace_file is not None:
            self._pjsiptrace_file.close()
            self._pjsiptrace_file = None

        # close notifications trace file
        if self._notifications_file is not None:
            self._notifications_file.close()
            self._notifications_file = None

        # unregister from receiving notifications
        notification_center = NotificationCenter()
        notification_center.remove_observer(self)

    def handle_notification(self, notification):
        self._event_queue.put(notification)

    def _process_notification(self, notification):
        settings = SIPSimpleSettings()
        handler = getattr(self, "_NH_%s" % notification.name, None)
        if handler is not None:
            handler(notification)

        handler = getattr(self, "_LH_%s" % notification.name, None)
        if handler is not None:
            handler(notification)

        if notification.name not in ("SIPEngineLog", "SIPEngineSIPTrace") and (
            self.notifications_to_stdout or settings.logs.trace_notifications
        ):
            message = "Notification name=%s sender=%s" % (notification.name, notification.sender)
            if notification.data is not None:
                message += "\n%s" % pformat(notification.data.__dict__)
            if self.notifications_to_stdout:
                print "%s: %s" % (datetime.datetime.now(), message)
            if settings.logs.trace_notifications:
                try:
                    self._init_log_file("notifications")
                except Exception:
                    pass
                else:
                    self._notifications_file.write(
                        "%s [%s %d]: %s\n"
                        % (datetime.datetime.now(), os.path.basename(sys.argv[0]).rstrip(".py"), os.getpid(), message)
                    )
                    self._notifications_file.flush()

    # notification handlers
    #

    def _NH_CFGSettingsObjectDidChange(self, notification):
        settings = SIPSimpleSettings()
        if notification.sender is settings:
            if "logs.directory" in notification.data.modified:
                # sip trace
                if self._siptrace_file is not None:
                    self._siptrace_file.close()
                    self._siptrace_file = None
                # pjsip trace
                if self._pjsiptrace_file is not None:
                    self._pjsiptrace_file.close()
                    self._pjsiptrace_file = None
                # notifications trace
                if self._notifications_file is not None:
                    self._notifications_file.close()
                    self._notifications_file = None
                # try to create the log directory
                try:
                    self._init_log_directory()
                except Exception:
                    pass

    # log handlers
    #

    def _LH_SIPEngineSIPTrace(self, notification):
        settings = SIPSimpleSettings()
        if not self.sip_to_stdout and not settings.logs.trace_sip:
            return
        if self._siptrace_start_time is None:
            self._siptrace_start_time = notification.data.timestamp
        self._siptrace_packet_count += 1
        if notification.data.received:
            direction = "RECEIVED"
        else:
            direction = "SENDING"
        buf = [
            "%s: Packet %d, +%s"
            % (direction, self._siptrace_packet_count, (notification.data.timestamp - self._siptrace_start_time))
        ]
        buf.append(
            "%(source_ip)s:%(source_port)d -(SIP over %(transport)s)-> %(destination_ip)s:%(destination_port)d"
            % notification.data.__dict__
        )
        buf.append(notification.data.data)
        buf.append("--")
        message = "\n".join(buf)
        if self.sip_to_stdout:
            print "%s: %s\n" % (notification.data.timestamp, message)
        if settings.logs.trace_sip:
            try:
                self._init_log_file("siptrace")
            except Exception:
                pass
            else:
                self._siptrace_file.write(
                    "%s [%s %d]: %s\n"
                    % (notification.data.timestamp, os.path.basename(sys.argv[0]).rstrip(".py"), os.getpid(), message)
                )
                self._siptrace_file.flush()

    def _LH_SIPEngineLog(self, notification):
        settings = SIPSimpleSettings()
        if not self.pjsip_to_stdout and not settings.logs.trace_pjsip:
            return
        message = "(%(level)d) %(sender)14s: %(message)s" % notification.data.__dict__
        if self.pjsip_to_stdout:
            print "%s %s" % (notification.data.timestamp, message)
        if settings.logs.trace_pjsip:
            try:
                self._init_log_file("pjsiptrace")
            except Exception:
                pass
            else:
                self._pjsiptrace_file.write(
                    "%s [%s %d] %s\n"
                    % (notification.data.timestamp, os.path.basename(sys.argv[0]).rstrip(".py"), os.getpid(), message)
                )
                self._pjsiptrace_file.flush()

    def _LH_DNSLookupTrace(self, notification):
        settings = SIPSimpleSettings()
        if not self.sip_to_stdout and not settings.logs.trace_sip:
            return
        message = "DNS lookup %(query_type)s %(query_name)s" % notification.data.__dict__
        if notification.data.error is None:
            message += " succeeded, ttl=%d: " % notification.data.answer.ttl
            if notification.data.query_type == "A":
                message += ", ".join(record.address for record in notification.data.answer)
            elif notification.data.query_type == "SRV":
                message += ", ".join(
                    "%d %d %d %s" % (record.priority, record.weight, record.port, record.target)
                    for record in notification.data.answer
                )
            elif notification.data.query_type == "NAPTR":
                message += ", ".join(
                    '%d %d "%s" "%s" "%s" %s'
                    % (record.order, record.preference, record.flags, record.service, record.regexp, record.replacement)
                    for record in notification.data.answer
                )
        else:
            import dns.resolver

            message_map = {
                dns.resolver.NXDOMAIN: "DNS record does not exist",
                dns.resolver.NoAnswer: "DNS response contains no answer",
                dns.resolver.NoNameservers: "no DNS name servers could be reached",
                dns.resolver.Timeout: "no DNS response received, the query has timed out",
            }
            message += " failed: %s" % message_map.get(notification.data.error.__class__, "")
        if self.sip_to_stdout:
            print "%s: %s" % (notification.data.timestamp, message)
        if settings.logs.trace_sip:
            try:
                self._init_log_file("siptrace")
            except Exception:
                pass
            else:
                self._siptrace_file.write(
                    "%s [%s %d]: %s\n"
                    % (notification.data.timestamp, os.path.basename(sys.argv[0]).rstrip(".py"), os.getpid(), message)
                )
                self._siptrace_file.flush()

    def _LH_MSRPTransportTrace(self, notification):
        settings = SIPSimpleSettings()
        if not self.msrp_to_stdout and not settings.logs.trace_msrp:
            return
        arrow = {"incoming": "<--", "outgoing": "-->"}[notification.data.direction]
        local_address = notification.sender.getHost()
        local_address = "%s:%d" % (local_address.host, local_address.port)
        remote_address = notification.sender.getPeer()
        remote_address = "%s:%d" % (remote_address.host, remote_address.port)
        message = "%s %s %s\n" % (local_address, arrow, remote_address) + notification.data.data
        if self.msrp_to_stdout:
            print "%s: %s" % (notification.data.timestamp, message)
        if settings.logs.trace_msrp:
            try:
                self._init_log_file("msrptrace")
            except Exception:
                pass
            else:
                self._msrptrace_file.write(
                    "%s [%s %d]: %s\n"
                    % (notification.data.timestamp, os.path.basename(sys.argv[0]).rstrip(".py"), os.getpid(), message)
                )
                self._msrptrace_file.flush()

    def _LH_MSRPLibraryLog(self, notification):
        settings = SIPSimpleSettings()
        if not self.msrp_to_stdout and not settings.logs.trace_msrp:
            return
        if notification.data.level < self.msrp_level:
            return
        message = "%s%s" % (notification.data.level.prefix, notification.data.message)
        if self.msrp_to_stdout:
            print "%s: %s" % (notification.data.timestamp, message)
        if settings.logs.trace_msrp:
            try:
                self._init_log_file("msrptrace")
            except Exception:
                pass
            else:
                self._msrptrace_file.write(
                    "%s [%s %d]: %s\n"
                    % (notification.data.timestamp, os.path.basename(sys.argv[0]).rstrip(".py"), os.getpid(), message)
                )
                self._msrptrace_file.flush()

    # private methods
    #

    def _init_log_directory(self):
        settings = SIPSimpleSettings()
        log_directory = settings.logs.directory.normalized
        try:
            makedirs(log_directory)
        except Exception, e:
            if not self._log_directory_error:
                print "failed to create logs directory '%s': %s" % (log_directory, e)
                self._log_directory_error = True
            self._siptrace_error = True
            self._pjsiptrace_error = True
            self._notifications_error = True
            raise
        else:
示例#32
0
class SubscriptionApplication(object):
    implements(IObserver)

    def __init__(self):
        # Loads the config file
        config = configparser.ConfigParser()
        try:
            config.read('config.ini')
        except Exception as e:
            print("ERROR: " + e)
            return
        self.account_name = config["SIPCONFIG"]["account_name"]
        self.target = None
        self.input = InputThread(self)
        self.output = EventQueue(self._write)
        self.logger = Logger(sip_to_stdout=False,
                             pjsip_to_stdout=False,
                             notifications_to_stdout=False)
        self.account = None
        self.subscriptions = []
        self.subscriptionqueue = []
        self.statusdict = {}
        self.stopping = False
        self.lastmessage = None
        self.commandsystemenabled = bool(config['SIPCONFIG']['commands'])

        self._subscription_routes = None
        self._subscription_timeout = 0.0
        self._subscription_wait = 0.5

        account_manager = AccountManager()
        engine = Engine()
        notification_center = NotificationCenter()
        notification_center.add_observer(self, sender=account_manager)
        notification_center.add_observer(self, sender=engine)
        notification_center.add_observer(self, sender=self.input)
        notification_center.add_observer(self, name='SIPEngineGotMessage')

        log.level.current = log.level.WARNING

    def _write(self, message):
        if isinstance(message, unicode):
            message = message.encode(sys.getfilesystemencoding())
        sys.stdout.write(message + '\n')

    def run(self):
        account_manager = AccountManager()
        configuration = ConfigurationManager()
        engine = Engine()

        # start output thread
        self.output.start()

        # startup configuration
        Account.register_extension(AccountExtension)
        SIPSimpleSettings.register_extension(SIPSimpleSettingsExtension)
        SIPApplication.storage = FileStorage(config_directory)
        try:
            configuration.start()
        except ConfigurationError, e:
            raise RuntimeError(
                "failed to load sipclient's configuration: %s\nIf an old configuration file is in place, delete it or move it and recreate the configuration using the sip_settings script."
                % str(e))
        account_manager.load()
        if self.account_name is None:
            # Uses a garbage default account if a account name is not specified
            self.account = account_manager.default_account
        else:
            # Otherwise iterates through the account manager and finds the account
            # You have to add a account to sip-settings through the terminal for this to work
            # ex: sip-settings -a add user@domain password
            possible_accounts = [
                account for account in account_manager.iter_accounts()
                if self.account_name in account.id and account.enabled
            ]
            if len(possible_accounts) > 1:
                raise RuntimeError(
                    "More than one account exists which matches %s: %s" %
                    (self.account_name, ", ".join(
                        sorted(account.id for account in possible_accounts))))
            if len(possible_accounts) == 0:
                raise RuntimeError(
                    "No enabled account that matches %s was found. Available and enabled accounts: %s"
                    % (self.account_name, ", ".join(
                        sorted(account.id
                               for account in account_manager.get_accounts()
                               if account.enabled))))
            self.account = possible_accounts[0]
            self.account.presence.enabled = True
            self.account.save()
        if self.account is None:
            raise RuntimeError(
                "Unknown account %s. Available accounts: %s" %
                (self.account_name, ', '.join(
                    account.id
                    for account in account_manager.iter_accounts())))
        for account in account_manager.iter_accounts():
            if account == self.account:
                account.sip.register = False
            else:
                account.enabled = False
        self.output.put('Using account %s' % self.account.id)
        settings = SIPSimpleSettings()

        # start logging
        self.logger.start()

        # start the SIPSIMPLE engine
        engine.start(
            auto_sound=False,
            events={'presence': [PIDFDocument.content_type]},
            udp_port=settings.sip.udp_port
            if "udp" in settings.sip.transport_list else None,
            tcp_port=settings.sip.tcp_port
            if "tcp" in settings.sip.transport_list else None,
            tls_port=settings.sip.tls_port
            if "tls" in settings.sip.transport_list else None,
            tls_verify_server=self.account.tls.verify_server,
            tls_ca_file=os.path.expanduser(settings.tls.ca_list)
            if settings.tls.ca_list else None,
            tls_cert_file=os.path.expanduser(self.account.tls.certificate)
            if self.account.tls.certificate else None,
            tls_privkey_file=os.path.expanduser(self.account.tls.certificate)
            if self.account.tls.certificate else None,
            user_agent=settings.user_agent,
            sample_rate=settings.audio.sample_rate,
            rtp_port_range=(settings.rtp.port_range.start,
                            settings.rtp.port_range.end),
            trace_sip=settings.logs.trace_sip or self.logger.sip_to_stdout,
            log_level=settings.logs.pjsip_level if
            (settings.logs.trace_pjsip or self.logger.pjsip_to_stdout) else 0)

        # start the input thread
        self.input.start()

        # Sets up the database manager for adding subscriptions
        self.db = dbmanager.DatabaseManager(self)
        self.db.loadExtensions()

        # start twisted
        try:
            reactor.run()
        finally:
            self.input.stop()

        # stop the output
        self.output.stop()
        self.output.join()

        # closes the database connection
        self.db.destroyDBConnection()

        self.logger.stop()

        return 0
示例#33
0
class RadiusDatabase(object):
    """Interface with the Radius database"""
    class RadiusTask(object):
        def __init__(self, deferred, tasktype, **kwargs):
            self.deferred = deferred
            self.tasktype = tasktype
            self.args = kwargs

    def __init__(self):
        self.queue = EventQueue(handler=self._handle_task, name='RadiusQueue')
        self.queue.start()

        credentials = RadiusDatabaseConfig.user and ( "%s%s@" % (RadiusDatabaseConfig.user, RadiusDatabaseConfig.password and ":%s" % (RadiusDatabaseConfig.password) or '') ) or ''
        self.conn = sqlobject.connectionForURI("mysql://%s%s/%s" % (credentials, RadiusDatabaseConfig.host, RadiusDatabaseConfig.database))

    def close(self):
        return threads.deferToThread(self._close)

    def _close(self):
        self.queue.stop()
        self.queue.join()
        self.conn.close()

    def getTerminatedCalls(self, calls):
        """
        Retrieve those calls from the ones in progress that were already terminated by caller/called.

        Returns a Deferred. Callback will be called with list of call ids.
        """
        deferred = defer.Deferred()
        self.queue.put(RadiusDatabase.RadiusTask(deferred, 'terminated', calls=calls))
        return deferred

    def getTimedoutCalls(self, calls):
        """
        Retrieve those calls from the ones in progress that did timeout and were closed by mediaproxy.

        Returns a Deferred. Callback will be called with list of call ids.
        """
        deferred = defer.Deferred()
        self.queue.put(RadiusDatabase.RadiusTask(deferred, 'timedout', calls=calls))
        return deferred

    def query(self, task):
        def _unknown_task(task):
            raise RadiusDatabaseError("Got unknown task to handle: %s" % task.tasktype)
        return getattr(self, '_RD_%s' % task.tasktype, _unknown_task)(task)

    def _handle_task(self, task):
        try:
            reactor.callFromThread(task.deferred.callback, self.query(task))
        except Exception as e:
            reactor.callFromThread(task.deferred.errback, failure.Failure(e))

    def _RD_terminated(self, task):
        calls = dict([(call.callid, call) for call in list(task.args['calls'].values()) if call.inprogress])
        if not calls:
            return {}
        ids = "(%s)" % ','.join(["'" + key + "'" for key in list(calls.keys())])
        query = """SELECT %(session_id_field)s AS callid, %(duration_field)s AS duration,
                          %(from_tag_field)s AS fromtag, %(to_tag_field)s AS totag
                   FROM   %(table)s
                   WHERE  %(session_id_field)s IN %(ids)s AND
                          (%(stop_info_field)s IS NOT NULL OR
                           %(stop_time_field)s IS NOT NULL)""" % {'session_id_field': RadiusDatabaseConfig.sessionIdField,
                                                                  'duration_field': RadiusDatabaseConfig.durationField,
                                                                  'from_tag_field': RadiusDatabaseConfig.fromTagField,
                                                                  'to_tag_field': RadiusDatabaseConfig.toTagField,
                                                                  'stop_info_field': RadiusDatabaseConfig.stopInfoField,
                                                                  'stop_time_field': RadiusDatabaseConfig.stopTimeField,
                                                                  'table': RadiusDatabaseConfig.table.normalized,
                                                                  'ids': ids}
        try:
            rows = self.conn.queryAll(query)
        except Exception as e:
            log.error("Query failed: %s" % query)
            raise RadiusDatabaseError("Exception while querying for terminated calls %s." % e)
        def find(row, calls):
            try:
                call = calls[row[0]]
            except KeyError:
                return False
            return call.fromtag==row[2] and call.totag==row[3]
        return dict([(row[0], {'callid': row[0], 'duration': row[1], 'fromtag': row[2], 'totag': row[3]}) for row in rows if find(row, calls)])

    def _RD_timedout(self, task):
        calls = dict([(call.callid, call) for call in list(task.args['calls'].values()) if call.inprogress])
        if not calls:
            return {}
        ids = "(%s)" % ','.join(["'" + key + "'" for key in list(calls.keys())])
        query = '''SELECT %(session_id_field)s AS callid, %(duration_field)s AS duration,
                          %(from_tag_field)s AS fromtag, %(to_tag_field)s AS totag
                   FROM   %(table)s
                   WHERE  %(session_id_field)s IN %(ids)s AND
                          %(media_info_field)s = 'timeout' AND
                          %(stop_info_field)s IS NULL''' % {'session_id_field': RadiusDatabaseConfig.sessionIdField,
                                                            'duration_field': RadiusDatabaseConfig.durationField,
                                                            'from_tag_field': RadiusDatabaseConfig.fromTagField,
                                                            'to_tag_field': RadiusDatabaseConfig.toTagField,
                                                            'media_info_field': RadiusDatabaseConfig.mediaInfoField,
                                                            'stop_info_field': RadiusDatabaseConfig.stopInfoField,
                                                            'table': RadiusDatabaseConfig.table.normalized,
                                                            'ids': ids}
        try:
            rows = self.conn.queryAll(query)
        except Exception as e:
            log.error("Query failed: %s" % query)
            raise RadiusDatabaseError("Exception while querying for timedout calls %s." % e)
        def find(row, calls):
            try:
                call = calls[row[0]]
            except KeyError:
                return False
            return call.fromtag==row[2] and call.totag==row[3]
        return dict([(row[0], {'callid': row[0], 'duration': row[1], 'fromtag': row[2], 'totag': row[3]}) for row in rows if find(row, calls)])
示例#34
0
class DataConnection(object):
    implements(IObserver)

    def __init__(self, name):
        self.name = name
        self.secret = None
        self.private_key = DSAPrivateKey.generate()
        self.otr_session = OTRSession(self.private_key, transport=self)
        self.peer = None
        self.send_queue = EventQueue(handler=self._send_handler)
        self.send_queue.start()
        self.ake_done = Event()
        self.smp_done = Event()
        self.all_done = Event()
        self.otr_done = Event()
        self.smp_status = None
        self.same_secrets = None
        self.sent_message = None
        self.received_message = None
        NotificationCenter().add_observer(self, sender=self.otr_session)

    def _send_handler(self, message):
        time.sleep(0.01)
        self.peer.receive(message)

    def connect(self, peer):
        self.peer = peer

    def disconnect(self):
        self.send_queue.stop()
        self.send_queue = None

    def start_otr(self, secret=None):
        self.secret = secret
        self.otr_session.start()

    def stop_otr(self):
        self.otr_session.stop()

    def inject_otr_message(self, message):
        log.debug("{0.name} sending: {1!r}".format(self, message))
        self.send_queue.put(message)

    def send(self, content, content_type='text/plain'):
        log.debug("{0.name} encoding: {1!r}".format(self, content))
        self.sent_message = content
        content = self.otr_session.handle_output(content, content_type)
        log.debug("{0.name} sending: {1!r}".format(self, content))
        self.send_queue.put(content)

    def receive(self, message):
        # log.debug("{0.name} received: {1!r}".format(self, message))
        try:
            message = self.otr_session.handle_input(message, 'text/plain')
        except IgnoreMessage:
            return
        else:
            log.debug("{0.name} decoded:  {1!r}".format(self, message))
            self.received_message = message
            self.all_done.set()

    def handle_notification(self, notification):
        handler = getattr(self, '_NH_{0.name}'.format(notification), Null)
        handler(notification)

    def _NH_OTRSessionStateChanged(self, notification):
        if notification.data.new_state is OTRState.Encrypted:
            self.ake_done.set()
            if self.secret is None:
                self.smp_done.set()
            elif self.name < self.peer.name:
                self.otr_session.smp_verify(secret=self.secret)
        elif notification.data.old_state is OTRState.Encrypted:
            self.otr_done.set()

    def _NH_OTRSessionSMPVerificationDidStart(self, notification):
        if notification.data.originator == 'remote':
            if self.secret:
                self.otr_session.smp_answer(secret=self.secret)
            else:
                self.otr_session.smp_abort()

    def _NH_OTRSessionSMPVerificationDidNotStart(self, notification):
        self.smp_status = notification.data.reason
        self.smp_done.set()

    def _NH_OTRSessionSMPVerificationDidEnd(self, notification):
        self.same_secrets = notification.data.same_secrets
        self.smp_status = notification.data.status
        self.smp_done.set()