changeset 72:6c4b841144f6

Better handling of participants Signed-off-by: Charly COSTE <changaco@changaco.net>
author Charly COSTE <changaco@changaco.net>
date Wed, 02 Sep 2009 14:57:57 +0200
parents c5e4bf95f52a
children fa291fd20480
files bot.py bridge.py participant.py
diffstat 3 files changed, 56 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/bot.py
+++ b/bot.py
@@ -85,7 +85,7 @@ class bot(Thread):
 			except RuntimeError:
 				pass
 			except (xml.parsers.expat.ExpatError, xmpp.protocol.XMLNotWellFormed):
-				self.error('=> Debug: received invalid stanza', debug=True)
+				self.error('=> Debug: invalid stanza', debug=True)
 				continue
 			except:
 				self.error('[Error] Unkonwn exception on XMPP thread:')
@@ -295,6 +295,9 @@ class bot(Thread):
 					self.error('=> Debug: ignoring IRC '+event.eventtype()+' sent by self', debug=True)
 					return
 			
+			if event.eventtype() == 'quit' and connection in self.irc.connections:
+				return
+			
 			# TODO: lock self.bridges for thread safety
 			for bridge in self.bridges:
 				if connection.server != bridge.irc_server:
@@ -333,7 +336,7 @@ class bot(Thread):
 					if event.target().lower() == bridge.irc_room:
 						try:
 							kicked = bridge.getParticipant(event.arguments()[0])
-							if kicked.irc_connection != None:
+							if isinstance(kicked.irc_connection, irclib.ServerConnection):
 								kicked.irc_connection.join(bridge.irc_room)
 							return
 						except NoSuchParticipantException:
@@ -400,8 +403,8 @@ class bot(Thread):
 				else:
 					try:
 						banned = bridge.getParticipant(event.target())
-						if banned.irc_connection != None:
-							banned.irc_connection = None
+						if banned.irc_connection != 'bannedfromchan':
+							banned.irc_connection = 'bannedfromchan'
 							self.error(event_str, debug=True)
 							self.error('[Notice] the nickname "'+event.target()+'" is banned from the IRC chan of bridge "'+str(bridge)+'"')
 							bridge.say('[Warning] the nickname "'+event.target()+'" is banned from the IRC chan')
--- a/bridge.py
+++ b/bridge.py
@@ -20,6 +20,7 @@ xmpp = muc.xmpp
 del muc
 from participant import *
 from encoding import *
+from irclib import ServerConnection
 import traceback
 import re
 import threading
@@ -108,35 +109,40 @@ class bridge:
 				raise Exception('[Error] "'+self.bot.nickname+'" is already used in the XMPP MUC or reserved on the XMPP server of bridge "'+str(self)+'"')
 	
 	
-	def addParticipant(self, protocol, nickname):
+	def addParticipant(self, from_protocol, nickname):
 		"""Add a participant to the bridge."""
-		if (protocol == 'irc' and nickname == self.irc_connection.get_nickname()) or (protocol == 'xmpp' and nickname == self.xmpp_room.nickname):
+		if (from_protocol == 'irc' and nickname == self.irc_connection.get_nickname()) or (from_protocol == 'xmpp' and nickname == self.xmpp_room.nickname):
 			self.bot.error('===> Debug: not adding self ('+self.bot.nickname+') to bridge "'+str(self)+'"', debug=True)
 			return
 		try:
 			p = self.getParticipant(nickname)
-			if p.protocol != protocol:
-				if protocol == 'irc':
-					p.createDuplicateOnXMPP()
-				elif protocol == 'xmpp':
-					p.createDuplicateOnIRC()
-				else:
-					raise Exception('[Internal Error] bad protocol')
+			if p.protocol != from_protocol:
+				if from_protocol == 'irc' and isinstance(p.irc_connection, ServerConnection) and p.irc_connection.really_connected == True or from_protocol == 'xmpp' and isinstance(p.muc, xmpp.muc) and p.muc.connected == True:
+					return
+				self.bot.error('===> Debug: "'+nickname+'" is on both sides of bridge "'+str(self)+'"', debug=True)
+				self.say('[Warning] The nickname "'+nickname+'" is used on both sides of the bridge, please avoid that if possible')
+				if isinstance(p.irc_connection, ServerConnection):
+					p.irc_connection.close('')
+					p.irc_connection = 'both'
+				if isinstance(p.muc, xmpp.muc):
+					p.muc.leave('')
+					self.bot.close_xmpp_connection(p.nickname)
+					p.xmpp_c = 'both'
 			return
 		except NoSuchParticipantException:
 			pass
-		self.bot.error('===> Debug: adding participant "'+nickname+'" from "'+protocol+'" to bridge "'+str(self)+'"', debug=True)
+		self.bot.error('===> Debug: adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'"', debug=True)
 		try:
-			p = participant(self, protocol, nickname)
+			p = participant(self, from_protocol, nickname)
 		except IOError:
-			self.bot.error('===> Debug: IOError while adding participant "'+nickname+'" from "'+protocol+'" to bridge "'+str(self)+'", reconnectiong ...', debug=True)
+			self.bot.error('===> Debug: IOError while adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'", reconnectiong ...', debug=True)
 			p.xmpp_c.reconnectAndReauth()
 		except:
-			self.bot.error('===> Debug: unknown error while adding participant "'+nickname+'" from "'+protocol+'" to bridge "'+str(self)+'"', debug=True)
+			self.bot.error('===> Debug: unknown error while adding participant "'+nickname+'" from "'+from_protocol+'" to bridge "'+str(self)+'"', debug=True)
 			traceback.print_exc()
 			return
 		self.participants.append(p)
-		if self.mode != 'normal' and protocol == 'xmpp':
+		if self.mode != 'normal' and from_protocol == 'xmpp':
 			xmpp_participants_nicknames = self.get_participants_nicknames_list(protocols=['xmpp'])
 			self.say('[Info] Participants on XMPP: '+'  '.join(xmpp_participants_nicknames), on_xmpp=False)
 		return p
@@ -181,7 +187,7 @@ class bridge:
 			if left_protocol == 'irc':
 				was_on_both = True
 			elif left_protocol == 'xmpp':
-				if p.irc_connection == None and self.mode == 'normal':
+				if p.irc_connection == 'both':
 					was_on_both = True
 					p.protocol = 'irc'
 					p.createDuplicateOnXMPP()
@@ -192,7 +198,7 @@ class bridge:
 			if left_protocol == 'xmpp':
 				was_on_both = True
 			elif left_protocol == 'irc':
-				if p.xmpp_c == None and self.mode != 'minimal':
+				if p.xmpp_c == 'both':
 					was_on_both = True
 					p.protocol = 'xmpp'
 					p.createDuplicateOnIRC()
@@ -268,7 +274,7 @@ class bridge:
 		for p in self.participants:
 			if p.protocol == 'xmpp':
 				i += 1
-				if p.irc_connection != None:
+				if isinstance(self.irc_connection, ServerConnection):
 					p.irc_connection.close('Bridge is switching to limited mode')
 					p.irc_connection = None
 		self.irc_connections_limit = i
--- a/participant.py
+++ b/participant.py
@@ -18,7 +18,7 @@
 import muc
 xmpp = muc.xmpp
 del muc
-from irclib import ServerNotConnectedError
+from irclib import ServerNotConnectedError, ServerConnection
 from encoding import *
 from threading import Thread
 from time import sleep
@@ -41,7 +41,7 @@ class participant:
 	
 	
 	def createDuplicateOnXMPP(self):
-		if self.xmpp_c != None or self.irc_connection != None or self.bridge.mode == 'minimal' or self.nickname == 'ChanServ':
+		if isinstance(self.xmpp_c, xmpp.client.Client) or isinstance(self.irc_connection, ServerConnection) or self.bridge.mode == 'minimal' or self.nickname == 'ChanServ':
 			return
 		self.xmpp_c = self.bridge.bot.get_xmpp_connection(self.nickname)
 		self.muc = xmpp.muc(self.bridge.xmpp_room.room_jid)
@@ -58,13 +58,13 @@ class participant:
 				except xmpp.muc.NicknameConflict:
 					self.bridge.bot.error('===> Debug: "'+self.nickname+'" is already used in the XMPP MUC or reserved on the XMPP server of bridge "'+str(self.bridge)+'"', debug=True)
 					self.bridge.say('[Warning] The nickname "'+self.nickname+'" is used on both rooms or reserved on the XMPP server, please avoid that if possible')
-					self.muc.leave('Nickname change')
+					self.muc.leave('Changed nickname to "'+self.nickname+'"')
 					self.bridge.bot.close_xmpp_connection(self.nickname)
 					self.xmpp_c = None
 	
 	
 	def createDuplicateOnIRC(self):
-		if self.irc_connection != None or self.xmpp_c != None or self.bridge.mode != 'normal':
+		if isinstance(self.xmpp_c, xmpp.client.Client) or isinstance(self.irc_connection, ServerConnection) or self.bridge.mode != 'normal':
 			return
 		sleep(1) # try to prevent "reconnecting too fast" shit
 		self.irc_connection = self.bridge.bot.irc.server(self.bridge.irc_server, self.bridge.irc_port, self.nickname)
@@ -79,27 +79,27 @@ class participant:
 			if error == 'nicknameinuse':
 				self.bridge.bot.error('===> Debug: "'+self.nickname+'" is already used in the IRC chan of bridge "'+str(self.bridge)+'"', debug=True)
 				self.bridge.say('[Warning] The nickname "'+self.nickname+'" is used on both rooms or reserved on the IRC server, please avoid that if possible')
-				if self.irc_connection != None:
+				if isinstance(self.irc_connection, ServerConnection):
 					self.irc_connection.close('')
-					self.irc_connection = None
+					self.irc_connection = 'nicknameinuse'
 			elif error == 'nickcollision':
 				self.bridge.bot.error('===> Debug: "'+self.nickname+'" is already used or reserved on the IRC server of bridge "'+str(self.bridge)+'"', debug=True)
 				self.bridge.say('[Warning] The nickname "'+self.nickname+'" is already used or reserved on the IRC server, please avoid that if possible')
-				if self.irc_connection != None:
+				if isinstance(self.irc_connection, ServerConnection):
 					self.irc_connection.close('')
-					self.irc_connection = None
+					self.irc_connection = 'nickcollision'
 			elif error == 'erroneusnickname':
 				self.bridge.bot.error('===> Debug: "'+self.nickname+'" got "erroneusnickname" on bridge "'+str(self.bridge)+'"', debug=True)
 				self.bridge.say('[Warning] The nickname "'+self.nickname+'" contains unauthorized characters and cannot be used in the IRC channel, please avoid that if possible')
-				if self.irc_connection != None:
+				if isinstance(self.irc_connection, ServerConnection):
 					self.irc_connection.close('')
-					self.irc_connection = None
+					self.irc_connection = 'erroneusnickname'
 			elif error == 'nicknametoolong':
 				self.bridge.bot.error('===> Debug: "'+self.nickname+'" got "nicknametoolong" on bridge "'+str(self.bridge)+'"', debug=True)
 				self.bridge.say('[Warning] The nickname "'+self.nickname+'" is too long (limit seems to be '+str(arguments[0])+') and cannot be used in the IRC channel, please avoid that if possible')
-				if self.irc_connection != None:
+				if isinstance(self.irc_connection, ServerConnection):
 					self.irc_connection.close('')
-					self.irc_connection = None
+					self.irc_connection = 'nicknametoolong'
 	
 	
 	def changeNickname(self, newnick, on_protocol):
@@ -114,7 +114,7 @@ class participant:
 			
 			else:
 				self.nickname = newnick
-				if self.irc_connection != None:
+				if isinstance(self.irc_connection, ServerConnection):
 					self.irc_connection.nick(newnick, callback=self._irc_nick_callback)
 				else:
 					self.createDuplicateOnIRC()
@@ -129,14 +129,15 @@ class participant:
 				if self.muc != None:
 					for b in self.bridge.bot.bridges:
 						if b.hasParticipant(oldnick) and b.irc_server != self.bridge.irc_server:
-							self.muc.leave(message='Nickname change')
+							self.muc.leave(message='Changed nickname to "'+self.nickname+'"')
 							self.xmpp_c = None
 							self.bridge.bot.close_xmpp_connection(oldnick)
 							self.createDuplicateOnXMPP()
 							return
 					
 					if not self.bridge.bot.xmpp_connections.has_key(newnick):
-						self.bridge.bot.xmpp_connections.pop(oldnick)
+						if self.bridge.bot.xmpp_connections.has_key(oldnick):
+							self.bridge.bot.xmpp_connections.pop(oldnick)
 						self.bridge.bot.xmpp_connections[newnick] = self.xmpp_c
 					
 					self.muc.change_nick(newnick, status='From IRC', callback=self._xmpp_join_callback)
@@ -146,24 +147,24 @@ class participant:
 	
 	def sayOnIRC(self, message):
 		try:
-			if self.irc_connection != None:
+			if isinstance(self.irc_connection, ServerConnection):
 				try:
 					self.irc_connection.privmsg(self.bridge.irc_room, message)
 				except ServerNotConnectedError:
 					self.bridge.irc_connection.privmsg(self.bridge.irc_room, '<'+self.nickname+'> '+message)
-			elif self.xmpp_c == None:
+			elif not isinstance(self.xmpp_c, xmpp.client.Client):
 				self.bridge.irc_connection.privmsg(self.bridge.irc_room, '<'+self.nickname+'> '+message)
 		except EncodingException:
 			self.bridge.say('[Warning] "'+self.nickname+'" is sending messages using an unknown encoding')
 	
 	
 	def sayOnIRCTo(self, to, message):
-		if self.irc_connection != None:
+		if isinstance(self.irc_connection, ServerConnection):
 			try:
 				self.irc_connection.privmsg(to, message)
 			except EncodingException:
 				self.bridge.say('[Warning] "'+self.nickname+'" is sending messages using an unknown encoding')
-		elif self.xmpp_c == None:
+		elif not isinstance(self.xmpp_c, xmpp.client.Client):
 			if self.bridge.mode != 'normal':
 				self.bridge.getParticipant(to).sayOnXMPPTo(self.nickname, 'Sorry but cross-protocol private messages are disabled in '+self.bridge.mode+' mode.')
 			else:
@@ -172,9 +173,9 @@ class participant:
 	
 	def sayOnXMPP(self, message):
 		try:
-			if self.xmpp_c != None:
+			if isinstance(self.xmpp_c, xmpp.client.Client):
 				self.muc.say(auto_decode(message))
-			elif self.irc_connection == None:
+			elif not isinstance(self.irc_connection, ServerConnection):
 				self.bridge.xmpp_room.say('<'+self.nickname+'> '+auto_decode(message))
 		except EncodingException:
 			self.bridge.say('[Warning] "'+self.nickname+'" is sending messages using an unknown encoding')
@@ -182,9 +183,9 @@ class participant:
 	
 	def sayOnXMPPTo(self, to, message):
 		try:
-			if self.xmpp_c != None:
+			if isinstance(self.xmpp_c, xmpp.client.Client):
 				self.muc.sayTo(to, auto_decode(message))
-			elif self.irc_connection == None:
+			elif not isinstance(self.irc_connection, ServerConnection):
 				if self.bridge.mode != 'normal':
 					self.bridge.getParticipant(to).sayOnXMPPTo(self.nickname, 'Sorry but cross-protocol private messages are disabled in '+self.bridge.mode+' mode.')
 				else:
@@ -196,10 +197,10 @@ class participant:
 	def leave(self, message):
 		if message == None:
 			message = ''
-		if self.xmpp_c != None:
+		if isinstance(self.xmpp_c, xmpp.client.Client):
 			self.muc.leave(auto_decode(message))
 			self.bridge.bot.close_xmpp_connection(self.nickname)
-		if self.irc_connection != None:
+		if isinstance(self.irc_connection, ServerConnection):
 			self.irc_connection.used_by -= 1
 			if self.irc_connection.used_by < 1:
 				self.irc_connection.close(message)