mirror of
https://github.com/weechat/weechat.git
synced 2026-06-25 20:36:38 +02:00
66cb9f6ea2
The type "enum" replaces type "integer" when used with string values. For compatibility, any option created with type "integer" and string values is automatically created to "enum" on creation, with no error.
1557 lines
53 KiB
C
1557 lines
53 KiB
C
/*
|
|
* plugin.c - WeeChat plugins management (load/unload dynamic C libraries)
|
|
*
|
|
* Copyright (C) 2003-2023 Sébastien Helleu <flashcode@flashtux.org>
|
|
*
|
|
* This file is part of WeeChat, the extensible chat client.
|
|
*
|
|
* WeeChat is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* WeeChat is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with WeeChat. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <unistd.h>
|
|
#include <libgen.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <dirent.h>
|
|
#include <dlfcn.h>
|
|
|
|
#include "../core/weechat.h"
|
|
#include "../core/wee-arraylist.h"
|
|
#include "../core/wee-config.h"
|
|
#include "../core/wee-dir.h"
|
|
#include "../core/wee-eval.h"
|
|
#include "../core/wee-hashtable.h"
|
|
#include "../core/wee-hdata.h"
|
|
#include "../core/wee-hook.h"
|
|
#include "../core/wee-infolist.h"
|
|
#include "../core/wee-list.h"
|
|
#include "../core/wee-log.h"
|
|
#include "../core/wee-network.h"
|
|
#include "../core/wee-string.h"
|
|
#include "../core/wee-upgrade-file.h"
|
|
#include "../core/wee-utf8.h"
|
|
#include "../core/wee-util.h"
|
|
#include "../gui/gui-bar.h"
|
|
#include "../gui/gui-bar-item.h"
|
|
#include "../gui/gui-buffer.h"
|
|
#include "../gui/gui-chat.h"
|
|
#include "../gui/gui-color.h"
|
|
#include "../gui/gui-completion.h"
|
|
#include "../gui/gui-key.h"
|
|
#include "../gui/gui-nicklist.h"
|
|
#include "../gui/gui-window.h"
|
|
#include "plugin.h"
|
|
#include "plugin-api.h"
|
|
#include "plugin-config.h"
|
|
|
|
|
|
int plugin_quiet = 0;
|
|
struct t_weechat_plugin *weechat_plugins = NULL;
|
|
struct t_weechat_plugin *last_weechat_plugin = NULL;
|
|
|
|
/* structure used to give arguments to callback of ... */
|
|
struct t_plugin_args
|
|
{
|
|
int argc;
|
|
char **argv;
|
|
};
|
|
|
|
int plugin_autoload_count = 0; /* number of items in autoload_array */
|
|
char **plugin_autoload_array = NULL; /* autoload array, this is split of */
|
|
/* option "weechat.plugin.autoload" */
|
|
|
|
|
|
void plugin_remove (struct t_weechat_plugin *plugin);
|
|
|
|
|
|
/*
|
|
* Checks if a plugin pointer is valid.
|
|
*
|
|
* Returns:
|
|
* 1: plugin exists
|
|
* 0: plugin does not exist
|
|
*/
|
|
|
|
int
|
|
plugin_valid (struct t_weechat_plugin *plugin)
|
|
{
|
|
struct t_weechat_plugin *ptr_plugin;
|
|
|
|
if (!plugin)
|
|
return 0;
|
|
|
|
for (ptr_plugin = weechat_plugins; ptr_plugin;
|
|
ptr_plugin = ptr_plugin->next_plugin)
|
|
{
|
|
if (ptr_plugin == plugin)
|
|
return 1;
|
|
}
|
|
|
|
/* plugin not found */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Searches for a plugin by name.
|
|
*
|
|
* Returns pointer to plugin found, NULL if not found.
|
|
*/
|
|
|
|
struct t_weechat_plugin *
|
|
plugin_search (const char *name)
|
|
{
|
|
struct t_weechat_plugin *ptr_plugin;
|
|
|
|
if (!name)
|
|
return NULL;
|
|
|
|
for (ptr_plugin = weechat_plugins; ptr_plugin;
|
|
ptr_plugin = ptr_plugin->next_plugin)
|
|
{
|
|
if (strcmp (ptr_plugin->name, name) == 0)
|
|
return ptr_plugin;
|
|
}
|
|
|
|
/* plugin not found */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Gets name of a plugin with a pointer.
|
|
*/
|
|
|
|
const char *
|
|
plugin_get_name (struct t_weechat_plugin *plugin)
|
|
{
|
|
static char *plugin_core = PLUGIN_CORE;
|
|
|
|
return (plugin) ? plugin->name : plugin_core;
|
|
}
|
|
|
|
/*
|
|
* Checks if extension of filename is allowed by option
|
|
* "weechat.plugin.extension".
|
|
*
|
|
* Returns:
|
|
* 1: extension allowed
|
|
* 0: extension not allowed
|
|
*/
|
|
|
|
int
|
|
plugin_check_extension_allowed (const char *filename)
|
|
{
|
|
int i, length, length_ext;
|
|
|
|
/* extension allowed if no extension is defined */
|
|
if (!config_plugin_extensions)
|
|
return 1;
|
|
|
|
if (!filename)
|
|
return 0;
|
|
|
|
length = strlen (filename);
|
|
for (i = 0; i < config_num_plugin_extensions; i++)
|
|
{
|
|
length_ext = strlen (config_plugin_extensions[i]);
|
|
if (length >= length_ext)
|
|
{
|
|
if (strcmp (filename + length - length_ext,
|
|
config_plugin_extensions[i]) == 0)
|
|
{
|
|
/* extension allowed */
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* extension not allowed */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Checks if a plugin can be autoloaded.
|
|
*
|
|
* List of autoloaded plugins is set in option "weechat.plugin.autoload".
|
|
*
|
|
* Returns:
|
|
* 1: plugin can be autoloaded
|
|
* 0: plugin can not be autoloaded
|
|
*/
|
|
|
|
int
|
|
plugin_check_autoload (const char *filename)
|
|
{
|
|
int i, length, length_ext, match;
|
|
char *full_name, *ptr_base_name, *base_name, *plugin_name;
|
|
|
|
/* by default we can auto load all plugins */
|
|
if (!plugin_autoload_array)
|
|
return 1;
|
|
|
|
full_name = strdup (filename);
|
|
if (!full_name)
|
|
return 0;
|
|
|
|
/* get short name of plugin (filename without extension) */
|
|
plugin_name = NULL;
|
|
ptr_base_name = basename (full_name);
|
|
if (!ptr_base_name)
|
|
{
|
|
free (full_name);
|
|
return 1;
|
|
}
|
|
|
|
base_name = strdup (ptr_base_name);
|
|
if (!base_name)
|
|
{
|
|
free (full_name);
|
|
return 1;
|
|
}
|
|
|
|
free (full_name);
|
|
|
|
if (config_plugin_extensions)
|
|
{
|
|
length = strlen (base_name);
|
|
for (i = 0; i < config_num_plugin_extensions; i++)
|
|
{
|
|
length_ext = strlen (config_plugin_extensions[i]);
|
|
if (length >= length_ext)
|
|
{
|
|
if (strcmp (base_name + length - length_ext,
|
|
config_plugin_extensions[i]) == 0)
|
|
{
|
|
plugin_name = string_strndup (base_name, length - length_ext);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
plugin_name = strdup (base_name);
|
|
}
|
|
|
|
free (base_name);
|
|
|
|
if (!plugin_name)
|
|
return 1;
|
|
|
|
match = string_match_list (plugin_name,
|
|
(const char **)plugin_autoload_array,
|
|
1);
|
|
|
|
free (plugin_name);
|
|
|
|
return match;
|
|
}
|
|
|
|
/*
|
|
* Returns arguments for plugins (only the relevant arguments for plugins,
|
|
* arguments for WeeChat core not returned).
|
|
*
|
|
* Note: plugin_argv must be freed after use.
|
|
*/
|
|
|
|
void
|
|
plugin_get_args (int argc, char **argv,
|
|
int *plugin_argc, char ***plugin_argv,
|
|
int *no_connect, int *no_script)
|
|
{
|
|
int i, temp_argc;
|
|
char **temp_argv;
|
|
|
|
temp_argc = 0;
|
|
temp_argv = NULL;
|
|
|
|
*no_connect = 0;
|
|
*no_script = 0;
|
|
|
|
if (argc > 0)
|
|
{
|
|
temp_argv = malloc ((argc + 1) * sizeof (*temp_argv));
|
|
if (temp_argv)
|
|
{
|
|
for (i = 0; i < argc; i++)
|
|
{
|
|
if ((strcmp (argv[i], "-a") == 0)
|
|
|| (strcmp (argv[i], "--no-connect") == 0))
|
|
{
|
|
*no_connect = 1;
|
|
}
|
|
else if ((strcmp (argv[i], "-s") == 0)
|
|
|| (strcmp (argv[i], "--no-script") == 0))
|
|
{
|
|
*no_script = 1;
|
|
}
|
|
else if (argv[i][0] != '-')
|
|
{
|
|
temp_argv[temp_argc++] = argv[i];
|
|
}
|
|
}
|
|
if (temp_argc == 0)
|
|
{
|
|
free (temp_argv);
|
|
temp_argv = NULL;
|
|
}
|
|
else
|
|
temp_argv[temp_argc] = NULL;
|
|
}
|
|
}
|
|
|
|
*plugin_argc = temp_argc;
|
|
*plugin_argv = temp_argv;
|
|
}
|
|
|
|
/*
|
|
* Initializes a plugin by calling its init() function.
|
|
*
|
|
* Returns:
|
|
* 1: OK
|
|
* 0: error
|
|
*/
|
|
|
|
int
|
|
plugin_call_init (struct t_weechat_plugin *plugin, int argc, char **argv)
|
|
{
|
|
t_weechat_init_func *init_func;
|
|
int no_connect, rc, old_auto_connect, no_script, old_auto_load_scripts;
|
|
int plugin_argc;
|
|
char **plugin_argv;
|
|
|
|
if (plugin->initialized)
|
|
return 1;
|
|
|
|
/* look for plugin init function */
|
|
init_func = dlsym (plugin->handle, "weechat_plugin_init");
|
|
if (!init_func)
|
|
return 0;
|
|
|
|
/* get arguments for the plugin */
|
|
plugin_get_args (argc, argv,
|
|
&plugin_argc, &plugin_argv, &no_connect, &no_script);
|
|
|
|
old_auto_connect = weechat_auto_connect;
|
|
weechat_auto_connect = (no_connect) ? 0 : 1;
|
|
|
|
old_auto_load_scripts = weechat_auto_load_scripts;
|
|
weechat_auto_load_scripts = (no_script) ? 0 : 1;
|
|
|
|
/* init plugin */
|
|
if (weechat_debug_core >= 1)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("Initializing plugin \"%s\" (priority: %d)"),
|
|
plugin->name,
|
|
plugin->priority);
|
|
}
|
|
rc = ((t_weechat_init_func *)init_func) (plugin,
|
|
plugin_argc, plugin_argv);
|
|
if (rc == WEECHAT_RC_OK)
|
|
{
|
|
plugin->initialized = 1;
|
|
}
|
|
else
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sUnable to initialize plugin \"%s\""),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
plugin->filename);
|
|
}
|
|
|
|
weechat_auto_connect = old_auto_connect;
|
|
weechat_auto_load_scripts = old_auto_load_scripts;
|
|
|
|
if (plugin_argv)
|
|
free (plugin_argv);
|
|
|
|
return (rc == WEECHAT_RC_OK) ? 1 : 0;
|
|
}
|
|
|
|
/*
|
|
* Loads a WeeChat plugin (a dynamic library).
|
|
*
|
|
* If init_plugin == 1, then the init() function in plugin is called
|
|
* (with argc/argv), otherwise the plugin is just loaded but not initialized.
|
|
*
|
|
* Returns a pointer to new WeeChat plugin, NULL if error.
|
|
*/
|
|
|
|
struct t_weechat_plugin *
|
|
plugin_load (const char *filename, int init_plugin, int argc, char **argv)
|
|
{
|
|
void *handle;
|
|
char *name, *api_version, *author, *description, *version;
|
|
char *license, *charset;
|
|
t_weechat_init_func *init_func;
|
|
int *priority;
|
|
struct t_weechat_plugin *new_plugin;
|
|
struct t_config_option *ptr_option;
|
|
|
|
if (!filename)
|
|
return NULL;
|
|
|
|
/*
|
|
* if plugin must not be autoloaded, then return immediately
|
|
* Note: the "plugin_autoload_array" variable is set only during auto-load,
|
|
* ie when WeeChat is starting or when doing /plugin autoload
|
|
*/
|
|
if (plugin_autoload_array && !plugin_check_autoload (filename))
|
|
return NULL;
|
|
|
|
handle = dlopen (filename, RTLD_GLOBAL | RTLD_NOW);
|
|
if (!handle)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sUnable to load plugin \"%s\": %s"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
filename, dlerror ());
|
|
gui_chat_printf (NULL,
|
|
_("%sIf you're trying to load a script and not a C "
|
|
"plugin, try command to load scripts (/perl, "
|
|
"/python, ...)"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]);
|
|
return NULL;
|
|
}
|
|
|
|
/* look for plugin name */
|
|
name = dlsym (handle, "weechat_plugin_name");
|
|
if (!name)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sSymbol \"%s\" not found in plugin \"%s\", "
|
|
"failed to load"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
"weechat_plugin_name",
|
|
filename);
|
|
dlclose (handle);
|
|
return NULL;
|
|
}
|
|
|
|
/* look for API version */
|
|
api_version = dlsym (handle, "weechat_plugin_api_version");
|
|
if (!api_version)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sSymbol \"%s\" not found in plugin \"%s\", "
|
|
"failed to load"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
"weechat_plugin_api_version",
|
|
filename);
|
|
gui_chat_printf (NULL,
|
|
_("%sIf plugin \"%s\" is old/obsolete, you can "
|
|
"delete this file."),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
name);
|
|
dlclose (handle);
|
|
return NULL;
|
|
}
|
|
if (strcmp (api_version, WEECHAT_PLUGIN_API_VERSION) != 0)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sAPI mismatch for plugin \"%s\" (current API: "
|
|
"\"%s\", plugin API: \"%s\"), failed to load"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
filename,
|
|
WEECHAT_PLUGIN_API_VERSION,
|
|
api_version);
|
|
gui_chat_printf (NULL,
|
|
_("%sIf plugin \"%s\" is old/obsolete, you can "
|
|
"delete this file."),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
name);
|
|
dlclose (handle);
|
|
return NULL;
|
|
}
|
|
|
|
/* check for plugin with same name */
|
|
if (plugin_search (name))
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sUnable to load plugin \"%s\": a plugin with "
|
|
"same name already exists"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
filename);
|
|
dlclose (handle);
|
|
return NULL;
|
|
}
|
|
|
|
/* look for plugin description */
|
|
description = dlsym (handle, "weechat_plugin_description");
|
|
if (!description)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sSymbol \"%s\" not found in plugin \"%s\", "
|
|
"failed to load"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
"weechat_plugin_description",
|
|
filename);
|
|
dlclose (handle);
|
|
return NULL;
|
|
}
|
|
|
|
/* look for plugin author */
|
|
author = dlsym (handle, "weechat_plugin_author");
|
|
if (!author)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sSymbol \"%s\" not found in plugin \"%s\", "
|
|
"failed to load"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
"weechat_plugin_author",
|
|
filename);
|
|
dlclose (handle);
|
|
return NULL;
|
|
}
|
|
|
|
/* look for plugin version */
|
|
version = dlsym (handle, "weechat_plugin_version");
|
|
if (!version)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sSymbol \"%s\" not found in plugin \"%s\", "
|
|
"failed to load"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
"weechat_plugin_version",
|
|
filename);
|
|
dlclose (handle);
|
|
return NULL;
|
|
}
|
|
|
|
/* look for plugin license */
|
|
license = dlsym (handle, "weechat_plugin_license");
|
|
if (!license)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sSymbol \"%s\" not found in plugin \"%s\", "
|
|
"failed to load"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
"weechat_plugin_license",
|
|
filename);
|
|
dlclose (handle);
|
|
return NULL;
|
|
}
|
|
|
|
/* look for plugin charset (optional, default is UTF-8) */
|
|
charset = dlsym (handle, "weechat_plugin_charset");
|
|
|
|
/* look for plugin init function */
|
|
init_func = dlsym (handle, "weechat_plugin_init");
|
|
if (!init_func)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sFunction \"%s\" not found in plugin \"%s\", "
|
|
"failed to load"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
"weechat_plugin_init",
|
|
filename);
|
|
dlclose (handle);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* look for plugin priority: it is used to initialize plugins in
|
|
* appropriate order: the important plugins that don't depend on other
|
|
* plugins are initialized first
|
|
*/
|
|
priority = dlsym (handle, "weechat_plugin_priority");
|
|
|
|
/* create new plugin */
|
|
new_plugin = malloc (sizeof (*new_plugin));
|
|
if (new_plugin)
|
|
{
|
|
/* variables */
|
|
new_plugin->filename = strdup (filename);
|
|
new_plugin->handle = handle;
|
|
new_plugin->name = strdup (name);
|
|
new_plugin->description = strdup (description);
|
|
new_plugin->author = strdup (author);
|
|
new_plugin->version = strdup (version);
|
|
new_plugin->license = strdup (license);
|
|
new_plugin->charset = (charset) ? strdup (charset) : NULL;
|
|
new_plugin->priority = (priority) ?
|
|
*priority : PLUGIN_PRIORITY_DEFAULT;
|
|
new_plugin->initialized = 0;
|
|
ptr_option = config_weechat_debug_get (name);
|
|
new_plugin->debug = (ptr_option) ? CONFIG_INTEGER(ptr_option) : 0;
|
|
new_plugin->upgrading = weechat_upgrading;
|
|
new_plugin->variables = hashtable_new (
|
|
32,
|
|
WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_STRING,
|
|
NULL, NULL);
|
|
|
|
/* functions */
|
|
new_plugin->plugin_get_name = &plugin_get_name;
|
|
|
|
new_plugin->charset_set = &plugin_api_charset_set;
|
|
new_plugin->iconv_to_internal = &string_iconv_to_internal;
|
|
new_plugin->iconv_from_internal = &string_iconv_from_internal;
|
|
new_plugin->gettext = &plugin_api_gettext;
|
|
new_plugin->ngettext = &plugin_api_ngettext;
|
|
new_plugin->strndup = &string_strndup;
|
|
new_plugin->string_cut = &string_cut;
|
|
new_plugin->string_tolower = &string_tolower;
|
|
new_plugin->string_toupper = &string_toupper;
|
|
new_plugin->string_charcmp = &string_charcmp;
|
|
new_plugin->string_charcasecmp = &string_charcasecmp;
|
|
new_plugin->strcmp = &string_strcmp;
|
|
new_plugin->strncmp = &string_strncmp;
|
|
new_plugin->strcasecmp = &string_strcasecmp;
|
|
new_plugin->strcasecmp_range = &string_strcasecmp_range;
|
|
new_plugin->strncasecmp = &string_strncasecmp;
|
|
new_plugin->strncasecmp_range = &string_strncasecmp_range;
|
|
new_plugin->strcmp_ignore_chars = &string_strcmp_ignore_chars;
|
|
new_plugin->strcasestr = &string_strcasestr;
|
|
new_plugin->strlen_screen = &gui_chat_strlen_screen;
|
|
new_plugin->string_match = &string_match;
|
|
new_plugin->string_match_list = &string_match_list;
|
|
new_plugin->string_replace = &string_replace;
|
|
new_plugin->string_expand_home = &string_expand_home;
|
|
new_plugin->string_eval_path_home = &string_eval_path_home;
|
|
new_plugin->string_remove_quotes = &string_remove_quotes;
|
|
new_plugin->string_strip = &string_strip;
|
|
new_plugin->string_convert_escaped_chars = &string_convert_escaped_chars;
|
|
new_plugin->string_mask_to_regex = &string_mask_to_regex;
|
|
new_plugin->string_regex_flags = &string_regex_flags;
|
|
new_plugin->string_regcomp = &string_regcomp;
|
|
new_plugin->string_has_highlight = &string_has_highlight;
|
|
new_plugin->string_has_highlight_regex = &string_has_highlight_regex;
|
|
new_plugin->string_replace_regex = &string_replace_regex;
|
|
new_plugin->string_translate_chars = &string_translate_chars;
|
|
new_plugin->string_split = &string_split;
|
|
new_plugin->string_split_shell = &string_split_shell;
|
|
new_plugin->string_free_split = &string_free_split;
|
|
new_plugin->string_rebuild_split_string = &string_rebuild_split_string;
|
|
new_plugin->string_split_command = &string_split_command;
|
|
new_plugin->string_free_split_command = &string_free_split_command;
|
|
new_plugin->string_format_size = &string_format_size;
|
|
new_plugin->string_parse_size = &string_parse_size;
|
|
new_plugin->string_color_code_size = &gui_color_code_size;
|
|
new_plugin->string_remove_color = &gui_color_decode;
|
|
new_plugin->string_base_encode = &string_base_encode;
|
|
new_plugin->string_base_decode = &string_base_decode;
|
|
new_plugin->string_hex_dump = &string_hex_dump;
|
|
new_plugin->string_is_command_char = &string_is_command_char;
|
|
new_plugin->string_input_for_buffer = &string_input_for_buffer;
|
|
new_plugin->string_eval_expression = &eval_expression;
|
|
new_plugin->string_dyn_alloc = &string_dyn_alloc;
|
|
new_plugin->string_dyn_copy = &string_dyn_copy;
|
|
new_plugin->string_dyn_concat = &string_dyn_concat;
|
|
new_plugin->string_dyn_free = &string_dyn_free;
|
|
|
|
new_plugin->utf8_has_8bits = &utf8_has_8bits;
|
|
new_plugin->utf8_is_valid = &utf8_is_valid;
|
|
new_plugin->utf8_normalize = &utf8_normalize;
|
|
new_plugin->utf8_prev_char = &utf8_prev_char;
|
|
new_plugin->utf8_next_char = &utf8_next_char;
|
|
new_plugin->utf8_char_int = &utf8_char_int;
|
|
new_plugin->utf8_char_size = &utf8_char_size;
|
|
new_plugin->utf8_strlen = &utf8_strlen;
|
|
new_plugin->utf8_strnlen = &utf8_strnlen;
|
|
new_plugin->utf8_strlen_screen = &utf8_strlen_screen;
|
|
new_plugin->utf8_char_size_screen = &utf8_char_size_screen;
|
|
new_plugin->utf8_add_offset = &utf8_add_offset;
|
|
new_plugin->utf8_real_pos = &utf8_real_pos;
|
|
new_plugin->utf8_pos = &utf8_pos;
|
|
new_plugin->utf8_strndup = &utf8_strndup;
|
|
new_plugin->utf8_strncpy = &utf8_strncpy;
|
|
|
|
new_plugin->crypto_hash = &plugin_api_crypto_hash;
|
|
new_plugin->crypto_hash_file = &plugin_api_crypto_hash_file;
|
|
new_plugin->crypto_hash_pbkdf2 = &plugin_api_crypto_hash_pbkdf2;
|
|
new_plugin->crypto_hmac = &plugin_api_crypto_hmac;
|
|
|
|
new_plugin->mkdir_home = &dir_mkdir_home;
|
|
new_plugin->mkdir = &dir_mkdir;
|
|
new_plugin->mkdir_parents = &dir_mkdir_parents;
|
|
new_plugin->exec_on_files = &dir_exec_on_files;
|
|
new_plugin->file_get_content = &dir_file_get_content;
|
|
new_plugin->file_copy = &dir_file_copy;
|
|
new_plugin->file_compress = &dir_file_compress;
|
|
|
|
new_plugin->util_timeval_cmp = &util_timeval_cmp;
|
|
new_plugin->util_timeval_diff = &util_timeval_diff;
|
|
new_plugin->util_timeval_add = &util_timeval_add;
|
|
new_plugin->util_get_time_string = &util_get_time_string;
|
|
new_plugin->util_version_number = &util_version_number;
|
|
|
|
new_plugin->list_new = &weelist_new;
|
|
new_plugin->list_add = &weelist_add;
|
|
new_plugin->list_search = &weelist_search;
|
|
new_plugin->list_search_pos = &weelist_search_pos;
|
|
new_plugin->list_casesearch = &weelist_casesearch;
|
|
new_plugin->list_casesearch_pos = &weelist_casesearch_pos;
|
|
new_plugin->list_get = &weelist_get;
|
|
new_plugin->list_set = &weelist_set;
|
|
new_plugin->list_next = &weelist_next;
|
|
new_plugin->list_prev = &weelist_prev;
|
|
new_plugin->list_string = &weelist_string;
|
|
new_plugin->list_user_data = &weelist_user_data;
|
|
new_plugin->list_size = &weelist_size;
|
|
new_plugin->list_remove = &weelist_remove;
|
|
new_plugin->list_remove_all = &weelist_remove_all;
|
|
new_plugin->list_free = &weelist_free;
|
|
|
|
new_plugin->arraylist_new = arraylist_new;
|
|
new_plugin->arraylist_size = arraylist_size;
|
|
new_plugin->arraylist_get = arraylist_get;
|
|
new_plugin->arraylist_search = arraylist_search;
|
|
new_plugin->arraylist_insert = arraylist_insert;
|
|
new_plugin->arraylist_add = arraylist_add;
|
|
new_plugin->arraylist_remove = arraylist_remove;
|
|
new_plugin->arraylist_clear = arraylist_clear;
|
|
new_plugin->arraylist_free = arraylist_free;
|
|
|
|
new_plugin->hashtable_new = &hashtable_new;
|
|
new_plugin->hashtable_set_with_size = &hashtable_set_with_size;
|
|
new_plugin->hashtable_set = &hashtable_set;
|
|
new_plugin->hashtable_get = &hashtable_get;
|
|
new_plugin->hashtable_has_key = &hashtable_has_key;
|
|
new_plugin->hashtable_map = &hashtable_map;
|
|
new_plugin->hashtable_map_string = &hashtable_map_string;
|
|
new_plugin->hashtable_dup = &hashtable_dup;
|
|
new_plugin->hashtable_get_integer = &hashtable_get_integer;
|
|
new_plugin->hashtable_get_string = &hashtable_get_string;
|
|
new_plugin->hashtable_set_pointer = &hashtable_set_pointer;
|
|
new_plugin->hashtable_add_to_infolist = &hashtable_add_to_infolist;
|
|
new_plugin->hashtable_add_from_infolist = &hashtable_add_from_infolist;
|
|
new_plugin->hashtable_remove = &hashtable_remove;
|
|
new_plugin->hashtable_remove_all = &hashtable_remove_all;
|
|
new_plugin->hashtable_free = &hashtable_free;
|
|
|
|
new_plugin->config_new = &config_file_new;
|
|
new_plugin->config_set_version = &config_file_set_version;
|
|
new_plugin->config_new_section = &config_file_new_section;
|
|
new_plugin->config_search_section = &config_file_search_section;
|
|
new_plugin->config_new_option = &config_file_new_option;
|
|
new_plugin->config_search_option = &config_file_search_option;
|
|
new_plugin->config_search_section_option = &config_file_search_section_option;
|
|
new_plugin->config_search_with_string = &config_file_search_with_string;
|
|
new_plugin->config_string_to_boolean = &config_file_string_to_boolean;
|
|
new_plugin->config_option_reset = &config_file_option_reset;
|
|
new_plugin->config_option_set = &config_file_option_set;
|
|
new_plugin->config_option_set_null = &config_file_option_set_null;
|
|
new_plugin->config_option_unset = &config_file_option_unset;
|
|
new_plugin->config_option_rename = &config_file_option_rename;
|
|
new_plugin->config_option_get_string = &config_file_option_get_string;
|
|
new_plugin->config_option_get_pointer = &config_file_option_get_pointer;
|
|
new_plugin->config_option_is_null = &config_file_option_is_null;
|
|
new_plugin->config_option_default_is_null = &config_file_option_default_is_null;
|
|
new_plugin->config_boolean = &config_file_option_boolean;
|
|
new_plugin->config_boolean_default = &config_file_option_boolean_default;
|
|
new_plugin->config_integer = &config_file_option_integer;
|
|
new_plugin->config_integer_default = &config_file_option_integer_default;
|
|
new_plugin->config_enum = &config_file_option_enum;
|
|
new_plugin->config_enum_default = &config_file_option_enum_default;
|
|
new_plugin->config_string = &config_file_option_string;
|
|
new_plugin->config_string_default = &config_file_option_string_default;
|
|
new_plugin->config_color = &config_file_option_color;
|
|
new_plugin->config_color_default = &config_file_option_color_default;
|
|
new_plugin->config_write_option = &config_file_write_option;
|
|
new_plugin->config_write_line = &config_file_write_line;
|
|
new_plugin->config_write = &config_file_write;
|
|
new_plugin->config_read = &config_file_read;
|
|
new_plugin->config_reload = &config_file_reload;
|
|
new_plugin->config_option_free = &plugin_api_config_file_option_free;
|
|
new_plugin->config_section_free_options = &config_file_section_free_options;
|
|
new_plugin->config_section_free = &config_file_section_free;
|
|
new_plugin->config_free = &config_file_free;
|
|
new_plugin->config_get = &plugin_api_config_get;
|
|
new_plugin->config_get_plugin = &plugin_api_config_get_plugin;
|
|
new_plugin->config_is_set_plugin = &plugin_api_config_is_set_plugin;
|
|
new_plugin->config_set_plugin = &plugin_api_config_set_plugin;
|
|
new_plugin->config_set_desc_plugin = &plugin_api_config_set_desc_plugin;
|
|
new_plugin->config_unset_plugin = &plugin_api_config_unset_plugin;
|
|
|
|
new_plugin->key_bind = &gui_key_bind_plugin;
|
|
new_plugin->key_unbind = &gui_key_unbind_plugin;
|
|
|
|
new_plugin->prefix = &plugin_api_prefix;
|
|
new_plugin->color = &plugin_api_color;
|
|
new_plugin->printf_date_tags = &gui_chat_printf_date_tags;
|
|
new_plugin->printf_y_date_tags = &gui_chat_printf_y_date_tags;
|
|
new_plugin->log_printf = &log_printf;
|
|
|
|
new_plugin->hook_command = &hook_command;
|
|
new_plugin->hook_command_run = &hook_command_run;
|
|
new_plugin->hook_timer = &hook_timer;
|
|
new_plugin->hook_fd = &hook_fd;
|
|
new_plugin->hook_process = &hook_process;
|
|
new_plugin->hook_process_hashtable = &hook_process_hashtable;
|
|
new_plugin->hook_connect = &hook_connect;
|
|
new_plugin->hook_line = &hook_line;
|
|
new_plugin->hook_print = &hook_print;
|
|
new_plugin->hook_signal = &hook_signal;
|
|
new_plugin->hook_signal_send = &hook_signal_send;
|
|
new_plugin->hook_hsignal = &hook_hsignal;
|
|
new_plugin->hook_hsignal_send = &hook_hsignal_send;
|
|
new_plugin->hook_config = &hook_config;
|
|
new_plugin->hook_completion = &hook_completion;
|
|
new_plugin->hook_completion_get_string = &gui_completion_get_string;
|
|
new_plugin->hook_completion_list_add = &gui_completion_list_add;
|
|
new_plugin->hook_modifier = &hook_modifier;
|
|
new_plugin->hook_modifier_exec = &hook_modifier_exec;
|
|
new_plugin->hook_info = &hook_info;
|
|
new_plugin->hook_info_hashtable = &hook_info_hashtable;
|
|
new_plugin->hook_infolist = &hook_infolist;
|
|
new_plugin->hook_hdata = &hook_hdata;
|
|
new_plugin->hook_focus = &hook_focus;
|
|
new_plugin->hook_set = &hook_set;
|
|
new_plugin->unhook = &unhook;
|
|
new_plugin->unhook_all = &unhook_all_plugin;
|
|
|
|
new_plugin->buffer_new = &gui_buffer_new;
|
|
new_plugin->buffer_new_props = &gui_buffer_new_props;
|
|
new_plugin->buffer_search = &gui_buffer_search_by_name;
|
|
new_plugin->buffer_search_main = &gui_buffer_search_main;
|
|
new_plugin->buffer_clear = &gui_buffer_clear;
|
|
new_plugin->buffer_close = &gui_buffer_close;
|
|
new_plugin->buffer_merge = &gui_buffer_merge;
|
|
new_plugin->buffer_unmerge = &gui_buffer_unmerge;
|
|
new_plugin->buffer_get_integer = &gui_buffer_get_integer;
|
|
new_plugin->buffer_get_string = &gui_buffer_get_string;
|
|
new_plugin->buffer_get_pointer = &gui_buffer_get_pointer;
|
|
new_plugin->buffer_set = &gui_buffer_set;
|
|
new_plugin->buffer_set_pointer = &gui_buffer_set_pointer;
|
|
new_plugin->buffer_string_replace_local_var = &gui_buffer_string_replace_local_var;
|
|
new_plugin->buffer_match_list = &gui_buffer_match_list;
|
|
|
|
new_plugin->window_search_with_buffer = &gui_window_search_with_buffer;
|
|
new_plugin->window_get_integer = &gui_window_get_integer;
|
|
new_plugin->window_get_string = &gui_window_get_string;
|
|
new_plugin->window_get_pointer = &gui_window_get_pointer;
|
|
new_plugin->window_set_title = &gui_window_set_title;
|
|
|
|
new_plugin->nicklist_add_group = &gui_nicklist_add_group;
|
|
new_plugin->nicklist_search_group = &gui_nicklist_search_group;
|
|
new_plugin->nicklist_add_nick = &gui_nicklist_add_nick;
|
|
new_plugin->nicklist_search_nick = &gui_nicklist_search_nick;
|
|
new_plugin->nicklist_remove_group = &gui_nicklist_remove_group;
|
|
new_plugin->nicklist_remove_nick = &gui_nicklist_remove_nick;
|
|
new_plugin->nicklist_remove_all = &gui_nicklist_remove_all;
|
|
new_plugin->nicklist_get_next_item = &gui_nicklist_get_next_item;
|
|
new_plugin->nicklist_group_get_integer = &gui_nicklist_group_get_integer;
|
|
new_plugin->nicklist_group_get_string = &gui_nicklist_group_get_string;
|
|
new_plugin->nicklist_group_get_pointer = &gui_nicklist_group_get_pointer;
|
|
new_plugin->nicklist_group_set = &gui_nicklist_group_set;
|
|
new_plugin->nicklist_nick_get_integer = &gui_nicklist_nick_get_integer;
|
|
new_plugin->nicklist_nick_get_string = &gui_nicklist_nick_get_string;
|
|
new_plugin->nicklist_nick_get_pointer = &gui_nicklist_nick_get_pointer;
|
|
new_plugin->nicklist_nick_set = &gui_nicklist_nick_set;
|
|
|
|
new_plugin->bar_item_search = &gui_bar_item_search;
|
|
new_plugin->bar_item_new = &gui_bar_item_new;
|
|
new_plugin->bar_item_update = &gui_bar_item_update;
|
|
new_plugin->bar_item_remove = &gui_bar_item_free;
|
|
new_plugin->bar_search = &gui_bar_search;
|
|
new_plugin->bar_new = &gui_bar_new;
|
|
new_plugin->bar_set = &gui_bar_set;
|
|
new_plugin->bar_update = &gui_bar_update;
|
|
new_plugin->bar_remove = &gui_bar_free;
|
|
|
|
new_plugin->command = &plugin_api_command;
|
|
new_plugin->command_options = &plugin_api_command_options;
|
|
|
|
new_plugin->completion_new = &gui_completion_new;
|
|
new_plugin->completion_search = &gui_completion_search;
|
|
new_plugin->completion_get_string = &gui_completion_get_string;
|
|
new_plugin->completion_list_add = &gui_completion_list_add;
|
|
new_plugin->completion_free = &gui_completion_free;
|
|
|
|
new_plugin->network_pass_proxy = &network_pass_proxy;
|
|
new_plugin->network_connect_to = &network_connect_to;
|
|
|
|
new_plugin->info_get = &hook_info_get;
|
|
new_plugin->info_get_hashtable = &hook_info_get_hashtable;
|
|
|
|
new_plugin->infolist_new = &infolist_new;
|
|
new_plugin->infolist_new_item = &infolist_new_item;
|
|
new_plugin->infolist_new_var_integer = &infolist_new_var_integer;
|
|
new_plugin->infolist_new_var_string = &infolist_new_var_string;
|
|
new_plugin->infolist_new_var_pointer = &infolist_new_var_pointer;
|
|
new_plugin->infolist_new_var_buffer = &infolist_new_var_buffer;
|
|
new_plugin->infolist_new_var_time = &infolist_new_var_time;
|
|
new_plugin->infolist_search_var = &infolist_search_var;
|
|
new_plugin->infolist_get = &hook_infolist_get;
|
|
new_plugin->infolist_next = &plugin_api_infolist_next;
|
|
new_plugin->infolist_prev = &plugin_api_infolist_prev;
|
|
new_plugin->infolist_reset_item_cursor = &plugin_api_infolist_reset_item_cursor;
|
|
new_plugin->infolist_fields = &plugin_api_infolist_fields;
|
|
new_plugin->infolist_integer = &plugin_api_infolist_integer;
|
|
new_plugin->infolist_string = &plugin_api_infolist_string;
|
|
new_plugin->infolist_pointer = &plugin_api_infolist_pointer;
|
|
new_plugin->infolist_buffer = &plugin_api_infolist_buffer;
|
|
new_plugin->infolist_time = &plugin_api_infolist_time;
|
|
new_plugin->infolist_free = &plugin_api_infolist_free;
|
|
|
|
new_plugin->hdata_new = &hdata_new;
|
|
new_plugin->hdata_new_var = &hdata_new_var;
|
|
new_plugin->hdata_new_list = &hdata_new_list;
|
|
new_plugin->hdata_get = &hook_hdata_get;
|
|
new_plugin->hdata_get_var_offset = &hdata_get_var_offset;
|
|
new_plugin->hdata_get_var_type = &hdata_get_var_type;
|
|
new_plugin->hdata_get_var_type_string = &hdata_get_var_type_string;
|
|
new_plugin->hdata_get_var_array_size = &hdata_get_var_array_size;
|
|
new_plugin->hdata_get_var_array_size_string = &hdata_get_var_array_size_string;
|
|
new_plugin->hdata_get_var_hdata = &hdata_get_var_hdata;
|
|
new_plugin->hdata_get_var = &hdata_get_var;
|
|
new_plugin->hdata_get_var_at_offset = &hdata_get_var_at_offset;
|
|
new_plugin->hdata_get_list = &hdata_get_list;
|
|
new_plugin->hdata_check_pointer = &hdata_check_pointer;
|
|
new_plugin->hdata_move = &hdata_move;
|
|
new_plugin->hdata_search = &hdata_search;
|
|
new_plugin->hdata_char = &hdata_char;
|
|
new_plugin->hdata_integer = &hdata_integer;
|
|
new_plugin->hdata_long = &hdata_long;
|
|
new_plugin->hdata_string = &hdata_string;
|
|
new_plugin->hdata_pointer = &hdata_pointer;
|
|
new_plugin->hdata_time = &hdata_time;
|
|
new_plugin->hdata_hashtable = &hdata_hashtable;
|
|
new_plugin->hdata_compare = &hdata_compare;
|
|
new_plugin->hdata_set = &hdata_set;
|
|
new_plugin->hdata_update = &hdata_update;
|
|
new_plugin->hdata_get_string = &hdata_get_string;
|
|
|
|
new_plugin->upgrade_new = &upgrade_file_new;
|
|
new_plugin->upgrade_write_object = &upgrade_file_write_object;
|
|
new_plugin->upgrade_read = &upgrade_file_read;
|
|
new_plugin->upgrade_close = &upgrade_file_close;
|
|
|
|
/* add new plugin to list */
|
|
new_plugin->prev_plugin = last_weechat_plugin;
|
|
new_plugin->next_plugin = NULL;
|
|
if (last_weechat_plugin)
|
|
last_weechat_plugin->next_plugin = new_plugin;
|
|
else
|
|
weechat_plugins = new_plugin;
|
|
last_weechat_plugin = new_plugin;
|
|
|
|
/*
|
|
* associate orphan buffers with this plugin (if asked during upgrade
|
|
* process)
|
|
*/
|
|
gui_buffer_set_plugin_for_upgrade (name, new_plugin);
|
|
|
|
if (init_plugin)
|
|
{
|
|
if (!plugin_call_init (new_plugin, argc, argv))
|
|
{
|
|
plugin_remove (new_plugin);
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sUnable to load plugin \"%s\" (not enough memory)"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
filename);
|
|
dlclose (handle);
|
|
return NULL;
|
|
}
|
|
|
|
if ((weechat_debug_core >= 1) || !plugin_quiet)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("Plugin \"%s\" loaded"),
|
|
name);
|
|
}
|
|
|
|
(void) hook_signal_send ("plugin_loaded",
|
|
WEECHAT_HOOK_SIGNAL_STRING, (char *)filename);
|
|
|
|
return new_plugin;
|
|
}
|
|
|
|
/*
|
|
* Loads a file found by function plugin_auto_load, but only if this is really a
|
|
* dynamic library.
|
|
*/
|
|
|
|
void
|
|
plugin_auto_load_file (void *data, const char *filename)
|
|
{
|
|
struct t_plugin_args *plugin_args;
|
|
|
|
plugin_args = (struct t_plugin_args *)data;
|
|
|
|
if (plugin_check_extension_allowed (filename))
|
|
plugin_load (filename, 0, plugin_args->argc, plugin_args->argv);
|
|
}
|
|
|
|
/*
|
|
* Callback used to sort plugins arraylist by priority (high priority first).
|
|
*/
|
|
|
|
int
|
|
plugin_arraylist_cmp_cb (void *data,
|
|
struct t_arraylist *arraylist,
|
|
void *pointer1, void *pointer2)
|
|
{
|
|
struct t_weechat_plugin *plugin1, *plugin2;
|
|
|
|
/* make C compiler happy */
|
|
(void) data;
|
|
(void) arraylist;
|
|
|
|
plugin1 = (struct t_weechat_plugin *)pointer1;
|
|
plugin2 = (struct t_weechat_plugin *)pointer2;
|
|
|
|
return (plugin1->priority > plugin2->priority) ?
|
|
-1 : ((plugin1->priority < plugin2->priority) ? 1 : 0);
|
|
}
|
|
|
|
/*
|
|
* Auto-loads WeeChat plugins, from user and system directories.
|
|
*/
|
|
|
|
void
|
|
plugin_auto_load (char *force_plugin_autoload,
|
|
int load_from_plugin_path,
|
|
int load_from_extra_lib_dir,
|
|
int load_from_lib_dir,
|
|
int argc, char **argv)
|
|
{
|
|
char *dir_name, *plugin_path, *extra_libdir;
|
|
const char *ptr_plugin_autoload;
|
|
struct t_weechat_plugin *ptr_plugin;
|
|
struct t_plugin_args plugin_args;
|
|
struct t_arraylist *arraylist;
|
|
struct t_hashtable *options;
|
|
int length, i;
|
|
|
|
plugin_args.argc = argc;
|
|
plugin_args.argv = argv;
|
|
|
|
plugin_autoload_array = NULL;
|
|
plugin_autoload_count = 0;
|
|
|
|
ptr_plugin_autoload = (force_plugin_autoload) ?
|
|
force_plugin_autoload : CONFIG_STRING(config_plugin_autoload);
|
|
|
|
if (ptr_plugin_autoload && ptr_plugin_autoload[0])
|
|
{
|
|
plugin_autoload_array = string_split (
|
|
ptr_plugin_autoload,
|
|
",",
|
|
NULL,
|
|
WEECHAT_STRING_SPLIT_STRIP_LEFT
|
|
| WEECHAT_STRING_SPLIT_STRIP_RIGHT
|
|
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
|
|
0,
|
|
&plugin_autoload_count);
|
|
}
|
|
|
|
/* auto-load plugins in custom path */
|
|
if (load_from_plugin_path
|
|
&& CONFIG_STRING(config_plugin_path)
|
|
&& CONFIG_STRING(config_plugin_path)[0])
|
|
{
|
|
options = hashtable_new (
|
|
32,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
NULL, NULL);
|
|
if (options)
|
|
hashtable_set (options, "directory", "data");
|
|
plugin_path = string_eval_path_home (CONFIG_STRING(config_plugin_path),
|
|
NULL, NULL, options);
|
|
if (options)
|
|
hashtable_free (options);
|
|
if (plugin_path)
|
|
{
|
|
dir_exec_on_files (plugin_path, 1, 0,
|
|
&plugin_auto_load_file, &plugin_args);
|
|
free (plugin_path);
|
|
}
|
|
}
|
|
|
|
/* auto-load plugins in WEECHAT_EXTRA_LIBDIR environment variable */
|
|
if (load_from_extra_lib_dir)
|
|
{
|
|
extra_libdir = getenv (WEECHAT_EXTRA_LIBDIR);
|
|
if (extra_libdir && extra_libdir[0])
|
|
{
|
|
length = strlen (extra_libdir) + 16 + 1;
|
|
dir_name = malloc (length);
|
|
snprintf (dir_name, length, "%s/plugins", extra_libdir);
|
|
dir_exec_on_files (dir_name, 1, 0,
|
|
&plugin_auto_load_file, &plugin_args);
|
|
free (dir_name);
|
|
}
|
|
}
|
|
|
|
/* auto-load plugins in WeeChat global lib dir */
|
|
if (load_from_lib_dir)
|
|
{
|
|
length = strlen (WEECHAT_LIBDIR) + 16 + 1;
|
|
dir_name = malloc (length);
|
|
if (dir_name)
|
|
{
|
|
snprintf (dir_name, length, "%s/plugins", WEECHAT_LIBDIR);
|
|
dir_exec_on_files (dir_name, 1, 0,
|
|
&plugin_auto_load_file, &plugin_args);
|
|
free (dir_name);
|
|
}
|
|
}
|
|
|
|
/* free autoload array */
|
|
if (plugin_autoload_array)
|
|
{
|
|
string_free_split (plugin_autoload_array);
|
|
plugin_autoload_array = NULL;
|
|
}
|
|
plugin_autoload_count = 0;
|
|
|
|
/* initialize all uninitialized plugins */
|
|
arraylist = arraylist_new (10, 1, 1,
|
|
&plugin_arraylist_cmp_cb, NULL, NULL, NULL);
|
|
if (arraylist)
|
|
{
|
|
for (ptr_plugin = weechat_plugins; ptr_plugin;
|
|
ptr_plugin = ptr_plugin->next_plugin)
|
|
{
|
|
arraylist_add (arraylist, ptr_plugin);
|
|
}
|
|
i = 0;
|
|
while (i < arraylist_size (arraylist))
|
|
{
|
|
ptr_plugin = arraylist_get (arraylist, i);
|
|
if (!ptr_plugin->initialized)
|
|
{
|
|
if (!plugin_call_init (ptr_plugin, argc, argv))
|
|
{
|
|
plugin_remove (ptr_plugin);
|
|
arraylist_remove (arraylist, i);
|
|
}
|
|
else
|
|
i++;
|
|
}
|
|
else
|
|
i++;
|
|
}
|
|
arraylist_free (arraylist);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Removes a WeeChat plugin.
|
|
*/
|
|
|
|
void
|
|
plugin_remove (struct t_weechat_plugin *plugin)
|
|
{
|
|
struct t_weechat_plugin *new_weechat_plugins;
|
|
struct t_gui_buffer *ptr_buffer, *next_buffer;
|
|
|
|
/* remove all completions (only those created by API) */
|
|
gui_completion_free_all_plugin (plugin);
|
|
|
|
/* close buffers created by this plugin */
|
|
ptr_buffer = gui_buffers;
|
|
while (ptr_buffer)
|
|
{
|
|
next_buffer = ptr_buffer->next_buffer;
|
|
|
|
if (ptr_buffer->plugin == plugin)
|
|
gui_buffer_close (ptr_buffer);
|
|
|
|
ptr_buffer = next_buffer;
|
|
}
|
|
|
|
/* remove plugin from list */
|
|
if (last_weechat_plugin == plugin)
|
|
last_weechat_plugin = plugin->prev_plugin;
|
|
if (plugin->prev_plugin)
|
|
{
|
|
(plugin->prev_plugin)->next_plugin = plugin->next_plugin;
|
|
new_weechat_plugins = weechat_plugins;
|
|
}
|
|
else
|
|
new_weechat_plugins = plugin->next_plugin;
|
|
|
|
if (plugin->next_plugin)
|
|
(plugin->next_plugin)->prev_plugin = plugin->prev_plugin;
|
|
|
|
/* remove all configuration files */
|
|
config_file_free_all_plugin (plugin);
|
|
|
|
/* remove all hooks */
|
|
unhook_all_plugin (plugin, NULL);
|
|
|
|
/* remove all infolists */
|
|
infolist_free_all_plugin (plugin);
|
|
|
|
/* remove all hdata */
|
|
hdata_free_all_plugin (plugin);
|
|
|
|
/* remove all bar items */
|
|
gui_bar_item_free_all_plugin (plugin);
|
|
|
|
/* free data */
|
|
if (plugin->filename)
|
|
free (plugin->filename);
|
|
if (!weechat_plugin_no_dlclose)
|
|
dlclose (plugin->handle);
|
|
if (plugin->name)
|
|
free (plugin->name);
|
|
if (plugin->description)
|
|
free (plugin->description);
|
|
if (plugin->author)
|
|
free (plugin->author);
|
|
if (plugin->version)
|
|
free (plugin->version);
|
|
if (plugin->license)
|
|
free (plugin->license);
|
|
if (plugin->charset)
|
|
free (plugin->charset);
|
|
hashtable_free (plugin->variables);
|
|
|
|
free (plugin);
|
|
|
|
weechat_plugins = new_weechat_plugins;
|
|
}
|
|
|
|
/*
|
|
* Unloads a WeeChat plugin.
|
|
*/
|
|
|
|
void
|
|
plugin_unload (struct t_weechat_plugin *plugin)
|
|
{
|
|
t_weechat_end_func *end_func;
|
|
char *name;
|
|
|
|
name = (plugin->name) ? strdup (plugin->name) : NULL;
|
|
|
|
if (plugin->initialized)
|
|
{
|
|
end_func = dlsym (plugin->handle, "weechat_plugin_end");
|
|
if (end_func)
|
|
(void) (end_func) (plugin);
|
|
}
|
|
|
|
plugin_remove (plugin);
|
|
|
|
if ((weechat_debug_core >= 1) || !plugin_quiet)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("Plugin \"%s\" unloaded"),
|
|
(name) ? name : "???");
|
|
}
|
|
(void) hook_signal_send ("plugin_unloaded",
|
|
WEECHAT_HOOK_SIGNAL_STRING, name);
|
|
if (name)
|
|
free (name);
|
|
}
|
|
|
|
/*
|
|
* Unloads a WeeChat plugin by name.
|
|
*/
|
|
|
|
void
|
|
plugin_unload_name (const char *name)
|
|
{
|
|
struct t_weechat_plugin *ptr_plugin;
|
|
|
|
ptr_plugin = plugin_search (name);
|
|
if (ptr_plugin)
|
|
plugin_unload (ptr_plugin);
|
|
else
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sPlugin \"%s\" not found"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
name);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Unloads all WeeChat plugins.
|
|
*/
|
|
|
|
void
|
|
plugin_unload_all ()
|
|
{
|
|
int plugins_loaded;
|
|
|
|
plugins_loaded = (weechat_plugins) ? 1 : 0;
|
|
|
|
plugin_quiet = 1;
|
|
while (weechat_plugins)
|
|
{
|
|
plugin_unload (last_weechat_plugin);
|
|
}
|
|
plugin_quiet = 0;
|
|
|
|
if (plugins_loaded)
|
|
{
|
|
gui_chat_printf (NULL, _("Plugins unloaded"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Reloads a WeeChat plugin by name.
|
|
*/
|
|
|
|
void
|
|
plugin_reload_name (const char *name, int argc, char **argv)
|
|
{
|
|
struct t_weechat_plugin *ptr_plugin;
|
|
char *filename;
|
|
|
|
ptr_plugin = plugin_search (name);
|
|
if (ptr_plugin)
|
|
{
|
|
filename = strdup (ptr_plugin->filename);
|
|
if (filename)
|
|
{
|
|
plugin_unload (ptr_plugin);
|
|
plugin_load (filename, 1, argc, argv);
|
|
free (filename);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sPlugin \"%s\" not found"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
name);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Displays list of loaded plugins on one line.
|
|
*/
|
|
|
|
void
|
|
plugin_display_short_list ()
|
|
{
|
|
const char *plugins_loaded;
|
|
char *buf;
|
|
int length;
|
|
struct t_weechat_plugin *ptr_plugin;
|
|
struct t_weelist *list;
|
|
struct t_weelist_item *ptr_item;
|
|
|
|
if (weechat_plugins)
|
|
{
|
|
list = weelist_new ();
|
|
if (list)
|
|
{
|
|
plugins_loaded = _("Plugins loaded:");
|
|
|
|
length = strlen (plugins_loaded) + 1;
|
|
|
|
for (ptr_plugin = weechat_plugins; ptr_plugin;
|
|
ptr_plugin = ptr_plugin->next_plugin)
|
|
{
|
|
length += strlen (ptr_plugin->name) + 2;
|
|
weelist_add (list, ptr_plugin->name, WEECHAT_LIST_POS_SORT, NULL);
|
|
}
|
|
length++;
|
|
|
|
buf = malloc (length);
|
|
if (buf)
|
|
{
|
|
strcpy (buf, plugins_loaded);
|
|
strcat (buf, " ");
|
|
for (ptr_item = list->items; ptr_item;
|
|
ptr_item = ptr_item->next_item)
|
|
{
|
|
strcat (buf, ptr_item->data);
|
|
if (ptr_item->next_item)
|
|
strcat (buf, ", ");
|
|
}
|
|
gui_chat_printf (NULL, "%s", buf);
|
|
free (buf);
|
|
}
|
|
weelist_free (list);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initializes plugin support.
|
|
*/
|
|
|
|
void
|
|
plugin_init (char *force_plugin_autoload, int argc, char *argv[])
|
|
{
|
|
/* read plugins options on disk */
|
|
plugin_config_init ();
|
|
plugin_config_read ();
|
|
|
|
/* auto-load plugins */
|
|
plugin_quiet = 1;
|
|
plugin_auto_load (force_plugin_autoload, 1, 1, 1, argc, argv);
|
|
plugin_display_short_list ();
|
|
plugin_quiet = 0;
|
|
}
|
|
|
|
/*
|
|
* Ends plugin support.
|
|
*/
|
|
|
|
void
|
|
plugin_end ()
|
|
{
|
|
/* write plugins configuration options */
|
|
plugin_config_write ();
|
|
|
|
/* unload all plugins */
|
|
plugin_unload_all ();
|
|
|
|
/* free all plugin options */
|
|
plugin_config_end ();
|
|
}
|
|
|
|
/*
|
|
* Gets hdata for plugin.
|
|
*/
|
|
|
|
struct t_hdata *
|
|
plugin_hdata_plugin_cb (const void *pointer, void *data,
|
|
const char *hdata_name)
|
|
{
|
|
struct t_hdata *hdata;
|
|
|
|
/* make C compiler happy */
|
|
(void) pointer;
|
|
(void) data;
|
|
|
|
hdata = hdata_new (NULL, hdata_name, "prev_plugin", "next_plugin",
|
|
0, 0, NULL, NULL);
|
|
if (hdata)
|
|
{
|
|
HDATA_VAR(struct t_weechat_plugin, filename, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_weechat_plugin, handle, POINTER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_weechat_plugin, name, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_weechat_plugin, description, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_weechat_plugin, author, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_weechat_plugin, version, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_weechat_plugin, license, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_weechat_plugin, charset, STRING, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_weechat_plugin, priority, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_weechat_plugin, initialized, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_weechat_plugin, debug, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_weechat_plugin, upgrading, INTEGER, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_weechat_plugin, variables, HASHTABLE, 0, NULL, NULL);
|
|
HDATA_VAR(struct t_weechat_plugin, prev_plugin, POINTER, 0, NULL, hdata_name);
|
|
HDATA_VAR(struct t_weechat_plugin, next_plugin, POINTER, 0, NULL, hdata_name);
|
|
HDATA_LIST(weechat_plugins, WEECHAT_HDATA_LIST_CHECK_POINTERS);
|
|
HDATA_LIST(last_weechat_plugin, 0);
|
|
}
|
|
return hdata;
|
|
}
|
|
|
|
/*
|
|
* Adds a plugin in an infolist.
|
|
*
|
|
* Returns:
|
|
* 1: OK
|
|
* 0: error
|
|
*/
|
|
|
|
int
|
|
plugin_add_to_infolist (struct t_infolist *infolist,
|
|
struct t_weechat_plugin *plugin)
|
|
{
|
|
struct t_infolist_item *ptr_item;
|
|
|
|
if (!infolist || !plugin)
|
|
return 0;
|
|
|
|
ptr_item = infolist_new_item (infolist);
|
|
if (!ptr_item)
|
|
return 0;
|
|
|
|
if (!infolist_new_var_pointer (ptr_item, "pointer", plugin))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "filename", plugin->filename))
|
|
return 0;
|
|
if (!infolist_new_var_pointer (ptr_item, "handle", plugin->handle))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "name", plugin->name))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "description", plugin->description))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "description_nls",
|
|
(plugin->description && plugin->description[0]) ?
|
|
_(plugin->description) : ""))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "author", plugin->author))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "version", plugin->version))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "license", plugin->license))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "charset", plugin->charset))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "priority", plugin->priority))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "initialized", plugin->initialized))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "debug", plugin->debug))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "upgrading", plugin->upgrading))
|
|
return 0;
|
|
if (!hashtable_add_to_infolist (plugin->variables, ptr_item, "var"))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Prints plugins in WeeChat log file (usually for crash dump).
|
|
*/
|
|
|
|
void
|
|
plugin_print_log ()
|
|
{
|
|
struct t_weechat_plugin *ptr_plugin;
|
|
|
|
for (ptr_plugin = weechat_plugins; ptr_plugin;
|
|
ptr_plugin = ptr_plugin->next_plugin)
|
|
{
|
|
log_printf ("");
|
|
log_printf ("[plugin (addr:0x%lx)]", ptr_plugin);
|
|
log_printf (" filename . . . . . . . : '%s'", ptr_plugin->filename);
|
|
log_printf (" handle . . . . . . . . : 0x%lx", ptr_plugin->handle);
|
|
log_printf (" name . . . . . . . . . : '%s'", ptr_plugin->name);
|
|
log_printf (" description. . . . . . : '%s'", ptr_plugin->description);
|
|
log_printf (" author . . . . . . . . : '%s'", ptr_plugin->author);
|
|
log_printf (" version. . . . . . . . : '%s'", ptr_plugin->version);
|
|
log_printf (" license. . . . . . . . : '%s'", ptr_plugin->license);
|
|
log_printf (" charset. . . . . . . . : '%s'", ptr_plugin->charset);
|
|
log_printf (" priority . . . . . . . : %d", ptr_plugin->priority);
|
|
log_printf (" initialized. . . . . . : %d", ptr_plugin->initialized);
|
|
log_printf (" debug. . . . . . . . . : %d", ptr_plugin->debug);
|
|
log_printf (" upgrading. . . . . . . : %d", ptr_plugin->upgrading);
|
|
hashtable_print_log (ptr_plugin->variables, "variables");
|
|
log_printf (" prev_plugin. . . . . . : 0x%lx", ptr_plugin->prev_plugin);
|
|
log_printf (" next_plugin. . . . . . : 0x%lx", ptr_plugin->next_plugin);
|
|
}
|
|
}
|