terom@41: """ terom@50: An IRC logfile consists of a series of lines/events terom@41: """ terom@41: terom@50: class LogTypes : terom@50: """ terom@86: Definitions of the various LogLines types: terom@86: terom@86: LogTypes.RAW terom@86: LogTypes.LOG_OPEN terom@86: LogTypes.LOG_CLOSE terom@86: terom@86: LogTypes.MSG terom@86: LogTypes.NOTICE terom@86: LogTypes.ACTION terom@86: terom@86: LogTypes.JOIN terom@86: LogTypes.PART terom@86: LogTypes.KICK terom@86: LogTypes.MODE terom@86: terom@86: LogTypes.NICK terom@86: LogTypes.QUIT terom@86: terom@86: LogTypes.TOPIC terom@86: terom@86: LogTypes.SELF_NOTICE terom@86: LogTypes.SELF_NICK terom@50: """ terom@86: terom@86: # list of LogType values by name terom@86: LIST = [ terom@86: ## special terom@86: # unknown type, may or may not have a timestamp, no source, only data terom@86: ('RAW', 0x01), terom@86: terom@86: # log opened terom@86: ('LOG_OPEN', 0x02), terom@86: terom@86: # log closed terom@86: ('LOG_CLOSE', 0x03), terom@86: terom@86: ## messages terom@92: # sent message to terom@86: ('MSG', 0x10), terom@86: terom@92: # sent notice with message to terom@86: ('NOTICE', 0x11), terom@86: terom@92: # sent CTCP action with message to terom@86: ('ACTION', 0x12), terom@86: terom@86: ## user-channel stats terom@92: # joined terom@86: ('JOIN', 0x21), terom@86: terom@92: # left with message terom@86: ('PART', 0x22), terom@86: terom@92: # kicked from with message terom@86: ('KICK', 0x25), terom@86: terom@92: # changed modes on with modestring terom@86: ('MODE', 0x26), terom@86: terom@86: ## user status terom@92: # changed nickname to terom@86: ('NICK', 0x31), terom@86: terom@92: # quit the network with quit-message terom@86: ('QUIT', 0x32), terom@86: terom@86: ## general channel status terom@92: # changed the topic of to terom@92: # data may be None if the topic was unset terom@86: ('TOPIC', 0x41), terom@86: terom@86: ## our own actions terom@92: # we () sent a notice with message to terom@86: ('SELF_NOTICE', 0x51), terom@92: terom@92: # we () changed nickname to terom@86: ('SELF_NICK', 0x52), terom@97: terom@97: ## slightly weirder bits terom@97: # netsplit between and , is a space-separated list of s affected terom@97: # the last item in the list of nicknames may also be of the form "+", where count is the number of additional, but hidden, nicknames affected terom@97: ('NETSPLIT_START', 0x61), terom@97: terom@97: # netsplit over, is a list of users affected, see NETSPLIT_START terom@97: ('NETSPLIT_END', 0x062), terom@86: ] terom@50: terom@86: @classmethod terom@86: def name_from_code (cls, code) : terom@86: """ terom@86: Looks up a LogType name by code terom@86: """ terom@86: terom@86: return dict((type, name) for name, type in cls.LIST)[code] terom@86: terom@86: # apply as attributes terom@86: for name, code in LogTypes.LIST : terom@86: setattr(LogTypes, name, code) terom@50: terom@97: # masks terom@97: LogTypes._NETSPLIT_MASK = 0x60 terom@97: terom@50: class LogLine (object) : terom@41: """ terom@41: An event on some specific channel terom@41: """ terom@41: terom@86: # the LogChannel terom@86: channel = None terom@86: terom@64: # the offset, only garunteed to be unique for a specific channel and date terom@64: offset = None terom@64: terom@50: # the event type, as defiend in LogTypes terom@41: type = None terom@41: terom@41: # the UTC timestamp of the event terom@41: timestamp = None terom@41: terom@92: # the source, this should be a (nickname, username, hostname, chanflags) tuple terom@41: source = None terom@41: terom@92: # possible target nickname for certain types (kick, nick) terom@86: target = None terom@86: terom@41: # associated data (message, etc) terom@41: data = None terom@50: terom@86: def __init__ (self, channel, offset, type, timestamp, source, target, data) : terom@50: """ terom@50: Initialize with given values terom@50: """ terom@64: terom@86: self.channel = channel terom@64: self.offset = offset terom@50: self.type = type terom@50: self.timestamp = timestamp terom@50: self.source = source terom@86: self.target = target terom@50: self.data = data terom@86: terom@90: def format_type (self) : terom@90: """ terom@90: Formats type as a string code terom@90: """ terom@90: terom@90: return LogTypes.name_from_code(self.type) terom@90: terom@90: def format_source (self) : terom@90: """ terom@92: Formats source as [][][!][@], omitting those parts that are missing. terom@92: terom@92: If all parts are None, this returns the empty string terom@90: """ terom@90: terom@90: nick, user, host, flags = self.source terom@90: terom@90: return "%s%s%s%s" % ( terom@91: flags if flags and flags != ' ' else '', terom@90: nick if nick else '', terom@90: '!' + user if user else '', terom@90: '@' + host if host else '' terom@86: ) terom@92: terom@97: def __unicode__ (self) : terom@92: return '\t'.join(( terom@92: self.channel.name, terom@92: str(self.offset), terom@92: self.format_type(), terom@92: str(self.timestamp), terom@92: self.format_source(), terom@92: str(self.target), terom@97: unicode(self.data) terom@92: )) terom@50: terom@90: def __repr__ (self) : terom@90: return "LogLine(%r, %s, %-12s, %s, %-35s, %-10s, %r)" % ( terom@90: self.channel, self.offset, self.format_type(), self.timestamp, self.format_source(), self.target, self.data terom@90: ) terom@90: