diff --git a/src/chat_control.py b/src/chat_control.py index 6d27e6b5b..98efd246b 100644 --- a/src/chat_control.py +++ b/src/chat_control.py @@ -337,14 +337,14 @@ class ChatControlBase(MessageControl): return True return False - def send_message(self, message, keyID = '', type = 'chat', chatstate = None): + def send_message(self, message, keyID = '', type = 'chat', chatstate = None, msg_id = None): '''Send the given message to the active tab''' if not message or message == '\n': return if not self._process_command(message): MessageControl.send_message(self, message, keyID, type = type, - chatstate = chatstate) + chatstate = chatstate, msg_id = msg_id) # Record message history self.save_sent_message(message) @@ -974,7 +974,7 @@ class ChatControl(ChatControlBase): self._schedule_activity_timers() ChatControlBase.send_message(self, message, keyID, type = 'chat', - chatstate = chatstate_to_send) + chatstate = chatstate_to_send, msg_id = contact.msg_id) self.print_conversation(message, self.contact.jid, encrypted = encrypted) def check_for_possible_paused_chatstate(self, arg): diff --git a/src/common/connection.py b/src/common/connection.py index 98c1f3c36..eaacb3ad5 100644 --- a/src/common/connection.py +++ b/src/common/connection.py @@ -388,23 +388,20 @@ class Connection: no_log_for = gajim.config.get_per('accounts', self.name, 'no_log_for') encrypted = False chatstate = None - xtags = msg.getTags('x') - encTag = None + encTag = msg.getTag('x', namespace = common.xmpp.NS_ENCRYPTED) decmsg = '' + # invitations invite = None - delayed = False - for xtag in xtags: - if xtag.getNamespace() == common.xmpp.NS_ENCRYPTED: - encTag = xtag - # invitations - elif xtag.getNamespace() == common.xmpp.NS_MUC_USER and \ - xtag.getTag('invite') and not encTag: - invite = xtag - elif xtag.getNamespace() == common.xmpp.NS_DELAY: - delayed = True + if not encTag: + invite = msg.getTag('x', namespace = common.xmpp.NS_MUC_USER) + if invite and not invite.getTag('invite'): + invite = None + delayed = msg.getTag('x', namespace = common.xmpp.NS_DELAY) != None + msg_id = None # FIXME: Msn transport (CMSN1.2.1 and PyMSN0.10) do NOT RECOMMENDED # invitation # stanza (MUC JEP) remove in 2007, as we do not do NOT RECOMMENDED + xtags = msg.getTags('x') for xtag in xtags: if xtag.getNamespace() == common.xmpp.NS_CONFERENCE and not invite: room_jid = xtag.getAttr('jid') @@ -417,7 +414,13 @@ class Connection: if child.getNamespace() == 'http://jabber.org/protocol/chatstates': chatstate = child.getName() break - + # No JEP-0085 support, fallback to JEP-0022 + if not chatstate: + chatstate_child = msg.getTag('x', namespace = common.xmpp.NS_EVENT) + chatstate = 'active' + if not msgtxt and chatstate_child.getTag('composing'): + chatstate = 'composing' + if encTag and USE_GPG: #decrypt encmsg = encTag.getData() @@ -452,7 +455,7 @@ class Connection: no_log_for: gajim.logger.write('chat_msg_recv', frm, msgtxt, tim = tim, subject = subject) self.dispatch('MSG', (frm, msgtxt, tim, encrypted, mtype, subject, - chatstate)) + chatstate, msg_id)) else: # it's single message if self.name not in no_log_for and jid not in no_log_for: gajim.logger.write('single_msg_recv', frm, msgtxt, tim = tim, subject = subject) @@ -465,7 +468,7 @@ class Connection: self.dispatch('GC_INVITATION',(frm, jid_from, reason, password)) else: self.dispatch('MSG', (frm, msgtxt, tim, encrypted, 'normal', - subject, None)) + subject, chatstate, msg_id)) # END messageCB def _presenceCB(self, con, prs): @@ -2105,7 +2108,7 @@ class Connection: msg_iq = common.xmpp.Message(to = jid, body = msg, subject = subject) self.connection.send(msg_iq) - def send_message(self, jid, msg, keyID, type = 'chat', subject='', chatstate = None): + def send_message(self, jid, msg, keyID, type = 'chat', subject='', chatstate = None, msg_id = None): if not self.connection: return if not msg and chatstate is None: @@ -2133,12 +2136,18 @@ class Connection: if msgenc: msg_iq.setTag(common.xmpp.NS_ENCRYPTED + ' x').setData(msgenc) - # chatstates - if peer supports jep85, send chatstates + # chatstates - if peer supports jep85 or jep22, send chatstates # please note that the only valid tag inside a message containing a # tag is the active event if chatstate is not None: - msg_iq.setTag(chatstate, {}, - namespace = 'http://jabber.org/protocol/chatstates') + # JEP-0085 + msg_iq.setTag(chatstate, namespace = common.xmpp.NS_CHATSTATES) + # JEP-0022 + chatstate_node = msg_iq.setTag('x', namespace = common.xmpp.NS_EVENT) + if msg_id: + chatstate_node.setTagData('id', msg_id) + if chatstate is 'composing' or msgtxt: + chatstate_node.addChild(name = 'composing') # we request JEP-0022 composing notification self.connection.send(msg_iq) no_log_for = gajim.config.get_per('accounts', self.name, 'no_log_for') diff --git a/src/common/contacts.py b/src/common/contacts.py index 59134cf72..9be2859a5 100644 --- a/src/common/contacts.py +++ b/src/common/contacts.py @@ -48,6 +48,7 @@ class Contact: # 'ask' if we sent the first 'active' chatstate and are waiting for reply # this holds what WE SEND to contact (our current chatstate) self.our_chatstate = our_chatstate + self.msg_id = None # this is contact's chatstate self.chatstate = chatstate self.last_status_time = last_status_time diff --git a/src/gajim.py b/src/gajim.py index 4ad091c8f..a2c0ceb84 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -473,6 +473,7 @@ class Interface: resource = gajim.get_resource_from_jid(array[0]) msg_type = array[4] chatstate = array[6] + msg_id = array[7] if jid.find('@') <= 0: jid = jid.replace('@', '') @@ -512,19 +513,21 @@ class Interface: # Handle chat states contact = gajim.contacts.get_first_contact_from_jid(account, jid) if chat_control and chat_control.type_id == message_control.TYPE_CHAT: - if chatstate is not None: # he or she sent us reply, so he supports jep85 + if chatstate is not None: # he or she sent us reply, so he supports jep85 or jep22 contact.chatstate = chatstate if contact.our_chatstate == 'ask': # we were jep85 disco? contact.our_chatstate = 'active' # no more chat_control.handle_incoming_chatstate() elif contact.chatstate != 'active': - # got no valid jep85 answer, peer does not support it + # got no valid jep85 no jep22 answer, peer does not support it contact.chatstate = False elif contact and chatstate == 'active': # Brand new message, incoming. contact.our_chatstate = chatstate contact.chatstate = chatstate + if msg_id: # Do not overwrite an existing msg_id with None + contact.msg_id = msg_id if not array[1]: #empty message text return diff --git a/src/message_control.py b/src/message_control.py index be7f59e34..40f1e894d 100644 --- a/src/message_control.py +++ b/src/message_control.py @@ -133,12 +133,12 @@ class MessageControl: n = len(gajim.awaiting_events[self.account][self.contact.jid]) return n - def send_message(self, message, keyID = '', type = 'chat', chatstate = None): + def send_message(self, message, keyID = '', type = 'chat', chatstate = None, msg_id = None): '''Send the given message to the active tab''' jid = self.contact.jid # Send and update history gajim.connections[self.account].send_message(jid, message, keyID, - type = type, chatstate = chatstate) + type = type, chatstate = chatstate, msg_id = msg_id) def position_menu_under_button(self, menu): #FIXME: BUG http://bugs.gnome.org/show_bug.cgi?id=316786