def _modules(self): home = os.getcwd() modules_dir = os.path.join(home, 'modules') filenames = willie.loader.enumerate_modules(self) os.sys.path.insert(0, modules_dir) for name, mod_spec in iteritems(filenames): path, type_ = mod_spec try: module, _ = willie.loader.load_module(name, path, type_) except Exception as e: filename, lineno = willie.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: if hasattr(module, 'configure'): prompt = name + ' module' if module.__doc__: doc = module.__doc__.split('\n', 1)[0] if doc: prompt = doc prompt = 'Configure {} (y/n)? [n]'.format(prompt) do_configure = get_input(prompt) do_configure = do_configure and do_configure.lower() == 'y' if do_configure: module.configure(self) self.save()
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 == '*') or (name.upper() == 'ALL THE THINGS'): bot.callables = None bot.commands = None bot.setup() return bot.reply('done') if not name in sys.modules: return bot.reply('%s: no such module!' % 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 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 _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 Willie. 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() try: rel_path = os.path.relpath( filename, os.path.dirname(__file__) ) except Exception as e2: rel_path = filename 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 check_callbacks(bot, trigger, url, run=True): """ Check the given URL against the callbacks list. If it matches, and ``run`` is given as ``True``, run the callback function, otherwise pass. Returns ``True`` if the url matched anything in the callbacks list. """ # Check if it matches the exclusion list first matched = any(regex.search(url) for regex in bot.memory['url_exclude']) # Then, check if there's anything in the callback list for regex, function in tools.iteritems(bot.memory['url_callbacks']): match = regex.search(url) if match: if run: function(bot, trigger, match) matched = True return matched
def setup(self): stderr("\nWelcome to Willie. 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() #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 = { '+': willie.module.VOICE, '%': willie.module.HALFOP, '@': willie.module.OP, '&': willie.module.ADMIN, '~': willie.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 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 = { "+": willie.module.VOICE, "%": willie.module.HALFOP, "@": willie.module.OP, "&": willie.module.ADMIN, "~": willie.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 req[2]: # Server is going to fail on it, so we call the failure function req[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.auth_method == 'sasl' or 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 req[2]: # Server is going to fail on it, so we call the failure function req[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.auth_method == 'sasl' or 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*)', bot.raw) if not channels: return channel = Nick(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 = {'+': willie.module.VOICE, '%': willie.module.HALFOP, '@': willie.module.OP, '&': willie.module.ADMIN, '~': willie.module.OWNER} for name in names: priv = 0 for prefix, value in iteritems(mapping): if prefix in name: priv = priv | value nick = Nick(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 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.core.owner: return bot.reply('What?') if not name or name == '*' or name.upper() == 'ALL THE THINGS': bot.callables = None bot.commands = None bot.setup() return bot.reply('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)): bot.unregister(obj) # 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 old_callables.keys(): delattr(old_module, obj_name) # Also delete the setup function if hasattr(old_module, "setup"): delattr(old_module, "setup") modules = willie.loader.enumerate_modules(bot.config) path, type_ = modules[name] load_module(bot, name, path, type_)