207 lines
5.5 KiB
Python
207 lines
5.5 KiB
Python
|
|
import supybot.callbacks as callbacks
|
|
import supybot.conf as conf
|
|
import supybot.utils as utils
|
|
import supybot.ircmsgs as ircmsgs
|
|
import supybot.world as world
|
|
import supybot.irclib as irclib
|
|
from supybot.commands import *
|
|
|
|
import time
|
|
|
|
from .storage import LogDB, MessageType
|
|
|
|
filename = conf.supybot.directories.log.dirize("Log.sqlite")
|
|
|
|
class Logger(callbacks.Plugin):
|
|
"""
|
|
An SQLite3 channel logger
|
|
"""
|
|
|
|
noIgnore = True
|
|
threaded = True
|
|
|
|
lastMsgs = {}
|
|
lastStates = {}
|
|
|
|
def __init__(self, irc):
|
|
self.__parent = super(Logger, self)
|
|
self.__parent.__init__(irc)
|
|
self.db = LogDB(filename)
|
|
world.flushers.append(self.flush)
|
|
|
|
def _seen(self, irc, msg, channel, nick, findAny):
|
|
if nick == irc.nick:
|
|
irc.reply("Of course I've seen myself!")
|
|
return
|
|
bufid = self.db.getBuffer(irc.network, channel)["id"]
|
|
if findAny:
|
|
entry = self.db.getLast(bufid, nick)
|
|
else:
|
|
entry = self.db.getLastMessage(bufid, nick)
|
|
if not entry:
|
|
irc.reply("I haven't seen %s in %s." % (nick, channel))
|
|
return
|
|
t = time.time()
|
|
rpl = "I saw %s in %s %s ago " % (
|
|
nick,
|
|
channel,
|
|
utils.timeElapsed(t - entry["timestamp"])
|
|
)
|
|
tp = entry["type"]
|
|
if tp == MessageType.privmsg or\
|
|
tp == MessageType.notice:
|
|
rpl += "saying \"%s\"" % (entry["message"],)
|
|
elif tp == MessageType.action:
|
|
rpl += "saying * %s %s" % (entry["nick"], entry["message"])
|
|
elif tp == MessageType.join:
|
|
rpl += "joining."
|
|
elif tp == MessageType.part:
|
|
rpl += "parting (%s)." % (entry["message"],)
|
|
elif tp == MessageType.quit:
|
|
rpl += "quiting"
|
|
if entry["message"] != "":
|
|
rpl += " (%s)" % (entry["message"],)
|
|
rpl += "."
|
|
elif tp == MessageType.kick:
|
|
kicked, space, reason = entry["message"].partition(" ")
|
|
rpl += "kicking %s (%s)." % (kicked, reason)
|
|
elif tp == MessageType.nick:
|
|
rpl += "changing nick to %s." % (entry["message"],)
|
|
elif tp == MessageType.mode:
|
|
rpl += "setting mode(s) %s." % (entry["message"],)
|
|
elif tp == MessageType.topic:
|
|
rpl += "setting the topic to \"%s\"" % (entry["message"],)
|
|
else:
|
|
rpl += "doing who knows what."
|
|
irc.reply(rpl)
|
|
|
|
def seen(self, irc, msg, args, channel, nick):
|
|
"""[channel] <nick>
|
|
|
|
Finds the last time a nick was seen speaking and what they said.
|
|
"""
|
|
self._seen(irc, msg, channel, nick, False)
|
|
seen = wrap(seen, ["channel", "nick"])
|
|
|
|
def seenany(self, irc, msg, args, channel, nick):
|
|
"""[channel] <nick>
|
|
|
|
Finds the last time a nick was seen and what they were doing.
|
|
"""
|
|
self._seen(irc, msg, channel, nick, True)
|
|
seenany = wrap(seenany, ["channel", "nick"])
|
|
|
|
def __call__(self, irc, msg):
|
|
try:
|
|
self.__parent.__call__(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:
|
|
self.lastMsgs[irc] = msg
|
|
|
|
def reset(self):
|
|
self.lastMsgs.clear()
|
|
self.lastStates.clear()
|
|
|
|
def die(self):
|
|
self.__parent.die()
|
|
world.flushers.remove(self.flush)
|
|
del self.db
|
|
|
|
def flush(self):
|
|
self.db.commit()
|
|
|
|
def shouldLog(self, irc, msg, msgtype):
|
|
if not self.registryValue("enable"):
|
|
return False
|
|
if msgtype == MessageType.privmsg or msgtype == MessageType.notice:
|
|
if not irc.isChannel(msg.args[0]):
|
|
return False
|
|
if ircmsgs.isCtcp(msg) and not ircmsgs.isAction(msg):
|
|
return False
|
|
if msgtype == MessageType.mode and msg.args[0] == irc.nick:
|
|
return False
|
|
return True
|
|
|
|
def _add(self, irc, msg, msgtype):
|
|
if not self.shouldLog(irc, msg, msgtype):
|
|
return
|
|
|
|
channel = msg.args[0]
|
|
if not self.registryValue("enable", channel):
|
|
return
|
|
|
|
text = None
|
|
if len(msg.args) > 1:
|
|
text = msg.args[1]
|
|
|
|
if msgtype == MessageType.mode:
|
|
text = " ".join(msg.args[1:])
|
|
elif msgtype == MessageType.kick:
|
|
# Add reason to text
|
|
text += " " + msg.args[2]
|
|
elif ircmsgs.isAction(msg):
|
|
msgtype = MessageType.action
|
|
text = msg.args[1][8:-1]
|
|
|
|
self.db.add(msgtype, irc.network, channel, msg, text)
|
|
self.db.commit()
|
|
|
|
def doPrivmsg(self, irc, msg): self._add(irc, msg, MessageType.privmsg)
|
|
def doNotice (self, irc, msg): self._add(irc, msg, MessageType.notice)
|
|
def doJoin (self, irc, msg): self._add(irc, msg, MessageType.join)
|
|
def doPart (self, irc, msg): self._add(irc, msg, MessageType.part)
|
|
def doKick (self, irc, msg): self._add(irc, msg, MessageType.kick)
|
|
def doMode (self, irc, msg): self._add(irc, msg, MessageType.mode)
|
|
def doTopic (self, irc, msg): self._add(irc, msg, MessageType.topic)
|
|
|
|
def doNick(self, irc, msg):
|
|
if not self.shouldLog(irc, msg, MessageType.nick):
|
|
return
|
|
oldNick = msg.nick
|
|
newNick = msg.args[0]
|
|
for (channel, chan) in irc.state.channels.items():
|
|
if newNick in chan.users:
|
|
if not self.registryValue("enable", channel):
|
|
continue
|
|
self.db.add(MessageType.nick,
|
|
irc.network,
|
|
channel,
|
|
msg,
|
|
newNick)
|
|
self.db.commit()
|
|
|
|
def doQuit(self, irc, msg):
|
|
if not self.shouldLog(irc, msg, MessageType.quit):
|
|
return
|
|
reason = None
|
|
if len(msg.args) == 1:
|
|
reason = msg.args[0]
|
|
if not isinstance(irc, irclib.Irc):
|
|
irc = irc.getRealIrc()
|
|
if not irc in self.lastStates:
|
|
return
|
|
for (channel, chan) in self.lastStates[irc].channels.items():
|
|
if not self.registryValue("enable", channel) or\
|
|
msg.nick not in chan.users:
|
|
continue
|
|
self.db.add(MessageType.quit,
|
|
irc.network,
|
|
channel,
|
|
msg,
|
|
reason)
|
|
self.db.commit()
|
|
|
|
def outFilter(self, irc, msg):
|
|
# Log our own messages
|
|
if msg.command in ('PRIVMSG', 'NOTICE'):
|
|
# Other messages should be sent back to us.
|
|
self(irc, ircmsgs.IrcMsg(msg=msg, prefix=irc.prefix))
|
|
return msg
|
|
|
|
Class = Logger
|
|
|