about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--configure.ac10
-rw-r--r--src/command/cmd_defs.c8
-rw-r--r--src/command/cmd_funcs.c89
-rw-r--r--src/command/cmd_funcs.h2
-rw-r--r--src/common.c31
-rw-r--r--src/common.h2
-rw-r--r--src/plugins/plugins.c37
-rw-r--r--src/plugins/plugins.h4
8 files changed, 147 insertions, 36 deletions
diff --git a/configure.ac b/configure.ac
index 5f85c83a..8f79a711 100644
--- a/configure.ac
+++ b/configure.ac
@@ -159,9 +159,13 @@ CFLAGS="$CFLAGS_RESTORE"
 AS_IF([test "x$ncurses_cv_wget_wch" != xyes],
     [AC_MSG_ERROR([ncurses does not support wide characters])])
 
-### Check for other profanity dependencies
+### Check for glib libraries
 PKG_CHECK_MODULES([glib], [glib-2.0 >= 2.40], [],
     [AC_MSG_ERROR([glib 2.40 or higher is required for profanity])])
+PKG_CHECK_MODULES([gio], [gio-2.0], [],
+    [AC_MSG_ERROR([libgio-2.0 from glib-2.0 is required for profanity])])
+
+### Check for other profanity dependencies
 PKG_CHECK_MODULES([curl], [libcurl], [],
     [AC_CHECK_LIB([curl], [main], [],
         [AC_MSG_ERROR([libcurl is required for profanity])])])
@@ -297,9 +301,9 @@ AS_IF([test "x$PACKAGE_STATUS" = xdevelopment],
 AS_IF([test "x$PLATFORM" = xosx],
     [AM_CFLAGS="$AM_CFLAGS -Qunused-arguments"])
 AM_LDFLAGS="$AM_LDFLAGS -export-dynamic"
-AM_CPPFLAGS="$AM_CPPFLAGS $glib_CFLAGS $curl_CFLAGS $libnotify_CFLAGS $PYTHON_CPPFLAGS ${GTK_CFLAGS}"
+AM_CPPFLAGS="$AM_CPPFLAGS $glib_CFLAGS $gio_CFLAGS $curl_CFLAGS $libnotify_CFLAGS $PYTHON_CPPFLAGS ${GTK_CFLAGS}"
 AM_CPPFLAGS="$AM_CPPFLAGS -DTHEMES_PATH=\"\\\"$THEMES_PATH\\\"\" -DICONS_PATH=\"\\\"$ICONS_PATH\\\"\""
-LIBS="$glib_LIBS $curl_LIBS $libnotify_LIBS $PYTHON_LIBS $PYTHON_LDFLAGS ${GTK_LIBS} -lgio-2.0 $LIBS"
+LIBS="$glib_LIBS $gio_LIBS $curl_LIBS $libnotify_LIBS $PYTHON_LIBS $PYTHON_LDFLAGS ${GTK_LIBS} $LIBS"
 
 AC_SUBST(AM_LDFLAGS)
 AC_SUBST(AM_CFLAGS)
diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c
index a523c939..ee320e84 100644
--- a/src/command/cmd_defs.c
+++ b/src/command/cmd_defs.c
@@ -2084,6 +2084,8 @@ static struct cmd_t command_defs[] =
         CMD_SUBFUNCS(
             { "sourcepath",     cmd_plugins_sourcepath },
             { "install",        cmd_plugins_install },
+            { "uninstall",      cmd_plugins_uninstall },
+            { "update",         cmd_plugins_update },
             { "load",           cmd_plugins_load },
             { "unload",         cmd_plugins_unload },
             { "reload",         cmd_plugins_reload },
@@ -2095,6 +2097,8 @@ static struct cmd_t command_defs[] =
             "/plugins sourcepath set <path>",
             "/plugins sourcepath clear",
             "/plugins install [<path>]",
+            "/plugins uninstall [<plugin>]",
+            "/plugins update [<path>]",
             "/plugins unload [<plugin>]",
             "/plugins load [<plugin>]",
             "/plugins reload [<plugin>]",
@@ -2105,6 +2109,8 @@ static struct cmd_t command_defs[] =
             { "sourcepath set <path>",  "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 [<path>]",       "Install a plugin, or all plugins found in a directory (recursive). Passing no argument will use the sourcepath if one is set." },
+            { "uninstall [<plugin>]",   "Uninstall a plugin." },
+            { "update [<path>]",        "Updates an installed plugin" },
             { "load [<plugin>]",        "Load a plugin that already exists in the plugin directory, passing no argument loads all found plugins." },
             { "unload [<plugin>]",      "Unload a loaded plugin, passing no argument will unload all plugins." },
             { "reload [<plugin>]",      "Reload a plugin, passing no argument will reload all plugins." },
@@ -2113,6 +2119,8 @@ static struct cmd_t command_defs[] =
             "/plugins sourcepath set /home/meee/projects/profanity-plugins",
             "/plugins install",
             "/plugins install /home/steveharris/Downloads/metal.py",
+            "/plugins update /home/steveharris/Downloads/metal.py",
+            "/plugins uninstall browser.py",
             "/plugins load browser.py",
             "/plugins unload say.py",
             "/plugins reload wikipedia.py")
diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c
index c8aa22b4..9cc7b881 100644
--- a/src/command/cmd_funcs.c
+++ b/src/command/cmd_funcs.c
@@ -6616,15 +6616,16 @@ cmd_plugins_install(ProfWin *window, const char *const command, gchar **args)
             return TRUE;
         }
 
+        GString* error_message = g_string_new(NULL);
         gchar *plugin_name = g_path_get_basename(path);
-        gboolean result = plugins_install(plugin_name, path);
+        gboolean result = plugins_install(plugin_name, path, error_message);
         if (result) {
             cons_show("Plugin installed: %s", plugin_name);
         } else {
-            cons_show("Failed to install plugin: %s", plugin_name);
+            cons_show("Failed to install plugin: %s. %s", plugin_name, error_message->str);
         }
         g_free(plugin_name);
-
+        g_string_free(error_message, TRUE);
         free(path);
         return TRUE;
     }
@@ -6663,6 +6664,88 @@ cmd_plugins_install(ProfWin *window, const char *const command, gchar **args)
 }
 
 gboolean
+cmd_plugins_update(ProfWin *window, const char *const command, gchar **args)
+{
+    char *path = args[1];
+    if (path == NULL) {
+        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;
+        }
+    } else {
+        path = strdup(path);
+    }
+
+    if (access(path, R_OK) != 0) {
+        cons_show("File not found: %s", path);
+        free(path);
+        return TRUE;
+    }
+
+    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;
+        }
+
+        GString* error_message = g_string_new(NULL);
+        gchar *plugin_name = g_path_get_basename(path);
+        if (plugins_unload(plugin_name)) {
+            if (plugins_uninstall(plugin_name)) {
+                if (plugins_install(plugin_name, path, error_message)) {
+                    cons_show("Plugin installed: %s", plugin_name);
+                } else {
+                    cons_show("Failed to install plugin: %s. %s", plugin_name, error_message->str);
+                }
+            } else {
+                cons_show("Failed to uninstall plugin: %s.", plugin_name);
+            }
+        } else {
+            cons_show("Failed to unload plugin: %s.", plugin_name);
+        }
+        g_free(plugin_name);
+        g_string_free(error_message, TRUE);
+        free(path);
+        return TRUE;
+    }
+
+    if (is_dir(path)) {
+        free(path);
+        return FALSE;
+    }
+
+    free(path);
+    cons_show("Argument must be a file or directory.");
+    return TRUE;
+}
+
+gboolean
+cmd_plugins_uninstall(ProfWin *window, const char *const command, gchar **args)
+{
+    if (args[1] == NULL) {
+        return FALSE;
+    }
+
+    gboolean res = plugins_uninstall(args[1]);
+    if (res) {
+        cons_show("Uninstalled plugin: %s", args[1]);
+    } else {
+        cons_show("Failed to uninstall plugin: %s", args[1]);
+    }
+
+    return TRUE;
+}
+
+gboolean
 cmd_plugins_load(ProfWin *window, const char *const command, gchar **args)
 {
     if (args[1] == NULL) {
diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h
index 0bbf338e..f4933d44 100644
--- a/src/command/cmd_funcs.h
+++ b/src/command/cmd_funcs.h
@@ -162,6 +162,8 @@ 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_update(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_plugins_uninstall(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);
diff --git a/src/common.c b/src/common.c
index 164523a2..1f37b664 100644
--- a/src/common.c
+++ b/src/common.c
@@ -46,6 +46,7 @@
 #include <curl/curl.h>
 #include <curl/easy.h>
 #include <glib.h>
+#include <gio/gio.h>
 
 #ifdef HAVE_NCURSESW_NCURSES_H
 #include <ncursesw/ncurses.h>
@@ -105,28 +106,16 @@ mkdir_recursive(const char *dir)
 }
 
 gboolean
-copy_file(const char *const sourcepath, const char *const targetpath)
+copy_file(const char *const sourcepath, const char *const targetpath, const gboolean overwrite_existing)
 {
-    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;
+    GFile *source = g_file_new_for_path(sourcepath);
+    GFile *dest = g_file_new_for_path(targetpath);
+    GError *error = NULL;
+    GFileCopyFlags flags = overwrite_existing ? G_FILE_COPY_OVERWRITE : G_FILE_COPY_NONE;
+    gboolean success = g_file_copy (source, dest, flags, NULL, NULL, NULL, &error);
+    g_object_unref(source);
+    g_object_unref(dest);
+    return success;
 }
 
 char*
diff --git a/src/common.h b/src/common.h
index b2c36c3f..cb0a3b5a 100644
--- a/src/common.h
+++ b/src/common.h
@@ -82,7 +82,7 @@ typedef enum {
 
 gboolean create_dir(char *name);
 gboolean mkdir_recursive(const char *dir);
-gboolean copy_file(const char *const src, const char *const target);
+gboolean copy_file(const char *const src, const char *const target, const gboolean overwrite_existing);
 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 ced170fe..3e07af4d 100644
--- a/src/plugins/plugins.c
+++ b/src/plugins/plugins.c
@@ -34,6 +34,7 @@
 
 #include <string.h>
 #include <stdlib.h>
+#include <gio/gio.h>
 
 #include "log.h"
 #include "config.h"
@@ -149,16 +150,19 @@ plugins_install_all(const char *const path)
     get_file_paths_recursive(path, &contents);
 
     GSList *curr = contents;
+    GString *error_message = NULL;
     while (curr) {
+        error_message = g_string_new(NULL);
         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)) {
+            if (plugins_install(plugin_name, curr->data, error_message)) {
                 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_string_free(error_message, TRUE);
     }
 
     g_slist_free_full(contents, g_free);
@@ -167,7 +171,25 @@ plugins_install_all(const char *const path)
 }
 
 gboolean
-plugins_install(const char *const plugin_name, const char *const filename)
+plugins_uninstall(const char *const plugin_name)
+{
+    plugins_unload(plugin_name);
+    char *plugins_dir = files_get_data_path(DIR_PLUGINS);   
+    GString *target_path = g_string_new(plugins_dir);
+    free(plugins_dir);
+    g_string_append(target_path, "/");
+    g_string_append(target_path, plugin_name);
+    GFile *file = g_file_new_for_path(target_path->str);
+    GError *error = NULL;
+    gboolean result = g_file_delete(file, NULL, &error);
+    g_object_unref(file);
+    g_error_free(error);
+    g_string_free(target_path, TRUE);
+    return result;
+}
+
+gboolean
+plugins_install(const char *const plugin_name, const char *const filename, GString *error_message)
 {
     char *plugins_dir = files_get_data_path(DIR_PLUGINS);
     GString *target_path = g_string_new(plugins_dir);
@@ -175,18 +197,19 @@ plugins_install(const char *const plugin_name, const char *const filename)
     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);
+    if (g_file_test (target_path->str, G_FILE_TEST_EXISTS))
+    {
+        log_info("Failed to install plugin: %s, file exists", plugin_name);
+        g_string_assign(error_message, "File exists");
+        return FALSE;
     }
 
-    gboolean result = copy_file(filename, target_path->str);
+    gboolean result = copy_file(filename, target_path->str, false);
     g_string_free(target_path, TRUE);
 
     if (result) {
         result = plugins_load(plugin_name);
     }
-
     return result;
 }
 
diff --git a/src/plugins/plugins.h b/src/plugins/plugins.h
index 16d6874a..56f2e042 100644
--- a/src/plugins/plugins.h
+++ b/src/plugins/plugins.h
@@ -114,7 +114,9 @@ void plugins_shutdown(void);
 
 void plugins_free_install_result(PluginsInstallResult *result);
 
-gboolean plugins_install(const char *const plugin_name, const char *const filename);
+gboolean plugins_install(const char *const plugin_name, const char *const filename, GString * error_message);
+gboolean plugins_uninstall(const char *const plugin_name);
+gboolean plugins_update(const char *const plugin_name, const char *const filename, GString * error_message);
 PluginsInstallResult* plugins_install_all(const char *const path);
 gboolean plugins_load(const char *const name);
 GSList* plugins_load_all(void);