diff options
Diffstat (limited to 'plugins.c')
-rw-r--r-- | plugins.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/plugins.c b/plugins.c new file mode 100644 index 00000000..43fb875f --- /dev/null +++ b/plugins.c @@ -0,0 +1,166 @@ +#include <dirent.h> +#include <dlfcn.h> +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include "plugins.h" +#include "md5/md5.h" + +// deadbeef api +DB_functions_t deadbeef_api = { + .ev_subscribe = plug_ev_subscribe, + .ev_unsubscribe = plug_ev_unsubscribe, + .md5 = plug_md5, + .md5_to_str = plug_md5_to_str +}; + +void +plug_md5 (uint8_t sig[16], const char *in, int len) { + md5_buffer (in, len, sig); +} + +void +plug_md5_to_str (char *str, const uint8_t sig[16]) { + md5_sig_to_string ((char *)sig, str, 33); +} + +// event handlers +typedef struct { + DB_plugin_t *plugin; + db_callback_t callback; + uintptr_t data; +} evhandler_t; +#define MAX_HANDLERS 100 +static evhandler_t handlers[DB_EV_MAX][MAX_HANDLERS]; + +// plugin control structures +typedef struct plugin_s { + void *handle; + DB_plugin_t *plugin; + struct plugin_s *next; +} plugin_t; +plugin_t *plugins; + +void +plug_ev_subscribe (DB_plugin_t *plugin, int ev, db_callback_t callback, uintptr_t data) { + assert (ev < DB_EV_MAX && ev >= 0); + for (int i = 0; i < MAX_HANDLERS; i++) { + if (!handlers[ev][i].plugin) { + handlers[ev][i].plugin = plugin; + handlers[ev][i].callback = callback; + handlers[ev][i].data = data; + return; + } + } + fprintf (stderr, "failed to subscribe plugin %s to event %d (too many event handlers)\n", plugin->name, ev); +} + +void +plug_ev_unsubscribe (DB_plugin_t *plugin, int ev, db_callback_t callback, uintptr_t data) { + assert (ev < DB_EV_MAX && ev >= 0); + for (int i = 0; i < MAX_HANDLERS; i++) { + if (handlers[ev][i].plugin == plugin) { + handlers[ev][i].plugin = NULL; + handlers[ev][i].callback = NULL; + handlers[ev][i].data = 0; + return; + } + } +} + +void +plug_trigger_event (int ev) { + for (int i = 0; i < MAX_HANDLERS; i++) { + if (handlers[ev][i].plugin && !handlers[ev][i].plugin->inactive) { + handlers[ev][i].callback (ev, handlers[ev][i].data); + } + } +} + +void +plug_load_all (void) { + char dirname[1024]; + snprintf (dirname, 1024, "%s/lib/deadbeef", PREFIX); + struct dirent **namelist = NULL; + int n = scandir (dirname, &namelist, NULL, alphasort); + if (n < 0) + { + if (namelist) { + free (namelist); + } + return; // not a dir or no read access + } + else + { + int i; + for (i = 0; i < n; i++) + { + // no hidden files + if (namelist[i]->d_name[0] != '.') + { + int l = strlen (namelist[i]->d_name); + if (l < 3) { + continue; + } + if (strcasecmp (&namelist[i]->d_name[l-3], ".so")) { + continue; + } + char fullname[1024]; + strcpy (fullname, dirname); + strncat (fullname, "/", 1024); + strncat (fullname, namelist[i]->d_name, 1024); + printf ("loading plugin %s\n", namelist[i]->d_name); + void *handle = dlopen (fullname, RTLD_NOW); + if (!handle) { + fprintf (stderr, "dlopen error: %s\n", dlerror ()); + continue; + } + namelist[i]->d_name[l-3] = 0; + printf ("module name is %s\n", namelist[i]->d_name); + strcat (namelist[i]->d_name, "_load"); + DB_plugin_t *(*plug_load)(DB_functions_t *api) = dlsym (handle, namelist[i]->d_name); + if (!plug_load) { + fprintf (stderr, "dlsym error: %s\n", dlerror ()); + dlclose (handle); + continue; + } + DB_plugin_t *plugin_api = plug_load (&deadbeef_api); + if (!plugin_api) { + namelist[i]->d_name[l-3] = 0; + fprintf (stderr, "plugin %s is incompatible with current version of deadbeef, please upgrade the plugin\n"); + dlclose (handle); + continue; + } + plugin_t *plug = malloc (sizeof (plugin_t)); + memset (plug, 0, sizeof (plugin_t)); + plug->plugin = plugin_api; + plug->handle = handle; + plug->next = plugins; + if (plug->plugin->start) { + if (plug->plugin->start () < 0) { + plug->plugin->inactive = 1; + } + } + plugins = plug; + } + free (namelist[i]); + } + free (namelist); + } +} + +void +plug_unload_all (void) { + while (plugins) { + plugin_t *next = plugins->next; + if (plugins->plugin->stop) { + plugins->plugin->stop (); + } + dlclose (plugins->handle); + plugins = next; + } +} |