log_line.py
author Tero Marttila <terom@fixme.fi>
Wed, 11 Feb 2009 03:58:20 +0200
changeset 101 f5f53cc0ce16
parent 97 6165f1ba458d
permissions -rw-r--r--
implement autoload --reset
"""
    An IRC logfile consists of a series of lines/events
"""

class LogTypes :
    """
        Definitions of the various LogLines types:

            LogTypes.RAW
            LogTypes.LOG_OPEN
            LogTypes.LOG_CLOSE

            LogTypes.MSG
            LogTypes.NOTICE
            LogTypes.ACTION

            LogTypes.JOIN
            LogTypes.PART
            LogTypes.KICK
            LogTypes.MODE

            LogTypes.NICK
            LogTypes.QUIT

            LogTypes.TOPIC

            LogTypes.SELF_NOTICE
            LogTypes.SELF_NICK
    """
 
    # list of LogType values by name
    LIST = [
        ## special
        # unknown type, may or may not have a timestamp, no source, only data
        ('RAW',         0x01),

        # log opened
        ('LOG_OPEN',    0x02),

        # log closed
        ('LOG_CLOSE',   0x03),

        ## messages
        # <source> sent message <data> to <channel>
        ('MSG',         0x10),
        
        # <source> sent notice with message <data> to <channel>
        ('NOTICE',      0x11),

        # <source> sent CTCP action with message <data> to <channel>
        ('ACTION',      0x12),
        
        ## user-channel stats
        # <source> joined <channel>
        ('JOIN',        0x21),

        # <source> left <channel> with message <data>
        ('PART',        0x22),

        # <source> kicked <target> from <channel> with message <data>
        ('KICK',        0x25),
     
        # <source> changed modes on <channel> with modestring <data>
        ('MODE',        0x26),
        
        ## user status
        # <source> changed nickname to <target>
        ('NICK',        0x31),

        # <source> quit the network with quit-message <data>
        ('QUIT',        0x32),

        ## general channel status
        # <source> changed the topic of <channel> to <data>
        # data may be None if the topic was unset
        ('TOPIC',       0x41),

        ## our own actions
        # we (<source>) sent a notice with message <data> to <channel>
        ('SELF_NOTICE', 0x51),

        # we (<source>) changed nickname to <target>
        ('SELF_NICK',   0x52),

        ## slightly weirder bits
        # netsplit between <source_hostname> and <target_hostname>, <data> is a space-separated list of <chanflags><nickname>s affected
        # the last item in the list of nicknames may also be of the form "+<count>", where count is the number of additional, but hidden, nicknames affected
        ('NETSPLIT_START',  0x61),

        # netsplit over, <data> is a list of users affected, see NETSPLIT_START
        ('NETSPLIT_END',    0x062),
    ]
    
    @classmethod
    def name_from_code (cls, code) :
        """
            Looks up a LogType name by code
        """

        return dict((type, name) for name, type in cls.LIST)[code]

# apply as attributes
for name, code in LogTypes.LIST :
    setattr(LogTypes, name, code)

# masks
LogTypes._NETSPLIT_MASK = 0x60

class LogLine (object) :
    """
        An event on some specific channel
    """

    # the LogChannel
    channel = None

    # the offset, only garunteed to be unique for a specific channel and date
    offset = None

    # the event type, as defiend in LogTypes
    type = None

    # the UTC timestamp of the event
    timestamp = None

    # the source, this should be a (nickname, username, hostname, chanflags) tuple
    source = None

    # possible target nickname for certain types (kick, nick)
    target = None

    # associated data (message, etc)
    data = None
    
    def __init__ (self, channel, offset, type, timestamp, source, target, data) :
        """
            Initialize with given values
        """
        
        self.channel = channel
        self.offset = offset
        self.type = type
        self.timestamp = timestamp
        self.source = source
        self.target = target
        self.data = data
    
    def format_type (self) :
        """
            Formats type as a string code
        """

        return LogTypes.name_from_code(self.type)

    def format_source (self) :
        """
            Formats source as [<chanflags>][<nickname>][!<username>][@<hostname>], omitting those parts that are missing.

            If all parts are None, this returns the empty string
        """

        nick, user, host, flags = self.source

        return "%s%s%s%s" % (
            flags if flags and flags != ' ' else '',
            nick if nick else '',
            '!' + user if user else '',
            '@' + host if host else ''
        )
   
    def __unicode__ (self) :
        return '\t'.join((
            self.channel.name,
            str(self.offset),
            self.format_type(),
            str(self.timestamp),
            self.format_source(),
            str(self.target),
            unicode(self.data)
        ))

    def __repr__ (self) :
        return "LogLine(%r, %s, %-12s, %s, %-35s, %-10s, %r)" % (
            self.channel, self.offset, self.format_type(), self.timestamp, self.format_source(), self.target, self.data
        )