From 59c3b7b3c87d5f98b5a3236b8a0145bbb42fade7 Mon Sep 17 00:00:00 2001 From: Yann Leboulanger Date: Thu, 1 Jun 2006 15:23:38 +0000 Subject: [PATCH] JEP 172 support (user nickname) Fixes #464 and #884 --- src/chat_control.py | 14 +++++++++-- src/common/connection.py | 25 +++++++++++++++++--- src/common/connection_handlers.py | 39 ++++++++++++++++++++++++------- src/common/xmpp/protocol.py | 1 + src/dialogs.py | 12 ++++++---- src/gajim.py | 8 +++---- src/message_control.py | 8 ++++--- src/roster_window.py | 13 +++++++---- 8 files changed, 91 insertions(+), 29 deletions(-) diff --git a/src/chat_control.py b/src/chat_control.py index a0862f95b..89bbfaf01 100644 --- a/src/chat_control.py +++ b/src/chat_control.py @@ -97,7 +97,8 @@ class ChatControlBase(MessageControl): event_keymod): pass # Derived should implement this rather than connecting to the event itself. - def __init__(self, type_id, parent_win, widget_name, display_names, contact, acct, resource = None): + def __init__(self, type_id, parent_win, widget_name, display_names, contact, + acct, resource = None): MessageControl.__init__(self, type_id, parent_win, widget_name, display_names, contact, acct, resource = resource); # when/if we do XHTML we will but formatting buttons back @@ -175,6 +176,10 @@ class ChatControlBase(MessageControl): self.style_event_id = 0 self.conv_textview.tv.show() + + # For JEP-0172 + self.user_nick = None + # moved from ChatControl def _on_banner_eventbox_button_press_event(self, widget, event): '''If right-clicked, show popup''' @@ -425,13 +430,18 @@ class ChatControlBase(MessageControl): if not message or message == '\n': return + if not self._process_command(message): MessageControl.send_message(self, message, keyID, type = type, chatstate = chatstate, msg_id = msg_id, - composing_jep = composing_jep, resource = resource) + composing_jep = composing_jep, resource = resource, + user_nick = self.user_nick) # Record message history self.save_sent_message(message) + # Be sure to send user nickname only once according to JEP-0172 + self.user_nick = None + # Clear msg input message_buffer = self.msg_textview.get_buffer() message_buffer.set_text('') # clear message buffer (and tv of course) diff --git a/src/common/connection.py b/src/common/connection.py index 6325a3758..852ecef00 100644 --- a/src/common/connection.py +++ b/src/common/connection.py @@ -87,8 +87,18 @@ class Connection(ConnectionHandlers): self.on_connect_failure = None self.retrycount = 0 self.jids_for_auto_auth = [] # list of jid to auto-authorize - # END __init__ + + def build_user_nick(self, user_nick): + df = common.xmpp.DataForm(typ = 'result') + field = df.setField('FORM_TYPE') + field.setType('hidden') + field.setValue(common.xmpp.NS_PROFILE) + field = df.setField('nickname') + field.delAttr('type') + field.setValue(user_nick) + return df + def put_event(self, ev): if gajim.handlers.has_key(ev[0]): gajim.handlers[ev[0]](self.name, ev[1]) @@ -606,7 +616,8 @@ class Connection(ConnectionHandlers): self.connection.send(msg_iq) def send_message(self, jid, msg, keyID, type = 'chat', subject='', - chatstate = None, msg_id = None, composing_jep = None, resource = None): + chatstate = None, msg_id = None, composing_jep = None, resource = None, + user_nick = None): if not self.connection: return if not msg and chatstate is None: @@ -637,6 +648,11 @@ class Connection(ConnectionHandlers): if msgenc: msg_iq.setTag(common.xmpp.NS_ENCRYPTED + ' x').setData(msgenc) + # JEP-0172: user_nickname + if user_nick: + df = self.build_user_nick(user_nick) + msg_iq.addChild(node = df) + # 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 @@ -691,7 +707,7 @@ class Connection(ConnectionHandlers): self.connection.send(p) def request_subscription(self, jid, msg = '', name = '', groups = [], - auto_auth = False): + auto_auth = False, user_nick = ''): if not self.connection: return gajim.log.debug('subscription request for %s' % jid) @@ -709,6 +725,9 @@ class Connection(ConnectionHandlers): self.connection.send(iq) p = common.xmpp.Presence(jid, 'subscribe') + if user_nick: + df = self.build_user_nick(user_nick) + p.addChild(node = df) p = self.add_sha(p) if not msg: msg = _('I would like to add you to my roster.') diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py index 082148b4a..bd0a100c3 100644 --- a/src/common/connection_handlers.py +++ b/src/common/connection_handlers.py @@ -1295,6 +1295,16 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco) composing_jep = 'JEP-0022' if not msgtxt and chatstate_child.getTag('composing'): chatstate = 'composing' + # JEP-0172 User Nickname + user_nick = '' + xtags = msg.getTags('x', attrs = {'type': 'result'}, + namespace = common.xmpp.NS_DATA) + for xtag in xtags: + df = common.xmpp.DataForm(node = xtag) + field = df.getField('FORM_TYPE') + if not field or field.getValue() != common.xmpp.NS_PROFILE: + continue + user_nick = df.getField('nickname').getValue() if encTag and GnuPG.USE_GPG: #decrypt @@ -1338,7 +1348,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco) msg_id = gajim.logger.write('chat_msg_recv', frm, msgtxt, tim = tim, subject = subject) self.dispatch('MSG', (frm, msgtxt, tim, encrypted, mtype, subject, - chatstate, msg_id, composing_jep)) + chatstate, msg_id, composing_jep, user_nick)) else: # it's single message if self.name not in no_log_for and jid not in no_log_for and msgtxt: gajim.logger.write('single_msg_recv', frm, msgtxt, tim = tim, @@ -1352,7 +1362,7 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco) self.dispatch('GC_INVITATION',(frm, jid_from, reason, password)) else: self.dispatch('MSG', (frm, msgtxt, tim, encrypted, 'normal', - subject, chatstate, msg_id, composing_jep)) + subject, chatstate, msg_id, composing_jep, user_nick)) # END messageCB def _presenceCB(self, con, prs): @@ -1367,25 +1377,36 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco) is_gc = False # is it a GC presence ? sigTag = None avatar_sha = None + user_nick = '' # for JEP-0172 transport_auto_auth = False xtags = prs.getTags('x') for x in xtags: - if x.getNamespace().startswith(common.xmpp.NS_MUC): + namespace = x.getNamespace() + if namespace.startswith(common.xmpp.NS_MUC): is_gc = True - if x.getNamespace() == common.xmpp.NS_SIGNED: + if namespace == common.xmpp.NS_SIGNED: sigTag = x - if x.getNamespace() == common.xmpp.NS_VCARD_UPDATE: + if namespace == common.xmpp.NS_VCARD_UPDATE: avatar_sha = x.getTagData('photo') - if x.getNamespace() == common.xmpp.NS_DELAY: + if namespace == common.xmpp.NS_DELAY: # JEP-0091 tim = prs.getTimestamp() tim = time.strptime(tim, '%Y%m%dT%H:%M:%S') timestamp = time.localtime(timegm(tim)) - if x.getNamespace() == 'http://delx.cjb.net/protocol/roster-subsync': + if namespace == 'http://delx.cjb.net/protocol/roster-subsync': # see http://trac.gajim.org/ticket/326 agent = gajim.get_server_from_jid(jid_stripped) if self.connection.getRoster().getItem(agent): # to be sure it's a transport contact transport_auto_auth = True + if namespace == common.xmpp.NS_DATA: + # JEP-0172 + df = common.xmpp.DataForm(node = x) + if df.getType() != 'result': + continue + field = df.getField('FORM_TYPE') + if not field or field.getValue() != common.xmpp.NS_PROFILE: + continue + user_nick = df.getField('nickname').getValue() no_log_for = gajim.config.get_per('accounts', self.name, 'no_log_for').split() @@ -1475,11 +1496,11 @@ class ConnectionHandlers(ConnectionVcard, ConnectionBytestream, ConnectionDisco) resource, prio, keyID, timestamp)) if transport_auto_auth: self.automatically_added.append(jid_stripped) - self.request_subscription(jid_stripped) + self.request_subscription(jid_stripped, name = user_nick) else: if not status: status = _('I would like to add you to my roster.') - self.dispatch('SUBSCRIBE', (who, status)) + self.dispatch('SUBSCRIBE', (who, status, user_nick)) elif ptype == 'subscribed': if jid_stripped in self.automatically_added: self.automatically_added.remove(jid_stripped) diff --git a/src/common/xmpp/protocol.py b/src/common/xmpp/protocol.py index 9b0224e44..708fd670c 100644 --- a/src/common/xmpp/protocol.py +++ b/src/common/xmpp/protocol.py @@ -67,6 +67,7 @@ NS_PHYSLOC ='http://jabber.org/protocol/physloc' # JEP-01 NS_PRESENCE ='presence' # Jabberd2 NS_PRIVACY ='jabber:iq:privacy' NS_PRIVATE ='jabber:iq:private' +NS_PROFILE ='http://jabber.org/protocol/profile' # JEP-0154 NS_PUBSUB ='http://jabber.org/protocol/pubsub' # JEP-0060 NS_REGISTER ='jabber:iq:register' NS_ROSTER ='jabber:iq:roster' diff --git a/src/dialogs.py b/src/dialogs.py index bb6a201c8..db02e1f4b 100644 --- a/src/dialogs.py +++ b/src/dialogs.py @@ -362,7 +362,7 @@ class ChangeStatusMessageDialog: class AddNewContactWindow: '''Class for AddNewContactWindow''' - def __init__(self, account = None, jid = None): + def __init__(self, account = None, jid = None, user_nick = None): self.account = account if account == None: # fill accounts with active accounts @@ -431,7 +431,10 @@ _('Please fill in the data of the contact you want to add in account %s') %accou else: self.uid_entry.set_text(jid) self.protocol_combobox.set_active(0) - self.set_nickname() + if user_nick: + self.nickname_entry.set_text(user_nick) + else: + self.set_nickname() self.nickname_entry.grab_focus() self.group_comboboxentry = self.xml.get_widget('group_comboboxentry') liststore = gtk.ListStore(str) @@ -860,11 +863,12 @@ ok_handler = None): return response class SubscriptionRequestWindow: - def __init__(self, jid, text, account): + def __init__(self, jid, text, account, user_nick = None): xml = gtkgui_helpers.get_glade('subscription_request_window.glade') self.window = xml.get_widget('subscription_request_window') self.jid = jid self.account = account + self.user_nick = user_nick if len(gajim.connections) >= 2: prompt_text = _('Subscription request for account %s from %s')\ % (account, self.jid) @@ -883,7 +887,7 @@ class SubscriptionRequestWindow: gajim.connections[self.account].send_authorization(self.jid) self.window.destroy() if self.jid not in gajim.contacts.get_jid_list(self.account): - AddNewContactWindow(self.account, self.jid) + AddNewContactWindow(self.account, self.jid, self.user_nick) def on_contact_info_button_clicked(self, widget): '''ask vcard''' diff --git a/src/gajim.py b/src/gajim.py index 54607878d..9d8f2c2cf 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -468,7 +468,7 @@ class Interface: def handle_event_msg(self, account, array): # 'MSG' (account, (jid, msg, time, encrypted, msg_type, subject, - # chatstate)) + # chatstate, msg_id, composing_jep, user_nick)) user_nick is JEP-0172 full_jid_with_resource = array[0] jid = gajim.get_jid_without_resource(full_jid_with_resource) @@ -555,7 +555,7 @@ class Interface: else: # array: (jid, msg, time, encrypted, msg_type, subject) self.roster.on_message(jid, message, array[2], account, array[3], - msg_type, array[5], resource, msg_id) + msg_type, array[5], resource, msg_id, array[9]) nickname = gajim.get_name_from_jid(account, jid) # Check and do wanted notifications notify.notify('new_message', jid, account, [msg_type, first, nickname, message]) @@ -611,8 +611,8 @@ class Interface: helpers.play_sound('message_sent') def handle_event_subscribe(self, account, array): - #('SUBSCRIBE', account, (jid, text)) - dialogs.SubscriptionRequestWindow(array[0], array[1], account) + #('SUBSCRIBE', account, (jid, text, user_nick)) user_nick is JEP-0172 + dialogs.SubscriptionRequestWindow(array[0], array[1], account, array[2]) if self.remote_ctrl: self.remote_ctrl.raise_signal('Subscribe', (account, array)) diff --git a/src/message_control.py b/src/message_control.py index df19f570f..8d6b71901 100644 --- a/src/message_control.py +++ b/src/message_control.py @@ -131,10 +131,12 @@ class MessageControl: return n def send_message(self, message, keyID = '', type = 'chat', - chatstate = None, msg_id = None, composing_jep = None, resource = None): + chatstate = None, msg_id = None, composing_jep = None, resource = None, + user_nick = 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, msg_id = msg_id, - composing_jep = composing_jep, resource = self.resource) + type = type, chatstate = chatstate, msg_id = msg_id, + composing_jep = composing_jep, resource = self.resource, + user_nick = user_nick) diff --git a/src/roster_window.py b/src/roster_window.py index b85a4a711..da38c33a0 100644 --- a/src/roster_window.py +++ b/src/roster_window.py @@ -1606,7 +1606,7 @@ class RosterWindow: menu.popup(None, self.tree, None, event_button, event.time) def on_add_to_roster(self, widget, contact, account): - dialogs.AddNewContactWindow(account, contact.jid) + dialogs.AddNewContactWindow(account, contact.jid, contact.name) def authorize(self, widget, jid, account): '''Authorize a contact (by re-sending auth menuitem)''' @@ -1622,7 +1622,7 @@ class RosterWindow: else: group = [] gajim.connections[account].request_subscription(jid, txt, pseudo, group, - auto_auth) + auto_auth, gajim.nicks[account]) contact = gajim.contacts.get_contact_with_highest_priority(account, jid) if not contact: keyID = '' @@ -2118,7 +2118,8 @@ _('If "%s" accepts this request you will know his or her status.') % jid) mw.new_tab(gc_control) def on_message(self, jid, msg, tim, account, encrypted = False, - msg_type = '', subject = None, resource = '', msg_id = None): + msg_type = '', subject = None, resource = '', msg_id = None, + user_nick = ''): '''when we receive a message''' contact = None # if chat window will be for specific resource @@ -2141,8 +2142,12 @@ _('If "%s" accepts this request you will know his or her status.') % jid) 'attached_gpg_keys').split() if jid in attached_keys: keyID = attached_keys[attached_keys.index(jid) + 1] + if user_nick: + nick = user_nick + else: + nick = jid.split('@')[0] contact = gajim.contacts.create_contact(jid = jid, - name = jid.split('@')[0], groups = [_('Not in Roster')], + name = nick, groups = [_('Not in Roster')], show = 'not in roster', status = '', ask = 'none', keyID = keyID, resource = resource) gajim.contacts.add_contact(account, contact)