Fixed up the bot a ton, rewrote it from scratch

This commit is contained in:
Chris Oliver 2010-02-13 17:37:58 -06:00
parent df6c918e40
commit 0ab04a77e7
4 changed files with 180 additions and 1739 deletions

View file

@ -1,11 +1,26 @@
[irc] [irc]
network = irc.freenode.net server = irc.freenode.net
port = 6667 port = 6667
channels = #keryx channels = #keryx
nick = Timber nick = Timber
password =
# This your nick identification password
password = testing
# Comma separated list of owner nicks
owners = excid3 owners = excid3
[log] [log]
# Location to store the logs
folder = logs folder = logs
stylesheet = file:///C:\Users\Chris Oliver\Desktop\logbot\conf\stylesheet.css # Location of the stylesheet
stylesheet = conf/stylesheet.css
[format]
join = -!- <span class="join">%user%</span> [%host%] has joined %channel%
kick = -!- <span class="kick">%user%</span> was kicked from %channel% by %kicker% [%reason%]
mode = -!- mode/<span class="mode">%channel%</span> [%modes% %person%] by %giver%
part = -!- <span class="part">%user%</span> has parted %channel%
pubmsg = <span class="person">&lt;%user%&gt;</span> %message%
pubnotice = <span class="notice">-%user%:%channel%-</span> %message%
quit = -!- <span class="quit">%user%</span> has quit [%reason%]

View file

@ -4,12 +4,18 @@ body {
font-size: 13px; font-size: 13px;
} }
.time { h1 {
font-family: sans-serif;
font-size: 24px;
text-align: center;
}
a, .time {
color: #525552; color: #525552;
text-decoration: none; text-decoration: none;
} }
.time:hover { text-decoration: underline; } a:hover, .time:hover { text-decoration: underline; }
.person { color: #DD1144; } .person { color: #DD1144; }

1560
irclib.py

File diff suppressed because it is too large Load diff

290
logbot.py
View file

@ -25,7 +25,7 @@
__author__ = "Chris Oliver <excid3@gmail.com>" __author__ = "Chris Oliver <excid3@gmail.com>"
__version__ = "0.2.1" __version__ = "0.3.0"
__date__ = "08/11/2009" __date__ = "08/11/2009"
__copyright__ = "Copyright (c) Chris Oliver" __copyright__ = "Copyright (c) Chris Oliver"
__license__ = "GPL2" __license__ = "GPL2"
@ -33,13 +33,16 @@ __license__ = "GPL2"
import os import os
import os.path import os.path
import irclib import shutil
from ConfigParser import ConfigParser from ConfigParser import ConfigParser
from ftplib import FTP from ftplib import FTP
from optparse import OptionParser from optparse import OptionParser
from time import strftime 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" html_header = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
@ -47,160 +50,98 @@ html_header = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>%s</title> <title>%s</title>
<link href="%s" rel="stylesheet" type="text/css" /> <link href="stylesheet.css" rel="stylesheet" type="text/css" />
</head> </head>
<body> <body>
</body> </body>
</html> </html>
""" """
index_header = """<h1>%s</h1><br />"""
class LogBot(object):
def __init__(self, network, port, channels, owner, nick, password, folder, stylesheet): class LogBot(SingleServerIRCBot):
self.network = network def __init__(self, server, port, channels, owners, nickname, password):
self.port = port """Initialize this badboy"""
self.channels = channels SingleServerIRCBot.__init__(self, [(server, port, password)],
self.owner = owner nickname,
self.nick = nick nickname)
self.password = password self.chans = channels
def set_format(self, folder, format, stylesheet):
self.folder = folder self.folder = folder
self.format = format
self.stylesheet = stylesheet self.stylesheet = stylesheet
def start(self): def on_nicknameinuse(self, c, e):
# Write logs locally, so we need the folder to exist """Append an underscore to the nick if it's already in use"""
if not os.path.exists(self.folder): c.nick(c.get_nickname() + "_")
os.mkdir(self.folder)
#os.chdir(self.folder)
# Create an IRC object def on_welcome(self, c, e):
self.irc = irclib.IRC() """Join the channels once we have made a successful connection"""
for channel in self.chans:
c.join(channel)
# Setup the IRC functionality we want to log def on_pubmsg(self, c, e):
handlers = {'join': self.handleJoin, user = nm_to_n(e.source())
'pubmsg': self.handlePubMessage, message = e.arguments()[0]
'privmsg': self.handlePrivMessage, channel = e.target()
'part': self.handlePart, self.write(channel, self.format["pubmsg"].replace("%user%", user) \
'invite': self.handleInvite, .replace("%message%", message))
'kick': self.handleKick,
'mode': self.handleMode,
'pubnotice': self.handlePubNotice,
'quit': self.handleQuit}
for key, val in handlers.items():
self.irc.add_global_handler(key, val)
# Create a server object, connect and join the channel def on_invite(self, c, e):
self.server = self.irc.server() pass
self.server.connect(self.network, self.port, self.nick, ircname=self.nick)
if self.password: def on_join(self, c, e):
self.server.privmsg("nickserv", "identify %s" % self.password) 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))
for channel in self.channels: def on_kick(self, c, e):
self.server.join(channel) 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))
# Jump into an infinte loop def on_mode(self, c, e):
self.irc.process_forever() modes, person = e.arguments()
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))
#eventtype -- A string describing the event. def on_part(self, c, e):
#source -- The originator of the event (a nick mask or a server). user = nm_to_n(e.source())
#target -- The target of the event (a nick or a channel). channel = e.target()
#arguments self.write(channel, self.format["part"].replace("%user%", user) \
.replace("%channel%", channel))
def handleKick(self, connection, event): def on_privmsg(self, c, e):
"""Handles kick messages pass
Writes messages to log
"""
# kicker, channel, [person, reason]
# event.source(), event.target(), event.arguments()
person, reason = event.arguments()
self.write(event.target(),
"-!- <span class=\"kick\">%s</span> was kicked from %s by %s [%s]" % \
(person, event.target(), event.source().split("!")[0], reason))
def handleMode(self, connection, event): def on_pubnotice(self, c, e):
"""Handles mode changes user = nm_to_n(e.source())
Writes messages to log channel = e.target()
""" message = e.arguments()[0]
# person giving ops, #channel, [modes, person] self.write(channel, self.format["pubnotice"].replace("%user%", user) \
#print event.source(), event.target(), event.arguments() .replace("%channel%", channel) \
modes, person = event.arguments() .replace("%message%", message))
self.write(event.target(),
"-!- mode/<span class=\"mode\">%s</span> [%s %s] by %s" % \
(event.target(), modes, person, event.source().split("!")[0]))
def handlePubNotice(self, connection, event): def on_quit(self, c, e):
"""Handles public notices user = nm_to_n(e.source())
Writes messages to log reason = e.arguments()[0]
""" channel = e.target()
# user, channel, [msg] print channel
#print event.source(), event.target(), event.arguments() self.write(channel, self.format["quit"].replace("%user%", user) \
self.write(event.target(), .replace("%reason%", reason))
"<span class=\"notice\">-%s:%s-</span> %s" % \
(event.source().split("!")[0], event.target(), event.arguments()[0]))
def handleQuit(self, connection, event):
"""Handles quite messages
Writes messages to log
"""
# user, channel?, [reason]
#print event.source(), event.target(), event.arguments()
self.write(None,
"-!- <span class=\"quit\">%s</span> has quit [%s]" % \
(event.source().split("!")[0], event.arguments()[0]))
def handlePrivMessage(self, connection, event):
"""Handles private messages
Used for owners to send instructions to bot
"""
# sender, receiver (me), [msg]
print "PRIVATE MESSGAE", event.source(), event.target(), event.arguments()
def handleJoin(self, connection, event):
"""Handles user join messages
Writes messages to log
"""
nick = event.source().split("!")
try:
nickmask = nick[1]
except:
nickmask = "unknown"
nick = nick[0]
self.write(event.target(),
"-!- <span class=\"join\">%s</span> (%s) has joined %s" % \
(nick, nickmask, event.target()))
def handlePubMessage(self, connection, event):
"""Handles public messages
Writes messages to log
"""
nick = event.source().split("!")[0]
self.write(event.target(),
"<span class=\"person\">&lt;%s&gt;</span> %s" % \
(nick, event.arguments()[0]))
def handlePart(self, connection, event):
"""Handles part messages
Writes messages to log
"""
nick = event.source().split("!")[0]
self.write(event.target(),
"-!- <span class=\"part\">%s</span> has parted %s" % \
(nick, event.target()))
def handleInvite(self, connection, event):
"""Handles invitations from IRC users
Only accept invites to join a channel if they are from an owner
"""
nick = event.source().split("!")[0]
# Only allow invites from owner(s)
if not nick in self.owner:
print "Invite from %s denied" % nick
return
for channel in event.arguments():
self.server.join(channel)
def write(self, channel, message): def write(self, channel, message):
time = strftime("%H:%M:%S") time = strftime("%H:%M:%S")
@ -211,27 +152,58 @@ class LogBot(object):
else: else:
# Quits don't have channels # Quits don't have channels
print "%s %s" % (time, message) print "%s %s" % (time, message)
channels = self.channels channels = self.chans
if not os.path.exists(self.folder):
# Create the log folder if we need to
os.mkdir(self.folder)
index = os.path.join(self.folder, "index.html")
create_html_file(index, "Logged Channels")
append_to_index(index, index_header % "Logged Channels")
shutil.copy2(self.stylesheet, self.folder)
for channel in channels: for channel in channels:
path = os.path.abspath(os.path.join(self.folder, channel)) path = os.path.abspath(os.path.join(self.folder, channel))
if not os.path.exists(path): if not os.path.exists(path):
# Create the folder if it doesn't exist
os.mkdir(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") path = os.path.join(path, date+".html")
if not os.path.exists(path): if not os.path.exists(path):
# Create the html header 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)
def create_html_file(path, title):
f = open(path, "wb") f = open(path, "wb")
f.write(html_header % (("%s | Logs for %s" % (channel, date)), self.stylesheet)) f.write(html_header % title)
f.close() f.close()
def append_to_index(path, line):
data = open(path, "rb").readlines()[:-2] data = open(path, "rb").readlines()[:-2]
data.append("<a href=\"#%s\" name=\"%s\" class=\"time\">[%s]</a> %s<br />\n" % (time, time, time, message)) data.append(line + "<br />\n")
data += [" </body>\n", "</html>\n"] data += [" </body>\n", "</html>\n"]
f = open(path, "wb") f = open(path, "wb")
f.writelines(data) f.writelines(data)
f.close()
def main(conf): def main(conf):
""" """
@ -242,29 +214,37 @@ def main(conf):
""" """
CONFIG = ConfigParser() CONFIG = ConfigParser()
CONFIG.read(conf) CONFIG.read(conf)
network = CONFIG.get('irc', 'network')
port = CONFIG.getint('irc', 'port') # Get the irc network configuration
channels = CONFIG.get('irc', 'channels').split(',') server = CONFIG.get("irc", "server")
nick = CONFIG.get('irc', 'nick') port = CONFIG.getint("irc", "port")
channels = CONFIG.get("irc", "channels").split(",")
nick = CONFIG.get("irc", "nick")
try: try:
password = CONFIG.get('irc', 'password') password = CONFIG.get("irc", "password")
except: except:
password = None password = None
owner = CONFIG.get('irc', 'owners').split(',') owner = CONFIG.get("irc", "owners").split(",")
logs_folder = CONFIG.get('log', 'folder')
stylesheet = CONFIG.get('log', 'stylesheet')
bot = LogBot(network, port, channels, owner, nick, password, logs_folder, stylesheet) # Get the log section
try: folder = CONFIG.get("log", "folder")
stylesheet = CONFIG.get("log", "stylesheet")
# Get the formation information
types = ["join", "kick", "mode", "part", "pubmsg", "pubnotice", "quit"]
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() bot.start()
except KeyboardInterrupt:
pass
if __name__ == '__main__': if __name__ == "__main__":
# Require a config # Require a config
parser = OptionParser() parser = OptionParser()
parser.add_option('-c', '--config', dest='conf', help='Config to use') parser.add_option("-c", "--config", dest="conf", help="Config to use")
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
if not options.conf or not os.access(options.conf, os.R_OK): if not options.conf or not os.access(options.conf, os.R_OK):