moved bosh code from client_nb.py to bosh.py, replaced debug logging with debug.py by logging in whole xmpppy (debug.py is now unused)

This commit is contained in:
tomk 2008-07-02 23:29:10 +00:00
parent 937bb01a69
commit 952e4a1569
13 changed files with 356 additions and 357 deletions

View File

@ -208,7 +208,7 @@ class Connection(ConnectionHandlers):
def _disconnectedReconnCB(self): def _disconnectedReconnCB(self):
'''Called when we are disconnected''' '''Called when we are disconnected'''
log.error('disconnectedReconnCB') log.info('disconnectedReconnCB called')
if gajim.account_is_connected(self.name): if gajim.account_is_connected(self.name):
# we cannot change our status to offline or connecting # we cannot change our status to offline or connecting
# after we auth to server # after we auth to server
@ -531,23 +531,17 @@ class Connection(ConnectionHandlers):
secur = None secur = None
if self._proxy and self._proxy['type'] == 'bosh': if self._proxy and self._proxy['type'] == 'bosh':
clientClass = common.xmpp.BOSHClient clientClass = common.xmpp.bosh.BOSHClient
else: else:
clientClass = common.xmpp.NonBlockingClient clientClass = common.xmpp.NonBlockingClient
if gajim.verbose: # there was:
con = common.xmpp.NonBlockingClient( # "if gajim.verbose:"
hostname=self._current_host['host'], # here
port=port, con = clientClass(
caller=self, domain=self._hostname,
idlequeue=gajim.idlequeue) caller=self,
else: idlequeue=gajim.idlequeue)
con = common.xmpp.NonBlockingClient(
hostname=self._current_host['host'],
debug=[],
port=port,
caller=self,
idlequeue=gajim.idlequeue)
self.last_connection = con self.last_connection = con
# increase default timeout for server responses # increase default timeout for server responses
@ -555,10 +549,19 @@ class Connection(ConnectionHandlers):
# FIXME: this is a hack; need a better way # FIXME: this is a hack; need a better way
if self.on_connect_success == self._on_new_account: if self.on_connect_success == self._on_new_account:
con.RegisterDisconnectHandler(self._on_new_account) con.RegisterDisconnectHandler(self._on_new_account)
# FIXME: BOSH properties should be in proxy dictionary - loaded from
# config
if self._proxy and self._proxy['type'] == 'bosh':
self._proxy['bosh_hold'] = '1'
self._proxy['bosh_wait'] = '60'
log.info('Connecting to %s: [%s:%d]', self.name, log.info('Connecting to %s: [%s:%d]', self.name,
self._current_host['host'], port) self._current_host['host'], port)
con.connect( con.connect(
hostname=self._current_host['host'],
port=port,
on_connect=self.on_connect_success, on_connect=self.on_connect_success,
on_proxy_failure=self.on_proxy_failure, on_proxy_failure=self.on_proxy_failure,
on_connect_failure=self.connect_to_next_type, on_connect_failure=self.connect_to_next_type,

View File

@ -26,7 +26,8 @@ and use only methods for access all values you should not have any problems.
""" """
import simplexml,protocol,debug,auth_nb,transports_nb,roster_nb,dispatcher_nb,features_nb,idlequeue import simplexml, protocol, auth_nb, transports_nb, roster_nb
import dispatcher_nb, features_nb, idlequeue, bosh, tls_nb
from client_nb import * from client_nb import *
from client import * from client import *
from protocol import * from protocol import *

View File

@ -22,6 +22,10 @@ from protocol import *
from client import PlugIn from client import PlugIn
import sha,base64,random,dispatcher_nb import sha,base64,random,dispatcher_nb
import logging
log = logging.getLogger('gajim.c.x.auth_nb')
import md5 import md5
def HH(some): return md5.new(some).hexdigest() def HH(some): return md5.new(some).hexdigest()
def H(some): return md5.new(some).digest() def H(some): return md5.new(some).digest()
@ -128,7 +132,7 @@ class SASL(PlugIn):
''' Used to determine if server supports SASL auth. Used internally. ''' ''' Used to determine if server supports SASL auth. Used internally. '''
if not feats.getTag('mechanisms', namespace=NS_SASL): if not feats.getTag('mechanisms', namespace=NS_SASL):
self.startsasl='not-supported' self.startsasl='not-supported'
self.DEBUG('SASL not supported by server', 'error') log.error('SASL not supported by server')
return return
mecs=[] mecs=[]
for mec in feats.getTag('mechanisms', namespace=NS_SASL).getTags('mechanism'): for mec in feats.getTag('mechanisms', namespace=NS_SASL).getTags('mechanism'):
@ -145,7 +149,7 @@ class SASL(PlugIn):
payload=[base64.encodestring(sasl_data).replace('\n','')]) payload=[base64.encodestring(sasl_data).replace('\n','')])
else: else:
self.startsasl='failure' self.startsasl='failure'
self.DEBUG('I can only use DIGEST-MD5 and PLAIN mecanisms.', 'error') log.error('I can only use DIGEST-MD5 and PLAIN mecanisms.')
return return
self.startsasl='in-process' self.startsasl='in-process'
self._owner.send(node.__str__()) self._owner.send(node.__str__())
@ -161,13 +165,13 @@ class SASL(PlugIn):
reason = challenge.getChildren()[0] reason = challenge.getChildren()[0]
except: except:
reason = challenge reason = challenge
self.DEBUG('Failed SASL authentification: %s' % reason, 'error') log.error('Failed SASL authentification: %s' % reason)
if self.on_sasl : if self.on_sasl :
self.on_sasl () self.on_sasl ()
raise NodeProcessed raise NodeProcessed
elif challenge.getName() == 'success': elif challenge.getName() == 'success':
self.startsasl='success' self.startsasl='success'
self.DEBUG('Successfully authenticated with remote server.', 'ok') log.info('Successfully authenticated with remote server.')
handlers=self._owner.Dispatcher.dumpHandlers() handlers=self._owner.Dispatcher.dumpHandlers()
print '6' * 79 print '6' * 79
print handlers print handlers
@ -182,7 +186,7 @@ class SASL(PlugIn):
########################################3333 ########################################3333
incoming_data = challenge.getData() incoming_data = challenge.getData()
data=base64.decodestring(incoming_data) data=base64.decodestring(incoming_data)
self.DEBUG('Got challenge:'+data,'ok') log.info('Got challenge:'+data)
chal = challenge_splitter(data) chal = challenge_splitter(data)
if not self.realm and chal.has_key('realm'): if not self.realm and chal.has_key('realm'):
self.realm = chal['realm'] self.realm = chal['realm']
@ -224,7 +228,7 @@ class SASL(PlugIn):
self._owner.send(Node('response', attrs={'xmlns':NS_SASL}).__str__()) self._owner.send(Node('response', attrs={'xmlns':NS_SASL}).__str__())
else: else:
self.startsasl='failure' self.startsasl='failure'
self.DEBUG('Failed SASL authentification: unknown challenge', 'error') log.error('Failed SASL authentification: unknown challenge')
if self.on_sasl : if self.on_sasl :
self.on_sasl () self.on_sasl ()
raise NodeProcessed raise NodeProcessed
@ -236,7 +240,6 @@ class NonBlockingNonSASL(PlugIn):
def __init__(self, user, password, resource, on_auth): def __init__(self, user, password, resource, on_auth):
''' Caches username, password and resource for auth. ''' ''' Caches username, password and resource for auth. '''
PlugIn.__init__(self) PlugIn.__init__(self)
self.DBG_LINE ='gen_auth'
self.user = user self.user = user
self.password= password self.password= password
self.resource = resource self.resource = resource
@ -248,7 +251,7 @@ class NonBlockingNonSASL(PlugIn):
Returns used method name on success. Used internally. ''' Returns used method name on success. Used internally. '''
if not self.resource: if not self.resource:
return self.authComponent(owner) return self.authComponent(owner)
self.DEBUG('Querying server about possible auth methods', 'start') log.info('Querying server about possible auth methods')
self.owner = owner self.owner = owner
resp = owner.Dispatcher.SendAndWaitForResponse( resp = owner.Dispatcher.SendAndWaitForResponse(
@ -257,7 +260,7 @@ class NonBlockingNonSASL(PlugIn):
def _on_username(self, resp): def _on_username(self, resp):
if not isResultNode(resp): if not isResultNode(resp):
self.DEBUG('No result node arrived! Aborting...','error') log.error('No result node arrived! Aborting...')
return self.on_auth(None) return self.on_auth(None)
iq=Iq(typ='set',node=resp) iq=Iq(typ='set',node=resp)
query=iq.getTag('query') query=iq.getTag('query')
@ -265,7 +268,7 @@ class NonBlockingNonSASL(PlugIn):
query.setTagData('resource',self.resource) query.setTagData('resource',self.resource)
if query.getTag('digest'): if query.getTag('digest'):
self.DEBUG("Performing digest authentication",'ok') log.info("Performing digest authentication")
query.setTagData('digest', query.setTagData('digest',
sha.new(self.owner.Dispatcher.Stream._document_attrs['id']+self.password).hexdigest()) sha.new(self.owner.Dispatcher.Stream._document_attrs['id']+self.password).hexdigest())
if query.getTag('password'): if query.getTag('password'):
@ -274,26 +277,26 @@ class NonBlockingNonSASL(PlugIn):
elif query.getTag('token'): elif query.getTag('token'):
token=query.getTagData('token') token=query.getTagData('token')
seq=query.getTagData('sequence') seq=query.getTagData('sequence')
self.DEBUG("Performing zero-k authentication",'ok') log.info("Performing zero-k authentication")
hash = sha.new(sha.new(self.password).hexdigest()+token).hexdigest() hash = sha.new(sha.new(self.password).hexdigest()+token).hexdigest()
for foo in xrange(int(seq)): for foo in xrange(int(seq)):
hash = sha.new(hash).hexdigest() hash = sha.new(hash).hexdigest()
query.setTagData('hash',hash) query.setTagData('hash',hash)
self._method='0k' self._method='0k'
else: else:
self.DEBUG("Sequre methods unsupported, performing plain text authentication",'warn') log.warn("Sequre methods unsupported, performing plain text authentication")
query.setTagData('password',self.password) query.setTagData('password',self.password)
self._method='plain' self._method='plain'
resp=self.owner.Dispatcher.SendAndWaitForResponse(iq, func=self._on_auth) resp=self.owner.Dispatcher.SendAndWaitForResponse(iq, func=self._on_auth)
def _on_auth(self, resp): def _on_auth(self, resp):
if isResultNode(resp): if isResultNode(resp):
self.DEBUG('Sucessfully authenticated with remove host.','ok') log.info('Sucessfully authenticated with remove host.')
self.owner.User=self.user self.owner.User=self.user
self.owner.Resource=self.resource self.owner.Resource=self.resource
self.owner._registered_name=self.owner.User+'@'+self.owner.Server+'/'+self.owner.Resource self.owner._registered_name=self.owner.User+'@'+self.owner.Server+'/'+self.owner.Resource
return self.on_auth(self._method) return self.on_auth(self._method)
self.DEBUG('Authentication failed!','error') log.error('Authentication failed!')
return self.on_auth(None) return self.on_auth(None)
def authComponent(self,owner): def authComponent(self,owner):
@ -309,7 +312,7 @@ class NonBlockingNonSASL(PlugIn):
if data: if data:
self.Dispatcher.ProcessNonBlocking(data) self.Dispatcher.ProcessNonBlocking(data)
if not self.handshake: if not self.handshake:
self.DEBUG('waiting on handshake', 'notify') log.info('waiting on handshake')
return return
self._owner.onreceive(None) self._owner.onreceive(None)
owner._registered_name=self.user owner._registered_name=self.user
@ -329,14 +332,13 @@ class NonBlockingBind(PlugIn):
def __init__(self): def __init__(self):
PlugIn.__init__(self) PlugIn.__init__(self)
self.DBG_LINE='bind'
self.bound=None self.bound=None
def FeaturesHandler(self,conn,feats): def FeaturesHandler(self,conn,feats):
""" Determine if server supports resource binding and set some internal attributes accordingly. """ """ Determine if server supports resource binding and set some internal attributes accordingly. """
if not feats.getTag('bind',namespace=NS_BIND): if not feats.getTag('bind',namespace=NS_BIND):
self.bound='failure' self.bound='failure'
self.DEBUG('Server does not requested binding.','error') log.error('Server does not requested binding.')
return return
if feats.getTag('session',namespace=NS_SESSION): self.session=1 if feats.getTag('session',namespace=NS_SESSION): self.session=1
else: self.session=-1 else: self.session=-1
@ -372,36 +374,36 @@ class NonBlockingBind(PlugIn):
def _on_bound(self, resp): def _on_bound(self, resp):
if isResultNode(resp): if isResultNode(resp):
self.bound.append(resp.getTag('bind').getTagData('jid')) self.bound.append(resp.getTag('bind').getTagData('jid'))
self.DEBUG('Successfully bound %s.'%self.bound[-1],'ok') log.info('Successfully bound %s.'%self.bound[-1])
jid=JID(resp.getTag('bind').getTagData('jid')) jid=JID(resp.getTag('bind').getTagData('jid'))
self._owner.User=jid.getNode() self._owner.User=jid.getNode()
self._owner.Resource=jid.getResource() self._owner.Resource=jid.getResource()
self._owner.SendAndWaitForResponse(Protocol('iq', typ='set', self._owner.SendAndWaitForResponse(Protocol('iq', typ='set',
payload=[Node('session', attrs={'xmlns':NS_SESSION})]), func=self._on_session) payload=[Node('session', attrs={'xmlns':NS_SESSION})]), func=self._on_session)
elif resp: elif resp:
self.DEBUG('Binding failed: %s.' % resp.getTag('error'),'error') log.error('Binding failed: %s.' % resp.getTag('error'))
self.on_bound(None) self.on_bound(None)
else: else:
self.DEBUG('Binding failed: timeout expired.', 'error') log.error('Binding failed: timeout expired.')
self.on_bound(None) self.on_bound(None)
def _on_session(self, resp): def _on_session(self, resp):
self._owner.onreceive(None) self._owner.onreceive(None)
if isResultNode(resp): if isResultNode(resp):
self.DEBUG('Successfully opened session.', 'ok') log.info('Successfully opened session.')
self.session = 1 self.session = 1
self.on_bound('ok') self.on_bound('ok')
else: else:
self.DEBUG('Session open failed.', 'error') log.error('Session open failed.')
self.session = 0 self.session = 0
self.on_bound(None) self.on_bound(None)
self._owner.onreceive(None) self._owner.onreceive(None)
if isResultNode(resp): if isResultNode(resp):
self.DEBUG('Successfully opened session.', 'ok') log.info('Successfully opened session.')
self.session = 1 self.session = 1
self.on_bound('ok') self.on_bound('ok')
else: else:
self.DEBUG('Session open failed.', 'error') log.error('Session open failed.')
self.session = 0 self.session = 0
self.on_bound(None) self.on_bound(None)
@ -411,7 +413,6 @@ class NBComponentBind(PlugIn):
''' '''
def __init__(self): def __init__(self):
PlugIn.__init__(self) PlugIn.__init__(self)
self.DBG_LINE='bind'
self.bound=None self.bound=None
self.needsUnregister=None self.needsUnregister=None
@ -448,13 +449,13 @@ class NBComponentBind(PlugIn):
def _on_bind_reponse(self, res): def _on_bind_reponse(self, res):
if resp and resp.getAttr('error'): if resp and resp.getAttr('error'):
self.DEBUG('Binding failed: %s.' % resp.getAttr('error'), 'error') log.error('Binding failed: %s.' % resp.getAttr('error'))
elif resp: elif resp:
self.DEBUG('Successfully bound.', 'ok') log.info('Successfully bound.')
if self.on_bind: if self.on_bind:
self.on_bind('ok') self.on_bind('ok')
else: else:
self.DEBUG('Binding failed: timeout expired.', 'error') log.error('Binding failed: timeout expired.')
if self.on_bind: if self.on_bind:
self.on_bind(None) self.on_bind(None)
@ -462,7 +463,7 @@ class NBComponentBind(PlugIn):
""" Determine if server supports resource binding and set some internal attributes accordingly. """ """ Determine if server supports resource binding and set some internal attributes accordingly. """
if not feats.getTag('bind',namespace=NS_BIND): if not feats.getTag('bind',namespace=NS_BIND):
self.bound='failure' self.bound='failure'
self.DEBUG('Server does not requested binding.','error') log.error('Server does not requested binding.')
return return
if feats.getTag('session',namespace=NS_SESSION): self.session=1 if feats.getTag('session',namespace=NS_SESSION): self.session=1
else: self.session=-1 else: self.session=-1
@ -473,10 +474,10 @@ class NBComponentBind(PlugIn):
while self.bound is None and self._owner.Process(1): pass while self.bound is None and self._owner.Process(1): pass
resp=self._owner.SendAndWaitForResponse(Protocol('bind',attrs={'name':domain},xmlns=NS_COMPONENT_1)) resp=self._owner.SendAndWaitForResponse(Protocol('bind',attrs={'name':domain},xmlns=NS_COMPONENT_1))
if resp and resp.getAttr('error'): if resp and resp.getAttr('error'):
self.DEBUG('Binding failed: %s.'%resp.getAttr('error'),'error') log.error('Binding failed: %s.'%resp.getAttr('error'))
elif resp: elif resp:
self.DEBUG('Successfully bound.','ok') log.info('Successfully bound.')
return 'ok' return 'ok'
else: else:
self.DEBUG('Binding failed: timeout expired.','error') log.error('Binding failed: timeout expired.')
return '' return ''

112
src/common/xmpp/bosh.py Normal file
View File

@ -0,0 +1,112 @@
import protocol, simplexml, locale, random, dispatcher_nb
from client_nb import NBCommonClient
import logging
log = logging.getLogger('gajim.c.x.bosh')
class BOSHClient(NBCommonClient):
'''
Client class implementing BOSH.
'''
def __init__(self, *args, **kw):
'''Preceeds constructor of NBCommonClient and sets some of values that will
be used as attributes in <body> tag'''
self.Namespace = protocol.NS_HTTP_BIND
# BOSH parameters should be given via Advanced Configuration Editor
self.bosh_xml_lang = None
self.bosh_hold = 1
self.bosh_wait=60
self.bosh_rid=None
self.bosh_sid=None
self.bosh_httpversion = 'HTTP/1.1'
NBCommonClient.__init__(self, *args, **kw)
def connect(self, *args, **kw):
if locale.getdefaultlocale()[0]:
self.bosh_xml_lang = locale.getdefaultlocale()[0].split('_')[0]
# with 50-bit random initial rid, session would have to go up
# to 7881299347898368 messages to raise rid over 2**53
# (see http://www.xmpp.org/extensions/xep-0124.html#rids)
r = random.Random()
r.seed()
self.bosh_rid = r.getrandbits(50)
proxy = kw['proxy']
#self.bosh_protocol, self.bosh_host, self.bosh_uri = transports_nb.urisplit(proxy['host'])
self.bosh_port = proxy['port']
self.bosh_wait = proxy['bosh_wait']
self.bosh_hold = proxy['bosh_hold']
self.bosh_to = proxy['to']
#self.bosh_ack = proxy['bosh_ack']
#self.bosh_secure = proxy['bosh_secure']
NBCommonClient.connect(self, *args, **kw)
def send(self, stanza, now = False):
(id, stanza_to_send) = self.Dispatcher.assign_id(stanza)
self.Connection.send(
self.boshify_stanza(stanza_to_send),
now = now)
return id
def get_bodytag(self):
# this should be called not until after session creation response so sid has
# to be initialized.
assert(self.sid is not None)
self.rid = self.rid+1
return protocol.BOSHBody(
attrs={ 'rid': str(self.bosh_rid),
'sid': self.bosh_sid})
def get_initial_bodytag(self):
return protocol.BOSHBody(
attrs={'content': 'text/xml; charset=utf-8',
'hold': str(self.bosh_hold),
'to': self.bosh_to,
'wait': str(self.bosh_wait),
'rid': str(self.bosh_rid),
'xmpp:version': '1.0',
'xmlns:xmpp': 'urn:xmpp:xbosh'}
)
def get_closing_bodytag(self):
closing_bodytag = self.get_bodytag()
closing_bodytag.setAttr('type', 'terminate')
return closing_bodytag
def boshify_stanza(self, stanza):
''' wraps stanza by body tag or modifies message entirely (in case of stream
opening and closing'''
log.info('boshify_staza - type is: %s' % type(stanza))
if isinstance(stanza, simplexml.Node):
tag = self.get_bodytag()
return tag.setPayload(stanza)
else:
# only stream initialization and stream terminatoion are not Nodes
if stanza.startswith(dispatcher_nb.XML_DECLARATION):
# stream init
return self.get_initial_bodytag()
else:
# should be stream closing
assert(stanza == dispatcher_nb.STREAM_TERMINATOR)
return self.get_closing_bodytag()
def _on_stream_start(self):
'''
Called after XMPP stream is opened. In BOSH, TLS is negotiated elsewhere
so success callback can be invoked.
(authentication is started from auth() method)
'''
self.onreceive(None)
if self.connected == 'tcp':
self._on_connect()

View File

@ -21,49 +21,21 @@ examples of xmpppy structures usage.
These classes can be used for simple applications "AS IS" though. These classes can be used for simple applications "AS IS" though.
""" """
import socket import logging
import debug log = logging.getLogger('gajim.c.x.plugin')
Debug=debug
Debug.DEBUGGING_IS_ON=1
Debug.Debug.colors['socket']=debug.color_dark_gray
Debug.Debug.colors['CONNECTproxy']=debug.color_dark_gray
Debug.Debug.colors['nodebuilder']=debug.color_brown
Debug.Debug.colors['client']=debug.color_cyan
Debug.Debug.colors['component']=debug.color_cyan
Debug.Debug.colors['dispatcher']=debug.color_green
Debug.Debug.colors['browser']=debug.color_blue
Debug.Debug.colors['auth']=debug.color_yellow
Debug.Debug.colors['roster']=debug.color_magenta
Debug.Debug.colors['ibb']=debug.color_yellow
Debug.Debug.colors['down']=debug.color_brown
Debug.Debug.colors['up']=debug.color_brown
Debug.Debug.colors['data']=debug.color_brown
Debug.Debug.colors['ok']=debug.color_green
Debug.Debug.colors['warn']=debug.color_yellow
Debug.Debug.colors['error']=debug.color_red
Debug.Debug.colors['start']=debug.color_dark_gray
Debug.Debug.colors['stop']=debug.color_dark_gray
Debug.Debug.colors['sent']=debug.color_yellow
Debug.Debug.colors['got']=debug.color_bright_cyan
DBG_CLIENT='client'
DBG_COMPONENT='component'
class PlugIn: class PlugIn:
""" Common xmpppy plugins infrastructure: plugging in/out, debugging. """ """ Common xmpppy plugins infrastructure: plugging in/out, debugging. """
def __init__(self): def __init__(self):
self._exported_methods=[] self._exported_methods=[]
self.DBG_LINE=self.__class__.__name__.lower()
def PlugIn(self,owner): def PlugIn(self,owner):
""" Attach to main instance and register ourself and all our staff in it. """ """ Attach to main instance and register ourself and all our staff in it. """
self._owner=owner self._owner=owner
if self.DBG_LINE not in owner.debug_flags: log.debug('Plugging %s into %s'%(self,self._owner))
owner.debug_flags.append(self.DBG_LINE)
self.DEBUG('Plugging %s into %s'%(self,self._owner),'start')
if owner.__dict__.has_key(self.__class__.__name__): if owner.__dict__.has_key(self.__class__.__name__):
return self.DEBUG('Plugging ignored: another instance already plugged.','error') log.debug('Plugging ignored: another instance already plugged.')
return
self._old_owners_methods=[] self._old_owners_methods=[]
for method in self._exported_methods: for method in self._exported_methods:
if owner.__dict__.has_key(method.__name__): if owner.__dict__.has_key(method.__name__):
@ -76,15 +48,10 @@ class PlugIn:
def PlugOut(self): def PlugOut(self):
""" Unregister all our staff from main instance and detach from it. """ """ Unregister all our staff from main instance and detach from it. """
self.DEBUG('Plugging %s out of %s.'%(self,self._owner),'stop') log.debug('Plugging %s out of %s.'%(self,self._owner))
self._owner.debug_flags.remove(self.DBG_LINE)
for method in self._exported_methods: del self._owner.__dict__[method.__name__] for method in self._exported_methods: del self._owner.__dict__[method.__name__]
for method in self._old_owners_methods: self._owner.__dict__[method.__name__]=method for method in self._old_owners_methods: self._owner.__dict__[method.__name__]=method
del self._owner.__dict__[self.__class__.__name__] del self._owner.__dict__[self.__class__.__name__]
if self.__class__.__dict__.has_key('plugout'): return self.plugout() if self.__class__.__dict__.has_key('plugout'): return self.plugout()
del self._owner del self._owner
def DEBUG(self,text,severity='info'):
""" Feed a provided debug line to main instance's debug facility along with our ID string. """
self._owner.DEBUG(self.DBG_LINE,text,severity)

View File

@ -22,8 +22,6 @@ These classes can be used for simple applications "AS IS" though.
''' '''
import socket import socket
import debug
import random
import transports_nb, tls_nb, dispatcher_nb, auth_nb, roster_nb, protocol import transports_nb, tls_nb, dispatcher_nb, auth_nb, roster_nb, protocol
from client import * from client import *
@ -31,54 +29,29 @@ from client import *
import logging import logging
log = logging.getLogger('gajim.c.x.client_nb') log = logging.getLogger('gajim.c.x.client_nb')
consoleloghandler = logging.StreamHandler()
consoleloghandler.setLevel(logging.DEBUG)
consoleloghandler.setFormatter(
logging.Formatter('%(levelname)s: %(message)s')
)
log.setLevel(logging.DEBUG)
log.addHandler(consoleloghandler)
log.propagate = False
class NBCommonClient: class NBCommonClient:
''' Base for Client and Component classes.''' ''' Base for Client and Component classes.'''
def __init__(self, hostname, idlequeue, port=5222, debug=['always', 'nodebuilder'], caller=None): def __init__(self, domain, idlequeue, caller=None):
''' Caches connection data: ''' Caches connection data:
:param hostname: hostname of machine where the XMPP server is running (from Account :param domain: domain - for to: attribute (from account info)
of from SRV request) and port to connect to.
:param idlequeue: processing idlequeue :param idlequeue: processing idlequeue
:param port: port of listening XMPP server :param port: port of listening XMPP server
:param debug: specifies the debug IDs that will go into debug output. You can either
specifiy an "include" or "exclude" list. The latter is done via adding "always"
pseudo-ID to the list. Full list: ['nodebuilder', 'dispatcher', 'gen_auth',
'SASL_auth', 'bind', 'socket', 'CONNECTproxy', 'TLS', 'roster', 'browser', 'ibb'].
TODO: get rid of debug.py using
:param caller: calling object - it has to implement certain methods (necessary?) :param caller: calling object - it has to implement certain methods (necessary?)
''' '''
self.DBG = DBG_CLIENT
self.Namespace = protocol.NS_CLIENT self.Namespace = protocol.NS_CLIENT
self.idlequeue = idlequeue self.idlequeue = idlequeue
self.defaultNamespace = self.Namespace self.defaultNamespace = self.Namespace
self.disconnect_handlers = [] self.disconnect_handlers = []
# XMPP server and port from account or SRV self.Server = domain
self.Server = hostname
self.Port = port
# caller is who initiated this client, it is sed to register the EventDispatcher # caller is who initiated this client, it is sed to register the EventDispatcher
self._caller = caller self._caller = caller
if debug and type(debug) != list:
debug = ['always', 'nodebuilder']
self._DEBUG = Debug.Debug(debug)
self.DEBUG = self._DEBUG.Show
self.debug_flags = self._DEBUG.debug_flags
self.debug_flags.append(self.DBG)
self._owner = self self._owner = self
self._registered_name = None self._registered_name = None
self.connected = '' self.connected = ''
@ -98,9 +71,9 @@ class NBCommonClient:
''' '''
self.connected='' self.connected=''
self.DEBUG(self.DBG,'Disconnect detected','stop') log.debug('Client disconnected..')
for i in reversed(self.disconnect_handlers): for i in reversed(self.disconnect_handlers):
self.DEBUG(self.DBG, 'Calling disc handler %s' % i, 'stop') log.debug('Calling disconnect handler %s' % i)
i() i()
if self.__dict__.has_key('NonBlockingRoster'): if self.__dict__.has_key('NonBlockingRoster'):
self.NonBlockingRoster.PlugOut() self.NonBlockingRoster.PlugOut()
@ -120,23 +93,22 @@ class NBCommonClient:
self.NonBlockingTcp.PlugOut() self.NonBlockingTcp.PlugOut()
def send(self, stanza, is_message = False, now = False): def send(self, stanza, now = False):
''' interface for putting stanzas on wire. Puts ID to stanza if needed and ''' interface for putting stanzas on wire. Puts ID to stanza if needed and
sends it via socket wrapper''' sends it via socket wrapper'''
(id, stanza_to_send) = self.Dispatcher.assign_id(stanza) (id, stanza_to_send) = self.Dispatcher.assign_id(stanza)
if is_message: self.Connection.send(stanza_to_send, now = now)
# somehow zeroconf-specific
self.Connection.send(stanza_to_send, True, now = now)
else:
self.Connection.send(stanza_to_send, now = now)
return id return id
def connect(self, on_connect, on_connect_failure, on_proxy_failure=None, proxy=None, secure=None): def connect(self, on_connect, on_connect_failure, hostname=None, port=5222,
on_proxy_failure=None, proxy=None, secure=None):
''' '''
Open XMPP connection (open streams in both directions). Open XMPP connection (open streams in both directions).
:param hostname: hostname of XMPP server from SRV request
:param port: port number of XMPP server
:param on_connect: called after stream is successfully opened :param on_connect: called after stream is successfully opened
:param on_connect_failure: called when error occures during connection :param on_connect_failure: called when error occures during connection
:param on_proxy_failure: called if error occurres during TCP connection to :param on_proxy_failure: called if error occurres during TCP connection to
@ -146,7 +118,12 @@ class NBCommonClient:
optionally keys 'user' and 'pass' as proxy credentials optionally keys 'user' and 'pass' as proxy credentials
:param secure: :param secure:
''' '''
self.Port = port
if hostname:
xmpp_hostname = hostname
else:
xmpp_hostname = self.Server
self.on_connect = on_connect self.on_connect = on_connect
self.on_connect_failure=on_connect_failure self.on_connect_failure=on_connect_failure
self.on_proxy_failure = on_proxy_failure self.on_proxy_failure = on_proxy_failure
@ -155,8 +132,8 @@ class NBCommonClient:
if proxy: if proxy:
# with proxies, client connects to proxy instead of directly to # with proxies, client connects to proxy instead of directly to
# XMPP server from __init__. # XMPP server ((hostname, port))
# tcp_server is hostname used for socket connecting # tcp_server is machine used for socket connection
tcp_server=proxy['host'] tcp_server=proxy['host']
tcp_port=proxy['port'] tcp_port=proxy['port']
self._on_tcp_failure = self.on_proxy_failure self._on_tcp_failure = self.on_proxy_failure
@ -168,30 +145,33 @@ class NBCommonClient:
type_ = proxy['type'] type_ = proxy['type']
if type_ == 'socks5': if type_ == 'socks5':
# SOCKS5 proxy
self.socket = transports_nb.NBSOCKS5ProxySocket( self.socket = transports_nb.NBSOCKS5ProxySocket(
on_disconnect=self.on_disconnect, on_disconnect=self.on_disconnect,
proxy_creds=proxy_creds, proxy_creds=proxy_creds,
xmpp_server=(self.Server, self.Port)) xmpp_server=(xmpp_hostname, self.Port))
elif type_ == 'http': elif type_ == 'http':
# HTTP CONNECT to proxy
self.socket = transports_nb.NBHTTPProxySocket( self.socket = transports_nb.NBHTTPProxySocket(
on_disconnect=self.on_disconnect, on_disconnect=self.on_disconnect,
proxy_creds=proxy_creds, proxy_creds=proxy_creds,
xmpp_server=(self.Server, self.Port)) xmpp_server=(xmpp_hostname, self.Port))
elif type_ == 'bosh': elif type_ == 'bosh':
# BOSH - XMPP over HTTP
tcp_server = transports_nb.urisplit(tcp_server)[1] tcp_server = transports_nb.urisplit(tcp_server)[1]
self.socket = transports_nb.NonBlockingHttpBOSH( self.socket = transports_nb.NonBlockingHTTP(
on_disconnect=self.on_disconnect, on_disconnect=self.on_disconnect,
bosh_uri = proxy['host'], http_uri = proxy['host'],
bosh_port = tcp_port) http_port = tcp_port)
else: else:
# HTTP CONNECT to proxy from environment variables # HTTP CONNECT to proxy from environment variables
self.socket = transports_nb.NBHTTPProxySocket( self.socket = transports_nb.NBHTTPProxySocket(
on_disconnect=self.on_disconnect, on_disconnect=self.on_disconnect,
proxy_creds=(None, None), proxy_creds=(None, None),
xmpp_server=(self.Server, self.Port)) xmpp_server=(xmpp_hostname, self.Port))
else: else:
self._on_tcp_failure = self._on_connect_failure self._on_tcp_failure = self._on_connect_failure
tcp_server=self.Server tcp_server=xmpp_hostname
tcp_port=self.Port tcp_port=self.Port
self.socket = transports_nb.NonBlockingTcp(on_disconnect = self.on_disconnect) self.socket = transports_nb.NonBlockingTcp(on_disconnect = self.on_disconnect)
@ -221,7 +201,7 @@ class NBCommonClient:
def _try_next_ip(self, err_message=None): def _try_next_ip(self, err_message=None):
'''iterates over IP addresses from getaddinfo''' '''iterates over IP addresses from getaddinfo'''
if err_message: if err_message:
self.DEBUG(self.DBG,err_message,'connect') log.debug('While looping over DNS A records: %s' % connect)
if self.ip_addresses == []: if self.ip_addresses == []:
self._on_tcp_failure(err_message='Run out of hosts for name %s:%s' % self._on_tcp_failure(err_message='Run out of hosts for name %s:%s' %
(self.Server, self.Port)) (self.Server, self.Port))
@ -305,7 +285,7 @@ class NBCommonClient:
def _on_connect_failure(self, retry=None, err_message=None): def _on_connect_failure(self, retry=None, err_message=None):
self.connected = None self.connected = None
if err_message: if err_message:
self.DEBUG(self.DBG, err_message, 'connecting') log.debug('While connecting: %s' % err_message)
if self.socket: if self.socket:
self.socket.disconnect() self.socket.disconnect()
self.on_connect_failure(retry) self.on_connect_failure(retry)
@ -460,83 +440,3 @@ class NonBlockingClient(NBCommonClient):
self.send(dispatcher_nb.Presence(to=jid, typ=typ)) self.send(dispatcher_nb.Presence(to=jid, typ=typ))
class BOSHClient(NBCommonClient):
'''
Client class implementing BOSH.
'''
def __init__(self, *args, **kw):
'''Preceeds constructor of NBCommonClient and sets some of values that will
be used as attributes in <body> tag'''
self.Namespace = NS_HTTP_BIND
# BOSH parameters should be given via Advanced Configuration Editor
self.bosh_hold = 1
self.bosh_wait=60
self.bosh_rid=-1
self.bosh_httpversion = 'HTTP/1.1'
NBCommonClient.__init__(self, *args, **kw)
def connect(self, *args, **kw):
proxy = kw['proxy']
self.bosh_protocol, self.bosh_host, self.bosh_uri = self.urisplit(proxy['host'])
self.bosh_port = proxy['port']
NBCommonClient.connect(*args, **kw)
def _on_stream_start(self):
'''
Called after XMPP stream is opened. In BOSH TLS is negotiated on tranport layer
so success callback can be invoked.
(authentication is started from auth() method)
'''
self.onreceive(None)
if self.connected == 'tcp':
self._on_connect()
def bosh_raise_event(self, realm, event, data):
# should to extract stanza from body
self.DEBUG(self.DBG,'realm: %s, event: %s, data: %s' % (realm, event, data),
'BOSH EventHandler')
self._caller._event_dispatcher(realm, event, data)
def StreamInit(self):
'''
Init of BOSH session. Called instead of Dispatcher.StreamInit()
Initial body tag is created and sent.
'''
#self.Dispatcher.RegisterEventHandler(self.bosh_event_handler)
self.Dispatcher.Stream = simplexml.NodeBuilder()
self.Dispatcher.Stream._dispatch_depth = 2
self.Dispatcher.Stream.dispatch = self.Dispatcher.dispatch
self.Dispatcher.Stream.stream_header_received = self._check_stream_start
self.Dispatcher.Stream.features = None
r = random.Random()
r.seed()
# with 50-bit random initial rid, session would have to go up
# to 7881299347898368 messages to raise rid over 2**53
# (see http://www.xmpp.org/extensions/xep-0124.html#rids)
self.bosh_rid = r.getrandbits(50)
initial_body_tag = BOSHBody(
attrs={'content': 'text/xml; charset=utf-8',
'hold': str(self.bosh_hold),
# "to" should be domain, not hostname of machine
'to': self.Server,
'wait': str(self.bosh_wait),
'rid': str(self.bosh_rid),
'xmpp:version': '1.0',
'xmlns:xmpp': 'urn:xmpp:xbosh'}
)
if locale.getdefaultlocale()[0]:
initial_body_tag.setAttr('xml:lang',
locale.getdefaultlocale()[0].split('_')[0])
initial_body_tag.setAttr('xmpp:version', '1.0')
initial_body_tag.setAttr('xmlns:xmpp', 'urn:xmpp:xbosh')
self.send(initial_body_tag)

View File

@ -28,16 +28,21 @@ from xml.parsers.expat import ExpatError
from protocol import * from protocol import *
from client import PlugIn from client import PlugIn
import logging
log = logging.getLogger('gajim.c.x.dispatcher_nb')
# default timeout to wait for response for our id # default timeout to wait for response for our id
DEFAULT_TIMEOUT_SECONDS = 25 DEFAULT_TIMEOUT_SECONDS = 25
ID = 0 ID = 0
STREAM_TERMINATOR = '</stream:stream>'
XML_DECLARATION = '<?xml version=\'1.0\'?>'
class Dispatcher(PlugIn): class Dispatcher(PlugIn):
''' Ancestor of PlugIn class. Handles XMPP stream, i.e. aware of stream headers. ''' Ancestor of PlugIn class. Handles XMPP stream, i.e. aware of stream headers.
Can be plugged out/in to restart these headers (used for SASL f.e.). ''' Can be plugged out/in to restart these headers (used for SASL f.e.). '''
def __init__(self): def __init__(self):
PlugIn.__init__(self) PlugIn.__init__(self)
DBG_LINE='dispatcher'
self.handlers={} self.handlers={}
self._expected={} self._expected={}
self._defaultHandler=None self._defaultHandler=None
@ -79,7 +84,7 @@ class Dispatcher(PlugIn):
def plugin(self, owner): def plugin(self, owner):
''' Plug the Dispatcher instance into Client class instance and send initial stream header. Used internally.''' ''' Plug the Dispatcher instance into Client class instance and send initial stream header. Used internally.'''
self.DEBUG('Dispatcher plugin', 'PlugIn') log.debug('Dispatcher plugin')
self._init() self._init()
self._owner.lastErrNode = None self._owner.lastErrNode = None
@ -93,7 +98,6 @@ class Dispatcher(PlugIn):
def plugout(self): def plugout(self):
''' Prepares instance to be destructed. ''' ''' Prepares instance to be destructed. '''
self.Stream.dispatch = None self.Stream.dispatch = None
self.Stream.DEBUG = None
self.Stream.features = None self.Stream.features = None
self.Stream.destroy() self.Stream.destroy()
self._owner = None self._owner = None
@ -105,8 +109,6 @@ class Dispatcher(PlugIn):
self.Stream._dispatch_depth = 2 self.Stream._dispatch_depth = 2
self.Stream.dispatch = self.dispatch self.Stream.dispatch = self.dispatch
self.Stream.stream_header_received = self._check_stream_start self.Stream.stream_header_received = self._check_stream_start
self._owner.debug_flags.append(simplexml.DBG_NODEBUILDER)
self.Stream.DEBUG = self._owner.DEBUG
self.Stream.features = None self.Stream.features = None
self._metastream = Node('stream:stream') self._metastream = Node('stream:stream')
self._metastream.setNamespace(self._owner.Namespace) self._metastream.setNamespace(self._owner.Namespace)
@ -116,11 +118,11 @@ class Dispatcher(PlugIn):
if locale.getdefaultlocale()[0]: if locale.getdefaultlocale()[0]:
self._metastream.setAttr('xml:lang', self._metastream.setAttr('xml:lang',
locale.getdefaultlocale()[0].split('_')[0]) locale.getdefaultlocale()[0].split('_')[0])
self._owner.send("<?xml version='1.0'?>%s>" % str(self._metastream)[:-2]) self._owner.send("%s%s>" % (XML_DECLARATION,str(self._metastream)[:-2]))
def StreamTerminate(self): def StreamTerminate(self):
''' Send a stream terminator. ''' ''' Send a stream terminator. '''
self._owner.send('</stream:stream>') self._owner.send(STREAM_TERMINATOR)
def _check_stream_start(self, ns, tag, attrs): def _check_stream_start(self, ns, tag, attrs):
if ns<>NS_STREAMS or tag<>'stream': if ns<>NS_STREAMS or tag<>'stream':
@ -144,7 +146,7 @@ class Dispatcher(PlugIn):
self._owner.Connection.disconnect() self._owner.Connection.disconnect()
return 0 return 0
except ExpatError: except ExpatError:
self.DEBUG('Invalid XML received from server. Forcing disconnect.', 'error') log.error('Invalid XML received from server. Forcing disconnect.')
self._owner.Connection.disconnect() self._owner.Connection.disconnect()
return 0 return 0
if len(self._pendingExceptions) > 0: if len(self._pendingExceptions) > 0:
@ -157,7 +159,7 @@ class Dispatcher(PlugIn):
''' Creates internal structures for newly registered namespace. ''' Creates internal structures for newly registered namespace.
You can register handlers for this namespace afterwards. By default one namespace You can register handlers for this namespace afterwards. By default one namespace
already registered (jabber:client or jabber:component:accept depending on context. ''' already registered (jabber:client or jabber:component:accept depending on context. '''
self.DEBUG('Registering namespace "%s"' % xmlns, order) log.info('Registering namespace "%s"' % xmlns)
self.handlers[xmlns]={} self.handlers[xmlns]={}
self.RegisterProtocol('unknown', Protocol, xmlns=xmlns) self.RegisterProtocol('unknown', Protocol, xmlns=xmlns)
self.RegisterProtocol('default', Protocol, xmlns=xmlns) self.RegisterProtocol('default', Protocol, xmlns=xmlns)
@ -167,8 +169,7 @@ class Dispatcher(PlugIn):
Needed to start registering handlers for such stanzas. Needed to start registering handlers for such stanzas.
Iq, message and presence protocols are registered by default. ''' Iq, message and presence protocols are registered by default. '''
if not xmlns: xmlns=self._owner.defaultNamespace if not xmlns: xmlns=self._owner.defaultNamespace
self.DEBUG('Registering protocol "%s" as %s(%s)' % log.info('Registering protocol "%s" as %s(%s)' %(tag_name, Proto, xmlns))
(tag_name, Proto, xmlns), order)
self.handlers[xmlns][tag_name]={type:Proto, 'default':[]} self.handlers[xmlns][tag_name]={type:Proto, 'default':[]}
def RegisterNamespaceHandler(self, xmlns, handler, typ='', ns='', makefirst=0, system=0): def RegisterNamespaceHandler(self, xmlns, handler, typ='', ns='', makefirst=0, system=0):
@ -195,8 +196,8 @@ class Dispatcher(PlugIn):
''' '''
if not xmlns: if not xmlns:
xmlns=self._owner.defaultNamespace xmlns=self._owner.defaultNamespace
self.DEBUG('Registering handler %s for "%s" type->%s ns->%s(%s)' % log.info('Registering handler %s for "%s" type->%s ns->%s(%s)' %
(handler, name, typ, ns, xmlns), 'info') (handler, name, typ, ns, xmlns))
if not typ and not ns: if not typ and not ns:
typ='default' typ='default'
if not self.handlers.has_key(xmlns): if not self.handlers.has_key(xmlns):
@ -313,13 +314,13 @@ class Dispatcher(PlugIn):
xmlns=stanza.getNamespace() xmlns=stanza.getNamespace()
if not self.handlers.has_key(xmlns): if not self.handlers.has_key(xmlns):
self.DEBUG("Unknown namespace: " + xmlns, 'warn') log.warn("Unknown namespace: " + xmlns)
xmlns='unknown' xmlns='unknown'
if not self.handlers[xmlns].has_key(name): if not self.handlers[xmlns].has_key(name):
self.DEBUG("Unknown stanza: " + name, 'warn') log.warn("Unknown stanza: " + name)
name='unknown' name='unknown'
else: else:
self.DEBUG("Got %s/%s stanza" % (xmlns, name), 'ok') log.debug("Got %s/%s stanza" % (xmlns, name))
if stanza.__class__.__name__=='Node': if stanza.__class__.__name__=='Node':
stanza=self.handlers[xmlns][name][type](node=stanza) stanza=self.handlers[xmlns][name][type](node=stanza)
@ -329,7 +330,7 @@ class Dispatcher(PlugIn):
stanza.props=stanza.getProperties() stanza.props=stanza.getProperties()
ID=stanza.getID() ID=stanza.getID()
session.DEBUG("Dispatching %s stanza with type->%s props->%s id->%s"%(name,typ,stanza.props,ID),'ok') log.debug("Dispatching %s stanza with type->%s props->%s id->%s"%(name,typ,stanza.props,ID))
list=['default'] # we will use all handlers: list=['default'] # we will use all handlers:
if self.handlers[xmlns][name].has_key(typ): list.append(typ) # from very common... if self.handlers[xmlns][name].has_key(typ): list.append(typ) # from very common...
for prop in stanza.props: for prop in stanza.props:
@ -345,13 +346,13 @@ class Dispatcher(PlugIn):
user=0 user=0
if type(session._expected[ID]) == type(()): if type(session._expected[ID]) == type(()):
cb,args = session._expected[ID] cb,args = session._expected[ID]
session.DEBUG("Expected stanza arrived. Callback %s(%s) found!" % (cb, args), 'ok') log.debug("Expected stanza arrived. Callback %s(%s) found!" % (cb, args))
try: try:
cb(session,stanza,**args) cb(session,stanza,**args)
except Exception, typ: except Exception, typ:
if typ.__class__.__name__ <>'NodeProcessed': raise if typ.__class__.__name__ <>'NodeProcessed': raise
else: else:
session.DEBUG("Expected stanza arrived!",'ok') log.debug("Expected stanza arrived!")
session._expected[ID]=stanza session._expected[ID]=stanza
else: else:
user=1 user=1

View File

@ -13,6 +13,8 @@
## GNU General Public License for more details. ## GNU General Public License for more details.
import select import select
import logging
log = logging.getLogger('gajim.c.x.idlequeue')
class IdleObject: class IdleObject:
''' base class for all idle listeners, these are the methods, which are called from IdleQueue ''' base class for all idle listeners, these are the methods, which are called from IdleQueue
@ -53,7 +55,7 @@ class IdleQueue:
self.selector = select.poll() self.selector = select.poll()
def remove_timeout(self, fd): def remove_timeout(self, fd):
print 'read timeout removed for fd %s' % fd log.debug('read timeout removed for fd %s' % fd)
if self.read_timeouts.has_key(fd): if self.read_timeouts.has_key(fd):
del(self.read_timeouts[fd]) del(self.read_timeouts[fd])
@ -69,7 +71,7 @@ class IdleQueue:
def set_read_timeout(self, fd, seconds): def set_read_timeout(self, fd, seconds):
''' set a new timeout, if it is not removed after 'seconds', ''' set a new timeout, if it is not removed after 'seconds',
then obj.read_timeout() will be called ''' then obj.read_timeout() will be called '''
print 'read timeout set for fd %s on %s seconds' % (fd, seconds) log.debug('read timeout set for fd %s on %s seconds' % (fd, seconds))
timeout = self.current_time() + seconds timeout = self.current_time() + seconds
self.read_timeouts[fd] = timeout self.read_timeouts[fd] = timeout
@ -79,6 +81,7 @@ class IdleQueue:
if timeout > current_time: if timeout > current_time:
continue continue
if self.queue.has_key(fd): if self.queue.has_key(fd):
log.debug('Calling read_timeout for fd %s' % fd)
self.queue[fd].read_timeout() self.queue[fd].read_timeout()
else: else:
self.remove_timeout(fd) self.remove_timeout(fd)

View File

@ -24,6 +24,10 @@ mass-renaming of contacts.
from protocol import * from protocol import *
from client import PlugIn from client import PlugIn
import logging
log = logging.getLogger('gajim.c.x.roster_nb')
class NonBlockingRoster(PlugIn): class NonBlockingRoster(PlugIn):
""" Defines a plenty of methods that will allow you to manage roster. """ Defines a plenty of methods that will allow you to manage roster.
Also automatically track presences from remote JIDs taking into Also automatically track presences from remote JIDs taking into
@ -35,7 +39,6 @@ class NonBlockingRoster(PlugIn):
def __init__(self): def __init__(self):
""" Init internal variables. """ """ Init internal variables. """
PlugIn.__init__(self) PlugIn.__init__(self)
self.DBG_LINE='roster'
self._data = {} self._data = {}
self.set=None self.set=None
self._exported_methods=[self.getRoster] self._exported_methods=[self.getRoster]
@ -46,7 +49,7 @@ class NonBlockingRoster(PlugIn):
if self.set is None: self.set=0 if self.set is None: self.set=0
elif not force: return elif not force: return
self._owner.send(Iq('get',NS_ROSTER)) self._owner.send(Iq('get',NS_ROSTER))
self.DEBUG('Roster requested from server','start') log.info('Roster requested from server')
def RosterIqHandler(self,dis,stanza): def RosterIqHandler(self,dis,stanza):
""" Subscription tracker. Used internally for setting items state in """ Subscription tracker. Used internally for setting items state in
@ -60,7 +63,7 @@ class NonBlockingRoster(PlugIn):
if item.getAttr('subscription')=='remove': if item.getAttr('subscription')=='remove':
if self._data.has_key(jid): del self._data[jid] if self._data.has_key(jid): del self._data[jid]
return return
self.DEBUG('Setting roster item %s...'%jid,'ok') log.info('Setting roster item %s...' % jid)
if not self._data.has_key(jid): self._data[jid]={} if not self._data.has_key(jid): self._data[jid]={}
self._data[jid]['name']=item.getAttr('name') self._data[jid]['name']=item.getAttr('name')
self._data[jid]['ask']=item.getAttr('ask') self._data[jid]['ask']=item.getAttr('ask')
@ -86,7 +89,7 @@ class NonBlockingRoster(PlugIn):
typ=pres.getType() typ=pres.getType()
if not typ: if not typ:
self.DEBUG('Setting roster item %s for resource %s...'%(jid.getStripped(),jid.getResource()),'ok') log.info('Setting roster item %s for resource %s...'%(jid.getStripped(),jid.getResource()))
item['resources'][jid.getResource()]=res={'show':None,'status':None,'priority':'0','timestamp':None} item['resources'][jid.getResource()]=res={'show':None,'status':None,'priority':'0','timestamp':None}
if pres.getTag('show'): res['show']=pres.getShow() if pres.getTag('show'): res['show']=pres.getShow()
if pres.getTag('status'): res['status']=pres.getStatus() if pres.getTag('status'): res['status']=pres.getStatus()

View File

@ -18,6 +18,9 @@
I'm personally using it in many other separate projects. It is designed to be as standalone as possible.""" I'm personally using it in many other separate projects. It is designed to be as standalone as possible."""
import xml.parsers.expat import xml.parsers.expat
import logging
log = logging.getLogger('gajim.c.x.simplexml')
def XMLescape(txt): def XMLescape(txt):
"""Returns provided string with symbols & < > " replaced by their respective XML entities.""" """Returns provided string with symbols & < > " replaced by their respective XML entities."""
@ -279,7 +282,6 @@ class NT(T):
if isinstance(val,Node): self.node.addChild(attr,node=val) if isinstance(val,Node): self.node.addChild(attr,node=val)
else: return self.node.addChild(attr,payload=[val]) else: return self.node.addChild(attr,payload=[val])
DBG_NODEBUILDER = 'nodebuilder'
class NodeBuilder: class NodeBuilder:
""" Builds a Node class minidom from data parsed to it. This class used for two purposes: """ Builds a Node class minidom from data parsed to it. This class used for two purposes:
1. Creation an XML Node from a textual representation. F.e. reading a config file. See an XML2Node method. 1. Creation an XML Node from a textual representation. F.e. reading a config file. See an XML2Node method.
@ -293,7 +295,7 @@ class NodeBuilder:
You can think about it as of "node upgrade". You can think about it as of "node upgrade".
"data" (if provided) feeded to parser immidiatedly after instance init. "data" (if provided) feeded to parser immidiatedly after instance init.
""" """
self.DEBUG(DBG_NODEBUILDER, "Preparing to handle incoming XML stream.", 'start') log.debug("Preparing to handle incoming XML stream.")
self._parser = xml.parsers.expat.ParserCreate(namespace_separator=' ') self._parser = xml.parsers.expat.ParserCreate(namespace_separator=' ')
self._parser.StartElementHandler = self.starttag self._parser.StartElementHandler = self.starttag
self._parser.EndElementHandler = self.endtag self._parser.EndElementHandler = self.endtag
@ -341,7 +343,7 @@ class NodeBuilder:
attrs[self.namespaces[ns]+attr[sp+1:]]=attrs[attr] attrs[self.namespaces[ns]+attr[sp+1:]]=attrs[attr]
del attrs[attr] # del attrs[attr] #
self._inc_depth() self._inc_depth()
self.DEBUG(DBG_NODEBUILDER, "DEPTH -> %i , tag -> %s, attrs -> %s" % (self.__depth, tag, `attrs`), 'down') log.info("DEPTH -> %i , tag -> %s, attrs -> %s" % (self.__depth, tag, `attrs`))
if self.__depth == self._dispatch_depth: if self.__depth == self._dispatch_depth:
if not self._mini_dom : if not self._mini_dom :
self._mini_dom = Node(tag=tag, attrs=attrs) self._mini_dom = Node(tag=tag, attrs=attrs)
@ -360,14 +362,14 @@ class NodeBuilder:
self.last_is_data = 0 self.last_is_data = 0
def endtag(self, tag ): def endtag(self, tag ):
"""XML Parser callback. Used internally""" """XML Parser callback. Used internally"""
self.DEBUG(DBG_NODEBUILDER, "DEPTH -> %i , tag -> %s" % (self.__depth, tag), 'up') log.info("DEPTH -> %i , tag -> %s" % (self.__depth, tag))
self.check_data_buffer() self.check_data_buffer()
if self.__depth == self._dispatch_depth: if self.__depth == self._dispatch_depth:
self.dispatch(self._mini_dom) self.dispatch(self._mini_dom)
elif self.__depth > self._dispatch_depth: elif self.__depth > self._dispatch_depth:
self._ptr = self._ptr.parent self._ptr = self._ptr.parent
else: else:
self.DEBUG(DBG_NODEBUILDER, "Got higher than dispatch level. Stream terminated?", 'stop') log.info("Got higher than dispatch level. Stream terminated?")
self._dec_depth() self._dec_depth()
self.last_is_data = 0 self.last_is_data = 0
if self.__depth == 0: self.stream_footer_received() if self.__depth == 0: self.stream_footer_received()
@ -385,8 +387,7 @@ class NodeBuilder:
self.check_data_buffer() self.check_data_buffer()
if prefix: self.namespaces[uri]=prefix+':' if prefix: self.namespaces[uri]=prefix+':'
else: self.xmlns=uri else: self.xmlns=uri
def DEBUG(self, level, text, comment=None):
""" Gets all NodeBuilder walking events. Can be used for debugging if redefined."""
def getDom(self): def getDom(self):
""" Returns just built Node. """ """ Returns just built Node. """
self.check_data_buffer() self.check_data_buffer()

View File

@ -26,16 +26,8 @@ import time
import traceback import traceback
import logging import logging
log = logging.getLogger('gajim.c.x.tls_nb') log = logging.getLogger('gajim.c.x.tls_nb')
consoleloghandler = logging.StreamHandler()
consoleloghandler.setLevel(logging.DEBUG)
consoleloghandler.setFormatter(
logging.Formatter('%(levelname)s: %(message)s')
)
log.setLevel(logging.DEBUG)
log.addHandler(consoleloghandler)
log.propagate = False
# I don't need to load gajim.py just because of few TLS variables, so I changed # I don't need to load gajim.py just because of few TLS variables, so I changed
# %s/common\.gajim\.DATA_DIR/\'\.\.\/data\'/c # %s/common\.gajim\.DATA_DIR/\'\.\.\/data\'/c
# %s/common\.gajim\.MY_CACERTS/\'\%s\/\.gajim\/cacerts\.pem\' \% os\.environ\[\'HOME\'\]/c # %s/common\.gajim\.MY_CACERTS/\'\%s\/\.gajim\/cacerts\.pem\' \% os\.environ\[\'HOME\'\]/c
@ -49,6 +41,11 @@ log.propagate = False
USE_PYOPENSSL = False USE_PYOPENSSL = False
#TODO: add callback set from PlugIn for errors during runtime
# - sth like on_disconnect in socket wrappers
try: try:
#raise ImportError("Manually disabled PyOpenSSL") #raise ImportError("Manually disabled PyOpenSSL")
import OpenSSL.SSL import OpenSSL.SSL
@ -164,8 +161,8 @@ class PyOpenSSLWrapper(SSLWrapper):
if flags is None: retval = self.sslobj.recv(bufsize) if flags is None: retval = self.sslobj.recv(bufsize)
else: retval = self.sslobj.recv(bufsize, flags) else: retval = self.sslobj.recv(bufsize, flags)
except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError), e: except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError), e:
log.debug("Recv: Want-error: " + repr(e))
pass pass
# log.debug("Recv: " + repr(e))
except OpenSSL.SSL.SysCallError, e: except OpenSSL.SSL.SysCallError, e:
log.debug("Recv: Got OpenSSL.SSL.SysCallError: " + repr(e), exc_info=True) log.debug("Recv: Got OpenSSL.SSL.SysCallError: " + repr(e), exc_info=True)
#traceback.print_exc() #traceback.print_exc()
@ -253,7 +250,6 @@ class NonBlockingTLS(PlugIn):
if owner.__dict__.has_key('NonBlockingTLS'): if owner.__dict__.has_key('NonBlockingTLS'):
return # Already enabled. return # Already enabled.
PlugIn.PlugIn(self, owner) PlugIn.PlugIn(self, owner)
DBG_LINE='NonBlockingTLS'
self.on_tls_success = on_tls_success self.on_tls_success = on_tls_success
self.on_tls_faliure = on_tls_failure self.on_tls_faliure = on_tls_failure
if now: if now:
@ -288,10 +284,10 @@ class NonBlockingTLS(PlugIn):
''' Used to analyse server <features/> tag for TLS support. ''' Used to analyse server <features/> tag for TLS support.
If TLS is supported starts the encryption negotiation. Used internally ''' If TLS is supported starts the encryption negotiation. Used internally '''
if not feats.getTag('starttls', namespace=NS_TLS): if not feats.getTag('starttls', namespace=NS_TLS):
self.DEBUG("TLS unsupported by remote server.", 'warn') log.warn("TLS unsupported by remote server.")
self.on_tls_failure("TLS unsupported by remote server.") self.on_tls_failure("TLS unsupported by remote server.")
return return
self.DEBUG("TLS supported by remote server. Requesting TLS start.", 'ok') log.debug("TLS supported by remote server. Requesting TLS start.")
self._owner.RegisterHandlerOnce('proceed', self.StartTLSHandler, xmlns=NS_TLS) self._owner.RegisterHandlerOnce('proceed', self.StartTLSHandler, xmlns=NS_TLS)
self._owner.RegisterHandlerOnce('failure', self.StartTLSHandler, xmlns=NS_TLS) self._owner.RegisterHandlerOnce('failure', self.StartTLSHandler, xmlns=NS_TLS)
self._owner.send('<starttls xmlns="%s"/>' % NS_TLS) self._owner.send('<starttls xmlns="%s"/>' % NS_TLS)
@ -425,7 +421,7 @@ class NonBlockingTLS(PlugIn):
if self.starttls == 'failure': if self.starttls == 'failure':
self.on_tls_failure('TLS <failure> received: %s' % self.starttls) self.on_tls_failure('TLS <failure> received: %s' % self.starttls)
return return
self.DEBUG('Got starttls proceed response. Switching to TLS/SSL...','ok') log.debug('Got starttls proceed response. Switching to TLS/SSL...')
try: try:
self._startSSL() self._startSSL()
except Exception, e: except Exception, e:

View File

@ -30,17 +30,9 @@ import traceback
import logging import logging
log = logging.getLogger('gajim.c.x.transports_nb') log = logging.getLogger('gajim.c.x.transports_nb')
consoleloghandler = logging.StreamHandler()
consoleloghandler.setLevel(logging.DEBUG)
consoleloghandler.setFormatter(
logging.Formatter('%(levelname)s: %(message)s')
)
log.setLevel(logging.DEBUG)
log.addHandler(consoleloghandler)
log.propagate = False
def urisplit(self, uri): def urisplit(uri):
''' '''
Function for splitting URI string to tuple (protocol, host, path). Function for splitting URI string to tuple (protocol, host, path).
e.g. urisplit('http://httpcm.jabber.org/webclient') returns e.g. urisplit('http://httpcm.jabber.org/webclient') returns
@ -72,6 +64,23 @@ CONNECTING ='CONNECTING'
CONNECTED ='CONNECTED' CONNECTED ='CONNECTED'
DISCONNECTING ='DISCONNECTING' DISCONNECTING ='DISCONNECTING'
class NonBlockingTransport(PlugIn):
def __init__(self, on_disconnect):
PlugIn.__init__(self)
self.on_disconnect = on_disconnect
def plugin(self, owner):
owner.Connection=self
self.idlequeue = owner.idlequeue
def plugout(self):
self._owner.Connection = None
self._owner = None
class NonBlockingTcp(PlugIn, IdleObject): class NonBlockingTcp(PlugIn, IdleObject):
''' '''
Non-blocking TCP socket wrapper Non-blocking TCP socket wrapper
@ -114,7 +123,6 @@ class NonBlockingTcp(PlugIn, IdleObject):
self.set_timeout, self.remove_timeout] self.set_timeout, self.remove_timeout]
def plugin(self, owner): def plugin(self, owner):
print 'plugin called'
owner.Connection=self owner.Connection=self
self.idlequeue = owner.idlequeue self.idlequeue = owner.idlequeue
@ -142,7 +150,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
self.on_connect = on_connect self.on_connect = on_connect
self.on_connect_failure = on_connect_failure self.on_connect_failure = on_connect_failure
(self.server, self.port) = conn_5tuple[4] (self.server, self.port) = conn_5tuple[4]
log.debug('NonBlocking Connect :: About tot connect to %s:%s' % conn_5tuple[4]) log.info('NonBlocking Connect :: About tot connect to %s:%s' % conn_5tuple[4])
try: try:
self._sock = socket.socket(*conn_5tuple[:3]) self._sock = socket.socket(*conn_5tuple[:3])
except socket.error, (errnum, errstr): except socket.error, (errnum, errstr):
@ -170,14 +178,14 @@ class NonBlockingTcp(PlugIn, IdleObject):
if errnum in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK): if errnum in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK):
# connecting in progress # connecting in progress
self.set_state(CONNECTING) self.set_state(CONNECTING)
log.debug('After connect. "%s" raised => CONNECTING' % errstr) log.info('After connect. "%s" raised => CONNECTING' % errstr)
# on_connect/failure will be called from self.pollin/self.pollout # on_connect/failure will be called from self.pollin/self.pollout
return return
elif errnum in (0, 10056, errno.EISCONN): elif errnum in (0, 10056, errno.EISCONN):
# already connected - this branch is very unlikely, nonblocking connect() will # already connected - this branch is very unlikely, nonblocking connect() will
# return EINPROGRESS exception in most cases. When here, we don't need timeout # return EINPROGRESS exception in most cases. When here, we don't need timeout
# on connected descriptor and success callback can be called. # on connected descriptor and success callback can be called.
log.debug('After connect. "%s" raised => CONNECTED' % errstr) log.info('After connect. "%s" raised => CONNECTED' % errstr)
self._on_connect(self) self._on_connect(self)
return return
@ -212,12 +220,12 @@ class NonBlockingTcp(PlugIn, IdleObject):
def pollin(self): def pollin(self):
'''called when receive on plugged socket is possible ''' '''called when receive on plugged socket is possible '''
log.debug('pollin called, state == %s' % self.state) log.info('pollin called, state == %s' % self.state)
self._do_receive() self._do_receive()
def pollout(self): def pollout(self):
'''called when send to plugged socket is possible''' '''called when send to plugged socket is possible'''
log.debug('pollout called, state == %s' % self.state) log.info('pollout called, state == %s' % self.state)
if self.state==CONNECTING: if self.state==CONNECTING:
self._on_connect(self) self._on_connect(self)
@ -225,7 +233,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
self._do_send() self._do_send()
def pollend(self): def pollend(self):
log.debug('pollend called, state == %s' % self.state) log.info('pollend called, state == %s' % self.state)
if self.state==CONNECTING: if self.state==CONNECTING:
self._on_connect_failure('Error during connect to %s:%s' % self._on_connect_failure('Error during connect to %s:%s' %
@ -251,7 +259,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
''' '''
Implemntation of IdleObject function called on timeouts from IdleQueue. Implemntation of IdleObject function called on timeouts from IdleQueue.
''' '''
log.debug('read_timeout called, state == %s' % self.state) log.warn('read_timeout called, state == %s' % self.state)
if self.state==CONNECTING: if self.state==CONNECTING:
# if read_timeout is called during connecting, connect() didn't end yet # if read_timeout is called during connecting, connect() didn't end yet
# thus we have to call the tcp failure callback # thus we have to call the tcp failure callback
@ -309,17 +317,18 @@ class NonBlockingTcp(PlugIn, IdleObject):
def _plug_idle(self): def _plug_idle(self):
# readable if socket is connected or disconnecting # readable if socket is connected or disconnecting
readable = self.state != DISCONNECTED readable = self.state != DISCONNECTED
fd = self.get_fd()
# writeable if sth to send # writeable if sth to send
if self.sendqueue or self.sendbuff: if self.sendqueue or self.sendbuff:
writable = True writable = True
else: else:
writable = False writable = False
print 'About to plug fd %d, W:%s, R:%s' % (self.get_fd(), writable, readable) log.debug('About to plug fd %d, W:%s, R:%s' % (fd, writable, readable))
if self.writable != writable or self.readable != readable: if self.writable != writable or self.readable != readable:
print 'Really plugging fd %d, W:%s, R:%s' % (self.get_fd(), writable, readable) log.debug('Really plugging fd %d, W:%s, R:%s' % (fd, writable, readable))
self.idlequeue.plug_idle(self, writable, readable) self.idlequeue.plug_idle(self, writable, readable)
else: else:
print 'Not plugging - is already plugged' log.debug('Not plugging fd %s because it\'s already plugged' % fd)
@ -343,7 +352,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
def _raise_event(self, event_type, data): def _raise_event(self, event_type, data):
if data and data.strip(): if data and data.strip():
log.debug('raising event from transport: %s %s' % (event_type,data)) log.info('raising event from transport: %s %s' % (event_type,data))
if hasattr(self._owner, 'Dispatcher'): if hasattr(self._owner, 'Dispatcher'):
self._owner.Dispatcher.Event('', event_type, data) self._owner.Dispatcher.Event('', event_type, data)
@ -356,7 +365,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
else: else:
self.on_receive = None self.on_receive = None
return return
log.debug('setting onreceive on %s' % recv_handler) log.info('setting onreceive on %s' % recv_handler)
self.on_receive = recv_handler self.on_receive = recv_handler
@ -372,7 +381,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
received = self._recv(RECV_BUFSIZE) received = self._recv(RECV_BUFSIZE)
except (socket.error, socket.herror, socket.gaierror), (errnum, errstr): except (socket.error, socket.herror, socket.gaierror), (errnum, errstr):
# save exception number and message to errnum, errstr # save exception number and message to errnum, errstr
log.debug("_do_receive: got %s:" % received , exc_info=True) log.info("_do_receive: got %s:" % received , exc_info=True)
if received == '': if received == '':
errnum = ERR_DISCONN errnum = ERR_DISCONN
@ -412,10 +421,76 @@ class NonBlockingTcp(PlugIn, IdleObject):
def _on_receive(self, data): def _on_receive(self, data):
# Overriding this method allows modifying received data before it is passed # Overriding this method allows modifying received data before it is passed
# to owner's callback. # to owner's callback.
log.debug('About to call on_receive which is %s' % self.on_receive) log.info('About to call on_receive which is %s' % self.on_receive)
self.on_receive(data) self.on_receive(data)
class NonBlockingHTTP(NonBlockingTcp):
'''
Socket wrapper that cretes HTTP message out of sent data and peels-off
HTTP headers from incoming messages
'''
def __init__(self, http_uri, http_port, on_disconnect):
self.http_protocol, self.http_host, self.http_path = urisplit(http_uri)
if self.http_protocol is None:
self.http_protocol = 'http'
if self.http_path == '':
http_path = '/'
self.http_port = http_port
NonBlockingTcp.__init__(self, on_disconnect)
def send(self, raw_data, now=False):
NonBlockingTcp.send(
self,
self.build_http_message(raw_data),
now)
def _on_receive(self,data):
'''Preceeds passing received data to Client class. Gets rid of HTTP headers
and checks them.'''
statusline, headers, httpbody = self.parse_http_message(data)
if statusline[1] != '200':
log.error('HTTP Error: %s %s' % (statusline[1], statusline[2]))
self.disconnect()
return
self.on_receive(httpbody)
def build_http_message(self, httpbody):
'''
Builds http message with given body.
Values for headers and status line fields are taken from class variables.
)
'''
headers = ['POST %s HTTP/1.1' % self.http_path,
'Host: %s:%s' % (self.http_host, self.http_port),
'Content-Type: text/xml; charset=utf-8',
'Content-Length: %s' % len(str(httpbody)),
'\r\n']
headers = '\r\n'.join(headers)
return('%s%s\r\n' % (headers, httpbody))
def parse_http_message(self, message):
'''
splits http message to tuple (
statusline - list of e.g. ['HTTP/1.1', '200', 'OK'],
headers - dictionary of headers e.g. {'Content-Length': '604',
'Content-Type': 'text/xml; charset=utf-8'},
httpbody - string with http body
)
'''
message = message.replace('\r','')
(header, httpbody) = message.split('\n\n')
header = header.split('\n')
statusline = header[0].split(' ')
header = header[1:]
headers = {}
for dummy in header:
row = dummy.split(' ',1)
headers[row[0][:-1]] = row[1]
return (statusline, headers, httpbody)
@ -460,7 +535,7 @@ class NBHTTPProxySocket(NBProxySocket):
''' Starts connection. Connects to proxy, supplies login and password to it ''' Starts connection. Connects to proxy, supplies login and password to it
(if were specified while creating instance). Instructs proxy to make (if were specified while creating instance). Instructs proxy to make
connection to the target server. Returns non-empty sting on success. ''' connection to the target server. Returns non-empty sting on success. '''
log.debug('Proxy server contacted, performing authentification') log.info('Proxy server contacted, performing authentification')
connector = ['CONNECT %s:%s HTTP/1.0' % self.xmpp_server, connector = ['CONNECT %s:%s HTTP/1.0' % self.xmpp_server,
'Proxy-Connection: Keep-Alive', 'Proxy-Connection: Keep-Alive',
'Pragma: no-cache', 'Pragma: no-cache',
@ -504,7 +579,7 @@ class NBHTTPProxySocket(NBProxySocket):
self.reply += reply.replace('\r', '') self.reply += reply.replace('\r', '')
self._on_connect_failure('Proxy authentification failed') self._on_connect_failure('Proxy authentification failed')
return return
log.debug('Authentification successfull. Jabber server contacted.') log.info('Authentification successfull. Jabber server contacted.')
self._on_connect(self) self._on_connect(self)
@ -517,7 +592,7 @@ class NBSOCKS5ProxySocket(NBProxySocket):
# _on_connect_failure, at the end call _on_connect() # _on_connect_failure, at the end call _on_connect()
def _on_tcp_connect(self): def _on_tcp_connect(self):
self.DEBUG('Proxy server contacted, performing authentification', 'start') log.info('Proxy server contacted, performing authentification')
if self.proxy.has_key('user') and self.proxy.has_key('password'): if self.proxy.has_key('user') and self.proxy.has_key('password'):
to_send = '\x05\x02\x00\x02' to_send = '\x05\x02\x00\x02'
else: else:
@ -532,7 +607,7 @@ class NBSOCKS5ProxySocket(NBProxySocket):
self.on_proxy_failure('Invalid proxy reply') self.on_proxy_failure('Invalid proxy reply')
return return
if reply[0] != '\x05': if reply[0] != '\x05':
self.DEBUG('Invalid proxy reply', 'error') log.info('Invalid proxy reply')
self._owner.disconnected() self._owner.disconnected()
self.on_proxy_failure('Invalid proxy reply') self.on_proxy_failure('Invalid proxy reply')
return return
@ -648,67 +723,3 @@ class NBSOCKS5ProxySocket(NBProxySocket):
class NonBlockingHttpBOSH(NonBlockingTcp):
'''
Socket wrapper that makes HTTP message out of send data and peels-off
HTTP headers from incoming messages
'''
def __init__(self, bosh_uri, bosh_port, on_disconnect):
self.bosh_protocol, self.bosh_host, self.bosh_path = self.urisplit(bosh_uri)
if self.bosh_protocol is None:
self.bosh_protocol = 'http'
if self.bosh_path == '':
bosh_path = '/'
self.bosh_port = bosh_port
def send(self, raw_data, now=False):
NonBlockingTcp.send(
self,
self.build_http_message(raw_data),
now)
def _on_receive(self,data):
'''Preceeds passing received data to Client class. Gets rid of HTTP headers
and checks them.'''
statusline, headers, httpbody = self.parse_http_message(data)
if statusline[1] != '200':
log.error('HTTP Error: %s %s' % (statusline[1], statusline[2]))
self.disconnect()
self.on_receive(httpbody)
def build_http_message(self, httpbody):
'''
Builds bosh http message with given body.
Values for headers and status line fields are taken from class variables.
)
'''
headers = ['POST %s HTTP/1.1' % self.bosh_path,
'Host: %s:%s' % (self.bosh_host, self.bosh_port),
'Content-Type: text/xml; charset=utf-8',
'Content-Length: %s' % len(str(httpbody)),
'\r\n']
headers = '\r\n'.join(headers)
return('%s%s\r\n' % (headers, httpbody))
def parse_http_message(self, message):
'''
splits http message to tuple (
statusline - list of e.g. ['HTTP/1.1', '200', 'OK'],
headers - dictionary of headers e.g. {'Content-Length': '604',
'Content-Type': 'text/xml; charset=utf-8'},
httpbody - string with http body
)
'''
message = message.replace('\r','')
(header, httpbody) = message.split('\n\n')
header = header.split('\n')
statusline = header[0].split(' ')
header = header[1:]
headers = {}
for dummy in header:
row = dummy.split(' ',1)
headers[row[0][:-1]] = row[1]
return (statusline, headers, httpbody)

View File

@ -50,7 +50,7 @@ import logging
consoleloghandler = logging.StreamHandler() consoleloghandler = logging.StreamHandler()
consoleloghandler.setLevel(1) consoleloghandler.setLevel(1)
consoleloghandler.setFormatter( consoleloghandler.setFormatter(
logging.Formatter('%(asctime)s %(name)s: %(levelname)s: %(message)s')) logging.Formatter('%(name)s: %(levelname)s: %(message)s'))
log = logging.getLogger('gajim') log = logging.getLogger('gajim')
log.setLevel(logging.WARNING) log.setLevel(logging.WARNING)
log.addHandler(consoleloghandler) log.addHandler(consoleloghandler)