changeset 31493:b4064198e017

Add functions for reading and writing a MsnFileContext which negates the need for any more packing. Fixes #12856.
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Fri, 17 Dec 2010 08:53:34 +0000
parents f91501dc406e
children a6d2d7de8a08
files libpurple/protocols/msn/slp.c libpurple/protocols/msn/slp.h libpurple/protocols/msn/slpcall.c libpurple/protocols/msn/xfer.c libpurple/protocols/msn/xfer.h
diffstat 5 files changed, 127 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/msn/slp.c	Fri Dec 17 07:58:33 2010 +0000
+++ b/libpurple/protocols/msn/slp.c	Fri Dec 17 08:53:34 2010 +0000
@@ -293,7 +293,7 @@
 gen_context(PurpleXfer *xfer, const char *file_name, const char *file_path)
 {
 	gsize size = 0;
-	MsnFileContext *header;
+	MsnFileContext header;
 	gchar *u8 = NULL;
 	gchar *ret;
 	gunichar2 *uni = NULL;
@@ -322,32 +322,34 @@
 	}
 
 	preview = purple_xfer_get_thumbnail(xfer, &preview_len);
-	header = g_malloc(sizeof(MsnFileContext) + preview_len);
 
-	header->length = GUINT32_TO_LE(sizeof(MsnFileContext) - 1);
-	header->version = GUINT32_TO_LE(2); /* V.3 contains additional unnecessary data */
-	header->file_size = GUINT64_TO_LE(size);
+	header.length = MSN_FILE_CONTEXT_SIZE;
+	header.version = 2; /* V.3 contains additional unnecessary data */
+	header.file_size = size;
 	if (preview)
-		header->type = GUINT32_TO_LE(0);
+		header.type = 0;
 	else
-		header->type = GUINT32_TO_LE(1);
+		header.type = 1;
 
 	len = MIN(len, MAX_FILE_NAME_LEN);
 	for (currentChar = 0; currentChar < len; currentChar++) {
-		header->file_name[currentChar] = GUINT16_TO_LE(uni[currentChar]);
+		header.file_name[currentChar] = GUINT16_TO_LE(uni[currentChar]);
 	}
-	memset(&header->file_name[currentChar], 0x00, (MAX_FILE_NAME_LEN - currentChar) * 2);
+	memset(&header.file_name[currentChar], 0x00, (MAX_FILE_NAME_LEN - currentChar) * 2);
+
+	memset(&header.unknown1, 0, sizeof(header.unknown1));
+	header.unknown2 = 0xffffffff;
 
-	memset(&header->unknown1, 0, sizeof(header->unknown1));
-	header->unknown2 = GUINT32_TO_LE(0xffffffff);
-	if (preview) {
-		memcpy(&header->preview, preview, preview_len);
-	}
-	header->preview[preview_len] = '\0';
+	/* Mind the cast, as in, don't free it after! */
+	header.preview = (char *)preview;
+	header.preview_len = preview_len;
+
+	u8 = msn_file_context_to_wire(&header);
+	ret = purple_base64_encode((const guchar *)u8, MSN_FILE_CONTEXT_SIZE + preview_len);
 
 	g_free(uni);
-	ret = purple_base64_encode((const guchar *)header, sizeof(MsnFileContext) + preview_len);
-	g_free(header);
+	g_free(u8);
+
 	return ret;
 }
 
--- a/libpurple/protocols/msn/slp.h	Fri Dec 17 07:58:33 2010 +0000
+++ b/libpurple/protocols/msn/slp.h	Fri Dec 17 08:53:34 2010 +0000
@@ -32,25 +32,6 @@
 #include "slplink.h"
 #include "user.h"
 
-#define MAX_FILE_NAME_LEN 260 /* MAX_PATH in Windows */
-
-/**
- * The context data for a file transfer request
- */
-#pragma pack(push,1) /* Couldn't they have made it the right size? */
-typedef struct
-{
-	guint32   length;       /*< Length of header */
-	guint32   version;      /*< MSN version */
-	guint64   file_size;    /*< Size of file */
-	guint32   type;         /*< Transfer type */
-	gunichar2 file_name[MAX_FILE_NAME_LEN]; /*< Self-explanatory */
-	gchar     unknown1[30]; /*< Used somehow for background sharing */
-	guint32   unknown2;     /*< Possibly for background sharing as well */
-	gchar     preview[1];   /*< File preview data, 96x96 PNG */
-} MsnFileContext;
-#pragma pack(pop)
-
 void
 msn_slp_send_ok(MsnSlpCall *slpcall, const char *branch,
 		const char *type, const char *content);
--- a/libpurple/protocols/msn/slpcall.c	Fri Dec 17 07:58:33 2010 +0000
+++ b/libpurple/protocols/msn/slpcall.c	Fri Dec 17 08:53:34 2010 +0000
@@ -512,6 +512,7 @@
 		PurpleAccount *account;
 		PurpleXfer *xfer;
 		MsnFileContext *header;
+		char *buf;
 		gsize bin_len;
 		guint32 file_size;
 		char *file_name;
@@ -526,11 +527,11 @@
 		xfer = purple_xfer_new(account, PURPLE_XFER_RECEIVE,
 							 slpcall->slplink->remote_user);
 
-		header = (MsnFileContext *)purple_base64_decode(context, &bin_len);
-		if (header != NULL && bin_len >= sizeof(MsnFileContext) - 1 &&
-			(header->version == 2 ||
-			 (header->version == 3 && header->length == sizeof(MsnFileContext) + 63))) {
-			file_size = GUINT64_FROM_LE(header->file_size);
+		buf = (char *)purple_base64_decode(context, &bin_len);
+		header = msn_file_context_from_wire(buf, bin_len);
+
+		if (header != NULL) {
+			file_size = header->file_size;
 
 			file_name = g_convert((const gchar *)&header->file_name,
 			                      MAX_FILE_NAME_LEN * 2,
@@ -553,15 +554,17 @@
 
 			xfer->data = slpcall;
 
-			if (header->type == 0 && bin_len >= sizeof(MsnFileContext)) {
-				purple_xfer_set_thumbnail(xfer, &header->preview,
-				                          bin_len - sizeof(MsnFileContext),
+			if (header->preview) {
+				purple_xfer_set_thumbnail(xfer, header->preview,
+				                          header->preview_len,
 				    					  "image/png");
+				g_free(header->preview);
 			}
 
 			purple_xfer_request(xfer);
 		}
 		g_free(header);
+		g_free(buf);
 
 		accepted = TRUE;
 
--- a/libpurple/protocols/msn/xfer.c	Fri Dec 17 07:58:33 2010 +0000
+++ b/libpurple/protocols/msn/xfer.c	Fri Dec 17 08:53:34 2010 +0000
@@ -25,6 +25,7 @@
 #include "internal.h"
 #include "debug.h"
 
+#include "msnutils.h"
 #include "sbconn.h"
 #include "xfer.h"
 
@@ -160,3 +161,72 @@
 	purple_xfer_end(xfer);
 }
 
+gchar *
+msn_file_context_to_wire(MsnFileContext *header)
+{
+	gchar *ret, *tmp;
+
+	tmp = ret = g_new(gchar, MSN_FILE_CONTEXT_SIZE + header->preview_len + 1);
+
+	msn_push32le(tmp, header->length);
+	msn_push32le(tmp, header->version);
+	msn_push64le(tmp, header->file_size);
+	msn_push32le(tmp, header->type);
+	memcpy(tmp, header->file_name, MAX_FILE_NAME_LEN * 2);
+	tmp += MAX_FILE_NAME_LEN * 2;
+	memcpy(tmp, header->unknown1, sizeof(header->unknown1));
+	tmp += sizeof(header->unknown1);
+	msn_push32le(tmp, header->unknown2);
+	if (header->preview) {
+		memcpy(tmp, header->preview, header->preview_len);
+	}
+	tmp[header->preview_len] = '\0';
+
+	return ret;
+}
+
+MsnFileContext *
+msn_file_context_from_wire(const char *buf, gsize len)
+{
+	MsnFileContext *header;
+
+	if (!buf || len < MSN_FILE_CONTEXT_SIZE)
+		return NULL;
+
+	header = g_new(MsnFileContext, 1);
+
+	header->length = msn_pop32le(buf);
+	header->version = msn_pop32le(buf);
+	if (header->version == 2) {
+		/* The length field is broken for this version. No check. */
+		header->length = MSN_FILE_CONTEXT_SIZE;
+	} else if (header->version == 3) {
+		if (header->length != MSN_FILE_CONTEXT_SIZE + 63) {
+			g_free(header);
+			return NULL;
+		} else if (len < MSN_FILE_CONTEXT_SIZE + 63) {
+			g_free(header);
+			return NULL;
+		}
+	} else {
+		purple_debug_warning("msn", "Received MsnFileContext with unknown version: %d\n", header->version);
+		g_free(header);
+		return NULL;
+	}
+
+	header->file_size = msn_pop64le(buf);
+	header->type = msn_pop32le(buf);
+	memcpy(header->file_name, buf, MAX_FILE_NAME_LEN * 2);
+	buf += MAX_FILE_NAME_LEN * 2;
+	memcpy(header->unknown1, buf, sizeof(header->unknown1));
+	buf += sizeof(header->unknown1);
+	header->unknown2 = msn_pop32le(buf);
+
+	if (header->type == 0 && len > header->length) {
+		header->preview_len = len - header->length;
+		header->preview = g_memdup(buf, header->preview_len);
+	}
+
+	return header;
+}
+
--- a/libpurple/protocols/msn/xfer.h	Fri Dec 17 07:58:33 2010 +0000
+++ b/libpurple/protocols/msn/xfer.h	Fri Dec 17 08:53:34 2010 +0000
@@ -25,6 +25,26 @@
 
 #include "slpcall.h"
 
+#define MAX_FILE_NAME_LEN 260 /* MAX_PATH in Windows */
+
+/**
+ * The context data for a file transfer request
+ */
+typedef struct
+{
+	guint32   length;       /*< Length of header */
+	guint32   version;      /*< MSN version */
+	guint64   file_size;    /*< Size of file */
+	guint32   type;         /*< Transfer type */
+	gunichar2 file_name[MAX_FILE_NAME_LEN]; /*< Self-explanatory */
+	gchar     unknown1[30]; /*< Used somehow for background sharing */
+	guint32   unknown2;     /*< Possibly for background sharing as well */
+	gchar     *preview;     /*< File preview data, 96x96 PNG */
+	gsize     preview_len;
+} MsnFileContext;
+
+#define MSN_FILE_CONTEXT_SIZE (4*4 + 1*8 + 2*MAX_FILE_NAME_LEN + 30)
+
 void msn_xfer_init(PurpleXfer *xfer);
 void msn_xfer_cancel(PurpleXfer *xfer);
 
@@ -34,3 +54,10 @@
 void msn_xfer_completed_cb(MsnSlpCall *slpcall,
 						   const guchar *body, gsize size);
 void msn_xfer_end_cb(MsnSlpCall *slpcall, MsnSession *session);
+
+gchar *
+msn_file_context_to_wire(MsnFileContext *header);
+
+MsnFileContext *
+msn_file_context_from_wire(const char *buf, gsize len);
+