def _NH_SIPAccountGotSelfPresenceState(self, notification): pidf_doc = notification.data.pidf services = [service for service in pidf_doc.services if service.status.extended is not None] if not services: return blink_settings = BlinkSettings() services.sort(key=lambda obj: obj.timestamp.value if obj.timestamp else epoch, reverse=True) service = services[0] if service.id in ('SID-%s' % uuid.UUID(SIPSimpleSettings().instance_id), 'SID-%s' % hashlib.md5(notification.sender.id).hexdigest()): # Our current state is the winning one return status = str(service.status.extended).title() note = None if not service.notes else str(list(service.notes)[0]) if status == 'Offline': status = 'Invisible' note = None new_state = PresenceState(status, note) blink_settings.presence.current_state = new_state if new_state.note: try: next(state for state in blink_settings.presence.state_history if state == new_state) except StopIteration: blink_settings.presence.state_history = [new_state] + blink_settings.presence.state_history else: blink_settings.presence.state_history = [new_state] + [state for state in blink_settings.presence.state_history if state != new_state] blink_settings.save()
def _NH_SIPAccountGotSelfPresenceState(self, notification): pidf_doc = notification.data.pidf services = [service for service in pidf_doc.services if service.status.extended is not None] if not services: return blink_settings = BlinkSettings() services.sort(key=lambda obj: obj.timestamp.value if obj.timestamp else epoch, reverse=True) service = services[0] if service.id in ('SID-%s' % uuid.UUID(SIPSimpleSettings().instance_id), 'SID-%s' % hashlib.md5(notification.sender.id).hexdigest()): # Our current state is the winning one return status = unicode(service.status.extended).title() note = None if not service.notes else unicode(list(service.notes)[0]) if status == 'Offline': status = 'Invisible' note = None new_state = PresenceState(status, note) blink_settings.presence.current_state = new_state if new_state.note: try: next(state for state in blink_settings.presence.state_history if state==new_state) except StopIteration: blink_settings.presence.state_history = [new_state] + blink_settings.presence.state_history else: blink_settings.presence.state_history = [new_state] + [state for state in blink_settings.presence.state_history if state!=new_state] blink_settings.save()
def _SH_AccountStateChanged(self): self.activity_note.setText(self.account_state.note) if self.account_state.state is AccountState.Invisible: self.activity_note.inactiveText = '(invisible)' self.activity_note.setEnabled(False) else: if not self.activity_note.isEnabled(): self.activity_note.inactiveText = 'Add an activity note here' self.activity_note.setEnabled(True) if not self.account_state.state.internal: self.saved_account_state = None blink_settings = BlinkSettings() blink_settings.presence.current_state = PresenceState(self.account_state.state, self.account_state.note) blink_settings.presence.state_history = [PresenceState(state, note) for state, note in self.account_state.history] blink_settings.save()
def _SH_AccountStateChanged(self): self.activity_note.setText(self.account_state.note) if self.account_state.state is AccountState.Invisible: self.activity_note.inactiveText = u'(invisible)' self.activity_note.setEnabled(False) else: if not self.activity_note.isEnabled(): self.activity_note.inactiveText = u'Add an activity note here' self.activity_note.setEnabled(True) if not self.account_state.state.internal: self.saved_account_state = None blink_settings = BlinkSettings() blink_settings.presence.current_state = PresenceState(self.account_state.state, self.account_state.note) blink_settings.presence.state_history = [PresenceState(state, note) for state, note in self.account_state.history] blink_settings.save()
def _NH_CFGSettingsObjectDidChange(self, notification): if notification.sender is BlinkSettings(): account_manager = AccountManager() if 'presence.offline_note' in notification.data.modified: for account in (account for account in account_manager.get_accounts() if account.xcap.discovered): state = BlinkPresenceState(account).offline_state account.xcap_manager.set_offline_status(OfflineStatus(state) if state is not None else None) if 'presence.icon' in notification.data.modified: icon = IconManager().get('avatar') status_icon = Icon(icon.content, icon.content_type) if icon is not None else None for account in (account for account in account_manager.get_accounts() if account.xcap.discovered): account.xcap_manager.set_status_icon(status_icon) if 'presence.current_state' in notification.data.modified: for account in (account for account in account_manager.get_accounts() if account.enabled and account.presence.enabled): account.presence_state = BlinkPresenceState(account).online_state else: account = notification.sender if {'xcap.enabled', 'xcap.xcap_root'}.intersection(notification.data.modified): account.xcap.icon = None account.save() elif {'presence.enabled', 'display_name', 'xcap.icon'}.intersection(notification.data.modified) and account.presence.enabled: account.presence_state = BlinkPresenceState(account).online_state if account.xcap.discovered and (set(notification.data.modified) != {'xcap.icon'} or account.id in self._should_set_offline_status): state = BlinkPresenceState(account).offline_state account.xcap_manager.set_offline_status(OfflineStatus(state) if state is not None else None) if account.id in self._should_set_offline_status: # do not use set.discard() here to avoid race conditions. it should only be removed if present. self._should_set_offline_status.remove(account.id)
def stop(self): notification_center = NotificationCenter() notification_center.remove_observer(self, name='SIPAccountWillActivate') notification_center.remove_observer(self, name='SIPAccountWillDeactivate') notification_center.remove_observer(self, name='SIPAccountDidDiscoverXCAPSupport') notification_center.remove_observer(self, name='XCAPManagerDidReloadData') notification_center.remove_observer(self, sender=BlinkSettings(), name='CFGSettingsObjectDidChange')
def text(self): result = str(self.name or self.uri) blink_settings = BlinkSettings() if blink_settings.interface.show_history_name_and_uri: result = f'{str(self.name)} ({str(self.uri)})' if self.call_time: call_time = self.call_time.astimezone(tzlocal()) call_date = call_time.date() today = date.today() days = (today - call_date).days if call_date == today: result += call_time.strftime(" at %H:%M") elif days == 1: result += call_time.strftime(" Yesterday at %H:%M") elif days < 7: result += call_time.strftime(" on %A") elif call_date.year == today.year: result += call_time.strftime(" on %B %d") else: result += call_time.strftime(" on %Y-%m-%d") if self.duration: seconds = int(self.duration.total_seconds()) if seconds >= 3600: result += """ (%dh%02d'%02d")""" % (seconds / 3600, (seconds % 3600) / 60, seconds % 60) else: result += """ (%d'%02d")""" % (seconds / 60, seconds % 60) elif self.reason: result += ' (%s)' % self.reason.title() return result
def offline_state(self): if self.account is BonjourAccount(): return None blink_settings = BlinkSettings() account_id = hashlib.md5(self.account.id.encode()).hexdigest() timestamp = ISOTimestamp.now() doc = pidf.PIDF(str(self.account.uri)) person = pidf.Person('PID-%s' % account_id) person.timestamp = timestamp person.activities = rpid.Activities() person.activities.add('offline') doc.add(person) service = pidf.Service('SID-%s' % account_id) service.status = 'closed' service.status.extended = 'offline' service.contact = str(self.account.uri) service.timestamp = timestamp service.capabilities = caps.ServiceCapabilities() service.display_name = self.account.display_name or None service.icon = "%s#blink-icon%s" % ( self.account.xcap.icon.url, self.account.xcap.icon.etag ) if self.account.xcap.icon is not None else None if blink_settings.presence.offline_note: service.notes.add(blink_settings.presence.offline_note) doc.add(service) return doc
def show(self, activate=True): settings = BlinkSettings() makedirs(settings.transfers_directory.normalized) self.setAttribute(Qt.WA_ShowWithoutActivating, not activate) super(FileTransferWindow, self).show() self.raise_() if activate: self.activateWindow()
def filename_generator(cls): settings = BlinkSettings() name = os.path.join( settings.screenshots_directory.normalized, 'ScreenSharing-{:%Y%m%d-%H.%M.%S}'.format(datetime.now())) yield '%s.png' % name for x in count(1): yield "%s-%d.png" % (name, x)
def _NH_CFGSettingsObjectDidChange(self, notification): settings = SIPSimpleSettings() blink_settings = BlinkSettings() icon_manager = IconManager() if notification.sender is settings: if 'audio.muted' in notification.data.modified: self.mute_action.setChecked(settings.audio.muted) self.mute_button.setChecked(settings.audio.muted) if 'audio.silent' in notification.data.modified: self.silent_action.setChecked(settings.audio.silent) self.silent_button.setChecked(settings.audio.silent) if 'audio.output_device' in notification.data.modified: action = (action for action in self.output_devices_group.actions() if action.data() == settings.audio.output_device).next() action.setChecked(True) if 'audio.input_device' in notification.data.modified: action = (action for action in self.input_devices_group.actions() if action.data() == settings.audio.input_device).next() action.setChecked(True) if 'audio.alert_device' in notification.data.modified: action = (action for action in self.alert_devices_group.actions() if action.data() == settings.audio.alert_device).next() action.setChecked(True) if 'video.device' in notification.data.modified: action = (action for action in self.video_devices_group.actions() if action.data() == settings.video.device).next() action.setChecked(True) if 'answering_machine.enabled' in notification.data.modified: self.answering_machine_action.setChecked(settings.answering_machine.enabled) if 'chat.auto_accept' in notification.data.modified: self.auto_accept_chat_action.setChecked(settings.chat.auto_accept) if 'sounds.play_message_alerts' in notification.data.modified: self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts) if 'google_contacts.authorization_token' in notification.data.modified: authorization_token = notification.sender.google_contacts.authorization_token if authorization_token is None: self.google_contacts_action.setText(u'Enable &Google Contacts...') else: self.google_contacts_action.setText(u'Disable &Google Contacts') if authorization_token is InvalidToken: self.google_contacts_dialog.open_for_incorrect_password() elif notification.sender is blink_settings: if 'presence.current_state' in notification.data.modified: state = getattr(AccountState, blink_settings.presence.current_state.state, AccountState.Available) self.account_state.setState(state, blink_settings.presence.current_state.note) if 'presence.icon' in notification.data.modified: self.set_user_icon(icon_manager.get('avatar')) if 'presence.offline_note' in notification.data.modified: # TODO: set offline note -Saul pass elif isinstance(notification.sender, (Account, BonjourAccount)): account_manager = AccountManager() account = notification.sender if 'enabled' in notification.data.modified: action = (action for action in self.accounts_menu.actions() if action.data() is account).next() action.setChecked(account.enabled) if 'display_name' in notification.data.modified and account is account_manager.default_account: self.display_name.setText(account.display_name or u'') if set(['enabled', 'message_summary.enabled', 'message_summary.voicemail_uri']).intersection(notification.data.modified): action = (action for action in self.voicemail_menu.actions() if action.data() is account).next() action.setVisible(False if account is BonjourAccount() else account.enabled and account.message_summary.enabled) action.setEnabled(False if account is BonjourAccount() else account.voicemail_uri is not None)
def _NH_XCAPManagerDidReloadData(self, notification): account = notification.sender.account blink_settings = BlinkSettings() icon_manager = IconManager() offline_status = notification.data.offline_status status_icon = notification.data.status_icon try: offline_note = next(note for service in offline_status.pidf.services for note in service.notes) except (AttributeError, StopIteration): offline_note = None blink_settings.presence.offline_note = offline_note blink_settings.save() if status_icon: icon_hash = hashlib.sha1(status_icon.data).hexdigest() icon_desc = IconDescriptor(status_icon.url, icon_hash) if not blink_settings.presence.icon or blink_settings.presence.icon.etag != icon_hash: icon = icon_manager.store_data('avatar', status_icon.data) blink_settings.presence.icon = IconDescriptor(FileURL(icon.filename), icon_hash) if icon is not None else None blink_settings.save() else: icon_desc = None icon_manager.remove('avatar') blink_settings.presence.icon = None blink_settings.save() account.xcap.icon = icon_desc account.save()
def _SH_AccountStateClicked(self, checked): filename = QFileDialog.getOpenFileName(self, u'Select Icon', self.last_icon_directory, u"Images (*.png *.tiff *.jpg *.xmp *.svg)") if filename: self.last_icon_directory = os.path.dirname(filename) filename = filename if os.path.realpath(filename) != os.path.realpath(self.default_icon_path) else None blink_settings = BlinkSettings() icon_manager = IconManager() if filename is not None: icon = icon_manager.store_file('avatar', filename) if icon is not None: blink_settings.presence.icon = IconDescriptor(FileURL(icon.filename), hashlib.sha1(icon.content).hexdigest()) else: icon_manager.remove('avatar') blink_settings.presence.icon = None else: icon_manager.remove('avatar') blink_settings.presence.icon = None blink_settings.save()
def _SH_AccountStateClicked(self, checked): filename = QFileDialog.getOpenFileName(self, 'Select Icon', self.last_icon_directory, "Images (*.png *.tiff *.jpg *.xmp *.svg)")[0] if filename: self.last_icon_directory = os.path.dirname(filename) filename = filename if os.path.realpath(filename) != os.path.realpath(self.default_icon_path) else None blink_settings = BlinkSettings() icon_manager = IconManager() if filename is not None: icon = icon_manager.store_file('avatar', filename) if icon is not None: blink_settings.presence.icon = IconDescriptor(FileURL(icon.filename), hashlib.sha1(icon.content).hexdigest()) else: icon_manager.remove('avatar') blink_settings.presence.icon = None else: icon_manager.remove('avatar') blink_settings.presence.icon = None blink_settings.save()
def _NH_SIPApplicationDidStart(self, notification): self.load_audio_devices() self.load_video_devices() notification.center.add_observer(self, name='CFGSettingsObjectDidChange') notification.center.add_observer(self, name='AudioDevicesDidChange') blink_settings = BlinkSettings() self.account_state.history = [(item.state, item.note) for item in blink_settings.presence.state_history] state = getattr(AccountState, blink_settings.presence.current_state.state, AccountState.Available) self.account_state.setState(state, blink_settings.presence.current_state.note)
def _NH_XCAPManagerDidReloadData(self, notification): account = notification.sender.account blink_settings = BlinkSettings() icon_manager = IconManager() offline_status = notification.data.offline_status status_icon = notification.data.status_icon try: offline_note = next(note for service in offline_status.pidf.services for note in service.notes) except (AttributeError, StopIteration): offline_note = None blink_settings.presence.offline_note = offline_note blink_settings.save() try: offline_icon = next(service.icon for service in offline_status.pidf.services) except (AttributeError, StopIteration): offline_icon_hash = None else: offline_icon_hash = str(offline_icon).partition( '#blink-icon')[2] or None if status_icon: icon_hash = hashlib.sha1(status_icon.data).hexdigest() icon_desc = IconDescriptor(status_icon.url, icon_hash) if not blink_settings.presence.icon or blink_settings.presence.icon.etag != icon_hash: icon = icon_manager.store_data('avatar', status_icon.data) blink_settings.presence.icon = IconDescriptor( FileURL(icon.filename), icon_hash) if icon is not None else None blink_settings.save() elif account.xcap.icon != icon_desc and icon_hash != offline_icon_hash: self._should_set_offline_status.add(account.id) else: if blink_settings.presence.icon is None is not account.xcap.icon: self._should_set_offline_status.add(account.id) elif blink_settings.presence.icon is account.xcap.icon is offline_status is None and account.xcap_manager.pidf_manipulation.supported: state = BlinkPresenceState(account).offline_state account.xcap_manager.set_offline_status( OfflineStatus(state) if state is not None else None) icon_desc = None icon_manager.remove('avatar') blink_settings.presence.icon = None blink_settings.save() account.xcap.icon = icon_desc account.save()
def _NH_XCAPManagerDidReloadData(self, notification): account = notification.sender.account blink_settings = BlinkSettings() icon_manager = IconManager() offline_status = notification.data.offline_status status_icon = notification.data.status_icon try: offline_note = next(note for service in offline_status.pidf.services for note in service.notes) except (AttributeError, StopIteration): offline_note = None blink_settings.presence.offline_note = offline_note blink_settings.save() try: offline_icon = next(service.icon for service in offline_status.pidf.services) except (AttributeError, StopIteration): offline_icon_hash = None else: offline_icon_hash = str(offline_icon).partition('#blink-icon')[2] or None if status_icon: icon_hash = hashlib.sha1(status_icon.data).hexdigest() icon_desc = IconDescriptor(status_icon.url, icon_hash) if not blink_settings.presence.icon or blink_settings.presence.icon.etag != icon_hash: icon = icon_manager.store_data('avatar', status_icon.data) blink_settings.presence.icon = IconDescriptor(FileURL(icon.filename), icon_hash) if icon is not None else None blink_settings.save() elif account.xcap.icon != icon_desc and icon_hash != offline_icon_hash: self._should_set_offline_status.add(account.id) else: if blink_settings.presence.icon is None is not account.xcap.icon: self._should_set_offline_status.add(account.id) elif blink_settings.presence.icon is account.xcap.icon is offline_status is None and account.xcap_manager.pidf_manipulation.supported: state = BlinkPresenceState(account).offline_state account.xcap_manager.set_offline_status(OfflineStatus(state) if state is not None else None) icon_desc = None icon_manager.remove('avatar') blink_settings.presence.icon = None blink_settings.save() account.xcap.icon = icon_desc account.save()
def _AH_OpenTransfersFolder(self): settings = BlinkSettings() QDesktopServices.openUrl( QUrl.fromLocalFile(settings.transfers_directory.normalized))
def _SH_ScreenshotsFolderActionTriggered(self): settings = BlinkSettings() QDesktopServices.openUrl( QUrl.fromLocalFile(settings.screenshots_directory.normalized))
def online_state(self): blink_settings = BlinkSettings() state = blink_settings.presence.current_state.state note = blink_settings.presence.current_state.note state = 'offline' if state == 'Invisible' else state.lower() if self.account is BonjourAccount(): return BonjourPresenceState(state, note) try: hostname = socket.gethostname() except Exception: hostname = 'localhost' account_id = hashlib.md5(self.account.id.encode()).hexdigest() timestamp = ISOTimestamp.now() doc = pidf.PIDF(str(self.account.uri)) person = pidf.Person('PID-%s' % account_id) person.timestamp = timestamp person.activities = rpid.Activities() person.activities.add(state) doc.add(person) if state == 'offline': service = pidf.Service('SID-%s' % account_id) service.status = 'closed' service.status.extended = state service.contact = str(self.account.uri) service.timestamp = timestamp service.capabilities = caps.ServiceCapabilities() service.display_name = self.account.display_name or None service.icon = "%s#blink-icon%s" % ( self.account.xcap.icon.url, self.account.xcap.icon.etag ) if self.account.xcap.icon is not None else None doc.add(service) else: settings = SIPSimpleSettings() instance_id = str(uuid.UUID(settings.instance_id)) service = pidf.Service('SID-%s' % instance_id) service.status = 'open' service.status.extended = state service.contact = str(self.account.contact.public_gruu or self.account.uri) service.timestamp = timestamp service.capabilities = caps.ServiceCapabilities() service.capabilities.audio = True service.capabilities.text = False service.capabilities.message = True service.capabilities.file_transfer = True service.capabilities.screen_sharing_server = True service.capabilities.screen_sharing_client = True service.display_name = self.account.display_name or None service.icon = "%s#blink-icon%s" % ( self.account.xcap.icon.url, self.account.xcap.icon.etag ) if self.account.xcap.icon is not None else None service.device_info = pidf.DeviceInfo( instance_id, description=hostname, user_agent=settings.user_agent) service.device_info.time_offset = pidf.TimeOffset() # TODO: Add real user input data -Saul service.user_input = rpid.UserInput() service.user_input.idle_threshold = 600 service.add(pidf.DeviceID(instance_id)) if note: service.notes.add(note) doc.add(service) device = pidf.Device('DID-%s' % instance_id, device_id=pidf.DeviceID(instance_id)) device.timestamp = timestamp device.notes.add('%s at %s' % (settings.user_agent, hostname)) doc.add(device) return doc
def _AH_ReceivedFilesWindowActionTriggered(self, checked): settings = BlinkSettings() directory = settings.transfers_directory.normalized makedirs(directory) QDesktopServices.openUrl(QUrl.fromLocalFile(directory))
def _AH_ScreenshotsWindowActionTriggered(self, checked): settings = BlinkSettings() directory = settings.screenshots_directory.normalized makedirs(directory) QDesktopServices.openUrl(QUrl.fromLocalFile(directory))
def _NH_SIPApplicationDidStart(self, notification): notification.center.add_observer(self, name='CFGSettingsObjectDidChange', sender=BlinkSettings())