diff --git a/pickups/irc.py b/pickups/irc.py index aef6025..2e8e73c 100644 --- a/pickups/irc.py +++ b/pickups/irc.py @@ -1,4 +1,5 @@ import logging +from . import util RPL_WELCOME = 1 RPL_WHOISUSER = 311 @@ -20,12 +21,14 @@ class Client(object): - def __init__(self, reader, writer): + def __init__(self, server, reader, writer): + self.server = server self.reader = reader self.writer = writer self.nickname = None self.sent_messages = [] + self.joined_channels = set() def readline(self): return self.reader.readline() @@ -62,7 +65,12 @@ def list_channels(self, info): def join(self, channel): """Tells the client to join a channel.""" - self.write(self.nickname, 'JOIN', ':{}'.format(channel)) + self.joined_channels.add(channel) + self.write(self.nickname, 'JOIN', channel) + conv = util.channel_to_conversation(channel, self.server._conv_list) + self.topic(channel, util.get_topic(conv)) + self.list_nicks(channel, (util.get_nick(user) for user in conv.users)) + def list_nicks(self, channel, nicks): """Tells the client what nicks are in channel.""" @@ -85,6 +93,8 @@ def topic(self, channel, topic): def privmsg(self, hostmask, target, message): """Sends the client a message from someone.""" + if target not in self.joined_channels: + self.join(target) for line in message.splitlines(): if line: self.write(hostmask, 'PRIVMSG', target, ':{}'.format(line)) diff --git a/pickups/server.py b/pickups/server.py index 96e07d3..3d1c23b 100644 --- a/pickups/server.py +++ b/pickups/server.py @@ -58,7 +58,7 @@ def _on_hangups_event(self, conv_event): def _on_client_connect(self, client_reader, client_writer): """Called when an IRC client connects.""" - client = irc.Client(client_reader, client_writer) + client = irc.Client(self, client_reader, client_writer) task = asyncio.Task(self._handle_client(client)) self.clients[task] = client logger.info("New Connection") @@ -112,9 +112,14 @@ def _handle_client(self, client): client.topic(channel, util.get_topic(conv)) client.list_nicks(channel, (util.get_nick(user) for user in conv.users)) + client.joined_channels.add(channel) + elif line.startswith('PART'): + channel = line.split(' ')[1] + client.joined_channels.remove(channel) elif line.startswith('WHO'): query = line.split(' ')[1] if query.startswith('#'): + channel = line.split(' ')[1] conv = util.channel_to_conversation(channel, self._conv_list) responses = [{ diff --git a/pickups/util.py b/pickups/util.py index a3d14b9..61a1931 100644 --- a/pickups/util.py +++ b/pickups/util.py @@ -6,21 +6,30 @@ CONV_HASH_LEN = 7 +hashes = {} def conversation_to_channel(conv): """Return channel name for hangups.Conversation.""" # Must be 50 characters max and not contain space or comma. - conv_hash = hashlib.sha1(conv.id_.encode()).hexdigest() name = get_conv_name(conv).replace(',', '_').replace(' ', '') - return '#{}[{}]'.format(name[:50 - CONV_HASH_LEN - 3], - conv_hash[:CONV_HASH_LEN]) + name = "#{}".format(name[:49]) + conv_hash = hashlib.sha1(conv.id_.encode()).hexdigest() + # Avoid name collisions. + if name in hashes and hashes[name] != conv_hash: + while name in hashes: + if len(name) > 50: + name = "{}_".format(name[:-1]) + else: + name = "{}_".format(name) + hashes[name] = conv_hash + return name def channel_to_conversation(channel, conv_list): """Return hangups.Conversation for channel name.""" - conv_hash = re.match(r'^.*\[([a-f0-9]+)\]$', channel).group(1) - return {hashlib.sha1(conv.id_.encode()).hexdigest()[:CONV_HASH_LEN]: conv - for conv in conv_list.get_all()}[conv_hash] + conv_hash = hashes[channel] + return {hashlib.sha1(conv.id_.encode()).hexdigest(): conv for conv in + conv_list.get_all()}[conv_hash] def get_nick(user):