From 8b722b2b24fdf36a1af2c63d576ddfa438036c4f Mon Sep 17 00:00:00 2001 From: Yann Leboulanger Date: Sun, 1 May 2011 22:09:50 +0200 Subject: [PATCH] new way to handle incominf messages, new notification event. --- plugins/snarl_notifications/plugin.py | 25 +---- src/chat_control.py | 2 +- src/common/connection_handlers.py | 1 + src/common/connection_handlers_events.py | 154 +++++++++++++++++++++++++++++ src/common/gajim.py | 3 + src/common/ged.py | 17 ++-- src/common/nec.py | 8 +- src/disco.py | 1 - src/groupchat_control.py | 23 ++++- src/notify.py | 27 ++++++ src/roster_window.py | 40 ++++++++ src/session.py | 162 +++++++++++++++++++------------ 12 files changed, 362 insertions(+), 101 deletions(-) diff --git a/plugins/snarl_notifications/plugin.py b/plugins/snarl_notifications/plugin.py index b152eac1d..7dfe24d26 100644 --- a/plugins/snarl_notifications/plugin.py +++ b/plugins/snarl_notifications/plugin.py @@ -45,7 +45,7 @@ class SnarlNotificationsPlugin(GajimPlugin): #self.gui_extension_points = {} #self.config_default_values = {} - self.events_handlers = {'NewMessage' : (ged.POSTCORE, self.newMessage)} + self.events_handlers = {'notification' : (ged.POSTCORE, self.notif)} @log_calls('SnarlNotificationsPlugin') def activate(self): @@ -56,29 +56,12 @@ class SnarlNotificationsPlugin(GajimPlugin): pass @log_calls('SnarlNotificationsPlugin') - def newMessage(self, args): - event_name = "NewMessage" - data = args - account = data[0] - jid = data[1][0] - jid_without_resource = gajim.get_jid_without_resource(jid) - msg = data[1][1] - msg_type = data[1][4] - if msg_type == 'chat': - nickname = gajim.get_contact_name_from_jid(account, jid_without_resource) - elif msg_type in ('pm', 'groupchat'): - nickname = gajim.get_resource_from_jid(jid) - else: - nickname = jid - - print "Event '%s' occured. Arguments: %s\n\n===\n"%(event_name, pformat(args)) - print "Event '%s' occured. Arguments: \naccount = %s\njid = %s\nmsg = %s\nnickname = %s"%( - event_name, account, jid, msg, nickname) - + def notif(self, obj): + print "Event '%s' occured.\n\n===\n" % obj.popup_event_type #if PySnarl.snGetVersion() != False: #(major, minor) = PySnarl.snGetVersion() #print "Found Snarl version",str(major)+"."+str(minor),"running." - #PySnarl.snShowMessage(nickname, msg[:20]+'...') + #PySnarl.snShowMessage(obj.popup_title, obj.popup_text) #else: #print "Sorry Snarl does not appear to be running" diff --git a/src/chat_control.py b/src/chat_control.py index 47d7450fd..bd3056ec5 100644 --- a/src/chat_control.py +++ b/src/chat_control.py @@ -2954,7 +2954,7 @@ class ChatControl(ChatControlBase): if len(data) > 6 and isinstance(data[6], int): message_ids.append(data[6]) - if len(data) > 8: + if len(data) > 8 and not self.session: self.set_session(data[8]) if message_ids: gajim.logger.set_read_messages(message_ids) diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py index 99183abca..4ea199037 100644 --- a/src/common/connection_handlers.py +++ b/src/common/connection_handlers.py @@ -1240,6 +1240,7 @@ ConnectionJingle, ConnectionIBBytestream): gajim.nec.register_incoming_event(ArchivingErrorReceivedEvent) gajim.nec.register_incoming_event( ArchivingPreferencesChangedReceivedEvent) + gajim.nec.register_incoming_event(NotificationEvent) gajim.ged.register_event_handler('http-auth-received', ged.CORE, self._nec_http_auth_received) diff --git a/src/common/connection_handlers_events.py b/src/common/connection_handlers_events.py index 4e7acac1c..976bc0f13 100644 --- a/src/common/connection_handlers_events.py +++ b/src/common/connection_handlers_events.py @@ -35,6 +35,8 @@ from common.zeroconf import zeroconf from common.logger import LOG_DB_PATH from common.pep import SUPPORTED_PERSONAL_USER_EVENTS +import gtkgui_helpers + import logging log = logging.getLogger('gajim.c.connection_handlers_events') @@ -1888,3 +1890,155 @@ class GatewayPromptReceivedEvent(nec.NetworkIncomingEvent, HelperEvent): self.prompt = None self.prompt_jid = None return True + +class NotificationEvent(nec.NetworkIncomingEvent): + name = 'notification' + base_network_events = ['decrypted-message-received', 'gc-message-received'] + + def detect_type(self): + if self.base_event.name == 'decrypted-message-received': + self.notif_type = 'msg' + if self.base_event.name == 'gc-message-received': + self.notif_type = 'gc-msg' + + def get_focused(self): + self.control_focused = False + if self.control: + parent_win = self.control.parent_win + if parent_win and self.control == parent_win.get_active_control() \ + and parent_win.window.has_focus: + self.control_focused = True + + def handle_incoming_msg_event(self, msg_obj): + if not msg_obj.msgtxt: + return + self.jid = msg_obj.jid + if msg_obj.session: + self.control = msg_obj.session.control + else: + self.control = None + self.get_focused() + # This event has already been added to event list + if not self.control and len(gajim.events.get_events(self.conn.name, \ + self.jid, [msg_obj.mtype])) <= 1: + self.first_unread = True + + if msg_obj.mtype == 'pm': + nick = msg_obj.resource + else: + nick = gajim.get_name_from_jid(self.conn.name, self.jid) + + if self.first_unread: + self.sound_event = 'first_message_received' + elif self.control_focused: + self.sound_event = 'next_message_received_focused' + else: + self.sound_event = 'next_message_received_unfocused' + + if gajim.config.get('notification_preview_message'): + self.popup_text = msg_obj.msgtxt + if self.popup_text and (self.popup_text.startswith('/me ') or \ + self.popup_text.startswith('/me\n')): + self.popup_text = '* ' + nick + self.popup_text[3:] + else: + # We don't want message preview, do_preview = False + self.popup_text = '' + if msg_obj.mtype == 'normal': # single message + self.popup_event_type = _('New Single Message') + self.popup_image = 'gajim-single_msg_recv' + self.popup_title = _('New Single Message from %(nickname)s') % \ + {'nickname': nick} + elif msg_obj.mtype == 'pm': + self.popup_event_type = _('New Private Message') + self.popup_image = 'gajim-priv_msg_recv' + self.popup_title = _('New Private Message from group chat %s') % \ + msg_obj.jid + if self.popup_text: + self.popup_text = _('%(nickname)s: %(message)s') % \ + {'nickname': nick, 'message': self.popup_text} + else: + self.popup_text = _('Messaged by %(nickname)s') % \ + {'nickname': nick} + else: # chat message + self.popup_event_type = _('New Message') + self.popup_image = 'gajim-chat_msg_recv' + self.popup_title = _('New Message from %(nickname)s') % \ + {'nickname': nick} + + self.popup_image = gtkgui_helpers.get_icon_path(self.popup_image, 48) + + if not gajim.config.get('notify_on_new_message') or \ + not self.first_unread: + self.do_popup = False + elif gajim.config.get('autopopupaway'): + # always show notification + self.do_popup = True + elif gajim.connections[self.conn.name].connected in (2, 3): + # we're online or chat + self.do_popup = True + + if self.first_unread and helpers.allow_sound_notification( + self.conn.name, 'first_message_received'): + self.do_sound = True + elif not self.first_unread and self.control_focused and \ + helpers.allow_sound_notification(self.conn.name, + 'next_message_received_focused'): + self.do_sound = True + elif not self.first_unread and not self.control_focused and \ + helpers.allow_sound_notification(self.conn.name, + 'next_message_received_unfocused'): + self.do_sound = True + + def handle_incoming_gc_msg_event(self, msg_obj): + sound = msg_obj.msg_obj.gc_control.highlighting_for_message( + msg_obj.msgtxt, msg_obj.timestamp)[1] + self.do_sound = True + if sound == 'received': + self.sound_event = 'muc_message_received' + elif sound == 'highlight': + self.sound_event = 'muc_message_highlight' + else: + self.do_sound = False + + self.do_popup = False + + def handle_incoming_pres_event(self, msg_obj): + pass + + def generate(self): + # what's needed to compute output + self.conn = self.base_event.conn + self.control = None + self.control_focused = False + self.first_unread = False + + # For output + self.do_sound = False + self.sound_file = '' + self.sound_event = '' # gajim sound played if not sound_file is set + self.show_popup = False + + self.do_popup = False + self.popup_title = '' + self.popup_text = '' + self.popup_event_type = '' + self.popup_msg_type = '' + self.popup_image = '' + + self.do_command = False + self.command = '' + + self.open_chat = False + self.activate_urgency_hint = False + self.show_in_notification_area = False + self.show_in_roster = False + + self.detect_type() + + if self.notif_type == 'msg': + self.handle_incoming_msg_event(self.base_event) + elif self.notif_type == 'gc-msg': + self.handle_incoming_gc_msg_event(self.base_event) + elif self.notif_type == 'pres': + self.handle_incoming_pres_event(self.base_event) + return True diff --git a/src/common/gajim.py b/src/common/gajim.py index 1131bb95e..872b083bc 100644 --- a/src/common/gajim.py +++ b/src/common/gajim.py @@ -35,6 +35,7 @@ import config import xmpp import defs import common.ged +import notify interface = None # The actual interface (the gtk one for the moment) thread_interface = None # Interface to run a thread and then a callback @@ -105,6 +106,8 @@ to_be_removed = {} # list of contacts that has just signed out events = Events() +notification = notify.Notification() + nicks = {} # list of our nick names in each account # should we block 'contact signed in' notifications for this account? # this is only for the first 30 seconds after we change our show diff --git a/src/common/ged.py b/src/common/ged.py index c0a2700f6..81af8d995 100644 --- a/src/common/ged.py +++ b/src/common/ged.py @@ -27,12 +27,17 @@ Global Events Dispatcher module. import logging log = logging.getLogger('gajim.common.ged') -PRECORE = 30 -CORE = 40 -POSTCORE = 50 +PRECORE = 10 +CORE = 20 +POSTCORE = 30 +PREGUI = 40 +PREGUI1 = 50 GUI1 = 60 -GUI2 = 70 -POSTGUI = 80 +POSTGUI1 = 70 +PREGUI2 = 80 +GUI2 = 90 +POSTGUI2 = 100 +POSTGUI = 110 class GlobalEventsDispatcher(object): @@ -68,4 +73,4 @@ class GlobalEventsDispatcher(object): if event_name in self.handlers: for priority, handler in self.handlers[event_name]: if handler(*args, **kwargs): - return + return True diff --git a/src/common/nec.py b/src/common/nec.py index c8c8bc38c..dcb03ad1e 100644 --- a/src/common/nec.py +++ b/src/common/nec.py @@ -58,8 +58,8 @@ class NetworkEventsController(object): def push_incoming_event(self, event_object): if event_object.generate(): - gajim.ged.raise_event(event_object.name, event_object) - self._generate_events_based_on_incoming_event(event_object) + if not gajim.ged.raise_event(event_object.name, event_object): + self._generate_events_based_on_incoming_event(event_object) def push_outgoing_event(self, event_object): pass @@ -78,8 +78,8 @@ class NetworkEventsController(object): for new_event_class in self.incoming_events_generators[base_event_name]: new_event_object = new_event_class(None, base_event=event_object) if new_event_object.generate(): - gajim.ged.raise_event(new_event_object.name, new_event_object) - self._generate_events_based_on_incoming_event(new_event_object) + if not gajim.ged.raise_event(new_event_object.name, new_event_object): + self._generate_events_based_on_incoming_event(new_event_object) class NetworkEvent(object): name = '' diff --git a/src/disco.py b/src/disco.py index 9a47a8765..b6679d4e3 100644 --- a/src/disco.py +++ b/src/disco.py @@ -1474,7 +1474,6 @@ class ToplevelAgentBrowser(AgentBrowser): if self.search_button: self.search_button.set_sensitive(False) model, iter_ = self.window.services_treeview.get_selection().get_selected() - model, iter_ = self.window.services_treeview.get_selection().get_selected() if not iter_: return if not model[iter_][0]: diff --git a/src/groupchat_control.py b/src/groupchat_control.py index 5013ed329..33ac423df 100644 --- a/src/groupchat_control.py +++ b/src/groupchat_control.py @@ -480,6 +480,8 @@ class GroupchatControl(ChatControlBase): self._nec_gc_config_changed_received) gajim.ged.register_event_handler('signed-in', ged.GUI1, self._nec_signed_in) + gajim.ged.register_event_handler('decrypted-message-received', ged.GUI2, + self._nec_decrypted_message_received) gajim.gc_connected[self.account][self.room_jid] = False # disable win, we are not connected yet ChatControlBase.got_disconnected(self) @@ -1108,10 +1110,6 @@ class GroupchatControl(ChatControlBase): self.attention_list.pop(0) # remove older self.attention_list.append(contact) - if sound == 'received': - helpers.play_sound('muc_message_received') - elif sound == 'highlight': - helpers.play_sound('muc_message_highlight') if text.startswith('/me ') or text.startswith('/me\n'): other_tags_for_text.append('gc_nickname_color_' + \ str(self.gc_custom_colors[contact])) @@ -1271,6 +1269,23 @@ class GroupchatControl(ChatControlBase): password = gajim.gc_passwords.get(self.room_jid, '') obj.conn.join_gc(self.nick, self.room_jid, password) + def _nec_decrypted_message_received(self, obj): + if obj.conn.name != self.account: + return + if obj.gc_control == self and obj.resource: + # We got a pm from this room + nick = obj.resource + if obj.session.control: + # print if a control is open + obj.session.control.print_conversation(obj.msgtxt, + tim=obj.timestamp, xhtml=obj.xhtml, encrypted=obj.encrypted, + displaymarking=obj.displaymarking) + else: + # otherwise pass it off to the control to be queued + self.on_private_message(nick, obj.msgtxt, obj.timestamp, + obj.xhtml, self, msg_id=obj.msg_id, encrypted=obj.encrypted, + displaymarking=obj.displaymarking) + def got_connected(self): # Make autorejoin stop. if self.autorejoin: diff --git a/src/notify.py b/src/notify.py index 888c2fbde..6da2f2e2e 100644 --- a/src/notify.py +++ b/src/notify.py @@ -36,6 +36,7 @@ import gtk from common import gajim from common import helpers +from common import ged from common import dbus_support if dbus_support.supported: @@ -390,6 +391,32 @@ def on_pynotify_notification_clicked(notification, action): notification.close() gajim.interface.handle_event(account, jid, msg_type) +class Notification: + """ + Handle notifications + """ + def __init__(self): + gajim.ged.register_event_handler('notification', ged.GUI2, + self._nec_notification) + + def _nec_notification(self, obj): + if obj.do_popup: + popup(obj.popup_event_type, obj.jid, obj.conn.name, + obj.popup_msg_type, path_to_image=obj.popup_image, + title=obj.popup_title, text=obj.popup_text) + + if obj.do_sound: + if obj.sound_file: + helpers.play_sound_file(obj.sound_file) + elif obj.sound_event: + helpers.play_sound(obj.sound_event) + + if obj.do_command: + try: + helpers.exec_command(obj.command) + except Exception: + pass + class NotificationResponseManager: """ Collect references to pending DesktopNotifications and manages there diff --git a/src/roster_window.py b/src/roster_window.py index b7ef6f054..32cca46c9 100644 --- a/src/roster_window.py +++ b/src/roster_window.py @@ -2568,6 +2568,44 @@ class RosterWindow: self.set_actions_menu_needs_rebuild() self.draw_account(obj.conn.name) + def _nec_decrypted_message_received(self, obj): + if not obj.msgtxt: # empty message text + return True + if obj.mtype not in ('norml', 'chat'): + return + if obj.session.control: + typ = '' + if obj.mtype == 'error': + typ = 'error' + + obj.session.control.print_conversation(obj.msgtxt, typ, + tim=obj.timestamp, encrypted=obj.encrypted, subject=obj.subject, + xhtml=obj.xhtml, displaymarking=obj.displaymarking) + elif obj.popup: + if not obj.session.control: + contact = gajim.contacts.get_contact(obj.conn.name, obj.jid, + obj.resource_for_chat) + obj.session.control = gajim.interface.new_chat(contact, + obj.conn.name, resource=obj.resource_for_chat, + session=obj.session) + if len(gajim.events.get_events(obj.conn.name, obj.fjid)): + obj.session.control.read_queue() + + if obj.show_in_roster: + self.draw_contact(obj.jid, obj.conn.name) + self.show_title() # we show the * or [n] + # Select the big brother contact in roster, it's visible because it + # has events. + family = gajim.contacts.get_metacontacts_family(obj.conn.name, + obj.jid) + if family: + nearby_family, bb_jid, bb_account = \ + gajim.contacts.get_nearby_family_and_big_brother(family, + obj.conn.name) + else: + bb_jid, bb_account = obj.jid, obj.conn.name + self.select_contact(bb_jid, bb_account) + ################################################################################ ### Menu and GUI callbacks ### FIXME: order callbacks in itself... @@ -6404,3 +6442,5 @@ class RosterWindow: self._nec_metacontacts_received) gajim.ged.register_event_handler('signed-in', ged.GUI1, self._nec_signed_in) + gajim.ged.register_event_handler('decrypted-message-received', ged.GUI2, + self._nec_decrypted_message_received) diff --git a/src/session.py b/src/session.py index 3068f5b7a..7e30e4c40 100644 --- a/src/session.py +++ b/src/session.py @@ -97,6 +97,8 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession): common.logger.LOG_DB_PATH self.conn.dispatch('ERROR', (pritext, sectext)) + obj.msg_id = msg_id + treat_as = gajim.config.get('treat_incoming_messages') if treat_as: obj.mtype = treat_as @@ -106,14 +108,6 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession): pm = True obj.mtype = 'pm' - highest_contact = gajim.contacts.get_contact_with_highest_priority( - self.conn.name, obj.jid) - - # does this resource have the highest priority of any available? - is_highest = not highest_contact or not highest_contact.resource or \ - obj.resource == highest_contact.resource or highest_contact.show ==\ - 'offline' - # Handle chat states contact = gajim.contacts.get_contact(self.conn.name, obj.jid, obj.resource) @@ -142,21 +136,20 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession): # THIS MUST BE AFTER chatstates handling # AND BEFORE playsound (else we ear sounding on chatstates!) if not obj.msgtxt: # empty message text - return + return True if gajim.config.get_per('accounts', self.conn.name, 'ignore_unknown_contacts') and not gajim.contacts.get_contacts( self.conn.name, obj.jid) and not pm: - return + return True - if not contact: - # contact is not in the roster, create a fake one to display - # notification - contact = gajim.contacts.create_not_in_roster_contact(jid=obj.jid, - account=self.conn.name, resource=obj.resource) + highest_contact = gajim.contacts.get_contact_with_highest_priority( + self.conn.name, obj.jid) - advanced_notif_num = notify.get_advanced_notification( - 'message_received', self.conn.name, contact) + # does this resource have the highest priority of any available? + is_highest = not highest_contact or not highest_contact.resource or \ + obj.resource == highest_contact.resource or highest_contact.show ==\ + 'offline' if not pm and is_highest: jid_of_control = obj.jid @@ -170,47 +163,8 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession): self.control = ctrl self.control.set_session(self) - # Is it a first or next message received ? - first = False - if not self.control and not gajim.events.get_events(self.conn.name, \ - jid_of_control, [obj.mtype]): - first = True - - if pm: - nickname = obj.resource - if self.control: - # print if a control is open - self.control.print_conversation(obj.msgtxt, tim=obj.timestamp, - xhtml=obj.xhtml, encrypted=obj.encrypted, - displaymarking=obj.displaymarking) - else: - # otherwise pass it off to the control to be queued - obj.gc_control.on_private_message(nickname, obj.msgtxt, - obj.timestamp, obj.xhtml, self, msg_id=msg_id, - encrypted=obj.encrypted, displaymarking=obj.displaymarking) - else: - self.roster_message(obj.jid, obj.msgtxt, obj.timestamp, - obj.encrypted, obj.mtype, - obj.subject, obj.resource, msg_id, obj.user_nick, - advanced_notif_num, xhtml=obj.xhtml, form_node=obj.form_node, - displaymarking=obj.displaymarking) - - nickname = gajim.get_name_from_jid(self.conn.name, obj.jid) - - # Check and do wanted notifications - msg = obj.msgtxt - if obj.subject: - msg = _('Subject: %s') % obj.subject + '\n' + msg - focused = False - - if self.control: - parent_win = self.control.parent_win - if parent_win and self.control == parent_win.get_active_control() \ - and parent_win.window.has_focus: - focused = True - - notify.notify('new_message', jid_of_control, self.conn.name, [obj.mtype, - first, nickname, msg, focused], advanced_notif_num) + if not pm: + self.roster_message2(obj) if gajim.interface.remote_ctrl: gajim.interface.remote_ctrl.raise_signal('NewMessage', ( @@ -218,14 +172,94 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession): obj.encrypted, obj.mtype, obj.subject, obj.chatstate, msg_id, obj.composing_xep, obj.user_nick, obj.xhtml, obj.form_node])) - gajim.ged.raise_event('NewMessage', - (self.conn.name, [obj.fjid, obj.msgtxt, obj.timestamp, - obj.encrypted, obj.mtype, obj.subject, obj.chatstate, msg_id, - obj.composing_xep, obj.user_nick, obj.xhtml, obj.form_node])) + def roster_message2(self, obj): + """ + Display the message or show notification in the roster + """ + contact = None + jid = obj.jid + resource = obj.resource + # if chat window will be for specific resource + resource_for_chat = resource + + fjid = jid + + # Try to catch the contact with correct resource + if resource: + fjid = jid + '/' + resource + contact = gajim.contacts.get_contact(obj.conn.name, jid, resource) + + highest_contact = gajim.contacts.get_contact_with_highest_priority( + obj.conn.name, jid) + if not contact: + # If there is another resource, it may be a message from an + # invisible resource + lcontact = gajim.contacts.get_contacts(obj.conn.name, jid) + if (len(lcontact) > 1 or (lcontact and lcontact[0].resource and \ + lcontact[0].show != 'offline')) and jid.find('@') > 0: + contact = gajim.contacts.copy_contact(highest_contact) + contact.resource = resource + contact.priority = 0 + contact.show = 'offline' + contact.status = '' + gajim.contacts.add_contact(obj.conn.name, contact) + + else: + # Default to highest prio + fjid = jid + resource_for_chat = None + contact = highest_contact + + if not contact: + # contact is not in roster + contact = gajim.interface.roster.add_to_not_in_the_roster( + obj.conn.name, jid, obj.user_nick) + + if not self.control: + ctrl = gajim.interface.msg_win_mgr.get_control(fjid, self.conn.name) + if ctrl: + self.control = ctrl + self.control.set_session(self) + else: + # if no control exists and message comes from highest prio, + # the new control shouldn't have a resource + if highest_contact and contact.resource == \ + highest_contact.resource and jid != gajim.get_jid_from_account( + self.conn.name): + fjid = jid + resource_for_chat = None + + obj.popup = helpers.allow_popup_window(self.conn.name) + obj.resource_for_chat = resource_for_chat + + type_ = 'chat' + event_type = 'message_received' + + if obj.mtype == 'normal': + type_ = 'normal' + event_type = 'single_message_received' + + if self.control and obj.mtype != 'normal': + obj.show_in_roster = False + obj.show_in_systray = False + else: + obj.show_in_roster = notify.get_show_in_roster(event_type, + self.conn.name, contact, self) + obj.show_in_systray = notify.get_show_in_systray(event_type, + self.conn.name, contact) + + if not self.control: + event = gajim.events.create_event(type_, (obj.msgtxt, obj.subject, + obj.mtype, obj.timestamp, obj.encrypted, obj.resource, + obj.msg_id, obj.xhtml, self, obj.form_node, obj.displaymarking), + show_in_roster=obj.show_in_roster, + show_in_systray=obj.show_in_systray) + + gajim.events.add_event(self.conn.name, fjid, event) def roster_message(self, jid, msg, tim, encrypted=False, msg_type='', - subject=None, resource='', msg_id=None, user_nick='', - advanced_notif_num=None, xhtml=None, form_node=None, displaymarking=None): + subject=None, resource='', msg_id=None, user_nick='', + advanced_notif_num=None, xhtml=None, form_node=None, displaymarking=None): """ Display the message or show notification in the roster """ -- 2.11.4.GIT