All pastes #765055 Raw Edit

silan-0.0.2 development 03

public python v1 · immutable
·published 2007-11-07 19:41 UTC
rendered paste body
#!/usr/bin/python -tt## SILAN# Simple IRC Log Analyzer# http://slackforge.com/silan/## Version 0.0.2# An extremely simple IRC log analyzer --;# Only supports dircproxy logs, because that's what I use## Copyright (c) 2007 Shidayu <shidayu@gmail.com>## Permission is hereby granted, free of charge, to any person obtaining a copy# of this software and associated documentation files (the "Software"), to deal# in the Software without restriction, including without limitation the rights# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell# copies of the Software, and to permit persons to whom the Software is# furnished to do so, subject to the following conditions:## The above copyright notice and this permission notice shall be included in# all copies or substantial portions of the Software.## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN# THE SOFTWARE.##### Import Other Modules#import os, re, stat, sys, glob, datetime, string, time, randomfrom ConfigParser import SafeConfigParser### Globals## Regular Expressions used by SILANre_rawlog = re.compile('^\[(\d\d) ([A-Z][a-z][a-z]) (\d\d):(\d\d)\] ([^\n\r\f\v]*)$')re_ownnick = re.compile('--- You changed your nickname to (\S*)')re_nickchange = re.compile('--- (\S*) \([^\t\n\r\f\v)]*\) changed nickname to (\S*)')re_quit = re.compile('<-- (\S*) \([^\t\n\r\f\v)]*\) quit from IRC: ([^\n\r\f\v]*)$')re_join = re.compile('--> (\S*) \([^\t\n\r\f\v)]*\) joined the channel$')re_part = re.compile('<-- (\S*) \([^\t\n\r\f\v)]*\) left the channel$')re_message = re.compile('<([^ \t\n\r\f\v!]*)![^\t\n\r\f\v>]*> ([^\n\r\f\v]*)$')re_describe = re.compile('\* (\S*) ([^\n\r\f\v]*)')re_topic = re.compile('--- (\S*) \([^\t\n\r\f\v)]*\) changed topic: ([^\t\n\r\f\v]*)$')re_kick = re.compile('<-- (\S*) kicked off by (\S*) \([^\t\n\r\f\v)]*\): ([^\n\r\f\v]*)$')re_ownkick = re.compile('<-- Kicked off by (\S*) \([^\t\n\r\f\v)]*\): ([^\n\r\f\v]*)$')re_nonword = re.compile('[^a-zA-Z0-9]*')re_channame = re.compile('^(\S*).log$')	# Month conversion Dictionaryfmt_month = {	"Jan": 1, "Feb": 2, "Mar": 3, "Apr": 4,				"May": 5, "Jun": 6, "Jul": 7, "Aug": 8,				"Sep": 9, "Oct": 10, "Nov": 11, "Dec": 12	}						### Class Definitions#class Silan(object):	""" Simple IRC Log Analyzer """		def __init__(self):		self.config = SafeConfigParser()				self.config.read("silan.ini")				self.networks = [Network(self.config)]			channellogs = glob.glob("#*.log")		for filename in channellogs:			self.networks[0].channels.append(Channel(re_channame.match(filename).group(1), self.networks[0], filename))					class Line(object):	""" Line of log data with date and time """		def __init__(self, dttm, text):		self.dttm = dttm		self.text = text			def wordcount(self):		return len(self.text.split())class UserLine(Line):	""" Line of log data that includes user instance """		def __init__(self, dttm, user, text):		Line.__init__(self, dttm, text)		self.user = user				class Message(UserLine):	""" Standard IRC message from a user """		def __init__(self, dttm, user, text):		UserLine.__init__(self, dttm, user, text)				class Describe(UserLine):	""" Describe or action from a user """		def __init__(self, dttm, user, text):		UserLine.__init__(self, dttm, user, text)				class Topic(UserLine):	""" Channel topic """							def __init__(self, dttm, user, text):		UserLine.__init__(self, dttm, user, text)class Kick(UserLine):	""" Channel kick """		def __init__(self, dttm, target, user, text):		UserLine.__init__(self, dttm, user, text)				self.target = target		class Log(object):	""" Log recorded by IRC client/proxy """		def __init__(self, filename):		self.filename = filename		self.lines = []				self._read_log()			def _read_log(self):		loghandler = open(self.filename, 'r')		loglist = loghandler.readlines()		loghandler.close()				creationdttm = datetime.datetime.fromtimestamp(os.stat(self.filename).st_ctime)				firstday = int(re_rawlog.match(loglist[0]).group(1))		firstmonth = fmt_month[re_rawlog.match(loglist[0]).group(2)]		firsthour = int(re_rawlog.match(loglist[0]).group(3))		firstminute = int(re_rawlog.match(loglist[0]).group(4))				prevdttm = datetime.datetime(creationdttm.year, firstmonth, firstday, firsthour, firstminute)				for logtext in loglist:			day = int(re_rawlog.match(logtext).group(1))			month = fmt_month[re_rawlog.match(logtext).group(2)]			hour = int(re_rawlog.match(logtext).group(3))			minute = int(re_rawlog.match(logtext).group(4))						text = re_rawlog.match(logtext).group(5)						if month < prevdttm.month or (month == prevdttm.month and day < prevdttm.day):				# The preceding: Does it look like we've gone back in time?				prevdttm = datetime.datetime(prevdttm.year + 1, month, day, hour, minute)			else:				prevdttm = datetime.datetime(prevdttm.year, month, day, hour, minute)			self.lines.append(Line(prevdttm, text))		class Network(Log):	""" IRC network """		def __init__(self, config, name="default", filename="Server.log"):		Log.__init__(self, filename)				self.name = name		self.channels = []		self.users = []		self.ownuser = None		self.config = config				self._config()		self._parse()		def _config(self):		for nick in self.config.options(self.name + ".alternates"):			for alt in self.config.get(self.name + ".alternates", nick).split():				self.add_alternate(nick, alt)					for nick in self.config.options(self.name + ".separates"):			for sep in self.config.get(self.name + ".separates", nick).split():				self.add_separate(nick, sep)						for nick in self.config.options(self.name + ".propercase"):			self.get_user(nick).name = self.config.get(self.name + ".propercase", nick)						def get_channel(self, channame):		for netchannel in self.channels:			if channame.lower() == netchannel.name.lower():				return netchannel				return None			def get_user(self, nickname):		netuser = self.find_user(nickname)				if not netuser:			newuser = User(nickname)			self.users.append(newuser)			return newuser		else:			return netuser			def find_user(self, nickname):		for netuser in self.users:			if nick_belongs_to_user(nickname, netuser):				return netuser		def add_separate(self, nick1, nick2):		netuser1 = self.get_user(nick1)		netuser2 = self.get_user(nick2)				if netuser1 == netuser2:			if netuser1.name.lower() == nick1.lower():				netuser1.alternates.remove(nick2)				newuser = self.get_user(nick2)				newuser.separates.append(nick1)				netuser1.separates.append(nick2)			if netuser2.name.lower() == nick2.lower():				netuser2.alternates.remove(nick1)				newuser = self.get_user(nick1)				newuser.separates.append(nick2)				netuser2.separates.append(nick1)		else:			netuser1.separates.append(nick2)			netuser2.separates.append(nick1)				def add_alternate(self, nick1, nick2):		netuser1 = self.find_user(nick1)		netuser2 = self.find_user(nick2)				if not netuser1 and not netuser2:			newuser = self.get_user(nick1)			newuser.alternates.append(nick2)		elif netuser1 and not netuser2:			if nick2.lower() not in [sep.lower() for sep in netuser1.separates]:				netuser1.alternates.append(nick2)			else:				self.get_user(nick2)		elif netuser2 and not netuser1:			if nick1.lower() not in [sep.lower() for sep in netuser2.separates]:				netuser2.alternates.append(nick1)			else:				self.get_user(nick1)		elif netuser1 and netuser2 and netuser1 != netuser2 and not are_separate(netuser1, netuser2):			if self.users.index(netuser1) < self.users.index(netuser2):				netuser1.alternates.append(netuser2.name)				netuser1.alternates.extend(netuser2.alternates)				self.users.remove(netuser2)				if self.ownuser == netuser2:					self.ownuser = netuser1					else:				netuser2.alternates.append(netuser1.name)				netuser2.alternates.extend(netuser1.alternates)				self.users.remove(netuser1)				if self.ownuser == netuser1:					self.ownuser = netuser2			def _parse(self):		for line in self.lines:			if re_nickchange.match(line.text):				oldnick = re_nickchange.match(line.text).group(1)				newnick = re_nickchange.match(line.text).group(2)				self.add_alternate(oldnick, newnick)						if re_ownnick.match(line.text):				newnick = re_ownnick.match(line.text).group(1)				if not self.ownuser:					self.ownuser = self.get_user(newnick)				else:					self.add_alternate(self.ownuser.name, newnick)		class Channel(Log):	""" IRC channel """		def __init__(self, name, network, filename):		Log.__init__(self, filename)			self.name = name		self.network = network		self.topics = []		self.messages = []		self.describes = []		self.kicks = []				self._parse()	def get_messages_by_hour(self, hour):		return [msg for msg in self.messages if msg.dttm.hour == hour]			def get_messages_by_weekday(self, weekday):		return [msg for msg in self.messages if msg.dttm.weekday == weekday]			def get_messages_by_user(self, nickname):		return [msg for msg in self.messages if nick_belongs_to_user(nickname, msg.user)]			def get_describes_by_user(self, nickname):		return [dsc for dsc in self.describes if nick_belongs_to_user(nickname, dsc.user)]			def get_kicks_by_user(self, nickname):		return [kck for kck in self.kicks if nick_belongs_to_user(nickname, kck.user)]			def get_kicks_by_target(self, nickname):		return [kck for kck in self.kicks if nick_belongs_to_user(nickname, kck.target)]			def _parse(self):		for line in self.lines:			if re_message.match(line.text):				user = self.network.get_user(re_message.match(line.text).group(1))				text = re_message.match(line.text).group(2)				self.messages.append(Message(line.dttm, user, text))						elif re_describe.match(line.text):				user = self.network.get_user(re_describe.match(line.text).group(1))				text = re_describe.match(line.text).group(2)				self.describes.append(Describe(line.dttm, user, text))						elif re_kick.match(line.text):				target = self.network.get_user(re_kick.match(line.text).group(1))				user = self.network.get_user(re_kick.match(line.text).group(2))				text = re_kick.match(line.text).group(3)				self.kicks.append(Kick(line.dttm, target, user, text))						elif re_ownkick.match(line.text):				user = self.network.get_user(re_ownkick.match(line.text).group(1))				text = re_ownkick.match(line.text).group(2)				self.kicks.append(Kick(line.dttm, self.network.ownuser, user, text))						elif re_topic.match(line.text):				user = self.network.get_user(re_topic.match(line.text).group(1))				text = re_topic.match(line.text).group(2)				self.topics.append(Topic(line.dttm, user, text))			class User(object):	""" IRC user """		def __init__(self, name):		self.name = name		self.alternates = []		self.separates = []	### Functions#def are_separate(user1, user2):	for sep in user1.separates:		if nick_belongs_to_user(sep, user2):			return 1	for sep in user2.separates:		if nick_belongs_to_user(sep, user1):			return 1	return 0	def nick_belongs_to_user(nick, user):		return nick.lower() == user.name.lower() or nick.lower() in [alt.lower() for alt in user.alternates]	def main():	appversion = "0.0.2"		print '\n\nSILAN', appversion, '- Simple IRC Log Analyzer - http://slackforge.com/silan/'	print 'Copyright (c) 2007 Shidayu <shidayu@gmail.com>'	try:		appinstance = Silan()				for user in appinstance.networks[0].users:			print user.name, user.alternates				except:		print "An unexpected error has occurred:", sys.exc_info()[0]		raise### Begin Here!#if __name__=="__main__":	main()