def f_reload(bot, trigger): """Reloads a module, for use by admins only.""" if not trigger.admin: return name = trigger.group(2) if name == bot.config.owner: return bot.reply('What?') if not name or name == '*': bot.callables = None bot.commands = None bot.setup() return bot.reply('Reloading all done!') if name not in sys.modules: return bot.reply('%s: not loaded, try the `load` command' % name) old_module = sys.modules[name] old_callables = {} for obj_name, obj in iteritems(vars(old_module)): if bot.is_callable(obj) or bot.is_shutdown(obj): old_callables[obj_name] = obj bot.unregister(old_callables) # Also remove all references to willie callables from top level of the # module, so that they will not get loaded again if reloading the # module does not override them. for obj_name in list(old_callables.keys()): delattr(old_module, obj_name) # Also delete the setup function if hasattr(old_module, "setup"): delattr(old_module, "setup") # Thanks to moot for prodding me on this path = old_module.__file__ if path.endswith('.pyc') or path.endswith('.pyo'): path = path[:-1] if not os.path.isfile(path): return bot.reply('Found %s, but not the source file' % name) module = imp.load_source(name, path) sys.modules[name] = module if hasattr(module, 'setup'): module.setup(bot) mtime = os.path.getmtime(module.__file__) modified = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(mtime)) bot.register(vars(module)) bot.bind_commands() bot.reply('%r (version: %s)' % (module, modified))
def _modules(self): home = os.getcwd() modules_dir = os.path.join(home, 'modules') filenames = self.enumerate_modules() os.sys.path.insert(0, modules_dir) for name, filename in iteritems(filenames): try: module = imp.load_source(name, filename) except Exception as e: print("Error loading %s: %s (in config.py)" % (name, e), file=sys.stderr) else: if hasattr(module, 'configure'): module.configure(self) self.save()
def setup(self): stderr("\nWelcome to lpbot. Loading modules...\n\n") self.callables = set() self.shutdown_methods = set() filenames = self.config.enumerate_modules() # Coretasks is special. No custom user coretasks. this_dir = os.path.dirname(os.path.abspath(__file__)) filenames['coretasks'] = os.path.join(this_dir, 'coretasks.py') modules = [] error_count = 0 for name, filename in iteritems(filenames): try: module = imp.load_source(name, filename) except Exception as e: error_count = error_count + 1 filename, lineno = tools.get_raising_file_and_line() rel_path = os.path.relpath(filename, os.path.dirname(__file__)) raising_stmt = "%s:%d" % (rel_path, lineno) stderr("Error loading %s: %s (%s)" % (name, e, raising_stmt)) else: try: if hasattr(module, 'setup'): module.setup(self) self.register(vars(module)) modules.append(name) except Exception as e: error_count = error_count + 1 filename, lineno = tools.get_raising_file_and_line() rel_path = os.path.relpath( filename, os.path.dirname(__file__) ) raising_stmt = "%s:%d" % (rel_path, lineno) stderr("Error in %s setup procedure: %s (%s)" % (name, e, raising_stmt)) if modules: stderr('\n\nRegistered %d modules,' % (len(modules) - 1)) stderr('%d modules failed to load\n\n' % error_count) else: stderr("Warning: Couldn't find any modules") self.bind_commands()
def handle_names(bot, trigger): """Handle NAMES response, happens when joining to channels.""" names = trigger.split() channels = re.search('(#\S*)', trigger.raw) if not channels: return channel = Identifier(channels.group(1)) if channel not in bot.privileges: bot.privileges[channel] = dict() bot.init_ops_list(channel) # This could probably be made flexible in the future, but I don't think # it'd be worth it. mapping = { '+': lpbot.module.VOICE, '%': lpbot.module.HALFOP, '@': lpbot.module.OP, '&': lpbot.module.ADMIN, '~': lpbot.module.OWNER } for name in names: priv = 0 for prefix, value in iteritems(mapping): if prefix in name: priv = priv | value nick = Identifier(name.lstrip(''.join(mapping.keys()))) bot.privileges[channel][nick] = priv # Old op list maintenance is down here, and should be removed at some # point if '@' in name or '~' in name or '&' in name: bot.add_op(channel, name.lstrip('@&%+~')) bot.add_halfop(channel, name.lstrip('@&%+~')) bot.add_voice(channel, name.lstrip('@&%+~')) elif '%' in name: bot.add_halfop(channel, name.lstrip('@&%+~')) bot.add_voice(channel, name.lstrip('@&%+~')) elif '+' in name: bot.add_voice(channel, name.lstrip('@&%+~'))
def recieve_cap_ls_reply(bot, trigger): if bot.server_capabilities: # We've already seen the results, so someone sent CAP LS from a module. # We're too late to do SASL, and we don't want to send CAP END before # the module has done what it needs to, so just return return bot.server_capabilities = set(trigger.split(' ')) # If some other module requests it, we don't need to add another request. # If some other module prohibits it, we shouldn't request it. if 'multi-prefix' not in bot._cap_reqs: # Whether or not the server supports multi-prefix doesn't change how we # parse it, so we don't need to worry if it fails. bot._cap_reqs['multi-prefix'] = (['', 'coretasks', None], ) for cap, reqs in iteritems(bot._cap_reqs): # At this point, we know mandatory and prohibited don't co-exist, but # we need to call back for optionals if they're also prohibited prefix = '' for entry in reqs: if prefix == '-' and entry[0] != '-': entry[2](bot, entry[0] + cap) continue if entry[0]: prefix = entry[0] # It's not required, or it's supported, so we can request it if prefix != '=' or cap in bot.server_capabilities: # REQs fail as a whole, so we send them one capability at a time bot.write(('CAP', 'REQ', entry[0] + cap)) elif reqs[2]: # Server is going to fail on it, so we call the failure function reqs[2](bot, entry[0] + cap) # If we want to do SASL, we have to wait before we can send CAP END. So if # we are, wait on 903 (SASL successful) to send it. if bot.config.core.sasl_password: bot.write(('CAP', 'REQ', 'sasl')) else: bot.write(('CAP', 'END'))
def recieve_cap_ls_reply(bot, trigger): if bot.server_capabilities: # We've already seen the results, so someone sent CAP LS from a module. # We're too late to do SASL, and we don't want to send CAP END before # the module has done what it needs to, so just return return bot.server_capabilities = set(trigger.split(' ')) # If some other module requests it, we don't need to add another request. # If some other module prohibits it, we shouldn't request it. if 'multi-prefix' not in bot._cap_reqs: # Whether or not the server supports multi-prefix doesn't change how we # parse it, so we don't need to worry if it fails. bot._cap_reqs['multi-prefix'] = (['', 'coretasks', None],) for cap, reqs in iteritems(bot._cap_reqs): # At this point, we know mandatory and prohibited don't co-exist, but # we need to call back for optionals if they're also prohibited prefix = '' for entry in reqs: if prefix == '-' and entry[0] != '-': entry[2](bot, entry[0] + cap) continue if entry[0]: prefix = entry[0] # It's not required, or it's supported, so we can request it if prefix != '=' or cap in bot.server_capabilities: # REQs fail as a whole, so we send them one capability at a time bot.write(('CAP', 'REQ', entry[0] + cap)) elif reqs[2]: # Server is going to fail on it, so we call the failure function reqs[2](bot, entry[0] + cap) # If we want to do SASL, we have to wait before we can send CAP END. So if # we are, wait on 903 (SASL successful) to send it. if bot.config.core.sasl_password: bot.write(('CAP', 'REQ', 'sasl')) else: bot.write(('CAP', 'END'))
def handle_names(bot, trigger): """Handle NAMES response, happens when joining to channels.""" names = trigger.split() #TODO specific to one channel type. See issue 281. channels = re.search('(#\S*)', trigger.raw) if not channels: return channel = Identifier(channels.group(1)) if channel not in bot.privileges: bot.privileges[channel] = dict() bot.init_ops_list(channel) # This could probably be made flexible in the future, but I don't think # it'd be worth it. mapping = {'+': lpbot.module.VOICE, '%': lpbot.module.HALFOP, '@': lpbot.module.OP, '&': lpbot.module.ADMIN, '~': lpbot.module.OWNER} for name in names: priv = 0 for prefix, value in iteritems(mapping): if prefix in name: priv = priv | value nick = Identifier(name.lstrip(''.join(mapping.keys()))) bot.privileges[channel][nick] = priv # Old op list maintenance is down here, and should be removed at some # point if '@' in name or '~' in name or '&' in name: bot.add_op(channel, name.lstrip('@&%+~')) bot.add_halfop(channel, name.lstrip('@&%+~')) bot.add_voice(channel, name.lstrip('@&%+~')) elif '%' in name: bot.add_halfop(channel, name.lstrip('@&%+~')) bot.add_voice(channel, name.lstrip('@&%+~')) elif '+' in name: bot.add_voice(channel, name.lstrip('@&%+~'))