def _send_messages(self, sub, msg, type):
        # Global silence
        if conf.get(conf.supybot.plugins.GitHubEventAnnounce.silence):
            return

        for chan in sub.channels:
            # See if we're under channel silence
            if conf.get(conf.supybot.plugins.GitHubEventAnnounce.silence, chan):  # noqa
                return

            # Get config for event type in chan
            try:
                group = getattr(conf.supybot.plugins.GitHubEventAnnounce, "announce%ss" % (type))
            except:
                e = sys.exc_info()
                logger.error("Failed to get config group for type %s" % (type))
                logger.error(pp.pformat(e))
                group = None

            # Allow if conf missing
            if group is None:
                event_allowed = True
            else:
                event_allowed = conf.get(group, chan)

            # Send allowed events
            if event_allowed:
                qmsg = ircmsgs.privmsg(chan, msg)
                sub.irc.queueMsg(qmsg)
Example #2
0
 def invalidCommand(self, irc, msg, tokens):
     assert not msg.repliedTo, 'repliedTo msg in Misc.invalidCommand.'
     assert self is irc.callbacks[-1], 'Misc isn\'t last callback.'
     self.log.debug('Misc.invalidCommand called (tokens %s)', tokens)
     channel = msg.args[0]
     # Only bother with the invaildCommand flood handling if it's actually
     # enabled
     if conf.supybot.abuse.flood.command.invalid():
         # First, we check for invalidCommand floods.  This is rightfully done
         # here since this will be the last invalidCommand called, and thus it
         # will only be called if this is *truly* an invalid command.
         maximum = conf.supybot.abuse.flood.command.invalid.maximum()
         banmasker = conf.supybot.protocols.irc.banmask.makeBanmask
         self.invalidCommands.enqueue(msg)
         if self.invalidCommands.len(msg) > maximum and \
            not ircdb.checkCapability(msg.prefix, 'owner'):
             penalty = conf.supybot.abuse.flood.command.invalid.punishment()
             banmask = banmasker(msg.prefix)
             self.log.info('Ignoring %s for %s seconds due to an apparent '
                           'invalid command flood.', banmask, penalty)
             if tokens and tokens[0] == 'Error:':
                 self.log.warning('Apparent error loop with another Supybot '
                                  'observed.  Consider ignoring this bot '
                                  'permanently.')
             ircdb.ignores.add(banmask, time.time() + penalty)
             if conf.supybot.abuse.flood.command.invalid.notify():
                 irc.reply('You\'ve given me %s invalid commands within '
                           'the last minute; I\'m now ignoring you for %s.' %
                           (maximum,
                            utils.timeElapsed(penalty, seconds=False)))
             return
     # Now, for normal handling.
     if conf.get(conf.supybot.reply.whenNotCommand, channel):
         if len(tokens) >= 2:
             cb = irc.getCallback(tokens[0])
             if cb:
                 plugin = cb.name()
                 irc.error(format('The %q plugin is loaded, but there is '
                                  'no command named %q in it.  Try "list '
                                  '%s" to see the commands in the %q '
                                  'plugin.', plugin, tokens[1],
                                  plugin, plugin))
             else:
                 irc.errorInvalid('command', tokens[0], repr=False)
         else:
             command = tokens and tokens[0] or ''
             irc.errorInvalid('command', command, repr=False)
     else:
         if tokens:
             # echo [] will get us an empty token set, but there's no need
             # to log this in that case anyway, it being a nested command.
             self.log.info('Not replying to %s, not a command.', tokens[0])
         if irc.nested:
             bracketConfig = conf.supybot.commands.nested.brackets
             brackets = conf.get(bracketConfig, channel)
             if brackets:
                 (left, right) = brackets
                 irc.reply(left + ' '.join(tokens) + right)
             else:
                 pass # Let's just do nothing, I can't think of better.
Example #3
0
    def _send_messages(self, sub, msg, type):
        # Global silence
        if conf.get(conf.supybot.plugins.GitHubEventAnnounce.silence):
            return

        for chan in sub.channels:
            # See if we're under channel silence
            if conf.get(conf.supybot.plugins.GitHubEventAnnounce.silence,
                        chan):  #noqa
                return

            # Get config for event type in chan
            try:
                group = getattr(conf.supybot.plugins.GitHubEventAnnounce,
                                'announce%ss' % (type))
            except:
                e = sys.exc_info()
                logger.error('Failed to get config group for type %s' % (type))
                logger.error(pp.pformat(e))
                group = None

            # Allow if conf missing
            if group is None:
                event_allowed = True
            else:
                event_allowed = conf.get(group, chan)

            # Send allowed events
            if event_allowed:
                qmsg = ircmsgs.privmsg(chan, msg)
                sub.irc.queueMsg(qmsg)
Example #4
0
    def getIssue(self, irc, msg, match, force=False):
        """Get a Jira Issue"""
        if not ircutils.isChannel(msg.args[0]) and not force:
            return
        if conf.get(conf.supybot.plugins.Jira.lookup, msg.args[0]) == False:
            return
        issueName = match.group('issue')
        try:
            issue = self.jira[self.user].issue(issueName)
        except Exception as e:
            self.log.exception('Error loading issue.', e)
            irc.reply("Cannot find %s bug." % issueName)
            print("Invalid Jira snarf: %s" % issueName)
            return

        if issue:
            try:
                assignee = issue.fields.assignee.displayName
            except:
                assignee = "Unassigned"

            displayTime = display_time(issue.fields.timeestimate)
            url = ''.join((self.server, 'browse/', issue.key))

            values = {  "type": issue.fields.issuetype.name,
                        "key": issue.key,
                        "summary": issue.fields.summary,
                        "status": _c(_b(issue.fields.status.name), "green"),
                        "assignee": _c(assignee, "blue"),
                        "displayTime": displayTime,
                        "url": url,
                    }

            replytext = (self.template % values)
            irc.reply(replytext, prefixNick=False)
Example #5
0
 def send(s):
     targetIRC = world.getIrc(relay.targetNetwork)
     if not targetIRC:
         self.log.info('LinkRelay:  Not connected to network %s.' %
                       relay.targetNetwork)
     elif targetIRC.zombie:
         self.log.info('LinkRelay:  IRC %s appears to be a zombie'%
                       relay.targetNetwork)
     elif irc.isChannel(relay.targetChannel) and \
             relay.targetChannel not in targetIRC.state.channels:
         self.log.info('LinkRelay:  I\'m not in in %s on %s' %
                       (relay.targetChannel, relay.targetNetwork))
     else:
         if isPrivmsg or \
                 self.registryValue('nonPrivmsgs', channel) == 'privmsg':
             f = ircmsgs.privmsg
         elif self.registryValue('nonPrivmsgs', channel) == 'notice':
             f = ircmsgs.notice
         else:
             return
         allowedLength = conf.get(conf.supybot.reply.mores.length,
                  relay.targetChannel) or 470
         cont = _('(continuation)')
         remainingLength = allowedLength - len(cont) - 1
         head = s[0:allowedLength]
         tail = [cont + ' ' + s[i:i+remainingLength] for i in
                 range(allowedLength, len(s), remainingLength)]
         for s in [head] + tail:
             msg = f(relay.targetChannel, s)
             msg.tag('relayedMsg')
             targetIRC.sendMsg(msg)
Example #6
0
 def _query_freebase(self, work_type, thing):
   key = conf.get(conf.supybot.plugins.Cast.FreebaseApiKey)
   props = FREEBASE_TYPES[work_type]
   url = "https://www.googleapis.com/freebase/v1/search?query=%s&type=%s&key=%s" % (web.urlquote(thing),props['type'],key)
   response = simplejson.loads(web.getUrl(url, headers=HEADERS))
   if len(response['result']) == 0:
     return None
   else:
     fbid = response['result'][0]['id']
     query = {
         "id": fbid,
         "type": props['type'],
         "name": None,
         "limit": 1
       }
     query.update(props['subquery'])
     url = "https://www.googleapis.com/freebase/v1/mqlread?query=%s&key=%s" % (web.urlquote(simplejson.dumps(query)),key)
     response = simplejson.loads(web.getUrl(url, headers=HEADERS))
     result = response['result']
     if result is None:
       return None
     else:
       return({
         'props': props,
         'url': "http://www.freebase.com" + result['id'],
         'title': result['name'],
         'characters': props['extractor'](result)
       })
Example #7
0
 def _query_freebase(self, work_type, thing):
     key = conf.get(conf.supybot.plugins.Cast.FreebaseApiKey)
     props = FREEBASE_TYPES[work_type]
     url = "https://www.googleapis.com/freebase/v1/search?query=%s&type=%s&key=%s" % (
         web.urlquote(thing), props['type'], key)
     response = simplejson.loads(web.getUrl(url, headers=HEADERS))
     if len(response['result']) == 0:
         return None
     else:
         fbid = response['result'][0]['id']
         query = {
             "id": fbid,
             "type": props['type'],
             "name": None,
             "limit": 1
         }
         query.update(props['subquery'])
         url = "https://www.googleapis.com/freebase/v1/mqlread?query=%s&key=%s" % (
             web.urlquote(simplejson.dumps(query)), key)
         response = simplejson.loads(web.getUrl(url, headers=HEADERS))
         result = response['result']
         if result is None:
             return None
         else:
             return ({
                 'props': props,
                 'url': "http://www.freebase.com" + result['id'],
                 'title': result['name'],
                 'characters': props['extractor'](result)
             })
Example #8
0
 def send(s):
     targetIRC = world.getIrc(relay.targetNetwork)
     if not targetIRC:
         self.log.info('LinkRelay:  Not connected to network %s.' %
                       relay.targetNetwork)
     elif targetIRC.zombie:
         self.log.info('LinkRelay:  IRC %s appears to be a zombie' %
                       relay.targetNetwork)
     elif irc.isChannel(relay.targetChannel) and \
             relay.targetChannel not in targetIRC.state.channels:
         self.log.info('LinkRelay:  I\'m not in in %s on %s' %
                       (relay.targetChannel, relay.targetNetwork))
     else:
         if isPrivmsg or \
                 self.registryValue('nonPrivmsgs', channel) == 'privmsg':
             f = ircmsgs.privmsg
         elif self.registryValue('nonPrivmsgs', channel) == 'notice':
             f = ircmsgs.notice
         else:
             return
         allowedLength = conf.get(conf.supybot.reply.mores.length,
                                  relay.targetChannel) or 470
         cont = _('(continuation)')
         remainingLength = allowedLength - len(cont) - 1
         head = s[0:allowedLength]
         tail = [
             cont + ' ' + s[i:i + remainingLength]
             for i in range(allowedLength, len(s), remainingLength)
         ]
         for s in [head] + tail:
             msg = f(relay.targetChannel, s)
             msg.tag('relayedMsg')
             targetIRC.sendMsg(msg)
Example #9
0
	def api(self, irc, msg, args, nick, clas, func):
		"""<class> [<function>] [<nick>]

		Link to API documentation for <class> (<function>), optionally telling it to <nick>"""
		
		# Set the reply to if its set
		if nick != None:
			# Don't allow people to tell to kohana-bot, he gets mad
			if re.match("kohana-bot",nick,flags=re.IGNORECASE):
				irc.reply("He doesn't care.")
				return
			msg.nick = nick
		
		# Build the link
		out = clas
		if type(func) == str:
			match = re.match("\$",func)
			if match is not None:
				out = out + "#property:" + func
			else:
				out = out + "#" + func
		msg = conf.get(conf.supybot.plugins.Kohanadocs.apilink) + out
		
		# And send it
		irc.reply(msg)
Example #10
0
 def quiet(self, irc, msg, args):
     """Turn polite-mode on."""
     if conf.get(conf.supybot.plugins.Infobot.unaddressed.answerQuestions)\
         or\
         conf.get(conf.supybot.plugins.Infobot.unaddressed.
                 replyExistingFactoid):
         if conf.get(conf.supybot.plugins.Infobot.personality):
             irc.reply("Sorry, {}, I'll try to stay "
                     "quiet.".format(msg.nick), prefixNick=False)
         else:
             irc.reply("Entering polite mode.")
         conf.supybot.plugins.Infobot.unaddressed.answerQuestions.\
                 setValue(False)
         conf.supybot.plugins.Infobot.unaddressed.replyExistingFactoid.\
                 setValue(False)
     else:
         pass
Example #11
0
 def wake(self, irc, msg, args):
     """Turn off polite-mode."""
     if conf.get(conf.supybot.plugins.Infobot.unaddressed.answerQuestions)\
         or\
         conf.get(conf.supybot.plugins.Infobot.unaddressed.
         replyExistingFactoid):
         pass
     else:
         if conf.get(conf.supybot.plugins.Infobot.personality):
             irc.reply("Good morning, {}.".format(msg.nick),
                     prefixNick=False)
         else:
             irc.reply("Leaving polite mode.")
         conf.supybot.plugins.Infobot.unaddressed.answerQuestions.\
                 setValue(True)
         conf.supybot.plugins.Infobot.unaddressed.replyExistingFactoid.\
                 setValue(True)
Example #12
0
 def _getTemp(temp, deg, unit, chan):
     assert unit == unit.upper()
     assert temp == float(temp)
     default = conf.get(conf.supybot.plugins.Weather.temperatureUnit, chan)
     convert = conf.get(conf.supybot.plugins.Weather.convert, chan)
     # Short circuit if we're the same unit as the default or no conversion
     # has been requested
     if unitAbbrevs[unit] == default or not convert:
         return format('%0.1f%s%s', temp, deg, unit)
     temp = Weather._toCelsius(temp, unit)
     unit = 'C'
     if default == 'Kelvin':
         temp = temp + 273.15
         unit = 'K'
         deg = ' '
     elif default == 'Fahrenheit':
         temp = temp * 9 / 5 + 32
         unit = 'F'
     return '%0.1f%s%s' % (temp, deg, unit)
Example #13
0
 def _getTemp(temp, deg, unit, chan):
     assert unit == unit.upper()
     assert temp == float(temp)
     default = conf.get(conf.supybot.plugins.Weather.temperatureUnit, chan)
     convert = conf.get(conf.supybot.plugins.Weather.convert, chan)
     # Short circuit if we're the same unit as the default or no conversion
     # has been requested
     if unitAbbrevs[unit] == default or not convert:
         return format('%0.1f%s%s', temp, deg, unit)
     temp = Weather._toCelsius(temp, unit)
     unit = 'C'
     if default == 'Kelvin':
         temp = temp + 273.15
         unit = 'K'
         deg = ' '
     elif default == 'Fahrenheit':
         temp = temp * 9 / 5 + 32
         unit = 'F'
     return '%0.1f%s%s' % (temp, deg, unit)
Example #14
0
	def docs(self, irc, msg, args, nick, page):
		"""<page> [<nick>]
		
		Link to the documentation for that <page>, optionally telling it to <nick>. If I don't recognize the page, I will try to guess"""
		
		# Set the reply to if its set
		if nick != None:
			# Don't allow people to tell to kohana-bot, he gets mad
			if re.match("kohana-bot",nick,flags=re.IGNORECASE):
				irc.reply("He doesn't care.")
				return
			msg.nick = nick
		
		# If no page specified, just return a link to the docs
		if page == None:
			msg = conf.get(conf.supybot.plugins.Kohanadocs.doclink)
			irc.reply(msg)
			return
		
		msg = conf.get(conf.supybot.plugins.Kohanadocs.doclink) + page
		irc.reply(msg)
Example #15
0
    def choose(self, irc, msg, args, choices):
        """<choice1> ... <choiceN>

        Randomly selects one of multiple choices.
        """
        if choices is None:
            if conf.get(conf.supybot.plugins.Infobot.personality):
                irc.reply(choice(zero_choice_reply))
            else:
                irc.reply(no_choice_reply)
            return

        options = [y.strip() for x in choices.split(' or ')
                    for y in x.split(';') if y not in ['', ' ']]
        if len(options) is 1:
            if conf.get(conf.supybot.plugins.Infobot.personality):
                irc.reply(choice(one_choice_reply))
            else:
                irc.reply(no_choice_reply)
            return
        else:
            irc.reply(choice(options))
Example #16
0
 def getCommandHelp(self, command, simpleSyntax=None):
     method = self.getCommandMethod(command)
     if method.im_func.func_name == "learn":
         chan = None
         if dynamic.msg is not None:
             chan = dynamic.msg.args[0]
         s = self.registryValue("learnSeparator", chan)
         help = callbacks.getHelp
         if simpleSyntax is None:
             simpleSyntax = conf.get(conf.supybot.reply.showSimpleSyntax, chan)
         if simpleSyntax:
             help = callbacks.getSyntax
         return help(method, doc=method._fake__doc__ % (s, s), name=callbacks.formatCommand(command))
     return super(Factoids, self).getCommandHelp(command, simpleSyntax)
Example #17
0
 def _getTemp(temp, deg, unit, chan):
     assert unit == unit.upper()
     assert temp == int(temp)
     default = conf.get(conf.supybot.plugins.Weather.temperatureUnit, chan)
     if unitAbbrevs[unit] == default:
         # Short circuit if we're the same unit as the default.
         return format('%i%s%s', temp, deg, unit)
     temp = Weather._toCelsius(temp, unit)
     unit = 'C'
     if default == 'Kelvin':
         temp = temp + 273.15
         unit = 'K'
         deg = ' '
     elif default == 'Fahrenheit':
         temp = temp * 9 / 5 + 32
         unit = 'F'
     return '%i%s%s' % (temp, deg, unit)
Example #18
0
 def _getTemp(temp, deg, unit, chan):
     assert unit == unit.upper()
     assert temp == int(temp)
     default = conf.get(conf.supybot.plugins.Weather.temperatureUnit, chan)
     if unitAbbrevs[unit] == default:
         # Short circuit if we're the same unit as the default.
         return format('%i%s%s', temp, deg, unit)
     temp = Weather._toCelsius(temp, unit)
     unit = 'C'
     if default == 'Kelvin':
         temp = temp + 273.15
         unit = 'K'
         deg = ' '
     elif default == 'Fahrenheit':
         temp = temp * 9 / 5 + 32
         unit = 'F'
     return '%i%s%s' % (temp, deg, unit)
Example #19
0
 def getCommandHelp(self, command, simpleSyntax=None):
     method = self.getCommandMethod(command)
     if method.im_func.func_name == 'learn':
         chan = None
         if dynamic.msg is not None:
             chan = dynamic.msg.args[0]
         s = self.registryValue('learnSeparator', chan)
         help = callbacks.getHelp
         if simpleSyntax is None:
             simpleSyntax = conf.get(conf.supybot.reply.showSimpleSyntax,
                                     chan)
         if simpleSyntax:
             help = callbacks.getSyntax
         return help(method,
                     doc=method._fake__doc__ % (s, s),
                     name=callbacks.formatCommand(command))
     return super(Factoids, self).getCommandHelp(command, simpleSyntax)
Example #20
0
        def random(self, irc, msg, args, optlist):
            """[--allow-english]

            Returns a random language supported by babelfish.  If --allow-english
            is provided, will include English in the list of possible languages.
            """
            allowEnglish = False
            for (option, arg) in optlist:
                if option == 'allow-english':
                    allowEnglish = True
            languages = conf.get(conf.supybot.plugins.Babelfish.languages,
                                 msg.args[0])
            if not languages:
                irc.error('I can\'t speak any other languages.', Raise=True)
            language = utils.iter.choice(languages)
            while not allowEnglish and language == 'English':
                language = utils.iter.choice(languages)
            irc.reply(language)
Example #21
0
    def time(self, irc, msg, args, channel, fmt, beats):
        """[<format>] <beats>

        Returns the current time represented by <beats> in <format>, or
        if <format> is not given, uses the configurable format for the
        current channel.
        """

        if not fmt:
            if channel:
                fmt = conf.get(conf.supybot.reply.format.time, channel)
            else:
                fmt = conf.supybot.reply.format.get('time')

        midnight = arrow.now('UTC+1').replace(hour=0, minute=0, second=0, microsecond=0)
        seconds = float(midnight.strftime('%s')) + (beats * 86.4)

        irc.reply(time_.strftime(fmt, time_.localtime(seconds)))
Example #22
0
        def random(self, irc, msg, args, optlist):
            """[--allow-english]

            Returns a random language supported by babelfish.  If --allow-english
            is provided, will include English in the list of possible languages.
            """
            allowEnglish = False
            for (option, arg) in optlist:
                if option == 'allow-english':
                    allowEnglish = True
            languages = conf.get(conf.supybot.plugins.Babelfish.languages,
                                 msg.args[0])
            if not languages:
                irc.error('I can\'t speak any other languages.', Raise=True)
            language = utils.iter.choice(languages)
            while not allowEnglish and language == 'English':
                language = utils.iter.choice(languages)
            irc.reply(language)
Example #23
0
def getChannelDb(irc, msg, args, state, **kwargs):
    channelSpecific = conf.supybot.databases.plugins.channelSpecific
    try:
        getChannel(irc, msg, args, state, **kwargs)
        channel = channelSpecific.getChannelLink(state.channel)
        state.channel = channel
        state.args[-1] = channel
    except (callbacks.ArgumentError, IndexError):
        if channelSpecific():
            raise
        channel = channelSpecific.link()
        if not conf.get(channelSpecific.link.allow, channel):
            log.warning('channelSpecific.link is globally set to %s, but '
                        '%s disallowed linking to its db.', channel, channel)
            raise
        else:
            channel = channelSpecific.getChannelLink(channel)
            state.channel = channel
            state.args.append(channel)
Example #24
0
def getChannelDb(irc, msg, args, state, **kwargs):
    channelSpecific = conf.supybot.databases.plugins.channelSpecific
    try:
        getChannel(irc, msg, args, state, **kwargs)
        channel = channelSpecific.getChannelLink(state.channel)
        state.channel = channel
        state.args[-1] = channel
    except (callbacks.ArgumentError, IndexError):
        if channelSpecific():
            raise
        channel = channelSpecific.link()
        if not conf.get(channelSpecific.link.allow, channel):
            log.warning(
                'channelSpecific.link is globally set to %s, but '
                '%s disallowed linking to its db.', channel, channel)
            raise
        else:
            channel = channelSpecific.getChannelLink(channel)
            state.channel = channel
            state.args.append(channel)
Example #25
0
    def getIssue(self, irc, msg, match):
        """Get a Jira Issue"""
        if not ircutils.isChannel(msg.args[0]):
            return
        if conf.get(conf.supybot.plugins.Jira.lookup, msg.args[0]) == False:
            return
        issueName = match.group('issue')
        try:
            issue = self.jira[self.user].issue(issueName)
        except:
            irc.reply("Cannot find %s bug." % issueName)
            print "Invalid Jira snarf: %s" % issueName
            return

        if issue:
            try:
                assignee = issue.fields.assignee.displayName
            except:
                assignee = "Unassigned"

            try:
                time = issue.fields.timeestimate
                hours = time / 60 / 60
                minutes = time / 60 % 60
                displayTime = " / %ih%im" % (hours, minutes)
            except:
                displayTime = ""

            url = ''.join((self.server, '/browse/', issue.key))

            values = {  "type": issue.fields.issuetype.name,
                        "key": issue.key,
                        "summary": issue.fields.summary,
                        "status": _c(_b(issue.fields.status.name), "green"),
                        "assignee": _c(assignee, "light blue"),
                        "displayTime": displayTime,
                        "url": url,
                    }

            replytext = (self.template % values)
            irc.reply(replytext, prefixNick=False)
Example #26
0
        def wunder(self, irc, msg, args, loc):
            """<US zip code | US/Canada city, state | Foreign city, country>

            Returns the approximate weather conditions for a given city.
            """
            url = '%s%s' % (self._wunderUrl, utils.web.urlquote(loc))
            text = utils.web.getUrl(url, headers=Weather.headers)
            if 'Search not found' in text or \
               re.search(r'size="2"> Place </font>', text, re.I):
                Weather._noLocation()
            if 'Place: Temperature' in text:
                m = self._backupUrl.search(text)
                if m is not None:
                    url = 'http://www.wunderground.com' + m.group(1)
                    text = utils.web.getUrl(url, headers=Weather.headers)
                    self._rss(irc, text)
                    return
            severe = ''
            m = self._wunderSevere.search(text)
            if m:
                severe = ircutils.bold(format('  %s', m.group(1)))
            soup = BeautifulSoup.BeautifulSoup()
            soup.feed(text)
            # Get the table with all the weather info
            table = soup.first('table', {'border':'1'})
            if not table:
                Weather._noLocation()
            trs = table.fetch('tr')
            (time, location) = trs.pop(0).fetch('b')
            time = time.string
            location = location.string
            info = {}
            def isText(t):
                return not isinstance(t, BeautifulSoup.NavigableText) \
                       and t.contents
            def getText(t):
                s = t.string
                if s is BeautifulSoup.Null:
                    t = t.contents
                    num = t[0].string
                    units = t[1].string
                    # htmlToText strips leading whitespace, so we have to
                    # handle strings with &nbsp; differently.
                    if units.startswith('&nbsp;'):
                        units = utils.web.htmlToText(units)
                        s = ' '.join((num, units))
                    else:
                        units = utils.web.htmlToText(units)
                        s = ' '.join((num, units[0], units[1:]))
                return s
            for tr in trs:
                k = tr.td.string
                v = filter(isText, tr.fetch('td')[1].contents)
                value = map(getText, v)
                info[k] = ' '.join(value)
            temp = info['Temperature']
            convert = conf.get(conf.supybot.plugins.Weather.convert,
                               msg.args[0])
            if location and temp:
                (temp, deg, unit) = temp.split()[3:] # We only want temp format
                if convert:
                    temp = Weather._getTemp(float(temp), deg, unit, msg.args[0])
                else:
                    temp = deg.join((temp, unit))
                resp = ['The current temperature in %s is %s (%s).' %\
                        (location, temp, time)]
                conds = info['Conditions']
                resp.append('Conditions: %s.' % info['Conditions'])
                humidity = info['Humidity']
                resp.append('Humidity: %s.' % info['Humidity'])
                # Apparently, the "Dew Point" and "Wind" categories are
                # occasionally set to "-" instead of an actual reading. So,
                # we'll just catch the ValueError from trying to unpack a tuple
                # of the wrong size.
                try:
                    (dew, deg, unit) = info['Dew Point'].split()[3:]
                    if convert:
                        dew = Weather._getTemp(float(dew), deg,
                                               unit, msg.args[0])
                    else:
                        dew = deg.join((dew, unit))
                    resp.append('Dew Point: %s.' % dew)
                except (ValueError, KeyError):
                    pass
                try:
                    wind = 'Wind: %s at %s %s.' % tuple(info['Wind'].split())
                    resp.append(wind)
                except (ValueError, TypeError):
                    pass
                try:
                    (chill, deg, unit) = info['Windchill'].split()[3:]
                    if convert:
                        chill = Weather._getTemp(float(chill), deg,
                                                 unit, msg.args[0])
                    else:
                        dew = deg.join((chill, unit))
                    resp.append('Windchill: %s.' % chill)
                except (ValueError, KeyError):
                    pass
                if info['Pressure']:
                    resp.append('Pressure: %s.' % info['Pressure'])
                resp.append(severe)
                resp = map(utils.web.htmlToText, resp)
                irc.reply(' '.join(resp))
            else:
                Weather._noLocation()
Example #27
0
 def invalidCommand(self, irc, msg, tokens):
     assert not msg.repliedTo, "repliedTo msg in Misc.invalidCommand."
     assert self is irc.callbacks[-1], "Misc isn't last callback."
     assert msg.command in ("PRIVMSG", "NOTICE")
     self.log.debug("Misc.invalidCommand called (tokens %s)", tokens)
     # First, we check for invalidCommand floods.  This is rightfully done
     # here since this will be the last invalidCommand called, and thus it
     # will only be called if this is *truly* an invalid command.
     maximum = conf.supybot.abuse.flood.command.invalid.maximum()
     self.invalidCommands.enqueue(msg)
     if (
         self.invalidCommands.len(msg) > maximum
         and conf.supybot.abuse.flood.command.invalid()
         and not ircdb.checkCapability(msg.prefix, "owner")
     ):
         punishment = conf.supybot.abuse.flood.command.invalid.punishment()
         banmask = "*!%s@%s" % (msg.user, msg.host)
         self.log.info(
             "Ignoring %s for %s seconds due to an apparent " "invalid command flood.", banmask, punishment
         )
         if tokens and tokens[0] == "Error:":
             self.log.warning(
                 "Apparent error loop with another Supybot " "observed.  Consider ignoring this bot " "permanently."
             )
         ircdb.ignores.add(banmask, time.time() + punishment)
         if conf.supybot.abuse.flood.command.invalid.notify():
             irc.reply(
                 _("You've given me %s invalid commands within the last " "%i seconds; I'm now ignoring you for %s.")
                 % (maximum, conf.supybot.abuse.flood.interval(), utils.timeElapsed(punishment, seconds=False))
             )
         return
     # Now, for normal handling.
     channel = msg.args[0]
     # Only bother with the invaildCommand flood handling if it's actually
     # enabled
     if conf.supybot.abuse.flood.command.invalid():
         # First, we check for invalidCommand floods.  This is rightfully done
         # here since this will be the last invalidCommand called, and thus it
         # will only be called if this is *truly* an invalid command.
         maximum = conf.supybot.abuse.flood.command.invalid.maximum()
         banmasker = conf.supybot.protocols.irc.banmask.makeBanmask
         self.invalidCommands.enqueue(msg)
         if (
             self.invalidCommands.len(msg) > maximum
             and not ircdb.checkCapability(msg.prefix, "owner")
             and msg.prefix != irc.prefix
             and ircutils.isUserHostmask(msg.prefix)
         ):
             penalty = conf.supybot.abuse.flood.command.invalid.punishment()
             banmask = banmasker(msg.prefix, channel=None)
             self.log.info(
                 "Ignoring %s for %s seconds due to an apparent " "invalid command flood.", banmask, penalty
             )
             if tokens and tokens[0] == "Error:":
                 self.log.warning(
                     "Apparent error loop with another Supybot "
                     "observed.  Consider ignoring this bot "
                     "permanently."
                 )
             ircdb.ignores.add(banmask, time.time() + penalty)
             if conf.supybot.abuse.flood.command.invalid.notify():
                 irc.reply(
                     "You've given me %s invalid commands within "
                     "the last minute; I'm now ignoring you for %s."
                     % (maximum, utils.timeElapsed(penalty, seconds=False))
                 )
             return
     # Now, for normal handling.
     if conf.get(conf.supybot.reply.whenNotCommand, channel):
         if len(tokens) >= 2:
             cb = irc.getCallback(tokens[0])
             if cb:
                 plugin = cb.name()
                 irc.error(
                     format(
                         _(
                             "The %q plugin is loaded, but there is "
                             'no command named %q in it.  Try "list '
                             '%s" to see the commands in the %q '
                             "plugin."
                         ),
                         plugin,
                         tokens[1],
                         plugin,
                         plugin,
                     )
                 )
             else:
                 irc.errorInvalid(_("command"), tokens[0], repr=False)
         else:
             command = tokens and tokens[0] or ""
             irc.errorInvalid(_("command"), command, repr=False)
     else:
         if tokens:
             # echo [] will get us an empty token set, but there's no need
             # to log this in that case anyway, it being a nested command.
             self.log.info("Not replying to %s, not a command.", tokens[0])
         if irc.nested:
             bracketConfig = conf.supybot.commands.nested.brackets
             brackets = conf.get(bracketConfig, channel)
             if brackets:
                 (left, right) = brackets
                 irc.reply(left + " ".join(tokens) + right)
             else:
                 pass  # Let's just do nothing, I can't think of better.
Example #28
0
        def wunder(self, irc, msg, args, loc):
            """<US zip code | US/Canada city, state | Foreign city, country>

            Returns the approximate weather conditions for a given city.
            """
            url = '%s%s' % (self._wunderUrl, utils.web.urlquote(loc))
            text = utils.web.getUrl(url, headers=Weather.headers)
            if 'Search not found' in text or \
               re.search(r'size="2"> Place </font>', text, re.I):
                Weather._noLocation()
            if 'Place: Temperature' in text:
                m = self._backupUrl.search(text)
                if m is not None:
                    url = 'http://www.wunderground.com' + m.group(1)
                    text = utils.web.getUrl(url, headers=Weather.headers)
                    self._rss(irc, text)
                    return
            severe = ''
            m = self._wunderSevere.search(text)
            if m:
                severe = ircutils.bold(format('  %s', m.group(1)))
            soup = BeautifulSoup.BeautifulSoup()
            soup.feed(text)
            # Get the table with all the weather info
            table = soup.first('table', {'border':'1'})
            if table is BeautifulSoup.Null:
                Weather._noLocation()
            trs = table.fetch('tr')
            try:
                time = trs.pop(0).b.string
            except AttributeError:
                time = ''
            info = {}
            def isText(t):
                return not isinstance(t, BeautifulSoup.NavigableText) \
                       and t.contents
            def getText(t):
                s = t.string
                if s is BeautifulSoup.Null:
                    t = t.contents
                    num = t[0].string
                    units = t[1].string
                    # htmlToText strips leading whitespace, so we have to
                    # handle strings with &nbsp; differently.
                    if units.startswith('&nbsp;'):
                        units = utils.web.htmlToText(units)
                        s = ' '.join((num, units))
                    else:
                        units = utils.web.htmlToText(units)
                        s = ' '.join((num, units[0], units[1:]))
                return s
            for tr in trs:
                k = tr.td.string
                v = filter(isText, tr.fetch('td')[1].contents)
                value = map(getText, v)
                info[k] = ' '.join(value)
            location = self._wunderLoc.search(text)
            temp = info['Temperature']
            convert = conf.get(conf.supybot.plugins.Weather.convert,
                               msg.args[0])
            if location and temp:
                (temp, deg, unit) = temp.split()[3:] # We only want temp format
                if convert:
                    temp = Weather._getTemp(int(temp), deg, unit, msg.args[0])
                else:
                    temp = deg.join((temp, unit))
                resp = ['The current temperature in %s is %s (%s).' %\
                        (location.group(1), temp, time)]
                conds = info['Conditions']
                resp.append('Conditions: %s.' % info['Conditions'])
                humidity = info['Humidity']
                resp.append('Humidity: %s.' % info['Humidity'])
                # Apparently, the "Dew Point" and "Wind" categories are
                # occasionally set to "-" instead of an actual reading. So,
                # we'll just catch the ValueError from trying to unpack a tuple
                # of the wrong size.
                try:
                    (dew, deg, unit) = info['Dew Point'].split()[3:]
                    if convert:
                        dew = Weather._getTemp(int(dew), deg,
                                               unit, msg.args[0])
                    else:
                        dew = deg.join((dew, unit))
                    resp.append('Dew Point: %s.' % dew)
                except (ValueError, KeyError):
                    pass
                try:
                    wind = 'Wind: %s at %s %s.' % tuple(info['Wind'].split())
                    resp.append(wind)
                except (ValueError, TypeError):
                    pass
                try:
                    (chill, deg, unit) = info['Windchill'].split()[3:]
                    if convert:
                        chill = Weather._getTemp(int(chill), deg,
                                                 unit, msg.args[0])
                    else:
                        dew = deg.join((chill, unit))
                    resp.append('Windchill: %s.' % chill)
                except (ValueError, KeyError):
                    pass
                if info['Pressure']:
                    resp.append('Pressure: %s.' % info['Pressure'])
                if info['Visibility']:
                    resp.append('Visibility: %s.' % info['Visibility'])
                resp.append(severe)
                resp = map(utils.web.htmlToText, resp)
                irc.reply(' '.join(resp))
            else:
                irc.error('Could not find weather information.')