"""
IMC2 packets. These are pretty well documented at:
http://www.mudbytes.net/index.php?a=articles&s=imc2_protocol

"""
import shlex
from django.conf import settings

class Lexxer(shlex.shlex):
    """
    A lexical parser for interpreting IMC2 packets.
    """
    def __init__(self, packet_str, posix=True):
        shlex.shlex.__init__(self, packet_str, posix=True)
        # Single-quotes are notably not present. This is important!
        self.quotes = '"'
        self.commenters = ''
        # This helps denote what constitutes a continuous token.
        self.wordchars += "~`!@#$%^&*()-_+=[{]}|\\;:',<.>/?"

class IMC2Packet(object):
    """
    Base IMC2 packet class. This is generally sub-classed, aside from using it
    to parse incoming packets from the IMC2 network server.
    """
    def __init__(self, mudname=None, packet_str=None):
        """
        Optionally, parse a packet and load it up.
        """
        # The following fields are all according to the basic packet format of:
        # <sender>@<origin> <sequence> <route> <packet-type> <target>@<destination> <data...>
        self.sender = None
        if not mudname:
            mudname = settings.SERVERNAME
        self.origin = mudname
        self.sequence = None
        self.route = mudname
        self.packet_type = None
        self.target = None
        self.destination = None
        # Optional data.
        self.optional_data = {}
        # Reference to the IMC2Protocol object doing the sending.
        self.imc2_protocol = None

        if packet_str:
            # The lexxer handles the double quotes correctly, unlike just
            # splitting. Spaces throw things off, so shlex handles it
            # gracefully, ala POSIX shell-style parsing.
            lex = Lexxer(packet_str)

            # Token counter.
            counter = 0
            for token in lex:
                if counter == 0:
                    # This is the sender@origin token.
                    sender_origin = token
                    split_sender_origin = sender_origin.split('@')
                    self.sender = split_sender_origin[0].strip()
                    self.origin = split_sender_origin[1]
                elif counter == 1:
                    # Numeric time-based sequence.
                    self.sequence = token
                elif counter == 2:
                    # Packet routing info.
                    self.route = token
                elif counter == 3:
                    # Packet type string.
                    self.packet_type = token
                elif counter == 4:
                    # Get values for the target and destination attributes.
                    target_destination = token
                    split_target_destination = target_destination.split('@')
                    self.target = split_target_destination[0]
                    try:
                        self.destination = split_target_destination[1]
                    except IndexError:
                        # There is only one element to the target@dest segment
                        # of the packet. Wipe the target and move the captured
                        # value to the destination attrib.
                        self.target = '*'
                        self.destination = split_target_destination[0]
                elif counter > 4:
                    # Populate optional data.
                    try:
                        key, value = token.split('=', 1)
                        self.optional_data[key] = value
                    except ValueError:
                        # Failed to split on equal sign, disregard.
                        pass
                # Increment and continue to the next token (if applicable)
                counter += 1

    def __str__(self):
        retval =  """
        --IMC2 package (%s)
        Sender:   %s
        Origin:   %s
        Sequence: %s
        Route:    %s
        Type:     %s
        Target:   %s
        Dest.:    %s
        Data:
         %s
       ------------------------""" % (self.packet_type, self.sender,
                                      self.origin, self.sequence,
                                      self.route, self.packet_type,
                                      self.target, self.destination,
                                      "\n         ".join(["%s: %s" % items for items in self.optional_data.items()]))
        return retval.strip()

    def _get_optional_data_string(self):
        """
        Generates the optional data string to tack on to the end of the packet.
        """
        if self.optional_data:
            data_string = ''
            for key, value in self.optional_data.items():
                # Determine the number of words in this value.
                words = len(str(value).split(' '))
                # Anything over 1 word needs double quotes.
                if words > 1:
                    value = '"%s"' % (value,)
                data_string += '%s=%s ' % (key, value)
            return data_string.strip()
        else:
            return ''

    def _get_sender_name(self):
        """
        Calculates the sender name to be sent with the packet.
        """
        if self.sender == '*':
            # Some packets have no sender.
            return '*'
        elif str(self.sender).isdigit():
            return self.sender
        elif type(self.sender) in [type(u""),type(str())]:
            #this is used by e.g. IRC where no user object is present.
            return self.sender.strip().replace(' ', '_')
        elif self.sender:
            # Player object.
            name = self.sender.get_name(fullname=False, show_dbref=False,
                                        show_flags=False,
                                        no_ansi=True)
            # IMC2 does not allow for spaces.
            return name.strip().replace(' ', '_')
        else:
            # None value. Do something or other.
            return 'Unknown'

    def assemble(self, mudname=None, client_pwd=None, server_pwd=None):
        """
        Assembles the packet and returns the ready-to-send string.
        Note that the arguments are not used, they are there for
        consistency across all packets.
        """
        self.sequence = self.imc2_protocol.sequence
        packet = "%s@%s %s %s %s %s@%s %s\n" % (
                 self._get_sender_name(),
                 self.origin,
                 self.sequence,
                 self.route,
                 self.packet_type,
                 self.target,
                 self.destination,
                 self._get_optional_data_string())
        return packet.strip()


class IMC2PacketAuthPlaintext(object):
    """
    IMC2 plain-text authentication packet. Auth packets are strangely
    formatted, so this does not sub-class IMC2Packet. The SHA and plain text
    auth packets are the two only non-conformers.

    CLIENT Sends:
    PW <mudname> <clientpw> version=<version#> autosetup <serverpw> (SHA256)

    Optional Arguments( required if using the specified authentication method:
    (SHA256)    The literal string: SHA256. This is sent to notify the server
                that the MUD is SHA256-Enabled. All future logins from this
                client will be expected in SHA256-AUTH format if the server
                supports it.
    """
    def assemble(self, mudname=None, client_pwd=None, server_pwd=None):
        """
        This is one of two strange packets, just assemble the packet manually
        and go.
        """
        return 'PW %s %s version=2 autosetup %s\n' %(mudname, client_pwd, server_pwd)


class IMC2PacketKeepAliveRequest(IMC2Packet):
    """
    Description:
    This packet is sent by a MUD to trigger is-alive packets from other MUDs.
    This packet is usually followed by the sending MUD's own is-alive packet.
    It is used in the filling of a client's MUD list, thus any MUD that doesn't
    respond with an is-alive isn't marked as online on the sending MUD's
    mudlist.

    Data:
    (none)

    Example of a received keepalive-request:
    *@YourMUD 1234567890 YourMUD!Hub1 keepalive-request *@*

    Example of a sent keepalive-request:
    *@YourMUD 1234567890 YourMUD keepalive-request *@*
    """
    def __init__(self):
        super(IMC2PacketKeepAliveRequest, self).__init__()
        self.sender = '*'
        self.packet_type = 'keepalive-request'
        self.target = '*'
        self.destination = '*'


class IMC2PacketIsAlive(IMC2Packet):
    """
    Description:
    This packet is the reply to a keepalive-request packet. It is responsible
    for filling a client's mudlist with the information about other MUDs on the
    network.

    Data:
    versionid=<string>
    Where <string> is the text version ID of the client. ("IMC2 4.5 MUD-Net")

    url=<string>
    Where <string> is the proper URL of the client. (http://www.domain.com)

    host=<string>
    Where <string> is the telnet address of the MUD. (telnet://domain.com)

    port=<int>
    Where <int> is the telnet port of the MUD.

    (These data fields are not sent by the MUD, they are added by the server.)
    networkname=<string>
    Where <string> is the network name that the MUD/server is on. ("MyNetwork")

    sha256=<int>
    This is an optional tag that denotes the SHA-256 capabilities of a
    MUD or server.

    Example of a received is-alive:
    *@SomeMUD 1234567890 SomeMUD!Hub2 is-alive *@YourMUD versionid="IMC2 4.5 MUD-Net" url="http://www.domain.com" networkname="MyNetwork" sha256=1 host=domain.com port=5500

    Example of a sent is-alive:
    *@YourMUD 1234567890 YourMUD is-alive *@* versionid="IMC2 4.5 MUD-Net" url="http://www.domain.com" host=domain.com port=5500
    """
    def __init__(self):
        super(IMC2PacketIsAlive, self).__init__()
        self.sender = '*'
        self.packet_type = 'is-alive'
        self.target = '*'
        self.destination = '*'
        self.optional_data = {'versionid': 'Evennia IMC2',
                              'url': '"http://www.evennia.com"',
                              'host': 'test.com',
                              'port': '5555'}


class IMC2PacketIceRefresh(IMC2Packet):
    """
    Description:
    This packet is sent by the MUD to request data about the channels on the
    network. Servers with channels reply with an ice-update packet for each
    channel they control. The usual target for this packet is IMC@$.

    Data:
    (none)

    Example:
    *@YourMUD 1234567890 YourMUD!Hub1 ice-refresh IMC@$
    """
    def __init__(self):
        super(IMC2PacketIceRefresh, self).__init__()
        self.sender = '*'
        self.packet_type = 'ice-refresh'
        self.target = 'IMC'
        self.destination = '$'


class IMC2PacketIceUpdate(IMC2Packet):
    """
    Description:
    A server returns this packet with the data of a channel when prompted with
    an ice-refresh request.

    Data:
    channel=<string>
    The channel's network name in the format of ServerName:ChannelName

    owner=<string>
    The Name@MUD of the channel's owner

    operators=<string>
    A space-seperated list of the Channel's operators, (format: Person@MUD)

    policy=<string>
    The policy is either "open" or "private" with no quotes.

    invited=<string>
    The space-seperated list of invited User@MUDs, only valid for a
    "private" channel.

    excluded=<string>
    The space-seperated list of banned User@MUDs, only valid for "open"
    channels.

    level=<string>      The default level of the channel: Admin, Imp, Imm,
    Mort, or None

    localname=<string>  The suggested local name of the channel.

    Examples:

    Open Policy:
    ICE@Hub1 1234567890 Hub1!Hub2 ice-update *@YourMUD channel=Hub1:ichat owner=Imm@SomeMUD operators=Other@SomeMUD policy=open excluded="Flamer@badMUD Jerk@dirtyMUD" level=Imm localname=ichat

    Private Policy:
    ICE@Hub1 1234567890 Hub1!Hub2 ice-update *@YourMUD channel=Hub1:secretchat owner=Imm@SomeMUD operators=Other@SomeMUD policy=private invited="SpecialDude@OtherMUD CoolDude@WeirdMUD" level=Mort localname=schat
    """
    pass


class IMC2PacketIceMsgRelayed(IMC2Packet):
    """
    Description:
    The -r in this ice-msg packet means it was relayed. This, along with the
    ice-msg-p packet, are used with private policy channels. The 'r' stands
    for 'relay'. All incoming channel messages are from ICE@<server>, where
    <server> is the server hosting the channel.

    Data:
    realfrom=<string>
    The User@MUD the message came from.

    channel=<string>
    The Server:Channel the message is intended to be displayed on.

    text=<string>
    The message text.

    emote=<int>
    An integer value designating emotes. 0 for no emote, 1 for an emote,
    and 2 for a social.

    Examples:
    ICE@Hub1 1234567890 Hub1!Hub2 ice-msg-r *@YourMUD realfrom=You@YourMUD channel=hub1:secret text="Aha! I got it!" emote=0

    ICE@Hub1 1234567890 Hub1!Hub2 ice-msg-r *@YourMUD realfrom=You@YourMUD channel=hub1:secret text=Ahh emote=0

    ICE@Hub1 1234567890 Hub1!Hub2 ice-msg-r *@YourMUD realfrom=You@YourMUD channel=hub1:secret text="grins evilly." emote=1

    ICE@Hub1 1234567890 Hub1!Hub2 ice-msg-r *@YourMUD realfrom=You@YourMUD channel=hub1:secret text="You@YourMUD grins evilly!" emote=2
    """
    pass


class IMC2PacketIceMsgPrivate(IMC2Packet):
    """
    Description:
    This packet is sent when a player sends a message to a private channel.
    This packet should never be seen as incoming to a client. The target of
    this packet should be IMC@<server> of the server hosting the channel.

    Data:
    channel=<string>
    The Server:Channel the message is intended to be displayed on.

    text=<string>
    The message text.

    emote=<int>
    An integer value designating emotes. 0 for no emote, 1 for an emote,
    and 2 for a social.

    echo=<int>
    Tells the server to echo the message back to the sending MUD. This is only
    seen on out-going messages.

    Examples:
    You@YourMUD 1234567890 YourMUD ice-msg-p IMC@Hub1 channel=Hub1:secret text="Ahh! I got it!" emote=0 echo=1
    You@YourMUD 1234567890 YourMUD ice-msg-p IMC@Hub1 channel=Hub1:secret text=Ahh! emote=0 echo=1
    You@YourMUD 1234567890 YourMUD ice-msg-p IMC@Hub1 channel=Hub1:secret text="grins evilly." emote=1 echo=1
    You@YourMUD 1234567890 YourMUD ice-msg-p IMC@Hub1 channel=Hub1:secret text="You@YourMUD grins evilly." emote=2 echo=1
    """
    pass


class IMC2PacketIceMsgBroadcasted(IMC2Packet):
    """
    Description:
    This is the packet used to chat on open policy channels. When sent from a
    MUD, it is broadcasted across the network. Other MUDs receive it in-tact
    as it was sent by the originating MUD. The server that hosts the channel
    sends the packet back to the originating MUD as an 'echo' by removing the
    "echo=1" and attaching the "sender=Person@MUD" data field.

    Data:
    channel=<string>
    The Server:Channel the message is intended to be displayed on.

    text=<string>
    The message text.

    emote=<int>
    An integer value designating emotes. 0 for no emote, 1 for an emote,
    and 2 for a social.

    *echo=<int>
    This stays on broadcasted messages. It tells the channel's server to
    relay an echo back.

    *sender=<string>
    The hosting server replaces "echo=1" with this when sending the echo back
    to the originating MUD.

    Examples:
    (See above for emote/social examples as they are pretty much the same)

    Return Echo Packet:
    You-YourMUD@Hub1 1234567890 Hub1 ice-msg-b *@YourMUD text=Hi! channel=Hub1:ichat sender=You@YourMUD emote=0

    Broadcasted Packet:
    You@YourMUD 1234567890 YourMUD!Hub1 ice-msg-b *@* channel=Hub1:ichat text=Hi! emote=0 echo=1
    """
    def __init__(self, server, channel, pobject, message):
        """
        Args:
          server: (String) Server name the channel resides on (obs - this is
                           e.g. Server01, not the full network name!)
          channel: (String) Name of the IMC2 channel.
          pobject: (Object) Object sending the message.
          message: (String) Message to send.
        """
        super(IMC2PacketIceMsgBroadcasted, self).__init__()
        self.sender = pobject
        self.packet_type = 'ice-msg-b'
        self.target = '*'
        self.destination = '*'
        self.optional_data = {'channel': '%s:%s' % (server, channel),
                              'text': message,
                              'emote': 0,
                              'echo': 1}


class IMC2PacketUserCache(IMC2Packet):
    """
    Description:
    Sent by a MUD with a new IMC2-able player or when a player's gender changes,
    this packet contains only the gender for data. The packet's origination
    should be the Player@MUD.

    Data:
    gender=<int>  0 is male, 1 is female, 2 is anything else such as neuter.
    Will be referred to as "it".

    Example:
    Dude@someMUD 1234567890 SomeMUD!Hub2!Hub1 user-cache *@* gender=0
    """
    pass


class IMC2PacketUserCacheRequest(IMC2Packet):
    """
    Description:
    The MUD sends this packet out when making a request for the user-cache
    information of the user included in the data part of the packet.

    Data:
    user=<string>  The Person@MUD whose data the MUD is seeking.

    Example:
    *@YourMUD 1234567890 YourMUD user-cache-request *@SomeMUD user=Dude@SomeMUD
    """
    pass


class IMC2PacketUserCacheReply(IMC2Packet):
    """
    Description:
    A reply to the user-cache-request packet. It contains the user and gender
    for the user.

    Data:
    user=<string>
    The Person@MUD whose data the MUD requested.

    gender=<int>
    The gender of the Person@MUD in the 'user' field.

    Example:
    *@someMUD 1234567890 SomeMUD!Hub2!Hub1 user-cache-reply *@YourMUD user=Dude@SomeMUD gender=0
    """
    pass


class IMC2PacketTell(IMC2Packet):
    """
    Description:
    This packet is used to communicate private messages between users on MUDs
    across the network.

    Data:
    text=<string>  Message text
    isreply=<int>  Two settings: 1 denotes a reply, 2 denotes a tell social.

    Example:

    Originating:
    You@YourMUD 1234567890 YourMUD tell Dude@SomeMUD text="Having fun?"

    Reply from Dude:
    Dude@SomeMUD 1234567890 SomeMUD!Hub1 tell You@YourMUD text="Yeah, this is cool!" isreply=1
    """
    def __init__(self, pobject, target, destination, message):
        super(IMC2PacketTell, self).__init__()
        self.sender = pobject
        self.packet_type = "tell"
        self.target = target
        self.destination = destination
        self.optional_data = {"text": message,
                              "isreply":None}

    def assemble(self, mudname=None, client_pwd=None, server_pwd=None):
        self.sequence = self.imc2_protocol.sequence
        #self.route = "%s!%s" % (self.origin, self.imc2_protocol.factory.servername.capitalize())
        return '''"%s@%s %s %s tell %s@%s text="%s"''' % (self.sender, self.origin, self.sequence,
                                                          self.route, self.target, self.destination,
                                                          self.optional_data.get("text","NO TEXT GIVEN"))


class IMC2PacketEmote(IMC2Packet):
    """
    Description:
    This packet seems to be sent by servers when notifying the network of a new
    channel or the destruction of a channel.

    Data:
    channel=<int>
    Unsure of what this means. The channel seen in both creation and
    destruction packets is 15.

    level=<int>
    I am assuming this is the permission level of the sender. In both
    creation and destruction messages, this is -1.

    text=<string>
    This is the message to be sent to the users.

    Examples:
    ICE@Hub1 1234567890 Hub1 emote *@* channel=15 level=-1 text="the
                    channel called hub1:test has been destroyed by You@YourMUD."
    """
    pass


class IMC2PacketRemoteAdmin(IMC2Packet):
    """
    Description:
    This packet is used in remote server administration. Please note that
    SHA-256 Support is *required* for a client to use this feature. The command
    can vary, in fact this very packet is highly dependant on the server it's
    being directed to. In most cases, sending the 'list' command will have a
    remote-admin enabled server send you the list of commands it will accept.

    Data:
    command=<string>
    The command being sent to the server for processing.

    data=<string>
    Data associated with the command. This is not always required.

    hash=<string>
    The SHA-256 hash that is verified by the server. This hash is generated in
    the same manner as an authentication packet.

    Example:
    You@YourMUD 1234567890 YourMUD remote-admin IMC@Hub1 command=list hash=<hash goes here>
    """
    pass


class IMC2PacketIceCmd(IMC2Packet):
    """
    Description:
    Used for remote channel administration. In most cases, one must be listed
    as a channel creator on the target server in order to do much with this
    packet. Other cases include channel operators.

    Data:
    channel=<string>
    The target server:channel for the command.

    command=<string>
    The command to be processed.

    data=<string>
    Data associated with the command. This is not always required.

    Example:
    You@YourMUD 1234567890 YourMUD ice-cmd IMC@hub1 channel=hub1:ichat command=list
    """
    pass


class IMC2PacketDestroy(IMC2Packet):
    """
    Description:
    Sent by a server to indicate the destruction of a channel it hosted.
    The mud should remove this channel from its local configuration.

    Data:
    channel=<string>  The server:channel being destroyed.
    """
    pass


class IMC2PacketWho(IMC2Packet):
    """
    Description:
    A seemingly mutli-purpose information-requesting packet. The istats
    packet currently only works on servers, or at least that's the case on
    MUD-Net servers. The 'finger' type takes a player name in addition to the
    type name.

    Example: "finger Dude". The 'who' and 'info' types take no argument.
    The MUD is responsible for building the reply text sent in the who-reply
    packet.

    Data:
    type=<string>  Types: who, info, "finger <name>", istats (server only)

    Example:
    Dude@SomeMUD 1234567890 SomeMUD!Hub1 who *@YourMUD type=who
    """
    pass


class IMC2PacketWhoReply(IMC2Packet):
    """
    Description:
    The multi-purpose reply to the multi-purpose information-requesting 'who'
    packet. The MUD is responsible for building the return data, including the
    format of it. The mud can use the permission level sent in the original who
    packet to filter the output. The example below is the MUD-Net format.

    Data:
    text=<string>  The formatted reply to a 'who' packet.

    Additional Notes:
    The example below is for the who list packet. The same construction would
    go into formatting the other types of who packets.

    Example:
    *@YourMUD 1234567890 YourMUD who-reply Dude@SomeMUD text="\n\r~R-=< ~WPlayers on YourMUD ~R>=-\n\r            ~Y-=< ~Wtelnet://yourmud.domain.com:1234 ~Y>=-\n\r\n\r~B--------------------------------=< ~WPlayers ~B>=---------------------------------\n\r\n\r      ~BPlayer        ~z<--->~G Mortal the Toy\n\r\n\r~R-------------------------------=< ~WImmortals ~R>=--------------------------------\n\r\n\r      ~YStaff        ~z<--->~G You the Immortal\n\r\n\r~Y<~W2 Players~Y> ~Y<~WHomepage: http://www.yourmud.com~Y> <~W  2 Max Since Reboot~Y>\n\r~Y<~W3 logins since last reboot on Tue Feb 24, 2004 6:55:59 PM EST~Y>"
    """
    pass


class IMC2PacketWhois(IMC2Packet):
    """
    Description:
    Sends a request to the network for the location of the specified player.

    Data:
    level=<int>  The permission level of the person making the request.

    Example:
    You@YourMUD 1234567890 YourMUD whois dude@* level=5
    """
    def __init__(self, pobject_id, whois_target):
        super(IMC2PacketWhois, self).__init__()
        # Use the dbref, it's easier to trace back for the whois-reply.
        self.sender = pobject_id
        self.packet_type = 'whois'
        self.target = whois_target
        self.destination = '*'
        self.optional_data = {'level': '5'}


class IMC2PacketWhoisReply(IMC2Packet):
    """
    Description:
    The reply to a whois packet. The MUD is responsible for building and formatting
    the text sent back to the requesting player, and can use the permission level
    sent in the original whois packet to filter or block the response.

    Data:
    text=<string>  The whois text.

    Example:
    *@SomeMUD 1234567890 SomeMUD!Hub1 whois-reply You@YourMUD text="~RIMC Locate: ~YDude@SomeMUD: ~cOnline.\n\r"
    """
    pass


class IMC2PacketBeep(IMC2Packet):
    """
    Description:
    Sends out a beep packet to the Player@MUD. The client receiving this should
    then send a bell-character to the target player to 'beep' them.

    Example:
    You@YourMUD 1234567890 YourMUD beep dude@somemud
    """
    pass


class IMC2PacketIceChanWho(IMC2Packet):
    """
    Description:
    Sends a request to the specified MUD or * to list all the users listening
    to the specified channel.

    Data:
    level=<int>
    Sender's permission level.

    channel=<string>
    The server:chan name of the channel.

    lname=<string>
    The localname of the channel.

    Example:
    You@YourMUD 1234567890 YourMUD ice-chan-who somemud level=5 channel=Hub1:ichat lname=ichat
    """
    pass


class IMC2PacketIceChanWhoReply(IMC2Packet):
    """
    Description:
    This is the reply packet for an ice-chan-who. The MUD is responsible for
    creating and formatting the list sent back in the 'list' field. The
    permission level sent in the original ice-chan-who packet can be used to
    filter or block the response.

    Data:
    channel=<string>
    The server:chan of the requested channel.

    list=<string>
    The formatted list of local listeners for that MUD.

    Example:
    *@SomeMUD 1234567890 SomeMUD!Hub1 ice-chan-whoreply You@YourMUD channel=Hub1:ichat list="The following people are listening to ichat on SomeMUD:\n\r\n\rDude\n\r"
    """
    pass


class IMC2PacketLaston(IMC2Packet):
    """
    Description:
    This packet queries the server the mud is connected to to find out when a
    specified user was last seen by the network on a public channel.

    Data:
    username=<string>  The user, user@mud, or "all" being queried. Responses
    to this packet will be sent by the server in the form of a series of tells.

    Example: User@MUD 1234567890 MUD imc-laston SERVER username=somenamehere
    """
    pass


class IMC2PacketCloseNotify(IMC2Packet):
    """
    Description:
    This packet alerts the network when a server or MUD has disconnected. The
    server hosting the server or MUD is responsible for sending this packet
    out across the network. Clients need only process the packet to remove the
    disconnected MUD from their MUD list (or mark it as Disconnected).

    Data:
    host=<string>
    The MUD or server that has disconnected from the network.

    Example:
    *@Hub2 1234567890 Hub2!Hub1 close-notify *@* host=DisconnMUD
    """
    pass

if __name__ == "__main__":
    packstr = "Kayle@MW 1234567 MW!Server02!Server01 ice-msg-b *@* channel=Server01:ichat text=\"*they're going woot\" emote=0 echo=1"
    packstr = "*@Lythelian 1234567 Lythelian!Server01 is-alive *@* versionid=\"Tim's LPC IMC2 client 30-Jan-05 / Dead Souls integrated\" networkname=Mudbytes url=http://dead-souls.net host=70.32.76.142 port=6666 sha256=0"
    print IMC2Packet(packstr)

