def checkIgnored(hostmask, recipient='', users=ircdb.users, channels=ircdb.channels): if ircdb.ignores.checkIgnored(hostmask): return True try: id = ircdb.users.getUserId(hostmask) user = users.getUser(id) except KeyError: # If there's no user... if ircutils.isChannel(recipient): channel = channels.getChannel(recipient) if channel.checkIgnored(hostmask): return True else: return False else: return False if user._checkCapability('owner'): # Owners shouldn't ever be ignored. return False elif user.ignore: return True elif recipient: if ircutils.isChannel(recipient): channel = ircdb.channels.getChannel(recipient) if channel.checkIgnored(hostmask): return True else: return False else: return False else: return False
def inFilter(self, irc, msg): self.filtering = True # We need to check for bad words here rather than in doPrivmsg because # messages don't get to doPrivmsg if the user is ignored. if msg.command == 'PRIVMSG' and self.words(): channel = msg.args[0] self.updateRegexp(channel) s = ircutils.stripFormatting(msg.args[1]) if ircutils.isChannel(channel) and self.registryValue( 'kick', channel): if self.regexp.search(s): c = irc.state.channels[channel] cap = ircdb.makeChannelCapability(channel, 'op') if c.isHalfopPlus(irc.nick): if c.isHalfopPlus(msg.nick) or \ ircdb.checkCapability(msg.prefix, cap): self.log.debug( "Not kicking %s from %s, because " "they are halfop+ or can't be " "kicked.", msg.nick, channel) else: message = self.registryValue( 'kick.message', channel) irc.queueMsg( ircmsgs.kick(channel, msg.nick, message)) else: self.log.warning( 'Should kick %s from %s, but not opped.', msg.nick, channel) elif ircutils.isChannel( channel) and self.regexp.search(s) and self.registryValue( 'inFilter', channel) and not ircdb.checkCapability( msg.prefix, 'trusted'): return None return msg
def lunch(self, irc, msg, args): # Reject query if privmsg if not ircutils.isChannel(msg.args[0]): irc.reply('I will not reply to your soft whispers.') return # Look for channel in arguments, else assume current channel is target for i in args: if ircutils.isChannel(i): chan = i args.remove(i) break else: chan = msg.args[0] # Look for arguments else spit list if not args: places = self.get_places(chan) if len(places) == 0: irc.reply('My list is empty, why not tell me what you like to', 'eat?') else: eatme = random.choice(places) irc.reply(eatme) elif 'add' in args: args.remove('add') place = ' '.join(args) places = self.get_places(chan) if place in places: irc.reply('%s already in list for %s' % (place, chan)) return places.append(place) self.setRegistryValue('places', places, chan) irc.reply('Added %s to %s\'s list.' % (place, chan)) elif 'remove' in args: args.remove('remove') place = ' '.join(args) places = self.get_places(chan) if place not in places: irc.reply('%s not found in list for %s' % (place, chan)) return places.remove(place) self.setRegistryValue('places', places, chan) irc.reply('Removed %s from %s\'s list.' % (place, chan)) elif 'list' in args: places = ', '.join(self.get_places(chan)) if len(places) == 0: irc.reply('List for %s is empty.' % chan) else: irc.reply(places) else: irc.reply('Unknown command.')
def getConnection(connections, channels, source, serverID = None): conn = None if not serverID: if ircutils.isChannel(source) and source.lower() in channels: conn = connections.get(source) else: if ircutils.isChannel(serverID): conn = connections.get(serverID) else: for c in connections.itervalues(): if c.ID == serverID.lower(): conn = c return conn
def inFilter(self, irc, msg): self.filtering = True # We need to check for bad words here rather than in doPrivmsg because # messages don't get to doPrivmsg is the user is ignored. if msg.command == 'PRIVMSG': self.updateRegexp() s = ircutils.stripFormatting(msg.args[1]) channel = msg.args[0] if ircutils.isChannel(channel) and self.registryValue( 'kickban', channel): if self.regexp.search(s): if irc.nick in irc.state.channels[channel].ops: message = self.registryValue('kickban.message', channel) bannedHostmask = irc.state.nickToHostmask(msg.nick) banmaskstyle = conf.supybot.protocols.irc.banmask banmask = banmaskstyle.makeBanmask(bannedHostmask) irc.queueMsg(ircmsgs.ban(channel, banmask)) irc.queueMsg(ircmsgs.kick(channel, msg.nick, message)) expiry = self.registryValue('kickban.banexpire', channel) if expiry > 0: def f(): if channel in irc.state.channels and \ banmask in irc.state.channels[channel].bans: irc.queueMsg( ircmsgs.unban(channel, banmask)) schedule.addEvent(f, time.time() + expiry) else: self.log.warning( 'Should kickban %s from %s, but not opped.', msg.nick, channel) else: if ircutils.isChannel(channel) and self.registryValue( 'kick', channel): if self.regexp.search(s): if irc.nick in irc.state.channels[channel].ops: message = self.registryValue( 'kick.message', channel) irc.queueMsg( ircmsgs.kick(channel, msg.nick, message)) else: self.log.warning( 'Should kick %s from %s, but not opped.', msg.nick, channel) return msg
def _is_not_ignored(self, msg, irc): channel = msg.args[0] enabled = self.registryValue('enable', channel) or \ (self.registryValue('enableIfModerated', channel) and \ 'm' in irc.state.channels[channel].modes) return ircutils.isChannel(channel) and enabled and \ not irc.state.channels[channel].isVoicePlus(msg.nick)
def get_feedName(irc, msg, args, state): if ircutils.isChannel(args[0]): state.errorInvalid('feed name', args[0], 'must not be channel names.') if not registry.isValidRegistryName(args[0]): state.errorInvalid('feed name', args[0], 'Feed names must not include spaces.') state.args.append(callbacks.canonicalName(args.pop(0)))
def listmaps(self, irc, msg, args, search_string): """[search_string] Searches for maps whose names are similar to search_string or that were submitted during week search_string. """ if search_string: map_results = self.db.search_map_names(search_string) else: if ircutils.isChannel(msg.args[0]): irc.reply( 'Please use a private message to browse the full list. Alternatively, provide a search string or week number, or visit http://maps.jukejuice.com' ) return map_results = self.db.get_all_map_names() if map_results: num_map_results = len(map_results) maps = ', '.join(map_results) resp = '{} result{}: {}'.format(num_map_results, 's' if num_map_results > 1 else '', maps) else: resp = ('Sorry, I cannot find "{}".').format(search_string) irc.reply(resp)
def quote(self, irc, msg, args, optlist, qid): """[--channel <#channel>] [<id>] Get a random quote or the quote number 'id'. If --channel is supplied the quote is fetched from that channel database.""" channel = msg.args[0] for (option, arg) in optlist: if option == 'channel': if not ircutils.isChannel(arg): irc.error(format(_('%s is not a valid channel.'), arg), Raise=True) channel = arg if qid is not None: q = self.db.getQuoteById(channel, qid) else: q = self.db.getQuoteRandom(channel) if q is not None: irc.reply(format("#%s: %s", q[0], q[1]), noLengthCheck=True) elif qid is not None: irc.error( format(_("No such quote %s in %s's database."), qid, channel)) else: irc.error( format(_("There is no quotes in %s's database."), channel))
def inFilter(self, irc, msg): self.filtering = True # We need to check for bad words here rather than in doPrivmsg because # messages don't get to doPrivmsg if the user is ignored. if msg.command == 'PRIVMSG': channel = msg.args[0] self.updateRegexp(channel) s = ircutils.stripFormatting(msg.args[1]) if ircutils.isChannel(channel) and self.registryValue('kick', channel): if self.words and self.regexp.search(s): c = irc.state.channels[channel] cap = ircdb.makeChannelCapability(channel, 'op') if c.isHalfopPlus(irc.nick): if c.isHalfopPlus(msg.nick) or \ ircdb.checkCapability(msg.prefix, cap): self.log.debug("Not kicking %s from %s, because " "they are halfop+ or can't be " "kicked.", msg.nick, channel) else: message = self.registryValue('kick.message', channel) irc.queueMsg(ircmsgs.kick(channel, msg.nick, message)) else: self.log.warning('Should kick %s from %s, but not opped.', msg.nick, channel) return msg
def do437(self, irc, msg): """Nick/channel is temporarily unavailable""" if ircutils.isChannel(msg.args[1]): return self.log.info('Nick %s is unavailable; attempting NickServ release ' 'on %s.' % (msg.args[1], irc.network)) irc.sendMsg(ircmsgs.privmsg('NickServ', 'release %s' % msg.args[1]))
def quote(self, irc, msg, args, optlist, qid): """[--channel <#channel>] [<id>] Get a random quote or the quote number 'id'. If --channel is supplied the quote is fetched from that channel database.""" channel = msg.args[0] for (option, arg) in optlist: if option == 'channel': if not ircutils.isChannel(arg): irc.error(format(_('%s is not a valid channel.'), arg), Raise=True) channel = arg if qid is not None: q = self.db.getQuoteById(channel, qid) else: q = self.db.getQuoteRandom(channel) if q is not None: irc.reply(format("#%s: %s", q[0], q[1]), noLengthCheck=True) elif qid is not None: irc.error(format(_("No such quote %s in %s's database."), qid, channel)) else: irc.error(format(_("There is no quotes in %s's database."), channel))
def addMsg(self, msg): assert msg.command == 'PRIVMSG' (channel, text) = msg.args if not ircutils.isChannel(channel): return channel = plugins.getChannel(channel) text = text.strip().lower() if not text: return try: id = ircdb.users.getUserId(msg.prefix) except KeyError: return msgwords = [s.strip(nonAlphaNumeric).lower() for s in text.split()] if channel not in self.channelWords: self.channelWords[channel] = {} for word in self.channelWords[channel]: lword = word.lower() count = msgwords.count(lword) if count: self.channelWords[channel][word] += count if (channel, id) not in self: self[channel, id] = {} if word not in self[channel, id]: self[channel, id][word] = 0 self[channel, id][word] += count
def makeBanmask(self, hostmask, options=None): """Create a banmask from the given hostmask. If a style of banmask isn't specified via options, the value of conf.supybot.protocols.irc.banmask is used. A variable named 'channel' (defining the channel the ban is taking place in) is expected to be in the environment of the caller of this function. options - A list specifying which parts of the hostmask should explicitly be matched: nick, user, host. If 'exact' is given, then only the exact hostmask will be used.""" assert ircutils.isChannel(dynamic.channel) (nick, user, host) = ircutils.splitHostmask(hostmask) bnick = '*' buser = '******' bhost = '*' if not options: options = get(supybot.protocols.irc.banmask, dynamic.channel) for option in options: if option == 'nick': bnick = nick elif option == 'user': buser = user elif option == 'host': bhost = host elif option == 'exact': return hostmask return ircutils.joinHostmask(bnick, buser, bhost)
def cveSnarfer(self, irc, msg, match): r"(https?://\S+=)?CVE[- ](?P<cveid>\d{4}[- ]\d{4,})" channel = msg.args[0] if ircutils.isChannel(msg.args[0]) else None if checkAddressed(msg.args[1].strip(), channel): return if not self.registryValue('bugSnarfer', channel) or not self.registryValue('cveSnarfer', channel): return cveid = match.group('cveid').replace(' ','-') if not self.is_ok(channel or msg.nick, 'cve', cveid): return url = 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-%s' % cveid try: cvedata = utils.web.getUrl(url).decode('utf-8') except Exception as e: raise BugtrackerError('Could not get CVE data: %s (%s)' % (e, url)) m = cvere.search(cvedata) if m: cve = utils.web.htmlToText(m.group('cve'), tagReplace='') if len(cve) > 380: cve = cve[:380] + '...' if not match.group(1): cve += ' <%s>' % url irc.reply(cve) else: m = cverre.search(cvedata) if m: cverr = utils.web.htmlToText(m.group('cverr'), tagReplace='') irc.reply(cverr)
def turlSnarfer(self, irc, msg, match): r"(https?://)?((bugs\.debian\.org|pad\.lv)/|\S+/(show_bug\.cgi\?id=|bugreport\.cgi\?bug=|view\.php\?id=|bug=|bugs/|\+bug/|ticket/|feature-requests/|patches/|todo/|issues/|pulls?/|merge_requests/))(?P<bug>\d+)/?" channel = msg.args[0] if ircutils.isChannel(msg.args[0]) else None if checkAddressed(msg.args[1].strip(), channel): return if not self.registryValue('bugSnarfer', channel): return nbugs = msg.tagged('nbugs') or 0 if nbugs >= 5: return msg.tag('nbugs', nbugs+1) url = match.group(0) bugid = int(match.group('bug')) if '://' in url: url = url[url.rfind('://')+3:] try: tracker = self.get_tracker(url, bugid) if not tracker: return report = self.get_bug(channel or msg.nick, tracker, bugid, self.registryValue('showassignee', channel), self.registryValue('extended', channel), do_url=False) except BugtrackerError as e: irc.error(str(e)) except BugNotFoundError: if self.registryValue('replyWhenNotFound'): irc.error("Could not find %s bug %s" % (tracker.description, match.group('bug'))) else: if report: irc.reply(report)
def getIssue(self, irc, msg, match): """Get a Jira Issue""" if not ircutils.isChannel(msg.args[0]): return issueName = match.group('issue') try: issue = self.jira.issue(issueName) except: print "Invalid Jira snarf: %s" % issueName return if issue: issuetype = issue.fields.issuetype.name key = issue.key name = issue.fields.summary status = issue.fields.status.name time = issue.fields.timeestimate if issue.fields.assignee: assignee = issue.fields.assignee.displayName else: assignee = "Unassigned" if time: hours = time / 60 / 60 minutes = time / 60 % 60 displayTime = " / %ih%im" % (hours, minutes) else: displayTime = "" url = ''.join((self.server, '/browse/', key)) replytext = ("(%s %s) %s [ \x032%s\x03%s ] \x033\x02%s\x02\x03 %s" % (issuetype, key, name, assignee, displayTime, status, url)) irc.reply(replytext, prefixNick=False)
def delquote(self, irc, msg, args, optlist, qid): """[--channel <#channel>] <id> Delete the quote number 'id', only by the creator of the quote in the first 5 minutes or by an admin. If --channel is supplied the quote is fetched from that channel database.""" channel = msg.args[0] for (option, arg) in optlist: if option == 'channel': if not ircutils.isChannel(arg): irc.error(format(_('%s is not a valid channel.'), arg), Raise=True) channel = arg q = self.db.getQuoteById(channel, qid) if q is not None: if ircdb.checkCapability(msg.prefix, 'admin'): self.db.delQuoteById(channel, qid) irc.replySuccess() elif (time.time() - 300) <= q[3]: if q[2].lower() == msg.nick.lower(): self.db.delQuoteById(channel, qid) irc.replySuccess() else: irc.error(format(_("This quote only can be deleted by %s " "or an admin."), q[2])) else: irc.error(format(_("Too late, it has already passed 5 minutes." " Ask an admin."), qid, channel)) else: irc.error(format(_("No such quote %s in %s's database."), qid, channel))
def soccerformation(self, irc, msg, args): """ Display a random lineup for channel users. """ if not ircutils.isChannel(msg.args[0]): # make sure its run in a channel. irc.reply("ERROR: Must be run from a channel.") return # now make sure we have more than 9 users. users = [i for i in irc.state.channels[msg.args[0]].users] if len(users) < 11: # need >9 users. irc.reply("Sorry, I can only run this in a channel with more than 9 users.") return # now that we're good.. formations = {'4-4-2':['(GK)', '(RB)', '(CB)', '(CB)', '(LB)', '(RM)', '(LM)', '(CM)', '(CM)', '(FW)', '(FW)'], '4-4-1-1':['(GK)', '(RB)', '(CB)', '(CB)', '(LB)', '(RM)', '(LM)', '(CM)', '(CM)', '(ST)', '(FW)'], '4-5-1':['(GK)', '(RB)', '(CB)', '(CB)', '(LB)', '(RM)', '(LM)', '(CM)', '(CM)', '(CM)', '(ST)'], '3-5-1-1':['(GK)', '(CB)', '(CB)', '(SW)', '(RM)', '(CM)', '(LM)', '(CM)', '(CM)', '(FW)', '(ST)'], '10-1 (CHELSEA)':['(GK)', '(LB)', '(CB)', '(RB)', '(CB)', '(CB)', '(CB)', '(CB)', '(CB)', '(CB)', '(DROGBA)'], '8-1-1 (PARK THE BUS)':['(GK)', '(LB)', '(CB)', '(RB)', '(CB)', '(CB)', '(CB)', '(CB)', '(CB)', '(CM)', '(ST)'] } formation = random.choice(formations.keys()) random.shuffle(formations[formation]) # shuffle. lineup = [] # list for output. for position in formations[formation]: # iterate through and highlight. a = random.choice(users) # pick a random user. users.remove(a) # remove so its unique. append below. lineup.append("{0}{1}".format(ircutils.bold(a), position)) # now output. output = "{0} ALL-STAR LINEUP ({1}) :: {2}".format(ircutils.mircColor(msg.args[0], 'red'), formation, ", ".join(lineup)) if not self.registryValue('disableANSI', msg.args[0]): # display color or not? irc.reply(output) else: irc.reply(ircutils.stripFormatting(output))
def makeBanmask(self, hostmask, options=None): """Create a banmask from the given hostmask. If a style of banmask isn't specified via options, the value of conf.supybot.protocols.irc.banmask is used. options - A list specifying which parts of the hostmask should explicitly be matched: nick, user, host. If 'exact' is given, then only the exact hostmask will be used.""" channel = dynamic.channel assert channel is None or ircutils.isChannel(channel) (nick, user, host) = ircutils.splitHostmask(hostmask) bnick = '*' buser = '******' bhost = '*' if not options: options = get(supybot.protocols.irc.banmask, channel) for option in options: if option == 'nick': bnick = nick elif option == 'user': buser = user elif option == 'host': bhost = host elif option == 'exact': return hostmask return ircutils.joinHostmask(bnick, buser, bhost)
def trends(self, irc, msg, args, getopts, optwoeid): """[--exclude] [location] Returns the Top 10 Twitter trends for a specific location. Use optional argument location for trends. Defaults to worldwide and can be set via config variable. Use --exclude to not include #hashtags in trends data. Ex: Boston or --exclude London """ # enforce +voice or above to use command? if self.registryValue('requireVoiceOrAbove', msg.args[0]): # should we check? if ircutils.isChannel(msg.args[0]): # are we in a channel? if not irc.state.channels[msg.args[0]].isVoicePlus(msg.nick): # are they + or @? irc.error("ERROR: You have to be at least voiced to use the trends command in {0}.".format(msg.args[0])) return # before we do anything, make sure we have a twitterApi object. if not self.twitterApi: irc.reply("ERROR: Twitter is not authorized. Please check logs before running this command.") return # default arguments. args = {'id': self.registryValue('woeid', msg.args[0]), 'exclude': self.registryValue('hideHashtagsTrends', msg.args[0])} # handle input. if getopts: for (key, value) in getopts: if key == 'exclude': # remove hashtags from trends. args['exclude'] = 'hashtags' # work with woeid. 1 is world, the default. can be set via input or via config. if optwoeid: # if we have an input location, lookup the woeid. if optwoeid.lower().startswith('world'): # looking for worldwide or some variation. (bypass) args['id'] = 1 # "World Wide" is worldwide (odd bug) = 1. else: # looking for something else. woeid = self._woeid_lookup(optwoeid) # yahoo search for woeid. if woeid: # if we get a returned value, set it. otherwise default value. args['id'] = woeid else: # location not found. irc.reply("ERROR: I could not lookup location: {0}. Try a different location.".format(optwoeid)) return # now build our API call data = self.twitterApi.ApiCall('trends/place', parameters=args) try: data = json.loads(data.read().decode()) except: irc.reply("ERROR: failed to lookup trends on Twitter: {0}".format(data)) return # now, before processing, check for errors: if 'errors' in data: if data['errors'][0]['code'] == 34: # 34 means location not found. irc.reply("ERROR: I do not have any trends for: {0}".format(optwoeid)) return else: # just return the message. errmsg = data['errors'][0] irc.reply("ERROR: Could not load trends. ({0} {1})".format(errmsg['code'], errmsg['message'])) return # if no error here, we found trends. prepare string and output. location = data[0]['locations'][0]['name'] ttrends = " | ".join([trend['name'] for trend in data[0]['trends']]) irc.reply("Top 10 Twitter Trends in {0} :: {1}".format(self._bold(location), ttrends))
def list(self, irc, msg, args, optlist): """[--channel <#channel>] [--keys] Lists all Akas defined for <channel>. If <channel> is not specified, lists all global Akas. If --keys is given, lists only the Aka names and not their commands.""" channel = 'global' for (option, arg) in optlist: if option == 'channel': if not ircutils.isChannel(arg): irc.error(_('%r is not a valid channel.') % arg, Raise=True) channel = arg aka_list = self._db.get_aka_list(channel) if aka_list: if 'keys' in dict(optlist): # Strange, aka_list is a list of one length tuples s = [k[0] for k in aka_list] else: aka_values = [self._db.get_alias(channel, aka) for aka in aka_list] s = ('{0}: "{1}"'.format(ircutils.bold(k), v) for (k, v) in zip(aka_list, aka_values)) irc.replies(s) else: irc.error(_("No Akas found."))
def checkIgnored(hostmask, recipient='', users=users, channels=channels): """checkIgnored(hostmask, recipient='') -> True/False Checks if the user is ignored by the recipient of the message. """ try: id = users.getUserId(hostmask) user = users.getUser(id) if user._checkCapability('owner'): # Owners shouldn't ever be ignored. return False elif user.ignore: log.debug('Ignoring %s due to his IrcUser ignore flag.', hostmask) return True except KeyError: # If there's no user... if conf.supybot.defaultIgnore(): log.debug('Ignoring %s due to conf.supybot.defaultIgnore', hostmask) return True if ignores.checkIgnored(hostmask): log.debug('Ignoring %s due to ignore database.', hostmask) return True if ircutils.isChannel(recipient): channel = channels.getChannel(recipient) if channel.checkIgnored(hostmask): log.debug('Ignoring %s due to the channel ignores.', hostmask) return True return False
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)
def nicks(self, irc, msg, args, channel, optlist): """[<channel>] [--count] Returns the nicks in <channel>. <channel> is only necessary if the message isn't sent in the channel itself. Returns only the number of nicks if --count option is provided. """ # Make sure we don't elicit information about private channels to # people or channels that shouldn't know capability = ircdb.makeChannelCapability(channel, 'op') hostmask = irc.state.nickToHostmask(msg.nick) if 's' in irc.state.channels[channel].modes and \ msg.args[0] != channel and \ not ircdb.checkCapability(hostmask, capability) and \ (ircutils.isChannel(msg.args[0]) or \ msg.nick not in irc.state.channels[channel].users): irc.error(_('You don\'t have access to that information.'), Raise=True) L = list(irc.state.channels[channel].users) keys = [option for (option, arg) in optlist] if 'count' not in keys: utils.sortBy(str.lower, L) private = self.registryValue("nicksInPrivate", channel) irc.reply(utils.str.commaAndify(L), private=private) else: irc.reply(str(len(L)))
def tell(self, irc, msg, args, target, text): """<nick> <text> Tells the <nick> whatever <text> is. Use nested commands to your benefit here. """ if irc.nested: irc.error("This command cannot be nested.", Raise=True) if target.lower() == "me": target = msg.nick if ircutils.isChannel(target): irc.error("Dude, just give the command. No need for the tell.") return if not ircutils.isNick(target): irc.errorInvalid("nick", target) if ircutils.nickEqual(target, irc.nick): irc.error("You just told me, why should I tell myself?", Raise=True) if target not in irc.state.nicksToHostmasks and not ircdb.checkCapability(msg.prefix, "owner"): # We'll let owners do this. s = "I haven't seen %s, I'll let you do the telling." % target irc.error(s, Raise=True) if irc.action: irc.action = False text = "* %s %s" % (irc.nick, text) s = "%s wants me to tell you: %s" % (msg.nick, text) irc.replySuccess() irc.reply(s, to=target, private=True)
def isChannelCapability(capability): """Returns True if capability is a channel capability; False otherwise.""" if ',' in capability: (channel, capability) = capability.split(',', 1) return ircutils.isChannel(channel) and isCapability(capability) else: return False
def set(self, irc, msg, args, optlist, name, alias): """[--channel <#channel>] <name> <command> Overwrites an existing alias <name> to execute <command> instead. The <command> should be in the standard "command argument [nestedcommand argument]" arguments to the alias; they'll be filled with the first, second, etc. arguments. $1, $2, etc. can be used for required arguments. @1, @2, etc. can be used for optional arguments. $* simply means "all arguments that have not replaced $1, $2, etc.", ie. it will also include optional arguments. """ channel = 'global' for (option, arg) in optlist: if option == 'channel': if not ircutils.isChannel(arg): irc.error(_('%r is not a valid channel.') % arg, Raise=True) channel = arg try: self._remove_aka(channel, name) except AkaError as e: irc.error(str(e), Raise=True) if ' ' not in alias: # If it's a single word, they probably want $*. alias += ' $*' try: self._add_aka(channel, name, alias) self.log.info('Setting Aka %r to %r (from %s)', name, alias, msg.prefix) irc.replySuccess() except AkaError as e: irc.error(str(e))
def doPrivmsg(self, irc, msg): if not conf.supybot.defaultIgnore(): # Only do this when defaultIgnore is set return if chr(1) in msg.args[1]: return try: user = ircdb.users.getUser(msg.prefix) if user.checkHostmask(msg.prefix): return except: pass text = callbacks.addressed(irc.nick, msg) cmd = '' if not text or text != "login": if msg.args[1]: if ircutils.isChannel(msg.args[0]): if msg.args[1][0] == '@': cmd = msg.args[1][1:] else: if msg.args[1][0] == '@': cmd = msg.args[1][1:] else: cmd = msg.args[1] if cmd != "login": return else: return self.log.info("IRCLogin: Calling login for %s" % msg.prefix) self._callCommand(["login"], irc, msg, [])
def np(self, irc, msg, args): """Return a list of a people currently in-game on Steam """ key = self.registryValue('apikey') if not key: irc.replyError('plugins.steamy.apikey has not been set') return self.update(key) ingame = filter(lambda player: player.isInGame(), self.group.members) playerCount = len(ingame) playerlist = map(lambda x: '{0}: {1}'.format(x.steamID.encode('utf8'), x.gameextrainfo.encode('utf8')), ingame) self.log.info(str(playerlist)) if len(playerlist) != 0: reply = 'Now Playing: %s' % (', '.join(playerlist)) else: reply = 'Now Playing: nobody :(' if ircutils.isChannel(msg.args[0]): irc.queueMsg(ircmsgs.privmsg(msg.args[0], reply)) else: irc.queueMsg(ircmsgs.privmsg(msg.nick, reply))
def doJoin(self, irc, msg): nick = ircutils.toLower(msg.nick) if len(msg.args) < 2: # extended-join is not supported return channel = msg.args[0].split(',')[0] account = msg.args[1] if ircutils.strEqual(irc.nick, msg.nick): # message from self return if 'batch' in msg.server_tags and \ msg.server_tags['batch'] in irc.state.batches and \ irc.state.batches[msg.server_tags['batch']].type == 'netjoin': # ignore netjoin return if not ircutils.isChannel( channel) or channel not in irc.state.channels: return if not self.registryValue('enabled', channel): return if account == '*': irc.queueMsg( ircmsgs.notice( nick, 'You joined {}, but you are not identified to services and cannot speak.' ' For help with identification, type "/msg nickserv help register"' .format(channel)))
def nicks(self, irc, msg, args, channel, optlist): """[<channel>] [--count] Returns the nicks in <channel>. <channel> is only necessary if the message isn't sent in the channel itself. Returns only the number of nicks if --count option is provided. """ # Make sure we don't elicit information about private channels to # people or channels that shouldn't know if 's' in irc.state.channels[channel].modes and \ msg.args[0] != channel and \ (ircutils.isChannel(msg.args[0]) or \ msg.nick not in irc.state.channels[channel].users): irc.error(_('You don\'t have access to that information.'), Raise=True) L = list(irc.state.channels[channel].users) keys = [option for (option, arg) in optlist] if 'count' not in keys: irc.reply(channel) irc.reply(optlist) irc.reply(keys) irc.reply(args) utils.sortBy(str.lower, L) irc.reply(utils.str.commaAndify(L)) else: irc.reply(args) irc.reply(channel) irc.reply(optlist) irc.reply(keys) irc.reply(str(len(L)))
def trends(self, irc, msg, args, getopts, optwoeid): """[--exclude] [location] Returns the Top 10 Twitter trends for a specific location. Use optional argument location for trends. Defaults to worldwide and can be set via config variable. Use --exclude to not include #hashtags in trends data. Ex: Boston or --exclude London """ # enforce +voice or above to use command? if self.registryValue('requireVoiceOrAbove', msg.args[0]): # should we check? if ircutils.isChannel(msg.args[0]): # are we in a channel? if not irc.state.channels[msg.args[0]].isVoicePlus(msg.nick): # are they + or @? irc.error("ERROR: You have to be at least voiced to use the trends command in {0}.".format(msg.args[0])) return # before we do anything, make sure we have a twitterApi object. if not self.twitterApi: irc.reply("ERROR: Twitter is not authorized. Please check logs before running this command.") return # default arguments. args = {'id': self.registryValue('woeid', msg.args[0]), 'exclude': self.registryValue('hideHashtagsTrends', msg.args[0])} # handle input. if getopts: for (key, value) in getopts: if key == 'exclude': # remove hashtags from trends. args['exclude'] = 'hashtags' # work with woeid. 1 is world, the default. can be set via input or via config. if optwoeid: # if we have an input location, lookup the woeid. if optwoeid.lower().startswith('world'): # looking for worldwide or some variation. (bypass) args['id'] = 1 # "World Wide" is worldwide (odd bug) = 1. else: # looking for something else. woeid = self._woeid_lookup(optwoeid) # yahoo search for woeid. if woeid: # if we get a returned value, set it. otherwise default value. args['id'] = woeid else: # location not found. irc.reply("ERROR: I could not lookup location: {0}. Try a different location.".format(optwoeid)) return # now build our API call data = self.twitterApi.ApiCall('trends/place', parameters=args) try: data = json.loads(data.read()) except: irc.reply("ERROR: failed to lookup trends on Twitter: {0}".format(data)) return # now, before processing, check for errors: if 'errors' in data: if data['errors'][0]['code'] == 34: # 34 means location not found. irc.reply("ERROR: I do not have any trends for: {0}".format(optwoeid)) return else: # just return the message. errmsg = data['errors'][0] irc.reply("ERROR: Could not load trends. ({0} {1})".format(errmsg['code'], errmsg['message'])) return # if no error here, we found trends. prepare string and output. location = data[0]['locations'][0]['name'] ttrends = " | ".join([trend['name'].encode('utf-8') for trend in data[0]['trends']]) irc.reply("Top 10 Twitter Trends in {0} :: {1}".format(self._bold(location), ttrends))
def calc(self, irc, msg, args, expr): """<expression> Uses Google's calculator to calculate the value of <expression>. """ channel = msg.args[0] if not ircutils.isChannel(channel): channel = None url = self._googleUrl(expr, channel) h = {"User-Agent":"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36"} html = utils.web.getUrl(url, headers=h).decode('utf8') match = self._calcRe1.search(html) if not match: match = self._calcRe2.search(html) if not match: match = self._calcRe3.search(html) if not match: irc.reply("I could not find an output from Google Calc for: %s" % expr) return else: s = match.group(1) else: s = match.group(1) else: s = match.group(1) # do some cleanup of text s = re.sub(r'<sup>(.*)</sup>⁄<sub>(.*)</sub>', r' \1/\2', s) s = re.sub(r'<sup>(.*)</sup>', r'^\1', s) s = utils.web.htmlToText(s) irc.reply("%s = %s" % (expr, s))
def tell(self, irc, msg, args, target, text): """<nick> <text> Tells the <nick> whatever <text> is. Use nested commands to your benefit here. """ if irc.nested: irc.error('This command cannot be nested.', Raise=True) if target.lower() == 'me': target = msg.nick if ircutils.isChannel(target): irc.error('Dude, just give the command. No need for the tell.') return if not ircutils.isNick(target): irc.errorInvalid('nick', target) if ircutils.nickEqual(target, irc.nick): irc.error('You just told me, why should I tell myself?',Raise=True) if target not in irc.state.nicksToHostmasks and \ not ircdb.checkCapability(msg.prefix, 'owner'): # We'll let owners do this. s = 'I haven\'t seen %s, I\'ll let you do the telling.' % target irc.error(s, Raise=True) if irc.action: irc.action = False text = '* %s %s' % (irc.nick, text) s = '%s wants me to tell you: %s' % (msg.nick, text) irc.replySuccess() irc.reply(s, to=target, private=True)
def tell(self, irc, msg, args, target, text): """<nick> <text> Tells the <nick> whatever <text> is. Use nested commands to your benefit here. """ if target.lower() == 'me': target = msg.nick if ircutils.isChannel(target): irc.error('Dude, just give the command. No need for the tell.') return if not ircutils.isNick(target): irc.errorInvalid('nick', target) if ircutils.nickEqual(target, irc.nick): irc.error('You just told me, why should I tell myself?',Raise=True) if target not in irc.state.nicksToHostmasks and \ not ircdb.checkCapability(msg.prefix, 'owner'): # We'll let owners do this. s = 'I haven\'t seen %s, I\'ll let you do the telling.' % target irc.error(s, Raise=True) if irc.action: irc.action = False text = '* %s %s' % (irc.nick, text) s = '%s wants me to tell you: %s' % (msg.nick, text) irc.reply(s, to=target, private=True)
def list(self, irc, msg, args, optlist): """[--channel <#channel>] [--keys] Lists all Akas defined for <channel>. If <channel> is not specified, lists all global Akas. If --keys is given, lists only the Aka names and not their commands.""" channel = 'global' for (option, arg) in optlist: if option == 'channel': if not ircutils.isChannel(arg): irc.error(_('%r is not a valid channel.') % arg, Raise=True) channel = arg aka_list = self._db.get_aka_list(channel) if aka_list: if 'keys' in dict(optlist): # Strange, aka_list is a list of one length tuples s = [k[0] for k in aka_list] else: aka_values = [ self._db.get_alias(channel, aka) for aka in aka_list ] s = ('{0}: "{1}"'.format(ircutils.bold(k), v) for (k, v) in zip(aka_list, aka_values)) irc.replies(s) else: irc.error(_("No Akas found."))
def outFilter(self, irc, msg): if msg.command == 'PRIVMSG' and \ ircutils.isChannel(msg.args[0]) and \ self.registryValue('enable', msg.args[0]): s = msg.args[1] prefixes = ["+", "$", ";", ".", "%", "!", "`", "\\", "@", "&", "*", "~", ":", "^", "(", ")", "-", "=", ">", "<", ","] rpairs = {"\007":"", } if self.registryValue('colorAware') and \ self.isChanStripColor(irc, msg.args[0]): rpairs['moo'] = 'm#oo' # \003 = Colour (Ctrl+K), \002 = Bold (Ctrl+B), \017 = # Reset Formatting (Ctrl+O), \037 = Underline, # \026 = Italic/Reverse video prefixes += ["\003", "\002", "\017", "\037", "\026"] else: rpairs['moo'] = 'm\003oo' if self.registryValue('spaceBeforeNicks', msg.args[0]): # If the last character of the first word ends with a ',' or # ':', prepend a space. if s.split()[0][-1] in [",", ":"]: s = " " + s # Handle actions properly but destroy any other \001 (CTCP) messages if self.registryValue('blockCtcp', msg.args[0]) and \ s.startswith("\001") and not s.startswith("\001ACTION"): s = s[1:-1] for k, v in rpairs.iteritems(): s = s.replace(k, v) for item in prefixes: if s.startswith(item): s = " " + s msg = ircmsgs.privmsg(msg.args[0], s, msg=msg) return msg
def inFilter(self, irc, msg): if ircutils.isChannel(msg.args[0]): if self.registryValue('enabled', msg.args[0]) and \ len(msg.args) > 1: s = ircutils.stripFormatting(msg.args[1]) msg = ircmsgs.privmsg(msg.args[0], s, msg=msg) return msg return msg
def checkRelays(self, irc, relays): for relay in relays: r = relay.split("@") if len(r) != 2 or not (ircutils.isChannel(r[0]) and r[1]): irc.error( "Channels must be given in the form " "#channel@networkname.", Raise=True)
def kickme(self, irc, msg, args, reason): """[<reason>] Kick yourself.""" if ircutils.isChannel(msg.args[0]): irc.queueMsg(ircmsgs.kick(msg.args[0], msg.nick, reason or '')) else: irc.error(_("This command must be run in a channel."))
def getchan(self, irc, msg, args): """takes no arguments. Returns the name of the current channel. """ channel = msg.args[0] if ircutils.isChannel(channel): irc.reply(channel) else: irc.reply(None)
def doGetOrHead(self, handler, path, write_content): parts = path.split('/')[1:] if path == '/': self.send_response(200) self.send_header('Content-type', 'text/html; charset=utf-8') self.end_headers() self.write(httpserver.get_template('factoids/index.html')) elif len(parts) == 2: channel = utils.web.urlunquote(parts[0]) if not ircutils.isChannel(channel): self.send_response(404) self.send_header('Content-type', 'text/html; charset=utf-8') self.end_headers() if write_content: self.write(httpserver.get_template('generic/error.html')% {'title': 'Factoids - not a channel', 'error': 'This is not a channel'}) return if not self._plugin.registryValue('web.channel', channel): self.send_response(403) self.send_header('Content-type', 'text/html; charset=utf-8') self.end_headers() if write_content: self.write(httpserver.get_template('generic/error.html')% {'title': 'Factoids - unavailable', 'error': 'This channel does not exist or its factoids ' 'are not available here.'}) return db = self._plugin.getDb(channel) cursor = db.cursor() cursor.execute("""SELECT keys.key, factoids.id, factoids.fact FROM factoids, keys, relations WHERE relations.key_id=keys.id AND relations.fact_id=factoids.id """) factoids = {} for (key, id_, fact) in cursor.fetchall(): if key not in factoids: factoids[key] = {} factoids[key][id_] = fact content = '' keys = sorted(factoids.keys()) for key in keys: facts = factoids[key] content += '<tr>' content += ('<td rowspan="%i" class="key">' '<a name="%s" href="#%s">%s</a>' '</td>') % (len(facts), key, key, key) for id_, fact in list(facts.items()): content += '<td class="id">%i</td>' % id_ content += '<td class="fact">%s</td>' % fact content += '</tr><tr>' content = content[:-len('<tr>')] self.send_response(200) self.send_header('Content-type', 'text/html; charset=utf-8') self.end_headers() if write_content: self.write(httpserver.get_template('factoids/channel.html')% {'channel': channel, 'rows': content})
def doBounce(self, irc, s, channel, **kw): channel = self.normalizeChannel(irc, channel) s = ircutils.stripFormatting(s) for t in self.targets: if ircutils.isChannel(channel): inreply = channel else: inreply = kw['nick'] t.sendReply(s.strip(), source='bnc', inreply=inreply, **kw)
def onPing(self, irc, msg, match): channel = msg.args[0] from_ = msg.nick to = match.group('nick') or match.group('nick2') if not ircutils.isChannel(channel): return if channel not in self._pings: self._pings[channel] = {} self._pings[channel][(from_, to)] = time.time()
def _is_not_ignored(self, irc, msg): channel = msg.args[0] if not ircutils.isChannel(channel) or \ channel not in irc.state.channels: return False enabled = self.registryValue('enable', channel) or \ (self.registryValue('enableIfModerated', channel) and \ 'm' in irc.state.channels[channel].modes) return enabled and \ not irc.state.channels[channel].isVoicePlus(msg.nick)
def _formatNoteId(self, msg, note, sent=False): if note.public or not ircutils.isChannel(msg.args[0]): if sent: sender = plugins.getUserName(note.to) return format('#%i to %s', note.id, sender) else: sender = plugins.getUserName(note.frm) return format('#%i from %s', note.id, sender) else: return format('#%i (private)', note.id)
def outFilter(self, irc, msg): if msg.command == 'PRIVMSG': if ircutils.isChannel(msg.args[0]): if self.registryValue('selfStats', msg.args[0]): try: self.outFiltering = True self.db.addMsg(msg, 0) finally: self.outFiltering = False return msg