changeset 8646:1e211dde3cae

[gaim-migrate @ 9398] Added a patch by shx to clean up the message-handling code and split the command stuff from it, among a few other things. Also, I fixed a crash in message parsing, which I think may close a couple bug reports. committer: Tailor Script <tailor@pidgin.im>
author Christian Hammond <chipx86@chipx86.com>
date Tue, 13 Apr 2004 04:08:22 +0000
parents 47f647dd2ac3
children d16e1bfaf08a
files src/protocols/msn/msg.c src/protocols/msn/msg.h src/protocols/msn/msn.c src/protocols/msn/msnslp.c src/protocols/msn/notification.c src/protocols/msn/page.c src/protocols/msn/page.h src/protocols/msn/servconn.c src/protocols/msn/servconn.h src/protocols/msn/switchboard.c src/protocols/msn/utils.c
diffstat 11 files changed, 365 insertions(+), 827 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/msn/msg.c	Tue Apr 13 03:53:37 2004 +0000
+++ b/src/protocols/msn/msg.c	Tue Apr 13 04:08:22 2004 +0000
@@ -130,86 +130,22 @@
 	return msg;
 }
 
-MsnMessage *
-msn_message_new_from_str(MsnSession *session, const char *str)
+void
+msn_message_parse_payload(MsnMessage *msg, const char *payload,
+						  size_t payload_len)
 {
-	MsnMessage *msg;
-	char *command_header;
-	char *tmp_base, *msg_base, *tmp, *field1, *field2, *c;
+	char *tmp_base, *tmp, *c;
 	const char *content_type;
-	const char *c2;
-
-	g_return_val_if_fail(str != NULL, NULL);
-	g_return_val_if_fail(!g_ascii_strncasecmp(str, "MSG", 3), NULL);
-
-	msg = msn_message_new();
-
-	/* Clear out the old stuff. */
-	msn_message_set_attr(msg, "User-Agent", NULL);
-	msn_message_set_content_type(msg, NULL);
-	msn_message_set_charset(msg, NULL);
 
-	/*
-	 * We need to grab the header and then the size, since this might have
-	 * binary data.
-	 */
-	if ((c2 = strchr(str, '\r')) != NULL)
-	{
-		tmp = command_header = g_strndup(str, (c2 - str));
-
-		GET_NEXT(tmp); /* Skip MSG */
-		field1 = tmp;
-
-		GET_NEXT(tmp); /* Skip the passport or TID */
-		field2 = tmp;
-
-		GET_NEXT(tmp); /* Skip the username or flag */
-		msg->size = atoi(tmp);
-	}
-	else
-	{
-		/* Kind of screwed :) This won't happen. */
-		msn_message_destroy(msg);
-
-		return NULL;
-	}
-
-	tmp_base = g_malloc(msg->size + 1);
-	memcpy(tmp_base, c2 + 2, msg->size);
-	tmp_base[msg->size] = '\0';
+	tmp_base = g_malloc(payload_len + 1);
+	memcpy(tmp_base, payload, payload_len);
+	tmp_base[payload_len] = '\0';
 
 	tmp = tmp_base;
 
-	/*
-	 * We're going to make sure this is incoming by checking field1.
-	 * If it has any non-numbers in it, it's incoming. Otherwise, outgoing.
-	 */
-	msg->incoming = FALSE;
-
-	for (c = field1; *c != '\0'; c++) {
-		if (*c < '0' || *c > '9') {
-			msg->incoming = TRUE;
-			break;
-		}
-	}
-
-	if (msg->incoming) {
-		msg->sender = msn_users_find_with_passport(session->users, field1);
-
-		if (msg->sender == NULL)
-			msg->sender = msn_user_new(session, field1, field2);
-		else
-			msn_user_ref(msg->sender);
-	}
-	else {
-		msg->tid  = atoi(field1);
-		msg->flag = *field2;
-	}
-
-	msg_base = tmp;
-
 	/* Back to the parsination. */
-	while (*tmp != '\r') {
+	while (*tmp != '\r')
+	{
 		char *key, *value;
 
 		key = tmp;
@@ -223,11 +159,14 @@
 		if ((c = strchr(key, ':')) != NULL)
 			*c = '\0';
 
-		if (!g_ascii_strcasecmp(key, "Content-Type")) {
+		if (!g_ascii_strcasecmp(key, "Content-Type"))
+		{
 			char *charset;
 
-			if ((c = strchr(value, ';')) != NULL) {
-				if ((charset = strchr(c, '=')) != NULL) {
+			if ((c = strchr(value, ';')) != NULL)
+			{
+				if ((charset = strchr(c, '=')) != NULL)
+				{
 					charset++;
 					msn_message_set_charset(msg, charset);
 				}
@@ -261,15 +200,18 @@
 
 		tmp += 48;
 
-		body_len = msg->size - (tmp - tmp_base) - 5;
-		msg->body = g_malloc(body_len + 1);
+		body_len = payload_len - (tmp - tmp_base) - 5;
 
 		if (body_len > 0)
+		{
+			msg->body = g_malloc(body_len + 1);
 			memcpy(msg->body, tmp, body_len);
+			msg->body[body_len] = '\0';
 
-		msg->body[body_len] = '\0';
-
-		tmp++;
+			tmp++;
+		}
+		else
+			msg->body = NULL;
 
 		memcpy(footer, tmp, 4);
 
@@ -312,7 +254,7 @@
 		char *tmp2;
 		size_t body_len;
 
-		body_len = msg->size - (tmp - tmp_base);
+		body_len = payload_len - (tmp - tmp_base);
 
 		tmp2 = g_malloc(body_len + 1);
 
@@ -326,12 +268,9 @@
 		g_free(tmp2);
 	}
 
-	g_free(command_header);
 	g_free(tmp_base);
 
 	/* Done! */
-
-	return msg;
 }
 
 void
@@ -339,18 +278,13 @@
 {
 	g_return_if_fail(msg != NULL);
 
-	if (msg->ref_count > 0) {
+	if (msg->ref_count > 0)
+	{
 		msn_message_unref(msg);
 
 		return;
 	}
 
-	if (msg->sender != NULL)
-		msn_user_unref(msg->sender);
-
-	if (msg->receiver != NULL)
-		msn_user_unref(msg->receiver);
-
 	if (msg->body != NULL)
 		g_free(msg->body);
 
@@ -400,10 +334,9 @@
 }
 
 char *
-msn_message_to_string(const MsnMessage *msg, size_t *ret_size)
+msn_message_gen_payload(const MsnMessage *msg, size_t *ret_size)
 {
 	GList *l;
-	char *msg_start;
 	char *str;
 	char buf[MSN_BUF_LEN];
 	int len;
@@ -419,35 +352,20 @@
 	 */
 	g_return_val_if_fail(msg != NULL, NULL);
 
-	if (msn_message_is_incoming(msg)) {
-		MsnUser *sender = msn_message_get_sender(msg);
-
-		g_snprintf(buf, sizeof(buf), "MSG %s %s %d\r\n",
-				   msn_user_get_passport(sender), msn_user_get_name(sender),
-				   (int)msg->size);
-	}
-	else {
-		g_snprintf(buf, sizeof(buf), "MSG %d %c %d\r\n",
-				   msn_message_get_transaction_id(msg),
-				   msn_message_get_flag(msg), (int)msg->size);
-	}
-
-	len = strlen(buf) + msg->size + 1;
+	len = msg->size + 1;
 
 	str = g_new0(char, len + 1);
 
-	g_strlcpy(str, buf, len);
-
-	msg_start = str + strlen(str);
-
 	/* Standard header. */
-	if (msg->charset == NULL) {
+	if (msg->charset == NULL)
+	{
 		g_snprintf(buf, sizeof(buf),
 				   "MIME-Version: 1.0\r\n"
 				   "Content-Type: %s\r\n",
 				   msg->content_type);
 	}
-	else {
+	else
+	{
 		g_snprintf(buf, sizeof(buf),
 				   "MIME-Version: 1.0\r\n"
 				   "Content-Type: %s; charset=%s\r\n",
@@ -456,7 +374,8 @@
 
 	g_strlcat(str, buf, len);
 
-	for (l = msg->attr_list; l != NULL; l = l->next) {
+	for (l = msg->attr_list; l != NULL; l = l->next)
+	{
 		const char *key = (char *)l->data;
 		const char *value;
 
@@ -522,7 +441,7 @@
 
 			if (body != NULL)
 			{
-				g_strlcpy(c, body, msg->size - (c - msg_start));
+				g_strlcpy(c, body, msg->size - (c - str));
 
 				c += strlen(body);
 
@@ -533,11 +452,11 @@
 
 		c += msn_put32(c, msg->msnslp_footer.app_id);
 
-		if (msg->size != (c - msg_start))
+		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 - msg_start));
+					   "do not match!\n", msg->size, (c - str));
 		}
 	}
 	else
@@ -546,10 +465,11 @@
 
 		g_strlcat(str, body, len);
 
-		if (msg->size != strlen(msg_start)) {
+		if (msg->size != strlen(str))
+		{
 			gaim_debug(GAIM_DEBUG_ERROR, "msn",
 					   "Outgoing message size (%d) and string length (%d) "
-					   "do not match!\n", msg->size, strlen(msg_start));
+					   "do not match!\n", msg->size, strlen(str));
 		}
 	}
 
@@ -559,80 +479,6 @@
 	return str;
 }
 
-gboolean
-msn_message_is_outgoing(const MsnMessage *msg)
-{
-	g_return_val_if_fail(msg != NULL, FALSE);
-
-	return !msg->incoming;
-}
-
-gboolean
-msn_message_is_incoming(const MsnMessage *msg)
-{
-	g_return_val_if_fail(msg != NULL, FALSE);
-
-	return msg->incoming;
-}
-
-void
-msn_message_set_sender(MsnMessage *msg, MsnUser *user)
-{
-	g_return_if_fail(msg != NULL);
-	g_return_if_fail(user != NULL);
-
-	msg->sender = user;
-
-	msn_user_ref(msg->sender);
-}
-
-MsnUser *
-msn_message_get_sender(const MsnMessage *msg)
-{
-	g_return_val_if_fail(msg != NULL, NULL);
-
-	return msg->sender;
-}
-
-void
-msn_message_set_receiver(MsnMessage *msg, MsnUser *user)
-{
-	g_return_if_fail(msg != NULL);
-	g_return_if_fail(user != NULL);
-
-	msg->receiver = user;
-
-	if (msg->msnslp_message)
-		msn_message_set_attr(msg, "P2P-Dest", msn_user_get_passport(user));
-
-	msn_user_ref(msg->receiver);
-}
-
-MsnUser *
-msn_message_get_receiver(const MsnMessage *msg)
-{
-	g_return_val_if_fail(msg != NULL, NULL);
-
-	return msg->receiver;
-}
-
-void
-msn_message_set_transaction_id(MsnMessage *msg, unsigned int tid)
-{
-	g_return_if_fail(msg != NULL);
-	g_return_if_fail(tid > 0);
-
-	msg->tid = tid;
-}
-
-unsigned int
-msn_message_get_transaction_id(const MsnMessage *msg)
-{
-	g_return_val_if_fail(msg != NULL, 0);
-
-	return msg->tid;
-}
-
 void
 msn_message_set_flag(MsnMessage *msg, char flag)
 {
--- a/src/protocols/msn/msg.h	Tue Apr 13 03:53:37 2004 +0000
+++ b/src/protocols/msn/msg.h	Tue Apr 13 04:08:22 2004 +0000
@@ -60,14 +60,11 @@
 	gboolean msnslp_message;
 	gboolean msnslp_ack_message;
 
-	MsnUser *sender;
-	MsnUser *receiver;
+	char *passport;
 
 	unsigned int tid;
 	char flag;
 
-	gboolean incoming;
-
 	size_t size;
 
 	gboolean bin_content;
@@ -112,14 +109,15 @@
 MsnMessage *msn_message_new_msnslp_ack(MsnMessage *acked_msg);
 
 /**
- * Creates a new message based off a string.
+ * Parse the payload of a message.
  *
- * @param session The MSN session.
- * @param str     The string.
- *
- * @return The new message.
+ * @param msg         The message.
+ * @param payload     The payload.
+ * @param payload_len The length payload.
  */
-MsnMessage *msn_message_new_from_str(MsnSession *session, const char *str);
+void msn_message_parse_payload(MsnMessage *msg,
+							   const char *payload,
+							   size_t payload_len);
 
 /**
  * Destroys a message.
@@ -149,83 +147,14 @@
 MsnMessage *msn_message_unref(MsnMessage *msg);
 
 /**
- * Converts a message to a string.
+ * Generates the payload data of a message.
  *
  * @param msg      The message.
- * @param ret_size The returned size of the string.
- *
- * @return The string representation of a message.
- */
-char *msn_message_to_string(const MsnMessage *msg, size_t *ret_size);
-
-/**
- * Returns TRUE if the message is outgoing.
- *
- * @param msg The message.
- *
- * @return @c TRUE if the message is outgoing, or @c FALSE otherwise.
- */
-gboolean msn_message_is_outgoing(const MsnMessage *msg);
-
-/**
- * Returns TRUE if the message is incoming.
- *
- * @param msg The message.
- *
- * @return @c TRUE if the message is incoming, or @c FALSE otherwise.
- */
-gboolean msn_message_is_incoming(const MsnMessage *msg);
-
-/**
- * Sets the message's sender.
- *
- * @param msg  The message.
- * @param user The sender.
- */
-void msn_message_set_sender(MsnMessage *msg, MsnUser *user);
-
-/**
- * Returns the message's sender.
- *
- * @param msg The message.
+ * @param ret_size The returned size of the payload.
  *
- * @return The sender.
- */
-MsnUser *msn_message_get_sender(const MsnMessage *msg);
-
-/**
- * Sets the message's receiver.
- *
- * @param msg  The message.
- * @param user The receiver.
- */
-void msn_message_set_receiver(MsnMessage *msg, MsnUser *user);
-
-/**
- * Returns the message's receiver.
- *
- * @param msg The message.
- *
- * @return The receiver.
+ * @return The payload data of the message.
  */
-MsnUser *msn_message_get_receiver(const MsnMessage *msg);
-
-/**
- * Sets the message transaction ID.
- *
- * @param msg The message.
- * @param tid The transaction ID.
- */
-void msn_message_set_transaction_id(MsnMessage *msg, unsigned int tid);
-
-/**
- * Returns the message transaction ID.
- *
- * @param msg The message.
- *
- * @return The transaction ID.
- */
-unsigned int msn_message_get_transaction_id(const MsnMessage *msg);
+char *msn_message_gen_payload(const MsnMessage *msg, size_t *ret_size);
 
 /**
  * Sets the flag for an outgoing message.
--- a/src/protocols/msn/msn.c	Tue Apr 13 03:53:37 2004 +0000
+++ b/src/protocols/msn/msn.c	Tue Apr 13 04:08:22 2004 +0000
@@ -138,30 +138,42 @@
 static void
 send_to_mobile_cb(MsnMobileData *data, const char *entry)
 {
-	MsnSession *session = data->gc->proto_data;
-	MsnServConn *servconn = session->notification_conn;
-	MsnUser *user;
+	MsnSession *session;
+	MsnServConn *servconn;
 	MsnPage *page;
-	char *page_str;
+	char *buf;
+	char *payload;
+	size_t len;
+	size_t payload_len;
 
-	user = msn_user_new(session, data->passport, NULL);
+	session = data->gc->proto_data;
+	servconn = session->notification_conn;
 
 	page = msn_page_new();
-	msn_page_set_receiver(page, user);
-	msn_page_set_transaction_id(page, ++session->trId);
 	msn_page_set_body(page, entry);
+	buf = g_strdup_printf("PGD %d %s 1 %d\r\n", ++session->trId,
+						  data->passport, page->size);
+
+	len = strlen(buf);
+
+	payload = msn_page_gen_payload(page, &payload_len);
 
-	page_str = msn_page_build_string(page);
+	if (payload != NULL)
+	{
+		buf = g_realloc(buf, len + payload_len + 1);
+		memcpy(buf + len, payload, payload_len);
+		len += payload_len;
+		buf[len] = 0;
+	}
 
-	msn_user_destroy(user);
 	msn_page_destroy(page);
 
-	if (!msn_servconn_write(servconn, page_str, strlen(page_str))) {
-
+	if (!msn_servconn_write(servconn, buf, len))
+	{
 		gaim_connection_error(data->gc, _("Write error"));
 	}
 
-	g_free(page_str);
+	g_free(buf);
 }
 
 static void
@@ -541,7 +553,6 @@
 		msn_import_html(message, &msgformat, &msgtext);
 
 		msg = msn_message_new();
-		msn_message_set_receiver(msg, user);
 		msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat);
 		msn_message_set_body(msg, msgtext);
 
@@ -611,7 +622,6 @@
 
 	msg = msn_message_new();
 	msn_message_set_content_type(msg, "text/x-msmsgscontrol");
-	msn_message_set_receiver(msg, user);
 	msn_message_set_charset(msg, NULL);
 	msn_message_set_flag(msg, 'U');
 	msn_message_set_attr(msg, "TypingUser",
--- a/src/protocols/msn/msnslp.c	Tue Apr 13 03:53:37 2004 +0000
+++ b/src/protocols/msn/msnslp.c	Tue Apr 13 04:08:22 2004 +0000
@@ -59,8 +59,7 @@
 
 static void
 msn_slp_session_send_message(MsnSlpSession *slpsession,
-							 MsnMessage *source_msg,
-							 MsnUser *local_user, MsnUser *remote_user,
+							 const char *local_user, const char *remote_user,
 							 const char *header, const char *branch,
 							 int cseq, const char *call_id,
 							 const char *content)
@@ -73,16 +72,6 @@
 	g_return_if_fail(branch     != NULL);
 	g_return_if_fail(call_id    != NULL);
 
-	if (source_msg != NULL)
-	{
-		if (msn_message_is_incoming(source_msg))
-			remote_user = msn_message_get_sender(source_msg);
-		else
-			remote_user = msn_message_get_receiver(source_msg);
-
-		local_user = slpsession->swboard->servconn->session->user;
-	}
-
 	if (branch == NULL)
 		branch = "null";
 
@@ -100,8 +89,8 @@
 		"%s"
 		"\r\n\r\n",
 		header,
-		msn_user_get_passport(remote_user),
-		msn_user_get_passport(local_user),
+		remote_user,
+		local_user,
 		branch, cseq, call_id,
 		(content == NULL ? 0  : (int)strlen(content) + 5),
 		(content == NULL ? "" : content));
@@ -110,9 +99,6 @@
 
 	invite_msg = msn_message_new_msnslp();
 
-	msn_message_set_sender(invite_msg, local_user);
-	msn_message_set_receiver(invite_msg, remote_user);
-
 	msn_message_set_body(invite_msg, body);
 
 	g_free(body);
@@ -123,10 +109,15 @@
 static gboolean
 send_error_500(MsnSlpSession *slpsession, const char *call_id, MsnMessage *msg)
 {
+	MsnUser *local_user;
+
 	g_return_val_if_fail(slpsession != NULL, TRUE);
 	g_return_val_if_fail(msg        != NULL, TRUE);
 
-	msn_slp_session_send_message(slpsession, msg, NULL, NULL,
+	local_user = slpsession->swboard->servconn->session->user;
+
+	msn_slp_session_send_message(slpsession, msg->passport,
+								 msn_user_get_passport(local_user),
 								 "MSNSLP/1.0 500 Internal Error",
 								 slpsession->branch, 1, call_id, NULL);
 
@@ -146,8 +137,6 @@
 	slpsession->remaining_size -= len;
 
 	msg = msn_message_new_msnslp();
-	msn_message_set_sender(msg,   slpsession->receiver);
-	msn_message_set_receiver(msg, slpsession->sender);
 	msn_message_set_bin_data(msg, data, len);
 
 	msn_slp_session_send_msg(slpsession, msg);
@@ -197,15 +186,20 @@
 		 *
 		 * Say BYE-BYE.
 		 */
+		MsnUser *local_user;
 		char *header;
 
 		fclose(slpsession->send_fp);
 		slpsession->send_fp = NULL;
 
 		header = g_strdup_printf("BYE MSNMSGR:%s MSNSLP/1.0",
-			msn_user_get_passport(msn_message_get_sender(msg)));
+			msg->passport);
+
+		local_user = slpsession->swboard->servconn->session->user;
 
-		msn_slp_session_send_message(slpsession, msg, NULL, NULL, header,
+		msn_slp_session_send_message(slpsession, msg->passport,
+									 msn_user_get_passport(local_user),
+									 header,
 									 "A0D624A6-6C0C-4283-A9E0-BC97B4B46D32",
 									 0, slpsession->call_id, "");
 
@@ -300,7 +294,10 @@
 
 		if (app_id == 1)
 		{
+			MsnSession *session;
 			MsnMessage *new_msg;
+			MsnUser *local_user;
+			MsnUser *remote_user;
 			char *content;
 			char nil_body[4];
 			struct stat st;
@@ -309,7 +306,12 @@
 			content = g_strdup_printf("SessionID: %d", session_id);
 			msn_slp_session_send_ack(slpsession, msg);
 
-			msn_slp_session_send_message(slpsession, msg, NULL, NULL,
+			session = slpsession->swboard->servconn->session;
+
+			local_user = session->user;
+
+			msn_slp_session_send_message(slpsession, msg->passport,
+										 msn_user_get_passport(local_user),
 										 "MSNSLP/1.0 200 OK",
 										 branch, 1, call_id, content);
 
@@ -319,12 +321,13 @@
 			memset(nil_body, 0, sizeof(nil_body));
 
 			slpsession->session_id = session_id;
-			slpsession->receiver = msn_message_get_sender(msg);
-			slpsession->sender = slpsession->swboard->servconn->session->user;
+
+			remote_user = msn_user_new(session, msg->passport, NULL);
+
+			slpsession->receiver = remote_user;
+			slpsession->sender = session->user;
 
 			new_msg = msn_message_new_msnslp();
-			msn_message_set_sender(new_msg, slpsession->sender);
-			msn_message_set_receiver(new_msg, slpsession->receiver);
 			msn_message_set_bin_data(new_msg, nil_body, 4);
 			new_msg->msnslp_footer.app_id = 1;
 
@@ -532,7 +535,9 @@
 	header = g_strdup_printf("INVITE MSNMSGR:%s MSNSLP/1.0",
 							 msn_user_get_passport(remote_user));
 
-	msn_slp_session_send_message(slpsession, NULL, local_user, remote_user,
+	msn_slp_session_send_message(slpsession,
+								 msn_user_get_passport(local_user),
+								 msn_user_get_passport(remote_user),
 								 header, slpsession->branch, 0,
 								 slpsession->call_id, content);
 
--- a/src/protocols/msn/notification.c	Tue Apr 13 03:53:37 2004 +0000
+++ b/src/protocols/msn/notification.c	Tue Apr 13 04:08:22 2004 +0000
@@ -199,7 +199,7 @@
 			size_t param_count)
 {
 	int errnum = 0;
-	
+
 	if (isdigit(*command)) {
 		errnum = atoi(command);
 
@@ -212,7 +212,7 @@
 			return TRUE;
 		}
 	}
-	
+
 	msn_error_handle(servconn->session, errnum);
 
 	return TRUE;
@@ -451,18 +451,30 @@
 /**************************************************************************
  * Messages
  **************************************************************************/
+static void
+msg_cmd_post(MsnServConn *servconn, char *payload, size_t len)
+{
+	MsnMessage *msg = msn_message_new();
+
+	msg->passport = servconn->msg_passport;
+
+	msn_message_parse_payload(msg, payload, len);
+
+	msn_servconn_process_message(servconn, msg);
+
+	msn_message_destroy(msg);
+}
+
 static gboolean
 msg_cmd(MsnServConn *servconn, const char *command, const char **params,
 		size_t param_count)
 {
 	gaim_debug(GAIM_DEBUG_INFO, "msn", "Found message. Parsing.\n");
 
-	servconn->parsing_multiline = TRUE;
-	servconn->multiline_type    = MSN_MULTILINE_MSG;
-	servconn->multiline_len     = atoi(params[2]);
+	servconn->payload_cb  = msg_cmd_post;
+	servconn->payload_len = atoi(params[2]);
 
 	servconn->msg_passport = g_strdup(params[0]);
-	servconn->msg_friendly = g_strdup(params[1]);
 
 	return TRUE;
 }
@@ -746,14 +758,8 @@
 ipg_cmd(MsnServConn *servconn, const char *command, const char **params,
 		size_t param_count)
 {
-	/* GaimConnection *gc = servconn->session->account->gc; */
-
-	servconn->parsing_multiline = TRUE;
-	servconn->multiline_type    = MSN_MULTILINE_IPG;
-	servconn->multiline_len     = atoi(params[0]);
-
-	servconn->msg_passport = NULL;
-	servconn->msg_friendly = NULL;
+	servconn->payload_cb  = NULL;
+	servconn->payload_len = atoi(params[2]);
 
 	return TRUE;
 }
@@ -1167,14 +1173,8 @@
 not_cmd(MsnServConn *servconn, const char *command, const char **params,
 		size_t param_count)
 {
-	/* GaimConnection *gc = servconn->session->account->gc; */
-
-	servconn->parsing_multiline = TRUE;
-	servconn->multiline_type    = MSN_MULTILINE_NOT;
-	servconn->multiline_len     = atoi(params[0]);
-
-	servconn->msg_passport = NULL;
-	servconn->msg_friendly = NULL;
+	servconn->payload_cb  = NULL;
+	servconn->payload_len = atoi(params[2]);
 
 	return TRUE;
 }
@@ -1604,7 +1604,9 @@
 									  port))
 		{
 			gaim_connection_error(gc, _("Unable to transfer to "
-									  "notification server"));
+										"notification server"));
+
+			g_free(host);
 
 			return FALSE;
 		}
@@ -1624,7 +1626,7 @@
 	MsnSession *session = servconn->session;
 	const char *value;
 
-	if (strcmp(servconn->msg_passport, "Hotmail")) {
+	if (strcmp(msg->passport, "Hotmail")) {
 		/* This isn't an official message. */
 		return TRUE;
 	}
@@ -1655,7 +1657,7 @@
 	GHashTable *table;
 	const char *unread;
 
-	if (strcmp(servconn->msg_passport, "Hotmail")) {
+	if (strcmp(msg->passport, "Hotmail")) {
 		/* This isn't an official message. */
 		return TRUE;
 	}
@@ -1705,7 +1707,7 @@
 	GHashTable *table;
 	char *from, *subject;
 
-	if (strcmp(servconn->msg_passport, "Hotmail")) {
+	if (strcmp(msg->passport, "Hotmail")) {
 		/* This isn't an official message. */
 		return TRUE;
 	}
@@ -1743,7 +1745,7 @@
 	GHashTable *table;
 	const char *type_s;
 
-	if (strcmp(servconn->msg_passport, "Hotmail")) {
+	if (strcmp(msg->passport, "Hotmail")) {
 		/* This isn't an official message. */
 		return TRUE;
 	}
--- a/src/protocols/msn/page.c	Tue Apr 13 03:53:37 2004 +0000
+++ b/src/protocols/msn/page.c	Tue Apr 13 04:08:22 2004 +0000
@@ -56,25 +56,11 @@
 	return page;
 }
 
-MsnPage *
-msn_page_new_from_str(MsnSession *session, const char *str)
-{
-	g_return_val_if_fail(str != NULL, NULL);
-
-	return NULL;
-}
-
 void
 msn_page_destroy(MsnPage *page)
 {
 	g_return_if_fail(page != NULL);
 
-	if (page->sender != NULL)
-		msn_user_unref(page->sender);
-
-	if (page->receiver != NULL)
-		msn_user_unref(page->receiver);
-
 	if (page->body != NULL)
 		g_free(page->body);
 
@@ -88,138 +74,37 @@
 }
 
 char *
-msn_page_build_string(const MsnPage *page)
+msn_page_gen_payload(const MsnPage *page, size_t *ret_size)
 {
-	char *page_start;
 	char *str;
-	char buf[MSN_BUF_LEN];
-	int len;
 
-	/*
-	 * 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(page != NULL, NULL);
 
-	if (msn_page_is_incoming(page)) {
-		/* We don't know this yet :) */
-		return NULL;
-	}
-	else {
-		MsnUser *receiver = msn_page_get_receiver(page);
+	str =
+		g_strdup_printf("<TEXT xml:space=\"preserve\" enc=\"utf-8\">%s</TEXT>",
+						msn_page_get_body(page));
 
-		g_snprintf(buf, sizeof(buf), "PGD %d %s 1 %d\r\n",
-				   msn_page_get_transaction_id(page),
-				   msn_user_get_passport(receiver),
-				   (int)page->size);
+	if (page->size != strlen(str))
+	{
+		gaim_debug(GAIM_DEBUG_ERROR, "msn",
+				   "Outgoing page size (%d) and string length (%d) "
+				   "do not match!\n", page->size, strlen(str));
 	}
 
-	len = strlen(buf) + page->size + 1;
-
-	str = g_new0(char, len);
-
-	g_strlcpy(str, buf, len);
-
-	page_start = str + strlen(str);
-
-	g_snprintf(buf, sizeof(buf),
-			   "<TEXT xml:space=\"preserve\" enc=\"utf-8\">%s</TEXT>",
-			   msn_page_get_body(page));
-
-	g_strlcat(str, buf, len);
-
-	if (page->size != strlen(page_start)) {
-		gaim_debug(GAIM_DEBUG_ERROR, "msn",
-				   "Outgoing page size (%d) and string length (%d) "
-				   "do not match!\n", page->size, strlen(page_start));
-	}
+	if (ret_size != NULL)
+		*ret_size = page->size - 1;
 
 	return str;
 }
 
-gboolean
-msn_page_is_outgoing(const MsnPage *page)
-{
-	g_return_val_if_fail(page != NULL, FALSE);
-
-	return !page->incoming;
-}
-
-gboolean
-msn_page_is_incoming(const MsnPage *page)
-{
-	g_return_val_if_fail(page != NULL, FALSE);
-
-	return page->incoming;
-}
-
-void
-msn_page_set_sender(MsnPage *page, MsnUser *user)
-{
-	g_return_if_fail(page != NULL);
-	g_return_if_fail(user != NULL);
-
-	page->sender = user;
-
-	msn_user_ref(page->sender);
-}
-
-MsnUser *
-msn_page_get_sender(const MsnPage *page)
-{
-	g_return_val_if_fail(page != NULL, NULL);
-
-	return page->sender;
-}
-
-void
-msn_page_set_receiver(MsnPage *page, MsnUser *user)
-{
-	g_return_if_fail(page != NULL);
-	g_return_if_fail(user != NULL);
-
-	page->receiver = user;
-
-	msn_user_ref(page->receiver);
-}
-
-MsnUser *
-msn_page_get_receiver(const MsnPage *page)
-{
-	g_return_val_if_fail(page != NULL, NULL);
-
-	return page->receiver;
-}
-
-void
-msn_page_set_transaction_id(MsnPage *page, unsigned int tid)
-{
-	g_return_if_fail(page != NULL);
-	g_return_if_fail(tid > 0);
-
-	page->trId = tid;
-}
-
-unsigned int
-msn_page_get_transaction_id(const MsnPage *page)
-{
-	g_return_val_if_fail(page != NULL, 0);
-
-	return page->trId;
-}
-
 void
 msn_page_set_body(MsnPage *page, const char *body)
 {
 	g_return_if_fail(page != NULL);
 	g_return_if_fail(body != NULL);
 
-	if (page->body != NULL) {
+	if (page->body != NULL)
+	{
 		page->size -= strlen(page->body);
 		g_free(page->body);
 	}
--- a/src/protocols/msn/page.h	Tue Apr 13 03:53:37 2004 +0000
+++ b/src/protocols/msn/page.h	Tue Apr 13 04:08:22 2004 +0000
@@ -32,16 +32,9 @@
  */
 struct _MsnPage
 {
-	MsnUser *sender;
-	MsnUser *receiver;
-
 	char *from_location;
 	char *from_phone;
 
-	gboolean incoming;
-
-	unsigned int trId;
-
 	size_t size;
 
 	char *body;
@@ -55,98 +48,19 @@
 MsnPage *msn_page_new(void);
 
 /**
- * Creates a new page based off a string.
- *
- * @param session The MSN session.
- * @param str     The string.
- *
- * @return The new page.
- */
-MsnPage *msn_page_new_from_str(MsnSession *session, const char *str);
-
-/**
  * Destroys a page.
  */
 void msn_page_destroy(MsnPage *page);
 
 /**
- * Converts a page to a string.
- *
- * @param page The page.
- *
- * @return The string representation of a page.
- */
-char *msn_page_build_string(const MsnPage *page);
-
-/**
- * Returns TRUE if the page is outgoing.
- *
- * @param page The page.
- *
- * @return @c TRUE if the page is outgoing, or @c FALSE otherwise.
- */
-gboolean msn_page_is_outgoing(const MsnPage *page);
-
-/**
- * Returns TRUE if the page is incoming.
- *
- * @param page The page.
- *
- * @return @c TRUE if the page is incoming, or @c FALSE otherwise.
- */
-gboolean msn_page_is_incoming(const MsnPage *page);
-
-/**
- * Sets the page's sender.
- *
- * @param page  The page.
- * @param user The sender.
- */
-void msn_page_set_sender(MsnPage *page, MsnUser *user);
-
-/**
- * Returns the page's sender.
- *
- * @param page The page.
+ * Converts a page to a payload string.
  *
- * @return The sender.
- */
-MsnUser *msn_page_get_sender(const MsnPage *page);
-
-/**
- * Sets the page's receiver.
+ * @param page     The page.
+ * @param ret_size The returned size of the payload.
  *
- * @param page  The page.
- * @param user The receiver.
- */
-void msn_page_set_receiver(MsnPage *page, MsnUser *user);
-
-/**
- * Returns the page's receiver.
- *
- * @param page The page.
- *
- * @return The receiver.
+ * @return The payload string of a page.
  */
-MsnUser *msn_page_get_receiver(const MsnPage *page);
-
-/**
- * Sets the page transaction ID.
- *
- * @param page The page.
- * @param tid  The transaction ID.
- */
-void msn_page_set_transaction_id(MsnPage *page, unsigned int tid);
-
-/**
- * Returns the page transaction ID.
- *
- * @param page The page.
- *
- * @return The transaction ID.
- */
-unsigned int msn_page_get_transaction_id(const MsnPage *page);
-
+char *msn_page_gen_payload(const MsnPage *page, size_t *ret_size);
 
 /**
  * Sets the body of a page.
--- a/src/protocols/msn/servconn.c	Tue Apr 13 03:53:37 2004 +0000
+++ b/src/protocols/msn/servconn.c	Tue Apr 13 04:08:22 2004 +0000
@@ -32,15 +32,16 @@
 
 } MsnQueueEntry;
 
-static gboolean
-process_message(MsnServConn *servconn, MsnMessage *msg)
+gboolean
+msn_servconn_process_message(MsnServConn *servconn, MsnMessage *msg)
 {
 	MsnServConnMsgCb cb;
 
 	cb = g_hash_table_lookup(servconn->msg_types,
 							 msn_message_get_content_type(msg));
 
-	if (cb == NULL) {
+	if (cb == NULL)
+	{
 		gaim_debug(GAIM_DEBUG_WARNING, "msn",
 				   "Unhandled content-type '%s': %s\n",
 				   msn_message_get_content_type(msg),
@@ -54,144 +55,6 @@
 	return TRUE;
 }
 
-static gboolean
-process_single_line(MsnServConn *servconn, char *str)
-{
-	MsnSession *session = servconn->session;
-	MsnServConnCommandCb cb;
-	GSList *l, *l_next = NULL;
-	gboolean result;
-	size_t param_count = 0;
-	char *command, *param_start;
-	char **params = NULL;
-
-	command = str;
-
-	/**
-	 * See how many spaces we have in this.
-	 */
-	param_start = strchr(command, ' ');
-
-	if (param_start != NULL) {
-		params = g_strsplit(param_start + 1, " ", 0);
-
-		for (param_count = 0; params[param_count] != NULL; param_count++)
-			;
-
-		*param_start = '\0';
-	}
-
-	cb = g_hash_table_lookup(servconn->commands, command);
-
-	if (cb == NULL) {
-		cb = g_hash_table_lookup(servconn->commands, "_unknown_");
-
-		if (cb == NULL) {
-			if (isdigit(*str))
-				msn_error_handle(session, atoi(str));
-			else
-				gaim_debug(GAIM_DEBUG_WARNING, "msn",
-					   "Unhandled command '%s'\n", str);
-
-			if (params != NULL)
-				g_strfreev(params);
-
-			return TRUE;
-		}
-	}
-
-	result = cb(servconn, command, (const char **)params, param_count);
-
-	if (params != NULL)
-		g_strfreev(params);
-
-	if (g_list_find(session->servconns, servconn) == NULL)
-		return result;
-
-	/* Process all queued messages that are waiting on this command. */
-	for (l = servconn->msg_queue; l != NULL; l = l_next) {
-		MsnQueueEntry *entry = l->data;
-		MsnMessage *msg;
-
-		l_next = l->next;
-
-		if (entry->command == NULL ||
-			!g_ascii_strcasecmp(entry->command, command)) {
-
-			MsnUser *sender;
-
-			msg = entry->msg;
-
-			msn_message_ref(msg);
-
-			sender = msn_message_get_sender(msg);
-
-			servconn->msg_passport = g_strdup(msn_user_get_passport(sender));
-			servconn->msg_friendly = g_strdup(msn_user_get_name(sender));
-
-			process_message(servconn, msg);
-
-			g_free(servconn->msg_passport);
-			g_free(servconn->msg_friendly);
-
-			msn_servconn_unqueue_message(servconn, entry->msg);
-
-			msn_message_destroy(msg);
-			entry->msg = NULL;
-		}
-	}
-
-	return result;
-}
-
-static gboolean
-process_multi_line(MsnServConn *servconn, char *buffer)
-{
-	char msg_str[MSN_BUF_LEN];
-	gboolean result = TRUE;
-
-	if (servconn->multiline_type == MSN_MULTILINE_MSG) {
-		MsnMessage *msg;
-		size_t header_len;
-
-		g_snprintf(msg_str, sizeof(msg_str),
-				   "MSG %s %s %d\r\n",
-				   servconn->msg_passport, servconn->msg_friendly,
-				   servconn->multiline_len);
-
-		header_len = strlen(msg_str);
-
-		memcpy(msg_str + header_len, buffer, servconn->multiline_len);
-
-		gaim_debug(GAIM_DEBUG_MISC, "msn",
-				   "Message: {%s}\n", buffer);
-
-		msg = msn_message_new_from_str(servconn->session, msg_str);
-
-		result = process_message(servconn, msg);
-
-		msn_message_destroy(msg);
-	}
-	else if (servconn->multiline_type == MSN_MULTILINE_IPG) {
-		g_snprintf(msg_str, sizeof(msg_str),
-				   "IPG %d\r\n%s",
-				   servconn->multiline_len, buffer);
-
-		gaim_debug(GAIM_DEBUG_MISC, "msn",
-				   "Incoming Page: {%s}\n", buffer);
-	}
-	else if (servconn->multiline_type == MSN_MULTILINE_NOT) {
-		g_snprintf(msg_str, sizeof(msg_str),
-				   "NOT %d\r\n%s",
-				   servconn->multiline_len, buffer);
-
-		gaim_debug(GAIM_DEBUG_MISC, "msn",
-				   "Notification: {%s}\n", buffer);
-	}
-
-	return result;
-}
-
 static void
 connect_cb(gpointer data, gint source, GaimInputCondition cond)
 {
@@ -284,13 +147,14 @@
 
 	session = servconn->session;
 
-	if (servconn->inpa)
+	if (servconn->inpa > 0)
+	{
 		gaim_input_remove(servconn->inpa);
+		servconn->inpa = 0;
+	}
 
 	close(servconn->fd);
 
-	servconn->connected = FALSE;
-
 	if (servconn->http_data != NULL)
 	{
 		if (servconn->http_data->session_id != NULL)
@@ -308,8 +172,8 @@
 		g_free(servconn->http_data);
 	}
 
-	if (servconn->rxqueue != NULL)
-		g_free(servconn->rxqueue);
+	servconn->rx_len = 0;
+	servconn->payload_len = 0;
 
 	while (servconn->txqueue != NULL) {
 		g_free(servconn->txqueue->data);
@@ -324,8 +188,10 @@
 		msn_servconn_unqueue_message(servconn, entry->msg);
 	}
 
-	if (servconn->disconnect_cb)
+	if (servconn->disconnect_cb != NULL)
 		servconn->disconnect_cb(servconn);
+
+	servconn->connected = FALSE;
 }
 
 void
@@ -526,15 +392,103 @@
 }
 
 static void
+process_payload(MsnServConn *servconn, char *payload, int payload_len)
+{
+	g_return_if_fail(servconn             != NULL);
+	g_return_if_fail(servconn->payload_cb != NULL);
+
+	servconn->payload_cb(servconn, payload, payload_len);
+}
+
+static int
+process_cmd_text(MsnServConn *servconn, const char *command)
+{
+	MsnSession *session = servconn->session;
+	MsnServConnCommandCb cb;
+	GSList *l, *l_next = NULL;
+	gboolean result;
+	size_t param_count = 0;
+	char *param_start;
+	char **params = NULL;
+
+#if 0
+	if (servconn->last_cmd != NULL)
+		gfree(servconn->last_cmd);
+
+	servconn->last_cmd = gstrdup(command);
+#endif
+
+	/**
+	 * See how many spaces we have in this.
+	 */
+	param_start = strchr(command, ' ');
+
+	if (param_start != NULL) {
+		params = g_strsplit(param_start + 1, " ", 0);
+
+		for (param_count = 0; params[param_count] != NULL; param_count++)
+			;
+
+		*param_start = '\0';
+	}
+
+	cb = g_hash_table_lookup(servconn->commands, command);
+
+	if (cb == NULL) {
+		cb = g_hash_table_lookup(servconn->commands, "_unknown_");
+
+		if (cb == NULL) {
+			gaim_debug(GAIM_DEBUG_WARNING, "msn",
+					   "Unhandled command '%s'\n", command);
+
+			if (params != NULL)
+				g_strfreev(params);
+
+			return TRUE;
+		}
+	}
+
+	result = cb(servconn, command, (const char **)params, param_count);
+
+	if (params != NULL)
+		g_strfreev(params);
+
+	if (g_list_find(session->servconns, servconn) == NULL)
+		return result;
+
+	/* Process all queued messages that are waiting on this command. */
+	for (l = servconn->msg_queue; l != NULL; l = l_next) {
+		MsnQueueEntry *entry = l->data;
+		MsnMessage *msg;
+
+		l_next = l->next;
+
+		if (entry->command == NULL ||
+			!g_ascii_strcasecmp(entry->command, command)) {
+
+			msg = entry->msg;
+
+			msn_servconn_process_message(servconn, msg);
+
+			msn_servconn_unqueue_message(servconn, msg);
+
+			entry->msg = NULL;
+		}
+	}
+
+	return result;
+}
+
+static void
 read_cb(gpointer data, gint source, GaimInputCondition cond)
 {
 	MsnServConn *servconn = (MsnServConn *)data;
 	MsnSession *session = servconn->session;
 	char buf[MSN_BUF_LEN];
-	gboolean cont = TRUE;
-	int len;
+	char *cur, *end, *old_rx_buf;
+	int len, cur_len;
 
-	len = read(servconn->fd, buf, sizeof(buf));
+	len = read(servconn->fd, buf, sizeof(buf) - 1);
 
 	if (len <= 0)
 	{
@@ -543,9 +497,9 @@
 		return;
 	}
 
-	servconn->rxqueue = g_realloc(servconn->rxqueue, len + servconn->rxlen);
-	memcpy(servconn->rxqueue + servconn->rxlen, buf, len);
-	servconn->rxlen += len;
+	servconn->rx_buf = g_realloc(servconn->rx_buf, len + servconn->rx_len);
+	memcpy(servconn->rx_buf + servconn->rx_len, buf, len);
+	servconn->rx_len += len;
 
 	if (session->http_method)
 	{
@@ -554,10 +508,10 @@
 		gboolean error;
 		char *tmp;
 
-		tmp = g_strndup(servconn->rxqueue, servconn->rxlen);
+		tmp = g_strndup(servconn->rx_buf, servconn->rx_len);
 
 		if (!msn_http_servconn_parse_data(servconn, tmp,
-										  servconn->rxlen, &result_msg,
+										  servconn->rx_len, &result_msg,
 										  &result_len, &error))
 		{
 			g_free(tmp);
@@ -607,90 +561,63 @@
 		}
 #endif
 
-		g_free(servconn->rxqueue);
-		servconn->rxqueue = result_msg;
-		servconn->rxlen   = result_len;
+		g_free(servconn->rx_buf);
+		servconn->rx_buf = result_msg;
+		servconn->rx_len = result_len;
 	}
 
-	while (cont)
+	end = old_rx_buf = servconn->rx_buf;
+
+	do
 	{
-		if (servconn->parsing_multiline)
+		cur = end;
+
+		if (servconn->payload_len)
 		{
-			char *msg;
-
-			if (servconn->rxlen == 0)
+			if (servconn->payload_len > servconn->rx_len)
+				/* The payload is still not complete. */
 				break;
 
-			if (servconn->multiline_len > servconn->rxlen)
+			cur_len = servconn->payload_len;
+			end += cur_len;
+		}
+		else
+		{
+			end = strstr(cur, "\r\n");
+
+			if (!end)
+				/* The command is still not complete. */
 				break;
 
-			msg = servconn->rxqueue;
-			servconn->rxlen -= servconn->multiline_len;
-
-			if (servconn->rxlen) {
-				servconn->rxqueue = g_memdup(msg + servconn->multiline_len,
-											 servconn->rxlen);
-			}
-			else {
-				servconn->rxqueue = NULL;
-				msg = g_realloc(msg, servconn->multiline_len + 1);
-			}
-
-			msg[servconn->multiline_len] = '\0';
-			servconn->parsing_multiline = FALSE;
+			*end = '\0';
+			cur_len = end - cur + 2;
+			end += 2;
+		}
 
-			process_multi_line(servconn, msg);
-
-			if (g_list_find(session->servconns, servconn) != NULL) {
-				servconn->multiline_len = 0;
-
-				if (servconn->msg_passport != NULL)
-					g_free(servconn->msg_passport);
+		servconn->rx_len -= cur_len;
 
-				if (servconn->msg_friendly != NULL)
-					g_free(servconn->msg_friendly);
-			}
-			else
-				cont = 0;
-
-			g_free(msg);
+		if (servconn->payload_len)
+		{
+			process_payload(servconn, cur, cur_len);
+			servconn->payload_len = 0;
 		}
-		else {
-			char *end = servconn->rxqueue;
-			char *cmd;
-			int cmdlen, i;
-
-			if (!servconn->rxlen)
-				return;
-
-			for (i = 0; i < servconn->rxlen - 1; end++, i++) {
-				if (*end == '\r' && end[1] == '\n')
-					break;
-			}
-
-			if (i == servconn->rxlen - 1)
-				return;
-
-			cmdlen = end - servconn->rxqueue + 2;
-			cmd = servconn->rxqueue;
-			servconn->rxlen -= cmdlen;
+		else
+		{
+			gaim_debug(GAIM_DEBUG_MISC, "msn", "S: %s\n", cur);
+			process_cmd_text(servconn, cur);
+		}
+	} while (servconn->connected && servconn->rx_len);
 
-			if (servconn->rxlen)
-				servconn->rxqueue = g_memdup(cmd + cmdlen, servconn->rxlen);
-			else {
-				servconn->rxqueue = NULL;
-				cmd = g_realloc(cmd, cmdlen + 1);
-			}
-
-			cmd[cmdlen] = '\0';
+	if (servconn->connected)
+	{
+		if (servconn->rx_len)
+			servconn->rx_buf = g_memdup(cur, servconn->rx_len);
+		else
+			servconn->rx_buf = NULL;
+	}
 
-			gaim_debug(GAIM_DEBUG_MISC, "msn", "S: %s", cmd);
-
-			g_strchomp(cmd);
+	if (servconn->wasted)
+		msn_servconn_destroy(servconn);
 
-			cont = process_single_line(servconn, cmd);
-
-			g_free(cmd);
-		}
-	}
+	g_free(old_rx_buf);
 }
--- a/src/protocols/msn/servconn.h	Tue Apr 13 03:53:37 2004 +0000
+++ b/src/protocols/msn/servconn.h	Tue Apr 13 04:08:22 2004 +0000
@@ -35,21 +35,17 @@
 
 typedef gboolean (*MsnServConnMsgCb)(MsnServConn *servconn, MsnMessage *msg);
 
-#include "session.h"
+typedef void (*MsnPayloadCb)(MsnServConn *servconn, char *payload,
+							 size_t len);
 
-typedef enum
-{
-	MSN_MULTILINE_MSG,
-	MSN_MULTILINE_IPG,
-	MSN_MULTILINE_NOT
-
-} MsnMultilineType;
+#include "session.h"
 
 struct _MsnServConn
 {
 	MsnSession *session;
 
 	gboolean connected;
+	gboolean wasted;
 
 	MsnHttpMethodData *http_data;
 
@@ -62,18 +58,17 @@
 	int fd;
 	int inpa;
 
-	char *rxqueue;
-	int rxlen;
+	char *rx_buf;
+	int rx_len;
+
+	MsnPayloadCb payload_cb;
+	int payload_len;
 
 	GSList *msg_queue;
 
 	GSList *txqueue;
 
-	gboolean parsing_multiline;
-	MsnMultilineType multiline_type;
 	char *msg_passport;
-	char *msg_friendly;
-	int multiline_len;
 
 	GHashTable *commands;
 	GHashTable *msg_types;
@@ -126,7 +121,7 @@
 									const char *content_type,
 									MsnServConnMsgCb cb);
 
-void msn_servconn_parse_data(gpointer data, gint source,
-							 GaimInputCondition cond);
+gboolean msn_servconn_process_message(MsnServConn *servconn,
+									  MsnMessage *msg);
 
 #endif /* _MSN_SERVCONN_H_ */
--- a/src/protocols/msn/switchboard.c	Tue Apr 13 03:53:37 2004 +0000
+++ b/src/protocols/msn/switchboard.c	Tue Apr 13 04:08:22 2004 +0000
@@ -260,18 +260,30 @@
 	return send_clientcaps(swboard);
 }
 
+static void
+msg_cmd_post(MsnServConn *servconn, char *payload, size_t len)
+{
+	MsnMessage *msg = msn_message_new();
+
+	msg->passport = servconn->msg_passport;
+
+	msn_message_parse_payload(msg, payload, len);
+
+	msn_servconn_process_message(servconn, msg);
+
+	msn_message_destroy(msg);
+}
+
 static gboolean
 msg_cmd(MsnServConn *servconn, const char *command, const char **params,
-		 size_t param_count)
+		size_t param_count)
 {
 	gaim_debug(GAIM_DEBUG_INFO, "msn", "Found message. Parsing.\n");
 
-	servconn->parsing_multiline = TRUE;
-	servconn->multiline_type    = MSN_MULTILINE_MSG;
-	servconn->multiline_len     = atoi(params[2]);
+	servconn->payload_cb  = msg_cmd_post;
+	servconn->payload_len = atoi(params[2]);
 
 	servconn->msg_passport = g_strdup(params[0]);
-	servconn->msg_friendly = g_strdup(params[1]);
 
 	return TRUE;
 }
@@ -338,7 +350,7 @@
 
 	body = gaim_escape_html(msn_message_get_body(msg));
 
-	if (!strcmp(servconn->msg_passport, "messenger@microsoft.com") &&
+	if (!strcmp(msg->passport, "messenger@microsoft.com") &&
 		strstr(body, "immediate security update"))
 	{
 		g_free(body);
@@ -346,11 +358,13 @@
 		return TRUE;
 	}
 
+#if 0
 	gaim_debug(GAIM_DEBUG_INFO, "msn", "Checking User-Agent...\n");
 
 	if ((value = msn_message_get_attr(msg, "User-Agent")) != NULL) {
 		gaim_debug(GAIM_DEBUG_MISC, "msn", "value = '%s'\n", value);
 	}
+#endif
 
 	if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL) {
 		char *pre_format, *post_format;
@@ -367,10 +381,10 @@
 	{
 		serv_got_chat_in(gc,
 						 gaim_conv_chat_get_id(GAIM_CONV_CHAT(swboard->chat)),
-						 servconn->msg_passport, 0, body, time(NULL));
+						 msg->passport, 0, body, time(NULL));
 	}
 	else
-		serv_got_im(gc, servconn->msg_passport, body, 0, time(NULL));
+		serv_got_im(gc, msg->passport, body, 0, time(NULL));
 
 	g_free(body);
 
@@ -387,7 +401,7 @@
 	if (swboard->chat == NULL &&
 		(value = msn_message_get_attr(msg, "TypingUser")) != NULL) {
 
-		serv_got_typing(gc, servconn->msg_passport, MSN_TYPING_RECV_TIMEOUT,
+		serv_got_typing(gc, msg->passport, MSN_TYPING_RECV_TIMEOUT,
 						GAIM_TYPING);
 	}
 
@@ -404,7 +418,7 @@
 	GHashTable *clientcaps;
 	const char *value;
 
-	user = msn_user_new(session, servconn->msg_passport, NULL);
+	user = msn_user_new(session, msg->passport, NULL);
 
 	clientcaps = msn_message_get_hashtable_from_body(msg);
 #endif
@@ -500,11 +514,11 @@
 		/* Register the message type callbacks. */
 		msn_servconn_register_msg_type(servconn, "text/plain",plain_msg);
 		msn_servconn_register_msg_type(servconn, "text/x-msmsgscontrol",
-									  control_msg);
+									   control_msg);
 		msn_servconn_register_msg_type(servconn, "text/x-clientcaps",
-									  clientcaps_msg);
+									   clientcaps_msg);
 		msn_servconn_register_msg_type(servconn, "text/x-clientinfo",
-									  clientcaps_msg);
+									   clientcaps_msg);
 #if 0
 		msn_servconn_register_msg_type(servconn, "application/x-msnmsgrp2p",
 									   msn_p2p_msg);
@@ -652,7 +666,9 @@
 msn_switchboard_send_msg(MsnSwitchBoard *swboard, MsnMessage *msg)
 {
 	char *buf;
+	char *payload;
 	size_t len;
+	size_t payload_len;
 	int ret;
 #if 0
 	FILE *fp;
@@ -661,12 +677,23 @@
 	g_return_val_if_fail(swboard != NULL, FALSE);
 	g_return_val_if_fail(msg     != NULL, FALSE);
 
-	msn_message_set_transaction_id(msg, ++swboard->trId);
-	buf = msn_message_to_string(msg, &len);
+	buf = g_strdup_printf("MSG %d %c %d\r\n", ++swboard->trId,
+						  msn_message_get_flag(msg), (int)msg->size);
+
+	len = strlen(buf);
+
+	payload = msn_message_gen_payload(msg, &payload_len);
 
-	g_return_val_if_fail(buf != NULL, FALSE);
+	if (payload != NULL)
+	{
+		buf = g_realloc(buf, len + payload_len + 1);
+		memcpy(buf + len, payload, payload_len);
+		len += payload_len;
+		buf[len] = 0;
+	}
 
-	if (swboard->servconn->txqueue != NULL || !swboard->in_use) {
+	if (swboard->servconn->txqueue != NULL || !swboard->in_use)
+	{
 		gaim_debug(GAIM_DEBUG_INFO, "msn", "Appending message to queue.\n");
 
 		swboard->servconn->txqueue =
--- a/src/protocols/msn/utils.c	Tue Apr 13 03:53:37 2004 +0000
+++ b/src/protocols/msn/utils.c	Tue Apr 13 04:08:22 2004 +0000
@@ -98,8 +98,6 @@
 					   "<FONT COLOR=\"#%02hhx%02hhx%02hhx\">",
 					   colors[0], colors[1], colors[2]);
 
-			gaim_debug_misc("msn", "Got: %s\n", tag);
-
 			pre = g_string_append(pre, tag);
 			post = g_string_prepend(post, "</FONT>");
 		}