class Validity(XMLListElement, ConditionElement): _xml_tag = 'validity' _xml_namespace = namespace _xml_application = CommonPolicyApplication def __init__(self, children=[]): XMLListElement.__init__(self) self[0:0] = children def _parse_element(self, element, *args, **kwargs): iterator = iter(element) for first_child in iterator: second_child = iterator.next() if first_child.tag == '{%s}from' % self._xml_namespace and second_child.tag == '{%s}until' % self._xml_namespace: try: self.append((first_child.text, second_child.text)) except: pass def _build_element(self, *args, **kwargs): self.element.clear() for (from_valid, until_valid) in self: from_elem = etree.SubElement(self.element, '{%s}from' % self._xml_namespace, nsmap=self._xml_application.xml_nsmap) from_elem.text = str(from_valid) until_elem = etree.SubElement( self.element, '{%s}until' % self._xml_namespace, nsmap=self._xml_application.xml_nsmap) until_elem.text = str(until_valid) def check_validity(self): if not self: raise ValidationError( "cannot have Validity element without any children") XMLListElement.check_validity(self) def _add_item(self, (from_valid, until_valid)): if isinstance(from_valid, (datetime.datetime, str)): from_valid = Timestamp(from_valid) if isinstance(until_valid, (datetime.datetime, str)): until_valid = Timestamp(until_valid) if not isinstance(from_valid, Timestamp) or not isinstance( until_valid, Timestamp): raise TypeError( "Validity element can only contain Timestamp 2-tuples") return (from_valid, until_valid)
def add_to_history(self): FileTransferHistory().add_transfer( transfer_id=self.ft_info.transfer_id, direction=self.ft_info.direction, local_uri=self.ft_info.local_uri, remote_uri=self.ft_info.remote_uri, file_path=self.ft_info.file_path, bytes_transfered=self.ft_info.bytes_transfered, file_size=self.ft_info.file_size or 0, status=self.ft_info.status) message = "<h3>%s File Transfer</h3>" % self.ft_info.direction.capitalize( ) message += "<p>%s (%s)" % (self.ft_info.file_path, format_size(self.ft_info.file_size or 0)) media_type = 'file-transfer' local_uri = self.ft_info.local_uri remote_uri = self.ft_info.remote_uri direction = self.ft_info.direction status = 'delivered' if self.ft_info.status == 'completed' else 'failed' cpim_from = self.ft_info.remote_uri cpim_to = self.ft_info.remote_uri timestamp = str(Timestamp(datetime.datetime.now(tzlocal()))) ChatHistory().add_message(self.ft_info.transfer_id, media_type, local_uri, remote_uri, direction, cpim_from, cpim_to, timestamp, message, "html", "0", status)
def sendMessage(self, text, content_type="text/plain"): self.lookup_destination(self.target_uri) timestamp = Timestamp(datetime.datetime.now(tzlocal())) hash = hashlib.sha1() hash.update(text.encode("utf-8") + str(timestamp)) msgid = hash.hexdigest() if content_type != "application/im-iscomposing+xml": icon = NSApp.delegate().contactsWindowController.iconPathForSelf() self.chatViewController.showMessage(msgid, 'outgoing', None, icon, text, timestamp, state="sent") recipient = CPIMIdentity(self.target_uri, self.display_name) self.messages[msgid] = MessageInfo(msgid, sender=self.account, recipient=recipient, timestamp=timestamp, content_type=content_type, text=text, status="queued") self.queue.append((msgid, text, content_type))
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 = Timestamp.parse(message.cpim_timestamp) except ValueError: pass else: is_html = False if message.content_type == 'text' else True private = True if message.private == "1" else False self.chatViewController.showMessage(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)
def __init__(self, value=None, id=None, since=None, until=None, description=None): if value is None: value = Timestamp.utc_offset() XMLStringElement.__init__(self, str(value)) self.id = id self.since = since self.until = until self.description = description
def get_policy(self, cls, obj): policy = cls(obj.pop('id', None), obj.pop('action', None)) policy.name = obj.pop('name', None) validity = obj.pop('validity', None) if validity is not None: if not isinstance(validity, list): raise ValueError( 'expected list attribute validity of policy object or nill' ) policy.validity = [(Timestamp(from_timestamp), Timestamp(until_timestamp)) for from_timestamp, until_timestamp in validity] sphere = obj.pop('sphere', None) if sphere is not None and not isinstance(sphere, basestring): raise ValueError( 'expected string attribute sphere of policy object or nill') policy.sphere = sphere multi_identity_conditions = obj.pop('multi_identity_conditions', None) if multi_identity_conditions is not None and not isinstance( multi_identity_conditions, list): raise ValueError( 'expected list attribute multi_identity_conditions of policy object or nill' ) if multi_identity_conditions is not None: policy.multi_identity_conditions = [] for multi_condition_attributes in multi_identity_conditions: if 'domain' in multi_condition_attributes: multi_condition = DomainCondition( multi_condition_attributes.pop('domain')) else: multi_condition = CatchAllCondition() policy.multi_identity_conditions.append(multi_condition) if multi_condition_attributes.get('exceptions', None): for exception_attributes in multi_condition_attributes[ 'exceptions']: if 'domain' in exception_attributes: print 'adding exception for domain' multi_condition.exceptions.append( DomainException( exception_attributes.pop('domain'))) elif 'uri' in exception_attributes: print 'adding exception for uri' multi_condition.exceptions.append( UserException(exception_attributes.pop('uri'))) return policy
def render_history_messages(self, messages): for message in messages: 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=Timestamp.parse(message.cpim_timestamp) is_html = False if message.content_type == 'text' else True self.chatViewController.showMessage(message.msgid, message.direction, message.cpim_from, icon, message.body, timestamp, recipient=message.cpim_to, state=message.status, is_html=is_html, history_entry=True)
def do_update_dialoginfo_policy(self, line): arguments = self.parse_arguments(line) policy = arguments.pop('policy', None) if not isinstance(policy, dict): raise ValueError('expected object policy') policy = self.get_dialoginfo_policy(policy) if 'validity' in arguments: validity = arguments.pop('validity') if validity is not None: if not isinstance(validity, list): raise ValueError('expected list validity or nill') validity = [(Timestamp(from_timestamp), Timestamp(until_timestamp)) for from_timestamp, until_timestamp in validity] arguments['validity'] = validity multi_identity_conditions = arguments.pop('multi_identity_conditions', None) if multi_identity_conditions is not None and not isinstance( multi_identity_conditions, list): raise ValueError('expected list multi_identity_conditions or nill') if multi_identity_conditions is not None: arguments['multi_identity_conditions'] = [] for multi_condition_attributes in multi_identity_conditions: if 'domain' in multi_condition_attributes: multi_condition = DomainCondition( multi_condition_attributes.pop('domain')) else: multi_condition = CatchAllCondition() arguments['multi_identity_conditions'].append(multi_condition) if multi_condition_attributes.get('exceptions', None): for exception_attributes in multi_condition_attributes[ 'exceptions']: if 'domain' in exception_attributes: multi_condition.exceptions.append( DomainException( exception_attributes.pop('domain'))) elif 'uri' in exception_attributes: multi_condition.exceptions.append( UserException(exception_attributes.pop('uri'))) application.xcap_manager.update_dialoginfo_policy(policy, **arguments)
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=Timestamp.parse(message.cpim_timestamp) except ValueError: pass else: is_html = False if message.content_type == 'text' else True private = True if message.private == "1" else False self.chatViewController.showMessage(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)
def addAnsweringMachineRecordingToHistory(self, filename, duration): message = "<h3>Answering Machine Recording</h3>" message += "<p>%s" % filename message += "<br>Duration: %s seconds" % duration message += "<p><audio src='%s' controls='controls'>" % urllib.quote( filename) media_type = 'voicemail' local_uri = format_identity_to_string(self.session.account) remote_uri = format_identity_to_string(self.session.remote_identity) direction = 'incoming' status = 'delivered' cpim_from = format_identity_to_string(self.session.remote_identity) cpim_to = format_identity_to_string(self.session.remote_identity) timestamp = str(Timestamp(datetime.datetime.now(tzlocal()))) self.add_to_history(media_type, local_uri, remote_uri, direction, cpim_from, cpim_to, timestamp, message, status)
def gotMessage(self, sender, message, is_html=False, state=None, timestamp=None): self.enableIsComposing = True icon = NSApp.delegate().contactsWindowController.iconPathForURI( format_identity_to_string(sender)) timestamp = timestamp or Timestamp(datetime.datetime.now(tzlocal())) hash = hashlib.sha1() hash.update(message.encode('utf-8') + str(timestamp) + str(sender)) msgid = hash.hexdigest() self.chatViewController.showMessage(msgid, 'incoming', format_identity_to_string(sender), icon, message, timestamp, is_html=is_html, state="delivered") self.notification_center.post_notification( 'ChatViewControllerDidDisplayMessage', sender=self, data=TimestampedNotificationData( 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', check_contact=True)) # save to history message = MessageInfo(msgid, direction='incoming', sender=sender, recipient=self.account, timestamp=timestamp, text=message, content_type="html" if is_html else "text", status="delivered") self.add_to_history(message)
def sendReplicationMessage(self, response_code, text, content_type="message/cpim", timestamp=None): timestamp = timestamp or datetime.datetime.now(tzlocal()) # 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) lookup = DNSLookup() settings = SIPSimpleSettings() try: routes = lookup.lookup_sip_proxy( uri, settings.sip.transport_list).wait() except DNSLookupError: pass else: utf8_encode = content_type not in ( 'application/im-iscomposing+xml', 'message/cpim') extra_headers = [ Header("X-Offline-Storage", "no"), Header("X-Replication-Code", str(response_code)), Header("X-Replication-Timestamp", str(Timestamp(datetime.datetime.now()))) ] message_request = Message( FromHeader(self.account.uri, self.account.display_name), ToHeader(self.account.uri), RouteHeader(routes[0].get_uri()), content_type, text.encode('utf-8') if utf8_encode else text, credentials=self.account.credentials, extra_headers=extra_headers) message_request.send( 15 if content_type != "application/im-iscomposing+xml" else 5)
def __str__(self): headers = [] if self.sender: headers.append(u'From: %s' % self.sender) for recipient in self.recipients: headers.append(u'To: %s' % recipient) for recipient in self.courtesy_recipients: headers.append(u'cc: %s' % recipient) if self.subject: headers.append(u'Subject: %s' % self.subject) if self.subject is not None: for lang, translation in self.subject.translations.iteritems(): headers.append(u'Subject:;lang=%s %s' % (lang, translation)) if self.timestamp: headers.append(u'DateTime: %s' % Timestamp.format(self.timestamp)) if self.required: headers.append(u'Required: %s' % ','.join(self.required)) namespaces = {u'': self.standard_namespace} for header in self.additional_headers: if namespaces.get(header.namespace.prefix, None) != header.namespace: if header.namespace.prefix: headers.append(u'NS: %s <%s>' % (header.namespace.prefix, header.namespace)) else: headers.append(u'NS: <%s>' % header.namespace) namespaces[header.namespace.prefix] = header.namespace if header.namespace.prefix: headers.append(u'%s.%s: %s' % (header.namespace.prefix, header.name, header.value)) else: headers.append(u'%s: %s' % (header.name, header.value)) headers.append(u'') headers = '\r\n'.join(s.encode('cpim-headers') for s in headers) message = Message() message.set_type(self.content_type) message.set_param('charset', 'utf-8') message.set_payload(self.body.encode('utf-8')) return headers + '\r\n' + message.as_string()
def render_history_messages(self, messages): for message in messages: 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 = Timestamp.parse(message.cpim_timestamp) is_html = False if message.content_type == 'text' else True self.chatViewController.showMessage(message.msgid, message.direction, message.cpim_from, icon, message.body, timestamp, recipient=message.cpim_to, state=message.status, is_html=is_html, history_entry=True)
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 parse(cls, string): message = cls('', None) try: headers_end = string.index('\r\n\r\n') except ValueError: raise CPIMParserError('Invalid CPIM message') else: headers = cls.headers_re.findall(buffer(string, 0, headers_end+2)) body = buffer(string, headers_end+4) namespaces = {u'': Namespace(cls.standard_namespace, u'')} subjects = {} for prefix, name, value in headers: if '.' in name: continue namespace = namespaces.get(prefix) if not namespace: continue try: value = value.decode('cpim-headers') if name == 'From' and namespace == cls.standard_namespace: message.sender = CPIMIdentity.parse(value) elif name == 'To' and namespace == cls.standard_namespace: message.recipients.append(CPIMIdentity.parse(value)) elif name == 'cc' and namespace == cls.standard_namespace: message.courtesy_recipients.append(CPIMIdentity.parse(value)) elif name == 'Subject' and namespace == cls.standard_namespace: 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' and namespace == cls.standard_namespace: message.timestamp = Timestamp.parse(value) elif name == 'Required' and namespace == cls.standard_namespace: message.required.extend(re.split(r'\s*,\s*', value)) elif name == 'NS' and namespace == cls.standard_namespace: match = cls.namespace_re.match(value) if match is None: raise ValueError('Illegal NS header: %r' % value) prefix, uri = match.groups() namespaces[prefix] = Namespace(uri, prefix) else: message.additional_headers.append(CPIMHeader(name, namespace, value)) except ValueError: pass if None in subjects: message.subject = MultilingualText(subjects.pop(None), **subjects) else: message.subject = MultilingualText(**subjects) mime_message = Parser().parsestr(body) message.content_type = mime_message.get_content_type() if message.content_type.startswith('multipart/') or message.content_type == 'message/rfc822': message.body = mime_message.get_payload() else: message.body = mime_message.get_payload().decode(mime_message.get_content_charset() or 'utf-8') if message.content_type is None: raise CPIMParserError("CPIM message missing Content-Type MIME header") return message