# 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]+""+names[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