about summary refs log tree commit diff stats
path: root/src/command
diff options
context:
space:
mode:
authorDominik Heidler <dominik@heidler.eu>2016-04-11 20:13:18 +0200
committerDominik Heidler <dominik@heidler.eu>2016-04-26 23:50:55 +0200
commit1b0ce852bba81c3bbed1f7cbf04d0b60f1f0961b (patch)
tree6a611a76d29452910014f9cee4060b372145ece4 /src/command
parent28e260c7da7bddebcb7b08003174eb16b9a6f596 (diff)
downloadprofani-tty-1b0ce852bba81c3bbed1f7cbf04d0b60f1f0961b.tar.gz
Implement XEP-0363: HTTP File Upload
Diffstat (limited to 'src/command')
-rw-r--r--src/command/command.c131
-rw-r--r--src/command/commands.c71
-rw-r--r--src/command/commands.h1
3 files changed, 195 insertions, 8 deletions
diff --git a/src/command/command.c b/src/command/command.c
index 984812f5..1ac87374 100644
--- a/src/command/command.c
+++ b/src/command/command.c
@@ -42,6 +42,10 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <libgen.h>
+
+#include <dirent.h>
+#include <sys/types.h>
 
 #include <glib.h>
 
@@ -120,6 +124,7 @@ static char* _console_autocomplete(ProfWin *window, const char *const input);
 static char* _win_autocomplete(ProfWin *window, const char *const input);
 static char* _close_autocomplete(ProfWin *window, const char *const input);
 static char* _plugins_autocomplete(ProfWin *window, const char *const input);
+static char* _sendfile_autocomplete(ProfWin *window, const char *const input);
 
 GHashTable *commands = NULL;
 
@@ -795,6 +800,22 @@ static struct cmd_t command_defs[] =
             "/disco info myfriend@server.com/laptop")
     },
 
+    { "/sendfile",
+        cmd_sendfile, parse_args_with_freetext, 1, 1, NULL,
+        CMD_TAGS(
+            CMD_TAG_CHAT,
+            CMD_TAG_GROUPCHAT)
+        CMD_SYN(
+            "/sendfile <file>")
+        CMD_DESC(
+            "Send a file using XEP-0363 HTTP file transfer.")
+        CMD_ARGS(
+            { "<file>", "Path to the file." })
+        CMD_EXAMPLES(
+            "/sendfile /etc/hosts",
+            "/sendfile ~/images/sweet_cat.jpg")
+    },
+
     { "/lastactivity",
         cmd_lastactivity, parse_args, 0, 1, NULL,
         CMD_TAGS(
@@ -2043,6 +2064,7 @@ static Autocomplete console_msg_ac;
 static Autocomplete autoping_ac;
 static Autocomplete plugins_ac;
 static Autocomplete plugins_load_ac;
+static Autocomplete sendfile_ac;
 
 /*
  * Initialise command autocompleter and history
@@ -2597,6 +2619,8 @@ cmd_init(void)
 
     plugins_ac = autocomplete_new();
     autocomplete_add(plugins_ac, "load");
+
+    sendfile_ac = autocomplete_new();
 }
 
 void
@@ -2686,6 +2710,7 @@ cmd_uninit(void)
     autocomplete_free(autoping_ac);
     autocomplete_free(plugins_ac);
     autocomplete_free(plugins_load_ac);
+    autocomplete_free(sendfile_ac);
 }
 
 gboolean
@@ -2834,6 +2859,7 @@ cmd_reset_autocomplete(ProfWin *window)
     autocomplete_reset(notify_mention_ac);
     autocomplete_reset(notify_trigger_ac);
     autocomplete_reset(sub_ac);
+    autocomplete_reset(sendfile_ac);
 
     autocomplete_reset(who_room_ac);
     autocomplete_reset(who_roster_ac);
@@ -3191,6 +3217,7 @@ _cmd_complete_parameters(ProfWin *window, const char *const input)
     g_hash_table_insert(ac_funcs, "/win",           _win_autocomplete);
     g_hash_table_insert(ac_funcs, "/close",         _close_autocomplete);
     g_hash_table_insert(ac_funcs, "/plugins",         _plugins_autocomplete);
+    g_hash_table_insert(ac_funcs, "/sendfile",      _sendfile_autocomplete);
 
     int len = strlen(input);
     char parsed[len+1];
@@ -4590,6 +4617,110 @@ _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;
+}
+
+
+static char*
 _subject_autocomplete(ProfWin *window, const char *const input)
 {
     char *result = NULL;
diff --git a/src/command/commands.c b/src/command/commands.c
index 50877227..257b8b5c 100644
--- a/src/command/commands.c
+++ b/src/command/commands.c
@@ -32,10 +32,13 @@
  *
  */
 
+#define _GNU_SOURCE 1
+
 #include "config.h"
 
 #include <string.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <errno.h>
 #include <assert.h>
 #include <glib.h>
@@ -80,6 +83,7 @@
 #ifdef HAVE_GTK
 #include "tray.h"
 #endif
+#include "tools/http_upload.h"
 
 static void _update_presence(const resource_presence_t presence,
     const char *const show, gchar **args);
@@ -128,21 +132,21 @@ cmd_execute_default(ProfWin *window, const char *inp)
     {
         ProfChatWin *chatwin = (ProfChatWin*)window;
         assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
-        cl_ev_send_msg(chatwin, inp);
+        cl_ev_send_msg(chatwin, inp, NULL);
         break;
     }
     case WIN_PRIVATE:
     {
         ProfPrivateWin *privatewin = (ProfPrivateWin*)window;
         assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK);
-        cl_ev_send_priv_msg(privatewin, inp);
+        cl_ev_send_priv_msg(privatewin, inp, NULL);
         break;
     }
     case WIN_MUC:
     {
         ProfMucWin *mucwin = (ProfMucWin*)window;
         assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
-        cl_ev_send_muc_msg(mucwin, inp);
+        cl_ev_send_muc_msg(mucwin, inp, NULL);
         break;
     }
     case WIN_XML:
@@ -1903,7 +1907,7 @@ cmd_msg(ProfWin *window, const char *const command, gchar **args)
             ui_focus_win((ProfWin*)privwin);
 
             if (msg) {
-                cl_ev_send_priv_msg(privwin, msg);
+                cl_ev_send_priv_msg(privwin, msg, NULL);
             }
 
             g_string_free(full_jid, TRUE);
@@ -1928,7 +1932,7 @@ cmd_msg(ProfWin *window, const char *const command, gchar **args)
         ui_focus_win((ProfWin*)chatwin);
 
         if (msg) {
-            cl_ev_send_msg(chatwin, msg);
+            cl_ev_send_msg(chatwin, msg, NULL);
         } else {
 #ifdef HAVE_LIBOTR
             if (otr_is_secure(barejid)) {
@@ -4225,6 +4229,57 @@ cmd_disco(ProfWin *window, const char *const command, gchar **args)
 }
 
 gboolean
+cmd_sendfile(ProfWin *window, const char *const command, gchar **args)
+{
+    jabber_conn_status_t conn_status = jabber_get_connection_status();
+    char *filename = args[0];
+
+    // 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 (conn_status != JABBER_CONNECTED) {
+        cons_show("You are not currently connected.");
+        free(filename);
+        return TRUE;
+    }
+
+    if (window->type != WIN_CHAT && window->type != WIN_PRIVATE && window->type != WIN_MUC) {
+        cons_show_error("Unsupported window for file transmission.");
+        free(filename);
+        return TRUE;
+    }
+
+    if (access(filename, R_OK) != 0) {
+        cons_show_error("Uploading '%s' failed: File not found!", filename);
+        free(filename);
+        return TRUE;
+    }
+
+    if (!is_regular_file(filename)) {
+        cons_show_error("Uploading '%s' failed: Not a file!", filename);
+        free(filename);
+        return TRUE;
+    }
+
+    HTTPUpload *upload = malloc(sizeof(HTTPUpload));
+    upload->window = window;
+
+    upload->filename = filename;
+    upload->filesize = file_size(filename);
+    upload->mime_type = file_mime_type(filename);
+
+    iq_http_upload_request(upload);
+
+    return TRUE;
+}
+
+gboolean
 cmd_lastactivity(ProfWin *window, const char *const command, gchar **args)
 {
     if ((g_strcmp0(args[0], "on") == 0) || (g_strcmp0(args[0], "off") == 0)) {
@@ -4375,21 +4430,21 @@ cmd_tiny(ProfWin *window, const char *const command, gchar **args)
     {
         ProfChatWin *chatwin = (ProfChatWin*)window;
         assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
-        cl_ev_send_msg(chatwin, tiny);
+        cl_ev_send_msg(chatwin, tiny, NULL);
         break;
     }
     case WIN_PRIVATE:
     {
         ProfPrivateWin *privatewin = (ProfPrivateWin*)window;
         assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK);
-        cl_ev_send_priv_msg(privatewin, tiny);
+        cl_ev_send_priv_msg(privatewin, tiny, NULL);
         break;
     }
     case WIN_MUC:
     {
         ProfMucWin *mucwin = (ProfMucWin*)window;
         assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
-        cl_ev_send_muc_msg(mucwin, tiny);
+        cl_ev_send_muc_msg(mucwin, tiny, NULL);
         break;
     }
     default:
diff --git a/src/command/commands.h b/src/command/commands.h
index cfa9d966..da958bea 100644
--- a/src/command/commands.h
+++ b/src/command/commands.h
@@ -85,6 +85,7 @@ gboolean cmd_connect(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_tls(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_decline(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_disco(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_sendfile(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_lastactivity(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_disconnect(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_dnd(ProfWin *window, const char *const command, gchar **args);