241 lines
8.1 KiB
Python
241 lines
8.1 KiB
Python
|
from twisted.internet.protocol import ReconnectingClientFactory
|
||
|
from twisted.words.protocols.irc import IRCClient
|
||
|
from twisted.internet.defer import Deferred
|
||
|
|
||
|
import modules.keyword as keyword
|
||
|
import modules.userinfo as userinfo
|
||
|
|
||
|
from core.main import *
|
||
|
from utils.logging.log import *
|
||
|
from utils.logging.send import *
|
||
|
|
||
|
class IRCBot(IRCClient):
|
||
|
def __init__(self, name):
|
||
|
self.connected = False
|
||
|
self.channels = []
|
||
|
|
||
|
self.name = name
|
||
|
instance = pool[name]
|
||
|
|
||
|
self.nickname = instance["nickname"]
|
||
|
self.realname = instance["realname"]
|
||
|
self.username = instance["username"]
|
||
|
self.userinfo = instance["userinfo"]
|
||
|
self.fingerReply = instance["finger"]
|
||
|
self.versionName = instance["version"]
|
||
|
self.versionNum = None
|
||
|
self.versionEnv = None
|
||
|
self.sourceURL = instance["source"]
|
||
|
self.autojoin = instance["autojoin"]
|
||
|
|
||
|
self._who = {}
|
||
|
self._getWho = {}
|
||
|
|
||
|
self.authtype = instance["authtype"]
|
||
|
if self.authtype == "ns":
|
||
|
self.authpass = instance["password"]
|
||
|
self.authentity = instance["authentity"]
|
||
|
else:
|
||
|
self.password = instance["password"]
|
||
|
|
||
|
def refresh(self):
|
||
|
instance = pool[self.name]
|
||
|
if not instance["nickname"] == self.nickname:
|
||
|
self.nickname = instance["nickname"]
|
||
|
self.setNick(self.nickname)
|
||
|
|
||
|
self.userinfo = instance["userinfo"]
|
||
|
self.fingerReply = instance["finger"]
|
||
|
self.versionName = instance["version"]
|
||
|
self.versionNum = None
|
||
|
self.versionEnv = None
|
||
|
self.sourceURL = instance["source"]
|
||
|
|
||
|
def parsen(self, user):
|
||
|
step = user.split("!")
|
||
|
nick = step[0]
|
||
|
if len(step) == 2:
|
||
|
step2 = step[1].split("@")
|
||
|
ident, host = step2
|
||
|
else:
|
||
|
ident = nick
|
||
|
host = nick
|
||
|
|
||
|
return [nick, ident, host]
|
||
|
|
||
|
def privmsg(self, user, channel, msg):
|
||
|
nick, ident, host = self.parsen(user)
|
||
|
userinfo.setWhoSingle(self.name, nick, ident, host)
|
||
|
|
||
|
keyword.actKeyword(user, channel, msg, self.nickname, "PRV", self.name)
|
||
|
|
||
|
def noticed(self, user, channel, msg):
|
||
|
nick, ident, host = self.parsen(user)
|
||
|
userinfo.setWhoSingle(self.name, nick, ident, host)
|
||
|
|
||
|
keyword.actKeyword(user, channel, msg, self.nickname, "NOT", self.name)
|
||
|
|
||
|
def action(self, user, channel, msg):
|
||
|
nick, ident, host = self.parsen(user)
|
||
|
userinfo.setWhoSingle(self.name, nick, ident, host)
|
||
|
|
||
|
keyword.actKeyword(user, channel, msg, self.nickname, "ACT", self.name)
|
||
|
|
||
|
def get(self, var):
|
||
|
try:
|
||
|
result = getattr(self, var)
|
||
|
except AttributeError:
|
||
|
result = None
|
||
|
return result
|
||
|
|
||
|
def setNick(self, nickname):
|
||
|
self._attemptedNick = nickname
|
||
|
self.sendLine("NICK %s" % nickname)
|
||
|
self.nickname = nickname
|
||
|
|
||
|
def alterCollidedNick(self, nickname):
|
||
|
newnick = nickname + "_"
|
||
|
return newnick
|
||
|
|
||
|
def irc_ERR_NICKNAMEINUSE(self, prefix, params):
|
||
|
self._attemptedNick = self.alterCollidedNick(self._attemptedNick)
|
||
|
self.setNick(self._attemptedNick)
|
||
|
|
||
|
def irc_ERR_PASSWDMISMATCH(self, prefix, params):
|
||
|
log("%s: password mismatch" % self.name)
|
||
|
sendAll("%s: password mismatch" % self.name)
|
||
|
|
||
|
def who(self, channel):
|
||
|
channel = channel
|
||
|
d = Deferred()
|
||
|
if channel not in self._who:
|
||
|
self._who[channel] = ([], {})
|
||
|
self._who[channel][0].append(d)
|
||
|
self.sendLine("WHO %s" % channel)
|
||
|
return d
|
||
|
|
||
|
def irc_RPL_WHOREPLY(self, prefix, params):
|
||
|
channel = params[1]
|
||
|
user = params[2]
|
||
|
host = params[3]
|
||
|
server = params[4]
|
||
|
nick = params[5]
|
||
|
status = params[6]
|
||
|
realname = params[7]
|
||
|
if channel not in self._who:
|
||
|
return
|
||
|
n = self._who[channel][1]
|
||
|
n[nick] = [nick, user, host, server, status, realname]
|
||
|
|
||
|
def irc_RPL_ENDOFWHO(self, prefix, params):
|
||
|
channel = params[1]
|
||
|
if channel not in self._who:
|
||
|
return
|
||
|
callbacks, info = self._who[channel]
|
||
|
for cb in callbacks:
|
||
|
cb.callback((channel, info))
|
||
|
del self._who[channel]
|
||
|
|
||
|
def got_who(self, whoinfo):
|
||
|
userinfo.setWho(self.name, whoinfo[1])
|
||
|
|
||
|
def signedOn(self):
|
||
|
self.connected = True
|
||
|
log("signed on: %s" % self.name)
|
||
|
if config["ConnectionNotifications"]:
|
||
|
keyword.sendMaster("SIGNON: %s" % self.name)
|
||
|
if self.authtype == "ns":
|
||
|
self.msg(self.authentity, "IDENTIFY %s" % self.nspass)
|
||
|
for i in self.autojoin:
|
||
|
self.join(i)
|
||
|
|
||
|
def joined(self, channel):
|
||
|
if not channel in self.channels:
|
||
|
self.channels.append(channel)
|
||
|
self.who(channel).addCallback(self.got_who)
|
||
|
|
||
|
def left(self, channel):
|
||
|
if channel in self.channels:
|
||
|
self.channels.remove(channel)
|
||
|
|
||
|
def kickedFrom(self, channel, kicker, message):
|
||
|
if channel in self.channels:
|
||
|
self.channels.remove(channel)
|
||
|
keyword.sendMaster("KICK %s: (%s/%s) %s" % (self.name, kicker, channel, message))
|
||
|
|
||
|
def userJoined(self, user, channel):
|
||
|
nick, ident, host = self.parsen(user)
|
||
|
userinfo.setWhoSingle(self.name, nick, ident, host)
|
||
|
|
||
|
def userLeft(self, user, channel):
|
||
|
nick, ident, host = self.parsen(user)
|
||
|
userinfo.setWhoSingle(self.name, nick, ident, host)
|
||
|
|
||
|
def userQuit(self, user, quitMessage):
|
||
|
nick, ident, host = self.parsen(user)
|
||
|
userinfo.setWhoSingle(self.name, nick, ident, host)
|
||
|
|
||
|
keyword.actKeyword(user, None, quitMessage, self.nickname, "QUT", self.name)
|
||
|
|
||
|
def userKicked(self, kickee, channel, kicker, message):
|
||
|
nick, ident, host = self.parsen(kicker)
|
||
|
userinfo.setWhoSingle(self.name, nick, ident, host)
|
||
|
|
||
|
keyword.actKeyword(kicker, channel, message, self.nickname, "KCK", self.name)
|
||
|
|
||
|
def userRenamed(self, oldname, newname):
|
||
|
nick, ident, host = self.parsen(oldname)
|
||
|
userinfo.setWhoSingle(self.name, nick, ident, host)
|
||
|
userinfo.setWhoSingle(self.name, newname, ident, host)
|
||
|
|
||
|
def topicUpdated(self, user, channel, newTopic):
|
||
|
nick, ident, host = self.parsen(user)
|
||
|
userinfo.setWhoSingle(self.name, nick, ident, host)
|
||
|
|
||
|
keyword.actKeyword(user, channel, newTopic, self.nickname, "TOP", self.name)
|
||
|
|
||
|
def modeChanged(self, user, channel, toset, modes, args):
|
||
|
nick, ident, host = self.parsen(user)
|
||
|
userinfo.setWhoSingle(self.name, nick, ident, host)
|
||
|
|
||
|
class IRCBotFactory(ReconnectingClientFactory):
|
||
|
def __init__(self, name):
|
||
|
self.instance = pool[name]
|
||
|
self.name = name
|
||
|
self.client = None
|
||
|
self.maxDelay = self.instance["maxdelay"]
|
||
|
self.initialDelay = self.instance["initialdelay"]
|
||
|
self.factor = self.instance["factor"]
|
||
|
self.jitter = self.instance["jitter"]
|
||
|
|
||
|
def buildProtocol(self, addr):
|
||
|
entry = IRCBot(self.name)
|
||
|
IRCPool[self.name] = entry
|
||
|
self.client = entry
|
||
|
return entry
|
||
|
|
||
|
def clientConnectionLost(self, connector, reason):
|
||
|
if not self.client == None:
|
||
|
self.client.connected = False
|
||
|
self.client.channels = []
|
||
|
error = reason.getErrorMessage()
|
||
|
log("%s: connection lost: %s" % (self.name, error))
|
||
|
sendAll("%s: connection lost: %s" % (self.name, error))
|
||
|
if config["ConnectionNotifications"]:
|
||
|
keyword.sendMaster("CONNLOST %s: %s" % (self.name, error))
|
||
|
self.retry(connector)
|
||
|
#ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
|
||
|
|
||
|
def clientConnectionFailed(self, connector, reason):
|
||
|
if not self.client == None:
|
||
|
self.client.connected = False
|
||
|
self.client.channels = []
|
||
|
error = reason.getErrorMessage()
|
||
|
log("%s: connection failed: %s" % (self.name, error))
|
||
|
sendAll("%s: connection failed: %s" % (self.name, error))
|
||
|
if config["ConnectionNotifications"]:
|
||
|
keyword.sendMaster("CONNFAIL %s: %s" % (self.name, error))
|
||
|
self.retry(connector)
|
||
|
#ReconnectingClientFactory.clientConnectionFailed(self, connector, reason)
|
||
|
|