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)