libpurple/protocols/gg/image-prpl.c

Tue, 07 Mar 2023 01:04:42 -0600

author
Elliott Sales de Andrade <quantum.analyst@gmail.com>
date
Tue, 07 Mar 2023 01:04:42 -0600
changeset 42128
118067ca0367
parent 41979
31c32b8d4bef
permissions
-rw-r--r--

Convert PurpleRequestPage into a GObject

And rename it from `PurpleRequestFields`.

Also, implements `GListModel` for the groups, but nothing uses it that way get.

Testing Done:
Compiled, and opened Request Fields from Demo protocol.

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

/* purple
 *
 * 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.
 *
 * Rewritten from scratch during Google Summer of Code 2012
 * by Tomek Wasilczyk (http://www.wasilczyk.pl).
 *
 * Previously implemented by:
 *  - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
 *  - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
 *  - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
 *
 * 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 <glib/gi18n-lib.h>

#include "image-prpl.h"

#include "gg.h"
#include "utils.h"

#include <purple.h>

struct _ggp_image_session_data
{
	GHashTable *recv_images;
	GHashTable *sent_images;
};

typedef struct
{
	PurpleImage *image;
	gchar *conv_name; /* TODO: callback */
} ggp_image_sent;

static void ggp_image_sent_free(gpointer _sent_image)
{
	ggp_image_sent *sent_image = _sent_image;
	g_object_unref(sent_image->image);
	g_free(sent_image->conv_name);
	g_free(sent_image);
}

static uint64_t ggp_image_params_to_id(uint32_t crc32, uint32_t size)
{
	return ((uint64_t)crc32 << 32) | size;
}

static inline ggp_image_session_data *
ggp_image_get_sdata(PurpleConnection *gc)
{
	GGPInfo *accdata = purple_connection_get_protocol_data(gc);
	return accdata->image_data;
}

void ggp_image_setup(PurpleConnection *gc)
{
	GGPInfo *accdata = purple_connection_get_protocol_data(gc);
	ggp_image_session_data *sdata = g_new0(ggp_image_session_data, 1);

	accdata->image_data = sdata;

	sdata->recv_images = g_hash_table_new_full(
		g_int64_hash, g_int64_equal, g_free, g_object_unref);
	sdata->sent_images = g_hash_table_new_full(
		g_int64_hash, g_int64_equal, g_free,
		ggp_image_sent_free);
}

void ggp_image_cleanup(PurpleConnection *gc)
{
	ggp_image_session_data *sdata = ggp_image_get_sdata(gc);

	g_hash_table_destroy(sdata->recv_images);
	g_hash_table_destroy(sdata->sent_images);
	g_free(sdata);
}

ggp_image_prepare_result
ggp_image_prepare(PurpleConversation *conv, PurpleImage *image, uint64_t *id)
{
	PurpleConnection *gc = purple_conversation_get_connection(conv);
	ggp_image_session_data *sdata = ggp_image_get_sdata(gc);
	size_t image_size;
	gconstpointer image_data;
	uint32_t image_crc;
	ggp_image_sent *sent_image;

	g_return_val_if_fail(image, GGP_IMAGE_PREPARE_FAILURE);

	image_size = purple_image_get_data_size(image);

	if (image_size > GGP_IMAGE_SIZE_MAX) {
		purple_debug_warning("gg", "ggp_image_prepare: image "
			"is too big (max bytes: %d)\n", GGP_IMAGE_SIZE_MAX);
		return GGP_IMAGE_PREPARE_TOO_BIG;
	}

	g_object_ref(image);
	image_data = purple_image_get_data(image);
	image_crc = gg_crc32(0, image_data, image_size);

	purple_debug_info("gg", "ggp_image_prepare: image prepared "
		"[crc=%u, size=%" G_GSIZE_FORMAT "]",
		image_crc, image_size);

	*id = ggp_image_params_to_id(image_crc, image_size);

	g_object_ref(image);
	sent_image = g_new(ggp_image_sent, 1);
	sent_image->image = image;
	sent_image->conv_name = g_strdup(purple_conversation_get_name(conv));
	g_hash_table_insert(sdata->sent_images, ggp_uint64dup(*id),
		sent_image);

	return GGP_IMAGE_PREPARE_OK;
}

void ggp_image_recv(PurpleConnection *gc,
	const struct gg_event_image_reply *image_reply)
{
	ggp_image_session_data *sdata = ggp_image_get_sdata(gc);
	PurpleImage *img;
	uint64_t id;

	id = ggp_image_params_to_id(image_reply->crc32, image_reply->size);
	img = g_hash_table_lookup(sdata->recv_images, &id);
	if (!img) {
		purple_debug_warning("gg", "ggp_image_recv: "
			"image " GGP_IMAGE_ID_FORMAT " wasn't requested\n",
			id);
		return;
	}

	purple_debug_info("gg", "ggp_image_recv: got image "
		"[crc=%u, size=%u, filename=%s, id=" GGP_IMAGE_ID_FORMAT "]",
		image_reply->crc32, image_reply->size,
		image_reply->filename, id);

	img = purple_image_new_from_data(
		(const guint8 *)image_reply->image,
		image_reply->size
	);
	purple_image_set_friendly_filename(img, image_reply->filename);

	g_hash_table_insert(sdata->recv_images, &id, img);
}

void ggp_image_send(PurpleConnection *gc,
	const struct gg_event_image_request *image_request)
{
	PurpleAccount *account = purple_connection_get_account(gc);
	PurpleContactInfo *info = PURPLE_CONTACT_INFO(account);
	GGPInfo *accdata = purple_connection_get_protocol_data(gc);
	ggp_image_session_data *sdata = ggp_image_get_sdata(gc);
	ggp_image_sent *sent_image;
	PurpleConversation *conv;
	PurpleConversationManager *manager;
	uint64_t id;
	uin_t sender;
	gchar *gg_filename;

	purple_debug_info("gg", "ggp_image_send: got image request "
		"[uin=%u, crc=%u, size=%u]\n",
		image_request->sender,
		image_request->crc32,
		image_request->size);

	id = ggp_image_params_to_id(image_request->crc32, image_request->size);

	sent_image = g_hash_table_lookup(sdata->sent_images, &id);

	sender = ggp_str_to_uin(purple_contact_info_get_username(info));
	if (sent_image == NULL && image_request->sender == sender) {
		purple_debug_misc("gg", "ggp_image_send: requested image "
			"not found, but this may be another session request\n");
		return;
	}
	if (sent_image == NULL) {
		purple_debug_warning("gg", "ggp_image_send: requested image "
			"not found\n");
		return;
	}

	purple_debug_misc("gg", "ggp_image_send: requested image found "
		"[id=" GGP_IMAGE_ID_FORMAT ", conv=%s]\n",
		id, sent_image->conv_name);

	g_return_if_fail(sent_image->image);

	/* TODO: check allowed recipients */
	gg_filename = g_strdup_printf(GGP_IMAGE_ID_FORMAT, id);
	gg_image_reply(accdata->session, image_request->sender,
		gg_filename,
		purple_image_get_data(sent_image->image),
		purple_image_get_data_size(sent_image->image));
	g_free(gg_filename);

	manager = purple_conversation_manager_get_default();
	conv = purple_conversation_manager_find(manager,
	                                        purple_connection_get_account(gc),
	                                        sent_image->conv_name);
	if (conv != NULL) {
		gchar *msg = g_strdup_printf(_("Image delivered to %u."),
			image_request->sender);
		purple_conversation_write_system_message(conv, msg,
			PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_NOTIFY);
		g_free(msg);
	}
}

PurpleImage *
ggp_image_request(PurpleConnection *gc, uin_t uin, uint64_t id)
{
	GGPInfo *accdata = purple_connection_get_protocol_data(gc);
	ggp_image_session_data *sdata = ggp_image_get_sdata(gc);
	PurpleImage *img;
	uint32_t crc = id >> 32;
	uint32_t size = id;

	if (size > GGP_IMAGE_SIZE_MAX && crc <= GGP_IMAGE_SIZE_MAX) {
		uint32_t tmp;
		purple_debug_warning("gg", "ggp_image_request: "
			"crc and size are swapped!\n");
		tmp = crc;
		crc = size;
		size = tmp;
		id = ggp_image_params_to_id(crc, size);
	}

	img = g_hash_table_lookup(sdata->recv_images, &id);
	if (img) {
		purple_debug_info("gg", "ggp_image_request: "
			"image " GGP_IMAGE_ID_FORMAT " got from cache", id);
		return img;
	}


	g_hash_table_insert(sdata->recv_images, ggp_uint64dup(id), NULL);

	purple_debug_info("gg", "ggp_image_request: requesting image "
		GGP_IMAGE_ID_FORMAT, id);
	if (gg_image_request(accdata->session, uin, size, crc) != 0)
		purple_debug_error("gg", "ggp_image_request: failed");

	return img;
}

mercurial