Exemple #1
0
 def __init__(self,
              content,
              content_type,
              charset=None,
              sender=None,
              recipients=None,
              courtesy_recipients=None,
              subject=None,
              timestamp=None,
              required=None,
              additional_headers=None):
     if not isinstance(content, bytes):
         raise TypeError("content should be an instance of bytes")
     self.content = content
     self.content_type = content_type
     self.charset = charset
     self.sender = sender
     self.recipients = recipients or []
     self.courtesy_recipients = courtesy_recipients or []
     self.subject = subject if isinstance(
         subject,
         (MultilingualText, type(None))) else MultilingualText(subject)
     self.timestamp = ISOTimestamp(
         timestamp) if timestamp is not None else None
     self.required = required or []
     self.additional_headers = additional_headers or []
 def __init__(self, content, content_type, sender=None, recipients=None, courtesy_recipients=None, subject=None, timestamp=None, required=None, additional_headers=None):
     self.content = content
     self.content_type = content_type
     self.sender = sender
     self.recipients = recipients or []
     self.courtesy_recipients = courtesy_recipients or []
     self.subject = subject
     self.timestamp = ISOTimestamp(timestamp) if timestamp is not None else None
     self.required = required or []
     self.additional_headers = additional_headers or []
 def renderMessage(self, message):
     if message.direction == 'outgoing':
         icon = NSApp.delegate().contactsWindowController.iconPathForSelf()
     else:
         sender_uri = sipuri_components_from_string(message.cpim_from)[0]
         # TODO: How to render the icons from Address Book? Especially in sandbox mode we do not have access to other folders
         icon = NSApp.delegate().contactsWindowController.iconPathForURI(sender_uri)
     try:
         timestamp=ISOTimestamp(message.cpim_timestamp)
     except Exception:
         pass
     else:
         is_html = False if message.content_type == 'text' else True
         private = True if message.private == "1" else False
         self.chatViewController.showMessage(message.sip_callid, message.msgid, message.direction, message.cpim_from, icon, message.body, timestamp, is_private=private, recipient=message.cpim_to, state=message.status, is_html=is_html, history_entry=True, media_type=message.media_type, encryption=message.encryption if message.media_type == 'chat' else None)
Exemple #4
0
    def _NH_SIPEngineGotMessage(self, sender, data):
        account = AccountManager().find_account(data.request_uri)
        if not account:
            BlinkLogger().log_warning(
                "Could not find local account for incoming SMS to %s, using default"
                % data.request_uri)
            account = AccountManager().default_account

        call_id = data.headers.get('Call-ID', Null).body
        try:
            self.received_call_ids.remove(call_id)
        except KeyError:
            self.received_call_ids.add(call_id)
        else:
            # drop duplicate message received
            return

        is_cpim = False
        cpim_message = None
        is_replication_message = False

        if data.content_type == 'message/cpim':
            try:
                cpim_message = CPIMPayload.decode(data.body)
            except CPIMParserError:
                BlinkLogger().log_warning(
                    "Incoming SMS from %s to %s has invalid CPIM content" %
                    format_identity_to_string(data.from_header), account.id)
                return
            else:
                is_cpim = True
                content = cpim_message.content
                content_type = cpim_message.content_type
                sender_identity = cpim_message.sender or data.from_header
                if cpim_message.sender and data.from_header.uri == data.to_header.uri and data.from_header.uri == cpim_message.sender.uri:
                    is_replication_message = True
                    window_tab_identity = cpim_message.recipients[
                        0] if cpim_message.recipients else data.to_header
                else:
                    window_tab_identity = data.from_header
        else:
            content = data.body.decode('utf-8')
            content_type = data.content_type
            sender_identity = data.from_header
            window_tab_identity = sender_identity

        is_html = content_type == 'text/html'

        if content_type in ('text/plain', 'text/html'):
            pass
            #BlinkLogger().log_info(u"Incoming SMS %s from %s to %s received" % (call_id, format_identity_to_string(sender_identity), account.id))
        elif content_type == 'application/im-iscomposing+xml':
            # body must not be utf-8 decoded
            content = cpim_message.content if is_cpim else data.body
            msg = IsComposingMessage.parse(content)
            state = msg.state.value
            refresh = msg.refresh.value if msg.refresh is not None else None
            content_type = msg.content_type.value if msg.content_type is not None else None
            last_active = msg.last_active.value if msg.last_active is not None else None

            viewer = self.openMessageWindow(SIPURI.new(
                window_tab_identity.uri),
                                            window_tab_identity.display_name,
                                            account,
                                            create_if_needed=False,
                                            note_new_message=False)
            if viewer:
                viewer.gotIsComposing(self.windowForViewer(viewer), state,
                                      refresh, last_active)
            return
        else:
            BlinkLogger().log_warning(
                "Incoming SMS %s from %s to %s has unknown content-type %s" %
                (call_id, format_identity_to_string(
                    data.from_header), account.id, data.content_type))
            return

        # display the message
        note_new_message = False if is_replication_message else True
        viewer = self.openMessageWindow(SIPURI.new(window_tab_identity.uri),
                                        window_tab_identity.display_name,
                                        account,
                                        note_new_message=note_new_message)
        self.windowForViewer(viewer).noteNewMessageForSession_(viewer)
        replication_state = None
        replication_timestamp = None

        if is_replication_message:
            replicated_response_code = data.headers.get(
                'X-Replication-Code', Null).body
            if replicated_response_code == '202':
                replication_state = 'deferred'
            elif replicated_response_code == '200':
                replication_state = 'delivered'
            else:
                replication_state = 'failed'
            replicated_timestamp = data.headers.get('X-Replication-Timestamp',
                                                    Null).body
            try:
                replication_timestamp = ISOTimestamp(replicated_timestamp)
            except Exception:
                replication_timestamp = ISOTimestamp.now()

        window = self.windowForViewer(viewer).window()
        viewer.gotMessage(sender_identity,
                          call_id,
                          content,
                          is_html,
                          is_replication_message,
                          replication_timestamp,
                          window=window)
        self.windowForViewer(viewer).noteView_isComposing_(viewer, False)
Exemple #5
0
    def decode(cls, message):

        headers, separator, body = message.partition('\r\n\r\n')
        if not separator:
            raise CPIMParserError('Invalid CPIM message')

        sender = None
        recipients = []
        courtesy_recipients = []
        subject = None
        timestamp = None
        required = []
        additional_headers = []

        namespaces = {'': CPIMNamespace(cls.standard_namespace)}
        subjects = {}

        for prefix, name, value in cls.headers_re.findall(headers):
            namespace = namespaces.get(prefix)

            if namespace is None or '.' in name:
                continue

            try:
                #value = value.decode('cpim-header')
                if namespace == cls.standard_namespace:
                    if name == 'From':
                        sender = ChatIdentity.parse(value)
                    elif name == 'To':
                        recipients.append(ChatIdentity.parse(value))
                    elif name == 'cc':
                        courtesy_recipients.append(ChatIdentity.parse(value))
                    elif name == 'Subject':
                        match = cls.subject_re.match(value)
                        if match is None:
                            raise ValueError('Illegal Subject header: %r' %
                                             value)
                        lang, subject = match.groups()
                        # language tags must be ASCII
                        subjects[str(lang
                                     ) if lang is not None else None] = subject
                    elif name == 'DateTime':
                        timestamp = ISOTimestamp(value)
                    elif name == 'Required':
                        required.extend(re.split(r'\s*,\s*', value))
                    elif name == 'NS':
                        match = cls.namespace_re.match(value)
                        if match is None:
                            raise ValueError('Illegal NS header: %r' % value)
                        prefix, uri = match.groups()
                        namespaces[prefix] = CPIMNamespace(uri, prefix)
                    else:
                        additional_headers.append(
                            CPIMHeader(name, namespace, value))
                else:
                    additional_headers.append(
                        CPIMHeader(name, namespace, value))
            except ValueError:
                pass

        if None in subjects:
            subject = MultilingualText(subjects.pop(None), **subjects)
        elif subjects:
            subject = MultilingualText(**subjects)

        mime_message = EmailParser().parsestr(body)
        content_type = mime_message.get_content_type()
        if content_type is None:
            raise CPIMParserError(
                "CPIM message missing Content-Type MIME header")
        content = mime_message.get_payload()
        charset = mime_message.get_content_charset()

        return cls(content, content_type, charset, sender, recipients,
                   courtesy_recipients, subject, timestamp, required,
                   additional_headers)
    def _NH_SIPEngineGotMessage(self, sender, data):
        account = AccountManager().find_account(data.request_uri)
        if not account:
            BlinkLogger().log_warning(
                "Could not find local account for incoming SMS to %s, using default"
                % data.request_uri)
            account = AccountManager().default_account

        call_id = data.headers.get('Call-ID', Null).body

        try:
            self.received_call_ids.remove(call_id)
        except KeyError:
            self.received_call_ids.add(call_id)
        else:
            # drop duplicate message received
            return

        is_cpim = False
        cpim_message = None
        is_replication_message = False
        imdn_id = None
        imdn_timestamp = None

        if data.content_type == 'message/cpim':
            try:
                cpim_message = CPIMPayload.decode(data.body)
            except CPIMParserError:
                BlinkLogger().log_warning(
                    "Incoming SMS from %s to %s has invalid CPIM content" %
                    format_identity_to_string(data.from_header), account.id)
                return
            else:
                is_cpim = True
                content = cpim_message.content
                content_type = cpim_message.content_type
                sender_identity = cpim_message.sender or data.from_header
                cpim_imdn_events = None
                imdn_timestamp = cpim_message.timestamp
                for h in cpim_message.additional_headers:
                    if h.name == "Message-ID":
                        imdn_id = h.value
                    if h.name == "Disposition-Notification":
                        cpim_imdn_events = h.value

                if imdn_id:
                    if cpim_imdn_events and 'positive-delivery' in cpim_imdn_events and imdn_timestamp:
                        BlinkLogger().log_info(
                            "Will send IMDN delivery notification for %s" %
                            imdn_id)
                    else:
                        imdn_id = None

                if cpim_message.sender and data.from_header.uri == data.to_header.uri and data.from_header.uri == cpim_message.sender.uri:
                    is_replication_message = True
                    window_tab_identity = cpim_message.recipients[
                        0] if cpim_message.recipients else data.to_header
                else:
                    window_tab_identity = data.from_header
        else:
            content = data.body
            content_type = data.content_type
            sender_identity = data.from_header
            window_tab_identity = sender_identity

        if content_type in ('text/plain', 'text/html'):
            BlinkLogger().log_info(
                u"Incoming SMS %s from %s to %s received" %
                (call_id, format_identity_to_string(sender_identity),
                 account.id))
        elif content_type in ('text/rsa-public-key'):
            uri = format_identity_to_string(sender_identity)
            BlinkLogger().log_info(
                u"Public key from %s received" %
                (format_identity_to_string(sender_identity)))

            if uri == account.id:
                BlinkLogger().log_info(
                    u"Public key save skipped for own account")
                return

            public_key = ''
            start_public = False

            for l in content.decode().split("\n"):
                if l == "-----BEGIN RSA PUBLIC KEY-----":
                    start_public = True

                if l == "-----END RSA PUBLIC KEY-----":
                    public_key = public_key + l
                    start_public = False
                    break

                if start_public:
                    public_key = public_key + l + '\n'

            if public_key:
                blink_contact = NSApp.delegate(
                ).contactsWindowController.getFirstContactFromAllContactsGroupMatchingURI(
                    uri)

                if blink_contact is not None:
                    contact = blink_contact.contact
                    if contact.public_key != public_key:
                        contact.public_key = public_key
                        contact.public_key_checksum = hashlib.sha1(
                            public_key.encode()).hexdigest()
                        contact.save()
                        BlinkLogger().log_info(
                            u"Public key %s from %s saved " %
                            (contact.public_key_checksum,
                             data.from_header.uri))
                        nc_title = NSLocalizedString(
                            "Public key", "System notification title")
                        nc_subtitle = format_identity_to_string(
                            sender_identity, check_contact=True, format='full')
                        nc_body = NSLocalizedString(
                            "Public key has changed",
                            "System notification title")
                        NSApp.delegate().gui_notify(nc_title, nc_body,
                                                    nc_subtitle)

                    else:
                        BlinkLogger().log_info(
                            u"Public key from %s has not changed" %
                            data.from_header.uri)
                else:
                    BlinkLogger().log_info(u"No contact found to save the key")

            return
        elif content_type in ('text/rsa-private-key'):
            BlinkLogger().log_info(u"Private key from %s to %s received" %
                                   (data.from_header.uri, account.id))

            if account.id == str(data.from_header.uri).split(":")[1]:
                self.import_key_window = ImportPrivateKeyController(
                    account, content)
                self.import_key_window.show()
            return
        elif content_type in ('message/imdn+xml'):
            document = IMDNDocument.parse(content)
            imdn_message_id = document.message_id.value
            imdn_status = document.notification.status.__str__()
            BlinkLogger().log_info(u"Received IMDN message %s" % imdn_status)
            viewer = self.openMessageWindow(
                SIPURI.new(window_tab_identity.uri),
                window_tab_identity.display_name, account)
            if viewer and imdn_status == 'displayed':
                viewer.chatViewController.markMessage(imdn_message_id,
                                                      MSG_STATE_DISPLAYED)
            return
        elif content_type == 'application/im-iscomposing+xml':
            content = cpim_message.content if is_cpim else data.body
            msg = IsComposingMessage.parse(content)
            state = msg.state.value
            refresh = msg.refresh.value if msg.refresh is not None else None
            content_type = msg.content_type.value if msg.content_type is not None else None
            last_active = msg.last_active.value if msg.last_active is not None else None

            viewer = self.openMessageWindow(SIPURI.new(
                window_tab_identity.uri),
                                            window_tab_identity.display_name,
                                            account,
                                            create_if_needed=False,
                                            note_new_message=False)
            if viewer:
                viewer.gotIsComposing(self.windowForViewer(viewer), state,
                                      refresh, last_active)
            return
        else:
            BlinkLogger().log_warning(
                "Incoming SMS %s from %s to %s has unknown content-type %s" %
                (call_id, format_identity_to_string(
                    data.from_header), account.id, content_type))
            return

        # display the message
        note_new_message = False if is_replication_message else True
        viewer = self.openMessageWindow(SIPURI.new(window_tab_identity.uri),
                                        window_tab_identity.display_name,
                                        account,
                                        note_new_message=note_new_message)
        self.windowForViewer(viewer).noteNewMessageForSession_(viewer)
        replication_state = None
        replication_timestamp = None

        if is_replication_message:
            replicated_response_code = data.headers.get(
                'X-Replication-Code', Null).body
            if replicated_response_code == '202':
                replication_state = 'deferred'
            elif replicated_response_code == '200':
                replication_state = 'delivered'
            else:
                replication_state = 'failed'
            replicated_timestamp = data.headers.get('X-Replication-Timestamp',
                                                    Null).body
            try:
                replication_timestamp = ISOTimestamp(replicated_timestamp)
            except Exception:
                replication_timestamp = ISOTimestamp.now()

        window = self.windowForViewer(viewer).window()
        viewer.gotMessage(sender_identity,
                          call_id,
                          content,
                          content_type,
                          is_replication_message,
                          replication_timestamp,
                          window=window,
                          imdn_id=imdn_id,
                          imdn_timestamp=imdn_timestamp)

        self.windowForViewer(viewer).noteView_isComposing_(viewer, False)
Exemple #7
0
    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_("")