Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/plugin.py
diff options
context:
space:
mode:
Diffstat (limited to 'plugin.py')
-rw-r--r--plugin.py211
1 files changed, 211 insertions, 0 deletions
diff --git a/plugin.py b/plugin.py
new file mode 100644
index 0000000..219a9b3
--- /dev/null
+++ b/plugin.py
@@ -0,0 +1,211 @@
+###
+# Copyright (c) 2002-2004, Jeremiah Fincher
+# Copyright (c) 2009-2010, James Vega
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions, and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions, and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of the author of this software nor the name of
+# contributors to this software may be used to endorse or promote products
+# derived from this software without specific prior written consent.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+###
+
+import re
+import time
+from os.path import join, dirname, exists
+from ConfigParser import ConfigParser
+
+import MySQLdb
+
+import supybot.conf as conf
+import supybot.world as world
+import supybot.irclib as irclib
+import supybot.ircmsgs as ircmsgs
+import supybot.ircutils as ircutils
+import supybot.registry as registry
+import supybot.callbacks as callbacks
+
+
+class MyLogger(callbacks.Plugin):
+
+ noIgnore = True
+
+ def __init__(self, irc):
+ callbacks.Plugin.__init__(self, irc)
+
+ self.lastMsgs = {}
+ self.lastStates = {}
+ self._conn = None
+ self._meetings = {}
+
+ confile = join(dirname(world.registryFilename), 'mylogger.conf')
+ if not exists(confile):
+ self.log.warning('Config %s for MyLogger was not found', confile)
+ return
+ self._config = ConfigParser()
+ self._config.read(confile)
+
+ def die(self):
+ if self._conn is not None:
+ self._conn.close()
+ self._conn = None
+
+ def __call__(self, irc, msg):
+ try:
+ callbacks.Plugin.__call__(self, irc, msg)
+ if irc in self.lastMsgs:
+ if irc not in self.lastStates:
+ self.lastStates[irc] = irc.state.copy()
+ self.lastStates[irc].addMsg(irc, self.lastMsgs[irc])
+ finally:
+ # We must make sure this always gets updated.
+ self.lastMsgs[irc] = msg
+
+ def doLog(self, irc, channel, nick, message):
+ if nick == irc.nick and message.startswith('Meeting started'):
+ match = re.match('Meeting started ([^.]+) [^ ]+\.', message)
+ if match:
+ timestamp = time.strptime(match.groups()[0])
+ self._meetings[channel] = time.strftime('%F %T', timestamp)
+ else:
+ self.log.warning('Cannot parse start meeting time ' \
+ 'from: %s', message)
+
+ if not self.registryValue('enable', channel) and \
+ channel not in self._meetings:
+ return
+
+ def db_insert():
+ cursor = self._conn.cursor()
+ cursor.execute('INSERT INTO irclog ' \
+ '(channel, day, nick, timestamp, line, meeting) ' \
+ 'VALUES (%s, %s, %s, %s, %s, %s)',
+ (ircutils.toLower(channel), time.strftime('%F'), nick,
+ int(time.time()), message,
+ self._meetings.get(channel)))
+ cursor.close()
+
+ try:
+ try:
+ db_insert()
+ except (AttributeError, MySQLdb.Error):
+ self._conn = MySQLdb.connect(
+ host=self._config.get('db', 'host'),
+ user=self._config.get('db', 'user'),
+ passwd=self._config.get('db', 'passwd'),
+ db=self._config.get('db', 'db'))
+ db_insert()
+ except MySQLdb.Error, error:
+ self.log.warning('Cannot store log message: %s', error)
+ finally:
+ if nick == irc.nick and message.startswith('Log:'):
+ if channel in self._meetings:
+ del self._meetings[channel]
+ else:
+ self.log.warning('Meeting start was not tracked ' \
+ 'for channel %s', channel)
+
+ def doPrivmsg(self, irc, msg):
+ (recipients, text) = msg.args
+ for channel in recipients.split(','):
+ if not irc.isChannel(channel):
+ continue
+ noLogPrefix = self.registryValue('noLogPrefix', channel)
+ if noLogPrefix and text.startswith(noLogPrefix):
+ continue
+ nick = msg.nick or irc.nick
+ if ircmsgs.isAction(msg):
+ self.doLog(irc, channel, nick, ircmsgs.unAction(msg))
+ else:
+ self.doLog(irc, channel, nick, text)
+
+ def doNotice(self, irc, msg):
+ (recipients, text) = msg.args
+ for channel in recipients.split(','):
+ if not irc.isChannel(channel):
+ continue
+ self.doLog(irc, channel, msg.nick, text)
+
+ def doNick(self, irc, msg):
+ oldNick = msg.nick
+ newNick = msg.args[0]
+ for (channel, c) in irc.state.channels.iteritems():
+ if newNick in c.users:
+ self.doLog(irc, channel, '',
+ '%s is now known as %s' % (oldNick, newNick))
+
+ def doJoin(self, irc, msg):
+ for channel in msg.args[0].split(','):
+ self.doLog(irc, channel, '', '%s <%s> has joined %s' % \
+ (msg.nick, msg.prefix, channel))
+
+ def doKick(self, irc, msg):
+ if len(msg.args) == 3:
+ (channel, target, kickmsg) = msg.args
+ else:
+ (channel, target) = msg.args
+ kickmsg = ''
+ if kickmsg:
+ self.doLog(irc, channel, '', '%s was kicked by %s (%s)' % \
+ (target, msg.nick, kickmsg))
+ else:
+ self.doLog(irc, channel, '', '%s was kicked by %s' % \
+ (target, msg.nick))
+
+ def doPart(self, irc, msg):
+ for channel in msg.args[0].split(','):
+ self.doLog(irc, channel, '', '%s has left %s' % \
+ (msg.nick or msg.prefix, channel))
+
+ def doMode(self, irc, msg):
+ channel = msg.args[0]
+ if irc.isChannel(channel) and msg.args[1:]:
+ self.doLog(irc, channel, '', '%s sets mode: %s %s' % \
+ (msg.nick or msg.prefix, msg.args[1],
+ ' '.join(msg.args[2:])))
+
+ def doTopic(self, irc, msg):
+ if len(msg.args) == 1:
+ return # It's an empty TOPIC just to get the current topic.
+ channel = msg.args[0]
+ self.doLog(irc, channel, '', '%s changes topic to "%s"' % \
+ (msg.nick, msg.args[1]))
+
+ def doQuit(self, irc, msg):
+ if not isinstance(irc, irclib.Irc):
+ irc = irc.getRealIrc()
+ for (channel, chan) in self.lastStates[irc].channels.iteritems():
+ if msg.nick in chan.users:
+ self.doLog(irc, channel, '', '%s has quit IRC' % \
+ msg.nick or msg.prefix)
+
+ def outFilter(self, irc, msg):
+ # Gotta catch my own messages *somehow* :)
+ # Let's try this little trick...
+ if msg.command in ('PRIVMSG', 'NOTICE'):
+ # Other messages should be sent back to us.
+ m = ircmsgs.IrcMsg(msg=msg, prefix=irc.prefix)
+ self(irc, m)
+ return msg
+
+
+Class = MyLogger
+# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: