PageRenderTime 74ms CodeModel.GetById 18ms app.highlight 50ms RepoModel.GetById 1ms app.codeStats 0ms

/src/legacy/glue.py

http://pyaimt.googlecode.com/
Python | 734 lines | 714 code | 10 blank | 10 comment | 8 complexity | 7dcc7267abeaa25073b7c7b6d5278aee MD5 | raw file
  1# Copyright 2004-2006 Daniel Henninger <jadestorm@nc.rr.com>
  2# Licensed for distribution under the GPL version 2, check COPYING for details
  3
  4import imgmanip
  5import utils
  6from twisted.words.xish.domish import Element
  7from twisted.internet import protocol, reactor, defer, task
  8from tlib import oscar
  9from tlib import socks5, sockserror
 10from twisted.python import log
 11import groupchat
 12import aimt
 13import config
 14from debug import LogEvent, INFO, WARN, ERROR
 15import sys, warnings, pprint
 16import lang
 17import os.path
 18import re
 19import time
 20import binascii
 21import avatar
 22import md5
 23
 24# The name of the transport
 25name = "AIM Transport"
 26
 27# The transport's version
 28version = "0.8a"
 29
 30# URL of the transport's web site
 31url = "http://pyaim-t.blathersource.org"
 32
 33# This should be set to the identity of the gateway
 34id = "aim"
 35
 36if not config.disableAvatars:
 37	# Load the default AIM and ICQ avatars
 38	f = open(os.path.join("data", "defaultAIMAvatar.png"))
 39	defaultAIMAvatarData = f.read()
 40	f.close()
 41	defaultAIMAvatar = avatar.AvatarCache().setAvatar(defaultAIMAvatarData)
 42
 43	f = open(os.path.join("data", "defaultICQAvatar.png"))
 44	defaultICQAvatarData = f.read()
 45	f.close()
 46	defaultICQAvatar = avatar.AvatarCache().setAvatar(defaultICQAvatarData)
 47
 48	defaultAvatar = defaultAIMAvatar
 49	defaultAvatarData = defaultAIMAvatarData
 50else:
 51	defaultAvatar = None
 52	defaultAvatarData = None
 53
 54# This function should return true if the JID is a group JID, false otherwise
 55def isGroupJID(jid):
 56	#if (jid[0] == "#" or jid[0] == "%"):
 57	if jid.find(config.confjid) > 0:
 58		return True
 59	else:
 60		return False
 61
 62# This function translates an AIM screen name to a JID
 63def aim2jid(aimid):
 64	if aimid:
 65		retstr = aimid.lower().replace(' ', '')
 66		return retstr.replace('@', '%') + "@" + config.jid
 67	else:
 68		return config.jid
 69
 70# This function translates a JID to an AIM screen name
 71def jid2aim(jid):
 72	return unicode(jid[:jid.find('@')].replace('%','@'))
 73
 74# This function translates an AIM chat room to a groupchat JID
 75def aim2jidGroup(chatid, userid=None, exchange=None):
 76	retstr = chatid.replace(' ', '_')
 77	retstr = retstr.replace('@', '')
 78	if exchange:
 79		retstr = retstr + "%" + str(exchange)
 80	retstr = retstr + "@" + config.confjid
 81	if userid:
 82		retstr = retstr + "/" + userid
 83	return retstr
 84
 85# This function translates a groupchat JID to an AIM chat room
 86def jid2aimGroup(jid):
 87	exchange = 4
 88	groupid = unicode(jid[0:jid.find('@')].replace('_',' '))
 89	if groupid.find('%') != -1:
 90		exchange = int(groupid[groupid.find('%')+1:])
 91		groupid = groupid[:groupid.find('%')]
 92	if jid.find('/') != -1:
 93		userid = unicode(jid[jid.find('/'):])
 94	else:
 95		userid = None
 96	return (groupid,userid,exchange)
 97
 98# This function is called to handle legacy id translation to a JID
 99translateAccount = aim2jid
100
101
102
103############################################################################
104# This class handles most interaction with AIM chatrooms
105############################################################################
106class LegacyGroupchat(groupchat.BaseGroupchat):
107	def __init__(self, session, resource, ID=None, existing=False, switchboardSession=None):
108		groupchat.BaseGroupchat.__init__(self, session, resource, ID)
109		groupid,userid,exchange = jid2aimGroup(self.roomJID())
110		LogEvent(INFO, self.session.jabberID)
111		self.session.legacycon.createChat(groupid,exchange)
112
113	def removeMe(self):
114		groupid,userid,exchange = jid2aimGroup(self.roomJID())
115		LogEvent(INFO, self.session.jabberID)
116		self.session.legacycon.leaveChat(groupid)
117		groupchat.BaseGroupchat.removeMe(self)
118		utils.mutilateMe(self)
119
120	def sendLegacyMessage(self, message, noerror):
121		groupid,userid,exchange = jid2aimGroup(self.roomJID())
122		LogEvent(INFO, self.session.jabberID)
123		self.session.legacycon.sendChat(groupid, message)
124	
125	def sendContactInvite(self, contactJID):
126		groupid,userid,exchange = jid2aimGroup(self.roomJID())
127		contactid = jid2aim(contactJID)
128		LogEvent(INFO, self.session.jabberID)
129		self.session.legacycon.sendInvite(groupid, contactid)
130
131
132
133############################################################################
134# This class handles most interaction with AIM
135############################################################################
136class LegacyConnection:
137	""" A glue class that connects to the legacy network """
138	def __init__(self, username, password, session):
139		import buddies
140
141		self.username = username
142		self.password = password
143		self.session = session
144		self.legacyList = buddies.BuddyList(self.session)
145		self.savedShow = None
146		self.savedFriendly = None
147		self.savedURL = None
148		self.reactor = reactor
149		self.deferred = defer.Deferred()
150		self.deferred.addErrback(self.errorCallback)
151		hostport = (config.aimServer, config.aimPort)
152		LogEvent(INFO, self.session.jabberID, "Creating")
153		if config.socksProxyServer and config.socksProxyPort:
154			self.oa = aimt.OA
155			self.creator = socks5.ProxyClientCreator(self.reactor, self.oa, self.username, self.password, self, deferred=self.deferred, icq=0)
156			LogEvent(INFO, self.session.jabberID, "Connect via socks proxy")
157			self.creator.connectSocks5Proxy(config.aimServer, config.aimPort, config.socksProxyServer, config.socksProxyPort, "AIMCONN")
158		else:
159			self.oa = aimt.OA
160			self.creator = protocol.ClientCreator(self.reactor, self.oa, self.username, self.password, self, deferred=self.deferred, icq=0)
161			LogEvent(INFO, self.session.jabberID, "Connect via direct tcp")
162			self.creator.connectTCP(*hostport)
163
164		LogEvent(INFO, self.session.jabberID, "Created!")
165
166	def removeMe(self):
167		from glue import aim2jid
168		LogEvent(INFO, self.session.jabberID)
169		try:
170			self.bos.stopKeepAlive()
171			self.bos.disconnect()
172		except AttributeError:
173			pass
174		self.legacyList.removeMe()
175		self.legacyList = None
176		self.session = None
177		utils.mutilateMe(self)
178
179	def jidRes(self, resource):
180		to = self.session.jabberID
181		if resource:
182			to += "/" + resource
183		return to
184
185	def highestResource(self):
186		""" Returns highest priority resource """
187		return self.session.highestResource()
188
189	def setURL(self, URL=None):
190		LogEvent(INFO, self.session.jabberID, "setURL %s" % URL)
191		try:
192			self.bos.setURL(utils.utf8encode(URL))
193		except AttributeError:
194			#self.alertUser(lang.get("sessionnotactive", config.jid)
195			pass
196
197	def sendMessage(self, target, resource, message, noerror, xhtml, autoResponse=0):
198		LogEvent(INFO, self.session.jabberID)
199		from glue import jid2aim
200		try:
201			self.session.pytrans.serviceplugins['Statistics'].stats['OutgoingMessages'] += 1
202			self.session.pytrans.serviceplugins['Statistics'].sessionUpdate(self.session.jabberID, 'OutgoingMessages', 1)
203			scrnname = jid2aim(target)
204			wantIcon = 0
205			if self.bos.requesticon.has_key(scrnname):
206				LogEvent(INFO, self.session.jabberID, "Going to ask for target's icon.")
207				wantIcon = 1
208				del self.bos.requesticon[scrnname]
209			offline = 1
210			try:
211				if self.legacyList.ssicontacts[scrnname]['presence'] != "unavailable":                       
212					offline = 0
213			except: 
214				# well then they're online in some way
215				pass
216
217			iconSum = None
218			iconLen = None
219			iconStamp = None
220			if hasattr(self, "myavatar"):
221				iconSum = oscar.getIconSum(self.myavatar)
222				iconLen = len(self.myavatar)
223				iconStamp = time.time()
224				LogEvent(INFO, self.session.jabberID, "Going to send info about our icon, length %d, cksum %d" % (iconLen, iconSum))
225
226			LogEvent(INFO, self.session.jabberID)
227			if scrnname[0].isdigit():
228				encoding = "iso-8859-1"
229				charset = "iso-8859-1"
230				if self.legacyList.hasCapability(scrnname, "unicode"):
231					encoding = "utf-16be"
232					charset = "unicode"
233				LogEvent(INFO, self.session.jabberID, "Encoding %r" % encoding)
234				self.bos.sendMessage(scrnname, [[message,charset]], offline=offline, wantIcon=wantIcon, autoResponse=autoResponse, iconSum=iconSum, iconLen=iconLen, iconStamp=iconStamp)
235				self.session.sendArchive(target, self.session.jabberID, message)
236			else:
237				if xhtml and not config.disableXHTML:
238					xhtml = utils.xhtml_to_aimhtml(xhtml)
239					self.bos.sendMessage(scrnname, xhtml, wantIcon=wantIcon, autoResponse=autoResponse, iconSum=iconSum, iconLen=iconLen, iconStamp=iconStamp)
240					self.session.sendArchive(target, self.session.jabberID, message)
241				else:
242					htmlized = oscar.html(message)
243					self.bos.sendMessage(scrnname, htmlized, wantIcon=wantIcon, autoResponse=autoResponse, iconSum=iconSum, iconLen=iconLen, iconStamp=iconStamp)
244					self.session.sendArchive(target, self.session.jabberID, message)
245		except AttributeError:
246			self.alertUser(lang.get("sessionnotactive", config.jid))
247
248	def newResourceOnline(self, resource):
249		from glue import aim2jid
250		LogEvent(INFO, self.session.jabberID)
251		try:
252			for c in self.legacyList.ssicontacts.keys( ):
253				LogEvent(INFO, self.session.jabberID, "Resending buddy %r" % c)
254				jid = aim2jid(c)
255				show = self.legacyList.ssicontacts[c]['show']
256				status = self.legacyList.ssicontacts[c]['status']
257				ptype = self.legacyList.ssicontacts[c]['presence']
258				url = self.legacyList.ssicontacts[c]['url']
259				#FIXME, needs to be contact based updatePresence
260				self.session.sendPresence(to=self.session.jabberID, fro=jid, show=show, status=status, ptype=ptype, url=url)
261		except AttributeError:
262			return
263
264	def setAway(self, awayMessage=None):
265		LogEvent(INFO, self.session.jabberID)
266		try:
267			self.bos.awayResponses = {}
268			self.bos.setAway(utils.xmlify(awayMessage))
269		except AttributeError:
270			#self.alertUser(lang.get("sessionnotactive", config.jid))
271			pass
272
273	def setBack(self, backMessage=None):
274		LogEvent(INFO, self.session.jabberID)
275		try:
276			self.bos.awayResponses = {}
277			self.bos.setBack(utils.utf8encode(backMessage))
278		except AttributeError:
279			#self.alertUser(lang.get("sessionnotactive", config.jid))
280			pass
281
282	def sendShowStatus(self, jid=None):
283		if not self.session: return
284		if not jid:
285			jid = self.jabberID
286		self.session.sendPresence(to=jid, fro=config.jid, show=self.savedShow, status=self.savedFriendly)
287	
288 	def setStatus(self, nickname, show, friendly, url=None):
289		LogEvent(INFO, self.session.jabberID)
290
291		if show=="away" and not friendly:
292			friendly="Away"
293		elif show=="dnd" and not friendly:
294			friendly="Do Not Disturb"
295		elif show=="xa" and not friendly:
296			friendly="Extended Away"
297		elif show=="chat" and not friendly:
298			friendly="Free to Chat"
299
300		self.savedShow = show
301		self.savedFriendly = friendly
302		self.savedURL = url
303
304		if not self.session.ready:
305			return
306
307		if not show or show == "online" or show == "Online" or show == "chat":
308			self.setBack(friendly)
309			self.setURL(url)
310			self.session.sendPresence(to=self.session.jabberID, fro=config.jid, show=None, url=url)
311		else:
312			self.setAway(friendly)
313			self.setURL(url)
314			self.session.sendPresence(to=self.session.jabberID, fro=config.jid, show=show, status=friendly, url=url)
315
316	def setProfile(self, profileMessage=None):
317		LogEvent(INFO, self.session.jabberID)
318		try:
319			self.bos.setProfile(profileMessage)
320		except AttributeError:
321			#self.alertUser(lang.get("sessionnotactive", config.jid))
322			pass
323
324        def buildFriendly(self, status):
325		friendly = self.jabberID[:self.jabberID.find('@')]
326		if status and len(status) > 0:
327			friendly += " - "
328			friendly += status
329		if len(friendly) > 127:
330			friendly = friendly[:124] + "..."
331		return friendly
332
333	def sendTypingNotify(self, type, dest):
334		from tlib.oscar import MTN_FINISH, MTN_IDLE, MTN_BEGIN
335		from glue import jid2aim
336		try:
337			username = jid2aim(dest)
338			LogEvent(INFO, self.session.jabberID)
339			if type == "begin":
340				self.bos.sendTypingNotification(username, MTN_BEGIN)
341			elif type == "idle":
342				self.bos.sendTypingNotification(username, MTN_IDLE)
343			elif type == "finish":
344				self.bos.sendTypingNotification(username, MTN_FINISH)
345		except AttributeError:
346			self.alertUser(lang.get("sessionnotactive", config.jid))
347	
348	def userTypingNotification(self, dest, resource, composing):
349		LogEvent(INFO, self.session.jabberID)
350		if composing:
351			self.sendTypingNotify("begin", dest)
352		else:
353			self.sendTypingNotify("finish", dest)
354
355	def chatStateNotification(self, dest, resource, state):
356		LogEvent(INFO, self.session.jabberID)
357		if state == "composing":
358			self.sendTypingNotify("begin", dest)
359		elif state == "paused" or state == "inactive":
360			self.sendTypingNotify("idle", dest)
361		elif state == "active" or state == "gone":
362			self.sendTypingNotify("finish", dest)
363
364	def jabberVCardRequest(self, vcard, user):
365		LogEvent(INFO, self.session.jabberID)
366		return self.getvCard(vcard, user)
367
368	def createChat(self, chatroom, exchange):
369		LogEvent(INFO, self.session.jabberID)
370		try:
371			self.bos.createChat(chatroom, exchange).addCallback(self.bos.createdRoom)
372		except AttributeError:
373			self.alertUser(lang.get("sessionnotactive", config.jid))
374
375	def leaveChat(self, chatroom):
376		LogEvent(INFO, self.session.jabberID)
377		try:
378			for c in self.bos.chats:
379				if c.name == chatroom:
380					c.leaveChat()
381					self.bos.chats.remove(c)
382					break
383		except AttributeError:
384			self.alertUser(lang.get("sessionnotactive", config.jid))
385
386	def sendChat(self, chatroom, message):
387		LogEvent(INFO, self.session.jabberID)
388		try:
389			for c in self.bos.chats:
390				#debug.log("Checking chat %s" % (c.name))
391				if c.name.lower() == chatroom.lower():
392					c.sendMessage(message)
393					#debug.log("Found chat and sent message.")
394					break
395		except AttributeError:
396			self.alertUser(lang.get("sessionnotactive", config.jid))
397
398	def sendInvite(self, chatroom, contact):
399		LogEvent(INFO, self.session.jabberID)
400		try:
401			for c in self.bos.chats:
402				if c.name.lower() == chatroom.lower():
403					self.bos.sendInvite(contact, c)
404		except AttributeError:
405			self.alertUser(lang.get("sessionnotactive", config.jid))
406
407	def resourceOffline(self, resource):
408		from glue import aim2jid
409		LogEvent(INFO, self.session.jabberID)
410		try:
411			show = None
412			status = None
413			ptype = "unavailable"
414			for c in self.legacyList.ssicontacts.keys( ):
415				LogEvent(INFO, self.session.jabberID, "Sending offline %r" % c)
416				jid = aim2jid(c)
417
418				self.session.sendPresence(to=self.session.jabberID+"/"+resource, fro=jid, ptype=ptype, show=show, status=status)
419			self.session.sendPresence(to=self.session.jabberID+"/"+resource, fro=config.jid, ptype=ptype, show=show, status=status)
420		except AttributeError:
421			return
422
423	def updateAvatar(self, av=None):
424		""" Called whenever a new avatar needs to be set. Instance of avatar.Avatar is passed """
425		if config.disableAvatars: return
426		imageData = ""
427		if av:
428			imageData = av.getImageData()
429		else:
430			if not config.disableDefaultAvatar:
431				global defaultAvatarData
432				imageData = defaultAvatarData
433			else:
434				imageData = None
435
436		self.changeAvatar(imageData)
437
438	def changeAvatar(self, imageData):
439		if config.disableAvatars: return
440		if imageData:
441			try:
442				self.myavatar = imgmanip.convertToJPG(imageData)
443				self.myavatarlen = len(self.myavatar)
444				m=md5.new()
445				m.update(self.myavatar)
446				self.myavatarsum = m.digest()
447				self.myavatarstamp = time.time()
448			except:
449				LogEvent(INFO, self.session.jabberID, "Unable to convert avatar to JPEG")
450				return
451		if hasattr(self, "bos") and self.session.ready:
452			if not imageData:
453				if hasattr(self, "myavatar"):
454					del self.myavatar
455				if len(self.bos.ssiiconsum) > 0:
456					self.bos.startModifySSI()
457					for i in self.bos.ssiiconsum:
458						LogEvent(INFO, self.session.jabberID, "Removing icon %s (u:%d g:%d)" % (i.name, i.buddyID, i.groupID))
459						de = self.bos.delItemSSI(i)
460					self.bos.endModifySSI()
461				return
462			if len(self.bos.ssiiconsum) > 0 and self.bos.ssiiconsum[0]:
463				LogEvent(INFO, self.session.jabberID, "Replacing existing icon")
464				self.bos.ssiiconsum[0].updateIcon(imageData)
465				self.bos.startModifySSI()
466				self.bos.modifyItemSSI(self.bos.ssiiconsum[0])
467				self.bos.endModifySSI()
468			else:
469				LogEvent(INFO, self.session.jabberID, "Adding new icon")
470				newBuddySum = oscar.SSIIconSum()
471				newBuddySum.updateIcon(imageData)
472				self.bos.startModifySSI()
473				self.bos.addItemSSI(newBuddySum)
474				self.bos.endModifySSI()
475
476	def doSearch(self, form, iq):
477		LogEvent(INFO, self.session.jabberID)
478		#TEST self.bos.sendInterestsRequest()
479		email = utils.getDataFormValue(form, "email")
480		first = utils.getDataFormValue(form, "first")
481		middle = utils.getDataFormValue(form, "middle")
482		last = utils.getDataFormValue(form, "last")
483		maiden = utils.getDataFormValue(form, "maiden")
484		nick = utils.getDataFormValue(form, "nick")
485		address = utils.getDataFormValue(form, "address")
486		city = utils.getDataFormValue(form, "city")
487		state = utils.getDataFormValue(form, "state")
488		zip = utils.getDataFormValue(form, "zip")
489		country = utils.getDataFormValue(form, "country")
490		interest = utils.getDataFormValue(form, "interest")
491		try:
492			d = defer.Deferred()
493			self.bos.sendDirectorySearch(email=email, first=first, middle=middle, last=last, maiden=maiden, nickname=nick, address=address, city=city, state=state, zip=zip, country=country, interest=interest).addCallback(self.gotSearchResults, iq, d).addErrback(self.gotSearchError, d)
494			return d
495		except AttributeError:
496			self.alertUser(lang.get("sessionnotactive", config.jid))
497
498	def gotSearchResults(self, results, iq, d):
499		LogEvent(INFO, self.session.jabberID)
500		from glue import aim2jid
501
502		x = None
503		for query in iq.elements():
504			if query.name == "query":
505				for child in query.elements():
506					if child.name == "x":
507						x = child
508						break
509				break
510
511		if x:
512			for r in results:
513				if r.has_key("screenname"):
514					r["jid"] = aim2jid(r["screenname"])
515				else:
516					r["jid"] = "Unknown"
517				item = x.addElement("item")
518				for k in ["jid","first","middle","last","maiden","nick","email","address","city","state","country","zip","region"]:
519					item.addChild(utils.makeDataFormElement(None, k, value=r.get(k,None)))
520		d.callback(iq)
521
522	def gotSearchError(self, error, d):
523		LogEvent(INFO, self.session.jabberID)
524		#d.callback(vcard)
525
526	def getvCard(self, vcard, user):
527		LogEvent(INFO, self.session.jabberID)
528		try:
529			d = defer.Deferred()
530			self.bos.getProfile(user).addCallback(self.gotvCard, user, vcard, d).addErrback(self.gotnovCard, user, vcard, d)
531			return d
532		except AttributeError:
533			self.alertUser(lang.get("sessionnotactive", config.jid))
534
535	def gotvCard(self, profile, user, vcard, d):
536		from glue import aim2jid
537
538		LogEvent(INFO, self.session.jabberID)
539
540		cutprofile = oscar.dehtml(profile)
541		nickname = vcard.addElement("NICKNAME")
542		nickname.addContent(utils.xmlify(user))
543		jabberid = vcard.addElement("JABBERID")
544		jabberid.addContent(aim2jid(user))
545		desc = vcard.addElement("DESC")
546		desc.addContent(utils.xmlify(cutprofile))
547
548		d.callback(vcard)
549
550	def gotnovCard(self, profile, user, vcard, d):
551		from glue import aim2jid
552		LogEvent(INFO, self.session.jabberID)
553
554		nickname = vcard.addElement("NICKNAME")
555		nickname.addContent(user)
556		jabberid = vcard.addElement("JABBERID")
557		jabberid.addContent(aim2jid(user))
558		desc = vcard.addElement("DESC")
559		desc.addContent("User is not online.")
560
561		d.callback(vcard)
562
563	def aim2uhandle(self, aimid):
564		retstr = aimid.replace(' ','')
565		return retstr.lower()
566
567	def updatePresence(self, userHandle, ptype): # Convenience
568		from glue import aim2jid
569		to = aim2jid(userHandle)
570		self.session.sendPresence(to=self.session.jabberID, fro=to, ptype=ptype)
571
572	def addContact(self, userHandle):
573		LogEvent(INFO, self.session.jabberID)
574		def cb(arg=None):
575			self.updatePresence(userHandle, "subscribed")
576
577		try:
578			for g in self.bos.ssigroups:
579				for u in g.users:
580					aimHandle = self.aim2uhandle(u.name)
581					if aimHandle == userHandle:
582						if not u.authorizationRequestSent and not u.authorized:
583							self.bos.sendAuthorizationRequest(userHandle, "Please authorize me!")
584							u.authorizationRequestSent = True
585							return
586						else:
587							cb()
588							return
589
590			savethisgroup = None
591			groupName = "PyAIM-t Buddies"
592			for g in self.bos.ssigroups:
593				if g.name == groupName:
594					LogEvent(INFO, self.session.jabberID, "Located group %s" % (g.name))
595					savethisgroup = g
596
597			if savethisgroup is None:
598				LogEvent(INFO, self.session.jabberID, "Adding new group")
599				newGroupID = self.generateGroupID()
600				newGroup = oscar.SSIGroup(groupName, newGroupID, 0)
601				self.bos.startModifySSI()
602				self.bos.addItemSSI(newGroup)
603				self.bos.endModifySSI()
604				savethisgroup = newGroup
605				self.bos.ssigroups.append(newGroup)
606
607			group = self.findGroupByName(groupName)
608			newUserID = self.generateBuddyID(group.groupID)
609			newUser = oscar.SSIBuddy(userHandle, group.groupID, newUserID)
610			savethisgroup.addUser(newUserID, newUser)
611
612			LogEvent(INFO, self.session.jabberID, "Adding item to SSI")
613			self.bos.startModifySSI()
614			self.bos.addItemSSI(newUser)
615			self.bos.modifyItemSSI(savethisgroup)
616			self.bos.endModifySSI()
617
618			self.legacyList.updateSSIContact(userHandle)
619			self.updatePresence(userHandle, "subscribe")
620		except AttributeError:
621			self.alertUser(lang.get("sessionnotactive", config.jid))
622
623	def removeContact(self, userHandle):
624		LogEvent(INFO, self.session.jabberID)
625		try:
626			def cb(arg=None):
627				self.updatePresence(userHandle, "unsubscribed")
628
629			savetheseusers = []
630
631			if userHandle in self.bos.authorizationRequests:
632				self.bos.sendAuthorizationResponse(userHandle, False, "")
633				self.bos.authorizationRequests.remove(userHandle)
634
635			for g in self.bos.ssigroups:
636				for u in g.users:
637					aimHandle = self.aim2uhandle(u.name)
638					LogEvent(INFO, self.session.jabberID, "Comparing %s and %s" % (aimHandle, userHandle))
639					if aimHandle == userHandle:
640						LogEvent(INFO, self.session.jabberID, "Located user %s" % (u.name))
641						savetheseusers.append(u)
642
643			if len(savetheseusers) == 0:
644				LogEvent(INFO, self.session.jabberID, "Did not find user")
645				return
646
647			self.bos.startModifySSI()
648			for u in savetheseusers:
649				LogEvent(INFO, self.session.jabberID, "Removing %s (u:%d g:%d) from group %s"%(u.name, u.buddyID, u.groupID, u.group.name))
650				de = self.bos.delItemSSI(u)
651				de.addCallback(self.SSIItemDeleted, u)
652			de.addCallback(cb)
653			self.bos.endModifySSI()
654		except AttributeError:
655			self.alertUser(lang.get("sessionnotactive", config.jid))
656
657	def authContact(self, userHandle):
658		LogEvent(INFO, self.session.jabberID)
659		try:
660			if userHandle in self.bos.authorizationRequests:
661				self.bos.sendAuthorizationResponse(userHandle, True, "OK")
662				self.bos.authorizationRequests.remove(userHandle)
663		except AttributeError:
664			self.alertUser(lang.get("sessionnotactive", config.jid))
665
666	def deauthContact(self, userHandle):
667		LogEvent(INFO, self.session.jabberID)
668		# I don't recall why these are the same
669		self.authContact(userHandle)
670
671	def SSIItemDeleted(self, x, user):
672		c = 0
673		for g in self.bos.ssigroups:
674			c += 1
675			for u in g.users:
676				if u.buddyID == user.buddyID and u.groupID == user.groupID:
677					g.users.remove(u)
678					del g.usersToID[u]
679
680	def errorCallback(self, result):
681		try:
682			LogEvent(INFO, self.session.jabberID)
683			errmsg = result.getErrorMessage()
684			errmsgs = errmsg.split("'")
685			message = "Authentication Error!" 
686			if errmsgs[1]:
687				message = message+"\n"+errmsgs[1]
688			if errmsgs[3]:
689				message = message+"\n"+errmsgs[3]
690			self.alertUser(message)
691			self.session.removeMe()
692		except:
693			pass
694
695	def findGroupByID(self, groupID):
696		for x in self.bos.ssigroups:
697			if x.groupID == groupID:
698				return x
699
700	def findGroupByName(self, groupName):
701		for x in self.bos.ssigroups:
702			if x.name == groupName:
703				return x
704
705	def generateGroupID(self):
706		pGroupID = len(self.bos.ssigroups)
707		while True:
708			pGroupID += 1
709			found = False
710			for x in self.bos.ssigroups:
711				if pGroupID == x.groupID:
712					found = True
713					break
714			if not found: break
715		return pGroupID
716
717	def generateBuddyID(self, groupID):
718		group = self.findGroupByID(groupID)
719		pBuddyID = len(group.users)
720		while True: # If all integers are taken we got a bigger problems
721			pBuddyID += 1
722			found = False
723			for x in group.users:
724				if pBuddyID == x.buddyID:
725					found = True
726					break
727			if not found: break
728		return pBuddyID
729
730	def alertUser(self, message):
731		tmpjid = config.jid
732		if self.session.registeredmunge:
733			tmpjid = tmpjid + "/registered"
734		self.session.sendMessage(to=self.session.jabberID, fro=tmpjid, body=message, mtype="error")