diff --git a/src/chat_control.py b/src/chat_control.py index bd3056ec5d13acf0cb80a009d573c8521591a71c..391396693f2ed90bec4653058a343dde7ad8db70 100644 --- a/src/chat_control.py +++ b/src/chat_control.py @@ -54,6 +54,7 @@ from common.pep import MOODS, ACTIVITIES from common.xmpp.protocol import NS_XHTML, NS_XHTML_IM, NS_FILE, NS_MUC from common.xmpp.protocol import NS_RECEIPTS, NS_ESESSION from common.xmpp.protocol import NS_JINGLE_RTP_AUDIO, NS_JINGLE_RTP_VIDEO, NS_JINGLE_ICE_UDP +from common.connection_handlers_events import MessageOutgoingEvent from command_system.implementation.middleware import ChatCommandProcessor from command_system.implementation.middleware import CommandTools @@ -517,6 +518,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): menu.show_all() def shutdown(self): + super(ChatControlBase, self).shutdown() # PluginSystem: removing GUI extension points connected with ChatControlBase # instance object gajim.plugin_manager.remove_gui_extension_point('chat_control_base', self) @@ -848,8 +850,8 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): return label def send_message(self, message, keyID='', type_='chat', chatstate=None, - msg_id=None, composing_xep=None, resource=None, xhtml=None, - callback=None, callback_args=[], process_commands=True): + msg_id=None, composing_xep=None, resource=None, xhtml=None, callback=None, + callback_args=[], process_commands=True): """ Send the given message to the active tab. Doesn't return None if error """ @@ -860,11 +862,12 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): return label = self.get_seclabel() - MessageControl.send_message(self, message, keyID, type_=type_, - chatstate=chatstate, msg_id=msg_id, composing_xep=composing_xep, - resource=resource, user_nick=self.user_nick, xhtml=xhtml, - label=label, - callback=callback, callback_args=callback_args) + + gajim.nec.push_outgoing_event(MessageOutgoingEvent(None, + account=self.account, message=message, keyID=keyID, type_=type_, + chatstate=chatstate, msg_id=msg_id, composing_xep=composing_xep, + resource=resource, user_nick=self.user_nick, xhtml=xhtml, + label=label, callback=callback, callback_args= callback_args)) # Record the history of sent messages self.save_message(message, 'sent') @@ -2209,6 +2212,7 @@ class ChatControl(ChatControlBase): """ Send a message to contact """ + message = helpers.remove_invalid_xml_chars(message) if message in ('', None, '\n'): return None @@ -2624,12 +2628,14 @@ class ChatControl(ChatControlBase): # if we're inactive prevent composing (JEP violation) if contact.our_chatstate == 'inactive' and state == 'composing': # go active before - MessageControl.send_message(self, None, chatstate='active') + gajim.nec.push_outgoing_event(MessageOutgoingEvent(None, + account=self.account, chatstate='active')) contact.our_chatstate = 'active' self.reset_kbd_mouse_timeout_vars() - MessageControl.send_message(self, "", chatstate = state, - msg_id = contact.msg_id, composing_xep = contact.composing_xep) + gajim.nec.push_outgoing_event(MessageOutgoingEvent(None, + account=self.account, chatstate=state, msg_id=contact.msg_id, + composing_xep=contact.composing_xep)) contact.our_chatstate = state if contact.our_chatstate == 'active': diff --git a/src/common/connection.py b/src/common/connection.py index 9ec3bea1e7721087a910ec76b8569af2c3f67b7a..18824b3aa2a5863fe30350ba8e904c12a08279d3 100644 --- a/src/common/connection.py +++ b/src/common/connection.py @@ -717,6 +717,8 @@ class Connection(CommonConnection, ConnectionHandlers): self._nec_agent_info_error_received) gajim.ged.register_event_handler('agent-info-received', ged.CORE, self._nec_agent_info_received) + gajim.ged.register_event_handler('message-outgoing', ged.OUT_CORE, + self._nec_message_outgoing) # END __init__ def cleanup(self): @@ -727,6 +729,8 @@ class Connection(CommonConnection, ConnectionHandlers): self._nec_agent_info_error_received) gajim.ged.remove_event_handler('agent-info-received', ged.CORE, self._nec_agent_info_received) + gajim.ged.remove_event_handler('message-outgoing', ged.OUT_CORE, + self._nec_message_outgoing) def get_config_values_or_default(self): if gajim.config.get_per('accounts', self.name, 'keep_alives_enabled'): @@ -1764,6 +1768,30 @@ class Connection(CommonConnection, ConnectionHandlers): session=session, forward_from=forward_from, form_node=form_node, original_message=original_message, delayed=delayed, callback=cb) + def _nec_message_outgoing(self, obj): + if obj.account != self.name: + return + + def cb(jid, msg, keyID, forward_from, session, original_message, + subject, type_, msg_iq): + msg_id = self.connection.send(msg_iq, now=obj.now) + jid = helpers.parse_jid(obj.jid) + gajim.nec.push_incoming_event(MessageSentEvent(None, conn=self, + jid=jid, message=msg, keyID=keyID, chatstate=obj.chatstate)) + if obj.callback: + obj.callback(msg_id, *obj.callback_args) + + self.log_message(jid, msg, forward_from, session, original_message, + subject, type_) + + self._prepare_message(obj.jid, obj.message, obj.keyID, type_=obj.type_, + subject=obj.subject, chatstate=obj.chatstate, msg_id=obj.msg_id, + composing_xep=obj.composing_xep, resource=obj.resource, + user_nick=obj.user_nick, xhtml=obj.xhtml, label=obj.label, + session=obj.session, forward_from=obj.forward_from, + form_node=obj.form_node, original_message=obj.original_message, + delayed=obj.delayed, callback=cb) + def send_contacts(self, contacts, jid): """ Send contacts with RosterX (Xep-0144) diff --git a/src/common/connection_handlers_events.py b/src/common/connection_handlers_events.py index 976bc0f13270d3238f5fcfa39293b440e5dd4b43..df850a28440b47bd41de7cf9575b30f77f6c50a7 100644 --- a/src/common/connection_handlers_events.py +++ b/src/common/connection_handlers_events.py @@ -2042,3 +2042,31 @@ class NotificationEvent(nec.NetworkIncomingEvent): elif self.notif_type == 'pres': self.handle_incoming_pres_event(self.base_event) return True + +class MessageOutgoingEvent(nec.NetworkIncomingEvent): + name = 'message-outgoing' + base_network_events = [] + + def init(self): + self.message = '' + self.keyID = None + self.type_ = 'chat' + self.subject = '' + self.chatstate = None + self.msg_id = None + self.composing_xep = None + self.resource = None + self.user_nick = None + self.xhtml = None + self.label = None + self.session = None + self.forward_from = None + self.form_node = None + self.original_message = '' + self.delayed = None + self.callback = None + self.callback_args = [] + self.now = False + + def generate(self): + return True \ No newline at end of file diff --git a/src/common/ged.py b/src/common/ged.py index 81af8d9955c1d019642c21e6ae37df607e8293d2..e4035fefb16878a0e23010119fe20464aa96bcc9 100644 --- a/src/common/ged.py +++ b/src/common/ged.py @@ -21,6 +21,7 @@ Global Events Dispatcher module. :author: Mateusz Biliński <mateusz@bilinski.it> :since: 8th August 2008 :copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it> +:copyright: Copyright (2011) Yann Leboulanger <asterix@lagaule.org> :license: GPL ''' @@ -39,6 +40,18 @@ GUI2 = 90 POSTGUI2 = 100 POSTGUI = 110 +OUT_PREGUI = 10 +OUT_PREGUI1 = 20 +OUT_GUI1 = 30 +OUT_POSTGUI1 = 40 +OUT_PREGUI2 = 50 +OUT_GUI2 = 60 +OUT_POSTGUI2 = 70 +OUT_POSTGUI = 80 +OUT_PRECORE = 90 +OUT_CORE = 100 +OUT_POSTCORE = 110 + class GlobalEventsDispatcher(object): def __init__(self): diff --git a/src/common/nec.py b/src/common/nec.py index dcb03ad1e5454860343a45a6d6eb7a2a19a06986..229771ad5ad1ac90627765de3aecdd8deebff091 100644 --- a/src/common/nec.py +++ b/src/common/nec.py @@ -21,6 +21,7 @@ Network Events Controller. :author: Mateusz Biliński <mateusz@bilinski.it> :since: 10th August 2008 :copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it> +:copyright: Copyright (2011) Yann Leboulanger <asterix@lagaule.org> :license: GPL ''' @@ -38,23 +39,38 @@ class NetworkEventsController(object): Values: list of class objects that are subclasses of `NetworkIncomingEvent` ''' + self.outgoing_events_generators = {} + ''' + Keys: names of events + Values: list of class objects that are subclasses + of `NetworkOutgoingEvent` + ''' def register_incoming_event(self, event_class): for base_event_name in event_class.base_network_events: - event_list = self.incoming_events_generators.setdefault(base_event_name, []) + event_list = self.incoming_events_generators.setdefault( + base_event_name, []) if not event_class in event_list: event_list.append(event_class) def unregister_incoming_event(self, event_class): for base_event_name in event_class.base_network_events: if base_event_name in self.incoming_events_generators: - self.incoming_events_generators[base_event_name].remove(event_class) + self.incoming_events_generators[base_event_name].remove( + event_class) def register_outgoing_event(self, event_class): - pass + for base_event_name in event_class.base_network_events: + event_list = self.outgoing_events_generators.setdefault( + base_event_name, []) + if not event_class in event_list: + event_list.append(event_class) def unregister_outgoing_event(self, event_class): - pass + for base_event_name in event_class.base_network_events: + if base_event_name in self.outgoing_events_generators: + self.outgoing_events_generators[base_event_name].remove( + event_class) def push_incoming_event(self, event_object): if event_object.generate(): @@ -62,7 +78,9 @@ class NetworkEventsController(object): self._generate_events_based_on_incoming_event(event_object) def push_outgoing_event(self, event_object): - pass + if event_object.generate(): + if not gajim.ged.raise_event(event_object.name, event_object): + self._generate_events_based_on_outgoing_event(event_object) def _generate_events_based_on_incoming_event(self, event_object): ''' @@ -75,11 +93,36 @@ class NetworkEventsController(object): ''' base_event_name = event_object.name if base_event_name in self.incoming_events_generators: - for new_event_class in self.incoming_events_generators[base_event_name]: - new_event_object = new_event_class(None, base_event=event_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(): - if not 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) + + def _generate_events_based_on_outgoing_event(self, event_object): + ''' + :return: True if even_object should be dispatched through Global + Events Dispatcher, False otherwise. This can be used to replace + base events with those that more data computed (easier to use + by handlers). + :note: replacing mechanism is not implemented currently, but will be + based on attribute in new network events object. + ''' + base_event_name = event_object.name + if base_event_name in self.outgoing_events_generators: + for new_event_class in self.outgoing_events_generators[ + base_event_name]: + new_event_object = new_event_class(None, + base_event=event_object) + if new_event_object.generate(): + if not gajim.ged.raise_event(new_event_object.name, + new_event_object): + self._generate_events_based_on_outgoing_event( + new_event_object) class NetworkEvent(object): name = '' @@ -88,10 +131,10 @@ class NetworkEvent(object): if new_name: self.name = new_name - self._set_kwargs_as_attributes(**kwargs) - self.init() + self._set_kwargs_as_attributes(**kwargs) + def init(self): pass @@ -130,5 +173,7 @@ class NetworkIncomingEvent(NetworkEvent): class NetworkOutgoingEvent(NetworkEvent): - pass - + base_network_events = [] + ''' + Names of base network events that new event is going to be generated on. + ''' \ No newline at end of file diff --git a/src/message_control.py b/src/message_control.py index 322de94b3e32fc4ab4e4d95367f55ebab6b2e9d4..14efb42dafdf8b1420265f176d3cbadcdf0fd231 100644 --- a/src/message_control.py +++ b/src/message_control.py @@ -30,6 +30,7 @@ import gtkgui_helpers from common import gajim from common import helpers +from common import ged from common.stanza_session import EncryptedStanzaSession, ArchivingStanzaSession # Derived types MUST register their type IDs here if custom behavor is required @@ -64,6 +65,9 @@ class MessageControl(object): self.xml = gtkgui_helpers.get_gtk_builder('%s.ui' % widget_name) self.widget = self.xml.get_object('%s_hbox' % widget_name) + gajim.ged.register_event_handler('message-outgoing', ged.OUT_GUI1, + self._nec_message_outgoing) + def get_full_jid(self): fjid = self.contact.jid if self.resource: @@ -110,7 +114,8 @@ class MessageControl(object): """ Derived classes MUST implement this """ - pass + gajim.ged.remove_event_handler('message-outgoing', ged.OUT_GUI1, + self._nec_message_outgoing) def repaint_themed_widgets(self): """ @@ -214,40 +219,35 @@ class MessageControl(object): if crypto_changed or archiving_changed: self.print_session_details() - def send_message(self, message, keyID='', type_='chat', chatstate=None, - msg_id=None, composing_xep=None, resource=None, user_nick=None, - xhtml=None, label=None, callback=None, callback_args=[]): + def _nec_message_outgoing(self, obj): # Send the given message to the active tab. # Doesn't return None if error - jid = self.contact.jid + if obj.account != self.account: + return - message = helpers.remove_invalid_xml_chars(message) + obj.jid = self.contact.jid + obj.message = helpers.remove_invalid_xml_chars(obj.message) + obj.original_message = obj.message - original_message = message conn = gajim.connections[self.account] if not self.session: - if not resource: + if not obj.resource: if self.resource: - resource = self.resource + obj.resource = self.resource else: - resource = self.contact.resource - sess = conn.find_controlless_session(jid, resource=resource) + obj.resource = self.contact.resource + sess = conn.find_controlless_session(obj.jid, resource=obj.resource) if self.resource: - jid += '/' + self.resource + obj.jid += '/' + self.resource if not sess: if self.type_id == TYPE_PM: - sess = conn.make_new_session(jid, type_='pm') + sess = conn.make_new_session(obj.jid, type_='pm') else: - sess = conn.make_new_session(jid) + sess = conn.make_new_session(obj.jid) self.set_session(sess) - # Send and update history - conn.send_message(jid, message, keyID, type_=type_, chatstate=chatstate, - msg_id=msg_id, composing_xep=composing_xep, resource=self.resource, - user_nick=user_nick, session=self.session, - original_message=original_message, xhtml=xhtml, label=label, callback=callback, - callback_args=callback_args) + obj.session = self.session