commit 05c5ccc89ddce3760b7ae87a99e2fc44f716e3a6 Author: Adam Roe Date: Wed Jul 19 17:42:10 2023 +1000 Initial commit diff --git a/mssql.py b/mssql.py new file mode 100644 index 0000000..6a6ccd0 --- /dev/null +++ b/mssql.py @@ -0,0 +1,241 @@ +#!/usr/bin/env python3 + +import znc +import pymssql +import re +from datetime import datetime +from contextlib import closing + +class mssql(znc.Module): + module_types = [znc.CModInfo.GlobalModule] + description = "Log all channels to a Microsoft SQL Server +database" + has_args = False + + sql_server = "db.spd.internal" + sql_user = "_srv_znc" + sql_password = "zncznc" + sql_database = "znc" + +# def OnLoad(self, args, message): +# self.PutModule("Loading MSSQL...") +# return True + + def OnOp(self, user, target_user, channel, noChange): + self.insert("OP", channel.GetName(), user.GetHost(), +user.GetNick(), user.GetIdent(), None, datetime.now(), +target_user.GetNick(), None, str(self.GetNetwork())) + return True + + def OnPrivNotice(self, user, message): + self.insert("NOTICE", None, user.GetHost(), +user.GetNick(), user.GetIdent(), None, datetime.now(), None, message.s, +str(self.GetNetwork())) + return True + + def OnDeop(self, user, target_user, channel, noChange): + self.insert("DEOP", channel.GetName(), user.GetHost(), +user.GetNick(), user.GetIdent(), None, datetime.now(), +target_user.GetNick(), None, str(self.GetNetwork())) + return True + + def OnVoice(self, user, target_user, channel, noChange): + self.insert("VOICE", channel.GetName(), user.GetHost(), +user.GetNick(), user.GetIdent(), None, datetime.now(), +target_user.GetNick(), None, str(self.GetNetwork())) + return True + + def OnDevoice(self, user, target_user, channel, noChange): + self.insert("DEVOICE", channel.GetName(), user.GetHost(), +user.GetNick(), user.GetIdent(), None, datetime.now(), +target_user.GetNick(), None, str(self.GetNetwork())) + return True + + def OnMode(self, user, channel, mode, argument, added, noChange): + mode = chr(mode) + code = "MODE" + if mode == "b": + code = "BAN" if added else "UNBAN" + else: + sign = "+" if added else "-" + argument = "{0}{1} {2}".format(sign, mode, +argument) + + self.insert(code, channel.GetName(), user.GetHost(), +user.GetNick(), user.GetIdent(), None, datetime.now(), None, argument, +str(self.GetNetwork())) + return True + + def OnQuit(self, user, message, channels): + for channel in channels: + self.insert("QUIT", channel.GetName(), +user.GetHost(), user.GetNick(), user.GetIdent(), None, datetime.now(), +None, message, str(self.GetNetwork())) + return True + + def OnNick(self, user, new_nick, channels): + for channel in channels: + self.insert("NICK", channel.GetName(), +user.GetHost(), user.GetNick(), user.GetIdent(), None, datetime.now(), +new_nick, None, str(self.GetNetwork())) + return True + + def OnKick(self, user, target_nick, channel, message): + self.insert("KICK", channel.GetName(), user.GetHost(), +user.GetNick(), user.GetIdent(), None, datetime.now(), target_nick, +message, str(self.GetNetwork())) + return True + + def OnJoin(self, user, channel): + self.insert("JOIN", channel.GetName(), user.GetHost(), +user.GetNick(), user.GetIdent(), None, datetime.now(), None, None, +str(self.GetNetwork())) + return True + + def OnPart(self, user, channel, message): + self.insert("PART", channel.GetName(), user.GetHost(), +user.GetNick(), user.GetIdent(), None, datetime.now(), None, message, +str(self.GetNetwork())) + return True + + def OnUserAction (self, target, message): + (channel, user) = self.resolveTarget(target) + if channel == None: + return True + return self.OnChanAction(user, channel, message) + + def OnPrivMsg(self, nick, message): + self.insert("MSG", "", nick.GetHost(), nick.GetNick(), +nick.GetIdent(), None, datetime.now(), None, message.s, +str(self.GetNetwork())) + return True + + def OnUserMsg (self, target, message): + (channel, user) = self.resolveTarget(target) + if channel == None: + return True + return self.OnChanMsg(user, channel, message) + + def OnChanAction(self, user, channel, message): + self.insert("ME", channel.GetName(), user.GetHost(), +user.GetNick(), user.GetIdent(), None, datetime.now(), None, message.s, +str(self.GetNetwork())) + return True + + def OnChanMsg(self, user, channel, message): + self.insert("SAY", channel.GetName(), user.GetHost(), +user.GetNick(), user.GetIdent(), self.findMode(channel, user), +datetime.now(), None, message.s, str(self.GetNetwork())) + return True + + def OnTopic(self, user, channel, message): + self.insert("TOPIC", channel.GetName(), user.GetHost(), +user.GetNick(), user.GetIdent(), None, datetime.now(), None, message.s, +str(self.GetNetwork())) + return True + +# def OnLoad(self, args, message): +# match = re.search("(.*?):(.*?)@(.*)", args) +# if match: +# self.username = match.group(1) +# self.password = match.group(2) +# self.host = match.group(3) +# return True +# else: +# return False + + def findMode(self, channel, user): + realUser = channel.FindNick(user.GetNick()) + if not realUser: + return None + return str(realUser.GetPermChar()) + + def resolveTarget(self, target): + target = target.s + channel = self.GetNetwork().FindChan(target) + if channel == None: + return (None, None) + user = self.GetNetwork().GetIRCNick() + return (channel, user) + + def colourstrip(self, data): + find = data.find('\x03') + while find > -1: + done = False + data = data[0:find] + data[find+1:] + if len(data) <= find+1: + done = True + try: + assert not done + assert int(data[find]) + while True: + assert int(data[find]) + data = data[0:find] + +data[find+1:] + except: + if not done: + if data[find] != ',': done = True + + if (not done) and (len(data) > find+1) and +(data[find] == ','): + try: + assert not done + assert int(data[find+1]) + data = data[0:find] + +data[find+1:] + data = data[0:find] + +data[find+1:] + except: + done = True + try: + assert not done + while True: + assert int(data[find]) + data = data[0:find] + +data[find+1:] + except: pass + + find = data.find('\x03') + data = data.replace('\x02','') + data = data.replace('\x1d','') + data = data.replace('\x1f','') + data = data.replace('\x16','') + data = data.replace('\x0f','') + return data + + def insert(self, code, channel, host, user, ident, user_mode, +date, target_user, message, network): +# self.PutModule("Inserting row...") + regex = +re.compile("\x1f|\x02|\x03(?:\d{1,2}(?:,\d{1,2})?)?", re.UNICODE) + + try: + with closing(pymssql.connect ("db.spd.internal", +"_srv_znc", "znc", "znc")) as conn: + with closing(conn.cursor()) as cursor: +# sql = "INSERT INTO log (date, +code, network, channel, host, [user], ident, mode, target, message) +VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)" + sql = "EXEC dbo.add_log (?, ?, ?, +?, ?, ?, ?, ?, ?, ?, ?)" + if message is not None: +# message = +message.encode('utf-8').decode('utf-8', 'replace') + message = regex.sub("", +message) + message = +self.colourstrip(message) + znc_user = +self.GetUser().GetUserName() if self.GetUser() is not None else None + params = (znc_user, str(date), +code, network, channel, host, user, ident, user_mode, target_user, +message) +# cursor.execute (sql, params) + cursor.callproc("add_log", params) + conn.commit() + conn.close() + + except Exception as e: + self.PutModule("Could not save {0} to database +caused by: {1} - {2}".format(code, type(e), str(e))) +