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:
parent
937bb01a69
commit
952e4a1569
|
@ -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,
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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 ''
|
||||
|
|
|
@ -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()
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue