upstream updates

This commit is contained in:
Norman Rasmussen 2006-01-18 20:46:29 +00:00
parent 5367d4a4fb
commit 65f67a7a04
9 changed files with 239 additions and 82 deletions

View File

@ -26,6 +26,6 @@ and use only methods for access all values you should not have any problems.
""" """
import simplexml,protocol,debug,auth,transports,roster,dispatcher,features,browser,filetransfer import simplexml,protocol,debug,auth,transports,roster,dispatcher,features,browser,filetransfer,commands
from client import * from client import *
from protocol import * from protocol import *

View File

@ -12,7 +12,7 @@
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details. ## GNU General Public License for more details.
# $Id: auth.py,v 1.33 2005/11/30 17:05:40 normanr Exp $ # $Id: auth.py,v 1.35 2006/01/18 19:26:43 normanr Exp $
""" """
Provides library with all Non-SASL and SASL authentication mechanisms. Provides library with all Non-SASL and SASL authentication mechanisms.
@ -259,3 +259,48 @@ class Bind(PlugIn):
else: else:
self.DEBUG('Binding failed: timeout expired.','error') self.DEBUG('Binding failed: timeout expired.','error')
return '' return ''
class ComponentBind(PlugIn):
""" ComponentBind some JID to the current connection to allow router know of our location."""
def __init__(self):
PlugIn.__init__(self)
self.DBG_LINE='bind'
self.bound=None
self.needsUnregister=None
def plugin(self,owner):
""" Start resource binding, if allowed at this time. Used internally. """
if self._owner.Dispatcher.Stream.features:
try: self.FeaturesHandler(self._owner.Dispatcher,self._owner.Dispatcher.Stream.features)
except NodeProcessed: pass
else:
self._owner.RegisterHandler('features',self.FeaturesHandler,xmlns=NS_STREAMS)
self.needsUnregister=1
def plugout(self):
""" Remove ComponentBind handler from owner's dispatcher. Used internally. """
if self.needsUnregister:
self._owner.UnregisterHandler('features',self.FeaturesHandler,xmlns=NS_STREAMS)
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')
return
if feats.getTag('session',namespace=NS_SESSION): self.session=1
else: self.session=-1
self.bound=[]
def Bind(self,domain=None):
""" Perform binding. Use provided domain name (if not provided). """
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')
elif resp:
self.DEBUG('Successfully bound.','ok')
return 'ok'
else:
self.DEBUG('Binding failed: timeout expired.','error')
return ''

View File

@ -12,7 +12,7 @@
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details. ## GNU General Public License for more details.
# $Id: client.py,v 1.35 2005/04/30 10:17:19 snakeru Exp $ # $Id: client.py,v 1.52 2006/01/02 19:40:55 normanr Exp $
""" """
Provides PlugIn class functionality to develop extentions for xmpppy. Provides PlugIn class functionality to develop extentions for xmpppy.
@ -31,6 +31,7 @@ Debug.Debug.colors['nodebuilder']=debug.color_brown
Debug.Debug.colors['client']=debug.color_cyan Debug.Debug.colors['client']=debug.color_cyan
Debug.Debug.colors['component']=debug.color_cyan Debug.Debug.colors['component']=debug.color_cyan
Debug.Debug.colors['dispatcher']=debug.color_green Debug.Debug.colors['dispatcher']=debug.color_green
Debug.Debug.colors['browser']=debug.color_blue
Debug.Debug.colors['auth']=debug.color_yellow Debug.Debug.colors['auth']=debug.color_yellow
Debug.Debug.colors['roster']=debug.color_magenta Debug.Debug.colors['roster']=debug.color_magenta
Debug.Debug.colors['ibb']=debug.color_yellow Debug.Debug.colors['ibb']=debug.color_yellow
@ -111,6 +112,7 @@ class CommonClient:
self._registered_name=None self._registered_name=None
self.RegisterDisconnectHandler(self.DisconnectHandler) self.RegisterDisconnectHandler(self.DisconnectHandler)
self.connected='' self.connected=''
self._component=0
def RegisterDisconnectHandler(self,handler): def RegisterDisconnectHandler(self,handler):
""" Register handler that will be called on disconnect.""" """ Register handler that will be called on disconnect."""
@ -147,6 +149,11 @@ class CommonClient:
""" Example of reconnection method. In fact, it can be used to batch connection and auth as well. """ """ Example of reconnection method. In fact, it can be used to batch connection and auth as well. """
handlerssave=self.Dispatcher.dumpHandlers() handlerssave=self.Dispatcher.dumpHandlers()
self.Dispatcher.PlugOut() self.Dispatcher.PlugOut()
if self.__dict__.has_key('NonSASL'): self.NonSASL.PlugOut()
if self.__dict__.has_key('SASL'): self.SASL.PlugOut()
if self.__dict__.has_key('TLS'): self.TLS.PlugOut()
if self.__dict__.has_key('HTTPPROXYsocket'): self.HTTPPROXYsocket.PlugOut()
if self.__dict__.has_key('TCPsocket'): self.TCPsocket.PlugOut()
if not self.connect(server=self._Server,proxy=self._Proxy): return if not self.connect(server=self._Server,proxy=self._Proxy): return
if not self.auth(self._User,self._Password,self._Resource): return if not self.auth(self._User,self._Password,self._Resource): return
self.Dispatcher.restoreHandlers(handlerssave) self.Dispatcher.restoreHandlers(handlerssave)
@ -159,16 +166,20 @@ class CommonClient:
if hasattr(self, 'Connection'): if hasattr(self, 'Connection'):
return self.Connection._sock.getsockname() return self.Connection._sock.getsockname()
def connect(self,server=None,proxy=None, ssl=None): def connect(self,server=None,proxy=None,ssl=None,use_srv=None):
""" Make a tcp/ip connection, protect it with tls/ssl if possible and start XMPP stream. """ """ Make a tcp/ip connection, protect it with tls/ssl if possible and start XMPP stream.
Returns None or 'tcp' or 'tls', depending on the result."""
if not server: server=(self.Server,self.Port) if not server: server=(self.Server,self.Port)
if proxy: connected=transports.HTTPPROXYsocket(proxy,server).PlugIn(self) if proxy: socket=transports.HTTPPROXYsocket(proxy,server,use_srv)
else: connected=transports.TCPsocket(server).PlugIn(self) else: socket=transports.TCPsocket(server,use_srv)
if not connected: return connected=socket.PlugIn(self)
if not connected:
socket.PlugOut()
return
self._Server,self._Proxy=server,proxy self._Server,self._Proxy=server,proxy
self.connected='tcp' self.connected='tcp'
if (ssl is None and self.Connection.getPort() in (5223, 443)) or ssl: if (ssl is None and self.Connection.getPort() in (5223, 443)) or ssl:
try: try: # FIXME. This should be done in transports.py
transports.TLS().PlugIn(self,now=1) transports.TLS().PlugIn(self,now=1)
self.connected='ssl' self.connected='ssl'
except socket.sslerror: except socket.sslerror:
@ -182,16 +193,16 @@ class CommonClient:
class Client(CommonClient): class Client(CommonClient):
""" Example client class, based on CommonClient. """ """ Example client class, based on CommonClient. """
def connect(self,server=None,proxy=None,secure=None): def connect(self,server=None,proxy=None,secure=None,use_srv=True):
""" Connect to jabber server. If you want to specify different ip/port to connect to you can """ Connect to jabber server. If you want to specify different ip/port to connect to you can
pass it as tuple as first parameter. If there is HTTP proxy between you and server - pass it as tuple as first parameter. If there is HTTP proxy between you and server
specify it's address and credentials (if needed) in the second argument specify it's address and credentials (if needed) in the second argument.
If you want ssl/tls support to be discovered and enable automatically - leave third argument as None. (ssl will be autodetected only if port is 5223 or 443) If you want ssl/tls support to be discovered and enable automatically - leave third argument as None. (ssl will be autodetected only if port is 5223 or 443)
If you want to force SSL start (i.e. if port 5223 or 443 is remapped to some non-standard port) then set it to 1 If you want to force SSL start (i.e. if port 5223 or 443 is remapped to some non-standard port) then set it to 1.
If you want to disable tls/ssl support completely, set it to 0 If you want to disable tls/ssl support completely, set it to 0.
Example: connect(('192.168.5.5',5222),{'host':'proxy.my.net','port':8080,'user':'me','password':'secret'}) Example: connect(('192.168.5.5',5222),{'host':'proxy.my.net','port':8080,'user':'me','password':'secret'})
Returns '' (on no connection) or 'tcp' or 'tls', depending on the result.""" Returns '' or 'tcp' or 'tls', depending on the result."""
if not CommonClient.connect(self,server,proxy,secure) or secure<>None and not secure: return self.connected if not CommonClient.connect(self,server,proxy,secure,use_srv) or secure<>None and not secure: return self.connected
transports.TLS().PlugIn(self) transports.TLS().PlugIn(self)
if not self.Dispatcher.Stream._document_attrs.has_key('version') or not self.Dispatcher.Stream._document_attrs['version']=='1.0': return self.connected if not self.Dispatcher.Stream._document_attrs.has_key('version') or not self.Dispatcher.Stream._document_attrs['version']=='1.0': return self.connected
while not self.Dispatcher.Stream.features and self.Process(): pass # If we get version 1.0 stream the features tag MUST BE presented while not self.Dispatcher.Stream.features and self.Process(): pass # If we get version 1.0 stream the features tag MUST BE presented
@ -247,19 +258,31 @@ class Client(CommonClient):
class Component(CommonClient): class Component(CommonClient):
""" Component class. The only difference from CommonClient is ability to perform component authentication. """ """ Component class. The only difference from CommonClient is ability to perform component authentication. """
def __init__(self,server,port=5347,typ=None,debug=['always', 'nodebuilder']): def __init__(self,server,port=5347,typ=None,debug=['always', 'nodebuilder'],domains=None,component=0):
""" Init function for Components. """ Init function for Components.
As components use a different auth mechanism which includes the namespace of the component. As components use a different auth mechanism which includes the namespace of the component.
Jabberd1.4 and Ejabberd use the default namespace then for all client messages. Jabberd1.4 and Ejabberd use the default namespace then for all client messages.
Jabberd2 uses jabber:client.""" Jabberd2 uses jabber:client.
'server' argument is a server name that you are connecting to (f.e. "localhost").
'port' can be specified if 'server' resolves to correct IP. If it is not then you'll need to specify IP
and port while calling "connect()"."""
CommonClient.__init__(self,server,port=port,debug=debug) CommonClient.__init__(self,server,port=port,debug=debug)
self.typ=typ self.typ=typ
self.component=component
if domains:
self.domains=domains
else:
self.domains=[server]
def connect(self,server=None,proxy=None): def connect(self,server=None,proxy=None):
""" This will connect to the server, and if the features tag is found then set """ This will connect to the server, and if the features tag is found then set
the namespace to be jabber:client as that is required for jabberd2""" the namespace to be jabber:client as that is required for jabberd2.
'server' and 'proxy' arguments have the same meaning as in xmpp.Client.connect() """
if self.component:
self.Namespace=auth.NS_COMPONENT_1
self.Server=server[0]
CommonClient.connect(self,server=server,proxy=proxy) CommonClient.connect(self,server=server,proxy=proxy)
if self.typ=='jabberd2' or not self.typ and self.Dispatcher.Stream.features != None: if self.connected and (self.typ=='jabberd2' or not self.typ and self.Dispatcher.Stream.features != None):
self.defaultNamespace=auth.NS_CLIENT self.defaultNamespace=auth.NS_CLIENT
self.Dispatcher.RegisterNamespace(self.defaultNamespace) self.Dispatcher.RegisterNamespace(self.defaultNamespace)
self.Dispatcher.RegisterProtocol('iq',dispatcher.Iq) self.Dispatcher.RegisterProtocol('iq',dispatcher.Iq)
@ -267,7 +290,32 @@ class Component(CommonClient):
self.Dispatcher.RegisterProtocol('presence',dispatcher.Presence) self.Dispatcher.RegisterProtocol('presence',dispatcher.Presence)
return self.connected return self.connected
def auth(self,name,password,dup=None): def auth(self,name,password,dup=None,sasl=0):
""" Authenticate component "name" with password "password".""" """ Authenticate component "name" with password "password"."""
self._User,self._Password,self._Resource=name,password,'' self._User,self._Password,self._Resource=name,password,''
return auth.NonSASL(name,password,'').PlugIn(self) try:
if self.component: sasl=1
if sasl: auth.SASL(name,password).PlugIn(self)
if not sasl or self.SASL.startsasl=='not-supported':
if auth.NonSASL(name,password,'').PlugIn(self):
self.connected+='+old_auth'
return 'old_auth'
return
self.SASL.auth()
while self.SASL.startsasl=='in-process' and self.Process(): pass
if self.SASL.startsasl=='success':
if self.component:
self._component=self.component
for domain in self.domains:
auth.ComponentBind().PlugIn(self)
while self.ComponentBind.bound is None: self.Process()
if (not self.ComponentBind.Bind(domain)):
self.ComponentBind.PlugOut()
return
self.ComponentBind.PlugOut()
self.connected+='+sasl'
return 'sasl'
else:
raise auth.NotAuthorized(self.SASL.startsasl)
except:
self.DEBUG(self.DBG,"Failed to authenticate %s"%name,'error')

View File

@ -1,4 +1,4 @@
## $Id: commands.py,v 1.10 2005/10/07 23:17:09 normanr Exp $ ## $Id: commands.py,v 1.11 2005/11/30 17:03:11 normanr Exp $
## Ad-Hoc Command manager ## Ad-Hoc Command manager
## Mike Albon (c) 5th January 2005 ## Mike Albon (c) 5th January 2005
@ -125,7 +125,7 @@ class Commands(PlugIn):
conn.send(Error(request,ERR_ITEM_NOT_FOUND)) conn.send(Error(request,ERR_ITEM_NOT_FOUND))
raise NodeProcessed raise NodeProcessed
elif typ == 'info': elif typ == 'info':
return {'ids':[],'features':[]} return {'ids':[{'category':'automation','type':'command-list'}],'features':[]}
def addCommand(self,name,cmddisco,cmdexecute,jid=''): def addCommand(self,name,cmddisco,cmdexecute,jid=''):
"""The method to call if adding a new command to the session, the requred parameters of cmddisco and cmdexecute are the methods to enable that command to be executed""" """The method to call if adding a new command to the session, the requred parameters of cmddisco and cmdexecute are the methods to enable that command to be executed"""
@ -197,7 +197,7 @@ class Command_Handler_Prototype(PlugIn):
self.sessioncount = 0 self.sessioncount = 0
self.sessions = {} self.sessions = {}
# Disco information for command list pre-formatted as a tuple # Disco information for command list pre-formatted as a tuple
self.discoinfo = {'ids':[{'category':'automation','type':'command','name':self.description}],'features': self.discofeatures} self.discoinfo = {'ids':[{'category':'automation','type':'command-node','name':self.description}],'features': self.discofeatures}
self._jid = jid self._jid = jid
def plugin(self,owner): def plugin(self,owner):

View File

@ -40,16 +40,16 @@ in this code
import sys import sys
import traceback
import time import time
import os import os
import types import types
if os.environ.has_key('TERM'):
colors_enabled=True
colornames = ['none', 'black', 'red', 'green', 'brown', 'blue', 'magenta', else:
'cyan', 'light_gray', 'dark_gray', 'bright_red', 'bright_green', 'yellow', colors_enabled=False
'bright_blue', 'purple', 'bright_cyan', 'white']
color_none = chr(27) + "[0m" color_none = chr(27) + "[0m"
color_black = chr(27) + "[30m" color_black = chr(27) + "[30m"
@ -69,11 +69,7 @@ color_purple = chr(27) + "[35;1m"
color_bright_cyan = chr(27) + "[36;1m" color_bright_cyan = chr(27) + "[36;1m"
color_white = chr(27) + "[37;1m" color_white = chr(27) + "[37;1m"
if os.name == 'nt':
for colorname in colornames:
name = 'color_' + colorname
mod = compile("%s = ''" % name, 'gajim', 'exec')
eval(mod)
""" """
Define your flags in yor modules like this: Define your flags in yor modules like this:
@ -125,7 +121,7 @@ class Debug:
# #
# active_flags are those that will trigger output # active_flags are those that will trigger output
# #
active_flags = None, active_flags = None,
# #
# Log file should be file object or file namne # Log file should be file object or file namne
# #
@ -136,7 +132,7 @@ class Debug:
# with prefix = chr(27) + '[34m' # with prefix = chr(27) + '[34m'
# sufix = chr(27) + '[37;1m\n' # sufix = chr(27) + '[37;1m\n'
# #
prefix = 'DEBUG: ', prefix = 'DEBUG: ',
sufix = '\n', sufix = '\n',
# #
# If you want unix style timestamps, # If you want unix style timestamps,
@ -144,7 +140,7 @@ class Debug:
# 1 before prefix, good when prefix is a string # 1 before prefix, good when prefix is a string
# 2 after prefix, good when prefix is a color # 2 after prefix, good when prefix is a color
# #
time_stamp = 0, time_stamp = 0,
# #
# flag_show should normaly be of, but can be turned on to get a # flag_show should normaly be of, but can be turned on to get a
# good view of what flags are actually used for calls, # good view of what flags are actually used for calls,
@ -204,7 +200,7 @@ class Debug:
mod_name = "" mod_name = ""
self.show('Debug created for %s%s' % (caller.f_code.co_filename, self.show('Debug created for %s%s' % (caller.f_code.co_filename,
mod_name )) mod_name ))
self.show(' flags defined: %s' % ' '.join( self.active )) self.show(' flags defined: %s' % ','.join( self.active ))
if type(flag_show) in (type(''), type(None)): if type(flag_show) in (type(''), type(None)):
self.flag_show = flag_show self.flag_show = flag_show
@ -397,12 +393,19 @@ class Debug:
colors={} colors={}
def Show(self, flag, msg, prefix=''): def Show(self, flag, msg, prefix=''):
msg=msg.replace('\r','\\r').replace('\n','\\n') msg=msg.replace('\r','\\r').replace('\n','\\n').replace('><','>\n <')
if self.colors.has_key(prefix): msg=self.colors[prefix]+msg+color_none if not colors_enabled: pass
elif self.colors.has_key(prefix): msg=self.colors[prefix]+msg+color_none
else: msg=color_none+msg else: msg=color_none+msg
if self.colors.has_key(flag): prefixcolor=self.colors[flag] if not colors_enabled: prefixcolor=''
elif self.colors.has_key(flag): prefixcolor=self.colors[flag]
else: prefixcolor=color_none else: prefixcolor=color_none
if prefix=='error':
_exception = sys.exc_info()
if _exception[0]:
msg=msg+'\n'+''.join(traceback.format_exception(_exception[0], _exception[1], _exception[2])).rstrip()
prefix= self.prefix+prefixcolor+(flag+' '*12)[:12]+' '+(prefix+' '*6)[:6] prefix= self.prefix+prefixcolor+(flag+' '*12)[:12]+' '+(prefix+' '*6)[:6]
self.show(msg, flag, prefix) self.show(msg, flag, prefix)

View File

@ -12,7 +12,7 @@
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details. ## GNU General Public License for more details.
# $Id: dispatcher.py,v 1.35 2005/05/07 03:26:51 snakeru Exp $ # $Id: dispatcher.py,v 1.40 2006/01/18 19:26:43 normanr Exp $
""" """
Main xmpppy mechanism. Provides library with methods to assign different handlers Main xmpppy mechanism. Provides library with methods to assign different handlers
@ -115,18 +115,21 @@ class Dispatcher(PlugIn):
Returns: Returns:
1) length of processed data if some data were processed; 1) length of processed data if some data were processed;
2) '0' string if no data were processed but link is alive; 2) '0' string if no data were processed but link is alive;
3) 0 (zero) if underlying connection is closed.""" 3) 0 (zero) if underlying connection is closed.
Take note that in case of disconnection detect during Process() call
disconnect handlers are called automatically.
"""
for handler in self._cycleHandlers: handler(self) for handler in self._cycleHandlers: handler(self)
if len(self._pendingExceptions) > 0: if len(self._pendingExceptions) > 0:
_pendingException = self._pendingExceptions.pop() _pendingException = self._pendingExceptions.pop()
raise _pendingException[0], _pendingException[1], _pendingException[2] raise _pendingException[0], _pendingException[1], _pendingException[2]
if self._owner.Connection.pending_data(timeout): if self._owner.Connection.pending_data(timeout):
try: data=self._owner.Connection.receive() try: data=self._owner.Connection.receive()
except IOError: return except IOError: return
self.Stream.Parse(data) self.Stream.Parse(data)
if len(self._pendingExceptions) > 0: if len(self._pendingExceptions) > 0:
_pendingException = self._pendingExceptions.pop() _pendingException = self._pendingExceptions.pop()
raise _pendingException[0], _pendingException[1], _pendingException[2] raise _pendingException[0], _pendingException[1], _pendingException[2]
return len(data) return len(data)
return '0' # It means that nothing is received but link is alive. return '0' # It means that nothing is received but link is alive.
@ -234,13 +237,30 @@ class Dispatcher(PlugIn):
3) data that comes along with event. Depends on event.""" 3) data that comes along with event. Depends on event."""
if self._eventHandler: self._eventHandler(realm,event,data) if self._eventHandler: self._eventHandler(realm,event,data)
def dispatch(self,stanza,session=None): def dispatch(self,stanza,session=None,direct=0):
""" Main procedure that performs XMPP stanza recognition and calling apppropriate handlers for it. """ Main procedure that performs XMPP stanza recognition and calling apppropriate handlers for it.
Called internally. """ Called internally. """
if not session: session=self if not session: session=self
session.Stream._mini_dom=None session.Stream._mini_dom=None
name=stanza.getName() name=stanza.getName()
if not direct and self._owner._component:
if name == 'route':
if stanza.getAttr('error') == None:
if len(stanza.getChildren()) == 1:
stanza = stanza.getChildren()[0]
name=stanza.getName()
else:
for each in stanza.getChildren():
self.dispatch(each,session,direct=1)
return
elif name == 'presence':
return
elif name in ('features','bind'):
pass
else:
raise UnsupportedStanzaType(name)
if name=='features': session.Stream.features=stanza if name=='features': session.Stream.features=stanza
xmlns=stanza.getNamespace() xmlns=stanza.getNamespace()
@ -251,7 +271,7 @@ class Dispatcher(PlugIn):
self.DEBUG("Unknown stanza: " + name,'warn') self.DEBUG("Unknown stanza: " + name,'warn')
name='unknown' name='unknown'
else: else:
self.DEBUG("Got %s stanza"%name, 'ok') self.DEBUG("Got %s/%s stanza"%(xmlns,name), 'ok')
if stanza.__class__.__name__=='Node': stanza=self.handlers[xmlns][name][type](node=stanza) if stanza.__class__.__name__=='Node': stanza=self.handlers[xmlns][name][type](node=stanza)
@ -281,7 +301,6 @@ class Dispatcher(PlugIn):
try: cb(session,stanza,**args) try: cb(session,stanza,**args)
except Exception, typ: except Exception, typ:
if typ.__class__.__name__<>'NodeProcessed': raise if typ.__class__.__name__<>'NodeProcessed': raise
else: else:
session.DEBUG("Expected stanza arrived!",'ok') session.DEBUG("Expected stanza arrived!",'ok')
session._expected[ID]=stanza session._expected[ID]=stanza
@ -344,6 +363,16 @@ class Dispatcher(PlugIn):
stanza.setID(_ID) stanza.setID(_ID)
else: _ID=stanza.getID() else: _ID=stanza.getID()
if self._owner._registered_name and not stanza.getAttr('from'): stanza.setAttr('from',self._owner._registered_name) if self._owner._registered_name and not stanza.getAttr('from'): stanza.setAttr('from',self._owner._registered_name)
if self._owner._component and stanza.getName()!='bind':
to=self._owner.Server
if stanza.getTo() and stanza.getTo().getDomain():
to=stanza.getTo().getDomain()
frm=stanza.getFrom()
if frm.getDomain():
frm=frm.getDomain()
route=Protocol('route',to=to,frm=frm,payload=[stanza])
stanza=route
stanza.setNamespace(self._owner.Namespace)
stanza.setParent(self._metastream) stanza.setParent(self._metastream)
self._owner_send(stanza) self._owner_send(stanza)
return _ID return _ID

View File

@ -12,7 +12,7 @@
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details. ## GNU General Public License for more details.
# $Id: features.py,v 1.20 2005/04/30 07:43:01 snakeru Exp $ # $Id: features.py,v 1.22 2005/09/30 20:13:04 mikealbon Exp $
""" """
This module contains variable stuff that is not worth splitting into separate modules. This module contains variable stuff that is not worth splitting into separate modules.
@ -60,7 +60,7 @@ def discoverInfo(disp,jid,node=None):
""" Query remote object about info that it publishes. Returns identities and features lists.""" """ Query remote object about info that it publishes. Returns identities and features lists."""
""" According to JEP-0030: """ According to JEP-0030:
query MAY have node attribute query MAY have node attribute
identity: MUST HAVE category and type attributes and MAY HAVE name attribute. identity: MUST HAVE category and name attributes and MAY HAVE type attribute.
feature: MUST HAVE var attribute""" feature: MUST HAVE var attribute"""
identities , features = [] , [] identities , features = [] , []
for i in _discover(disp,NS_DISCO_INFO,jid,node): for i in _discover(disp,NS_DISCO_INFO,jid,node):

View File

@ -12,7 +12,7 @@
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details. ## GNU General Public License for more details.
# $Id: protocol.py,v 1.41 2005/05/02 08:36:41 snakeru Exp $ # $Id: protocol.py,v 1.52 2006/01/09 22:08:57 normanr Exp $
""" """
Protocol module contains tools that is needed for processing of Protocol module contains tools that is needed for processing of
@ -21,61 +21,79 @@ xmpp-related data structures.
from simplexml import Node,ustr from simplexml import Node,ustr
import time import time
NS_ACTIVITY ='http://jabber.org/protocol/activity' # JEP-0108
NS_ADDRESS ='http://jabber.org/protocol/address' # JEP-0033
NS_AGENTS ='jabber:iq:agents' NS_AGENTS ='jabber:iq:agents'
NS_AMP ='http://jabber.org/protocol/amp' NS_AMP ='http://jabber.org/protocol/amp'
NS_AMP_ERRORS =NS_AMP+'#errors'
NS_AUTH ='jabber:iq:auth' NS_AUTH ='jabber:iq:auth'
NS_BIND ='urn:ietf:params:xml:ns:xmpp-bind' NS_BIND ='urn:ietf:params:xml:ns:xmpp-bind'
NS_BROWSE ='jabber:iq:browse' NS_BROWSE ='jabber:iq:browse'
NS_BYTESTREAM ='http://jabber.org/protocol/bytestreams' # JEP-0065
NS_CAPS ='http://jabber.org/protocol/caps' # JEP-0115
NS_CHATSTATES ='http://jabber.org/protocol/chatstates' # JEP-0085
NS_CLIENT ='jabber:client' NS_CLIENT ='jabber:client'
NS_COMMANDS ='http://jabber.org/protocol/commands' NS_COMMANDS ='http://jabber.org/protocol/commands'
NS_COMPONENT_ACCEPT='jabber:component:accept' NS_COMPONENT_ACCEPT='jabber:component:accept'
NS_COMPONENT_1 ='http://jabberd.jabberstudio.org/ns/component/1.0'
NS_COMPRESS ='http://jabber.org/protocol/compress' # JEP-0138
NS_CONFERENCE ='jabber:x:conference' NS_CONFERENCE ='jabber:x:conference'
NS_DATA ='jabber:x:data' # JEP-0004 NS_DATA ='jabber:x:data' # JEP-0004
NS_DELAY ='jabber:x:delay' NS_DELAY ='jabber:x:delay'
NS_DIALBACK ='jabber:server:dialback' NS_DIALBACK ='jabber:server:dialback'
NS_DISCO_INFO ='http://jabber.org/protocol/disco#info' NS_DISCO ='http://jabber.org/protocol/disco'
NS_DISCO_ITEMS ='http://jabber.org/protocol/disco#items' NS_DISCO_INFO =NS_DISCO+'#info'
NS_DISCO_ITEMS =NS_DISCO+'#items'
NS_ENCRYPTED ='jabber:x:encrypted' # JEP-0027
NS_EVENT ='jabber:x:event' # JEP-0022
NS_FEATURE ='http://jabber.org/protocol/feature-neg'
NS_FILE ='http://jabber.org/protocol/si/profile/file-transfer' # JEP-0096
NS_GEOLOC ='http://jabber.org/protocol/geoloc' # JEP-0080
NS_GROUPCHAT ='gc-1.0' NS_GROUPCHAT ='gc-1.0'
NS_HTTP_AUTH ='http://jabber.org/protocol/http-auth' # JEP-0070
NS_HTTP_BIND ='http://jabber.org/protocol/httpbind' # JEP-0124
NS_IBB ='http://jabber.org/protocol/ibb' NS_IBB ='http://jabber.org/protocol/ibb'
NS_INVISIBLE ='presence-invisible' # jabberd2 NS_INVISIBLE ='presence-invisible' # Jabberd2
NS_IQ ='iq' # jabberd2 NS_IQ ='iq' # Jabberd2
NS_LAST ='jabber:iq:last' NS_LAST ='jabber:iq:last'
NS_MESSAGE ='message' # jabberd2 NS_MESSAGE ='message' # Jabberd2
NS_MOOD ='http://jabber.org/protocol/mood' # JEP-0107
NS_MUC ='http://jabber.org/protocol/muc' NS_MUC ='http://jabber.org/protocol/muc'
NS_MUC_USER ='http://jabber.org/protocol/muc#user' NS_MUC_USER =NS_MUC+'#user'
NS_MUC_ADMIN ='http://jabber.org/protocol/muc#admin' NS_MUC_ADMIN =NS_MUC+'#admin'
NS_MUC_OWNER ='http://jabber.org/protocol/muc#owner' NS_MUC_OWNER =NS_MUC+'#owner'
NS_OFFLINE ='http://www.jabber.org/jeps/jep-0030.html' # JEP-0013 NS_OFFLINE ='http://www.jabber.org/jeps/jep-0030.html' # JEP-0013
NS_PRESENCE ='presence' # jabberd2 NS_PHYSLOC ='http://jabber.org/protocol/physloc' # JEP-0112
NS_PRESENCE ='presence' # Jabberd2
NS_PRIVACY ='jabber:iq:privacy' NS_PRIVACY ='jabber:iq:privacy'
NS_PRIVATE ='jabber:iq:private' NS_PRIVATE ='jabber:iq:private'
NS_PUBSUB ='http://jabber.org/protocol/pubsub' # JEP-0060
NS_REGISTER ='jabber:iq:register' NS_REGISTER ='jabber:iq:register'
NS_ROSTER ='jabber:iq:roster' NS_ROSTER ='jabber:iq:roster'
NS_RPC ='jabber:iq:rpc' # JEP-0009 NS_ROSTERX ='http://jabber.org/protocol/rosterx' # JEP-0144
NS_RPC ='jabber:iq:rpc' # JEP-0009
NS_SASL ='urn:ietf:params:xml:ns:xmpp-sasl' NS_SASL ='urn:ietf:params:xml:ns:xmpp-sasl'
NS_SEARCH ='jabber:iq:search' NS_SEARCH ='jabber:iq:search'
NS_SERVER ='jabber:server' NS_SERVER ='jabber:server'
NS_SESSION ='urn:ietf:params:xml:ns:xmpp-session' NS_SESSION ='urn:ietf:params:xml:ns:xmpp-session'
NS_SI ='http://jabber.org/protocol/si' # JEP-0096
NS_SI_PUB ='http://jabber.org/protocol/sipub' # JEP-0137
NS_SIGNED ='jabber:x:signed' # JEP-0027
NS_STANZAS ='urn:ietf:params:xml:ns:xmpp-stanzas' NS_STANZAS ='urn:ietf:params:xml:ns:xmpp-stanzas'
NS_STREAM ='http://affinix.com/jabber/stream'
NS_STREAMS ='http://etherx.jabber.org/streams' NS_STREAMS ='http://etherx.jabber.org/streams'
NS_TIME ='jabber:iq:time' NS_TIME ='jabber:iq:time'
NS_TLS ='urn:ietf:params:xml:ns:xmpp-tls' NS_TLS ='urn:ietf:params:xml:ns:xmpp-tls'
NS_VACATION ='http://jabber.org/protocol/vacation' NS_VACATION ='http://jabber.org/protocol/vacation'
NS_VCARD ='vcard-temp' NS_VCARD ='vcard-temp'
NS_GMAILNOTIFY ='google:mail:notify' NS_GMAILNOTIFY ='google:mail:notify'
NS_VCARD_UPDATE =NS_VCARD+':x:update' NS_VCARD_UPDATE =NS_VCARD+':x:update'
NS_VERSION ='jabber:iq:version' NS_VERSION ='jabber:iq:version'
NS_ENCRYPTED ='jabber:x:encrypted' # JEP-0027 NS_WAITINGLIST ='http://jabber.org/protocol/waitinglist' # JEP-0130
NS_XHTML_IM ='http://jabber.org/protocol/xhtml-im' # JEP-0071
NS_DATA_LAYOUT ='http://jabber.org/protocol/xdata-layout' # JEP-0141
NS_DATA_VALIDATE='http://jabber.org/protocol/xdata-validate' # JEP-0122
NS_XMPP_STREAMS ='urn:ietf:params:xml:ns:xmpp-streams' NS_XMPP_STREAMS ='urn:ietf:params:xml:ns:xmpp-streams'
NS_SIGNED ='jabber:x:signed' # JEP-0027
NS_SI ='http://jabber.org/protocol/si' # JEP-0096
NS_FILE ='http://jabber.org/protocol/si/profile/file-transfer' # JEP-0096
NS_FEATURE ='http://jabber.org/protocol/feature-neg'
NS_BYTESTREAM ='http://jabber.org/protocol/bytestreams' # JEP-0065
NS_DISCO ='http://jabber.org/protocol/disco#info' # JEP-0095
NS_STREAM ='http://affinix.com/jabber/stream'
NS_HTTP_AUTH ='http://jabber.org/protocol/http-auth' # JEP-0070
xmpp_stream_error_conditions=""" xmpp_stream_error_conditions="""
bad-format -- -- -- The entity has sent XML that cannot be processed. bad-format -- -- -- The entity has sent XML that cannot be processed.
@ -676,7 +694,7 @@ class DataForm(Node):
for field in self.getTags('field'): for field in self.getTags('field'):
name=field.getAttr('var') name=field.getAttr('var')
typ=field.getType() typ=field.getType()
if type(typ) in [type(''),type(u'')] and typ[-6:]=='multi': if type(typ) in [type(''),type(u'')] and typ[-6:]=='-multi':
val=[] val=[]
for i in field.getTags('value'): val.append(i.getData()) for i in field.getTags('value'): val.append(i.getData())
else: val=field.getTagData('value') else: val=field.getTagData('value')

View File

@ -66,7 +66,7 @@ class error:
class TCPsocket(PlugIn): class TCPsocket(PlugIn):
""" This class defines direct TCP connection method. """ """ This class defines direct TCP connection method. """
def __init__(self, server=None): def __init__(self, server=None, use_srv=True):
""" Cache connection point 'server'. 'server' is the tuple of (host, port) """ Cache connection point 'server'. 'server' is the tuple of (host, port)
absolutely the same as standard tcp socket uses. """ absolutely the same as standard tcp socket uses. """
PlugIn.__init__(self) PlugIn.__init__(self)
@ -165,12 +165,12 @@ class HTTPPROXYsocket(TCPsocket):
""" HTTP (CONNECT) proxy connection class. Uses TCPsocket as the base class """ HTTP (CONNECT) proxy connection class. Uses TCPsocket as the base class
redefines only connect method. Allows to use HTTP proxies like squid with redefines only connect method. Allows to use HTTP proxies like squid with
(optionally) simple authentication (using login and password). """ (optionally) simple authentication (using login and password). """
def __init__(self,proxy,server): def __init__(self,proxy,server,use_srv=True):
""" Caches proxy and target addresses. """ Caches proxy and target addresses.
'proxy' argument is a dictionary with mandatory keys 'host' and 'port' (proxy address) 'proxy' argument is a dictionary with mandatory keys 'host' and 'port' (proxy address)
and optional keys 'user' and 'password' to use for authentication. and optional keys 'user' and 'password' to use for authentication.
'server' argument is a tuple of host and port - just like TCPsocket uses. """ 'server' argument is a tuple of host and port - just like TCPsocket uses. """
TCPsocket.__init__(self,server) TCPsocket.__init__(self,server,use_srv)
self.DBG_LINE=DBG_CONNECT_PROXY self.DBG_LINE=DBG_CONNECT_PROXY
self._proxy=proxy self._proxy=proxy
@ -196,14 +196,23 @@ class HTTPPROXYsocket(TCPsocket):
connector.append('Proxy-Authorization: Basic '+credentials) connector.append('Proxy-Authorization: Basic '+credentials)
connector.append('\r\n') connector.append('\r\n')
self.send('\r\n'.join(connector)) self.send('\r\n'.join(connector))
reply = self.receive().replace('\r','') try: reply = self.receive().replace('\r','')
except IOError:
self.DEBUG('Proxy suddenly disconnected','error')
self._owner.disconnected()
return
try: proto,code,desc=reply.split('\n')[0].split(' ',2) try: proto,code,desc=reply.split('\n')[0].split(' ',2)
except: raise error('Invalid proxy reply') except: raise error('Invalid proxy reply')
if code<>'200': if code<>'200':
self.DEBUG('Invalid proxy reply: %s %s %s'%(proto,code,desc),'error') self.DEBUG('Invalid proxy reply: %s %s %s'%(proto,code,desc),'error')
self._owner.disconnected() self._owner.disconnected()
return return
while reply.find('\n\n') == -1: reply += self.receive().replace('\r','') while reply.find('\n\n') == -1:
try: reply += self.receive().replace('\r','')
except IOError:
self.DEBUG('Proxy suddenly disconnected','error')
self._owner.disconnected()
return
self.DEBUG("Authentification successfull. Jabber server contacted.",'ok') self.DEBUG("Authentification successfull. Jabber server contacted.",'ok')
return 'ok' return 'ok'
@ -247,8 +256,13 @@ class TLS(PlugIn):
self._owner.Connection.send('<starttls xmlns="%s"/>'%NS_TLS) self._owner.Connection.send('<starttls xmlns="%s"/>'%NS_TLS)
raise NodeProcessed raise NodeProcessed
def pending_data(self,timeout=0):
""" Returns true if there possible is a data ready to be read. """
return self._tcpsock._seen_data or select.select([self._tcpsock._sock],[],[],timeout)[0]
def _startSSL(self): def _startSSL(self):
""" Immidiatedly switch socket to TLS mode. Used internally.""" """ Immidiatedly switch socket to TLS mode. Used internally."""
""" Here we should switch pending_data to hint mode."""
tcpsock=self._owner.Connection tcpsock=self._owner.Connection
tcpsock._sslObj = socket.ssl(tcpsock._sock, None, None) tcpsock._sslObj = socket.ssl(tcpsock._sock, None, None)
tcpsock._sslIssuer = tcpsock._sslObj.issuer() tcpsock._sslIssuer = tcpsock._sslObj.issuer()