# Time-stamp: <2004-04-30 13:18:36 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 # #{{{ emacs instructions # I highly recommend editing this file in emacs using Anders Lindgren's Folding mode, # available at http://user.it.uu.se/~andersl/emacs.shtml#folding # here's my .emacs modifications # ;;; # ;;; Folding mode stuff # ;;; # (require 'folding) # (folding-add-to-marks-list 'python-mode "#{{{" "#}}}" nil t) # ... # (add-hook 'python-mode-hook # (progn # (folding-mode) # (global-set-key "\C-cq" 'folding-toggle-show-hide)) #}}} #{{{ imports from JabberTags import * from threading import * from JabberHandler import * from IHTTPServer import IMComHTTPServer, FileGet #from DTCPSocket import DTCPSocket #import DTCPSocketManager #import JIDLink import string import socket import os import sha import sys import time import types import operator import traceback import random #}}} #{{{ constants and helper functions errorCodes = {"0":"Unknown or unspecified error", "400":"Bad Request", "401":"Unauthorized", "402":"Payment Required", "403":"Forbidden", "404":"Not Found", "405":"Not Allowed", "406":"Not Acceptable", "407":"Registration Required", "408":"Request Timeout", "409":"Username Not Available", "500":"Internal Server Error", "501":"Not Implemented", "502":"Remote Server Error", "503":"Service Unavailable", "504":"Remove Server Timeout"} def logDebug(s): if isinstance(s, types.UnicodeType): print s.encode(sys.getdefaultencoding(),'replace') sys.stdout.flush() else: print s sys.stdout.flush() #}}} class IMCom(Thread): #{{{ init(self, listener) def __init__(self, listener): Thread.__init__(self) self.VERSION = "1.33" self.NAME = "IMCom" self.jch = None self.idhash = {} self.nickhash = {} self.jidhash = {} self.agenthash = {} self.grouphash = {} #group names are the keys, lists of JIDs the data self.gjidhash = {} #jids are keys, list of groups are the data self.reshash = {} #jids are keys, (last_resource, high_priority, {res1:(stat,show,pri),res2:(stat,show,pri)}) is data, self.filehash = {} self.preshash = {} # jids are keys, (available, show, status) are values self.subscriptions = {} # mapping JID->subscription state self.asks = {} # mapping JID->ask status self.conferences = {} #jids are keys, (conf-nick-name, your-nick-name, {nick:(stat,show,affiliation,role,jid),nick2:(stat,show,aff,role,jid),...}) self.confnick = {} #nicks are keys, values are jids of conference self.id = 0 self.mainSocket = None self.listener = listener self.debug = 0 self.setDaemon(1) self.running = 1 self.keepalive = "\n" self.status = "online" self.sendport = 8000 self.ssl = 0 self.clearpass = 0 self.currentStatus = "online" self.currentStatusReason = "logging in" self.priority = None #self.jidLinkHash = {} # key is fully Qualified Jid, value is a list of established JIDLink objects #self.jidLinkKeys = {} # key is fully Qualified jid, value is a list of unused JIDLink Objects self.iqTempHash = {} # key is an IQ id, value is arbitrary, used for storage of iq data. #self.DTCPManager = None #self.DTCPPORT = 8000 # Callbacks self.cbHandleDisconnected = self.dummyWrapper self.cbHandleAdminWho = self.dummyWrapper self.cbHandlePresenceUpdate = self.dummyWrapper self.cbHandlePresenceError = self.dummyWrapper self.cbHandleMessageReceive = self.dummyWrapper self.cbHandleMessageError = self.dummyWrapper self.cbHandleIQError = self.dummyWrapper self.cbHandleInfoError = self.dummyWrapper self.cbHandleFileReceive = self.dummyWrapper self.cbHandleFileReceived = self.dummyWrapper self.cbHandleFileErrorReceived = self.dummyWrapper self.cbHandleAgentList = self.dummyWrapper self.cbHandleAgentRegister = self.dummyWrapper self.cbHandleAgentRegistered = self.dummyWrapper self.cbHandleSubscribe = self.dummyWrapper self.cbHandleSubscribed = self.dummyWrapper self.cbHandleUnsubscribed = self.dummyWrapper self.cbHandleUnsubscribe = self.dummyWrapper self.cbHandleRosterUpdateCheck = self.dummyWrapper self.cbHandleRosterUpdate = self.dummyWrapper self.cbHandleVCardSubmit = self.dummyWrapper self.cbHandleVCard = self.dummyWrapper self.cbHandleNoVCard = self.dummyWrapper self.cbHandleLogin = self.dummyWrapper self.cbHandleGrabRoster = self.dummyWrapper self.cbHandleAgentUnRegistered = self.dummyWrapper self.cbHandleNegotiationRequest = self.dummyWrapper self.cbHandleNegotiationResult = self.dummyWrapper self.cbHandleVersionResponse = self.dummyWrapper self.cbHandleChangePassword = self.dummyWrapper self.cbHandleConferenceMessage = self.dummyWrapper self.cbHandleConferencePresence = self.dummyWrapper self.cbHandleConferenceCreated = self.dummyWrapper self.cbHandleConferenceNicknameChange = self.dummyWrapper self.cbHandleConferenceNicknameChangeSuccess = self.dummyWrapper self.cbHandleConferenceInvite = self.dummyWrapper self.cbHandleConferenceRoomRegister = self.dummyWrapper self.cbHandleConferenceRoomRegisterSuccess = self.dummyWrapper self.cbHandleConferenceSubject = self.dummyWrapper self.cbHandleConferenceUserKicked = self.dummyWrapper self.cbHandleConferenceKicked = self.dummyWrapper self.cbHandleConferenceUserBanned = self.dummyWrapper self.cbHandleConferenceBanned = self.dummyWrapper self.cbHandleConferenceDestroyed = self.dummyWrapper self.cbHandleConferenceConfig = self.dummyWrapper self.cbHandleConferenceConfigSet = self.dummyWrapper self.cbHandleNickCollision = self.dummyWrapper self.cbHandleNickHasSlash = self.dummyWrapper self.cbHandleStreamError = self.dummyWrapper self.cbHandleStreamClose = self.dummyWrapper #}}} #{{{ Utility Functions # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # ------------------------------------------------------------------------- # Utility Functions # ------------------------------------------------------------------------- # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ def dummyWrapper(self, *args): if(self.debug): text = "Call to dummyWrapper with args: [ " for a in args: text = text + str(a) + ", " print text + " ] " pass # Fix text so it is proper XML def normalize(self, str): if str != None: str = string.replace( str, "&", "&" ); str = string.replace( str, '"', """); str = string.replace( str, "'", "'"); str = string.replace( str, "<", "<"); str = string.replace( str, ">", ">"); return str; # Send keepalive packets every 60 seconds def run(self): while(self.running): time.sleep(60) #self.listener.handleIdleTick() #self.sendPacket(self.keepalive) if(self.running): self.sendPacket("\n") def setDebug(self, debug): "Sets the value of the debug variable for both the XML parser \ and the IMCom handler." self.debug = debug if(self.jch != None): self.jch.debug = debug def updateHash(self, hash, oldkey, newkey, value): keys = hash.keys() for item in keys: if(item == oldkey): del hash[item] hash[newkey] = value def getFullyQualifiedJid(self, to, resource): if resource == None: if self.reshash.has_key(to): resource = self.reshash[to][0] else: logDebug("Resource required for fully qualified jid") return tojid = to + "/" + resource return tojid def getOutsideIPAddress(self): if hasattr(self, "tempsocket"): return self.tempsocket.getsockname()[0] else: return self.mainSocket.getsockname()[0] def isMyIPPrivate(self): ip = self.getOutsideIPAddress() if "192.168" == ip[:7]: return 1 if "10.0.0" == ip[:7]: return 1 if "127.0.0" == ip[:7]: return 1 #if "172.16" == ip[:6]: this should do 172.16.0.0/12 not 172.16.0.0/16 # return 1 return 0 def incrementListenPort(self): self.sendport = self.sendport + 1 % 65000 if self.sendport < 8000: self.sendport = 8000 def getUnusedJIDLink(self, jid, key): print "looking for key", key, "with respect to", jid for jl in self.jidLinkKeys[jid]: print "jl.key is", jl.key if jl.key == key: print "returning jl" return jl return None def jidlinkEstablished(self, jid, theJL): if not self.jidLinkKeys.has_key(jid): return try: self.jidLinkKeys[jid].remove(theJL) except: pass if not self.jidLinkHash.has_key(jid): self.jidLinkHash[jid] = [] self.jidLinkHash[jid].append(theJL) print "jidLinkEstablished finished: There are", len(self.jidLinkHash[jid]), "jidlinks for", jid def removeJIDLink(self, theJL): jid = self.getFullyQualifiedJid(theJL.to, theJL.resource) try: self.jidLinkHash[jid].remove(theJL) except: pass print "removeJIDLink finished: There are", len(self.jidLinkHash[jid]), "jidlinks for", jid def doesJIDLinkKeyExist(self, jid, theKey): if self.jidLinkHash.has_key(jid): for jl in self.jidLinkHash[jid]: if jl.key == theKey: return 1 #for jl in self.jidLinkKeys[jid]: # if jl.key == theKey: # return 1 return 0 # end api utility functions #}}} #{{{ API Functions for the profile,login procedure # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # ------------------------------------------------------------------------- # API Functions for the profile,login procedure # ------------------------------------------------------------------------- # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ def changeProfile(self, host, port, user, password, resource, ssl, clearpass, priority, encoding): """Sets up the current profile to use. This function MUST be called before connect() is called. Return values are tuples (value, message): 0 - Success 1 - Name resolution error 2 - Socket error On error the exception is still available in sys.exc_info(). """ if host == None: print "You didn't specify a host." return (3, "Invalid parameters!") if port == None: print "You didn't specify a port." return (3, "Invalid parameters!") if user == None: print "You didn't specify a user." return (3, "Invalid parameters!") if password == None: print "You didn't specify a password." return (3, "Invalid parameters!") if resource == None: print "You didn't specify a resource." return (3, "Invalid parameters!") self.host = host self.port = port self.user = user self.password = password self.resource = resource if priority < 6: priority = 6 self.priority = priority if (encoding): self.encoding = encoding else: self.encoding = sys.getdefaultencoding() if(ssl): self.ssl = 1 else: self.ssl = 0 if(clearpass): self.clearpass = 1 else: self.clearpass = 0 try: if(self.mainSocket != None): # print "Disconnecting" self.disconnect() self.jidhash = {} self.nickhash = {} self.idhash = {} self.filehash = {} self.preshash = {} self.mainSocket = None # print "Connecting..." retval = self.connect() return retval except: # print "IMCom.changeProfile failed" traceback.print_exc() a,b,c = sys.exc_info() print a print b return -1 def connect(self): """Actually connects to the jabber server and initiates communications. It is important to call changeProfile() before calling this function. This function will automatically start the parser thread and the keep-alive thread. Return values are tuples, (value, message): 0 - Success 1 - Host resolution problem 2 - Connection refused On Error the exception information will still be available in sys.exc_info()""" error = None try: tempsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) error = tempsocket.connect((self.host,self.port)) except socket.gaierror: a,b,c = sys.exc_info() return (1,b[1]) except socket.error: a,b,c = sys.exc_info() return (2,b[1]) if(self.ssl!=0): self.mainSocket = socket.ssl(tempsocket, None, None) self.tempsocket = tempsocket else: self.mainSocket = tempsocket #self.DTCPManager = DTCPSocketManager.DTCPSocketManager(self.getOutsideIPAddress(), self.DTCPPORT) #self.DTCPManager.start() self.jch = JabberContentHandler(self, self.ssl) self.jch.debug = self.debug self.keepalive = "\n" self.status = "unknown" self.sendPacket('') self.sendPacket("") self.jch.setDaemon(1) self.jch.start() #self.currentStatus = "online" #self.currentStatusReason = "online" self.running = 1 self.start() return (0,"Success") def disconnect(self, mangleFunctions=1): "Disconnect sends the server a \"We're going offline\" message, \ followed by the stream termination sequence, then closes the socket." self.sendOffline() self.sendPacket("") self.closeSocket(mangleFunctions) def closeSocket(self, mangleFunctions=1): "This function should not be called by the user, it forcefully \ terminates the connection which may cause the jabber server to \ become confused about the user's presence. It is here to handle \ errors in the socket connection. It is called by the xml parser \ thread." self.running = 0 if self.jch != None: self.jch.running = 0 if(self.ssl != 0): self.tempsocket.close() else: self.mainSocket.close() if(mangleFunctions == 1): self.mangleFunctions() self.mainSocket = None def nullFunction(self, *rest): pass def mangleFunctions(self): "A user should never call this function. The purpose of this \ function is to mangle function which may cause problems when \ the connection has already been closed" if(self.debug): logDebug("Mangling functions") self.handleDisconnected = self.nullFunction self.sendPacket = self.nullFunction self.closeSocket = self.nullFunction self.disconnect = self.nullFunction def getRoster(self): self.id = self.id + 1 id = "getroster%d"%self.id tosend = "" self.sendPacket(tosend) self.idhash[id] = "getroster" # end api functions for login,profile handling #}}} #{{{ API Functions for sending requests to the server #{{{ sendPacket(self, text) def sendPacket(self, text): "Sends a packet of text to the server" if(self.mainSocket == None or self.running == 0): self.running = 0 if self.jch != None: self.jch.running = 0 self.mangleFunctions() return try: text = text.encode("utf-8","replace") if(self.debug and text != "\n"): logDebug("Sending: " + unicode(text, "utf-8").encode(self.encoding,"replace")) if(self.ssl != 0): self.mainSocket.write(text) else: self.mainSocket.send(text) except: logDebug("Error sending: " + unicode(text,"utf-8").encode(self.encoding,"replace")) i = 0 traceback.print_exc() a,b,c = sys.exc_info() print a print b self.running=0 if self.jch != None: self.jch.running = 0 self.handleDisconnected() #}}} #{{{ sendMultiMessage(self, tolist, body, thread) def sendMultiMessage(self, tolist, body, thread): "Send a message to each jid in tolist with body and thread \n\ id. If thread is None it will not use a thread id." for to in tolist: self.sendMessage(to, body, thread) #}}} #{{{ sendMessage(self, to, body, thread, resource) def sendMessage(self, to, body, thread, resource = None): "Send a message to someone with body and thread id. \n\ if thread is None it will not use a thread id." body = self.normalize(body) packet = None if resource == None and self.reshash.has_key(to) and string.find(to,'/') == -1 and self.reshash[to][0] != None and self.reshash[to][0] != "": to = to + '/' + self.reshash[to][0] if resource != None and string.find(to,'/') == -1: to = to + '/' + resource if(self.conferences.has_key(to)): if resource == None: packet = ""\ ""+body+"" self.sendPacket(packet) return else: packet = ""\ ""+body+"" self.sendPacket(packet) return if(thread): packet = ""\ ""+body+"" +\ thread + "" else: packet = ""+body+"" self.sendPacket(packet) #}}} #{{{ sendFile(self, to, fname) def sendFile(self, to, fname): "Send a file to a particular jid. The jid MUST include the \ resource string." self.sendport = self.sendport + 1 ihs = IMComHTTPServer(os.path.dirname(fname),self.sendport) ihs.setDaemon(1) ihs.start() hostname = self.getOutsideIPAddress() self.id = self.id + 1 id = "file_id%d"%self.id packet = "" + \ "" + \ "http://"+hostname+":%d"%self.sendport packet = packet + "/"+os.path.basename(fname)+""+"" self.sendPacket(packet) #}}} #{{{ getFile(self, jid) def getFile(self, jid): "Will accept a transfer initiated by a user. JID must be the \ fully qualified JID of the user." if(self.filehash.has_key(jid)): file, id = self.filehash[jid].pop(0) fg = FileGet(jid,file,id,self.cbHandleFileErrorReceived,self.cbHandleFileReceived) fg.start() # del self.filehash[jid] else: self.cbHandleFileErrorReceived(jid, "none", "Input Error", "Not expecting a file " \ "from user specified.") return #}}} #{{{ Presence packet thingies def sendSubscribed(self, to): "Send a subscription authorization to someone" packet = "" self.sendPacket(packet) def sendSubscribe(self, to, status=""): "Send a subscription request to someone" packet = "" + status + "" self.sendPacket(packet) def sendUnsubscribed(self, to): "Send an unsubscribed authorization to someone -- this should never be needed." packet = "" self.sendPacket(packet) def sendUnsubscribe(self, to): "Send an unsubscription request to someone" packet = "" self.sendPacket(packet) def sendPriority(self, priority): self.priority = priority tosend = ""\ ""+self.currentStatus+""\ ""+str(priority)+"" if(self.currentStatusReason != None or self.currentStatusReason != ""): tosend = tosend + ""+self.currentStatusReason+"" tosend = tosend + "" self.sendPacket(tosend) def sendPresenceToConferences(self, show, status): for key in self.conferences.keys(): packet = "" packet = packet + "" + show + "" packet = packet + "" + status + "" packet = packet + "" self.sendPacket(packet) def sendOnline(self, reason="online"): "Send an online presence event" priority = "%d"%(self.priority) self.currentStatus = "online" self.currentStatusReason = reason if(reason == None): tosend = ""\ "online"\ ""+priority+""\ "" else: tosend = ""\ "online"+self.normalize(reason)+""\ ""+priority+""\ "" self.keepalive = tosend self.status = "online" self.sendPresenceToConferences("online", self.normalize(reason)) self.sendPacket(tosend) def sendOffline(self): "Send and offline presence event" tosend = "" self.keepalive = tosend self.status = "disconnected" self.sendPacket(tosend) def sendChat(self): "Send a chat presence event" priority = "%d"%(self.priority) self.currentStatus = "chat" self.currentStatusReason = None tosend = ""\ "chatonline"\ ""+priority+""\ "" self.keepalive = tosend self.status = "chat" self.sendPresenceToConferences("chat", "chat") self.sendPacket(tosend) def sendAway(self, reason): "Send an away presence event with the given reason. Reason CANNOT be \ None" priority = "%d"%(self.priority-2) self.currentStatus = "away" self.currentStatusReason = reason tosend = ""\ "away"+self.normalize(reason)+\ ""\ ""+priority+""\ "" self.keepalive = tosend self.status = "away" self.sendPresenceToConferences(self.status, self.normalize(reason)) self.sendPacket(tosend) def sendXA(self, reason): "Send an xa presence event with the given reason. Reason CANNOT be \ None" priority = "%d"%(self.priority-4) self.currentStatus = "xa" self.currentStatusReason = reason tosend = ""\ "xa"+self.normalize(reason)+""\ ""+priority+""\ "" self.keepalive = tosend self.status = "xa" self.sendPresenceToConferences(self.status, self.normalize(reason)) self.sendPacket(tosend) def sendDND(self, reason): "Send an dnd presence event with the given reason. Reason CANNOT be \ None" priority = "%d"%(self.priority-6) self.currentStatus = "dnd" self.currentStatusReason = reason tosend = ""\ "dnd"+self.normalize(reason)+""\ ""+priority+""\ "" self.keepalive = tosend self.status = "dnd" self.sendPresenceToConferences(self.status, self.normalize(reason)) self.sendPacket(tosend) #}}} #{{{ VCard Stuff def sendGetInfo(self, to): "Send an information request on a person." self.id = self.id + 1 id = "vcard%d"%self.id tosend = ""\ "" self.idhash[id] = "vcard" self.sendPacket(tosend) def sendSetInfo(self, displayname, family, given, nickname, email): "Submit your vCard to the Server." self.id = self.id + 1 id = "svcard%d"%self.id tosend = ""\ ""+displayname+"" + \ ""+family+""+given+"" + \ ""+nickname+"" + \ email + "" self.idhash[id] = "vcard-submit" self.sendPacket(tosend) #}}} #{{{ Agent Registration def sendAgentListRequest(self): "Send a request for the transport list." self.id = self.id + 1 id = "agentlist%d"%self.id packet = ""\ ""\ "" self.idhash[id] = "agentlist" self.sendPacket(packet) def sendAgentRegHelp(self, to): "Begin the registration process with a transport." self.id = self.id + 1 id = "agenthelp%d"%self.id packet = ""\ "" self.idhash[id] = "agenthelp" self.sendPacket(packet) def sendAgentRegistration(self, to, fields): "Complete registration process with a transport." names = self.regkey[2] self.idhash[self.regkey[1]] = "registration" if(len(names) != len(fields)): return packet = ""\ "" if(self.regkey[0]): packet = packet + ""+self.regkey[0]+"" i = 0 while(i < len(fields)): if(fields[i] == '""'): fields[i] = "" i = i + 1 i = 0 while(i < len(fields)): packet = packet + "<"+names[i]+">"+fields[i]+"" i = i + 1 packet = packet +"" self.sendPacket(packet) return def sendAgentUnregistration(self, to): self.id = self.id + 1 id = "agentunregister%d"%self.id packet = "" self.idhash[id] = "agentunregister" self.sendPacket(packet) #}}} #{{{ Change Password def sendChangePassword(self, newPassword): self.id = self.id +1 id = "changepassword%d"%self.id self.idhash[id] = "changepassword" self.iqTempHash[id] = newPassword packet = "" packet = packet + ""+self.user+"" packet = packet + ""+newPassword+"" packet = packet + "" self.sendPacket(packet) #}}} #{{{ Roster Management (Nick set, groups, etc) # Sets a roster item's nickname def setNick(self, jid, nick): "Set someones nickname" self.id = self.id + 1 id = "setnick%d"%self.id packet = ""\ ""\ "" if(self.gjidhash.has_key(jid)): for item in self.gjidhash[jid]: packet = packet + ""+item+"" packet = packet + "" self.idhash[id] = "setnick" self.sendPacket(packet) # Set a users group to just the group specified def setGroup(self, jid, group): "Set someones group to just the group specified" if(not self.jidhash.has_key(jid)): return self.id = self.id + 1 id = "setgroup%d"%self.id packet = ""\ ""\ "" packet = packet + ""+group+"" packet = packet + "" self.idhash[id] = "setgroup" self.sendPacket(packet) # Add a user to a group def addGroup(self, jid, group): "Add someone to a group" if(not self.jidhash.has_key(jid)): return self.id = self.id + 1 id = "setgroup%d"%self.id packet = ""\ ""\ "" if self.gjidhash.has_key(jid): for item in self.gjidhash[jid]: packet = packet + ""+item+"" packet = packet + ""+group+"" packet = packet + "" self.idhash[id] = "setgroup" self.sendPacket(packet) def helperRemoveUserFromGroup(self, jid, group): "This is a helper function for the remove group function. \ Users should NOT call this function directly." if(self.debug): logDebug("Attempting to remove " + jid + " from " + group) if(not self.grouphash.has_key(group)): return g = self.grouphash[group] if(not operator.contains(g,jid)): return if(self.debug): logDebug("Found " + jid + " in group " + group) g.remove(jid) self.grouphash[group] = g if(self.debug): logDebug("Successfully removed " + jid + " from " + group) # Remove a user from a group def removeGroup(self, jid, group): "Remove someone from a group" if(not self.jidhash.has_key(jid) or not self.grouphash.has_key(group)): if(self.debug): logDebug(jid + "not found in jidhash or grouphash") return self.id = self.id + 1 id = "setgroup%d"%self.id packet = ""\ ""\ "" for item in self.gjidhash[jid]: if(item == group): continue packet = packet + ""+item+"" packet = packet + "" self.idhash[id] = "setgroup" self.sendPacket(packet) # Permanently removes an item from a roster, killing ALL subscriptions: # both to and from. def removeUser(self, jid): "Deletes an item from a roster, killing ALL subscriptions: both \ to and from." self.id = self.id + 1 id = "removeuser%d"%self.id packet = ""\ ""\ "" self.idhash[id] = "removeuser" self.sendPacket(packet) #}}} #{{{ Conference Stuff # Join a conference def joinConference(self, confjid, confnick, mynick, password=None): "Joins a conference specified by confjid, and creates an alias nickname confnick for it" self.conferences[confjid] = [confnick, mynick, {}] self.confnick[confnick] = confjid packet = "Online" packet = packet + "" if password != None: packet = packet + "" + password + "" packet = packet + "" packet = packet + "" self.sendPacket(packet) def leaveConference(self, conf): "Leaves a conferences specified by conf which can be either the jid or the nickname" confjid = None try: if(self.conferences.has_key(conf)): confjid = conf nick = self.conferences[conf][0] del self.conferences[conf] del self.confnick[nick] if(self.confnick.has_key(conf)): confjid = self.confnick[conf] del self.confnick[conf] del self.conferences[confjid] if(confjid != None): packet = "" self.sendPacket(packet) except: if(self.debug): traceback.print_exc() a,b,c = sys.exc_info() print "An exception occured" print(a) print(b) def sendConferenceConfigRequest(self, conf): self.id = self.id + 1 id = "confroomconfig%d"%self.id self.idhash[id] = "confroomconfig" packet = "" packet = packet + "" packet = packet + "" self.sendPacket(packet) def sendConferenceConfigResults(self, conf, results): if not self.conferences.has_key(conf): return self.id = self.id + 1 id = "confroomconfigresult%d"%self.id self.idhash[id] = "confroomconfigresult" packet = "" packet = packet + "" for field in results: packet = packet + "" values = str(field[1]).split('\n') for value in values: packet = packet + "" + value + "" packet = packet + "" packet = packet + "" self.sendPacket(packet) def sendConferenceChangeNick(self, conf, newnick): if not self.conferences.has_key(conf): return packet = "" # BUG BUG BUG, according to JEP0045 is seems there is no way for a nick change to fail. self.sendPacket(packet) def sendConferenceInvite(self, conf, to, reason="Come join us."): if not self.conferences.has_key(conf): return me = self.user + "@" + self.host + "/" + self.resource packet = "" packet = packet + "" + self.normalize(reason) + "" self.sendPacket(packet) def sendConferenceChangeSubject(self, conf, subject): if not self.conferences.has_key(conf): return packet = "" packet = packet + "" + self.normalize(subject) + "" packet = packet + "" self.sendPacket(packet) def sendConferenceKickUser(self, conf, user, reason="Go away"): #if not self.conferences.has_key(conf): # return self.id = self.id + 1 id = "confkick%d"%self.id self.idhash[id] = "confkick" if reason == None: reason = "Go Away!" packet = "" packet = packet + "" packet = packet + "" packet = packet + "" + reason + "" packet = packet + "" self.sendPacket(packet) def sendConferenceBanUser(self, conf, user, reason="Go away"): self.id = self.id + 1 id = "confban%d"%self.id self.idhash[id] = "confban" if reason == None: reason = "Go Away!" packet = "" packet = packet + "" packet = packet + "" packet = packet + "" + reason + "" packet = packet + "" self.sendPacket(packet) def sendConferenceVoiceUser(self, conf, user): self.id = self.id + 1 id = "confvoice%d"%self.id self.idhash[id] = "confvoice" packet = "" packet = packet + "" packet = packet + "" packet = packet + "" self.sendPacket(packet) def sendConferenceDeVoiceUser(self, conf, user): self.id = self.id + 1 id = "confdevoice%d"%self.id self.idhash[id] = "confdevoice" packet = "" packet = packet + "" packet = packet + "" packet = packet + "" self.sendPacket(packet) def sendConferenceGrantModerator(self, conf, user): self.id = self.id + 1 id = "confmoderator%d"%self.id self.idhash[id] = "confmoderator" packet = "" packet = packet + "" packet = packet + "" packet = packet + "" self.sendPacket(packet) def sendConferenceRevokeModerator(self, conf, user): self.id = self.id + 1 id = "confmoderator%d"%self.id self.idhash[id] = "confmoderator" packet = "" packet = packet + "" packet = packet + "" packet = packet + "" self.sendPacket(packet) def sendConferenceGrantMember(self, conf, user): self.id = self.id + 1 id = "confmember%d"%self.id self.idhash[id] = "confmember" packet = "" packet = packet + "" packet = packet + "" packet = packet + "" self.sendPacket(packet) def sendConferenceRevokeMember(self, conf, user): self.id = self.id + 1 id = "confmember%d"%self.id self.idhash[id] = "confmember" packet = "" packet = packet + "" packet = packet + "" packet = packet + "" self.sendPacket(packet) def sendConferenceGrantAdmin(self, conf, user): self.id = self.id + 1 id = "confadmin%d"%self.id self.idhash[id] = "confadmin" packet = "" packet = packet + "" packet = packet + "" packet = packet + "" self.sendPacket(packet) def sendConferenceRevokeAdmin(self, conf, user): self.id = self.id + 1 id = "confadmin%d"%self.id self.idhash[id] = "confadmin" packet = "" packet = packet + "" packet = packet + "" packet = packet + "" self.sendPacket(packet) def sendConferenceGrantOwner(self, conf, user): self.id = self.id + 1 id = "confowner%d"%self.id self.idhash[id] = "confowner" packet = "" packet = packet + "" packet = packet + "" packet = packet + "" self.sendPacket(packet) def sendConferenceRevokeOwner(self, conf, user): self.id = self.id + 1 id = "confowner%d"%self.id self.idhash[id] = "confowner" packet = "" packet = packet + "" packet = packet + "" packet = packet + "" self.sendPacket(packet) def sendConferenceDestroy(self, conf): self.id = self.id + 1 id = "confdestroy%d"%self.id self.idhash[id] = "confdestroy" packet = "" packet = packet + "" packet = packet + "" self.sendPacket(packet) #}}} #{{{ sendNegotiationRequest(self, to, type, options, resource = None) def sendNegotiationRequest(self, to, type, options, resource = None): self.id = self.id + 1 id = "negotiate"+type+"%d"%self.id tojid = self.getFullyQualifiedJid(to, resource) packet = "" packet = packet + "" packet = packet + "" for option in options: packet = packet + "" packet = packet + "" self.idhash[id] = "negotiate"+type self.sendPacket(packet) #}}} #{{{ sendNegotiationResult(self, to, type, option, id, resource = None) def sendNegotiationResult(self, to, type, option, id, resource = None): tojid = self.getFullyQualifiedJid(to, resource) packet = "" packet = packet + "" + option + "" self.sendPacket(packet) #}}} #{{{ sendIQError(self, to, code, comment, id, resource = None) def sendIQError(self, to, code, comment, id, resource = None): tojid = self.getFullyQualifiedJid(to, resource) packet = "" + comment +"" self.sendPacket(packet) #}}} #{{{ sendDTCPRequest(self, to, resource, comment, DTCPKey = None) def sendDTCPRequest(self, to, resource, comment, DTCPKey = None): tojid = self.getFullyQualifiedJid(to, resource) self.id = self.id + 1 id = "dtcprequest%d"%self.id self.idhash[id] = "dtcprequest" if DTCPKey == None: DTCPKey = str(int(random.random() * 100000000)) self.iqTempHash[id] = DTCPKey packet = ""+DTCPKey+"" packet = packet + "" if comment != None: packet = packet + comment packet = packet + "" packet = packet + "" + self.getOutsideIPAddress() + ":" + str(self.DTCPPORT) + "" packet = packet + "" self.DTCPManager.addKey(DTCPKey, 1, None, None) self.sendPacket(packet) return DTCPKey #}}} #{{{ sendDTCPResponse(self, to, resource, id, DTCPKey = None) def sendDTCPResponse(self, to, resource, id, DTCPKey = None): tojid = self.getFullyQualifiedJid(to, resource) if DTCPKey == None: DTCPKey = str(int(random.random() * 100000000)) host = self.getOutsideIPAddress() port = self.DTCPPORT packet = "" packet = packet + ""+DTCPKey+"" packet = packet + "" + host + ":" + str(port) + "" packet = packet + "" self.sendPacket(packet) return DTCPKey #}}} #{{{ sendDTCPConnectError(self, to, resource, theirDTCPKey) def sendDTCPConnectError(self, to, theirDTCPKey): packet = "" packet = packet + theirDTCPKey+"Could not connect to any of the hosts." self.sendPacket(packet) #}}} #{{{ JIDLink #{{{ sendJIDLinkNegotiationRequest(self, to, resource, jidLink) def sendJIDLinkNegotiationRequest(self, to, resource, jidLink): self.id = self.id + 1 id = "negotiatejidlink%d"%self.id tojid = self.getFullyQualifiedJid(to, resource) self.iqTempHash[id] = jidLink packet = "" packet = packet + "" if 0 == self.isMyIPPrivate(): packet = packet + "" packet = packet + "" packet = packet + "" self.idhash[id] = "negotiatejidlink" self.sendPacket(packet) #}}} #{{{ sendJIDLinkNegotiationResult(self, to, option, id, resource = None) def sendJIDLinkNegotiationResult(self, to, option, id, resource = None): self.sendNegotiationResult(to, "jabber:iq:jidlink", option, id, resource) #}}} #{{{ sendJIDLinkRequest(self, to, resource, key) def sendJIDLinkRequest(self, to, resource, key): tojid = self.getFullyQualifiedJid(to, resource) self.id = self.id + 1 id = "jidlinkrequest%d"%self.id print "key is", key if(key == None): key=str(int(random.random() * 100000000)) self.iqTempHash[id] = [key, None] packet = ""+key+"" self.idhash[id] = "jidlinkrequest" self.sendPacket(packet) #}}} #{{{ sendJIDLinkResponse(self, to, resource, id): def sendJIDLinkResponse(self, to, resource, id): tojid = self.getFullyQualifiedJid(to, resource) packet = "" self.sendPacket(packet) #}}} #{{{ sendJIDLinkTestRequest(self, to, resource) def sendJIDLinkTestRequest(self, to, resource): tojid = self.getFullyQualifiedJid(to, resource) self.id = self.id + 1 id = "jidlinktestrequest%d"%self.id self.idhash[id] = "jidlinktestrequest" packet = "" self.sendPacket(packet) #}}} #{{{ sendJIDLinkTestResult(self, to, resource, id, key) def sendJIDLinkTestResult(self, to, resource, id, key): tojid = self.getFullyQualifiedJid(to, resource) packet = "" packet = packet + ""+key+"" self.sendPacket(packet) #}}} #}}} #{{{ sendVersionRequest(self, to, resource) def sendVersionRequest(self, to, resource): tojid = self.getFullyQualifiedJid(to, resource) self.id = self.id+1 id = "versionrequest%d"%self.id self.idhash[id] = "versionrequest" packet = "" self.sendPacket(packet) #}}} #{{{ sendVersionResponse(self, to, resource, id) def sendVersionResponse(self, to, resource, id): tojid = self.getFullyQualifiedJid(to, resource) packet = "" if id == None: packet = "" else: packet = "" packet = packet + "" packet = packet + ""+self.NAME+"" packet = packet + "" + str(self.VERSION) + "" packet = packet + "" self.sendPacket(packet) #}}} def sendTest(self): self.sendDTCPRequest("test5@floobin.cx", "IMCom", None, None) # end API Functions for sending requests to the server #}}} #{{{ Callback functions from the XML parsing layer # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # ------------------------------------------------------------------------- # Callback functions from the XML parsing layer # ------------------------------------------------------------------------- # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ### TODO BUG BUG BUG Handle Error conditions in all my handleIQ* functions #{{{ def handleDisconnected(self): def handleDisconnected(self): "This is another function the user should never call. It is \ called by the xml parser when something has gone awry" self.running = 0 self.mangleFunctions() self.cbHandleDisconnected() self.mainSocket = None #}}} #{{{ def handleStream(self, stream): def handleStream(self, stream): # This function handles the initial startup by sending in the # login information id = "login1" if self.clearpass: hd = ""+self.password+"" else: hd = ""+sha.new(stream.id+self.password).hexdigest()+"" toSend = ""\ ""\ ""+self.user+""+hd+\ ""+self.resource+"" self.sendPacket(toSend) self.idhash[id] = "login" #}}} #{{{ def handleStreamClose(self): def handleStreamClose(self): self.sendPacket("") self.running = 0 self.closeSocket() self.cbHandleStreamClose() #}}} #{{{ def handleStreamError(self, packet): def handleStreamError(self, packet): if packet.text != None: self.cbHandleStreamError(packet.text) #}}} #{{{ def setHighestPriorityProfile(self, ffrom): def setHighestPriorityProfile(self, ffrom): pkeys = self.reshash[ffrom][2].keys() highestn = pkeys[0] highestp = self.reshash[ffrom][2][highestn][2] for key in pkeys: if(self.reshash[ffrom][2][key][2] > highestp): highestn = key highestp = self.reshash[ffrom][2][key][2] self.reshash[ffrom][0] = highestn self.reshash[ffrom][1] = highestp #}}} #{{{ def handlePresence(self, pres): def handlePresence(self, pres): # um, ick. duplicate = 0 if pres.type == "error": ffrom = "" if hasattr(pres, "ffrom"): ffrom = pres.ffrom error = "" text = "" if hasattr(pres,"error"): if hasattr(pres.error, "code"): error = pres.error.code if hasattr(pres.error, "text"): text = pres.error.text self.cbHandlePresenceError(ffrom, error, text) return # handle conference stuff first. if(self.conferences.has_key(pres.ffrom)): if(pres.type == None or string.lower(pres.type) == "available"): # update our list of people in the conference # update the listener.. nick = pres.resource try: show = pres.show.text except: show = "online" try: reason = pres.status.text except: reason = "unspecified" self.conferences[pres.ffrom][2][nick] = (reason,show,pres.mucAffiliation,pres.mucRole) self.cbHandleConferencePresence(pres.ffrom, nick, show, reason, pres.mucAffiliation, pres.mucRole, pres.mucJID) if pres.createdConference == 1: self.cbHandleConferenceCreated(pres.ffrom) return if(string.lower(pres.type) == "unavailable"): # update our list of people in the conference # update the listener.. nick = pres.resource try: del self.conferences[pres.ffrom][2][nick] except: pass if pres.mucCode == "303": #rename if nick == self.conferences[pres.ffrom][1]: self.conferences[pres.ffrom][1] = pres.mucNick self.cbHandleConferenceNicknameChangeSuccess(pres.ffrom, nick, pres.mucNick) else: self.cbHandleConferenceNicknameChange(pres.ffrom, nick, pres.mucNick) if pres.mucCode == "307": #someone was kicked if nick == self.conferences[pres.ffrom][1]: del self.confnick[self.conferences[pres.ffrom][0]] del self.conferences[pres.ffrom] self.cbHandleConferenceKicked(pres.ffrom, pres.mucReason, pres.mucActor) return else: self.cbHandleConferenceUserKicked(pres.ffrom, nick, pres.mucReason, pres.mucActor) return if pres.mucCode == "301": # someone was banned if nick == self.conferences[pres.ffrom][1]: del self.confnick[self.conferences[pres.ffrom][0]] del self.conferences[pres.ffrom][0] self.cbHandleConferenceBanned(pres.ffrom, pres.mucReason, pres.mucActor) return else: self.cbHandleConferenceUserBanned(pres.ffrom, nick, pres.mucReason, pres.mucActor) return if pres.mucCode == "302": # conference destroyed del self.confnick[self.conferences[pres.ffrom][0]] del self.conferences[pres.ffrom][0] self.cbHandleConferenceDestroyed(pres.ffrom) else: self.cbHandleConferencePresence(pres.ffrom, nick, "offline", "leaving", None, None, None) return return if(pres.type == None or string.lower(pres.type) == "available"): if(pres.show == None): show="online" else: try: show = pres.show.text except: show = "online" if(pres.status == None or pres.status.text == None): status="online" else: status=pres.status.text priority = pres.priority jid = pres.ffrom if not self.jidhash.has_key(jid) and pres.resource != None and self.jidhash.has_key(jid + "/" + pres.resource): jid = jid + "/" + pres.resource if self.preshash.has_key( jid ): a,b,c = self.preshash[jid] if( a == 1 and b == show and c == status ): duplicate = 1 self.preshash[jid]=(1, show, status) if(not self.reshash.has_key(jid)): self.reshash[jid] = [pres.resource,priority,{}] #else: # self.reshash[jid][0] = pres.resource self.reshash[jid][2][pres.resource] = (status,show,priority) if(priority >= self.reshash[jid][1]): self.reshash[jid][1] = priority self.reshash[jid][0] = pres.resource elif(pres.resource == self.reshash[jid][0] and priority < self.reshash[jid][1]): self.setHighestPriorityProfile(jid) self.cbHandlePresenceUpdate(jid,show,status,1, pres.resource, duplicate) return if(string.lower(pres.type) == "unavailable"): if(pres.show == None or pres.show.text == None): show = "offline" else: show = pres.show.text if(pres.status == None): status = "Disconnected" else: status = pres.status.text jid = pres.ffrom if not self.jidhash.has_key(jid) and pres.resource != None and self.jidhash.has_key(jid + "/" + pres.resource): jid = jid + "/" + pres.resource if self.preshash.has_key( jid ): a,b,c = self.preshash[jid] if( a == 0 ): duplicate = 1 if(self.reshash.has_key(jid)): if(len(self.reshash[jid][2]) == 1): del self.reshash[jid] self.preshash[jid]=(0, show, status) else: del self.reshash[jid][2][pres.resource] if(self.reshash[jid][0] == pres.resource): self.setHighestPriorityProfile(jid) status2, reason, priority = self.reshash[jid][2][self.reshash[jid][0]] self.preshash[jid] = (1, reason, status2) self.cbHandlePresenceUpdate(jid,show,status,0, pres.resource, duplicate) return if(string.lower(pres.type) == "subscribe"): self.cbHandleSubscribe(pres.ffrom, pres.status) return if(string.lower(pres.type) == "unsubscribe"): self.cbHandleUnsubscribe(pres.ffrom) return if(string.lower(pres.type) == "subscribed"): self.preshash[pres.ffrom] = (0, "offline", "Disconnected") self.gjidhash[pres.ffrom] = [] self.cbHandleSubscribed(pres.ffrom) return if(string.lower(pres.type) == "unsubscribed"): try: if(not self.jidhash.has_key(pres.ffrom)): return self.cbHandleUnsubscribed(pres.ffrom,1) except: traceback.print_exc() a,b,c = sys.exc_info() print "An exception occured" print(a) print(b) self.cbHandleUnsubscribed(pres.ffrom,0) return #}}} #{{{ def handleMessage(self, msg): def handleMessage(self, msg): # um, hrm if(msg.type == "error"): if(hasattr(msg,"body") and hasattr(msg,"ffrom") and hasattr(msg,"error") and hasattr(msg.error, "code") and msg.error.code != None ): self.cbHandleMessageError(msg.ffrom,msg.body, msg.error.code) elif(hasattr(msg,"error") and hasattr(msg.error, "code") and msg.error.code != None ): self.cbHandleMessageError("unknown","",msg.error.code) elif(hasattr(msg,"error") and hasattr(msg.error,"text")): self.cbHandleMessageError("",msg.error.text,"0") elif(hasattr(msg,"body")): self.cbHandleMessageError("",msg.body,"0") else: self.cbHandleMessageError("", "Unknown message error","0") return if(msg.body != None and msg.ffrom != None and msg.type != "error"): thread = None delay = None try: thread = msg.thread except: pass try: delay = msg.delay if(self.debug): logDebug("Found a delayed message") except: if(self.debug): logDebug("Message was not delayed") pass if(self.reshash.has_key(msg.ffrom)): self.reshash[msg.ffrom][0] = msg.resource if(self.conferences.has_key(msg.ffrom)): self.cbHandleConferenceMessage(self.conferences[msg.ffrom][0], msg.resource, msg.body, delay) else: self.cbHandleMessageReceive(msg.ffrom,msg.body, thread,delay,msg.resource) if msg.type == "groupchat" and msg.subject != None: self.cbHandleConferenceSubject(self.conferences[msg.ffrom][0], msg.resource, msg.subject) if msg.mucInviteFrom != None: self.cbHandleConferenceInvite(msg.ffrom, msg.mucInviteFrom, msg.mucInviteReason, msg.mucInvitePassword) return #}}} #{{{ def handleIQ def handleIQ(self, iq): type = iq.type ns = iq.ns idtype = None if self.idhash.has_key(iq.id): idtype = self.idhash[iq.id] #if(type == "error"): # Throw error to the IQ ID manager. # self.handleIQHelper(iq,0) if(ns == "jabber:iq:roster" or idtype == "rosterupdate" or idtype == "setgroup" or idtype == "setnick" or idtype == "removeuser"): self.handleIQRoster(iq) return if(ns == "jabber:iq:oob"): self.handleIQOOB(iq) return if(ns == "jabber:iq:admin"): self.handleIQAdmin(iq) return if(ns == "jabber:iq:auth" or idtype == "login"): self.handleIQAuth(iq) return if(ns == "vcard-temp" or idtype == "vcard" or idtype == "vcard-submit"): self.handleIQVCard(iq) return if(ns == "jabber:iq:agents" or idtype == "agentlist"): self.handleIQAgents(iq) return if(idtype == "changepassword"): self.handleIQChangePassword(iq) return if(ns == "jabber:iq:register" or idtype == "agenthelp" or idtype == "registration" or idtype == "agentunregister"): self.handleIQRegister(iq) return if(ns == "jabber:iq:negotiate" or idtype == "negotiate" or str(idtype).find("negotiate") > -1): self.handleIQNegotiate(iq) return #if(ns == "jabber:iq:jidlink" or idtype == "jidlinkrequest"): # self.handleIQJIDLink(iq) # return #if(ns == "http://jabber.org/protocol/dtcp" or idtype == "dtcprequest"): # self.handleIQDTCP(iq) # return #if(ns == "jabber:iq:jidlink-test"): # self.handleIQJIDLinkTest(iq) # return if(ns == "jabber:iq:version"): self.handleIQVersion(iq) return if idtype == "confroomregister": self.handleMUCRoomRegister(iq) return if ns == "http://jabber.org/protocol/muc#admin" or idtype == "confkick" or idtype == "confdestroy": self.handleMUCAdmin(iq) return if ns == "http://jabber.org/protocol/muc#owner" or idtype == "confroomconfig" or idtype == "confroomconfigresult": self.handleMUCOwner(iq) return if type == "result" and not self.idhash.has_key(iq.id): if(self.debug): logDebug("I dunno what this IQ Query id is: " + str(iq.id)) return #}}} #{{{ handleIQRoster(self, iq): def handleIQRoster(self, iq): type = iq.type id = iq.id idtype = None if self.idhash.has_key(iq.id): idtype = self.idhash[iq.id] # first, handle all the results. if type == "result": if idtype == None: logDebug("I dunno what this IQ id is: " + str(id)) return if idtype == "setnick": del self.idhash[id] self.cbHandleRosterUpdateCheck(1, "Nick name set successfully") return if idtype == "setgroup": del self.idhash[id] self.cbHandleRosterUpdateCheck(1, "Group modification successful.") return if idtype == "rosterupdate": del self.idhash[id] self.cbHandleRosterUpdateCheck(1, "Generic roster update successful, don't get here,") return if idtype == "removeuser": del self.idhash[id] # this in an antiquated roster management. return if idtype == "getroster": for user in iq.query.users: tmp = user.jid if user.name: tmp = user.name if user.subscription in ('none', 'to', 'from', 'both'): if user.name: if user.name.find("/") != -1: origname = user.name newname = "" oldpos = 0 pos = origname.find("/") while(pos != -1): if(pos == 0): oldpos = 1 pos = origname.find("/",1) continue newname = newname + origname[oldpos:pos] oldpos = pos + 1 pos = origname.find("/",oldpos) newname = newname + origname[oldpos:] self.cbHandleNickHasSlash(user.name, newname, user.jid) user.name = newname if self.nickhash.has_key(user.name) and self.nickhash[user.name] != user.jid: oldjid = self.nickhash[user.name] self.cbHandleNickCollision(user.name, user.jid, oldjid) self.jidhash[oldjid] = oldjid self.nickhash[oldjid] = oldjid self.nickhash[user.name] = user.jid self.jidhash[user.jid] = user.name else: self.nickhash[user.jid] = user.jid self.jidhash[user.jid] = user.jid if not self.preshash.has_key(user.jid): self.preshash[user.jid] = (0, "offline", "Disconnected") self.subscriptions[user.jid] = user.subscription self.asks[user.jid] = user.ask self.gjidhash[user.jid] = user.groups for g in user.groups: if self.grouphash.has_key(g): self.grouphash[g].append(user.jid) else: self.grouphash[g] = [user.jid] self.cbHandleGrabRoster() return return # done with type == result # now handle all type == set if type == "set": for item in iq.query.users: if item.subscription == 'remove': #remove the user from our lists try: nick = self.jidhash[item.jid] del self.jidhash[item.jid] del self.nickhash[nick] del self.preshash[item.jid] del self.gjidhash[item.jid] del self.subscriptions[item.jid] del self.asks[item.jid] # update grouphash (ugh) keys = self.grouphash.keys() for k in keys: self.helperRemoveUserFromGroup(item.jid, k) if(len(k) == 0): self.grouphash.remove(k) self.cbHandleRosterUpdate(item.jid, item.name, item.subscription, item.ask, 1) except: #traceback.print_exc() #a,b,c = sys.exc_info() #print "An exception occured" #print(a) #print(b) self.cbHandleRosterUpdate(item.jid, item.name, item.subscription, item.ask, 0) else: # handle any other subscription case than 'remove' self.subscriptions[item.jid] = item.subscription self.asks[item.jid] = item.ask oldNick = None try: oldNick = self.jidhash[item.jid] except: pass if not self.gjidhash.has_key(item.jid): self.gjidhash[item.jid] = [] # remove all references to this jid in groups. for group in self.gjidhash[item.jid][:]: if item.jid in self.grouphash[group]: self.grouphash[group].remove(item.jid) if len(self.grouphash[group]) == 0: del self.grouphash[group] # clear the list of groups this jid belongs to. self.gjidhash[item.jid] = [] # set up the groups the user is in. for group in item.groups: if not (group in self.gjidhash[item.jid]): self.gjidhash[item.jid].append(group) if not self.grouphash.has_key(group): self.grouphash[group] = [] if not item.jid in self.grouphash[group]: self.grouphash[group].append(item.jid) if item.name == None: self.jidhash[item.jid] = item.jid else: self.jidhash[item.jid] = item.name if oldNick != None: if self.nickhash.has_key(item.name) and self.nickhash[item.name] != item.jid: self.cbHandleNickCollision(item.name, item.jid, self.nickhash[item.name]) self.updateHash(self.nickhash,oldNick,item.name,item.jid) else: self.nickhash[item.name] = item.jid self.cbHandleRosterUpdate(item.jid, item.name, item.subscription, item.ask, 1) #}}} #{{{ handleIQOOB(self, iq): def handleIQOOB(self, iq): type = iq.type ns = iq.ns if(type == "set"): query = iq.query urls = string.split(query.url,"\n") url = urls[-1] if(self.filehash.has_key(iq.ffrom)): self.filehash[iq.ffrom].append((url,iq.id)) else: self.filehash[iq.ffrom] = [(url,iq.id)] self.cbHandleFileReceive(iq.ffrom, url) return if(type == "result"): # nothing to do? return #}}} #{{{ handleIQAdmin(self,iq): def handleIQAdmin(self, iq): id = iq.id ns = iq.ns pl = iq.query.w.presencelist for pres in pl: if(pres.show == None or pres.show.text == None): show = "online" else: show = pres.show.text if(pres.status == None or pres.status.text == None): status = "online" else: status = pres.status.text self.cbHandleAdminWho(pres.ffrom, show, status, 1, pres.resource) return #}}} #{{{ handleIQVCard(self, iq): def handleIQVCard(self, iq): type = iq.type ns = iq.ns idtype = None if self.idhash.has_key(iq.id): idtype = self.idhash[iq.id] if(type == "result" and ns == "vcard-temp"): del self.idhash[iq.id] vc = iq.query self.cbHandleVCard(iq.ffrom, vc.fn, vc.given, vc.family, vc.nickname, vc.email) return elif(type == "result" and idtype == "vcard"): del self.idhash[iq.id] self.cbHandleNoVCard(iq.ffrom) return elif(idtype == "vcard-submit"): del self.idhash[iq.id] if(type == "result"): self.cbHandleVCardSubmit(1) else: self.cbHandleVCardSubmit(0) return #}}} #{{{ handleIQAuth(self, iq): def handleIQAuth(self, iq): id = iq.id ns = iq.ns type = iq.type if self.idhash[id] == "login": del self.idhash[id] if type == "result": self.cbHandleLogin(1) self.sendAgentListRequest() self.getRoster() return else: self.cbHandleLogin(0) self.disconnect() return #}}} #{{{ handleIQChangePassword(self, iq) def handleIQChangePassword(self, iq): id = iq.id if not self.idhash.has_key(id): logDebug("Unexpected ChangePassword result.") return del self.idhash[id] newPassword = self.iqTempHash[id] del self.iqTempHash[id] type = iq.type if type == "result": self.password = newPassword self.cbHandleChangePassword(1, newPassword, None, None) return else: self.cbHandleChangePassword(0, None, iq.error.code, iq.error.text) return #}}} #{{{ handleIQAgents(self, iq): def handleIQAgents(self, iq): id = iq.id ns = iq.ns type = iq.type if self.idhash[id] == "agentlist": del self.idhash[id] if len(self.agenthash) == 0: for x in iq.query.agentlist: if x.name: self.agenthash[x.jid] = x.name return if type == "result" and hasattr(iq,"query") and hasattr(iq.query, "agentlist"): self.cbHandleAgentList(iq.query.agentlist) return #}}} #{{{ handleIQRegister(self, iq): def handleIQRegister(self, iq): id = iq.id ns = iq.ns type = iq.type if not self.idhash.has_key(id): return if self.idhash[id] == "agenthelp": del self.idhash[id] if type == "result" and hasattr(iq, "query") and hasattr(iq.query, "fields") and hasattr(iq.query,"instructions"): key = None if hasattr(iq.query, "key"): key = iq.query.key self.regkey = [key, id, iq.query.fields] self.cbHandleAgentRegister(id, iq.ffrom, iq.query.instructions, iq.query.fields) elif type == "error": self.cbHandleIQError(iq.ffrom, iq.error.code, iq.error.text) return if self.idhash[id] == "register": del self.idhash[id] if type == "result": self.cbHandleAgentRegistered(iq.ffrom) return if self.idhash[id] == "agentunregister": del self.idhash[id] if type == "result": self.cbHandleAgentUnRegistered(iq.ffrom) return return #}}} #{{{ handleIQNegotiate(self, iq): def handleIQNegotiate(self, iq): id = iq.id ns = iq.ns type = iq.type if self.idhash.has_key(id): del self.idhash[id] if self.iqTempHash.has_key(id): del self.iqTempHash[id] if type == "get": for field in iq.query.xdataform.fields: # handle special case negotiations we care about here. # if field.var == "jabber:iq:jidlink": # self.handleJIDLinkNegotiationRequest(iq.ffrom, iq.fromResource, field, id) #else: self.cbHandleNegotiationRequest(iq.ffrom, field.var, field.options, id) if type == "result": for field in iq.query.xdataform.fields: #if field.var == "jabber:iq:jidlink": # self.handleJIDLinkNegotiationResult(iq.ffrom, iq.fromResource, field, id) #else: self.cbHandleNegotiationResult(iq.ffrom, field.var, field.options, id) if type == "error": if self.idhash.has_key(id): del self.idhash[id] if self.iqTempHash.has_key(id): del self.iqTempHash[id] self.cbHandleIQError(iq.ffrom, iq.error.code, iq.error.text) #}}} #{{{ handleIQJIDLink(self, iq): def handleIQJIDLink(self, iq): ns = iq.ns id = iq.id type = iq.type jid = self.getFullyQualifiedJid(iq.ffrom,iq.fromResource) if type == "set": # BUG BUG BUG somehow deal with duplicates if self.doesJIDLinkKeyExist(jid, iq.query.key): packet = "Key in use" self.sendPacket(packet) return if not self.jidLinkKeys.has_key(jid): self.jidLinkKeys[jid] = [] theJidLink = self.getUnusedJIDLink(jid, iq.query.key) if theJidLink == None: logDebug("Not expecting a jidlink. screw off.") return self.sendJIDLinkResponse(iq.ffrom, iq.fromResource, iq.id) return if type == "result": if not self.iqTempHash.has_key(iq.id): logDebug("iqTempHash doesn't have iq.id, unexpected jidlink result.") return jidLinkKey = self.iqTempHash[iq.id][0] del self.iqTempHash[iq.id] jl = self.getUnusedJIDLink(jid, jidLinkKey) self.sendJIDLinkNegotiationRequest(iq.ffrom, iq.fromResource, jl) return if type == "error": if self.iqTempHash.has_key[iq.id]: del self.iqTempHash[iq.id] # bug bug bug, handle the I give up stage. if int(iq.error.code) == 501: # key was in use, try again. self.sendJIDLinkRequest(iq.ffrom, iq.fromResource, None) return self.cbHandleIQError(iq.ffrom, iq.error.code, iq.error.text) return #}}} #{{{ handleIQJIDLinkTest(self, iq) def handleIQJIDLinkTest(self, iq): ns = iq.ns id = iq.id type = iq.type jid = self.getFullyQualifiedJid(iq.ffrom, iq.fromResource) if type == "set": if hasattr(iq.query, "key"): if not self.jidLinkKeys.has_key(jid): self.jidLinkKeys[jid] = [] actionObject = JIDLink.JIDLinkTestModeAction() jl = JIDLink.JIDLink(iq.ffrom, iq.fromResource, iq.query.key, actionObject, self) self.jidLinkKeys[jid].append(jl) self.sendJIDLinkRequest(iq.ffrom, iq.fromResource, iq.query.key) else: key = str(int(random.random() * 100000000)) actionObject = JIDLink.JIDLinkTestModeAction() jl = JIDLink.JIDLink(iq.ffrom, iq.fromResource, key, actionObject, self) if not self.jidLinkKeys.has_key(jid): self.jidLinkKeys[jid] = [] self.jidLinkKeys[jid].append(jl) self.sendJIDLinkTestResult(iq.ffrom, iq.fromResource, iq.id, key) return #}}} #{{{ handleIQDTCP(self, iq) def handleIQDTCP(self, iq): id = iq.id ns = iq.ns type = iq.type if type == "set": OurDTCPKey = str(int(random.random() * 100000000)) handler = DTCPSocketManager.DTCPSocketBogusXFer(0) self.DTCPManager.addKey(OurDTCPKey, 0, iq.query.key, handler) self.sendDTCPResponse(iq.ffrom, iq.fromResource, id, OurDTCPKey) self.DTCPManager.createConnection(iq.ffrom + "/" + iq.fromResource, iq.query.hosts, 0, iq.query.key, OurDTCPKey, handler, self) return if type == "result": OurDTCPKey = self.iqTempHash[id] del self.iqTempHash[id] del self.idhash[id] handler = DTCPSocketManager.DTCPSocketBogusXFer(1) self.DTCPManager.addKey(OurDTCPKey, 1, iq.query.key, handler) self.DTCPManager.createConnection(iq.ffrom + "/" + iq.fromResource, iq.query.hosts, 1, iq.query.key, OurDTCPKey, handler, self) return if type == "error": self.DTCPManager.removeListeningKey(iq.query.key) #}}} #{{{ handleIQVersion(self, iq) def handleIQVersion(self, iq): id = iq.id type = iq.type query = iq.query if hasattr(query, "name"): if not self.idhash.has_key(id): logDebug("Unexpected Version Response, ignoring") return del self.idhash[id] name = query.name version = None os = None if hasattr(query, "version"): version = query.version if hasattr(query, "os"): os = query.os self.cbHandleVersionResponse(iq.ffrom, iq.fromResource, name, version, os) else: self.sendVersionResponse(iq.ffrom, iq.fromResource, id) #}}} #{{{ handleMUCRoomRegister(self, iq) def handleMUCRoomRegister(self, iq): id = iq.id type = iq.type if type == "result": if not self.idhash.has_key(id): return idtype = self.idhash[id] del self.idhash[id] if idtype == "confroomregister": self.cbHandleConferenceRoomRegister(iq.query.ffrom, iq.query.instruction, iq.query.xdataform) return if idtype == "confroomregisterresult": self.cbHandleConferenceRoomRegisterSuccess(iq.query.ffrom) return return return #}}} #{{{ handleMUCAdmin(self, iq) def handleMUCAdmin(self, iq): type = iq.type if type == "error": if self.idhash.has_key(iq.id): del self.idhash[iq.id] self.cbHandleIQError(iq.ffrom, iq.error.code, iq.error.text) return if type == "result": # BUG BUG BUG could return results here if I cared. return return #}}} #{{{ handleMUCOwner(self, iq) def handleMUCOwner(self, iq): if iq.type == "error": if self.idhash.has_key(iq.id): del self.idhash[iq.id] self.cbHandleIQError(iq.ffrom, iq.error.code, iq.error.text) return if iq.type == "result": if not self.idhash.has_key(iq.id): return idtype = self.idhash[iq.id] del self.idhash[iq.id] if idtype == "confroomconfig": self.cbHandleConferenceConfig(iq.ffrom, iq.query.xdataform) return if idtype == "confroomconfigresult": self.cbHandleConferenceConfigSet(iq.ffrom) return return return #}}} #{{{ handleJIDLinkNegotiationRequest(self, ffrom, resource, feature, id) def handleJIDLinkNegotiationRequest(self, ffrom, resource, feature, id): jid = self.getFullyQualifiedJid(ffrom, resource) for option in feature.options: #if option == "dtcp-passive": # self.sendJIDLinkNegotiationResult(ffrom, option, id, resource) # return if option == "dtcp-active" or (option == "dtcp-passive" and 0 == isMyIPPrivate()): self.sendJIDLinkNegotiationResult(ffrom, option, id, resource) return self.sendIQError(ffrom, 501, "No supported protocols.", id, resource) #}}} #{{{ handleJIDLinkNegotiationResult(self, ffrom, resource, feature, id) def handleJIDLinkNegotiationResult(self, ffrom, resource, feature, id): if self.idhash[id] == "negotiatejidlink": del self.idhash[id] # actually establish the connection jid = self.getFullyQualifiedJid(ffrom, resource) if not self.iqTempHash.has_key(id): logDebug("Error, unexpected JIDLinkNegotiation Result.") return jl = self.iqTempHash[id] del self.iqTempHash[id] if jl == None: return option = feature.options[0] key = jl.key if option == "dtcp-active": self.sendDTCPActiveRequest(ffrom, resource, "hi", key) return if option == "dtcp-passive": self.sendDTCPPassiveRequest(ffrom, resource, "hi", key) return # BUG BUG BUG handle other transports. #}}} #{{{ handleFileReceived(self, jid, URL, id) def handleFileReceived(self, jid, URL, id): tosend = "" self.sendPacket(tosend) self.cbHandleFileReceived(jid, os.path.basename(URL)) #}}} #{{{ handleFileErrorReceived(self, jid, url, id, type, text) def handleFileErrorReceived(self, jid, url, id, type, text): tosend = "" self.sendPacket(tosend) self.cbHandleFileErrorReceived(jid,url,type,text) #}}} # end Callback functions from the XML parsing layer #}}} # end file