Beispiel #1
0
    def __init__(self):
        # mode and state handler
        from pycon_bot.modes.base import SkeletonMode
        self.mode = SkeletonMode(self)
        self.state_handler = None

        # variables storing superuser information
        self.potential_superusers = settings.IRC_SUPERUSERS
        self.superusers = set()
        self._namescallback = {}

        # the timer running, if any
        self.timer = None
Beispiel #2
0
 def __init__(self):
     # mode and state handler
     from pycon_bot.modes.base import SkeletonMode
     self.mode = SkeletonMode(self)
     self.state_handler = None
     
     # variables storing superuser information
     self.potential_superusers = settings.IRC_SUPERUSERS
     self.superusers = set()
     self._namescallback = {}
     
     # the timer running, if any
     self.timer = None
Beispiel #3
0
class PyConBot(irc.IRCClient):
    def __init__(self):
        # mode and state handler
        from pycon_bot.modes.base import SkeletonMode
        self.mode = SkeletonMode(self)
        self.state_handler = None

        # variables storing superuser information
        self.potential_superusers = settings.IRC_SUPERUSERS
        self.superusers = set()
        self._namescallback = {}

        # the timer running, if any
        self.timer = None

    #
    # "Public" API - stuff to be called by drivers.
    #

    @property
    def nickname(self):
        return self.factory.nickname

    def set_timer(self,
                  channel,
                  seconds,
                  message='Time has ended.',
                  callback=None,
                  callback_kwargs={}):
        """Set a timer. By default, simply say `message` after
        `seconds` have elapsed.

        Additionally, if a callback is provided, run it.
        """
        seconds = int(seconds)

        def say_time(channel):
            self.timer = None
            if message:
                self.msg(channel, "=== %s ===" % message)
            if callback and callable(callback):
                callback(**callback_kwargs)

        self.clear_timer()
        self.timer = reactor.callLater(seconds, say_time, channel)

    def clear_timer(self):
        """Clear an already-set timer, and return it."""

        # get the timer so I can get data out of it, in case
        # I need to re-instutite the timer
        if self.timer:
            self.timer.cancel()
            self.timer = None

    def names(self, channel):
        """List names in the channel.

        Returns a deferred. Because THIS IS TWISTED!
        """
        channel = channel.lower()
        d = defer.Deferred()
        self._namescallback.setdefault(channel, [[], []])[0].append(d)
        self.sendLine("NAMES %s" % channel)
        return d

    #
    # Internals
    #

    # Auth.

    def check_auth(self):
        """
        Check that everyone in set as a superuser in the env is actually
        logged in (and not spoofing) by asking NickServ. This resets the
        superuser list each time it's called.

        NickServ will respond by sending a NOTICE (*not* a PRIVMSG), which
        gets picked up by the callback below, see that.
        """
        for username in self.potential_superusers:
            self.msg('NickServ', 'ACC %s' % username)

    def noticed(self, user, channel, message):
        # Only pay attention to ACC responses from NickServ
        user = user.split('!')[0]
        if channel != self.nickname or user != 'NickServ':
            return
        try:
            username, acc, status = message.split()[0:3]
        except ValueError:
            return
        if acc != 'ACC':
            return

        # Now add or remove superusers depending on the response. A code of "3"
        # means the user's identiied with services, so if they're in the
        # allowed SUs and NickServ gives us a "3", then that user is auth'd.
        if username in self.potential_superusers and status == '3':
            self.superusers.add(username)
        elif username in self.superusers and status != '3':
            self.superusers.discard(username)

    # Support functions for the NAMES command.

    def irc_RPL_NAMREPLY(self, prefix, params):
        channel = params[2].lower()
        if channel not in self._namescallback:
            return
        nicklist = [name.strip('@+') for name in params[3].split(' ')]
        self._namescallback[channel][1] += nicklist

    def irc_RPL_ENDOFNAMES(self, prefix, params):
        channel = params[1].lower()
        if channel not in self._namescallback:
            return
        callbacks, namelist = self._namescallback[channel]
        for cb in callbacks:
            cb.callback(namelist)
        del self._namescallback[channel]

    # Twisted callbacks and such.

    def signedOn(self):
        for channel in self.factory.channels:
            self.join(channel)

    def joined(self, channel):
        log.msg('Joined %s' % channel)
        self.msg(channel, 'Hello, denizens of %s!' % channel)
        self.msg(
            channel, ' '.join((
                'To contribute to me:',
                'https://github.com/PyCon/pc-bot',
            )))
        self.check_auth()

    def userJoined(self, user, channel):
        """When a new user joins the channel, take appropriate action,
        and also ask the node what, if anything, it wants to do."""

        # is this a potential superuser? if so, we
        # need to refresh the superuser list
        if user in self.potential_superusers:
            self.check_auth()

        # now ship us off to the mode
        if hasattr(self.mode, 'event_user_joined'):
            self.mode.event_user_joined(user, channel)

    def privmsg(self, user, channel, message):
        """Called whenever a message is recived.
        
        If this is a private message, dispatch it to the private messaging
        command bank.

        If the message starts with ",<cmd>", then dispatch to a `handle_<cmd>`
        function, either on self or on the bot mode object, but only if the
        user is a superuser.
        """

        user = user.split("!")[0]

        # if this is a private message, then it uses the
        # private messaging commands rather than the chair commands
        if not channel.startswith('#'):
            command_parts = message.split()
            command, args = command_parts[0], command_parts[1:]
            self.mode.exec_command(command, 'private', user, channel, *args)
            return

        # Modes can define a log_message function which'll be called for each
        # message, command or not. This lets modes do logging.
        if hasattr(self.mode, 'log_message'):
            self.mode.log_message(user, channel, message)

        # Some times - voting - we want to record every command. In those cases,
        # the botmode will set state_handler and we'll call that. Othwewise,
        # we only care about ,-prefixed commands.
        if not message.startswith(','):
            if self.state_handler:
                user_message = message.lower().strip()
                if not user_message:
                    return
                self.state_handler(user, channel, user_message)
            return

        # only accept commands from superusers
        if user not in self.superusers:
            return

        # find the appropriate callback on the mode
        # (or one of its superclasses)
        message = message[1:]
        command_parts = message.split()
        command, command_args = command_parts[0], command_parts[1:]
        self.mode.exec_command(command, 'chair', user, channel, *command_args)

    def msg(self, channel, message):
        # Make sure things I say go into the transcript, too.
        if channel.startswith('#') and hasattr(self.mode, 'log_message'):
            self.mode.log_message(self.nickname, channel, message)
        irc.IRCClient.msg(self, channel, message)  # scumbag old-style class
Beispiel #4
0
class PyConBot(irc.IRCClient):
    def __init__(self):
        # mode and state handler
        from pycon_bot.modes.base import SkeletonMode
        self.mode = SkeletonMode(self)
        self.state_handler = None
        
        # variables storing superuser information
        self.potential_superusers = settings.IRC_SUPERUSERS
        self.superusers = set()
        self._namescallback = {}
        
        # the timer running, if any
        self.timer = None
        
    #
    # "Public" API - stuff to be called by drivers.
    #

    @property
    def nickname(self):
        return self.factory.nickname

    def set_timer(self, channel, seconds, message='Time has ended.',
                        callback=None, callback_kwargs={}):
        """Set a timer. By default, simply say `message` after
        `seconds` have elapsed.

        Additionally, if a callback is provided, run it.
        """
        seconds = int(seconds)
        
        def say_time(channel):
            self.timer = None
            if message:
                self.msg(channel, "=== %s ===" % message)
            if callback and callable(callback):
                callback(**callback_kwargs)
        
        self.clear_timer()
        self.timer = reactor.callLater(seconds, say_time, channel)
        
    def clear_timer(self):
        """Clear an already-set timer, and return it."""
        
        # get the timer so I can get data out of it, in case
        # I need to re-instutite the timer       
        if self.timer:
            self.timer.cancel()
            self.timer = None        
                    
    def names(self, channel):
        """List names in the channel.

        Returns a deferred. Because THIS IS TWISTED!
        """
        channel = channel.lower()
        d = defer.Deferred()
        self._namescallback.setdefault(channel, [[], []])[0].append(d)
        self.sendLine("NAMES %s" % channel)
        return d


    #
    # Internals
    #

    # Auth.

    def check_auth(self):
        """
        Check that everyone in set as a superuser in the env is actually
        logged in (and not spoofing) by asking NickServ. This resets the
        superuser list each time it's called.

        NickServ will respond by sending a NOTICE (*not* a PRIVMSG), which
        gets picked up by the callback below, see that.
        """
        for username in self.potential_superusers:
            self.msg('NickServ', 'ACC %s' % username)

    def noticed(self, user, channel, message):
        # Only pay attention to ACC responses from NickServ
        user = user.split('!')[0]
        if channel != self.nickname or user != 'NickServ':
            return
        try:
            username, acc, status = message.split()[0:3]
        except ValueError:
            return
        if acc != 'ACC':
            return

        # Now add or remove superusers depending on the response. A code of "3"
        # means the user's identiied with services, so if they're in the
        # allowed SUs and NickServ gives us a "3", then that user is auth'd.
        if username in self.potential_superusers and status == '3':
            self.superusers.add(username)
        elif username in self.superusers and status != '3':
            self.superusers.discard(username)

    # Support functions for the NAMES command.

    def irc_RPL_NAMREPLY(self, prefix, params):
        channel = params[2].lower()
        if channel not in self._namescallback:
            return
        nicklist = [name.strip('@+') for name in params[3].split(' ')]
        self._namescallback[channel][1] += nicklist

    def irc_RPL_ENDOFNAMES(self, prefix, params):
        channel = params[1].lower()
        if channel not in self._namescallback:
            return
        callbacks, namelist = self._namescallback[channel]
        for cb in callbacks:
            cb.callback(namelist)
        del self._namescallback[channel]

    # Twisted callbacks and such.

    def signedOn(self):
        for channel in self.factory.channels:
            self.join(channel)

    def joined(self, channel):
        log.msg('Joined %s' % channel)
        self.msg(channel, 'Hello, denizens of %s!' % channel)
        self.msg(channel, ' '.join((
            'To contribute to me:',
            'https://github.com/PyCon/pc-bot',
        )))
        self.check_auth()
        
    def userJoined(self, user, channel):
        """When a new user joins the channel, take appropriate action,
        and also ask the node what, if anything, it wants to do."""
        
        # is this a potential superuser? if so, we
        # need to refresh the superuser list
        if user in self.potential_superusers:
            self.check_auth()
        
        # now ship us off to the mode
        if hasattr(self.mode, 'event_user_joined'):
            self.mode.event_user_joined(user, channel)

    def privmsg(self, user, channel, message):
        """Called whenever a message is recived.
        
        If this is a private message, dispatch it to the private messaging
        command bank.

        If the message starts with ",<cmd>", then dispatch to a `handle_<cmd>`
        function, either on self or on the bot mode object, but only if the
        user is a superuser.
        """

        user = user.split("!")[0]

        # if this is a private message, then it uses the
        # private messaging commands rather than the chair commands
        if not channel.startswith('#'):
            command_parts = message.split()
            command, args = command_parts[0], command_parts[1:]
            self.mode.exec_command(command, 'private', user, channel, *args)
            return
        
        # Modes can define a log_message function which'll be called for each
        # message, command or not. This lets modes do logging.
        if hasattr(self.mode, 'log_message'):
            self.mode.log_message(user, channel, message)

        # Some times - voting - we want to record every command. In those cases,
        # the botmode will set state_handler and we'll call that. Othwewise,
        # we only care about ,-prefixed commands.
        if not message.startswith(','):
            if self.state_handler:
                user_message = message.lower().strip()
                if not user_message:
                    return
                self.state_handler(user, channel, user_message)
            return

        # only accept commands from superusers
        if user not in self.superusers:
            return

        # find the appropriate callback on the mode
        # (or one of its superclasses)
        message = message[1:]
        command_parts = message.split()
        command, command_args = command_parts[0], command_parts[1:]
        self.mode.exec_command(command, 'chair', user, channel, *command_args)

    def msg(self, channel, message):
        # Make sure things I say go into the transcript, too.
        if channel.startswith('#') and hasattr(self.mode, 'log_message'):
            self.mode.log_message(self.nickname, channel, message)
        irc.IRCClient.msg(self, channel, message)  # scumbag old-style class