changeset 7604:43803965ef45

[gaim-migrate @ 8227] Committing what I have of MSN. It's disabled. committer: Tailor Script <tailor@pidgin.im>
author Christian Hammond <chipx86@chipx86.com>
date Sun, 23 Nov 2003 03:23:02 +0000
parents dfebaa14bf67
children 7b9630667f43
files src/protocols/msn/msg.c src/protocols/msn/msg.h src/protocols/msn/msnslp.c src/protocols/msn/msnslp.h src/protocols/msn/servconn.c
diffstat 5 files changed, 359 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/msn/msg.c	Sat Nov 22 23:17:31 2003 +0000
+++ b/src/protocols/msn/msg.c	Sun Nov 23 03:23:02 2003 +0000
@@ -134,7 +134,9 @@
 msn_message_new_from_str(MsnSession *session, const char *str)
 {
 	MsnMessage *msg;
+	char *command_header;
 	char *tmp_base, *msg_base, *tmp, *field1, *field2, *c;
+	const char *c2;
 
 	g_return_val_if_fail(str != NULL, NULL);
 	g_return_val_if_fail(!g_ascii_strncasecmp(str, "MSG", 3), NULL);
@@ -146,25 +148,36 @@
 	msn_message_set_content_type(msg, NULL);
 	msn_message_set_charset(msg, NULL);
 
-	tmp_base = tmp = g_strdup(str);
+	/*
+	 * 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 MSG */
+		field1 = tmp;
 
-	GET_NEXT(tmp); /* Skip the passport or TID */
-	field2 = tmp;
+		GET_NEXT(tmp); /* Skip the passport or TID */
+		field2 = tmp;
 
-	GET_NEXT(tmp); /* Skip the username or flag */
-	msg->size = atoi(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);
 
-#if 0
-	/* Put this back when we intelligently handle binary strings. */
-	if (msg->size != strlen(strchr(str, '\n') + 1)) {
-		gaim_debug(GAIM_DEBUG_ERROR, "msn",
-				   "Incoming message size (%d) and string length (%d) "
-				   "do not match!\n", msg->size, strlen(str));
+		return NULL;
 	}
-#endif
+
+	tmp_base = g_malloc(msg->size + 1);
+	memcpy(tmp_base, c2 + 2, msg->size);
+	tmp_base[msg->size] = '\0';
+
+	tmp = tmp_base;
 
 	/*
 	 * We're going to make sure this is incoming by checking field1.
@@ -236,6 +249,7 @@
 		char header[48];
 		char footer[4];
 		size_t body_len;
+		char *tmp2;
 
 		msg->msnslp_message = TRUE;
 
@@ -243,8 +257,7 @@
 
 		tmp += 48;
 
-		body_len = msg->size - (tmp - msg_base);
-		gaim_debug_misc("msn", "Body len = %d\n", body_len);
+		body_len = msg->size - (tmp - tmp_base) - 5;
 		msg->body = g_malloc(body_len + 1);
 
 		if (body_len > 0)
@@ -256,19 +269,22 @@
 
 		memcpy(footer, tmp, 4);
 
+		tmp += 4;
+
 		/* Import the header. */
-		msg->msnslp_header.session_id     = msn_get32(tmp); tmp += 4;
-		msg->msnslp_header.id             = msn_get32(tmp); tmp += 4;
-		msg->msnslp_header.offset_1       = msn_get32(tmp); tmp += 4;
-		msg->msnslp_header.offset_2       = msn_get32(tmp); tmp += 4;
-		msg->msnslp_header.total_size_1   = msn_get32(tmp); tmp += 4;
-		msg->msnslp_header.total_size_2   = msn_get32(tmp); tmp += 4;
-		msg->msnslp_header.length         = msn_get32(tmp); tmp += 4;
-		msg->msnslp_header.flags          = msn_get32(tmp); tmp += 4;
-		msg->msnslp_header.ack_session_id = msn_get32(tmp); tmp += 4;
-		msg->msnslp_header.ack_unique_id  = msn_get32(tmp); tmp += 4;
-		msg->msnslp_header.ack_length_1   = msn_get32(tmp); tmp += 4;
-		msg->msnslp_header.ack_length_2   = msn_get32(tmp); tmp += 4;
+		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;
 
 		/* Convert to the right endianness */
 		msg->msnslp_header.session_id = ntohl(msg->msnslp_header.session_id);
@@ -292,6 +308,7 @@
 		msn_message_set_body(msg, tmp);
 	}
 
+	g_free(command_header);
 	g_free(tmp_base);
 
 	/* Done! */
@@ -476,7 +493,7 @@
 
 			if (body != NULL)
 			{
-				memcpy(c, body, msg->size - (c - msg_start));
+				memcpy(c, body, bin_len);
 
 				c += bin_len;
 			}
@@ -626,7 +643,10 @@
 	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);
--- a/src/protocols/msn/msg.h	Sat Nov 22 23:17:31 2003 +0000
+++ b/src/protocols/msn/msg.h	Sun Nov 23 03:23:02 2003 +0000
@@ -79,7 +79,7 @@
 
 	MsnSlpHeader msnslp_header;
 	MsnSlpFooter msnslp_footer;
-	
+
 	MsnMessage *acked_msg;
 
 	GHashTable *attr_table;
--- a/src/protocols/msn/msnslp.c	Sat Nov 22 23:17:31 2003 +0000
+++ b/src/protocols/msn/msnslp.c	Sun Nov 23 03:23:02 2003 +0000
@@ -51,13 +51,123 @@
 	if (session->call_id != NULL)
 		g_free(session->call_id);
 
+	if (session->branch != NULL)
+		g_free(session->branch);
+
 	g_free(session);
 }
 
+static void
+msn_slp_session_send_message(MsnSlpSession *slpsession,
+							 MsnMessage *source_msg,
+							 MsnUser *local_user, MsnUser *remote_user,
+							 const char *header, const char *branch,
+							 int cseq, const char *call_id,
+							 const char *content)
+{
+	MsnMessage *invite_msg;
+	char *body;
+
+	g_return_if_fail(slpsession != NULL);
+	g_return_if_fail(header     != NULL);
+	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";
+
+	body = g_strdup_printf(
+		"%s\r\n"
+		"To: <msnmsgr:%s>\r\n"
+		"From: <msnmsgr:%s>\r\n"
+		"Via: MSNSLP/1.0/TLP ;branch={%s}\r\n"
+		"CSeq: %d\r\n"
+		"Call-ID: {%s}\r\n"
+		"Max-Forwards: 0\r\n"
+		"Content-Type: application/x-msnmsgr-sessionreqbody\r\n"
+		"Content-Length: %d\r\n"
+		"\r\n"
+		"%s"
+		"\r\n\r\n",
+		header,
+		msn_user_get_passport(remote_user),
+		msn_user_get_passport(local_user),
+		branch, cseq, call_id,
+		(content == NULL ? 0  : (int)strlen(content) + 5),
+		(content == NULL ? "" : content));
+
+	gaim_debug_misc("msn", "Message = {%s}\n", body);
+
+	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);
+
+	msn_slp_session_send_msg(slpsession, invite_msg);
+}
+
+static gboolean
+send_error_500(MsnSlpSession *slpsession, const char *call_id, MsnMessage *msg)
+{
+	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,
+								 "MSNSLP/1.0 500 Internal Error",
+								 slpsession->branch, 1, call_id, NULL);
+
+	return TRUE;
+}
+
+static gboolean
+send_cb(gpointer user_data)
+{
+	MsnSlpSession *slpsession = (MsnSlpSession *)user_data;
+	MsnMessage *msg;
+	char data[1200];
+	size_t len;
+
+	len = fread(data, 1, 1200, slpsession->send_fp);
+
+	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);
+
+	if (slpsession->remaining_size <= 0)
+	{
+		slpsession->send_timer = 0;
+
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
 gboolean
 msn_slp_session_msg_received(MsnSlpSession *slpsession, MsnMessage *msg)
 {
 	const char *body;
+	const char *c, *c2;
+	GaimAccount *account;
 
 	g_return_val_if_fail(slpsession != NULL,  TRUE);
 	g_return_val_if_fail(msg != NULL,         TRUE);
@@ -65,9 +175,13 @@
 	g_return_val_if_fail(!strcmp(msn_message_get_content_type(msg),
 								 "application/x-msnmsgrp2p"), TRUE);
 
+	account = slpsession->swboard->servconn->session->account;
+
 	body = msn_message_get_body(msg);
 
-	if (strlen(body) == 0)
+	gaim_debug_misc("msn", "MSNSLP Message: {%s}\n", body);
+
+	if (*body == '\0')
 	{
 		/* ACK. Ignore it. */
 		gaim_debug_info("msn", "Received MSNSLP ACK\n");
@@ -75,6 +189,161 @@
 		return FALSE;
 	}
 
+	if (slpsession->send_fp != NULL && slpsession->remaining_size == 0)
+	{
+		/*
+		 * In theory, if we received something while send_fp is non-NULL,
+		 * but remaining_size is 0, then this is a data ack message.
+		 *
+		 * Say BYE-BYE.
+		 */
+		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)));
+
+		msn_slp_session_send_message(slpsession, msg, NULL, NULL, header,
+									 "A0D624A6-6C0C-4283-A9E0-BC97B4B46D32",
+									 0, slpsession->call_id, "");
+
+		g_free(header);
+
+		return TRUE;
+	}
+
+	if (!strncmp(body, "MSNSLP/1.0 ", strlen("MSNSLP/1.0 ")))
+	{
+		/* Make sure this is "OK" */
+		const char *status = body + strlen("MSNSLP/1.0 ");
+
+		if (strncmp(status, "200 OK", 6))
+		{
+			/* It's not valid. Kill this off. */
+			char temp[32];
+			const char *c;
+
+			/* Eww */
+			if ((c = strchr(status, '\r')) || (c = strchr(status, '\n')) ||
+				(c = strchr(status, '\0')))
+			{
+				strncpy(temp, status, c - status);
+				temp[c - status] = '\0';
+			}
+
+			gaim_debug_error("msn", "Received non-OK result: %s\n", temp);
+
+			return TRUE;
+		}
+	}
+	else if (!strncmp(body, "INVITE", strlen("INVITE")))
+	{
+		/* Parse it. Oh this is fun. */
+		char *branch, *call_id, *temp;
+		unsigned int session_id, app_id;
+
+		/* First, branch. */
+		if ((c = strstr(body, ";branch={")) == NULL)
+			return send_error_500(slpsession, NULL, msg);
+
+		c += strlen(";branch={");
+
+		if ((c2 = strchr(c, '}')) == NULL)
+			return send_error_500(slpsession, NULL, msg);
+
+		branch = g_strndup(c, c2 - c);
+
+		if (slpsession->branch != NULL)
+			slpsession->branch = branch;
+
+		/* Second, Call-ID */
+		if ((c = strstr(body, "Call-ID: {")) == NULL)
+			return send_error_500(slpsession, NULL, msg);
+
+		c += strlen("Call-ID: {");
+
+		if ((c2 = strchr(c, '}')) == NULL)
+			return send_error_500(slpsession, NULL, msg);
+
+		call_id = g_strndup(c, c2 - c);
+
+		if (slpsession->call_id != NULL)
+			slpsession->call_id = call_id;
+
+		/* Third, SessionID */
+		if ((c = strstr(body, "SessionID: ")) == NULL)
+			return send_error_500(slpsession, NULL, msg);
+
+		c += strlen("SessionID: ");
+
+		if ((c2 = strchr(c, '\r')) == NULL)
+			return send_error_500(slpsession, NULL, msg);
+
+		temp = g_strndup(c, c2 - c);
+		session_id = atoi(temp);
+		g_free(temp);
+
+		/* Fourth, AppID */
+		if ((c = strstr(body, "AppID: ")) == NULL)
+			return send_error_500(slpsession, NULL, msg);
+
+		c += strlen("AppID: ");
+
+		if ((c2 = strchr(c, '\r')) == NULL)
+			return send_error_500(slpsession, NULL, msg);
+
+		temp = g_strndup(c, c2 - c);
+		app_id = atoi(temp);
+		g_free(temp);
+
+		if (app_id == 1)
+		{
+			MsnMessage *new_msg;
+			char *content;
+			char nil_body[4];
+			struct stat st;
+
+			/* Send the 200 OK message. */
+			content = g_strdup_printf("SessionID: %d", session_id);
+			msn_slp_session_send_ack(slpsession, msg);
+
+			msn_slp_session_send_message(slpsession, msg, NULL, NULL,
+										 "MSNSLP/1.0 200 OK",
+										 branch, 1, call_id, content);
+
+			g_free(content);
+
+			/* Send the Data Preparation message. */
+			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;
+
+			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;
+
+			msn_slp_session_send_msg(slpsession, new_msg);
+
+			slpsession->send_fp =
+				fopen(gaim_account_get_buddy_icon(account), "rb");
+
+			if (stat(gaim_account_get_buddy_icon(account), &st) == 0)
+				slpsession->remaining_size = st.st_size;
+
+			slpsession->send_timer = g_timeout_add(10, send_cb, slpsession);
+		}
+		else
+			return send_error_500(slpsession, call_id, msg);
+
+		return FALSE;
+	}
+
 	/* Now send an ack, since we got this. */
 	msn_slp_session_send_ack(slpsession, msg);
 
@@ -207,14 +476,11 @@
 									 MsnUser *remote_user,
 									 const MsnObject *obj)
 {
-	MsnMessage *invite_msg;
 	long session_id;
 	char *msnobj_data;
 	char *msnobj_base64;
-	char *branch;
+	char *header;
 	char *content;
-	char *body;
-	char *c;
 
 	g_return_if_fail(slpsession  != NULL);
 	g_return_if_fail(local_user  != NULL);
@@ -225,20 +491,23 @@
 	msnobj_base64 = gaim_base64_encode(msnobj_data, strlen(msnobj_data));
 	g_free(msnobj_data);
 
-	if ((c = strchr(msnobj_base64, '=')) != NULL)
-		*c = '\0';
-
 	session_id = rand() % 0xFFFFFF00 + 4;
 
-	branch = g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X",
-							 rand() % 0xAAFF + 0x1111,
-							 rand() % 0xAAFF + 0x1111,
-							 rand() % 0xAAFF + 0x1111,
-							 rand() % 0xAAFF + 0x1111,
-							 rand() % 0xAAFF + 0x1111,
-							 rand() % 0xAAFF + 0x1111,
-							 rand() % 0xAAFF + 0x1111,
-							 rand() % 0xAAFF + 0x1111);
+	if (slpsession->branch != NULL)
+		g_free(slpsession->branch);
+
+	slpsession->branch = g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X",
+										 rand() % 0xAAFF + 0x1111,
+										 rand() % 0xAAFF + 0x1111,
+										 rand() % 0xAAFF + 0x1111,
+										 rand() % 0xAAFF + 0x1111,
+										 rand() % 0xAAFF + 0x1111,
+										 rand() % 0xAAFF + 0x1111,
+										 rand() % 0xAAFF + 0x1111,
+										 rand() % 0xAAFF + 0x1111);
+
+	if (slpsession->call_id != NULL)
+		g_free(slpsession->call_id);
 
 	slpsession->call_id = g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X",
 										  rand() % 0xAAFF + 0x1111,
@@ -260,44 +529,15 @@
 
 	g_free(msnobj_base64);
 
-	body = g_strdup_printf(
-		"INVITE MSNMSGR:%s MSNSLP/1.0\r\n"
-		"To: <msnmsgr:%s>\r\n"
-		"From: <msnmsgr:%s>\r\n"
-		"Via: MSNSLP/1.0/TLP ;branch={%s}\r\n"
-		"CSeq: 0\r\n"
-		"Call-ID: {%s}\r\n"
-		"Max-Forwards: 0\r\n"
-		"Content-Type: application/x-msnmsgr-sessionreqbody\r\n"
-		"Content-Length: %d\r\n"
-		"\r\n"
-		"%s"
-		"\r\n\r\n",
-		msn_user_get_passport(remote_user),
-		msn_user_get_passport(remote_user),
-		msn_user_get_passport(local_user),
-		branch,
-		slpsession->call_id,
-		(int)strlen(content) + 5,
-		content);
+	header = g_strdup_printf("INVITE MSNMSGR:%s MSNSLP/1.0",
+							 msn_user_get_passport(remote_user));
 
-	g_free(content);
-	g_free(branch);
-
-	gaim_debug_misc("msn", "Message = {%s}\n", body);
-
-	invite_msg = msn_message_new_msnslp();
+	msn_slp_session_send_message(slpsession, NULL, local_user, remote_user,
+								 header, slpsession->branch, 0,
+								 slpsession->call_id, content);
 
-	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);
-
-	msn_slp_session_send_msg(slpsession, invite_msg);
-
-	msn_message_destroy(invite_msg);
+	g_free(header);
+	g_free(content);
 }
 
 gboolean
--- a/src/protocols/msn/msnslp.h	Sat Nov 22 23:17:31 2003 +0000
+++ b/src/protocols/msn/msnslp.h	Sun Nov 23 03:23:02 2003 +0000
@@ -35,6 +35,7 @@
 
 	MsnSwitchBoard *swboard;
 
+	char *branch;
 	char *call_id;
 
 	long session_id;
@@ -46,6 +47,14 @@
 	void *orig_body;
 	size_t orig_len;
 
+	guint send_timer;
+	FILE *send_fp;
+
+	size_t remaining_size;
+
+	MsnUser *receiver;
+	MsnUser *sender;
+
 	MsnMessage *outgoing_msg;
 };
 
--- a/src/protocols/msn/servconn.c	Sat Nov 22 23:17:31 2003 +0000
+++ b/src/protocols/msn/servconn.c	Sun Nov 23 03:23:02 2003 +0000
@@ -146,11 +146,16 @@
 
 	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%s",
+				   "MSG %s %s %d\r\n",
 				   servconn->msg_passport, servconn->msg_friendly,
-				   servconn->multiline_len, buffer);
+				   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);