def __init__(self): self.modules = {} self.commands = {} self.eventhandlers = { 'privmsg': [self.privmsg_], 'joined': [self.joined_], 'joinedHomeChannel': [self.joinedHomeChannel], 'irc_JOIN': [self.irc_JOIN_], 'irc_PART': [self.irc_PART_], 'irc_QUIT': [self.irc_QUIT_], 'irc_KICK': [self.irc_KICK_], 'irc_RPL_WELCOME': [self.welcome_], } self.fetching_lists={} self.channel = None self.setTopic = self.topic self.topic = None try: self.password = config.get('Server', 'password') except ConfigParser.NoOptionError: self.password = None try: self.username = config.get('Server', 'username') except ConfigParser.NoOptionError: self.username = None try: self.realname = config.get('Server', 'realname') except ConfigParser.NoOptionError: self.realname = None self.channelpws = config.getdict('Server', 'channel passwords')
def help(self, call, args): """!help <command> Gives help on a particular command. Try !commands for a list of commands.""" if len(args) != 1: return self.help(call, ['help']) cmd = args[0] if cmd.startswith(config.get('Bot', 'command prefix')): cmd = cmd[len(config.get('Bot', 'command prefix')):] if cmd not in self.pypickupbot.commands: call.reply(_("Unknown command: %s") % args[0]) return try: docstring = getattr( self.pypickupbot.commands[cmd][0].im_self, self.pypickupbot.commands[cmd][0].__name__ + '_doc' ) except AttributeError: docstring = None if docstring == None: docstring = self.pypickupbot.commands[cmd][0].__doc__ if docstring == None: call.reply(_("No help available for %s") % cmd) return docstring = '\n'.join([s.lstrip() for s in docstring.split('\n')]) command, helpstring = docstring.split('\n\n', 1) if command[0] == '!': command = config.get('Bot', 'command prefix') + command[1:] helpstring = helpstring.replace('\n', ' ') commandflags = self.pypickupbot.commands[cmd][1] commandinfo = [] if commandflags & COMMAND.NOT_FROM_CHANNEL: commandinfo.append(_("not from channel")) if commandflags & COMMAND.NOT_FROM_PM: commandinfo.append(_("not from PM")) # if commandflags & COMMAND.ON_MESSAGE: # commandinfo.append(_("")) if commandflags & COMMAND.ADMIN: commandinfo.append(_("admin command")) if len(commandinfo): call.reply('\x02'+command+'\x02\x0315' + '('+', '.join(commandinfo)+')\x0f: ' + helpstring ) else: call.reply('\x02'+command+'\x02: ' + helpstring )
def _printResult(r): if len(r) < 1: if args and args[0].startswith('#'): call.reply(_("No record for game #{0}").format(id)) else: call.reply(_("No game played yet in mode(s): {0}").format(' '.join(games))) return gamenick, gtime, players_, captains_, id_ = r[0] if ',' in players_: players = json.loads(players_) captains = json.loads(captains_) else: players = players_.split() captains = captains_.split() try: game = self.pickup.get_game(call, [gamenick]) gamename = game.name teamnameFactory = game.teamname except InputError: gamename = _("Unknown(%s)") % gamenick teamnameFactory = lambda i: _("Team {0}").format(i + 1) timestr = str_from_timediff(itime()-gtime) if captains: call.reply(config.get('Pickup player tracking', 'lastgame').decode('string-escape') % \ { 'name': gamename, 'nick': gamenick, 'id': id_, 'when': timestr, 'playerlist': ', '.join(players), 'captainlist': ', '.join(captains) }) elif not isinstance(players[0], StringTypes): call.reply(config.get('Pickup player tracking', 'lastgame autopick').decode('string-escape') % \ { 'name': gamename, 'nick': gamenick, 'id': id_, 'when': timestr, 'teamslist': ', '.join([ config.get('Pickup messages', 'game ready autopick team').decode('string-escape')% { 'name': teamnameFactory(i), 'players': ', '.join(team) } for i, team in enumerate(players)]) }) else: call.reply(config.get('Pickup player tracking', 'lastgame nocaptains').decode('string-escape') % \ { 'name': gamename, 'nick': gamenick, 'id': id_, 'when': timestr, 'playerlist': ', '.join(players), })
def _cback(playerlist): o = [config.get('Pickup player tracking', 'top10 player').decode('string-escape') % { 'player': player, 'count': count, } for player, count in playerlist] call.reply( config.get('Pickup player tracking', 'top10').decode('string-escape') % { 'playerlist': ', '.join(o), 'games': ' '.join(games) }, ', ')
def __str__(self): sorted_topic = { self.__class__.GRAVITY_BEGINNING : {}, self.__class__.GRAVITY_NONE : {}, self.__class__.GRAVITY_END : {}, } as_list = [] for num, part in self.parts.iteritems(): s = str(part) if len(s) > 0: sorted_topic[part.gravity][num] = s for i in [self.GRAVITY_BEGINNING, self.GRAVITY_NONE, self.GRAVITY_END]: as_list.extend(sorted_topic[i].values()) return config.get('Topic', 'prefix').decode('string-escape') + config.get('Topic', 'separator').decode('string-escape').join(as_list) + config.get('Topic', 'suffix').decode('string-escape')
def motd_from_str(self, s): sep = config.get('Topic', 'separator').decode('string-escape') self.motd_str = re.split( '%s|%s' % ( re.escape(sep), re.escape(filter_irc_colors(sep)) ), s)
def _split_reply(self, msg, split, times): """Splits a reply into multiple messages. @arg splitpoint: what pattern is it best to split at?""" times += 1 added_len = len("PRIVMSG %s \n"%self.nick) if len(msg) + added_len <= 255: self.reply(msg) else: more_suffix = "" if times == config.getint("Bot", "max reply splits before waiting"): more_suffix = split \ + _("Reply is too long, use \x02%(prefix)smore\x02 to continue reading.")\ % {'prefix':config.get('Bot', 'command prefix')} added_len += len(more_suffix) m = re.match("^(?P<send>.{0,%d})%s(?P<rest>.*?)$"\ % (255-added_len, re.escape(split)), msg) if not m: # If we can't split conveniently, cut straight in self.reply(msg[:255-added_len]+more_suffix) rest = msg[255-added_len:] else: self.reply(m.group('send')+more_suffix) rest = m.group('rest') if len(more_suffix): t = time() self.bot.more_buffer[self.nick] = (rest, t) reactor.callLater(60, self._dropMoreBuffer, t) else: self._split_reply(rest, split, times)
def _printResult(r): o = [] for nick, ts, id in r: date = datetime.fromtimestamp(ts) o.append(config.get('Pickup player tracking', 'lastgames game').decode('string-escape') % { 'year': date.year, 'month': date.month, 'day': date.day, 'hour': date.hour, 'minutes': date.minute, 'nick': nick, 'id': id, }) o.reverse() call.reply(config.get('Pickup player tracking', 'lastgames').decode('string-escape')%{ 'games': ', '.join(games), 'lastgames': config.get('Pickup player tracking', 'lastgames separator').decode('string-escape').join(o) }, config.get('Pickup player tracking', 'lastgames separator').decode('string-escape'))
def _handleMore(self): if self.nick in self.bot.more_buffer: if self.bot.more_buffer[self.nick][1] + 5 > time(): self.reply(_("Please wait between \x02%(prefix)smore\x02 calls.") \ % {'prefix':config.get('Bot', 'command prefix')}) else: self.reply(self.bot.more_buffer[self.nick][0]) else: self.reply(_("There's nothing more."))
def _knowAdmin(admin): if self.last_promote + config.getint('Pickup', 'promote delay') > time() \ and not admin: raise InputError(_("Can't promote so often.")) game = self.get_game(call, args) if call.nick not in game.players \ and not admin: raise InputError(_("Join the game yourself before promoting it.")) self.last_promote = time() self.pypickupbot.cmsg( config.get('Pickup messages', 'promote').decode('string-escape') % { 'bold': '\x02', 'prefix': config.get('Bot', 'command prefix'), 'name': game.name, 'nick': game.nick, 'command': config.get('Bot', 'command prefix')+'add '+game.nick, 'channel': self.pypickupbot.channel, 'playersneeded': game.maxplayers-len(game.players), 'maxplayers': game.maxplayers, 'numplayers': len(game.players), })
def who(self, call, args): """!who [game [game ..]] Shows who has signed up""" games = [i for i in self.get_games(call, args).who() if i != None] all = False if len(args) < 1 or len(args) == len(self.games): all = True if len(games): if all: call.reply(_("All games:")+" "+config.get('Pickup messages', 'who game separator').decode('string-escape').join(games), config.get('Pickup messages', 'who game separator').decode('string-escape')) else: call.reply(config.get('Pickup messages', 'who game separator').decode('string-escape').join(games), config.get('Pickup messages', 'who game separator').decode('string-escape')) else: if all: call.reply(_("No game going on!")) else: call.reply(_n("No game in mode %s", "No game in modes %s", len(args)) % ' '.join(args) )
def update_topic(self): """Update the pickup part of the channel topic""" config_topic = config.getint('Pickup', 'topic') if not config_topic: return out = [] for gamenick in self.order: game = self.games[gamenick] if config_topic == 1 or game.players: out.append( config.get('Pickup messages', 'topic game').decode('string-escape') % { 'nick': game.nick, 'playernum': len(game.players), 'playermax': game.maxplayers, 'name': game.name, 'numcaps': game.caps }) self.topic.update( config.get('Pickup messages', 'topic game separator')\ .decode('string-escape')\ .join(out) )
def confirm(self, msg, wait=60, split=" ", assume=False): """Prompts caller for confirmation. @arg wait: time in seconds to wait for confirmation until it is assumed to be dismissed. @returns deferred fired with True/False""" if self.nick in self.bot.prompts[self.channel]: self._removePrompt(self.bot.prompts[self.channel][self.nick][1]) self.reply( msg + " " + _("Reply with \x02%(prefix)syes\x02 or \x02%(prefix)sno\x02.") % {'prefix':config.get('Bot', 'command prefix')}, split) t = time() d = defer.Deferred() self.bot.prompts[self.channel][self.nick] = (d, t, assume) reactor.callLater(60, self._removePrompt, t) return d
def who(self): """Who is in this game""" if len(self.players): return config.get('Pickup messages', 'who game').decode('string-escape') % {'nick': self.nick, 'playernum': len(self.players), 'playermax': self.maxplayers, 'name': self.name, 'numcaps': self.caps, 'playerlist': ', '.join(self.players) }
def __init__(self, bot, user, channel, message): self.bot = bot self.user = user self.nick = user.split('!',1)[0] self.channel = channel command = str() if channel[0]=='#': if message.startswith(config.get('Bot', 'command prefix')): command = message[len(config.get('Bot', 'command prefix')):] self.context = self.CONTEXT_COMMAND else: m = re.match( '^'+re.escape(self.bot.nickname)+'[^A-Za-z0-9 ]\W*(.*)', message ) if m and config.getboolean('Bot', 'allow mentions'): command = m.group(1) self.context = self.CONTEXT_MENTION else: # chanmsg return elif channel == self.bot.nickname: command = message self.context = self.CONTEXT_PRIVATE self.channel = 'PM' else: return self.args = command.split() self.cmd = self.args.pop(0).lower() if self.cmd in ['yes', 'no']: self._handle_confirm_reply() return if self.cmd == 'more': log.msg(_("{0} asked for more")) self._handleMore() return if self.cmd not in self.bot.commands: log.msg(_("{0} attempted to use unknown command {1}.").format(self.nick, self.cmd)) if config.getboolean('Bot', 'warn on unknown command'): self.reply(_("Unknown command %s.") % self.cmd) return flags = self.bot.commands[self.cmd][1] can_run = [] if flags & COMMAND.ADMIN: def _knowIs_admin(is_admin): if not is_admin: log.msg(_("{0} attempted to use admin command {1}.").format(self.nick, self.cmd)) raise InputError(_("Command %s is only available to admins.") % self.cmd) else: return True can_run.append( self.bot.is_admin(self.user, self.nick)\ .addCallback(_knowIs_admin) ) if self.context == self.CONTEXT_PRIVATE and flags & COMMAND.NOT_FROM_PM: log.msg(_("{0} attempted to use command {1} in a PM.").format(self.nick, self.cmd)) can_run.append(defer.fail(InputError( _("Command %s cannot be used in private.") % self.cmd))) else: can_run.append(defer.succeed(True)) if self.context == self.CONTEXT_COMMAND and flags & COMMAND.NOT_FROM_CHANNEL: log.msg(_("{0} attempted to use command {1} in a channel.").format(self.nick, self.cmd)) can_run.append(defer.fail(InputError( _("Command {0} cannot be used in public.").format(self.cmd)))) else: can_run.append(defer.succeed(True)) def _canRun(true): log.msg(message) try: d = log.callWithContext({'system': 'pypickupbot %s %s'%(self.channel,self.cmd)}, self.bot.commands[self.cmd][0], self, self.args) if isinstance(d, defer.Deferred): d.addErrback(_catchInputError).addErrback(_catchInternalError) except InputError as e: self.reply(str(e)) except Exception as e: self.reply(_("Internal error.")) log.err() def _catchInputError(f): t = f.trap(InputError) self.reply(str(f.value)) def _catchInternalError(f): f.trap(Exception) self.reply(_("Internal error.")) f.printTraceback() defer.DeferredList(can_run, fireOnOneErrback=True, consumeErrors=True)\ .addCallbacks(_canRun, _catchInputError).addErrback(_catchInternalError)
def __init__(self): self.channels = config.getlist('Server', 'channels') self.nickname = config.get('Bot', 'nickname')
def do_start(self): """Does the actual starting of the game""" if self.abort_start or not self.starting: self.abort_start = False self.starting = False return players = self.players[:self.maxplayers] for player in players: self.pickup.all_games().force_remove(player) self.pickup.update_topic() self.pickup.pypickupbot.notice(self.pickup.pypickupbot.channel, _("%(gamenick)s game ready to start in %(channel)s") % {'gamenick': self.nick, 'channel': self.pickup.pypickupbot.channel}) captains = [] if not self.autopick: pickpool = sorted(players) captains = random.sample(pickpool,2) self.pickup.pypickupbot.fire('pickup_game_starting', self, players, captains) if len( captains ) > 0: self.pickup.pypickupbot.msg( self.pickup.pypickupbot.channel, config.get('Pickup messages', 'game ready').decode('string-escape')% { 'nick': self.nick, 'playernum': len(self.players), 'playermax': self.maxplayers, 'name': self.name, 'numcaps': self.caps, 'playerlist': ', '.join(players), 'captainlist': ', '.join(captains) }) if config.getboolean("Pickup", "PM each player on start"): for player in players: self.pickup.pypickupbot.msg(player, config.get("Pickup messages", "youre needed").decode('string-escape')% { 'channel': self.pickup.pypickupbot.channel, 'name': self.name, 'nick': self.nick, 'numcaps': self.caps, 'playerlist': ', '.join(players), 'captainlist': ', '.join(captains) }) else: self.pickup.pypickupbot.msg( self.pickup.pypickupbot.channel, config.get('Pickup messages', 'game ready nocaptains').decode('string-escape')% { 'nick': self.nick, 'playernum': len(self.players), 'playermax': self.maxplayers, 'name': self.name, 'numcaps': self.caps, 'playerlist': ', '.join(players) }) if config.getboolean("Pickup", "PM each player on start"): for player in players: self.pickup.pypickupbot.msg(player, config.get("Pickup messages", "youre needed nocaptains").decode('string-escape')% { 'channel': self.pickup.pypickupbot.channel, 'name': self.name, 'nick': self.nick, 'numcaps': self.caps, 'playerlist': ', '.join(players), }) else: teams = [[] for i in range(self.caps)] players_ = sorted(players) for i in range(len(players)): player = random.choice(players_) players_.remove(player) teams[i % self.caps].append(player) self.pickup.pypickupbot.fire('pickup_game_starting', self, teams, captains) self.pickup.pypickupbot.cmsg( config.get('Pickup messages', 'game ready autopick').decode('string-escape')% { 'nick': self.nick, 'playernum': len(players), 'playermax': self.maxplayers, 'name': self.name, 'numcaps': self.caps, 'teamslist': ', '.join([ config.get('Pickup messages', 'game ready autopick team').decode('string-escape')% { 'name': self.teamname(i), 'players': ', '.join(team) } for i, team in enumerate(teams)]) }) self.pickup.pypickupbot.fire('pickup_game_started', self, players, captains) self.starting = False
def joinedHomeChannel(self): """when home channel joined, set topic""" if config.get('Pickup', 'topic'): self.topic = self.pypickupbot.topic.add('', Topic.GRAVITY_BEGINNING) self.update_topic()