Example #1
0
 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()
Example #2
0
 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()
Example #3
0
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))
Example #4
0
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))
Example #5
0
 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()
Example #6
0
 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()
Example #7
0
    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()
Example #8
0
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
Example #9
0
    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()
Example #10
0
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('@&%+~'))
Example #11
0
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("@&%+~"))
Example #12
0
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'))
Example #13
0
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'))
Example #14
0
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('@&%+~'))
Example #15
0
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_)
Example #16
0
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_)