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):
'''Called when we are disconnected'''
log.error('disconnectedReconnCB')
log.info('disconnectedReconnCB called')
if gajim.account_is_connected(self.name):
# we cannot change our status to offline or connecting
# after we auth to server
@ -531,23 +531,17 @@ class Connection(ConnectionHandlers):
secur = None
if self._proxy and self._proxy['type'] == 'bosh':
clientClass = common.xmpp.BOSHClient
clientClass = common.xmpp.bosh.BOSHClient
else:
clientClass = common.xmpp.NonBlockingClient
if gajim.verbose:
con = common.xmpp.NonBlockingClient(
hostname=self._current_host['host'],
port=port,
caller=self,
idlequeue=gajim.idlequeue)
else:
con = common.xmpp.NonBlockingClient(
hostname=self._current_host['host'],
debug=[],
port=port,
caller=self,
idlequeue=gajim.idlequeue)
# there was:
# "if gajim.verbose:"
# here
con = clientClass(
domain=self._hostname,
caller=self,
idlequeue=gajim.idlequeue)
self.last_connection = con
# increase default timeout for server responses
@ -555,10 +549,19 @@ class Connection(ConnectionHandlers):
# FIXME: this is a hack; need a better way
if self.on_connect_success == 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,
self._current_host['host'], port)
con.connect(
hostname=self._current_host['host'],
port=port,
on_connect=self.on_connect_success,
on_proxy_failure=self.on_proxy_failure,
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 import *
from protocol import *

View File

@ -22,6 +22,10 @@ from protocol import *
from client import PlugIn
import sha,base64,random,dispatcher_nb
import logging
log = logging.getLogger('gajim.c.x.auth_nb')
import md5
def HH(some): return md5.new(some).hexdigest()
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. '''
if not feats.getTag('mechanisms', namespace=NS_SASL):
self.startsasl='not-supported'
self.DEBUG('SASL not supported by server', 'error')
log.error('SASL not supported by server')
return
mecs=[]
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','')])
else:
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
self.startsasl='in-process'
self._owner.send(node.__str__())
@ -161,13 +165,13 @@ class SASL(PlugIn):
reason = challenge.getChildren()[0]
except:
reason = challenge
self.DEBUG('Failed SASL authentification: %s' % reason, 'error')
log.error('Failed SASL authentification: %s' % reason)
if self.on_sasl :
self.on_sasl ()
raise NodeProcessed
elif challenge.getName() == 'success':
self.startsasl='success'
self.DEBUG('Successfully authenticated with remote server.', 'ok')
log.info('Successfully authenticated with remote server.')
handlers=self._owner.Dispatcher.dumpHandlers()
print '6' * 79
print handlers
@ -182,7 +186,7 @@ class SASL(PlugIn):
########################################3333
incoming_data = challenge.getData()
data=base64.decodestring(incoming_data)
self.DEBUG('Got challenge:'+data,'ok')
log.info('Got challenge:'+data)
chal = challenge_splitter(data)
if not self.realm and chal.has_key('realm'):
self.realm = chal['realm']
@ -224,7 +228,7 @@ class SASL(PlugIn):
self._owner.send(Node('response', attrs={'xmlns':NS_SASL}).__str__())
else:
self.startsasl='failure'
self.DEBUG('Failed SASL authentification: unknown challenge', 'error')
log.error('Failed SASL authentification: unknown challenge')
if self.on_sasl :
self.on_sasl ()
raise NodeProcessed
@ -236,7 +240,6 @@ class NonBlockingNonSASL(PlugIn):
def __init__(self, user, password, resource, on_auth):
''' Caches username, password and resource for auth. '''
PlugIn.__init__(self)
self.DBG_LINE ='gen_auth'
self.user = user
self.password= password
self.resource = resource
@ -248,7 +251,7 @@ class NonBlockingNonSASL(PlugIn):
Returns used method name on success. Used internally. '''
if not self.resource:
return self.authComponent(owner)
self.DEBUG('Querying server about possible auth methods', 'start')
log.info('Querying server about possible auth methods')
self.owner = owner
resp = owner.Dispatcher.SendAndWaitForResponse(
@ -257,7 +260,7 @@ class NonBlockingNonSASL(PlugIn):
def _on_username(self, 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)
iq=Iq(typ='set',node=resp)
query=iq.getTag('query')
@ -265,7 +268,7 @@ class NonBlockingNonSASL(PlugIn):
query.setTagData('resource',self.resource)
if query.getTag('digest'):
self.DEBUG("Performing digest authentication",'ok')
log.info("Performing digest authentication")
query.setTagData('digest',
sha.new(self.owner.Dispatcher.Stream._document_attrs['id']+self.password).hexdigest())
if query.getTag('password'):
@ -274,26 +277,26 @@ class NonBlockingNonSASL(PlugIn):
elif query.getTag('token'):
token=query.getTagData('token')
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()
for foo in xrange(int(seq)):
hash = sha.new(hash).hexdigest()
query.setTagData('hash',hash)
self._method='0k'
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)
self._method='plain'
resp=self.owner.Dispatcher.SendAndWaitForResponse(iq, func=self._on_auth)
def _on_auth(self, 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.Resource=self.resource
self.owner._registered_name=self.owner.User+'@'+self.owner.Server+'/'+self.owner.Resource
return self.on_auth(self._method)
self.DEBUG('Authentication failed!','error')
log.error('Authentication failed!')
return self.on_auth(None)
def authComponent(self,owner):
@ -309,7 +312,7 @@ class NonBlockingNonSASL(PlugIn):
if data:
self.Dispatcher.ProcessNonBlocking(data)
if not self.handshake:
self.DEBUG('waiting on handshake', 'notify')
log.info('waiting on handshake')
return
self._owner.onreceive(None)
owner._registered_name=self.user
@ -329,14 +332,13 @@ class NonBlockingBind(PlugIn):
def __init__(self):
PlugIn.__init__(self)
self.DBG_LINE='bind'
self.bound=None
def FeaturesHandler(self,conn,feats):
""" Determine if server supports resource binding and set some internal attributes accordingly. """
if not feats.getTag('bind',namespace=NS_BIND):
self.bound='failure'
self.DEBUG('Server does not requested binding.','error')
log.error('Server does not requested binding.')
return
if feats.getTag('session',namespace=NS_SESSION): self.session=1
else: self.session=-1
@ -372,36 +374,36 @@ class NonBlockingBind(PlugIn):
def _on_bound(self, resp):
if isResultNode(resp):
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'))
self._owner.User=jid.getNode()
self._owner.Resource=jid.getResource()
self._owner.SendAndWaitForResponse(Protocol('iq', typ='set',
payload=[Node('session', attrs={'xmlns':NS_SESSION})]), func=self._on_session)
elif resp:
self.DEBUG('Binding failed: %s.' % resp.getTag('error'),'error')
log.error('Binding failed: %s.' % resp.getTag('error'))
self.on_bound(None)
else:
self.DEBUG('Binding failed: timeout expired.', 'error')
log.error('Binding failed: timeout expired.')
self.on_bound(None)
def _on_session(self, resp):
self._owner.onreceive(None)
if isResultNode(resp):
self.DEBUG('Successfully opened session.', 'ok')
log.info('Successfully opened session.')
self.session = 1
self.on_bound('ok')
else:
self.DEBUG('Session open failed.', 'error')
log.error('Session open failed.')
self.session = 0
self.on_bound(None)
self._owner.onreceive(None)
if isResultNode(resp):
self.DEBUG('Successfully opened session.', 'ok')
log.info('Successfully opened session.')
self.session = 1
self.on_bound('ok')
else:
self.DEBUG('Session open failed.', 'error')
log.error('Session open failed.')
self.session = 0
self.on_bound(None)
@ -411,7 +413,6 @@ class NBComponentBind(PlugIn):
'''
def __init__(self):
PlugIn.__init__(self)
self.DBG_LINE='bind'
self.bound=None
self.needsUnregister=None
@ -448,13 +449,13 @@ class NBComponentBind(PlugIn):
def _on_bind_reponse(self, res):
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:
self.DEBUG('Successfully bound.', 'ok')
log.info('Successfully bound.')
if self.on_bind:
self.on_bind('ok')
else:
self.DEBUG('Binding failed: timeout expired.', 'error')
log.error('Binding failed: timeout expired.')
if self.on_bind:
self.on_bind(None)
@ -462,7 +463,7 @@ class NBComponentBind(PlugIn):
""" Determine if server supports resource binding and set some internal attributes accordingly. """
if not feats.getTag('bind',namespace=NS_BIND):
self.bound='failure'
self.DEBUG('Server does not requested binding.','error')
log.error('Server does not requested binding.')
return
if feats.getTag('session',namespace=NS_SESSION): 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
resp=self._owner.SendAndWaitForResponse(Protocol('bind',attrs={'name':domain},xmlns=NS_COMPONENT_1))
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:
self.DEBUG('Successfully bound.','ok')
log.info('Successfully bound.')
return 'ok'
else:
self.DEBUG('Binding failed: timeout expired.','error')
log.error('Binding failed: timeout expired.')
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.
"""
import socket
import debug
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'
import logging
log = logging.getLogger('gajim.c.x.plugin')
class PlugIn:
""" Common xmpppy plugins infrastructure: plugging in/out, debugging. """
def __init__(self):
self._exported_methods=[]
self.DBG_LINE=self.__class__.__name__.lower()
def PlugIn(self,owner):
""" Attach to main instance and register ourself and all our staff in it. """
self._owner=owner
if self.DBG_LINE not in owner.debug_flags:
owner.debug_flags.append(self.DBG_LINE)
self.DEBUG('Plugging %s into %s'%(self,self._owner),'start')
log.debug('Plugging %s into %s'%(self,self._owner))
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=[]
for method in self._exported_methods:
if owner.__dict__.has_key(method.__name__):
@ -76,15 +48,10 @@ class PlugIn:
def PlugOut(self):
""" Unregister all our staff from main instance and detach from it. """
self.DEBUG('Plugging %s out of %s.'%(self,self._owner),'stop')
self._owner.debug_flags.remove(self.DBG_LINE)
log.debug('Plugging %s out of %s.'%(self,self._owner))
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
del self._owner.__dict__[self.__class__.__name__]
if self.__class__.__dict__.has_key('plugout'): return self.plugout()
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 debug
import random
import transports_nb, tls_nb, dispatcher_nb, auth_nb, roster_nb, protocol
from client import *
@ -31,54 +29,29 @@ from client import *
import logging
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:
''' 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:
:param hostname: hostname of machine where the XMPP server is running (from Account
of from SRV request) and port to connect to.
:param domain: domain - for to: attribute (from account info)
:param idlequeue: processing idlequeue
: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?)
'''
self.DBG = DBG_CLIENT
self.Namespace = protocol.NS_CLIENT
self.idlequeue = idlequeue
self.defaultNamespace = self.Namespace
self.disconnect_handlers = []
# XMPP server and port from account or SRV
self.Server = hostname
self.Port = port
self.Server = domain
# caller is who initiated this client, it is sed to register the EventDispatcher
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._registered_name = None
self.connected = ''
@ -98,9 +71,9 @@ class NBCommonClient:
'''
self.connected=''
self.DEBUG(self.DBG,'Disconnect detected','stop')
log.debug('Client disconnected..')
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()
if self.__dict__.has_key('NonBlockingRoster'):
self.NonBlockingRoster.PlugOut()
@ -120,23 +93,22 @@ class NBCommonClient:
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
sends it via socket wrapper'''
(id, stanza_to_send) = self.Dispatcher.assign_id(stanza)
if is_message:
# somehow zeroconf-specific
self.Connection.send(stanza_to_send, True, now = now)
else:
self.Connection.send(stanza_to_send, now = now)
self.Connection.send(stanza_to_send, now = now)
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).
: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_failure: called when error occures during connection
: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
:param secure:
'''
self.Port = port
if hostname:
xmpp_hostname = hostname
else:
xmpp_hostname = self.Server
self.on_connect = on_connect
self.on_connect_failure=on_connect_failure
self.on_proxy_failure = on_proxy_failure
@ -155,8 +132,8 @@ class NBCommonClient:
if proxy:
# with proxies, client connects to proxy instead of directly to
# XMPP server from __init__.
# tcp_server is hostname used for socket connecting
# XMPP server ((hostname, port))
# tcp_server is machine used for socket connection
tcp_server=proxy['host']
tcp_port=proxy['port']
self._on_tcp_failure = self.on_proxy_failure
@ -168,30 +145,33 @@ class NBCommonClient:
type_ = proxy['type']
if type_ == 'socks5':
# SOCKS5 proxy
self.socket = transports_nb.NBSOCKS5ProxySocket(
on_disconnect=self.on_disconnect,
proxy_creds=proxy_creds,
xmpp_server=(self.Server, self.Port))
xmpp_server=(xmpp_hostname, self.Port))
elif type_ == 'http':
# HTTP CONNECT to proxy
self.socket = transports_nb.NBHTTPProxySocket(
on_disconnect=self.on_disconnect,
proxy_creds=proxy_creds,
xmpp_server=(self.Server, self.Port))
xmpp_server=(xmpp_hostname, self.Port))
elif type_ == 'bosh':
# BOSH - XMPP over HTTP
tcp_server = transports_nb.urisplit(tcp_server)[1]
self.socket = transports_nb.NonBlockingHttpBOSH(
self.socket = transports_nb.NonBlockingHTTP(
on_disconnect=self.on_disconnect,
bosh_uri = proxy['host'],
bosh_port = tcp_port)
http_uri = proxy['host'],
http_port = tcp_port)
else:
# HTTP CONNECT to proxy from environment variables
self.socket = transports_nb.NBHTTPProxySocket(
on_disconnect=self.on_disconnect,
proxy_creds=(None, None),
xmpp_server=(self.Server, self.Port))
xmpp_server=(xmpp_hostname, self.Port))
else:
self._on_tcp_failure = self._on_connect_failure
tcp_server=self.Server
tcp_server=xmpp_hostname
tcp_port=self.Port
self.socket = transports_nb.NonBlockingTcp(on_disconnect = self.on_disconnect)
@ -221,7 +201,7 @@ class NBCommonClient:
def _try_next_ip(self, err_message=None):
'''iterates over IP addresses from getaddinfo'''
if err_message:
self.DEBUG(self.DBG,err_message,'connect')
log.debug('While looping over DNS A records: %s' % connect)
if self.ip_addresses == []:
self._on_tcp_failure(err_message='Run out of hosts for name %s:%s' %
(self.Server, self.Port))
@ -305,7 +285,7 @@ class NBCommonClient:
def _on_connect_failure(self, retry=None, err_message=None):
self.connected = None
if err_message:
self.DEBUG(self.DBG, err_message, 'connecting')
log.debug('While connecting: %s' % err_message)
if self.socket:
self.socket.disconnect()
self.on_connect_failure(retry)
@ -460,83 +440,3 @@ class NonBlockingClient(NBCommonClient):
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 client import PlugIn
import logging
log = logging.getLogger('gajim.c.x.dispatcher_nb')
# default timeout to wait for response for our id
DEFAULT_TIMEOUT_SECONDS = 25
ID = 0
STREAM_TERMINATOR = '</stream:stream>'
XML_DECLARATION = '<?xml version=\'1.0\'?>'
class Dispatcher(PlugIn):
''' 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.). '''
def __init__(self):
PlugIn.__init__(self)
DBG_LINE='dispatcher'
self.handlers={}
self._expected={}
self._defaultHandler=None
@ -79,7 +84,7 @@ class Dispatcher(PlugIn):
def plugin(self, owner):
''' 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._owner.lastErrNode = None
@ -93,7 +98,6 @@ class Dispatcher(PlugIn):
def plugout(self):
''' Prepares instance to be destructed. '''
self.Stream.dispatch = None
self.Stream.DEBUG = None
self.Stream.features = None
self.Stream.destroy()
self._owner = None
@ -105,8 +109,6 @@ class Dispatcher(PlugIn):
self.Stream._dispatch_depth = 2
self.Stream.dispatch = self.dispatch
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._metastream = Node('stream:stream')
self._metastream.setNamespace(self._owner.Namespace)
@ -116,11 +118,11 @@ class Dispatcher(PlugIn):
if locale.getdefaultlocale()[0]:
self._metastream.setAttr('xml:lang',
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):
''' Send a stream terminator. '''
self._owner.send('</stream:stream>')
self._owner.send(STREAM_TERMINATOR)
def _check_stream_start(self, ns, tag, attrs):
if ns<>NS_STREAMS or tag<>'stream':
@ -144,7 +146,7 @@ class Dispatcher(PlugIn):
self._owner.Connection.disconnect()
return 0
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()
return 0
if len(self._pendingExceptions) > 0:
@ -157,7 +159,7 @@ class Dispatcher(PlugIn):
''' Creates internal structures for newly registered namespace.
You can register handlers for this namespace afterwards. By default one namespace
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.RegisterProtocol('unknown', Protocol, xmlns=xmlns)
self.RegisterProtocol('default', Protocol, xmlns=xmlns)
@ -167,8 +169,7 @@ class Dispatcher(PlugIn):
Needed to start registering handlers for such stanzas.
Iq, message and presence protocols are registered by default. '''
if not xmlns: xmlns=self._owner.defaultNamespace
self.DEBUG('Registering protocol "%s" as %s(%s)' %
(tag_name, Proto, xmlns), order)
log.info('Registering protocol "%s" as %s(%s)' %(tag_name, Proto, xmlns))
self.handlers[xmlns][tag_name]={type:Proto, 'default':[]}
def RegisterNamespaceHandler(self, xmlns, handler, typ='', ns='', makefirst=0, system=0):
@ -195,8 +196,8 @@ class Dispatcher(PlugIn):
'''
if not xmlns:
xmlns=self._owner.defaultNamespace
self.DEBUG('Registering handler %s for "%s" type->%s ns->%s(%s)' %
(handler, name, typ, ns, xmlns), 'info')
log.info('Registering handler %s for "%s" type->%s ns->%s(%s)' %
(handler, name, typ, ns, xmlns))
if not typ and not ns:
typ='default'
if not self.handlers.has_key(xmlns):
@ -313,13 +314,13 @@ class Dispatcher(PlugIn):
xmlns=stanza.getNamespace()
if not self.handlers.has_key(xmlns):
self.DEBUG("Unknown namespace: " + xmlns, 'warn')
log.warn("Unknown namespace: " + xmlns)
xmlns='unknown'
if not self.handlers[xmlns].has_key(name):
self.DEBUG("Unknown stanza: " + name, 'warn')
log.warn("Unknown stanza: " + name)
name='unknown'
else:
self.DEBUG("Got %s/%s stanza" % (xmlns, name), 'ok')
log.debug("Got %s/%s stanza" % (xmlns, name))
if stanza.__class__.__name__=='Node':
stanza=self.handlers[xmlns][name][type](node=stanza)
@ -329,7 +330,7 @@ class Dispatcher(PlugIn):
stanza.props=stanza.getProperties()
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:
if self.handlers[xmlns][name].has_key(typ): list.append(typ) # from very common...
for prop in stanza.props:
@ -345,13 +346,13 @@ class Dispatcher(PlugIn):
user=0
if type(session._expected[ID]) == type(()):
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:
cb(session,stanza,**args)
except Exception, typ:
if typ.__class__.__name__ <>'NodeProcessed': raise
else:
session.DEBUG("Expected stanza arrived!",'ok')
log.debug("Expected stanza arrived!")
session._expected[ID]=stanza
else:
user=1

View File

@ -13,6 +13,8 @@
## GNU General Public License for more details.
import select
import logging
log = logging.getLogger('gajim.c.x.idlequeue')
class IdleObject:
''' 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()
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):
del(self.read_timeouts[fd])
@ -69,7 +71,7 @@ class IdleQueue:
def set_read_timeout(self, fd, seconds):
''' set a new timeout, if it is not removed after 'seconds',
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
self.read_timeouts[fd] = timeout
@ -79,6 +81,7 @@ class IdleQueue:
if timeout > current_time:
continue
if self.queue.has_key(fd):
log.debug('Calling read_timeout for fd %s' % fd)
self.queue[fd].read_timeout()
else:
self.remove_timeout(fd)

View File

@ -24,6 +24,10 @@ mass-renaming of contacts.
from protocol import *
from client import PlugIn
import logging
log = logging.getLogger('gajim.c.x.roster_nb')
class NonBlockingRoster(PlugIn):
""" Defines a plenty of methods that will allow you to manage roster.
Also automatically track presences from remote JIDs taking into
@ -35,7 +39,6 @@ class NonBlockingRoster(PlugIn):
def __init__(self):
""" Init internal variables. """
PlugIn.__init__(self)
self.DBG_LINE='roster'
self._data = {}
self.set=None
self._exported_methods=[self.getRoster]
@ -46,7 +49,7 @@ class NonBlockingRoster(PlugIn):
if self.set is None: self.set=0
elif not force: return
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):
""" Subscription tracker. Used internally for setting items state in
@ -60,7 +63,7 @@ class NonBlockingRoster(PlugIn):
if item.getAttr('subscription')=='remove':
if self._data.has_key(jid): del self._data[jid]
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]={}
self._data[jid]['name']=item.getAttr('name')
self._data[jid]['ask']=item.getAttr('ask')
@ -86,7 +89,7 @@ class NonBlockingRoster(PlugIn):
typ=pres.getType()
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}
if pres.getTag('show'): res['show']=pres.getShow()
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."""
import xml.parsers.expat
import logging
log = logging.getLogger('gajim.c.x.simplexml')
def XMLescape(txt):
"""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)
else: return self.node.addChild(attr,payload=[val])
DBG_NODEBUILDER = 'nodebuilder'
class NodeBuilder:
""" 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.
@ -293,7 +295,7 @@ class NodeBuilder:
You can think about it as of "node upgrade".
"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.StartElementHandler = self.starttag
self._parser.EndElementHandler = self.endtag
@ -341,7 +343,7 @@ class NodeBuilder:
attrs[self.namespaces[ns]+attr[sp+1:]]=attrs[attr]
del attrs[attr] #
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 not self._mini_dom :
self._mini_dom = Node(tag=tag, attrs=attrs)
@ -360,14 +362,14 @@ class NodeBuilder:
self.last_is_data = 0
def endtag(self, tag ):
"""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()
if self.__depth == self._dispatch_depth:
self.dispatch(self._mini_dom)
elif self.__depth > self._dispatch_depth:
self._ptr = self._ptr.parent
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.last_is_data = 0
if self.__depth == 0: self.stream_footer_received()
@ -385,8 +387,7 @@ class NodeBuilder:
self.check_data_buffer()
if prefix: self.namespaces[uri]=prefix+':'
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):
""" Returns just built Node. """
self.check_data_buffer()

View File

@ -26,16 +26,8 @@ import time
import traceback
import logging
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
# %s/common\.gajim\.DATA_DIR/\'\.\.\/data\'/c
# %s/common\.gajim\.MY_CACERTS/\'\%s\/\.gajim\/cacerts\.pem\' \% os\.environ\[\'HOME\'\]/c
@ -49,6 +41,11 @@ log.propagate = False
USE_PYOPENSSL = False
#TODO: add callback set from PlugIn for errors during runtime
# - sth like on_disconnect in socket wrappers
try:
#raise ImportError("Manually disabled PyOpenSSL")
import OpenSSL.SSL
@ -164,8 +161,8 @@ class PyOpenSSLWrapper(SSLWrapper):
if flags is None: retval = self.sslobj.recv(bufsize)
else: retval = self.sslobj.recv(bufsize, flags)
except (OpenSSL.SSL.WantReadError, OpenSSL.SSL.WantWriteError), e:
log.debug("Recv: Want-error: " + repr(e))
pass
# log.debug("Recv: " + repr(e))
except OpenSSL.SSL.SysCallError, e:
log.debug("Recv: Got OpenSSL.SSL.SysCallError: " + repr(e), exc_info=True)
#traceback.print_exc()
@ -253,7 +250,6 @@ class NonBlockingTLS(PlugIn):
if owner.__dict__.has_key('NonBlockingTLS'):
return # Already enabled.
PlugIn.PlugIn(self, owner)
DBG_LINE='NonBlockingTLS'
self.on_tls_success = on_tls_success
self.on_tls_faliure = on_tls_failure
if now:
@ -288,10 +284,10 @@ class NonBlockingTLS(PlugIn):
''' Used to analyse server <features/> tag for TLS support.
If TLS is supported starts the encryption negotiation. Used internally '''
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.")
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('failure', self.StartTLSHandler, xmlns=NS_TLS)
self._owner.send('<starttls xmlns="%s"/>' % NS_TLS)
@ -425,7 +421,7 @@ class NonBlockingTLS(PlugIn):
if self.starttls == 'failure':
self.on_tls_failure('TLS <failure> received: %s' % self.starttls)
return
self.DEBUG('Got starttls proceed response. Switching to TLS/SSL...','ok')
log.debug('Got starttls proceed response. Switching to TLS/SSL...')
try:
self._startSSL()
except Exception, e:

View File

@ -30,17 +30,9 @@ import traceback
import logging
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).
e.g. urisplit('http://httpcm.jabber.org/webclient') returns
@ -72,6 +64,23 @@ CONNECTING ='CONNECTING'
CONNECTED ='CONNECTED'
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):
'''
Non-blocking TCP socket wrapper
@ -114,7 +123,6 @@ class NonBlockingTcp(PlugIn, IdleObject):
self.set_timeout, self.remove_timeout]
def plugin(self, owner):
print 'plugin called'
owner.Connection=self
self.idlequeue = owner.idlequeue
@ -142,7 +150,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
self.on_connect = on_connect
self.on_connect_failure = on_connect_failure
(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:
self._sock = socket.socket(*conn_5tuple[:3])
except socket.error, (errnum, errstr):
@ -170,14 +178,14 @@ class NonBlockingTcp(PlugIn, IdleObject):
if errnum in (errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK):
# connecting in progress
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
return
elif errnum in (0, 10056, errno.EISCONN):
# already connected - this branch is very unlikely, nonblocking connect() will
# return EINPROGRESS exception in most cases. When here, we don't need timeout
# 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)
return
@ -212,12 +220,12 @@ class NonBlockingTcp(PlugIn, IdleObject):
def pollin(self):
'''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()
def pollout(self):
'''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:
self._on_connect(self)
@ -225,7 +233,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
self._do_send()
def pollend(self):
log.debug('pollend called, state == %s' % self.state)
log.info('pollend called, state == %s' % self.state)
if self.state==CONNECTING:
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.
'''
log.debug('read_timeout called, state == %s' % self.state)
log.warn('read_timeout called, state == %s' % self.state)
if self.state==CONNECTING:
# if read_timeout is called during connecting, connect() didn't end yet
# thus we have to call the tcp failure callback
@ -309,17 +317,18 @@ class NonBlockingTcp(PlugIn, IdleObject):
def _plug_idle(self):
# readable if socket is connected or disconnecting
readable = self.state != DISCONNECTED
fd = self.get_fd()
# writeable if sth to send
if self.sendqueue or self.sendbuff:
writable = True
else:
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:
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)
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):
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'):
self._owner.Dispatcher.Event('', event_type, data)
@ -356,7 +365,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
else:
self.on_receive = None
return
log.debug('setting onreceive on %s' % recv_handler)
log.info('setting onreceive on %s' % recv_handler)
self.on_receive = recv_handler
@ -372,7 +381,7 @@ class NonBlockingTcp(PlugIn, IdleObject):
received = self._recv(RECV_BUFSIZE)
except (socket.error, socket.herror, socket.gaierror), (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 == '':
errnum = ERR_DISCONN
@ -412,10 +421,76 @@ class NonBlockingTcp(PlugIn, IdleObject):
def _on_receive(self, data):
# Overriding this method allows modifying received data before it is passed
# 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)
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
(if were specified while creating instance). Instructs proxy to make
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,
'Proxy-Connection: Keep-Alive',
'Pragma: no-cache',
@ -504,7 +579,7 @@ class NBHTTPProxySocket(NBProxySocket):
self.reply += reply.replace('\r', '')
self._on_connect_failure('Proxy authentification failed')
return
log.debug('Authentification successfull. Jabber server contacted.')
log.info('Authentification successfull. Jabber server contacted.')
self._on_connect(self)
@ -517,7 +592,7 @@ class NBSOCKS5ProxySocket(NBProxySocket):
# _on_connect_failure, at the end call _on_connect()
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'):
to_send = '\x05\x02\x00\x02'
else:
@ -532,7 +607,7 @@ class NBSOCKS5ProxySocket(NBProxySocket):
self.on_proxy_failure('Invalid proxy reply')
return
if reply[0] != '\x05':
self.DEBUG('Invalid proxy reply', 'error')
log.info('Invalid proxy reply')
self._owner.disconnected()
self.on_proxy_failure('Invalid proxy reply')
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.setLevel(1)
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.setLevel(logging.WARNING)
log.addHandler(consoleloghandler)