From 620e6a5a3764c0dad6c0adb203227e7b8df84083 Mon Sep 17 00:00:00 2001 From: James Booth Date: Wed, 22 Jun 2016 01:09:39 +0100 Subject: [PATCH 01/34] Add function to get plugin name --- src/plugins/python_api.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/plugins/python_api.c b/src/plugins/python_api.c index 5c4cf913..e0222e8d 100644 --- a/src/plugins/python_api.c +++ b/src/plugins/python_api.c @@ -33,6 +33,7 @@ */ #include +#include #include @@ -41,6 +42,9 @@ #include "plugins/python_plugins.h" #include "plugins/callbacks.h" #include "plugins/autocompleters.h" +#include "log.h" + +static char* _python_plugin_name(void); static PyObject* python_api_cons_alert(PyObject *self, PyObject *args) @@ -157,6 +161,9 @@ python_api_register_command(PyObject *self, PyObject *args) } c_examples[len] = NULL; + char *plugin_name = _python_plugin_name(); + log_debug("FILENAME : %s", plugin_name); + allow_python_threads(); api_register_command(command_name, min_args, max_args, c_synopsis, description, c_arguments, c_examples, p_callback, python_command_callback); @@ -790,3 +797,16 @@ python_api_init(void) { Py_InitModule("prof", apiMethods); } + +static char* +_python_plugin_name(void) +{ + PyThreadState *ts = PyThreadState_Get(); + PyFrameObject *frame = ts->frame; + char const* filename = PyString_AsString(frame->f_code->co_filename); + gchar **split = g_strsplit(filename, "/", 0); + char *plugin_name = strdup(split[g_strv_length(split)-1]); + g_strfreev(split); + + return plugin_name; +} From c6288d89f9682ee090f5776956cc2e6e8e6889bc Mon Sep 17 00:00:00 2001 From: James Booth Date: Thu, 23 Jun 2016 00:26:50 +0100 Subject: [PATCH 02/34] Add function to get C plugin name --- src/plugins/c_api.c | 23 +++++++++++++++++++++-- src/plugins/profapi.c | 2 +- src/plugins/profapi.h | 4 +++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/plugins/c_api.c b/src/plugins/c_api.c index 770fd9a3..726f7d45 100644 --- a/src/plugins/c_api.c +++ b/src/plugins/c_api.c @@ -53,6 +53,8 @@ typedef struct window_wrapper_t { void(*func)(char *tag, char *line); } WindowWrapper; +static char* _c_plugin_name(const char *filename); + static void c_api_cons_alert(void) { @@ -78,10 +80,13 @@ c_api_cons_bad_cmd_usage(const char *const cmd) } static void -c_api_register_command(const char *command_name, int min_args, int max_args, +c_api_register_command(const char *filename, const char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void(*callback)(char **args)) { + char *plugin_name = _c_plugin_name(filename); + log_debug("FILENAME : %s", plugin_name); + CommandWrapper *wrapper = malloc(sizeof(CommandWrapper)); wrapper->func = callback; api_register_command(command_name, min_args, max_args, synopsis, @@ -297,7 +302,7 @@ c_api_init(void) prof_cons_show = c_api_cons_show; prof_cons_show_themed = c_api_cons_show_themed; prof_cons_bad_cmd_usage = c_api_cons_bad_cmd_usage; - prof_register_command = c_api_register_command; + _prof_register_command = c_api_register_command; prof_register_timed = c_api_register_timed; prof_completer_add = c_api_completer_add; prof_completer_remove = c_api_completer_remove; @@ -328,3 +333,17 @@ c_api_init(void) prof_incoming_message = c_api_incoming_message; prof_disco_add_feature = c_api_disco_add_feature; } + +static char * +_c_plugin_name(const char *filename) +{ + GString *plugin_name_str = g_string_new(""); + char *name = strndup(filename, strlen(filename)-1); + g_string_append(plugin_name_str, name); + free(name); + g_string_append(plugin_name_str, "so"); + char *result = plugin_name_str->str; + g_string_free(plugin_name_str, FALSE); + + return result; +} diff --git a/src/plugins/profapi.c b/src/plugins/profapi.c index 4b18da3b..9c352343 100644 --- a/src/plugins/profapi.c +++ b/src/plugins/profapi.c @@ -42,7 +42,7 @@ int (*prof_cons_show)(const char * const message) = NULL; int (*prof_cons_show_themed)(const char *const group, const char *const item, const char *const def, const char *const message) = NULL; int (*prof_cons_bad_cmd_usage)(const char *const cmd) = NULL; -void (*prof_register_command)(const char *command_name, int min_args, int max_args, +void (*_prof_register_command)(const char *filename, const char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void(*callback)(char **args)) = NULL; diff --git a/src/plugins/profapi.h b/src/plugins/profapi.h index 54497c8d..d25944c3 100644 --- a/src/plugins/profapi.h +++ b/src/plugins/profapi.h @@ -35,6 +35,8 @@ #ifndef PROF_API_H #define PROF_API_H +#define prof_register_command(command_name, min_args, max_args, synopsis, description, arguments, examples, callback) _prof_register_command(__FILE__, command_name, min_args, max_args, synopsis, description, arguments, examples, callback) + typedef char* PROF_WIN_TAG; void (*prof_cons_alert)(void); @@ -42,7 +44,7 @@ int (*prof_cons_show)(const char * const message); int (*prof_cons_show_themed)(const char *const group, const char *const item, const char *const def, const char *const message); int (*prof_cons_bad_cmd_usage)(const char *const cmd); -void (*prof_register_command)(const char *command_name, int min_args, int max_args, +void (*_prof_register_command)(const char *filename, const char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void(*callback)(char **args)); From 1e37b755fe4030586b6994c397ddc855a659af43 Mon Sep 17 00:00:00 2001 From: James Booth Date: Thu, 23 Jun 2016 00:36:26 +0100 Subject: [PATCH 03/34] Add macro for C plugins register_timed --- src/plugins/c_api.c | 9 ++++++--- src/plugins/profapi.c | 2 +- src/plugins/profapi.h | 3 ++- src/plugins/python_api.c | 9 ++++++--- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/plugins/c_api.c b/src/plugins/c_api.c index 726f7d45..97d2e2f8 100644 --- a/src/plugins/c_api.c +++ b/src/plugins/c_api.c @@ -85,7 +85,7 @@ c_api_register_command(const char *filename, const char *command_name, int min_a void(*callback)(char **args)) { char *plugin_name = _c_plugin_name(filename); - log_debug("FILENAME : %s", plugin_name); + log_debug("Register command %s for %s", command_name, plugin_name); CommandWrapper *wrapper = malloc(sizeof(CommandWrapper)); wrapper->func = callback; @@ -94,8 +94,11 @@ c_api_register_command(const char *filename, const char *command_name, int min_a } static void -c_api_register_timed(void(*callback)(void), int interval_seconds) +c_api_register_timed(const char *filename, void(*callback)(void), int interval_seconds) { + char *plugin_name = _c_plugin_name(filename); + log_debug("Register timed for %s", plugin_name); + TimedWrapper *wrapper = malloc(sizeof(TimedWrapper)); wrapper->func = callback; api_register_timed(wrapper, interval_seconds, c_timed_callback); @@ -303,7 +306,7 @@ c_api_init(void) prof_cons_show_themed = c_api_cons_show_themed; prof_cons_bad_cmd_usage = c_api_cons_bad_cmd_usage; _prof_register_command = c_api_register_command; - prof_register_timed = c_api_register_timed; + _prof_register_timed = c_api_register_timed; prof_completer_add = c_api_completer_add; prof_completer_remove = c_api_completer_remove; prof_completer_clear = c_api_completer_clear; diff --git a/src/plugins/profapi.c b/src/plugins/profapi.c index 9c352343..33967613 100644 --- a/src/plugins/profapi.c +++ b/src/plugins/profapi.c @@ -46,7 +46,7 @@ void (*_prof_register_command)(const char *filename, const char *command_name, i const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void(*callback)(char **args)) = NULL; -void (*prof_register_timed)(void(*callback)(void), int interval_seconds) = NULL; +void (*_prof_register_timed)(const char *filename, void(*callback)(void), int interval_seconds) = NULL; void (*prof_completer_add)(const char *key, char **items) = NULL; void (*prof_completer_remove)(const char *key, char **items) = NULL; diff --git a/src/plugins/profapi.h b/src/plugins/profapi.h index d25944c3..697e9598 100644 --- a/src/plugins/profapi.h +++ b/src/plugins/profapi.h @@ -36,6 +36,7 @@ #define PROF_API_H #define prof_register_command(command_name, min_args, max_args, synopsis, description, arguments, examples, callback) _prof_register_command(__FILE__, command_name, min_args, max_args, synopsis, description, arguments, examples, callback) +#define prof_register_timed(callback, interval_seconds) _prof_register_timed(__FILE__, callback, interval_seconds) typedef char* PROF_WIN_TAG; @@ -48,7 +49,7 @@ void (*_prof_register_command)(const char *filename, const char *command_name, i const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void(*callback)(char **args)); -void (*prof_register_timed)(void(*callback)(void), int interval_seconds); +void (*_prof_register_timed)(const char *filename, void(*callback)(void), int interval_seconds); void (*prof_completer_add)(const char *key, char **items); void (*prof_completer_remove)(const char *key, char **items); diff --git a/src/plugins/python_api.c b/src/plugins/python_api.c index e0222e8d..a5c5d73c 100644 --- a/src/plugins/python_api.c +++ b/src/plugins/python_api.c @@ -119,6 +119,9 @@ python_api_register_command(PyObject *self, PyObject *args) return Py_BuildValue(""); } + char *plugin_name = _python_plugin_name(); + log_debug("Register command %s for %s", command_name, plugin_name); + if (p_callback && PyCallable_Check(p_callback)) { Py_ssize_t len = PyList_Size(synopsis); const char *c_synopsis[len == 0 ? 0 : len+1]; @@ -161,9 +164,6 @@ python_api_register_command(PyObject *self, PyObject *args) } c_examples[len] = NULL; - char *plugin_name = _python_plugin_name(); - log_debug("FILENAME : %s", plugin_name); - allow_python_threads(); api_register_command(command_name, min_args, max_args, c_synopsis, description, c_arguments, c_examples, p_callback, python_command_callback); @@ -176,6 +176,9 @@ python_api_register_command(PyObject *self, PyObject *args) static PyObject * python_api_register_timed(PyObject *self, PyObject *args) { + char *plugin_name = _python_plugin_name(); + log_debug("Register timed for %s", plugin_name); + PyObject *p_callback = NULL; int interval_seconds = 0; From 61a09476c511c33abd9b6be3d5786fee1fa93b94 Mon Sep 17 00:00:00 2001 From: James Booth Date: Thu, 23 Jun 2016 00:44:52 +0100 Subject: [PATCH 04/34] Add macro for plugins completer add --- src/plugins/c_api.c | 7 +++++-- src/plugins/profapi.c | 2 +- src/plugins/profapi.h | 3 ++- src/plugins/python_api.c | 3 +++ 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/plugins/c_api.c b/src/plugins/c_api.c index 97d2e2f8..b5624946 100644 --- a/src/plugins/c_api.c +++ b/src/plugins/c_api.c @@ -105,8 +105,11 @@ c_api_register_timed(const char *filename, void(*callback)(void), int interval_s } static void -c_api_completer_add(const char *key, char **items) +c_api_completer_add(const char *filename, const char *key, char **items) { + char *plugin_name = _c_plugin_name(filename); + log_debug("Autocomplete add %s for %s", key, plugin_name); + api_completer_add(key, items); } @@ -307,7 +310,7 @@ c_api_init(void) prof_cons_bad_cmd_usage = c_api_cons_bad_cmd_usage; _prof_register_command = c_api_register_command; _prof_register_timed = c_api_register_timed; - prof_completer_add = c_api_completer_add; + _prof_completer_add = c_api_completer_add; prof_completer_remove = c_api_completer_remove; prof_completer_clear = c_api_completer_clear; prof_notify = c_api_notify; diff --git a/src/plugins/profapi.c b/src/plugins/profapi.c index 33967613..d80e2690 100644 --- a/src/plugins/profapi.c +++ b/src/plugins/profapi.c @@ -48,7 +48,7 @@ void (*_prof_register_command)(const char *filename, const char *command_name, i void (*_prof_register_timed)(const char *filename, void(*callback)(void), int interval_seconds) = NULL; -void (*prof_completer_add)(const char *key, char **items) = NULL; +void (*_prof_completer_add)(const char *filename, const char *key, char **items) = NULL; void (*prof_completer_remove)(const char *key, char **items) = NULL; void (*prof_completer_clear)(const char *key) = NULL; diff --git a/src/plugins/profapi.h b/src/plugins/profapi.h index 697e9598..8c41b2f2 100644 --- a/src/plugins/profapi.h +++ b/src/plugins/profapi.h @@ -37,6 +37,7 @@ #define prof_register_command(command_name, min_args, max_args, synopsis, description, arguments, examples, callback) _prof_register_command(__FILE__, command_name, min_args, max_args, synopsis, description, arguments, examples, callback) #define prof_register_timed(callback, interval_seconds) _prof_register_timed(__FILE__, callback, interval_seconds) +#define prof_completer_add(key, items) _prof_completer_add(__FILE__, key, items) typedef char* PROF_WIN_TAG; @@ -51,7 +52,7 @@ void (*_prof_register_command)(const char *filename, const char *command_name, i void (*_prof_register_timed)(const char *filename, void(*callback)(void), int interval_seconds); -void (*prof_completer_add)(const char *key, char **items); +void (*_prof_completer_add)(const char *filename, const char *key, char **items); void (*prof_completer_remove)(const char *key, char **items); void (*prof_completer_clear)(const char *key); diff --git a/src/plugins/python_api.c b/src/plugins/python_api.c index a5c5d73c..87a2b4d2 100644 --- a/src/plugins/python_api.c +++ b/src/plugins/python_api.c @@ -205,6 +205,9 @@ python_api_completer_add(PyObject *self, PyObject *args) return Py_BuildValue(""); } + char *plugin_name = _python_plugin_name(); + log_debug("Autocomplete add %s for %s", key, plugin_name); + Py_ssize_t len = PyList_Size(items); char *c_items[len]; From a01eb5d08e1b39d60a6f8fc26e5a87ceb92ec18f Mon Sep 17 00:00:00 2001 From: James Booth Date: Wed, 29 Jun 2016 23:35:57 +0100 Subject: [PATCH 05/34] WIP - Unload plugin commands --- src/command/cmd_ac.c | 9 ++++++ src/command/cmd_ac.h | 1 + src/command/cmd_defs.c | 9 ++++-- src/command/cmd_funcs.c | 55 +++++++++++++++++++++++++++++++++++- src/command/cmd_funcs.h | 11 ++++---- src/config/preferences.c | 7 +++++ src/config/preferences.h | 1 + src/plugins/api.c | 3 +- src/plugins/api.h | 2 +- src/plugins/c_api.c | 4 +-- src/plugins/callbacks.c | 34 ++++++++++++++++++++++ src/plugins/callbacks.h | 4 ++- src/plugins/plugins.c | 27 ++++++++++++++++++ src/plugins/plugins.h | 1 + src/plugins/profapi.c | 2 +- src/plugins/profapi.h | 2 +- src/plugins/python_api.c | 4 +-- src/plugins/python_plugins.c | 1 + src/ui/core.c | 2 +- src/ui/ui.h | 2 +- tests/unittests/ui/stub_ui.c | 2 +- 21 files changed, 162 insertions(+), 21 deletions(-) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 1dfc5cc0..46c1d940 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -702,6 +702,7 @@ cmd_ac_init(void) plugins_ac = autocomplete_new(); autocomplete_add(plugins_ac, "load"); + autocomplete_add(plugins_ac, "unload"); sendfile_ac = autocomplete_new(); @@ -784,6 +785,14 @@ cmd_ac_remove(const char *const value) } } +void +cmd_ac_remove_help(const char *const value) +{ + if (help_ac) { + autocomplete_remove(help_ac, value); + } +} + gboolean cmd_ac_exists(char *cmd) { diff --git a/src/command/cmd_ac.h b/src/command/cmd_ac.h index b294fcd5..637ebcf6 100644 --- a/src/command/cmd_ac.h +++ b/src/command/cmd_ac.h @@ -48,6 +48,7 @@ void cmd_ac_add_alias(ProfAlias *alias); void cmd_ac_add_alias_value(char *value); void cmd_ac_remove(const char *const value); +void cmd_ac_remove_help(const char *const value); void cmd_ac_remove_alias_value(char *value); gboolean cmd_ac_exists(char *cmd); diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index dacf1c91..663a8948 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -1979,13 +1979,16 @@ static struct cmd_t command_defs[] = CMD_NOTAGS CMD_SYN( "/plugins", - "/plugins load ") + "/plugins load ", + "/plugins unload ") CMD_DESC( "Manage plugins. Passing no arguments lists currently loaded plugins.") CMD_ARGS( - { "load ", "Load a plugin." }) + { "load ", "Load a plugin." }, + { "unload ", "Unload a plugin." }) CMD_EXAMPLES( - "/plugin load browser.py") + "/plugin load browser.py", + "/plugin unload pid.so") }, { "/prefs", diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 7f3419e3..0d673248 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -95,6 +95,49 @@ static gboolean _cmd_execute(ProfWin *window, const char *const command, const c static gboolean _cmd_execute_default(ProfWin *window, const char *inp); static gboolean _cmd_execute_alias(ProfWin *window, const char *const inp, gboolean *ran); +void +command_help_free(CommandHelp *help) +{ + free(help->desc); + + if (help->tags) { + int i = 0; + while (i < 20 && help->tags[i]) { + free(help->tags[i]); + i++; + } + free(help->tags); + } + + if (help->synopsis) { + int i = 0; + while (i < 50 && help->synopsis[i]) { + free(help->synopsis[i]); + i++; + } + free(help->synopsis); + } + + if (help->examples) { + int i = 0; + while (i < 20 && help->examples[i]) { + free(help->examples[i]); + i++; + } + free(help->examples); + } + + if (help->args) { + int i = 0; + while (i < 120 && help->args[i]) { + free(help->args[i][0]); + free(help->args[i][1]); + free(help->args[i]); + } + free(help->args); + } +} + /* * Take a line of input and process it, return TRUE if profanity is to * continue, FALSE otherwise @@ -3809,7 +3852,7 @@ cmd_form(ProfWin *window, const char *const command, gchar **args) } else { mucconfwin_form_help(confwin); - const gchar **help_text = NULL; + gchar **help_text = NULL; Command *command = cmd_get("/form"); if (command) { @@ -6038,6 +6081,16 @@ cmd_plugins(ProfWin *window, const char *const command, gchar **args) cons_show("Failed to load plugin: %s", args[1]); } + return TRUE; + } else if (g_strcmp0(args[0], "unload") == 0) { + if (args[1] == NULL) { + cons_bad_cmd_usage(command); + return TRUE; + } + plugins_unload(args[1]); + prefs_remove_plugin(args[1]); + cons_show("Unloaded plugin: %s", args[1]); + return TRUE; } else { GSList *plugins = plugins_get_list(); diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h index 52b9946e..c68efe43 100644 --- a/src/command/cmd_funcs.h +++ b/src/command/cmd_funcs.h @@ -39,11 +39,11 @@ // Command help strings typedef struct cmd_help_t { - const gchar *tags[20]; - const gchar *synopsis[50]; - const gchar *desc; - const gchar *args[128][2]; - const gchar *examples[20]; + gchar *tags[20]; + gchar *synopsis[50]; + gchar *desc; + gchar *args[128][2]; + gchar *examples[20]; } CommandHelp; /* @@ -69,6 +69,7 @@ typedef struct cmd_t { CommandHelp help; } Command; +void command_help_free(CommandHelp *help); gboolean cmd_process_input(ProfWin *window, char *inp); void cmd_execute_connect(ProfWin *window, const char *const account); diff --git a/src/config/preferences.c b/src/config/preferences.c index 9381d014..636bd33d 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -631,6 +631,13 @@ prefs_add_plugin(const char *const name) _save_prefs(); } +void +prefs_remove_plugin(const char *const name) +{ + conf_string_list_remove(prefs, "plugins", "load", name); + _save_prefs(); +} + void prefs_free_plugins(gchar **plugins) { diff --git a/src/config/preferences.h b/src/config/preferences.h index a7b84dfe..3111f81e 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -191,6 +191,7 @@ void prefs_set_autoxa_time(gint value); gchar** prefs_get_plugins(void); void prefs_free_plugins(gchar **plugins); void prefs_add_plugin(const char *const name); +void prefs_remove_plugin(const char *const name); char prefs_get_otr_char(void); void prefs_set_otr_char(char ch); diff --git a/src/plugins/api.c b/src/plugins/api.c index 326ec61d..90272684 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -106,11 +106,12 @@ api_cons_bad_cmd_usage(const char *const cmd) } void -api_register_command(const char *command_name, int min_args, int max_args, +api_register_command(char *plugin_name, char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void *callback, void(*callback_func)(PluginCommand *command, gchar **args)) { PluginCommand *command = malloc(sizeof(PluginCommand)); + command->plugin_name = plugin_name; command->command_name = command_name; command->min_args = min_args; command->max_args = max_args; diff --git a/src/plugins/api.h b/src/plugins/api.h index a835cd8b..6bbcfa5c 100644 --- a/src/plugins/api.h +++ b/src/plugins/api.h @@ -50,7 +50,7 @@ gboolean api_current_win_is_console(void); char* api_get_current_nick(void); char** api_get_current_occupants(void); -void api_register_command(const char *command_name, int min_args, int max_args, +void api_register_command(char *plugin_name, char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void *callback, void(*callback_func)(PluginCommand *command, gchar **args)); void api_register_timed(void *callback, int interval_seconds, diff --git a/src/plugins/c_api.c b/src/plugins/c_api.c index b5624946..4e5900b9 100644 --- a/src/plugins/c_api.c +++ b/src/plugins/c_api.c @@ -80,7 +80,7 @@ c_api_cons_bad_cmd_usage(const char *const cmd) } static void -c_api_register_command(const char *filename, const char *command_name, int min_args, int max_args, +c_api_register_command(const char *filename, char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void(*callback)(char **args)) { @@ -89,7 +89,7 @@ c_api_register_command(const char *filename, const char *command_name, int min_a CommandWrapper *wrapper = malloc(sizeof(CommandWrapper)); wrapper->func = callback; - api_register_command(command_name, min_args, max_args, synopsis, + api_register_command(plugin_name, command_name, min_args, max_args, synopsis, description, arguments, examples, wrapper, c_command_callback); } diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c index 2572f7a4..8960738f 100644 --- a/src/plugins/callbacks.c +++ b/src/plugins/callbacks.c @@ -77,6 +77,40 @@ callbacks_add_command(PluginCommand *command) cmd_ac_add_help(&command->command_name[1]); } +void +_command_destroy(PluginCommand *command) +{ + free(command->command_name); + free(command->plugin_name); + command_help_free(command->help); + // TODO free callback +} + +void +callbacks_remove_commands(const char *const plugin_name) +{ + GSList *items_to_remove = NULL; + GSList *curr = p_commands; + while (curr) { + PluginCommand *command = curr->data; + if (g_strcmp0(command->plugin_name, plugin_name) == 0) { + cmd_ac_remove(command->command_name); + cmd_ac_remove_help(&command->command_name[1]); + items_to_remove = g_slist_append(items_to_remove, curr); + } + curr = g_slist_next(curr); + } + + curr = items_to_remove; + while (curr) { + GSList *item = curr->data; + PluginCommand *command = item->data; + _command_destroy(command); + p_commands = g_slist_remove_link(p_commands, item); + curr = g_slist_next(curr); + } +} + void callbacks_add_timed(PluginTimedFunction *timed_function) { diff --git a/src/plugins/callbacks.h b/src/plugins/callbacks.h index 9b175d0a..a8253e21 100644 --- a/src/plugins/callbacks.h +++ b/src/plugins/callbacks.h @@ -40,7 +40,8 @@ #include "command/cmd_defs.h" typedef struct p_command { - const char *command_name; + char *plugin_name; + char *command_name; int min_args; int max_args; CommandHelp *help; @@ -65,6 +66,7 @@ void callbacks_init(void); void callbacks_close(void); void callbacks_add_command(PluginCommand *command); +void callbacks_remove_commands(const char *const plugin_name); void callbacks_add_timed(PluginTimedFunction *timed_function); void callbacks_add_window_handler(const char *tag, PluginWindowCallback *window_callback); void * callbacks_get_window_handler(const char *tag); diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 5757a174..3395c77f 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -172,6 +172,33 @@ plugins_load(const char *const name) } } +gboolean +plugins_unload(const char *const name) +{ + GSList *found = g_slist_find_custom(plugins, name, (GCompareFunc)_find_by_name); + if (!found) { + log_info("Failed to unload plugin: %s, plugin not currently loaded", name); + return FALSE; + } + + plugins = g_slist_remove_link(plugins, found); + +#ifdef HAVE_PYTHON + if (g_str_has_suffix(name, ".py")) { + python_plugin_destroy(found->data); + } +#endif +#ifdef HAVE_C + if (g_str_has_suffix(name, ".so")) { + c_plugin_destroy(found->data); + } +#endif + + g_slist_free(found); + + return TRUE; +} + GSList * plugins_get_list(void) { diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index b03248ab..19ac269d 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -105,6 +105,7 @@ void plugins_reset_autocomplete(void); void plugins_shutdown(void); gboolean plugins_load(const char *const name); +gboolean plugins_unload(const char *const name); void plugins_on_start(void); void plugins_on_shutdown(void); diff --git a/src/plugins/profapi.c b/src/plugins/profapi.c index d80e2690..617fd9f0 100644 --- a/src/plugins/profapi.c +++ b/src/plugins/profapi.c @@ -42,7 +42,7 @@ int (*prof_cons_show)(const char * const message) = NULL; int (*prof_cons_show_themed)(const char *const group, const char *const item, const char *const def, const char *const message) = NULL; int (*prof_cons_bad_cmd_usage)(const char *const cmd) = NULL; -void (*_prof_register_command)(const char *filename, const char *command_name, int min_args, int max_args, +void (*_prof_register_command)(const char *filename, char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void(*callback)(char **args)) = NULL; diff --git a/src/plugins/profapi.h b/src/plugins/profapi.h index 8c41b2f2..7f26c33f 100644 --- a/src/plugins/profapi.h +++ b/src/plugins/profapi.h @@ -46,7 +46,7 @@ int (*prof_cons_show)(const char * const message); int (*prof_cons_show_themed)(const char *const group, const char *const item, const char *const def, const char *const message); int (*prof_cons_bad_cmd_usage)(const char *const cmd); -void (*_prof_register_command)(const char *filename, const char *command_name, int min_args, int max_args, +void (*_prof_register_command)(const char *filename, char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void(*callback)(char **args)); diff --git a/src/plugins/python_api.c b/src/plugins/python_api.c index 87a2b4d2..356a2854 100644 --- a/src/plugins/python_api.c +++ b/src/plugins/python_api.c @@ -105,7 +105,7 @@ python_api_cons_bad_cmd_usage(PyObject *self, PyObject *args) static PyObject* python_api_register_command(PyObject *self, PyObject *args) { - const char *command_name = NULL; + char *command_name = NULL; int min_args = 0; int max_args = 0; PyObject *synopsis = NULL; @@ -165,7 +165,7 @@ python_api_register_command(PyObject *self, PyObject *args) c_examples[len] = NULL; allow_python_threads(); - api_register_command(command_name, min_args, max_args, c_synopsis, + api_register_command(plugin_name, command_name, min_args, max_args, c_synopsis, description, c_arguments, c_examples, p_callback, python_command_callback); disable_python_threads(); } diff --git a/src/plugins/python_plugins.c b/src/plugins/python_plugins.c index 7861f484..8e8f72a7 100644 --- a/src/plugins/python_plugins.c +++ b/src/plugins/python_plugins.c @@ -888,6 +888,7 @@ python_check_error(void) void python_plugin_destroy(ProfPlugin *plugin) { + callbacks_remove_commands(plugin->name); disable_python_threads(); free(plugin->name); Py_XDECREF(plugin->module); diff --git a/src/ui/core.c b/src/ui/core.c index 3a89008f..c687cba6 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -1230,7 +1230,7 @@ ui_handle_room_config_submit_result_error(const char *const roomjid, const char } void -ui_show_lines(ProfWin *window, const gchar** lines) +ui_show_lines(ProfWin *window, gchar** lines) { if (lines) { int i; diff --git a/src/ui/ui.h b/src/ui/ui.h index c15af910..5cf8cb31 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -110,7 +110,7 @@ void ui_goodbye_title(void); void ui_handle_room_configuration_form_error(const char *const roomjid, const char *const message); void ui_handle_room_config_submit_result(const char *const roomjid); void ui_handle_room_config_submit_result_error(const char *const roomjid, const char *const message); -void ui_show_lines(ProfWin *window, const gchar** lines); +void ui_show_lines(ProfWin *window, gchar** lines); void ui_redraw_all_room_rosters(void); void ui_show_all_room_rosters(void); void ui_hide_all_room_rosters(void); diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c index 5e86799a..b0635fb8 100644 --- a/tests/unittests/ui/stub_ui.c +++ b/tests/unittests/ui/stub_ui.c @@ -265,7 +265,7 @@ void mucconfwin_show_form(ProfMucConfWin *confwin) {} void mucconfwin_show_form_field(ProfMucConfWin *confwin, DataForm *form, char *tag) {} void mucconfwin_form_help(ProfMucConfWin *confwin) {} void mucconfwin_field_help(ProfMucConfWin *confwin, char *tag) {} -void ui_show_lines(ProfWin *window, const gchar** lines) {} +void ui_show_lines(ProfWin *window, gchar** lines) {} void ui_redraw_all_room_rosters(void) {} void ui_show_all_room_rosters(void) {} void ui_hide_all_room_rosters(void) {} From 29eb843d56c2c52e9ae13144c93f094821ecff06 Mon Sep 17 00:00:00 2001 From: James Booth Date: Thu, 30 Jun 2016 22:37:52 +0100 Subject: [PATCH 06/34] Revert "WIP - Unload plugin commands" This reverts commit a01eb5d08e1b39d60a6f8fc26e5a87ceb92ec18f. --- src/command/cmd_ac.c | 9 ------ src/command/cmd_ac.h | 1 - src/command/cmd_defs.c | 9 ++---- src/command/cmd_funcs.c | 55 +----------------------------------- src/command/cmd_funcs.h | 11 ++++---- src/config/preferences.c | 7 ----- src/config/preferences.h | 1 - src/plugins/api.c | 3 +- src/plugins/api.h | 2 +- src/plugins/c_api.c | 4 +-- src/plugins/callbacks.c | 34 ---------------------- src/plugins/callbacks.h | 4 +-- src/plugins/plugins.c | 27 ------------------ src/plugins/plugins.h | 1 - src/plugins/profapi.c | 2 +- src/plugins/profapi.h | 2 +- src/plugins/python_api.c | 4 +-- src/plugins/python_plugins.c | 1 - src/ui/core.c | 2 +- src/ui/ui.h | 2 +- tests/unittests/ui/stub_ui.c | 2 +- 21 files changed, 21 insertions(+), 162 deletions(-) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 46c1d940..1dfc5cc0 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -702,7 +702,6 @@ cmd_ac_init(void) plugins_ac = autocomplete_new(); autocomplete_add(plugins_ac, "load"); - autocomplete_add(plugins_ac, "unload"); sendfile_ac = autocomplete_new(); @@ -785,14 +784,6 @@ cmd_ac_remove(const char *const value) } } -void -cmd_ac_remove_help(const char *const value) -{ - if (help_ac) { - autocomplete_remove(help_ac, value); - } -} - gboolean cmd_ac_exists(char *cmd) { diff --git a/src/command/cmd_ac.h b/src/command/cmd_ac.h index 637ebcf6..b294fcd5 100644 --- a/src/command/cmd_ac.h +++ b/src/command/cmd_ac.h @@ -48,7 +48,6 @@ void cmd_ac_add_alias(ProfAlias *alias); void cmd_ac_add_alias_value(char *value); void cmd_ac_remove(const char *const value); -void cmd_ac_remove_help(const char *const value); void cmd_ac_remove_alias_value(char *value); gboolean cmd_ac_exists(char *cmd); diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 663a8948..dacf1c91 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -1979,16 +1979,13 @@ static struct cmd_t command_defs[] = CMD_NOTAGS CMD_SYN( "/plugins", - "/plugins load ", - "/plugins unload ") + "/plugins load ") CMD_DESC( "Manage plugins. Passing no arguments lists currently loaded plugins.") CMD_ARGS( - { "load ", "Load a plugin." }, - { "unload ", "Unload a plugin." }) + { "load ", "Load a plugin." }) CMD_EXAMPLES( - "/plugin load browser.py", - "/plugin unload pid.so") + "/plugin load browser.py") }, { "/prefs", diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 0d673248..7f3419e3 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -95,49 +95,6 @@ static gboolean _cmd_execute(ProfWin *window, const char *const command, const c static gboolean _cmd_execute_default(ProfWin *window, const char *inp); static gboolean _cmd_execute_alias(ProfWin *window, const char *const inp, gboolean *ran); -void -command_help_free(CommandHelp *help) -{ - free(help->desc); - - if (help->tags) { - int i = 0; - while (i < 20 && help->tags[i]) { - free(help->tags[i]); - i++; - } - free(help->tags); - } - - if (help->synopsis) { - int i = 0; - while (i < 50 && help->synopsis[i]) { - free(help->synopsis[i]); - i++; - } - free(help->synopsis); - } - - if (help->examples) { - int i = 0; - while (i < 20 && help->examples[i]) { - free(help->examples[i]); - i++; - } - free(help->examples); - } - - if (help->args) { - int i = 0; - while (i < 120 && help->args[i]) { - free(help->args[i][0]); - free(help->args[i][1]); - free(help->args[i]); - } - free(help->args); - } -} - /* * Take a line of input and process it, return TRUE if profanity is to * continue, FALSE otherwise @@ -3852,7 +3809,7 @@ cmd_form(ProfWin *window, const char *const command, gchar **args) } else { mucconfwin_form_help(confwin); - gchar **help_text = NULL; + const gchar **help_text = NULL; Command *command = cmd_get("/form"); if (command) { @@ -6081,16 +6038,6 @@ cmd_plugins(ProfWin *window, const char *const command, gchar **args) cons_show("Failed to load plugin: %s", args[1]); } - return TRUE; - } else if (g_strcmp0(args[0], "unload") == 0) { - if (args[1] == NULL) { - cons_bad_cmd_usage(command); - return TRUE; - } - plugins_unload(args[1]); - prefs_remove_plugin(args[1]); - cons_show("Unloaded plugin: %s", args[1]); - return TRUE; } else { GSList *plugins = plugins_get_list(); diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h index c68efe43..52b9946e 100644 --- a/src/command/cmd_funcs.h +++ b/src/command/cmd_funcs.h @@ -39,11 +39,11 @@ // Command help strings typedef struct cmd_help_t { - gchar *tags[20]; - gchar *synopsis[50]; - gchar *desc; - gchar *args[128][2]; - gchar *examples[20]; + const gchar *tags[20]; + const gchar *synopsis[50]; + const gchar *desc; + const gchar *args[128][2]; + const gchar *examples[20]; } CommandHelp; /* @@ -69,7 +69,6 @@ typedef struct cmd_t { CommandHelp help; } Command; -void command_help_free(CommandHelp *help); gboolean cmd_process_input(ProfWin *window, char *inp); void cmd_execute_connect(ProfWin *window, const char *const account); diff --git a/src/config/preferences.c b/src/config/preferences.c index 636bd33d..9381d014 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -631,13 +631,6 @@ prefs_add_plugin(const char *const name) _save_prefs(); } -void -prefs_remove_plugin(const char *const name) -{ - conf_string_list_remove(prefs, "plugins", "load", name); - _save_prefs(); -} - void prefs_free_plugins(gchar **plugins) { diff --git a/src/config/preferences.h b/src/config/preferences.h index 3111f81e..a7b84dfe 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -191,7 +191,6 @@ void prefs_set_autoxa_time(gint value); gchar** prefs_get_plugins(void); void prefs_free_plugins(gchar **plugins); void prefs_add_plugin(const char *const name); -void prefs_remove_plugin(const char *const name); char prefs_get_otr_char(void); void prefs_set_otr_char(char ch); diff --git a/src/plugins/api.c b/src/plugins/api.c index 90272684..326ec61d 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -106,12 +106,11 @@ api_cons_bad_cmd_usage(const char *const cmd) } void -api_register_command(char *plugin_name, char *command_name, int min_args, int max_args, +api_register_command(const char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void *callback, void(*callback_func)(PluginCommand *command, gchar **args)) { PluginCommand *command = malloc(sizeof(PluginCommand)); - command->plugin_name = plugin_name; command->command_name = command_name; command->min_args = min_args; command->max_args = max_args; diff --git a/src/plugins/api.h b/src/plugins/api.h index 6bbcfa5c..a835cd8b 100644 --- a/src/plugins/api.h +++ b/src/plugins/api.h @@ -50,7 +50,7 @@ gboolean api_current_win_is_console(void); char* api_get_current_nick(void); char** api_get_current_occupants(void); -void api_register_command(char *plugin_name, char *command_name, int min_args, int max_args, +void api_register_command(const char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void *callback, void(*callback_func)(PluginCommand *command, gchar **args)); void api_register_timed(void *callback, int interval_seconds, diff --git a/src/plugins/c_api.c b/src/plugins/c_api.c index 4e5900b9..b5624946 100644 --- a/src/plugins/c_api.c +++ b/src/plugins/c_api.c @@ -80,7 +80,7 @@ c_api_cons_bad_cmd_usage(const char *const cmd) } static void -c_api_register_command(const char *filename, char *command_name, int min_args, int max_args, +c_api_register_command(const char *filename, const char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void(*callback)(char **args)) { @@ -89,7 +89,7 @@ c_api_register_command(const char *filename, char *command_name, int min_args, i CommandWrapper *wrapper = malloc(sizeof(CommandWrapper)); wrapper->func = callback; - api_register_command(plugin_name, command_name, min_args, max_args, synopsis, + api_register_command(command_name, min_args, max_args, synopsis, description, arguments, examples, wrapper, c_command_callback); } diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c index 8960738f..2572f7a4 100644 --- a/src/plugins/callbacks.c +++ b/src/plugins/callbacks.c @@ -77,40 +77,6 @@ callbacks_add_command(PluginCommand *command) cmd_ac_add_help(&command->command_name[1]); } -void -_command_destroy(PluginCommand *command) -{ - free(command->command_name); - free(command->plugin_name); - command_help_free(command->help); - // TODO free callback -} - -void -callbacks_remove_commands(const char *const plugin_name) -{ - GSList *items_to_remove = NULL; - GSList *curr = p_commands; - while (curr) { - PluginCommand *command = curr->data; - if (g_strcmp0(command->plugin_name, plugin_name) == 0) { - cmd_ac_remove(command->command_name); - cmd_ac_remove_help(&command->command_name[1]); - items_to_remove = g_slist_append(items_to_remove, curr); - } - curr = g_slist_next(curr); - } - - curr = items_to_remove; - while (curr) { - GSList *item = curr->data; - PluginCommand *command = item->data; - _command_destroy(command); - p_commands = g_slist_remove_link(p_commands, item); - curr = g_slist_next(curr); - } -} - void callbacks_add_timed(PluginTimedFunction *timed_function) { diff --git a/src/plugins/callbacks.h b/src/plugins/callbacks.h index a8253e21..9b175d0a 100644 --- a/src/plugins/callbacks.h +++ b/src/plugins/callbacks.h @@ -40,8 +40,7 @@ #include "command/cmd_defs.h" typedef struct p_command { - char *plugin_name; - char *command_name; + const char *command_name; int min_args; int max_args; CommandHelp *help; @@ -66,7 +65,6 @@ void callbacks_init(void); void callbacks_close(void); void callbacks_add_command(PluginCommand *command); -void callbacks_remove_commands(const char *const plugin_name); void callbacks_add_timed(PluginTimedFunction *timed_function); void callbacks_add_window_handler(const char *tag, PluginWindowCallback *window_callback); void * callbacks_get_window_handler(const char *tag); diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 3395c77f..5757a174 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -172,33 +172,6 @@ plugins_load(const char *const name) } } -gboolean -plugins_unload(const char *const name) -{ - GSList *found = g_slist_find_custom(plugins, name, (GCompareFunc)_find_by_name); - if (!found) { - log_info("Failed to unload plugin: %s, plugin not currently loaded", name); - return FALSE; - } - - plugins = g_slist_remove_link(plugins, found); - -#ifdef HAVE_PYTHON - if (g_str_has_suffix(name, ".py")) { - python_plugin_destroy(found->data); - } -#endif -#ifdef HAVE_C - if (g_str_has_suffix(name, ".so")) { - c_plugin_destroy(found->data); - } -#endif - - g_slist_free(found); - - return TRUE; -} - GSList * plugins_get_list(void) { diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index 19ac269d..b03248ab 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -105,7 +105,6 @@ void plugins_reset_autocomplete(void); void plugins_shutdown(void); gboolean plugins_load(const char *const name); -gboolean plugins_unload(const char *const name); void plugins_on_start(void); void plugins_on_shutdown(void); diff --git a/src/plugins/profapi.c b/src/plugins/profapi.c index 617fd9f0..d80e2690 100644 --- a/src/plugins/profapi.c +++ b/src/plugins/profapi.c @@ -42,7 +42,7 @@ int (*prof_cons_show)(const char * const message) = NULL; int (*prof_cons_show_themed)(const char *const group, const char *const item, const char *const def, const char *const message) = NULL; int (*prof_cons_bad_cmd_usage)(const char *const cmd) = NULL; -void (*_prof_register_command)(const char *filename, char *command_name, int min_args, int max_args, +void (*_prof_register_command)(const char *filename, const char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void(*callback)(char **args)) = NULL; diff --git a/src/plugins/profapi.h b/src/plugins/profapi.h index 7f26c33f..8c41b2f2 100644 --- a/src/plugins/profapi.h +++ b/src/plugins/profapi.h @@ -46,7 +46,7 @@ int (*prof_cons_show)(const char * const message); int (*prof_cons_show_themed)(const char *const group, const char *const item, const char *const def, const char *const message); int (*prof_cons_bad_cmd_usage)(const char *const cmd); -void (*_prof_register_command)(const char *filename, char *command_name, int min_args, int max_args, +void (*_prof_register_command)(const char *filename, const char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void(*callback)(char **args)); diff --git a/src/plugins/python_api.c b/src/plugins/python_api.c index 356a2854..87a2b4d2 100644 --- a/src/plugins/python_api.c +++ b/src/plugins/python_api.c @@ -105,7 +105,7 @@ python_api_cons_bad_cmd_usage(PyObject *self, PyObject *args) static PyObject* python_api_register_command(PyObject *self, PyObject *args) { - char *command_name = NULL; + const char *command_name = NULL; int min_args = 0; int max_args = 0; PyObject *synopsis = NULL; @@ -165,7 +165,7 @@ python_api_register_command(PyObject *self, PyObject *args) c_examples[len] = NULL; allow_python_threads(); - api_register_command(plugin_name, command_name, min_args, max_args, c_synopsis, + api_register_command(command_name, min_args, max_args, c_synopsis, description, c_arguments, c_examples, p_callback, python_command_callback); disable_python_threads(); } diff --git a/src/plugins/python_plugins.c b/src/plugins/python_plugins.c index 8e8f72a7..7861f484 100644 --- a/src/plugins/python_plugins.c +++ b/src/plugins/python_plugins.c @@ -888,7 +888,6 @@ python_check_error(void) void python_plugin_destroy(ProfPlugin *plugin) { - callbacks_remove_commands(plugin->name); disable_python_threads(); free(plugin->name); Py_XDECREF(plugin->module); diff --git a/src/ui/core.c b/src/ui/core.c index c687cba6..3a89008f 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -1230,7 +1230,7 @@ ui_handle_room_config_submit_result_error(const char *const roomjid, const char } void -ui_show_lines(ProfWin *window, gchar** lines) +ui_show_lines(ProfWin *window, const gchar** lines) { if (lines) { int i; diff --git a/src/ui/ui.h b/src/ui/ui.h index 5cf8cb31..c15af910 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -110,7 +110,7 @@ void ui_goodbye_title(void); void ui_handle_room_configuration_form_error(const char *const roomjid, const char *const message); void ui_handle_room_config_submit_result(const char *const roomjid); void ui_handle_room_config_submit_result_error(const char *const roomjid, const char *const message); -void ui_show_lines(ProfWin *window, gchar** lines); +void ui_show_lines(ProfWin *window, const gchar** lines); void ui_redraw_all_room_rosters(void); void ui_show_all_room_rosters(void); void ui_hide_all_room_rosters(void); diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c index b0635fb8..5e86799a 100644 --- a/tests/unittests/ui/stub_ui.c +++ b/tests/unittests/ui/stub_ui.c @@ -265,7 +265,7 @@ void mucconfwin_show_form(ProfMucConfWin *confwin) {} void mucconfwin_show_form_field(ProfMucConfWin *confwin, DataForm *form, char *tag) {} void mucconfwin_form_help(ProfMucConfWin *confwin) {} void mucconfwin_field_help(ProfMucConfWin *confwin, char *tag) {} -void ui_show_lines(ProfWin *window, gchar** lines) {} +void ui_show_lines(ProfWin *window, const gchar** lines) {} void ui_redraw_all_room_rosters(void) {} void ui_show_all_room_rosters(void) {} void ui_hide_all_room_rosters(void) {} From 56480ce9ea25697215e677d029f0ad25f9cc8b99 Mon Sep 17 00:00:00 2001 From: James Booth Date: Thu, 30 Jun 2016 22:54:46 +0100 Subject: [PATCH 07/34] Pass plugin name to api layer --- src/plugins/api.c | 6 +++--- src/plugins/api.h | 6 +++--- src/plugins/c_api.c | 6 +++--- src/plugins/python_api.c | 10 +++++----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/plugins/api.c b/src/plugins/api.c index 326ec61d..3bdb073b 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -106,7 +106,7 @@ api_cons_bad_cmd_usage(const char *const cmd) } void -api_register_command(const char *command_name, int min_args, int max_args, +api_register_command(const char *const plugin_name, const char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void *callback, void(*callback_func)(PluginCommand *command, gchar **args)) { @@ -144,7 +144,7 @@ api_register_command(const char *command_name, int min_args, int max_args, } void -api_register_timed(void *callback, int interval_seconds, +api_register_timed(const char *const plugin_name, void *callback, int interval_seconds, void (*callback_func)(PluginTimedFunction *timed_function)) { PluginTimedFunction *timed_function = malloc(sizeof(PluginTimedFunction)); @@ -157,7 +157,7 @@ api_register_timed(void *callback, int interval_seconds, } void -api_completer_add(const char *key, char **items) +api_completer_add(const char *const plugin_name, const char *key, char **items) { autocompleters_add(key, items); } diff --git a/src/plugins/api.h b/src/plugins/api.h index a835cd8b..afa9f5a1 100644 --- a/src/plugins/api.h +++ b/src/plugins/api.h @@ -50,13 +50,13 @@ gboolean api_current_win_is_console(void); char* api_get_current_nick(void); char** api_get_current_occupants(void); -void api_register_command(const char *command_name, int min_args, int max_args, +void api_register_command(const char *const plugin_name, const char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void *callback, void(*callback_func)(PluginCommand *command, gchar **args)); -void api_register_timed(void *callback, int interval_seconds, +void api_register_timed(const char *const plugin_name, void *callback, int interval_seconds, void (*callback_func)(PluginTimedFunction *timed_function)); -void api_completer_add(const char *key, char **items); +void api_completer_add(const char *const plugin_name, const char *key, char **items); void api_completer_remove(const char *key, char **items); void api_completer_clear(const char *key); diff --git a/src/plugins/c_api.c b/src/plugins/c_api.c index b5624946..1fab40f9 100644 --- a/src/plugins/c_api.c +++ b/src/plugins/c_api.c @@ -89,7 +89,7 @@ c_api_register_command(const char *filename, const char *command_name, int min_a CommandWrapper *wrapper = malloc(sizeof(CommandWrapper)); wrapper->func = callback; - api_register_command(command_name, min_args, max_args, synopsis, + api_register_command(plugin_name, command_name, min_args, max_args, synopsis, description, arguments, examples, wrapper, c_command_callback); } @@ -101,7 +101,7 @@ c_api_register_timed(const char *filename, void(*callback)(void), int interval_s TimedWrapper *wrapper = malloc(sizeof(TimedWrapper)); wrapper->func = callback; - api_register_timed(wrapper, interval_seconds, c_timed_callback); + api_register_timed(plugin_name, wrapper, interval_seconds, c_timed_callback); } static void @@ -110,7 +110,7 @@ c_api_completer_add(const char *filename, const char *key, char **items) char *plugin_name = _c_plugin_name(filename); log_debug("Autocomplete add %s for %s", key, plugin_name); - api_completer_add(key, items); + api_completer_add(plugin_name, key, items); } static void diff --git a/src/plugins/python_api.c b/src/plugins/python_api.c index 87a2b4d2..d0d223e8 100644 --- a/src/plugins/python_api.c +++ b/src/plugins/python_api.c @@ -165,7 +165,7 @@ python_api_register_command(PyObject *self, PyObject *args) c_examples[len] = NULL; allow_python_threads(); - api_register_command(command_name, min_args, max_args, c_synopsis, + api_register_command(plugin_name, command_name, min_args, max_args, c_synopsis, description, c_arguments, c_examples, p_callback, python_command_callback); disable_python_threads(); } @@ -188,7 +188,7 @@ python_api_register_timed(PyObject *self, PyObject *args) if (p_callback && PyCallable_Check(p_callback)) { allow_python_threads(); - api_register_timed(p_callback, interval_seconds, python_timed_callback); + api_register_timed(plugin_name, p_callback, interval_seconds, python_timed_callback); disable_python_threads(); } @@ -220,7 +220,7 @@ python_api_completer_add(PyObject *self, PyObject *args) c_items[len] = NULL; allow_python_threads(); - autocompleters_add(key, c_items); + api_completer_add(plugin_name, key, c_items); disable_python_threads(); return Py_BuildValue(""); @@ -248,7 +248,7 @@ python_api_completer_remove(PyObject *self, PyObject *args) c_items[len] = NULL; allow_python_threads(); - autocompleters_remove(key, c_items); + api_completer_remove(key, c_items); disable_python_threads(); return Py_BuildValue(""); @@ -264,7 +264,7 @@ python_api_completer_clear(PyObject *self, PyObject *args) } allow_python_threads(); - autocompleters_clear(key); + api_completer_clear(key); disable_python_threads(); return Py_BuildValue(""); From ef6bad483eef8f83393623127e1a27a46fa8b221 Mon Sep 17 00:00:00 2001 From: James Booth Date: Thu, 30 Jun 2016 23:14:05 +0100 Subject: [PATCH 08/34] /plugins unload command and completer --- src/command/cmd_ac.c | 27 +++++++++++++++++++++++++++ src/command/cmd_defs.c | 7 +++++-- src/command/cmd_funcs.c | 14 ++++++++++++++ src/config/preferences.c | 7 +++++++ src/config/preferences.h | 1 + src/plugins/plugins.c | 20 ++++++++++++++++++++ src/plugins/plugins.h | 2 ++ 7 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 1dfc5cc0..a4cd788e 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -185,6 +185,7 @@ static Autocomplete console_msg_ac; static Autocomplete autoping_ac; static Autocomplete plugins_ac; static Autocomplete plugins_load_ac; +static Autocomplete plugins_unload_ac; static Autocomplete sendfile_ac; static Autocomplete blocked_ac; static Autocomplete tray_ac; @@ -484,6 +485,7 @@ cmd_ac_init(void) theme_load_ac = NULL; plugins_load_ac = NULL; + plugins_unload_ac = NULL; who_roster_ac = autocomplete_new(); autocomplete_add(who_roster_ac, "chat"); @@ -702,6 +704,7 @@ cmd_ac_init(void) plugins_ac = autocomplete_new(); autocomplete_add(plugins_ac, "load"); + autocomplete_add(plugins_ac, "unload"); sendfile_ac = autocomplete_new(); @@ -909,6 +912,10 @@ cmd_ac_reset(ProfWin *window) autocomplete_free(plugins_load_ac); plugins_load_ac = NULL; } + if (plugins_unload_ac) { + autocomplete_free(plugins_unload_ac); + plugins_unload_ac = NULL; + } autocomplete_reset(account_ac); autocomplete_reset(account_set_ac); autocomplete_reset(account_clear_ac); @@ -1087,6 +1094,7 @@ cmd_ac_uninit(void) autocomplete_free(autoping_ac); autocomplete_free(plugins_ac); autocomplete_free(plugins_load_ac); + autocomplete_free(plugins_unload_ac); autocomplete_free(sendfile_ac); autocomplete_free(blocked_ac); autocomplete_free(tray_ac); @@ -1865,6 +1873,7 @@ static char* _plugins_autocomplete(ProfWin *window, const char *const input) { char *result = NULL; + if (strncmp(input, "/plugins load ", 14) == 0) { if (plugins_load_ac == NULL) { plugins_load_ac = autocomplete_new(); @@ -1881,6 +1890,24 @@ _plugins_autocomplete(ProfWin *window, const char *const input) return result; } } + + if (strncmp(input, "/plugins unload ", 16) == 0) { + if (plugins_unload_ac == NULL) { + plugins_unload_ac = autocomplete_new(); + GSList *plugins = plugins_loaded_list(); + GSList *curr = plugins; + while (curr) { + autocomplete_add(plugins_unload_ac, curr->data); + curr = g_slist_next(curr); + } + g_slist_free(plugins); + } + result = autocomplete_param_with_ac(input, "/plugins unload", plugins_unload_ac, TRUE); + if (result) { + return result; + } + } + result = autocomplete_param_with_ac(input, "/plugins", plugins_ac, TRUE); if (result) { return result; diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index dacf1c91..02f5ee93 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -1979,13 +1979,16 @@ static struct cmd_t command_defs[] = CMD_NOTAGS CMD_SYN( "/plugins", + "/plugins unload ", "/plugins load ") CMD_DESC( "Manage plugins. Passing no arguments lists currently loaded plugins.") CMD_ARGS( - { "load ", "Load a plugin." }) + { "load ", "Load a plugin." }, + { "unload ", "Unload a plugin." }) CMD_EXAMPLES( - "/plugin load browser.py") + "/plugin load browser.py", + "/plugin unload say.py") }, { "/prefs", diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 7f3419e3..b935f13d 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -6038,6 +6038,20 @@ cmd_plugins(ProfWin *window, const char *const command, gchar **args) cons_show("Failed to load plugin: %s", args[1]); } + return TRUE; + } else if (g_strcmp0(args[0], "unload") == 0) { + if (args[1] == NULL) { + cons_bad_cmd_usage(command); + return TRUE; + } + gboolean res = plugins_unload(args[1]); + if (res) { + prefs_remove_plugin(args[1]); + cons_show("Unloaded plugin: %s", args[1]); + } else { + cons_show("Failed to unload plugin: %s", args[1]); + } + return TRUE; } else { GSList *plugins = plugins_get_list(); diff --git a/src/config/preferences.c b/src/config/preferences.c index 9381d014..636bd33d 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -631,6 +631,13 @@ prefs_add_plugin(const char *const name) _save_prefs(); } +void +prefs_remove_plugin(const char *const name) +{ + conf_string_list_remove(prefs, "plugins", "load", name); + _save_prefs(); +} + void prefs_free_plugins(gchar **plugins) { diff --git a/src/config/preferences.h b/src/config/preferences.h index a7b84dfe..3111f81e 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -191,6 +191,7 @@ void prefs_set_autoxa_time(gint value); gchar** prefs_get_plugins(void); void prefs_free_plugins(gchar **plugins); void prefs_add_plugin(const char *const name); +void prefs_remove_plugin(const char *const name); char prefs_get_otr_char(void); void prefs_set_otr_char(char ch); diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 5757a174..707ca497 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -172,6 +172,12 @@ plugins_load(const char *const name) } } +gboolean +plugins_unload(const char *const name) +{ + return FALSE; +} + GSList * plugins_get_list(void) { @@ -218,6 +224,20 @@ plugins_unloaded_list(void) return result; } +GSList* +plugins_loaded_list(void) +{ + GSList *result = NULL; + GSList *curr = plugins; + while (curr) { + ProfPlugin *plugin = curr->data; + result = g_slist_append(result, plugin->name); + curr = g_slist_next(curr); + } + + return result; +} + char * plugins_autocomplete(const char * const input) { diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index b03248ab..a5b10a3e 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -100,11 +100,13 @@ typedef struct prof_plugin_t { void plugins_init(void); GSList* plugins_get_list(void); GSList *plugins_unloaded_list(void); +GSList *plugins_loaded_list(void); char* plugins_autocomplete(const char *const input); void plugins_reset_autocomplete(void); void plugins_shutdown(void); gboolean plugins_load(const char *const name); +gboolean plugins_unload(const char *const name); void plugins_on_start(void); void plugins_on_shutdown(void); From 0cd1b50122294ac5a5d967d934eea82aec2874f1 Mon Sep 17 00:00:00 2001 From: James Booth Date: Thu, 30 Jun 2016 23:16:49 +0100 Subject: [PATCH 09/34] Move plugin config add on load --- src/command/cmd_funcs.c | 1 - src/plugins/plugins.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index b935f13d..40944874 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -6032,7 +6032,6 @@ cmd_plugins(ProfWin *window, const char *const command, gchar **args) } gboolean res = plugins_load(args[1]); if (res) { - prefs_add_plugin(args[1]); cons_show("Loaded plugin: %s", args[1]); } else { cons_show("Failed to load plugin: %s", args[1]); diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 707ca497..ac8e33c6 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -165,6 +165,7 @@ plugins_load(const char *const name) plugin->init_func(plugin, PACKAGE_VERSION, PACKAGE_STATUS, NULL, NULL); } log_info("Loaded plugin: %s", name); + prefs_add_plugin(args[1]); return TRUE; } else { log_info("Failed to load plugin: %s", name); From bb33522e4d52d13b0814690b63c5d397c1828ed2 Mon Sep 17 00:00:00 2001 From: James Booth Date: Thu, 30 Jun 2016 23:18:30 +0100 Subject: [PATCH 10/34] Fix plugin load prefs --- src/plugins/plugins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index ac8e33c6..59aa27a9 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -165,7 +165,7 @@ plugins_load(const char *const name) plugin->init_func(plugin, PACKAGE_VERSION, PACKAGE_STATUS, NULL, NULL); } log_info("Loaded plugin: %s", name); - prefs_add_plugin(args[1]); + prefs_add_plugin(name); return TRUE; } else { log_info("Failed to load plugin: %s", name); From 3bd3de036f68b107e9b599f44adcaf0842c708b0 Mon Sep 17 00:00:00 2001 From: James Booth Date: Thu, 30 Jun 2016 23:58:04 +0100 Subject: [PATCH 11/34] Use hash table to store plugins --- src/command/cmd_ac.c | 8 +- src/command/cmd_funcs.c | 22 ++-- src/plugins/plugins.c | 219 +++++++++++++++++++++++----------------- src/plugins/plugins.h | 3 +- 4 files changed, 143 insertions(+), 109 deletions(-) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index a4cd788e..da466b76 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -1894,13 +1894,13 @@ _plugins_autocomplete(ProfWin *window, const char *const input) if (strncmp(input, "/plugins unload ", 16) == 0) { if (plugins_unload_ac == NULL) { plugins_unload_ac = autocomplete_new(); - GSList *plugins = plugins_loaded_list(); - GSList *curr = plugins; + GList *plugins = plugins_loaded_list(); + GList *curr = plugins; while (curr) { autocomplete_add(plugins_unload_ac, curr->data); - curr = g_slist_next(curr); + curr = g_list_next(curr); } - g_slist_free(plugins); + g_list_free(plugins); } result = autocomplete_param_with_ac(input, "/plugins unload", plugins_unload_ac, TRUE); if (result) { diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 40944874..70365a60 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -6053,19 +6053,19 @@ cmd_plugins(ProfWin *window, const char *const command, gchar **args) return TRUE; } else { - GSList *plugins = plugins_get_list(); - GSList *curr = plugins; - if (curr == NULL) { + GList *plugins = plugins_loaded_list(); + if (plugins == NULL) { cons_show("No plugins installed."); - } else { - cons_show("Installed plugins:"); - while (curr) { - ProfPlugin *plugin = curr->data; - cons_show(" %s", plugin->name); - curr = g_slist_next(curr); - } + return TRUE; } - g_slist_free(curr); + + GList *curr = plugins; + cons_show("Installed plugins:"); + while (curr) { + cons_show(" %s", curr->data); + curr = g_list_next(curr); + } + g_list_free(plugins); return TRUE; } diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 59aa27a9..2166729a 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -60,12 +60,12 @@ #include "ui/ui.h" -static GSList* plugins; +static GHashTable *plugins; void plugins_init(void) { - plugins = NULL; + plugins = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL); callbacks_init(); autocompleters_init(); @@ -91,7 +91,7 @@ plugins_init(void) if (g_str_has_suffix(filename, ".py")) { ProfPlugin *plugin = python_plugin_create(filename); if (plugin) { - plugins = g_slist_append(plugins, plugin); + g_hash_table_insert(plugins, strdup(filename), plugin); loaded = TRUE; } } @@ -100,7 +100,7 @@ plugins_init(void) if (g_str_has_suffix(filename, ".so")) { ProfPlugin *plugin = c_plugin_create(filename); if (plugin) { - plugins = g_slist_append(plugins, plugin); + g_hash_table_insert(plugins, strdup(filename), plugin); loaded = TRUE; } } @@ -113,12 +113,15 @@ plugins_init(void) } // initialise plugins - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->init_func(plugin, PACKAGE_VERSION, PACKAGE_STATUS, NULL, NULL); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); + } prefs_free_plugins(plugins_pref); @@ -126,25 +129,15 @@ plugins_init(void) return; } -gboolean -_find_by_name(gconstpointer pluginp, gconstpointer namep) -{ - char *name = (char*)namep; - ProfPlugin *plugin = (ProfPlugin*)pluginp; - - return g_strcmp0(name, plugin->name); -} - gboolean plugins_load(const char *const name) { - GSList *found = g_slist_find_custom(plugins, name, (GCompareFunc)_find_by_name); - if (found) { + ProfPlugin *plugin = g_hash_table_lookup(plugins, name); + if (plugin) { log_info("Failed to load plugin: %s, plugin already loaded", name); return FALSE; } - ProfPlugin *plugin = NULL; #ifdef HAVE_PYTHON if (g_str_has_suffix(name, ".py")) { plugin = python_plugin_create(name); @@ -156,7 +149,7 @@ plugins_load(const char *const name) } #endif if (plugin) { - plugins = g_slist_append(plugins, plugin); + g_hash_table_insert(plugins, strdup(name), plugin); if (connection_get_status() == JABBER_CONNECTED) { const char *account_name = session_get_account_name(); const char *fulljid = connection_get_fulljid(); @@ -179,12 +172,6 @@ plugins_unload(const char *const name) return FALSE; } -GSList * -plugins_get_list(void) -{ - return plugins; -} - static gchar* _get_plugins_dir(void) { @@ -205,7 +192,7 @@ _plugins_unloaded_list_dir(const gchar *const dir, GSList **result) const gchar *plugin = g_dir_read_name(plugins_dir); while (plugin) { - GSList *found = g_slist_find_custom(plugins, plugin, (GCompareFunc)_find_by_name); + ProfPlugin *found = g_hash_table_lookup(plugins, plugin); if ((g_str_has_suffix(plugin, ".so") || g_str_has_suffix(plugin, ".py")) && !found) { *result = g_slist_append(*result, strdup(plugin)); } @@ -225,18 +212,10 @@ plugins_unloaded_list(void) return result; } -GSList* +GList* plugins_loaded_list(void) { - GSList *result = NULL; - GSList *curr = plugins; - while (curr) { - ProfPlugin *plugin = curr->data; - result = g_slist_append(result, plugin->name); - curr = g_slist_next(curr); - } - - return result; + return g_hash_table_get_keys(plugins); } char * @@ -261,45 +240,53 @@ plugins_win_process_line(char *win, const char * const line) void plugins_on_start(void) { - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->on_start_func(plugin); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); } void plugins_on_shutdown(void) { - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->on_shutdown_func(plugin); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); } void plugins_on_connect(const char * const account_name, const char * const fulljid) { - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->on_connect_func(plugin, account_name, fulljid); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); } void plugins_on_disconnect(const char * const account_name, const char * const fulljid) { - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->on_disconnect_func(plugin, account_name, fulljid); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); } char* @@ -308,7 +295,8 @@ plugins_pre_chat_message_display(const char * const jid, const char *message) char *new_message = NULL; char *curr_message = strdup(message); - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; new_message = plugin->pre_chat_message_display(plugin, jid, curr_message); @@ -317,8 +305,9 @@ plugins_pre_chat_message_display(const char * const jid, const char *message) curr_message = strdup(new_message); free(new_message); } - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); return curr_message; } @@ -326,12 +315,14 @@ plugins_pre_chat_message_display(const char * const jid, const char *message) void plugins_post_chat_message_display(const char * const jid, const char *message) { - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->post_chat_message_display(plugin, jid, message); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); } char* @@ -340,7 +331,8 @@ plugins_pre_chat_message_send(const char * const jid, const char *message) char *new_message = NULL; char *curr_message = strdup(message); - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; new_message = plugin->pre_chat_message_send(plugin, jid, curr_message); @@ -349,8 +341,9 @@ plugins_pre_chat_message_send(const char * const jid, const char *message) curr_message = strdup(new_message); free(new_message); } - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); return curr_message; } @@ -358,12 +351,14 @@ plugins_pre_chat_message_send(const char * const jid, const char *message) void plugins_post_chat_message_send(const char * const jid, const char *message) { - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->post_chat_message_send(plugin, jid, message); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); } char* @@ -372,7 +367,8 @@ plugins_pre_room_message_display(const char * const room, const char * const nic char *new_message = NULL; char *curr_message = strdup(message); - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; new_message = plugin->pre_room_message_display(plugin, room, nick, curr_message); @@ -381,8 +377,9 @@ plugins_pre_room_message_display(const char * const room, const char * const nic curr_message = strdup(new_message); free(new_message); } - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); return curr_message; } @@ -390,12 +387,14 @@ plugins_pre_room_message_display(const char * const room, const char * const nic void plugins_post_room_message_display(const char * const room, const char * const nick, const char *message) { - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->post_room_message_display(plugin, room, nick, message); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); } char* @@ -404,7 +403,8 @@ plugins_pre_room_message_send(const char * const room, const char *message) char *new_message = NULL; char *curr_message = strdup(message); - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; new_message = plugin->pre_room_message_send(plugin, room, curr_message); @@ -413,8 +413,9 @@ plugins_pre_room_message_send(const char * const room, const char *message) curr_message = strdup(new_message); free(new_message); } - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); return curr_message; } @@ -422,12 +423,14 @@ plugins_pre_room_message_send(const char * const room, const char *message) void plugins_post_room_message_send(const char * const room, const char *message) { - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->post_room_message_send(plugin, room, message); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); } void @@ -441,12 +444,14 @@ plugins_on_room_history_message(const char *const room, const char *const nick, timestamp_str = g_time_val_to_iso8601(×tamp_tv); } - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->on_room_history_message(plugin, room, nick, message, timestamp_str); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); free(timestamp_str); } @@ -458,7 +463,8 @@ plugins_pre_priv_message_display(const char * const jid, const char *message) char *new_message = NULL; char *curr_message = strdup(message); - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; new_message = plugin->pre_priv_message_display(plugin, jidp->barejid, jidp->resourcepart, curr_message); @@ -467,8 +473,9 @@ plugins_pre_priv_message_display(const char * const jid, const char *message) curr_message = strdup(new_message); free(new_message); } - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); jid_destroy(jidp); return curr_message; @@ -479,12 +486,14 @@ plugins_post_priv_message_display(const char * const jid, const char *message) { Jid *jidp = jid_create(jid); - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->post_priv_message_display(plugin, jidp->barejid, jidp->resourcepart, message); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); jid_destroy(jidp); } @@ -496,7 +505,8 @@ plugins_pre_priv_message_send(const char * const jid, const char * const message char *new_message = NULL; char *curr_message = strdup(message); - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; new_message = plugin->pre_priv_message_send(plugin, jidp->barejid, jidp->resourcepart, curr_message); @@ -505,8 +515,9 @@ plugins_pre_priv_message_send(const char * const jid, const char * const message curr_message = strdup(new_message); free(new_message); } - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); jid_destroy(jidp); return curr_message; @@ -517,12 +528,14 @@ plugins_post_priv_message_send(const char * const jid, const char * const messag { Jid *jidp = jid_create(jid); - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->post_priv_message_send(plugin, jidp->barejid, jidp->resourcepart, message); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); jid_destroy(jidp); } @@ -533,7 +546,8 @@ plugins_on_message_stanza_send(const char *const text) char *new_stanza = NULL; char *curr_stanza = strdup(text); - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; new_stanza = plugin->on_message_stanza_send(plugin, curr_stanza); @@ -542,8 +556,9 @@ plugins_on_message_stanza_send(const char *const text) curr_stanza = strdup(new_stanza); free(new_stanza); } - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); return curr_stanza; } @@ -553,15 +568,17 @@ plugins_on_message_stanza_receive(const char *const text) { gboolean cont = TRUE; - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; gboolean res = plugin->on_message_stanza_receive(plugin, text); if (res == FALSE) { cont = FALSE; } - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); return cont; } @@ -572,7 +589,8 @@ plugins_on_presence_stanza_send(const char *const text) char *new_stanza = NULL; char *curr_stanza = strdup(text); - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; new_stanza = plugin->on_presence_stanza_send(plugin, curr_stanza); @@ -581,8 +599,9 @@ plugins_on_presence_stanza_send(const char *const text) curr_stanza = strdup(new_stanza); free(new_stanza); } - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); return curr_stanza; } @@ -592,15 +611,17 @@ plugins_on_presence_stanza_receive(const char *const text) { gboolean cont = TRUE; - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; gboolean res = plugin->on_presence_stanza_receive(plugin, text); if (res == FALSE) { cont = FALSE; } - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); return cont; } @@ -611,7 +632,8 @@ plugins_on_iq_stanza_send(const char *const text) char *new_stanza = NULL; char *curr_stanza = strdup(text); - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; new_stanza = plugin->on_iq_stanza_send(plugin, curr_stanza); @@ -620,8 +642,9 @@ plugins_on_iq_stanza_send(const char *const text) curr_stanza = strdup(new_stanza); free(new_stanza); } - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); return curr_stanza; } @@ -631,15 +654,17 @@ plugins_on_iq_stanza_receive(const char *const text) { gboolean cont = TRUE; - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; gboolean res = plugin->on_iq_stanza_receive(plugin, text); if (res == FALSE) { cont = FALSE; } - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); return cont; } @@ -647,45 +672,53 @@ plugins_on_iq_stanza_receive(const char *const text) void plugins_on_contact_offline(const char *const barejid, const char *const resource, const char *const status) { - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->on_contact_offline(plugin, barejid, resource, status); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); } void plugins_on_contact_presence(const char *const barejid, const char *const resource, const char *const presence, const char *const status, const int priority) { - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->on_contact_presence(plugin, barejid, resource, presence, status, priority); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); } void plugins_on_chat_win_focus(const char *const barejid) { - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->on_chat_win_focus(plugin, barejid); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); } void plugins_on_room_win_focus(const char *const roomjid) { - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { ProfPlugin *plugin = curr->data; plugin->on_room_win_focus(plugin, roomjid); - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); } GList* @@ -697,7 +730,8 @@ plugins_get_disco_features(void) void plugins_shutdown(void) { - GSList *curr = plugins; + GList *values = g_hash_table_get_values(plugins); + GList *curr = values; while (curr) { #ifdef HAVE_PYTHON @@ -711,8 +745,9 @@ plugins_shutdown(void) } #endif - curr = g_slist_next(curr); + curr = g_list_next(curr); } + g_list_free(values); #ifdef HAVE_PYTHON python_shutdown(); #endif diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index a5b10a3e..13bb6e2f 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -98,9 +98,8 @@ typedef struct prof_plugin_t { } ProfPlugin; void plugins_init(void); -GSList* plugins_get_list(void); GSList *plugins_unloaded_list(void); -GSList *plugins_loaded_list(void); +GList *plugins_loaded_list(void); char* plugins_autocomplete(const char *const input); void plugins_reset_autocomplete(void); void plugins_shutdown(void); From 31c66bf8573c1d6c486b99808cc471ac6da79b97 Mon Sep 17 00:00:00 2001 From: James Booth Date: Fri, 1 Jul 2016 00:01:07 +0100 Subject: [PATCH 12/34] Move plugin theme and settings init --- src/plugins/plugins.c | 5 ++--- src/plugins/themes.c | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 2166729a..01b07e6f 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -68,6 +68,8 @@ plugins_init(void) plugins = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL); callbacks_init(); autocompleters_init(); + plugin_themes_init(); + plugin_settings_init(); #ifdef HAVE_PYTHON python_env_init(); @@ -76,9 +78,6 @@ plugins_init(void) c_env_init(); #endif - plugin_themes_init(); - plugin_settings_init(); - // load plugins gchar **plugins_pref = prefs_get_plugins(); if (plugins_pref) { diff --git a/src/plugins/themes.c b/src/plugins/themes.c index f441af84..229bfd8f 100644 --- a/src/plugins/themes.c +++ b/src/plugins/themes.c @@ -61,7 +61,6 @@ plugin_themes_init(void) g_chmod(fileloc->str, S_IRUSR | S_IWUSR); g_free(g_data); g_string_free(fileloc, TRUE); - } void From 70a79abd3bbc978f2dc1a4c54bdc7202e14ea9a8 Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 3 Jul 2016 00:48:22 +0100 Subject: [PATCH 13/34] Add plugin name to win_create api call --- src/plugins/api.c | 1 + src/plugins/api.h | 1 + src/plugins/c_api.c | 9 ++++++--- src/plugins/profapi.c | 2 +- src/plugins/profapi.h | 3 ++- src/plugins/python_api.c | 5 ++++- 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/plugins/api.c b/src/plugins/api.c index 3bdb073b..24947d95 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -292,6 +292,7 @@ api_win_exists(const char *tag) void api_win_create( + const char *const plugin_name, const char *tag, void *callback, void(*destroy)(void *callback), diff --git a/src/plugins/api.h b/src/plugins/api.h index afa9f5a1..571c6168 100644 --- a/src/plugins/api.h +++ b/src/plugins/api.h @@ -67,6 +67,7 @@ void api_log_error(const char *message); int api_win_exists(const char *tag); void api_win_create( + const char *const plugin_name, const char *tag, void *callback, void(*destroy)(void *callback), diff --git a/src/plugins/c_api.c b/src/plugins/c_api.c index 1fab40f9..96673972 100644 --- a/src/plugins/c_api.c +++ b/src/plugins/c_api.c @@ -198,11 +198,14 @@ c_api_win_exists(char *tag) } static void -c_api_win_create(char *tag, void(*callback)(char *tag, char *line)) +c_api_win_create(const char *filename, char *tag, void(*callback)(char *tag, char *line)) { + char *plugin_name = _c_plugin_name(filename); + log_debug("Win create %s for %s", tag, plugin_name); + WindowWrapper *wrapper = malloc(sizeof(WindowWrapper)); wrapper->func = callback; - api_win_create(tag, wrapper, free, c_window_callback); + api_win_create(plugin_name, tag, wrapper, free, c_window_callback); } static int @@ -311,6 +314,7 @@ c_api_init(void) _prof_register_command = c_api_register_command; _prof_register_timed = c_api_register_timed; _prof_completer_add = c_api_completer_add; + _prof_win_create = c_api_win_create; prof_completer_remove = c_api_completer_remove; prof_completer_clear = c_api_completer_clear; prof_notify = c_api_notify; @@ -325,7 +329,6 @@ c_api_init(void) prof_log_warning = c_api_log_warning; prof_log_error = c_api_log_error; prof_win_exists = c_api_win_exists; - prof_win_create = c_api_win_create; prof_win_focus = c_api_win_focus; prof_win_show = c_api_win_show; prof_win_show_themed = c_api_win_show_themed; diff --git a/src/plugins/profapi.c b/src/plugins/profapi.c index d80e2690..2f955ecb 100644 --- a/src/plugins/profapi.c +++ b/src/plugins/profapi.c @@ -67,8 +67,8 @@ void (*prof_log_info)(const char *message) = NULL; void (*prof_log_warning)(const char *message) = NULL; void (*prof_log_error)(const char *message) = NULL; +void (*_prof_win_create)(const char *filename, PROF_WIN_TAG win, void(*input_handler)(PROF_WIN_TAG win, char *line)) = NULL; int (*prof_win_exists)(PROF_WIN_TAG win) = NULL; -void (*prof_win_create)(PROF_WIN_TAG win, void(*input_handler)(PROF_WIN_TAG win, char *line)) = NULL; int (*prof_win_focus)(PROF_WIN_TAG win) = NULL; int (*prof_win_show)(PROF_WIN_TAG win, char *line) = NULL; int (*prof_win_show_themed)(PROF_WIN_TAG tag, char *group, char *key, char *def, char *line) = NULL; diff --git a/src/plugins/profapi.h b/src/plugins/profapi.h index 8c41b2f2..d42bf70f 100644 --- a/src/plugins/profapi.h +++ b/src/plugins/profapi.h @@ -38,6 +38,7 @@ #define prof_register_command(command_name, min_args, max_args, synopsis, description, arguments, examples, callback) _prof_register_command(__FILE__, command_name, min_args, max_args, synopsis, description, arguments, examples, callback) #define prof_register_timed(callback, interval_seconds) _prof_register_timed(__FILE__, callback, interval_seconds) #define prof_completer_add(key, items) _prof_completer_add(__FILE__, key, items) +#define prof_win_create(win, input_handler) _prof_win_create(__FILE__, win, input_handler) typedef char* PROF_WIN_TAG; @@ -71,8 +72,8 @@ void (*prof_log_info)(const char *message); void (*prof_log_warning)(const char *message); void (*prof_log_error)(const char *message); +void (*_prof_win_create)(const char *filename, PROF_WIN_TAG win, void(*input_handler)(PROF_WIN_TAG win, char *line)); int (*prof_win_exists)(PROF_WIN_TAG win); -void (*prof_win_create)(PROF_WIN_TAG win, void(*input_handler)(PROF_WIN_TAG win, char *line)); int (*prof_win_focus)(PROF_WIN_TAG win); int (*prof_win_show)(PROF_WIN_TAG win, char *line); int (*prof_win_show_themed)(PROF_WIN_TAG tag, char *group, char *key, char *def, char *line); diff --git a/src/plugins/python_api.c b/src/plugins/python_api.c index d0d223e8..1a60a07c 100644 --- a/src/plugins/python_api.c +++ b/src/plugins/python_api.c @@ -456,13 +456,16 @@ python_api_win_create(PyObject *self, PyObject *args) char *tag = NULL; PyObject *p_callback = NULL; + char *plugin_name = _python_plugin_name(); + log_debug("Win create %s for %s", tag, plugin_name); + if (!PyArg_ParseTuple(args, "sO", &tag, &p_callback)) { return Py_BuildValue(""); } if (p_callback && PyCallable_Check(p_callback)) { allow_python_threads(); - api_win_create(tag, p_callback, NULL, python_window_callback); + api_win_create(plugin_name, tag, p_callback, NULL, python_window_callback); disable_python_threads(); } From 606a860bdc2fd93773405655be467064aa949cc6 Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 3 Jul 2016 01:03:05 +0100 Subject: [PATCH 14/34] Rename callback execte and destroy functions --- src/plugins/api.c | 16 ++++++++-------- src/plugins/callbacks.c | 8 ++++---- src/plugins/callbacks.h | 8 ++++---- src/plugins/plugins.c | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/plugins/api.c b/src/plugins/api.c index 24947d95..ea134fe4 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -108,14 +108,14 @@ api_cons_bad_cmd_usage(const char *const cmd) void api_register_command(const char *const plugin_name, const char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void *callback, - void(*callback_func)(PluginCommand *command, gchar **args)) + void(*callback_exec)(PluginCommand *command, gchar **args)) { PluginCommand *command = malloc(sizeof(PluginCommand)); command->command_name = command_name; command->min_args = min_args; command->max_args = max_args; command->callback = callback; - command->callback_func = callback_func; + command->callback_exec = callback_exec; CommandHelp *help = malloc(sizeof(CommandHelp)); @@ -145,11 +145,11 @@ api_register_command(const char *const plugin_name, const char *command_name, in void api_register_timed(const char *const plugin_name, void *callback, int interval_seconds, - void (*callback_func)(PluginTimedFunction *timed_function)) + void (*callback_exec)(PluginTimedFunction *timed_function)) { PluginTimedFunction *timed_function = malloc(sizeof(PluginTimedFunction)); timed_function->callback = callback; - timed_function->callback_func = callback_func; + timed_function->callback_exec = callback_exec; timed_function->interval_seconds = interval_seconds; timed_function->timer = g_timer_new(); @@ -295,13 +295,13 @@ api_win_create( const char *const plugin_name, const char *tag, void *callback, - void(*destroy)(void *callback), - void(*callback_func)(PluginWindowCallback *window_callback, const char *tag, const char * const line)) + void(*callback_exec)(PluginWindowCallback *window_callback, const char *tag, const char * const line), + void(*callback_destroy)(void *callback)) { PluginWindowCallback *window = malloc(sizeof(PluginWindowCallback)); window->callback = callback; - window->callback_func = callback_func; - window->destroy = destroy; + window->callback_exec = callback_exec; + window->callback_destroy = callback_destroy; callbacks_add_window_handler(tag, window); wins_new_plugin(tag); diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c index 2572f7a4..57a8c09d 100644 --- a/src/plugins/callbacks.c +++ b/src/plugins/callbacks.c @@ -51,8 +51,8 @@ static GHashTable *p_window_callbacks = NULL; static void _free_window_callback(PluginWindowCallback *window_callback) { - if (window_callback->destroy) { - window_callback->destroy(window_callback->callback); + if (window_callback->callback_destroy) { + window_callback->callback_destroy(window_callback->callback); } free(window_callback); } @@ -115,7 +115,7 @@ plugins_run_command(const char * const input) g_strfreev(split); return TRUE; } else { - command->callback_func(command, args); + command->callback_exec(command, args); g_strfreev(split); g_strfreev(args); return TRUE; @@ -153,7 +153,7 @@ plugins_run_timed(void) gdouble elapsed = g_timer_elapsed(timed_function->timer, NULL); if (timed_function->interval_seconds > 0 && elapsed >= timed_function->interval_seconds) { - timed_function->callback_func(timed_function); + timed_function->callback_exec(timed_function); g_timer_start(timed_function->timer); } diff --git a/src/plugins/callbacks.h b/src/plugins/callbacks.h index 9b175d0a..0ef6de9f 100644 --- a/src/plugins/callbacks.h +++ b/src/plugins/callbacks.h @@ -45,20 +45,20 @@ typedef struct p_command { int max_args; CommandHelp *help; void *callback; - void (*callback_func)(struct p_command *command, gchar **args); + void (*callback_exec)(struct p_command *command, gchar **args); } PluginCommand; typedef struct p_timed_function { void *callback; - void (*callback_func)(struct p_timed_function *timed_function); + void (*callback_exec)(struct p_timed_function *timed_function); int interval_seconds; GTimer *timer; } PluginTimedFunction; typedef struct p_window_input_callback { void *callback; - void (*destroy)(void *callback); - void (*callback_func)(struct p_window_input_callback *window_callback, const char *tag, const char * const line); + void (*callback_exec)(struct p_window_input_callback *window_callback, const char *tag, const char * const line); + void (*callback_destroy)(void *callback); } PluginWindowCallback; void callbacks_init(void); diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 01b07e6f..dfa8e763 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -233,7 +233,7 @@ void plugins_win_process_line(char *win, const char * const line) { PluginWindowCallback *window = callbacks_get_window_handler(win); - window->callback_func(window, win, line); + window->callback_exec(window, win, line); } void From 71879a3f64f5f04cdceeedf0317175b2bab1701c Mon Sep 17 00:00:00 2001 From: James Booth Date: Mon, 4 Jul 2016 00:41:29 +0100 Subject: [PATCH 15/34] Free plugins commands on quit --- Makefile.am | 1 + src/command/cmd_funcs.c | 2 +- src/command/cmd_funcs.h | 10 +-- src/plugins/api.c | 14 ++-- src/plugins/api.h | 8 +- src/plugins/c_api.c | 14 +++- src/plugins/callbacks.c | 131 ++++++++++++++++++++++++++----- src/plugins/callbacks.h | 6 +- src/plugins/python_api.c | 26 +++--- src/ui/core.c | 2 +- src/ui/ui.h | 2 +- tests/unittests/test_callbacks.c | 32 ++++++++ tests/unittests/test_callbacks.h | 2 + tests/unittests/ui/stub_ui.c | 2 +- tests/unittests/unittests.c | 4 + 15 files changed, 203 insertions(+), 53 deletions(-) create mode 100644 tests/unittests/test_callbacks.c create mode 100644 tests/unittests/test_callbacks.h diff --git a/Makefile.am b/Makefile.am index 61b5783d..bcd964a1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -123,6 +123,7 @@ unittest_sources = \ tests/unittests/test_cmd_join.c tests/unittests/test_cmd_join.h \ tests/unittests/test_cmd_roster.c tests/unittests/test_cmd_roster.h \ tests/unittests/test_cmd_disconnect.c tests/unittests/test_cmd_disconnect.h \ + tests/unittests/test_callbacks.c tests/unittests/test_callbacks.h \ tests/unittests/unittests.c functionaltest_sources = \ diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 70365a60..9b7c36a8 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -3809,7 +3809,7 @@ cmd_form(ProfWin *window, const char *const command, gchar **args) } else { mucconfwin_form_help(confwin); - const gchar **help_text = NULL; + gchar **help_text = NULL; Command *command = cmd_get("/form"); if (command) { diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h index 52b9946e..43731050 100644 --- a/src/command/cmd_funcs.h +++ b/src/command/cmd_funcs.h @@ -39,11 +39,11 @@ // Command help strings typedef struct cmd_help_t { - const gchar *tags[20]; - const gchar *synopsis[50]; - const gchar *desc; - const gchar *args[128][2]; - const gchar *examples[20]; + gchar *tags[20]; + gchar *synopsis[50]; + gchar *desc; + gchar *args[128][2]; + gchar *examples[20]; } CommandHelp; /* diff --git a/src/plugins/api.c b/src/plugins/api.c index ea134fe4..2a577296 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -107,18 +107,21 @@ api_cons_bad_cmd_usage(const char *const cmd) void api_register_command(const char *const plugin_name, const char *command_name, int min_args, int max_args, - const char **synopsis, const char *description, const char *arguments[][2], const char **examples, void *callback, - void(*callback_exec)(PluginCommand *command, gchar **args)) + const char **synopsis, const char *description, const char *arguments[][2], const char **examples, + void *callback, void(*callback_exec)(PluginCommand *command, gchar **args), void(*callback_destroy)(void *callback)) { PluginCommand *command = malloc(sizeof(PluginCommand)); - command->command_name = command_name; + command->command_name = strdup(command_name); command->min_args = min_args; command->max_args = max_args; command->callback = callback; command->callback_exec = callback_exec; + command->callback_destroy = callback_destroy; CommandHelp *help = malloc(sizeof(CommandHelp)); + help->tags[0] = NULL; + int i = 0; for (i = 0; synopsis[i] != NULL; i++) { help->synopsis[i] = strdup(synopsis[i]); @@ -140,16 +143,17 @@ api_register_command(const char *const plugin_name, const char *command_name, in command->help = help; - callbacks_add_command(command); + callbacks_add_command(plugin_name, command); } void api_register_timed(const char *const plugin_name, void *callback, int interval_seconds, - void (*callback_exec)(PluginTimedFunction *timed_function)) + void (*callback_exec)(PluginTimedFunction *timed_function), void(*callback_destroy)(void *callback)) { PluginTimedFunction *timed_function = malloc(sizeof(PluginTimedFunction)); timed_function->callback = callback; timed_function->callback_exec = callback_exec; + timed_function->callback_destroy = callback_destroy; timed_function->interval_seconds = interval_seconds; timed_function->timer = g_timer_new(); diff --git a/src/plugins/api.h b/src/plugins/api.h index 571c6168..0b1aec32 100644 --- a/src/plugins/api.h +++ b/src/plugins/api.h @@ -52,9 +52,9 @@ char** api_get_current_occupants(void); void api_register_command(const char *const plugin_name, const char *command_name, int min_args, int max_args, const char **synopsis, const char *description, const char *arguments[][2], const char **examples, - void *callback, void(*callback_func)(PluginCommand *command, gchar **args)); + void *callback, void(*callback_func)(PluginCommand *command, gchar **args), void(*callback_destroy)(void *callback)); void api_register_timed(const char *const plugin_name, void *callback, int interval_seconds, - void (*callback_func)(PluginTimedFunction *timed_function)); + void (*callback_func)(PluginTimedFunction *timed_function), void(*callback_destroy)(void *callback)); void api_completer_add(const char *const plugin_name, const char *key, char **items); void api_completer_remove(const char *key, char **items); @@ -70,8 +70,8 @@ void api_win_create( const char *const plugin_name, const char *tag, void *callback, - void(*destroy)(void *callback), - void(*callback_func)(PluginWindowCallback *window_callback, char *tag, char *line)); + void(*callback_func)(PluginWindowCallback *window_callback, char *tag, char *line), + void(*destroy)(void *callback)); int api_win_focus(const char *tag); int api_win_show(const char *tag, const char *line); int api_win_show_themed(const char *tag, const char *const group, const char *const key, const char *const def, const char *line); diff --git a/src/plugins/c_api.c b/src/plugins/c_api.c index 96673972..32719feb 100644 --- a/src/plugins/c_api.c +++ b/src/plugins/c_api.c @@ -90,7 +90,9 @@ c_api_register_command(const char *filename, const char *command_name, int min_a CommandWrapper *wrapper = malloc(sizeof(CommandWrapper)); wrapper->func = callback; api_register_command(plugin_name, command_name, min_args, max_args, synopsis, - description, arguments, examples, wrapper, c_command_callback); + description, arguments, examples, wrapper, c_command_callback, free); + + free(plugin_name); } static void @@ -101,7 +103,9 @@ c_api_register_timed(const char *filename, void(*callback)(void), int interval_s TimedWrapper *wrapper = malloc(sizeof(TimedWrapper)); wrapper->func = callback; - api_register_timed(plugin_name, wrapper, interval_seconds, c_timed_callback); + api_register_timed(plugin_name, wrapper, interval_seconds, c_timed_callback, free); + + free(plugin_name); } static void @@ -111,6 +115,8 @@ c_api_completer_add(const char *filename, const char *key, char **items) log_debug("Autocomplete add %s for %s", key, plugin_name); api_completer_add(plugin_name, key, items); + + free(plugin_name); } static void @@ -205,7 +211,9 @@ c_api_win_create(const char *filename, char *tag, void(*callback)(char *tag, cha WindowWrapper *wrapper = malloc(sizeof(WindowWrapper)); wrapper->func = callback; - api_win_create(plugin_name, tag, wrapper, free, c_window_callback); + api_win_create(plugin_name, tag, wrapper, c_window_callback, free); + + free(plugin_name); } static int diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c index 57a8c09d..2569962c 100644 --- a/src/plugins/callbacks.c +++ b/src/plugins/callbacks.c @@ -44,7 +44,7 @@ #include "ui/ui.h" -static GSList *p_commands = NULL; +static GHashTable *p_commands = NULL; static GSList *p_timed_functions = NULL; static GHashTable *p_window_callbacks = NULL; @@ -57,22 +57,88 @@ _free_window_callback(PluginWindowCallback *window_callback) free(window_callback); } -void -callbacks_init(void) +//typedef struct cmd_help_t { +// const gchar *tags[20]; +// const gchar *synopsis[50]; +// const gchar *desc; +// const gchar *args[128][2]; +// const gchar *examples[20]; +//} CommandHelp; + +static void +_free_command_help(CommandHelp *help) { - p_window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_window_callback); + int i = 0; + while (help->tags[i] != NULL) { + free(help->tags[i++]); + } + + i = 0; + while (help->synopsis[i] != NULL) { + free(help->synopsis[i++]); + } + + free(help->desc); + + i = 0; + while (help->args[i] != NULL && help->args[i][0] != NULL) { + free(help->args[i][0]); + free(help->args[i][1]); + i++; + } + + i = 0; + while (help->examples[i] != NULL) { + free(help->examples[i++]); + } + + free(help); +} + +static void +_free_command(PluginCommand *command) +{ + if (command->callback_destroy) { + command->callback_destroy(command->callback); + } + free(command->command_name); + + _free_command_help(command->help); + free(command); +} + +static void +_free_command_hash(GHashTable *command_hash) +{ + g_hash_table_destroy(command_hash); } +void +callbacks_init(void) +{ + p_commands = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_command_hash); + p_window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_window_callback); +} + +// TODO move to plugin destroy functions void callbacks_close(void) { + g_hash_table_destroy(p_commands); g_hash_table_destroy(p_window_callbacks); } void -callbacks_add_command(PluginCommand *command) +callbacks_add_command(const char *const plugin_name, PluginCommand *command) { - p_commands = g_slist_append(p_commands, command); + GHashTable *command_hash = g_hash_table_lookup(p_commands, plugin_name); + if (command_hash) { + g_hash_table_insert(command_hash, strdup(command->command_name), command); + } else { + command_hash = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_command); + g_hash_table_insert(command_hash, strdup(command->command_name), command); + g_hash_table_insert(p_commands, strdup(plugin_name), command_hash); + } cmd_ac_add(command->command_name); cmd_ac_add_help(&command->command_name[1]); } @@ -104,25 +170,32 @@ plugins_run_command(const char * const input) { gchar **split = g_strsplit(input, " ", -1); - GSList *p_command = p_commands; - while (p_command) { - PluginCommand *command = p_command->data; - if (g_strcmp0(split[0], command->command_name) == 0) { + GList *command_hashes = g_hash_table_get_values(p_commands); + GList *curr_hash = command_hashes; + while (curr_hash) { + GHashTable *command_hash = curr_hash->data; + + PluginCommand *command = g_hash_table_lookup(command_hash, split[0]); + if (command) { gboolean result; gchar **args = parse_args_with_freetext(input, command->min_args, command->max_args, &result); if (result == FALSE) { ui_invalid_command_usage(command->command_name, NULL); g_strfreev(split); + g_list_free(command_hashes); return TRUE; } else { command->callback_exec(command, args); g_strfreev(split); g_strfreev(args); + g_list_free(command_hashes); return TRUE; } } - p_command = g_slist_next(p_command); + + curr_hash = g_list_next(curr_hash); } + g_strfreev(split); return FALSE; } @@ -130,16 +203,22 @@ plugins_run_command(const char * const input) CommandHelp* plugins_get_help(const char *const cmd) { - GSList *curr = p_commands; - while (curr) { - PluginCommand *command = curr->data; - if (g_strcmp0(cmd, command->command_name) == 0) { + GList *command_hashes = g_hash_table_get_values(p_commands); + GList *curr_hash = command_hashes; + while (curr_hash) { + GHashTable *command_hash = curr_hash->data; + + PluginCommand *command = g_hash_table_lookup(command_hash, cmd); + if (command) { + g_list_free(command_hashes); return command->help; } - curr = g_slist_next(curr); + curr_hash = g_list_next(curr_hash); } + g_list_free(command_hashes); + return NULL; } @@ -167,12 +246,22 @@ plugins_get_command_names(void) { GList *result = NULL; - GSList *curr = p_commands; - while (curr) { - PluginCommand *command = curr->data; - result = g_list_append(result, (char*)command->command_name); - curr = g_slist_next(curr); + GList *command_hashes = g_hash_table_get_values(p_commands); + GList *curr_hash = command_hashes; + while (curr_hash) { + GHashTable *command_hash = curr_hash->data; + GList *commands = g_hash_table_get_keys(command_hash); + GList *curr = commands; + while (curr) { + char *command = curr->data; + result = g_list_append(result, command); + curr = g_list_next(curr); + } + g_list_free(commands); + curr_hash = g_list_next(curr_hash); } + g_list_free(command_hashes); + return result; } diff --git a/src/plugins/callbacks.h b/src/plugins/callbacks.h index 0ef6de9f..fa78d2c6 100644 --- a/src/plugins/callbacks.h +++ b/src/plugins/callbacks.h @@ -40,17 +40,19 @@ #include "command/cmd_defs.h" typedef struct p_command { - const char *command_name; + char *command_name; int min_args; int max_args; CommandHelp *help; void *callback; void (*callback_exec)(struct p_command *command, gchar **args); + void (*callback_destroy)(void *callback); } PluginCommand; typedef struct p_timed_function { void *callback; void (*callback_exec)(struct p_timed_function *timed_function); + void (*callback_destroy)(void *callback); int interval_seconds; GTimer *timer; } PluginTimedFunction; @@ -64,7 +66,7 @@ typedef struct p_window_input_callback { void callbacks_init(void); void callbacks_close(void); -void callbacks_add_command(PluginCommand *command); +void callbacks_add_command(const char *const plugin, PluginCommand *command); void callbacks_add_timed(PluginTimedFunction *timed_function); void callbacks_add_window_handler(const char *tag, PluginWindowCallback *window_callback); void * callbacks_get_window_handler(const char *tag); diff --git a/src/plugins/python_api.c b/src/plugins/python_api.c index 1a60a07c..82cf22eb 100644 --- a/src/plugins/python_api.c +++ b/src/plugins/python_api.c @@ -166,19 +166,18 @@ python_api_register_command(PyObject *self, PyObject *args) allow_python_threads(); api_register_command(plugin_name, command_name, min_args, max_args, c_synopsis, - description, c_arguments, c_examples, p_callback, python_command_callback); + description, c_arguments, c_examples, p_callback, python_command_callback, NULL); disable_python_threads(); } + free(plugin_name); + return Py_BuildValue(""); } static PyObject * python_api_register_timed(PyObject *self, PyObject *args) { - char *plugin_name = _python_plugin_name(); - log_debug("Register timed for %s", plugin_name); - PyObject *p_callback = NULL; int interval_seconds = 0; @@ -186,12 +185,17 @@ python_api_register_timed(PyObject *self, PyObject *args) return Py_BuildValue(""); } + char *plugin_name = _python_plugin_name(); + log_debug("Register timed for %s", plugin_name); + if (p_callback && PyCallable_Check(p_callback)) { allow_python_threads(); - api_register_timed(plugin_name, p_callback, interval_seconds, python_timed_callback); + api_register_timed(plugin_name, p_callback, interval_seconds, python_timed_callback, NULL); disable_python_threads(); } + free(plugin_name); + return Py_BuildValue(""); } @@ -223,6 +227,8 @@ python_api_completer_add(PyObject *self, PyObject *args) api_completer_add(plugin_name, key, c_items); disable_python_threads(); + free(plugin_name); + return Py_BuildValue(""); } @@ -456,19 +462,21 @@ python_api_win_create(PyObject *self, PyObject *args) char *tag = NULL; PyObject *p_callback = NULL; - char *plugin_name = _python_plugin_name(); - log_debug("Win create %s for %s", tag, plugin_name); - if (!PyArg_ParseTuple(args, "sO", &tag, &p_callback)) { return Py_BuildValue(""); } + char *plugin_name = _python_plugin_name(); + log_debug("Win create %s for %s", tag, plugin_name); + if (p_callback && PyCallable_Check(p_callback)) { allow_python_threads(); - api_win_create(plugin_name, tag, p_callback, NULL, python_window_callback); + api_win_create(plugin_name, tag, p_callback, python_window_callback, NULL); disable_python_threads(); } + free(plugin_name); + return Py_BuildValue(""); } diff --git a/src/ui/core.c b/src/ui/core.c index 3a89008f..c687cba6 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -1230,7 +1230,7 @@ ui_handle_room_config_submit_result_error(const char *const roomjid, const char } void -ui_show_lines(ProfWin *window, const gchar** lines) +ui_show_lines(ProfWin *window, gchar** lines) { if (lines) { int i; diff --git a/src/ui/ui.h b/src/ui/ui.h index c15af910..5cf8cb31 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -110,7 +110,7 @@ void ui_goodbye_title(void); void ui_handle_room_configuration_form_error(const char *const roomjid, const char *const message); void ui_handle_room_config_submit_result(const char *const roomjid); void ui_handle_room_config_submit_result_error(const char *const roomjid, const char *const message); -void ui_show_lines(ProfWin *window, const gchar** lines); +void ui_show_lines(ProfWin *window, gchar** lines); void ui_redraw_all_room_rosters(void); void ui_show_all_room_rosters(void); void ui_hide_all_room_rosters(void); diff --git a/tests/unittests/test_callbacks.c b/tests/unittests/test_callbacks.c new file mode 100644 index 00000000..32959aa7 --- /dev/null +++ b/tests/unittests/test_callbacks.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "plugins/callbacks.h" +#include "plugins/plugins.h" + +void returns_no_commands(void **state) +{ + callbacks_init(); + GList *commands = plugins_get_command_names(); + + assert_true(commands == NULL); +} + +void returns_commands(void **state) +{ + callbacks_init(); + PluginCommand *command = malloc(sizeof(PluginCommand)); + command->command_name = strdup("something"); + callbacks_add_command("Cool plugin", command); + + GList *commands = plugins_get_command_names(); + assert_true(g_list_length(commands) == 1); + + char *name = commands->data; + assert_string_equal(name, "something"); +} diff --git a/tests/unittests/test_callbacks.h b/tests/unittests/test_callbacks.h new file mode 100644 index 00000000..35751d2e --- /dev/null +++ b/tests/unittests/test_callbacks.h @@ -0,0 +1,2 @@ +void returns_no_commands(void **state); +void returns_commands(void **state); diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c index 5e86799a..b0635fb8 100644 --- a/tests/unittests/ui/stub_ui.c +++ b/tests/unittests/ui/stub_ui.c @@ -265,7 +265,7 @@ void mucconfwin_show_form(ProfMucConfWin *confwin) {} void mucconfwin_show_form_field(ProfMucConfWin *confwin, DataForm *form, char *tag) {} void mucconfwin_form_help(ProfMucConfWin *confwin) {} void mucconfwin_field_help(ProfMucConfWin *confwin, char *tag) {} -void ui_show_lines(ProfWin *window, const gchar** lines) {} +void ui_show_lines(ProfWin *window, gchar** lines) {} void ui_redraw_all_room_rosters(void) {} void ui_show_all_room_rosters(void) {} void ui_hide_all_room_rosters(void) {} diff --git a/tests/unittests/unittests.c b/tests/unittests/unittests.c index 5577104e..91fb3cb2 100644 --- a/tests/unittests/unittests.c +++ b/tests/unittests/unittests.c @@ -33,6 +33,7 @@ #include "test_cmd_roster.h" #include "test_cmd_disconnect.h" #include "test_form.h" +#include "test_callbacks.h" int main(int argc, char* argv[]) { const UnitTest all_tests[] = { @@ -602,6 +603,9 @@ int main(int argc, char* argv[]) { unit_test(prof_partial_occurrences_tests), unit_test(prof_whole_occurrences_tests), + + unit_test(returns_no_commands), + unit_test(returns_commands), }; return run_tests(all_tests); From 3fe1d76a059f476372b242dee5f9fb93d434e66a Mon Sep 17 00:00:00 2001 From: James Booth Date: Mon, 4 Jul 2016 21:10:11 +0100 Subject: [PATCH 16/34] Unit test for callback_add_command() --- tests/unittests/test_callbacks.c | 39 ++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/tests/unittests/test_callbacks.c b/tests/unittests/test_callbacks.c index 32959aa7..78693d4c 100644 --- a/tests/unittests/test_callbacks.c +++ b/tests/unittests/test_callbacks.c @@ -20,13 +20,38 @@ void returns_no_commands(void **state) void returns_commands(void **state) { callbacks_init(); - PluginCommand *command = malloc(sizeof(PluginCommand)); - command->command_name = strdup("something"); - callbacks_add_command("Cool plugin", command); - GList *commands = plugins_get_command_names(); - assert_true(g_list_length(commands) == 1); + PluginCommand *command1 = malloc(sizeof(PluginCommand)); + command1->command_name = strdup("command1"); + callbacks_add_command("plugin1", command1); - char *name = commands->data; - assert_string_equal(name, "something"); + PluginCommand *command2 = malloc(sizeof(PluginCommand)); + command2->command_name = strdup("command2"); + callbacks_add_command("plugin1", command2); + + PluginCommand *command3 = malloc(sizeof(PluginCommand)); + command3->command_name = strdup("command3"); + callbacks_add_command("plugin2", command3); + + GList *names = plugins_get_command_names(); + assert_true(g_list_length(names) == 3); + + gboolean foundCommand1 = FALSE; + gboolean foundCommand2 = FALSE; + gboolean foundCommand3 = FALSE; + GList *curr = names; + while (curr) { + if (g_strcmp0(curr->data, "command1") == 0) { + foundCommand1 = TRUE; + } + if (g_strcmp0(curr->data, "command2") == 0) { + foundCommand2 = TRUE; + } + if (g_strcmp0(curr->data, "command3") == 0) { + foundCommand3 = TRUE; + } + curr = g_list_next(curr); + } + + assert_true(foundCommand1 && foundCommand2 && foundCommand3); } From a779ad0764b830fe9e72bc188789ca22ecd4e394 Mon Sep 17 00:00:00 2001 From: James Booth Date: Mon, 4 Jul 2016 21:48:04 +0100 Subject: [PATCH 17/34] Use hash table for plugin timed functions --- src/plugins/api.c | 2 +- src/plugins/callbacks.c | 70 ++++++++++++++++++++++++++++------------- src/plugins/callbacks.h | 4 +-- 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/plugins/api.c b/src/plugins/api.c index 2a577296..955a7bde 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -157,7 +157,7 @@ api_register_timed(const char *const plugin_name, void *callback, int interval_s timed_function->interval_seconds = interval_seconds; timed_function->timer = g_timer_new(); - callbacks_add_timed(timed_function); + callbacks_add_timed(plugin_name, timed_function); } void diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c index 2569962c..41ba30db 100644 --- a/src/plugins/callbacks.c +++ b/src/plugins/callbacks.c @@ -45,7 +45,7 @@ #include "ui/ui.h" static GHashTable *p_commands = NULL; -static GSList *p_timed_functions = NULL; +static GHashTable *p_timed_functions = NULL; static GHashTable *p_window_callbacks = NULL; static void @@ -57,14 +57,6 @@ _free_window_callback(PluginWindowCallback *window_callback) free(window_callback); } -//typedef struct cmd_help_t { -// const gchar *tags[20]; -// const gchar *synopsis[50]; -// const gchar *desc; -// const gchar *args[128][2]; -// const gchar *examples[20]; -//} CommandHelp; - static void _free_command_help(CommandHelp *help) { @@ -104,6 +96,7 @@ _free_command(PluginCommand *command) free(command->command_name); _free_command_help(command->help); + free(command); } @@ -113,10 +106,29 @@ _free_command_hash(GHashTable *command_hash) g_hash_table_destroy(command_hash); } +static void +_free_timed_function(PluginTimedFunction *timed_function) +{ + if (timed_function->callback_destroy) { + timed_function->callback_destroy(timed_function->callback); + } + + g_timer_destroy(timed_function->timer); + + free(timed_function); +} + +static void +_free_timed_function_list(GList *timed_functions) +{ + g_list_free_full(timed_functions, (GDestroyNotify)_free_timed_function); +} + void callbacks_init(void) { p_commands = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_command_hash); + p_timed_functions = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_timed_function_list); p_window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_window_callback); } @@ -125,6 +137,7 @@ void callbacks_close(void) { g_hash_table_destroy(p_commands); + g_hash_table_destroy(p_timed_functions); g_hash_table_destroy(p_window_callbacks); } @@ -144,9 +157,16 @@ callbacks_add_command(const char *const plugin_name, PluginCommand *command) } void -callbacks_add_timed(PluginTimedFunction *timed_function) +callbacks_add_timed(const char *const plugin_name, PluginTimedFunction *timed_function) { - p_timed_functions = g_slist_append(p_timed_functions, timed_function); + GList *timed_function_list = g_hash_table_lookup(p_timed_functions, plugin_name); + if (timed_function_list) { + timed_function_list = g_list_append(timed_function_list, timed_function); + g_hash_table_replace(p_timed_functions, strdup(plugin_name), timed_function_list); + } else { + timed_function_list = g_list_append(timed_function_list, timed_function); + g_hash_table_insert(p_timed_functions, strdup(plugin_name), timed_function_list); + } } void @@ -225,20 +245,28 @@ plugins_get_help(const char *const cmd) void plugins_run_timed(void) { - GSList *p_timed_function = p_timed_functions; + GList *timed_functions_lists = g_hash_table_get_values(p_timed_functions); - while (p_timed_function) { - PluginTimedFunction *timed_function = p_timed_function->data; - gdouble elapsed = g_timer_elapsed(timed_function->timer, NULL); + GList *curr_list = timed_functions_lists; + while (curr_list) { + GList *timed_function_list = curr_list->data; + GList *curr = timed_function_list; + while (curr) { + PluginTimedFunction *timed_function = curr->data; - if (timed_function->interval_seconds > 0 && elapsed >= timed_function->interval_seconds) { - timed_function->callback_exec(timed_function); - g_timer_start(timed_function->timer); + gdouble elapsed = g_timer_elapsed(timed_function->timer, NULL); + + if (timed_function->interval_seconds > 0 && elapsed >= timed_function->interval_seconds) { + timed_function->callback_exec(timed_function); + g_timer_start(timed_function->timer); + } + + curr = g_list_next(curr); } - - p_timed_function = g_slist_next(p_timed_function); + curr_list = g_list_next(curr_list); } - return; + + g_list_free(timed_functions_lists); } GList* diff --git a/src/plugins/callbacks.h b/src/plugins/callbacks.h index fa78d2c6..7284ba28 100644 --- a/src/plugins/callbacks.h +++ b/src/plugins/callbacks.h @@ -66,8 +66,8 @@ typedef struct p_window_input_callback { void callbacks_init(void); void callbacks_close(void); -void callbacks_add_command(const char *const plugin, PluginCommand *command); -void callbacks_add_timed(PluginTimedFunction *timed_function); +void callbacks_add_command(const char *const plugin_name, PluginCommand *command); +void callbacks_add_timed(const char *const plugin_name, PluginTimedFunction *timed_function); void callbacks_add_window_handler(const char *tag, PluginWindowCallback *window_callback); void * callbacks_get_window_handler(const char *tag); From 0d7b4cb4a7bac70bdb494dbcbeaaa18996e1a496 Mon Sep 17 00:00:00 2001 From: James Booth Date: Mon, 4 Jul 2016 22:42:15 +0100 Subject: [PATCH 18/34] Store plugin window callbacks by plugin name --- src/plugins/api.c | 4 +++- src/plugins/callbacks.c | 35 +++++++++++++++++++++++++++++++---- src/plugins/callbacks.h | 2 +- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/plugins/api.c b/src/plugins/api.c index 955a7bde..53138a4e 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -306,7 +306,9 @@ api_win_create( window->callback = callback; window->callback_exec = callback_exec; window->callback_destroy = callback_destroy; - callbacks_add_window_handler(tag, window); + + callbacks_add_window_handler(plugin_name, tag, window); + wins_new_plugin(tag); // set status bar active diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c index 41ba30db..a837e067 100644 --- a/src/plugins/callbacks.c +++ b/src/plugins/callbacks.c @@ -57,6 +57,12 @@ _free_window_callback(PluginWindowCallback *window_callback) free(window_callback); } +static void +_free_window_callbacks(GHashTable *window_callbacks) +{ + g_hash_table_destroy(window_callbacks); +} + static void _free_command_help(CommandHelp *help) { @@ -129,7 +135,7 @@ callbacks_init(void) { p_commands = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_command_hash); p_timed_functions = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_timed_function_list); - p_window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_window_callback); + p_window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_window_callbacks); } // TODO move to plugin destroy functions @@ -170,16 +176,37 @@ callbacks_add_timed(const char *const plugin_name, PluginTimedFunction *timed_fu } void -callbacks_add_window_handler(const char *tag, PluginWindowCallback *window_callback) +callbacks_add_window_handler(const char *const plugin_name, const char *tag, PluginWindowCallback *window_callback) { - g_hash_table_insert(p_window_callbacks, strdup(tag), window_callback); + GHashTable *window_callbacks = g_hash_table_lookup(p_window_callbacks, plugin_name); + if (window_callbacks) { + g_hash_table_insert(window_callbacks, strdup(tag), window_callback); + } else { + window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_window_callback); + g_hash_table_insert(window_callbacks, strdup(tag), window_callback); + g_hash_table_insert(p_window_callbacks, strdup(plugin_name), window_callbacks); + } } void * callbacks_get_window_handler(const char *tag) { if (p_window_callbacks) { - return g_hash_table_lookup(p_window_callbacks, tag); + GList *window_callback_hashes = g_hash_table_get_values(p_window_callbacks); + GList *curr_hash = window_callback_hashes; + while (curr_hash) { + GHashTable *window_callback_hash = curr_hash->data; + PluginWindowCallback *callback = g_hash_table_lookup(window_callback_hash, tag); + if (callback) { + g_list_free(window_callback_hashes); + return callback; + } + + curr_hash = g_list_next(curr_hash); + } + + g_list_free(window_callback_hashes); + return NULL; } else { return NULL; } diff --git a/src/plugins/callbacks.h b/src/plugins/callbacks.h index 7284ba28..8fd577fb 100644 --- a/src/plugins/callbacks.h +++ b/src/plugins/callbacks.h @@ -68,7 +68,7 @@ void callbacks_close(void); void callbacks_add_command(const char *const plugin_name, PluginCommand *command); void callbacks_add_timed(const char *const plugin_name, PluginTimedFunction *timed_function); -void callbacks_add_window_handler(const char *tag, PluginWindowCallback *window_callback); +void callbacks_add_window_handler(const char *const plugin_name, const char *tag, PluginWindowCallback *window_callback); void * callbacks_get_window_handler(const char *tag); #endif From c8d09083a805c4ea40a9d76ac2199d1b939cd024 Mon Sep 17 00:00:00 2001 From: James Booth Date: Mon, 4 Jul 2016 22:54:55 +0100 Subject: [PATCH 19/34] Remove plugin callbacks in plugin_destroy functions --- src/plugins/c_plugins.c | 2 ++ src/plugins/callbacks.c | 9 ++++++++- src/plugins/callbacks.h | 1 + src/plugins/python_plugins.c | 1 + 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/plugins/c_plugins.c b/src/plugins/c_plugins.c index 7fe10905..5c0047c8 100644 --- a/src/plugins/c_plugins.c +++ b/src/plugins/c_plugins.c @@ -523,6 +523,8 @@ c_plugin_destroy(ProfPlugin *plugin) { assert (plugin && plugin->module); + callbacks_remove(plugin->name); + if (dlclose (plugin->module)) { log_warning ("dlclose failed to close `%s' with `%s'", plugin->name, dlerror ()); } diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c index a837e067..c0a25ca6 100644 --- a/src/plugins/callbacks.c +++ b/src/plugins/callbacks.c @@ -138,7 +138,14 @@ callbacks_init(void) p_window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_window_callbacks); } -// TODO move to plugin destroy functions +void +callbacks_remove(const char *const plugin_name) +{ + g_hash_table_remove(p_commands, plugin_name); + g_hash_table_remove(p_timed_functions, plugin_name); + g_hash_table_remove(p_window_callbacks, plugin_name); +} + void callbacks_close(void) { diff --git a/src/plugins/callbacks.h b/src/plugins/callbacks.h index 8fd577fb..b73f80ff 100644 --- a/src/plugins/callbacks.h +++ b/src/plugins/callbacks.h @@ -64,6 +64,7 @@ typedef struct p_window_input_callback { } PluginWindowCallback; void callbacks_init(void); +void callbacks_remove(const char *const plugin_name); void callbacks_close(void); void callbacks_add_command(const char *const plugin_name, PluginCommand *command); diff --git a/src/plugins/python_plugins.c b/src/plugins/python_plugins.c index 7861f484..0dac55ec 100644 --- a/src/plugins/python_plugins.c +++ b/src/plugins/python_plugins.c @@ -889,6 +889,7 @@ void python_plugin_destroy(ProfPlugin *plugin) { disable_python_threads(); + callbacks_remove(plugin->name); free(plugin->name); Py_XDECREF(plugin->module); free(plugin); From 03c7ac73fd903a6c48658fd3c5e270d35f5a80c2 Mon Sep 17 00:00:00 2001 From: James Booth Date: Mon, 4 Jul 2016 23:00:41 +0100 Subject: [PATCH 20/34] Move prefs_remove_plugin to plugins_unload --- src/command/cmd_funcs.c | 1 - src/plugins/plugins.c | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 9b7c36a8..540773d7 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -6045,7 +6045,6 @@ cmd_plugins(ProfWin *window, const char *const command, gchar **args) } gboolean res = plugins_unload(args[1]); if (res) { - prefs_remove_plugin(args[1]); cons_show("Unloaded plugin: %s", args[1]); } else { cons_show("Failed to unload plugin: %s", args[1]); diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index dfa8e763..ae0e65b0 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -168,7 +168,9 @@ plugins_load(const char *const name) gboolean plugins_unload(const char *const name) { - return FALSE; + prefs_remove_plugin(name); + + return TRUE; } static gchar* From fd218ac3e443650a7b310d4f8cde758f08c0ed8c Mon Sep 17 00:00:00 2001 From: James Booth Date: Mon, 4 Jul 2016 23:14:08 +0100 Subject: [PATCH 21/34] Pass plugin name to all autocompleter functions --- src/plugins/api.c | 4 ++-- src/plugins/api.h | 4 ++-- src/plugins/c_api.c | 22 ++++++++++++++++------ src/plugins/callbacks.c | 1 + src/plugins/profapi.c | 4 ++-- src/plugins/profapi.h | 6 ++++-- src/plugins/python_api.c | 14 ++++++++++++-- 7 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/plugins/api.c b/src/plugins/api.c index 53138a4e..ecd1749e 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -167,13 +167,13 @@ api_completer_add(const char *const plugin_name, const char *key, char **items) } void -api_completer_remove(const char *key, char **items) +api_completer_remove(const char *const plugin_name, const char *key, char **items) { autocompleters_remove(key, items); } void -api_completer_clear(const char *key) +api_completer_clear(const char *const plugin_name, const char *key) { autocompleters_clear(key); } diff --git a/src/plugins/api.h b/src/plugins/api.h index 0b1aec32..b87b9bc5 100644 --- a/src/plugins/api.h +++ b/src/plugins/api.h @@ -57,8 +57,8 @@ void api_register_timed(const char *const plugin_name, void *callback, int inter void (*callback_func)(PluginTimedFunction *timed_function), void(*callback_destroy)(void *callback)); void api_completer_add(const char *const plugin_name, const char *key, char **items); -void api_completer_remove(const char *key, char **items); -void api_completer_clear(const char *key); +void api_completer_remove(const char *const plugin_name, const char *key, char **items); +void api_completer_clear(const char *const plugin_name, const char *key); void api_log_debug(const char *message); void api_log_info(const char *message); diff --git a/src/plugins/c_api.c b/src/plugins/c_api.c index 32719feb..22a2fde4 100644 --- a/src/plugins/c_api.c +++ b/src/plugins/c_api.c @@ -120,15 +120,25 @@ c_api_completer_add(const char *filename, const char *key, char **items) } static void -c_api_completer_remove(const char *key, char **items) +c_api_completer_remove(const char *filename, const char *key, char **items) { - api_completer_remove(key, items); + char *plugin_name = _c_plugin_name(filename); + log_debug("Autocomplete remove %s for %s", key, plugin_name); + + api_completer_remove(plugin_name, key, items); + + free(plugin_name); } static void -c_api_completer_clear(const char *key) +c_api_completer_clear(const char *filename, const char *key) { - api_completer_clear(key); + char *plugin_name = _c_plugin_name(filename); + log_debug("Autocomplete clear %s for %s", key, plugin_name); + + api_completer_clear(plugin_name, key); + + free(plugin_name); } static void @@ -322,9 +332,9 @@ c_api_init(void) _prof_register_command = c_api_register_command; _prof_register_timed = c_api_register_timed; _prof_completer_add = c_api_completer_add; + _prof_completer_remove = c_api_completer_remove; + _prof_completer_clear = c_api_completer_clear; _prof_win_create = c_api_win_create; - prof_completer_remove = c_api_completer_remove; - prof_completer_clear = c_api_completer_clear; prof_notify = c_api_notify; prof_send_line = c_api_send_line; prof_get_current_recipient = c_api_get_current_recipient; diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c index c0a25ca6..d313690b 100644 --- a/src/plugins/callbacks.c +++ b/src/plugins/callbacks.c @@ -141,6 +141,7 @@ callbacks_init(void) void callbacks_remove(const char *const plugin_name) { + // TODO remove from cmd_ac and cmd_ac_help g_hash_table_remove(p_commands, plugin_name); g_hash_table_remove(p_timed_functions, plugin_name); g_hash_table_remove(p_window_callbacks, plugin_name); diff --git a/src/plugins/profapi.c b/src/plugins/profapi.c index 2f955ecb..20b8c26b 100644 --- a/src/plugins/profapi.c +++ b/src/plugins/profapi.c @@ -49,8 +49,8 @@ void (*_prof_register_command)(const char *filename, const char *command_name, i void (*_prof_register_timed)(const char *filename, void(*callback)(void), int interval_seconds) = NULL; void (*_prof_completer_add)(const char *filename, const char *key, char **items) = NULL; -void (*prof_completer_remove)(const char *key, char **items) = NULL; -void (*prof_completer_clear)(const char *key) = NULL; +void (*_prof_completer_remove)(const char *filename, const char *key, char **items) = NULL; +void (*_prof_completer_clear)(const char *filename, const char *key) = NULL; void (*prof_notify)(const char *message, int timeout_ms, const char *category) = NULL; diff --git a/src/plugins/profapi.h b/src/plugins/profapi.h index d42bf70f..87bfd6d3 100644 --- a/src/plugins/profapi.h +++ b/src/plugins/profapi.h @@ -38,6 +38,8 @@ #define prof_register_command(command_name, min_args, max_args, synopsis, description, arguments, examples, callback) _prof_register_command(__FILE__, command_name, min_args, max_args, synopsis, description, arguments, examples, callback) #define prof_register_timed(callback, interval_seconds) _prof_register_timed(__FILE__, callback, interval_seconds) #define prof_completer_add(key, items) _prof_completer_add(__FILE__, key, items) +#define prof_completer_remove(key, items) _prof_completer_remove(__FILE__, key, items) +#define prof_completer_clear(key) _prof_completer_clear(__FILE__, key) #define prof_win_create(win, input_handler) _prof_win_create(__FILE__, win, input_handler) typedef char* PROF_WIN_TAG; @@ -54,8 +56,8 @@ void (*_prof_register_command)(const char *filename, const char *command_name, i void (*_prof_register_timed)(const char *filename, void(*callback)(void), int interval_seconds); void (*_prof_completer_add)(const char *filename, const char *key, char **items); -void (*prof_completer_remove)(const char *key, char **items); -void (*prof_completer_clear)(const char *key); +void (*_prof_completer_remove)(const char *filename, const char *key, char **items); +void (*_prof_completer_clear)(const char *filename, const char *key); void (*prof_notify)(const char *message, int timeout_ms, const char *category); diff --git a/src/plugins/python_api.c b/src/plugins/python_api.c index 82cf22eb..6f478893 100644 --- a/src/plugins/python_api.c +++ b/src/plugins/python_api.c @@ -242,6 +242,9 @@ python_api_completer_remove(PyObject *self, PyObject *args) return Py_BuildValue(""); } + char *plugin_name = _python_plugin_name(); + log_debug("Autocomplete remove %s for %s", key, plugin_name); + Py_ssize_t len = PyList_Size(items); char *c_items[len]; @@ -254,9 +257,11 @@ python_api_completer_remove(PyObject *self, PyObject *args) c_items[len] = NULL; allow_python_threads(); - api_completer_remove(key, c_items); + api_completer_remove(plugin_name, key, c_items); disable_python_threads(); + free(plugin_name); + return Py_BuildValue(""); } @@ -269,10 +274,15 @@ python_api_completer_clear(PyObject *self, PyObject *args) return Py_BuildValue(""); } + char *plugin_name = _python_plugin_name(); + log_debug("Autocomplete clear %s for %s", key, plugin_name); + allow_python_threads(); - api_completer_clear(key); + api_completer_clear(plugin_name, key); disable_python_threads(); + free(plugin_name); + return Py_BuildValue(""); } From 71178b3696cceae72c93d2e904ae41a811dec87d Mon Sep 17 00:00:00 2001 From: James Booth Date: Tue, 5 Jul 2016 21:46:36 +0100 Subject: [PATCH 22/34] Store plugin completers by plugin name --- src/plugins/api.c | 6 +- src/plugins/autocompleters.c | 109 ++++++++++++++++++++++------------- src/plugins/autocompleters.h | 6 +- src/tools/autocomplete.c | 18 ++++++ src/tools/autocomplete.h | 2 + 5 files changed, 96 insertions(+), 45 deletions(-) diff --git a/src/plugins/api.c b/src/plugins/api.c index ecd1749e..c8e6a166 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -163,19 +163,19 @@ api_register_timed(const char *const plugin_name, void *callback, int interval_s void api_completer_add(const char *const plugin_name, const char *key, char **items) { - autocompleters_add(key, items); + autocompleters_add(plugin_name, key, items); } void api_completer_remove(const char *const plugin_name, const char *key, char **items) { - autocompleters_remove(key, items); + autocompleters_remove(plugin_name, key, items); } void api_completer_clear(const char *const plugin_name, const char *key) { - autocompleters_clear(key); + autocompleters_clear(plugin_name, key); } void diff --git a/src/plugins/autocompleters.c b/src/plugins/autocompleters.c index 36ffea4a..ab4a70b7 100644 --- a/src/plugins/autocompleters.c +++ b/src/plugins/autocompleters.c @@ -38,56 +38,71 @@ #include "tools/autocomplete.h" -static GHashTable *autocompleters; +static GHashTable *plugin_to_acs; + +static void +_free_autocompleters(GHashTable *key_to_ac) +{ + g_hash_table_destroy(key_to_ac); +} void autocompleters_init(void) { - autocompleters = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)autocomplete_free); + plugin_to_acs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_autocompleters); } void -autocompleters_add(const char *key, char **items) +autocompleters_add(const char *const plugin_name, const char *key, char **items) { - if (g_hash_table_contains(autocompleters, key)) { - Autocomplete existing_ac = g_hash_table_lookup(autocompleters, key); - - int i = 0; - for (i = 0; i < g_strv_length(items); i++) { - autocomplete_add(existing_ac, items[i]); + GHashTable *key_to_ac = g_hash_table_lookup(plugin_to_acs, plugin_name); + if (key_to_ac) { + if (g_hash_table_contains(key_to_ac, key)) { + Autocomplete existing_ac = g_hash_table_lookup(key_to_ac, key); + autocomplete_add_all(existing_ac, items); + } else { + Autocomplete new_ac = autocomplete_new(); + autocomplete_add_all(new_ac, items); + g_hash_table_insert(key_to_ac, strdup(key), new_ac); } } else { + key_to_ac = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)autocomplete_free); Autocomplete new_ac = autocomplete_new(); - int i = 0; - for (i = 0; i < g_strv_length(items); i++) { - autocomplete_add(new_ac, items[i]); - } - g_hash_table_insert(autocompleters, strdup(key), new_ac); + autocomplete_add_all(new_ac, items); + g_hash_table_insert(key_to_ac, strdup(key), new_ac); + g_hash_table_insert(plugin_to_acs, strdup(plugin_name), key_to_ac); } } void -autocompleters_remove(const char *key, char **items) +autocompleters_remove(const char *const plugin_name, const char *key, char **items) { - if (!g_hash_table_contains(autocompleters, key)) { + GHashTable *key_to_ac = g_hash_table_lookup(plugin_to_acs, plugin_name); + if (!key_to_ac) { return; } - Autocomplete ac = g_hash_table_lookup(autocompleters, key); - int i = 0; - for (i = 0; i < g_strv_length(items); i++) { - autocomplete_remove(ac, items[i]); + if (!g_hash_table_contains(key_to_ac, key)) { + return; } + + Autocomplete ac = g_hash_table_lookup(key_to_ac, key); + autocomplete_remove_all(ac, items); } void -autocompleters_clear(const char *key) +autocompleters_clear(const char *const plugin_name, const char *key) { - if (!g_hash_table_contains(autocompleters, key)) { + GHashTable *key_to_ac = g_hash_table_lookup(plugin_to_acs, plugin_name); + if (!key_to_ac) { return; } - Autocomplete ac = g_hash_table_lookup(autocompleters, key); + if (!g_hash_table_contains(key_to_ac, key)) { + return; + } + + Autocomplete ac = g_hash_table_lookup(key_to_ac, key); autocomplete_clear(ac); } @@ -96,17 +111,26 @@ autocompleters_complete(const char * const input) { char *result = NULL; - GList *keys = g_hash_table_get_keys(autocompleters); - GList *curr = keys; - while (curr) { - result = autocomplete_param_with_ac(input, curr->data, g_hash_table_lookup(autocompleters, curr->data), TRUE); - if (result) { - g_list_free(keys); - return result; + GList *ac_hashes = g_hash_table_get_values(plugin_to_acs); + GList *curr_hash = ac_hashes; + while (curr_hash) { + GHashTable *key_to_ac = curr_hash->data; + + GList *keys = g_hash_table_get_keys(key_to_ac); + GList *curr = keys; + while (curr) { + result = autocomplete_param_with_ac(input, curr->data, g_hash_table_lookup(key_to_ac, curr->data), TRUE); + if (result) { + g_list_free(keys); + return result; + } + curr = g_list_next(curr); } - curr = g_list_next(curr); + g_list_free(keys); + + curr_hash = g_list_next(curr_hash); } - g_list_free(keys); + g_list_free(ac_hashes); return NULL; } @@ -114,17 +138,24 @@ autocompleters_complete(const char * const input) void autocompleters_reset(void) { - GList *acs = g_hash_table_get_values(autocompleters); - GList *curr = acs; - while (curr) { - autocomplete_reset(curr->data); - curr = g_list_next(curr); + GList *ac_hashes = g_hash_table_get_values(plugin_to_acs); + GList *curr_hash = ac_hashes; + while (curr_hash) { + GList *acs = g_hash_table_get_values(curr_hash->data); + GList *curr = acs; + while (curr) { + autocomplete_reset(curr->data); + curr = g_list_next(curr); + } + + g_list_free(acs); + curr_hash = g_list_next(curr_hash); } - g_list_free(acs); + g_list_free(ac_hashes); } void autocompleters_destroy(void) { - g_hash_table_destroy(autocompleters); + g_hash_table_destroy(plugin_to_acs); } diff --git a/src/plugins/autocompleters.h b/src/plugins/autocompleters.h index a04dfe2f..1350ba7c 100644 --- a/src/plugins/autocompleters.h +++ b/src/plugins/autocompleters.h @@ -38,9 +38,9 @@ #include void autocompleters_init(void); -void autocompleters_add(const char *key, char **items); -void autocompleters_remove(const char *key, char **items); -void autocompleters_clear(const char *key); +void autocompleters_add(const char *const plugin_name, const char *key, char **items); +void autocompleters_remove(const char *const plugin_name, const char *key, char **items); +void autocompleters_clear(const char *const plugin_name, const char *key); char* autocompleters_complete(const char * const input); void autocompleters_reset(void); void autocompleters_destroy(void); diff --git a/src/tools/autocomplete.c b/src/tools/autocomplete.c index 2484a6e1..258f02da 100644 --- a/src/tools/autocomplete.c +++ b/src/tools/autocomplete.c @@ -117,6 +117,15 @@ autocomplete_add(Autocomplete ac, const char *item) return; } +void +autocomplete_add_all(Autocomplete ac, char **items) +{ + int i = 0; + for (i = 0; i < g_strv_length(items); i++) { + autocomplete_add(ac, items[i]); + } +} + void autocomplete_remove(Autocomplete ac, const char *const item) { @@ -139,6 +148,15 @@ autocomplete_remove(Autocomplete ac, const char *const item) return; } +void +autocomplete_remove_all(Autocomplete ac, char **items) +{ + int i = 0; + for (i = 0; i < g_strv_length(items); i++) { + autocomplete_remove(ac, items[i]); + } +} + GSList* autocomplete_create_list(Autocomplete ac) { diff --git a/src/tools/autocomplete.h b/src/tools/autocomplete.h index 9c2f8fc2..12b60718 100644 --- a/src/tools/autocomplete.h +++ b/src/tools/autocomplete.h @@ -50,7 +50,9 @@ void autocomplete_clear(Autocomplete ac); void autocomplete_free(Autocomplete ac); void autocomplete_add(Autocomplete ac, const char *item); +void autocomplete_add_all(Autocomplete ac, char **items); void autocomplete_remove(Autocomplete ac, const char *const item); +void autocomplete_remove_all(Autocomplete ac, char **items); // find the next item prefixed with search string gchar* autocomplete_complete(Autocomplete ac, const gchar *search_str, gboolean quote); From 99598e7d57be923ce18fa5cded11431e5b462720 Mon Sep 17 00:00:00 2001 From: James Booth Date: Tue, 5 Jul 2016 22:03:14 +0100 Subject: [PATCH 23/34] Add plugins on_unload hook --- src/plugins/c_plugins.c | 15 +++++++++++++++ src/plugins/c_plugins.h | 1 + src/plugins/plugins.c | 5 +++++ src/plugins/plugins.h | 1 + src/plugins/python_plugins.c | 20 ++++++++++++++++++++ src/plugins/python_plugins.h | 1 + 6 files changed, 43 insertions(+) diff --git a/src/plugins/c_plugins.c b/src/plugins/c_plugins.c index 5c0047c8..1a4b8754 100644 --- a/src/plugins/c_plugins.c +++ b/src/plugins/c_plugins.c @@ -81,6 +81,7 @@ c_plugin_create(const char *const filename) plugin->init_func = c_init_hook; plugin->on_start_func = c_on_start_hook; plugin->on_shutdown_func = c_on_shutdown_hook; + plugin->on_unload_func = c_on_unload_hook; plugin->on_connect_func = c_on_connect_hook; plugin->on_disconnect_func = c_on_disconnect_hook; plugin->pre_chat_message_display = c_pre_chat_message_display_hook; @@ -161,6 +162,20 @@ c_on_shutdown_hook(ProfPlugin *plugin) func(); } +void +c_on_unload_hook(ProfPlugin *plugin) +{ + void *f = NULL; + void (*func)(void); + assert(plugin && plugin->module); + + if (NULL == (f = dlsym(plugin->module, "prof_on_unload"))) + return; + + func = (void (*)(void))f; + func(); +} + void c_on_connect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid) { diff --git a/src/plugins/c_plugins.h b/src/plugins/c_plugins.h index a62e302f..f4f88752 100644 --- a/src/plugins/c_plugins.h +++ b/src/plugins/c_plugins.h @@ -47,6 +47,7 @@ void c_init_hook(ProfPlugin *plugin, const char *const version, const char *cons const char *const fulljid); void c_on_start_hook(ProfPlugin *plugin); void c_on_shutdown_hook(ProfPlugin *plugin); +void c_on_unload_hook(ProfPlugin *plugin); void c_on_connect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid); void c_on_disconnect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid); diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index ae0e65b0..449bbecf 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -168,6 +168,11 @@ plugins_load(const char *const name) gboolean plugins_unload(const char *const name) { + ProfPlugin *plugin = g_hash_table_lookup(plugins, name); + if (plugin) { + plugin->on_unload_func(plugin); + } + prefs_remove_plugin(name); return TRUE; diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index 13bb6e2f..feddcbfe 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -51,6 +51,7 @@ typedef struct prof_plugin_t { void (*on_start_func)(struct prof_plugin_t* plugin); void (*on_shutdown_func)(struct prof_plugin_t* plugin); + void (*on_unload_func)(struct prof_plugin_t* plugin); void (*on_connect_func)(struct prof_plugin_t* plugin, const char *const account_name, const char *const fulljid); void (*on_disconnect_func)(struct prof_plugin_t* plugin, const char *const account_name, diff --git a/src/plugins/python_plugins.c b/src/plugins/python_plugins.c index 0dac55ec..efd225b0 100644 --- a/src/plugins/python_plugins.c +++ b/src/plugins/python_plugins.c @@ -91,6 +91,7 @@ python_plugin_create(const char *const filename) plugin->init_func = python_init_hook; plugin->on_start_func = python_on_start_hook; plugin->on_shutdown_func = python_on_shutdown_hook; + plugin->on_unload_func = python_on_unload_hook; plugin->on_connect_func = python_on_connect_hook; plugin->on_disconnect_func = python_on_disconnect_hook; plugin->pre_chat_message_display = python_pre_chat_message_display_hook; @@ -186,6 +187,25 @@ python_on_shutdown_hook(ProfPlugin *plugin) allow_python_threads(); } +void +python_on_unload_hook(ProfPlugin *plugin) +{ + disable_python_threads(); + PyObject *p_function; + + PyObject *p_module = plugin->module; + if (PyObject_HasAttrString(p_module, "prof_on_unload")) { + p_function = PyObject_GetAttrString(p_module, "prof_on_unload"); + python_check_error(); + if (p_function && PyCallable_Check(p_function)) { + PyObject_CallObject(p_function, NULL); + python_check_error(); + Py_XDECREF(p_function); + } + } + allow_python_threads(); +} + void python_on_connect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid) { diff --git a/src/plugins/python_plugins.h b/src/plugins/python_plugins.h index 71a62f1c..facf3ff2 100644 --- a/src/plugins/python_plugins.h +++ b/src/plugins/python_plugins.h @@ -47,6 +47,7 @@ void python_init_hook(ProfPlugin *plugin, const char *const version, const char const char *const account_name, const char *const fulljid); void python_on_start_hook(ProfPlugin *plugin); void python_on_shutdown_hook(ProfPlugin *plugin); +void python_on_unload_hook(ProfPlugin *plugin); void python_on_connect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid); void python_on_disconnect_hook(ProfPlugin *plugin, const char *const account_name, const char *const fulljid); From 97f79970252a06a1583ca1e1c8b22111720ddf94 Mon Sep 17 00:00:00 2001 From: James Booth Date: Tue, 5 Jul 2016 22:10:41 +0100 Subject: [PATCH 24/34] Move adding plugins commands to autocompleters --- src/plugins/api.c | 4 ++++ src/plugins/callbacks.c | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/api.c b/src/plugins/api.c index c8e6a166..e98e44d5 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -52,6 +52,7 @@ #include "command/cmd_defs.h" #include "window_list.h" #include "common.h" +#include "command/cmd_ac.h" void api_cons_alert(void) @@ -144,6 +145,9 @@ api_register_command(const char *const plugin_name, const char *command_name, in command->help = help; callbacks_add_command(plugin_name, command); + + cmd_ac_add(command->command_name); + cmd_ac_add_help(&command->command_name[1]); } void diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c index d313690b..5af5d0bc 100644 --- a/src/plugins/callbacks.c +++ b/src/plugins/callbacks.c @@ -36,7 +36,6 @@ #include #include "command/cmd_defs.h" -#include "command/cmd_ac.h" #include "plugins/callbacks.h" #include "plugins/plugins.h" #include "tools/autocomplete.h" @@ -166,8 +165,6 @@ callbacks_add_command(const char *const plugin_name, PluginCommand *command) g_hash_table_insert(command_hash, strdup(command->command_name), command); g_hash_table_insert(p_commands, strdup(plugin_name), command_hash); } - cmd_ac_add(command->command_name); - cmd_ac_add_help(&command->command_name[1]); } void From 82458c9d96a0d1a81b1d8d2b5232780fb653f2ae Mon Sep 17 00:00:00 2001 From: James Booth Date: Tue, 5 Jul 2016 22:11:58 +0100 Subject: [PATCH 25/34] Revert "Move adding plugins commands to autocompleters" This reverts commit 97f79970252a06a1583ca1e1c8b22111720ddf94. --- src/plugins/api.c | 4 ---- src/plugins/callbacks.c | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/plugins/api.c b/src/plugins/api.c index e98e44d5..c8e6a166 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -52,7 +52,6 @@ #include "command/cmd_defs.h" #include "window_list.h" #include "common.h" -#include "command/cmd_ac.h" void api_cons_alert(void) @@ -145,9 +144,6 @@ api_register_command(const char *const plugin_name, const char *command_name, in command->help = help; callbacks_add_command(plugin_name, command); - - cmd_ac_add(command->command_name); - cmd_ac_add_help(&command->command_name[1]); } void diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c index 5af5d0bc..d313690b 100644 --- a/src/plugins/callbacks.c +++ b/src/plugins/callbacks.c @@ -36,6 +36,7 @@ #include #include "command/cmd_defs.h" +#include "command/cmd_ac.h" #include "plugins/callbacks.h" #include "plugins/plugins.h" #include "tools/autocomplete.h" @@ -165,6 +166,8 @@ callbacks_add_command(const char *const plugin_name, PluginCommand *command) g_hash_table_insert(command_hash, strdup(command->command_name), command); g_hash_table_insert(p_commands, strdup(plugin_name), command_hash); } + cmd_ac_add(command->command_name); + cmd_ac_add_help(&command->command_name[1]); } void From 1926ceea3d11cdf83fc2323aa512861e342e1eba Mon Sep 17 00:00:00 2001 From: James Booth Date: Tue, 5 Jul 2016 22:46:00 +0100 Subject: [PATCH 26/34] Plugin unload remove cmd_acs and close window --- src/command/cmd_ac.c | 8 ++++++++ src/command/cmd_ac.h | 1 + src/plugins/callbacks.c | 25 ++++++++++++++++++++++++- src/plugins/plugins.c | 19 +++++++++++++++---- src/profanity.c | 4 ++-- src/window_list.c | 23 +++++++++++++++++++++++ src/window_list.h | 2 ++ 7 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index da466b76..565ce336 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -787,6 +787,14 @@ cmd_ac_remove(const char *const value) } } +void +cmd_ac_remove_help(const char *const value) +{ + if (help_ac) { + autocomplete_remove(help_ac, value); + } +} + gboolean cmd_ac_exists(char *cmd) { diff --git a/src/command/cmd_ac.h b/src/command/cmd_ac.h index b294fcd5..637ebcf6 100644 --- a/src/command/cmd_ac.h +++ b/src/command/cmd_ac.h @@ -48,6 +48,7 @@ void cmd_ac_add_alias(ProfAlias *alias); void cmd_ac_add_alias_value(char *value); void cmd_ac_remove(const char *const value); +void cmd_ac_remove_help(const char *const value); void cmd_ac_remove_alias_value(char *value); gboolean cmd_ac_exists(char *cmd); diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c index d313690b..52f0aebd 100644 --- a/src/plugins/callbacks.c +++ b/src/plugins/callbacks.c @@ -41,6 +41,7 @@ #include "plugins/plugins.h" #include "tools/autocomplete.h" #include "tools/parser.h" +#include "window_list.h" #include "ui/ui.h" @@ -141,9 +142,31 @@ callbacks_init(void) void callbacks_remove(const char *const plugin_name) { - // TODO remove from cmd_ac and cmd_ac_help + GHashTable *command_hash = g_hash_table_lookup(p_commands, plugin_name); + if (command_hash) { + GList *commands = g_hash_table_get_keys(command_hash); + GList *curr = commands; + while (curr) { + char *command = curr->data; + cmd_ac_remove(command); + cmd_ac_remove_help(&command[1]); + curr = g_list_next(curr); + } + g_list_free(commands); + } + g_hash_table_remove(p_commands, plugin_name); g_hash_table_remove(p_timed_functions, plugin_name); + + GHashTable *tag_to_win_cb_hash = g_hash_table_lookup(p_window_callbacks, plugin_name); + GList *tags = g_hash_table_get_keys(tag_to_win_cb_hash); + GList *curr = tags; + while (curr) { + wins_close_plugin(curr->data); + curr = g_list_next(curr); + } + g_list_free(tags); + g_hash_table_remove(p_window_callbacks, plugin_name); } diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 449bbecf..ea8e7d6a 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -171,10 +171,19 @@ plugins_unload(const char *const name) ProfPlugin *plugin = g_hash_table_lookup(plugins, name); if (plugin) { plugin->on_unload_func(plugin); +#ifdef HAVE_PYTHON + if (plugin->lang == LANG_PYTHON) { + python_plugin_destroy(plugin); + } +#endif +#ifdef HAVE_C + if (plugin->lang == LANG_C) { + c_plugin_destroy(plugin); + } +#endif + prefs_remove_plugin(name); + g_hash_table_remove(plugins, name); } - - prefs_remove_plugin(name); - return TRUE; } @@ -240,7 +249,9 @@ void plugins_win_process_line(char *win, const char * const line) { PluginWindowCallback *window = callbacks_get_window_handler(win); - window->callback_exec(window, win, line); + if (window) { + window->callback_exec(window, win, line); + } } void diff --git a/src/profanity.c b/src/profanity.c index c9e19fa8..37e9dbcf 100644 --- a/src/profanity.c +++ b/src/profanity.c @@ -391,7 +391,6 @@ _shutdown(void) plugins_on_shutdown(); muc_close(); caps_close(); - ui_close(); #ifdef HAVE_LIBOTR otr_shutdown(); #endif @@ -402,10 +401,11 @@ _shutdown(void) theme_close(); accounts_close(); tlscerts_close(); - cmd_uninit(); log_stderr_close(); log_close(); plugins_shutdown(); + cmd_uninit(); + ui_close(); prefs_close(); if (saved_status) { free(saved_status); diff --git a/src/window_list.c b/src/window_list.c index 01d5d412..4f2d86e0 100644 --- a/src/window_list.c +++ b/src/window_list.c @@ -226,6 +226,29 @@ wins_get_plugin(const char *const tag) return NULL; } +void +wins_close_plugin(const char *const tag) +{ + GList *values = g_hash_table_get_values(windows); + GList *curr = values; + + while (curr) { + ProfWin *window = curr->data; + if (window->type == WIN_PLUGIN) { + ProfPluginWin *pluginwin = (ProfPluginWin*)window; + if (g_strcmp0(pluginwin->tag, tag) == 0) { + int num = wins_get_num(window); + wins_close_by_num(num); + g_list_free(values); + return; + } + } + curr = g_list_next(curr); + } + + g_list_free(values); +} + GList* wins_get_private_chats(const char *const roomjid) { diff --git a/src/window_list.h b/src/window_list.h index 97fe43e1..109620f9 100644 --- a/src/window_list.h +++ b/src/window_list.h @@ -61,6 +61,8 @@ ProfPrivateWin* wins_get_private(const char *const fulljid); ProfPluginWin* wins_get_plugin(const char *const tag); ProfXMLWin* wins_get_xmlconsole(void); +void wins_close_plugin(const char *const tag); + ProfWin* wins_get_current(void); void wins_set_current_by_num(int i); From 7776c1494ad83f6094e4997fd3f647cb413b538e Mon Sep 17 00:00:00 2001 From: James Booth Date: Sat, 9 Jul 2016 23:13:36 +0100 Subject: [PATCH 27/34] Reaload python module if previous loaded on /plugin load --- src/plugins/python_plugins.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/plugins/python_plugins.c b/src/plugins/python_plugins.c index efd225b0..69c40eca 100644 --- a/src/plugins/python_plugins.c +++ b/src/plugins/python_plugins.c @@ -43,6 +43,7 @@ #include "ui/ui.h" static PyThreadState *thread_state; +static GHashTable *unloaded_modules; void allow_python_threads() @@ -59,6 +60,8 @@ disable_python_threads() void python_env_init(void) { + unloaded_modules = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL); + Py_Initialize(); PyEval_InitThreads(); python_api_init(); @@ -81,7 +84,15 @@ python_plugin_create(const char *const filename) { disable_python_threads(); gchar *module_name = g_strndup(filename, strlen(filename) - 3); - PyObject *p_module = PyImport_ImportModule(module_name); + + PyObject *p_module = g_hash_table_lookup(unloaded_modules, filename); + if (p_module) { + p_module = PyImport_ReloadModule(p_module); + g_hash_table_remove(unloaded_modules, filename); + } else { + p_module = PyImport_ImportModule(module_name); + } + python_check_error(); if (p_module) { ProfPlugin *plugin = malloc(sizeof(ProfPlugin)); @@ -910,8 +921,9 @@ python_plugin_destroy(ProfPlugin *plugin) { disable_python_threads(); callbacks_remove(plugin->name); + g_hash_table_insert(unloaded_modules, strdup(plugin->name), plugin->module); +// Py_XDECREF(plugin->module); free(plugin->name); - Py_XDECREF(plugin->module); free(plugin); allow_python_threads(); } From d24a0508f47d3021ebe17e60a7aa2349c49cbadb Mon Sep 17 00:00:00 2001 From: James Booth Date: Sat, 9 Jul 2016 23:42:09 +0100 Subject: [PATCH 28/34] Store python modules on load --- src/plugins/python_plugins.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/plugins/python_plugins.c b/src/plugins/python_plugins.c index 69c40eca..61a4c479 100644 --- a/src/plugins/python_plugins.c +++ b/src/plugins/python_plugins.c @@ -43,7 +43,7 @@ #include "ui/ui.h" static PyThreadState *thread_state; -static GHashTable *unloaded_modules; +static GHashTable *loaded_modules; void allow_python_threads() @@ -57,10 +57,16 @@ disable_python_threads() PyEval_RestoreThread(thread_state); } +static void +_unref_module(PyObject *module) +{ + Py_XDECREF(module); +} + void python_env_init(void) { - unloaded_modules = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL); + loaded_modules = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_unref_module); Py_Initialize(); PyEval_InitThreads(); @@ -83,14 +89,15 @@ ProfPlugin* python_plugin_create(const char *const filename) { disable_python_threads(); - gchar *module_name = g_strndup(filename, strlen(filename) - 3); - PyObject *p_module = g_hash_table_lookup(unloaded_modules, filename); + PyObject *p_module = g_hash_table_lookup(loaded_modules, filename); if (p_module) { p_module = PyImport_ReloadModule(p_module); - g_hash_table_remove(unloaded_modules, filename); } else { + gchar *module_name = g_strndup(filename, strlen(filename) - 3); p_module = PyImport_ImportModule(module_name); + g_hash_table_insert(loaded_modules, strdup(filename), p_module); + g_free(module_name); } python_check_error(); @@ -128,12 +135,10 @@ python_plugin_create(const char *const filename) plugin->on_contact_presence = python_on_contact_presence_hook; plugin->on_chat_win_focus = python_on_chat_win_focus_hook; plugin->on_room_win_focus = python_on_room_win_focus_hook; - g_free(module_name); allow_python_threads(); return plugin; } else { - g_free(module_name); allow_python_threads(); return NULL; } @@ -921,8 +926,6 @@ python_plugin_destroy(ProfPlugin *plugin) { disable_python_threads(); callbacks_remove(plugin->name); - g_hash_table_insert(unloaded_modules, strdup(plugin->name), plugin->module); -// Py_XDECREF(plugin->module); free(plugin->name); free(plugin); allow_python_threads(); @@ -932,5 +935,6 @@ void python_shutdown(void) { disable_python_threads(); + g_hash_table_destroy(loaded_modules); Py_Finalize(); } From 44862fe84233f82d997c458b2eb162af9ae6cf0b Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 10 Jul 2016 00:43:53 +0100 Subject: [PATCH 29/34] Remove string allocation for conflists --- src/config/conflists.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/config/conflists.c b/src/config/conflists.c index b005ccb8..00005924 100644 --- a/src/config/conflists.c +++ b/src/config/conflists.c @@ -64,7 +64,7 @@ conf_string_list_add(GKeyFile *keyfile, const char *const group, const char *con GList *curr = glist; i = 0; while (curr) { - new_list[i++] = strdup(curr->data); + new_list[i++] = curr->data; curr = g_list_next(curr); } new_list[i] = NULL; @@ -73,7 +73,7 @@ conf_string_list_add(GKeyFile *keyfile, const char *const group, const char *con // list not found } else { const gchar* new_list[2]; - new_list[0] = strdup(item); + new_list[0] = item; new_list[1] = NULL; g_key_file_set_string_list(keyfile, group, key, new_list, 1); } @@ -114,7 +114,7 @@ conf_string_list_remove(GKeyFile *keyfile, const char *const group, const char * GList *curr = glist; i = 0; while (curr) { - new_list[i++] = strdup(curr->data); + new_list[i++] = curr->data; curr = g_list_next(curr); } new_list[i] = NULL; From 448bef247b076683862e45aee78f06e29938ffc6 Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 10 Jul 2016 01:07:41 +0100 Subject: [PATCH 30/34] Add /plugin reload command --- src/command/cmd_ac.c | 25 +++++++++++++++++++++++++ src/command/cmd_defs.c | 7 +++++-- src/command/cmd_funcs.c | 13 +++++++++++++ src/plugins/plugins.c | 11 +++++++++++ src/plugins/plugins.h | 1 + 5 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 565ce336..09383edf 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -186,6 +186,7 @@ static Autocomplete autoping_ac; static Autocomplete plugins_ac; static Autocomplete plugins_load_ac; static Autocomplete plugins_unload_ac; +static Autocomplete plugins_reload_ac; static Autocomplete sendfile_ac; static Autocomplete blocked_ac; static Autocomplete tray_ac; @@ -486,6 +487,7 @@ cmd_ac_init(void) theme_load_ac = NULL; plugins_load_ac = NULL; plugins_unload_ac = NULL; + plugins_reload_ac = NULL; who_roster_ac = autocomplete_new(); autocomplete_add(who_roster_ac, "chat"); @@ -705,6 +707,7 @@ cmd_ac_init(void) plugins_ac = autocomplete_new(); autocomplete_add(plugins_ac, "load"); autocomplete_add(plugins_ac, "unload"); + autocomplete_add(plugins_ac, "reload"); sendfile_ac = autocomplete_new(); @@ -924,6 +927,10 @@ cmd_ac_reset(ProfWin *window) autocomplete_free(plugins_unload_ac); plugins_unload_ac = NULL; } + if (plugins_reload_ac) { + autocomplete_free(plugins_reload_ac); + plugins_reload_ac = NULL; + } autocomplete_reset(account_ac); autocomplete_reset(account_set_ac); autocomplete_reset(account_clear_ac); @@ -1103,6 +1110,7 @@ cmd_ac_uninit(void) autocomplete_free(plugins_ac); autocomplete_free(plugins_load_ac); autocomplete_free(plugins_unload_ac); + autocomplete_free(plugins_reload_ac); autocomplete_free(sendfile_ac); autocomplete_free(blocked_ac); autocomplete_free(tray_ac); @@ -1899,6 +1907,23 @@ _plugins_autocomplete(ProfWin *window, const char *const input) } } + if (strncmp(input, "/plugins reload ", 16) == 0) { + if (plugins_reload_ac == NULL) { + plugins_reload_ac = autocomplete_new(); + GList *plugins = plugins_loaded_list(); + GList *curr = plugins; + while (curr) { + autocomplete_add(plugins_reload_ac, curr->data); + curr = g_list_next(curr); + } + g_list_free(plugins); + } + result = autocomplete_param_with_ac(input, "/plugins reload", plugins_reload_ac, TRUE); + if (result) { + return result; + } + } + if (strncmp(input, "/plugins unload ", 16) == 0) { if (plugins_unload_ac == NULL) { plugins_unload_ac = autocomplete_new(); diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 02f5ee93..bc8a1057 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -1980,15 +1980,18 @@ static struct cmd_t command_defs[] = CMD_SYN( "/plugins", "/plugins unload ", - "/plugins load ") + "/plugins load ", + "/plugins reload ") CMD_DESC( "Manage plugins. Passing no arguments lists currently loaded plugins.") CMD_ARGS( { "load ", "Load a plugin." }, + { "reload ", "Reload a plugin." }, { "unload ", "Unload a plugin." }) CMD_EXAMPLES( "/plugin load browser.py", - "/plugin unload say.py") + "/plugin unload say.py", + "/plugin reload wikipedia.py") }, { "/prefs", diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 540773d7..f5646a51 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -6050,6 +6050,19 @@ cmd_plugins(ProfWin *window, const char *const command, gchar **args) cons_show("Failed to unload plugin: %s", args[1]); } + return TRUE; + } else if (g_strcmp0(args[0], "reload") == 0) { + if (args[1] == NULL) { + cons_bad_cmd_usage(command); + return TRUE; + } + gboolean res = plugins_reload(args[1]); + if (res) { + cons_show("Reloaded plugin: %s", args[1]); + } else { + cons_show("Failed to reload plugin: %s", args[1]); + } + return TRUE; } else { GList *plugins = plugins_loaded_list(); diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index ea8e7d6a..46fa482f 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -187,6 +187,17 @@ plugins_unload(const char *const name) return TRUE; } +gboolean +plugins_reload(const char *const name) +{ + gboolean res = plugins_unload(name); + if (res) { + res = plugins_load(name); + } + + return res; +} + static gchar* _get_plugins_dir(void) { diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index feddcbfe..45be1fc6 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -107,6 +107,7 @@ void plugins_shutdown(void); gboolean plugins_load(const char *const name); gboolean plugins_unload(const char *const name); +gboolean plugins_reload(const char *const name); void plugins_on_start(void); void plugins_on_shutdown(void); From 9a0111c10a3bd461c036d6d5ffb0e3390bed47c5 Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 10 Jul 2016 01:28:30 +0100 Subject: [PATCH 31/34] Allow reloading all plugins with /plugin reload --- src/command/cmd_defs.c | 6 +++--- src/command/cmd_funcs.c | 15 ++++++++------- src/plugins/plugins.c | 21 +++++++++++++++++++++ src/plugins/plugins.h | 1 + 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index bc8a1057..1a94605a 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -1981,13 +1981,13 @@ static struct cmd_t command_defs[] = "/plugins", "/plugins unload ", "/plugins load ", - "/plugins reload ") + "/plugins reload []") CMD_DESC( "Manage plugins. Passing no arguments lists currently loaded plugins.") CMD_ARGS( { "load ", "Load a plugin." }, - { "reload ", "Reload a plugin." }, - { "unload ", "Unload a plugin." }) + { "unload ", "Unload a plugin." }, + { "reload []", "Reload a plugin, passing no argument will reload all plugins" }) CMD_EXAMPLES( "/plugin load browser.py", "/plugin unload say.py", diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index f5646a51..fcce7028 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -6053,14 +6053,15 @@ cmd_plugins(ProfWin *window, const char *const command, gchar **args) return TRUE; } else if (g_strcmp0(args[0], "reload") == 0) { if (args[1] == NULL) { - cons_bad_cmd_usage(command); - return TRUE; - } - gboolean res = plugins_reload(args[1]); - if (res) { - cons_show("Reloaded plugin: %s", args[1]); + plugins_reload_all(); + cons_show("Reloaded all plugins"); } else { - cons_show("Failed to reload plugin: %s", args[1]); + gboolean res = plugins_reload(args[1]); + if (res) { + cons_show("Reloaded plugin: %s", args[1]); + } else { + cons_show("Failed to reload plugin: %s", args[1]); + } } return TRUE; diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 46fa482f..ef3fc5c2 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -187,6 +187,27 @@ plugins_unload(const char *const name) return TRUE; } +void +plugins_reload_all(void) +{ + GList *plugin_names = g_hash_table_get_keys(plugins); + GList *plugin_names_dup = NULL; + GList *curr = plugin_names; + while (curr) { + plugin_names_dup = g_list_append(plugin_names_dup, strdup(curr->data)); + curr = g_list_next(curr); + } + g_list_free(plugin_names); + + curr = plugin_names_dup; + while (curr) { + plugins_reload(curr->data); + curr = g_list_next(curr); + } + + g_list_free_full(plugin_names_dup, free); +} + gboolean plugins_reload(const char *const name) { diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index 45be1fc6..78bae9e6 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -108,6 +108,7 @@ void plugins_shutdown(void); gboolean plugins_load(const char *const name); gboolean plugins_unload(const char *const name); gboolean plugins_reload(const char *const name); +void plugins_reload_all(void); void plugins_on_start(void); void plugins_on_shutdown(void); From 1a7eb0076395faf9be1fcd0f5b076b3156693f37 Mon Sep 17 00:00:00 2001 From: James Booth Date: Tue, 12 Jul 2016 01:51:27 +0100 Subject: [PATCH 32/34] Check for plugin win before creating --- src/plugins/api.c | 4 ++++ src/plugins/callbacks.c | 14 ++++++++++++++ src/plugins/callbacks.h | 1 + src/window_list.c | 29 +++++++++++------------------ src/window_list.h | 2 +- 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/plugins/api.c b/src/plugins/api.c index c8e6a166..d66975d5 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -302,6 +302,10 @@ api_win_create( void(*callback_exec)(PluginWindowCallback *window_callback, const char *tag, const char * const line), void(*callback_destroy)(void *callback)) { + if (callbacks_win_exists(plugin_name, tag)) { + return; + } + PluginWindowCallback *window = malloc(sizeof(PluginWindowCallback)); window->callback = callback; window->callback_exec = callback_exec; diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c index 52f0aebd..4b958a67 100644 --- a/src/plugins/callbacks.c +++ b/src/plugins/callbacks.c @@ -206,6 +206,20 @@ callbacks_add_timed(const char *const plugin_name, PluginTimedFunction *timed_fu } } +gboolean +callbacks_win_exists(const char *const plugin_name, const char *tag) +{ + GHashTable *window_callbacks = g_hash_table_lookup(p_window_callbacks, plugin_name); + if (window_callbacks) { + PluginWindowCallback *cb = g_hash_table_lookup(window_callbacks, tag); + if (cb) { + return TRUE; + } + } + + return FALSE; +} + void callbacks_add_window_handler(const char *const plugin_name, const char *tag, PluginWindowCallback *window_callback) { diff --git a/src/plugins/callbacks.h b/src/plugins/callbacks.h index b73f80ff..0b5ea141 100644 --- a/src/plugins/callbacks.h +++ b/src/plugins/callbacks.h @@ -69,6 +69,7 @@ void callbacks_close(void); void callbacks_add_command(const char *const plugin_name, PluginCommand *command); void callbacks_add_timed(const char *const plugin_name, PluginTimedFunction *timed_function); +gboolean callbacks_win_exists(const char *const plugin_name, const char *tag); void callbacks_add_window_handler(const char *const plugin_name, const char *tag, PluginWindowCallback *window_callback); void * callbacks_get_window_handler(const char *tag); diff --git a/src/window_list.c b/src/window_list.c index 4f2d86e0..0f90ac6b 100644 --- a/src/window_list.c +++ b/src/window_list.c @@ -48,7 +48,7 @@ #include "window_list.h" #include "plugins/plugins.h" #include "xmpp/xmpp.h" - +#include "config/preferences.h" static GHashTable *windows; static int current; @@ -227,26 +227,19 @@ wins_get_plugin(const char *const tag) } void -wins_close_plugin(const char *const tag) +wins_close_plugin(char *tag) { - GList *values = g_hash_table_get_values(windows); - GList *curr = values; - - while (curr) { - ProfWin *window = curr->data; - if (window->type == WIN_PLUGIN) { - ProfPluginWin *pluginwin = (ProfPluginWin*)window; - if (g_strcmp0(pluginwin->tag, tag) == 0) { - int num = wins_get_num(window); - wins_close_by_num(num); - g_list_free(values); - return; - } - } - curr = g_list_next(curr); + ProfWin *toclose = wins_get_by_string(tag); + if (toclose == NULL) { + return; } - g_list_free(values); + int index = wins_get_num(toclose); + ui_close_win(index); + + if (prefs_get_boolean(PREF_WINS_AUTO_TIDY)) { + wins_tidy(); + } } GList* diff --git a/src/window_list.h b/src/window_list.h index 109620f9..930f2150 100644 --- a/src/window_list.h +++ b/src/window_list.h @@ -61,7 +61,7 @@ ProfPrivateWin* wins_get_private(const char *const fulljid); ProfPluginWin* wins_get_plugin(const char *const tag); ProfXMLWin* wins_get_xmlconsole(void); -void wins_close_plugin(const char *const tag); +void wins_close_plugin(char *tag); ProfWin* wins_get_current(void); From 5f393a6d9f995a9be86923f24e8b634a7a9d4ed9 Mon Sep 17 00:00:00 2001 From: James Booth Date: Tue, 12 Jul 2016 02:16:12 +0100 Subject: [PATCH 33/34] Remove plugin window on /close --- src/plugins/api.c | 2 +- src/plugins/callbacks.c | 10 ++++++++++ src/plugins/callbacks.h | 1 + src/plugins/plugins.c | 6 ++++++ src/plugins/plugins.h | 1 + src/ui/ui.h | 2 +- src/ui/win_types.h | 1 + src/ui/window.c | 3 ++- src/window_list.c | 5 +++-- src/window_list.h | 2 +- tests/unittests/ui/stub_ui.c | 2 +- 11 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/plugins/api.c b/src/plugins/api.c index d66975d5..a5f5deea 100644 --- a/src/plugins/api.c +++ b/src/plugins/api.c @@ -313,7 +313,7 @@ api_win_create( callbacks_add_window_handler(plugin_name, tag, window); - wins_new_plugin(tag); + wins_new_plugin(plugin_name, tag); // set status bar active ProfPluginWin *pluginwin = wins_get_plugin(tag); diff --git a/src/plugins/callbacks.c b/src/plugins/callbacks.c index 4b958a67..1ac4c5b9 100644 --- a/src/plugins/callbacks.c +++ b/src/plugins/callbacks.c @@ -220,6 +220,16 @@ callbacks_win_exists(const char *const plugin_name, const char *tag) return FALSE; } +void +callbacks_remove_win(const char *const plugin_name, const char *const tag) +{ + GHashTable *window_callbacks = g_hash_table_lookup(p_window_callbacks, plugin_name); + if (window_callbacks) { + g_hash_table_remove(window_callbacks, tag); + } +} + + void callbacks_add_window_handler(const char *const plugin_name, const char *tag, PluginWindowCallback *window_callback) { diff --git a/src/plugins/callbacks.h b/src/plugins/callbacks.h index 0b5ea141..72e5d4e2 100644 --- a/src/plugins/callbacks.h +++ b/src/plugins/callbacks.h @@ -72,5 +72,6 @@ void callbacks_add_timed(const char *const plugin_name, PluginTimedFunction *tim gboolean callbacks_win_exists(const char *const plugin_name, const char *tag); void callbacks_add_window_handler(const char *const plugin_name, const char *tag, PluginWindowCallback *window_callback); void * callbacks_get_window_handler(const char *tag); +void callbacks_remove_win(const char *const plugin_name, const char *const tag); #endif diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index ef3fc5c2..24eb40d2 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -286,6 +286,12 @@ plugins_win_process_line(char *win, const char * const line) } } +void +plugins_close_win(const char *const plugin_name, const char *const tag) +{ + callbacks_remove_win(plugin_name, tag); +} + void plugins_on_start(void) { diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index 78bae9e6..fc10c363 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -134,6 +134,7 @@ char* plugins_pre_priv_message_send(const char *const jid, const char *const mes void plugins_post_priv_message_send(const char *const jid, const char *const message); void plugins_win_process_line(char *win, const char *const line); +void plugins_close_win(const char *const plugin_name, const char *const tag); char* plugins_on_message_stanza_send(const char *const text); gboolean plugins_on_message_stanza_receive(const char *const text); diff --git a/src/ui/ui.h b/src/ui/ui.h index 5cf8cb31..79c1b201 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -344,7 +344,7 @@ ProfWin* win_create_chat(const char *const barejid); ProfWin* win_create_muc(const char *const roomjid); ProfWin* win_create_muc_config(const char *const title, DataForm *form); ProfWin* win_create_private(const char *const fulljid); -ProfWin* win_create_plugin(const char *const tag); +ProfWin* win_create_plugin(const char *const plugin_name, const char *const tag); void win_update_virtual(ProfWin *window); void win_free(ProfWin *window); gboolean win_notify_remind(ProfWin *window); diff --git a/src/ui/win_types.h b/src/ui/win_types.h index f05f237e..8b456993 100644 --- a/src/ui/win_types.h +++ b/src/ui/win_types.h @@ -190,6 +190,7 @@ typedef struct prof_xml_win_t { typedef struct prof_plugin_win_t { ProfWin super; char *tag; + char *plugin_name; unsigned long memcheck; } ProfPluginWin; diff --git a/src/ui/window.c b/src/ui/window.c index b9a8c7fd..2bbb327c 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -238,13 +238,14 @@ win_create_xmlconsole(void) } ProfWin* -win_create_plugin(const char *const tag) +win_create_plugin(const char *const plugin_name, const char *const tag) { ProfPluginWin *new_win = malloc(sizeof(ProfPluginWin)); new_win->super.type = WIN_PLUGIN; new_win->super.layout = _win_create_simple_layout(); new_win->tag = strdup(tag); + new_win->plugin_name = strdup(plugin_name); new_win->memcheck = PROFPLUGINWIN_MEMCHECK; diff --git a/src/window_list.c b/src/window_list.c index 0f90ac6b..af17f405 100644 --- a/src/window_list.c +++ b/src/window_list.c @@ -580,6 +580,7 @@ wins_close_by_num(int i) case WIN_PLUGIN: { ProfPluginWin *pluginwin = (ProfPluginWin*)window; + plugins_close_win(pluginwin->plugin_name, pluginwin->tag); autocomplete_remove(wins_ac, pluginwin->tag); autocomplete_remove(wins_close_ac, pluginwin->tag); break; @@ -681,12 +682,12 @@ wins_new_private(const char *const fulljid) } ProfWin * -wins_new_plugin(const char * const tag) +wins_new_plugin(const char *const plugin_name, const char * const tag) { GList *keys = g_hash_table_get_keys(windows); int result = get_next_available_win_num(keys); g_list_free(keys); - ProfWin *newwin = win_create_plugin(tag); + ProfWin *newwin = win_create_plugin(plugin_name, tag); g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin); autocomplete_add(wins_ac, tag); autocomplete_add(wins_close_ac, tag); diff --git a/src/window_list.h b/src/window_list.h index 930f2150..483301af 100644 --- a/src/window_list.h +++ b/src/window_list.h @@ -44,7 +44,7 @@ ProfWin* wins_new_chat(const char *const barejid); ProfWin* wins_new_muc(const char *const roomjid); ProfWin* wins_new_muc_config(const char *const roomjid, DataForm *form); ProfWin* wins_new_private(const char *const fulljid); -ProfWin* wins_new_plugin(const char *const tag); +ProfWin* wins_new_plugin(const char *const plugin_name, const char *const tag); gboolean wins_chat_exists(const char *const barejid); GList* wins_get_private_chats(const char *const roomjid); diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c index b0635fb8..2f9c3bdb 100644 --- a/tests/unittests/ui/stub_ui.c +++ b/tests/unittests/ui/stub_ui.c @@ -497,7 +497,7 @@ ProfWin* win_create_private(const char * const fulljid) { return NULL; } -ProfWin* win_create_plugin(const char * const tag) +ProfWin* win_create_plugin(const char *const plugin_name, const char * const tag) { return NULL; } From 0991699ae65387dc67852a3f9d465de25d6067a0 Mon Sep 17 00:00:00 2001 From: James Booth Date: Tue, 12 Jul 2016 23:50:21 +0100 Subject: [PATCH 34/34] Add /plugins install command --- src/command/cmd_ac.c | 218 +++++++++++++++++++++------------------- src/command/cmd_defs.c | 7 +- src/command/cmd_funcs.c | 45 ++++++++- src/common.c | 26 +++++ src/common.h | 1 + src/plugins/plugins.c | 26 +++++ src/plugins/plugins.h | 1 + 7 files changed, 218 insertions(+), 106 deletions(-) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 09383edf..d738b455 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -57,6 +57,8 @@ #include "pgp/gpg.h" #endif +static char* _complete_filepath(const char *const input, char *const startstr); + static char* _sub_autocomplete(ProfWin *window, const char *const input); static char* _notify_autocomplete(ProfWin *window, const char *const input); static char* _theme_autocomplete(ProfWin *window, const char *const input); @@ -187,7 +189,7 @@ static Autocomplete plugins_ac; static Autocomplete plugins_load_ac; static Autocomplete plugins_unload_ac; static Autocomplete plugins_reload_ac; -static Autocomplete sendfile_ac; +static Autocomplete filepath_ac; static Autocomplete blocked_ac; static Autocomplete tray_ac; static Autocomplete presence_ac; @@ -705,11 +707,12 @@ cmd_ac_init(void) autocomplete_add(autoping_ac, "timeout"); plugins_ac = autocomplete_new(); + autocomplete_add(plugins_ac, "install"); autocomplete_add(plugins_ac, "load"); autocomplete_add(plugins_ac, "unload"); autocomplete_add(plugins_ac, "reload"); - sendfile_ac = autocomplete_new(); + filepath_ac = autocomplete_new(); blocked_ac = autocomplete_new(); autocomplete_add(blocked_ac, "add"); @@ -903,7 +906,7 @@ cmd_ac_reset(ProfWin *window) autocomplete_reset(notify_mention_ac); autocomplete_reset(notify_trigger_ac); autocomplete_reset(sub_ac); - autocomplete_reset(sendfile_ac); + autocomplete_reset(filepath_ac); autocomplete_reset(who_room_ac); autocomplete_reset(who_roster_ac); @@ -1111,7 +1114,7 @@ cmd_ac_uninit(void) autocomplete_free(plugins_load_ac); autocomplete_free(plugins_unload_ac); autocomplete_free(plugins_reload_ac); - autocomplete_free(sendfile_ac); + autocomplete_free(filepath_ac); autocomplete_free(blocked_ac); autocomplete_free(tray_ac); autocomplete_free(presence_ac); @@ -1890,6 +1893,10 @@ _plugins_autocomplete(ProfWin *window, const char *const input) { char *result = NULL; + if (strncmp(input, "/plugins install ", 17) == 0) { + return _complete_filepath(input, "/plugins install"); + } + if (strncmp(input, "/plugins load ", 14) == 0) { if (plugins_load_ac == NULL) { plugins_load_ac = autocomplete_new(); @@ -2719,107 +2726,9 @@ _close_autocomplete(ProfWin *window, const char *const input) static char* _sendfile_autocomplete(ProfWin *window, const char *const input) { - static char* last_directory = NULL; - - unsigned int output_off = 0; - - char *result = NULL; - char *tmp; - - // strip command - char *inpcp = (char*)input + 9; - while (*inpcp == ' ') { - inpcp++; - } - - inpcp = strdup(inpcp); - - // strip quotes - if (*inpcp == '"') { - tmp = strchr(inpcp+1, '"'); - if (tmp) { - *tmp = '\0'; - } - tmp = strdup(inpcp+1); - free(inpcp); - inpcp = tmp; - } - - // expand ~ to $HOME - if (inpcp[0] == '~' && inpcp[1] == '/') { - if (asprintf(&tmp, "%s/%sfoo", getenv("HOME"), inpcp+2) == -1) { - return NULL; - } - output_off = strlen(getenv("HOME"))+1; - } else { - if (asprintf(&tmp, "%sfoo", inpcp) == -1) { - return NULL; - } - } - free(inpcp); - inpcp = tmp; - - char* inpcp2 = strdup(inpcp); - char* foofile = strdup(basename(inpcp2)); - char* directory = strdup(dirname(inpcp)); - free(inpcp); - free(inpcp2); - - if (!last_directory || strcmp(last_directory, directory) != 0) { - free(last_directory); - last_directory = directory; - autocomplete_reset(sendfile_ac); - - struct dirent *dir; - - DIR *d = opendir(directory); - if (d) { - while ((dir = readdir(d)) != NULL) { - if (strcmp(dir->d_name, ".") == 0) { - continue; - } else if (strcmp(dir->d_name, "..") == 0) { - continue; - } else if (*(dir->d_name) == '.' && *foofile != '.') { - // only show hidden files on explicit request - continue; - } - char * acstring; - if (output_off) { - if (asprintf(&tmp, "%s/%s", directory, dir->d_name) == -1) { - return NULL; - } - if (asprintf(&acstring, "~/%s", tmp+output_off) == -1) { - return NULL; - } - free(tmp); - } else if (strcmp(directory, "/") == 0) { - if (asprintf(&acstring, "/%s", dir->d_name) == -1) { - return NULL; - } - } else { - if (asprintf(&acstring, "%s/%s", directory, dir->d_name) == -1) { - return NULL; - } - } - autocomplete_add(sendfile_ac, acstring); - free(acstring); - } - closedir(d); - } - } else { - free(foofile); - free(directory); - } - - result = autocomplete_param_with_ac(input, "/sendfile", sendfile_ac, TRUE); - if (result) { - return result; - } - - return NULL; + return _complete_filepath(input, "/sendfile"); } - static char* _subject_autocomplete(ProfWin *window, const char *const input) { @@ -3019,3 +2928,106 @@ _presence_autocomplete(ProfWin *window, const char *const input) return NULL; } + +static char* +_complete_filepath(const char *const input, char *const startstr) +{ + static char* last_directory = NULL; + + unsigned int output_off = 0; + + char *result = NULL; + char *tmp; + + // strip command + char *inpcp = (char*)input + strlen(startstr); + while (*inpcp == ' ') { + inpcp++; + } + + inpcp = strdup(inpcp); + + // strip quotes + if (*inpcp == '"') { + tmp = strchr(inpcp+1, '"'); + if (tmp) { + *tmp = '\0'; + } + tmp = strdup(inpcp+1); + free(inpcp); + inpcp = tmp; + } + + // expand ~ to $HOME + if (inpcp[0] == '~' && inpcp[1] == '/') { + if (asprintf(&tmp, "%s/%sfoo", getenv("HOME"), inpcp+2) == -1) { + return NULL; + } + output_off = strlen(getenv("HOME"))+1; + } else { + if (asprintf(&tmp, "%sfoo", inpcp) == -1) { + return NULL; + } + } + free(inpcp); + inpcp = tmp; + + char* inpcp2 = strdup(inpcp); + char* foofile = strdup(basename(inpcp2)); + char* directory = strdup(dirname(inpcp)); + free(inpcp); + free(inpcp2); + + if (!last_directory || strcmp(last_directory, directory) != 0) { + free(last_directory); + last_directory = directory; + autocomplete_reset(filepath_ac); + + struct dirent *dir; + + DIR *d = opendir(directory); + if (d) { + while ((dir = readdir(d)) != NULL) { + if (strcmp(dir->d_name, ".") == 0) { + continue; + } else if (strcmp(dir->d_name, "..") == 0) { + continue; + } else if (*(dir->d_name) == '.' && *foofile != '.') { + // only show hidden files on explicit request + continue; + } + char * acstring; + if (output_off) { + if (asprintf(&tmp, "%s/%s", directory, dir->d_name) == -1) { + return NULL; + } + if (asprintf(&acstring, "~/%s", tmp+output_off) == -1) { + return NULL; + } + free(tmp); + } else if (strcmp(directory, "/") == 0) { + if (asprintf(&acstring, "/%s", dir->d_name) == -1) { + return NULL; + } + } else { + if (asprintf(&acstring, "%s/%s", directory, dir->d_name) == -1) { + return NULL; + } + } + autocomplete_add(filepath_ac, acstring); + free(acstring); + } + closedir(d); + } + } else { + free(foofile); + free(directory); + } + + result = autocomplete_param_with_ac(input, startstr, filepath_ac, TRUE); + if (result) { + return result; + } + + return NULL; +} diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 1a94605a..a9fc3089 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -1979,16 +1979,19 @@ static struct cmd_t command_defs[] = CMD_NOTAGS CMD_SYN( "/plugins", + "/plugins install ", "/plugins unload ", "/plugins load ", "/plugins reload []") CMD_DESC( "Manage plugins. Passing no arguments lists currently loaded plugins.") CMD_ARGS( - { "load ", "Load a plugin." }, - { "unload ", "Unload a plugin." }, + { "install ", "Install file to plugins directory, and load or reload the plugin." }, + { "load ", "Load a plugin that already exists in the plugin directory." }, + { "unload ", "Unload a loaded plugin." }, { "reload []", "Reload a plugin, passing no argument will reload all plugins" }) CMD_EXAMPLES( + "/plugin install /home/steveharris/Downloads/metal.py", "/plugin load browser.py", "/plugin unload say.py", "/plugin reload wikipedia.py") diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index fcce7028..05de90a5 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -6025,7 +6025,50 @@ cmd_xa(ProfWin *window, const char *const command, gchar **args) gboolean cmd_plugins(ProfWin *window, const char *const command, gchar **args) { - if (g_strcmp0(args[0], "load") == 0) { + if (g_strcmp0(args[0], "install") == 0) { + char *filename = args[1]; + if (filename == NULL) { + cons_bad_cmd_usage(command); + return TRUE; + } + + // expand ~ to $HOME + if (filename[0] == '~' && filename[1] == '/') { + if (asprintf(&filename, "%s/%s", getenv("HOME"), filename+2) == -1) { + return TRUE; + } + } else { + filename = strdup(filename); + } + + if (access(filename, R_OK) != 0) { + cons_show("File not found: %s", filename); + free(filename); + return TRUE; + } + + if (!is_regular_file(filename)) { + cons_show("Not a file: %s", filename); + free(filename); + return TRUE; + } + + if (!g_str_has_suffix(filename, ".py") && !g_str_has_suffix(filename, ".so")) { + cons_show("Plugins must have one of the following extensions: '.py' '.so'"); + free(filename); + return TRUE; + } + + char *plugin_name = basename(filename); + gboolean result = plugins_install(plugin_name, filename); + if (result) { + cons_show("Plugin installed, use '/plugin load %s' to enable the plugin.", plugin_name); + } else { + cons_show("Failed to install plugin: %s", plugin_name); + } + + return TRUE; + } else if (g_strcmp0(args[0], "load") == 0) { if (args[1] == NULL) { cons_bad_cmd_usage(command); return TRUE; diff --git a/src/common.c b/src/common.c index 13a2366c..efa459de 100644 --- a/src/common.c +++ b/src/common.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -155,6 +156,31 @@ mkdir_recursive(const char *dir) return result; } +gboolean +copy_file(const char *const sourcepath, const char *const targetpath) +{ + int ch; + FILE *source = fopen(sourcepath, "rb"); + if (source == NULL) { + return FALSE; + } + + FILE *target = fopen(targetpath, "wb"); + if (target == NULL) { + fclose(source); + return FALSE; + } + + while((ch = fgetc(source)) != EOF) { + fputc(ch, target); + } + + fclose(source); + fclose(target); + + return TRUE; +} + char* str_replace(const char *string, const char *substr, const char *replacement) diff --git a/src/common.h b/src/common.h index c67b1460..ca6900dc 100644 --- a/src/common.h +++ b/src/common.h @@ -102,6 +102,7 @@ gboolean p_hash_table_contains(GHashTable *hash_table, gconstpointer key); gboolean create_dir(char *name); gboolean mkdir_recursive(const char *dir); +gboolean copy_file(const char *const src, const char *const target); char* str_replace(const char *string, const char *substr, const char *replacement); int str_contains(const char str[], int size, char ch); gboolean strtoi_range(char *str, int *saveptr, int min, int max, char **err_msg); diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 24eb40d2..5096bdee 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -62,6 +62,8 @@ static GHashTable *plugins; +static gchar* _get_plugins_dir(void); + void plugins_init(void) { @@ -128,6 +130,30 @@ plugins_init(void) return; } +gboolean +plugins_install(const char *const plugin_name, const char *const filename) +{ + char *plugins_dir = _get_plugins_dir(); + GString *target_path = g_string_new(plugins_dir); + free(plugins_dir); + g_string_append(target_path, "/"); + g_string_append(target_path, plugin_name); + + ProfPlugin *plugin = g_hash_table_lookup(plugins, plugin_name); + if (plugin) { + plugins_unload(plugin_name); + } + + gboolean result = copy_file(filename, target_path->str); + g_string_free(target_path, TRUE); + + if (result) { + result = plugins_load(plugin_name); + } + + return result; +} + gboolean plugins_load(const char *const name) { diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index fc10c363..28f00ab4 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -105,6 +105,7 @@ char* plugins_autocomplete(const char *const input); void plugins_reset_autocomplete(void); void plugins_shutdown(void); +gboolean plugins_install(const char *const plugin_name, const char *const filename); gboolean plugins_load(const char *const name); gboolean plugins_unload(const char *const name); gboolean plugins_reload(const char *const name);