libpurple/protocols/gg/image.c

Tue, 07 Aug 2012 20:23:21 +0200

author
Tomasz Wasilczyk <tomkiewicz@cpw.pidgin.im>
date
Tue, 07 Aug 2012 20:23:21 +0200
branch
soc.2012.gg
changeset 33334
734fc6da6179
parent 33313
5a0c6582d5b1
child 33348
2394cd23ce8f
permissions
-rw-r--r--

Gadu-Gadu: initial multilogon support

#include "image.h"

#include <debug.h>

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

#define GGP_PENDING_IMAGE_ID_PREFIX "gg-pending-image-"

typedef struct
{
	uin_t from;
	gchar *text;
	time_t mtime;
} ggp_image_pending_message;

typedef struct
{
	int id;
	gchar *conv_name;
} ggp_image_pending_image;

static void ggp_image_pending_message_free(gpointer data)
{
	ggp_image_pending_message *pending_message =
		(ggp_image_pending_message*)data;
	g_free(pending_message->text);
	g_free(pending_message);
}

static void ggp_image_pending_image_free(gpointer data)
{
	ggp_image_pending_image *pending_image =
		(ggp_image_pending_image*)data;
	g_free(pending_image->conv_name);
	g_free(pending_image);
}

static inline ggp_image_connection_data *
ggp_image_get_imgdata(PurpleConnection *gc)
{
	GGPInfo *accdata = purple_connection_get_protocol_data(gc);
	return &accdata->image_data;
}

void ggp_image_setup(PurpleConnection *gc)
{
	ggp_image_connection_data *imgdata = ggp_image_get_imgdata(gc);
	
	imgdata->pending_messages = NULL;
	imgdata->pending_images = g_hash_table_new_full(NULL, NULL, NULL,
		ggp_image_pending_image_free);
}

void ggp_image_cleanup(PurpleConnection *gc)
{
	ggp_image_connection_data *imgdata = ggp_image_get_imgdata(gc);
	
	g_list_free_full(imgdata->pending_messages,
		&ggp_image_pending_message_free);
	g_hash_table_destroy(imgdata->pending_images);
}

const char * ggp_image_pending_placeholder(uint32_t id)
{
	static char buff[50];
	
	g_snprintf(buff, 50, "<img id=\"" GGP_PENDING_IMAGE_ID_PREFIX
		"%u\">", id);
	
	return buff;
}

void ggp_image_got_im(PurpleConnection *gc, uin_t from, gchar *text,
	time_t mtime)
{
	ggp_image_connection_data *imgdata = ggp_image_get_imgdata(gc);
	ggp_image_pending_message *pending_message =
		g_new(ggp_image_pending_message, 1);
	
	purple_debug_info("gg", "ggp_image_got_im: received message with "
		"images from %u: %s\n", from, text);
	
	pending_message->from = from;
	pending_message->text = text;
	pending_message->mtime = mtime;
	
	imgdata->pending_messages = g_list_append(imgdata->pending_messages,
		pending_message);
}

ggp_image_prepare_result ggp_image_prepare(PurpleConnection *gc, const int id,
	const char *conv_name, struct gg_msg_richtext_image *image_info)
{
	ggp_image_connection_data *imgdata = ggp_image_get_imgdata(gc);
	PurpleStoredImage *image = purple_imgstore_find_by_id(id);
	size_t image_size;
	gconstpointer image_data;
	const char *image_filename;
	uint32_t image_crc;
	ggp_image_pending_image *pending_image;
	
	if (!image)
	{
		purple_debug_error("gg", "ggp_image_prepare_to_send: image %d "
			"not found in image store\n", id);
		return GGP_IMAGE_PREPARE_FAILURE;
	}
	
	image_size = purple_imgstore_get_size(image);
	
	if (image_size > GGP_IMAGE_SIZE_MAX)
	{
		purple_debug_warning("gg", "ggp_image_prepare_to_send: image "
			"is too big (max bytes: %d)\n", GGP_IMAGE_SIZE_MAX);
		return GGP_IMAGE_PREPARE_TOO_BIG;
	}
	
	purple_imgstore_ref(image);
	image_data = purple_imgstore_get_data(image);
	image_filename = purple_imgstore_get_filename(image);
	image_crc = gg_crc32(0, image_data, image_size);
	
	purple_debug_info("gg", "ggp_image_prepare_to_send: image prepared "
		"[id=%d, crc=%u, size=%d, filename=%s]\n",
		id, image_crc, image_size, image_filename);
	
	pending_image = g_new(ggp_image_pending_image, 1);
	pending_image->id = id;
	pending_image->conv_name = g_strdup(conv_name);
	g_hash_table_insert(imgdata->pending_images, GINT_TO_POINTER(image_crc),
		pending_image);
	
	image_info->unknown1 = 0x0109;
	image_info->size = gg_fix32(image_size);
	image_info->crc32 = gg_fix32(image_crc);
	
	return GGP_IMAGE_PREPARE_OK;
}

void ggp_image_recv(PurpleConnection *gc,
	const struct gg_event_image_reply *image_reply)
{
	ggp_image_connection_data *imgdata = ggp_image_get_imgdata(gc);
	int stored_id;
	const char *imgtag_search;
	gchar *imgtag_replace;
	GList *pending_messages_it;
	
	stored_id = purple_imgstore_add_with_id(
		g_memdup(image_reply->image, image_reply->size),
		image_reply->size,
		image_reply->filename);
	
	purple_debug_info("gg", "ggp_image_recv: got image "
		"[id=%d, crc=%u, size=%u, filename=\"%s\"]\n",
		stored_id,
		image_reply->crc32,
		image_reply->size,
		image_reply->filename);

	imgtag_search = ggp_image_pending_placeholder(image_reply->crc32);
	imgtag_replace = g_strdup_printf("<img src=\""
		PURPLE_STORED_IMAGE_PROTOCOL "%u\">", stored_id);

	pending_messages_it = g_list_first(imgdata->pending_messages);
	while (pending_messages_it)
	{
		ggp_image_pending_message *pending_message =
			(ggp_image_pending_message*)pending_messages_it->data;
		gchar *newText;
		
		if (strstr(pending_message->text, imgtag_search) == NULL)
		{
			pending_messages_it = g_list_next(pending_messages_it);
			continue;
		}
		
		purple_debug_misc("gg", "ggp_image_recv: found message "
			"containing image: %s\n", pending_message->text);
		
		newText = purple_strreplace(pending_message->text,
			imgtag_search, imgtag_replace);
		g_free(pending_message->text);
		pending_message->text = newText;

		if (strstr(pending_message->text,
			"<img id=\"" GGP_PENDING_IMAGE_ID_PREFIX) == NULL)
		{
			purple_debug_info("gg", "ggp_image_recv: "
				"message is ready to display\n");
			serv_got_im(gc, ggp_uin_to_str(pending_message->from),
				pending_message->text,
				PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_IMAGES,
				pending_message->mtime);
			
			ggp_image_pending_message_free(pending_message);
			imgdata->pending_messages = g_list_remove(
				imgdata->pending_messages, pending_message);
		}
		
		pending_messages_it = g_list_next(pending_messages_it);
	}
	g_free(imgtag_replace);
}

void ggp_image_send(PurpleConnection *gc,
	const struct gg_event_image_request *image_request)
{
	GGPInfo *accdata = purple_connection_get_protocol_data(gc);
	ggp_image_connection_data *imgdata = ggp_image_get_imgdata(gc);
	ggp_image_pending_image *pending_image;
	PurpleStoredImage *image;
	PurpleConversation *conv;
	
	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);
	
	pending_image = g_hash_table_lookup(imgdata->pending_images,
		GINT_TO_POINTER(image_request->crc32));
	
	if (pending_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=%d, conv=%s]\n",
		pending_image->id,
		pending_image->conv_name);
	
	image = purple_imgstore_find_by_id(pending_image->id);
	
	if (!image)
	{
		purple_debug_error("gg", "ggp_image_send: requested image "
			"found, but doesn't exists in image store\n");
		g_hash_table_remove(imgdata->pending_images,
			GINT_TO_POINTER(image_request->crc32));
		return;
	}
	
	//TODO: check allowed recipients
	gg_image_reply(accdata->session, image_request->sender,
		purple_imgstore_get_filename(image),
		purple_imgstore_get_data(image),
		purple_imgstore_get_size(image));
	purple_imgstore_unref(image);
	
	conv = purple_find_conversation_with_account(
		PURPLE_CONV_TYPE_IM, pending_image->conv_name,
		purple_connection_get_account(gc));
	if (conv != NULL)
		purple_conversation_write(conv, "", _("Image delivered."),
			PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_NOTIFY,
			time(NULL));
	
	g_hash_table_remove(imgdata->pending_images,
		GINT_TO_POINTER(image_request->crc32));
}

mercurial