From a01eb5d08e1b39d60a6f8fc26e5a87ceb92ec18f Mon Sep 17 00:00:00 2001 From: James Booth Date: Wed, 29 Jun 2016 23:35:57 +0100 Subject: [PATCH] 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) {}