# HG changeset patch # User Charly COSTE # Date 1251896277 -7200 # Node ID 6c4b841144f6cfcef35235fcbe346a11f332b584 # Parent c5e4bf95f52a0945de6b8947a0443b021ab5a878 Better handling of participants Signed-off-by: Charly COSTE diff --git a/bot.py b/bot.py --- 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') diff --git a/bridge.py b/bridge.py --- 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 diff --git a/participant.py b/participant.py --- 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)