about summary refs log tree commit diff stats
path: root/src/command
diff options
context:
space:
mode:
Diffstat (limited to 'src/command')
-rw-r--r--src/command/cmd_ac.c218
-rw-r--r--src/command/cmd_defs.c7
-rw-r--r--src/command/cmd_funcs.c45
3 files changed, 164 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 <path>",
             "/plugins unload <plugin>",
             "/plugins load <plugin>",
             "/plugins reload [<plugin>]")
         CMD_DESC(
             "Manage plugins. Passing no arguments lists currently loaded plugins.")
         CMD_ARGS(
-            { "load <plugin>",       "Load a plugin." },
-            { "unload <plugin>",     "Unload a plugin." },
+            { "install <file>",      "Install file to plugins directory, and load or reload the plugin." },
+            { "load <plugin>",       "Load a plugin that already exists in the plugin directory." },
+            { "unload <plugin>",     "Unload a loaded plugin." },
             { "reload [<plugin>]",   "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;