Commit 4ac17680 authored by Yann Leboulanger's avatar Yann Leboulanger

handle outgoing messages with events. Fixes #6743

parent 9fc82bbf
...@@ -54,6 +54,7 @@ from common.pep import MOODS, ACTIVITIES ...@@ -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_XHTML, NS_XHTML_IM, NS_FILE, NS_MUC
from common.xmpp.protocol import NS_RECEIPTS, NS_ESESSION 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.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 ChatCommandProcessor
from command_system.implementation.middleware import CommandTools from command_system.implementation.middleware import CommandTools
...@@ -517,6 +518,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): ...@@ -517,6 +518,7 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
menu.show_all() menu.show_all()
def shutdown(self): def shutdown(self):
super(ChatControlBase, self).shutdown()
# PluginSystem: removing GUI extension points connected with ChatControlBase # PluginSystem: removing GUI extension points connected with ChatControlBase
# instance object # instance object
gajim.plugin_manager.remove_gui_extension_point('chat_control_base', self) gajim.plugin_manager.remove_gui_extension_point('chat_control_base', self)
...@@ -848,8 +850,8 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): ...@@ -848,8 +850,8 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
return label return label
def send_message(self, message, keyID='', type_='chat', chatstate=None, def send_message(self, message, keyID='', type_='chat', chatstate=None,
msg_id=None, composing_xep=None, resource=None, xhtml=None, msg_id=None, composing_xep=None, resource=None, xhtml=None, callback=None,
callback=None, callback_args=[], process_commands=True): callback_args=[], process_commands=True):
""" """
Send the given message to the active tab. Doesn't return None if error Send the given message to the active tab. Doesn't return None if error
""" """
...@@ -860,11 +862,12 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools): ...@@ -860,11 +862,12 @@ class ChatControlBase(MessageControl, ChatCommandProcessor, CommandTools):
return return
label = self.get_seclabel() label = self.get_seclabel()
MessageControl.send_message(self, message, keyID, type_=type_,
chatstate=chatstate, msg_id=msg_id, composing_xep=composing_xep, gajim.nec.push_outgoing_event(MessageOutgoingEvent(None,
resource=resource, user_nick=self.user_nick, xhtml=xhtml, account=self.account, message=message, keyID=keyID, type_=type_,
label=label, chatstate=chatstate, msg_id=msg_id, composing_xep=composing_xep,
callback=callback, callback_args=callback_args) resource=resource, user_nick=self.user_nick, xhtml=xhtml,
label=label, callback=callback, callback_args= callback_args))
# Record the history of sent messages # Record the history of sent messages
self.save_message(message, 'sent') self.save_message(message, 'sent')
...@@ -2209,6 +2212,7 @@ class ChatControl(ChatControlBase): ...@@ -2209,6 +2212,7 @@ class ChatControl(ChatControlBase):
""" """
Send a message to contact Send a message to contact
""" """
message = helpers.remove_invalid_xml_chars(message)
if message in ('', None, '\n'): if message in ('', None, '\n'):
return None return None
...@@ -2624,12 +2628,14 @@ class ChatControl(ChatControlBase): ...@@ -2624,12 +2628,14 @@ class ChatControl(ChatControlBase):
# if we're inactive prevent composing (JEP violation) # if we're inactive prevent composing (JEP violation)
if contact.our_chatstate == 'inactive' and state == 'composing': if contact.our_chatstate == 'inactive' and state == 'composing':
# go active before # 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' contact.our_chatstate = 'active'
self.reset_kbd_mouse_timeout_vars() self.reset_kbd_mouse_timeout_vars()
MessageControl.send_message(self, "", chatstate = state, gajim.nec.push_outgoing_event(MessageOutgoingEvent(None,
msg_id = contact.msg_id, composing_xep = contact.composing_xep) account=self.account, chatstate=state, msg_id=contact.msg_id,
composing_xep=contact.composing_xep))
contact.our_chatstate = state contact.our_chatstate = state
if contact.our_chatstate == 'active': if contact.our_chatstate == 'active':
......
...@@ -717,6 +717,8 @@ class Connection(CommonConnection, ConnectionHandlers): ...@@ -717,6 +717,8 @@ class Connection(CommonConnection, ConnectionHandlers):
self._nec_agent_info_error_received) self._nec_agent_info_error_received)
gajim.ged.register_event_handler('agent-info-received', ged.CORE, gajim.ged.register_event_handler('agent-info-received', ged.CORE,
self._nec_agent_info_received) self._nec_agent_info_received)
gajim.ged.register_event_handler('message-outgoing', ged.OUT_CORE,
self._nec_message_outgoing)
# END __init__ # END __init__
def cleanup(self): def cleanup(self):
...@@ -727,6 +729,8 @@ class Connection(CommonConnection, ConnectionHandlers): ...@@ -727,6 +729,8 @@ class Connection(CommonConnection, ConnectionHandlers):
self._nec_agent_info_error_received) self._nec_agent_info_error_received)
gajim.ged.remove_event_handler('agent-info-received', ged.CORE, gajim.ged.remove_event_handler('agent-info-received', ged.CORE,
self._nec_agent_info_received) 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): def get_config_values_or_default(self):
if gajim.config.get_per('accounts', self.name, 'keep_alives_enabled'): if gajim.config.get_per('accounts', self.name, 'keep_alives_enabled'):
...@@ -1764,6 +1768,30 @@ class Connection(CommonConnection, ConnectionHandlers): ...@@ -1764,6 +1768,30 @@ class Connection(CommonConnection, ConnectionHandlers):
session=session, forward_from=forward_from, form_node=form_node, session=session, forward_from=forward_from, form_node=form_node,
original_message=original_message, delayed=delayed, callback=cb) 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): def send_contacts(self, contacts, jid):
""" """
Send contacts with RosterX (Xep-0144) Send contacts with RosterX (Xep-0144)
......
...@@ -2042,3 +2042,31 @@ class NotificationEvent(nec.NetworkIncomingEvent): ...@@ -2042,3 +2042,31 @@ class NotificationEvent(nec.NetworkIncomingEvent):
elif self.notif_type == 'pres': elif self.notif_type == 'pres':
self.handle_incoming_pres_event(self.base_event) self.handle_incoming_pres_event(self.base_event)
return True 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
...@@ -21,6 +21,7 @@ Global Events Dispatcher module. ...@@ -21,6 +21,7 @@ Global Events Dispatcher module.
:author: Mateusz Biliński <mateusz@bilinski.it> :author: Mateusz Biliński <mateusz@bilinski.it>
:since: 8th August 2008 :since: 8th August 2008
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it> :copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
:copyright: Copyright (2011) Yann Leboulanger <asterix@lagaule.org>
:license: GPL :license: GPL
''' '''
...@@ -39,6 +40,18 @@ GUI2 = 90 ...@@ -39,6 +40,18 @@ GUI2 = 90
POSTGUI2 = 100 POSTGUI2 = 100
POSTGUI = 110 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): class GlobalEventsDispatcher(object):
def __init__(self): def __init__(self):
......
...@@ -21,6 +21,7 @@ Network Events Controller. ...@@ -21,6 +21,7 @@ Network Events Controller.
:author: Mateusz Biliński <mateusz@bilinski.it> :author: Mateusz Biliński <mateusz@bilinski.it>
:since: 10th August 2008 :since: 10th August 2008
:copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it> :copyright: Copyright (2008) Mateusz Biliński <mateusz@bilinski.it>
:copyright: Copyright (2011) Yann Leboulanger <asterix@lagaule.org>
:license: GPL :license: GPL
''' '''
...@@ -38,23 +39,38 @@ class NetworkEventsController(object): ...@@ -38,23 +39,38 @@ class NetworkEventsController(object):
Values: list of class objects that are subclasses Values: list of class objects that are subclasses
of `NetworkIncomingEvent` 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): def register_incoming_event(self, event_class):
for base_event_name in event_class.base_network_events: 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: if not event_class in event_list:
event_list.append(event_class) event_list.append(event_class)
def unregister_incoming_event(self, event_class): def unregister_incoming_event(self, event_class):
for base_event_name in event_class.base_network_events: for base_event_name in event_class.base_network_events:
if base_event_name in self.incoming_events_generators: 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): 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): 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): def push_incoming_event(self, event_object):
if event_object.generate(): if event_object.generate():
...@@ -62,7 +78,9 @@ class NetworkEventsController(object): ...@@ -62,7 +78,9 @@ class NetworkEventsController(object):
self._generate_events_based_on_incoming_event(event_object) self._generate_events_based_on_incoming_event(event_object)
def push_outgoing_event(self, 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): def _generate_events_based_on_incoming_event(self, event_object):
''' '''
...@@ -75,11 +93,36 @@ class NetworkEventsController(object): ...@@ -75,11 +93,36 @@ class NetworkEventsController(object):
''' '''
base_event_name = event_object.name base_event_name = event_object.name
if base_event_name in self.incoming_events_generators: if base_event_name in self.incoming_events_generators:
for new_event_class in self.incoming_events_generators[base_event_name]: for new_event_class in self.incoming_events_generators[
new_event_object = new_event_class(None, base_event=event_object) base_event_name]:
new_event_object = new_event_class(None,
base_event=event_object)
if new_event_object.generate(): if new_event_object.generate():
if not gajim.ged.raise_event(new_event_object.name, new_event_object): if not gajim.ged.raise_event(new_event_object.name,
self._generate_events_based_on_incoming_event(new_event_object) 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): class NetworkEvent(object):
name = '' name = ''
...@@ -88,10 +131,10 @@ class NetworkEvent(object): ...@@ -88,10 +131,10 @@ class NetworkEvent(object):
if new_name: if new_name:
self.name = new_name self.name = new_name
self._set_kwargs_as_attributes(**kwargs)
self.init() self.init()
self._set_kwargs_as_attributes(**kwargs)
def init(self): def init(self):
pass pass
...@@ -130,5 +173,7 @@ class NetworkIncomingEvent(NetworkEvent): ...@@ -130,5 +173,7 @@ class NetworkIncomingEvent(NetworkEvent):
class NetworkOutgoingEvent(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
...@@ -30,6 +30,7 @@ import gtkgui_helpers ...@@ -30,6 +30,7 @@ import gtkgui_helpers
from common import gajim from common import gajim
from common import helpers from common import helpers
from common import ged
from common.stanza_session import EncryptedStanzaSession, ArchivingStanzaSession from common.stanza_session import EncryptedStanzaSession, ArchivingStanzaSession
# Derived types MUST register their type IDs here if custom behavor is required # Derived types MUST register their type IDs here if custom behavor is required
...@@ -64,6 +65,9 @@ class MessageControl(object): ...@@ -64,6 +65,9 @@ class MessageControl(object):
self.xml = gtkgui_helpers.get_gtk_builder('%s.ui' % widget_name) self.xml = gtkgui_helpers.get_gtk_builder('%s.ui' % widget_name)
self.widget = self.xml.get_object('%s_hbox' % 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): def get_full_jid(self):
fjid = self.contact.jid fjid = self.contact.jid
if self.resource: if self.resource:
...@@ -110,7 +114,8 @@ class MessageControl(object): ...@@ -110,7 +114,8 @@ class MessageControl(object):
""" """
Derived classes MUST implement this 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): def repaint_themed_widgets(self):
""" """
...@@ -214,40 +219,35 @@ class MessageControl(object): ...@@ -214,40 +219,35 @@ class MessageControl(object):
if crypto_changed or archiving_changed: if crypto_changed or archiving_changed:
self.print_session_details() self.print_session_details()
def send_message(self, message, keyID='', type_='chat', chatstate=None, def _nec_message_outgoing(self, obj):
msg_id=None, composing_xep=None, resource=None, user_nick=None,
xhtml=None, label=None, callback=None, callback_args=[]):
# Send the given message to the active tab. # Send the given message to the active tab.
# Doesn't return None if error # 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] conn = gajim.connections[self.account]
if not self.session: if not self.session:
if not resource: if not obj.resource:
if self.resource: if self.resource:
resource = self.resource obj.resource = self.resource
else: else:
resource = self.contact.resource obj.resource = self.contact.resource
sess = conn.find_controlless_session(jid, resource=resource) sess = conn.find_controlless_session(obj.jid, resource=obj.resource)
if self.resource: if self.resource:
jid += '/' + self.resource obj.jid += '/' + self.resource
if not sess: if not sess:
if self.type_id == TYPE_PM: if self.type_id == TYPE_PM:
sess = conn.make_new_session(jid, type_='pm') sess = conn.make_new_session(obj.jid, type_='pm')
else: else:
sess = conn.make_new_session(jid) sess = conn.make_new_session(obj.jid)
self.set_session(sess) self.set_session(sess)
# Send and update history obj.session = self.session
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)
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