# HG changeset patch # User Elliott Sales de Andrade # Date 1292576014 0 # Node ID b4064198e017e592114fe96e40e2358776992395 # Parent f91501dc406e4011d54c22129b04da31682bc1a7 Add functions for reading and writing a MsnFileContext which negates the need for any more packing. Fixes #12856. diff -r f91501dc406e -r b4064198e017 libpurple/protocols/msn/slp.c --- 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; } diff -r f91501dc406e -r b4064198e017 libpurple/protocols/msn/slp.h --- 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); diff -r f91501dc406e -r b4064198e017 libpurple/protocols/msn/slpcall.c --- 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; diff -r f91501dc406e -r b4064198e017 libpurple/protocols/msn/xfer.c --- 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; +} + diff -r f91501dc406e -r b4064198e017 libpurple/protocols/msn/xfer.h --- 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); +