mirror of
https://git.jabber.space/devs/cproof.git
synced 2026-07-19 11:06:21 +00:00
Implement XEP-0363: HTTP File Upload
This commit is contained in:
@@ -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];
|
||||
@@ -4589,6 +4616,110 @@ _close_autocomplete(ProfWin *window, const char *const input)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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)) {
|
||||
@@ -4224,6 +4228,57 @@ cmd_disco(ProfWin *window, const char *const command, gchar **args)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user