From a9fab9ed2dc75671e61a6d44ba0ea5c861eeb5dc Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 5 Feb 2017 18:54:33 +0000 Subject: [PATCH 1/6] Allow unloading all plugins --- src/command/cmd_defs.c | 11 +- src/command/cmd_funcs.c | 242 ++++++++++++++++++++++------------------ src/command/cmd_funcs.h | 7 ++ src/plugins/plugins.c | 21 ++++ src/plugins/plugins.h | 1 + 5 files changed, 168 insertions(+), 114 deletions(-) diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index fb33dac9..eb5eca01 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -2047,13 +2047,18 @@ static struct cmd_t command_defs[] = { "/plugins", parse_args, 0, 2, NULL, - CMD_NOSUBFUNCS + CMD_SUBFUNCS( + { "install", cmd_plugins_install }, + { "load", cmd_plugins_load }, + { "unload", cmd_plugins_unload }, + { "reload", cmd_plugins_reload }, + { "python_version", cmd_plugins_python_version }) CMD_MAINFUNC(cmd_plugins) CMD_NOTAGS CMD_SYN( "/plugins", "/plugins install ", - "/plugins unload ", + "/plugins unload []", "/plugins load ", "/plugins reload []", "/plugins python_version") @@ -2062,7 +2067,7 @@ static struct cmd_t command_defs[] = CMD_ARGS( { "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." }, + { "unload []", "Unload a loaded plugin, passing no argument will unload all plugins." }, { "reload []", "Reload a plugin, passing no argument will reload all plugins." }, { "python_version", "Show the Python interpreter version." }) CMD_EXAMPLES( diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index b8657e59..6f238612 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -6212,120 +6212,140 @@ cmd_xa(ProfWin *window, const char *const command, gchar **args) } gboolean -cmd_plugins(ProfWin *window, const char *const command, gchar **args) +cmd_plugins_install(ProfWin *window, const char *const command, gchar **args) { - 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; - } - - gchar *plugin_name = g_path_get_basename(filename); - gboolean result = plugins_install(plugin_name, filename); - if (result) { - cons_show("Plugin installed: %s", plugin_name); - } else { - cons_show("Failed to install plugin: %s", plugin_name); - } - g_free(plugin_name); - - free(filename); - return TRUE; - } else if (g_strcmp0(args[0], "load") == 0) { - if (args[1] == NULL) { - cons_bad_cmd_usage(command); - return TRUE; - } - gboolean res = plugins_load(args[1]); - if (res) { - cons_show("Loaded plugin: %s", args[1]); - } else { - 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) { - cons_show("Unloaded plugin: %s", args[1]); - } else { - cons_show("Failed to unload plugin: %s", args[1]); - } - - return TRUE; - } else if (g_strcmp0(args[0], "reload") == 0) { - if (args[1] == NULL) { - plugins_reload_all(); - cons_show("Reloaded all plugins"); - } else { - 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 if (g_strcmp0(args[0], "python_version") == 0) { -#ifdef HAVE_PYTHON - const char *version = python_get_version(); - cons_show("Python version:"); - cons_show("%s", version); -#else - cons_show("This build does not support pytyon plugins."); -#endif - return TRUE; - - } else { - GList *plugins = plugins_loaded_list(); - if (plugins == NULL) { - cons_show("No plugins installed."); - return TRUE; - } - - GList *curr = plugins; - cons_show("Installed plugins:"); - while (curr) { - cons_show(" %s", curr->data); - curr = g_list_next(curr); - } - g_list_free(plugins); - + 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; + } + + gchar *plugin_name = g_path_get_basename(filename); + gboolean result = plugins_install(plugin_name, filename); + if (result) { + cons_show("Plugin installed: %s", plugin_name); + } else { + cons_show("Failed to install plugin: %s", plugin_name); + } + g_free(plugin_name); + + free(filename); + return TRUE; +} + +gboolean +cmd_plugins_load(ProfWin *window, const char *const command, gchar **args) +{ + if (args[1] == NULL) { + cons_bad_cmd_usage(command); + return TRUE; + } + gboolean res = plugins_load(args[1]); + if (res) { + cons_show("Loaded plugin: %s", args[1]); + } else { + cons_show("Failed to load plugin: %s", args[1]); + } + + return TRUE; +} + +gboolean +cmd_plugins_unload(ProfWin *window, const char *const command, gchar **args) +{ + if (args[1] == NULL) { + plugins_unload_all(); + cons_show("Unloaded all plugins"); + return TRUE; + } + + gboolean res = plugins_unload(args[1]); + if (res) { + cons_show("Unloaded plugin: %s", args[1]); + } else { + cons_show("Failed to unload plugin: %s", args[1]); + } + + return TRUE; +} + +gboolean +cmd_plugins_reload(ProfWin *window, const char *const command, gchar **args) +{ + if (args[1] == NULL) { + plugins_reload_all(); + cons_show("Reloaded all plugins"); + 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; +} + +gboolean +cmd_plugins_python_version(ProfWin *window, const char *const command, gchar **args) +{ +#ifdef HAVE_PYTHON + const char *version = python_get_version(); + cons_show("Python version:"); + cons_show("%s", version); +#else + cons_show("This build does not support pytyon plugins."); +#endif + return TRUE; +} + +gboolean +cmd_plugins(ProfWin *window, const char *const command, gchar **args) +{ + GList *plugins = plugins_loaded_list(); + if (plugins == NULL) { + cons_show("No plugins installed."); + return TRUE; + } + + 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; } gboolean diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h index b16c187a..c7a89e43 100644 --- a/src/command/cmd_funcs.h +++ b/src/command/cmd_funcs.h @@ -158,7 +158,14 @@ gboolean cmd_script(ProfWin *window, const char *const command, gchar **args); gboolean cmd_export(ProfWin *window, const char *const command, gchar **args); gboolean cmd_charset(ProfWin *window, const char *const command, gchar **args); gboolean cmd_console(ProfWin *window, const char *const command, gchar **args); + gboolean cmd_plugins(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_plugins_install(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_plugins_load(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_plugins_unload(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_plugins_reload(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_plugins_python_version(ProfWin *window, const char *const command, gchar **args); + gboolean cmd_blocked(ProfWin *window, const char *const command, gchar **args); gboolean cmd_account(ProfWin *window, const char *const command, gchar **args); diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 5b4de8a0..c9e37c15 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -190,6 +190,27 @@ plugins_load(const char *const name) } } +void +plugins_unload_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_unload(curr->data); + curr = g_list_next(curr); + } + + g_list_free_full(plugin_names_dup, free); +} + gboolean plugins_unload(const char *const name) { diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index a899bde3..8762556e 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -110,6 +110,7 @@ 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); +void plugins_unload_all(void); gboolean plugins_reload(const char *const name); void plugins_reload_all(void); From dd42c3de6af29f1a59aa890ee0dae92f71efa23b Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 5 Feb 2017 19:16:14 +0000 Subject: [PATCH 2/6] Allow loading all plugins --- src/command/cmd_funcs.c | 22 +++++++++++++++++++--- src/plugins/plugins.c | 26 ++++++++++++++++++++++++-- src/plugins/plugins.h | 3 ++- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 6f238612..7f854249 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -6264,9 +6264,21 @@ gboolean cmd_plugins_load(ProfWin *window, const char *const command, gchar **args) { if (args[1] == NULL) { - cons_bad_cmd_usage(command); + GSList *loaded = plugins_load_all(); + if (loaded) { + cons_show("Loaded plugins:"); + GSList *curr = loaded; + while (curr) { + cons_show(" %s", curr->data); + curr = g_slist_next(curr); + } + g_slist_free_full(loaded, g_free); + } else { + cons_show("No plugins loaded."); + } return TRUE; } + gboolean res = plugins_load(args[1]); if (res) { cons_show("Loaded plugin: %s", args[1]); @@ -6281,8 +6293,12 @@ gboolean cmd_plugins_unload(ProfWin *window, const char *const command, gchar **args) { if (args[1] == NULL) { - plugins_unload_all(); - cons_show("Unloaded all plugins"); + gboolean res = plugins_unload_all(); + if (res) { + cons_show("Unloaded all plugins."); + } else { + cons_show("No plugins unloaded."); + } return TRUE; } diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index c9e37c15..4896fedb 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -153,6 +153,23 @@ plugins_install(const char *const plugin_name, const char *const filename) return result; } +GSList* +plugins_load_all(void) +{ + GSList *plugins = plugins_unloaded_list(); + GSList *loaded = NULL; + GSList *curr = plugins; + while (curr) { + if (plugins_load(curr->data)) { + loaded = g_slist_append(loaded, strdup(curr->data)); + } + curr = g_slist_next(curr); + } + g_slist_free_full(plugins, g_free); + + return loaded; +} + gboolean plugins_load(const char *const name) { @@ -190,9 +207,10 @@ plugins_load(const char *const name) } } -void +gboolean plugins_unload_all(void) { + gboolean result = FALSE; GList *plugin_names = g_hash_table_get_keys(plugins); GList *plugin_names_dup = NULL; GList *curr = plugin_names; @@ -204,11 +222,15 @@ plugins_unload_all(void) curr = plugin_names_dup; while (curr) { - plugins_unload(curr->data); + if (plugins_unload(curr->data)) { + result = TRUE; + } curr = g_list_next(curr); } g_list_free_full(plugin_names_dup, free); + + return result; } gboolean diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index 8762556e..502af806 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -109,8 +109,9 @@ void plugins_shutdown(void); gboolean plugins_install(const char *const plugin_name, const char *const filename); gboolean plugins_load(const char *const name); +GSList* plugins_load_all(void); gboolean plugins_unload(const char *const name); -void plugins_unload_all(void); +gboolean plugins_unload_all(void); gboolean plugins_reload(const char *const name); void plugins_reload_all(void); From c405367dfeb3c23bac192a170501e569be934f26 Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 5 Feb 2017 19:23:16 +0000 Subject: [PATCH 3/6] Update plugins help --- src/command/cmd_defs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index eb5eca01..2ca3b967 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -2059,14 +2059,14 @@ static struct cmd_t command_defs[] = "/plugins", "/plugins install ", "/plugins unload []", - "/plugins load ", + "/plugins load []", "/plugins reload []", "/plugins python_version") CMD_DESC( "Manage plugins. Passing no arguments lists currently loaded plugins.") CMD_ARGS( { "install ", "Install file to plugins directory, and load or reload the plugin." }, - { "load ", "Load a plugin that already exists in the plugin directory." }, + { "load []", "Load a plugin that already exists in the plugin directory, passing no argument loads all found plugins." }, { "unload []", "Unload a loaded plugin, passing no argument will unload all plugins." }, { "reload []", "Reload a plugin, passing no argument will reload all plugins." }, { "python_version", "Show the Python interpreter version." }) From 286fecf38d218d10366f025faf7cffcb425e19f4 Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 5 Feb 2017 21:09:03 +0000 Subject: [PATCH 4/6] Allow installing plugins from directory --- src/command/cmd_funcs.c | 76 ++++++++++++++++-------- src/common.c | 42 +++++++++++++ src/common.h | 4 ++ src/plugins/plugins.c | 37 ++++++++++++ src/plugins/plugins.h | 8 +++ src/tools/http_upload.c | 8 +-- src/tools/http_upload.h | 1 - tests/unittests/tools/stub_http_upload.c | 1 - 8 files changed, 144 insertions(+), 33 deletions(-) diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 7f854249..d26ff43f 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -6214,49 +6214,77 @@ cmd_xa(ProfWin *window, const char *const command, gchar **args) gboolean cmd_plugins_install(ProfWin *window, const char *const command, gchar **args) { - char *filename = args[1]; - if (filename == NULL) { + char *path = args[1]; + if (path == 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) { + if (path[0] == '~' && path[1] == '/') { + if (asprintf(&path, "%s/%s", getenv("HOME"), path+2) == -1) { return TRUE; } } else { - filename = strdup(filename); + path = strdup(path); } - if (access(filename, R_OK) != 0) { - cons_show("File not found: %s", filename); - free(filename); + if (access(path, R_OK) != 0) { + cons_show("File not found: %s", path); + free(path); return TRUE; } - if (!is_regular_file(filename)) { - cons_show("Not a file: %s", filename); - free(filename); + if (is_regular_file(path)) { + if (!g_str_has_suffix(path, ".py") && !g_str_has_suffix(path, ".so")) { + cons_show("Plugins must have one of the following extensions: '.py' '.so'"); + free(path); + return TRUE; + } + + gchar *plugin_name = g_path_get_basename(path); + gboolean result = plugins_install(plugin_name, path); + if (result) { + cons_show("Plugin installed: %s", plugin_name); + } else { + cons_show("Failed to install plugin: %s", plugin_name); + } + g_free(plugin_name); + + free(path); 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); + if (is_dir(path)) { + PluginsInstallResult* result = plugins_install_all(path); + if (result->installed || result->failed) { + if (result->installed) { + cons_show(""); + cons_show("Installed plugins:"); + GSList *curr = result->installed; + while (curr) { + cons_show(" %s", curr->data); + curr = g_slist_next(curr); + } + } + if (result->failed) { + cons_show(""); + cons_show("Failed installs:"); + GSList *curr = result->failed; + while (curr) { + cons_show(" %s", curr->data); + curr = g_slist_next(curr); + } + } + } else { + cons_show("No plugins found in: %s", path); + } + free(path); + plugins_free_install_result(result); return TRUE; } - gchar *plugin_name = g_path_get_basename(filename); - gboolean result = plugins_install(plugin_name, filename); - if (result) { - cons_show("Plugin installed: %s", plugin_name); - } else { - cons_show("Failed to install plugin: %s", plugin_name); - } - g_free(plugin_name); - - free(filename); + cons_show("Argument must be a file or directory."); return TRUE; } diff --git a/src/common.c b/src/common.c index ef7129cd..898f62fa 100644 --- a/src/common.c +++ b/src/common.c @@ -536,3 +536,45 @@ prof_occurrences(const char *const needle, const char *const haystack, int offse return *result; } +int +is_regular_file(const char *path) +{ + struct stat st; + stat(path, &st); + return S_ISREG(st.st_mode); +} + +int +is_dir(const char *path) +{ + struct stat st; + stat(path, &st); + return S_ISDIR(st.st_mode); +} + +void +get_file_paths_recursive(const char *path, GSList **contents) +{ + if (!is_dir(path)) { + return; + } + + GDir* directory = g_dir_open(path, 0, NULL); + const gchar *entry = g_dir_read_name(directory); + while (entry) { + GString *full = g_string_new(path); + if (!g_str_has_suffix(full->str, "/")) { + g_string_append(full, "/"); + } + g_string_append(full, entry); + + if (is_dir(full->str)) { + get_file_paths_recursive(full->str, contents); + } else if (is_regular_file(full->str)) { + *contents = g_slist_append(*contents, full->str); + } + + g_string_free(full, FALSE); + entry = g_dir_read_name(directory); + } +} diff --git a/src/common.h b/src/common.h index c2317390..8c42ae52 100644 --- a/src/common.h +++ b/src/common.h @@ -123,4 +123,8 @@ gboolean is_notify_enabled(void); GSList* prof_occurrences(const char *const needle, const char *const haystack, int offset, gboolean whole_word, GSList **result); +int is_regular_file(const char *path); +int is_dir(const char *path); +void get_file_paths_recursive(const char *directory, GSList **contents); + #endif diff --git a/src/plugins/plugins.c b/src/plugins/plugins.c index 4896fedb..92d605e8 100644 --- a/src/plugins/plugins.c +++ b/src/plugins/plugins.c @@ -129,6 +129,43 @@ plugins_init(void) return; } +void +plugins_free_install_result(PluginsInstallResult *result) +{ + if (!result) { + return; + } + g_slist_free_full(result->installed, free); + g_slist_free_full(result->failed, free); +} + +PluginsInstallResult* +plugins_install_all(const char *const path) +{ + PluginsInstallResult *result = malloc(sizeof(PluginsInstallResult)); + result->installed = NULL; + result->failed = NULL; + GSList *contents = NULL; + get_file_paths_recursive(path, &contents); + + GSList *curr = contents; + while (curr) { + if (g_str_has_suffix(curr->data, ".py") || g_str_has_suffix(curr->data, ".so")) { + gchar *plugin_name = g_path_get_basename(curr->data); + if (plugins_install(plugin_name, curr->data)) { + result->installed = g_slist_append(result->installed, strdup(curr->data)); + } else { + result->failed = g_slist_append(result->failed, strdup(curr->data)); + } + } + curr = g_slist_next(curr); + } + + g_slist_free_full(contents, g_free); + + return result; +} + gboolean plugins_install(const char *const plugin_name, const char *const filename) { diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h index 502af806..af659757 100644 --- a/src/plugins/plugins.h +++ b/src/plugins/plugins.h @@ -42,6 +42,11 @@ typedef enum { LANG_C } lang_t; +typedef struct prof_plugins_install_t { + GSList *installed; + GSList *failed; +} PluginsInstallResult; + typedef struct prof_plugin_t { char *name; lang_t lang; @@ -107,7 +112,10 @@ char* plugins_autocomplete(const char *const input); void plugins_reset_autocomplete(void); void plugins_shutdown(void); +void plugins_free_install_result(PluginsInstallResult *result); + gboolean plugins_install(const char *const plugin_name, const char *const filename); +PluginsInstallResult* plugins_install_all(const char *const path); gboolean plugins_load(const char *const name); GSList* plugins_load_all(void); gboolean plugins_unload(const char *const name); diff --git a/src/tools/http_upload.c b/src/tools/http_upload.c index c1ac9fdf..6e5dd27c 100644 --- a/src/tools/http_upload.c +++ b/src/tools/http_upload.c @@ -52,6 +52,7 @@ #include "config/preferences.h" #include "ui/ui.h" #include "ui/window.h" +#include "common.h" #define FALLBACK_MIMETYPE "application/octet-stream" #define FALLBACK_CONTENTTYPE_HEADER "Content-Type: application/octet-stream" @@ -330,10 +331,3 @@ off_t file_size(const char* const filename) stat(filename, &st); return st.st_size; } - -int is_regular_file(const char *filename) -{ - struct stat st; - stat(filename, &st); - return S_ISREG(st.st_mode); -} diff --git a/src/tools/http_upload.h b/src/tools/http_upload.h index 15281fa5..ae8f8223 100644 --- a/src/tools/http_upload.h +++ b/src/tools/http_upload.h @@ -62,6 +62,5 @@ void* http_file_put(void *userdata); char* file_mime_type(const char* const file_name); off_t file_size(const char* const file_name); -int is_regular_file(const char *filename); #endif diff --git a/tests/unittests/tools/stub_http_upload.c b/tests/unittests/tools/stub_http_upload.c index c0b4e979..508d3f8b 100644 --- a/tests/unittests/tools/stub_http_upload.c +++ b/tests/unittests/tools/stub_http_upload.c @@ -24,6 +24,5 @@ void* http_file_put(void *userdata) {} char* file_mime_type(const char* const file_name) {} off_t file_size(const char* const file_name) {} -int is_regular_file(const char *filename) {} #endif From 5f1ba08f5500646fb92df8d4b9920eac987bc11a Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 5 Feb 2017 22:37:48 +0000 Subject: [PATCH 5/6] Add plugins sourcepath property --- src/command/cmd_ac.c | 18 +++++++++++ src/command/cmd_defs.c | 21 ++++++++----- src/command/cmd_funcs.c | 65 ++++++++++++++++++++++++++++++++++++---- src/command/cmd_funcs.h | 1 + src/config/preferences.c | 15 ++++++---- src/config/preferences.h | 1 + 6 files changed, 103 insertions(+), 18 deletions(-) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 56baafc8..544719d4 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -184,6 +184,7 @@ static Autocomplete console_ac; static Autocomplete console_msg_ac; static Autocomplete autoping_ac; static Autocomplete plugins_ac; +static Autocomplete plugins_sourcepath_ac; static Autocomplete plugins_load_ac; static Autocomplete plugins_unload_ac; static Autocomplete plugins_reload_ac; @@ -714,6 +715,11 @@ cmd_ac_init(void) autocomplete_add(plugins_ac, "unload"); autocomplete_add(plugins_ac, "reload"); autocomplete_add(plugins_ac, "python_version"); + autocomplete_add(plugins_ac, "sourcepath"); + + plugins_sourcepath_ac = autocomplete_new(); + autocomplete_add(plugins_sourcepath_ac, "set"); + autocomplete_add(plugins_sourcepath_ac, "clear"); filepath_ac = autocomplete_new(); @@ -1011,6 +1017,7 @@ cmd_ac_reset(ProfWin *window) autocomplete_reset(console_msg_ac); autocomplete_reset(autoping_ac); autocomplete_reset(plugins_ac); + autocomplete_reset(plugins_sourcepath_ac); autocomplete_reset(blocked_ac); autocomplete_reset(tray_ac); autocomplete_reset(presence_ac); @@ -2025,10 +2032,21 @@ _plugins_autocomplete(ProfWin *window, const char *const input) { char *result = NULL; + if (strncmp(input, "/plugins sourcepath set ", 24) == 0) { + return cmd_ac_complete_filepath(input, "/plugins sourcepath set"); + } + if (strncmp(input, "/plugins install ", 17) == 0) { return cmd_ac_complete_filepath(input, "/plugins install"); } + if (strncmp(input, "/plugins sourcepath ", 20) == 0) { + result = autocomplete_param_with_ac(input, "/plugins sourcepath", plugins_sourcepath_ac, TRUE); + if (result) { + return result; + } + } + if (strncmp(input, "/plugins load ", 14) == 0) { if (plugins_load_ac == NULL) { plugins_load_ac = autocomplete_new(); diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 2ca3b967..8f8ced09 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -2046,8 +2046,9 @@ static struct cmd_t command_defs[] = }, { "/plugins", - parse_args, 0, 2, NULL, + parse_args, 0, 3, NULL, CMD_SUBFUNCS( + { "sourcepath", cmd_plugins_sourcepath }, { "install", cmd_plugins_install }, { "load", cmd_plugins_load }, { "unload", cmd_plugins_unload }, @@ -2057,7 +2058,9 @@ static struct cmd_t command_defs[] = CMD_NOTAGS CMD_SYN( "/plugins", - "/plugins install ", + "/plugins sourcepath set ", + "/plugins sourcepath clear", + "/plugins install []", "/plugins unload []", "/plugins load []", "/plugins reload []", @@ -2065,12 +2068,16 @@ static struct cmd_t command_defs[] = CMD_DESC( "Manage plugins. Passing no arguments lists currently loaded plugins.") CMD_ARGS( - { "install ", "Install file to plugins directory, and load or reload the plugin." }, - { "load []", "Load a plugin that already exists in the plugin directory, passing no argument loads all found plugins." }, - { "unload []", "Unload a loaded plugin, passing no argument will unload all plugins." }, - { "reload []", "Reload a plugin, passing no argument will reload all plugins." }, - { "python_version", "Show the Python interpreter version." }) + { "sourcepath set ", "Set the default path to install plugins from, will be used if no arg is passed to /plugins install." }, + { "sourcepath clear", "Clear the default plugins source path." }, + { "install []", "Install a plugin, or all plugins found in a directory (recursive). Passing no argument will use the sourcepath if one is set." }, + { "load []", "Load a plugin that already exists in the plugin directory, passing no argument loads all found plugins." }, + { "unload []", "Unload a loaded plugin, passing no argument will unload all plugins." }, + { "reload []", "Reload a plugin, passing no argument will reload all plugins." }, + { "python_version", "Show the Python interpreter version." }) CMD_EXAMPLES( + "/plugins sourcepath set /home/meee/projects/profanity-plugins", + "/plugins install", "/plugins install /home/steveharris/Downloads/metal.py", "/plugins load browser.py", "/plugins unload say.py", diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index d26ff43f..3df17079 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -6211,17 +6211,70 @@ cmd_xa(ProfWin *window, const char *const command, gchar **args) return TRUE; } +gboolean +cmd_plugins_sourcepath(ProfWin *window, const char *const command, gchar **args) +{ + if (args[1] == NULL) { + char *sourcepath = prefs_get_string(PREF_PLUGINS_SOURCEPATH); + if (sourcepath) { + cons_show("Current plugins sourcepath: %s", sourcepath); + prefs_free_string(sourcepath); + } else { + cons_show("Plugins sourcepath not currently set."); + } + return TRUE; + } + + if (g_strcmp0(args[1], "clear") == 0) { + prefs_set_string(PREF_PLUGINS_SOURCEPATH, NULL); + cons_show("Plugins sourcepath cleared."); + return TRUE; + } + + if (g_strcmp0(args[1], "set") == 0) { + char *path = args[2]; + if (path == NULL) { + cons_bad_cmd_usage(command); + return TRUE; + } + + // expand ~ to $HOME + if (path[0] == '~' && path[1] == '/') { + if (asprintf(&path, "%s/%s", getenv("HOME"), path+2) == -1) { + return TRUE; + } + } else { + path = strdup(path); + } + + if (!is_dir(path)) { + cons_show("Plugins sourcepath must be a directory."); + return TRUE; + } + + cons_show("Setting plugins sourcepath: %s", path); + prefs_set_string(PREF_PLUGINS_SOURCEPATH, path); + return TRUE; + } + + cons_bad_cmd_usage(command); + return TRUE; +} + gboolean cmd_plugins_install(ProfWin *window, const char *const command, gchar **args) { char *path = args[1]; if (path == NULL) { - cons_bad_cmd_usage(command); - return TRUE; - } - - // expand ~ to $HOME - if (path[0] == '~' && path[1] == '/') { + char* sourcepath = prefs_get_string(PREF_PLUGINS_SOURCEPATH); + if (sourcepath) { + path = strdup(sourcepath); + prefs_free_string(sourcepath); + } else { + cons_show("Either a path must be provided or the sourcepath property must be set, see /help plugins"); + return TRUE; + } + } else if (path[0] == '~' && path[1] == '/') { if (asprintf(&path, "%s/%s", getenv("HOME"), path+2) == -1) { return TRUE; } diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h index c7a89e43..2f0e0bac 100644 --- a/src/command/cmd_funcs.h +++ b/src/command/cmd_funcs.h @@ -160,6 +160,7 @@ gboolean cmd_charset(ProfWin *window, const char *const command, gchar **args); gboolean cmd_console(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_plugins_sourcepath(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins_install(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins_load(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins_unload(ProfWin *window, const char *const command, gchar **args); diff --git a/src/config/preferences.c b/src/config/preferences.c index f759da35..6dc8ef32 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -59,6 +59,7 @@ #define PREF_GROUP_OTR "otr" #define PREF_GROUP_PGP "pgp" #define PREF_GROUP_MUC "muc" +#define PREF_GROUP_PLUGINS "plugins" #define INPBLOCK_DEFAULT 1000 @@ -665,27 +666,27 @@ prefs_get_tray_timer(void) gchar** prefs_get_plugins(void) { - if (!g_key_file_has_group(prefs, "plugins")) { + if (!g_key_file_has_group(prefs, PREF_GROUP_PLUGINS)) { return NULL; } - if (!g_key_file_has_key(prefs, "plugins", "load", NULL)) { + if (!g_key_file_has_key(prefs, PREF_GROUP_PLUGINS, "load", NULL)) { return NULL; } - return g_key_file_get_string_list(prefs, "plugins", "load", NULL, NULL); + return g_key_file_get_string_list(prefs, PREF_GROUP_PLUGINS, "load", NULL, NULL); } void prefs_add_plugin(const char *const name) { - conf_string_list_add(prefs, "plugins", "load", name); + conf_string_list_add(prefs, PREF_GROUP_PLUGINS, "load", name); _save_prefs(); } void prefs_remove_plugin(const char *const name) { - conf_string_list_remove(prefs, "plugins", "load", name); + conf_string_list_remove(prefs, PREF_GROUP_PLUGINS, "load", name); _save_prefs(); } @@ -1614,6 +1615,8 @@ _get_group(preference_t pref) return PREF_GROUP_PGP; case PREF_BOOKMARK_INVITE: return PREF_GROUP_MUC; + case PREF_PLUGINS_SOURCEPATH: + return PREF_GROUP_PLUGINS; default: return NULL; } @@ -1814,6 +1817,8 @@ _get_key(preference_t pref) return "console.chat"; case PREF_BOOKMARK_INVITE: return "bookmark.invite"; + case PREF_PLUGINS_SOURCEPATH: + return "sourcepath"; default: return NULL; } diff --git a/src/config/preferences.h b/src/config/preferences.h index dbc74148..cc605c79 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -141,6 +141,7 @@ typedef enum { PREF_CONSOLE_PRIVATE, PREF_CONSOLE_CHAT, PREF_BOOKMARK_INVITE, + PREF_PLUGINS_SOURCEPATH, } preference_t; typedef struct prof_alias_t { From 1242fb7f71e32426e09e9c1dcb61aa398fc41209 Mon Sep 17 00:00:00 2001 From: James Booth Date: Tue, 7 Feb 2017 23:39:25 +0000 Subject: [PATCH 6/6] Include CHANGELOG and README.md in package fixes #904 --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index b8424856..e3b72b86 100644 --- a/Makefile.am +++ b/Makefile.am @@ -245,7 +245,7 @@ endif man_MANS = $(man_sources) -EXTRA_DIST = $(man_sources) $(icons_sources) $(themes_sources) $(script_sources) profrc.example LICENSE.txt +EXTRA_DIST = $(man_sources) $(icons_sources) $(themes_sources) $(script_sources) profrc.example LICENSE.txt README.md CHANGELOG if INCLUDE_GIT_VERSION EXTRA_DIST += .git/HEAD .git/index