diff src/protocols/msn/msg.c @ 9158:c30d81b4dd22

[gaim-migrate @ 9942] Patch from Felipe Contreras to sync our MSN prpl with what's in his tree. He says this may fix a couple bugs, but the important thing is the restructuring of how MsnMessages work. Lots of style changes and other stuff as well. committer: Tailor Script <tailor@pidgin.im>
author Christian Hammond <chipx86@chipx86.com>
date Tue, 01 Jun 2004 06:42:20 +0000
parents 9e5a709c30a8
children 502707ca1836
line wrap: on
line diff
--- a/src/protocols/msn/msg.c	Tue Jun 01 01:55:55 2004 +0000
+++ b/src/protocols/msn/msg.c	Tue Jun 01 06:42:20 2004 +0000
@@ -54,17 +54,6 @@
 		(((*((buf)+3)    )&0x000000ff)))
 
 
-/*
- * "MIME-Version: 1.0\r\n" == 19
- * "Content-Type: "        == 14
- * "\r\n"                  ==  2
- * "\r\n" before body      ==  2
- *                           ----
- *                            37
- *  MATH PAYS OFF!!
- */
-#define MSN_MESSAGE_BASE_SIZE 37
-
 MsnMessage *
 msn_message_new(void)
 {
@@ -74,14 +63,29 @@
 
 	msg->attr_table = g_hash_table_new_full(g_str_hash, g_str_equal,
 											g_free, g_free);
-	msg->size = MSN_MESSAGE_BASE_SIZE;
+
+	msn_message_ref(msg);
+
+	return msg;
+}
 
+MsnMessage *
+msn_message_new_plain(const char *message)
+{
+	MsnMessage *msg;
+	char *message_cr;
+
+	msg = msn_message_new();
 	msn_message_set_attr(msg, "User-Agent", "Gaim/" VERSION);
 	msn_message_set_content_type(msg, "text/plain");
 	msn_message_set_charset(msg, "UTF-8");
-	msn_message_set_flag(msg, 'U');
+	msn_message_set_flag(msg, 'N');
+	msn_message_set_attr(msg, "X-MMS-IM-Format",
+						 "FN=MS%20Sans%20Serif; EF=; CO=0; PF=0");
 
-	msn_message_ref(msg);
+	message_cr = gaim_str_add_cr(message);
+	msn_message_set_bin_data(msg, message_cr, strlen(message_cr));
+	g_free(message_cr);
 
 	return msg;
 }
@@ -96,11 +100,9 @@
 	msn_message_set_attr(msg, "User-Agent", NULL);
 
 	msg->msnslp_message = TRUE;
-	msg->size += 52;
 
 	msn_message_set_flag(msg, 'D');
 	msn_message_set_content_type(msg, "application/x-msnmsgrp2p");
-	msn_message_set_charset(msg, NULL);
 
 	return msg;
 }
@@ -118,35 +120,31 @@
 	msg->msnslp_ack_message = TRUE;
 	msg->acked_msg = msn_message_ref(acked_msg);
 
-	msg->msnslp_header.session_id     = acked_msg->msnslp_header.session_id;
-	msg->msnslp_header.total_size_1   = acked_msg->msnslp_header.total_size_1;
-	msg->msnslp_header.total_size_2   = acked_msg->msnslp_header.total_size_2;
-	msg->msnslp_header.flags          = 0x02;
-	msg->msnslp_header.ack_session_id = acked_msg->msnslp_header.session_id;
-	msg->msnslp_header.ack_unique_id  = acked_msg->msnslp_header.ack_session_id;
-	msg->msnslp_header.ack_length_1   = acked_msg->msnslp_header.total_size_1;
-	msg->msnslp_header.ack_length_2   = acked_msg->msnslp_header.total_size_2;
+	msg->msnslp_header.session_id  = acked_msg->msnslp_header.session_id;
+	msg->msnslp_header.total_size  = acked_msg->msnslp_header.total_size;
+	msg->msnslp_header.flags       = 0x02;
+	msg->msnslp_header.ack_id      = acked_msg->msnslp_header.id;
+	msg->msnslp_header.ack_sub_id  = acked_msg->msnslp_header.ack_id;
+	msg->msnslp_header.ack_size    = acked_msg->msnslp_header.total_size;
 
 	return msg;
 }
 
 void
-msn_message_parse_payload(MsnMessage *msg, const char *payload,
-						  size_t payload_len)
+msn_message_parse_payload(MsnMessage *msg,
+						  const char *payload, size_t payload_len)
 {
-	char *tmp_base, *tmp, *c;
+	char *tmp_base, *tmp;
 	const char *content_type;
 
-	tmp_base = g_malloc(payload_len + 1);
-	memcpy(tmp_base, payload, payload_len);
-	tmp_base[payload_len] = '\0';
+	g_return_if_fail(payload != NULL);
 
-	tmp = tmp_base;
+	tmp_base = tmp = g_memdup(payload, payload_len);
 
 	/* Back to the parsination. */
 	while (*tmp != '\r')
 	{
-		char *key, *value;
+		char *key, *value, *c;
 
 		key = tmp;
 
@@ -159,6 +157,9 @@
 		if ((c = strchr(key, ':')) != NULL)
 			*c = '\0';
 
+		if (!g_ascii_strcasecmp(key, "MIME-Version"))
+			continue;
+
 		if (!g_ascii_strcasecmp(key, "Content-Type"))
 		{
 			char *charset;
@@ -189,83 +190,43 @@
 	if (content_type != NULL &&
 		!strcmp(content_type, "application/x-msnmsgrp2p"))
 	{
-		char header[48];
-		char footer[4];
-		size_t body_len;
-		char *tmp2;
+		MsnSlpHeader header;
+		MsnSlpFooter footer;
 
 		msg->msnslp_message = TRUE;
 
-		memcpy(header, tmp, 48);
-
-		tmp += 48;
-
-		body_len = payload_len - (tmp - tmp_base) - 4;
-
-		if (body_len > 0)
-		{
-			msg->body = g_malloc(body_len + 1);
-			memcpy(msg->body, tmp, body_len);
-			msg->body[body_len] = '\0';
-
-			tmp++;
-		}
-		else
-			msg->body = NULL;
-
-		memcpy(footer, tmp, 4);
-
-		tmp += 4;
+		/* Import the header. */
+		memcpy(&header, tmp, sizeof(header));
+		tmp += sizeof(header);
 
-		/* Import the header. */
-		tmp2 = header;
-		msg->msnslp_header.session_id     = msn_get32(tmp2); tmp2 += 4;
-		msg->msnslp_header.id             = msn_get32(tmp2); tmp2 += 4;
-		msg->msnslp_header.offset_1       = msn_get32(tmp2); tmp2 += 4;
-		msg->msnslp_header.offset_2       = msn_get32(tmp2); tmp2 += 4;
-		msg->msnslp_header.total_size_1   = msn_get32(tmp2); tmp2 += 4;
-		msg->msnslp_header.total_size_2   = msn_get32(tmp2); tmp2 += 4;
-		msg->msnslp_header.length         = msn_get32(tmp2); tmp2 += 4;
-		msg->msnslp_header.flags          = msn_get32(tmp2); tmp2 += 4;
-		msg->msnslp_header.ack_session_id = msn_get32(tmp2); tmp2 += 4;
-		msg->msnslp_header.ack_unique_id  = msn_get32(tmp2); tmp2 += 4;
-		msg->msnslp_header.ack_length_1   = msn_get32(tmp2); tmp2 += 4;
-		msg->msnslp_header.ack_length_2   = msn_get32(tmp2); tmp2 += 4;
+		msg->msnslp_header.session_id = GUINT32_FROM_LE(header.session_id);
+		msg->msnslp_header.id         = GUINT64_FROM_LE(header.id);
+		msg->msnslp_header.offset     = GUINT64_FROM_LE(header.offset);
+		msg->msnslp_header.total_size = GUINT32_FROM_LE(header.total_size);
+		msg->msnslp_header.length     = GUINT32_FROM_LE(header.length);
+		msg->msnslp_header.flags      = GUINT32_FROM_LE(header.flags);
+		msg->msnslp_header.ack_id     = GUINT32_FROM_LE(header.ack_id);
+		msg->msnslp_header.ack_sub_id = GUINT32_FROM_LE(header.ack_sub_id);
+		msg->msnslp_header.ack_size   = GUINT64_FROM_LE(header.ack_size);
 
-		/* Convert to the right endianness */
-		msg->msnslp_header.session_id = ntohl(msg->msnslp_header.session_id);
-		msg->msnslp_header.id         = ntohl(msg->msnslp_header.id);
-		msg->msnslp_header.length     = ntohl(msg->msnslp_header.length);
-		msg->msnslp_header.flags      = ntohl(msg->msnslp_header.flags);
-		msg->msnslp_header.ack_length_1 =
-			ntohl(msg->msnslp_header.ack_length_1);
-		msg->msnslp_header.ack_length_2 =
-			ntohl(msg->msnslp_header.ack_length_2);
-		msg->msnslp_header.ack_session_id =
-			ntohl(msg->msnslp_header.ack_session_id);
-		msg->msnslp_header.ack_unique_id =
-			ntohl(msg->msnslp_header.ack_unique_id);
+		/* Import the body. */
+		msg->body_len = payload_len - (tmp - tmp_base) - sizeof(footer);
+		
+		if (msg->body_len > 0)
+			msg->body = g_memdup(tmp, msg->body_len);
+
+		tmp += msg->body_len;
 
 		/* Import the footer. */
-		msg->msnslp_footer.app_id = (long)footer;
+		memcpy(&footer, tmp, sizeof(footer));
+		tmp += sizeof(footer);
+
+		msg->msnslp_footer.value = GUINT32_FROM_BE(footer.value);
 	}
 	else
 	{
-		char *tmp2;
-		size_t body_len;
-
-		body_len = payload_len - (tmp - tmp_base);
-
-		tmp2 = g_malloc(body_len + 1);
-
-		if (body_len > 0)
-			memcpy(tmp2, tmp, body_len);
-
-		tmp2[body_len] = '\0';
-
-		msn_message_set_body(msg, tmp2);
-
-		g_free(tmp2);
+		msg->body_len = payload_len - (tmp - tmp_base);
+		msg->body = g_memdup(tmp, msg->body_len);
 	}
 
 	g_free(tmp_base);
@@ -300,7 +261,6 @@
 	if (msg->msnslp_ack_message)
 		msn_message_unref(msg->acked_msg);
 
-	gaim_debug(GAIM_DEBUG_INFO, "msn", "Destroying message\n");
 	g_free(msg);
 }
 
@@ -337,151 +297,99 @@
 msn_message_gen_payload(const MsnMessage *msg, size_t *ret_size)
 {
 	GList *l;
-	char *str;
-	char buf[MSN_BUF_LEN];
+	char *n, *base, *end;
 	int len;
+	size_t body_len;
+	const void *body;
 
-	/*
-	 * Okay, how we do things here is just bad. I don't like writing to
-	 * a static buffer and then copying to the string. Unfortunately,
-	 * just trying to append to the string is causing issues.. Such as
-	 * the string you're appending to being erased. Ugh. So, this is
-	 * good enough for now.
-	 *
-	 *     -- ChipX86
-	 */
 	g_return_val_if_fail(msg != NULL, NULL);
 
-	len = msg->size + 1;
+	len = MSN_BUF_LEN;
 
-	str = g_new0(char, len + 1);
+	base = n = end = g_malloc(len + 1);
+	end += len;
 
 	/* Standard header. */
 	if (msg->charset == NULL)
 	{
-		g_snprintf(buf, sizeof(buf),
+		g_snprintf(n, len,
 				   "MIME-Version: 1.0\r\n"
 				   "Content-Type: %s\r\n",
 				   msg->content_type);
 	}
 	else
 	{
-		g_snprintf(buf, sizeof(buf),
+		g_snprintf(n, len,
 				   "MIME-Version: 1.0\r\n"
 				   "Content-Type: %s; charset=%s\r\n",
 				   msg->content_type, msg->charset);
 	}
 
-	g_strlcat(str, buf, len);
+	n += strlen(n);
 
 	for (l = msg->attr_list; l != NULL; l = l->next)
 	{
-		const char *key = (char *)l->data;
+		const char *key;
 		const char *value;
 
+		key = l->data;
 		value = msn_message_get_attr(msg, key);
 
-		g_snprintf(buf, sizeof(buf), "%s: %s\r\n", key, value);
-
-		g_strlcat(str, buf, len);
+		g_snprintf(n, end - n, "%s: %s\r\n", key, value);
+		n += strlen(n);
 	}
 
-	g_strlcat(str, "\r\n", len);
+	n += g_strlcpy(n, "\r\n", end - n);
+
+	body = msn_message_get_bin_data(msg, &body_len);
 
 	if (msg->msnslp_message)
 	{
-		char *c;
-		long session_id, id, offset_1, offset_2, total_size_1, total_size_2;
-		long length, flags;
-		long ack_session_id, ack_unique_id, ack_length_1, ack_length_2;
-
-		c = str + strlen(str);
-
-		session_id      = htonl(msg->msnslp_header.session_id);
-		id              = htonl(msg->msnslp_header.id);
-		offset_1        = htonl(msg->msnslp_header.offset_1);
-		offset_2        = htonl(msg->msnslp_header.offset_2);
-		total_size_1    = htonl(msg->msnslp_header.total_size_1);
-		total_size_2    = htonl(msg->msnslp_header.total_size_2);
-		length          = htonl(msg->msnslp_header.length);
-		flags           = htonl(msg->msnslp_header.flags);
-		ack_session_id  = htonl(msg->msnslp_header.ack_session_id);
-		ack_unique_id   = htonl(msg->msnslp_header.ack_unique_id);
-		ack_length_1    = htonl(msg->msnslp_header.ack_length_1);
-		ack_length_2    = htonl(msg->msnslp_header.ack_length_2);
+		MsnSlpHeader header;
+		MsnSlpFooter footer;
 
-		c += msn_put32(c, session_id);
-		c += msn_put32(c, id);
-		c += msn_put32(c, offset_1);
-		c += msn_put32(c, offset_2);
-		c += msn_put32(c, total_size_1);
-		c += msn_put32(c, total_size_2);
-		c += msn_put32(c, length);
-		c += msn_put32(c, flags);
-		c += msn_put32(c, ack_session_id);
-		c += msn_put32(c, ack_unique_id);
-		c += msn_put32(c, ack_length_1);
-		c += msn_put32(c, ack_length_2);
-
-		if (msg->bin_content)
-		{
-			size_t bin_len;
-			const void *body = msn_message_get_bin_data(msg, &bin_len);
+		header.session_id = GUINT32_TO_LE(msg->msnslp_header.session_id);
+		header.id         = GUINT64_TO_LE(msg->msnslp_header.id);
+		header.offset     = GUINT64_TO_LE(msg->msnslp_header.offset);
+		header.total_size = GUINT32_TO_LE(msg->msnslp_header.total_size);
+		header.length     = GUINT32_TO_LE(msg->msnslp_header.length);
+		header.flags      = GUINT32_TO_LE(msg->msnslp_header.flags);
+		header.ack_id     = GUINT32_TO_LE(msg->msnslp_header.ack_id);
+		header.ack_sub_id = GUINT32_TO_LE(msg->msnslp_header.ack_sub_id);
+		header.ack_size   = GUINT64_TO_LE(msg->msnslp_header.ack_size);
 
-			if (body != NULL)
-			{
-				memcpy(c, body, bin_len);
+		memcpy(n, &header, 48);
+		n += 48;
 
-				c += bin_len;
-			}
-		}
-		else
+		if (body != NULL)
 		{
-			const char *body = msn_message_get_body(msg);
-
-			if (body != NULL)
-			{
-				g_strlcpy(c, body, msg->size - (c - str));
-
-				c += strlen(body);
-
-				if (strlen(body) > 0)
-					*c++ = '\0';
-			}
+			memcpy(n, body, body_len);
+			n += body_len;
 		}
 
-		c += msn_put32(c, msg->msnslp_footer.app_id);
+		footer.value = GUINT32_TO_BE(msg->msnslp_footer.value);
 
-		if (msg->size != (c - str))
-		{
-			gaim_debug(GAIM_DEBUG_ERROR, "msn",
-					   "Outgoing message size (%d) and data length (%d) "
-					   "do not match!\n", msg->size, (c - str));
-		}
+		memcpy(n, &footer, 4);
+		n += 4;
 	}
 	else
 	{
-		const char *body = msn_message_get_body(msg);
-
-		g_strlcat(str, body, len);
-
-		if (msg->size != strlen(str))
+		if (body != NULL)
 		{
-			gaim_debug(GAIM_DEBUG_ERROR, "msn",
-					   "Outgoing message size (%d) and string length (%d) "
-					   "do not match!\n", msg->size, strlen(str));
+			memcpy(n, body, body_len);
+			n += body_len;
 		}
 	}
 
 	if (ret_size != NULL)
 	{
-		*ret_size = len - 1;
+		*ret_size = n - base;
 
 		if (*ret_size > 1664)
 			*ret_size = 1664;
 	}
 
-	return str;
+	return base;
 }
 
 void
@@ -502,98 +410,26 @@
 }
 
 void
-msn_message_set_body(MsnMessage *msg, const char *body)
-{
-	const char *c;
-	char *buf, *d;
-	int newline_count = 0;
-	size_t new_len;
-
-	g_return_if_fail(msg  != NULL);
-
-	if (msg->bin_content)
-	{
-		msn_message_set_bin_data(msg, NULL, 0);
-		return;
-	}
-
-	if (msg->body != NULL) {
-		msg->size -= strlen(msg->body);
-		g_free(msg->body);
-
-		if (msg->msnslp_message)
-			msg->size--;
-	}
-
-	if (body != NULL)
-	{
-		for (c = body; *c != '\0'; c++)
-		{
-			if (*c == '\n' && (c == body || *(c - 1) != '\r'))
-				newline_count++;
-		}
-
-		new_len = strlen(body) + newline_count;
-
-		buf = g_new0(char, new_len + 1);
-
-		for (c = body, d = buf; *c != '\0'; c++) {
-			if (*c == '\n' && (c == body || *(c - 1) != '\r')) {
-				*d++ = '\r';
-				*d++ = '\n';
-			}
-			else
-				*d++ = *c;
-		}
-
-		msg->body = buf;
-		msg->size += new_len;
-
-		msg->bin_content = FALSE;
-
-		if (msg->msnslp_message)
-			msg->size++;
-	}
-	else
-		msg->body = NULL;
-}
-
-const char *
-msn_message_get_body(const MsnMessage *msg)
-{
-	g_return_val_if_fail(msg != NULL, NULL);
-	g_return_val_if_fail(!msg->bin_content, NULL);
-
-	return msg->body;
-}
-
-void
 msn_message_set_bin_data(MsnMessage *msg, const void *data, size_t len)
 {
 	g_return_if_fail(msg != NULL);
 
-	if (!msg->bin_content)
-		msn_message_set_body(msg, NULL);
-
-	msg->bin_content = TRUE;
+	/* There is no need to waste memory on data we cannot send anyway */
+	if (len > 1664)
+		len = 1664;
 
 	if (msg->body != NULL)
-	{
-		msg->size -= msg->bin_len;
 		g_free(msg->body);
-	}
 
 	if (data != NULL && len > 0)
 	{
 		msg->body = g_memdup(data, len);
-		msg->bin_len = len;
-
-		msg->size += len;
+		msg->body_len = len;
 	}
 	else
 	{
 		msg->body = NULL;
-		msg->bin_len = 0;
+		msg->body_len = 0;
 	}
 }
 
@@ -601,10 +437,9 @@
 msn_message_get_bin_data(const MsnMessage *msg, size_t *len)
 {
 	g_return_val_if_fail(msg != NULL, NULL);
-	g_return_val_if_fail(len != NULL, NULL);
-	g_return_val_if_fail(msg->bin_content, NULL);
 
-	*len = msg->bin_len;
+	if (len)
+		*len = msg->body_len;
 
 	return msg->body;
 }
@@ -614,16 +449,11 @@
 {
 	g_return_if_fail(msg != NULL);
 
-	if (msg->content_type != NULL) {
-		msg->size -= strlen(msg->content_type);
+	if (msg->content_type != NULL)
 		g_free(msg->content_type);
-	}
 
-	if (type != NULL) {
+	if (type != NULL)
 		msg->content_type = g_strdup(type);
-
-		msg->size += strlen(type);
-	}
 	else
 		msg->content_type = NULL;
 }
@@ -641,16 +471,11 @@
 {
 	g_return_if_fail(msg != NULL);
 
-	if (msg->charset != NULL) {
-		msg->size -= strlen(msg->charset) + strlen("; charset=");
+	if (msg->charset != NULL)
 		g_free(msg->charset);
-	}
 
-	if (charset != NULL) {
+	if (charset != NULL)
 		msg->charset = g_strdup(charset);
-
-		msg->size += strlen(charset) + strlen("; charset=");
-	}
 	else
 		msg->charset = NULL;
 }
@@ -674,14 +499,16 @@
 
 	temp = msn_message_get_attr(msg, attr);
 
-	if (value == NULL) {
-		if (temp != NULL) {
+	if (value == NULL)
+	{
+		if (temp != NULL)
+		{
 			GList *l;
 
-			msg->size -= strlen(temp) + strlen(attr) + 4;
-
-			for (l = msg->attr_list; l != NULL; l = l->next) {
-				if (!g_ascii_strcasecmp(l->data, attr)) {
+			for (l = msg->attr_list; l != NULL; l = l->next)
+			{
+				if (!g_ascii_strcasecmp(l->data, attr))
+				{
 					msg->attr_list = g_list_remove(msg->attr_list, l->data);
 
 					break;
@@ -698,14 +525,8 @@
 
 	g_hash_table_insert(msg->attr_table, new_attr, g_strdup(value));
 
-	if (temp == NULL) {
+	if (temp == NULL)
 		msg->attr_list = g_list_append(msg->attr_list, new_attr);
-		msg->size += strlen(attr) + 4;
-	}
-	else
-		msg->size -= strlen(temp);
-
-	msg->size += strlen(value);
 }
 
 const char *
@@ -724,13 +545,15 @@
 	char *body, *s, *c;
 
 	g_return_val_if_fail(msg != NULL, NULL);
-	g_return_val_if_fail(msn_message_get_body(msg) != NULL, NULL);
 
-	s = body = g_strdup(msn_message_get_body(msg));
+	s = body = g_strdup(msn_message_get_bin_data(msg, NULL));
+
+	g_return_val_if_fail(body != NULL, NULL);
 
 	table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 
-	while (*s != '\r' && *s != '\0') {
+	while (*s != '\r' && *s != '\0')
+	{
 		char *key, *value;
 
 		key = s;
@@ -741,7 +564,8 @@
 
 		GET_NEXT_LINE(s);
 
-		if ((c = strchr(key, ':')) != NULL) {
+		if ((c = strchr(key, ':')) != NULL)
+		{
 			*c = '\0';
 
 			g_hash_table_insert(table, g_strdup(key), g_strdup(value));
@@ -752,4 +576,3 @@
 
 	return table;
 }
-