changeset ceb45ebd484e in /home/hg/repos/gajim
details:http://hg.gajim.org/gajim?cmd=changeset;node=ceb45ebd484e description: merge XEP-0198 implementation from gajim-XEP-198 branch to trunk. Thanks Jefry for your work during GSOC
diffstat:
src/common/connection.py | 42 +++++++++-- src/common/xmpp/__init__.py | 1 + src/common/xmpp/auth_nb.py | 113 ++++++++++++++++++++------------ src/common/xmpp/client_nb.py | 11 ++- src/common/xmpp/dispatcher_nb.py | 17 ++++ src/common/xmpp/protocol.py | 29 ++++++++ src/common/xmpp/smacks.py | 129 +++++++++++++++++++++++++++++++++++++ test/unit/test_xmpp_smacks.py | 133 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 424 insertions(+), 51 deletions(-)
diffs (truncated from 797 to 300 lines):
diff -r b1153c146cfa -r ceb45ebd484e src/common/connection.py --- a/src/common/connection.py Mon Aug 22 09:10:50 2011 +0200 +++ b/src/common/connection.py Mon Aug 22 09:45:51 2011 +0200 @@ -57,9 +57,9 @@ from common import gpg from common import passwords from common import exceptions - from connection_handlers import *
+from xmpp import Smacks from string import Template import logging log = logging.getLogger('gajim.c.connection') @@ -717,6 +717,9 @@ self.privacy_rules_requested = False self.streamError = '' self.secret_hmac = str(random.random())[2:] + + self.sm = Smacks(self) # Stream Management + gajim.ged.register_event_handler('privacy-list-received', ged.CORE, self._nec_privacy_list_received) gajim.ged.register_event_handler('agent-info-error-received', ged.CORE, @@ -780,6 +783,8 @@ self.connected = 0 self.time_to_reconnect = None self.privacy_rules_supported = False + if on_purpose: + self.sm = Smacks(self) if self.connection: # make sure previous connection is completely closed gajim.proxy65_manager.disconnect(self.connection) @@ -788,6 +793,15 @@ self.connection.disconnect() self.last_connection = None self.connection = None + def set_oldst(self): # Set old state + if self.old_show: + self.connected = gajim.SHOW_LIST.index(self.old_show) + gajim.nec.push_incoming_event(OurShowEvent(None, conn=self, + show=self.connected)) + else: # we default to online + self.connected = 2 + gajim.nec.push_incoming_event(OurShowEvent(None, conn=self, + show=gajim.SHOW_LIST[self.connected]))
def _disconnectedReconnCB(self): """ @@ -800,8 +814,9 @@ self.old_show = gajim.SHOW_LIST[self.connected] self.connected = 0 if not self.on_purpose: - gajim.nec.push_incoming_event(OurShowEvent(None, conn=self, - show='offline')) + if not (self.sm and self.sm.resumption): + gajim.nec.push_incoming_event(OurShowEvent(None, conn=self, + show='offline')) self.disconnect() if gajim.config.get_per('accounts', self.name, 'autoreconnect'): self.connected = -1 @@ -989,7 +1004,14 @@ if self.connection: return self.connection, ''
- if data: + if self.sm.resuming and self.sm.location: + # If resuming and server gave a location, connect from there + hostname = self.sm.location + self.try_connecting_for_foo_secs = gajim.config.get_per('accounts', + self.name, 'try_connecting_for_foo_secs') + use_custom = False + + elif data: hostname = data['hostname'] self.try_connecting_for_foo_secs = 45 p = data['proxy'] @@ -1607,12 +1629,16 @@ self.connection.set_send_timeout2(self.pingalives, self.sendPing) self.connection.onreceive(None)
- self.request_message_archiving_preferences() + self.privacy_rules_requested = False
- self.privacy_rules_requested = False - self.discoverInfo(gajim.config.get_per('accounts', self.name, 'hostname'), - id_prefix='Gajim_') + # If we are not resuming, we ask for discovery info + # and archiving preferences + if not self.sm.resuming: + self.request_message_archiving_preferences() + self.discoverInfo(gajim.config.get_per('accounts', self.name, + 'hostname'), id_prefix='Gajim_')
+ self.sm.resuming = False # back to previous state # Discover Stun server(s) gajim.resolver.resolve('_stun._udp.' + helpers.idn_to_ascii( self.connected_hostname), self._on_stun_resolved) diff -r b1153c146cfa -r ceb45ebd484e src/common/xmpp/__init__.py --- a/src/common/xmpp/__init__.py Mon Aug 22 09:10:50 2011 +0200 +++ b/src/common/xmpp/__init__.py Mon Aug 22 09:45:51 2011 +0200 @@ -15,3 +15,4 @@ import dispatcher_nb, features_nb, idlequeue, bosh, tls_nb, proxy_connectors from client_nb import NonBlockingClient from plugin import PlugIn +from smacks import Smacks diff -r b1153c146cfa -r ceb45ebd484e src/common/xmpp/auth_nb.py --- a/src/common/xmpp/auth_nb.py Mon Aug 22 09:10:50 2011 +0200 +++ b/src/common/xmpp/auth_nb.py Mon Aug 22 09:45:51 2011 +0200 @@ -22,8 +22,10 @@ """
from protocol import NS_SASL, NS_SESSION, NS_STREAMS, NS_BIND, NS_AUTH +from protocol import NS_STREAM_MGMT from protocol import Node, NodeProcessed, isResultNode, Iq, Protocol, JID from plugin import PlugIn +from smacks import Smacks import base64 import random import itertools @@ -142,7 +144,7 @@ elif self._owner.Dispatcher.Stream.features: try: self.FeaturesHandler(self._owner.Dispatcher, - self._owner.Dispatcher.Stream.features) + self._owner.Dispatcher.Stream.features) except NodeProcessed: pass else: @@ -154,16 +156,16 @@ """ if 'features' in self._owner.__dict__: self._owner.UnregisterHandler('features', self.FeaturesHandler, - xmlns=NS_STREAMS) + xmlns=NS_STREAMS) if 'challenge' in self._owner.__dict__: self._owner.UnregisterHandler('challenge', self.SASLHandler, - xmlns=NS_SASL) + xmlns=NS_SASL) if 'failure' in self._owner.__dict__: self._owner.UnregisterHandler('failure', self.SASLHandler, - xmlns=NS_SASL) + xmlns=NS_SASL) if 'success' in self._owner.__dict__: self._owner.UnregisterHandler('success', self.SASLHandler, - xmlns=NS_SASL) + xmlns=NS_SASL)
def auth(self): """ @@ -178,12 +180,12 @@ elif self._owner.Dispatcher.Stream.features: try: self.FeaturesHandler(self._owner.Dispatcher, - self._owner.Dispatcher.Stream.features) + self._owner.Dispatcher.Stream.features) except NodeProcessed: pass else: self._owner.RegisterHandler('features', - self.FeaturesHandler, xmlns=NS_STREAMS) + self.FeaturesHandler, xmlns=NS_STREAMS)
def FeaturesHandler(self, conn, feats): """ @@ -198,7 +200,8 @@ 'mechanism'): self.mecs.append(mec.getData())
- self._owner.RegisterHandler('challenge', self.SASLHandler, xmlns=NS_SASL) + self._owner.RegisterHandler('challenge', self.SASLHandler, + xmlns=NS_SASL) self._owner.RegisterHandler('failure', self.SASLHandler, xmlns=NS_SASL) self._owner.RegisterHandler('success', self.SASLHandler, xmlns=NS_SASL) self.MechanismHandler() @@ -206,7 +209,8 @@ def MechanismHandler(self): if 'ANONYMOUS' in self.mecs and self.username is None: self.mecs.remove('ANONYMOUS') - node = Node('auth', attrs={'xmlns': NS_SASL, 'mechanism': 'ANONYMOUS'}) + node = Node('auth', attrs={'xmlns': NS_SASL, + 'mechanism': 'ANONYMOUS'}) self.mechanism = 'ANONYMOUS' self.startsasl = SASL_IN_PROCESS self._owner.send(str(node)) @@ -226,11 +230,11 @@ self.mecs.remove('GSSAPI') try: self.gss_vc = kerberos.authGSSClientInit('xmpp@' + \ - self._owner.xmpp_hostname)[1] + self._owner.xmpp_hostname)[1] kerberos.authGSSClientStep(self.gss_vc, '') response = kerberos.authGSSClientResponse(self.gss_vc) - node=Node('auth', attrs={'xmlns': NS_SASL, 'mechanism': 'GSSAPI'}, - payload=(response or '')) + node=Node('auth', attrs={'xmlns': NS_SASL, + 'mechanism': 'GSSAPI'}, payload=(response or '')) self.mechanism = 'GSSAPI' self.gss_step = GSS_STATE_STEP self.startsasl = SASL_IN_PROCESS @@ -247,7 +251,8 @@ raise NodeProcessed if 'DIGEST-MD5' in self.mecs: self.mecs.remove('DIGEST-MD5') - node = Node('auth', attrs={'xmlns': NS_SASL, 'mechanism': 'DIGEST-MD5'}) + node = Node('auth', attrs={'xmlns': NS_SASL, + 'mechanism': 'DIGEST-MD5'}) self.mechanism = 'DIGEST-MD5' self.startsasl = SASL_IN_PROCESS self._owner.send(str(node)) @@ -307,13 +312,13 @@ handlers = self._owner.Dispatcher.dumpHandlers()
# Bosh specific dispatcher replugging - # save old features. They will be used in case we won't get response on - # stream restart after SASL auth (happens with XMPP over BOSH with - # Openfire) + # save old features. They will be used in case we won't get response + # on stream restart after SASL auth (happens with XMPP over BOSH + # with Openfire) old_features = self._owner.Dispatcher.Stream.features self._owner.Dispatcher.PlugOut() dispatcher_nb.Dispatcher.get_instance().PlugIn(self._owner, - after_SASL=True, old_features=old_features) + after_SASL=True, old_features=old_features) self._owner.Dispatcher.restoreHandlers(handlers) self._owner.User = self.username
@@ -333,12 +338,12 @@ rc = kerberos.authGSSClientUnwrap(self.gss_vc, incoming_data) response = kerberos.authGSSClientResponse(self.gss_vc) rc = kerberos.authGSSClientWrap(self.gss_vc, response, - kerberos.authGSSClientUserName(self.gss_vc)) + kerberos.authGSSClientUserName(self.gss_vc)) response = kerberos.authGSSClientResponse(self.gss_vc) if not response: response = '' self._owner.send(Node('response', attrs={'xmlns': NS_SASL}, - payload=response).__str__()) + payload=response).__str__()) raise NodeProcessed if self.mechanism == 'SCRAM-SHA-1': hashfn = hashlib.sha1 @@ -416,8 +421,8 @@ else: self.resp['realm'] = self._owner.Server self.resp['nonce'] = chal['nonce'] - self.resp['cnonce'] = ''.join("%x" % randint(0, 2**28) for randint in - itertools.repeat(random.randint, 7)) + self.resp['cnonce'] = ''.join("%x" % randint(0, 2**28) for randint \ + in itertools.repeat(random.randint, 7)) self.resp['nc'] = ('00000001') self.resp['qop'] = 'auth' self.resp['digest-uri'] = 'xmpp/' + self._owner.Server @@ -477,14 +482,15 @@ else: sasl_data += u'%s="%s",' % (key, self.resp[key]) sasl_data = sasl_data[:-1].encode('utf-8').encode('base64').replace( - '\r', '').replace('\n', '') - node = Node('response', attrs={'xmlns':NS_SASL}, payload=[sasl_data]) + '\r', '').replace('\n', '') + node = Node('response', attrs={'xmlns': NS_SASL}, + payload=[sasl_data]) elif self.mechanism == 'PLAIN': sasl_data = u'\x00%s\x00%s' % (self.username, self.password) sasl_data = sasl_data.encode('utf-8').encode('base64').replace( - '\n', '') + '\n', '') node = Node('auth', attrs={'xmlns': NS_SASL, 'mechanism': 'PLAIN'}, - payload=[sasl_data]) + payload=[sasl_data]) self._owner.send(str(node))
@@ -516,8 +522,8 @@ self.owner = owner
owner.Dispatcher.SendAndWaitForResponse( - Iq('get', NS_AUTH, payload=[Node('username', payload=[self.user])]), - func=self._on_username) + Iq('get', NS_AUTH, payload=[Node('username', payload=[self.user])]), + func=self._on_username)
def _on_username(self, resp): if not isResultNode(resp): @@ -532,8 +538,8 @@ if query.getTag('digest'): log.info("Performing digest authentication") query.setTagData('digest', - hashlib.sha1(self.owner.Dispatcher.Stream._document_attrs['id'] - + self.password).hexdigest()) + hashlib.sha1(self.owner.Dispatcher.Stream._document_attrs['id'] + + self.password).hexdigest()) if query.getTag('password'): query.delChild('password') self._method = 'digest' @@ -548,23 +554,25 @@ def hash_n_times(s, count): return count and hasher(hash_n_times(s, count-1)) or s