libpurple/protocols/jabber/oob.c

Sun, 16 Aug 2020 18:58:39 -0500

author
Elliott Sales de Andrade <quantum.analyst@gmail.com>
date
Sun, 16 Aug 2020 18:58:39 -0500
changeset 40514
30d9cbf04922
parent 40439
e9838d634d5e
child 41212
9f0f4c23132e
permissions
-rw-r--r--

Fix some leaks.

Also, expand `g_ascii_dtostr` buffers to `G_ASCII_DTOSTR_BUF_SIZE`.

This is the size it's guaranteed to be under, so might as well have it be that size. It not too much bigger than the existing choice anyway.

Testing Done:
Compile only.

Reviewed at https://reviews.imfreedom.org/r/71/

/*
 * purple - Jabber Protocol Plugin
 *
 * Purple is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 *
 */
#include <purple.h>

#include "jabber.h"
#include "iq.h"
#include "oob.h"

struct _JabberOOBXfer {
	JabberStream *js;
	gchar *iq_id;
	gchar *url;
	SoupMessage *msg;
};

G_DEFINE_DYNAMIC_TYPE(JabberOOBXfer, jabber_oob_xfer, PURPLE_TYPE_XFER);

static void jabber_oob_xfer_xfer_init(PurpleXfer *xfer)
{
	purple_xfer_start(xfer, -1, NULL, 0);
}

static void jabber_oob_xfer_end(PurpleXfer *xfer)
{
	JabberOOBXfer *jox = JABBER_OOB_XFER(xfer);
	JabberIq *iq;

	iq = jabber_iq_new(jox->js, JABBER_IQ_RESULT);
	purple_xmlnode_set_attrib(iq->node, "to", purple_xfer_get_remote_user(xfer));
	jabber_iq_set_id(iq, jox->iq_id);

	jabber_iq_send(iq);
}

static void
jabber_oob_xfer_got(G_GNUC_UNUSED SoupSession *session, SoupMessage *msg,
                    gpointer user_data)
{
	PurpleXfer *xfer = user_data;
	JabberOOBXfer *jox;

	if (purple_xfer_is_cancelled(xfer))
		return;

	jox = JABBER_OOB_XFER(xfer);
	jox->msg = NULL;

	if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code) ||
	    purple_xfer_get_bytes_remaining(xfer) > 0) {
		purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_REMOTE);
		purple_xfer_end(xfer);
	} else {
		purple_xfer_set_completed(xfer, TRUE);
		purple_xfer_end(xfer);
	}
}

static void
jabber_oob_xfer_got_content_length(SoupMessage *msg, gpointer user_data)
{
	PurpleXfer *xfer = user_data;
	goffset total;

	total = soup_message_headers_get_content_length(msg->response_headers);

	purple_xfer_set_size(xfer, total);
}

static void
jabber_oob_xfer_writer(SoupMessage *msg, SoupBuffer *chunk, gpointer user_data)
{
	PurpleXfer *xfer = user_data;

	if (!purple_xfer_write_file(xfer, (const guchar *)chunk->data,
	                            chunk->length)) {
		JabberOOBXfer *jox = JABBER_OOB_XFER(xfer);
		soup_session_cancel_message(jox->js->http_conns, msg,
		                            SOUP_STATUS_IO_ERROR);
	}
}

static void jabber_oob_xfer_start(PurpleXfer *xfer)
{
	SoupMessage *msg;
	JabberOOBXfer *jox = JABBER_OOB_XFER(xfer);

	msg = soup_message_new("GET", jox->url);
	soup_message_add_header_handler(
	        msg, "got-headers", "Content-Length",
	        G_CALLBACK(jabber_oob_xfer_got_content_length), xfer);
	soup_message_body_set_accumulate(msg->response_body, FALSE);
	g_signal_connect(msg, "got-chunk", G_CALLBACK(jabber_oob_xfer_writer),
	                 xfer);
	soup_session_queue_message(jox->js->http_conns, msg, jabber_oob_xfer_got,
	                           xfer);
}

static void jabber_oob_xfer_recv_error(PurpleXfer *xfer, const char *code) {
	JabberOOBXfer *jox = JABBER_OOB_XFER(xfer);
	JabberIq *iq;
	PurpleXmlNode *y, *z;

	iq = jabber_iq_new(jox->js, JABBER_IQ_ERROR);
	purple_xmlnode_set_attrib(iq->node, "to", purple_xfer_get_remote_user(xfer));
	jabber_iq_set_id(iq, jox->iq_id);
	y = purple_xmlnode_new_child(iq->node, "error");
	purple_xmlnode_set_attrib(y, "code", code);
	if(purple_strequal(code, "406")) {
		z = purple_xmlnode_new_child(y, "not-acceptable");
		purple_xmlnode_set_attrib(y, "type", "modify");
		purple_xmlnode_set_namespace(z, NS_XMPP_STANZAS);
	} else if(purple_strequal(code, "404")) {
		z = purple_xmlnode_new_child(y, "not-found");
		purple_xmlnode_set_attrib(y, "type", "cancel");
		purple_xmlnode_set_namespace(z, NS_XMPP_STANZAS);
	}
	jabber_iq_send(iq);
}

static void jabber_oob_xfer_recv_denied(PurpleXfer *xfer) {
	jabber_oob_xfer_recv_error(xfer, "406");
}

static void jabber_oob_xfer_recv_cancelled(PurpleXfer *xfer) {
	JabberOOBXfer *jox = JABBER_OOB_XFER(xfer);

	soup_session_cancel_message(jox->js->http_conns, jox->msg,
	                            SOUP_STATUS_CANCELLED);
	jabber_oob_xfer_recv_error(xfer, "404");
}

void jabber_oob_parse(JabberStream *js, const char *from, JabberIqType type,
	const char *id, PurpleXmlNode *querynode) {
	JabberOOBXfer *jox;
	const gchar *filename, *slash;
	gchar *url;
	PurpleXmlNode *urlnode;

	if(type != JABBER_IQ_SET)
		return;

	if(!from)
		return;

	if(!(urlnode = purple_xmlnode_get_child(querynode, "url")))
		return;

	url = purple_xmlnode_get_data(urlnode);
	if (!url)
		return;

	jox = g_object_new(
		JABBER_TYPE_OOB_XFER,
		"account", purple_connection_get_account(js->gc),
		"type", PURPLE_XFER_TYPE_RECEIVE,
		"remote-user", from,
		NULL
	);

	jox->iq_id = g_strdup(id);
	jox->js = js;
	jox->url = url;

	slash = strrchr(url, '/');
	if (slash == NULL) {
		filename = url;
	} else {
		filename = slash + 1;
	}

	purple_xfer_set_filename(PURPLE_XFER(jox), filename);

	js->oob_file_transfers = g_list_append(js->oob_file_transfers, jox);

	purple_xfer_request(PURPLE_XFER(jox));
}

static void
jabber_oob_xfer_init(JabberOOBXfer *xfer) {

}

static void
jabber_oob_xfer_finalize(GObject *obj) {
	JabberOOBXfer *jox = JABBER_OOB_XFER(obj);

	jox->js->oob_file_transfers = g_list_remove(jox->js->oob_file_transfers,
			jox);

	g_free(jox->iq_id);
	g_free(jox->url);

	G_OBJECT_CLASS(jabber_oob_xfer_parent_class)->finalize(obj);
}

static void
jabber_oob_xfer_class_finalize(JabberOOBXferClass *klass) {

}

static void
jabber_oob_xfer_class_init(JabberOOBXferClass *klass) {
	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
	PurpleXferClass *xfer_class = PURPLE_XFER_CLASS(klass);

	obj_class->finalize = jabber_oob_xfer_finalize;

	xfer_class->init = jabber_oob_xfer_xfer_init;
	xfer_class->end = jabber_oob_xfer_end;
	xfer_class->request_denied = jabber_oob_xfer_recv_denied;
	xfer_class->cancel_recv = jabber_oob_xfer_recv_cancelled;
	xfer_class->start = jabber_oob_xfer_start;
}

void
jabber_oob_xfer_register(GTypeModule *module) {
	jabber_oob_xfer_register_type(module);
}

mercurial