about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorJames Booth <boothj5@gmail.com>2016-07-12 23:50:21 +0100
committerJames Booth <boothj5@gmail.com>2016-07-12 23:50:21 +0100
commit0991699ae65387dc67852a3f9d465de25d6067a0 (patch)
tree93ac5aab454e6d2b7a281deb0441965c5242f47a /src
parent5f393a6d9f995a9be86923f24e8b634a7a9d4ed9 (diff)
downloadprofani-tty-0991699ae65387dc67852a3f9d465de25d6067a0.tar.gz
Add /plugins install command
Diffstat (limited to 'src')
-rw-r--r--src/command/cmd_ac.c218
-rw-r--r--src/command/cmd_defs.c7
-rw-r--r--src/command/cmd_funcs.c45
-rw-r--r--src/common.c26
-rw-r--r--src/common.h1
-rw-r--r--src/plugins/plugins.c26
-rw-r--r--src/plugins/plugins.h1
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 <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;
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 <assert.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -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)
 {
@@ -129,6 +131,30 @@ plugins_init(void)
 }
 
 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)
 {
     ProfPlugin *plugin = g_hash_table_lookup(plugins, 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);