more usage of NEC to handle messages

This commit is contained in:
Yann Leboulanger 2010-12-08 21:58:13 +01:00
parent 2c1f20b773
commit cc032163d0
4 changed files with 148 additions and 139 deletions

View File

@ -1603,6 +1603,8 @@ class ChatControl(ChatControlBase):
self._nec_vcard_received)
gajim.ged.register_event_handler('failed-decrypt', ged.GUI1,
self._nec_failed_decrypt)
gajim.ged.register_event_handler('chatstate-received', ged.GUI1,
self._nec_chatstate_received)
# PluginSystem: adding GUI extension point for this ChatControl
# instance object
@ -2593,6 +2595,8 @@ class ChatControl(ChatControlBase):
self._nec_vcard_received)
gajim.ged.remove_event_handler('failed-decrypt', ged.GUI1,
self._nec_failed_decrypt)
gajim.ged.remove_event_handler('chatstate-received', ged.GUI1,
self._nec_chatstate_received)
self.send_chatstate('gone', self.contact)
self.contact.chatstate = None
@ -2661,7 +2665,7 @@ class ChatControl(ChatControlBase):
return
on_yes(self)
def handle_incoming_chatstate(self):
def _nec_chatstate_received(self, obj):
"""
Handle incoming chatstate that jid SENT TO us
"""

View File

@ -1329,18 +1329,15 @@ ConnectionJingle, ConnectionIBBytestream):
if obj.mtype == 'error':
self.dispatch_error_message(obj.stanza, obj.msgtxt,
obj.session, obj.fjid, obj.timestamp)
return True
elif obj.mtype == 'groupchat':
gajim.nec.push_incoming_event(GcMessageReceivedEvent(None,
conn=self, msg_obj=obj))
return True
elif obj.invite_tag is not None:
gajim.nec.push_incoming_event(GcInvitationReceivedEvent(None,
conn=self, msg_obj=obj))
else:
if isinstance(obj.session, gajim.default_session_type):
obj.session.received(obj.fjid, obj.msgtxt, obj.timestamp,
obj.encrypted, obj.stanza)
else:
obj.session.received(obj.stanza)
return True
# process and dispatch an error message
def dispatch_error_message(self, msg, msgtxt, session, frm, tim):

View File

@ -65,6 +65,34 @@ class HelperEvent:
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() == 'http://jabber.org/protocol/chatstates':
self.chatstate = child.getName()
self.composing_xep = 'XEP-0085'
break
# No XEP-0085 support, fallback to XEP-0022
if not self.chatstate:
chatstate_child = self.stanza.getTag('x',
namespace=xmpp.NS_EVENT)
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 @@ class GcInvitationReceivedEvent(nec.NetworkIncomingEvent):
return True
class DecryptedMessageReceivedEvent(nec.NetworkIncomingEvent):
class DecryptedMessageReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
name = 'decrypted-message-received'
base_network_events = []
@ -1044,6 +1072,43 @@ class DecryptedMessageReceivedEvent(nec.NetworkIncomingEvent):
namespace=xmpp.NS_RECEIPTS)
self.receipt_received_tag = self.stanza.getTag('received',
namespace=xmpp.NS_RECEIPTS)
self.subject = self.stanza.getSubject()
self.displaymarking = None
self.seclabel = self.stanza.getTag('securitylabel',
namespace=xmpp.NS_SECLABEL)
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
else:
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
self.get_chatstate()
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):

View File

@ -27,6 +27,8 @@ from common import exceptions
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,
type_='chat')
gajim.ged.register_event_handler('decrypted-message-received', ged.GUI1,
self._nec_decrypted_message_received)
self.control = None
def detach_from_control(self):
if self.control:
self.control.set_session(None)
gajim.ged.remove_event_handler('decrypted-message-received',
ged.GUI1, self._nec_decrypted_message_received)
def acknowledge_termination(self):
self.detach_from_control()
@ -56,175 +62,107 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
stanza_session.EncryptedStanzaSession.terminate(self, send_termination)
self.detach_from_control()
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() == 'http://jabber.org/protocol/chatstates':
chatstate = child.getName()
composing_xep = 'XEP-0085'
break
# 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:
return
if self.resource != obj.resource:
self.resource = obj.resource
if self.control and self.control.resource:
self.control.change_resource(self.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
break
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:
return
log_type = 'chat_msg_recv'
else:
log_type = 'single_msg_recv'
if self.is_loggable() and msgtxt:
if self.is_loggable() and obj.msgtxt:
try:
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 http://trac.gajim.org/wiki/DatabaseBackup) 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 http://trac.gajim.org/wiki/DatabaseBackup) '
'or remove it (all history will be lost).') % \
common.logger.LOG_DB_PATH
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,
self.conn.name)
if not groupchat_control and \
jid in gajim.interface.minimized_controls[self.conn.name]:
groupchat_control = gajim.interface.minimized_controls[self.conn.name]\
[jid]
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(
self.conn.name, jid)
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 \
resource == highest_contact.resource or highest_contact.show == \
'offline'
obj.resource == highest_contact.resource or highest_contact.show ==\
'offline'
# Handle chat states
contact = gajim.contacts.get_contact(self.conn.name, jid, resource)
contact = gajim.contacts.get_contact(self.conn.name, obj.jid,
obj.resource)
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 == \
message_control.TYPE_CHAT:
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
self.control.handle_incoming_chatstate()
gajim.nec.push_incoming_event(ChatstateReceivedEvent(None,
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
return
if gajim.config.get_per('accounts', self.conn.name,
'ignore_unknown_contacts') and not gajim.contacts.get_contacts(
self.conn.name, jid) and not pm:
self.conn.name, obj.jid) and not pm:
return
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,
account=self.conn.name, resource=resource)
contact = gajim.contacts.create_not_in_roster_contact(jid=obj.jid,
account=self.conn.name, resource=obj.resource)
advanced_notif_num = notify.get_advanced_notification('message_received',
self.conn.name, contact)
advanced_notif_num = notify.get_advanced_notification(
'message_received', self.conn.name, contact)
if not pm and is_highest:
jid_of_control = jid
jid_of_control = obj.jid
else:
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,
self.conn.name)
self.conn.name)
if ctrl:
self.control = ctrl
self.control.set_session(self)
@ -232,50 +170,55 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
# 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, [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,
displaymarking=obj.displaymarking)
else:
# 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)
else:
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,
displaymarking=obj.displaymarking)
nickname = gajim.get_name_from_jid(self.conn.name, jid)
nickname = gajim.get_name_from_jid(self.conn.name, 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 \
parent_win.window.has_focus:
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, [msg_type,
notify.notify('new_message', jid_of_control, self.conn.name, [obj.mtype,
first, nickname, msg, focused], advanced_notif_num)
if gajim.interface.remote_ctrl:
gajim.interface.remote_ctrl.raise_signal('NewMessage', (self.conn.name,
[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', (
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]))
gajim.ged.raise_event('NewMessage',
(self.conn.name, [full_jid_with_resource, msgtxt, tim,
encrypted, msg_type, subject, chatstate, msg_id,
composing_xep, user_nick, xhtml, 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_message(self, jid, msg, tim, encrypted=False, msg_type='',
subject=None, resource='', msg_id=None, user_nick='',