""" bots.py: Spawn virtual users/bots on a PyLink server and make them interact with things. """ import sys import os sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import utils from log import log @utils.add_cmd def spawnclient(irc, source, args): """ Admin-only. Spawns the specified PseudoClient on the PyLink server. Note: this doesn't check the validity of any fields you give it!""" utils.checkAuthenticated(irc, source, allowOper=False) try: nick, ident, host = args[:3] except ValueError: irc.reply("Error: Not enough arguments. Needs 3: nick, user, host.") return irc.proto.spawnClient(nick, ident, host, manipulatable=True) @utils.add_cmd def quit(irc, source, args): """ [] Admin-only. Quits the PyLink client with nick , if one exists.""" utils.checkAuthenticated(irc, source, allowOper=False) try: nick = args[0] except IndexError: irc.reply("Error: Not enough arguments. Needs 1-2: nick, reason (optional).") return if irc.pseudoclient.uid == utils.nickToUid(irc, nick): irc.reply("Error: Cannot quit the main PyLink PseudoClient!") return u = utils.nickToUid(irc, nick) quitmsg = ' '.join(args[1:]) or 'Client Quit' if not utils.isManipulatableClient(irc, u): irc.reply("Error: Cannot force quit a protected PyLink services client.") return irc.proto.quitClient(u, quitmsg) irc.callHooks([u, 'PYLINK_BOTSPLUGIN_QUIT', {'text': quitmsg, 'parse_as': 'QUIT'}]) def joinclient(irc, source, args): """ ,[], etc. Admin-only. Joins , the nick of a PyLink client, to a comma-separated list of channels.""" utils.checkAuthenticated(irc, source, allowOper=False) try: nick = args[0] clist = args[1].split(',') if not clist: raise IndexError except IndexError: irc.reply("Error: Not enough arguments. Needs 2: nick, comma separated list of channels.") return u = utils.nickToUid(irc, nick) if not utils.isManipulatableClient(irc, u): irc.reply("Error: Cannot force join a protected PyLink services client.") return for channel in clist: if not utils.isChannel(channel): irc.reply("Error: Invalid channel name %r." % channel) return irc.proto.joinClient(u, channel) irc.callHooks([u, 'PYLINK_BOTSPLUGIN_JOIN', {'channel': channel, 'users': [u], 'modes': irc.channels[channel].modes, 'parse_as': 'JOIN'}]) utils.add_cmd(joinclient, name='join') @utils.add_cmd def nick(irc, source, args): """ Admin-only. Changes the nick of , a PyLink client, to .""" utils.checkAuthenticated(irc, source, allowOper=False) try: nick = args[0] newnick = args[1] except IndexError: irc.reply("Error: Not enough arguments. Needs 2: nick, newnick.") return u = utils.nickToUid(irc, nick) if newnick in ('0', u): newnick = u elif not utils.isNick(newnick): irc.reply('Error: Invalid nickname %r.' % newnick) return elif not utils.isManipulatableClient(irc, u): irc.reply("Error: Cannot force nick changes for a protected PyLink services client.") return irc.proto.nickClient(u, newnick) irc.callHooks([u, 'PYLINK_BOTSPLUGIN_NICK', {'newnick': newnick, 'oldnick': nick, 'parse_as': 'NICK'}]) @utils.add_cmd def part(irc, source, args): """ ,[],... [] Admin-only. Parts , the nick of a PyLink client, from a comma-separated list of channels.""" utils.checkAuthenticated(irc, source, allowOper=False) try: nick = args[0] clist = args[1].split(',') reason = ' '.join(args[2:]) except IndexError: irc.reply("Error: Not enough arguments. Needs 2: nick, comma separated list of channels.") return u = utils.nickToUid(irc, nick) if not utils.isManipulatableClient(irc, u): irc.reply("Error: Cannot force part a protected PyLink services client.") return for channel in clist: if not utils.isChannel(channel): irc.reply("Error: Invalid channel name %r." % channel) return irc.proto.partClient(u, channel, reason) irc.callHooks([u, 'PYLINK_BOTSPLUGIN_PART', {'channels': clist, 'text': reason, 'parse_as': 'PART'}]) @utils.add_cmd def mode(irc, source, args): """ Admin-only. Sets modes on from , where is either the nick of a PyLink client, or the SID of a PyLink server. can be either a nick or a channel.""" utils.checkAuthenticated(irc, source, allowOper=False) try: modesource, target, modes = args[0], args[1], args[2:] except IndexError: irc.reply('Error: Not enough arguments. Needs 3: source nick, target, modes to set.') return target = utils.nickToUid(irc, target) or target extclient = target in irc.users and not utils.isInternalClient(irc, target) parsedmodes = utils.parseModes(irc, target, modes) ischannel = target in irc.channels if not (target in irc.users or ischannel): irc.reply("Error: Invalid channel or nick %r." % target) return elif not parsedmodes: irc.reply("Error: No valid modes were given.") return elif not (ischannel or utils.isManipulatableClient(irc, target)): irc.reply("Error: Can only set modes on channels or non-protected PyLink clients.") return if utils.isInternalServer(irc, modesource): # Setting modes from a server. irc.proto.modeServer(modesource, target, parsedmodes) else: # Setting modes from a client. modesource = utils.nickToUid(irc, modesource) irc.proto.modeClient(modesource, target, parsedmodes) irc.callHooks([modesource, 'PYLINK_BOTSPLUGIN_MODE', {'target': target, 'modes': parsedmodes, 'parse_as': 'MODE'}]) @utils.add_cmd def msg(irc, source, args): """ Admin-only. Sends message from , where is the nick of a PyLink client.""" utils.checkAuthenticated(irc, source, allowOper=False) try: msgsource, target, text = args[0], args[1], ' '.join(args[2:]) except IndexError: irc.reply('Error: Not enough arguments. Needs 3: source nick, target, text.') return sourceuid = utils.nickToUid(irc, msgsource) if not sourceuid: irc.reply('Error: Unknown user %r.' % msgsource) return if not utils.isChannel(target): real_target = utils.nickToUid(irc, target) if real_target is None: irc.reply('Error: Unknown user %r.' % target) return else: real_target = target if not text: irc.reply('Error: No text given.') return irc.proto.messageClient(sourceuid, real_target, text) irc.callHooks([sourceuid, 'PYLINK_BOTSPLUGIN_MSG', {'target': real_target, 'text': text, 'parse_as': 'PRIVMSG'}])