def _NH_IncomingFileTransferHandlerDidEnd(self, notification): notification.center.remove_observer(self, sender=self) remote_hash = self.file_selector.hash if not self.transfer_finished: log.msg('File transfer of %s cancelled' % os.path.basename(self.filename)) self.remove_bogus_file(self.filename) self.status = 'INCOMPLETE' else: local_hash = 'sha1:' + ':'.join(re.findall(r'..', self.hash.hexdigest().upper())) if local_hash != remote_hash: log.warning('Hash of transferred file does not match the remote hash (file may have changed).') self.status = 'HASH_MISSMATCH' self.remove_bogus_file(self.filename) else: self.status = 'OK' self_uri = SIPURI.new(self.session.local_identity.uri) self_uri.parameters.clear() sender_uri = SIPURI.new(self.session.remote_identity.uri) sender_uri.parameters.clear() self.session = None self.stream = None file = File(self.filename, remote_hash, self.file_selector.size) notification.center.post_notification('IncomingFileTransferHandlerGotFile', sender=self, data=NotificationData(local_uri=self_uri, remote_uri=sender_uri, file=file))
def __init__(self, account, target_uri, filename, hash): self.account = account self._file_selector = FileSelector(name=os.path.basename(filename), hash=hash) self.remote_identity = format_identity_to_string(target_uri) self.target_uri = SIPURI.new(target_uri) self._ended = False
def incoming_message(self, message_request, data): content_type = data.headers.get('Content-Type', Null).content_type from_header = data.headers.get('From', Null) to_header = data.headers.get('To', Null) if Null in (content_type, from_header, to_header): message_request.answer(400) return log.info('New SIP Message from %s to %s' % (from_header.uri, to_header.uri)) # Check domain if from_header.uri.host not in XMPPGatewayConfig.domains: log.info('Message rejected: From domain is not a local XMPP domain') message_request.answer(606) return if content_type == 'message/cpim': try: cpim_message = CPIMPayload.decode(data.body) except CPIMParserError: log.info('Message rejected: CPIM parse error') message_request.answer(400) return else: body = cpim_message.content content_type = cpim_message.content_type sender = cpim_message.sender or from_header from_uri = sender.uri else: body = data.body from_uri = from_header.uri to_uri = str(to_header.uri) message_request.answer(200) if from_uri.parameters.get('gr', None) is None: from_uri = SIPURI.new(from_uri) from_uri.parameters['gr'] = generate_sylk_resource() sender = Identity(FrozenURI.parse(from_uri)) recipient = Identity(FrozenURI.parse(to_uri)) if content_type in ('text/plain', 'text/html'): if content_type == 'text/plain': html_body = None else: html_body = body body = None if XMPPGatewayConfig.use_msrp_for_chat: message = NormalMessage(sender, recipient, body, html_body, use_receipt=False) self.xmpp_manager.send_stanza(message) else: message = ChatMessage(sender, recipient, body, html_body, use_receipt=False) self.xmpp_manager.send_stanza(message) elif content_type == IsComposingDocument.content_type: if not XMPPGatewayConfig.use_msrp_for_chat: try: msg = IsComposingMessage.parse(body) except ParserError: pass else: state = 'composing' if msg.state == 'active' else 'paused' message = ChatComposingIndication(sender, recipient, state, use_receipt=False) self.xmpp_manager.send_stanza(message)
def incoming_message(self, message_request, data): content_type = data.headers.get('Content-Type', Null).content_type from_header = data.headers.get('From', Null) to_header = data.headers.get('To', Null) if Null in (content_type, from_header, to_header): message_request.answer(400) return log.msg('New SIP Message from %s to %s' % (from_header.uri, to_header.uri)) # Check domain if from_header.uri.host not in XMPPGatewayConfig.domains: log.msg('Message rejected: From domain is not a local XMPP domain') message_request.answer(606) return if content_type == 'message/cpim': try: cpim_message = CPIMMessage.parse(data.body) except CPIMParserError: log.msg('Message rejected: CPIM parse error') message_request.answer(400) return else: body = cpim_message.body content_type = cpim_message.content_type sender = cpim_message.sender or from_header from_uri = sender.uri else: body = data.body from_uri = from_header.uri to_uri = str(to_header.uri) message_request.answer(200) if from_uri.parameters.get('gr', None) is None: from_uri = SIPURI.new(from_uri) from_uri.parameters['gr'] = generate_sylk_resource() sender = Identity(FrozenURI.parse(from_uri)) recipient = Identity(FrozenURI.parse(to_uri)) if content_type in ('text/plain', 'text/html'): if content_type == 'text/plain': html_body = None else: html_body = body body = None if XMPPGatewayConfig.use_msrp_for_chat: message = NormalMessage(sender, recipient, body, html_body, use_receipt=False) self.xmpp_manager.send_stanza(message) else: message = ChatMessage(sender, recipient, body, html_body, use_receipt=False) self.xmpp_manager.send_stanza(message) elif content_type == IsComposingDocument.content_type: if not XMPPGatewayConfig.use_msrp_for_chat: try: msg = IsComposingMessage.parse(body) except ParserError: pass else: state = 'composing' if msg.state == 'active' else 'paused' message = ChatComposingIndication(sender, recipient, state, use_receipt=False) self.xmpp_manager.send_stanza(message)
def incoming_message(self, message_request, data): content_type = data.headers.get("Content-Type", Null).content_type from_header = data.headers.get("From", Null) to_header = data.headers.get("To", Null) if Null in (content_type, from_header, to_header): message_request.answer(400) return log.msg("New SIP Message from %s to %s" % (from_header.uri, to_header.uri)) # Check domain if from_header.uri.host not in XMPPGatewayConfig.domains: log.msg("Message rejected: From domain is not a local XMPP domain") message_request.answer(606) return if content_type == "message/cpim": try: cpim_message = CPIMPayload.decode(data.body) except CPIMParserError: log.msg("Message rejected: CPIM parse error") message_request.answer(400) return else: body = cpim_message.content content_type = cpim_message.content_type sender = cpim_message.sender or from_header from_uri = sender.uri else: body = data.body from_uri = from_header.uri to_uri = str(to_header.uri) message_request.answer(200) if from_uri.parameters.get("gr", None) is None: from_uri = SIPURI.new(from_uri) from_uri.parameters["gr"] = generate_sylk_resource() sender = Identity(FrozenURI.parse(from_uri)) recipient = Identity(FrozenURI.parse(to_uri)) if content_type in ("text/plain", "text/html"): if content_type == "text/plain": html_body = None else: html_body = body body = None if XMPPGatewayConfig.use_msrp_for_chat: message = NormalMessage(sender, recipient, body, html_body, use_receipt=False) self.xmpp_manager.send_stanza(message) else: message = ChatMessage(sender, recipient, body, html_body, use_receipt=False) self.xmpp_manager.send_stanza(message) elif content_type == IsComposingDocument.content_type: if not XMPPGatewayConfig.use_msrp_for_chat: try: msg = IsComposingMessage.parse(body) except ParserError: pass else: state = "composing" if msg.state == "active" else "paused" message = ChatComposingIndication(sender, recipient, state, use_receipt=False) self.xmpp_manager.send_stanza(message)
def incoming_sip_message(self, message_request, data): # Handle incoming MESSAGE from_header = data.headers.get('From', Null) to_header = data.headers.get('To', Null) content_type = data.headers.get('Content-Type', Null)[0] if from_header is Null or to_header is Null: message_request.answer(400) return message_request.answer(200) if content_type not in ('text/plain', 'text/html'): return source_uri = SIPURI.new(to_header.uri) destination_uri = SIPURI.new(from_header.uri) try: fact = self.facts.next() except StopIteration: return else: self.send_chuck_norris_fact(source_uri, destination_uri, fact)
def incoming_sip_message(self, message_request, data): # Handle incoming MESSAGE from_header = data.headers.get('From', Null) to_header = data.headers.get('To', Null) content_type = data.headers.get('Content-Type', Null)[0] if from_header is Null or to_header is Null: message_request.answer(400) return message_request.answer(200) if content_type not in ('text/plain', 'text/html'): return source_uri = SIPURI.new(to_header.uri) destination_uri = SIPURI.new(from_header.uri) try: fact = self.facts.next() except StopIteration: return else: self.send_chuck_norris_fact(source_uri, destination_uri, fact)
def _NH_DNSLookupDidSucceed(self, notification): notification_center = NotificationCenter() notification_center.remove_observer(self, sender=notification.sender) account = DefaultAccount() conference_application = ConferenceApplication() try: room = conference_application.get_room(self.room_uri) except RoomNotFoundError: log.info('Room %s - failed to add %s' % (self.room_uri_str, self.refer_to_uri)) self._refer_request.end(500) return active_media = set(room.active_media).intersection(('audio', 'chat')) if not active_media: log.info('Room %s - failed to add %s' % (self.room_uri_str, self.refer_to_uri)) self._refer_request.end(500) return for stream_type in active_media: self.streams.append(MediaStreamRegistry.get(stream_type)()) self.session = Session(account) notification_center.add_observer(self, sender=self.session) original_from_header = self._refer_headers.get('From') if original_from_header.display_name: original_identity = "%s <%s@%s>" % ( original_from_header.display_name, original_from_header.uri.user, original_from_header.uri.host) else: original_identity = "%s@%s" % (original_from_header.uri.user, original_from_header.uri.host) from_header = FromHeader(SIPURI.new(self.room_uri), u'Conference Call') to_header = ToHeader(self.refer_to_uri) extra_headers = [] if self._refer_headers.get('Referred-By', None) is not None: extra_headers.append( Header.new(self._refer_headers.get('Referred-By'))) else: extra_headers.append( Header('Referred-By', str(original_from_header.uri))) if ThorNodeConfig.enabled: extra_headers.append(Header('Thor-Scope', 'conference-invitation')) extra_headers.append( Header('X-Originator-From', str(original_from_header.uri))) extra_headers.append( SubjectHeader(u'Join conference request from %s' % original_identity)) route = notification.data.result[0] self.session.connect(from_header, to_header, route=route, streams=self.streams, is_focus=True, extra_headers=extra_headers)
def _NH_IncomingFileTransferHandlerDidEnd(self, notification): notification.center.remove_observer(self, sender=self) remote_hash = self.file_selector.hash if not self.transfer_finished: log.msg('File transfer of %s cancelled' % os.path.basename(self.filename)) self.remove_bogus_file(self.filename) self.status = 'INCOMPLETE' else: local_hash = 'sha1:' + ':'.join( re.findall(r'..', self.hash.hexdigest().upper())) if local_hash != remote_hash: log.warning( 'Hash of transferred file does not match the remote hash (file may have changed).' ) self.status = 'HASH_MISSMATCH' self.remove_bogus_file(self.filename) else: self.status = 'OK' self_uri = SIPURI.new(self.session.local_identity.uri) self_uri.parameters.clear() sender_uri = SIPURI.new(self.session.remote_identity.uri) sender_uri.parameters.clear() self.session = None self.stream = None file = File(self.filename, remote_hash, self.file_selector.size) notification.center.post_notification( 'IncomingFileTransferHandlerGotFile', sender=self, data=NotificationData(local_uri=self_uri, remote_uri=sender_uri, file=file))
def __init__(self, account, target_uri, filename, hash): self.account = account self.end_session_when_done = True self.error = False self.file_selector = FileSelector(name=filename, hash=hash) self.finished_transfer = False self.hash = hashlib.sha1() self.interrupted = False self.remote_identity = format_identity_to_string(target_uri) self.session = None self.session_ended = False self.started = False self.stream = None self.target_uri = SIPURI.new(target_uri) self.timer = None self.transfer_id = str(uuid.uuid1())
def __init__(self, account, target_uri, filename, hash): self.account = account self.end_session_when_done = True self.error = False self.file_selector = FileSelector(name=filename, hash=hash) self.finished_transfer = False self.hash = hashlib.sha1() self.interrupted = False self.remote_identity = format_identity_to_string(target_uri) self.session = None self.session_ended = False self.started = False self.stream = None self.target_uri = SIPURI.new(target_uri) self.timer = None self.transfer_id = str(uuid.uuid1())
def _NH_DNSLookupDidSucceed(self, notification): notification_center = NotificationCenter() notification_center.remove_observer(self, sender=notification.sender) account = DefaultAccount() conference_application = ConferenceApplication() try: room = conference_application.get_room(self.room_uri) except RoomNotFoundError: log.msg("Room %s - failed to add %s" % (self.room_uri_str, self.refer_to_uri)) self._refer_request.end(500) return active_media = set(room.active_media).intersection(("audio", "chat")) if not active_media: log.msg("Room %s - failed to add %s" % (self.room_uri_str, self.refer_to_uri)) self._refer_request.end(500) return registry = MediaStreamRegistry() for stream_type in active_media: self.streams.append(registry.get(stream_type)()) self.session = Session(account) notification_center.add_observer(self, sender=self.session) original_from_header = self._refer_headers.get("From") if original_from_header.display_name: original_identity = "%s <%s@%s>" % ( original_from_header.display_name, original_from_header.uri.user, original_from_header.uri.host, ) else: original_identity = "%s@%s" % (original_from_header.uri.user, original_from_header.uri.host) from_header = FromHeader(SIPURI.new(self.room_uri), u"Conference Call") to_header = ToHeader(self.refer_to_uri) extra_headers = [] if self._refer_headers.get("Referred-By", None) is not None: extra_headers.append(Header.new(self._refer_headers.get("Referred-By"))) else: extra_headers.append(Header("Referred-By", str(original_from_header.uri))) if ThorNodeConfig.enabled: extra_headers.append(Header("Thor-Scope", "conference-invitation")) extra_headers.append(Header("X-Originator-From", str(original_from_header.uri))) extra_headers.append(SubjectHeader(u"Join conference request from %s" % original_identity)) route = notification.data.result[0] self.session.connect( from_header, to_header, route=route, streams=self.streams, is_focus=True, extra_headers=extra_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 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)
def _NH_SIPEngineGotMessage(self, sender, data): account = AccountManager().find_account(data.request_uri) if not account: BlinkLogger().log_warning(u"Could not find recipient account for message to %s, using default" % data.request_uri) account = AccountManager().default_account is_cpim = False cpim_message = None replication_message = False if data.content_type == 'message/cpim': try: cpim_message = CPIMMessage.parse(data.body) except CPIMParserError: BlinkLogger().log_warning(u"SMS from %s has invalid CPIM content" % format_identity_to_string(data.from_header)) return else: is_cpim = True body = cpim_message.body 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: 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: body = 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'): BlinkLogger().log_info(u"Got SMS from %s" % format_identity_to_string(sender_identity)) elif content_type == 'application/im-iscomposing+xml': # body must not be utf-8 decoded body = cpim_message.body if is_cpim else data.body msg = IsComposingMessage.parse(body) 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(u"SMS from %s has unknown content-type %s" % (format_identity_to_string(data.from_header), data.content_type)) return # display the message note_new_message = False if 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 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 = Timestamp.parse(replicated_timestamp) except (TypeError, ValueError): replication_timestamp = Timestamp(datetime.datetime.now(tzlocal())) viewer.gotMessage(sender_identity, body, is_html, replication_state, replication_timestamp) self.windowForViewer(viewer).noteView_isComposing_(viewer, False) if replication_message: return if not self.windowForViewer(viewer).window().isKeyWindow(): # notify growl growl_data = TimestampedNotificationData() if is_html: growl_data.content = html2txt(body) else: growl_data.content = body growl_data.sender = format_identity_to_string(sender_identity, format='compact') self.notification_center.post_notification("GrowlGotSMS", sender=self, data=growl_data)
def _NH_SIPEngineGotMessage(self, sender, data): account = AccountManager().find_account(data.request_uri) if not account: BlinkLogger().log_warning(u"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 = CPIMMessage.parse(data.body) except CPIMParserError: BlinkLogger().log_warning(u"Incoming SMS from %s to %s has invalid CPIM content" % format_identity_to_string(data.from_header), account.id) return else: is_cpim = True body = cpim_message.body 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: body = 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 body = cpim_message.body if is_cpim else data.body msg = IsComposingMessage.parse(body) 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(u"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, body, is_html, is_replication_message, replication_timestamp, window=window) self.windowForViewer(viewer).noteView_isComposing_(viewer, False)
def _run(self): notification_center = NotificationCenter() settings = SIPSimpleSettings() sender_uri = self.sender.uri.as_sip_uri() recipient_uri = self.recipient.uri.as_sip_uri() participant_uri = self.participant.uri.as_sip_uri() try: # Lookup routes account = DefaultAccount() if account.sip.outbound_proxy is not None and account.sip.outbound_proxy.transport in settings.sip.transport_list: uri = SIPURI(host=account.sip.outbound_proxy.host, port=account.sip.outbound_proxy.port, parameters={ 'transport': account.sip.outbound_proxy.transport }) elif account.sip.always_use_my_proxy: uri = SIPURI(host=account.id.domain) else: uri = SIPURI.new(recipient_uri) lookup = DNSLookup() try: routes = lookup.lookup_sip_proxy( uri, settings.sip.transport_list).wait() except DNSLookupError as e: raise ReferralError(error='DNS lookup failed: %s' % e) timeout = time() + 30 for route in routes: self.route = route remaining_time = timeout - time() if remaining_time > 0: transport = route.transport parameters = {} if transport == 'udp' else { 'transport': transport } contact_uri = SIPURI(user=account.contact.username, host=SIPConfig.local_ip.normalized, port=getattr(Engine(), '%s_port' % transport), parameters=parameters) refer_to_header = ReferToHeader(str(participant_uri)) refer_to_header.parameters['method'] = 'INVITE' referral = Referral(recipient_uri, FromHeader(sender_uri), ToHeader(recipient_uri), refer_to_header, ContactHeader(contact_uri), RouteHeader(route.uri), account.credentials) notification_center.add_observer(self, sender=referral) try: referral.send_refer( timeout=limit(remaining_time, min=1, max=5)) except SIPCoreError: notification_center.remove_observer(self, sender=referral) timeout = 5 raise ReferralError(error='Internal error') self._referral = referral try: while True: notification = self._channel.wait() if notification.name == 'SIPReferralDidStart': break except SIPReferralDidFail as e: notification_center.remove_observer(self, sender=referral) self._referral = None if e.data.code in (403, 405): raise ReferralError( error=sip_status_messages[e.data.code], code=e.data.code) else: # Otherwise just try the next route continue else: break else: self.route = None raise ReferralError(error='No more routes to try') # At this point it is subscribed. Handle notifications and ending/failures. try: self.active = True while True: notification = self._channel.wait() if notification.name == 'SIPReferralDidEnd': break except SIPReferralDidFail as e: notification_center.remove_observer(self, sender=self._referral) raise ReferralError(error=e.data.reason, code=e.data.code) else: notification_center.remove_observer(self, sender=self._referral) finally: self.active = False except ReferralError as e: self._failure = MucInvitationFailure(e.code, e.error) finally: notification_center.remove_observer( self, name='NetworkConditionsDidChange') self._referral = None if self._failure is not None: notification_center.post_notification( 'X2SMucInvitationHandlerDidFail', sender=self, data=NotificationData(failure=self._failure)) else: notification_center.post_notification( 'X2SMucInvitationHandlerDidEnd', sender=self)
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)