diff --git a/common/jabber.py b/common/jabber.py index 03496e862..c77fac0f0 100644 --- a/common/jabber.py +++ b/common/jabber.py @@ -1,4 +1,4 @@ -## jabber.py +## jabber.py ## ## 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 # "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 - + # # JANA JEP namespaces, ordered by JEP # 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 - + Defined in jabberd/lib/lib.h, but not JANA aproved and not used in jabber.py so commented out, should/could propably be removed... - + NS_ADMIN = "jabber:iq:admin" NS_AUTH_OK = "jabber:iq:auth:0k" NS_CONFERENCE = "jabber:iq:conference" @@ -189,13 +189,13 @@ def ustr(what): return r 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): """Forms the base for both Client and Component Classes""" 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, debug=debug, log=log, connection=connection, @@ -207,11 +207,11 @@ class Connection(xmlstream.Client): self.registerProtocol('presence', Presence) self.registerHandler('iq',self._expectedIqHandler,system=True) - + self._expected = {} - + self._id = 0; - + self.lastErr = '' self.lastErrCode = 0 @@ -230,13 +230,13 @@ class Connection(xmlstream.Client): print "WARNING! setIqHandler(...) method is obsolette, use registerHandler('iq',...) instead." return self.registerHandler('iq', func, type, ns) - def header(self): + def header(self): self.DEBUG("stream: sending initial header",DBG_INIT) str = u" \ " self.send(str) 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(typ): typ='' if not self.handlers[name].has_key(typns): typns='' - if typ==typns: typns='' + if typ==typns: typns='' chain=[] 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): """Sets the callback func for processing incoming stanzas. Multiple callback functions can be set which are called in - succession. Callback can optionally raise an NodeProcessed error to - stop stanza from further processing. A type and namespace attributes can + succession. Callback can optionally raise an NodeProcessed error to + 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 - 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. 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 the operation times out (which only happens if a timeout value is 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 scripts and such. 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) else: self.DEBUG("waiting for %s" % ustr(ID),DBG_NODE_IQ) - + while (not self._expected[ID]) and not has_timed_out: if not self.process(0.2): return None if timeout and (time.time() > abort_time): @@ -405,17 +405,17 @@ class Connection(xmlstream.Client): """Returns a unique ID""" self._id = self._id + 1 return ustr(self._id) - + ############################################################################# class Client(Connection): """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.__init__(self, host, port, NS_CLIENT, debug, log, connection=connection, hostIP=hostIP, proxy=proxy) - + self.registerHandler('iq',self._IqRosterManage,'result',NS_ROSTER,system=True) self.registerHandler('iq',self._IqRosterManage,'set',NS_ROSTER,system=True) self.registerHandler('iq',self._IqRegisterResult,'result',NS_REGISTER,system=True) @@ -478,7 +478,7 @@ class Client(Connection): "NS_REGISTER and type==result" self._reg_info = {} 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): "NS_AGENTS and type==result" @@ -515,13 +515,13 @@ class Client(Connection): auth_set_iq = Iq(type='set') auth_set_iq.setID('auth-set') - + q = auth_set_iq.setQuery(NS_AUTH) q.insertTag('username').insertData(username) q.insertTag('resource').insertData(resource) if auth_ret_query.getTag('token'): - + token = auth_ret_query.getTag('token').getData() seq = auth_ret_query.getTag('sequence').getData() self.DEBUG("zero-k authentication supported",(DBG_INIT,DBG_NODE_IQ)) @@ -538,7 +538,7 @@ class Client(Connection): else: self.DEBUG("plain text authentication supported",(DBG_INIT,DBG_NODE_IQ)) q.insertTag('password').insertData(passwd) - + iq_result = self.SendAndWaitForResponse(auth_set_iq) if iq_result==None: @@ -592,7 +592,6 @@ class Client(Connection): if groups != None: for group in groups: item.insertTag('group').insertData(group) -# self.send(iq) 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:" % agent, DBG_NODE_IQ) self.DEBUG(ustr(reg_iq),DBG_NODE_IQ) - return self.SendAndWaitForResponse(reg_iq) + return self.SendAndWaitForResponse(reg_iq) def getRegInfo(self): @@ -656,14 +655,16 @@ class Client(Connection): Note that you must be authorised before attempting to deregister. """ if agent: - agent = agent + '.' - self.send(Presence(to=agent+self._host,type='unsubscribed')) # This is enough f.e. for icqv7t or jit +# 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,type='unsubscribed')) # This is enough f.e. for icqv7t or jit if agent is None: agent = '' q = self.requestRegInfo() kids = q.getQueryPayload() 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.setQueryNode("") q = iq.getQueryNode() @@ -766,7 +767,7 @@ class Protocol(xmlstream.Node): try: return JID(self.getAttr('to')) except: return None - + def getFrom(self): """Returns the 'from' attribute as a JID object.""" try: return JID(self.getAttr('from')) @@ -808,7 +809,7 @@ class Protocol(xmlstream.Node): def getX(self,index=0): """Returns the x namespace, optionally passed an index if there are multiple tags.""" - try: return self.getXNodes('x')[index].namespace + try: return self.getXNodes()[index].namespace except: return None @@ -829,10 +830,10 @@ class Protocol(xmlstream.Node): if type(payload) == type('') or type(payload) == type(u''): 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) - + def getXPayload(self, val=None): """Returns the x tags' payload as a list of Node instances.""" nodes = [] @@ -849,7 +850,7 @@ class Protocol(xmlstream.Node): nodes.append(xnode.kids[0]) return nodes - + def getXNode(self, val=None): """Returns the x Node instance. If there are multiple tags the first Node is returned. For multiple X nodes use getXNodes @@ -904,7 +905,7 @@ class Message(Protocol): except: return None - def getSubject(self): + def getSubject(self): """Returns the message's subject.""" try: return self.getTag('subject').getData() except: return None @@ -928,7 +929,7 @@ class Message(Protocol): else: body = self.insertTag('body').putData(val) - + def setSubject(self,val): """Sets the message subject text.""" subj = self.getTag('subject') @@ -959,7 +960,7 @@ class Message(Protocol): automatically set.""" m = Message(to=self.getFrom(), body=reply_txt) if not self.getType() == None: - m.setType(self.getType()) + m.setType(self.getType()) t = self.getThread() if t: m.setThread(t) return m @@ -993,7 +994,7 @@ class Presence(Protocol): """Returns the presence priority""" try: return self.getTag('priority').getData() except: return None - + def setShow(self,val): """Sets the presence show""" show = self.getTag('show') @@ -1014,7 +1015,7 @@ class Presence(Protocol): ############################################################################# -class Iq(Protocol): +class Iq(Protocol): """Class for creating and managing jabber protocol elements""" 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 = [] q.insertNode(payload) - + def getQueryPayload(self): """Returns the query's payload as a Node list""" q = self.getQueryNode() if q: return q.kids - + def getQueryNode(self): """Returns any textual data contained by the query tag""" try: return self.getTag('query') @@ -1141,7 +1142,7 @@ class Roster: def getStatus(self, jid): ## extended """Returns the 'status' value for a Roster item with the given jid.""" - jid = ustr(jid) + jid = ustr(jid) if self._data.has_key(jid): return self._data[jid]['status'] return None @@ -1149,7 +1150,7 @@ class Roster: def getShow(self, jid): ## extended """Returns the 'show' value for a Roster item with the given jid.""" - jid = ustr(jid) + jid = ustr(jid) if self._data.has_key(jid): return self._data[jid]['show'] return None @@ -1158,16 +1159,16 @@ class Roster: def getOnline(self,jid): ## extended """Returns the 'online' status for a Roster item with the given jid. """ - jid = ustr(jid) + jid = ustr(jid) if self._data.has_key(jid): return self._data[jid]['online'] return None - + def getSub(self,jid): """Returns the 'subscription' status for a Roster item with the given jid.""" - jid = ustr(jid) + jid = ustr(jid) if self._data.has_key(jid): return self._data[jid]['sub'] return None @@ -1175,7 +1176,7 @@ class Roster: def getName(self,jid): """Returns the 'name' for a Roster item with the given jid.""" - jid = ustr(jid) + jid = ustr(jid) if self._data.has_key(jid): return self._data[jid]['name'] return None @@ -1192,7 +1193,7 @@ class Roster: def getAsk(self,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): return self._data[jid]['ask'] return None @@ -1258,12 +1259,12 @@ class Roster: def _setOnline(self,jid,val): """Used internally - private""" - jid = ustr(jid) + jid = ustr(jid) if self._data.has_key(jid): self._data[jid]['online'] = val if self._listener != None: self._listener("update", jid, {'online' : val}) - else: ## fall back + else: ## fall back jid_basic = JID(jid).getStripped() if self._data.has_key(jid_basic): self._data[jid_basic]['online'] = val @@ -1273,12 +1274,12 @@ class Roster: def _setShow(self,jid,val): """Used internally - private""" - jid = ustr(jid) + jid = ustr(jid) if self._data.has_key(jid): - self._data[jid]['show'] = val + self._data[jid]['show'] = val if self._listener != None: self._listener("update", jid, {'show' : val}) - else: ## fall back + else: ## fall back jid_basic = JID(jid).getStripped() if self._data.has_key(jid_basic): self._data[jid_basic]['show'] = val @@ -1288,12 +1289,12 @@ class Roster: def _setStatus(self,jid,val): """Used internally - private""" - jid = ustr(jid) + jid = ustr(jid) if self._data.has_key(jid): self._data[jid]['status'] = val if self._listener != None: self._listener("update", jid, {'status' : val}) - else: ## fall back + else: ## fall back jid_basic = JID(jid).getStripped() if self._data.has_key(jid_basic): self._data[jid_basic]['status'] = val @@ -1320,12 +1321,12 @@ class JID: bits = jid.split('@', 1) self.node = bits[0] jid = bits[1] - + if jid.find('/') == -1: self.domain = jid self.resource = '' else: - self.domain, self.resource = jid.split('/', 1) + self.domain, self.resource = jid.split('/', 1) else: self.node = node self.domain = domain @@ -1342,7 +1343,7 @@ class JID: def getBasic(self): """Returns a jid string with no resource""" - return self.node + '@' + self.domain + return self.node + '@' + self.domain def getNode(self): """Returns JID Node as string""" @@ -1375,7 +1376,7 @@ class JID: 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 else: return self.domain @@ -1395,7 +1396,7 @@ class JID: class Component(Connection): """docs to come soon... """ 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, log=log, connection=connection, hostIP=hostIP, proxy=proxy) self._auth_OK = False @@ -1404,7 +1405,7 @@ class Component(Connection): def auth(self,secret): """will disconnect on failure""" - self.send( u"%s" + self.send( u"%s" % sha.new( self.getIncomingID() + secret ).hexdigest() ) while not self._auth_OK: @@ -1434,7 +1435,7 @@ class Log(Protocol): ## eg: Hello Log File 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) - + def setBody(self,val): "Sets the log message text." self.getTag('log').putData(val) diff --git a/common/xmlstream.py b/common/xmlstream.py index 9dc8cf76c..43646bec7 100644 --- a/common/xmlstream.py +++ b/common/xmlstream.py @@ -1,4 +1,4 @@ -## xmlstream.py +## xmlstream.py ## ## 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 from select import select @@ -37,7 +37,7 @@ import xml.parsers.expat import debug _debug=debug -VERSION = "0.5-rc1" +VERSION = "0.5" False = 0 True = 1 @@ -78,7 +78,7 @@ class error: self.value = str(value) def __str__(self): return self.value - + class Node: """A simple XML DOM like class""" def __init__(self, tag=None, parent=None, attrs={}, payload=[], node=None): @@ -93,7 +93,7 @@ class Node: 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(): self.attrs[attr]=attrs[attr] @@ -101,7 +101,7 @@ class Node: for i in payload: if type(i)==type(self): self.insertNode(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): "Set the nodes parent node." @@ -127,29 +127,29 @@ class Node: "Get a value for the nodes named attribute." try: return self.attrs[key] except: return None - + def putData(self, data): - "Set the nodes textual data" + "Set the nodes textual data" self.data.append(data) def insertData(self, data): - "Set the nodes textual data" + "Set the nodes textual data" self.data.append(data) def getData(self): - "Return the nodes textual data" + "Return the nodes textual data" return ''.join(self.data) def getDataAsParts(self): - "Return the node data as an array" + "Return the node data as an array" return self.data def getNamespace(self): - "Returns the nodes namespace." + "Returns the nodes namespace." return self.namespace def setNamespace(self, namespace): - "Set the nodes namespace." + "Set the nodes namespace." self.namespace = namespace def insertTag(self, name=None, attrs={}, payload=[], node=None): @@ -178,7 +178,7 @@ class Node: def _xmlnode2str(self, parent=None): """Returns an xml ( string ) representation of the node and it children""" - s = "<" + self.name + s = "<" + self.name if self.namespace: if parent and parent.namespace != self.namespace: s = s + " xmlns = '%s' " % self.namespace @@ -186,7 +186,7 @@ class Node: val = ustr(self.attrs[key]) s = s + " %s='%s'" % ( key, XMLescape(val) ) s = s + ">" - cnt = 0 + cnt = 0 if self.kids != None: for a in self.kids: if (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt]) @@ -199,12 +199,13 @@ class Node: s = s + "" return s - def getTag(self, name): + def getTag(self, name, index=None): """Returns a child node with tag name. Returns None if not found.""" for node in self.kids: if node.getName() == name: - return node + if not index: return node + if index is not None: index-=1 return None def getTags(self, name): @@ -214,7 +215,7 @@ class Node: if node.getName() == name: nodes.append(node) return nodes - + def getChildren(self): """Returns a nodes children""" return self.kids @@ -242,7 +243,7 @@ class NodeBuilder: self.__depth = 0 self._dispatch_depth = 1 - + if data: self._parser.Parse(data,1) def unknown_starttag(self, tag, attrs): @@ -293,8 +294,8 @@ class NodeBuilder: class Stream(NodeBuilder): - """Extention of NodeBuilder class. Handles stream of XML stanzas. - Calls dispatch method for every child of root node + """Extention of NodeBuilder class. Handles stream of XML stanzas. + Calls dispatch method for every child of root node (stream:stream for jabber stream). attributes _read, _write and _reader must be set by external entity """ @@ -371,7 +372,7 @@ class Stream(NodeBuilder): except: self.DEBUG("xmlstream write threw error",DBG_CONN_ERROR) self.disconnected(self) - + def process(self, timeout=0): """Receives incoming data (if any) and processes it. Waits for data no more than timeout seconds.""" @@ -379,7 +380,7 @@ class Stream(NodeBuilder): data = self.read() self._parser.Parse(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): """Close the stream and socket""" @@ -387,7 +388,7 @@ class Stream(NodeBuilder): while self.process(): pass self._sock.close() self._sock = None - + def disconnected(self,conn): """Called when a Network Error or disconnection occurs.""" try: self.disconnectHandler(conn) @@ -399,7 +400,7 @@ class Stream(NodeBuilder): raise error("Standart disconnectionHandler called. Replace it with appropriate for your client.") 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""" if self._logFH is not None: if self._timestampLog: @@ -431,7 +432,7 @@ class Client(Stream): Stream.__init__(self, namespace, debug, log, id) self._host = host - self._port = port + self._port = port self._sock = sock self._connection = connection if hostIP: self._hostIP = hostIP @@ -528,33 +529,33 @@ class Client(Stream): self.DEBUG('unknown connection type',DBG_CONN_ERROR) raise IOError('unknown connection type') -class Server: +class Server: def now(self): return time.ctime(time.time()) def __init__(self, maxclients=10): - self.host = '' + self.host = '' self.port = 5222 self.streams = [] - + # make main sockets for accepting new client requests self.mainsocks, self.readsocks, self.writesocks = [], [], [] self.portsock = socket(AF_INET, SOCK_STREAM) - self.portsock.bind((self.host, self.port)) - self.portsock.listen(maxclients) - + self.portsock.bind((self.host, self.port)) + self.portsock.listen(maxclients) + 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 def serve(self): - + print 'select-server loop starting' - + while 1: print "LOOPING" readables, writeables, exceptions = select(self.readsocks, @@ -562,7 +563,7 @@ class Server: for sockobj in readables: if sockobj in self. mainsocks: # for ready input sockets newsock, address = sockobj.accept() # accept not block - print 'Connect:', address, id(newsock) + print 'Connect:', address, id(newsock) self.readsocks.append(newsock) self._makeNewStream(newsock) # add to select list, wait @@ -571,9 +572,9 @@ class Server: data = sockobj.recv(1024) # recv should not block 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 - self.readsocks.remove(sockobj) + self.readsocks.remove(sockobj) else: # this may block: should really select for writes too sockobj.send('Echo=>%s' % data) @@ -592,7 +593,7 @@ class Server: for s in self.streams: socks.append(s.getSocket()) return socks - + def _getStreamFromSocket(self, sock): for s in self.streams: if s.getSocket() == sock: