aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjgeboski <jgeboski@gmail.com>2016-05-15 14:17:34 -0400
committerjgeboski <jgeboski@gmail.com>2016-05-25 22:48:08 -0400
commitd28fe1c4f463314a79f0a71f6f8a01db53e37253 (patch)
tree70a8a2b8b86ad62a4bfc2da57608ca45404b5bb4
parent0e48e549e7693f665b43bcad5e14ef26447bfe5b (diff)
Implemented plugin information for external plugins
As of now, bitlbee will load any plugin regardless of the ABI it was built against. This is really problematic when structures or symbols are changed within bitlbee. This often leads to the plugin not loading or the plugin acting in an undefined way. Typically a simple rebuild of the plugin will resolve such issues, but many users have no idea that this is required after they have updated bitlbee. Furthermore, it is often times impossible to determine the version of a plugin, without relying on the package manager of the system. This is quite a problem when users are reporting bugs for external plugins, and they have no idea what version of the plugin they are running. This is also an opportunity to provide additional metadata for each plugin that can then be displayed to the user. Solving these issues is done by adding a new required function to each plugin. The init_plugin_info() function must now be implemented along with the init_plugin() function. This function then returns a static structure, which retains all of the metadata for the plugin. Then this is used by bitlbee to check the ABI version and provide information to the user. The introduction of the new function is required as bitlbee needs to obtain the ABI version before calling init_plugin(). The boiler-plate implementation of init_plugin_info(): #ifdef BITLBEE_ABI_VERSION_CODE struct plugin_info *init_plugin_info(void) { static struct plugin_info info = { BITLBEE_ABI_VERSION_CODE, /* Required */ "plugin-name", /* Required */ "1.3.3.7", /* Required */ "A short description of the plugin", /* Optional */ "First Last <alias@domain.tld>", /* Optional */ "http://www.domain.tld" /* Optional */ }; return &info; } #endif The example wraps the function declaration in an if block for backwards compatibility with older bitlbee versions. Displaying the plugin metadata is done via the newly added "plugins" command, which simply dumps formatted data to the root channel.
-rw-r--r--bitlbee.h1
-rw-r--r--doc/user-guide/commands.xml12
-rw-r--r--otr.c16
-rw-r--r--protocols/nogaim.c67
-rw-r--r--protocols/nogaim.h14
-rw-r--r--protocols/skype/skype.c14
-rw-r--r--root_commands.c33
7 files changed, 156 insertions, 1 deletions
diff --git a/bitlbee.h b/bitlbee.h
index 26a1c982..de54d05c 100644
--- a/bitlbee.h
+++ b/bitlbee.h
@@ -39,6 +39,7 @@ extern "C" {
#define VERSION BITLBEE_VERSION
#define BITLBEE_VER(a, b, c) (((a) << 16) + ((b) << 8) + (c))
#define BITLBEE_VERSION_CODE BITLBEE_VER(3, 4, 2)
+#define BITLBEE_ABI_VERSION_CODE 1
#define MAX_STRING 511
diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml
index 6f66a39d..260e6abe 100644
--- a/doc/user-guide/commands.xml
+++ b/doc/user-guide/commands.xml
@@ -1834,6 +1834,18 @@
</description>
</bitlbee-command>
+ <bitlbee-command name="plugins">
+ <short-description>List all the external plugins</short-description>
+ <syntax>plugins</syntax>
+
+ <description>
+ <para>
+ This gives you a list of all the external plugins.
+ </para>
+ </description>
+
+ </bitlbee-command>
+
<bitlbee-command name="qlist">
<short-description>List all the unanswered questions root asked</short-description>
<syntax>qlist</syntax>
diff --git a/otr.c b/otr.c
index 4888691a..0328f478 100644
--- a/otr.c
+++ b/otr.c
@@ -267,6 +267,22 @@ void init_plugin(void)
register_irc_plugin(&otr_plugin);
}
+#ifndef OTR_BI
+struct plugin_info *init_plugin_info(void)
+{
+ static struct plugin_info info = {
+ BITLBEE_ABI_VERSION_CODE,
+ "otr",
+ BITLBEE_VERSION,
+ "Off-the-Record communication",
+ NULL,
+ NULL
+ };
+
+ return &info;
+}
+#endif
+
gboolean otr_irc_new(irc_t *irc)
{
set_t *s;
diff --git a/protocols/nogaim.c b/protocols/nogaim.c
index c9cbb033..9ed3b64b 100644
--- a/protocols/nogaim.c
+++ b/protocols/nogaim.c
@@ -39,24 +39,84 @@
GSList *connections;
#ifdef WITH_PLUGINS
+GList *plugins = NULL;
+
+static gint pluginscmp(gconstpointer a, gconstpointer b, gpointer data)
+{
+ const struct plugin_info *ia = a;
+ const struct plugin_info *ib = b;
+
+ return g_strcasecmp(ia->name, ib->name);
+}
+
gboolean load_plugin(char *path)
{
+ GList *l;
+ struct plugin_info *i;
+ struct plugin_info *info;
+ struct plugin_info * (*info_function) (void) = NULL;
void (*init_function) (void);
GModule *mod = g_module_open(path, G_MODULE_BIND_LAZY);
+ gboolean loaded = FALSE;
if (!mod) {
log_message(LOGLVL_ERROR, "Error loading plugin `%s': %s\n", path, g_module_error());
return FALSE;
}
+ if (g_module_symbol(mod, "init_plugin_info", (gpointer *) &info_function)) {
+ info = info_function();
+
+ if (info->abiver != BITLBEE_ABI_VERSION_CODE) {
+ log_message(LOGLVL_ERROR,
+ "`%s' uses ABI %u but %u is required\n",
+ path, info->abiver,
+ BITLBEE_ABI_VERSION_CODE);
+ g_module_close(mod);
+ return FALSE;
+ }
+
+ if (!info->name || !info->version) {
+ log_message(LOGLVL_ERROR,
+ "Name or version missing from the "
+ "plugin info in `%s'\n", path);
+ g_module_close(mod);
+ return FALSE;
+ }
+
+ for (l = plugins; l; l = l->next) {
+ i = l->data;
+
+ if (g_strcasecmp(i->name, info->name) == 0) {
+ loaded = TRUE;
+ break;
+ }
+ }
+
+ if (loaded) {
+ log_message(LOGLVL_WARNING,
+ "%s plugin already loaded\n",
+ info->name);
+ g_module_close(mod);
+ return FALSE;
+ }
+ } else {
+ log_message(LOGLVL_WARNING, "Can't find function `init_plugin_info' in `%s'\n", path);
+ }
+
if (!g_module_symbol(mod, "init_plugin", (gpointer *) &init_function)) {
log_message(LOGLVL_WARNING, "Can't find function `init_plugin' in `%s'\n", path);
+ g_module_close(mod);
return FALSE;
}
- init_function();
+ if (info_function) {
+ plugins = g_list_insert_sorted_with_data(plugins, info,
+ pluginscmp, NULL);
+ }
+ init_function();
return TRUE;
}
@@ -86,6 +146,11 @@ void load_plugins(void)
g_dir_close(dir);
}
}
+
+GList *get_plugins()
+{
+ return plugins;
+}
#endif
GList *protocols = NULL;
diff --git a/protocols/nogaim.h b/protocols/nogaim.h
index 40b1ed7b..f5b1f212 100644
--- a/protocols/nogaim.h
+++ b/protocols/nogaim.h
@@ -270,6 +270,20 @@ struct prpl {
void *resv5;
};
+struct plugin_info
+{
+ guint abiver;
+ const char *name;
+ const char *version;
+ const char *description;
+ const char *author;
+ const char *url;
+};
+
+#ifdef WITH_PLUGINS
+G_MODULE_EXPORT GList *get_plugins();
+#endif
+
/* im_api core stuff. */
void nogaim_init();
G_MODULE_EXPORT GSList *get_connections();
diff --git a/protocols/skype/skype.c b/protocols/skype/skype.c
index a21af8ef..bd8a1850 100644
--- a/protocols/skype/skype.c
+++ b/protocols/skype/skype.c
@@ -1762,3 +1762,17 @@ void init_plugin(void)
#endif
register_protocol(ret);
}
+
+struct plugin_info *init_plugin_info(void)
+{
+ static struct plugin_info info = {
+ BITLBEE_ABI_VERSION_CODE,
+ "skype",
+ BITLBEE_VERSION,
+ "Skype protocol plugin",
+ NULL,
+ NULL
+ };
+
+ return &info;
+}
diff --git a/root_commands.c b/root_commands.c
index dcf7a7ed..25c5c49e 100644
--- a/root_commands.c
+++ b/root_commands.c
@@ -1106,6 +1106,36 @@ static void cmd_blist(irc_t *irc, char **cmd)
}
}
+#ifdef WITH_PLUGINS
+static void cmd_plugins(irc_t *irc, char **cmd)
+{
+ GList *l;
+ struct plugin_info *info;
+
+ for (l = get_plugins(); l; l = l->next) {
+ info = l->data;
+ irc_rootmsg(irc, "%s:", info->name);
+ irc_rootmsg(irc, " Version: %s", info->version);
+
+ if (info->description) {
+ irc_rootmsg(irc, " Description: %s", info->description);
+ }
+
+ if (info->author) {
+ irc_rootmsg(irc, " Author: %s", info->author);
+ }
+
+ if (info->url) {
+ irc_rootmsg(irc, " URL: %s", info->url);
+ }
+
+ if (l->next) {
+ irc_rootmsg(irc, "");
+ }
+ }
+}
+#endif
+
static void cmd_qlist(irc_t *irc, char **cmd)
{
query_t *q = irc->queries;
@@ -1357,6 +1387,9 @@ command_t root_commands[] = {
{ "info", 1, cmd_info, 0 },
{ "nick", 1, cmd_nick, 0 },
{ "no", 0, cmd_yesno, 0 },
+#ifdef WITH_PLUGINS
+ { "plugins", 0, cmd_plugins, 0 },
+#endif
{ "qlist", 0, cmd_qlist, 0 },
{ "register", 0, cmd_register, 0 },
{ "remove", 1, cmd_remove, 0 },