summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliott Sales de Andrade <qulogic@pidgin.im>2010-02-28 02:11:57 +0000
committerElliott Sales de Andrade <qulogic@pidgin.im>2010-02-28 02:11:57 +0000
commit5ff6919005fd1603bca53fc950a9a00b362a410f (patch)
tree1bd58e0c2b655a0b4984196fec49544325bacda0
parent2bc2a1d633284fe7d3cf858ccbf7952af09e7e26 (diff)
downloadpidgin-5ff6919005fd1603bca53fc950a9a00b362a410f.tar.gz
I never liked randomly poking at offsets. Fortunately, I was able to find
an old document by Siebe on the Internet Archive that explained (as best possible) the FT request Context field. Also, make the incoming request handling a bit stricter.
-rw-r--r--libpurple/protocols/msn/slp.c21
-rw-r--r--libpurple/protocols/msn/slp.h19
-rw-r--r--libpurple/protocols/msn/slplink.c57
3 files changed, 47 insertions, 50 deletions
diff --git a/libpurple/protocols/msn/slp.c b/libpurple/protocols/msn/slp.c
index 37061ceac0..c1a9fe9a7d 100644
--- a/libpurple/protocols/msn/slp.c
+++ b/libpurple/protocols/msn/slp.c
@@ -308,8 +308,6 @@ find_valid_emoticon(PurpleAccount *account, const char *path)
return NULL;
}
-#define MAX_FILE_NAME_LEN 0x226
-
static void
got_sessionreq(MsnSlpCall *slpcall, const char *branch,
const char *euf_guid, const char *context)
@@ -382,7 +380,7 @@ got_sessionreq(MsnSlpCall *slpcall, const char *branch,
/* File Transfer */
PurpleAccount *account;
PurpleXfer *xfer;
- char *bin;
+ MsnFileContext *header;
gsize bin_len;
guint32 file_size;
char *file_name;
@@ -396,15 +394,17 @@ got_sessionreq(MsnSlpCall *slpcall, const char *branch,
xfer = purple_xfer_new(account, PURPLE_XFER_RECEIVE,
slpcall->slplink->remote_user);
- if (xfer)
- {
- bin = (char *)purple_base64_decode(context, &bin_len);
- file_size = GUINT32_FROM_LE(*(gsize *)(bin + 8));
- file_name = g_convert(bin + 20, MAX_FILE_NAME_LEN, "UTF-8", "UTF-16LE",
- NULL, NULL, NULL);
+ header = (MsnFileContext *)purple_base64_decode(context, &bin_len);
+ if (bin_len >= sizeof(MsnFileContext) - 1 &&
+ header->length == sizeof(MsnFileContext) - 1 &&
+ header->version == 2) {
+ file_size = GUINT64_FROM_LE(header->file_size);
- g_free(bin);
+ file_name = g_convert((const gchar *)&header->file_name,
+ MAX_FILE_NAME_LEN * 2,
+ "UTF-8", "UTF-16LE",
+ NULL, NULL, NULL);
purple_xfer_set_filename(xfer, file_name ? file_name : "");
g_free(file_name);
@@ -424,6 +424,7 @@ got_sessionreq(MsnSlpCall *slpcall, const char *branch,
purple_xfer_request(xfer);
}
+ g_free(header);
accepted = TRUE;
diff --git a/libpurple/protocols/msn/slp.h b/libpurple/protocols/msn/slp.h
index 2b7ef672e8..a340fbe6c7 100644
--- a/libpurple/protocols/msn/slp.h
+++ b/libpurple/protocols/msn/slp.h
@@ -30,6 +30,25 @@
#include "session.h"
#include "slpcall.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)
+
MsnSlpCall * msn_slp_sip_recv(MsnSlpLink *slplink,
const char *body);
diff --git a/libpurple/protocols/msn/slplink.c b/libpurple/protocols/msn/slplink.c
index 640943fb91..60c1308ddb 100644
--- a/libpurple/protocols/msn/slplink.c
+++ b/libpurple/protocols/msn/slplink.c
@@ -658,74 +658,51 @@ msn_slplink_process_msg(MsnSlpLink *slplink, MsnMessage *msg)
}
}
-typedef struct
-{
- guint32 length;
- guint32 unk1;
- guint32 file_size;
- guint32 unk2;
- guint32 unk3;
-} MsnContextHeader;
-
-#define MAX_FILE_NAME_LEN 0x226
-
static gchar *
gen_context(PurpleXfer *xfer, const char *file_name, const char *file_path)
{
gsize size = 0;
- MsnContextHeader header;
+ MsnFileContext header;
gchar *u8 = NULL;
- guchar *base;
- guchar *n;
gchar *ret;
gunichar2 *uni = NULL;
glong currentChar = 0;
- glong uni_len = 0;
- gsize len;
+ glong len = 0;
size = purple_xfer_get_size(xfer);
- if(!file_name) {
+ if (!file_name) {
gchar *basename = g_path_get_basename(file_path);
u8 = purple_utf8_try_convert(basename);
g_free(basename);
file_name = u8;
}
- uni = g_utf8_to_utf16(file_name, -1, NULL, &uni_len, NULL);
+ uni = g_utf8_to_utf16(file_name, -1, NULL, &len, NULL);
- if(u8) {
+ if (u8) {
g_free(u8);
file_name = NULL;
u8 = NULL;
}
- len = sizeof(MsnContextHeader) + MAX_FILE_NAME_LEN + 4;
-
- header.length = GUINT32_TO_LE(len);
- header.unk1 = GUINT32_TO_LE(2);
- header.file_size = GUINT32_TO_LE(size);
- header.unk2 = GUINT32_TO_LE(0);
- header.unk3 = GUINT32_TO_LE(0);
-
- base = g_malloc(len + 1);
- n = base;
-
- memcpy(n, &header, sizeof(MsnContextHeader));
- n += sizeof(MsnContextHeader);
+ header.length = GUINT32_TO_LE(sizeof(MsnFileContext));
+ header.version = GUINT32_TO_LE(2); /* V.3 contains additional unnecessary data */
+ header.file_size = GUINT64_TO_LE(size);
+ header.type = GUINT32_TO_LE(1); /* No file preview */
- memset(n, 0x00, MAX_FILE_NAME_LEN);
- for(currentChar = 0; currentChar < uni_len; currentChar++) {
- *((gunichar2 *)n + currentChar) = GUINT16_TO_LE(uni[currentChar]);
+ len = MIN(len, MAX_FILE_NAME_LEN);
+ for (currentChar = 0; currentChar < len; currentChar++) {
+ header.file_name[currentChar] = GUINT16_TO_LE(uni[currentChar]);
}
- n += MAX_FILE_NAME_LEN;
+ memset(&header.file_name[currentChar], 0x00, (MAX_FILE_NAME_LEN - currentChar) * 2);
- memset(n, 0xFF, 4);
- n += 4;
+ memset(&header.unknown1, 0, sizeof(header.unknown1));
+ header.unknown2 = GUINT32_TO_LE(0xffffffff);
+ header.preview[0] = '\0';
g_free(uni);
- ret = purple_base64_encode(base, len);
- g_free(base);
+ ret = purple_base64_encode((const guchar *)&header, sizeof(MsnFileContext));
return ret;
}