From 181133d9173f1c052a1d3692b6d00a6f7c1500e8 Mon Sep 17 00:00:00 2001 From: Greg Taylor Date: Thu, 30 Apr 2009 03:56:52 +0000 Subject: [PATCH] Add tracking of IMC2 channels and the new 'imcchanlist' command. --- src/commands/imc2.py | 32 +++++++++++++++----------- src/imc2/connection.py | 17 ++++++++++++++ src/imc2/packets.py | 7 +++++- src/imc2/trackers.py | 51 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 92 insertions(+), 15 deletions(-) diff --git a/src/commands/imc2.py b/src/commands/imc2.py index abe5a8553b..5f3de25d48 100644 --- a/src/commands/imc2.py +++ b/src/commands/imc2.py @@ -13,7 +13,7 @@ from src.ansi import parse_ansi from src.imc2.imc_ansi import IMCANSIParser from src.imc2 import connection as imc2_conn from src.imc2.packets import * -from src.imc2.trackers import IMC2_MUDLIST +from src.imc2.trackers import IMC2_MUDLIST, IMC2_CHANLIST def cmd_imcwhois(command): """ @@ -42,27 +42,33 @@ def cmd_imcansi(command): source_object.emit_to(retval) GLOBAL_CMD_TABLE.add_command("imcansi", cmd_imcansi) -def cmd_imckeepalive(command): +def cmd_imcicerefresh(command): """ - Sends an is-alive packet to the network. + Semds an ice-refresh packet. """ source_object = command.source_object - source_object.emit_to("Sending") - packet = IMC2PacketIsAlive() + packet = IMC2PacketIceRefresh() imc2_conn.IMC2_PROTOCOL_INSTANCE.send_packet(packet) source_object.emit_to("Sent") -GLOBAL_CMD_TABLE.add_command("imckeepalive", cmd_imckeepalive) +GLOBAL_CMD_TABLE.add_command("imcicerefresh", cmd_imcicerefresh) -def cmd_imckeeprequest(command): +def cmd_imcchanlist(command): """ - Sends a keepalive-request packet to the network. + Shows the list of cached channels from the IMC2 Channel list. """ source_object = command.source_object - source_object.emit_to("Sending") - packet = IMC2PacketKeepAliveRequest() - imc2_conn.IMC2_PROTOCOL_INSTANCE.send_packet(packet) - source_object.emit_to("Sent") -GLOBAL_CMD_TABLE.add_command("imckeeprequest", cmd_imckeeprequest) + + retval = 'Channels on %s\n\r' % imc2_conn.IMC2_PROTOCOL_INSTANCE.network_name + + retval += ' Full Name Name Owner Perm Policy\n\r' + retval += ' --------- ---- ----- ---- ------\n\r' + for channel in IMC2_CHANLIST.get_channel_list(): + retval += ' %-18s %-10s %-15s %-7s %s\n\r' % (channel.full_name, channel.name, + channel.owner, channel.level, + channel.policy) + retval += '%s channels found.' % len(IMC2_CHANLIST.chan_list) + source_object.emit_to(retval) +GLOBAL_CMD_TABLE.add_command("imcchanlist", cmd_imcchanlist) def cmd_imclist(command): """ diff --git a/src/imc2/connection.py b/src/imc2/connection.py index 54ebf2605f..6f86d4f5d2 100644 --- a/src/imc2/connection.py +++ b/src/imc2/connection.py @@ -100,6 +100,8 @@ class IMC2Protocol(StatefulTelnetProtocol): # IMC2 protocol states that KeepAliveRequests should be followed # up by the requester sending an IsAlive packet. self.send_packet(IMC2PacketIsAlive()) + # Get a listing of channels. + self.send_packet(IMC2PacketIceRefresh()) def _handle_channel_mappings(self, packet): """ @@ -135,10 +137,23 @@ class IMC2Protocol(StatefulTelnetProtocol): self._parse_auth_response(line) else: if settings.IMC2_DEBUG and 'is-alive' not in line: + # if IMC2_DEBUG mode is on, print the contents of the packet + # to stdout. logger.log_infomsg("PACKET: %s" % line) + + # Parse the packet and encapsulate it for easy access packet = IMC2Packet(packet_str = line) + if settings.IMC2_DEBUG and packet.packet_type not in ['is-alive', 'keepalive-request']: + # Print the parsed packet's __str__ representation. + # is-alive and keepalive-requests happen pretty frequently. + # Don't bore us with them in stdout. logger.log_infomsg(packet) + + """ + Figure out what kind of packet we're dealing with and hand it + off to the correct handler. + """ if packet.packet_type == 'is-alive': IMC2_MUDLIST.update_mud_from_packet(packet) elif packet.packet_type == 'keepalive-request': @@ -151,6 +166,8 @@ class IMC2Protocol(StatefulTelnetProtocol): reply_listener.handle_whois_reply(packet) elif packet.packet_type == 'close-notify': IMC2_MUDLIST.remove_mud_from_packet(packet) + elif packet.packet_type == 'ice-update': + IMC2_CHANLIST.update_channel_from_packet(packet) elif packet.packet_type == 'tell': sessions = session_mgr.find_sessions_from_username(packet.target) for session in sessions: diff --git a/src/imc2/packets.py b/src/imc2/packets.py index 6944e367ca..f521fd2d5f 100644 --- a/src/imc2/packets.py +++ b/src/imc2/packets.py @@ -274,7 +274,12 @@ class IMC2PacketIceRefresh(IMC2Packet): Example: *@YourMUD 1234567890 YourMUD!Hub1 ice-refresh IMC@$ """ - pass + def __init__(self): + super(IMC2PacketIceRefresh, self).__init__() + self.sender = '*' + self.packet_type = 'ice-refresh' + self.target = 'IMC' + self.destination = '$' class IMC2PacketIceUpdate(IMC2Packet): """ diff --git a/src/imc2/trackers.py b/src/imc2/trackers.py index 57627ef954..757c7cd3ac 100644 --- a/src/imc2/trackers.py +++ b/src/imc2/trackers.py @@ -55,6 +55,55 @@ class IMC2MudList(object): except KeyError: # No matching entry, no big deal. pass + +class IMC2Channel(object): + """ + Stores information about channels available on the network. + """ + def __init__(self, packet): + self.name = packet.optional_data.get('localname', None) + self.full_name = packet.optional_data.get('channel', None) + self.level = packet.optional_data.get('level', None) + self.owner = packet.optional_data.get('owner', None) + self.policy = packet.optional_data.get('policy', None) + self.last_updated = time() + +class IMC2ChanList(object): + """ + Keeps track of other MUDs connected to the IMC network. + """ + def __init__(self): + # Chan list is stored in a dict, key being the IMC Mud name. + self.chan_list = {} + + def get_channel_list(self): + """ + Returns a sorted list of cached channels. + """ + channels = self.chan_list.items() + channels.sort() + return [value for key, value in channels] + + def update_channel_from_packet(self, packet): + """ + This grabs relevant info from the packet and stuffs it in the + channel list for later retrieval. + """ + channel = IMC2Channel(packet) + self.chan_list[channel.name] = channel + + def remove_channel_from_packet(self, packet): + """ + Removes a channel from the Channel list when given a packet. + """ + channel = IMC2Channel(packet) + try: + del self.chan_list[channel.name] + except KeyError: + # No matching entry, no big deal. + pass # Use this instance to keep track of the other games on the network. -IMC2_MUDLIST = IMC2MudList() \ No newline at end of file +IMC2_MUDLIST = IMC2MudList() +# Tracks the list of available channels on the network. +IMC2_CHANLIST = IMC2ChanList() \ No newline at end of file