Go to most recent revision | Compare with Previous | Blame | View Log
--- jabberpy0.4-0/jabber.py Thu Feb 20 02:22:33 2003+++ jabberpy0.4-0-patched/jabber.py Wed Apr 2 23:49:00 2003@@ -62,7 +62,7 @@"""-# $Id: jabber.py,v 1.30 2003/02/20 10:22:33 shire Exp $+# $Id: jabber.py,v 1.3 2003/04/03 07:49:00 andy Exp $import xmlstreamimport sha, time@@ -73,84 +73,37 @@False = 0;True = 1;-USTR_ENCODING='iso-8859-1'---#-# 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-#-NS_AGENT = "jabber:iq:agent"-NS_AGENTS = "jabber:iq:agents"-NS_AUTH = "jabber:iq:auth"NS_CLIENT = "jabber:client"-NS_DELAY = "jabber:x:delay"-NS_OOB = "jabber:iq:oob"+NS_SERVER = "jabber:server"+NS_AUTH = "jabber:iq:auth"NS_REGISTER = "jabber:iq:register"NS_ROSTER = "jabber:iq:roster"-NS_XROSTER = "jabber:x:roster" # myname-NS_SERVER = "jabber:server"-NS_TIME = "jabber:iq:time"+NS_OFFLINE = "jabber:x:offline"+NS_AGENT = "jabber:iq:agent"+NS_AGENTS = "jabber:iq:agents"+NS_DELAY = "jabber:x:delay"NS_VERSION = "jabber:iq:version"--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-# all names by jaclu-#-_NS_PROTOCOL = "http://jabber.org/protocol" # base for other-NS_PASS = "jabber:iq:pass" # JEP-0003-NS_XDATA = "jabber:x:data" # JEP-0004-NS_RPC = "jabber:iq:rpc" # JEP-0009-NS_BROWSE = "jabber:iq:browse" # JEP-0011-NS_LAST = "jabber:iq:last" #JEP-0012-NS_PRIVACY = "jabber:iq:privacy" # JEP-0016-NS_XEVENT = "jabber:x:event" # JEP-0022-NS_XEXPIRE = "jabber:x:expire" # JEP-0023-NS_XENCRYPTED = "jabber:x:encrypted" # JEP-0027-NS_XSIGNED = "jabber:x:signed" # JEP-0027-NS_P_MUC = _NS_PROTOCOL + "/muc" # JEP-0045-NS_VCARD = "vcard-temp" # JEP-0054---#-# Non JANA aproved, ordered by JEP-# all names by jaclu-#-_NS_P_DISCO = _NS_PROTOCOL + "/disco" # base for other-NS_P_DISC_INFO = _NS_P_DISCO + "#info" # JEP-0030-NS_P_DISC_ITEMS = _NS_P_DISCO + "#items" # JEP-0030-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"- NS_ENVELOPE = "jabber:x:envelope"- NS_FILTER = "jabber:iq:filter"- NS_GATEWAY = "jabber:iq:gateway"- NS_OFFLINE = "jabber:x:offline"- NS_PRIVATE = "jabber:iq:private"- NS_SEARCH = "jabber:iq:search"- NS_XDBGINSERT = "jabber:xdb:ginsert"- NS_XDBNSLIST = "jabber:xdb:nslist"- NS_XHTML = "http://www.w3.org/1999/xhtml"- NS_XOOB = "jabber:x:oob"- NS_COMP_EXECUTE = "jabber:component:execute" # myname-"""-+NS_TIME = "jabber:iq:time"+NS_VCARD = "vcard-temp"+NS_PRIVATE = "jabber:iq:private"+NS_SEARCH = "jabber:iq:search"+NS_OOB = "jabber:iq:oob"+NS_XOOB = "jabber:x:oob"+NS_ADMIN = "jabber:iq:admin"+NS_FILTER = "jabber:iq:filter"+NS_AUTH_0K = "jabber:iq:auth:0k"+NS_BROWSE = "jabber:iq:browse"+NS_EVENT = "jabber:x:event"+NS_CONFERENCE = "jabber:iq:conference"+NS_SIGNED = "jabber:x:signed"+NS_ENCRYPTED = "jabber:x:encrypted"+NS_GATEWAY = "jabber:iq:gateway"+NS_LAST = "jabber:iq:last"+NS_ENVELOPE = "jabber:x:envelope"+NS_EXPIRE = "jabber:x:expire"+NS_XHTML = "http://www.w3.org/1999/xhtml"+NS_XDBGINSERT = "jabber:xdb:ginsert"+NS_XDBNSLIST = "jabber:xdb:nslist"## Possible constants for Roster class .... hmmm ##RS_SUB_BOTH = 0@@ -164,41 +117,6 @@RS_EXT_OFFLINE = 1RS_EXT_PENDING = 0-#############################################################################--def ustr(what, encoding=USTR_ENCODING):- """- If sending object is already a unicode str, just- return it, otherwise convert it using encoding- """- if type(what) == type(u''):- r = what- else:- r = what.__str__()- # make sure __str__() didnt return a unicode- if type(r) <> type(u''):- r = unicode(r,encoding,'replace')- return r---def str(what):- """quick and dirty catchall for all the str() usage.-- The code in this module should really be changed to call ustr()- instead of str() unless there is a good reason,- but remember all data on the wire are suposed to be unicode,- so this piece saves sloppy code ;)-- str() usage generally tend to break things for everybody that- doesnt speek english - and we are quite a few on this planet...-- If this is just to much to swallow, feel free to comment this out,- but please at least make sure that at least Client.send() uses ustr()- in that case- """- return ustr(what)--class Connection(xmlstream.Client):"""Forms the base for both Client and Component Classes"""@@ -221,34 +139,31 @@debug=debug, log=log,connection=connection )-def connect(self):"""Attempts to connect to the specified jabber server.- Raises an IOError on failure"""+ Raises an IOError on failiure"""self.DEBUG("jabberpy connect called")try:xmlstream.Client.connect(self)except xmlstream.error, e:raise IOError(e)-def disconnect(self):"""Safely disconnects from the connected server"""self.send(Presence(type='unavailable'));xmlstream.Client.disconnect(self)-def send(self, what):"""Sends a jabber protocol element (Node) to the server"""xmlstream.Client.write(self,str(what))-def dispatch(self, root_node ):- """Called internally when a 'protocol element' is received.- Builds the relevant jabber.py object and dispatches it+ """Called internally when a 'protocol element' is recieved.+ builds the relevant jabber.py object and dispatches itto a relevant function or callback.Also does some processing for roster and authenticationhelper fuctions"""+self.DEBUG("dispatch called")if root_node.name == 'message':@@ -275,138 +190,84 @@else:self.DEBUG("whats a tag -> " + root_node.name)- ## Callback stuff ###-- def setMessageHandler(self, func, type='default', chainOutput=False):- """Sets the callback func for receiving messages.- Multiple callback functions can be set which are called in- succession. A type attribute can also be optionally passed so the- callback is only called when a message of this type is received.-- If 'chainOutput' is set to False (the default), the given function- should be defined as follows:-- def myMsgCallback(c, msg)-- Where the first parameter is the Client object, and the second- parameter is the Message object representing the message which was- received.-- If 'chainOutput' is set to True, the output from the various message- handler functions will be chained together. In this case, the given- callback function should be defined like this:-- def myMsgCallback(c, msg, output)-- Where 'output' is the value returned by the previous message- callback function. For the first callback routine, 'output' will be- set to an empty string.- """- self.msg_hdlrs.append({ type : { 'cb' : func,- 'chain' : chainOutput} })--- def setPresenceHandler(self, func, type='default', chainOutput=False):- """Sets the callback func for receiving presence.- Multiple callback functions can be set which are called in- succession. A type attribute can also be optionally passed so the- callback is only called when a presence of this type is received.+ ## Call back stuff ###- If 'chainOutput' is set to False (the default), the given function- should be defined as follows:-- def myPrCallback(c, p)-- Where the first parameter is the Client object, and the second- parameter is the Presence object representing the presence packet- which was received.-- If 'chainOutput' is set to True, the output from the various- presence handler functions will be chained together. In this case,- the given callback function should be defined like this:+ def setMessageHandler(self, func, type='default'):+ """Sets a the callback func for recieving messages+ Mulitple callback functions can be set which are+ called in succession. A type attribute can also be+ optionally passed so the callback is only called when a+ message of this type is recieved.+ """- def myPrCallback(c, p, output)+ self.msg_hdlrs.append({ type : func })- Where 'output' is the value returned by the previous presence- callback function. For the first callback routine, 'output' will be- set to an empty string.- """+ def setPresenceHandler(self, func, type='default'):+ """Sets a the callback func for recieving presence+ Mulitple callback functions can be set which are+ called in succession. A type attribute can also be+ optionally passed so the callback is only called when a+ presence of this type is recieved.+ """## self.pres_hdlr = func- self.pres_hdlrs.append({ type : { 'cb' : func,- 'chain' : chainOutput} })-+ self.pres_hdlrs.append({ type : func })def setIqHandler(self, func, type='default', ns='default'):- """Sets the callback func for receiving iq.- Multiple callback functions can be set which are+ """Sets a the callback func for recieving iq+ Mulitple callback functions can be set which arecalled in succession. A type and namespace attributecan also be set so set functions are only called foriq elements with these properties.+ """- The given function should have two parameters, like this:-- def myIQCallback(c, iq)-- The first parameter will be set to the Client object, and the second- parameter will be set to the Iq object representing the IQ packet- which was received.- """self.iq_hdlrs.append({ type : { ns : func } })-def setDisconnectHandler(self, func):- """Set the callback for a disconnect.- The given function will be called with a single parameter (the- connection object) when the connection is broken unexpectedly (eg,- in response to sending badly formed XML). self.lastErr and- self.lastErrCode will be set to the error which caused the- disconnection, if any.- """+ """Set the callback for a disconnect"""self.disconnect_hdlr = func-def messageHandler(self, msg_obj): ## Overide If You Want ##- """Called when a message protocol element is received - can be- overidden. """+ """Called when a message protocol element is recieved - can be+ overidden"""+output = ''- type = msg_obj.getType()for dicts in self.msg_hdlrs:- if dicts.has_key(type):- if dicts[type]['chain']:- output = dicts[type]['cb'](self, msg_obj, output)+ if dicts.has_key(msg_obj.getType()):+ if dicts[msg_obj.getType()].func_code.co_argcount == 2:+ dicts[msg_obj.getType()](self, msg_obj)else:- dicts[type]['cb'](self, msg_obj)+ output = dicts[msg_obj.getType()](self, msg_obj, output)elif dicts.has_key('default'):- if dicts['default']['chain']:- output = dicts['default']['cb'](self, msg_obj, output)+ if dicts['default'].func_code.co_argcount == 2:+ dicts['default'](self, msg_obj)else:- dicts['default']['cb'](self, msg_obj)+ output = dicts['default'](self, msg_obj, output)else: pass-def presenceHandler(self, pres_obj): ## Overide If You Want ##- """Called when a presence protocol element is received - can be- overidden. """+ """Called when a pressence protocol element is recieved - can be+ overidden"""+output = ''- type = pres_obj.getType()for dicts in self.pres_hdlrs:- if dicts.has_key(type):- if dicts[type]['chain']:- output = dicts[type]['cb'](self, pres_obj, output)+ if dicts.has_key(pres_obj.getType()):+ if dicts[pres_obj.getType()].func_code.co_argcount == 2:+ dicts[pres_obj.getType()](self, pres_obj)else:- dicts[type]['cb'](self, pres_obj)+ output = dicts[pres_obj.getType()](self, pres_obj, output)elif dicts.has_key('default'):- if dicts['default']['chain']:- output = dicts['default']['cb'](self, pres_obj, output)+ if dicts['default'].func_code.co_argcount == 2:+ dicts['default'](self, pres_obj)else:- dicts['default']['cb'](self, pres_obj)+ output = dicts['default'](self, pres_obj, output)else: passdef iqHandler(self, iq_obj): ## Overide If You Want ##- """Called when an iq protocol element is received - can be+ """Called when an iq protocol element is recieved - can beoveridden"""+for dicts in self.iq_hdlrs: ## do stackables to check ##if dicts.has_key(iq_obj.getType()):if dicts[iq_obj.getType()].has_key(iq_obj.getQuery()):@@ -422,32 +283,24 @@"""Called when a network error occurs - can be overidden"""if self.disconnect_hdlr != None: self.disconnect_hdlr(self)+## functions for sending element with ID's ##- def waitForResponse(self, ID, timeout=300):- """Blocks untils a protocol element with the given id is received.- If an error is received, waitForResponse returns None and- 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".- 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"""+ def waitForResponse(self, ID, timeout=0):+ """Blocks untils a protocol element with ID id is recieved.+ If an error is recieved or a timeout occurs ( only if timeout attr+ is set, None is returned with lastErr set to the error"""ID = str(ID)self._expected[ID] = None+ then = time.time()has_timed_out = False-- abort_time = time.time() + timeout- if timeout:- self.DEBUG("waiting with timeout:%s for %s" % (timeout,str(ID)))- else:- self.DEBUG("waiting for %s" % str(ID))-- while (not self._expected[ID]) and not has_timed_out:- self.process(0.2)- if timeout and (time.time() > abort_time):+ ## TODO , add a timeout+ while (not self._expected[ID]) or has_timed_out:+ self.DEBUG("waiting on %s" % str(ID))+ self.process(1)+ if timeout and time.time()-then > timeout:has_timed_out = True+if has_timed_out:self.lastErr = "Timeout"return None@@ -457,14 +310,12 @@self.lastErr = response.getError()self.lastErrCode = response.getErrorCode()return None-- return response+ return response- def SendAndWaitForResponse(self, obj, ID=None, timeout=300):+ def SendAndWaitForResponse(self, obj, ID=None):"""Sends a protocol element object and blocks until a response with- the same ID is received. The received protocol object is returned- as the function result. """+ the same ID is recieved"""if ID is None :ID = obj.getID()if ID is None:@@ -472,22 +323,21 @@obj.setID(ID)ID = str(ID)self.send(obj)- return self.waitForResponse(ID,timeout)-+ return self.waitForResponse(ID)def getAnID(self):"""Returns a unique ID"""self._id = self._id + 1return str(self._id)-#############################################################################class Client(Connection):- """Class for managing a client connection to a jabber server."""+ """Class for managing a connection to a jabber server.+ Inherits from the xmlstream Client class"""def __init__(self, host, port=5222, debug=False, log=False,connection=xmlstream.TCP ):- Connection.__init__(self, host, port, NS_CLIENT, debug, log,+ Connection.__init__(self, host, port,'jabber:client', debug, log,connection=connection)self._roster = Roster()@@ -496,43 +346,39 @@self._reg_agent = ''#xmlstream.Client.__init__(self, host, port,- # NS_CLIENT, debug, log)-+ # 'jabber:client', debug, log)def connect(self):"""Attempts to connect to the specified jabber server.- Raises an IOError on failure"""+ Raises an IOError on failiure"""self.DEBUG("jabberpy connect called")try:xmlstream.Client.connect(self)except xmlstream.error, e:raise IOError(e)-def disconnect(self):"""Safely disconnects from the connected server"""self.send(Presence(type='unavailable'));xmlstream.Client.disconnect(self)-def send(self, what):"""Sends a jabber protocol element (Node) to the server"""- xmlstream.Client.write(self,ustr(what))-+ xmlstream.Client.write(self,str(what))def sendInitPresence(self):"""Sends an empty presence protocol element to the- server. Used to inform the server that you are online"""+ server. Used to 'tell' the server your online"""p = Presence()self.send(p);--+def dispatch(self, root_node ):- """Called internally when a protocol element is received.- Builds the relevant jabber.py object and dispatches it+ """Called internally when a 'protocol element' is recieved.+ builds the relevant jabber.py object and dispatches itto a relevant function or callback.Also does some processing for roster and authenticationhelper fuctions"""+self.DEBUG("dispatch called")if root_node.name == 'message':@@ -581,18 +427,12 @@name = item.getAttr('name')sub = item.getAttr('subscription')ask = item.getAttr('ask')-- groups = []- for group in item.getTags("group"):- groups.append(group.getData())-if jid:- if sub == 'remove' or sub == 'none':+ if sub == 'remove':self._roster._remove(jid)else:- self._roster._set(jid=jid, name=name,- groups=groups, sub=sub,- ask=ask)+ self._roster._set(jid=jid,name=name,+ sub=sub,ask=ask)else:self.DEBUG("roster - jid not defined ?")@@ -629,29 +469,22 @@"""Authenticates and logs in to the specified jabber serverAutomatically selects the 'best' authentication methodprovided by the server.- Supports plain text, digest and zero-k authentication.+ Supports plain text, deigest and zero-k authentication"""- Returns True if the login was successful, False otherwise.- """auth_get_iq = Iq(type='get')auth_get_iq.setID('auth-get')- q = auth_get_iq.setQuery(NS_AUTH)+ q = auth_get_iq.setQuery('jabber:iq:auth')q.insertTag('username').insertData(username)self.send(auth_get_iq)-- auth_response = self.waitForResponse("auth-get")- if auth_response == None:- return False # Error- else:- auth_ret_node = auth_response.asNode()-++ auth_ret_node = self.waitForResponse("auth-get").asNode()auth_ret_query = auth_ret_node.getTag('query')self.DEBUG("auth-get node arrived!")auth_set_iq = Iq(type='set')auth_set_iq.setID('auth-set')- q = auth_set_iq.setQuery(NS_AUTH)+ q = auth_set_iq.setQuery('jabber:iq:auth')q.insertTag('username').insertData(username)q.insertTag('resource').insertData(resource)@@ -676,6 +509,9 @@iq_result = self.SendAndWaitForResponse(auth_set_iq)+ if iq_result == None:+ return False+if iq_result.getError() is None:return Trueelse:@@ -683,151 +519,82 @@self.lastErrCode = iq_result.getErrorCode()# raise error(iq_result.getError()) ?return False- if iq_result is None:- return False- return True## Roster 'helper' func's - also see the Roster class ##def requestRoster(self):- """Requests the roster from the server and returns a- Roster() class instance."""+ """requests the roster from the server and returns a+ Roster() class instance."""rost_iq = Iq(type='get')- rost_iq.setQuery(NS_ROSTER)+ rost_iq.setQuery('jabber:iq:roster')self.SendAndWaitForResponse(rost_iq)self.DEBUG("got roster response")self.DEBUG("roster -> %s" % str(self._agents))return self._roster-def getRoster(self):"""Returns the current Roster() class instance. Does- not contact the server."""+ not contect the server."""return self._roster-- def addRosterItem(self, jid):- """ Send off a request to subscribe to the given jid.- """- self.send(Presence(to=jid, type="subscribe"))--- def updateRosterItem(self, jid, name=None, groups=None):- """ Update the information stored in the roster about a roster item.-- 'jid' is the Jabber ID of the roster entry; 'name' is the value to- set the entry's name to, and 'groups' is a list of groups to which- this roster entry can belong. If either 'name' or 'groups' is not- specified, that value is not updated in the roster.- """- iq = Iq(type='set')- item = iq.setQuery(NS_ROSTER).insertTag('item')- item.putAtrr('jid', str(jid))- if name != None: item.putAtrr('name', name)- if groups != None:- for group in groups:- item.insertTag('group').insertData(group)- dummy = self.sendAndWaitForResponse(iq) # Do we need to wait??--def removeRosterItem(self,jid):"""Removes an item with Jabber ID jid from both the- server's roster and the local internal Roster()- instance"""+ servers roster and the local interenal Roster()+ instance"""rost_iq = Iq(type='set')- q = rost_iq.setQuery(NS_ROSTER).insertTag('item')- q.putAttr('jid', str(jid))- q.putAttr('subscription', 'remove')+ q = rost_iq.setQuery('jabber:iq:roster').insertTag('item')+ q.putAtrr('jid', str(jid))+ q.putAtrr('subscription', 'remove')self.SendAndWaitForResponse(rost_iq)return self._roster## Registration 'helper' funcs ##-+def requestRegInfo(self,agent=None):"""Requests registration info from the server.- Returns the Iq object received from the server."""+ returns a dict of required values."""if agent: agent = agent + '.'if agent is None: agent = ''self._reg_info = {}self.DEBUG("agent -> %s, _host -> %s" % ( agent ,self._host))reg_iq = Iq(type='get', to = agent + self._host)- reg_iq.setQuery(NS_REGISTER)+ reg_iq.setQuery('jabber:iq:register')self.DEBUG("got reg response")self.DEBUG("roster -> %s" % str(self._agents))return self.SendAndWaitForResponse(reg_iq)-def getRegInfo(self):- """Returns a dictionary of fields requested by the server for a- registration attempt. Each dictionary entry maps from the name of- the field to the field's current value (either as returned by the- server or set programmatically by calling self.setRegInfo(). """+ """Returns the last requested register dict."""return self._reg_info-def setRegInfo(self,key,val):"""Sets a name/value attribute. Note: requestRegInfo must becalled before setting."""self._reg_info[key] = val-def sendRegInfo(self, agent=None):- """Sends the populated registration dictionary back to the server"""+ """Sends the populated register dict back to the server"""if agent: agent = agent + '.'if agent is None: agent = ''reg_iq = Iq(to = agent + self._host, type='set')- q = reg_iq.setQuery(NS_REGISTER)+ q = reg_iq.setQuery('jabber:iq:register')for info in self._reg_info.keys():q.insertTag(info).putData(self._reg_info[info])return self.SendAndWaitForResponse(reg_iq)-- def deregister(self, agent=None):- """ Send off a request to deregister with the server or with the given- agent. Returns True if successful, else False.-- Note that you must be authorised before attempting to deregister.- """- if agent: agent = agent + '.'- if agent is None: agent = ''- q = self.requestRegInfo()- kids = q.getQueryPayload()- keyTag = kids.getTag("key")-- iq = Iq(to=agent+self._host, type="set")- iq.setQuery(NS_REGISTER)- iq.setQueryNode("")- q = iq.getQueryNode()- if keyTag != None:- q.insertXML("<key>" + keyTag.getData() + "</key>")- q.insertXML("<remove/>")-- result = self.SendAndWaitForResponse(iq)-- if result == None:- return False- elif result.getType() == "result":- return True- else:- return False-## Agent helper funcs ##def requestAgents(self):- """Requests a list of available agents. Returns a dictionary- containing information about each agent; each entry in the- dictionary maps the agent's JID to a dictionary of attributes- describing what that agent can do (as returned by the- NS_AGENTS query)."""+ """Requests a list of available agents. returns a dict of+ agents and info"""self._agents = {}agents_iq = Iq(type='get')- agents_iq.setQuery(NS_AGENTS)+ agents_iq.setQuery('jabber:iq:agents')self.SendAndWaitForResponse(agents_iq)self.DEBUG("got agents response")self.DEBUG("agents -> %s" % str(self._agents))return self._agents-#############################################################################class Protocol:"""Base class for jabber 'protocol elements' - messages, presences and iqs.@@ -835,72 +602,58 @@def __init__(self):self._node = None-def asNode(self):- """Returns an XMLStreamNode representation of the protocol element."""+ """returns an xmlstreamnode representation of the protocol element"""return self._node-def __str__(self):return self._node.__str__()-def getTo(self):- """Returns the 'to' attribute as a JID object."""+ "Returns a JID object of the to attr of the element"try: return JID(self._node.getAttr('to'))except: return None-def getFrom(self):- """Returns the 'from' attribute as a JID object."""+ "Returns a JID object of the from attribute of the element"try: return JID(self._node.getAttr('from'))except: return None-def getType(self):- """Returns the 'type' attribute of the protocol element."""+ "Returns the type attribute of the protocol element"try: return self._node.getAttr('type')except: return None-def getID(self):- """Returns the 'id' attribute of the protocol element."""+ "Returns the ID attribute of the protocol element"try: return self._node.getAttr('id')except: return None-def setTo(self,val):- """Sets the 'to' element to the given JID."""+ "Sets the to JID of the protocol element"self._node.putAttr('to', str(val))-def setFrom(self,val):- """Sets the 'from' element to the given JID."""+ "Sets the from JID of the protocol element"self._node.putAttr('from', str(val))-def setType(self,val):- """Sets the 'type' attribute of the protocol element"""+ "Sets the type attribute of the protocol element"self._node.putAttr('type', val)-def setID(self,val):- """Sets the ID of the protocol element"""+ "Sets the ID of the protocol element"self._node.putAttr('id', val)-def getX(self,index=None):- """Returns the x namespace, optionally passed an index if there are- multiple tags."""+ "returns the x namespace, optionally passed an index if multiple tags"## TODO make it work for multiple x nodes- # jaclu 021231 commented out .namespace to get timestamps working- try: return self._node.getTag('x') #.namespace+ try: return self._node.getTag('x').namespaceexcept: return None-def setX(self,namespace,index=None):"""Sets the name space of the x tag. It also creates the node- if it doesn't already exist."""+ if it doesn't already exist"""## TODO make it work for multiple x nodesx = self._node.getTag('x')if x:@@ -910,10 +663,9 @@x.setNamespace(namespace)return x-def setXPayload(self, payload):- """Sets the Child of an 'x' tag. Can be a Node instance or an- XML document"""+ """Sets the Child of an x tag. Can be a Node instance or a+ XML document"""x = self._node.insertTag('x')if type(payload) == type('') or type(payload) == type(u''):@@ -921,10 +673,9 @@x.kids = [] # should be a method for this realyx.insertNode(payload)-def getXPayload(self, val=None):- """Returns the x tags' payload as a list of Node instances."""+ """Returns the x tags payload as a Node instance"""nodes = []if val is not None:if type(val) == type(""):@@ -938,13 +689,12 @@for xnode in self._node.getTags('x'):nodes.append(xnode.kids[0])return nodes-def getXNode(self, val=None):"""Returns the x Node instance. If there are multiple tagsthe first Node is returned. For multiple X nodes use getXNodesor pass an index integer value or namespace string to getXNode- and if a match is found it will be returned."""+ and if a match is found it will be returned"""if val is not None:nodes = []if type(val) == type(""):@@ -958,133 +708,107 @@try: return self._node.getTag('x')except: return None-def getXNodes(self, val=None):- """Returns a list of X nodes."""+ """Returns a list of X nodes"""try: return self._node.getTags('x')[val]except: return None-def setXNode(self, val=''):- """Sets the x tag's data to the given textual value."""+ """Sets the x tags data - just text"""self._node.insertTag('x').putData(val)-def fromTo(self):- """Swaps the element's from and to attributes.- Note that this is only useful for writing components; if you are- writing a Jabber client you shouldn't use this, because the Jabber- server will set the 'from' field automatically."""+ """Swaps the element from and to attributes.+ Not any use with Clients as Server sets from."""tmp = self.getTo()self.setTo(self.getFrom())self.setFrom(tmp)__repr__ = __str__-#############################################################################class Message(Protocol):"""Builds on the Protocol class to provide an interface for sendingmessage protocol elements"""def __init__(self, to=None, body=None, node=None):- self.time_stamp = Noneif node:self._node = node- # examine x tag and set timestamp if pressent- x = self._node.getTag('x')- if x:- ts = x.getAttr('stamp')- if ts:- self.setTimestamp( ts )else:self._node = xmlstream.Node(tag='message')if to: self.setTo(str(to))if body: self.setBody(body)--+def getBody(self):- """Returns the message body."""+ "Returns the message body."body = self._node.getTag('body')try: return self._node.getTag('body').getData()except: return None-def getSubject(self):- """Returns the message's subject."""+ "Returns the messages subject."try: return self._node.getTag('subject').getData()except: return None-def getThread(self):- """Returns the message's thread ID."""+ "Returns the messages thread ID."try: return self._node.getTag('thread').getData()except: return None--+def getError(self):- """Returns the message's error string, if any."""+ "Returns the messgaes Error string, if any"try: return self._node.getTag('error').getData()except: return None-def getErrorCode(self):- """Returns the message's error Code, if any."""+ "Returns the messgaes Error Code, if any"try: return self._node.getTag('error').getAttr('code')except: return None-def getTimestamp(self):- return self.time_stamp-+ "Not yet implemented"+ passdef setBody(self,val):- """Sets the message body text."""+ "Sets the message body text."body = self._node.getTag('body')if body:body.putData(val)else:body = self._node.insertTag('body').putData(val)-def setSubject(self,val):- """Sets the message subject text."""+ "Sets the message subject text."subj = self._node.getTag('subject')if subj:subj.putData(val)else:self._node.insertTag('subject').putData(val)-def setThread(self,val):- """Sets the message thread ID."""+ "Sets the message thread ID."thread = self._node.getTag('thread')if thread:thread.putData(val)else:self._node.insertTag('thread').putData(val)-def setError(self,val,code):- """Sets the message error text."""+ "Sets the message error text"err = self._node.getTag('error')if err:err.putData(val)else:- err = self._node.insertTag('error')- err.putData(val)- err.putAttr('code',str(code))-+ err = self._node.insertTag('thread').putData(val)+ err.setAttr('code',str(code))def setTimestamp(self,val):- if not val:- val = time.strftime( '%Y%m%dT%H:%M:%S', time.gmtime( time.time()))- self.time_stamp = val-+ "Not yet implemented"+ passdef build_reply(self, reply_txt=''):- """Returns a new Message object as a reply to itself.- The reply message has the 'to', 'type' and 'thread' attributes- automatically set."""+ """Returns a new Message object as a reply to its self.+ The reply message, has the to and type automatically+ set."""m = Message(to=self.getFrom(), body=reply_txt)if not self.getType() == None:m.setType(self.getType())@@ -1092,11 +816,11 @@if t: m.setThread(t)return m-#############################################################################+class Presence(Protocol):"""Class for creating and managing jabber <presence> protocol- elements"""+ elements"""def __init__(self, to=None, type=None, node=None):if node:self._node = node@@ -1111,18 +835,15 @@try: return self._node.getTag('status').getData()except: return None-def getShow(self):"""Returns the presence show"""try: return self._node.getTag('show').getData()except: return None-def getPriority(self):"""Returns the presence priority"""try: return self._node.getTag('priority').getData()except: return None-def setShow(self,val):"""Sets the presence show"""@@ -1132,7 +853,6 @@else:self._node.insertTag('show').putData(val)-def setStatus(self,val):"""Sets the presence status"""status = self._node.getTag('status')@@ -1141,7 +861,6 @@else:self._node.insertTag('status').putData(val)-def setPriority(self,val):"""Sets the presence priority"""pri = self._node.getTag('priority')@@ -1150,11 +869,11 @@else:self._node.insertTag('priority').putData(val)-#############################################################################class Iq(Protocol):"""Class for creating and managing jabber <iq> protocol- elements"""+ elements"""+def __init__(self, to='', type=None, node=None):if node:self._node = node@@ -1163,19 +882,16 @@if to: self.setTo(to)if type: self.setType(type)-def getError(self):"""Returns the Iq's error string, if any"""try: return self._node.getTag('error').getData()except: return None-def getErrorCode(self):"""Returns the Iq's error code, if any"""try: return self._node.getTag('error').getAttr('code')except: return None-def setError(self,val,code):"""Sets an Iq's error string and code"""err = self._node.getTag('error')@@ -1187,43 +903,26 @@err.putAttr('code',str(code))- def _getTag(self,tag):- try: return self._node.getTag(tag).namespace+ def getQuery(self):+ "returns the query namespace"+ try: return self._node.getTag('query').namespaceexcept: return None- def _setTag(self,tag,namespace):- q = self._node.getTag(tag)+ def setQuery(self,namespace):+ """Sets a querys namespace, also inserts a query tag if+ it doesn't already exist"""+ q = self._node.getTag('query')if q:q.namespace = namespaceelse:- q = self._node.insertTag(tag)+ q = self._node.insertTag('query')q.setNamespace(namespace)return q-- def getList(self):- "returns the list namespace"- return self._getTag('list')-- def setList(self,namespace):- return self._setTag('list',namespace)--- def getQuery(self):- "returns the query namespace"- return self._getTag('query')-- def setQuery(self,namespace):- """Sets a query's namespace, and inserts a query tag if- one doesn't already exist. The resulting query tag- is returned as the function result."""- return self._setTag('query',namespace)--def setQueryPayload(self, payload):- """Sets a Iq's query payload. 'payload' can be either a Node- structure or a valid xml document. The query tag is automatically- inserted if it doesn't already exist."""+ """Sets a Iq's query payload. Payload can be either a Node+ structure or a valid xml document. The query tag is automatically+ inserted if it doesn't already exist"""q = self.getQueryNode()if q is None:@@ -1234,23 +933,20 @@q.kids = []q.insertNode(payload)-def getQueryPayload(self):- """Returns the query's payload as a Node instance"""+ """Returns the querys payload as a Node instance"""q = self.getQueryNode()if q:return q.kids[0]return None-def getQueryNode(self):"""Returns any textual data contained by the query tag"""try: return self._node.getTag('query')except: return None-- def setQueryNode(self, val):+ def setQueryNode(self):"""Sets textual data contained by the query tag"""q = self._node.getTag('query')if q:@@ -1258,202 +954,116 @@else:self._node.insertTag('query').putData(val)-#############################################################################-class Roster:"""A Class for simplifying roster management. Also tracks roster- item availability."""+ items availability"""def __init__(self):self._data = {}- self._listener = None## unused for now ... ##self._lut = { 'both':RS_SUB_BOTH,'from':RS_SUB_FROM,'to':RS_SUB_TO }-- def setListener(self, listener):- """ Set a listener function to be called whenever the roster changes.-- The given function will be called whenever the contents of the- roster changes in response to a received <presence> or <iq> packet.- The listener function should be defined as follows:-- def listener(action, jid, info)-- 'action' is a string indicating what type of change has occurred:-- "add" A new item has been added to the roster.- "update" An existing roster item has been updated.- "remove" A roster entry has been removed.-- 'jid' is the Jabber ID (as a string) of the affected roster entry.-- 'info' is a dictionary containing the information that has been- added or updated for this roster entry. This dictionary may- contain any combination of the following:-- "name" The associated name of this roster entry.- "groups" A list of groups associated with this roster entry.- "online" The roster entry's "online" value ("online",- "offline" or "pending").- "sub" The roster entry's subscription value ("none",- "from", "to" or "both").- "ask" The roster entry's ask value, if any (None,- "subscribe", "unsubscribe").- "show" The roster entry's show value, if any (None, "away",- "chat", "dnd", "normal", "xa").- "status" The roster entry's current 'status' value, if- specified.- """- self._listener = listener--def getStatus(self, jid): ## extended- """Returns the 'status' value for a Roster item with the given jid."""+ """Gets the status for a Roster item with JID jid"""jid = str(jid)if self._data.has_key(jid):return self._data[jid]['status']return None-def getShow(self, jid): ## extended- """Returns the 'show' value for a Roster item with the given jid."""+ """Gets the show for a Roster item with JID jid"""jid = str(jid)if self._data.has_key(jid):return self._data[jid]['show']return None-def getOnline(self,jid): ## extended- """Returns the 'online' status for a Roster item with the given jid.- """+ """Gets the online status for a Roster item with JID jid"""jid = str(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."""+ """Gets the subscription status for a Roster item with JID jid"""jid = str(jid)if self._data.has_key(jid):return self._data[jid]['sub']return None-def getName(self,jid):- """Returns the 'name' for a Roster item with the given jid."""+ """Gets the 'name' for a Roster item with JID jid"""jid = str(jid)if self._data.has_key(jid):return self._data[jid]['name']return None-- def getGroups(self,jid):- """ Returns the lsit of groups associated with the given roster item.- """- jid = str(jid)- if self._data.has_key(jid):- return self._data[jid]['groups']- return None--def getAsk(self,jid):- """Returns the 'ask' status for a Roster item with the given jid."""+ """Gets the 'ask' status for a Roster item with JID jid"""jid = str(jid)if self._data.has_key(jid):return self._data[jid]['ask']return None-def getSummary(self):- """Returns a summary of the roster's contents. The returned value is a- dictionary mapping the basic (no resource) JIDs to their current- availability status (online, offline, pending). """+ """Returns a list of basic ( no resource ) JID's with there+ 'availability' - online, offline, pending """to_ret = {}for jid in self._data.keys():to_ret[jid] = self._data[jid]['online']return to_ret-def getJIDs(self):- """Returns a list of JIDs stored within the roster. Each entry in the- list is a JID object."""+ """Returns a list of JID instances of Roster entries"""to_ret = [];for jid in self._data.keys():to_ret.append(JID(jid))return to_ret-def getRaw(self):- """Returns the internal data representation of the roster."""+ """Returns the internal data representation of the roster"""return self._data-def isOnline(self,jid):- """Returns True if the given jid is online, False if not."""+ """Returns TRUE if the jid is online, FALSE if not"""jid = str(jid)if self.getOnline(jid) != 'online':return Falseelse:return True--- def _set(self,jid,name,groups,sub,ask):- # meant to be called by actual iq tag++ def _set(self,jid,name,sub,ask): # meant to be called by actual iq tag"""Used internally - private"""jid = str(jid) # just in caseonline = 'offline'if ask: online = 'pending'if self._data.has_key(jid): # update itself._data[jid]['name'] = name- self._data[jid]['groups'] = groupsself._data[jid]['ask'] = askself._data[jid]['sub'] = sub- if self._listener != None:- self._listener("update", jid, {'name' : name,- 'groups' : groups,- 'sub' : sub, 'ask' : ask})- else:- self._data[jid] = { 'name': name, 'groups' : groups, 'ask': ask,- 'sub': sub, 'online': online, 'status': None,- 'show': None}- if self._listener != None:- self._listener("add", jid, {'name' : name, 'groups' : groups,- 'sub' : sub, 'ask' : ask,- 'online' : online})--+ else:+ self._data[jid] = { 'name': name, 'ask': ask, 'sub': sub,+ 'online': online, 'status': None, 'show': None}def _setOnline(self,jid,val):"""Used internally - private"""jid = str(jid)if self._data.has_key(jid):self._data[jid]['online'] = val- if self._listener != None:- self._listener("update", jid, {'online' : val})else: ## fall backjid_basic = JID(jid).getStripped()if self._data.has_key(jid_basic):self._data[jid_basic]['online'] = val- if self._listener != None:- self._listener("update", jid_basic, {'online' : val})-def _setShow(self,jid,val):"""Used internally - private"""jid = str(jid)if self._data.has_key(jid):self._data[jid]['show'] = val- if self._listener != None:- self._listener("update", jid, {'show' : val})else: ## fall backjid_basic = JID(jid).getStripped()if self._data.has_key(jid_basic):self._data[jid_basic]['show'] = val- if self._listener != None:- self._listener("update", jid_basic, {'show' : val})def _setStatus(self,jid,val):@@ -1461,33 +1071,24 @@jid = str(jid)if self._data.has_key(jid):self._data[jid]['status'] = val- if self._listener != None:- self._listener("update", jid, {'status' : val})else: ## fall backjid_basic = JID(jid).getStripped()if self._data.has_key(jid_basic):self._data[jid_basic]['status'] = val- if self._listener != None:- self._listener("update", jid_basic, {'status' : val})def _remove(self,jid):"""Used internally - private"""- if self._data.has_key(jid):- del self._data[jid]- if self._listener != None:- self._listener("remove", jid, {})--#############################################################################+ if self._data.has_key(jid): del self._data[jid]class JID:- """A Simple class for managing jabber users id's """+ """A Simple calss for managing jabber users id's """def __init__(self, jid='', node='', domain='', resource=''):if jid:if find(jid, '@') == -1:self.node = ''else:- bits = split(jid, '@',1)+ bits = split(jid, '@')self.node = bits[0]jid = bits[1]@@ -1495,13 +1096,15 @@self.domain = jidself.resource = ''else:- self.domain, self.resource = split(jid, '/',1)+ self.domain, self.resource = split(jid, '/')+ slash_ind = find(jid, '/')+ self.domain = jid[:slash_ind]+ self.resource = jid[(slash_ind + 1):]else:self.node = nodeself.domain = domainself.resource = resource-def __str__(self):try:jid_str = ''@@ -1514,59 +1117,43 @@__repr__ = __str__-def getNode(self):"""Returns JID Node as string"""return self.node--def getDomain(self):"""Returns JID domain as string"""return self.domain--def getResource(self):"""Returns JID resource as string"""return self.resource-def setNode(self,val):"""Sets JID Node from string"""self.node = val--def setDomain(self,val):"""Sets JID domain from string"""self.domain = val--def setResource(self,val):"""Sets JID resource from string"""self.resource = val-def getStripped(self):- """Returns a jid string with no resource"""+ """returns a jid string with no resource"""jid_str = ''if self.node: jid_str = jid_str + self.node + '@'if self.domain: jid_str = jid_str + self.domainreturn jid_str-#############################################################################-## component types-## Accept NS_COMP_ACCEPT-## Connect NS_COMP_CONNECT-## Execute NS_COMP_EXECUTE+## Accept jabber:component:accept+## Connect jabber:component:connect+## Execute jabber:component:executeclass Component(Connection):"""docs to come soon... """def __init__(self, host, port=5222, connection=xmlstream.TCP,- debug=False, log=False, ns=NS_COMP_ACCEPT):- # EJW: Does it make sense to have a default port here? Components, by- # definition, will use a port different from the standard Jabber client- # connection port, so the above is misleading...+ debug=False, log=False, ns='jabber:component:accept'):self._auth_OK = False@@ -1576,9 +1163,8 @@log=log,connection=connection)-def auth(self,secret):- """will disconnect on failure"""+ """will disconnect on faliaure"""self.send( u"<handshake id='1'>%s</handshake>"% sha.new( self.getIncomingID() + secret ).hexdigest())@@ -1588,14 +1174,12 @@return True-def dispatch(self, root_node):"""Catch the <handshake/> here"""if root_node.name == 'handshake': # check id too ?self._auth_OK = TrueConnection.dispatch(self, root_node)-############################################################################### component protocol elements@@ -1610,7 +1194,6 @@if type: self.setType(type)if frm: self.setFrom(type)-#############################################################################class Log(Protocol):## eg: <log type='warn' from='component'>Hello Log File</log>@@ -1624,17 +1207,14 @@if type: self.setType(type)if frm: self.setFrom(type)-def setBody(self,val):"Sets the log message text."self._node.getTag('log').putData(val)-def setBody(self):"Returns the log message text."return self._node.getTag('log').getData()-#############################################################################class Server:pass--- jabberpy0.4-0/xmlstream.py Thu Feb 20 02:22:33 2003+++ jabberpy0.4-0-patched/xmlstream.py Thu Apr 3 11:51:56 2003@@ -28,16 +28,14 @@"""-# $Id: xmlstream.py,v 1.26 2003/02/20 10:22:33 shire Exp $+# $Id: xmlstream.py,v 1.3 2003/04/03 19:51:56 morgen Exp $-import site-site.encoding = 'UTF-8'-import time, sys, re, socket+import time, sys, re, site, socketfrom select import selectfrom string import split,find,replace,joinimport xml.parsers.expat-VERSION = 0.3+VERSION = 0.2False = 0True = 1@@ -46,12 +44,14 @@STDIO = 0TCP_SSL = 2-ENCODING = site.encoding+ENCODING = site.encoding ## fallback encoding to avoid random+ ## random UnicodeError: ASCII decoding error:+ ## ordinal not in range(128)+ ## type errors - being looked into.BLOCK_SIZE = 1024 ## Number of bytes to get at at time via socket## transactions-def XMLescape(txt):"Escape XML entities"txt = replace(txt, "&", "&")@@ -61,9 +61,9 @@def XMLunescape(txt):"Unescape XML entities"+ txt = replace(txt, "&", "&")txt = replace(txt, "<", "<")txt = replace(txt, ">", ">")- txt = replace(txt, "&", "&")return txtclass error:@@ -118,20 +118,21 @@def putData(self, data):"Set the nodes textual data"- self.data.append(data)+ self.data.append(XMLescape(data))def insertData(self, data):"Set the nodes textual data"- self.data.append(data)+ self.data.append(XMLescape(data))def getData(self):"Return the nodes textual data"- return join(self.data, '')+ return XMLunescape(join(self.data))def getDataAsParts(self):"Return the node data as an array"return self.data+def getNamespace(self):"Returns the nodes namespace."return self.namespace@@ -141,10 +142,7 @@self.namespace = namespacedef insertTag(self, name):- """ Add a child tag of name 'name' to the node.-- Returns the newly created node.- """+ "Add a child tag of name 'name' to the node"newnode = Node(tag=name, parent=self)self.kids.append(newnode)return newnode@@ -298,28 +296,10 @@self._logFH = logelse:self._logFH = None- self._timestampLog = True-- def timestampLog(self,timestamp):- """ Enable or disable the showing of a timestamp in the log.- By default, timestamping is enabled.- """- self._timestampLog = timestamp-+def DEBUG(self,txt):if self._debug:- try:- sys.stderr.write("DEBUG: %s\n" % txt)- except:- # unicode strikes again ;)- s=u''- for i in range(len(txt)):- if ord(txt[i]) < 128:- c = txt[i]- else:- c = '?'- s=s+c- sys.stderr.write("DEBUG: %s\n" % s )+ sys.stderr.write("DEBUG: %s\n" % txt)def getSocket(self):return self._sock@@ -382,53 +362,50 @@##def syntax_error(self, message):## self.DEBUG("error " + message)- def _do_read( self, action, buff_size ):- """workhorse for read() method.-- added 021231 by jaclu"""- data=''- data_in = action(buff_size)- while data_in:- data = data + data_in- if len(data_in) != buff_size:- break- data_in = action(buff_size)- return data-def read(self):- """Reads incoming data. Called by process() so nonblocking-- changed 021231 by jaclu- """+ """Reads incoming data. Called by process() so nonblocking"""+ data = u''+ data_in = u''if self._connection == TCP:- raw_data = self._do_read(self._sock.recv, BLOCK_SIZE)- elif self._connection == TCP_SSL:- raw_data = self._do_read(self._sslObj.read, BLOCK_SIZE)+ data_in = data_in + \+ unicode(self._sock.recv(BLOCK_SIZE),'utf-8').encode(ENCODING,+ 'replace')+ while data_in:+ data = data + data_in+ if len(data_in) != BLOCK_SIZE:+ break+ data_in = unicode(self._sock.recv(BLOCK_SIZE),'utf-8').encode(+ ENCODING, 'replace')++ if self._connection == TCP_SSL:+ data_in = data_in + \+ unicode(self._sslObj.recv(BLOCK_SIZE),'utf-8').encode(ENCODING,'replace')+ while data_in:+ data = data + data_in+ if len(data_in) != BLOCK_SIZE:+ break+ data_in = unicode(self._sslObj.recv(BLOCK_SIZE),'utf-8').encode(ENCODING, 'replace')+elif self._connection == STDIO:- raw_data = self._do_read(self.stdin.read, 1024)+ ## Hope this dont buffer !+ data_in = data_in + unicode(sys.stdin.read(1024),'utf-8').encode(+ ENCODING, 'replace')+ while data_in:+ data = data + data_in+ if len(data_in) != 1024:+ break+ data_in = unicode(sys.stdin.read(1024),'utf-8').encode(+ ENCODING, 'replace')else:- raw_data = '' # should never get here-- # just encode incoming data once!- data = unicode(raw_data,'utf-8').encode(ENCODING,'replace')+ pass # should never get here+self.DEBUG("got data %s" % data )self.log(data, 'RECV:')self._parser.Parse(data)return data-- def write(self,raw_data=u''):- """Writes raw outgoing data. blocks-- changed 021231 by jaclu, added unicode encoding- """- if type(raw_data) == type(u''):- data_out = raw_data.encode('utf-8','replace')- else:- # since not suplied as unicode, we must guess at- # what the data is, iso-8859-1 seems reasonable.- # To avoid this auto assumption,- # send your data as a unicode string!- data_out = unicode(raw_data,'iso-8859-1').encode(ENCODING,'replace')++ def write(self,data_out=u''):+ """Writes raw outgoing data. blocks"""try:if self._connection == TCP:self._sock.send (data_out)@@ -451,12 +428,12 @@if self._connection == TCP:reader = self._sockelif self._connection == TCP_SSL:- reader = self._sock+ reader = self._sslObjelif self._connection == STDIO:reader = sys.stdinelse:pass-+ready_for_read,ready_for_write,err = \select( [reader],[],[],timeout)for s in ready_for_read:@@ -470,6 +447,7 @@def disconnect(self):"""Close the stream and socket"""+ time.sleep(1) ## sleep for a second - server bug ? ##self.write ( "</stream:stream>" )self._sock.close()self._sock = None@@ -481,15 +459,12 @@passdef log(self, data, inout=''):- """Logs data to the specified filehandle. Data is time stamped+ """Logs data to the specified filehandle. Data is time stampedand prefixed with inout"""if self._logFH is not None:- if self._timestampLog:- self._logFH.write("%s - %s - %s\n" % (time.asctime(), inout, data))- else:- self._logFH.write("%s - %s\n" % (inout, data ) )- self._logFH.flush()-+ self._logFH.write("%s - %s - %s\n" %+ (time.asctime(time.localtime(time.time())), inout, data ) )+def getIncomingID(self):"""Returns the streams ID"""return self._incomingID@@ -514,7 +489,7 @@self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)try:self._sock.connect((self._host, self._port))- except socket.error, e:+ except socket.error, e:self.DEBUG("socket error")raise error(e)@@ -522,8 +497,8 @@try:self.DEBUG("Attempting to create ssl socket")self._sslObj = socket.ssl( self._sock, None, None )- self._sslIssuer = self._sslObj.issuer()- self._sslServer = self._sslObj.server()+ self._sslIssuer = self._sslSock.issuer()+ self._sslServer = self._sslSock.server()except:self.DEBUG("Socket Error: No SSL Support")raise error("No SSL Support")@@ -602,4 +577,18 @@if s.getSocket() == sock:return sreturn None++++++++++++++