xmpppy changes:
- Sync with latest CVS version + gajim patches. - streamErrorHandler disabled. If you want enable it - unrem it at line 66 of dispatcher.py - TLS re-enabled. Should work fine now - disconnection TLS plugout re-enabled. Didn't successed in reproducing problem though so maybe not fixed. - My temporary fixes replaced with CVS ones. gajim connection.py changes (in chunks order): - getTags is incorrect. Replaced with getChildren - browseAgents is absent from xmpppy. Fixed with manual node send. Made use of buildReply method and con argument - formatting fix - crude fixed register problem. I do not know how to do it properly. It is client stuff. Honest! I have no idea how to make it non-blocking and yet make library to fallback to older protocols. getInstructions() moved to xmpppy Thanks Alexey !
This commit is contained in:
parent
66249dafb5
commit
56d60f3fd5
|
@ -328,7 +328,7 @@ class Connection:
|
|||
for key in q.getAttrs().keys():
|
||||
attr[key.encode('utf8')] = q.getAttr(key).encode('utf8')
|
||||
identities = [attr]
|
||||
for node in q.getTags():
|
||||
for node in q.getChildren():
|
||||
if node.getName() == 'ns':
|
||||
features.append(node.getData())
|
||||
else:
|
||||
|
@ -387,24 +387,22 @@ class Connection:
|
|||
features.append(i.getAttr('var'))
|
||||
jid = str(iq_obj.getFrom())
|
||||
if not identities:
|
||||
self.connection.browseAgents(jid, node)
|
||||
self.connection.send(common.xmpp.Iq(typ = 'get', queryNS = \
|
||||
common.xmpp.NS_AGENTS))
|
||||
else:
|
||||
self.dispatch('AGENT_INFO_INFO', (jid, node, identities, features))
|
||||
self.discoverItems(jid, node)
|
||||
|
||||
def _VersionCB(self, con, iq_obj):
|
||||
gajim.log.debug('VersionCB')
|
||||
f = iq_obj.getFrom()
|
||||
iq_obj.setFrom(iq_obj.getTo())
|
||||
iq_obj.setTo(f)
|
||||
iq_obj.setType('result')
|
||||
iq_obj = iq_obj.buildReply('result')
|
||||
qp = iq_obj.getTag('query')
|
||||
qp.setTagData('name', 'Gajim')
|
||||
qp.setTagData('version', gajim.version)
|
||||
send_os = gajim.config.get('send_os_info')
|
||||
if send_os:
|
||||
qp.setTagData('os', get_os_info())
|
||||
self.connection.send(iq_obj)
|
||||
con.send(iq_obj)
|
||||
|
||||
def _VersionResultCB(self, con, iq_obj):
|
||||
gajim.log.debug('VersionResultCB')
|
||||
|
@ -638,8 +636,7 @@ class Connection:
|
|||
prio = str(gajim.config.get_per('accounts', self.name, 'priority'))
|
||||
p = common.xmpp.Presence(typ = ptype, priority = prio, show = status,
|
||||
status = msg)
|
||||
if signed: p.setTag(common.xmpp.NS_SIGNED + ' x').setData(
|
||||
signed)
|
||||
if signed: p.setTag(common.xmpp.NS_SIGNED + ' x').setData(signed)
|
||||
self.connection.send(p)
|
||||
self.dispatch('STATUS', status)
|
||||
|
||||
|
@ -712,17 +709,14 @@ class Connection:
|
|||
|
||||
def request_agents(self, jid, node):
|
||||
if self.connection:
|
||||
self.connection.send(common.xmpp.Iq(to = jid, typ = 'get',
|
||||
queryNS = common.xmpp.NS_BROWSE))
|
||||
self.discoverInfo(jid, node)
|
||||
|
||||
def ask_register_agent_info(self, agent):
|
||||
if not self.connection:
|
||||
return None
|
||||
data = common.xmpp.features.getRegInfo(self.connection, agent) # FIXME: blocking
|
||||
info = data.asDict()
|
||||
instructions = data.getInstructions()
|
||||
if instructions:
|
||||
info['instructions'] = instructions
|
||||
return info
|
||||
return common.xmpp.features.getRegInfo(self.connection, agent).asDict() # FIXME: blocking
|
||||
|
||||
def register_agent(self, agent, info):
|
||||
if not self.connection:
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
|
||||
# $Id: auth.py,v 1.25 2005/03/08 19:36:29 snakeru Exp $
|
||||
# $Id: auth.py,v 1.27 2005/04/30 10:17:20 snakeru Exp $
|
||||
|
||||
"""
|
||||
Provides library with all Non-SASL and SASL authentication mechanisms.
|
||||
|
@ -97,7 +97,8 @@ class NonSASL(PlugIn):
|
|||
class SASL(PlugIn):
|
||||
""" Implements SASL authentication. """
|
||||
def plugin(self,owner):
|
||||
self.startsasl=None
|
||||
if not self._owner.Dispatcher.Stream._document_attrs.has_key('version'): self.startsasl='not-supported'
|
||||
else: self.startsasl=None
|
||||
|
||||
def auth(self,username,password):
|
||||
""" Start authentication. Result can be obtained via "SASL.startsasl" attribute and will be
|
||||
|
@ -120,7 +121,7 @@ class SASL(PlugIn):
|
|||
def FeaturesHandler(self,conn,feats):
|
||||
""" Used to determine if server supports SASL auth. Used internally. """
|
||||
if not feats.getTag('mechanisms',namespace=NS_SASL):
|
||||
self.startsasl='failure'
|
||||
self.startsasl='not-supported'
|
||||
self.DEBUG('SASL not supported by server','error')
|
||||
return
|
||||
mecs=[]
|
||||
|
@ -213,7 +214,7 @@ class Bind(PlugIn):
|
|||
except NodeProcessed: pass
|
||||
else: self._owner.RegisterHandler('features',self.FeaturesHandler,xmlns=NS_STREAMS)
|
||||
|
||||
def plugout(self,owner):
|
||||
def plugout(self):
|
||||
""" Remove Bind handler from owner's dispatcher. Used internally. """
|
||||
self._owner.UnregisterHandler('features',self.FeaturesHandler,xmlns=NS_STREAMS)
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
|
||||
# $Id: browser.py,v 1.8 2004/12/24 19:56:35 snakeru Exp $
|
||||
# $Id: browser.py,v 1.9 2005/04/30 07:13:33 snakeru Exp $
|
||||
|
||||
"""Browser module provides DISCO server framework for your application.
|
||||
This functionality can be used for very different purposes - from publishing
|
||||
|
@ -27,7 +27,9 @@ from dispatcher import *
|
|||
from client import PlugIn
|
||||
|
||||
class Browser(PlugIn):
|
||||
""" Standart xmpppy class that is ancestor of PlugIn and can be attached
|
||||
""" WARNING! This class is for components only. It will not work in client mode!
|
||||
|
||||
Standart xmpppy class that is ancestor of PlugIn and can be attached
|
||||
to your application.
|
||||
All processing will be performed in the handlers registered in the browser
|
||||
instance. You can register any number of handlers ensuring that for each
|
||||
|
@ -85,14 +87,14 @@ class Browser(PlugIn):
|
|||
def plugin(self, owner):
|
||||
""" Registers it's own iq handlers in your application dispatcher instance.
|
||||
Used internally."""
|
||||
owner.RegisterHandler('iq',self._DiscoveryHandler,ns=NS_DISCO_INFO)
|
||||
owner.RegisterHandler('iq',self._DiscoveryHandler,ns=NS_DISCO_ITEMS)
|
||||
owner.RegisterHandler('iq',self._DiscoveryHandler,typ='get',ns=NS_DISCO_INFO)
|
||||
owner.RegisterHandler('iq',self._DiscoveryHandler,typ='get',ns=NS_DISCO_ITEMS)
|
||||
|
||||
def plugout(self):
|
||||
""" Unregisters browser's iq handlers from your application dispatcher instance.
|
||||
Used internally."""
|
||||
self._owner.UnregisterHandler('iq',self._DiscoveryHandler,ns=NS_DISCO_INFO)
|
||||
self._owner.UnregisterHandler('iq',self._DiscoveryHandler,ns=NS_DISCO_ITEMS)
|
||||
self._owner.UnregisterHandler('iq',self._DiscoveryHandler,typ='get',ns=NS_DISCO_INFO)
|
||||
self._owner.UnregisterHandler('iq',self._DiscoveryHandler,typ='get',ns=NS_DISCO_ITEMS)
|
||||
|
||||
def _traversePath(self,node,jid,set=0):
|
||||
""" Returns dictionary and key or None,None
|
||||
|
@ -136,7 +138,7 @@ class Browser(PlugIn):
|
|||
{'jid':'jid2','action':'action2','node':'node2','name':'name2'},
|
||||
{'jid':'jid3','node':'node3','name':'name3'},
|
||||
{'jid':'jid4','node':'node4'}
|
||||
]
|
||||
],
|
||||
'info' :{
|
||||
'ids':[
|
||||
{'category':'category1','type':'type1','name':'name1'},
|
||||
|
@ -182,7 +184,9 @@ class Browser(PlugIn):
|
|||
to handle the request. Used internally.
|
||||
"""
|
||||
handler=self.getDiscoHandler(request.getQuerynode(),request.getTo())
|
||||
if not handler: return conn.send(Error(request,ERR_ITEM_NOT_FOUND))
|
||||
if not handler:
|
||||
conn.send(Error(request,ERR_ITEM_NOT_FOUND))
|
||||
raise NodeProcessed
|
||||
rep=request.buildReply('result')
|
||||
q=rep.getTag('query')
|
||||
if request.getQueryNS()==NS_DISCO_ITEMS:
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
|
||||
# $Id: client.py,v 1.33 2005/04/10 08:09:23 snakeru Exp $
|
||||
# $Id: client.py,v 1.35 2005/04/30 10:17:19 snakeru Exp $
|
||||
|
||||
"""
|
||||
Provides PlugIn class functionality to develop extentions for xmpppy.
|
||||
|
@ -105,7 +105,7 @@ class CommonClient:
|
|||
self.debug_flags.append(self.DBG)
|
||||
self._owner=self
|
||||
self._registered_name=None
|
||||
# self.RegisterDisconnectHandler(self.DisconnectHandler)
|
||||
self.RegisterDisconnectHandler(self.DisconnectHandler)
|
||||
self.connected=''
|
||||
|
||||
def RegisterDisconnectHandler(self,handler):
|
||||
|
@ -123,7 +123,7 @@ class CommonClient:
|
|||
self.disconnect_handlers.reverse()
|
||||
for i in self.disconnect_handlers: i()
|
||||
self.disconnect_handlers.reverse()
|
||||
# if self.__dict__.has_key('TLS'): self.TLS.PlugOut()
|
||||
if self.__dict__.has_key('TLS'): self.TLS.PlugOut()
|
||||
|
||||
def DisconnectHandler(self):
|
||||
""" Default disconnect handler. Just raises an IOError.
|
||||
|
@ -156,9 +156,9 @@ class CommonClient:
|
|||
if not connected: return
|
||||
self._Server,self._Proxy=server,proxy
|
||||
self.connected='tcp'
|
||||
# if self.Connection.getPort()==5223:
|
||||
# transports.TLS().PlugIn(self,now=1)
|
||||
# self.connected='tls'
|
||||
if self.Connection.getPort()==5223:
|
||||
transports.TLS().PlugIn(self,now=1)
|
||||
self.connected='tls'
|
||||
dispatcher.Dispatcher().PlugIn(self)
|
||||
while self.Dispatcher.Stream._document_attrs is None: self.Process(1)
|
||||
if self.Dispatcher.Stream._document_attrs.has_key('version') and self.Dispatcher.Stream._document_attrs['version']=='1.0':
|
||||
|
@ -173,32 +173,32 @@ class Client(CommonClient):
|
|||
specify it's address and credentials (if needed) in the second argument.
|
||||
Example: connect(('192.168.5.5':5222),{'host':'proxy.my.net','port':8080,'user':'me','password':'secret'})"""
|
||||
if not CommonClient.connect(self,server,proxy): 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
|
||||
while not self.Dispatcher.Stream.features and self.Process(): pass # If we get version 1.0 stream the features tag MUST BE presented
|
||||
# if not self.Dispatcher.Stream.features.getTag('starttls'): return self.connected # TLS not supported by server
|
||||
# while not self.TLS.starttls and self.Process(): pass
|
||||
# if self.TLS.starttls<>'success': self.event('tls_failed'); return self.connected
|
||||
# self.connected='tls'
|
||||
if not self.Dispatcher.Stream.features.getTag('starttls'): return self.connected # TLS not supported by server
|
||||
while not self.TLS.starttls and self.Process(): pass
|
||||
if self.TLS.starttls<>'success': self.event('tls_failed'); return self.connected
|
||||
self.connected='tls'
|
||||
return self.connected
|
||||
|
||||
def auth(self,user,password,resource=''):
|
||||
""" Authenticate connnection and bind resource. If resource is not provided
|
||||
random one or library name used. """
|
||||
self._User,self._Password,self._Resource=user,password,resource
|
||||
auth.SASL().PlugIn(self)
|
||||
self.SASL.auth(user,password)
|
||||
while not self.Dispatcher.Stream._document_attrs and self.Process(): pass
|
||||
if self.Dispatcher.Stream._document_attrs.has_key('version') and self.Dispatcher.Stream._document_attrs['version']=='1.0':
|
||||
while not self.Dispatcher.Stream.features and self.Process(): pass # If we get version 1.0 stream the features tag MUST BE presented
|
||||
while self.SASL.startsasl=='in-process' and self.Process(): pass
|
||||
else: self.SASL.startsasl='failure'
|
||||
if self.SASL.startsasl=='failure':
|
||||
auth.SASL().PlugIn(self)
|
||||
if self.SASL.startsasl=='not-supported':
|
||||
if not resource: resource='xmpppy'
|
||||
if auth.NonSASL(user,password,resource).PlugIn(self):
|
||||
self.connected+='+old_auth'
|
||||
return 'old_auth'
|
||||
else:
|
||||
return
|
||||
self.SASL.auth(user,password)
|
||||
while self.SASL.startsasl=='in-process' and self.Process(): pass
|
||||
if self.SASL.startsasl=='success':
|
||||
auth.Bind().PlugIn(self)
|
||||
while self.Bind.bound is None: self.Process()
|
||||
if self.Bind.Bind(resource):
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
## $Id: commands.py,v 1.3 2005/03/08 19:50:43 snakeru Exp $
|
||||
## $Id: commands.py,v 1.4 2005/04/30 07:33:11 snakeru Exp $
|
||||
|
||||
## Ad-Hoc Command manager
|
||||
## Mike Albon (c) 5th January 2005
|
||||
|
@ -34,8 +34,6 @@ What it supplies:
|
|||
from xmpp.protocol import *
|
||||
from xmpp.client import PlugIn
|
||||
|
||||
NS_COMMANDS='http://jabber.org/protocol/commands'
|
||||
|
||||
class Commands(PlugIn):
|
||||
"""Commands is an ancestor of Plugin and can be attached to any session.
|
||||
|
||||
|
@ -167,7 +165,10 @@ class Commands(PlugIn):
|
|||
return self._handlers[jid][name]
|
||||
|
||||
class Command_Handler_Prototype(PlugIn):
|
||||
"""This is a prototype command handler, as each command uses a disco method and execute method you can implement it any way you like, however this is my first attempt at making a generic handler that you can hang process stages on too. There is an example command below.
|
||||
"""This is a prototype command handler, as each command uses a disco method
|
||||
and execute method you can implement it any way you like, however this is
|
||||
my first attempt at making a generic handler that you can hang process
|
||||
stages on too. There is an example command below.
|
||||
|
||||
The parameters are as follows:
|
||||
name : the name of the command within the jabber environment
|
||||
|
@ -241,14 +242,19 @@ class Command_Handler_Prototype(PlugIn):
|
|||
return self.discoinfo
|
||||
|
||||
class TestCommand(Command_Handler_Prototype):
|
||||
""" Example class. You should read source if you wish to understate how it works.
|
||||
Generally, it presents a "master" that giudes user through to calculate something.
|
||||
"""
|
||||
name = 'testcommand'
|
||||
description = 'a noddy example command'
|
||||
def __init__(self):
|
||||
""" Init internal constants. """
|
||||
Command_Handler_Prototype.__init__(self)
|
||||
self.pi = 3.14
|
||||
self.initial = {'execute':self.cmdFirstStage}
|
||||
|
||||
def cmdFirstStage(self,conn,request):
|
||||
""" Determine """
|
||||
# This is the only place this should be repeated as all other stages should have SessionIDs
|
||||
try:
|
||||
session = request.getTagAttr('command','sessionid')
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
|
||||
# $Id: dispatcher.py,v 1.31 2005/03/08 19:36:29 snakeru Exp $
|
||||
# $Id: dispatcher.py,v 1.34 2005/05/02 08:36:41 snakeru Exp $
|
||||
|
||||
"""
|
||||
Main xmpppy mechanism. Provides library with methods to assign different handlers
|
||||
|
@ -55,6 +55,7 @@ class Dispatcher(PlugIn):
|
|||
self.handlers=handlers
|
||||
|
||||
def _init(self):
|
||||
""" Registers default namespaces/protocols/handlers. Used internally. """
|
||||
self.RegisterNamespace('unknown')
|
||||
self.RegisterNamespace(NS_STREAMS)
|
||||
self.RegisterNamespace(self._owner.defaultNamespace)
|
||||
|
@ -62,6 +63,7 @@ class Dispatcher(PlugIn):
|
|||
self.RegisterProtocol('presence',Presence)
|
||||
self.RegisterProtocol('message',Message)
|
||||
self.RegisterDefaultHandler(self.returnStanzaHandler)
|
||||
# self.RegisterHandler('error',self.streamErrorHandler,xmlns=NS_STREAMS)
|
||||
|
||||
def plugin(self, owner):
|
||||
""" Plug the Dispatcher instance into Client class instance and send initial stream header. Used internally."""
|
||||
|
@ -74,6 +76,7 @@ class Dispatcher(PlugIn):
|
|||
self.StreamInit()
|
||||
|
||||
def plugout(self):
|
||||
""" Prepares instance to be destructed. """
|
||||
self.Stream.dispatch=None
|
||||
self.Stream.DEBUG=None
|
||||
self.Stream.features=None
|
||||
|
@ -99,7 +102,10 @@ class Dispatcher(PlugIn):
|
|||
Returns:
|
||||
1) length of processed data if some data were processed;
|
||||
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.
|
||||
"""
|
||||
if time.time() > self._lastIncome + 60: #1 min
|
||||
iq = Iq('get', NS_LAST, to=self._owner.Server)
|
||||
self.send(iq)
|
||||
|
@ -107,10 +113,12 @@ class Dispatcher(PlugIn):
|
|||
self.disconnected()
|
||||
for handler in self._cycleHandlers: handler(self)
|
||||
if self._owner.Connection.pending_data(timeout):
|
||||
data=self._owner.Connection.receive()
|
||||
try: data=self._owner.Connection.receive()
|
||||
except IOError: return
|
||||
self.Stream.Parse(data)
|
||||
self._lastIncome = time.time()
|
||||
return len(data)
|
||||
if data:
|
||||
self._lastIncome = time.time()
|
||||
return len(data)
|
||||
return '0' # It means that nothing is received but link is alive.
|
||||
|
||||
def RegisterNamespace(self,xmlns,order='info'):
|
||||
|
@ -190,6 +198,16 @@ class Dispatcher(PlugIn):
|
|||
if stanza.getType() in ['get','set']:
|
||||
conn.send(Error(stanza,ERR_FEATURE_NOT_IMPLEMENTED))
|
||||
|
||||
def streamErrorHandler(self,conn,error):
|
||||
name,text='error',error.getData()
|
||||
for tag in error.getChildren():
|
||||
if tag.getNamespace()==NS_XMPP_STREAMS:
|
||||
if tag.getName()=='text': text=tag.getData()
|
||||
else: name=tag.getName()
|
||||
if name in stream_exceptions.keys(): exc=stream_exceptions[name]
|
||||
else: exc=StreamError
|
||||
raise exc((name,text))
|
||||
|
||||
def RegisterCycleHandler(self,handler):
|
||||
""" Register handler that will be called on every Dispatcher.Process() call. """
|
||||
if handler not in self._cycleHandlers: self._cycleHandlers.append(handler)
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
|
||||
# $Id: features.py,v 1.19 2004/12/25 20:06:59 snakeru Exp $
|
||||
# $Id: features.py,v 1.20 2005/04/30 07:43:01 snakeru Exp $
|
||||
|
||||
"""
|
||||
This module contains variable stuff that is not worth splitting into separate modules.
|
||||
|
@ -88,10 +88,9 @@ def getRegInfo(disp,host,info={}):
|
|||
if df: return DataForm(node=df)
|
||||
df=DataForm(typ='form')
|
||||
for i in resp.getQueryPayload():
|
||||
try: #FIXME: temporary patch by Alexey to make it work :|
|
||||
if i.getName()=='instructions': df.addInstructions(i.getData())
|
||||
else: df.setField(i.getName()).setValue(i.getData())
|
||||
except: pass
|
||||
if type(i)<>type(iq): pass
|
||||
elif i.getName()=='instructions': df.addInstructions(i.getData())
|
||||
else: df.setField(i.getName()).setValue(i.getData())
|
||||
return df
|
||||
|
||||
def register(disp,host,info):
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
|
||||
# $Id: protocol.py,v 1.39 2005/03/08 19:36:29 snakeru Exp $
|
||||
# $Id: protocol.py,v 1.41 2005/05/02 08:36:41 snakeru Exp $
|
||||
|
||||
"""
|
||||
Protocol module contains tools that is needed for processing of
|
||||
|
@ -28,13 +28,13 @@ NS_AUTH ='jabber:iq:auth'
|
|||
NS_BIND ='urn:ietf:params:xml:ns:xmpp-bind'
|
||||
NS_BROWSE ='jabber:iq:browse'
|
||||
NS_CLIENT ='jabber:client'
|
||||
NS_COMMANDS ='http://jabber.org/protocol/commands'
|
||||
NS_COMPONENT_ACCEPT='jabber:component:accept'
|
||||
NS_DATA ='jabber:x:data' # JEP-0004
|
||||
NS_DELAY ='jabber:x:delay'
|
||||
NS_DIALBACK ='jabber:server:dialback'
|
||||
NS_DISCO_INFO ='http://jabber.org/protocol/disco#info'
|
||||
NS_DISCO_ITEMS ='http://jabber.org/protocol/disco#items'
|
||||
NS_ENCRYPTED ='jabber:x:encrypted' # JEP-0027
|
||||
NS_GROUPCHAT ='gc-1.0'
|
||||
NS_IBB ='http://jabber.org/protocol/ibb'
|
||||
NS_INVISIBLE ='presence-invisible' # jabberd2
|
||||
|
@ -42,8 +42,9 @@ NS_IQ ='iq' # jabberd2
|
|||
NS_LAST ='jabber:iq:last'
|
||||
NS_MESSAGE ='message' # jabberd2
|
||||
NS_MUC ='http://jabber.org/protocol/muc'
|
||||
NS_MUC_OWNER ='http://jabber.org/protocol/muc#owner'
|
||||
NS_MUC_USER ='http://jabber.org/protocol/muc#user'
|
||||
NS_MUC_ADMIN ='http://jabber.org/protocol/muc#admin'
|
||||
NS_MUC_OWNER ='http://jabber.org/protocol/muc#owner'
|
||||
NS_OFFLINE ='http://www.jabber.org/jeps/jep-0030.html' # JEP-0013
|
||||
NS_PRESENCE ='presence' # jabberd2
|
||||
NS_PRIVACY ='jabber:iq:privacy'
|
||||
|
@ -55,7 +56,6 @@ NS_SASL ='urn:ietf:params:xml:ns:xmpp-sasl'
|
|||
NS_SEARCH ='jabber:iq:search'
|
||||
NS_SERVER ='jabber:server'
|
||||
NS_SESSION ='urn:ietf:params:xml:ns:xmpp-session'
|
||||
NS_SIGNED ='jabber:x:signed' # JEP-0027
|
||||
NS_STANZAS ='urn:ietf:params:xml:ns:xmpp-stanzas'
|
||||
NS_STREAMS ='http://etherx.jabber.org/streams'
|
||||
NS_TIME ='jabber:iq:time'
|
||||
|
@ -63,7 +63,9 @@ NS_TLS ='urn:ietf:params:xml:ns:xmpp-tls'
|
|||
NS_VACATION ='http://jabber.org/protocol/vacation'
|
||||
NS_VCARD ='vcard-temp'
|
||||
NS_VERSION ='jabber:iq:version'
|
||||
NS_ENCRYPTED ='jabber:x:encrypted' # JEP-0027
|
||||
NS_XMPP_STREAMS ='urn:ietf:params:xml:ns:xmpp-streams'
|
||||
NS_SIGNED ='jabber:x:signed' # JEP-0027
|
||||
|
||||
xmpp_stream_error_conditions="""
|
||||
bad-format -- -- -- The entity has sent XML that cannot be processed.
|
||||
|
@ -140,8 +142,60 @@ def isResultNode(node):
|
|||
def isErrorNode(node):
|
||||
""" Returns true if the node is a negative reply. """
|
||||
return node and node.getType()=='error'
|
||||
|
||||
class NodeProcessed(Exception):
|
||||
""" Exception that should be raised by handler when the handling should be stopped. """
|
||||
class StreamError(Exception):
|
||||
""" Base exception class for stream errors."""
|
||||
class BadFormat(StreamError): pass
|
||||
class BadNamespacePrefix(StreamError): pass
|
||||
class Conflict(StreamError): pass
|
||||
class ConnectionTimeout(StreamError): pass
|
||||
class HostGone(StreamError): pass
|
||||
class HostUnknown(StreamError): pass
|
||||
class ImproperAddressing(StreamError): pass
|
||||
class InternalServerError(StreamError): pass
|
||||
class InvalidFrom(StreamError): pass
|
||||
class InvalidID(StreamError): pass
|
||||
class InvalidNamespace(StreamError): pass
|
||||
class InvalidXML(StreamError): pass
|
||||
class NotAuthorized(StreamError): pass
|
||||
class PolicyViolation(StreamError): pass
|
||||
class RemoteConnectionFailed(StreamError): pass
|
||||
class ResourceConstraint(StreamError): pass
|
||||
class RestrictedXML(StreamError): pass
|
||||
class SeeOtherHost(StreamError): pass
|
||||
class SystemShutdown(StreamError): pass
|
||||
class UndefinedCondition(StreamError): pass
|
||||
class UnsupportedEncoding(StreamError): pass
|
||||
class UnsupportedStanzaType(StreamError): pass
|
||||
class UnsupportedVersion(StreamError): pass
|
||||
class XMLNotWellFormed(StreamError): pass
|
||||
|
||||
stream_exceptions = {'bad-format': BadFormat,
|
||||
'bad-namespace-prefix': BadNamespacePrefix,
|
||||
'conflict': Conflict,
|
||||
'connection-timeout': ConnectionTimeout,
|
||||
'host-gone': HostGone,
|
||||
'host-unknown': HostUnknown,
|
||||
'improper-addressing': ImproperAddressing,
|
||||
'internal-server-error': InternalServerError,
|
||||
'invalid-from': InvalidFrom,
|
||||
'invalid-id': InvalidID,
|
||||
'invalid-namespace': InvalidNamespace,
|
||||
'invalid-xml': InvalidXML,
|
||||
'not-authorized': NotAuthorized,
|
||||
'policy-violation': PolicyViolation,
|
||||
'remote-connection-failed': RemoteConnectionFailed,
|
||||
'resource-constraint': ResourceConstraint,
|
||||
'restricted-xml': RestrictedXML,
|
||||
'see-other-host': SeeOtherHost,
|
||||
'system-shutdown': SystemShutdown,
|
||||
'undefined-condition': UndefinedCondition,
|
||||
'unsupported-encoding': UnsupportedEncoding,
|
||||
'unsupported-stanza-type': UnsupportedStanzaType,
|
||||
'unsupported-version': UnsupportedVersion,
|
||||
'xml-not-well-formed': XMLNotWellFormed}
|
||||
|
||||
class JID:
|
||||
""" JID object. JID can be built from string, modified, compared, serialised into string. """
|
||||
|
@ -345,6 +399,16 @@ class Presence(Protocol):
|
|||
def getStatus(self):
|
||||
""" Returns the status string of the message. """
|
||||
return self.getTagData('status')
|
||||
def setPriority(self,val):
|
||||
""" Sets the priority of the message. """
|
||||
self.setTagData('priority',val)
|
||||
def setShow(self,val):
|
||||
""" Sets the show value of the message. """
|
||||
self.setTagData('show',val)
|
||||
def setStatus(self,val):
|
||||
""" Sets the status string of the message. """
|
||||
self.setTagData('status',val)
|
||||
|
||||
def _muc_getItemAttr(self,tag,attr):
|
||||
for xtag in self.getTags('x'):
|
||||
for child in xtag.getTags(tag):
|
||||
|
@ -373,15 +437,6 @@ class Presence(Protocol):
|
|||
def getStatusCode(self):
|
||||
"""Returns the status code of the presence (for groupchat)"""
|
||||
return self._muc_getItemAttr('status','code')
|
||||
def setPriority(self,val):
|
||||
""" Sets the priority of the message. """
|
||||
self.setTagData('priority',val)
|
||||
def setShow(self,val):
|
||||
""" Sets the show value of the message. """
|
||||
self.setTagData('show',val)
|
||||
def setStatus(self,val):
|
||||
""" Sets the status string of the message. """
|
||||
self.setTagData('status',val)
|
||||
|
||||
class Iq(Protocol):
|
||||
""" XMPP Iq object - get/set dialog mechanism. """
|
||||
|
@ -613,6 +668,7 @@ class DataForm(Node):
|
|||
for i in field.getTags('value'): val.append(i.getData())
|
||||
else: val=field.getTagData('value')
|
||||
ret[name]=val
|
||||
if self.getTag('instructions'): ret['instructions']=self.getInstructions()
|
||||
return ret
|
||||
def __getitem__(self,name):
|
||||
""" Simple dictionary interface for getting datafields values by their names."""
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
|
||||
# $Id: roster.py,v 1.16 2005/02/25 05:49:03 snakeru Exp $
|
||||
# $Id: roster.py,v 1.17 2005/05/02 08:38:49 snakeru Exp $
|
||||
|
||||
"""
|
||||
Simple roster implementation. Can be used though for different tasks like
|
||||
|
@ -98,7 +98,7 @@ class Roster(PlugIn):
|
|||
if not pres.getTimestamp(): pres.setTimestamp()
|
||||
res['timestamp']=pres.getTimestamp()
|
||||
elif typ=='unavailable' and item['resources'].has_key(jid.getResource()): del item['resources'][jid.getResource()]
|
||||
# Need to handle type='error' also
|
||||
# Need to handle type='error' also
|
||||
|
||||
def _getItemData(self,jid,dataname):
|
||||
""" Return specific jid's representation in internal format. Used internally. """
|
||||
|
@ -159,9 +159,6 @@ class Roster(PlugIn):
|
|||
def getItems(self):
|
||||
""" Return list of all [bare] JIDs that the roster is currently tracks."""
|
||||
return self._data.keys()
|
||||
def getRaw(self):
|
||||
""" Returns internal representation of roster."""
|
||||
return self._data
|
||||
def keys(self):
|
||||
""" Same as getItems. Provided for the sake of dictionary interface."""
|
||||
return self._data.keys()
|
||||
|
@ -184,3 +181,6 @@ class Roster(PlugIn):
|
|||
""" Unauthorise JID 'jid'. Use for declining authorisation request
|
||||
or for removing existing authorization. """
|
||||
self._owner.send(Presence(jid,'unsubscribed'))
|
||||
def getRaw(self):
|
||||
"""Returns the internal data representation of the roster."""
|
||||
return self._data
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
|
||||
# $Id: simplexml.py,v 1.26 2005/04/10 08:21:35 snakeru Exp $
|
||||
# $Id: simplexml.py,v 1.27 2005/04/30 07:20:27 snakeru Exp $
|
||||
|
||||
"""Simplexml module provides xmpppy library with all needed tools to handle XML nodes and XML streams.
|
||||
I'm personally using it in many other separate projects. It is designed to be as standalone as possible."""
|
||||
|
@ -77,9 +77,9 @@ class Node:
|
|||
else: self.data.append(ustr(i))
|
||||
|
||||
def __str__(self,fancy=0):
|
||||
s = (fancy-1) * 2 * ' ' + "<" + self.name
|
||||
""" Method used to dump node into textual representation.
|
||||
if "fancy" argument is set to True produces indented output for readability."""
|
||||
s = (fancy-1) * 2 * ' ' + "<" + self.name
|
||||
if self.namespace:
|
||||
if not self.parent or self.parent.namespace!=self.namespace:
|
||||
s = s + ' xmlns="%s"'%self.namespace
|
||||
|
@ -249,7 +249,7 @@ class Node:
|
|||
raise AttributeError
|
||||
|
||||
class T:
|
||||
""" Auxiliary class used to quick acces to node's child nodes. """
|
||||
""" Auxiliary class used to quick access to node's child nodes. """
|
||||
def __init__(self,node): self.__dict__['node']=node
|
||||
def __getattr__(self,attr): return self.node.setTag(attr)
|
||||
def __setattr__(self,attr,val):
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
## GNU General Public License for more details.
|
||||
|
||||
# $Id: transports.py,v 1.15 2004/12/25 20:06:59 snakeru Exp $
|
||||
# $Id: transports.py,v 1.18 2005/04/30 08:56:36 snakeru Exp $
|
||||
|
||||
"""
|
||||
This module contains the low-level implementations of xmpppy connect methods or
|
||||
|
@ -42,6 +42,7 @@ class error:
|
|||
"""Serialise exception into pre-cached descriptive string."""
|
||||
return self._comment
|
||||
|
||||
BUFLEN=1024
|
||||
class TCPsocket(PlugIn):
|
||||
""" This class defines direct TCP connection method. """
|
||||
def __init__(self, server=None):
|
||||
|
@ -89,21 +90,27 @@ class TCPsocket(PlugIn):
|
|||
del self._owner.Connection
|
||||
|
||||
def receive(self):
|
||||
""" Reads all pending incoming data. Calls owner's disconnected() method if appropriate."""
|
||||
try: received = self._recv(1024)
|
||||
""" Reads all pending incoming data.
|
||||
In case of disconnection calls owner's disconnected() method and then raises IOError exception."""
|
||||
try: received = self._recv(BUFLEN)
|
||||
except socket.sslerror:
|
||||
self._seen_data=0
|
||||
return ''
|
||||
except: received = ''
|
||||
|
||||
while select.select([self._sock],[],[],0)[0]:
|
||||
try: add = self._recv(1024)
|
||||
while self.pending_data(0):
|
||||
try: add = self._recv(BUFLEN)
|
||||
except: add=''
|
||||
received +=add
|
||||
if not add: break
|
||||
|
||||
if len(received): # length of 0 means disconnect
|
||||
self._seen_data=1
|
||||
self.DEBUG(received,'got')
|
||||
else:
|
||||
self.DEBUG('Socket error while receiving data','error')
|
||||
self._owner.disconnected()
|
||||
raise IOError("Disconnected from server")
|
||||
return received
|
||||
|
||||
def send(self,raw_data):
|
||||
|
@ -167,18 +174,28 @@ class HTTPPROXYsocket(TCPsocket):
|
|||
connector.append('Proxy-Authorization: Basic '+credentials)
|
||||
connector.append('\r\n')
|
||||
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)
|
||||
except: raise error('Invalid proxy reply')
|
||||
if code<>'200':
|
||||
self.DEBUG('Invalid proxy reply: %s %s %s'%(proto,code,desc),'error')
|
||||
self._owner.disconnected()
|
||||
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')
|
||||
return 'ok'
|
||||
|
||||
def DEBUG(self,text,severity):
|
||||
"""Overwrites DEBUG tag to allow debug output be presented as "CONNECTproxy"."""
|
||||
return self._owner.DEBUG(DBG_CONNECT_PROXY,text,severity)
|
||||
|
||||
class TLS(PlugIn):
|
||||
|
@ -202,8 +219,8 @@ class TLS(PlugIn):
|
|||
""" Unregisters TLS handler's from owner's dispatcher. Take note that encription
|
||||
can not be stopped once started. You can only break the connection and start over."""
|
||||
self._owner.UnregisterHandler('features',self.FeaturesHandler,xmlns=NS_STREAMS)
|
||||
# self._owner.UnregisterHandler('proceed',self.StartTLSHandler,xmlns=NS_TLS)
|
||||
# self._owner.UnregisterHandler('failure',self.StartTLSHandler,xmlns=NS_TLS)
|
||||
self._owner.UnregisterHandlerOnce('proceed',self.StartTLSHandler,xmlns=NS_TLS)
|
||||
self._owner.UnregisterHandlerOnce('failure',self.StartTLSHandler,xmlns=NS_TLS)
|
||||
|
||||
def FeaturesHandler(self, conn, feats):
|
||||
""" Used to analyse server <features/> tag for TLS support.
|
||||
|
@ -217,14 +234,25 @@ class TLS(PlugIn):
|
|||
self._owner.Connection.send('<starttls xmlns="%s"/>'%NS_TLS)
|
||||
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):
|
||||
""" Immidiatedly switch socket to TLS mode. Used internally."""
|
||||
""" Here we should switch pending_data to hint mode."""
|
||||
tcpsock=self._owner.Connection
|
||||
tcpsock._sslObj = socket.ssl(tcpsock._sock, None, None)
|
||||
tcpsock._sslIssuer = tcpsock._sslObj.issuer()
|
||||
tcpsock._sslServer = tcpsock._sslObj.server()
|
||||
tcpsock._recv = tcpsock._sslObj.read
|
||||
tcpsock._send = tcpsock._sslObj.write
|
||||
|
||||
tcpsock._seen_data=1
|
||||
self._tcpsock=tcpsock
|
||||
tcpsock.pending_data=self.pending_data
|
||||
tcpsock._sock.setblocking(0)
|
||||
|
||||
self.starttls='success'
|
||||
|
||||
def StartTLSHandler(self, conn, starttls):
|
||||
|
|
Loading…
Reference in New Issue