more usage of NEC to handle messages
This commit is contained in:
parent
2c1f20b773
commit
cc032163d0
4 changed files with 148 additions and 139 deletions
|
@ -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
|
||||
"""
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
199
src/session.py
199
src/session.py
|
@ -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,171 +62,103 @@ 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 == \
|
||||
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,
|
||||
|
@ -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]))
|
||||
(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='',
|
||||
|
|
Loading…
Add table
Reference in a new issue