Gadu-Gadu: fix receiving of inline images after 3.x changes; code refactoring here as well soc.2012.gg

Tue, 26 Jun 2012 22:38:37 +0200

author
Tomasz Wasilczyk <tomkiewicz@cpw.pidgin.im>
date
Tue, 26 Jun 2012 22:38:37 +0200
branch
soc.2012.gg
changeset 33298
519acf37d16e
parent 33297
f4d15445488e
child 33299
b3c4ab3aeb7f

Gadu-Gadu: fix receiving of inline images after 3.x changes; code refactoring here as well

libpurple/protocols/gg/Makefile.am file | annotate | diff | comparison | revisions
libpurple/protocols/gg/gg-utils.c file | annotate | diff | comparison | revisions
libpurple/protocols/gg/gg-utils.h file | annotate | diff | comparison | revisions
libpurple/protocols/gg/gg.c file | annotate | diff | comparison | revisions
libpurple/protocols/gg/gg.h file | annotate | diff | comparison | revisions
libpurple/protocols/gg/image.c file | annotate | diff | comparison | revisions
libpurple/protocols/gg/image.h file | annotate | diff | comparison | revisions
libpurple/protocols/gg/resolver-purple.h file | annotate | diff | comparison | revisions
--- a/libpurple/protocols/gg/Makefile.am	Mon Jun 25 18:28:55 2012 +0200
+++ b/libpurple/protocols/gg/Makefile.am	Tue Jun 26 22:38:37 2012 +0200
@@ -55,7 +55,9 @@
 	gg.h \
 	gg.c \
 	resolver-purple.h \
-	resolver-purple.c
+	resolver-purple.c \
+	image.h \
+	image.c
 
 AM_CFLAGS = $(st)
 
--- a/libpurple/protocols/gg/gg-utils.c	Mon Jun 25 18:28:55 2012 +0200
+++ b/libpurple/protocols/gg/gg-utils.c	Tue Jun 26 22:38:37 2012 +0200
@@ -50,6 +50,15 @@
 }
 /* }}} */
 
+const char * ggp_uin_to_str(uin_t uin)
+{
+	static char buff[GGP_UIN_LEN_MAX + 1];
+	
+	g_snprintf(buff, GGP_UIN_LEN_MAX + 1, "%u", uin);
+	
+	return buff;
+}
+
 /* unsigned int ggp_array_size(char **array) {{{ */
 unsigned int ggp_array_size(char **array)
 {
--- a/libpurple/protocols/gg/gg-utils.h	Mon Jun 25 18:28:55 2012 +0200
+++ b/libpurple/protocols/gg/gg-utils.h	Tue Jun 26 22:38:37 2012 +0200
@@ -37,6 +37,7 @@
 
 #include "gg.h"
 
+#define GGP_UIN_LEN_MAX 10
 
 /**
  * Convert a base 10 string to a UIN.
@@ -48,6 +49,8 @@
 uin_t
 ggp_str_to_uin(const char *str);
 
+const char * ggp_uin_to_str(uin_t uin);
+
 /**
  * Calculate size of a NULL-terminated array.
  *
--- a/libpurple/protocols/gg/gg.c	Mon Jun 25 18:28:55 2012 +0200
+++ b/libpurple/protocols/gg/gg.c	Tue Jun 26 22:38:37 2012 +0200
@@ -1456,47 +1456,6 @@
 	}
 }
 
-static void ggp_recv_image_handler(PurpleConnection *gc, const struct gg_event *ev)
-{
-	gint imgid = 0;
-	GGPInfo *info = purple_connection_get_protocol_data(gc);
-	GList *entry = g_list_first(info->pending_richtext_messages);
-	gchar *handlerid = g_strdup_printf("IMGID_HANDLER-%i", ev->event.image_reply.crc32);
-
-	imgid = purple_imgstore_add_with_id(
-		g_memdup(ev->event.image_reply.image, ev->event.image_reply.size),
-		ev->event.image_reply.size,
-		ev->event.image_reply.filename);
-
-	purple_debug_info("gg", "ggp_recv_image_handler: got image with crc32: %u\n", ev->event.image_reply.crc32);
-
-	while(entry) {
-		if (strstr((gchar *)entry->data, handlerid) != NULL) {
-			gchar **split = g_strsplit((gchar *)entry->data, handlerid, 3);
-			gchar *text = g_strdup_printf("%s%i%s", split[0], imgid, split[1]);
-			purple_debug_info("gg", "ggp_recv_image_handler: found message matching crc32: %s\n", (gchar *)entry->data);
-			g_strfreev(split);
-			info->pending_richtext_messages = g_list_remove(info->pending_richtext_messages, entry->data);
-			/* We don't have any more images to download */
-			if (strstr(text, "<IMG ID=\"IMGID_HANDLER") == NULL) {
-				gchar *buf = g_strdup_printf("%lu", (unsigned long int)ev->event.image_reply.sender);
-				serv_got_im(gc, buf, text, PURPLE_MESSAGE_IMAGES, time(NULL));
-				g_free(buf);
-				purple_debug_info("gg", "ggp_recv_image_handler: richtext message: %s\n", text);
-				g_free(text);
-				break;
-			}
-			info->pending_richtext_messages = g_list_append(info->pending_richtext_messages, text);
-			break;
-		}
-		entry = g_list_next(entry);
-	}
-	g_free(handlerid);
-
-	return;
-}
-
-
 /**
  * Dispatch a message received from a buddy.
  *
@@ -1513,6 +1472,7 @@
 	gchar *msg;
 	gchar *tmp;
 	time_t mtime;
+	uin_t sender = ev->event.msg.sender;
 
 	if (ev->event.msg.message == NULL)
 	{
@@ -1531,6 +1491,11 @@
 	msg = g_markup_escape_text(tmp, -1);
 	g_free(tmp);
 
+	if (ev->event.msg.msgclass & GG_CLASS_QUEUED)
+		mtime = ev->event.msg.time;
+	else
+		mtime = time(NULL);
+
 	/* We got richtext message */
 	if (ev->event.msg.formats_length)
 	{
@@ -1541,7 +1506,6 @@
 		struct gg_msg_richtext_format *actformat;
 		struct gg_msg_richtext_image *actimage;
 		GString *message = g_string_new(msg);
-		gchar *handlerid;
 
 		purple_debug_info("gg", "ggp_recv_message_handler: richtext msg from (%s): %s %i formats\n", from, msg, ev->event.msg.formats_length);
 
@@ -1564,7 +1528,10 @@
 				(actformat->font & GG_FONT_UNDERLINE) != 0,
 				increased_len);
 
-			if (actformat->font & GG_FONT_IMAGE) {
+			if (actformat->font & GG_FONT_IMAGE)
+			{
+				const char *placeholder;
+			
 				got_image = TRUE;
 				actimage = (struct gg_msg_richtext_image*)(cformats);
 				cformats += sizeof(struct gg_msg_richtext_image);
@@ -1580,10 +1547,9 @@
 				gg_image_request(info->session, ev->event.msg.sender,
 					actimage->size, actimage->crc32);
 
-				handlerid = g_strdup_printf("<IMG ID=\"IMGID_HANDLER-%i\">", actimage->crc32);
-				g_string_insert(message, byteoffset, handlerid);
-				increased_len += strlen(handlerid);
-				g_free(handlerid);
+				placeholder = ggp_image_pending_placeholder(actimage->crc32);
+				g_string_insert(message, byteoffset, placeholder);
+				increased_len += strlen(placeholder);
 				continue;
 			}
 
@@ -1631,8 +1597,9 @@
 		msg = message->str;
 		g_string_free(message, FALSE);
 
-		if (got_image) {
-			info->pending_richtext_messages = g_list_append(info->pending_richtext_messages, msg);
+		if (got_image)
+		{
+			ggp_image_got_im(gc, sender, msg, mtime);
 			return;
 		}
 	}
@@ -1641,11 +1608,6 @@
 			from, msg, ev->event.msg.msgclass,
 			ev->event.msg.recipients_count);
 
-	if (ev->event.msg.msgclass & GG_CLASS_QUEUED)
-		mtime = ev->event.msg.time;
-	else
-		mtime = time(NULL);
-
 	if (ev->event.msg.recipients_count == 0) {
 		serv_got_im(gc, from, msg, 0, mtime);
 	} else {
@@ -1680,11 +1642,12 @@
 	g_free(from);
 }
 
+/* TODO: image */
 static void ggp_send_image_handler(PurpleConnection *gc, const struct gg_event *ev)
 {
 	GGPInfo *info = purple_connection_get_protocol_data(gc);
 	PurpleStoredImage *image;
-	gint imgid = GPOINTER_TO_INT(g_hash_table_lookup(info->pending_images, GINT_TO_POINTER(ev->event.image_request.crc32)));
+	gint imgid = GPOINTER_TO_INT(g_hash_table_lookup(info->image_data.pending_images, GINT_TO_POINTER(ev->event.image_request.crc32)));
 
 	purple_debug_info("gg", "ggp_send_image_handler: image request received, crc32: %u, imgid: %d\n", ev->event.image_request.crc32, imgid);
 
@@ -1701,7 +1664,7 @@
 		} else {
 			purple_debug_error("gg", "ggp_send_image_handler: image imgid: %i, crc: %u in hash but not found in imgstore!\n", imgid, ev->event.image_request.crc32);
 		}
-		g_hash_table_remove(info->pending_images, GINT_TO_POINTER(ev->event.image_request.crc32));
+		g_hash_table_remove(info->image_data.pending_images, GINT_TO_POINTER(ev->event.image_request.crc32));
 	}
 }
 
@@ -1816,7 +1779,7 @@
 				ev->event.ack.seq);
 			break;
 		case GG_EVENT_IMAGE_REPLY:
-			ggp_recv_image_handler(gc, ev);
+			ggp_image_recv(gc, &ev->event.image_reply);
 			break;
 		case GG_EVENT_IMAGE_REQUEST:
 			ggp_send_image_handler(gc, ev);
@@ -2276,12 +2239,12 @@
 	info->chats_count = 0;
 	info->token = NULL;
 	info->searches = ggp_search_new();
-	info->pending_richtext_messages = NULL;
-	info->pending_images = g_hash_table_new(g_direct_hash, g_direct_equal);
 	info->status_broadcasting = purple_account_get_bool(account, "status_broadcasting", TRUE);
 	
 	purple_connection_set_protocol_data(gc, info);
 
+	ggp_image_setup(gc);
+	
 	glp->uin = ggp_get_uin(account);
 	glp->password = charset_convert(purple_account_get_password(account),
 		"UTF-8", "CP1250");
@@ -2395,8 +2358,7 @@
 		purple_notify_close_with_handle(gc);
 
 		ggp_search_destroy(info->searches);
-		g_list_free(info->pending_richtext_messages);
-		g_hash_table_destroy(info->pending_images);
+		ggp_image_free(gc);
 
 		if (info->inpa > 0)
 			purple_input_remove(info->inpa);
@@ -2443,6 +2405,7 @@
 				g_string_append_len(string_buffer, last, start - last);
 			}
 
+			/* TODO: image */
 			if((id = g_datalist_get_data(&attribs, "id")) && (image = purple_imgstore_find_by_id(atoi(id)))) {
 				struct gg_msg_richtext_format actformat;
 				struct gg_msg_richtext_image actimage;
@@ -2451,7 +2414,7 @@
 				const char *image_filename = purple_imgstore_get_filename(image);
 				uint32_t crc32 = gg_crc32(0, image_bin, image_size);
 
-				g_hash_table_insert(info->pending_images, GINT_TO_POINTER(crc32), GINT_TO_POINTER(atoi(id)));
+				g_hash_table_insert(info->image_data.pending_images, GINT_TO_POINTER(crc32), GINT_TO_POINTER(atoi(id)));
 				purple_imgstore_ref(image);
 				purple_debug_info("gg", "ggp_send_im_richtext: got crc: %u for imgid: %i\n", crc32, atoi(id));
 
--- a/libpurple/protocols/gg/gg.h	Mon Jun 25 18:28:55 2012 +0200
+++ b/libpurple/protocols/gg/gg.h	Tue Jun 26 22:38:37 2012 +0200
@@ -30,6 +30,8 @@
 #include "search.h"
 #include "connection.h"
 
+#include "image.h"
+
 
 #define PUBDIR_RESULTS_MAX 20
 
@@ -64,9 +66,9 @@
 	GList *chats;
 	GGPSearches *searches;
 	int chats_count;
-	GList *pending_richtext_messages;
-	GHashTable *pending_images;
 	gboolean status_broadcasting; //When TRUE status is visible to all, when FALSE status is visible only to friends.
+
+	ggp_image_connection_data image_data;
 } GGPInfo;
 
 #endif /* _PURPLE_GG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/gg/image.c	Tue Jun 26 22:38:37 2012 +0200
@@ -0,0 +1,141 @@
+#include "image.h"
+
+#include <debug.h>
+
+#include "gg.h"
+#include "gg-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;
+
+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 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(g_direct_hash, g_direct_equal);
+}
+
+void ggp_image_free(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); // TODO: remove content
+}
+
+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);
+}
+
+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_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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/protocols/gg/image.h	Tue Jun 26 22:38:37 2012 +0200
@@ -0,0 +1,24 @@
+#ifndef _GGP_IMAGE_H
+#define _GGP_IMAGE_H
+
+#include <internal.h>
+#include <libgadu.h>
+
+typedef struct
+{
+	GList *pending_messages;
+	GHashTable *pending_images;
+} ggp_image_connection_data;
+
+void ggp_image_setup(PurpleConnection *gc);
+void ggp_image_free(PurpleConnection *gc);
+
+const char * ggp_image_pending_placeholder(uint32_t id);
+
+void ggp_image_got_im(PurpleConnection *gc, uin_t from, gchar *msg,
+	time_t mtime);
+
+void ggp_image_recv(PurpleConnection *gc,
+	const struct gg_event_image_reply *image_reply);
+
+#endif /* _GGP_IMAGE_H */
--- a/libpurple/protocols/gg/resolver-purple.h	Mon Jun 25 18:28:55 2012 +0200
+++ b/libpurple/protocols/gg/resolver-purple.h	Tue Jun 26 22:38:37 2012 +0200
@@ -1,9 +1,9 @@
-#ifndef _PURPLE_GG_RESOLVER_PURPLE
-#define _PURPLE_GG_RESOLVER_PURPLE
+#ifndef _GGP_RESOLVER_PURPLE_H
+#define _GGP_RESOLVER_PURPLE_H
 
 /**
  * Registers custom resolver for libgadu, that uses libpurple for DNS queries.
  */
 void ggp_resolver_purple_setup(void);
 
-#endif /* _PURPLE_GG_RESOLVER_PURPLE */
+#endif /* _GGP_RESOLVER_PURPLE_H */

mercurial