Implement XEP-0363: HTTP File Upload
This commit is contained in:
@@ -64,6 +64,7 @@
|
||||
#include "roster_list.h"
|
||||
#include "xmpp/xmpp.h"
|
||||
#include "plugins/plugins.h"
|
||||
#include "tools/http_upload.h"
|
||||
|
||||
typedef struct p_room_info_data_t {
|
||||
char *room;
|
||||
@@ -88,6 +89,7 @@ static void _ping_get_handler(xmpp_stanza_t *const stanza);
|
||||
static int _version_result_id_handler(xmpp_stanza_t *const stanza, void *const userdata);
|
||||
static int _disco_info_response_id_handler(xmpp_stanza_t *const stanza, void *const userdata);
|
||||
static int _disco_info_response_id_handler_onconnect(xmpp_stanza_t *const stanza, void *const userdata);
|
||||
static int _http_upload_response_id_handler(xmpp_stanza_t *const stanza, void *const upload_ctx);
|
||||
static int _last_activity_response_id_handler(xmpp_stanza_t *const stanza, void *const userdata);
|
||||
static int _room_info_response_id_handler(xmpp_stanza_t *const stanza, void *const userdata);
|
||||
static int _destroy_room_result_id_handler(xmpp_stanza_t *const stanza, void *const userdata);
|
||||
@@ -293,6 +295,42 @@ iq_disable_carbons(void)
|
||||
xmpp_stanza_release(iq);
|
||||
}
|
||||
|
||||
void
|
||||
iq_http_upload_request(HTTPUpload *upload)
|
||||
{
|
||||
GSList *disco_items = jabber_get_disco_items();
|
||||
DiscoInfo *disco_info;
|
||||
if (disco_items && (g_slist_length(disco_items) > 0)) {
|
||||
while (disco_items) {
|
||||
disco_info = disco_items->data;
|
||||
if (g_hash_table_lookup_extended(disco_info->features, STANZA_NS_HTTP_UPLOAD, NULL, NULL)) {
|
||||
break;
|
||||
}
|
||||
disco_items = g_slist_next(disco_items);
|
||||
if (!disco_items) {
|
||||
cons_show_error("XEP-0363 HTTP File Upload is not supported by the server");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cons_show_error("No disco items");
|
||||
return;
|
||||
}
|
||||
|
||||
xmpp_ctx_t * const ctx = connection_get_ctx();
|
||||
char *id = create_unique_id("http_upload_request");
|
||||
|
||||
xmpp_stanza_t *iq = stanza_create_http_upload_request(ctx, id, disco_info->item, upload);
|
||||
|
||||
id_handler_add(id, _http_upload_response_id_handler, upload);
|
||||
|
||||
free(id);
|
||||
|
||||
send_iq_stanza(iq);
|
||||
xmpp_stanza_release(iq);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
iq_disco_info_request(gchar *jid)
|
||||
{
|
||||
@@ -1904,6 +1942,60 @@ _disco_info_response_id_handler_onconnect(xmpp_stanza_t *const stanza, void *con
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_http_upload_response_id_handler(xmpp_stanza_t *const stanza, void *const userdata)
|
||||
{
|
||||
HTTPUpload *upload = (HTTPUpload *)userdata;
|
||||
const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM);
|
||||
const char *type = xmpp_stanza_get_type(stanza);
|
||||
|
||||
if (from) {
|
||||
log_info("Received http_upload response from: %s", from);
|
||||
} else {
|
||||
log_info("Received http_upload response");
|
||||
}
|
||||
|
||||
// handle error responses
|
||||
if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) {
|
||||
char *error_message = stanza_get_error_message(stanza);
|
||||
if (from) {
|
||||
cons_show_error("Uploading '%s' failed for %s: %s", upload->filename, from, error_message);
|
||||
} else {
|
||||
cons_show_error("Uploading '%s' failed: %s", upload->filename, error_message);
|
||||
}
|
||||
free(error_message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xmpp_stanza_t *slot = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_SLOT);
|
||||
|
||||
if (slot && g_strcmp0(xmpp_stanza_get_ns(slot), STANZA_NS_HTTP_UPLOAD) == 0) {
|
||||
xmpp_stanza_t *put = xmpp_stanza_get_child_by_name(slot, STANZA_NAME_PUT);
|
||||
xmpp_stanza_t *get = xmpp_stanza_get_child_by_name(slot, STANZA_NAME_GET);
|
||||
|
||||
if (put && get) {
|
||||
char *put_url = xmpp_stanza_get_text(put);
|
||||
char *get_url = xmpp_stanza_get_text(get);
|
||||
|
||||
upload->put_url = strdup(put_url);
|
||||
upload->get_url = strdup(get_url);
|
||||
|
||||
xmpp_conn_t *conn = connection_get_conn();
|
||||
xmpp_ctx_t *ctx = xmpp_conn_get_context(conn);
|
||||
if (put_url) xmpp_free(ctx, put_url);
|
||||
if (get_url) xmpp_free(ctx, get_url);
|
||||
|
||||
pthread_create(&(upload->worker), NULL, &http_file_put, upload);
|
||||
upload_processes = g_slist_append(upload_processes, upload);
|
||||
} else {
|
||||
log_error("Invalid XML in HTTP Upload slot");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_disco_items_result_handler(xmpp_stanza_t *const stanza)
|
||||
{
|
||||
|
||||
@@ -163,7 +163,7 @@ _session_state(const char *const barejid)
|
||||
}
|
||||
|
||||
char*
|
||||
message_send_chat(const char *const barejid, const char *const msg)
|
||||
message_send_chat(const char *const barejid, const char *const msg, const char *const oob_url)
|
||||
{
|
||||
xmpp_ctx_t * const ctx = connection_get_ctx();
|
||||
|
||||
@@ -178,6 +178,10 @@ message_send_chat(const char *const barejid, const char *const msg)
|
||||
stanza_attach_state(ctx, message, state);
|
||||
}
|
||||
|
||||
if (oob_url) {
|
||||
stanza_attach_x_oob_url(ctx, message, oob_url);
|
||||
}
|
||||
|
||||
if (prefs_get_boolean(PREF_RECEIPTS_REQUEST)) {
|
||||
stanza_attach_receipt_request(ctx, message);
|
||||
}
|
||||
@@ -274,25 +278,33 @@ message_send_chat_otr(const char *const barejid, const char *const msg)
|
||||
}
|
||||
|
||||
void
|
||||
message_send_private(const char *const fulljid, const char *const msg)
|
||||
message_send_private(const char *const fulljid, const char *const msg, const char *const oob_url)
|
||||
{
|
||||
xmpp_ctx_t * const ctx = connection_get_ctx();
|
||||
char *id = create_unique_id("prv");
|
||||
xmpp_stanza_t *message = stanza_create_message(ctx, id, fulljid, STANZA_TYPE_CHAT, msg);
|
||||
free(id);
|
||||
|
||||
if (oob_url) {
|
||||
stanza_attach_x_oob_url(ctx, message, oob_url);
|
||||
}
|
||||
|
||||
_send_message_stanza(message);
|
||||
xmpp_stanza_release(message);
|
||||
}
|
||||
|
||||
void
|
||||
message_send_groupchat(const char *const roomjid, const char *const msg)
|
||||
message_send_groupchat(const char *const roomjid, const char *const msg, const char *const oob_url)
|
||||
{
|
||||
xmpp_ctx_t * const ctx = connection_get_ctx();
|
||||
char *id = create_unique_id("muc");
|
||||
xmpp_stanza_t *message = stanza_create_message(ctx, id, roomjid, STANZA_TYPE_GROUPCHAT, msg);
|
||||
free(id);
|
||||
|
||||
if (oob_url) {
|
||||
stanza_attach_x_oob_url(ctx, message, oob_url);
|
||||
}
|
||||
|
||||
_send_message_stanza(message);
|
||||
xmpp_stanza_release(message);
|
||||
}
|
||||
|
||||
@@ -32,10 +32,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE 1
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <libgen.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
@@ -206,6 +211,61 @@ stanza_create_bookmarks_pubsub_add(xmpp_ctx_t *ctx, const char *const jid,
|
||||
}
|
||||
#endif
|
||||
|
||||
xmpp_stanza_t*
|
||||
stanza_create_http_upload_request(xmpp_ctx_t *ctx, const char *const id,
|
||||
const char *const jid, HTTPUpload *upload)
|
||||
{
|
||||
int i;
|
||||
|
||||
xmpp_stanza_t *iq = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(iq, STANZA_NAME_IQ);
|
||||
xmpp_stanza_set_type(iq, STANZA_TYPE_GET);
|
||||
xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, jid);
|
||||
xmpp_stanza_set_id(iq, id);
|
||||
|
||||
xmpp_stanza_t *request = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(request, STANZA_NAME_REQUEST);
|
||||
xmpp_stanza_set_ns(request, STANZA_NS_HTTP_UPLOAD);
|
||||
|
||||
xmpp_stanza_t *filename = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(filename, STANZA_NAME_FILENAME);
|
||||
xmpp_stanza_t *filename_txt = xmpp_stanza_new(ctx);
|
||||
char* filename_cpy = strdup(upload->filename);
|
||||
// strip spaces from filename (servers don't spaces)
|
||||
for (i=0; i<strlen(filename_cpy); i++) {
|
||||
if (filename_cpy[i] == ' ') {
|
||||
filename_cpy[i] = '_';
|
||||
}
|
||||
}
|
||||
xmpp_stanza_set_text(filename_txt, basename(filename_cpy));
|
||||
free(filename_cpy);
|
||||
xmpp_stanza_add_child(filename, filename_txt);
|
||||
xmpp_stanza_add_child(request, filename);
|
||||
|
||||
xmpp_stanza_t *size = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(size, STANZA_NAME_SIZE);
|
||||
xmpp_stanza_t *size_txt = xmpp_stanza_new(ctx);
|
||||
char* filesize = NULL;
|
||||
if (asprintf(&filesize, "%jd", (intmax_t)(upload->filesize)) != -1) {
|
||||
xmpp_stanza_set_text(size_txt, filesize);
|
||||
free(filesize);
|
||||
}
|
||||
xmpp_stanza_add_child(size, size_txt);
|
||||
xmpp_stanza_add_child(request, size);
|
||||
|
||||
xmpp_stanza_t *content_type = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(content_type, STANZA_NAME_CONTENT_TYPE);
|
||||
xmpp_stanza_t *content_type_txt = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_text(content_type_txt, upload->mime_type);
|
||||
xmpp_stanza_add_child(content_type, content_type_txt);
|
||||
xmpp_stanza_add_child(request, content_type);
|
||||
|
||||
xmpp_stanza_add_child(iq, request);
|
||||
xmpp_stanza_release(request);
|
||||
|
||||
return iq;
|
||||
}
|
||||
|
||||
xmpp_stanza_t*
|
||||
stanza_enable_carbons(xmpp_ctx_t *ctx)
|
||||
{
|
||||
@@ -353,6 +413,30 @@ stanza_attach_receipt_request(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza)
|
||||
return stanza;
|
||||
}
|
||||
|
||||
xmpp_stanza_t*
|
||||
stanza_attach_x_oob_url(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char *const url)
|
||||
{
|
||||
xmpp_stanza_t *x_oob = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(x_oob, STANZA_NAME_X);
|
||||
xmpp_stanza_set_ns(x_oob, STANZA_NS_X_OOB);
|
||||
|
||||
xmpp_stanza_t *surl = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_name(surl, STANZA_NAME_URL);
|
||||
|
||||
xmpp_stanza_t *surl_txt = xmpp_stanza_new(ctx);
|
||||
xmpp_stanza_set_text(surl_txt, url);
|
||||
xmpp_stanza_add_child(surl, surl_txt);
|
||||
xmpp_stanza_release(surl_txt);
|
||||
|
||||
xmpp_stanza_add_child(x_oob, surl);
|
||||
xmpp_stanza_release(surl);
|
||||
|
||||
xmpp_stanza_add_child(stanza, x_oob);
|
||||
xmpp_stanza_release(x_oob);
|
||||
|
||||
return stanza;
|
||||
}
|
||||
|
||||
xmpp_stanza_t*
|
||||
stanza_create_message(xmpp_ctx_t *ctx, char *id, const char *const recipient,
|
||||
const char *const type, const char *const message)
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
#define STANZA_NAME_STATUS "status"
|
||||
#define STANZA_NAME_IQ "iq"
|
||||
#define STANZA_NAME_QUERY "query"
|
||||
#define STANZA_NAME_REQUEST "request"
|
||||
#define STANZA_NAME_DELAY "delay"
|
||||
#define STANZA_NAME_ERROR "error"
|
||||
#define STANZA_NAME_PING "ping"
|
||||
@@ -87,6 +88,13 @@
|
||||
#define STANZA_NAME_ACTOR "actor"
|
||||
#define STANZA_NAME_ENABLE "enable"
|
||||
#define STANZA_NAME_DISABLE "disable"
|
||||
#define STANZA_NAME_FILENAME "filename"
|
||||
#define STANZA_NAME_SIZE "size"
|
||||
#define STANZA_NAME_CONTENT_TYPE "content-type"
|
||||
#define STANZA_NAME_SLOT "slot"
|
||||
#define STANZA_NAME_PUT "put"
|
||||
#define STANZA_NAME_GET "get"
|
||||
#define STANZA_NAME_URL "url"
|
||||
|
||||
// error conditions
|
||||
#define STANZA_NAME_BAD_REQUEST "bad-request"
|
||||
@@ -171,6 +179,8 @@
|
||||
#define STANZA_NS_RECEIPTS "urn:xmpp:receipts"
|
||||
#define STANZA_NS_SIGNED "jabber:x:signed"
|
||||
#define STANZA_NS_ENCRYPTED "jabber:x:encrypted"
|
||||
#define STANZA_NS_HTTP_UPLOAD "urn:xmpp:http:upload"
|
||||
#define STANZA_NS_X_OOB "jabber:x:oob"
|
||||
|
||||
#define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo"
|
||||
|
||||
@@ -195,6 +205,8 @@ typedef enum {
|
||||
|
||||
xmpp_stanza_t* stanza_create_bookmarks_storage_request(xmpp_ctx_t *ctx);
|
||||
|
||||
xmpp_stanza_t* stanza_create_http_upload_request(xmpp_ctx_t *ctx, const char *const id, const char *const jid, HTTPUpload *upload);
|
||||
|
||||
xmpp_stanza_t* stanza_enable_carbons(xmpp_ctx_t *ctx);
|
||||
|
||||
xmpp_stanza_t* stanza_disable_carbons(xmpp_ctx_t *ctx);
|
||||
@@ -207,6 +219,7 @@ xmpp_stanza_t* stanza_attach_carbons_private(xmpp_ctx_t *ctx, xmpp_stanza_t *sta
|
||||
xmpp_stanza_t* stanza_attach_hints_no_copy(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza);
|
||||
xmpp_stanza_t* stanza_attach_hints_no_store(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza);
|
||||
xmpp_stanza_t* stanza_attach_receipt_request(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza);
|
||||
xmpp_stanza_t* stanza_attach_x_oob_url(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char *const url);
|
||||
|
||||
xmpp_stanza_t* stanza_create_message(xmpp_ctx_t *ctx, char *id,
|
||||
const char *const recipient, const char *const type, const char *const message);
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "contact.h"
|
||||
#include "jid.h"
|
||||
#include "tools/autocomplete.h"
|
||||
#include "tools/http_upload.h"
|
||||
|
||||
#define JABBER_PRIORITY_MIN -128
|
||||
#define JABBER_PRIORITY_MAX 127
|
||||
@@ -169,11 +170,11 @@ gboolean jabber_conn_is_secured(void);
|
||||
gboolean jabber_send_stanza(const char *const stanza);
|
||||
|
||||
// message functions
|
||||
char* message_send_chat(const char *const barejid, const char *const msg);
|
||||
char* message_send_chat(const char *const barejid, const char *const msg, const char *const oob_url);
|
||||
char* message_send_chat_otr(const char *const barejid, const char *const msg);
|
||||
char* message_send_chat_pgp(const char *const barejid, const char *const msg);
|
||||
void message_send_private(const char *const fulljid, const char *const msg);
|
||||
void message_send_groupchat(const char *const roomjid, const char *const msg);
|
||||
void message_send_private(const char *const fulljid, const char *const msg, const char *const oob_url);
|
||||
void message_send_groupchat(const char *const roomjid, const char *const msg, const char *const oob_url);
|
||||
void message_send_groupchat_subject(const char *const roomjid, const char *const subject);
|
||||
|
||||
void message_send_inactive(const char *const jid);
|
||||
@@ -225,6 +226,7 @@ void iq_room_kick_occupant(const char *const room, const char *const nick, const
|
||||
void iq_room_role_set(const char *const room, const char *const nick, char *role, const char *const reason);
|
||||
void iq_room_role_list(const char * const room, char *role);
|
||||
void iq_autoping_check(void);
|
||||
void iq_http_upload_request(HTTPUpload *upload);
|
||||
|
||||
// caps functions
|
||||
Capabilities* caps_lookup(const char *const jid);
|
||||
|
||||
Reference in New Issue
Block a user