"""
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
)