def start(self, restart=False): self.ft_info = FileTransferInfo( transfer_id=self.transfer_id, direction='outgoing', file_size=self.file_size, local_uri=format_identity_to_string(self.account) if self.account is not BonjourAccount() else 'bonjour', remote_uri=self.remote_identity, file_path=self.file_path) self.ft_info.status = "pending" self.status = "Pending" notification_center = NotificationCenter() if restart: notification_center.post_notification( "BlinkFileTransferRestarting", self, data=TimestampedNotificationData()) else: notification_center.post_notification( "BlinkFileTransferInitializing", self, data=TimestampedNotificationData()) BlinkLogger().log_info(u"Computing checksum for file %s" % os.path.basename(self.file_path)) self.stop_event.clear() self.initiate_file_transfer()
def _NH_SIPSessionDidEnd(self, sender, data): self.log_info(u"File Transfer Session ended by %s" % data.originator) notification_center = NotificationCenter() self.end_time = datetime.datetime.now() if not self.finished_transfer: self.fail_reason = "Interrupted" self.ft_info.status = "failed" self.ft_info.bytes_transfered = self.file_pos self.status = "%s %s %s" % (str(format_size( self.file_pos, 1024)), unichr(0x2014), self.fail_reason) notification_center.post_notification( "BlinkFileTransferDidFail", sender=self, data=TimestampedNotificationData()) else: self.ft_info.status = "completed" self.ft_info.bytes_transfered = self.file_size self.status = "Completed in %s %s %s" % ( format_duration(self.end_time - self.start_time), unichr(0x2014), format_size(self.file_size)) notification_center.post_notification( "BlinkFileTransferDidEnd", sender=self, data=TimestampedNotificationData(file_path=self.file_path)) self.file_selector.fd.close() self.file_selector = None
def _NH_SIPRequestDidSucceed(self, notification): request = notification.sender notification_center = NotificationCenter() with self._lock: if request is not self._current_request: return self._current_request = None if self._unregistering: if self._last_request is not None: self._last_request.end() self._last_request = None notification_center.post_notification( "SIPRegistrationDidEnd", sender=self, data=TimestampedNotificationData(expired=False)) else: self._last_request = request try: contact_header_list = notification.data.headers["Contact"] except KeyError: contact_header_list = [] notification_center.post_notification( "SIPRegistrationDidSucceed", sender=self, data=TimestampedNotificationData( code=notification.data.code, reason=notification.data.reason, contact_header=request.contact_header, contact_header_list=contact_header_list, expires_in=notification.data.expires, route_header=request.route_header))
def _NH_SIPRequestDidSucceed(self, notification): request = notification.sender notification_center = NotificationCenter() with self._lock: if request is not self._current_request: return self._current_request = None if self._unpublishing: if self._last_request is not None: self._last_request.end() self._last_request = None self._last_etag = None notification_center.post_notification( "SIPPublicationDidEnd", sender=self, data=TimestampedNotificationData(expired=False)) else: self._last_request = request self._last_etag = notification.data.headers[ "SIP-ETag"].body if "SIP-ETag" in notification.data.headers else None # TODO: add more data? notification_center.post_notification( "SIPPublicationDidSucceed", sender=self, data=TimestampedNotificationData( code=notification.data.code, reason=notification.data.reason, expires_in=notification.data.expires, route_header=request.route_header))
def _resolve_cb(self, file, flags, interface_index, error_code, fullname, host_target, port, txtrecord): notification_center = NotificationCenter() settings = SIPSimpleSettings() file = BonjourResolutionFile.find_by_file(file) if error_code == bonjour.kDNSServiceErr_NoError: txt = bonjour.TXTRecord.parse(txtrecord) name = txt['name'].decode('utf-8') if 'name' in txt else None host = re.match(r'^(.*?)(\.local)?\.?$', host_target).group(1) contact = txt.get('contact', file.service_description.name).split( None, 1)[0].strip('<>') try: uri = FrozenSIPURI.parse(contact) except SIPCoreError: pass else: account = BonjourAccount() service_description = file.service_description transport = uri.transport supported_transport = transport in settings.sip.transport_list and ( transport != 'tls' or account.tls.certificate is not None) if not supported_transport and service_description in self._servers: del self._servers[service_description] notification_center.post_notification( 'BonjourConferenceServicesDidRemoveServer', sender=self, data=TimestampedNotificationData( server=service_description)) elif supported_transport: try: contact_uri = account.contact[transport] except KeyError: return if uri != contact_uri: notification_name = 'BonjourConferenceServicesDidUpdateServer' if service_description in self._servers else 'BonjourConferenceServicesDidAddServer' notification_data = TimestampedNotificationData( server=service_description, name=name, host=host, uri=uri) server_description = BonjourConferenceServerDescription( uri, host, name) self._servers[service_description] = server_description notification_center.post_notification( notification_name, sender=self, data=notification_data) else: self._files.remove(file) self._select_proc.kill(RestartSelect) file.close() error = bonjour.BonjourError(error_code) notification_center.post_notification( 'BonjourConferenceServicesDiscoveryFailure', sender=self, data=TimestampedNotificationData(error=str(error), transport=file.transport))
def _CH_discover(self, command): notification_center = NotificationCenter() settings = SIPSimpleSettings() if self._discover_timer is not None and self._discover_timer.active(): self._discover_timer.cancel() self._discover_timer = None account = BonjourAccount() supported_transports = set( transport for transport in settings.sip.transport_list if transport != 'tls' or account.tls.certificate is not None) discoverable_transports = set( 'tcp' if transport == 'tls' else transport for transport in supported_transports) old_files = [] for file in ( f for f in self._files[:] if isinstance(f, (BonjourDiscoveryFile, BonjourResolutionFile)) and f.transport not in discoverable_transports): old_files.append(file) self._files.remove(file) self._select_proc.kill(RestartSelect) for file in old_files: file.close() for service_description in [ service for service, description in self._servers.iteritems() if description.uri.transport not in supported_transports ]: del self._servers[service_description] notification_center.post_notification( 'BonjourConferenceServicesDidRemoveServer', sender=self, data=TimestampedNotificationData(server=service_description)) discovered_transports = set(file.transport for file in self._files if isinstance(file, BonjourDiscoveryFile)) missing_transports = discoverable_transports - discovered_transports added_transports = set() for transport in missing_transports: notification_center.post_notification( 'BonjourConferenceServicesWillInitiateDiscovery', sender=self, data=TimestampedNotificationData(transport=transport)) try: file = bonjour.DNSServiceBrowse(regtype="_sipfocus._%s" % transport, callBack=self._browse_cb) except bonjour.BonjourError, e: notification_center.post_notification( 'BonjourConferenceServicesDiscoveryDidFail', sender=self, data=TimestampedNotificationData(reason=str(e), transport=transport)) else: self._files.append(BonjourDiscoveryFile(file, transport)) added_transports.add(transport)
def _browse_cb(self, file, flags, interface_index, error_code, service_name, regtype, reply_domain): notification_center = NotificationCenter() file = BonjourDiscoveryFile.find_by_file(file) service_description = BonjourServiceDescription( service_name, regtype, reply_domain) if error_code != bonjour.kDNSServiceErr_NoError: error = bonjour.BonjourError(error_code) notification_center.post_notification( 'BonjourConferenceServicesDiscoveryDidFail', sender=self, data=TimestampedNotificationData(reason=str(error), transport=file.transport)) removed_files = [file] + [ f for f in self._files if isinstance(f, BonjourResolutionFile) and f.discovery_file == file ] for f in removed_files: self._files.remove(f) self._select_proc.kill(RestartSelect) for f in removed_files: f.close() if self._discover_timer is None: self._discover_timer = reactor.callLater( 1, self._command_channel.send, Command('discover')) return if reply_domain != 'local.': return if flags & bonjour.kDNSServiceFlagsAdd: try: resolution_file = ( f for f in self._files if isinstance(f, BonjourResolutionFile) and f.discovery_file == file and f.service_description == service_description).next() except StopIteration: try: resolution_file = bonjour.DNSServiceResolve( 0, interface_index, service_name, regtype, reply_domain, self._resolve_cb) except bonjour.BonjourError, e: notification_center.post_notification( 'BonjourConferenceServicesDiscoveryFailure', sender=self, data=TimestampedNotificationData( error=str(e), transport=file.transport)) else: resolution_file = BonjourResolutionFile( resolution_file, discovery_file=file, service_description=service_description) self._files.append(resolution_file) self._select_proc.kill(RestartSelect)
def _NH_SIPAccountMWIDidGetSummary(self, account, data): BlinkLogger().log_info(u"Received NOTIFY for MWI of account %s" % account.id) summary = data.message_summary if summary.summaries.get('voice-message') is None: return voice_messages = summary.summaries['voice-message'] growl_data = TimestampedNotificationData() growl_data.new_messages = int(voice_messages['new_messages']) growl_data.old_messages = int(voice_messages['old_messages']) MWIData.store(account, summary) if summary.messages_waiting and growl_data.new_messages > 0: self.notification_center.post_notification("GrowlGotMWI", sender=self, data=growl_data)
def _lookup_a_records(self, resolver, hostnames, additional_records=[], log_context={}): notification_center = NotificationCenter() additional_addresses = dict((rset.name.to_text(), rset) for rset in additional_records if rset.rdtype == rdatatype.A) addresses = {} for hostname in hostnames: if hostname in additional_addresses: addresses[hostname] = [ r.address for r in additional_addresses[hostname] ] else: try: answer = resolver.query(hostname, rdatatype.A) except dns.resolver.Timeout, e: notification_center.post_notification( 'DNSLookupTrace', sender=self, data=TimestampedNotificationData( query_type='A', query_name=str(hostname), answer=None, error=e, **log_context)) raise except exception.DNSException, e: notification_center.post_notification( 'DNSLookupTrace', sender=self, data=TimestampedNotificationData( query_type='A', query_name=str(hostname), answer=None, error=e, **log_context)) addresses[hostname] = [] else: notification_center.post_notification( 'DNSLookupTrace', sender=self, data=TimestampedNotificationData( query_type='A', query_name=str(hostname), answer=answer, error=None, **log_context)) addresses[hostname] = [r.address for r in answer.rrset]
def _NH_OutgoingPullFileTransferHandlerDidEnd(self, sender, data): notification_center = NotificationCenter() if not self.finished_transfer: self.log_info(u"Removing incomplete file %s" % self.file_path) os.remove(self.file_path) self.fail_reason = "Interrupted" else: local_hash = 'sha1:' + ':'.join( re.findall(r'..', self.hash.hexdigest())) remote_hash = self.file_selector.hash.lower() if local_hash == remote_hash: oname = self.file_path self.file_path = self.file_path[:-len(".download")] self.ft_info.file_path = self.file_path self.log_info(u"Renaming downloaded file to %s" % self.file_path) os.rename(oname, self.file_path) else: self.error = True self.fail_reason = "File hash mismatch" self.log_info(u"Removing corrupted file %s" % self.file_path) os.remove(self.file_path) self.log_info( "Incoming File Transfer ended (%i of %i bytes transferred)" % (self.file_pos, self.file_size)) self.end_time = datetime.datetime.now() if self.finished_transfer and not self.error: self.status = "Completed in %s %s %s" % ( format_duration(self.end_time - self.start_time), unichr(0x2014), format_size(self.file_size)) self.ft_info.status = "completed" self.ft_info.bytes_transfered = self.file_size notification_center.post_notification( "BlinkFileTransferDidEnd", sender=self, data=TimestampedNotificationData(file_path=self.file_path)) else: self.status = self.fail_reason self.ft_info.status = "failed" self.ft_info.bytes_transfered = self.file_pos notification_center.post_notification( "BlinkFileTransferDidFail", sender=self, data=TimestampedNotificationData())
def _NH_SIPSessionWillStart(self, sender, data): self.status = "Starting File Transfer..." notification_center = NotificationCenter() notification_center.post_notification( "BlinkFileTransferUpdate", sender=self, data=TimestampedNotificationData())
def update_transfer_rate(self): if self.last_rate_time > 0: if time.time() - self.last_rate_time >= 1: dt = time.time() - self.last_rate_time db = self.file_pos - self.last_rate_pos transfer_rate = int(db / dt) self.rate_history.append(transfer_rate) while len(self.rate_history) > 5: del self.rate_history[0] self.last_rate_time = time.time() self.last_rate_pos = self.file_pos self.transfer_rate = sum(self.rate_history) / len( self.rate_history) else: self.last_rate_time = time.time() self.last_rate_pos = self.file_pos self.rate_history = [] notification_center = NotificationCenter() notification_center.post_notification( "BlinkFileTransferSpeedDidUpdate", sender=self, data=TimestampedNotificationData())
def save(self): """ Use the ConfigurationManager to store the object under its id in the specified group or top-level otherwise, depending on whether group is None. This method will also post a CFGSettingsObjectDidChange notification, regardless of whether the settings have been saved to persistent storage or not. If the save does fail, a CFGManagerSaveFailed notification is posted as well. """ modified_settings = self.get_modified() id_descriptor = self.__class__.__id__ if isinstance( self.__class__.__id__, SettingsObjectID) else None if not modified_settings and not (id_descriptor and id_descriptor.isdirty(self)): return configuration = ConfigurationManager() notification_center = NotificationCenter() if id_descriptor and id_descriptor.isdirty(self): old = id_descriptor.get_old(self) new = self.__id__ configuration.rename(self.__group__, old, new) notification_center.post_notification( 'CFGSettingsObjectDidChangeID', sender=self, data=TimestampedNotificationData(old_id=old, new_id=new)) if modified_settings: notification_center.post_notification( 'CFGSettingsObjectDidChange', sender=self, data=TimestampedNotificationData(modified=modified_settings)) configuration.update(self.__group__, self.__id__, self.__getstate__()) try: configuration.save() except Exception, e: import traceback traceback.print_exc() notification_center.post_notification( 'CFGManagerSaveFailed', sender=configuration, data=TimestampedNotificationData(object=self, modified=modified_settings, exception=e))
def _NH_SIPRequestDidFail(self, notification): with self._lock: NotificationCenter().post_notification( "SIPMessageDidFail", sender=self, data=TimestampedNotificationData( code=notification.data.code, reason=notification.data.reason))
def collaborativeEditorisTyping(self): self.editor_has_changed = True self.delegate.resetIsComposingTimer(5) NotificationCenter().post_notification( "BlinkColaborativeEditorContentHasChanged", sender=self, data=TimestampedNotificationData())
def lookup_xcap_server(self, uri, timeout=3.0, lifetime=15.0): """ Performs a TXT query against xcap.<uri.host> and returns all results that look like HTTP URIs. """ log_context = dict(context='lookup_xcap_server', uri=uri) notification_center = NotificationCenter() try: resolver = DNSResolver() resolver.cache = self.cache resolver.timeout = timeout resolver.lifetime = lifetime # If the host part of the URI is an IP address, we cannot not do any lookup if re.match("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", uri.host): raise DNSLookupError( "Cannot perform DNS query because the host is an IP address" ) record_name = 'xcap.%s' % uri.host results = [] try: answer = resolver.query(record_name, rdatatype.TXT) except dns.resolver.Timeout, e: notification_center.post_notification( 'DNSLookupTrace', sender=self, data=TimestampedNotificationData( query_type='TXT', query_name=str(record_name), answer=None, error=e, **log_context)) raise except exception.DNSException, e: notification_center.post_notification( 'DNSLookupTrace', sender=self, data=TimestampedNotificationData( query_type='TXT', query_name=str(record_name), answer=None, error=e, **log_context))
def _NH_SIPRequestWillExpire(self, notification): with self._lock: if notification.sender is not self._last_request: return NotificationCenter().post_notification( "SIPPublicationWillExpire", sender=self, data=TimestampedNotificationData( expires=notification.data.expires))
def end(self, timeout=None): with self._lock: if self._last_request is None: return NotificationCenter().post_notification( "SIPRegistrationWillEnd", sender=self, data=TimestampedNotificationData()) try: self._make_and_send_request( ContactHeader.new(self._last_request.contact_header), RouteHeader.new(self._last_request.route_header), timeout, False) except SIPCoreError, e: NotificationCenter().post_notification( "SIPRegistrationDidNotEnd", sender=self, data=TimestampedNotificationData(code=0, reason=e.args[0]))
def start(self): notification_center = NotificationCenter() settings = SIPSimpleSettings() download_folder = unicodedata.normalize( 'NFC', NSSearchPathForDirectoriesInDomains(NSDownloadsDirectory, NSUserDomainMask, True)[0]) for name in self.filename_generator( os.path.join(download_folder, self.file_name)): if not os.path.exists(name) and not os.path.exists(name + ".download"): self.file_path = name + '.download' break self.ft_info = FileTransferInfo( transfer_id=self.transfer_id, direction='incoming', local_uri=format_identity_to_string(self.account) if self.account is not BonjourAccount() else 'bonjour', file_size=self.file_size, remote_uri=self.remote_identity, file_path=self.file_path) BlinkLogger().log_info(u"Will write file to %s" % self.file_path) self.file_selector.fd = open(self.file_path, "w+") self.ft_info.status = "preparing" self.status = "Accepting File Transfer..." notification_center.add_observer(self, sender=self) notification_center.add_observer(self, sender=self.session) notification_center.add_observer(self, sender=self.stream) BlinkLogger().log_info("Initiating Incoming File Transfer") notification_center.post_notification( "BlinkFileTransferInitializing", self, data=TimestampedNotificationData()) notification_center.post_notification( "BlinkFileTransferInitiated", self, data=TimestampedNotificationData())
def __setstate__(self, state): for name, value in state.iteritems(): attribute = getattr(self.__class__, name, None) if isinstance(attribute, SettingsGroupMeta): group = getattr(self, name) try: group.__setstate__(value) except ValueError, e: configuration_manager = ConfigurationManager() notification_center = NotificationCenter() notification_center.post_notification( 'CFGManagerLoadFailed', sender=configuration_manager, data=TimestampedNotificationData(attribute=name, container=self, error=e)) elif isinstance(attribute, Setting): try: if value is None: pass elif issubclass(attribute.type, bool): if value.lower() in ('true', 'yes', 'on', '1'): value = True elif value.lower() in ('false', 'no', 'off', '0'): value = False else: raise ValueError("invalid boolean value: %s" % (value, )) elif issubclass(attribute.type, (int, long, basestring)): value = attribute.type(value) else: object = attribute.type.__new__(attribute.type) object.__setstate__(value) value = object setattr(self, name, value) except ValueError, e: configuration_manager = ConfigurationManager() notification_center = NotificationCenter() notification_center.post_notification( 'CFGManagerLoadFailed', sender=configuration_manager, data=TimestampedNotificationData(attribute=name, container=self, error=e))
def wrapper(obj, *args, **kwargs): notification_center = NotificationCenter() try: result = func(obj, *args, **kwargs) except DNSLookupError, e: notification_center.post_notification( 'DNSLookupDidFail', sender=obj, data=TimestampedNotificationData(error=str(e))) raise
def _NH_FileTransferStreamDidDeliverChunk(self, sender, data): self.file_pos = data.transferred_bytes self.update_transfer_rate() self.status = self.format_progress() notification_center = NotificationCenter() notification_center.post_notification( "BlinkFileTransferUpdate", sender=self, data=TimestampedNotificationData())
def initiate_file_transfer(self): notification_center = NotificationCenter() notification_center.add_observer(self, sender=self) self.file_selector = FileSelector.for_file( self.file_path.encode('utf-8'), hash=None) self.ft_info.file_size = self.file_size # compute the file hash first self.ft_info.status = "preparing" self.status = "Computing checksum..." hash = hashlib.sha1() pos = progress = 0 chunk_size = limit(self.file_selector.size / 100, min=65536, max=1048576) notification_center.post_notification( 'BlinkFileTransferHashUpdate', sender=self, data=TimestampedNotificationData(progress=0)) while not self.stop_event.isSet(): content = self.file_selector.fd.read(chunk_size) if not content: break hash.update(content) pos += len(content) old_progress, progress = progress, int( float(pos) / self.file_selector.size * 100) if old_progress != progress: notification_center.post_notification( 'BlinkFileTransferHashUpdate', sender=self, data=TimestampedNotificationData(progress=progress)) else: notification_center.post_notification( 'BlinkFileTransferDidNotComputeHash', sender=self) return self.file_selector.fd.seek(0) self.file_selector.hash = hash notification_center.post_notification( 'BlinkFileTransferDidComputeHash', sender=self, data=TimestampedNotificationData())
def _NH_SIPRequestDidSucceed(self, notification): with self._lock: if notification.data.expires: # this shouldn't happen really notification.sender.end() NotificationCenter().post_notification( "SIPMessageDidSucceed", sender=self, data=TimestampedNotificationData( code=notification.data.code, reason=notification.data.reason))
def end(self, timeout=None): with self._lock: if self._last_request is None: raise PublicationError("Nothing is currently published") self._make_and_send_request( None, RouteHeader.new(self._last_request.route_header), timeout, False) NotificationCenter().post_notification( "SIPPublicationWillEnd", sender=self, data=TimestampedNotificationData())
def register(self, contact_header, route_header, timeout=None): with self._lock: try: self._make_and_send_request(contact_header, route_header, timeout, True) except SIPCoreError, e: NotificationCenter().post_notification( "SIPRegistrationDidFail", sender=self, data=TimestampedNotificationData( code=0, reason=e.args[0], route_header=route_header))
def _NH_MediaStreamDidStart(self, sender, data): self.log_info("Receiving File...") self.status = format_size(self.file_pos, 1024) self.ft_info.status = "transfering" self.started = True self.start_time = datetime.datetime.now() notification_center = NotificationCenter() notification_center.post_notification( "BlinkFileTransferDidStart", sender=self, data=TimestampedNotificationData())
def _NH_DNSLookupDidSucceed(self, sender, data): notification_center = NotificationCenter() notification_center.remove_observer(self, sender=sender) if self.interrupted: notification_center.post_notification( "BlinkFileTransferDidFail", sender=self, data=TimestampedNotificationData()) return self.session.connect(ToHeader(self.target_uri), data.result, [self.stream])
def _NH_BlinkFileTransferDidNotComputeHash(self, sender, data): self.file_selector.fd.close() self.file_selector = None self.status = "Interrupted" self.ft_info.status = "interrupted" notification_center = NotificationCenter() notification_center.post_notification( "BlinkFileTransferDidFail", sender=self, data=TimestampedNotificationData())
def write_chunk(self, data): notification_center = NotificationCenter() if data is not None: try: self.file_selector.fd.write(data) except EnvironmentError, e: notification_center.post_notification( 'OutgoingPullFileTransferHandlerGotError', sender=self, data=TimestampedNotificationData(error=str(e))) else: self.hash.update(data)
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)