Jabberpy V0.5

This commit is contained in:
Yann Leboulanger 2004-03-06 04:11:57 +00:00
parent cf2c7b5037
commit fa49d30545
2 changed files with 108 additions and 106 deletions

View File

@ -1,4 +1,4 @@
## jabber.py ## jabber.py
## ##
## Copyright (C) 2001 Matthew Allum ## Copyright (C) 2001 Matthew Allum
## ##
@ -86,7 +86,7 @@ DBG_NODE_UNKNOWN = 'jb-node-unknown' ; debug.debug_flags.append( DBG_NODE_UNK
# #
# JANA core namespaces # JANA core namespaces
# from http://www.jabber.org/jana/namespaces.php as of 2003-01-12 # from http://www.jabber.org/jana/namespaces.php as of 2003-01-12
# "myname" means that namespace didnt have a name in the jabberd headers # "myname" means that namespace didnt have a name in the jabberd headers
# #
@ -107,7 +107,7 @@ NS_COMP_ACCEPT = "jabber:component:accept" # myname
NS_COMP_CONNECT = "jabber:component:connect" # myname NS_COMP_CONNECT = "jabber:component:connect" # myname
# #
# JANA JEP namespaces, ordered by JEP # JANA JEP namespaces, ordered by JEP
# from http://www.jabber.org/jana/namespaces.php as of 2003-01-12 # from http://www.jabber.org/jana/namespaces.php as of 2003-01-12
@ -140,10 +140,10 @@ NS_P_COMMANDS = _NS_PROTOCOL + "/commands" # JEP-0050
""" """
2002-01-11 jaclu 2002-01-11 jaclu
Defined in jabberd/lib/lib.h, but not JANA aproved and not used in jabber.py Defined in jabberd/lib/lib.h, but not JANA aproved and not used in jabber.py
so commented out, should/could propably be removed... so commented out, should/could propably be removed...
NS_ADMIN = "jabber:iq:admin" NS_ADMIN = "jabber:iq:admin"
NS_AUTH_OK = "jabber:iq:auth:0k" NS_AUTH_OK = "jabber:iq:auth:0k"
NS_CONFERENCE = "jabber:iq:conference" NS_CONFERENCE = "jabber:iq:conference"
@ -189,13 +189,13 @@ def ustr(what):
return r return r
xmlstream.ustr = ustr xmlstream.ustr = ustr
class NodeProcessed(Exception): pass # currently only for Connection._expectedIqHandler class NodeProcessed(Exception): pass # currently only for Connection._expectedIqHandler
class Connection(xmlstream.Client): class Connection(xmlstream.Client):
"""Forms the base for both Client and Component Classes""" """Forms the base for both Client and Component Classes"""
def __init__(self, host, port, namespace, def __init__(self, host, port, namespace,
debug=False, log=False, connection=xmlstream.TCP, hostIP=None, proxy=None): debug=[], log=False, connection=xmlstream.TCP, hostIP=None, proxy=None):
xmlstream.Client.__init__(self, host, port, namespace, xmlstream.Client.__init__(self, host, port, namespace,
debug=debug, log=log, debug=debug, log=log,
connection=connection, connection=connection,
@ -207,11 +207,11 @@ class Connection(xmlstream.Client):
self.registerProtocol('presence', Presence) self.registerProtocol('presence', Presence)
self.registerHandler('iq',self._expectedIqHandler,system=True) self.registerHandler('iq',self._expectedIqHandler,system=True)
self._expected = {} self._expected = {}
self._id = 0; self._id = 0;
self.lastErr = '' self.lastErr = ''
self.lastErrCode = 0 self.lastErrCode = 0
@ -230,13 +230,13 @@ class Connection(xmlstream.Client):
print "WARNING! setIqHandler(...) method is obsolette, use registerHandler('iq',...) instead." print "WARNING! setIqHandler(...) method is obsolette, use registerHandler('iq',...) instead."
return self.registerHandler('iq', func, type, ns) return self.registerHandler('iq', func, type, ns)
def header(self): def header(self):
self.DEBUG("stream: sending initial header",DBG_INIT) self.DEBUG("stream: sending initial header",DBG_INIT)
str = u"<?xml version='1.0' encoding='UTF-8' ?> \ str = u"<?xml version='1.0' encoding='UTF-8' ?> \
<stream:stream to='%s' xmlns='%s'" % ( self._host, <stream:stream to='%s' xmlns='%s'" % ( self._host,
self._namespace ) self._namespace )
if self._outgoingID: str = str + " id='%s' " % self._outgoingID if self._outgoingID: str = str + " id='%s' " % self._outgoingID
str = str + " xmlns:stream='http://etherx.jabber.org/streams'>" str = str + " xmlns:stream='http://etherx.jabber.org/streams'>"
self.send(str) self.send(str)
self.process(timeout) self.process(timeout)
@ -276,7 +276,7 @@ class Connection(xmlstream.Client):
if not self.handlers[name].has_key(ns): ns='' if not self.handlers[name].has_key(ns): ns=''
if not self.handlers[name].has_key(typ): typ='' if not self.handlers[name].has_key(typ): typ=''
if not self.handlers[name].has_key(typns): typns='' if not self.handlers[name].has_key(typns): typns=''
if typ==typns: typns='' if typ==typns: typns=''
chain=[] chain=[]
for key in ['default',typ,ns,typns]: # we will use all handlers: from very common to very particular for key in ['default',typ,ns,typns]: # we will use all handlers: from very common to very particular
@ -307,10 +307,10 @@ class Connection(xmlstream.Client):
def registerHandler(self,name,handler,type='',ns='',chained=False, makefirst=False, system=False): def registerHandler(self,name,handler,type='',ns='',chained=False, makefirst=False, system=False):
"""Sets the callback func for processing incoming stanzas. """Sets the callback func for processing incoming stanzas.
Multiple callback functions can be set which are called in Multiple callback functions can be set which are called in
succession. Callback can optionally raise an NodeProcessed error to succession. Callback can optionally raise an NodeProcessed error to
stop stanza from further processing. A type and namespace attributes can stop stanza from further processing. A type and namespace attributes can
also be optionally passed so the callback is only called when a stanza of also be optionally passed so the callback is only called when a stanza of
this type is received. Namespace attribute MUST be omitted if you this type is received. Namespace attribute MUST be omitted if you
registering an Iq processing handler. registering an Iq processing handler.
If 'chainOutput' is set to False (the default), the given function If 'chainOutput' is set to False (the default), the given function
@ -359,7 +359,7 @@ class Connection(xmlstream.Client):
self.lastErr and self.lastErrCode is set to the received error. If self.lastErr and self.lastErrCode is set to the received error. If
the operation times out (which only happens if a timeout value is the operation times out (which only happens if a timeout value is
given), waitForResponse will return None and self.lastErr will be given), waitForResponse will return None and self.lastErr will be
set to "Timeout". set to "Timeout".
Changed default from timeout=0 to timeout=300 to avoid hangs in Changed default from timeout=0 to timeout=300 to avoid hangs in
scripts and such. scripts and such.
If you _really_ want no timeout, just set it to 0""" If you _really_ want no timeout, just set it to 0"""
@ -372,7 +372,7 @@ class Connection(xmlstream.Client):
self.DEBUG("waiting with timeout:%s for %s" % (timeout,ustr(ID)),DBG_NODE_IQ) self.DEBUG("waiting with timeout:%s for %s" % (timeout,ustr(ID)),DBG_NODE_IQ)
else: else:
self.DEBUG("waiting for %s" % ustr(ID),DBG_NODE_IQ) self.DEBUG("waiting for %s" % ustr(ID),DBG_NODE_IQ)
while (not self._expected[ID]) and not has_timed_out: while (not self._expected[ID]) and not has_timed_out:
if not self.process(0.2): return None if not self.process(0.2): return None
if timeout and (time.time() > abort_time): if timeout and (time.time() > abort_time):
@ -405,17 +405,17 @@ class Connection(xmlstream.Client):
"""Returns a unique ID""" """Returns a unique ID"""
self._id = self._id + 1 self._id = self._id + 1
return ustr(self._id) return ustr(self._id)
############################################################################# #############################################################################
class Client(Connection): class Client(Connection):
"""Class for managing a client connection to a jabber server.""" """Class for managing a client connection to a jabber server."""
def __init__(self, host, port=5222, debug=False, log=False, def __init__(self, host, port=5222, debug=[], log=False,
connection=xmlstream.TCP, hostIP=None, proxy=None): connection=xmlstream.TCP, hostIP=None, proxy=None):
Connection.__init__(self, host, port, NS_CLIENT, debug, log, Connection.__init__(self, host, port, NS_CLIENT, debug, log,
connection=connection, hostIP=hostIP, proxy=proxy) connection=connection, hostIP=hostIP, proxy=proxy)
self.registerHandler('iq',self._IqRosterManage,'result',NS_ROSTER,system=True) self.registerHandler('iq',self._IqRosterManage,'result',NS_ROSTER,system=True)
self.registerHandler('iq',self._IqRosterManage,'set',NS_ROSTER,system=True) self.registerHandler('iq',self._IqRosterManage,'set',NS_ROSTER,system=True)
self.registerHandler('iq',self._IqRegisterResult,'result',NS_REGISTER,system=True) self.registerHandler('iq',self._IqRegisterResult,'result',NS_REGISTER,system=True)
@ -478,7 +478,7 @@ class Client(Connection):
"NS_REGISTER and type==result" "NS_REGISTER and type==result"
self._reg_info = {} self._reg_info = {}
for item in iq_obj.getQueryNode().getChildren(): for item in iq_obj.getQueryNode().getChildren():
self._reg_info[item.getName()] = item.getData() self._reg_info[item.getName()] = item.getData()
def _IqAgentsResult(self, conn, iq_obj): def _IqAgentsResult(self, conn, iq_obj):
"NS_AGENTS and type==result" "NS_AGENTS and type==result"
@ -515,13 +515,13 @@ class Client(Connection):
auth_set_iq = Iq(type='set') auth_set_iq = Iq(type='set')
auth_set_iq.setID('auth-set') auth_set_iq.setID('auth-set')
q = auth_set_iq.setQuery(NS_AUTH) q = auth_set_iq.setQuery(NS_AUTH)
q.insertTag('username').insertData(username) q.insertTag('username').insertData(username)
q.insertTag('resource').insertData(resource) q.insertTag('resource').insertData(resource)
if auth_ret_query.getTag('token'): if auth_ret_query.getTag('token'):
token = auth_ret_query.getTag('token').getData() token = auth_ret_query.getTag('token').getData()
seq = auth_ret_query.getTag('sequence').getData() seq = auth_ret_query.getTag('sequence').getData()
self.DEBUG("zero-k authentication supported",(DBG_INIT,DBG_NODE_IQ)) self.DEBUG("zero-k authentication supported",(DBG_INIT,DBG_NODE_IQ))
@ -538,7 +538,7 @@ class Client(Connection):
else: else:
self.DEBUG("plain text authentication supported",(DBG_INIT,DBG_NODE_IQ)) self.DEBUG("plain text authentication supported",(DBG_INIT,DBG_NODE_IQ))
q.insertTag('password').insertData(passwd) q.insertTag('password').insertData(passwd)
iq_result = self.SendAndWaitForResponse(auth_set_iq) iq_result = self.SendAndWaitForResponse(auth_set_iq)
if iq_result==None: if iq_result==None:
@ -592,7 +592,6 @@ class Client(Connection):
if groups != None: if groups != None:
for group in groups: for group in groups:
item.insertTag('group').insertData(group) item.insertTag('group').insertData(group)
# self.send(iq)
dummy = self.SendAndWaitForResponse(iq) # Do we need to wait?? dummy = self.SendAndWaitForResponse(iq) # Do we need to wait??
@ -620,7 +619,7 @@ class Client(Connection):
# self.DEBUG("Requesting reg info from %s%s:" % (agent, self._host), DBG_NODE_IQ) # self.DEBUG("Requesting reg info from %s%s:" % (agent, self._host), DBG_NODE_IQ)
self.DEBUG("Requesting reg info from %s:" % agent, DBG_NODE_IQ) self.DEBUG("Requesting reg info from %s:" % agent, DBG_NODE_IQ)
self.DEBUG(ustr(reg_iq),DBG_NODE_IQ) self.DEBUG(ustr(reg_iq),DBG_NODE_IQ)
return self.SendAndWaitForResponse(reg_iq) return self.SendAndWaitForResponse(reg_iq)
def getRegInfo(self): def getRegInfo(self):
@ -656,14 +655,16 @@ class Client(Connection):
Note that you must be authorised before attempting to deregister. Note that you must be authorised before attempting to deregister.
""" """
if agent: if agent:
agent = agent + '.' # agent = agent + '.'
self.send(Presence(to=agent+self._host,type='unsubscribed')) # This is enough f.e. for icqv7t or jit # self.send(Presence(to=agent+self._host,type='unsubscribed')) # This is enough f.e. for icqv7t or jit
self.send(Presence(to=agent,type='unsubscribed')) # This is enough f.e. for icqv7t or jit
if agent is None: agent = '' if agent is None: agent = ''
q = self.requestRegInfo() q = self.requestRegInfo()
kids = q.getQueryPayload() kids = q.getQueryPayload()
keyTag = kids.getTag("key") keyTag = kids.getTag("key")
iq = Iq(to=agent+self._host, type="set") # iq = Iq(to=agent+self._host, type="set")
iq = Iq(to=agent, type="set")
iq.setQuery(NS_REGISTER) iq.setQuery(NS_REGISTER)
iq.setQueryNode("") iq.setQueryNode("")
q = iq.getQueryNode() q = iq.getQueryNode()
@ -766,7 +767,7 @@ class Protocol(xmlstream.Node):
try: return JID(self.getAttr('to')) try: return JID(self.getAttr('to'))
except: return None except: return None
def getFrom(self): def getFrom(self):
"""Returns the 'from' attribute as a JID object.""" """Returns the 'from' attribute as a JID object."""
try: return JID(self.getAttr('from')) try: return JID(self.getAttr('from'))
@ -808,7 +809,7 @@ class Protocol(xmlstream.Node):
def getX(self,index=0): def getX(self,index=0):
"""Returns the x namespace, optionally passed an index if there are """Returns the x namespace, optionally passed an index if there are
multiple tags.""" multiple tags."""
try: return self.getXNodes('x')[index].namespace try: return self.getXNodes()[index].namespace
except: return None except: return None
@ -829,10 +830,10 @@ class Protocol(xmlstream.Node):
if type(payload) == type('') or type(payload) == type(u''): if type(payload) == type('') or type(payload) == type(u''):
payload = xmlstream.NodeBuilder(payload).getDom() payload = xmlstream.NodeBuilder(payload).getDom()
x.kids = [] # should be a method for this realy x.kids = [] # should be a method for this realy
x.insertNode(payload) x.insertNode(payload)
def getXPayload(self, val=None): def getXPayload(self, val=None):
"""Returns the x tags' payload as a list of Node instances.""" """Returns the x tags' payload as a list of Node instances."""
nodes = [] nodes = []
@ -849,7 +850,7 @@ class Protocol(xmlstream.Node):
nodes.append(xnode.kids[0]) nodes.append(xnode.kids[0])
return nodes return nodes
def getXNode(self, val=None): def getXNode(self, val=None):
"""Returns the x Node instance. If there are multiple tags """Returns the x Node instance. If there are multiple tags
the first Node is returned. For multiple X nodes use getXNodes the first Node is returned. For multiple X nodes use getXNodes
@ -904,7 +905,7 @@ class Message(Protocol):
except: return None except: return None
def getSubject(self): def getSubject(self):
"""Returns the message's subject.""" """Returns the message's subject."""
try: return self.getTag('subject').getData() try: return self.getTag('subject').getData()
except: return None except: return None
@ -928,7 +929,7 @@ class Message(Protocol):
else: else:
body = self.insertTag('body').putData(val) body = self.insertTag('body').putData(val)
def setSubject(self,val): def setSubject(self,val):
"""Sets the message subject text.""" """Sets the message subject text."""
subj = self.getTag('subject') subj = self.getTag('subject')
@ -959,7 +960,7 @@ class Message(Protocol):
automatically set.""" automatically set."""
m = Message(to=self.getFrom(), body=reply_txt) m = Message(to=self.getFrom(), body=reply_txt)
if not self.getType() == None: if not self.getType() == None:
m.setType(self.getType()) m.setType(self.getType())
t = self.getThread() t = self.getThread()
if t: m.setThread(t) if t: m.setThread(t)
return m return m
@ -993,7 +994,7 @@ class Presence(Protocol):
"""Returns the presence priority""" """Returns the presence priority"""
try: return self.getTag('priority').getData() try: return self.getTag('priority').getData()
except: return None except: return None
def setShow(self,val): def setShow(self,val):
"""Sets the presence show""" """Sets the presence show"""
show = self.getTag('show') show = self.getTag('show')
@ -1014,7 +1015,7 @@ class Presence(Protocol):
############################################################################# #############################################################################
class Iq(Protocol): class Iq(Protocol):
"""Class for creating and managing jabber <iq> protocol """Class for creating and managing jabber <iq> protocol
elements""" elements"""
def __init__(self, to=None, type=None, query=None, attrs=None, frm=None, payload=[], node=None): def __init__(self, to=None, type=None, query=None, attrs=None, frm=None, payload=[], node=None):
@ -1069,12 +1070,12 @@ class Iq(Protocol):
if not add: q.kids = [] if not add: q.kids = []
q.insertNode(payload) q.insertNode(payload)
def getQueryPayload(self): def getQueryPayload(self):
"""Returns the query's payload as a Node list""" """Returns the query's payload as a Node list"""
q = self.getQueryNode() q = self.getQueryNode()
if q: return q.kids if q: return q.kids
def getQueryNode(self): def getQueryNode(self):
"""Returns any textual data contained by the query tag""" """Returns any textual data contained by the query tag"""
try: return self.getTag('query') try: return self.getTag('query')
@ -1141,7 +1142,7 @@ class Roster:
def getStatus(self, jid): ## extended def getStatus(self, jid): ## extended
"""Returns the 'status' value for a Roster item with the given jid.""" """Returns the 'status' value for a Roster item with the given jid."""
jid = ustr(jid) jid = ustr(jid)
if self._data.has_key(jid): if self._data.has_key(jid):
return self._data[jid]['status'] return self._data[jid]['status']
return None return None
@ -1149,7 +1150,7 @@ class Roster:
def getShow(self, jid): ## extended def getShow(self, jid): ## extended
"""Returns the 'show' value for a Roster item with the given jid.""" """Returns the 'show' value for a Roster item with the given jid."""
jid = ustr(jid) jid = ustr(jid)
if self._data.has_key(jid): if self._data.has_key(jid):
return self._data[jid]['show'] return self._data[jid]['show']
return None return None
@ -1158,16 +1159,16 @@ class Roster:
def getOnline(self,jid): ## extended def getOnline(self,jid): ## extended
"""Returns the 'online' status for a Roster item with the given jid. """Returns the 'online' status for a Roster item with the given jid.
""" """
jid = ustr(jid) jid = ustr(jid)
if self._data.has_key(jid): if self._data.has_key(jid):
return self._data[jid]['online'] return self._data[jid]['online']
return None return None
def getSub(self,jid): def getSub(self,jid):
"""Returns the 'subscription' status for a Roster item with the given """Returns the 'subscription' status for a Roster item with the given
jid.""" jid."""
jid = ustr(jid) jid = ustr(jid)
if self._data.has_key(jid): if self._data.has_key(jid):
return self._data[jid]['sub'] return self._data[jid]['sub']
return None return None
@ -1175,7 +1176,7 @@ class Roster:
def getName(self,jid): def getName(self,jid):
"""Returns the 'name' for a Roster item with the given jid.""" """Returns the 'name' for a Roster item with the given jid."""
jid = ustr(jid) jid = ustr(jid)
if self._data.has_key(jid): if self._data.has_key(jid):
return self._data[jid]['name'] return self._data[jid]['name']
return None return None
@ -1192,7 +1193,7 @@ class Roster:
def getAsk(self,jid): def getAsk(self,jid):
"""Returns the 'ask' status for a Roster item with the given jid.""" """Returns the 'ask' status for a Roster item with the given jid."""
jid = ustr(jid) jid = ustr(jid)
if self._data.has_key(jid): if self._data.has_key(jid):
return self._data[jid]['ask'] return self._data[jid]['ask']
return None return None
@ -1258,12 +1259,12 @@ class Roster:
def _setOnline(self,jid,val): def _setOnline(self,jid,val):
"""Used internally - private""" """Used internally - private"""
jid = ustr(jid) jid = ustr(jid)
if self._data.has_key(jid): if self._data.has_key(jid):
self._data[jid]['online'] = val self._data[jid]['online'] = val
if self._listener != None: if self._listener != None:
self._listener("update", jid, {'online' : val}) self._listener("update", jid, {'online' : val})
else: ## fall back else: ## fall back
jid_basic = JID(jid).getStripped() jid_basic = JID(jid).getStripped()
if self._data.has_key(jid_basic): if self._data.has_key(jid_basic):
self._data[jid_basic]['online'] = val self._data[jid_basic]['online'] = val
@ -1273,12 +1274,12 @@ class Roster:
def _setShow(self,jid,val): def _setShow(self,jid,val):
"""Used internally - private""" """Used internally - private"""
jid = ustr(jid) jid = ustr(jid)
if self._data.has_key(jid): if self._data.has_key(jid):
self._data[jid]['show'] = val self._data[jid]['show'] = val
if self._listener != None: if self._listener != None:
self._listener("update", jid, {'show' : val}) self._listener("update", jid, {'show' : val})
else: ## fall back else: ## fall back
jid_basic = JID(jid).getStripped() jid_basic = JID(jid).getStripped()
if self._data.has_key(jid_basic): if self._data.has_key(jid_basic):
self._data[jid_basic]['show'] = val self._data[jid_basic]['show'] = val
@ -1288,12 +1289,12 @@ class Roster:
def _setStatus(self,jid,val): def _setStatus(self,jid,val):
"""Used internally - private""" """Used internally - private"""
jid = ustr(jid) jid = ustr(jid)
if self._data.has_key(jid): if self._data.has_key(jid):
self._data[jid]['status'] = val self._data[jid]['status'] = val
if self._listener != None: if self._listener != None:
self._listener("update", jid, {'status' : val}) self._listener("update", jid, {'status' : val})
else: ## fall back else: ## fall back
jid_basic = JID(jid).getStripped() jid_basic = JID(jid).getStripped()
if self._data.has_key(jid_basic): if self._data.has_key(jid_basic):
self._data[jid_basic]['status'] = val self._data[jid_basic]['status'] = val
@ -1320,12 +1321,12 @@ class JID:
bits = jid.split('@', 1) bits = jid.split('@', 1)
self.node = bits[0] self.node = bits[0]
jid = bits[1] jid = bits[1]
if jid.find('/') == -1: if jid.find('/') == -1:
self.domain = jid self.domain = jid
self.resource = '' self.resource = ''
else: else:
self.domain, self.resource = jid.split('/', 1) self.domain, self.resource = jid.split('/', 1)
else: else:
self.node = node self.node = node
self.domain = domain self.domain = domain
@ -1342,7 +1343,7 @@ class JID:
def getBasic(self): def getBasic(self):
"""Returns a jid string with no resource""" """Returns a jid string with no resource"""
return self.node + '@' + self.domain return self.node + '@' + self.domain
def getNode(self): def getNode(self):
"""Returns JID Node as string""" """Returns JID Node as string"""
@ -1375,7 +1376,7 @@ class JID:
def getStripped(self): def getStripped(self):
"""Returns a JID string with no resource""" """Returns a JID string with no resource"""
if self.node: return self.node + '@' + self.domain if self.node: return self.node + '@' + self.domain
else: return self.domain else: return self.domain
@ -1395,7 +1396,7 @@ class JID:
class Component(Connection): class Component(Connection):
"""docs to come soon... """ """docs to come soon... """
def __init__(self, host, port, connection=xmlstream.TCP, def __init__(self, host, port, connection=xmlstream.TCP,
debug=False, log=False, ns=NS_COMP_ACCEPT, hostIP=None, proxy=None): debug=[], log=False, ns=NS_COMP_ACCEPT, hostIP=None, proxy=None):
Connection.__init__(self, host, port, namespace=ns, debug=debug, Connection.__init__(self, host, port, namespace=ns, debug=debug,
log=log, connection=connection, hostIP=hostIP, proxy=proxy) log=log, connection=connection, hostIP=hostIP, proxy=proxy)
self._auth_OK = False self._auth_OK = False
@ -1404,7 +1405,7 @@ class Component(Connection):
def auth(self,secret): def auth(self,secret):
"""will disconnect on failure""" """will disconnect on failure"""
self.send( u"<handshake id='1'>%s</handshake>" self.send( u"<handshake id='1'>%s</handshake>"
% sha.new( self.getIncomingID() + secret ).hexdigest() % sha.new( self.getIncomingID() + secret ).hexdigest()
) )
while not self._auth_OK: while not self._auth_OK:
@ -1434,7 +1435,7 @@ class Log(Protocol):
## eg: <log type='warn' from='component'>Hello Log File</log> ## eg: <log type='warn' from='component'>Hello Log File</log>
def __init__(self, attrs=None, type=None, frm=None, to=None, payload=[], node=None): def __init__(self, attrs=None, type=None, frm=None, to=None, payload=[], node=None):
Protocol.__init__(self, 'log', attrs=attrs, type=type, frm=frm, to=to, payload=payload, node=node) Protocol.__init__(self, 'log', attrs=attrs, type=type, frm=frm, to=to, payload=payload, node=node)
def setBody(self,val): def setBody(self,val):
"Sets the log message text." "Sets the log message text."
self.getTag('log').putData(val) self.getTag('log').putData(val)

View File

@ -1,4 +1,4 @@
## xmlstream.py ## xmlstream.py
## ##
## Copyright (C) 2001 Matthew Allum ## Copyright (C) 2001 Matthew Allum
## ##
@ -28,7 +28,7 @@ case.
""" """
# $Id: xmlstream.py,v 1.42 2004/01/08 15:47:40 snakeru Exp $ # $Id$
import time, sys, re, socket import time, sys, re, socket
from select import select from select import select
@ -37,7 +37,7 @@ import xml.parsers.expat
import debug import debug
_debug=debug _debug=debug
VERSION = "0.5-rc1" VERSION = "0.5"
False = 0 False = 0
True = 1 True = 1
@ -78,7 +78,7 @@ class error:
self.value = str(value) self.value = str(value)
def __str__(self): def __str__(self):
return self.value return self.value
class Node: class Node:
"""A simple XML DOM like class""" """A simple XML DOM like class"""
def __init__(self, tag=None, parent=None, attrs={}, payload=[], node=None): def __init__(self, tag=None, parent=None, attrs={}, payload=[], node=None):
@ -93,7 +93,7 @@ class Node:
if parent: self.parent = parent if parent: self.parent = parent
# if self.parent and not self.namespace: self.namespace=self.parent.namespace # Doesn't checked if this neccessary # if self.parent and not self.namespace: self.namespace=self.parent.namespace # Doesn't checked if this neccessary
for attr in attrs.keys(): for attr in attrs.keys():
self.attrs[attr]=attrs[attr] self.attrs[attr]=attrs[attr]
@ -101,7 +101,7 @@ class Node:
for i in payload: for i in payload:
if type(i)==type(self): self.insertNode(i) if type(i)==type(self): self.insertNode(i)
else: self.insertXML(i) else: self.insertXML(i)
# self.insertNode(Node(node=i)) # Alternative way. Needs perfomance testing. # self.insertNode(Node(node=i)) # Alternative way. Needs perfomance testing.
def setParent(self, node): def setParent(self, node):
"Set the nodes parent node." "Set the nodes parent node."
@ -127,29 +127,29 @@ class Node:
"Get a value for the nodes named attribute." "Get a value for the nodes named attribute."
try: return self.attrs[key] try: return self.attrs[key]
except: return None except: return None
def putData(self, data): def putData(self, data):
"Set the nodes textual data" "Set the nodes textual data"
self.data.append(data) self.data.append(data)
def insertData(self, data): def insertData(self, data):
"Set the nodes textual data" "Set the nodes textual data"
self.data.append(data) self.data.append(data)
def getData(self): def getData(self):
"Return the nodes textual data" "Return the nodes textual data"
return ''.join(self.data) return ''.join(self.data)
def getDataAsParts(self): def getDataAsParts(self):
"Return the node data as an array" "Return the node data as an array"
return self.data return self.data
def getNamespace(self): def getNamespace(self):
"Returns the nodes namespace." "Returns the nodes namespace."
return self.namespace return self.namespace
def setNamespace(self, namespace): def setNamespace(self, namespace):
"Set the nodes namespace." "Set the nodes namespace."
self.namespace = namespace self.namespace = namespace
def insertTag(self, name=None, attrs={}, payload=[], node=None): def insertTag(self, name=None, attrs={}, payload=[], node=None):
@ -178,7 +178,7 @@ class Node:
def _xmlnode2str(self, parent=None): def _xmlnode2str(self, parent=None):
"""Returns an xml ( string ) representation of the node """Returns an xml ( string ) representation of the node
and it children""" and it children"""
s = "<" + self.name s = "<" + self.name
if self.namespace: if self.namespace:
if parent and parent.namespace != self.namespace: if parent and parent.namespace != self.namespace:
s = s + " xmlns = '%s' " % self.namespace s = s + " xmlns = '%s' " % self.namespace
@ -186,7 +186,7 @@ class Node:
val = ustr(self.attrs[key]) val = ustr(self.attrs[key])
s = s + " %s='%s'" % ( key, XMLescape(val) ) s = s + " %s='%s'" % ( key, XMLescape(val) )
s = s + ">" s = s + ">"
cnt = 0 cnt = 0
if self.kids != None: if self.kids != None:
for a in self.kids: for a in self.kids:
if (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt]) if (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt])
@ -199,12 +199,13 @@ class Node:
s = s + "</" + self.name + ">" s = s + "</" + self.name + ">"
return s return s
def getTag(self, name): def getTag(self, name, index=None):
"""Returns a child node with tag name. Returns None """Returns a child node with tag name. Returns None
if not found.""" if not found."""
for node in self.kids: for node in self.kids:
if node.getName() == name: if node.getName() == name:
return node if not index: return node
if index is not None: index-=1
return None return None
def getTags(self, name): def getTags(self, name):
@ -214,7 +215,7 @@ class Node:
if node.getName() == name: if node.getName() == name:
nodes.append(node) nodes.append(node)
return nodes return nodes
def getChildren(self): def getChildren(self):
"""Returns a nodes children""" """Returns a nodes children"""
return self.kids return self.kids
@ -242,7 +243,7 @@ class NodeBuilder:
self.__depth = 0 self.__depth = 0
self._dispatch_depth = 1 self._dispatch_depth = 1
if data: self._parser.Parse(data,1) if data: self._parser.Parse(data,1)
def unknown_starttag(self, tag, attrs): def unknown_starttag(self, tag, attrs):
@ -293,8 +294,8 @@ class NodeBuilder:
class Stream(NodeBuilder): class Stream(NodeBuilder):
"""Extention of NodeBuilder class. Handles stream of XML stanzas. """Extention of NodeBuilder class. Handles stream of XML stanzas.
Calls dispatch method for every child of root node Calls dispatch method for every child of root node
(stream:stream for jabber stream). (stream:stream for jabber stream).
attributes _read, _write and _reader must be set by external entity attributes _read, _write and _reader must be set by external entity
""" """
@ -371,7 +372,7 @@ class Stream(NodeBuilder):
except: except:
self.DEBUG("xmlstream write threw error",DBG_CONN_ERROR) self.DEBUG("xmlstream write threw error",DBG_CONN_ERROR)
self.disconnected(self) self.disconnected(self)
def process(self, timeout=0): def process(self, timeout=0):
"""Receives incoming data (if any) and processes it. """Receives incoming data (if any) and processes it.
Waits for data no more than timeout seconds.""" Waits for data no more than timeout seconds."""
@ -379,7 +380,7 @@ class Stream(NodeBuilder):
data = self.read() data = self.read()
self._parser.Parse(data) self._parser.Parse(data)
return len(data) return len(data)
return '0' # Zero means that nothing received but link is alive. return '0' # Zero means that nothing received but link is alive.
def disconnect(self): def disconnect(self):
"""Close the stream and socket""" """Close the stream and socket"""
@ -387,7 +388,7 @@ class Stream(NodeBuilder):
while self.process(): pass while self.process(): pass
self._sock.close() self._sock.close()
self._sock = None self._sock = None
def disconnected(self,conn): def disconnected(self,conn):
"""Called when a Network Error or disconnection occurs.""" """Called when a Network Error or disconnection occurs."""
try: self.disconnectHandler(conn) try: self.disconnectHandler(conn)
@ -399,7 +400,7 @@ class Stream(NodeBuilder):
raise error("Standart disconnectionHandler called. Replace it with appropriate for your client.") raise error("Standart disconnectionHandler called. Replace it with appropriate for your client.")
def log(self, data, inout=''): def log(self, data, inout=''):
"""Logs data to the specified filehandle. Data is time stamped """Logs data to the specified filehandle. Data is time stamped
and prefixed with inout""" and prefixed with inout"""
if self._logFH is not None: if self._logFH is not None:
if self._timestampLog: if self._timestampLog:
@ -431,7 +432,7 @@ class Client(Stream):
Stream.__init__(self, namespace, debug, log, id) Stream.__init__(self, namespace, debug, log, id)
self._host = host self._host = host
self._port = port self._port = port
self._sock = sock self._sock = sock
self._connection = connection self._connection = connection
if hostIP: self._hostIP = hostIP if hostIP: self._hostIP = hostIP
@ -528,33 +529,33 @@ class Client(Stream):
self.DEBUG('unknown connection type',DBG_CONN_ERROR) self.DEBUG('unknown connection type',DBG_CONN_ERROR)
raise IOError('unknown connection type') raise IOError('unknown connection type')
class Server: class Server:
def now(self): return time.ctime(time.time()) def now(self): return time.ctime(time.time())
def __init__(self, maxclients=10): def __init__(self, maxclients=10):
self.host = '' self.host = ''
self.port = 5222 self.port = 5222
self.streams = [] self.streams = []
# make main sockets for accepting new client requests # make main sockets for accepting new client requests
self.mainsocks, self.readsocks, self.writesocks = [], [], [] self.mainsocks, self.readsocks, self.writesocks = [], [], []
self.portsock = socket(AF_INET, SOCK_STREAM) self.portsock = socket(AF_INET, SOCK_STREAM)
self.portsock.bind((self.host, self.port)) self.portsock.bind((self.host, self.port))
self.portsock.listen(maxclients) self.portsock.listen(maxclients)
self.mainsocks.append(self.portsock) # add to main list to identify self.mainsocks.append(self.portsock) # add to main list to identify
self.readsocks.append(self.portsock) # add to select inputs list self.readsocks.append(self.portsock) # add to select inputs list
# event loop: listen and multiplex until server process killed # event loop: listen and multiplex until server process killed
def serve(self): def serve(self):
print 'select-server loop starting' print 'select-server loop starting'
while 1: while 1:
print "LOOPING" print "LOOPING"
readables, writeables, exceptions = select(self.readsocks, readables, writeables, exceptions = select(self.readsocks,
@ -562,7 +563,7 @@ class Server:
for sockobj in readables: for sockobj in readables:
if sockobj in self. mainsocks: # for ready input sockets if sockobj in self. mainsocks: # for ready input sockets
newsock, address = sockobj.accept() # accept not block newsock, address = sockobj.accept() # accept not block
print 'Connect:', address, id(newsock) print 'Connect:', address, id(newsock)
self.readsocks.append(newsock) self.readsocks.append(newsock)
self._makeNewStream(newsock) self._makeNewStream(newsock)
# add to select list, wait # add to select list, wait
@ -571,9 +572,9 @@ class Server:
data = sockobj.recv(1024) data = sockobj.recv(1024)
# recv should not block # recv should not block
print '\tgot', data, 'on', id(sockobj) print '\tgot', data, 'on', id(sockobj)
if not data: # if closed by the clients if not data: # if closed by the clients
sockobj.close() # close here and remv from sockobj.close() # close here and remv from
self.readsocks.remove(sockobj) self.readsocks.remove(sockobj)
else: else:
# this may block: should really select for writes too # this may block: should really select for writes too
sockobj.send('Echo=>%s' % data) sockobj.send('Echo=>%s' % data)
@ -592,7 +593,7 @@ class Server:
for s in self.streams: for s in self.streams:
socks.append(s.getSocket()) socks.append(s.getSocket())
return socks return socks
def _getStreamFromSocket(self, sock): def _getStreamFromSocket(self, sock):
for s in self.streams: for s in self.streams:
if s.getSocket() == sock: if s.getSocket() == sock: