Changeset d28fe1c4


Ignore:
Timestamp:
2016-05-26T02:48:08Z (3 years ago)
Author:
jgeboski <jgeboski@…>
Branches:
master
Children:
808825e
Parents:
0e48e54
git-author:
jgeboski <jgeboski@…> (15-05-16 18:17:34)
git-committer:
jgeboski <jgeboski@…> (26-05-16 02:48:08)
Message:

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@…>", /* 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.

Files:
7 edited

Legend:

Unmodified
Added
Removed
  • bitlbee.h

    r0e48e54 rd28fe1c4  
    4040#define BITLBEE_VER(a, b, c) (((a) << 16) + ((b) << 8) + (c))
    4141#define BITLBEE_VERSION_CODE BITLBEE_VER(3, 4, 2)
     42#define BITLBEE_ABI_VERSION_CODE 1
    4243
    4344#define MAX_STRING 511
  • doc/user-guide/commands.xml

    r0e48e54 rd28fe1c4  
    18351835        </bitlbee-command>
    18361836
     1837        <bitlbee-command name="plugins">
     1838                <short-description>List all the external plugins</short-description>
     1839                <syntax>plugins</syntax>
     1840
     1841                <description>
     1842                        <para>
     1843                                This gives you a list of all the external plugins.
     1844                        </para>
     1845                </description>
     1846
     1847        </bitlbee-command>
     1848
    18371849        <bitlbee-command name="qlist">
    18381850                <short-description>List all the unanswered questions root asked</short-description>
  • otr.c

    r0e48e54 rd28fe1c4  
    267267        register_irc_plugin(&otr_plugin);
    268268}
     269
     270#ifndef OTR_BI
     271struct plugin_info *init_plugin_info(void)
     272{
     273        static struct plugin_info info = {
     274                BITLBEE_ABI_VERSION_CODE,
     275                "otr",
     276                BITLBEE_VERSION,
     277                "Off-the-Record communication",
     278                NULL,
     279                NULL
     280        };
     281
     282        return &info;
     283}
     284#endif
    269285
    270286gboolean otr_irc_new(irc_t *irc)
  • protocols/nogaim.c

    r0e48e54 rd28fe1c4  
    4040
    4141#ifdef WITH_PLUGINS
     42GList *plugins = NULL;
     43
     44static gint pluginscmp(gconstpointer a, gconstpointer b, gpointer data)
     45{
     46        const struct plugin_info *ia = a;
     47        const struct plugin_info *ib = b;
     48
     49        return g_strcasecmp(ia->name, ib->name);
     50}
     51
    4252gboolean load_plugin(char *path)
    4353{
     54        GList *l;
     55        struct plugin_info *i;
     56        struct plugin_info *info;
     57        struct plugin_info * (*info_function) (void) = NULL;
    4458        void (*init_function) (void);
    4559
    4660        GModule *mod = g_module_open(path, G_MODULE_BIND_LAZY);
     61        gboolean loaded = FALSE;
    4762
    4863        if (!mod) {
     
    5166        }
    5267
     68        if (g_module_symbol(mod, "init_plugin_info", (gpointer *) &info_function)) {
     69                info = info_function();
     70
     71                if (info->abiver != BITLBEE_ABI_VERSION_CODE) {
     72                        log_message(LOGLVL_ERROR,
     73                                    "`%s' uses ABI %u but %u is required\n",
     74                                    path, info->abiver,
     75                                    BITLBEE_ABI_VERSION_CODE);
     76                        g_module_close(mod);
     77                        return FALSE;
     78                }
     79
     80                if (!info->name || !info->version) {
     81                        log_message(LOGLVL_ERROR,
     82                                    "Name or version missing from the "
     83                                    "plugin info in `%s'\n", path);
     84                        g_module_close(mod);
     85                        return FALSE;
     86                }
     87
     88                for (l = plugins; l; l = l->next) {
     89                        i = l->data;
     90
     91                        if (g_strcasecmp(i->name, info->name) == 0) {
     92                                loaded = TRUE;
     93                                break;
     94                        }
     95                }
     96
     97                if (loaded) {
     98                        log_message(LOGLVL_WARNING,
     99                                    "%s plugin already loaded\n",
     100                                    info->name);
     101                        g_module_close(mod);
     102                        return FALSE;
     103                }
     104        } else {
     105                log_message(LOGLVL_WARNING, "Can't find function `init_plugin_info' in `%s'\n", path);
     106        }
     107
    53108        if (!g_module_symbol(mod, "init_plugin", (gpointer *) &init_function)) {
    54109                log_message(LOGLVL_WARNING, "Can't find function `init_plugin' in `%s'\n", path);
     110                g_module_close(mod);
    55111                return FALSE;
    56112        }
    57113
     114        if (info_function) {
     115                plugins = g_list_insert_sorted_with_data(plugins, info,
     116                                                         pluginscmp, NULL);
     117        }
     118
    58119        init_function();
    59 
    60120        return TRUE;
    61121}
     
    86146                g_dir_close(dir);
    87147        }
     148}
     149
     150GList *get_plugins()
     151{
     152        return plugins;
    88153}
    89154#endif
  • protocols/nogaim.h

    r0e48e54 rd28fe1c4  
    271271};
    272272
     273struct plugin_info
     274{
     275        guint abiver;
     276        const char *name;
     277        const char *version;
     278        const char *description;
     279        const char *author;
     280        const char *url;
     281};
     282
     283#ifdef WITH_PLUGINS
     284G_MODULE_EXPORT GList *get_plugins();
     285#endif
     286
    273287/* im_api core stuff. */
    274288void nogaim_init();
  • protocols/skype/skype.c

    r0e48e54 rd28fe1c4  
    17631763        register_protocol(ret);
    17641764}
     1765
     1766struct plugin_info *init_plugin_info(void)
     1767{
     1768        static struct plugin_info info = {
     1769                BITLBEE_ABI_VERSION_CODE,
     1770                "skype",
     1771                BITLBEE_VERSION,
     1772                "Skype protocol plugin",
     1773                NULL,
     1774                NULL
     1775        };
     1776
     1777        return &info;
     1778}
  • root_commands.c

    r0e48e54 rd28fe1c4  
    11061106        }
    11071107}
     1108
     1109#ifdef WITH_PLUGINS
     1110static void cmd_plugins(irc_t *irc, char **cmd)
     1111{
     1112        GList *l;
     1113        struct plugin_info *info;
     1114
     1115        for (l = get_plugins(); l; l = l->next) {
     1116                info = l->data;
     1117                irc_rootmsg(irc, "%s:", info->name);
     1118                irc_rootmsg(irc, "  Version: %s", info->version);
     1119
     1120                if (info->description) {
     1121                        irc_rootmsg(irc, "  Description: %s", info->description);
     1122                }
     1123
     1124                if (info->author) {
     1125                        irc_rootmsg(irc, "  Author: %s", info->author);
     1126                }
     1127
     1128                if (info->url) {
     1129                        irc_rootmsg(irc, "  URL: %s", info->url);
     1130                }
     1131
     1132                if (l->next) {
     1133                        irc_rootmsg(irc, "");
     1134                }
     1135        }
     1136}
     1137#endif
    11081138
    11091139static void cmd_qlist(irc_t *irc, char **cmd)
     
    13581388        { "nick",           1, cmd_nick,           0 },
    13591389        { "no",             0, cmd_yesno,          0 },
     1390#ifdef WITH_PLUGINS
     1391        { "plugins",        0, cmd_plugins,        0 },
     1392#endif
    13601393        { "qlist",          0, cmd_qlist,          0 },
    13611394        { "register",       0, cmd_register,       0 },
Note: See TracChangeset for help on using the changeset viewer.