handle outgoing messages with events. Fixes #6743

This commit is contained in:
Yann Leboulanger 2011-05-18 19:44:43 +02:00
parent 9fc82bbffc
commit 4ac1768040
6 changed files with 163 additions and 43 deletions

View File

@ -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':

View File

@ -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)

View File

@ -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

View File

@ -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):

View File

@ -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.
'''

View File

@ -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