示例#1
0
 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)
示例#2
0
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