# HG changeset patch # User Charly COSTE # Date 1268498327 -3600 # Node ID 9a2302e8382b0debd1f2a94e7c1903bb069dd9e1 # Parent 3b318108e9e04968002478624fbab89a54318e4c (irclib) created a "Channel" class Signed-off-by: Charly COSTE diff --git a/bridge.py b/bridge.py --- a/bridge.py +++ b/bridge.py @@ -19,7 +19,7 @@ import re import threading import traceback -from irclib import ServerConnection +import irclib import muc xmpp = muc.xmpp del muc @@ -142,7 +142,7 @@ class Bridge: try: p = self.get_participant(nickname) if p.protocol != from_protocol: - if from_protocol == 'irc' and isinstance(p.irc_connection, ServerConnection) and p.irc_connection.logged_in or from_protocol == 'xmpp' and isinstance(p.muc, xmpp.muc) and p.muc.state >= p.muc.JOINING: + if from_protocol == 'irc' and isinstance(p.irc_connection, irclib.ServerConnection) and p.irc_connection.channels.has_key(self.irc_room) and p.irc_connection.channels[self.irc_room].state >= irclib.JOINING or from_protocol == 'xmpp' and isinstance(p.muc, xmpp.muc) and p.muc.state >= p.muc.JOINING: return p p.set_both_sides() return p @@ -294,13 +294,13 @@ class Bridge: was_on_both = False elif left_protocol == 'irc': # got disconnected somehow - if isinstance(p.irc_connection, ServerConnection): + if isinstance(p.irc_connection, irclib.ServerConnection): if p.irc_connection.socket == 'closed': return p.irc_connection.join(self.irc_room) else: c = self.bot.irc.get_connection(self.irc_server, self.irc_port, p.duplicate_nickname) - if not (c and self.irc_room in c.left_channels): + if not (c and c.channels.has_key(self.irc_room) and c.channels[self.irc_room].state <= irclib.LEAVING): p.create_duplicate_on_irc() return @@ -403,7 +403,7 @@ class Bridge: self.bot.error(-1, message+' '+str(self), send_to_admins=True) # Leave - if isinstance(self.irc_connection, ServerConnection) and isinstance(self.xmpp_room, xmpp.muc): + if isinstance(self.irc_connection, irclib.ServerConnection) and isinstance(self.xmpp_room, xmpp.muc): self.irc_connection.part(self.irc_room, message=message) self.xmpp_room.leave(message=message) else: @@ -423,7 +423,7 @@ class Bridge: self.bot.error(-1, message+' '+str(self), send_to_admins=True) # Close IRC connection if not used by an other bridge, just leave the room otherwise - if isinstance(self.irc_connection, ServerConnection): + if isinstance(self.irc_connection, irclib.ServerConnection): self.irc_connection.used_by -= 1 if self.irc_connection.used_by < 1: self.irc_connection.close(message) diff --git a/irclib.py b/irclib.py --- a/irclib.py +++ b/irclib.py @@ -410,6 +410,56 @@ class IRC: if self.fn_to_remove_socket: self.fn_to_remove_socket(connection._get_socket()) + +LEFT, LEAVING, NOT_IN, JOINING, JOINED = range(5) + +class Channel: + + def __init__(self, connection, channel_name): + self.connection = connection + self.channel_name = channel_name + self.callbacks = [] + self.state = NOT_IN + + def _callback(self, error): + if not error: + self.state = JOINED + else: + self.state = NOT_IN + m = 'channel "'+self.channel_name+'" on connection "'+str(self.connection)+'"' + if len(self.callbacks) == 0: + self.connection.irclibobj.bot.error(1, 'no join callback for '+m, debug=True) + else: + self.connection.irclibobj.bot.error(1, 'calling '+str(len(self.callbacks))+' join callback(s) for '+m, debug=True) + for f in self.callbacks: + f(self.channel_name, error) + + def add_callback(self, callback): + if callback and not callback in self.callbacks: + self.callbacks.append(callback) + + def join(self, key=None, callback=None): + self.state = JOINING + self.key = key + self.add_callback(callback) + self.connection.send_raw("JOIN %s%s" % (self.channel_name, (key and (" " + key)))) + + def part(self, message=None): + if self.state <= NOT_IN: + return + self.state = LEAVING + self.connection.send_raw("PART " + self.channel_name + (message and (" " + message))) + + def rejoin(self): + self.join(key=self.key) + + def remove_callback(self, callback): + try: + self.callbacks.remove(callback) + except ValueError: + pass + + _rfc_1459_command_regexp = re.compile("^(:(?P[^ ]+) +)?(?P[^ ]+)( *(?P .+))?") class Connection: @@ -464,9 +514,7 @@ class ServerConnection(Connection): self.nick_callbacks = [] self.join_callbacks = {} self.lock = threading.RLock() - self.left_channels = [] - self.channels = [] - self.channels_keys = {} + self.channels = {} self.irc_id = None self.previous_buffer = "" self.handlers = {} @@ -594,12 +642,8 @@ class ServerConnection(Connection): # Rejoin channels if len(self.channels) > 0: - for channel in self.channels: - if self.channels_keys.has_key(channel): - key = self.channels_keys[channel] - else: - key = '' - self.join(channel, key=key) + for channel in self.channels.itervalues(): + channel.rejoin() self.lock.release() return self @@ -615,19 +659,6 @@ class ServerConnection(Connection): self.nick_callbacks = [] - def _call_join_callbacks(self, channel, error): - self.lock.acquire() - m = 'channel "'+channel+'" on connection "'+str(self)+'"' - if not self.join_callbacks.has_key(channel) or len(self.join_callbacks[channel]) == 0: - self.irclibobj.bot.error(1, 'no join callback for '+m, debug=True) - else: - self.irclibobj.bot.error(1, 'calling '+str(len(self.join_callbacks[channel]))+' join callback(s) for '+m, debug=True) - for f in self.join_callbacks[channel]: - f(channel, error) - self.join_callbacks.pop(channel, None) - self.lock.release() - - def add_nick_callback(self, callback): self.nick_callbacks.append(callback) @@ -797,14 +828,11 @@ class ServerConnection(Connection): if DEBUG: print "irc_id: %s" % (prefix) channel = target.lower() - if not channel in self.channels: - self.channels.append(channel) - if channel in self.left_channels: - self.left_channels.remove(channel) - self._call_join_callbacks(channel, None) + if self.channels[channel].state != JOINED: + self.channels[channel]._callback(None) if command in ['inviteonlychan', 'bannedfromchan', 'channelisfull', 'badchannelkey']: - self._call_join_callbacks(arguments[0].lower(), command) + self.channels[arguments[0].lower()]._callback(command) if DEBUG: print "command: %s, source: %s, target: %s, arguments: %s" % ( @@ -914,13 +942,11 @@ class ServerConnection(Connection): """ self.send_raw("ISON " + " ".join(nicks)) - def join(self, channel, callback=None, key=""): + def join(self, channel_name, callback=None, key=""): """Send a JOIN command.""" - if callback: - self.add_join_callback(channel, callback) - if key: - self.channels_keys[channel] = key - self.send_raw("JOIN %s%s" % (channel, (key and (" " + key)))) + if not self.channels.has_key(channel_name): + self.channels[channel_name] = Channel(self, channel_name) + self.channels[channel_name].join(key=key, callback=callback) def kick(self, channel, nick, comment=""): """Send a KICK command.""" @@ -984,23 +1010,15 @@ class ServerConnection(Connection): def oper(self, nick, password): """Send an OPER command.""" self.send_raw("OPER %s %s" % (nick, password)) - - def _remove_channel(self, channel): - if channel in self.channels: - self.channels.remove(channel) - if not channel in self.left_channels: - self.left_channels.append(channel) def part(self, channels, message=""): """Send a PART command.""" try: if isinstance(channels, basestring): - self._remove_channel(channels) - self.send_raw("PART " + channels + (message and (" " + message))) + self.channels[channels].part(message=message) else: for channel in channels: - self._remove_channel(channel) - self.send_raw("PART " + ",".join(channels) + (message and (" " + message))) + self.channels[channel].part(message=message) except ServerNotConnectedError: self.disconnect(volontary=True) self.connect() diff --git a/participant.py b/participant.py --- a/participant.py +++ b/participant.py @@ -354,8 +354,7 @@ class Participant: def _close_irc_connection(self, message): if isinstance(self.irc_connection, ServerConnection): - if self.irc_connection.logged_in: - self.irc_connection.part(self.bridge.irc_room, message=message) + self.irc_connection.part(self.bridge.irc_room, message=message) self.irc_connection.used_by -= 1 if self.irc_connection.used_by < 1: self.irc_connection.close(message)