Commit e10d8fc8 authored by Tijmen de Mes's avatar Tijmen de Mes

Added IMDN support

parent 5a3ca07a
...@@ -174,6 +174,9 @@ class Blink(QApplication, metaclass=QSingleton): ...@@ -174,6 +174,9 @@ class Blink(QApplication, metaclass=QSingleton):
self.main_window.conference_dialog.close() self.main_window.conference_dialog.close()
self.main_window.filetransfer_window.close() self.main_window.filetransfer_window.close()
self.main_window.preferences_window.close() self.main_window.preferences_window.close()
if watched is self.chat_window:
if event.type() == QEvent.WindowActivate:
watched.send_pending_imdn_messages(watched.selected_session)
return False return False
def customEvent(self, event): def customEvent(self, event):
......
...@@ -1551,6 +1551,8 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -1551,6 +1551,8 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
if geometry: if geometry:
self.restoreGeometry(geometry) self.restoreGeometry(geometry)
self.pending_displayed_notifications = {}
notification_center = NotificationCenter() notification_center = NotificationCenter()
notification_center.add_observer(self, name='SIPApplicationDidStart') notification_center.add_observer(self, name='SIPApplicationDidStart')
notification_center.add_observer(self, name='BlinkSessionNewIncoming') notification_center.add_observer(self, name='BlinkSessionNewIncoming')
...@@ -1572,6 +1574,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -1572,6 +1574,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
notification_center.add_observer(self, name='MediaStreamWillEnd') notification_center.add_observer(self, name='MediaStreamWillEnd')
notification_center.add_observer(self, name='BlinkGotMessage') notification_center.add_observer(self, name='BlinkGotMessage')
notification_center.add_observer(self, name='BlinkGotComposingIndication') notification_center.add_observer(self, name='BlinkGotComposingIndication')
notification_center.add_observer(self, name='BlinkGotDispositionNotification')
notification_center.add_observer(self, name='BlinkMessageDidSucceed') notification_center.add_observer(self, name='BlinkMessageDidSucceed')
notification_center.add_observer(self, name='BlinkMessageDidFail') notification_center.add_observer(self, name='BlinkMessageDidFail')
...@@ -2025,7 +2028,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2025,7 +2028,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
def closeEvent(self, event): def closeEvent(self, event):
QSettings().setValue("chat_window/geometry", self.saveGeometry()) QSettings().setValue("chat_window/geometry", self.saveGeometry())
super(ChatWindow, self).closeEvent(event) super(ChatWindow, self).closeEvent(event)
def eventFilter(self, watched, event): def eventFilter(self, watched, event):
event_type = event.type() event_type = event.type()
if watched is self.session_widget: if watched is self.session_widget:
...@@ -2152,6 +2155,12 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2152,6 +2155,12 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
painter.drawLine(-3.5, 3.5, 3.5, -3.5) painter.drawLine(-3.5, 3.5, 3.5, -3.5)
painter.restore() painter.restore()
def send_pending_imdn_messages(self, session):
if session and session.blink_session in self.pending_displayed_notifications:
item = self.pending_displayed_notifications.pop(self.selected_session.blink_session)
for (id, timestamp) in item:
MessageManager().send_imdn_message(session.blink_session, id, timestamp, 'displayed')
@run_in_gui_thread @run_in_gui_thread
def handle_notification(self, notification): def handle_notification(self, notification):
handler = getattr(self, '_NH_%s' % notification.name, Null) handler = getattr(self, '_NH_%s' % notification.name, Null)
...@@ -2313,6 +2322,12 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2313,6 +2322,12 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
session.chat_widget.add_message(ChatMessage(content, sender, 'incoming', id=message.id)) session.chat_widget.add_message(ChatMessage(content, sender, 'incoming', id=message.id))
if message.disposition is not None and 'display' in message.disposition:
if self.selected_session.blink_session is blink_session and not self.isMinimized() and self.isActiveWindow():
MessageManager().send_imdn_message(blink_session, message.id, message.timestamp, 'displayed')
else:
self.pending_displayed_notifications.setdefault(blink_session, []).append((message.id, message.timestamp))
session.remote_composing = False session.remote_composing = False
settings = SIPSimpleSettings() settings = SIPSimpleSettings()
if settings.sounds.play_message_alerts and self.selected_session is session: if settings.sounds.play_message_alerts and self.selected_session is session:
...@@ -2326,6 +2341,14 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2326,6 +2341,14 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
return return
session.update_composing_indication(notification.data) session.update_composing_indication(notification.data)
def _NH_BlinkGotDispositionNotification(self, notification):
blink_session = notification.sender
session = blink_session.items.chat
if session is None:
return
data = notification.data
session.chat_widget.update_message_status(id=data.id, status=data.status)
def _NH_BlinkMessageDidSucceed(self, notification): def _NH_BlinkMessageDidSucceed(self, notification):
blink_session = notification.sender blink_session = notification.sender
session = blink_session.items.chat session = blink_session.items.chat
...@@ -2580,6 +2603,8 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin): ...@@ -2580,6 +2603,8 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
self.session_details.setCurrentWidget(self.selected_session.active_panel) self.session_details.setCurrentWidget(self.selected_session.active_panel)
self.participants_list.setModel(self.selected_session.participants_model) self.participants_list.setModel(self.selected_session.participants_model)
self.control_button.setEnabled(True) self.control_button.setEnabled(True)
if not self.isMinimized():
self.send_pending_imdn_messages(self.selected_session)
else: else:
self.tab_widget.setCurrentWidget(self.dummy_tab) self.tab_widget.setCurrentWidget(self.dummy_tab)
self.session_details.setCurrentWidget(self.info_panel) self.session_details.setCurrentWidget(self.info_panel)
......
...@@ -11,7 +11,7 @@ from sipsimple.configuration.settings import SIPSimpleSettings ...@@ -11,7 +11,7 @@ from sipsimple.configuration.settings import SIPSimpleSettings
from sipsimple.core import SIPURI, FromHeader, ToHeader, Message, RouteHeader from sipsimple.core import SIPURI, FromHeader, ToHeader, Message, RouteHeader
from sipsimple.lookup import DNSLookup from sipsimple.lookup import DNSLookup
from sipsimple.payloads.iscomposing import IsComposingDocument, IsComposingMessage, State, LastActive, Refresh, ContentType from sipsimple.payloads.iscomposing import IsComposingDocument, IsComposingMessage, State, LastActive, Refresh, ContentType
from sipsimple.payloads.imdn import IMDNDocument from sipsimple.payloads.imdn import IMDNDocument, DeliveryNotification, DisplayNotification
from sipsimple.streams.msrp.chat import CPIMPayload, CPIMParserError, CPIMNamespace, CPIMHeader, ChatIdentity, Message as MSRPChatMessage, SimplePayload from sipsimple.streams.msrp.chat import CPIMPayload, CPIMParserError, CPIMNamespace, CPIMHeader, ChatIdentity, Message as MSRPChatMessage, SimplePayload
from sipsimple.util import ISOTimestamp from sipsimple.util import ISOTimestamp
...@@ -34,6 +34,7 @@ class BlinkMessage(MSRPChatMessage): ...@@ -34,6 +34,7 @@ class BlinkMessage(MSRPChatMessage):
@implementer(IObserver) @implementer(IObserver)
class OutgoingMessage(object): class OutgoingMessage(object):
__ignored_content_types__ = {IsComposingDocument.content_type, IMDNDocument.content_type} #Content types to ignore in notifications __ignored_content_types__ = {IsComposingDocument.content_type, IMDNDocument.content_type} #Content types to ignore in notifications
__disabled_imdn_content_types__ = {'text/pgp-public-key', 'text/pgp-private-key'}.union(__ignored_content_types__) #Content types to ignore in notifications
def __init__(self, account, contact, content, content_type='text/plain', recipients=None, courtesy_recipients=None, subject=None, timestamp=None, required=None, additional_headers=None, id=None): def __init__(self, account, contact, content, content_type='text/plain', recipients=None, courtesy_recipients=None, subject=None, timestamp=None, required=None, additional_headers=None, id=None):
self.lookup = None self.lookup = None
...@@ -136,11 +137,20 @@ class OutgoingMessage(object): ...@@ -136,11 +137,20 @@ class OutgoingMessage(object):
def _NH_SIPMessageDidSucceed(self, notification): def _NH_SIPMessageDidSucceed(self, notification):
notification_center = NotificationCenter() notification_center = NotificationCenter()
if self.content_type.lower() in self.__ignored_content_types__:
if self.content_type.lower() == IMDNDocument.content_type:
document = IMDNDocument.parse(self.content)
imdn_message_id = document.message_id.value
imdn_status = document.notification.status.__str__()
notification_center.post_notification('BlinkDidSendDispositionNotification', sender=self.session, data=NotificationData(id=imdn_message_id, status=imdn_status))
return
notification_center.post_notification('BlinkMessageDidSucceed', sender=self.session, data=NotificationData(data=notification.data, id=self.id)) notification_center.post_notification('BlinkMessageDidSucceed', sender=self.session, data=NotificationData(data=notification.data, id=self.id))
def _NH_SIPMessageDidFail(self, notification): def _NH_SIPMessageDidFail(self, notification):
if self.content_type.lower() in self.__ignored_content_types__: if self.content_type.lower() in self.__ignored_content_types__:
return return
notification_center = NotificationCenter() notification_center = NotificationCenter()
notification_center.post_notification('BlinkMessageDidFail', sender=self.session, data=NotificationData(data=notification.data, id=self.id)) notification_center.post_notification('BlinkMessageDidFail', sender=self.session, data=NotificationData(data=notification.data, id=self.id))
...@@ -226,12 +236,28 @@ class MessageManager(object, metaclass=Singleton): ...@@ -226,12 +236,28 @@ class MessageManager(object, metaclass=Singleton):
return return
timestamp = str(cpim_message.timestamp) if cpim_message is not None and cpim_message.timestamp is not None else str(ISOTimestamp.now()) timestamp = str(cpim_message.timestamp) if cpim_message is not None and cpim_message.timestamp is not None else str(ISOTimestamp.now())
message = BlinkMessage(body, content_type, sender, timestamp=timestamp, id=message_id)
if account.sms.use_cpim and account.sms.enable_imdn and content_type.lower() == IMDNDocument.content_type:
# print("-- IMDN received")
document = IMDNDocument.parse(body)
imdn_message_id = document.message_id.value
imdn_status = document.notification.status.__str__()
imdn_datetime = document.datetime.__str__()
notification_center.post_notification('BlinkGotDispositionNotification', sender=blink_session, data=NotificationData(id=imdn_message_id, status=imdn_status))
return
message = BlinkMessage(body, content_type, sender, timestamp=timestamp, id=message_id, disposition=disposition)
notification_center.post_notification('BlinkMessageIsParsed', sender=blink_session, data=message)
if disposition is not None and 'positive-delivery' in disposition:
# print("-- Should send delivered imdn")
self.send_imdn_message(blink_session, message_id, timestamp, 'delivered')
notification_center.post_notification('BlinkGotMessage', sender=blink_session, data=message) notification_center.post_notification('BlinkGotMessage', sender=blink_session, data=message)
else: else:
pass
# TODO handle replicated messages # TODO handle replicated messages
pass
def _NH_BlinkSessionWasCreated(self, notification): def _NH_BlinkSessionWasCreated(self, notification):
self.sessions.append(notification.sender) self.sessions.append(notification.sender)
...@@ -248,6 +274,25 @@ class MessageManager(object, metaclass=Singleton): ...@@ -248,6 +274,25 @@ class MessageManager(object, metaclass=Singleton):
self.send_message(session.account, session.contact, content, IsComposingDocument.content_type) self.send_message(session.account, session.contact, content, IsComposingDocument.content_type)
def send_imdn_message(self, session, id, timestamp, state):
if not session.account.sms.use_cpim and not session.account.sms.enable_imdn:
return
# print(f"-- Will send imdn for {id} -> {state}")
if state == 'delivered':
notification = DeliveryNotification(state)
elif state == 'displayed':
notification = DisplayNotification(state)
elif state == 'error':
notification = DisplayNotification(state)
content = IMDNDocument.create(message_id=id,
datetime=timestamp,
recipient_uri=session.contact.uri.uri,
notification=notification)
self.send_message(session.account, session.contact, content, IMDNDocument.content_type)
def send_message(self, account, contact, content, content_type='text/plain', recipients=None, courtesy_recipients=None, subject=None, timestamp=None, required=None, additional_headers=None, id=None): def send_message(self, account, contact, content, content_type='text/plain', recipients=None, courtesy_recipients=None, subject=None, timestamp=None, required=None, additional_headers=None, id=None):
blink_session = next(session for session in self.sessions if session.reusable and session.contact.settings is contact.settings) blink_session = next(session for session in self.sessions if session.reusable and session.contact.settings is contact.settings)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment