270 lines
9.4 KiB
Python
270 lines
9.4 KiB
Python
#!/usr/bin/env python
|
|
"""
|
|
LogBot
|
|
|
|
A minimal IRC log bot
|
|
|
|
Written by Chris Oliver
|
|
|
|
Includes python-irclib from http://python-irclib.sourceforge.net/
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
"""
|
|
|
|
|
|
__author__ = "Chris Oliver <excid3@gmail.com>"
|
|
__version__ = "0.3.0"
|
|
__date__ = "08/11/2009"
|
|
__copyright__ = "Copyright (c) Chris Oliver"
|
|
__license__ = "GPL2"
|
|
|
|
|
|
import os
|
|
import os.path
|
|
import shutil
|
|
|
|
from ConfigParser import ConfigParser
|
|
from ftplib import FTP
|
|
from optparse import OptionParser
|
|
from time import strftime
|
|
|
|
from irclib import nm_to_n
|
|
from ircbot import SingleServerIRCBot
|
|
|
|
|
|
html_header = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<title>%s</title>
|
|
<link href="stylesheet.css" rel="stylesheet" type="text/css" />
|
|
</head>
|
|
<body>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
index_header = """<h1>%s</h1><br />"""
|
|
|
|
|
|
class LogBot(SingleServerIRCBot):
|
|
def __init__(self, server, port, channels, owners, nickname, password):
|
|
"""Initialize this badboy"""
|
|
SingleServerIRCBot.__init__(self, [(server, port, password)],
|
|
nickname,
|
|
nickname)
|
|
self.chans = channels
|
|
|
|
def set_format(self, folder, format, stylesheet):
|
|
self.folder = folder
|
|
self.format = format
|
|
self.stylesheet = stylesheet
|
|
|
|
def on_nicknameinuse(self, c, e):
|
|
"""Append an underscore to the nick if it's already in use"""
|
|
c.nick(c.get_nickname() + "_")
|
|
|
|
def on_welcome(self, c, e):
|
|
"""Join the channels once we have made a successful connection"""
|
|
for channel in self.chans:
|
|
c.join(channel)
|
|
|
|
def on_pubmsg(self, c, e):
|
|
user = nm_to_n(e.source())
|
|
message = e.arguments()[0]
|
|
channel = e.target()
|
|
self.write(channel, self.format["pubmsg"].replace("%user%", user) \
|
|
.replace("%message%", message))
|
|
|
|
def on_invite(self, c, e):
|
|
pass
|
|
|
|
def on_join(self, c, e):
|
|
user = nm_to_n(e.source())
|
|
host = e.source()
|
|
channel = e.target()
|
|
self.write(channel, self.format["join"].replace("%user%", user) \
|
|
.replace("%host%", host) \
|
|
.replace("%channel%", channel))
|
|
|
|
def on_kick(self, c, e):
|
|
kicker = e.source()
|
|
channel = e.target()
|
|
user, reason = e.arguments()
|
|
self.write(channel, self.format["kick"].replace("%kicker%", kicker) \
|
|
.replace("%channel%", channel) \
|
|
.replace("%user%", user) \
|
|
.replace("%reason%", reason))
|
|
|
|
def on_mode(self, c, e):
|
|
modes, person = e.arguments()[:2]
|
|
channel = e.target()
|
|
giver = nm_to_n(e.source())
|
|
self.write(channel, self.format["mode"].replace("%channel%", channel) \
|
|
.replace("%modes%", modes) \
|
|
.replace("%person%", person) \
|
|
.replace("%giver%", giver))
|
|
|
|
def on_part(self, c, e):
|
|
user = nm_to_n(e.source())
|
|
channel = e.target()
|
|
self.write(channel, self.format["part"].replace("%user%", user) \
|
|
.replace("%channel%", channel))
|
|
|
|
def on_privmsg(self, c, e):
|
|
pass
|
|
|
|
def on_topic(self, c, e):
|
|
user = nm_to_n(e.source())
|
|
channel = e.target()
|
|
topic = e.arguments()[0]
|
|
self.write(channel, self.format["topic"].replace("%user%", user) \
|
|
.replace("%channel%", channel) \
|
|
.replace("%topic%", topic))
|
|
|
|
def on_nick(self, c, e):
|
|
new = nm_to_n(e.source())
|
|
old = e.target()
|
|
self.write(None, self.format["nick"].replace("%old%", old) \
|
|
.replace("%new%", new))
|
|
|
|
def on_pubnotice(self, c, e):
|
|
user = nm_to_n(e.source())
|
|
channel = e.target()
|
|
message = e.arguments()[0]
|
|
self.write(channel, self.format["pubnotice"].replace("%user%", user) \
|
|
.replace("%channel%", channel) \
|
|
.replace("%message%", message))
|
|
|
|
def on_quit(self, c, e):
|
|
user = nm_to_n(e.source())
|
|
reason = e.arguments()[0]
|
|
channel = e.target()
|
|
self.write(channel, self.format["quit"].replace("%user%", user) \
|
|
.replace("%reason%", reason))
|
|
|
|
def write(self, channel, message):
|
|
time = strftime("%H:%M:%S")
|
|
date = strftime("%d-%m-%Y")
|
|
if channel:
|
|
print "%s> %s %s" % (channel, time, message)
|
|
channels = [channel]
|
|
else:
|
|
# Quit/nick don't have channels
|
|
print "%s %s" % (time, message)
|
|
channels = self.chans
|
|
|
|
index = os.path.join(self.folder, "index.html")
|
|
if not os.path.exists(self.folder):
|
|
# Create the log folder if we need to
|
|
os.mkdir(self.folder)
|
|
|
|
if not os.path.exists(index):
|
|
create_html_file(index, "Logged Channels")
|
|
append_to_index(index, index_header % "Logged Channels")
|
|
shutil.copy2(self.stylesheet, self.folder)
|
|
|
|
for channel in channels:
|
|
path = os.path.abspath(os.path.join(self.folder, channel))
|
|
|
|
if not os.path.exists(path):
|
|
os.mkdir(path)
|
|
|
|
if not os.path.exists(os.path.join(path, "stylesheet.css")):
|
|
shutil.copy2(self.stylesheet, path)
|
|
|
|
chan_index = os.path.join(path, "index.html")
|
|
path = os.path.join(path, date+".html")
|
|
if not os.path.exists(path):
|
|
create_html_file(chan_index, "%s | Logs" % channel)
|
|
append_to_index(chan_index, index_header % "%s | Logs" % channel)
|
|
|
|
append_to_index(index, "<a href=\"%%23%s\">%s</a>" % \
|
|
(channel[1:]+"/index.html", channel))
|
|
|
|
create_html_file(path, "%s | Logs for %s" % (channel, date))
|
|
append_to_index(chan_index, "<a href=\"%s\">%s</a>" % \
|
|
(date+".html", date))
|
|
|
|
str = "<a href=\"#%s\" name=\"%s\" class=\"time\">[%s]</a> %s" % \
|
|
(time, time, time, message)
|
|
append_to_index(path, str, True)
|
|
|
|
|
|
def create_html_file(path, title):
|
|
f = open(path, "wb")
|
|
f.write(html_header % title)
|
|
f.close()
|
|
|
|
|
|
def append_to_index(path, line, br=False, back=-2):
|
|
data = open(path, "rb").readlines()[:back]
|
|
if br: data += [line + "<br />\n"]
|
|
else: data += [line + "\n"]
|
|
data += [" </body>\n", "</html>\n"]
|
|
|
|
f = open(path, "wb")
|
|
f.writelines(data)
|
|
f.close()
|
|
|
|
|
|
def main(conf):
|
|
"""
|
|
Start the bot using a config file.
|
|
|
|
:Parameters:
|
|
- `conf`: config file location
|
|
"""
|
|
CONFIG = ConfigParser()
|
|
CONFIG.read(conf)
|
|
|
|
# Get the irc network configuration
|
|
server = CONFIG.get("irc", "server")
|
|
port = CONFIG.getint("irc", "port")
|
|
channels = CONFIG.get("irc", "channels").split(",")
|
|
nick = CONFIG.get("irc", "nick")
|
|
try:
|
|
password = CONFIG.get("irc", "password")
|
|
except:
|
|
password = None
|
|
owner = CONFIG.get("irc", "owners").split(",")
|
|
|
|
# Get the log section
|
|
folder = CONFIG.get("log", "folder")
|
|
stylesheet = CONFIG.get("log", "stylesheet")
|
|
|
|
# Get the formation information
|
|
types = ["join", "kick", "mode", "nick", "part", "pubmsg", "pubnotice",
|
|
"quit", "topic"]
|
|
format = {}
|
|
for type in types:
|
|
format[type] = CONFIG.get("format", type)
|
|
|
|
bot = LogBot(server, port, channels, owner, nick, password)
|
|
bot.set_format(folder, format, stylesheet)
|
|
bot.start()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Require a config
|
|
parser = OptionParser()
|
|
parser.add_option("-c", "--config", dest="conf", help="Config to use")
|
|
(options, args) = parser.parse_args()
|
|
|
|
if not options.conf or not os.access(options.conf, os.R_OK):
|
|
parser.print_help()
|
|
raise SystemExit(1)
|
|
main(options.conf)
|