def _seen(self, irc, channel, name, any=False): if any: db = self.anydb else: db = self.db try: results = [] if '*' in name: results = db.seenWildcard(channel, name) else: results = [[name, db.seen(channel, name)]] if len(results) == 1: (nick, info) = results[0] (when, said) = info irc.reply(format('%s was last seen in %s %s ago: %s', nick, channel, utils.timeElapsed(time.time()-when), said)) elif len(results) > 1: L = [] for (nick, info) in results: (when, said) = info L.append(format('%s (%s ago)', nick, utils.timeElapsed(time.time()-when))) irc.reply(format('%s could be %L', name, (L, 'or'))) else: irc.reply(format('I haven\'t seen anyone matching %s.', name)) except KeyError: irc.reply(format('I have not seen %s.', name))
def _seen(self, irc, channel, name, any=False): if any: db = self.anydb else: db = self.db try: results = [] if '*' in name: if (len(name.replace('*', '')) < self.registryValue('minimumNonWildcard', channel)): irc.error(_('Not enough non-wildcard characters.'), Raise=True) results = db.seenWildcard(channel, name) else: results = [[name, db.seen(channel, name)]] if len(results) == 1: (nick, info) = results[0] (when, said) = info irc.reply(format(_('%s was last seen in %s %s ago: %s'), nick, channel, utils.timeElapsed(time.time()-when), said)) elif len(results) > 1: L = [] for (nick, info) in results: (when, said) = info L.append(format(_('%s (%s ago)'), nick, utils.timeElapsed(time.time()-when))) irc.reply(format(_('%s could be %L'), name, (L, _('or')))) else: irc.reply(format(_('I haven\'t seen anyone matching %s.'), name)) except KeyError: irc.reply(format(_('I have not seen %s.'), name))
def elapsed(self, irc, msg, args, seconds): """<seconds> Returns a pretty string that is the amount of time represented by <seconds>. """ irc.reply(utils.timeElapsed(seconds))
def info(self, irc, msg, args, url): """<url|feed> Returns information from the given RSS feed, namely the title, URL, description, and last update date, if available. """ try: url = self.registryValue("feeds.%s" % url) except registry.NonExistentRegistryEntry: pass feed = self.getFeed(url) conv = self._getConverter(feed) info = feed.get("feed") if not info: irc.error("I couldn't retrieve that RSS feed.") return # check the 'modified_parsed' key, if it's there, convert it here first if "modified" in info: seconds = time.mktime(info["modified_parsed"]) now = time.mktime(time.gmtime()) when = utils.timeElapsed(now - seconds) + " ago" else: when = "time unavailable" title = conv(info.get("title", "unavailable")) desc = conv(info.get("description", "unavailable")) link = conv(info.get("link", "unavailable")) # The rest of the entries are all available in the channel key response = format("Title: %s; URL: %u; " "Description: %s; Last updated: %s.", title, link, desc, when) irc.reply(utils.str.normalizeWhitespace(response))
def info(self, irc, msg, args, url): """<url|feed> Returns information from the given RSS feed, namely the title, URL, description, and last update date, if available. """ try: url = self.registryValue('feeds.%s' % url) except registry.NonExistentRegistryEntry: pass feed = self.get_feed(url) if not feed: feed = Feed(url, url, True) self.update_feed_if_needed(feed) info = feed.data if not info: irc.error(_('I couldn\'t retrieve that RSS feed.')) return # check the 'modified_parsed' key, if it's there, convert it here first if 'modified' in info: seconds = time.mktime(info['modified_parsed']) now = time.mktime(time.gmtime()) when = utils.timeElapsed(now - seconds) + ' ago' else: when = _('time unavailable') title = info.get('title', _('unavailable')) desc = info.get('description', _('unavailable')) link = info.get('link', _('unavailable')) # The rest of the entries are all available in the channel key response = format(_('Title: %s; URL: %u; ' 'Description: %s; Last updated: %s.'), title, link, desc, when) irc.reply(utils.str.normalizeWhitespace(response))
def _timestamp(self, when): #format = conf.supybot.reply.format.time() diff = when - time.time() try: return utils.timeElapsed(diff, seconds=False) except ValueError: return _('just now')
def doPrivmsg(self, irc, msg): assert self is irc.callbacks[0], \ 'Owner isn\'t first callback: %r' % irc.callbacks if ircmsgs.isCtcp(msg): return s = callbacks.addressed(irc.nick, msg) if s: ignored = ircdb.checkIgnored(msg.prefix) if ignored: self.log.info('Ignoring command from %s.', msg.prefix) return maximum = conf.supybot.abuse.flood.command.maximum() self.commands.enqueue(msg) if conf.supybot.abuse.flood.command() \ and self.commands.len(msg) > maximum \ and not ircdb.checkCapability(msg.prefix, 'trusted'): punishment = conf.supybot.abuse.flood.command.punishment() banmask = ircutils.banmask(msg.prefix) self.log.info('Ignoring %s for %s seconds due to an apparent ' 'command flood.', banmask, punishment) ircdb.ignores.add(banmask, time.time() + punishment) irc.reply('You\'ve given me %s commands within the last ' 'minute; I\'m now ignoring you for %s.' % (maximum, utils.timeElapsed(punishment, seconds=False))) return try: tokens = callbacks.tokenize(s, channel=msg.args[0]) self.Proxy(irc, msg, tokens) except SyntaxError, e: irc.queueMsg(callbacks.error(msg, str(e)))
def uptime(self, irc, msg, args): """takes no arguments Returns the amount of time the bot has been running. """ response = _("I have been running for %s.") % utils.timeElapsed(time.time() - world.startedAt) irc.reply(response)
def net(self, irc, msg, args): """takes no arguments Returns some interesting network-related statistics. """ try: elapsed = time.time() - self.connected[irc.getRealIrc()] timeElapsed = utils.timeElapsed(elapsed) except KeyError: timeElapsed = _("an indeterminate amount of time") irc.reply( format( _( "I have received %s messages for a total of %S. " "I have sent %s messages for a total of %S. " "I have been connected to %s for %s." ), self.recvdMsgs, self.recvdBytes, self.sentMsgs, self.sentBytes, irc.server, timeElapsed, ) )
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.
def bcstats(self, irc, msg, args): """takes no arguments Shows a number of statistics about the state of the block chain. """ blocks = self._blocks() diff = self._diff() try: estimate = self._nethashsincelast() * 139.696254564 except: estimate = None try: diffchange = round((estimate/float(diff) - 1) * 100, 5) except: diffchange = None nextretarget = self._nextretarget() try: blockstoretarget = int(nextretarget) - int(blocks) except: blockstoretarget = None try: timetonext = utils.timeElapsed(self._timetonext()) except: timetonext = None irc.reply("Current Blocks: %s | Current Difficulty: %s | " "Next Difficulty At Block: %s | " "Next Difficulty In: %s blocks | " "Next Difficulty In About: %s | " "Next Difficulty Estimate: %s | " "Estimated Percent Change: %s" % (blocks, diff, nextretarget, blockstoretarget, timetonext, estimate, diffchange))
def _timestamp(self, when): # format = conf.supybot.reply.format.time() diff = time.time() - when try: return _("%s ago") % utils.timeElapsed(diff, seconds=False) except ValueError: return _("just now")
def tblb(self, irc, msg, args, interval): """<interval> Calculate the expected time between blocks which take at least <interval> seconds to create. To provide the <interval> argument, a nested 'seconds' command may be helpful. """ try: difficulty = float(self._diff()) nh = float(self._nethash3d()) gp = self._genprob(nh*1000, interval, difficulty) except: irc.error("Problem retrieving data. Try again later.") return sblb = (difficulty * 2**48 / 65535) / (nh * 1e9) / (1 - gp) irc.reply("The expected time between blocks taking %s to generate is %s" % \ (utils.timeElapsed(interval), utils.timeElapsed(sblb),))
def _formatNote(self, note, to): elapsed = utils.timeElapsed(time.time() - note.at) if note.to == to: author = plugins.getUserName(note.frm) return format("#%i: %s (Sent by %s %s ago)", note.id, note.text, author, elapsed) else: assert note.frm == to, "Odd, userid isn't frm either." recipient = plugins.getUserName(note.to) return format("#%i: %s (Sent to %s %s ago)", note.id, note.text, recipient, elapsed)
def uptime(self, irc, msg, args, otherIrc): """[<network>] Returns the time duration since the connection was established. """ network = otherIrc.network now = time.time() started = otherIrc.startedAt irc.reply(_("I've been connected to %s for %s.") % (network, utils.timeElapsed(now - started)))
def uptime(self, irc, msg, args, otherIrc): """[<network>] Returns the time duration since the connection was established. """ network = otherIrc.network now = time.time() started = otherIrc.startedAt irc.reply( _("I've been connected to %s for %s.") % (network, utils.timeElapsed(now - started)))
def _formatNote(self, note, to): elapsed = utils.timeElapsed(time.time() - note.at) if note.to == to: author = plugins.getUserName(note.frm) return format('#%i: %s (Sent by %s %s ago)', note.id, note.text, author, elapsed) else: assert note.frm == to, 'Odd, userid isn\'t frm either.' recipient = plugins.getUserName(note.to) return format('#%i: %s (Sent to %s %s ago)', note.id, note.text, recipient, elapsed)
def _doPrivmsgs(self, irc, msg): """If the given message is a command, triggers Limnoria's command-dispatching for that command. Takes the same arguments as ``doPrivmsg`` would, but ``msg`` can potentially be an artificial message synthesized in doBatch from a multiline batch. Usually, a command is a single message, so ``payload=msg.params[0]`` However, when ``msg`` is part of a multiline message, the payload is the concatenation of multiple messages. See <https://ircv3.net/specs/extensions/multiline>. """ assert self is irc.callbacks[0], \ 'Owner isn\'t first callback: %r' % irc.callbacks if ircmsgs.isCtcp(msg): return s = callbacks.addressed(irc, msg) if s: ignored = ircdb.checkIgnored(msg.prefix) if ignored: self.log.info('Ignoring command from %s.', msg.prefix) return maximum = conf.supybot.abuse.flood.command.maximum() self.commands.enqueue(msg) if conf.supybot.abuse.flood.command() \ and self.commands.len(msg) > maximum \ and not ircdb.checkCapability(msg.prefix, 'trusted'): punishment = conf.supybot.abuse.flood.command.punishment() banmask = conf.supybot.protocols.irc.banmask \ .makeBanmask(msg.prefix) self.log.info( 'Ignoring %s for %s seconds due to an apparent ' 'command flood.', banmask, punishment) ircdb.ignores.add(banmask, time.time() + punishment) if conf.supybot.abuse.flood.command.notify(): irc.reply('You\'ve given me %s 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 try: tokens = callbacks.tokenize(s, channel=msg.channel, network=irc.network) self.Proxy(irc, msg, tokens) except SyntaxError as e: if conf.supybot.reply.error.detailed(): irc.error(str(e)) else: irc.replyError(msg=msg) self.log.info('Syntax error: %s', e)
def _last(self, irc, channel, any=False): if any: db = self.anydb else: db = self.db try: (when, said) = db.seen(channel, '<last>') irc.reply( format(_('Someone was last seen in %s %s ago: %s'), channel, utils.timeElapsed(time.time() - when), said)) except KeyError: irc.reply(_('I have never seen anyone.'))
def _user(self, irc, channel, user, any=False): if any: db = self.anydb else: db = self.db try: (when, said) = db.seen(channel, user.id) irc.reply( format(_('%s was last seen in %s %s ago: %s'), user.name, channel, utils.timeElapsed(time.time() - when), said)) except KeyError: irc.reply(format(_('I have not seen %s.'), user.name))
def _user(self, irc, channel, user, any=False): if any: db = self.anydb else: db = self.db try: (when, said) = db.seen(channel, user.id) irc.reply(format('%s was last seen in %s %s ago: %s', user.name, channel, utils.timeElapsed(time.time()-when), said)) except KeyError: irc.reply(format('I have not seen %s.', user.name))
def _last(self, irc, channel, any=False): if any: db = self.anydb else: db = self.db try: (when, said) = db.seen(channel, '<last>') irc.reply(format('Someone was last seen in %s %s ago: %s', channel, utils.timeElapsed(time.time()-when), said)) except KeyError: irc.reply('I have never seen anyone.')
def tslb(self, irc, msg, args): """takes no arguments Shows time elapsed since latest generated block. This uses the block timestamp, so may be slightly off clock-time. """ blocknum = self._blocks() block = self._rawblockbynum(blocknum) try: blocktime = block['time'] irc.reply("Time since last block: %s" % utils.timeElapsed(time.time() - blocktime)) except: irc.error("Problem retrieving latest block data.")
def _elapsed(self, current_time, timestamp): """Returns a nice approximation of elapsed time""" delta = int(current_time-timestamp) seconds = minutes = hours = True if delta > 60: seconds = False if delta > 3600: minutes = False if delta > 86400: hours = False return utils.timeElapsed(delta, short=False, leadingZeroes=False, years=True, weeks=True, days=True, hours, minutes, seconds)
def _seen(self, irc, channel, name, any=False): if any: db = self.anydb else: db = self.db try: results = [] if '*' in name: if (len(name.replace('*', '')) < self.registryValue( 'minimumNonWildcard', channel, irc.network)): irc.error(_('Not enough non-wildcard characters.'), Raise=True) results = db.seenWildcard(channel, name) else: results = [[name, db.seen(channel, name)]] if len(results) == 1: (nick, info) = results[0] (when, said) = info reply = format(_('%s was last seen in %s %s ago'), nick, channel, utils.timeElapsed(time.time() - when)) if self.registryValue('showLastMessage', channel, irc.network): if minisix.PY2: said = said.decode('utf8') reply = _('%s: %s') % (reply, said) irc.reply(reply) elif len(results) > 1: L = [] for (nick, info) in results: (when, said) = info L.append( format(_('%s (%s ago)'), nick, utils.timeElapsed(time.time() - when))) irc.reply(format(_('%s could be %L'), name, (L, _('or')))) else: irc.reply( format(_('I haven\'t seen anyone matching %s.'), name)) except KeyError: irc.reply(format(_('I have not seen %s.'), name))
def _user(self, irc, channel, user, any=False): if any: db = self.anydb else: db = self.db try: (when, said) = db.seen(channel, user.id) reply = format(_('%s was last seen in %s %s ago'), user.name, channel, utils.timeElapsed(time.time() - when)) if self.registryValue('showLastMessage', channel, irc.network): reply = _('%s: %s') % (reply, said) irc.reply(reply) except KeyError: irc.reply(format(_('I have not seen %s.'), user.name))
def _last(self, irc, channel, any=False): if any: db = self.anydb else: db = self.db try: (when, said) = db.seen(channel, '<last>') reply = format(_('Someone was last seen in %s %s ago'), channel, utils.timeElapsed(time.time() - when)) if self.registryValue('showLastMessage', channel, irc.network): reply = _('%s: %s') % (reply, said) irc.reply(reply) except KeyError: irc.reply(_('I have never seen anyone.'))
def status(self, irc, msg, args): """ returns bot status""" pending, last_bundle, unconfirmed = self.deeds.status() pending = 'No' if pending == 0 else pending _deeds = 'deed' if pending == 1 else 'deeds' now = int(time.time()) ago = utils.timeElapsed(now - last_bundle, weeks=False, seconds=False, short=True) if last_bundle else 'n/a' txt = '{0} pending {1} | Last bundle {2} ago'.format(pending, _deeds, ago) if unconfirmed: _bundles = 'bundle' if unconfirmed == 1 else 'bundles' txt += ' | {0} unconfirmed {1}'.format(unconfirmed, _bundles) irc.reply(txt)
def _last(self, irc, channel, any=False): if any: db = self.anydb else: db = self.db try: (when, said) = db.seen(channel, '<last>') reply = format(_('Someone was last seen in %s %s ago'), channel, utils.timeElapsed(time.time()-when)) if self.registryValue('showLastMessage', channel): reply = _('%s: %s') % (reply, said) irc.reply(reply) except KeyError: irc.reply(_('I have never seen anyone.'))
def net(self, irc, msg, args): """takes no arguments Returns some interesting network-related statistics. """ try: elapsed = time.time() - self.connected[irc.getRealIrc()] timeElapsed = utils.timeElapsed(elapsed) except KeyError: timeElapsed = _('an indeterminate amount of time') irc.reply(format(_('I have received %s messages for a total of %S. ' 'I have sent %s messages for a total of %S. ' 'I have been connected to %s for %s.'), self.recvdMsgs, self.recvdBytes, self.sentMsgs, self.sentBytes, irc.server, timeElapsed))
def _user(self, irc, channel, user, any=False): if any: db = self.anydb else: db = self.db try: (when, said) = db.seen(channel, user.id) reply = format(_('%s was last seen in %s %s ago'), user.name, channel, utils.timeElapsed(time.time()-when)) if self.registryValue('showLastMessage', channel): reply = _('%s: %s') % (reply, said) irc.reply(reply) except KeyError: irc.reply(format(_('I have not seen %s.'), user.name))
def gentime(self, irc, msg, args, hashrate, difficulty): '''<hashrate> [<difficulty>] Calculate expected time to generate a block using <hashrate> Mhps, at current difficulty. If optional <difficulty> argument is provided, expected generation time is for supplied difficulty. ''' if difficulty is None: try: difficulty = float(self._diff()) except: irc.error("Failed to fetch current difficulty. Try again later or supply difficulty manually.") return gentime = self._gentime(hashrate, difficulty) irc.reply("The average time to generate a block at %s Mhps, given difficulty of %s, is %s" % \ (hashrate, difficulty, utils.timeElapsed(gentime)))
def testTimeElapsed(self): self.assertRaises(ValueError, utils.timeElapsed, 0, leadingZeroes=False, seconds=False) then = 0 now = 0 for now, expected in [(0, '0 seconds'), (1, '1 second'), (60, '1 minute and 0 seconds'), (61, '1 minute and 1 second'), (62, '1 minute and 2 seconds'), (122, '2 minutes and 2 seconds'), (3722, '1 hour, 2 minutes, and 2 seconds'), (7322, '2 hours, 2 minutes, and 2 seconds'), (90061,'1 day, 1 hour, 1 minute, and 1 second'), (180122, '2 days, 2 hours, 2 minutes, ' 'and 2 seconds')]: self.assertEqual(utils.timeElapsed(now - then), expected)
def genprob(self, irc, msg, args, hashrate, interval, difficulty): '''<hashrate> <interval> [<difficulty>] Calculate probability to generate a block using <hashrate> Mhps, in <interval> seconds, at current difficulty. If optional <difficulty> argument is provided, probability is for supplied difficulty. To provide the <interval> argument, a nested 'seconds' command may be helpful. ''' if difficulty is None: try: difficulty = float(self._diff()) except: irc.error("Failed to current difficulty. Try again later or supply difficulty manually.") return gp = self._genprob(hashrate, interval, difficulty) irc.reply("The probability to generate a block at %s Mhps within %s, given difficulty of %s, is %s" % \ (hashrate, utils.timeElapsed(interval), difficulty, gp))
def halfreward(self, irc, msg, args): """takes no arguments Show estimated time of next block bounty halving. """ try: blocks = int(self._blocks()) except: irc.error("Failed to retrieve block count. Try again later.") return halfpoint = 210000 while halfpoint < blocks: halfpoint += 210000 blocksremaining = halfpoint - blocks sectohalve = blocksremaining * 10 * 60 irc.reply("Estimated time of bitcoin block reward halving: %s UTC | Time remaining: %s." % \ (time.asctime(time.gmtime(time.time() + sectohalve)), utils.timeElapsed(sectohalve)))
def _seen(self, irc, msg, channel, nick, findAny): if nick == irc.nick: irc.reply("Of course I've seen myself!") return bufid = self.db.getBuffer(irc.network, channel)["id"] if findAny: entry = self.db.getLast(bufid, nick) else: entry = self.db.getLastMessage(bufid, nick) if not entry: irc.reply("I haven't seen %s in %s." % (nick, channel)) return t = time.time() rpl = "I saw %s in %s %s ago " % ( nick, channel, utils.timeElapsed(t - entry["timestamp"]) ) tp = entry["type"] if tp == MessageType.privmsg or\ tp == MessageType.notice: rpl += "saying \"%s\"" % (entry["message"],) elif tp == MessageType.action: rpl += "saying * %s %s" % (entry["nick"], entry["message"]) elif tp == MessageType.join: rpl += "joining." elif tp == MessageType.part: rpl += "parting (%s)." % (entry["message"],) elif tp == MessageType.quit: rpl += "quiting" if entry["message"] != "": rpl += " (%s)" % (entry["message"],) rpl += "." elif tp == MessageType.kick: kicked, space, reason = entry["message"].partition(" ") rpl += "kicking %s (%s)." % (kicked, reason) elif tp == MessageType.nick: rpl += "changing nick to %s." % (entry["message"],) elif tp == MessageType.mode: rpl += "setting mode(s) %s." % (entry["message"],) elif tp == MessageType.topic: rpl += "setting the topic to \"%s\"" % (entry["message"],) else: rpl += "doing who knows what." irc.reply(rpl)
def seen(self, irc, msg, network, channel, nick): """[channel] <nick> Finds the last time a nick was seen and what they said. """ if nick == irc.nick: irc.reply("Of course I've seen myself!") return entry = self.getChan(irc.network, channel, nick) if not entry: irc.reply("I haven't seen %s in %s." % (nick, channel)) return t = time.time() irc.reply("I saw %s in %s %s ago saying \"%s\"." % ( nick, entry.channel.name, utils.timeElapsed(t - entry.timestamp), entry.message))
def _checkForAnnouncements(self, irc): start = time.time() self.log.info('Checking mailbox for announcements.') pop = self._getPop(irc) i = None for (i, msg) in self._getMsgs(pop): message = rfc822.Message(sio(msg)) frm = message.get('From') if not frm: self.log.warning('Received message without From header.') continue else: frm = frm.rstrip() subject = message.get('Subject', '').rstrip() content = message.fp.read() self.log.info('Received message with subject %q from %q.', subject, frm) if subject == 'all': channels = list(irc.state.channels) else: channels = subject.split() if not channels or not all(irc.isChannel, channels): channels = list(self.registryValue('defaultChannels')) if subject: content = '%s: %s' % (subject, content) if not channels: self.log.info('Received message with improper subject ' 'line from %s.', frm) continue prefix = self.registryValue('prefix') content = utils.str.normalizeWhitespace(content) self.log.info('Making announcement to %L.', channels) chunks = textwrap.wrap(content, 350) for channel in channels: if channel in irc.state.channels: maximum = self.registryValue('limit', channel) for chunk in chunks[:maximum]: s = self._formatChunk( self._formatPrefix(prefix + " ")+chunk) irc.queueMsg(ircmsgs.privmsg(channel, s)) prefix = '' self._quit(pop) self.log.info('Finished checking mailbox, time elapsed: %s', utils.timeElapsed(time.time() - start))
def remind(self, irc, msg, args, a): """[me|<who>] [in] <time> [of|to] <what> Reminds people of something in a set time. <who> must be an IRC nickname; default is yourself. <time> must be a string describing time, such as 2 hr 30 min 15 s. <what> is what to be reminded of. """ tname = irc.msg.nick ttime = 0 twhat = 'reminder!' # begin parsing i = 0 if i < len(a) and not (a[i] == 'in' or a[i] == 'of' or a[i] == 'to' or self._isNumber(a[i])): if a[i] != 'me': tname = a[i] i += 1 if i < len(a) and a[i] == 'in': i += 1 while i < len(a) and self._isNumber(a[i]): v = int(a[i]) i += 1 m = 60 if i < len(a): m = self._getMultiplier(a[i]) if m > 0: i += 1 else: m = 60 ttime += v * m if i < len(a) and (a[i] == 'of' or a[i] == 'to'): i += 1 if i < len(a): twhat = ' '.join(a[i:len(a)]) # end parsing f = self._makeRemindFunction(irc, msg, tname, twhat) id = schedule.addEvent(f, time.time() + ttime) f.eventId = id self.events[str(id)] = tname + ': ' + twhat irc.reply('Okay, will remind in ' + utils.timeElapsed(ttime) + ' (id: ' + str(id) + ')')
def stats(self, irc, msg, args, channel): """[<channel>] Returns the number of changes and requests made to the Infobot database since the plugin was loaded. <channel> is only necessary if the message isn't in the channel itself. """ changes = self.db.getChangeCount(channel) responses = self.db.getResponseCount(channel) now = time.time() diff = int(now - world.startedAt) mode = {True: 'optional', False: 'require'} answer = self.registryValue('unaddressed.answerQuestions') irc.reply( format( 'Since %s, there %h been %n and %n. I have been awake' ' for %s this session, and currently reference %n. ' 'Addressing is in %s mode.', time.ctime(world.startedAt), changes, (changes, 'modification'), (responses, 'question'), utils.timeElapsed(int(now - world.startedAt)), (self.db.getNumFacts(channel), 'factoid'), mode[answer]))
def stats(self, irc, msg, args, channel): """[<channel>] Returns the number of changes and requests made to the Infobot database since the plugin was loaded. <channel> is only necessary if the message isn't in the channel itself. """ changes = self.db.getChangeCount(channel) responses = self.db.getResponseCount(channel) now = time.time() diff = int(now - world.startedAt) mode = {True: 'optional', False: 'require'} answer = self.registryValue('unaddressed.answerQuestions') irc.reply(format('Since %s, there %h been %n and %n. I have been awake' ' for %s this session, and currently reference %n. ' 'Addressing is in %s mode.', time.ctime(world.startedAt), changes, (changes, 'modification'), (responses, 'question'), utils.timeElapsed(int(now - world.startedAt)), (self.db.getNumFacts(channel), 'factoid'), mode[answer]))
def doPrivmsg(self, irc, msg): assert self is irc.callbacks[0], \ 'Owner isn\'t first callback: %r' % irc.callbacks if ircmsgs.isCtcp(msg): return s = callbacks.addressed(irc, msg) if s: ignored = ircdb.checkIgnored(msg.prefix) if ignored: self.log.info('Ignoring command from %s.', msg.prefix) return maximum = conf.supybot.abuse.flood.command.maximum() self.commands.enqueue(msg) if conf.supybot.abuse.flood.command() \ and self.commands.len(msg) > maximum \ and not ircdb.checkCapability(msg.prefix, 'trusted'): punishment = conf.supybot.abuse.flood.command.punishment() banmask = conf.supybot.protocols.irc.banmask \ .makeBanmask(msg.prefix) self.log.info( 'Ignoring %s for %s seconds due to an apparent ' 'command flood.', banmask, punishment) ircdb.ignores.add(banmask, time.time() + punishment) if conf.supybot.abuse.flood.command.notify(): irc.reply('You\'ve given me %s 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 try: tokens = callbacks.tokenize(s, channel=msg.channel, network=irc.network) self.Proxy(irc, msg, tokens) except SyntaxError as e: if conf.supybot.reply.error.detailed(): irc.error(str(e)) else: irc.replyError(msg=msg) self.log.info('Syntax error: %s', e)
def do318(self, irc, msg): irc = self._getRealIrc(irc) nick = msg.args[1] loweredNick = ircutils.toLower(nick) if (irc, loweredNick) not in self._whois: return (replyIrc, replyMsg, d) = self._whois[(irc, loweredNick)] hostmask = '@'.join(d['311'].args[2:4]) user = d['311'].args[-1] if '319' in d: channels = d['319'].args[-1].split() ops = [] voices = [] normal = [] halfops = [] for channel in channels: if channel.startswith('@'): ops.append(channel[1:]) elif channel.startswith('%'): halfops.append(channel[1:]) elif channel.startswith('+'): voices.append(channel[1:]) else: normal.append(channel) L = [] if ops: L.append(format(_('is an op on %L'), ops)) if halfops: L.append(format(_('is a halfop on %L'), halfups)) if voices: L.append(format(_('is voiced on %L'), voices)) if normal: if L: L.append(format(_('is also on %L'), normal)) else: L.append(format(_('is on %L'), normal)) else: L = [_('isn\'t on any non-secret channels')] channels = format('%L', L) if '317' in d: idle = utils.timeElapsed(d['317'].args[2]) signon = time.strftime(conf.supybot.reply.format.time(), time.localtime(float(d['317'].args[3]))) else: idle = _('<unknown>') signon = _('<unknown>') if '312' in d: server = d['312'].args[2] else: server = _('<unknown>') if '301' in d: away = format(_(' %s is away: %s.'), nick, d['301'].args[2]) else: away = '' if '320' in d: if d['320'].args[2]: identify = _(' identified') else: identify = '' else: identify = '' s = format(_('%s (%s) has been%s on server %s since %s (idle for %s) ' 'and %s.%s'), user, hostmask, identify, server, signon, idle, channels, away) replyIrc.reply(s) del self._whois[(irc, loweredNick)]
def do318(self, irc, msg): nick = msg.args[1] loweredNick = ircutils.toLower(nick) if (irc, loweredNick) not in self._whois: return (replyIrc, replyMsg, d) = self._whois[(irc, loweredNick)] hostmask = '@'.join(d['311'].args[2:4]) user = d['311'].args[-1] if '319' in d: channels = d['319'].args[-1].split() ops = [] voices = [] normal = [] halfops = [] for channel in channels: chan = irc.state.channels.get(channel) if chan: # Skip channels the callee isn't in. This helps prevents # us leaking information when the channel is +s or the # target is +i if replyMsg.nick not in chan.users: continue # Skip +s channels the target is in only if the reply isn't # being sent to that channel if 's' in chan.modes and \ not ircutils.strEqual(replyMsg.args[0], channel): continue if channel.startswith('@'): ops.append(channel[1:]) elif channel.startswith('%'): halfops.append(channel[1:]) elif channel.startswith('+'): voices.append(channel[1:]) else: normal.append(channel) L = [] if ops: L.append(format('is an op on %L', ops)) if halfops: L.append(format('is a halfop on %L', halfops)) if voices: L.append(format('is voiced on %L', voices)) if normal: if L: L.append(format('is also on %L', normal)) else: L.append(format('is on %L', normal)) else: L = ['isn\'t on any non-secret channels'] channels = format('%L', L) if '317' in d: idle = utils.timeElapsed(d['317'].args[2]) signon = time.strftime(conf.supybot.reply.format.time(), time.localtime(float(d['317'].args[3]))) else: idle = '<unknown>' signon = '<unknown>' if '312' in d: server = d['312'].args[2] else: server = '<unknown>' if '301' in d: away = ' %s is away: %s.' % (nick, d['301'].args[2]) else: away = '' if '320' in d: if d['320'].args[2]: identify = ' identified' else: identify = '' else: identify = '' s = '%s (%s) has been%s on server %s since %s (idle for %s) and ' \ '%s.%s' % (user, hostmask, identify, server, signon, idle, channels, away) replyIrc.reply(s) del self._whois[(irc, loweredNick)]
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, 'trusted'): 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.channel # 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 if self.invalidCommands.len(msg) > maximum and \ not ircdb.checkCapability(msg.prefix, 'trusted') and \ msg.prefix != irc.prefix and \ ircutils.isUserHostmask(msg.prefix): penalty = conf.supybot.abuse.flood.command.invalid.punishment() banmask = banmasker(msg.prefix, channel=channel, network=irc.network) 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.supybot.reply.whenNotCommand.getSpecific(irc.network, 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 in %s, not a command.', tokens[0], channel if channel != irc.nick else _('private')) if irc.nested: bracketConfig = conf.supybot.commands.nested.brackets brackets = bracketConfig.getSpecific(irc.network, 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.
def timeElapsedShort(self): self.assertEqual(utils.timeElapsed(123, short=True), '2m 3s')
def do318(self, irc, msg): nick = msg.args[1] loweredNick = ircutils.toLower(nick) if (irc, loweredNick) not in self._whois: return (replyIrc, replyMsg, d, command) = self._whois[(irc, loweredNick)] START_CODE = '311' if command == 'whois' else '314' hostmask = '@'.join(d[START_CODE].args[2:4]) user = d[START_CODE].args[-1] if '319' in d: channels = d['319'].args[-1].split() ops = [] voices = [] normal = [] halfops = [] for channel in channels: origchan = channel channel = channel.lstrip('@%+~!') # UnrealIRCd uses & for user modes and disallows it as a # channel-prefix, flying in the face of the RFC. Have to # handle this specially when processing WHOIS response. testchan = channel.lstrip('&') if testchan != channel and irc.isChannel(testchan): channel = testchan diff = len(channel) - len(origchan) modes = origchan[:diff] chan = irc.state.channels.get(channel) # The user is in a channel the bot is in, so the ircd may have # responded with otherwise private data. if chan: # Skip channels the callee isn't in. This helps prevents # us leaking information when the channel is +s or the # target is +i if replyMsg.nick not in chan.users: continue # Skip +s channels the target is in only if the reply isn't # being sent to that channel if 's' in chan.modes and \ not ircutils.strEqual(replyMsg.args[0], channel): continue if not modes: normal.append(channel) elif utils.iter.any(lambda c: c in modes, ('@', '&', '~', '!')): ops.append(channel) elif utils.iter.any(lambda c: c in modes, ('%', )): halfops.append(channel) elif utils.iter.any(lambda c: c in modes, ('+', )): voices.append(channel) L = [] if ops: L.append(format(_('is an op on %L'), ops)) if halfops: L.append(format(_('is a halfop on %L'), halfops)) if voices: L.append(format(_('is voiced on %L'), voices)) if normal: if L: L.append(format(_('is also on %L'), normal)) else: L.append(format(_('is on %L'), normal)) else: if command == 'whois': L = [_('isn\'t on any non-secret channels')] else: L = [] channels = format('%L', L) if '317' in d: idle = utils.timeElapsed(d['317'].args[2]) signon = time.strftime(conf.supybot.reply.format.time(), time.localtime(float(d['317'].args[3]))) else: idle = _('<unknown>') signon = _('<unknown>') if '312' in d: server = d['312'].args[2] if len(d['312']) > 3: signoff = d['312'].args[3] else: server = _('<unknown>') if '301' in d: away = ' %s is away: %s.' % (nick, d['301'].args[2]) else: away = '' if '320' in d: if d['320'].args[2]: identify = _(' identified') else: identify = '' else: identify = '' if command == 'whois': s = _('%s (%s) has been%s on server %s since %s (idle for %s) and ' '%s.%s') % (user, hostmask, identify, server, signon, idle, channels, away) else: s = _('%s (%s) has been%s on server %s and disconnect on %s.') % \ (user, hostmask, identify, server, signoff) replyIrc.reply(s) del self._whois[(irc, loweredNick)]