def connectionMade(self): self.logger = MessageLogger(open(self.factory.filename, "a")) self.logger.log("[connected at %s]" % asctime(localtime(time()))) self.options = self.factory.options self.svn = self.factory.svn self.nickname = self.options.nick self.realname = self.options.name self.authQ = [] self.loggedIn = [] self.topics = {} self.redos = {} self.undos = {} self.userWatch = {} self.undo = False self.lastSearchStart = -1 self.lastSearchQuery = None self.init() irc.IRCClient.connectionMade(self)
class TehBot(irc.IRCClient): """A IRC bot.""" def connectionMade(self): self.logger = MessageLogger(open(self.factory.filename, "a")) self.logger.log("[connected at %s]" % asctime(localtime(time()))) self.options = self.factory.options self.svn = self.factory.svn self.nickname = self.options.nick self.realname = self.options.name self.authQ = [] self.loggedIn = [] self.topics = {} self.redos = {} self.undos = {} self.userWatch = {} self.undo = False self.lastSearchStart = -1 self.lastSearchQuery = None self.init() irc.IRCClient.connectionMade(self) def connectionLost(self, reason): irc.IRCClient.connectionLost(self, reason) self.logger.log("[disconnected at %s]" % asctime(localtime(time()))) self.logger.close() def init(self): # set vars that may change during execution self.versionName = self.options.options['CLIENTNAME'] self.versionNum = self.options.options['VERSION'] self.versionEnv = sys.platform self.options.options['REVISION'] = self.svn.lastRev() self.readWatchDataFromFile() # SVN announce code if self.options.announce: # if svn announce commits mode # create/start timer self.timer = TimerService(self.options.frequency, self.svnAnnounce) self.timer.startService() else: if hasattr(self, 'timer') and self.timer.running: # if running self.timer.stopService() # stop it def svnAnnounce(self): rev = self.svn.lastRev() if rev == -1: print 'ERROR: Error connecting to SVN repo' return if rev != self.options.options['REVISION']: # check against stored revision # new commit, yay :) temp = int(self.options.options['REVISION']) temp += 1 self.options.options['REVISION'] = str(temp) for target in self.options.announce_targets: # tell everybody about it self.cmd_lastlog(target, target, []) def writeWatchDataToFile(self): """Outputs watch data to permanent storage (disk)""" if not checkDir('watchdata'): mkdir('watchdata') current = getcwd() chdir('watchdata') for user in self.userWatch: f = open(user + '.watch', 'w') for message in self.userWatch[user]: f.write('%s<*!*>%s' % (message, self.userWatch[user][message])) f.close() chdir(current) def readWatchDataFromFile(self): """Outputs watch data to permanent storage (disk)""" if not checkDir('watchdata'): mkdir('watchdata') current = getcwd() chdir('watchdata') for user in self.options.watchUsers: if not self.userWatch.has_key(user): self.userWatch[user] = {} try: f = open(user + '.watch', 'r') for line in f: message, count = line.split('<*!*>') self.userWatch[user][message.strip()] = int(count) f.close() except IOError: continue chdir(current) # callbacks for events def signedOn(self): """Called when bot has succesfully signed on to server.""" if self.options.registeredNick: self.msg('nickserv','identify ' + self.options.nickPassword) for chan in self.options.chanstojoin: self.join(chan) def joined(self, channel): """This will get called when the bot joins the channel.""" self.options.channels.append(channel.lower()) for user in self.options.authUsers: if user.lower() not in self.loggedIn: print ' *** Attempting login for %s on %s' % (user, channel) self.cmd_login(user, channel, []) def userJoined(self, user, channel): """Called when a user joins a channel Im on""" user = user.split('!', 1)[0] if user != self.nickname: print 'JOIN: %s on %s' % (user, channel) self.logger.log('JOIN: %s on %s' % (user, channel)) if self.options.welcome: if user.lower() in self.options.authUsers: self.msg(channel, 'Welcome to %s, the all powerful %s, thank you for blessing us with your presence' % (channel, user)) else: self.msg(channel, 'Welcome to %s, %s' % (channel, user)) if user in self.options.authUsers: print ' *** Attempting login for %s on %s' % (user, channel) self.cmd_login(user, channel, []) def kickedFrom(self, channel, kicker, message): """Called when Im kicked from a channel""" if self.options.rejoin: self.join(channel) self.msg(channel, '%s: thanks for that (%s)' % (kicker, message)) def action(self, user, channel, data): """Called when another user performs an action""" user = user.split('!', 1)[0] msg = data.strip() self.logger.log('(%s): *%s %s ' % (channel, user, msg)) def cmd_login(self, user, channel, params): """Gains usage access to bot. Usage: LOGIN""" #XXX: this is non-RFC standard message (307), so may not # work on other servers, besides Shadowfire if user.lower() in self.options.authUsers: self.authQ.append(user) self.sendLine("WHOIS %s" % user) else: self.msg(user, 'ERROR: You Are Not Authorised!') def cmd_logout(self, user, channel, params): """Removes usage access to bot. Usage: LOGOUT""" if user.lower() in self.loggedIn: self.loggedIn.remove(user.lower()) else: self.msg(user, 'ERROR: Not Logged In') def irc_307(self, prefix, params): """Reply from WHOIS message, indicates a registered nick""" if len(params) == 3: user = params[1].lower() msg = params[2] if user in self.authQ: self.authQ.remove(user) if user not in self.loggedIn: if msg == 'is a registered nick': self.loggedIn.append(user) if self.options.announceLogins: self.msg(user, 'You are now Logged In!') def privmsg(self, user, channel, msg): """This will get called when the bot receives a message.""" user = user.split('!', 1)[0] message = msg.strip() checkUser = user.lower() self.logger.log('%s (%s): %s' % (user, channel, msg)) if channel in self.options.channels: # if from channel,then only process if proceeded by nick: or !nick: # if nick, then respond to user from which msg originated # if !nick, then respond to channel if message.startswith(self.nickname + ':'): message = message[len(self.nickname)+1:].strip() elif message.startswith('!' + self.nickname + ':'): message = message[len(self.nickname)+2:].strip() user = channel elif message.startswith(self.options.channelChar): message = message[len(self.options.channelChar):].strip() user = channel else: return elif self.nickname != channel: return params = message.split() command = params.pop(0) # empty command like "::", just ignore if not command: return # is the message from an authorised user? or open command? if checkUser in self.loggedIn or command.lower() in self.options.openCommands: print 'DEBUG: Remote Command %s from %s with parameters: %s' % (command, user, params) self.logger.log('Remote Command: %s from %s with parameters: %s' % (command, user, params)) # special cases if command.lower() == 'login': self.cmd_login(checkUser, channel, params) elif command.lower() == 'logout': self.cmd_logout(checkUser, channel, params) elif command.lower() in _admin_commands and checkUser not in self.options.authors: self.msg(user, 'ERROR: Administrator only command: %s' % command) elif command.lower() in self.options.disabledCommands and checkUser not in self.options.authors: self.msg(user, 'ERROR: Disabled command: %s' % command) else: # despatch command try: handler = getattr(self, 'cmd_' + command.lower()) except AttributeError: self.msg(user, 'Unrecognised command: %s' % command) else: # call the handler here in case it throws an AttributeError handler(user, channel, params) # User commands def cmd_quit(self, user, channel, params): """Quits IRC. Usage: QUIT <quit message>""" self.factory.quit = True self.quit(' '.join(params)) def cmd_op(self, user, channel, params): """Gives Channel operator status to a user. Usage: OP [channel] <user | me>""" if len(params) > 1: # they've specified a channel channel = params.pop(0) target = params[0] if (target.lower() == 'me'): target = user self.mode(channel, 1, 'o', user=target) def cmd_deop(self, user, channel, params): """Removes Channel operator status from a user. Usage: DEOP [channel] <user | me>""" if len(params) > 1: # they've specified a channel channel = params.pop(0) target = params[0] if (target.lower() == 'me'): target = user self.mode(channel, 0, 'o', user=target) def cmd_topic(self, user, channel, params): """ Updates the current channel's topic. Usage: TOPIC [channel] [command] <topic> Commands: add - add to current topic. Usage: TOPIC [channel] add <text> del - remove from topic, based on position (starting at 0). Usage: TOPIC [channel] del <index> edit - replaces topic in specified position with new text. Usage: TOPIC [channel] edit <index> <text> set - sets the topic. Usage: TOPIC [channel] set <text> get - gets the current topic. Usage: TOPIC [channel] get undo - undo the last topic change. Usage: TOPIC [channel] undo redo - redo the last topic undo. Usage: TOPIC [channel] redo replace - replaces one word (using regexp) with a phrase throughout the whole topic. Usage: TOPIC [channel] replace <to replace - regexp> <phrase> """ if len(params) > 1: if params[0] in self.options.channels: channel = params.pop(0) command = params.pop(0).lower() if not self.topics.has_key(channel): self.topics[channel] = [] current = self.topics[channel] if command == 'add': temp = current + [' '.join(params)] # current.append(' '.join(params)) topic = ' | '.join(temp) elif command == 'del': index = int(params.pop(0)) topic = current[:index] index += 1 if index > 0: topic.extend(current[index:]) topic = ' | '.join(topic) elif command == 'edit': index = int(params.pop(0)) current[index] = ' '.join(params) topic = ' | '.join(current) elif command == 'replace': #what = params.pop(0) what = re.compile(params.pop(0)) with = ' '.join(params) topic = ' | '.join(current) #topic = topic.replace(what, with) topic = what.sub(with, topic) elif command == 'get': self.msg(user, 'topic for %s is: %s' % (channel, ' | '.join(current))) return