# Time-stamp: <2004-05-29 13:34:46 crabbkw> # Code and design by Casey Crabb (crabbkw@nafai.dyndns.org) # This code is licensed under the BSD license. # See the LICENSE file for details # # Copyright Casey Crabb (crabbkw@nafai.dyndns.org) July 2001 # # from xml.sax.handler import * # from xml.sax import * # There is a bug in expat that won't return white space between any of # the encoded characters. For now people will just have to deal, it # might be fixed in the new version of python try: from xml.parsers import expat except: from xml.parsers import pyexpat expat = pyexpat from JabberTags import * from IMCom import * from threading import * import VCardTags import string import socket import os import time import types import sys import traceback import operator def logDebug(s): if isinstance(s, types.UnicodeType): print s.encode(sys.getdefaultencoding(), "replace") sys.stdout.flush() else: print s sys.stdout.flush() class JabberContentHandler(Thread): """JCH is a parser for Jabber IM xml data. It requires a listener passed to the constructor to have the following attributes defined: mainSocket - the socket by which you are connected to the jabber server Also required are the following methods: closeSocket() - Closes the sockets and finishes cleaning up handleStream(JabberStream) - Receives the initial stream start information handleIQ(JabberIQ) - Receives IQ events handlePresence(JabberPresence) - Receives Presences Events handleMessage(JabberMessage) - Receives Message Events handleDisconnected() - Called when the server disconnected us. """ def __init__(self, imcom, ssl): "Constructor for JabberContentHandler. The imcom parameter is a\ listener with many functions defined which are used as callbacks\ as XML is parsed. A complete list of these is in the class docstring" Thread.__init__(self) self.elementStack=[] self.goalStack = [] self.goalStack.append(0) self.imcom = imcom self.parser = expat.ParserCreate() self.parser.StartElementHandler = self.startElement self.parser.EndElementHandler = self.endElement self.parser.CharacterDataHandler = self.characters self.debug = 1 self.ssl = ssl self.ignoreTag = None self.TOPLEVELGOAL = 0 self.BUILDROSTER = 1 self.GETPRESENCE = 2 self.GETMESSAGE = 3 self.GETVCARD = 4 self.REGISTER = 5 self.GETAGENTLIST = 6 self.OOB = 7 self.ADMINQUERY = 8 self.ADMINWHO = 9 self.NEGOTIATE = 10 self.NEGOTIATEFEATURE = 11 self.JIDLINKREQUEST = 12 self.DTCPCONNECTION = 13 self.JIDLINKTESTREQUEST = 14 self.DTCPCOMMENT = 15 self.DTCPUSECOMMENT = 16 self.VERSION = 17 self.XMUCUSER = 18 self.XDATASTART = 19 self.XDATAFIELD = 20 self.MUCOWNERQUERY = 21 self.XMUCUSERINVITE = 22 self.IGNOREMODE = 23 self.GETIQ = 24 self.STREAMERROR = 25 #{{{ startElement(self, name, attrs) def startElement(self, name, attrs): "startElement is a callback used by the expat parser. It is called\ when a new element is started. This particular handler will parse\ the attributes appropriately and push the correct element onto our\ element stack." ds = "Started element " + name ds = ds + "\n" + self.getAttrs(attrs) self.debugStream(ds) #{{{ Stream and Error (start) if(string.lower(name) == "stream:stream"): to = self.getAttr(attrs, "to") ffrom = self.getAttr(attrs, "from") ffrom = string.lower(self.stripFrom(ffrom)) id = self.getAttr(attrs, "id") self.goalStack.append(0) self.imcom.handleStream(JabberStream(to,ffrom,id)) return if(string.lower(name) == "stream:error"): self.goalStack.append(self.STREAMERROR) self.elementStack.append(JabberDummyTag()) # Error (Start) Subelement of EVERYTHING if(string.lower(name) == "error"): code = self.getAttr(attrs,"code") self.elementStack.append(ErrorTag(code)) return #}}} topgoal = self.goalStack[-1] sl = string.lower(name) if topgoal == self.IGNOREMODE: return #{{{ The dreaded X (start) if(string.lower(name) == "x"): ns = self.getAttr(attrs,"xmlns") if(ns == "jabber:x:delay"): stamp = self.getAttr(attrs,"stamp") e = self.elementStack.pop() e.delay = stamp self.elementStack.append(e) return #}}} #{{{ XData (start) if string.lower(name) == "x": ns = self.getAttr(attrs, "xmlns") if ns == "jabber:x:data": self.elementStack.append(JabberXDataForm()) self.goalStack.append(self.XDATASTART) return #}}} #{{{ Topgoal == XDATASTART or XDATAFIELD if topgoal == self.XDATASTART: if sl == "title" or sl == "instructions": self.elementStack.append(JabberDummyTag()) return if sl == "field": ft = JabberXDataField() ft.type = self.getAttr(attrs, "type") ft.label = self.getAttr(attrs, "label") ft.var = self.getAttr(attrs, "var") self.elementStack.append(ft) self.goalStack.append(self.XDATAFIELD) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return if topgoal == self.XDATAFIELD: if sl == "required": ft = self.elementStack.pop() ft.required = 1 self.elementStack.append(ft) return if sl == "value" or sl == "desc": self.elementStack.append(JabberDummyTag()) return if sl == "option": ft = JabberXDataField() ft.label = self.getAttr(attrs, "label") self.elementStack.append(ft) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ Message, Presence, IQ (Start) if topgoal == self.TOPLEVELGOAL or topgoal == self.ADMINWHO: if sl == "presence": to = self.getAttr(attrs,"to") ffrom = self.getAttr(attrs,"from") jid = string.lower(self.stripFrom(ffrom)) resource = self.getFromResource(ffrom) status = self.getAttr(attrs, "status") type = self.getAttr(attrs,"type") self.goalStack.append(self.GETPRESENCE) self.elementStack.append(JabberPresence(to,jid,type,resource,status)) return if topgoal == self.TOPLEVELGOAL: if sl == "message": to = self.getAttr(attrs,"to") ffrom = self.getAttr(attrs,"from") resource = self.getFromResource(ffrom) tmp = self.stripFrom(ffrom) if tmp != None: tmp = tmp.lower() ffrom = tmp id = self.getAttr(attrs,"id") type = self.getAttr(attrs,"type") if(type == None): type = "" self.goalStack.append(self.GETMESSAGE) self.elementStack.append(JabberMessage(to,ffrom,resource,id,type)) return if(string.lower(name) == "iq"): to = self.getAttr(attrs, "to") toResource = self.getFromResource(to) to = self.stripFrom(to) ffrom = self.getAttr(attrs, "from") fromResource = self.getFromResource(ffrom) ffrom = self.stripFrom(ffrom) id = self.getAttr(attrs, "id") type = self.getAttr(attrs, "type") self.elementStack.append(JabberIQ(to,toResource,ffrom,fromResource,id,type)) self.goalStack.append(self.GETIQ) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ Query (start) if topgoal == self.GETIQ and sl == "query": ns = self.getAttr(attrs,"xmlns") iq = self.elementStack.pop() iq.ns = ns self.elementStack.append(iq) if(ns == "jabber:iq:roster"): self.elementStack.append(JabberRoster()) self.goalStack.append(self.BUILDROSTER) return if(ns == "jabber:iq:register"): self.elementStack.append(JabberRegister()) self.goalStack.append(self.REGISTER) return if(ns == "jabber:iq:oob"): self.elementStack.append(JabberOOB()) self.goalStack.append(self.OOB) return if(ns == "jabber:iq:agents"): self.elementStack.append(JabberAgentList()) self.goalStack.append(self.GETAGENTLIST) return if(ns == "jabber:iq:admin"): self.elementStack.append(JabberAdmin()) self.goalStack.append(self.ADMINQUERY) return if(ns == "jabber:iq:negotiate"): self.elementStack.append(JabberNegotiate()) self.goalStack.append(self.NEGOTIATE) return if(ns == "vcard-temp"): self.elementStack.append(VCardTags.VCard()) self.goalStack.append(self.GETVCARD) return if(ns == "jabber:iq:jidlink"): self.elementStack.append(JabberIQQueryJidLink()) self.goalStack.append(self.JIDLINKREQUEST) return if(ns == "http://jabber.org/protocol/dtcp"): self.elementStack.append(JabberIQQueryDTCP()) self.goalStack.append(self.DTCPCONNECTION) return if(ns == "jabber:iq:jidlink-test"): self.elementStack.append(JabberDummyTag()) self.goalStack.append(self.JIDLINKTESTREQUEST) return if(ns == "jabber:iq:version"): self.elementStack.append(JabberDummyTag()) self.goalStack.append(self.VERSION) return if(ns == "http://jabber.org/protocol/muc#owner"): self.elementStack.append(JabberDummyTag()) self.goalStack.append(self.MUCOWNERQUERY) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ VCard (Start) if topgoal == self.GETIQ and sl == "vcard": iq = self.elementStack.pop() iq.ns = "vcard-temp" self.elementStack.append(iq) self.goalStack.append(self.GETVCARD) self.elementStack.append(VCardTags.VCard()) return if(topgoal == self.GETVCARD): sl = string.lower(name) if(sl == "fn" or sl == "given" or sl == "family" or sl == "nickname" or sl == "email"): self.elementStack.append(VCardTags.VCardTemp()) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} if topgoal == self.GETIQ: self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #{{{ jabber:IQ:ADMIN WHO START if(topgoal == self.ADMINQUERY): sl = string.lower(name) if(sl == "who"): self.elementStack.append(JabberAdminWho()) self.goalStack.append(self.ADMINWHO) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ self.GETAGENTLIST start if(topgoal == self.GETAGENTLIST): sl = string.lower(name) if(sl == "agent"): jid = self.getAttr(attrs,"jid") self.elementStack.append(JabberAgent(jid)) return if(sl == "name" or sl == "transport"): self.elementStack.append(JabberDummyTag()) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ self.REGISTER start if(topgoal == self.REGISTER): # Key (start) if(string.lower(name) == "key"): self.elementStack.append(JabberRegisterKey()) return # instructions, username, nick, password, name, first, last, email # address, city, state, zip, phone, url, date, misc, text sl = string.lower(name) if(sl == "instructions" or sl == "username" or sl == "nick" or sl == "password" or sl == "name" or sl == "first" or sl == "last" or sl == "email" or sl == "address" or sl == "city" or sl == "state" or sl == "zip" or sl == "phone" or sl == "url" or sl == "date" or sl == "misc" or sl == "text"): self.elementStack.append(JabberDummyTag()) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ self.BUILDROSTER start if(topgoal == self.BUILDROSTER): # Item (start) if(string.lower(name) == "item"): # BUG BUG BUG -- should we string.lower the jid?! jid = string.lower(self.getAttr(attrs,"jid")) name = self.getAttr(attrs,"name") subscription = self.getAttr(attrs,"subscription") ask = self.getAttr(attrs,"ask") self.elementStack.append(JabberRosterItem(jid,name,subscription,ask)) return # Group support for roster items if(string.lower(name) == "group"): dt = JabberDummyTag() self.elementStack.append(dt) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ self.OOB start if(topgoal == self.OOB): sl = string.lower(name) if(sl == "url" or sl == "desc"): self.elementStack.append(JabberDummyTag()) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ self.GETPRESENCE start if(topgoal == self.GETPRESENCE): # Status (Start) Presence Subelement if(string.lower(name) == "status"): self.elementStack.append(JabberStatus()) return # Show (Start) Presence Subelement if(string.lower(name) == "show"): self.elementStack.append(JabberShow()) return # Priority (Start) Presence Subelement if(string.lower(name) == "priority"): self.elementStack.append(JabberDummyTag()) return if(string.lower(name) == "x"): ns = self.getAttr(attrs, "xmlns") if ns == 'http://jabber.org/protocol/muc#user': self.goalStack.append(self.XMUCUSER) return return if sl == "created": ns = self.getAttr(attrs, "xmlns") if ns == 'http://jabber.org/protocol/muc#owner': pres = self.elementStack.pop() pres.createdConference = 1 self.elementStack.append(pres) return return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ self.XMUCUSER starts if topgoal == self.XMUCUSER: if sl == "item": presTag = self.elementStack.pop() presTag.mucNick = self.getAttr(attrs, "nick") presTag.mucAffiliation = self.getAttr(attrs, "affiliation") presTag.mucRole = self.getAttr(attrs, "role") presTag.mucJID = self.getAttr(attrs, "jid") self.elementStack.append(presTag) return if sl == "status": presTag = self.elementStack.pop() presTag.mucCode = self.getAttr(attrs, "code") self.elementStack.append(presTag) return if sl == "reason": self.elementStack.append(JabberDummyTag()) return if sl == "actor": presTag = self.elementStack.pop() presTag.mucActor = self.getAttr(attrs, "jid") return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ self.GETMESSAGE start if topgoal == self.GETMESSAGE: # Body (Start) Message Subelement if sl == "body": self.elementStack.append(JabberBody()) return # Thread (Start) Message Subelement if sl == "thread": self.elementStack.append(JabberBody()) return if sl == "x": ns = self.getAttr(attrs, "xmlns") if ns == "http://jabber.org/protocol/muc#user": self.goalStack.append(self.XMUCUSERINVITE) return if sl == "subject": self.elementStack.append(JabberDummyTag()) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return if topgoal == self.XMUCUSERINVITE: if sl == "invite": msgTag = self.elementStack.pop() msgTag.mucInviteFrom = self.getAttr(attrs, "from") self.elementStack.append(msgTag) return if sl == "password" or sl == "reason": self.elementStack.append(JabberDummyTag()) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ Negotiate start if(topgoal == self.NEGOTIATE): sl = string.lower(name) if(sl == "feature"): catagory = self.getAttr(attrs, "catagory") type = self.getAttr(attrs, "type") self.elementStack.append(JabberNegotiateFeature(catagory, type)) self.goalStack.append(self.NEGOTIATEFEATURE) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return if(topgoal == self.NEGOTIATEFEATURE): sl = string.lower(name) if(sl == "option"): self.elementStack.append(JabberDummyTag()) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ JIDLink if(topgoal == self.JIDLINKREQUEST): sl = string.lower(name) if(sl == "key"): self.elementStack.append(JabberDummyTag()) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ JIDLink-test if(topgoal == self.JIDLINKTESTREQUEST): sl = string.lower(name) if(sl == "key"): jdt = JabberDummyTag() self.elementStack.append(jdt) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ DTCP Connections if(topgoal == self.DTCPCONNECTION): sl = string.lower(name) if(sl == "comment"): self.elementStack.append(JabberDummyTag()) self.goalStack.append(self.DTCPCOMMENT) return if(sl == "key" or sl == "comment" or sl == "verify"): self.elementStack.append(JabberDummyTag()) return if(sl == "host"): jdt = JabberDummyTag() jdt.port = self.getAttr(attrs, "port") self.elementStack.append(jdt) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return if(topgoal == self.DTCPCOMMENT): sl = string.lower(name) if(sl == "use"): ns = self.getAttr(attrs, "xmlns") if ns == "jabber:iq:jidlink": self.elementStack.append(JabberDummyTag()) self.goalStack.append(self.DTCPUSECOMMENT) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #{{{ Version Support if(topgoal == self.VERSION): sl = string.lower(name) if(sl == "name" or sl == "version" or sl == "os"): self.elementStack.append(JabberDummyTag()) return self.ignoreTag = sl self.goalStack.append(self.IGNOREMODE) return #}}} #}}} #{{{ endElement(self, name) def endElement(self, name): "startElement is a callback used by the expat parser. It is called\ when a new element is started. This particular handler will parse\ the attributes appropriately and push the correct element onto our\ element stack." self.debugStream("ended element " + name) #{{{ Stream and Error tags, ending # Stream (end) if(string.lower(name) == "stream:stream"): self.imcom.handleStreamClose() return if string.lower(name) == "stream:error": self.imcom.handleStreamError(self.elementStack.pop()) return # Error (end) if(string.lower(name) == "error"): e = self.elementStack.pop() t = self.elementStack.pop() t.error = e self.elementStack.append(t) return #}}} # Top level end topgoal = self.goalStack[-1] sl = string.lower(name) if topgoal == self.IGNOREMODE: if sl == self.ignoreTag: self.goalStack.pop() return return # IQ (end) if(sl == "iq"): self.goalStack.pop() self.imcom.handleIQ(self.elementStack.pop()) return #{{{ Query (End) IQ Subelement if(string.lower(name) == "query" and (topgoal == self.OOB or topgoal == self.BUILDROSTER or topgoal == self.REGISTER or topgoal == self.GETAGENTLIST or topgoal == self.ADMINQUERY or topgoal == self.NEGOTIATE or topgoal == self.JIDLINKREQUEST or topgoal == self.DTCPCONNECTION or topgoal == self.JIDLINKTESTREQUEST or topgoal == self.VERSION or topgoal == self.MUCOWNERQUERY)): query = self.elementStack.pop() iq = self.elementStack.pop() iq.query = query self.elementStack.append(iq) self.goalStack.pop() return #}}} #{{{ Presence (end) if(topgoal == self.GETPRESENCE): if sl == "presence": if self.goalStack[-2] == self.ADMINWHO: self.goalStack.pop() p = self.elementStack.pop() w = self.elementStack.pop() w.presencelist.append(p) self.elementStack.append(w) return self.goalStack.pop() self.imcom.handlePresence(self.elementStack.pop()) return # Status (End) Presence Subelement if(sl == "status"): stat = self.elementStack.pop() pres = self.elementStack.pop() pres.status = stat self.elementStack.append(pres) return # Show (End) Presence Subelement if(sl == "show"): show = self.elementStack.pop() pres = self.elementStack.pop() pres.show = show self.elementStack.append(pres) return if(sl == "priority"): pri = self.elementStack.pop() pres = self.elementStack.pop() pres.priority = int(pri.text) self.elementStack.append(pres) return #}}} #{{{ XDataForm, XDataField if topgoal == self.XDATASTART: if sl == "instructions": tmp = self.elementStack.pop() form = self.elementStack.pop() form.instructions = tmp.text self.elementStack.append(form) return if sl == "title": tmp = self.elementStack.pop() form = self.elementStack.pop() form.title = tmp.text self.elementStack.append(form) return if sl == "x": form = self.elementStack.pop() something = self.elementStack.pop() something.xdataform = form self.elementStack.append(something) self.goalStack.pop() return return if topgoal == self.XDATAFIELD: if sl == "value": tmp = self.elementStack.pop() field = self.elementStack.pop() field.value = tmp.text self.elementStack.append(field) return if sl == "desc": tmp = self.elementStack.pop() field = self.elementStack.pop() field.description = tmp.text self.elementStack.append(field) return if sl == "option": option = self.elementStack.pop() field = self.elementStack.pop() field.options.append([option.label, option.value]) self.elementStack.append(field) return if sl == "field": field = self.elementStack.pop() form = self.elementStack.pop() form.fields.append([field.type, field.var, field.label, field.value, field.options, field.required, field.description]) self.elementStack.append(form) self.goalStack.pop() return #}}} #{{{ XMUCUSER end if topgoal == self.XMUCUSER: if sl == "x": self.goalStack.pop() return if sl == "reason": reason = self.elementStack.pop() presTag = self.elementStack.pop() presTag.mucReason = reason.text self.elementStack.append(presTag) return return #}}} #{{{ Message (end) if string.lower(name) == "message": msg = self.elementStack.pop() self.goalStack.pop() self.imcom.handleMessage(msg) return # GETMESSAGE (end) if topgoal == self.GETMESSAGE: # Body (end) Message Subelement if sl == "body": body = self.elementStack.pop() msg = self.elementStack.pop() msg.body = body.text self.elementStack.append(msg) return # Thread (end) Message SubElement if sl == "thread": thread = self.elementStack.pop() msg = self.elementStack.pop() msg.thread = thread.text self.elementStack.append(msg) return if sl == "subject": sub = self.elementStack.pop() msg = self.elementStack.pop() msg.subject = sub.text self.elementStack.append(msg) return return if topgoal == self.XMUCUSERINVITE: if sl == "reason": tmp = self.elementStack.pop() msg = self.elementStack.pop() msg.mucInviteReason = tmp.text self.elementStack.append(msg) return if sl == "password": tmp = self.elementStack.pop() msg = self.elementStack.pop() msg.mucInvitePassword = tmp.text self.elementStack.append(msg) return if sl == "x": self.goalStack.pop() return return #}}} #{{{ jabber:iq:admin WHO end if(topgoal == self.ADMINWHO): if(sl == "who"): w = self.elementStack.pop() q = self.elementStack.pop() q.w = w self.elementStack.append(q) self.goalStack.pop() return return #}}} #{{{ jabber:iq:register (End) Goal is REGISTER # Switch on element name. if(topgoal == self.REGISTER): if(sl == "username" or sl == "nick" or sl == "password" or sl == "name" or sl == "first" or sl == "last" or sl == "email" or sl == "address" or sl == "city" or sl == "state" or sl == "zip" or sl == "phone" or sl == "url" or sl == "date" or sl == "misc" or sl == "text"): d = self.elementStack.pop() q = self.elementStack.pop() q.fields.append(sl) self.elementStack.append(q) return if(sl == "instructions"): k = self.elementStack.pop() q = self.elementStack.pop() if(hasattr(k,"text")): q.instructions = k.text self.elementStack.append(q) return if(sl == "key"): k = self.elementStack.pop() q = self.elementStack.pop() if(hasattr(k,"text")): q.key = k.text self.elementStack.append(q) return return #}}} #{{{ jabber:iq:oob (end) if(topgoal == self.OOB): if(sl == "url"): dt = self.elementStack.pop() q = self.elementStack.pop() q.url = dt.text self.elementStack.append(q) return if(sl == "desc"): dt = self.elementStack.pop() q = self.elementStack.pop() q.desc = dt.text self.elementStack.append(q) return return #}}} #{{{ BUILDROSTER (end) if(topgoal == self.BUILDROSTER): # Item (End) IQ Subelement if(sl == "item"): rosterItem = self.elementStack.pop() roster = self.elementStack.pop() roster.users.append(rosterItem) self.elementStack.append(roster) return # Group (End) Item Subelement if(sl == "group"): gt = self.elementStack.pop() ri = self.elementStack.pop() if(hasattr(gt,"text") and gt.text != None and len(gt.text) > 0): ri.groups.append(gt.text) self.elementStack.append(ri) return else: self.elementStack.append(ri) return #}}} #{{{ VCard (end) if(topgoal == self.GETVCARD): # VCard (end) if(sl == "vcard" or sl == "query"): vc = self.elementStack.pop() iq = self.elementStack.pop() iq.query = vc self.elementStack.append(iq) self.goalStack.pop() return # FN (end) VCard Subelement if(sl == "fn"): te = self.elementStack.pop() vc = self.elementStack.pop() vc.fn = te.text self.elementStack.append(vc) return # Given (end) VCard Subelement if(sl == "given"): te = self.elementStack.pop() vc = self.elementStack.pop() vc.given = te.text self.elementStack.append(vc) return # Family (end) VCard Subelement if(sl == "family"): te = self.elementStack.pop() vc = self.elementStack.pop() vc.family = te.text self.elementStack.append(vc) return # Nickname (end) VCard Subelement if(sl == "nickname"): te = self.elementStack.pop() vc = self.elementStack.pop() vc.nickname = te.text self.elementStack.append(vc) return # Email (end) VCard Subelement if(sl == "email"): te = self.elementStack.pop() vc = self.elementStack.pop() vc.email = te.text self.elementStack.append(vc) return return #}}} #{{{ Agent list if(topgoal == self.GETAGENTLIST): if(sl == "agent"): a = self.elementStack.pop() q = self.elementStack.pop() q.agentlist.append(a) self.elementStack.append(q) return if(sl == "name"): n = self.elementStack.pop() a = self.elementStack.pop() if(hasattr(n,"text")): a.name = n.text else: a.name = None self.elementStack.append(a) return if(sl == "transport"): t = self.elementStack.pop() a = self.elementStack.pop() if(hasattr(t,"text")): a.transport = t.text else: a.name = None self.elementStack.append(a) return return #}}} #{{{ negotiation of a single feature if(topgoal == self.NEGOTIATEFEATURE): if(sl == "feature"): feature = self.elementStack.pop() negs = self.elementStack.pop() negs.features.append(feature) self.elementStack.append(negs) self.goalStack.pop() return if(sl == "option"): option = self.elementStack.pop() feature = self.elementStack.pop() if(hasattr(option,"text")): feature.options.append(option.text) self.elementStack.append(feature) return return #}}} #{{{ request to establish a jid link if(topgoal == self.JIDLINKREQUEST): if(sl == "key"): key = self.elementStack.pop() query = self.elementStack.pop() if hasattr(key, "text"): query.key = key.text else: query.key = None self.elementStack.append(query) return return #}}} #{{{ request to test a jid link if(topgoal == self.JIDLINKTESTREQUEST): if(sl == "key"): key = self.elementStack.pop() query = self.elementStack.pop() if hasattr(key, "text"): query.key = key.text else: query.key = None self.elementStack.append(query) return return #}}} #{{{ dtcp connection handling if(topgoal == self.DTCPCONNECTION): if(sl == "key"): key = self.elementStack.pop() dtcpQuery = self.elementStack.pop() if hasattr(key, "text"): dtcpQuery.key = key.text self.elementStack.append(dtcpQuery) return if(sl == "verify"): verify = self.elementStack.pop() dtcpQuery = self.elementStack.pop() if hasattr(verify, "text"): dtcpQuery.verify = verify.text self.elementStack.append(dtcpQuery) return if(sl == "host"): host = self.elementStack.pop() dtcpQuery = self.elementStack.pop() if hasattr(host, "text"): dtcpQuery.hosts.append([host.text, host.port]) self.elementStack.append(dtcpQuery) return return if topgoal == self.DTCPCOMMENT: if(sl == "comment"): comment = self.elementStack.pop() dtcpQuery = self.elementStack.pop() if hasattr(comment, "text"): dtcpQuery.comment = comment.text self.elementStack.append(dtcpQuery) self.goalStack.pop() return return if topgoal == self.DTCPUSECOMMENT: if sl == "use": use = self.elementStack.pop() comment = self.elementStack.pop() dtcpQuery = self.elementStack.pop() if hasattr(use, "text"): dtcpQuery.jidLinkKey = use.text self.elementStack.append(dtcpQuery) self.elementStack.append(comment) self.goalStack.pop() return return #}}} #{{{ Version support if(topgoal == self.VERSION): if(sl == "name"): name = self.elementStack.pop() versionQuery = self.elementStack.pop() versionQuery.name = name.text self.elementStack.append(versionQuery) return if(sl == "os"): os = self.elementStack.pop() versionQuery = self.elementStack.pop() versionQuery.os = os.text self.elementStack.append(versionQuery) return if(sl == "version"): version = self.elementStack.pop() versionQuery = self.elementStack.pop() versionQuery.version = version.text self.elementStack.append(versionQuery) return return #}}} #}}} #{{{ characters(self, content) content is a string of the cdata def characters(self, content): "characters is another callback for the expat parser. It is called\ when CDATA is read. Unfortunately it doesn't return the CDATA verbatim\ , it returns chunks of CDATA divided by escaped charaters or newlines.\ There are many hacks in this function to deal with that, but since\ white space around all split points is lost I have to guess at what\ to fill in." if len(string.strip(content)) < 0: return if(self.debug): self.debugStream("Content: >" + content) if len(self.elementStack) == 0: return element = self.elementStack.pop() if not hasattr(element, "text") or element.text == None: element.text = content self.elementStack.append(element) return element.text = element.text + content self.elementStack.append(element) return # not needed anymore? # try: # blah = element.text # if(blah == None): # element.text = content # self.elementStack.append(element) # return # except: # element.text = content # self.elementStack.append(element) # return # if(element.text[-1] == "'" or element.text[-1] == ">" or # element.text[-1] == '"' or element.text[-1] == "<" or # element.text[-1] == "&" or content[0] == "'" or # content[0] == '"' or content[0] == ">" or # content[0] == "<" or content[0] == "&"): # element.text = element.text + content # else: # element.text = element.text + content # "\n" + content # self.elementStack.append(element) # self.debugStream("\tcontent: " + string.strip(content)) #}}} #{{{ start doc, end doc (empty) # signals the start of a document def startDocument(self): pass # signals the end of the document def endDocument(self): pass #}}} #{{{ helper functions def getAttr(self, attrs, name): try: return attrs[name] except: return None def getAttrs(self, attrs): "Prints out the key value pairs in an AttributesNS instance" retval = "" keys = attrs.keys() for temp in keys: retval = retval+"\t"+temp+" is "+attrs[temp]+"\n" return retval def debugStream(self, string): "If debug is turned on, print out the string" #if(self.debug): # logDebug(string) pass def feed(self, data): "Feed data read from the socket to the parser" # try: # filename = os.path.join(os.path.expanduser("~"),".imcom","incoming-packet-stream.log") # # might have to use... # # logfile = codecs.open(filename, "ab+", "utf8") # # hopefully we can just raw-log though. # logfile = file(filename, "ab+") # logfile.write(data) # logfile.flush() # logfile.close() # except Exception, inst: # print type(inst) # print inst.args # print inst self.parser.Parse(data,0) def stripFrom(self, ffrom): "This function strips the resource information from a JID" result = ffrom if(ffrom != None and -1 != string.find(ffrom,"/")): result = ffrom[:string.find(ffrom,"/")] if(result != None): result = string.lower(result) return result def getFromResource(self, ffrom): "This function returns the resource information from a JID" result = ffrom if(ffrom != None and -1 != string.find(ffrom,"/")): result = ffrom[string.find(ffrom,'/')+1:] else: result = "" return result #}}} #{{{ run(self): def run(self): "The start function should be called, and not this one. Start will\ create a new thread and then run this function. The purpose of this\ function is to sit and read from the socket, and feed the xml parser." self.running = 1 if(self.ssl and (sys.version_info[0] < 2 or (sys.version_info[0] == 2 and sys.version_info[1] < 2))): self.imcom.tempsocket.setblocking(0) while(self.running): try: if(self.ssl): data = self.imcom.mainSocket.read(4096) else: data = self.imcom.mainSocket.recv(4096) if(self.debug and data): logDebug("Recv :> " + unicode(data, "utf-8").encode(self.imcom.encoding)) self.feed(data) except: a,b,c = sys.exc_info() if(self.ssl and operator.isSequenceType(b) and b[0] == 11): time.sleep(.1) data = None continue if(operator.isSequenceType(b) and hasattr(b,"__len__") and len(b) > 0 and b[0] == 4): continue if(operator.isSequenceType(b) and hasattr(b,"args") and len(b.args) > 0 and b.args[0] == 4): continue if str(a) == "exceptions.SystemExit": os.abort() return if 1: print "Receive Exception\n" traceback.print_exc() print "a is ", a print "b is ", b print if(self.running): self.running = 0 self.imcom.handleDisconnected() if(self.imcom.mainSocket): if(self.ssl != 0 and self.imcom.tempsocket): self.imcom.tempsocket.close() else: self.imcom.mainSocket.close() #}}}