Commit cc032163 authored by Yann Leboulanger's avatar Yann Leboulanger

more usage of NEC to handle messages

parent 2c1f20b7
......@@ -1603,6 +1603,8 @@ def __init__(self, parent_win, contact, acct, session, resource = None):
gajim.ged.register_event_handler('failed-decrypt', ged.GUI1,
gajim.ged.register_event_handler('chatstate-received', ged.GUI1,
# PluginSystem: adding GUI extension point for this ChatControl
# instance object
......@@ -2593,6 +2595,8 @@ def shutdown(self):
gajim.ged.remove_event_handler('failed-decrypt', ged.GUI1,
gajim.ged.remove_event_handler('chatstate-received', ged.GUI1,
self.send_chatstate('gone', = None
......@@ -2661,7 +2665,7 @@ def on_cancel():
def handle_incoming_chatstate(self):
def _nec_chatstate_received(self, obj):
Handle incoming chatstate that jid SENT TO us
......@@ -1329,18 +1329,15 @@ def _nec_decrypted_message_received(self, obj):
if obj.mtype == 'error':
self.dispatch_error_message(obj.stanza, obj.msgtxt,
obj.session, obj.fjid, obj.timestamp)
return True
elif obj.mtype == 'groupchat':,
conn=self, msg_obj=obj))
return True
elif obj.invite_tag is not None:,
conn=self, msg_obj=obj))
if isinstance(obj.session, gajim.default_session_type):
obj.session.received(obj.fjid, obj.msgtxt, obj.timestamp,
obj.encrypted, obj.stanza)
return True
# process and dispatch an error message
def dispatch_error_message(self, msg, msgtxt, session, frm, tim):
......@@ -65,6 +65,34 @@ def _generate_timestamp(self, tag):
tim = helpers.datetime_tuple(tag)
self.timestamp = localtime(timegm(tim))
def get_chatstate(self):
Extract chatstate from a <message/> stanza
Requires self.stanza and self.msgtxt
self.composing_xep = None
self.chatstate = None
# chatstates - look for chatstate tags in a message if not delayed
delayed = self.stanza.getTag('x', namespace=xmpp.NS_DELAY) is not None
if not delayed:
self.composing_xep = False
children = self.stanza.getChildren()
for child in children:
if child.getNamespace() == '':
self.chatstate = child.getName()
self.composing_xep = 'XEP-0085'
# No XEP-0085 support, fallback to XEP-0022
if not self.chatstate:
chatstate_child = self.stanza.getTag('x',
if chatstate_child:
self.chatstate = 'active'
self.composing_xep = 'XEP-0022'
if not self.msgtxt and chatstate_child.getTag('composing'):
self.chatstate = 'composing'
class HttpAuthReceivedEvent(nec.NetworkIncomingEvent):
name = 'http-auth-received'
base_network_events = []
......@@ -1021,7 +1049,7 @@ def generate(self):
return True
class DecryptedMessageReceivedEvent(nec.NetworkIncomingEvent):
class DecryptedMessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
name = 'decrypted-message-received'
base_network_events = []
......@@ -1044,6 +1072,43 @@ def generate(self):
self.receipt_received_tag = self.stanza.getTag('received',
self.subject = self.stanza.getSubject()
self.displaymarking = None
self.seclabel = self.stanza.getTag('securitylabel',
if self.seclabel:
self.displaymarking = self.seclabel.getTag('displaymarking')
self.form_node = self.stanza.getTag('x', namespace=xmpp.NS_DATA)
if gajim.config.get('ignore_incoming_xhtml'):
self.xhtml = None
self.xhtml = self.stanza.getXHTML()
# XEP-0172 User Nickname
self.user_nick = self.stanza.getTagData('nick') or ''
treat_as = gajim.config.get('treat_incoming_messages')
if treat_as:
self.mtype = treat_as
return True
class ChatstateReceivedEvent(nec.NetworkIncomingEvent):
name = 'chatstate-received'
base_network_events = []
def generate(self):
self.stanza = self.msg_obj.stanza
self.jid = self.msg_obj.jid
self.fjid = self.msg_obj.fjid
self.resource = self.msg_obj.resource
self.composing_xep = self.msg_obj.composing_xep
self.chatstate = self.msg_obj.chatstate
return True
class GcMessageReceivedEvent(nec.NetworkIncomingEvent):
......@@ -27,6 +27,8 @@
from common import gajim
from common import stanza_session
from common import contacts
from common import ged
from common.connection_handlers_events import ChatstateReceivedEvent
import common.xmpp
......@@ -41,12 +43,16 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
def __init__(self, conn, jid, thread_id, type_='chat'):
stanza_session.EncryptedStanzaSession.__init__(self, conn, jid, thread_id,
gajim.ged.register_event_handler('decrypted-message-received', ged.GUI1,
self.control = None
def detach_from_control(self):
if self.control:
ged.GUI1, self._nec_decrypted_message_received)
def acknowledge_termination(self):
......@@ -56,175 +62,107 @@ def terminate(self, send_termination = True):
stanza_session.EncryptedStanzaSession.terminate(self, send_termination)
def get_chatstate(self, msg, msgtxt):
Extract chatstate from a <message/> stanza
composing_xep = None
chatstate = None
# chatstates - look for chatstate tags in a message if not delayed
delayed = msg.getTag('x', namespace=common.xmpp.NS_DELAY) is not None
if not delayed:
composing_xep = False
children = msg.getChildren()
for child in children:
if child.getNamespace() == '':
chatstate = child.getName()
composing_xep = 'XEP-0085'
# No XEP-0085 support, fallback to XEP-0022
if not chatstate:
chatstate_child = msg.getTag('x', namespace=common.xmpp.NS_EVENT)
if chatstate_child:
chatstate = 'active'
composing_xep = 'XEP-0022'
if not msgtxt and chatstate_child.getTag('composing'):
chatstate = 'composing'
return (composing_xep, chatstate)
def received(self, full_jid_with_resource, msgtxt, tim, encrypted, msg):
def _nec_decrypted_message_received(self, obj):
Dispatch a received <message> stanza
msg_type = msg.getType()
subject = msg.getSubject()
resource = gajim.get_resource_from_jid(full_jid_with_resource)
if self.resource != resource:
self.resource = resource
if obj.session != self:
if self.resource != obj.resource:
self.resource = obj.resource
if self.control and self.control.resource:
seclabel = None
displaymarking = None
if not msg_type or msg_type not in ('chat', 'groupchat', 'error'):
msg_type = 'normal'
msg_id = None
# XEP-0172 User Nickname
user_nick = msg.getTagData('nick')
if not user_nick:
user_nick = ''
form_node = None
for xtag in msg.getTags('x'):
if xtag.getNamespace() == common.xmpp.NS_DATA:
form_node = xtag
composing_xep, chatstate = self.get_chatstate(msg, msgtxt)
seclabel = msg.getTag('securitylabel')
if seclabel and seclabel.getNamespace() == common.xmpp.NS_SECLABEL:
displaymarking = seclabel.getTag('displaymarking')
xhtml = msg.getXHTML()
if msg_type == 'chat':
if not msg.getTag('body') and chatstate is None:
if obj.mtype == 'chat':
if not obj.stanza.getTag('body') and obj.chatstate is None:
log_type = 'chat_msg_recv'
log_type = 'single_msg_recv'
if self.is_loggable() and msgtxt:
if self.is_loggable() and obj.msgtxt:
msg_id = gajim.logger.write(log_type, full_jid_with_resource,
msgtxt, tim=tim, subject=subject)
msg_id = gajim.logger.write(log_type, obj.fjid,
obj.msgtxt, tim=obj.timestamp, subject=obj.subject)
except exceptions.PysqliteOperationalError, e:
self.conn.dispatch('ERROR', (_('Disk WriteError'), str(e)))
except exceptions.DatabaseMalformed:
pritext = _('Database Error')
sectext = _('The database file (%s) cannot be read. Try to repair '
'it (see or remove '
'it (all history will be lost).') % common.logger.LOG_DB_PATH
sectext = _('The database file (%s) cannot be read. Try to '
'repair it (see '
'or remove it (all history will be lost).') % \
self.conn.dispatch('ERROR', (pritext, sectext))
treat_as = gajim.config.get('treat_incoming_messages')
if treat_as:
msg_type = treat_as
jid = gajim.get_jid_without_resource(full_jid_with_resource)
resource = gajim.get_resource_from_jid(full_jid_with_resource)
if gajim.config.get('ignore_incoming_xhtml'):
xhtml = None
if gajim.jid_is_transport(jid):
jid = jid.replace('@', '')
groupchat_control = gajim.interface.msg_win_mgr.get_gc_control(jid,
if not groupchat_control and \
jid in gajim.interface.minimized_controls[]:
groupchat_control = gajim.interface.minimized_controls[]\
pm = False
if groupchat_control and groupchat_control.type_id == \
message_control.TYPE_GC and resource:
if obj.gc_control and obj.resource:
# It's a Private message
pm = True
msg_type = 'pm'
obj.mtype = 'pm'
highest_contact = gajim.contacts.get_contact_with_highest_priority(, jid), obj.jid)
# does this resource have the highest priority of any available?
is_highest = not highest_contact or not highest_contact.resource or \
resource == highest_contact.resource or == \
obj.resource == highest_contact.resource or ==\
# Handle chat states
contact = gajim.contacts.get_contact(, jid, resource)
contact = gajim.contacts.get_contact(, obj.jid,
if contact:
if contact.composing_xep != 'XEP-0085': # We cache xep85 support
contact.composing_xep = composing_xep
if self.control and self.control.type_id == message_control.TYPE_CHAT:
if chatstate is not None:
contact.composing_xep = obj.composing_xep
if self.control and self.control.type_id == \
if obj.chatstate is not None:
# other peer sent us reply, so he supports jep85 or jep22
contact.chatstate = chatstate
contact.chatstate = obj.chatstate
if contact.our_chatstate == 'ask': # we were jep85 disco?
contact.our_chatstate = 'active' # no more
conn=obj.conn, msg_obj=obj))
elif contact.chatstate != 'active':
# got no valid jep85 answer, peer does not support it
contact.chatstate = False
elif chatstate == 'active':
elif obj.chatstate == 'active':
# Brand new message, incoming.
contact.our_chatstate = chatstate
contact.chatstate = chatstate
contact.our_chatstate = obj.chatstate
contact.chatstate = obj.chatstate
if msg_id: # Do not overwrite an existing msg_id with None
contact.msg_id = msg_id
# THIS MUST BE AFTER chatstates handling
# AND BEFORE playsound (else we ear sounding on chatstates!)
if not msgtxt: # empty message text
if not obj.msgtxt: # empty message text
if gajim.config.get_per('accounts',,
'ignore_unknown_contacts') and not gajim.contacts.get_contacts(, jid) and not pm:, obj.jid) and not pm:
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=jid,, resource=resource)
contact = gajim.contacts.create_not_in_roster_contact(jid=obj.jid,, resource=obj.resource)
advanced_notif_num = notify.get_advanced_notification('message_received',, contact)
advanced_notif_num = notify.get_advanced_notification(
'message_received',, contact)
if not pm and is_highest:
jid_of_control = jid
jid_of_control = obj.jid
jid_of_control = full_jid_with_resource
jid_of_control = obj.fjid
if not self.control:
ctrl = gajim.interface.msg_win_mgr.get_control(jid_of_control,
if ctrl:
self.control = ctrl
......@@ -232,50 +170,55 @@ def received(self, full_jid_with_resource, msgtxt, tim, encrypted, msg):
# Is it a first or next message received ?
first = False
if not self.control and not, \
jid_of_control, [msg_type]):
jid_of_control, [obj.mtype]):
first = True
if pm:
nickname = resource
nickname = obj.resource
if self.control:
# print if a control is open
self.control.print_conversation(msgtxt, tim=tim, xhtml=xhtml,
encrypted=encrypted, displaymarking=displaymarking)
self.control.print_conversation(obj.msgtxt, tim=obj.timestamp,
xhtml=obj.xhtml, encrypted=obj.encrypted,
# otherwise pass it off to the control to be queued
groupchat_control.on_private_message(nickname, msgtxt, tim,
xhtml, self, msg_id=msg_id, encrypted=encrypted, displaymarking=displaymarking)
obj.gc_control.on_private_message(nickname, obj.msgtxt,
obj.timestamp, obj.xhtml, self, msg_id=msg_id,
encrypted=obj.encrypted, displaymarking=obj.displaymarking)
self.roster_message(jid, msgtxt, tim, encrypted, msg_type,
subject, resource, msg_id, user_nick, advanced_notif_num,
xhtml=xhtml, form_node=form_node, displaymarking=displaymarking)
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,
nickname = gajim.get_name_from_jid(, jid)
nickname = gajim.get_name_from_jid(, obj.jid)
# Check and do wanted notifications
msg = msgtxt
if subject:
msg = _('Subject: %s') % subject + '\n' + msg
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 \
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,, [msg_type,
notify.notify('new_message', jid_of_control,, [obj.mtype,
first, nickname, msg, focused], advanced_notif_num)
if gajim.interface.remote_ctrl:
gajim.interface.remote_ctrl.raise_signal('NewMessage', (,
[full_jid_with_resource, msgtxt, tim, encrypted, msg_type, subject,
chatstate, msg_id, composing_xep, user_nick, xhtml, form_node]))
(, [full_jid_with_resource, msgtxt, tim,
encrypted, msg_type, subject, chatstate, msg_id,
composing_xep, user_nick, xhtml, form_node]))
gajim.interface.remote_ctrl.raise_signal('NewMessage', (, [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]))
(, [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_message(self, jid, msg, tim, encrypted=False, msg_type='',
subject=None, resource='', msg_id=None, user_nick='',
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