Exemple #1
0
 def testExnToString(self):
     try:
         raise KeyError(1)
     except Exception as e:
         self.assertEqual(utils.exnToString(e), 'KeyError: 1')
     try:
         raise EOFError()
     except Exception as e:
         self.assertEqual(utils.exnToString(e), 'EOFError')
Exemple #2
0
 def testExnToString(self):
     try:
         raise KeyError(1)
     except Exception as e:
         self.assertEqual(utils.exnToString(e), 'KeyError: 1')
     try:
         raise EOFError()
     except Exception as e:
         self.assertEqual(utils.exnToString(e), 'EOFError')
Exemple #3
0
 def connectError(self, server, e):
     if isinstance(e, Exception):
         if isinstance(e, socket.gaierror):
             e = e.args[1]
         else:
             e = utils.exnToString(e)
     self.warning('Error connecting to %s: %s', server, e)
Exemple #4
0
    def sing(self, irc, msg, args, input):
        """
        Usage: sing artist [: title] [: * | line | pattern] --
        Example: @sing bon jovi : wanted dead or alive --
        Searches http://lyricsmania.com
        """

        args = map(lambda x: x.strip(), re.split(':', input))
        line = None
        
        try: 
            artist, title, line = args
            logger.info('got %s, %s, %s' % (artist, title, line))
        except ValueError:
            try:
                artist, title = args
                logger.info('got %s, %s' % (artist, title))
            except:
                artist = args[0]
                logger.info('got %s' % (artist))
                try:
                    title = randtitle(artist)
                except Exception, e:
                    logger.error(utils.exnToString(e))
                    irc.reply("Arrgh! Something went horribly wrong")
                    return
Exemple #5
0
    def icalc(self, irc, msg, args, text):
        """<math expression>

        This is the same as the calc command except that it allows integer
        math, and can thus cause the bot to suck up CPU.  Hence it requires
        the 'trusted' capability to use.
        """
        if self._calc_match_forbidden_chars.match(text):
            # Note: this is important to keep this to forbid usage of
            # __builtins__
            irc.error(_('There\'s really no reason why you should have '
                           'underscores or brackets in your mathematical '
                           'expression.  Please remove them.'))
            return
        # This removes spaces, too, but we'll leave the removal of _[] for
        # safety's sake.
        text = self._calc_remover(text)
        if 'lambda' in text:
            irc.error(_('You can\'t use lambda in this command.'))
            return
        text = text.replace('lambda', '')
        try:
            self.log.info('evaluating %q from %s', text, msg.prefix)
            irc.reply(str(eval(text, self._mathEnv, self._mathEnv)))
        except OverflowError:
            maxFloat = math.ldexp(0.9999999999999999, 1024)
            irc.error(_('The answer exceeded %s or so.') % maxFloat)
        except TypeError:
            irc.error(_('Something in there wasn\'t a valid number.'))
        except NameError as e:
            irc.error(_('%s is not a defined function.') % str(e).split()[1])
        except Exception as e:
            irc.error(utils.exnToString(e))
Exemple #6
0
 def __call__(self, irc, msg, args, state):
     try:
         super(optional, self).__call__(irc, msg, args, state)
     except (callbacks.ArgumentError, callbacks.Error), e:
         log.debug('Got %s, returning default.', utils.exnToString(e))
         state.errored = False
         setDefault(state, self.default)
Exemple #7
0
    def icalc(self, irc, msg, args, text):
        """<math expression>

        This is the same as the calc command except that it allows integer
        math, and can thus cause the bot to suck up CPU.  Hence it requires
        the 'trusted' capability to use.
        """
        if self._calc_match_forbidden_chars.match(text):
            # Note: this is important to keep this to forbid usage of
            # __builtins__
            irc.error(
                _('There\'s really no reason why you should have '
                  'underscores or brackets in your mathematical '
                  'expression.  Please remove them.'))
            return
        # This removes spaces, too, but we'll leave the removal of _[] for
        # safety's sake.
        text = self._calc_remover(text)
        if 'lambda' in text:
            irc.error(_('You can\'t use lambda in this command.'))
            return
        text = text.replace('lambda', '')
        try:
            self.log.info('evaluating %q from %s', text, msg.prefix)
            irc.reply(str(eval(text, self._mathEnv, self._mathEnv)))
        except OverflowError:
            maxFloat = math.ldexp(0.9999999999999999, 1024)
            irc.error(_('The answer exceeded %s or so.') % maxFloat)
        except TypeError:
            irc.error(_('Something in there wasn\'t a valid number.'))
        except NameError as e:
            irc.error(_('%s is not a defined function.') % str(e).split()[1])
        except Exception as e:
            irc.error(utils.exnToString(e))
Exemple #8
0
    def rank(self, irc, msg, args, channel, expr):
        """[<channel>] <stat expression>

        Returns the ranking of users according to the given stat expression.
        Valid variables in the stat expression include 'msgs', 'chars',
        'words', 'smileys', 'frowns', 'actions', 'joins', 'parts', 'quits',
        'kicks', 'kicked', 'topics', and 'modes'.  Any simple mathematical
        expression involving those variables is permitted.
        """
        # XXX I could do this the right way, and abstract out a safe eval,
        #     or I could just copy/paste from the Math plugin.
        if expr != expr.translate(utils.str.chars, '_[]'):
            irc.error(
                'There\'s really no reason why you should have '
                'underscores or brackets in your mathematical '
                'expression.  Please remove them.',
                Raise=True)
        if 'lambda' in expr:
            irc.error('You can\'t use lambda in this command.', Raise=True)
        expr = expr.lower()
        users = []
        for ((c, id), stats) in self.db.items():
            if ircutils.strEqual(c, channel) and ircdb.users.hasUser(id):
                e = self._env.copy()
                for attr in stats._values:
                    e[attr] = float(getattr(stats, attr))
                try:
                    v = eval(expr, e, e)
                except ZeroDivisionError:
                    v = float('inf')
                except NameError, e:
                    irc.errorInvalid('stat variable', str(e).split()[1])
                except Exception, e:
                    irc.error(utils.exnToString(e), Raise=True)
                users.append((v, ircdb.users.getUser(id).name))
Exemple #9
0
    def rank(self, irc, msg, args, channel, expr):
        """[<channel>] <stat expression>

        Returns the ranking of users according to the given stat expression.
        Valid variables in the stat expression include 'msgs', 'chars',
        'words', 'smileys', 'frowns', 'actions', 'joins', 'parts', 'quits',
        'kicks', 'kicked', 'topics', and 'modes'.  Any simple mathematical
        expression involving those variables is permitted.
        """
        # XXX I could do this the right way, and abstract out a safe eval,
        #     or I could just copy/paste from the Math plugin.
        if expr != expr.translate(utils.str.chars, '_[]'):
            irc.error('There\'s really no reason why you should have '
                      'underscores or brackets in your mathematical '
                      'expression.  Please remove them.', Raise=True)
        if 'lambda' in expr:
            irc.error('You can\'t use lambda in this command.', Raise=True)
        expr = expr.lower()
        users = []
        for ((c, id), stats) in self.db.items():
            if ircutils.strEqual(c, channel) and ircdb.users.hasUser(id):
                e = self._env.copy()
                for attr in stats._values:
                    e[attr] = float(getattr(stats, attr))
                try:
                    v = eval(expr, e, e)
                except ZeroDivisionError:
                    v = float('inf')
                except NameError, e:
                    irc.errorInvalid('stat variable', str(e).split()[1])
                except Exception, e:
                    irc.error(utils.exnToString(e), Raise=True)
                users.append((v, ircdb.users.getUser(id).name))
Exemple #10
0
    def sing(self, irc, msg, args, input):
        """
        Usage: sing artist [: title] [: * | line | pattern] --
        Example: @sing bon jovi : wanted dead or alive --
        Searches http://lyricsmania.com
        """

        args = map(lambda x: x.strip(), re.split(':', input))
        line = None

        try:
            artist, title, line = args
            logger.info('got %s, %s, %s' % (artist, title, line))
        except ValueError:
            try:
                artist, title = args
                logger.info('got %s, %s' % (artist, title))
            except:
                artist = args[0]
                logger.info('got %s' % (artist))
                try:
                    title = randtitle(artist)
                except Exception, e:
                    logger.error(utils.exnToString(e))
                    irc.reply("Arrgh! Something went horribly wrong")
                    return
Exemple #11
0
 def connectError(self, server, e):
     if isinstance(e, Exception):
         if isinstance(e, socket.gaierror):
             e = e.args[1]
         else:
             e = utils.exnToString(e)
     self.warning('Error connecting to %s: %s', server, e)
Exemple #12
0
 def __call__(self, irc, msg, args, state):
     try:
         super(optional, self).__call__(irc, msg, args, state)
     except (callbacks.ArgumentError, callbacks.Error), e:
         log.debug('Got %s, returning default.', utils.exnToString(e))
         state.errored = False
         setDefault(state, self.default)
Exemple #13
0
 def formatException(self, xxx_todo_changeme):
     (E, e, tb) = xxx_todo_changeme
     L = [utils.exnToString(e), '::']
     frames = utils.stackTrace(frame=tb.tb_frame).split()
     L.extend(frames)
     del tb
     while sum(map(len, L)) > 350:
         L.pop()
     return ' '.join(L)
Exemple #14
0
    def ircquote(self, irc, msg, args, s):
        """<string to be sent to the server>

        Sends the raw string given to the server.
        """
        try:
            m = ircmsgs.IrcMsg(s)
        except Exception, e:
            irc.error(utils.exnToString(e))
Exemple #15
0
    def ircquote(self, irc, msg, args, s):
        """<string to be sent to the server>

        Sends the raw string given to the server.
        """
        try:
            m = ircmsgs.IrcMsg(s)
        except Exception, e:
            irc.error(utils.exnToString(e))
Exemple #16
0
    def simpleeval(self, irc, msg, args, text):
        """<expression>

        Evaluates the given expression.
        """
        try:
            irc.reply(repr(eval(text)))
        except Exception as e:
            irc.reply(utils.exnToString(e))
Exemple #17
0
    def simpleeval(self, irc, msg, args, text):
        """<expression>

        Evaluates the given expression.
        """
        try:
            irc.reply(repr(eval(text)))
        except Exception as e:
            irc.reply(utils.exnToString(e))
Exemple #18
0
    def add(self, irc, msg, args, filename):
        """<filename>

        Basically does the equivalent of tail -f to the targets.
        """
        try:
            self._add(filename)
        except EnvironmentError, e:
            irc.error(utils.exnToString(e))
            return
Exemple #19
0
    def add(self, irc, msg, args, filename):
        """<filename>

        Basically does the equivalent of tail -f to the targets.
        """
        try:
            self._add(filename)
        except EnvironmentError, e:
            irc.error(utils.exnToString(e))
            return
Exemple #20
0
 def disconnect(self, server, e=None):
     if e:
         if isinstance(e, Exception):
             e = utils.exnToString(e)
         else:
             e = str(e)
         if not e.endswith("."):
             e += "."
         self.warning("Disconnect from %s: %s", server, e)
     else:
         self.info("Disconnect from %s.", server)
Exemple #21
0
 def disconnect(self, server, e=None):
     if e:
         if isinstance(e, Exception):
             e = utils.exnToString(e)
         else:
             e = str(e)
         if not e.endswith('.'):
             e += '.'
         self.warning('Disconnect from %s: %s', server, e)
     else:
         self.info('Disconnect from %s.', server)
Exemple #22
0
 def disconnect(self, server, e=None):
     if e:
         if isinstance(e, Exception):
             e = utils.exnToString(e)
         else:
             e = str(e)
         if not e.endswith('.'):
             e += '.'
         self.warning('Disconnect from %s: %s', server, e)
     else:
         self.info('Disconnect from %s.', server)
Exemple #23
0
 def _callCommand(self, command, irc, msg, *args, **kwargs):
     method = self.getCommandMethod(command)
     if command[0] in mess:
         msg.tag("messcmd", command[0])
     try:
         method(irc, msg, *args, **kwargs)
     except Exception, e:
         self.log.exception("Mess: Uncaught exception in %s.", command)
         if conf.supybot.reply.error.detailed():
             irc.error(utils.exnToString(e))
         else:
             irc.replyError()
Exemple #24
0
    def eval(self, irc, msg, args):
        """<text>

        This is the help for eval.  Since Owner doesn't have an eval command
        anymore, we needed to add this so as not to invalidate any of the tests
        that depended on that eval command.
        """
        try:
            irc.reply(repr(eval(' '.join(args))))
        except callbacks.ArgumentError:
            raise
        except Exception, e:
            irc.reply(utils.exnToString(e))
Exemple #25
0
 def _runCommandFunction(self, irc, msg, command):
     """Run a command from message, as if command was sent over IRC."""
     try:
         tokens = callbacks.tokenize(command,
             channel=msg.channel, network=irc.network)
     except SyntaxError as e:
         # Emulate what callbacks.py does
         self.log.debug('Error return: %s', utils.exnToString(e))
         irc.error(str(e))
     try:
         self.Proxy(irc.irc, msg, tokens)
     except Exception as e:
         log.exception('Uncaught exception in function called by MessageParser:')
Exemple #26
0
 def __call__(self, irc, msg, args, state):
     st = state.essence()
     try:
         while args:
             self.__parent.__call__(irc, msg, args, st)
     except IndexError:
         pass
     except (callbacks.ArgumentError, callbacks.Error), e:
         if not self.continueOnError:
             raise
         else:
             log.debug('Got %s, returning default.', utils.exnToString(e))
             pass
Exemple #27
0
 def __call__(self, irc, msg, args, state):
     st = state.essence()
     try:
         while args:
             self.__parent.__call__(irc, msg, args, st)
     except IndexError:
         pass
     except (callbacks.ArgumentError, callbacks.Error), e:
         if not self.continueOnError:
             raise
         else:
             log.debug('Got %s, returning default.', utils.exnToString(e))
             pass
Exemple #28
0
    def eval(self, irc, msg, args):
        """<text>

        This is the help for eval.  Since Owner doesn't have an eval command
        anymore, we needed to add this so as not to invalidate any of the tests
        that depended on that eval command.
        """
        try:
            irc.reply(repr(eval(' '.join(args))))
        except callbacks.ArgumentError:
            raise
        except Exception, e:
            irc.reply(utils.exnToString(e))
Exemple #29
0
 def open(self, filename):
     self.filename = filename
     reader = unpreserve.Reader(IrcUserCreator, self)
     try:
         self.noFlush = True
         try:
             reader.readFile(filename)
             self.noFlush = False
             self.flush()
         except EnvironmentError, e:
             log.error('Invalid user dictionary file, resetting to empty.')
             log.error('Exact error: %s', utils.exnToString(e))
         except Exception, e:
             log.exception('Exact error:')
Exemple #30
0
 def open(self, filename):
     self.filename = filename
     reader = unpreserve.Reader(IrcUserCreator, self)
     try:
         self.noFlush = True
         try:
             reader.readFile(filename)
             self.noFlush = False
             self.flush()
         except EnvironmentError, e:
             log.error('Invalid user dictionary file, resetting to empty.')
             log.error('Exact error: %s', utils.exnToString(e))
         except Exception, e:
             log.exception('Exact error:')
Exemple #31
0
 def open(self, filename):
     self.noFlush = True
     try:
         self.filename = filename
         reader = unpreserve.Reader(IrcChannelCreator, self)
         try:
             reader.readFile(filename)
             self.noFlush = False
             self.flush()
         except EnvironmentError, e:
             log.error("Invalid channel database, resetting to empty.")
             log.error("Exact error: %s", utils.exnToString(e))
         except Exception, e:
             log.error("Invalid channel database, resetting to empty.")
             log.exception("Exact error:")
Exemple #32
0
    def rank(self, irc, msg, args, channel, expr):
        """[<channel>] <stat expression>

        Returns the ranking of users according to the given stat expression.
        Valid variables in the stat expression include 'msgs', 'chars',
        'words', 'smileys', 'frowns', 'actions', 'joins', 'parts', 'quits',
        'kicks', 'kicked', 'topics', and 'modes'.  Any simple mathematical
        expression involving those variables is permitted.
        """
        if msg.nick not in irc.state.channels[channel].users:
            irc.error(format('You must be in %s to use this command.',
                             channel))
            return
        # XXX I could do this the right way, and abstract out a safe eval,
        #     or I could just copy/paste from the Math plugin.
        if self._calc_match_forbidden_chars.match(expr):
            irc.error(_('There\'s really no reason why you should have '
                        'underscores or brackets in your mathematical '
                        'expression.  Please remove them.'),
                      Raise=True)
        if 'lambda' in expr:
            irc.error(_('You can\'t use lambda in this command.'), Raise=True)
        expr = expr.lower()
        users = []
        for ((c, id), stats) in self.db.items():
            if ircutils.strEqual(c, channel) and \
               (id == 0 or ircdb.users.hasUser(id)):
                e = self._env.copy()
                for attr in stats._values:
                    e[attr] = float(getattr(stats, attr))
                try:
                    v = eval(expr, e, e)
                except ZeroDivisionError:
                    v = float('inf')
                except NameError as e:
                    irc.errorInvalid(_('stat variable'), str(e).split()[1])
                except Exception as e:
                    irc.error(utils.exnToString(e), Raise=True)
                if id == 0:
                    users.append((v, irc.nick))
                else:
                    users.append((v, ircdb.users.getUser(id).name))
        users.sort()
        users.reverse()
        s = utils.str.commaAndify([
            '#%s %s (%.3g)' % (i + 1, u, v) for (i, (v, u)) in enumerate(users)
        ])
        irc.reply(s)
Exemple #33
0
    def format(self, irc, msg, args):
        """<format string> [<arg> ...]

        Expands a Python-style format string using the remaining args.  Just be
        sure always to use %s, not %d or %f or whatever, because all the args
        are strings.
        """
        if not args:
            raise callbacks.ArgumentError
        s = args.pop(0)
        try:
            s %= tuple(args)
            irc.reply(s)
        except TypeError, e:
            self.log.debug(utils.exnToString(e))
            irc.error('Not enough arguments for the format string.',Raise=True)
Exemple #34
0
    def eval(self, irc, msg, args, s):
        """<expression>

        Evaluates <expression> (which should be a Python expression) and
        returns its value.  If an exception is raised, reports the
        exception (and logs the traceback to the bot's logfile).
        """
        try:
            self._evalEnv.update(locals())
            x = eval(s, self._evalEnv, self._evalEnv)
            self._evalEnv['___'] = self._evalEnv['__']
            self._evalEnv['__'] = self._evalEnv['_']
            self._evalEnv['_'] = x
            irc.reply(repr(x))
        except SyntaxError as e:
            irc.reply(format('%s: %q', utils.exnToString(e), s))
Exemple #35
0
    def eval(self, irc, msg, args, s):
        """<expression>

        Evaluates <expression> (which should be a Python expression) and
        returns its value.  If an exception is raised, reports the
        exception (and logs the traceback to the bot's logfile).
        """
        try:
            self._evalEnv.update(locals())
            x = eval(s, self._evalEnv, self._evalEnv)
            self._evalEnv['___'] = self._evalEnv['__']
            self._evalEnv['__'] = self._evalEnv['_']
            self._evalEnv['_'] = x
            irc.reply(repr(x))
        except SyntaxError as e:
            irc.reply(format('%s: %q', utils.exnToString(e), s))
Exemple #36
0
    def format(self, irc, msg, args):
        """<format string> [<arg> ...]

        Expands a Python-style format string using the remaining args.  Just be
        sure always to use %s, not %d or %f or whatever, because all the args
        are strings.
        """
        if not args:
            raise callbacks.ArgumentError
        s = args.pop(0)
        try:
            s %= tuple(args)
            irc.reply(s)
        except TypeError as e:
            self.log.debug(utils.exnToString(e))
            irc.error(_('Not enough arguments for the format string.'),
                      Raise=True)
Exemple #37
0
    def add(self, irc, msg, args, filename, identifier, channet):
        """<filename> <identifier> <channel,network...>

        Add FILENAME as IDENTIFIER for announcing in
        Make sure the bot has rights to read whatever you tail.
        channels are written as #channel,network|#channel2,network2
        """
        try:
            self.config[filename] = {}
            self.config[filename]['identifier'] = identifier
            self.config[filename]['channels'] = channet
            json.dump(self.config, open(self.registryValue('configfile'), 'w'))
            self._add(filename)
        except EnvironmentError as e:
            irc.error(utils.exnToString(e))
            return
        irc.replySuccess()
Exemple #38
0
    def rank(self, irc, msg, args, channel, expr):
        """[<channel>] <stat expression>

        Returns the ranking of users according to the given stat expression.
        Valid variables in the stat expression include 'msgs', 'chars',
        'words', 'smileys', 'frowns', 'actions', 'joins', 'parts', 'quits',
        'kicks', 'kicked', 'topics', and 'modes'.  Any simple mathematical
        expression involving those variables is permitted.
        """
        if msg.nick not in irc.state.channels[channel].users:
            irc.error(format('You must be in %s to use this command.', channel))
            return
        # XXX I could do this the right way, and abstract out a safe eval,
        #     or I could just copy/paste from the Math plugin.
        if self._calc_match_forbidden_chars.match(expr):
            irc.error(_('There\'s really no reason why you should have '
                      'underscores or brackets in your mathematical '
                      'expression.  Please remove them.'), Raise=True)
        if 'lambda' in expr:
            irc.error(_('You can\'t use lambda in this command.'), Raise=True)
        expr = expr.lower()
        users = []
        for ((c, id), stats) in self.db.items():
            if ircutils.strEqual(c, channel) and \
               (id == 0 or ircdb.users.hasUser(id)):
                e = self._env.copy()
                for attr in stats._values:
                    e[attr] = float(getattr(stats, attr))
                try:
                    v = eval(expr, e, e)
                except ZeroDivisionError:
                    v = float('inf')
                except NameError as e:
                    irc.errorInvalid(_('stat variable'), str(e).split()[1])
                except Exception as e:
                    irc.error(utils.exnToString(e), Raise=True)
                if id == 0:
                    users.append((v, irc.nick))
                else:
                    users.append((v, ircdb.users.getUser(id).name))
        users.sort()
        users.reverse()
        s = utils.str.commaAndify(['#%s %s (%.3g)' % (i+1, u, v)
                                   for (i, (v, u)) in enumerate(users)])
        irc.reply(s)
Exemple #39
0
    def rank(self, irc, msg, args, channel, expr):
        """[<channel>] <stat expression>

        Returns the ranking of users according to the given stat expression.
        Valid variables in the stat expression include 'msgs', 'chars',
        'words', 'smileys', 'frowns', 'actions', 'joins', 'parts', 'quits',
        'kicks', 'kicked', 'topics', and 'modes'.  Any simple mathematical
        expression involving those variables is permitted.
        """
        if channel != '#':
            # Skip this check if databases.plugins.channelspecific is False.
            if msg.nick not in irc.state.channels[channel].users:
                irc.error(
                    format('You must be in %s to use this command.', channel))
                return
        expr = expr.lower()
        users = []
        for ((c, id), stats) in self.db.items():
            if ircutils.strEqual(c, channel) and \
               (id == 0 or ircdb.users.hasUser(id)):
                e = {}
                for attr in stats._values:
                    e[attr] = float(getattr(stats, attr))
                try:
                    v = safe_eval(expr, allow_ints=True, variables=e)
                except ZeroDivisionError:
                    v = float('inf')
                except NameError as e:
                    irc.errorInvalid(_('stat variable'), str(e))
                except InvalidNode as e:
                    irc.error(_('Invalid syntax: %s') % e.args[0], Raise=True)
                except Exception as e:
                    irc.error(utils.exnToString(e), Raise=True)
                else:
                    v = float(v)
                if id == 0:
                    users.append((v, irc.nick))
                else:
                    users.append((v, ircdb.users.getUser(id).name))
        users.sort()
        users.reverse()
        s = utils.str.commaAndify([
            '#%s %s (%.3g)' % (i + 1, u, v) for (i, (v, u)) in enumerate(users)
        ])
        irc.reply(s)
Exemple #40
0
    def songs(self, irc, msg, args, input):
        """<string>
        fetches song list from lyricsmania.com"""

        args = map(lambda x: x.strip(), re.split(':', input))

        try:
            artist, searchstring = args
        except:
            artist, searchstring = args[0], None

        songs = []
        try:
            songs = songlist(artist, searchstring)
        except Exception, e:
            logger.error(utils.exnToString(e))
            irc.reply("Arrgh! Something went horribly wrong")
            return
Exemple #41
0
    def songs(self, irc, msg, args, input):
        """<string>
        fetches song list from lyricsmania.com"""

        args = map(lambda x: x.strip(), re.split(':', input))

        try:
            artist, searchstring = args
        except:
            artist, searchstring = args[0], None

        songs = []
        try:
            songs = songlist(artist, searchstring)
        except Exception, e:
            logger.error(utils.exnToString(e))
            irc.reply("Arrgh! Something went horribly wrong")
            return
Exemple #42
0
    def icalc(self, irc, msg, args, text):
        """<math expression>

        This is the same as the calc command except that it allows integer
        math, and can thus cause the bot to suck up CPU.  Hence it requires
        the 'trusted' capability to use.
        """
        try:
            self.log.info('evaluating %q from %s', text, msg.prefix)
            x = safe_eval(text, allow_ints=True)
            irc.reply(str(x))
        except OverflowError:
            maxFloat = math.ldexp(0.9999999999999999, 1024)
            irc.error(_('The answer exceeded %s or so.') % maxFloat)
        except InvalidNode as e:
            irc.error(_('Invalid syntax: %s') % e.args[0])
        except NameError as e:
            irc.error(_('%s is not a defined function.') % str(e).split()[1])
        except Exception as e:
            irc.error(utils.exnToString(e))
Exemple #43
0
    def email(self, irc, msg, args):
        """<first name> <middle initial> <last name>

        Returns possible email address matches for the given name.
        """
        s = '.'.join(args)
        url = 'http://www.ohio-state.edu/cgi-bin/inquiry2.cgi?keyword=%s' % s
        try:
            data = utils.web.getUrl(url)
            emails = []
            for line in data.splitlines():
                line.strip()
                if 'Published address' in line:
                    emails.append(line.split()[-1])
            if len(emails) == 0:
                irc.reply('There seem to be no matches to that name.')
            elif len(emails) == 1:
                irc.reply(emails[0])
            else:
                irc.reply('Possible matches: %s.' % ', '.join(emails))
        except Exception, e:
            irc.error(utils.exnToString(e))
Exemple #44
0
    def email(self, irc, msg, args):
        """<first name> <middle initial> <last name>

        Returns possible email address matches for the given name.
        """
        s = '.'.join(args)
        url = 'http://www.ohio-state.edu/cgi-bin/inquiry2.cgi?keyword=%s' % s
        try:
            data = utils.web.getUrl(url)
            emails = []
            for line in data.splitlines():
                line.strip()
                if 'Published address' in line:
                    emails.append(line.split()[-1])
            if len(emails) == 0:
                irc.reply('There seem to be no matches to that name.')
            elif len(emails) == 1:
                irc.reply(emails[0])
            else:
                irc.reply('Possible matches: %s.' % ', '.join(emails))
        except Exception, e:
            irc.error(utils.exnToString(e))
Exemple #45
0
            (wRating, wWins, wLosses, wDraws) = \
                      self._gkRating.search(wRating).groups()
            (bRating, bWins, bLosses, bDraws) = \
                      self._gkRating.search(bRating).groups()
            wStats = format('%i; W-%i, L-%i, D-%i',
                            wRating, wWins, wLosses, wDraws)
            bStats = format('%i; W-%i, L-%i, D-%i',
                            bRating, bWins, bLosses, bDraws)
            s = format('%s: %s (%s) vs. %s (%s);  %s',
                       gameTitle, wName, wStats, bName, bStats, toMove)
            irc.reply(s, prefixNick=False)
        except ValueError:
            s = format('%u doesn\'t appear to be a proper Gameknot game.', url)
            self.log.debug('Unable to snarf.  %s', s)
        except Exception, e:
            self.log.warning(utils.exnToString(e))
    gameknotSnarfer = urlSnarfer(gameknotSnarfer)

    def gameknotStatsSnarfer(self, irc, msg, match):
        r"http://gameknot\.com/stats\.pl\?([^& ]+)"
        if not self.registryValue('statSnarfer', msg.args[0]):
            return
        name = match.group(1)
        s = self.getStats(name)
        irc.reply(s, prefixNick=False)
    gameknotStatsSnarfer = urlSnarfer(gameknotStatsSnarfer)


Class = Gameknot

Exemple #46
0
            (wRating, wWins, wLosses, wDraws) = \
                      self._gkRating.search(wRating).groups()
            (bRating, bWins, bLosses, bDraws) = \
                      self._gkRating.search(bRating).groups()
            wStats = format('%i; W-%i, L-%i, D-%i', wRating, wWins, wLosses,
                            wDraws)
            bStats = format('%i; W-%i, L-%i, D-%i', bRating, bWins, bLosses,
                            bDraws)
            s = format('%s: %s (%s) vs. %s (%s);  %s', gameTitle, wName,
                       wStats, bName, bStats, toMove)
            irc.reply(s, prefixNick=False)
        except ValueError:
            s = format('%u doesn\'t appear to be a proper Gameknot game.', url)
            self.log.debug('Unable to snarf.  %s', s)
        except Exception, e:
            self.log.warning(utils.exnToString(e))

    gameknotSnarfer = urlSnarfer(gameknotSnarfer)

    def gameknotStatsSnarfer(self, irc, msg, match):
        r"http://gameknot\.com/stats\.pl\?([^& ]+)"
        if not self.registryValue('statSnarfer', msg.args[0]):
            return
        name = match.group(1)
        s = self.getStats(name)
        irc.reply(s, prefixNick=False)

    gameknotStatsSnarfer = urlSnarfer(gameknotStatsSnarfer)


Class = Gameknot
Exemple #47
0
    def sync(self, irc, msg, args, channel):
        """[<channel>]

        Downloads a copy of the database from the remote server.
        Set the server with the channel variable supybot.plugins.Encyclopedia.remotedb.
        If <channel> is not set it will default to the channel the command is given in or the global value.
        """
        if not capab(msg.prefix, "owner"):
            irc.error("Sorry, you can't do that")
            return
        if channel:
            if not ircutils.isChannel(channel):
                irc.error("'%s' is not a valid channel" % safeQuote(channel))
                return
        remotedb = self.registryValue('remotedb', channel)
        if not remotedb:
            return
        def download_database(location, dpath):
            """Download the database located at location to path dpath"""
            import urllib2
            tmp_db = "%s%stmp" % (dpath, os.extsep)
            fd = urllib2.urlopen(location)
            fd2 = open(tmp_db, 'w')
            fd2.write(fd.read()) # Download to a temparary file
            fd.close()
            fd2.close()
            # Do some checking to make sure we have an SQLite database
            fd2 = open(tmp_db, 'rb')
            data = fd2.read(47)
            if data == '** This file contains an SQLite 2.1 database **': # OK, rename to dpath
                os.rename(tmp_db, dpath)
                try:
                    self.databases[channel].close()
                except:
                    pass
                try:
                    self.databases.pop(channel)
                except:
                    pass
            else: # Remove the tmpparary file and raise an error
                os.remove(tmp_db)
                raise RuntimeError, "Downloaded file was not a SQLite 2.1 database"

        db = self.registryValue('database', channel)
        if not db:
            if channel:
                irc.error("I don't have a database set for %s" % channel)
                return
            irc.error("There is no global database set, use 'config supybot.plugins.Encyclopedia.database <database>' to set it")
            return
        if not remotedb:
            if channel:
                irc.error("I don't have a remote database set for %s" % channel)
                return
            irc.error("There is no global remote database set, use 'config supybot.plugins.Encyclopedia.remotedb <url>' to set it")
            return
        dbpath = os.path.join(self.registryValue('datadir'), '%s.db' % db)
        # We're moving files and downloading, lots can go wrong so use lots of try blocks.
        try:
            os.rename(dbpath, "%s.backup" % dbpath)
        except OSError:
            # file doesn't exist yet, so nothing to backup
            pass
        except Exception, e:
            self.log.error("Encyclopedia: Could not rename %s to %s.backup" % (dbpath, dbpath))
            self.log.error('Encyclopedia: ' + utils.exnToString(e))
            irc.error("Internal error, see log")
            return
Exemple #48
0
                logger.error(utils.exnToString(e))
                irc.reply("Arrgh! Something went horribly wrong")
                return
        elif not title:
            irc.reply('No songs found by ' + artist)
            return

        try:
            song = lyricsmania(artist, title)
            if not song or song['lyrics'] == 'Not found':
                irc.reply("No lyrics found for %s by %s" % (title, artist))
            else:
                lyrics = formatlyrics(song, line)
                irc.reply(lyrics.encode('utf8', 'ignore'), prefixNick=False)
        except Exception, e:
            logger.error(utils.exnToString(e))
            irc.reply("Arrgh! Something went horribly wrong")

    sing = wrap(sing, ['text'])

    def songs(self, irc, msg, args, input):
        """<string>
        fetches song list from lyricsmania.com"""

        args = map(lambda x: x.strip(), re.split(':', input))

        try:
            artist, searchstring = args
        except:
            artist, searchstring = args[0], None
Exemple #49
0
 def run(self):
     try:
         super(UrlSnarfThread, self).run()
     except utils.web.Error, e:
         log.debug('Exception in urlSnarfer: %s', utils.exnToString(e))
Exemple #50
0
        if 'lambda' in text:
            irc.error('You can\'t use lambda in this command.')
            return
        text = text.replace('lambda', '')
        try:
            self.log.info('evaluating %q from %s', text, msg.prefix)
            irc.reply(str(eval(text, self._mathEnv, self._mathEnv)))
        except OverflowError:
            maxFloat = math.ldexp(0.9999999999999999, 1024)
            irc.error('The answer exceeded %s or so.' % maxFloat)
        except TypeError:
            irc.error('Something in there wasn\'t a valid number.')
        except NameError, e:
            irc.error('%s is not a defined function.' % str(e).split()[1])
        except Exception, e:
            irc.error(utils.exnToString(e))

    icalc = wrap(icalc, [('checkCapability', 'trusted'), 'text'])

    _rpnEnv = {
        'dup': lambda s: s.extend([s.pop()] * 2),
        'swap': lambda s: s.extend([s.pop(), s.pop()])
    }

    def rpn(self, irc, msg, args):
        """<rpn math expression>

        Returns the value of an RPN expression.
        """
        stack = []
        for arg in args:
Exemple #51
0
                logger.error(utils.exnToString(e))
                irc.reply("Arrgh! Something went horribly wrong")
                return
        elif not title:
            irc.reply('No songs found by ' + artist)
            return

        try:
            song = lyricsmania(artist, title)
            if not song or song['lyrics'] == 'Not found':
                irc.reply("No lyrics found for %s by %s" % (title, artist))
            else:
                lyrics = formatlyrics(song, line)
                irc.reply(lyrics.encode('utf8', 'ignore'), prefixNick=False)
        except Exception, e:
            logger.error(utils.exnToString(e))
            irc.reply("Arrgh! Something went horribly wrong")

    sing = wrap(sing, ['text'])

    def songs(self, irc, msg, args, input):
        """<string>
        fetches song list from lyricsmania.com"""

        args = map(lambda x: x.strip(), re.split(':', input))

        try:
            artist, searchstring = args
        except:
            artist, searchstring = args[0], None
Exemple #52
0
 def testExnToString(self):
     try:
         raise KeyError, 1
     except Exception, e:
         self.assertEqual(utils.exnToString(e), 'KeyError: 1')
Exemple #53
0
class Encyclopedia(callbacks.Plugin):
    """!factoid: show factoid"""
    def __init__(self, irc):
        callbacks.Plugin.__init__(self, irc)
        self.databases = {}
        self.times = {}
        self.edits = {}
        self.alert = False

    def addeditor(self, irc, msg, args, name):
        """<name>

        Adds the user with the name <name> to the list of editors.
        """
        if not capab(msg.prefix, 'addeditors'):
            return
        try:
            u = ircdb.users.getUser(name)
            u.addCapability('editfactoids')
            irc.replySuccess()
        except:
            irc.error('User %s is not registered' % name)

    addeditor = wrap(addeditor, ['text'])

    def removeeditor(self, irc, msg, args, name):
        """<name>

        Removes the user with the name <name> from the list of editors.
        """
        if not capab(msg.prefix, 'addeditors'):
            return
        try:
            u = ircdb.users.getUser(name)
            u.removeCapability('editfactoids')
            irc.replySuccess()
        except:
            irc.error('User %s is not registered or not an editor' % name)

    removeeditor = wrap(removeeditor, ['text'])

    def editors(self, irc, msg, args):
        """Takes no arguments

        Lists all the users who are in the list of editors.
        """
        irc.reply(', '.join([
            u.name for u in ircdb.users.users.values()
            if capab(u.name, 'editfactoids')
        ]),
                  private=True)

    editors = wrap(editors)

    def moderators(self, irc, msg, args):
        """Takes no arguments

        Lists all the users who can add users to the list of editors.
        """
        irc.reply(', '.join([
            u.name for u in ircdb.users.users.values()
            if capab(u.name, 'addeditors')
        ]),
                  private=True)

    moderators = wrap(moderators)

    def get_target(self, nick, text, orig_target):
        target = orig_target
        retmsg = ''
        rettext = text[:]
        hasPipe = False
        hasRedir = False

        if text.startswith('tell '):
            text = ' ' + text

        if '|' in text and not text.strip().endswith('|'):
            hasPipe = True
            retmsg = text[text.find('|') + 1:].strip() + ': '
            rettext = text[:text.find('|')].strip()

        if ' tell ' in text and ' about ' in text:
            target = text[text.find(' tell ') + 6:].strip().split(None, 1)[0]
            rettext = text[text.find(' about ') + 7:].strip()
            retmsg = "<%s> wants you to know: " % nick

        if '>' in text:
            if hasPipe:
                if text.index('|') > text.index('>'):
                    target = text[text.rfind('>') + 1:].strip().split()[0]
                    rettext = text[:text.rfind('>')].strip()
                    retmsg = "<%s> wants you to know: " % nick
            else:
                target = text[text.rfind('>') + 1:].strip().split()[0]
                rettext = text[:text.rfind('>')].strip()
                retmsg = "<%s> wants you to know: " % nick

        if target == 'me':
            target = nick
        if target.lower() != orig_target.lower() and target.startswith('#'):
            target = orig_target
            retmsg = ''

        if (target.lower() == nick.lower() or retmsg[:-2].lower()
                == nick.lower()) and nick.lower() != orig_target.lower():
            target = nick
            retmsg = '(In the future, please use a private message to investigate) '

        return (rettext, target, retmsg)

    def get_db(self, channel):
        db = self.registryValue('database', channel)
        if channel in self.databases:
            if self.databases[channel].time < time.time(
            ) - 3600 or self.databases[channel].name != db:
                self.databases[channel].close()
                self.databases.pop(channel)
        if channel not in self.databases:
            self.databases[channel] = sqlite.connect(
                os.path.join(self.registryValue('datadir'), '%s.db' % db))
            self.databases[channel].name = db
            self.databases[channel].time = time.time()
        return self.databases[channel]

    def get_log_db(self, channel=None):
        db = "%s-log" % self.registryValue('database', channel)
        db_path = os.path.join(self.registryValue('datadir'), "%s.db" % db)
        if not os.access(db_path, os.R_OK | os.W_OK):
            self.log.warning(
                "Encyclopedia: Could not access log database at '%s.db'" %
                db_path)
            return None
        channel = "%s-log" % channel
        if channel in self.databases:
            if self.databases[channel].time < time.time(
            ) - 3600 or self.databases[channel].name != db:
                self.databases[channel].close()
                self.databases.pop(channel)
        if channel not in self.databases:
            self.databases[channel] = sqlite.connect(db_path)
            self.databases[channel].name = db
            self.databases[channel].time = time.time()
        return self.databases[channel]

    def addressed(self, recipients, text, irc, msg):
        nlen = len(irc.nick)
        if recipients[0] == '#':
            text = text.strip()
            if text.lower() == self.registryValue(
                    'prefixchar', channel=recipients) + irc.nick.lower():
                return irc.nick.lower()
            if len(text) and text[0] == self.registryValue('prefixchar',
                                                           channel=recipients):
                text = text[1:]
                if text.lower().startswith(
                        irc.nick.lower()) and (len(text) < nlen
                                               or not text[nlen].isalnum()):
                    t2 = text[nlen + 1:].strip()
                    if t2 and t2.find('>') != -1 and t2.find('|') != -1:
                        text = text[nlen + 1:].strip()
                return text
            if text.lower().startswith(
                    irc.nick.lower()) and (len(text) > nlen
                                           and not text[nlen].isalnum()):
                return text[nlen + 1:]
            return False
        else:  # Private
            if text.strip()[0] in str(
                    conf.supybot.reply.whenAddressedBy.chars.get(msg.args[0])):
                return False
            if not text.split()[0] == 'search':
                for c in irc.callbacks:
                    comm = text.split()[0]
                    if c.isCommandMethod(comm) and not c.isDisabled(comm):
                        return False
            if text[0] == self.registryValue('prefixchar', channel=recipients):
                return text[1:]
            return text

    def get_factoids(self, name, channel, resolve=True, info=False, raw=False):
        factoids = FactoidSet()
        factoids.global_primary = self.get_single_factoid(channel,
                                                          name,
                                                          deleted=raw)
        factoids.global_secondary = self.get_single_factoid(channel,
                                                            name + '-also',
                                                            deleted=raw)
        factoids.channel_primary = self.get_single_factoid(channel,
                                                           name + '-' +
                                                           channel.lower(),
                                                           deleted=raw)
        factoids.channel_secondary = self.get_single_factoid(
            channel, name + '-' + channel.lower() + '-also', deleted=raw)
        if resolve and not raw:
            factoids.global_primary = self.resolve_alias(
                channel, factoids.global_primary)
            factoids.global_secondary = self.resolve_alias(
                channel, factoids.global_secondary)
            factoids.channel_primary = self.resolve_alias(
                channel, factoids.channel_primary)
            factoids.channel_secondary = self.resolve_alias(
                channel, factoids.channel_secondary)
        if info:
            # Get aliases for factoids
            factoids.global_primary = self.factoid_info(
                channel, factoids.global_primary)
            factoids.global_secondary = self.factoid_info(
                channel, factoids.global_secondary)
            factoids.channel_primary = self.factoid_info(
                channel, factoids.channel_primary)
            factoids.channel_secondary = self.factoid_info(
                channel, factoids.channel_secondary)
        return factoids

    def get_single_factoid(self, channel, name, deleted=False):
        db = self.get_db(channel)
        cur = db.cursor()
        if deleted:
            cur.execute(
                "SELECT name, value, author, added, popularity FROM facts WHERE name = %s",
                name)
        else:
            cur.execute(
                "SELECT name, value, author, added, popularity FROM facts WHERE name = %s AND value NOT like '<deleted>%%'",
                name)
        factoids = cur.fetchall()
        if len(factoids):
            f = factoids[0]
            return Factoid(f[0], f[1], f[2], f[3], f[4])

    def resolve_alias(self, channel, factoid, loop=0):
        if factoid and factoid.name in self.registryValue('alert', channel):
            self.alert = True
        if loop >= 10:
            return Factoid('', '<reply> Error: infinite <alias> loop detected',
                           '', '', 0)
        if factoid and factoid.value.lower().startswith('<alias>'):
            new_factoids = self.get_factoids(factoid.value[7:].lower().strip(),
                                             channel, False)
            for x in ['channel_primary', 'global_primary']:
                if getattr(new_factoids, x):
                    return self.resolve_alias(channel,
                                              getattr(new_factoids,
                                                      x), loop + 1)
            return Factoid(
                '', '<reply> Error: unresolvable <alias> to %s' %
                factoid.value[7:].lower().strip(), '', '', 0)
        else:
            return factoid

    def factoid_info(self, channel, factoid):
        if not factoid:
            return
        if not factoid.value.startswith('<alias>'):
            # Try and find aliases
            db = self.get_db(channel)
            cur = db.cursor()
            cur.execute("SELECT name FROM facts WHERE value = %s",
                        '<alias> ' + factoid.name)
            data = cur.fetchall()
            if data:
                factoid.value = "<reply> %s aliases: %s" % (
                    factoid.name, ', '.join([x[0] for x in data]))
            else:
                factoid.value = "<reply> %s has no aliases" % (factoid.name)
        # Author info
        db = self.get_db(channel)
        cur = db.cursor()
        cur.execute("SELECT author, added FROM log WHERE name = %s",
                    factoid.name)
        data = cur.fetchall()
        factoid.value += " - added by %s on %s" % (
            factoid.author[:factoid.author.find('!')],
            factoid.added[:factoid.added.find('.')])
        if data:
            last_edit = data[len(data) - 1]
            who = last_edit[0][:last_edit[0].find('!')]
            when = last_edit[1][:last_edit[1].find('.')]
            factoid.value += " - last edited by %s on %s" % (who, when)
        return factoid

    def check_aliases(self, channel, factoid):
        now = time.time()
        for e in self.edits.keys():
            if self.edits[e] + 10 < now:
                self.edits.pop(e)
        if not factoid.value.startswith('<alias>'):
            return
        # Was the old value an alias?
        oldf = self.get_single_factoid(channel, factoid.name)
        if oldf and oldf.value.startswith('<alias>'):
            if factoid.name not in self.edits:
                self.edits[factoid.name] = now
                return "You are editing an alias. Please repeat the edit command within the next 10 seconds to confirm"
        # Do some alias resolving
        if factoid.value.startswith('<alias>'):
            aliasname = factoid.value[7:].strip()
            alias = self.get_single_factoid(channel, aliasname)
            if not alias:
                return "Factoid '%s' does not exist" % aliasname
            alias = self.resolve_alias(channel, factoid)
            if alias.value.lower().startswith('error'):
                return alias.value.lower
            factoid.value = '<alias> ' + alias.name

    def callPrecedence(self, irc):
        before = []
        for cb in irc.callbacks:
            if cb.name() == 'IRCLogin':
                before.append(cb)
        return (before, [])

    def inFilter(self, irc, msg):
        orig_msg = msg
        if msg.command == "PRIVMSG" and msg.args[0].lower() == irc.nick.lower(
        ):
            recipient, text = msg.args
            new_text = self.addressed(recipient, text, irc, msg)
            if new_text:
                irc = callbacks.ReplyIrcProxy(irc, msg)
                if (irc.nick.lower() == msg.args[0]):
                    self.doPrivmsg(irc, msg)
        return orig_msg

    def doPrivmsg(self, irc, msg):
        def beginswith(text, strings):
            for string in strings:
                if text.startswith(string):
                    return True
            return False

        # Filter CTCP
        if chr(1) in msg.args[1]:
            return

        if checkIgnored(msg.prefix, msg.args[0]):
            return
        # Are we being queried?
        recipient, text = msg.args
        text = self.addressed(recipient, text, irc, msg)
        if not text:
            return
        doChanMsg = True
        display_info = False
        display_raw = False
        target = msg.args[0]
        if target[0] != '#':
            target = msg.nick
        channel = msg.args[0]

        # Strip leading nonalnums
        while text and not text[0].isalnum():
            if text[0] == '-':
                if not display_raw:
                    display_info = True
            if text[0] == '+':
                if not display_info:
                    display_raw = True
            text = text[1:]
        if not text:
            return

        # Now switch between actions
        orig_text = text
        lower_text = text.lower()
        if "please see" in lower_text:
            if "from %s" % irc.nick.lower(
            ) in lower_text or "from the bot" in lower_text:
                doChanMsg = False
        ret = ''
        retmsg = ''
        term = self.get_target(msg.nick, orig_text, target)
        if term[0] == "search":  # Usage info for the !search command
            ret = "Search factoids for term: !search <term>"
            retmsg = term[2]
        elif beginswith(
                lower_text, self.registryValue('ignores', channel)
        ):  # Make sure ignores can ignore these built-in "facts"
            return
        elif term[0] in ("what", "whats", "what's") or term[0].startswith(
                "what ") or term[0].startswith("what ") or term[0].startswith(
                    "whats ") or term[0].startswith(
                        "what's "
                    ):  # Try and catch people saying "ubottu: what is ...?"
            ret = "I suck balls"
            retmsg = term[2]
        else:
            # Lookup, search or edit?
            if lower_text.startswith('search '):
                ret = self.search_factoid(lower_text[7:].strip(), channel)
            elif (' is ' in lower_text and lower_text[:3] in ('no ', 'no,')) or '<sed>' in lower_text or '=~' in lower_text \
                or '~=' in lower_text or '<alias>' in lower_text or lower_text.startswith('forget') or lower_text.startswith('unforget'):
                if not (capab(msg.prefix, 'editfactoids') \
                        or channel in self.registryValue('editchannel') \
                        and capab(msg.prefix, 'restricted-editor')):
                    irc.reply(
                        "Your edit request has been forwarded to %s.  Thank you for your attention to detail"
                        % self.registryValue('relaychannel', channel),
                        private=True)
                    irc.queueMsg(
                        ircmsgs.privmsg(
                            self.registryValue('relaychannel',
                                               channel), "In %s, %s said: %s" %
                            (msg.args[0], msg.nick, msg.args[1])))
                    self.logRequest(msg.args[0], msg.nick, text)
                    return
                ret = self.factoid_edit(text, channel, msg.prefix)
            elif (' is ' in lower_text and '|' in lower_text
                  and lower_text.index('|') > lower_text.index(' is ')) or (
                      ' is ' in lower_text and '|' not in lower_text):
                if not (capab(msg.prefix, 'editfactoids') \
                        or channel in self.registryValue('editchannel') \
                        and capab(msg.prefix, 'restricted-editor')):
                    if len(text[:text.find('is')]) > 15:
                        irc.error("I suck balls")
                    else:
                        irc.reply(
                            "Your edit request has been forwarded to %s.  Thank you for your attention to detail"
                            % self.registryValue('relaychannel', channel),
                            private=True)
                        irc.queueMsg(
                            ircmsgs.privmsg(
                                self.registryValue('relaychannel', channel),
                                "In %s, %s said: %s" %
                                (msg.args[0], msg.nick, msg.args[1])))
                        self.logRequest(msg.args[0], msg.nick, text)
                    return
                ret = self.factoid_add(text, channel, msg.prefix)
            else:
                text, target, retmsg = self.get_target(msg.nick, orig_text,
                                                       target)
                if text.startswith('bug ') and text != ('bug 1'):
                    return
                ret = self.factoid_lookup(text, channel, display_info,
                                          display_raw)

        if not ret:
            if len(text) > 15:
                irc.error("I suck balls")
                return
            retmsg = ''
            ret = self.registryValue('notfoundmsg')
            if ret.count('%') == ret.count('%s') == 1:
                ret = ret % repr(text)
            if channel.lower() == irc.nick.lower():
                queue(irc, msg.nick, ret)
            elif self.registryValue('privateNotFound', channel):
                queue(irc, msg.nick, ret)
            else:
                queue(irc, channel, ret)
            return
        # check if retmsg has urls (possible spam)
        if checkUrl(retmsg):
            if self.alert and (target[0] == '#'
                               and not target.endswith('bots')):
                # !ops factoid called with an url, most likely spam.
                # we filter the msg, but we still warn in -ops.
                queue(
                    irc, self.registryValue('relayChannel', channel),
                    '%s called the ops in %s (%s)' %
                    (msg.nick, msg.args[0], retmsg[:-2]))
                self.alert = False
            # do nothing
            return
        if doChanMsg and channel.lower() != irc.nick.lower(
        ) and target[0] != '#':  # not /msg
            if target in irc.state.channels[channel].users:
                queue(irc, channel,
                      "%s, please see my private message" % target)
        if type(ret) != list:
            queue(irc, target, retmsg + ret)
        else:
            queue(irc, target, retmsg + ret[0])
            if self.alert:
                if target.startswith('#') and not target.endswith('bots'):
                    queue(
                        irc, self.registryValue('relayChannel', channel),
                        '%s called the ops in %s (%s)' %
                        (msg.nick, msg.args[0], retmsg[:-2]))
                self.alert = False
            for r in ret[1:]:
                queue(irc, target, r)

    def doPart(self, irc, msg):
        if len(msg.args) < 2 or not msg.args[1].startswith('requested by'):
            return

        #self.log.debug('msg: %s', msg.args)
        channel, reason = msg.args
        reason = reason[reason.find('(') + 1:-1]  # get the text between ()
        self._forcedFactoid(irc, channel, msg.nick, reason)

    def doKick(self, irc, msg):
        #self.log.debug('msg: %s', msg.args)
        channel, nick, reason = msg.args
        self._forcedFactoid(irc, channel, nick, reason)

    def _forcedFactoid(self, irc, channel, nick, reason):
        if not self.registryValue('forcedFactoid', channel):
            return

        prefix = self.registryValue('prefixchar', channel)
        factoidRe = re.compile(r'%s\w+\b' % prefix)
        factoids = factoidRe.findall(reason)
        #self.log.debug('factoids in reason: %s', factoids)
        if not factoids:
            # no factoid in reason
            return

        L = []
        for factoid in factoids:
            result = self.factoid_lookup(factoid.strip(prefix), channel, False)
            L.extend(result)

        if not L:
            return

        for s in L:
            msg = ircmsgs.privmsg(nick, s)
            irc.queueMsg(msg)

    def factoid_edit(self, text, channel, editor):
        db = self.get_db(channel)
        cs = db.cursor()
        factoid = retmsg = None

        def log_change(factoid):
            cs.execute(
                '''insert into log (author, name, added, oldvalue) values (%s, %s, %s, %s)''',
                (editor, factoid.name,
                 str(datetime.datetime.now(
                     pytz.timezone("UTC"))), factoid.value))
            db.commit()

        if '<alias>' in text.lower() and not text.lower().startswith('no'):
            return self.factoid_add(text, channel, editor)

        if text.lower().startswith('forget '):
            factoid = self.get_single_factoid(channel, text[7:])
            if not factoid:
                return "I know nothing about %s yet, %s" % (
                    text[7:], editor[:editor.find('!')])
            else:
                log_change(factoid)
                factoid.value = '<deleted>' + factoid.value
                retmsg = "I'll forget that, %s" % editor[:editor.find('!')]

        if text.lower().startswith('unforget '):
            factoid = self.get_single_factoid(channel, text[9:], deleted=True)
            if not factoid:
                return "I knew nothing about %s at all, %s" % (
                    text[9:], editor[:editor.find('!')])
            else:
                if not factoid.value.startswith('<deleted>'):
                    return "Factoid %s wasn't deleted yet, %s" % (
                        factoid.name, editor[:editor.find('!')])
                log_change(factoid)
                factoid.value = factoid.value[9:]
                retmsg = "I suddenly remember %s again, %s" % (
                    factoid.name, editor[:editor.find('!')])

        if text.lower()[:3] in ('no ', 'no,'):
            text = text[3:].strip()
            p = text.lower().find(' is ')
            name, value = text[:p].strip(), text[p + 4:].strip()
            if not name or not value:
                return
            name = name.lower()
            factoid = self.get_single_factoid(channel, name)
            if not factoid:
                return "I know nothing about %s yet, %s" % (
                    name, editor[:editor.find('!')])
            log_change(factoid)
            factoid.value = value
            retmsg = "I'll remember that %s" % editor[:editor.find('!')]

        if not retmsg:
            if ' is<sed>' in text:
                text = text.replace('is<sed>', '=~', 1)
            if ' is <sed>' in text:
                text = text.replace('is <sed>', '=~', 1)
            if '~=' in text:
                text = text.replace('~=', '=~', 1)
            # Split into name and regex
            name = text[:text.find('=~')].strip()
            regex = text[text.find('=~') + 2:].strip()
            # Edit factoid
            factoid = self.get_single_factoid(channel, name)
            if not factoid:
                return "I know nothing about %s yet, %s" % (
                    name, editor[:editor.find('!')])
            # Grab the regex
            if regex.startswith('s'):
                regex = regex[1:]
            if regex[-1] != regex[0]:
                return "Missing end delimiter"
            if regex.count(regex[0]) != 3:
                return "Too many (or not enough) delimiters"
            regex, replace = regex[1:-1].split(regex[0])
            try:
                regex = re.compile(regex)
            except:
                return "Malformed regex"
            newval = regex.sub(replace, factoid.value, 1)
            if newval == factoid.value:
                return "Nothing changed there"
            log_change(factoid)
            factoid.value = newval
            retmsg = "I'll remember that %s" % editor[:editor.find('!')]

        ret = self.check_aliases(channel, factoid)
        if ret:
            return ret
        cs.execute("UPDATE facts SET value=%s where name=%s",
                   (factoid.value, factoid.name))
        db.commit()
        return retmsg

    def factoid_add(self, text, channel, editor):
        db = self.get_db(channel)
        cs = db.cursor()

        p = text.lower().find(' is ')
        name, value = text[:p].strip(), text[p + 4:].strip()
        if not name or not value:
            return
        name = name.lower()
        if value.startswith('also ') or value.startswith('also:'):
            name += '-also'
            value = value[5:].strip()
            if not value:
                return
        if self.get_single_factoid(channel, name, deleted=True):
            return "But %s already means something else!" % name
        factoid = Factoid(name, value, None, None, None)
        ret = self.check_aliases(channel, factoid)
        if ret:
            return ret
        cs.execute(
            "INSERT INTO facts (name, value, author, added) VALUES (%s, %s, %s, %s)",
            (name, value, editor,
             str(datetime.datetime.now(pytz.timezone("UTC")))))
        db.commit()
        return "I'll remember that, %s" % editor[:editor.find('!')]

    def factoid_lookup(self, text, channel, display_info, display_raw=False):
        def subvars(val):
            curStable = self.registryValue('curStable')
            curStableLong = self.registryValue('curStableLong')
            curStableNum = self.registryValue('curStableNum')
            curLTS = self.registryValue('curLTS')
            curLTSLong = self.registryValue('curLTSLong')
            curLTSNum = self.registryValue('curLTSNum')
            curDevel = self.registryValue('curDevel')
            curDevelLong = self.registryValue('curDevelLong')
            curDevelNum = self.registryValue('curDevelNum')
            val = val.replace('$chan', channel)
            val = val.replace('$curStableLong', curStableLong)
            val = val.replace('$curStableNum', curStableNum)
            val = val.replace('$curStableLower', curStable.lower())
            val = val.replace('$curStable', curStable)
            val = val.replace('$curLTSLong', curLTSLong)
            val = val.replace('$curLTSNum', curLTSNum)
            val = val.replace('$curLTSLower', curLTS.lower())
            val = val.replace('$curLTS', curLTS)
            val = val.replace('$curDevelLong', curDevelLong)
            val = val.replace('$curDevelNum', curDevelNum)
            val = val.replace('$curDevelLower', curDevel.lower())
            val = val.replace('$curDevel', curDevel)
            return val

        db = self.get_db(channel)
        factoids = self.get_factoids(text.lower(),
                                     channel,
                                     resolve=(not display_info
                                              and not display_raw),
                                     info=display_info,
                                     raw=display_raw)
        ret = []
        for order in ('primary', 'secondary'):
            for loc in ('channel', 'global'):
                key = '%s_%s' % (loc, order)
                if getattr(factoids, key):
                    factoid = getattr(factoids, key)
                    if (not display_info and not display_raw):
                        cur = db.cursor()
                        cur.execute(
                            "UPDATE FACTS SET popularity = %d WHERE name = %s",
                            factoid.popularity + 1, factoid.name)
                        db.commit()
                    if display_raw:
                        ret.append(factoid.value)
                    elif factoid.value.startswith('<reply>'):
                        ret.append(subvars(factoid.value[7:].strip()))
                    elif order == 'secondary':
                        ret.append(subvars(factoid.value.strip()))
                    else:
                        n = factoid.name
                        if '-#' in n:
                            n = n[:n.find('-#')]
                        ret.append('%s is %s' % (n, subvars(factoid.value)))
                    if not display_info:
                        break
        return ret

    def sanatizeRequest(self, channel, msg):
        def normalize(s):
            while s.count("  "):
                s = s.replace("  ", '')
            return s.strip()

        msg = normalize(msg)
        if msg[0] == self.registryValue('prefixchar', channel):
            msg = msg[1:]
        if msg.startswith("no "):
            msg = msg[3:]
        if " is " in msg:
            msg = msg.replace(" is ", " ", 1)
        (name, msg) = msg.split(None, 1)
        factoid = self.get_single_factoid(channel, name)
        oldval = ''
        if factoid:
            oldval = factoid.value
        return (name, msg, oldval)

    def logRequest(self, channel, nick, msg):
        (name, msg, oldval) = self.sanatizeRequest(channel, msg)
        if msg.strip() == oldval.strip():
            return
        if oldval:
            self.doLogRequest(0, channel, nick, name, msg, oldval)
        else:
            self.doLogRequest(1, channel, nick, name, msg)

    def doLogRequest(self, tp, channel, nick, name, msg, oldval=''):
        db = self.get_log_db(channel)
        if not db:
            return
        cur = db.cursor()
        now = str(datetime.datetime.now(pytz.timezone("UTC")))
        cur.execute("SELECT value FROM requests WHERE name = %s", name)
        items = cur.fetchall()
        if len(items):
            for item in items:
                if item[0] == msg:
                    return
        cur.execute(
            "INSERT INTO requests (type, name, value, oldval, who, date, rank) VALUES (%i, %s, %s, %s, %s, %s, 0)",
            (int(bool(tp)), name, msg, oldval, nick, now))
        db.commit()

    def search_factoid(self, factoid, channel):
        keys = factoid.split()[:5]
        db = self.get_db(channel)
        cur = db.cursor()
        ret = {}
        for k in keys:
            k = k.replace("'", "\'")
            cur.execute(
                "SELECT name,value FROM facts WHERE name LIKE '%%%s%%' OR VAlUE LIKE '%%%s%%'"
                % (k, k))
            res = cur.fetchall()
            for r in res:
                val = r[1]
                d = r[1].startswith('<deleted>')
                a = r[1].startswith('<alias>')
                r = r[0]
                if d:
                    r += '*'
                if a:
                    r += '@' + val[7:].strip()
                try:
                    ret[r] += 1
                except:
                    ret[r] = 1
        if not ret:
            return "None found"
        return 'Found: %s' % ', '.join(
            sorted(ret.keys(), lambda x, y: cmp(ret[x], ret[y]))[:10])

    def sync(self, irc, msg, args, channel):
        """[<channel>]

        Downloads a copy of the database from the remote server.
        Set the server with the channel variable supybot.plugins.Encyclopedia.remotedb.
        If <channel> is not set it will default to the channel the command is given in or the global value.
        """
        if not capab(msg.prefix, "owner"):
            irc.error("Sorry, you can't do that")
            return
        if channel:
            if not ircutils.isChannel(channel):
                irc.error("'%s' is not a valid channel" % safeQuote(channel))
                return
        remotedb = self.registryValue('remotedb', channel)
        if not remotedb:
            return

        def download_database(location, dpath):
            """Download the database located at location to path dpath"""
            import urllib2
            tmp_db = "%s%stmp" % (dpath, os.extsep)
            fd = urllib2.urlopen(location)
            fd2 = open(tmp_db, 'w')
            fd2.write(fd.read())  # Download to a temparary file
            fd.close()
            fd2.close()
            # Do some checking to make sure we have an SQLite database
            fd2 = open(tmp_db, 'rb')
            data = fd2.read(47)
            if data == '** This file contains an SQLite 2.1 database **':  # OK, rename to dpath
                os.rename(tmp_db, dpath)
                try:
                    self.databases[channel].close()
                except:
                    pass
                try:
                    self.databases.pop(channel)
                except:
                    pass
            else:  # Remove the tmpparary file and raise an error
                os.remove(tmp_db)
                raise RuntimeError, "Downloaded file was not a SQLite 2.1 database"

        db = self.registryValue('database', channel)
        if not db:
            if channel:
                irc.error("I don't have a database set for %s" % channel)
                return
            irc.error(
                "There is no global database set, use 'config supybot.plugins.Encyclopedia.database <database>' to set it"
            )
            return
        if not remotedb:
            if channel:
                irc.error("I don't have a remote database set for %s" %
                          channel)
                return
            irc.error(
                "There is no global remote database set, use 'config supybot.plugins.Encyclopedia.remotedb <url>' to set it"
            )
            return
        dbpath = os.path.join(self.registryValue('datadir'), '%s.db' % db)
        # We're moving files and downloading, lots can go wrong so use lots of try blocks.
        try:
            os.rename(dbpath, "%s.backup" % dbpath)
        except OSError:
            # file doesn't exist yet, so nothing to backup
            pass
        except Exception, e:
            self.log.error("Encyclopedia: Could not rename %s to %s.backup" %
                           (dbpath, dbpath))
            self.log.error('Encyclopedia: ' + utils.exnToString(e))
            irc.error("Internal error, see log")
            return

        try:
            # Downloading can take some time, let the user know we're doing something
            irc.reply("Attemting to download database", prefixNick=False)
            download_database(remotedb, dbpath)
            irc.replySuccess()
        except Exception, e:
            self.log.error("Encyclopedia: Could not download %s to %s" %
                           (remotedb, dbpath))
            self.log.error('Encyclopedia: ' + utils.exnToString(e))
            irc.error("Internal error, see log")
            os.rename("%s.backup" % dbpath, dbpath)
            return
Exemple #54
0
    def sync(self, irc, msg, args, channel):
        """[<channel>]

        Downloads a copy of the database from the remote server.
        Set the server with the channel variable supybot.plugins.Encyclopedia.remotedb.
        If <channel> is not set it will default to the channel the command is given in or the global value.
        """
        if not capab(msg.prefix, "owner"):
            irc.error("Sorry, you can't do that")
            return
        if channel:
            if not ircutils.isChannel(channel):
                irc.error("'%s' is not a valid channel" % safeQuote(channel))
                return
        remotedb = self.registryValue('remotedb', channel)
        if not remotedb:
            return

        def download_database(location, dpath):
            """Download the database located at location to path dpath"""
            import urllib2
            tmp_db = "%s%stmp" % (dpath, os.extsep)
            fd = urllib2.urlopen(location)
            fd2 = open(tmp_db, 'w')
            fd2.write(fd.read())  # Download to a temparary file
            fd.close()
            fd2.close()
            # Do some checking to make sure we have an SQLite database
            fd2 = open(tmp_db, 'rb')
            data = fd2.read(47)
            if data == '** This file contains an SQLite 2.1 database **':  # OK, rename to dpath
                os.rename(tmp_db, dpath)
                try:
                    self.databases[channel].close()
                except:
                    pass
                try:
                    self.databases.pop(channel)
                except:
                    pass
            else:  # Remove the tmpparary file and raise an error
                os.remove(tmp_db)
                raise RuntimeError, "Downloaded file was not a SQLite 2.1 database"

        db = self.registryValue('database', channel)
        if not db:
            if channel:
                irc.error("I don't have a database set for %s" % channel)
                return
            irc.error(
                "There is no global database set, use 'config supybot.plugins.Encyclopedia.database <database>' to set it"
            )
            return
        if not remotedb:
            if channel:
                irc.error("I don't have a remote database set for %s" %
                          channel)
                return
            irc.error(
                "There is no global remote database set, use 'config supybot.plugins.Encyclopedia.remotedb <url>' to set it"
            )
            return
        dbpath = os.path.join(self.registryValue('datadir'), '%s.db' % db)
        # We're moving files and downloading, lots can go wrong so use lots of try blocks.
        try:
            os.rename(dbpath, "%s.backup" % dbpath)
        except OSError:
            # file doesn't exist yet, so nothing to backup
            pass
        except Exception, e:
            self.log.error("Encyclopedia: Could not rename %s to %s.backup" %
                           (dbpath, dbpath))
            self.log.error('Encyclopedia: ' + utils.exnToString(e))
            irc.error("Internal error, see log")
            return
Exemple #55
0
        if 'lambda' in text:
            irc.error(_('You can\'t use lambda in this command.'))
            return
        text = text.replace('lambda', '')
        try:
            self.log.info('evaluating %q from %s', text, msg.prefix)
            irc.reply(str(eval(text, self._mathEnv, self._mathEnv)))
        except OverflowError:
            maxFloat = math.ldexp(0.9999999999999999, 1024)
            irc.error(_('The answer exceeded %s or so.') % maxFloat)
        except TypeError:
            irc.error(_('Something in there wasn\'t a valid number.'))
        except NameError, e:
            irc.error(_('%s is not a defined function.') % str(e).split()[1])
        except Exception, e:
            irc.error(utils.exnToString(e))
    icalc = wrap(icalc, [('checkCapability', 'trusted'), 'text'])

    _rpnEnv = {
        'dup': lambda s: s.extend([s.pop()]*2),
        'swap': lambda s: s.extend([s.pop(), s.pop()])
        }
    def rpn(self, irc, msg, args):
        """<rpn math expression>

        Returns the value of an RPN expression.
        """
        stack = []
        for arg in args:
            try:
                x = complex(arg)
Exemple #56
0
 def run(self):
     try:
         super(UrlSnarfThread, self).run()
     except utils.web.Error, e:
         log.debug('Exception in urlSnarfer: %s', utils.exnToString(e))