changeset 10463:9bed28273ec7

[gaim-migrate @ 11737] Felipe Contreras fixed the MSN HTTP Method. Yay! Thanks Felipe. committer: Tailor Script <tailor@pidgin.im>
author Stu Tomlinson <stu@nosnilmot.com>
date Fri, 31 Dec 2004 16:34:22 +0000
parents f7b32dd67bdf
children 61ef9a964574
files src/protocols/msn/Makefile.am src/protocols/msn/Makefile.mingw src/protocols/msn/cmdproc.h src/protocols/msn/httpconn.c src/protocols/msn/httpconn.h src/protocols/msn/httpmethod.c src/protocols/msn/httpmethod.h src/protocols/msn/msn.c src/protocols/msn/notification.c src/protocols/msn/notification.h src/protocols/msn/servconn.c src/protocols/msn/servconn.h src/protocols/msn/session.c src/protocols/msn/session.h src/protocols/msn/switchboard.c src/protocols/msn/switchboard.h
diffstat 16 files changed, 1199 insertions(+), 860 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/msn/Makefile.am	Fri Dec 31 15:34:18 2004 +0000
+++ b/src/protocols/msn/Makefile.am	Fri Dec 31 16:34:22 2004 +0000
@@ -18,8 +18,8 @@
 	group.h \
 	history.c \
 	history.h \
-	httpmethod.c \
-	httpmethod.h \
+	httpconn.c \
+	httpconn.h \
 	msg.c \
 	msg.h \
 	msn.c \
--- a/src/protocols/msn/Makefile.mingw	Fri Dec 31 15:34:18 2004 +0000
+++ b/src/protocols/msn/Makefile.mingw	Fri Dec 31 16:34:22 2004 +0000
@@ -75,7 +75,7 @@
 			error.c \
 			group.c \
 			history.c \
-			httpmethod.c \
+			httpconn.c \
 			msg.c \
 			msn.c \
 			nexus.c \
--- a/src/protocols/msn/cmdproc.h	Fri Dec 31 15:34:18 2004 +0000
+++ b/src/protocols/msn/cmdproc.h	Fri Dec 31 16:34:22 2004 +0000
@@ -55,6 +55,8 @@
 	/* MsnPayloadCb payload_cb; */
 
 	MsnHistory *history;
+
+	void *data; /**< Extra data, like the switchboard. */
 };
 
 MsnCmdProc *msn_cmdproc_new(MsnSession *session);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/protocols/msn/httpconn.c	Fri Dec 31 16:34:22 2004 +0000
@@ -0,0 +1,742 @@
+/**
+ * @file httpmethod.c HTTP connection method
+ *
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "msn.h"
+#include "debug.h"
+#include "httpconn.h"
+
+typedef struct
+{
+	MsnHttpConn *httpconn;
+	char *buffer;
+	size_t size;
+
+} MsnHttpQueueData;
+
+static void read_cb(gpointer data, gint source, GaimInputCondition cond);
+void msn_httpconn_process_queue(MsnHttpConn *httpconn);
+gboolean msn_httpconn_parse_data(MsnHttpConn *httpconn, const char *buf,
+								 size_t size, char **ret_buf, size_t *ret_size,
+								 gboolean *error);
+
+MsnHttpConn *
+msn_httpconn_new(MsnServConn *servconn)
+{
+	MsnHttpConn *httpconn;
+
+	g_return_val_if_fail(servconn != NULL, NULL);
+
+	httpconn = g_new0(MsnHttpConn, 1);
+
+	/* TODO: Remove this */
+	httpconn->session = servconn->session;
+
+	httpconn->servconn = servconn;
+
+	return httpconn;
+}
+
+void
+msn_httpconn_destroy(MsnHttpConn *httpconn)
+{
+	g_return_if_fail(httpconn != NULL);
+
+	if (httpconn->connected)
+		msn_httpconn_disconnect(httpconn);
+
+	if (httpconn->host != NULL)
+		g_free(httpconn->host);
+
+	g_free(httpconn);
+}
+
+static void
+show_error(MsnHttpConn *httpconn)
+{
+	GaimConnection *gc;
+	char *tmp;
+	char *cmd;
+
+	const char *names[] = { "Notification", "Switchboard" };
+	const char *name;
+
+	gc = gaim_account_get_connection(httpconn->servconn->session->account);
+	name = names[httpconn->servconn->type];
+
+	switch (httpconn->servconn->cmdproc->error)
+	{
+		case MSN_ERROR_CONNECT:
+			tmp = g_strdup_printf(_("Unable to connect to %s server"),
+								  name);
+			break;
+		case MSN_ERROR_WRITE:
+			tmp = g_strdup_printf(_("Error writing to %s server"), name);
+			break;
+		case MSN_ERROR_READ:
+			cmd = httpconn->servconn->cmdproc->last_trans;
+			tmp = g_strdup_printf(_("Error reading from %s server"), name);
+			gaim_debug_info("msn", "Last command was: %s\n", cmd);
+			break;
+		default:
+			tmp = g_strdup_printf(_("Unknown error from %s server"), name);
+			break;
+	}
+
+	if (httpconn->servconn->type == MSN_SERVER_NS)
+	{
+		gaim_connection_error(gc, tmp);
+	}
+	else
+	{
+		MsnSwitchBoard *swboard;
+		swboard = httpconn->servconn->cmdproc->data;
+		swboard->error = MSN_SB_ERROR_CONNECTION;
+	}
+
+	g_free(tmp);
+}
+
+static ssize_t
+write_raw(MsnHttpConn *httpconn, const void *buffer, size_t len)
+{
+	ssize_t s;
+	ssize_t res; /* result of the write operation */
+
+#ifdef MSN_DEBUG_HTTP
+	gaim_debug_misc("msn", "Writing HTTP: {%s}\n", buffer);
+#endif
+
+	s = 0;
+
+	do
+	{
+		res = write(httpconn->fd, buffer, len);
+		if (res >= 0)
+		{
+			s += res;
+		}
+		else if (errno != EAGAIN)
+		{
+			httpconn->servconn->cmdproc->error = MSN_ERROR_WRITE;
+			show_error(httpconn);
+			return -1;
+		}
+	} while (s < len);
+
+	return s;
+}
+
+void
+msn_httpconn_poll(MsnHttpConn *httpconn)
+{
+	int r;
+	char *temp;
+
+	g_return_if_fail(httpconn != NULL);
+
+	if (httpconn->waiting_response ||
+		httpconn->queue != NULL)
+	{
+		return;
+	}
+
+	temp = g_strdup_printf(
+		"POST http://%s/gateway/gateway.dll?Action=poll&SessionID=%s HTTP/1.1\r\n"
+		"Accept: */*\r\n"
+		"Accept-Language: en-us\r\n"
+		"User-Agent: MSMSGS\r\n"
+		"Host: %s\r\n"
+		"Proxy-Connection: Keep-Alive\r\n"
+		"Connection: Keep-Alive\r\n"
+		"Pragma: no-cache\r\n"
+		"Content-Type: application/x-msn-messenger\r\n"
+		"Content-Length: 0\r\n"
+		"\r\n",
+		httpconn->host,
+		httpconn->full_session_id,
+		httpconn->host);
+
+	r = write_raw(httpconn, temp, strlen(temp));
+
+	g_free(temp);
+
+	if (r > 0)
+	{
+		httpconn->waiting_response = TRUE;
+		httpconn->dirty = FALSE;
+	}
+}
+
+static gboolean
+poll(gpointer data)
+{
+	MsnHttpConn *httpconn;
+
+	httpconn = data;
+
+#if 0
+	gaim_debug_info("msn", "polling from %s\n", httpconn->session_id);
+#endif
+
+	if (httpconn->dirty)
+		msn_httpconn_poll(httpconn);
+
+	return TRUE;
+}
+
+static void
+connect_cb(gpointer data, gint source, GaimInputCondition cond)
+{
+	MsnHttpConn *httpconn = data;
+
+	httpconn->fd = source;
+
+	if (source > 0)
+	{
+		httpconn->inpa = gaim_input_add(httpconn->fd, GAIM_INPUT_READ,
+										read_cb, data);
+
+		httpconn->timer = gaim_timeout_add(2000, poll, httpconn);
+
+		httpconn->waiting_response = FALSE;
+		msn_httpconn_process_queue(httpconn);
+	}
+	else
+	{
+		gaim_debug_error("msn", "HTTP: Connection error\n");
+		show_error(httpconn);
+	}
+}
+
+gboolean
+msn_httpconn_connect(MsnHttpConn *httpconn, const char *host, int port)
+{
+	int r;
+
+	g_return_val_if_fail(httpconn != NULL, FALSE);
+	g_return_val_if_fail(host     != NULL, FALSE);
+	g_return_val_if_fail(port      > 0,    FALSE);
+
+	if (httpconn->connected)
+		msn_httpconn_disconnect(httpconn);
+
+	r = gaim_proxy_connect(httpconn->session->account,
+						   "gateway.messenger.hotmail.com", 80, connect_cb,
+						   httpconn);
+
+	if (r == 0)
+	{
+		httpconn->waiting_response = TRUE;
+		httpconn->connected = TRUE;
+	}
+
+	return httpconn->connected;
+}
+
+void
+msn_httpconn_disconnect(MsnHttpConn *httpconn)
+{
+	g_return_if_fail(httpconn != NULL);
+	g_return_if_fail(httpconn->connected);
+
+	if (httpconn->timer)
+		gaim_timeout_remove(httpconn->timer);
+
+	httpconn->timer = 0;
+
+	if (httpconn->inpa > 0)
+	{
+		gaim_input_remove(httpconn->inpa);
+		httpconn->inpa = 0;
+	}
+
+	close(httpconn->fd);
+
+	httpconn->rx_buf = NULL;
+	httpconn->rx_len = 0;
+
+	httpconn->connected = FALSE;
+
+	/* msn_servconn_disconnect(httpconn->servconn); */
+}
+
+static void
+read_cb(gpointer data, gint source, GaimInputCondition cond)
+{
+	MsnHttpConn *httpconn;
+	MsnServConn *servconn;
+	MsnSession *session;
+	char buf[MSN_BUF_LEN];
+	char *cur, *end, *old_rx_buf;
+	int len, cur_len;
+	char *result_msg = NULL;
+	size_t result_len = 0;
+	gboolean error;
+
+	httpconn = data;
+	servconn = NULL;
+	session = httpconn->session;
+
+	len = read(httpconn->fd, buf, sizeof(buf) - 1);
+
+	if (len <= 0)
+	{
+		gaim_debug_error("msn", "HTTP: Read error\n");
+		show_error(httpconn);
+		msn_httpconn_disconnect(httpconn);
+
+		return;
+	}
+
+	buf[len] = '\0';
+
+	httpconn->rx_buf = g_realloc(httpconn->rx_buf, len + httpconn->rx_len + 1);
+	memcpy(httpconn->rx_buf + httpconn->rx_len, buf, len + 1);
+	httpconn->rx_len += len;
+
+	if (!msn_httpconn_parse_data(httpconn, httpconn->rx_buf, httpconn->rx_len,
+								 &result_msg, &result_len, &error))
+	{
+		/* We must wait for more input */
+
+		return;
+	}
+
+	httpconn->servconn->processing = FALSE;
+
+	servconn = httpconn->servconn;
+
+	if (error)
+	{
+		gaim_debug_error("msn", "HTTP: Special error\n");
+		show_error(httpconn);
+		msn_httpconn_disconnect(httpconn);
+
+		return;
+	}
+
+	if (result_len == 0)
+	{
+		/* Nothing to do here */
+#if 0
+		gaim_debug_info("msn", "HTTP: nothing to do here\n");
+#endif
+		g_free(httpconn->rx_buf);
+		httpconn->rx_buf = NULL;
+		httpconn->rx_len = 0;
+		return;
+	}
+
+	g_free(httpconn->rx_buf);
+	httpconn->rx_buf = NULL;
+	httpconn->rx_len = 0;
+
+	servconn->rx_buf = result_msg;
+	servconn->rx_len = result_len;
+
+	end = old_rx_buf = servconn->rx_buf;
+
+	servconn->processing = TRUE;
+
+	do
+	{
+		cur = end;
+
+		if (servconn->payload_len)
+		{
+			if (servconn->payload_len > servconn->rx_len)
+				/* The payload is still not complete. */
+				break;
+
+			cur_len = servconn->payload_len;
+			end += cur_len;
+		}
+		else
+		{
+			end = strstr(cur, "\r\n");
+
+			if (end == NULL)
+				/* The command is still not complete. */
+				break;
+
+			*end = '\0';
+			end += 2;
+			cur_len = end - cur;
+		}
+
+		servconn->rx_len -= cur_len;
+
+		if (servconn->payload_len)
+		{
+			msn_cmdproc_process_payload(servconn->cmdproc, cur, cur_len);
+			servconn->payload_len = 0;
+		}
+		else
+		{
+			msn_cmdproc_process_cmd_text(servconn->cmdproc, cur);
+		}
+	} while (servconn->connected && servconn->rx_len > 0);
+
+	if (servconn->connected)
+	{
+		if (servconn->rx_len > 0)
+			servconn->rx_buf = g_memdup(cur, servconn->rx_len);
+		else
+			servconn->rx_buf = NULL;
+	}
+
+	servconn->processing = FALSE;
+
+	if (servconn->wasted)
+		msn_servconn_destroy(servconn);
+
+	g_free(old_rx_buf);
+}
+
+void
+msn_httpconn_process_queue(MsnHttpConn *httpconn)
+{
+	if (httpconn->queue != NULL)
+	{
+		MsnHttpQueueData *queue_data;
+
+		queue_data = (MsnHttpQueueData *)httpconn->queue->data;
+
+		httpconn->queue = g_list_remove(httpconn->queue, queue_data);
+
+		msn_httpconn_write(queue_data->httpconn,
+						   queue_data->buffer,
+						   queue_data->size);
+
+		g_free(queue_data->buffer);
+		g_free(queue_data);
+	}
+	else
+	{
+		httpconn->dirty = TRUE;
+	}
+}
+
+size_t
+msn_httpconn_write(MsnHttpConn *httpconn, const char *buf, size_t size)
+{
+	char *params;
+	char *temp;
+	gboolean first;
+	const char *server_types[] = { "NS", "SB" };
+	const char *server_type;
+	size_t r; /* result of the write operation */
+	size_t len;
+	char *host;
+	MsnServConn *servconn;
+
+	/* TODO: remove http data from servconn */
+
+	g_return_val_if_fail(httpconn != NULL, 0);
+	g_return_val_if_fail(buf      != NULL, 0);
+	g_return_val_if_fail(size      > 0,    0);
+
+	servconn = httpconn->servconn;
+
+	if (httpconn->waiting_response)
+	{
+		MsnHttpQueueData *queue_data = g_new0(MsnHttpQueueData, 1);
+
+		queue_data->httpconn = httpconn;
+		queue_data->buffer   = g_memdup(buf, size);
+		queue_data->size     = size;
+
+		httpconn->queue = g_list_append(httpconn->queue, queue_data);
+		/* httpconn->dirty = TRUE; */
+
+		/* servconn->processing = TRUE; */
+
+		return size;
+	}
+
+	first = httpconn->virgin;
+	server_type = server_types[servconn->type];
+
+	if (first)
+	{
+		host = "gateway.messenger.hotmail.com";
+
+		/* The first time servconn->host is the host we should connect to. */
+		params = g_strdup_printf("Action=open&Server=%s&IP=%s",
+								 server_type,
+								 servconn->host);
+	}
+	else
+	{
+		/* The rest of the times servconn->host is the gateway host. */
+		host = httpconn->host;
+
+		params = g_strdup_printf("SessionID=%s",
+								 httpconn->full_session_id);
+	}
+
+	temp = g_strdup_printf(
+		"POST http://%s/gateway/gateway.dll?%s HTTP/1.1\r\n"
+		"Accept: */*\r\n"
+		"Accept-Language: en-us\r\n"
+		"User-Agent: MSMSGS\r\n"
+		"Host: %s\r\n"
+		"Proxy-Connection: Keep-Alive\r\n"
+		"Connection: Keep-Alive\r\n"
+		"Pragma: no-cache\r\n"
+		"Content-Type: application/x-msn-messenger\r\n"
+		"Content-Length: %d\r\n"
+		"\r\n",
+		host,
+		params,
+		host,
+		(int)size);
+
+	g_free(params);
+
+	len = strlen(temp);
+	temp = g_realloc(temp, len + size + 1);
+	memcpy(temp + len, buf, size);
+	len += size;
+	temp[len] = '\0';
+
+	r = write_raw(httpconn, temp, len);
+
+	g_free(temp);
+
+	if (r > 0)
+	{
+		httpconn->virgin = FALSE;
+		httpconn->waiting_response = TRUE;
+		httpconn->dirty = FALSE;
+	}
+
+	return r;
+}
+
+gboolean
+msn_httpconn_parse_data(MsnHttpConn *httpconn, const char *buf,
+						size_t size, char **ret_buf, size_t *ret_size,
+						gboolean *error)
+{
+	GaimConnection *gc;
+	const char *s, *c;
+	char *headers, *body;
+	const char *body_start;
+	char *tmp;
+	size_t body_len = 0;
+	gboolean wasted = FALSE;
+
+	g_return_val_if_fail(httpconn != NULL, FALSE);
+	g_return_val_if_fail(buf      != NULL, FALSE);
+	g_return_val_if_fail(size      > 0,    FALSE);
+	g_return_val_if_fail(ret_buf  != NULL, FALSE);
+	g_return_val_if_fail(ret_size != NULL, FALSE);
+	g_return_val_if_fail(error    != NULL, FALSE);
+
+#if 0
+	gaim_debug_info("msn", "HTTP: parsing data {%s}\n", buf);
+#endif
+
+	httpconn->waiting_response = FALSE;
+
+	gc = gaim_account_get_connection(httpconn->session->account);
+
+	/* Healthy defaults. */
+	body = NULL;
+
+	*ret_buf  = NULL;
+	*ret_size = 0;
+	*error    = FALSE;
+
+	/* First, some tests to see if we have a full block of stuff. */
+	if (((strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) != 0) &&
+		 (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) != 0)) &&
+		((strncmp(buf, "HTTP/1.0 200 OK\r\n", 17) != 0) &&
+		 (strncmp(buf, "HTTP/1.0 100 Continue\r\n", 23) != 0)))
+	{
+		*error = TRUE;
+
+		return FALSE;
+	}
+
+	if (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) == 0)
+	{
+		if ((s = strstr(buf, "\r\n\r\n")) == NULL)
+			return FALSE;
+
+		s += 4;
+
+		if (*s == '\0')
+		{
+			*ret_buf = g_strdup("");
+			*ret_size = 0;
+
+			msn_httpconn_process_queue(httpconn);
+
+			return TRUE;
+		}
+
+		buf = s;
+		size -= (s - buf);
+	}
+
+	if ((s = strstr(buf, "\r\n\r\n")) == NULL)
+		return FALSE;
+
+	headers = g_strndup(buf, s - buf);
+	s += 4; /* Skip \r\n */
+	body_start = s;
+	body_len = size - (body_start - buf);
+
+	if ((s = strstr(headers, "Content-Length: ")) != NULL)
+	{
+		int tmp_len;
+
+		s += strlen("Content-Length: ");
+
+		if ((c = strchr(s, '\r')) == NULL)
+		{
+			g_free(headers);
+
+			return FALSE;
+		}
+
+		tmp = g_strndup(s, c - s);
+		tmp_len = atoi(tmp);
+		g_free(tmp);
+
+		if (body_len != tmp_len)
+		{
+			g_free(headers);
+
+#if 0
+			gaim_debug_warning("msn",
+							   "body length (%d) != content length (%d)\n",
+							   body_len, tmp_len);
+#endif
+
+			return FALSE;
+		}
+	}
+
+	body = g_memdup(body_start, body_len);
+
+#ifdef MSN_DEBUG_HTTP
+	gaim_debug_misc("msn", "Incoming HTTP buffer: {%s\r\n\r\n%s}\n", headers, body);
+#endif
+
+	/* Now we should be able to process the data. */
+	if ((s = strstr(headers, "X-MSN-Messenger: ")) != NULL)
+	{
+		char *full_session_id, *gw_ip, *session_action;
+		char *t, *session_id;
+		char **elems, **cur, **tokens;
+
+		full_session_id = gw_ip = session_action = NULL;
+
+		s += strlen("X-MSN-Messenger: ");
+
+		if ((c = strchr(s, '\r')) == NULL)
+		{
+			gaim_connection_error(gc, "Malformed X-MSN-Messenger field.");
+			gaim_debug_error("msn", "Malformed X-MSN-Messenger field.\n{%s}",
+							 buf);
+
+			return FALSE;
+		}
+
+		tmp = g_strndup(s, c - s);
+
+		elems = g_strsplit(tmp, "; ", 0);
+
+		for (cur = elems; *cur != NULL; cur++)
+		{
+			tokens = g_strsplit(*cur, "=", 2);
+
+			if (strcmp(tokens[0], "SessionID") == 0)
+				full_session_id = tokens[1];
+			else if (strcmp(tokens[0], "GW-IP") == 0)
+				gw_ip = tokens[1];
+			else if (strcmp(tokens[0], "Session") == 0)
+				session_action = tokens[1];
+
+			g_free(tokens[0]);
+			/* Don't free each of the tokens, only the array. */
+			g_free(tokens);
+		}
+
+		g_strfreev(elems);
+
+		g_free(tmp);
+
+		if ((session_action != NULL) && (strcmp(session_action, "close") == 0))
+			wasted = TRUE;
+
+		g_free(session_action);
+
+		t = strchr(full_session_id, '.');
+		session_id = g_strndup(full_session_id, t - full_session_id);
+
+		if (!wasted)
+		{
+			if (httpconn->full_session_id != NULL);
+				g_free(httpconn->full_session_id);
+
+			httpconn->full_session_id = full_session_id;
+
+			if (httpconn->session_id != NULL);
+				g_free(httpconn->session_id);
+
+			httpconn->session_id = session_id;
+
+			if (httpconn->host != NULL);
+				g_free(httpconn->host);
+
+			httpconn->host = gw_ip;
+		}
+		else
+		{
+			MsnServConn *servconn;
+
+			/* It's going to die. */
+
+			servconn = httpconn->servconn;
+
+			if (servconn != NULL)
+				servconn->wasted = TRUE;
+
+			g_free(full_session_id);
+			g_free(gw_ip);
+		}
+	}
+
+	g_free(headers);
+
+	*ret_buf  = body;
+	*ret_size = body_len;
+
+	msn_httpconn_process_queue(httpconn);
+
+	return TRUE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/protocols/msn/httpconn.h	Fri Dec 31 16:34:22 2004 +0000
@@ -0,0 +1,128 @@
+/**
+ * @file httpconn.h HTTP connection
+ *
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef _MSN_HTTPCONN_H_
+#define _MSN_HTTPCONN_H_
+
+typedef struct _MsnHttpConn MsnHttpConn;
+
+#include "servconn.h"
+
+struct _MsnHttpConn
+{
+	MsnSession *session;
+	MsnServConn *servconn;
+
+	char *full_session_id;
+	char *session_id;
+
+	int timer;
+
+	gboolean waiting_response;
+	gboolean dirty; /**< The flag that states if we should poll. */
+	gboolean connected;
+
+	char *host;
+	GList *queue;
+
+	int fd;
+	int inpa;
+
+	char *rx_buf;
+	int rx_len;
+
+#if 0
+	GQueue *servconn_queue;
+#endif
+
+	gboolean virgin;
+};
+
+MsnHttpConn *msn_httpconn_new(MsnServConn *servconn);
+void msn_httpconn_destroy(MsnHttpConn *httpconn);
+size_t msn_httpconn_write(MsnHttpConn *httpconn, const char *buf, size_t size);
+
+gboolean msn_httpconn_connect(MsnHttpConn *httpconn,
+							  const char *host, int port);
+void msn_httpconn_disconnect(MsnHttpConn *httpconn);
+
+#if 0
+void msn_httpconn_queue_servconn(MsnHttpConn *httpconn, MsnServConn *servconn);
+#endif
+
+#if 0
+/**
+ * Initializes the HTTP data for a session.
+ *
+ * @param session The session.
+ */
+void msn_http_session_init(MsnSession *session);
+
+/**
+ * Uninitializes the HTTP data for a session.
+ *
+ * @param session The session.
+ */
+void msn_http_session_uninit(MsnSession *session);
+
+/**
+ * Writes data to the server using the HTTP connection method.
+ *
+ * @param servconn    The server connection.
+ * @param buf         The data to write.
+ * @param size        The size of the data to write.
+ * @param server_type The optional server type.
+ *
+ * @return The number of bytes written.
+ */
+size_t msn_http_servconn_write(MsnServConn *servconn, const char *buf,
+							   size_t size, const char *server_type);
+
+/**
+ * Polls the server for data.
+ *
+ * @param servconn The server connection.
+ */
+void msn_http_servconn_poll(MsnServConn *servconn);
+
+/**
+ * Processes an incoming message and returns a string the rest of MSN
+ * can deal with.
+ *
+ * @param servconn The server connection.
+ * @param buf      The incoming buffer.
+ * @param size     The incoming size.
+ * @param ret_buf  The returned buffer.
+ * @param ret_len  The returned length.
+ * @param error    TRUE if there was an HTTP error.
+ *
+ * @return TRUE if the returned buffer is ready to be processed.
+ *         FALSE otherwise.
+ */
+gboolean msn_http_servconn_parse_data(MsnServConn *servconn,
+									  const char *buf, size_t size,
+									  char **ret_buf, size_t *ret_size,
+									  gboolean *error);
+#endif
+
+#endif /* _MSN_HTTPCONN_H_ */
--- a/src/protocols/msn/httpmethod.c	Fri Dec 31 15:34:18 2004 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,462 +0,0 @@
-/**
- * @file httpmethod.c HTTP connection method
- *
- * gaim
- *
- * Gaim is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#include "debug.h"
-#include "httpmethod.h"
-
-#define GET_NEXT(tmp) \
-	while (*(tmp) && *(tmp) != ' ' && *(tmp) != '\r') \
-		(tmp)++; \
-	if (*(tmp) != '\0') *(tmp)++ = '\0'; \
-	if (*(tmp) == '\n') (tmp)++; \
-	while (*(tmp) && *(tmp) == ' ') \
-		(tmp)++
-
-#define GET_NEXT_LINE(tmp) \
-	while (*(tmp) && *(tmp) != '\r') \
-		(tmp)++; \
-	if (*(tmp) != '\0') *(tmp)++ = '\0'; \
-	if (*(tmp) == '\n') (tmp)++
-
-typedef struct
-{
-	MsnServConn *servconn;
-	char *buffer;
-	size_t size;
-	const char *server_type;
-
-} MsnHttpQueueData;
-
-static gboolean
-http_poll(gpointer data)
-{
-	MsnSession *session;
-	GList *l;
-
-	session = data;
-
-	for (l = session->switches; l != NULL; l = l->next)
-	{
-		MsnSwitchBoard *swboard;
-
-		swboard = l->data;
-
-		g_return_val_if_fail(swboard->servconn->http_data != NULL, FALSE);
-
-		if (swboard->servconn->http_data->dirty)
-		{
-#if 0
-			gaim_debug_info("msn", "Polling server %s.\n",
-							servconn->http_data->gateway_host);
-#endif
-			msn_http_servconn_poll(swboard->servconn);
-		}
-	}
-
-	if (session->notification->servconn->http_data->dirty)
-		msn_http_servconn_poll(session->notification->servconn);
-
-	return TRUE;
-}
-
-static void
-stop_timer(MsnSession *session)
-{
-	if (session->http_poll_timer)
-	{
-		gaim_timeout_remove(session->http_poll_timer);
-		session->http_poll_timer = 0;
-	}
-}
-
-static void
-start_timer(MsnSession *session)
-{
-	stop_timer(session);
-
-	session->http_poll_timer = gaim_timeout_add(2000, http_poll, session);
-}
-
-void
-msn_http_session_init(MsnSession *session)
-{
-	g_return_if_fail(session != NULL);
-
-	start_timer(session);
-}
-
-void
-msn_http_session_uninit(MsnSession *session)
-{
-	g_return_if_fail(session != NULL);
-
-	stop_timer(session);
-}
-
-size_t
-msn_http_servconn_write(MsnServConn *servconn, const char *buf, size_t size,
-						const char *server_type)
-{
-	size_t s, needed;
-	char *params;
-	char *temp;
-	gboolean first;
-	int res; /* result of the write operation */
-
-	g_return_val_if_fail(servconn != NULL, 0);
-	g_return_val_if_fail(buf      != NULL, 0);
-	g_return_val_if_fail(size      > 0,    0);
-	g_return_val_if_fail(servconn->http_data != NULL, 0);
-
-	if (servconn->http_data->waiting_response)
-	{
-		MsnHttpQueueData *queue_data = g_new0(MsnHttpQueueData, 1);
-
-		queue_data->servconn    = servconn;
-		queue_data->buffer      = g_strdup(buf);
-		queue_data->size        = size;
-		queue_data->server_type = server_type;
-
-		servconn->http_data->queue =
-			g_list_append(servconn->http_data->queue, queue_data);
-
-		return size;
-	}
-
-	first = servconn->http_data->virgin;
-
-	if (first)
-	{
-		if (server_type)
-		{
-			params = g_strdup_printf("Action=open&Server=%s&IP=%s",
-									 server_type,
-									 servconn->http_data->gateway_host);
-		}
-		else
-		{
-			params = g_strdup_printf("Action=open&IP=%s",
-									 servconn->http_data->gateway_host);
-		}
-	}
-	else
-	{
-		params = g_strdup_printf("SessionID=%s",
-								 servconn->http_data->session_id);
-	}
-
-	temp = g_strdup_printf(
-		"POST http://%s/gateway/gateway.dll?%s HTTP/1.1\r\n"
-		"Accept: */*\r\n"
-		"Accept-Language: en-us\r\n"
-		"User-Agent: MSMSGS\r\n"
-		"Host: %s\r\n"
-		"Proxy-Connection: Keep-Alive\r\n"
-		"Connection: Keep-Alive\r\n"
-		"Pragma: no-cache\r\n"
-		"Content-Type: application/x-msn-messenger\r\n"
-		"Content-Length: %d\r\n"
-		"\r\n"
-		"%s",
-		((strcmp(server_type, "SB") == 0) && first
-		 ? "gateway.messenger.hotmail.com"
-		 : servconn->http_data->gateway_host),
-		params,
-		servconn->http_data->gateway_host,
-		(int)size,
-		buf);
-
-	g_free(params);
-
-#if 0
-	gaim_debug_misc("msn", "Writing HTTP to fd %d: {%s}\n",
-					servconn->fd, temp);
-#endif
-
-	s = 0;
-	needed = strlen(temp);
-
-	do
-	{
-		res = write(servconn->fd, temp, needed);
-		if (res >= 0)
-			s += res;
-		else if (errno != EAGAIN)
-		{
-			char *msg = g_strdup_printf("Unable to write to MSN server via HTTP (error %d)", errno);
-			gaim_connection_error(servconn->session->account->gc, msg);
-			g_free(msg);
-			return -1;
-		}
-	} while (s < needed);
-
-	g_free(temp);
-
-	servconn->http_data->waiting_response = TRUE;
-	servconn->http_data->virgin = FALSE;
-	servconn->http_data->dirty = FALSE;
-
-	return s;
-}
-
-void
-msn_http_servconn_poll(MsnServConn *servconn)
-{
-	size_t s;
-	char *temp;
-
-	g_return_if_fail(servconn != NULL);
-	g_return_if_fail(servconn->http_data != NULL);
-
-	if (servconn->http_data->waiting_response ||
-		servconn->http_data->queue != NULL)
-	{
-		return;
-	}
-
-	temp = g_strdup_printf(
-		"POST http://%s/gateway/gateway.dll?Action=poll&SessionID=%s HTTP/1.1\r\n"
-		"Accept: */*\r\n"
-		"Accept-Language: en-us\r\n"
-		"User-Agent: MSMSGS\r\n"
-		"Host: %s\r\n"
-		"Proxy-Connection: Keep-Alive\r\n"
-		"Connection: Keep-Alive\r\n"
-		"Pragma: no-cache\r\n"
-		"Content-Type: application/x-msn-messenger\r\n"
-		"Content-Length: 0\r\n"
-		"\r\n",
-		servconn->http_data->gateway_host,
-		servconn->http_data->session_id,
-		servconn->http_data->gateway_host);
-
-#if 0
-	gaim_debug_misc("msn", "Writing to HTTP: {%s}\n", temp);
-#endif
-
-	s = write(servconn->fd, temp, strlen(temp));
-
-	g_free(temp);
-
-	servconn->http_data->waiting_response = TRUE;
-	servconn->http_data->dirty = FALSE;
-
-	if (s <= 0)
-		gaim_connection_error(servconn->session->account->gc,
-							  _("Write error"));
-}
-
-gboolean
-msn_http_servconn_parse_data(MsnServConn *servconn, const char *buf,
-							 size_t size, char **ret_buf, size_t *ret_size,
-							 gboolean *error)
-{
-	GaimConnection *gc;
-	const char *s, *c;
-	char *headers, *body;
-	char *tmp;
-	size_t len = 0;
-
-	g_return_val_if_fail(servconn != NULL, FALSE);
-	g_return_val_if_fail(buf      != NULL, FALSE);
-	g_return_val_if_fail(size      > 0,    FALSE);
-	g_return_val_if_fail(ret_buf  != NULL, FALSE);
-	g_return_val_if_fail(ret_size != NULL, FALSE);
-	g_return_val_if_fail(error    != NULL, FALSE);
-
-#if 0
-	gaim_debug_info("msn", "parsing data {%s} from fd %d\n",
-					buf, servconn->fd);
-#endif
-	servconn->http_data->waiting_response = FALSE;
-
-	gc = gaim_account_get_connection(servconn->session->account);
-
-	/* Healthy defaults. */
-	*ret_buf  = NULL;
-	*ret_size = 0;
-	*error    = FALSE;
-
-	/* First, some tests to see if we have a full block of stuff. */
-	if (((strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) != 0) &&
-		 (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) != 0)) &&
-		((strncmp(buf, "HTTP/1.0 200 OK\r\n", 17) != 0) &&
-		 (strncmp(buf, "HTTP/1.0 100 Continue\r\n", 23) != 0)))
-	{
-		*error = TRUE;
-
-		return FALSE;
-	}
-
-	if (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) == 0)
-	{
-		if ((s = strstr(buf, "\r\n\r\n")) == NULL)
-			return FALSE;
-
-		s += 4;
-
-		if (*s == '\0')
-		{
-			*ret_buf = g_strdup("");
-			*ret_size = 0;
-
-			return TRUE;
-		}
-
-		buf = s;
-		size -= (s - buf);
-	}
-
-	if ((s = strstr(buf, "\r\n\r\n")) == NULL)
-		return FALSE;
-
-	headers = g_strndup(buf, s - buf);
-	s += 4; /* Skip \r\n */
-	body = g_strndup(s, size - (s - buf));
-
-#if 0
-	gaim_debug_misc("msn", "Incoming HTTP buffer: {%s\r\n%s}", headers, body);
-#endif
-
-	if ((s = strstr(headers, "Content-Length: ")) != NULL)
-	{
-		s += strlen("Content-Length: ");
-
-		if ((c = strchr(s, '\r')) == NULL)
-		{
-			g_free(headers);
-			g_free(body);
-
-			return FALSE;
-		}
-
-		tmp = g_strndup(s, c - s);
-		len = atoi(tmp);
-		g_free(tmp);
-
-		if (strlen(body) != len)
-		{
-			g_free(headers);
-			g_free(body);
-
-			gaim_debug_warning("msn",
-							   "body length (%d) != content length (%d)\n",
-							   strlen(body), len);
-			return FALSE;
-		}
-	}
-
-	/* Now we should be able to process the data. */
-	if ((s = strstr(headers, "X-MSN-Messenger: ")) != NULL)
-	{
-		char *session_id, *gw_ip;
-		char *c2, *s2;
-
-		s += strlen("X-MSN-Messenger: ");
-
-		if ((c = strchr(s, '\r')) == NULL)
-		{
-			gaim_connection_error(gc, "Malformed X-MSN-Messenger field.");
-			return FALSE;
-		}
-
-		tmp = g_strndup(s, c - s);
-
-		/* Find the value for the Session ID */
-		if ((s2 = strchr(tmp, '=')) == NULL)
-		{
-			gaim_connection_error(gc, "Malformed X-MSN-Messenger field.");
-			return FALSE;
-		}
-
-		s2++;
-
-		/* Terminate the ; so we can g_strdup it. */
-		if ((c2 = strchr(s2, ';')) == NULL)
-		{
-			gaim_connection_error(gc, "Malformed X-MSN-Messenger field.");
-			return FALSE;
-		}
-
-		*c2 = '\0';
-		c2++;
-
-		/* Now grab that session ID. */
-		session_id = g_strdup(s2);
-
-		/* Continue to the gateway IP */
-		if ((s2 = strchr(c2, '=')) == NULL)
-		{
-			gaim_connection_error(gc, "Malformed X-MSN-Messenger field.");
-			return FALSE;
-		}
-
-		s2++;
-
-		/* Grab the gateway IP */
-		gw_ip = g_strdup(s2);
-
-		g_free(tmp);
-
-		/* Set the new data. */
-		if (servconn->http_data->session_id != NULL)
-			g_free(servconn->http_data->session_id);
-
-		if (servconn->http_data->old_gateway_host != NULL)
-			g_free(servconn->http_data->old_gateway_host);
-
-		servconn->http_data->old_gateway_host =
-			servconn->http_data->gateway_host;
-
-		servconn->http_data->session_id = session_id;
-		servconn->http_data->gateway_host = gw_ip;
-	}
-
-	g_free(headers);
-
-	*ret_buf  = body;
-	*ret_size = len;
-
-	if (servconn->http_data->queue != NULL)
-	{
-		MsnHttpQueueData *queue_data;
-
-		queue_data = (MsnHttpQueueData *)servconn->http_data->queue->data;
-
-		servconn->http_data->queue =
-			g_list_remove(servconn->http_data->queue, queue_data);
-
-		msn_http_servconn_write(queue_data->servconn,
-								queue_data->buffer,
-								queue_data->size,
-								queue_data->server_type);
-
-		g_free(queue_data->buffer);
-		g_free(queue_data);
-	}
-	else
-		servconn->http_data->dirty = TRUE;
-
-	return TRUE;
-}
-
--- a/src/protocols/msn/httpmethod.h	Fri Dec 31 15:34:18 2004 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-/**
- * @file httpmethod.h HTTP connection method
- *
- * gaim
- *
- * Gaim is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#ifndef _MSN_HTTP_METHOD_H_
-#define _MSN_HTTP_METHOD_H_
-
-typedef struct _MsnHttpMethodData MsnHttpMethodData;
-
-#include "servconn.h"
-
-struct _MsnHttpMethodData
-{
-	char *session_id;
-	char *old_gateway_host;
-	char *gateway_host;
-	const char *server_type;
-
-	int timer;
-
-	gboolean virgin;
-	gboolean waiting_response;
-	gboolean dirty;
-
-	GList *queue;
-};
-
-/**
- * Initializes the HTTP data for a session.
- *
- * @param session The session.
- */
-void msn_http_session_init(MsnSession *session);
-
-/**
- * Uninitializes the HTTP data for a session.
- *
- * @param session The session.
- */
-void msn_http_session_uninit(MsnSession *session);
-
-/**
- * Writes data to the server using the HTTP connection method.
- *
- * @param servconn    The server connection.
- * @param buf         The data to write.
- * @param size        The size of the data to write.
- * @param server_type The optional server type.
- *
- * @return The number of bytes written.
- */
-size_t msn_http_servconn_write(MsnServConn *servconn, const char *buf,
-							   size_t size, const char *server_type);
-
-/**
- * Polls the server for data.
- *
- * @param servconn The server connection.
- */
-void msn_http_servconn_poll(MsnServConn *servconn);
-
-/**
- * Processes an incoming message and returns a string the rest of MSN
- * can deal with.
- *
- * @param servconn The server connection.
- * @param buf      The incoming buffer.
- * @param size     The incoming size.
- * @param ret_buf  The returned buffer.
- * @param ret_len  The returned length.
- * @param error    TRUE if there was an HTTP error.
- *
- * @return TRUE if the returned buffer is ready to be processed.
- *         FALSE otherwise.
- */
-gboolean msn_http_servconn_parse_data(MsnServConn *servconn,
-									  const char *buf, size_t size,
-									  char **ret_buf, size_t *ret_size,
-									  gboolean *error);
-
-#endif /* _MSN_HTTP_METHOD_H_ */
--- a/src/protocols/msn/msn.c	Fri Dec 31 15:34:18 2004 +0000
+++ b/src/protocols/msn/msn.c	Fri Dec 31 16:34:22 2004 +0000
@@ -621,13 +621,12 @@
 											 show_send_to_mobile_cb, NULL);
 			m = g_list_append(m, act);
 		}
-
 	}
 
 	if (g_ascii_strcasecmp(buddy->name,
 						   gaim_account_get_username(buddy->account)))
 	{
-		act = gaim_blist_node_action_new(_("Initiate Chat"),
+		act = gaim_blist_node_action_new(_("Initiate _Chat"),
 										 initiate_chat_cb, NULL);
 		m = g_list_append(m, act);
 	}
@@ -671,25 +670,13 @@
 	}
 
 	if (gaim_account_get_bool(account, "http_method", FALSE))
-	{
 		http_method = TRUE;
 
-		gaim_debug_info("msn", "using http method\n");
-
-		host = "gateway.messenger.hotmail.com";
-		port = 80;
-	}
-	else
-	{
-		host = gaim_account_get_string(account, "server", MSN_SERVER);
-		port = gaim_account_get_int(account,    "port",   MSN_PORT);
-	}
+	host = gaim_account_get_string(account, "server", MSN_SERVER);
+	port = gaim_account_get_int(account,    "port",   MSN_PORT);
 
 	session = msn_session_new(account, host, port, http_method);
 
-	if (session->http_method)
-		msn_http_session_init(session);
-
 	gc->proto_data = session;
 	gc->flags |= GAIM_CONNECTION_HTML | GAIM_CONNECTION_FORMATTING_WBFO | GAIM_CONNECTION_NO_BGCOLOR | GAIM_CONNECTION_NO_FONTSIZE | GAIM_CONNECTION_NO_URLDESC;
 
@@ -713,9 +700,6 @@
 
 	g_return_if_fail(session != NULL);
 
-	if (session->http_method)
-		msn_http_session_uninit(session);
-
 	msn_session_destroy(session);
 
 	gc->proto_data = NULL;
@@ -1865,7 +1849,7 @@
 	NULL,					/* warn */
 	NULL,					/* join_chat */
 	NULL,					/* reject chat invite */
-	NULL,				/* get_chat_name */
+	NULL,					/* get_chat_name */
 	msn_chat_invite,		/* chat_invite */
 	msn_chat_leave,			/* chat_leave */
 	NULL,					/* chat_whisper */
--- a/src/protocols/msn/notification.c	Fri Dec 31 15:34:18 2004 +0000
+++ b/src/protocols/msn/notification.c	Fri Dec 31 16:34:22 2004 +0000
@@ -37,9 +37,124 @@
 static MsnTable *cbs_table;
 
 /**************************************************************************
+ * Main
+ **************************************************************************/
+static void
+destroy_cb(MsnServConn *servconn)
+{
+	MsnNotification *notification;
+
+	notification = servconn->cmdproc->data;
+	g_return_if_fail(notification != NULL);
+
+	msn_notification_destroy(notification);
+}
+
+MsnNotification *
+msn_notification_new(MsnSession *session)
+{
+	MsnNotification *notification;
+	MsnServConn *servconn;
+
+	g_return_val_if_fail(session != NULL, NULL);
+
+	notification = g_new0(MsnNotification, 1);
+
+	notification->session = session;
+	notification->servconn = servconn = msn_servconn_new(session, MSN_SERVER_NS);
+	msn_servconn_set_destroy_cb(servconn, destroy_cb);
+
+	notification->cmdproc = servconn->cmdproc;
+	notification->cmdproc->data = notification;
+	notification->cmdproc->cbs_table = cbs_table;
+
+	return notification;
+}
+
+void
+msn_notification_destroy(MsnNotification *notification)
+{
+	if (notification->destroying)
+		return;
+
+	notification->destroying = TRUE;
+
+	msn_servconn_destroy(notification->servconn);
+
+	notification->session->notification = NULL;
+	g_free(notification);
+}
+
+/**************************************************************************
+ * Connect
+ **************************************************************************/
+static void
+connect_cb(MsnServConn *servconn)
+{
+	MsnCmdProc *cmdproc;
+	MsnSession *session;
+	GaimAccount *account;
+	char **a, **c, *vers;
+	int i;
+
+	g_return_if_fail(servconn != NULL);
+
+	cmdproc = servconn->cmdproc;
+	session = servconn->session;
+	account = session->account;
+
+	/* Allocate an array for CVR0, NULL, and all the versions */
+	a = c = g_new0(char *, session->protocol_ver - 8 + 3);
+
+	for (i = session->protocol_ver; i >= 8; i--)
+		*c++ = g_strdup_printf("MSNP%d", i);
+
+	*c++ = g_strdup("CVR0");
+
+	vers = g_strjoinv(" ", a);
+
+	msn_cmdproc_send(cmdproc, "VER", "%s", vers);
+
+	g_strfreev(a);
+	g_free(vers);
+
+	if (cmdproc->error)
+		return;
+
+	if (session->user == NULL)
+		session->user = msn_user_new(session->userlist,
+									 gaim_account_get_username(account), NULL);
+}
+
+gboolean
+msn_notification_connect(MsnNotification *notification, const char *host, int port)
+{
+	MsnServConn *servconn;
+
+	g_return_val_if_fail(notification != NULL, FALSE);
+
+	servconn = notification->servconn;
+
+	msn_servconn_set_connect_cb(servconn, connect_cb);
+	notification->in_use = msn_servconn_connect(servconn, host, port);
+
+	return notification->in_use;
+}
+
+void
+msn_notification_disconnect(MsnNotification *notification)
+{
+	g_return_if_fail(notification != NULL);
+	g_return_if_fail(notification->in_use);
+
+	msn_servconn_disconnect(notification->servconn);
+
+	notification->in_use = FALSE;
+}
+
+/**************************************************************************
  * Util
  **************************************************************************/
-
 static void
 group_error_helper(MsnSession *session, const char *msg, int group_id, int error)
 {
@@ -83,7 +198,6 @@
 /**************************************************************************
  * Login
  **************************************************************************/
-
 void
 msn_got_login_params(MsnSession *session, const char *login_params)
 {
@@ -266,6 +380,16 @@
 		msn_cmdproc_show_error(cmdproc, MSN_ERROR_SERVDOWN);
 }
 
+void
+msn_notification_close(MsnNotification *notification)
+{
+	g_return_if_fail(notification != NULL);
+
+	msn_cmdproc_send_quick(notification->cmdproc, "OUT", NULL, NULL);
+
+	msn_notification_disconnect(notification);
+}
+
 /**************************************************************************
  * Messages
  **************************************************************************/
@@ -1177,44 +1301,6 @@
 	g_hash_table_destroy(table);
 }
 
-static void
-connect_cb(MsnServConn *servconn)
-{
-	MsnCmdProc *cmdproc;
-	MsnSession *session;
-	GaimAccount *account;
-	char **a, **c, *vers;
-	int i;
-
-	g_return_if_fail(servconn != NULL);
-
-	cmdproc = servconn->cmdproc;
-	session = servconn->session;
-	account = session->account;
-
-	/* Allocate an array for CVR0, NULL, and all the versions */
-	a = c = g_new0(char *, session->protocol_ver - 8 + 3);
-
-	for (i = session->protocol_ver; i >= 8; i--)
-		*c++ = g_strdup_printf("MSNP%d", i);
-
-	*c++ = g_strdup("CVR0");
-
-	vers = g_strjoinv(" ", a);
-
-	msn_cmdproc_send(cmdproc, "VER", "%s", vers);
-
-	g_strfreev(a);
-	g_free(vers);
-
-	if (cmdproc->error)
-		return;
-
-	if (session->user == NULL)
-		session->user = msn_user_new(session->userlist,
-									 gaim_account_get_username(account), NULL);
-}
-
 void
 msn_notification_add_buddy(MsnNotification *notification, const char *list,
 						   const char *who, const char *store_name,
@@ -1254,6 +1340,9 @@
 	}
 }
 
+/**************************************************************************
+ * Init
+ **************************************************************************/
 void
 msn_notification_init(void)
 {
@@ -1336,57 +1425,3 @@
 {
 	msn_table_destroy(cbs_table);
 }
-
-MsnNotification *
-msn_notification_new(MsnSession *session)
-{
-	MsnNotification *notification;
-	MsnServConn *servconn;
-
-	g_return_val_if_fail(session != NULL, NULL);
-
-	notification = g_new0(MsnNotification, 1);
-
-	notification->session = session;
-	notification->servconn = servconn = msn_servconn_new(session, MSN_SERVER_NS);
-	notification->cmdproc = servconn->cmdproc;
-	msn_servconn_set_connect_cb(servconn, connect_cb);
-
-	if (session->http_method)
-		servconn->http_data->server_type = "NS";
-
-	servconn->cmdproc->cbs_table = cbs_table;
-
-	return notification;
-}
-
-void
-msn_notification_destroy(MsnNotification *notification)
-{
-	msn_servconn_destroy(notification->servconn);
-
-	g_free(notification);
-}
-
-gboolean
-msn_notification_connect(MsnNotification *notification, const char *host, int port)
-{
-	MsnServConn *servconn;
-
-	g_return_val_if_fail(notification != NULL, FALSE);
-
-	servconn = notification->servconn;
-
-	return (notification->in_use = msn_servconn_connect(servconn, host, port));
-}
-
-void
-msn_notification_disconnect(MsnNotification *notification)
-{
-	g_return_if_fail(notification != NULL);
-
-	notification->in_use = FALSE;
-
-	if (notification->servconn->connected)
-		msn_servconn_disconnect(notification->servconn);
-}
--- a/src/protocols/msn/notification.h	Fri Dec 31 15:34:18 2004 +0000
+++ b/src/protocols/msn/notification.h	Fri Dec 31 16:34:22 2004 +0000
@@ -36,6 +36,9 @@
 	MsnCmdProc *cmdproc;
 	MsnServConn *servconn;
 
+	gboolean destroying;	/**< A flag that states if the notification is on
+							  the process of being destroyed. */
+
 	gboolean in_use;
 };
 
@@ -56,6 +59,15 @@
 							  const char *host, int port);
 void msn_notification_disconnect(MsnNotification *notification);
 
+/**
+ * Closes a notification.
+ *
+ * It's first closed, and then disconnected.
+ * 
+ * @param notification The notification object to close.
+ */
+void msn_notification_close(MsnNotification *notification);
+
 void msn_got_login_params(MsnSession *session, const char *login_params);
 
 #endif /* _MSN_NOTIFICATION_H_ */
--- a/src/protocols/msn/servconn.c	Fri Dec 31 15:34:18 2004 +0000
+++ b/src/protocols/msn/servconn.c	Fri Dec 31 16:34:22 2004 +0000
@@ -43,10 +43,7 @@
 	servconn->cmdproc->servconn = servconn;
 
 	if (session->http_method)
-	{
-		servconn->http_data = g_new0(MsnHttpMethodData, 1);
-		servconn->http_data->virgin = TRUE;
-	}
+		servconn->httpconn = msn_httpconn_new(servconn);
 
 	servconn->num = session->servconns_count++;
 
@@ -64,11 +61,22 @@
 		return;
 	}
 
+	if (servconn->destroying)
+		return;
+
+	servconn->destroying = TRUE;
+
 	if (servconn->connected)
 		msn_servconn_disconnect(servconn);
 
-	if (servconn->http_data != NULL)
-		g_free(servconn->http_data);
+	if (servconn->destroy_cb)
+		servconn->destroy_cb(servconn);
+
+	if (servconn->httpconn != NULL)
+		msn_httpconn_destroy(servconn->httpconn);
+
+	if (servconn->host != NULL)
+		g_free(servconn->host);
 
 	msn_cmdproc_destroy(servconn->cmdproc);
 	g_free(servconn);
@@ -113,7 +121,7 @@
 	else
 	{
 		MsnSwitchBoard *swboard;
-		swboard = servconn->data;
+		swboard = servconn->cmdproc->data;
 		swboard->error = MSN_SB_ERROR_CONNECTION;
 	}
 
@@ -167,12 +175,26 @@
 	if (servconn->connected)
 		msn_servconn_disconnect(servconn);
 
+	if (servconn->host != NULL)
+		g_free(servconn->host);
+
+	servconn->host = g_strdup(host);
+
 	if (session->http_method)
 	{
-		if (servconn->http_data->gateway_host != NULL)
-			g_free(servconn->http_data->gateway_host);
+		/* HTTP Connection. */
+
+		if (!servconn->httpconn->connected)
+			msn_httpconn_connect(servconn->httpconn, host, port);
 
-		servconn->http_data->gateway_host = g_strdup(host);
+		servconn->connected = TRUE;
+		servconn->cmdproc->ready = TRUE;
+		servconn->httpconn->virgin = TRUE;
+
+		/* Someone wants to know we connected. */
+		servconn->connect_cb(servconn);
+
+		return TRUE;
 	}
 
 	r = gaim_proxy_connect(session->account, host, port, connect_cb,
@@ -200,6 +222,15 @@
 		return;
 	}
 
+	if (servconn->session->http_method)
+	{
+		/* Fake disconnection */
+		if (servconn->disconnect_cb != NULL)
+			servconn->disconnect_cb(servconn);
+
+		return;
+	}
+
 	if (servconn->inpa > 0)
 	{
 		gaim_input_remove(servconn->inpa);
@@ -208,21 +239,6 @@
 
 	close(servconn->fd);
 
-	if (servconn->http_data != NULL)
-	{
-		if (servconn->http_data->session_id != NULL)
-			g_free(servconn->http_data->session_id);
-
-		if (servconn->http_data->old_gateway_host != NULL)
-			g_free(servconn->http_data->old_gateway_host);
-
-		if (servconn->http_data->gateway_host != NULL)
-			g_free(servconn->http_data->gateway_host);
-
-		if (servconn->http_data->timer)
-			gaim_timeout_remove(servconn->http_data->timer);
-	}
-
 	servconn->rx_buf = NULL;
 	servconn->rx_len = 0;
 	servconn->payload_len = 0;
@@ -235,20 +251,31 @@
 }
 
 void
-msn_servconn_set_connect_cb(MsnServConn *servconn, void (*connect_cb)(MsnServConn *))
+msn_servconn_set_connect_cb(MsnServConn *servconn,
+							void (*connect_cb)(MsnServConn *))
 {
 	g_return_if_fail(servconn != NULL);
 	servconn->connect_cb = connect_cb;
 }
 
 void
-msn_servconn_set_disconnect_cb(MsnServConn *servconn, void (*disconnect_cb)(MsnServConn *))
+msn_servconn_set_disconnect_cb(MsnServConn *servconn,
+							   void (*disconnect_cb)(MsnServConn *))
 {
 	g_return_if_fail(servconn != NULL);
 
 	servconn->disconnect_cb = disconnect_cb;
 }
 
+void
+msn_servconn_set_destroy_cb(MsnServConn *servconn,
+							   void (*destroy_cb)(MsnServConn *))
+{
+	g_return_if_fail(servconn != NULL);
+
+	servconn->destroy_cb = destroy_cb;
+}
+
 static void
 failed_io(MsnServConn *servconn)
 {
@@ -266,7 +293,7 @@
 
 	g_return_val_if_fail(servconn != NULL, 0);
 
-	if (servconn->http_data == NULL)
+	if (!servconn->session->http_method)
 	{
 		switch (servconn->type)
 		{
@@ -285,8 +312,7 @@
 	}
 	else
 	{
-		ret = msn_http_servconn_write(servconn, buf, len,
-									  servconn->http_data->server_type);
+		ret = msn_httpconn_write(servconn->httpconn, buf, len);
 	}
 
 	if (ret == -1)
@@ -327,69 +353,6 @@
 	memcpy(servconn->rx_buf + servconn->rx_len, buf, len + 1);
 	servconn->rx_len += len;
 
-	if (session->http_method)
-	{
-		char *result_msg = NULL;
-		size_t result_len = 0;
-		gboolean error;
-		char *tmp;
-
-		tmp = g_strndup(servconn->rx_buf, servconn->rx_len);
-
-		if (!msn_http_servconn_parse_data(servconn, tmp, servconn->rx_len,
-										  &result_msg, &result_len,
-										  &error))
-		{
-			g_free(tmp);
-			return;
-		}
-
-		g_free(tmp);
-
-		if (error)
-		{
-			gaim_connection_error(gaim_account_get_connection(session->account),
-								  _("Received HTTP error. Please report this."));
-
-			return;
-		}
-
-		if (servconn->http_data->session_id != NULL &&
-			!strcmp(servconn->http_data->session_id, "close"))
-		{
-			msn_servconn_destroy(servconn);
-
-			return;
-		}
-
-#if 0
-		if (strcmp(servconn->http_data->gateway_ip,
-				   msn_servconn_get_server(servconn)) != 0)
-		{
-			int i;
-
-			/* Evil hackery. I promise to remove it, even though I can't. */
-
-			servconn->connected = FALSE;
-
-			if (servconn->inpa)
-				gaim_input_remove(servconn->inpa);
-
-			close(servconn->fd);
-
-			i = gaim_proxy_connect(session->account, servconn->host,
-								   servconn->port, read_cb, servconn);
-
-			if (i == 0)
-				servconn->connected = TRUE;
-		}
-#endif
-
-		g_free(servconn->rx_buf);
-		servconn->rx_buf = result_msg;
-		servconn->rx_len = result_len;
-	}
-
 	end = old_rx_buf = servconn->rx_buf;
 
 	servconn->processing = TRUE;
--- a/src/protocols/msn/servconn.h	Fri Dec 31 15:34:18 2004 +0000
+++ b/src/protocols/msn/servconn.h	Fri Dec 31 16:34:22 2004 +0000
@@ -30,13 +30,11 @@
 #include "cmdproc.h"
 
 #include "proxy.h"
-#include "httpmethod.h"
+#include "httpconn.h"
 
 /*
-#include "msg.h"
-#include "history.h"
-*/
-
+ * Connection types
+ */
 typedef enum
 {
 	MSN_SERVER_NS,
@@ -47,44 +45,107 @@
 
 } MsnServConnType;
 
+/*
+ * A Connection
+ */
 struct _MsnServConn
 {
-	MsnServConnType type;
-	MsnSession *session;
-	MsnCmdProc *cmdproc;
+	MsnServConnType type; /**< The type of this connection. */
+	MsnSession *session;  /**< The MSN session of this connection. */
+	MsnCmdProc *cmdproc;  /**< The command processor of this connection. */
 
-	gboolean connected;
-	gboolean processing;
-	gboolean wasted;
+	gboolean connected;   /**< A flag that states if it's connected. */
+	gboolean processing;  /**< A flag that states if something is working
+							with this connection. */
+	gboolean wasted;      /**< A flag that states if it should be destroyed. */
+	gboolean destroying;  /**< A flag that states if the connection is on
+							the process of being destroyed. */
 
-	int num;
-
-	MsnHttpMethodData *http_data;
+	char *host; /**< The host this connection is connected or should be
+				  connected to. */
+	int num; /**< A number id of this connection. */
 
-	int fd;
-	int inpa;
+	MsnHttpConn *httpconn; /**< The HTTP connection this connection should use. */
 
-	char *rx_buf;
-	int rx_len;
+	int fd; /**< The connection's file descriptor. */
+	int inpa; /**< The connection's input handler. */
+
+	char *rx_buf; /**< The receive buffer. */
+	int rx_len; /**< The receive buffer lenght. */
 
-	size_t payload_len;
+	size_t payload_len; /**< The length of the payload.
+						  It's only set when we've received a command that
+						  has a payload. */
 
-	void (*connect_cb)(MsnServConn *);
-	void (*disconnect_cb)(MsnServConn *);
-	void (*data_free_cb)(void *data);
-	void *data;
+	void (*connect_cb)(MsnServConn *); /**< The callback to call when connecting. */
+	void (*disconnect_cb)(MsnServConn *); /**< The callback to call when disconnecting. */
+	void (*destroy_cb)(MsnServConn *); /**< The callback to call when destroying. */
 };
 
+/**
+ * Creates a new connection object.
+ *
+ * @param session The session.
+ * @param type The type of the connection.
+ */
 MsnServConn *msn_servconn_new(MsnSession *session, MsnServConnType type);
+
+/**
+ * Destroys a connection object.
+ *
+ * @param servconn The connection.
+ */
 void msn_servconn_destroy(MsnServConn *servconn);
 
+/**
+ * Connects to a host.
+ *
+ * @param servconn The connection.
+ * @param host The host.
+ * @param port The port.
+ */
 gboolean msn_servconn_connect(MsnServConn *servconn, const char *host, int port);
+
+/**
+ * Disconnects.
+ *
+ * @param servconn The connection.
+ */
 void msn_servconn_disconnect(MsnServConn *servconn);
 
+/**
+ * Sets the connect callback.
+ *
+ * @param servconn The servconn.
+ * @param connect_cb The connect callback.
+ */
 void msn_servconn_set_connect_cb(MsnServConn *servconn,
 								 void (*connect_cb)(MsnServConn *));
+/**
+ * Sets the disconnect callback.
+ *
+ * @param servconn The servconn.
+ * @param disconnect_cb The disconnect callback.
+ */
 void msn_servconn_set_disconnect_cb(MsnServConn *servconn,
 									void (*disconnect_cb)(MsnServConn *));
-size_t msn_servconn_write(MsnServConn *servconn, const char *buf, size_t size);
+/**
+ * Sets the destroy callback.
+ *
+ * @param servconn The servconn that's being destroyed.
+ * @param destroy_cb The destroy callback.
+ */
+void msn_servconn_set_destroy_cb(MsnServConn *servconn,
+								 void (*destroy_cb)(MsnServConn *));
+
+/**
+ * Writes a chunck of data to the servconn.
+ *
+ * @param servconn The servconn.
+ * @param buf The data to write.
+ * @param size The size of the data.
+ */
+size_t msn_servconn_write(MsnServConn *servconn, const char *buf,
+						  size_t size);
 
 #endif /* _MSN_SERVCONN_H_ */
--- a/src/protocols/msn/session.c	Fri Dec 31 15:34:18 2004 +0000
+++ b/src/protocols/msn/session.c	Fri Dec 31 16:34:22 2004 +0000
@@ -113,6 +113,12 @@
 
 	session->connected = TRUE;
 
+	if (session->notification == NULL)
+	{
+		gaim_debug_error("msn", "This shouldn't happen\n");
+		g_return_val_if_reached(FALSE);
+	}
+
 	if (msn_notification_connect(session->notification,
 								 session->dispatch_host,
 								 session->dispatch_port))
@@ -130,10 +136,12 @@
 	g_return_if_fail(session->connected);
 
 	while (session->switches != NULL)
-		msn_switchboard_destroy(session->switches->data);
+		msn_switchboard_close(session->switches->data);
 
 	if (session->notification != NULL)
-		msn_notification_disconnect(session->notification);
+		msn_notification_close(session->notification);
+
+	session->connected = FALSE;
 }
 
 /* TODO: This must go away when conversation is redesigned */
--- a/src/protocols/msn/session.h	Fri Dec 31 15:34:18 2004 +0000
+++ b/src/protocols/msn/session.h	Fri Dec 31 16:34:22 2004 +0000
@@ -35,6 +35,7 @@
 
 #include "cmdproc.h"
 #include "nexus.h"
+#include "httpconn.h"
 
 #include "userlist.h"
 #include "sync.h"
--- a/src/protocols/msn/switchboard.c	Fri Dec 31 15:34:18 2004 +0000
+++ b/src/protocols/msn/switchboard.c	Fri Dec 31 16:34:22 2004 +0000
@@ -42,7 +42,6 @@
 {
 	MsnSwitchBoard *swboard;
 	MsnServConn *servconn;
-	MsnCmdProc *cmdproc;
 
 	g_return_val_if_fail(session != NULL, NULL);
 
@@ -50,17 +49,16 @@
 
 	swboard->session = session;
 	swboard->servconn = servconn = msn_servconn_new(session, MSN_SERVER_SB);
-	cmdproc = servconn->cmdproc;
+	swboard->cmdproc = servconn->cmdproc;
 
 	swboard->im_queue = g_queue_new();
 	swboard->empty = TRUE;
 
-	servconn->data = swboard;
+	swboard->cmdproc->data = swboard;
+	swboard->cmdproc->cbs_table = cbs_table;
 
 	session->switches = g_list_append(session->switches, swboard);
 
-	cmdproc->cbs_table = cbs_table;
-
 	return swboard;
 }
 
@@ -88,7 +86,7 @@
 		if (swboard->error != MSN_SB_ERROR_NONE)
 		{
 			/* The messages could not be sent due to a switchboard error */
-			msg_error_helper(swboard->servconn->cmdproc, msg,
+			msg_error_helper(swboard->cmdproc, msg,
 							 MSN_MSG_ERROR_SB);
 		}
 		msn_message_unref(msg);
@@ -199,8 +197,8 @@
 
 	g_return_if_fail(swboard != NULL);
 
-	cmdproc = swboard->servconn->cmdproc;
-	account = swboard->servconn->session->account;
+	cmdproc = swboard->cmdproc;
+	account = cmdproc->session->account;
 
 	swboard->users = g_list_prepend(swboard->users, g_strdup(user));
 	swboard->current_users++;
@@ -313,7 +311,7 @@
 	if (swboard->total_users == 0)
 	{
 		swboard->error = reason;
-		msn_switchboard_destroy(swboard);
+		msn_switchboard_close(swboard);
 	}
 }
 
@@ -346,7 +344,7 @@
 	if ((error != MSN_MSG_ERROR_SB) && (msg->nak_cb != NULL))
 		msg->nak_cb(msg, msg->ack_data);
 
-	swboard = cmdproc->servconn->data;
+	swboard = cmdproc->data;
 
 	if (msg->type == MSN_MSG_TEXT)
 	{
@@ -434,7 +432,7 @@
 {
 	MsnSwitchBoard *swboard;
 
-	swboard = cmdproc->servconn->data;
+	swboard = cmdproc->data;
 	swboard->ready = TRUE;
 }
 
@@ -444,7 +442,7 @@
 	MsnSwitchBoard *swboard;
 	const char *user;
 
-	swboard = cmdproc->servconn->data;
+	swboard = cmdproc->data;
 	user = cmd->params[0];
 
 	if (swboard->conv == NULL)
@@ -509,7 +507,7 @@
 
 	account = cmdproc->session->account;
 	gc = account->gc;
-	swboard = cmdproc->servconn->data;
+	swboard = cmdproc->data;
 
 	swboard->total_users = atoi(cmd->params[2]);
 
@@ -530,13 +528,14 @@
 	session = cmdproc->session;
 	account = session->account;
 	gc = account->gc;
-	swboard = cmdproc->servconn->data;
+	swboard = cmdproc->data;
 
 	msn_switchboard_add_user(swboard, passport);
 
 	msn_switchboard_process_queue(swboard);
 
-	send_clientcaps(swboard);
+	if (!session->http_method)
+		send_clientcaps(swboard);
 
 	if (swboard->closed)
 		msn_switchboard_close(swboard);
@@ -590,7 +589,7 @@
 	if (msg->ack_cb != NULL)
 		msg->ack_cb(msg, msg->ack_data);
 
-	swboard = cmdproc->servconn->data;
+	swboard = cmdproc->data;
 	swboard->ack_list = g_list_remove(swboard->ack_list, msg);
 	msn_message_unref(msg);
 }
@@ -602,7 +601,7 @@
 	MsnSwitchBoard *swboard;
 
 	gc = cmdproc->session->account->gc;
-	swboard = cmdproc->servconn->data;
+	swboard = cmdproc->data;
 
 	if (swboard->current_users > 1)
 		serv_got_chat_left(gc, swboard->chat_id);
@@ -615,7 +614,7 @@
 {
 	MsnSwitchBoard *swboard;
 
-	swboard = cmdproc->servconn->data;
+	swboard = cmdproc->data;
 
 #if 0
 	GList *l;
@@ -650,7 +649,7 @@
 	const char *value;
 
 	gc = cmdproc->session->account->gc;
-	swboard = cmdproc->servconn->data;
+	swboard = cmdproc->data;
 
 	body = msn_message_get_bin_data(msg, &body_len);
 	body_str = g_strndup(body, body_len);
@@ -709,7 +708,7 @@
 	char *passport;
 
 	gc = cmdproc->session->account->gc;
-	swboard = cmdproc->servconn->data;
+	swboard = cmdproc->data;
 	passport = msg->remote_user;
 
 	if (swboard->current_users == 1 &&
@@ -798,7 +797,7 @@
 	g_return_if_fail(swboard != NULL);
 	g_return_if_fail(msg     != NULL);
 
-	cmdproc = swboard->servconn->cmdproc;
+	cmdproc = swboard->cmdproc;
 
 	payload = msn_message_gen_payload(msg, &payload_len);
 
@@ -885,8 +884,8 @@
 
 	cmdproc->ready = TRUE;
 
-	account = servconn->session->account;
-	swboard = servconn->data;
+	account = cmdproc->session->account;
+	swboard = cmdproc->data;
 	g_return_if_fail(swboard != NULL);
 
 	if (msn_switchboard_is_invited(swboard))
@@ -910,7 +909,7 @@
 {
 	MsnSwitchBoard *swboard;
 
-	swboard = servconn->data;
+	swboard = servconn->cmdproc->data;
 	g_return_if_fail(swboard != NULL);
 
 	msn_switchboard_destroy(swboard);
@@ -945,7 +944,7 @@
 	MsnSwitchBoard *swboard;
 	const char *user;
 
-	swboard = cmdproc->servconn->data;
+	swboard = cmdproc->data;
 
 	user = cmd->params[0];
 
@@ -985,7 +984,7 @@
 
 	g_return_if_fail(swboard != NULL);
 
-	cmdproc = swboard->servconn->cmdproc;
+	cmdproc = swboard->cmdproc;
 
 	trans = msn_transaction_new(cmdproc, "CAL", "%s", user);
 	/* this doesn't do anything, but users seem to think that
@@ -1020,41 +1019,6 @@
 
 	msn_parse_socket(cmd->params[2], &host, &port);
 
-	if (swboard->session->http_method)
-	{
-		GaimAccount *account;
-		MsnSession *session;
-		MsnServConn *servconn;
-
-		port = 80;
-
-		session = swboard->session;
-		servconn = swboard->servconn;
-		account = session->account;
-
-		swboard->empty = FALSE;
-
-		servconn->http_data->gateway_host = g_strdup(host);
-
-#if 0
-		servconn->connected = TRUE;
-		servconn->cmdproc->ready = TRUE;
-#endif
-
-		if (msn_switchboard_is_invited(swboard))
-		{
-			msn_cmdproc_send(servconn->cmdproc, "ANS", "%s %s %s",
-							 gaim_account_get_username(account),
-							 swboard->auth_key, swboard->session_id);
-		}
-		else
-		{
-			msn_cmdproc_send(servconn->cmdproc, "USR", "%s %s",
-							 gaim_account_get_username(account),
-							 swboard->auth_key);
-		}
-	}
-
 	msn_switchboard_connect(swboard, host, port);
 
 	g_free(host);
@@ -1102,7 +1066,7 @@
 	{
 		MsnCmdProc *cmdproc;
 
-		cmdproc = swboard->servconn->cmdproc;
+		cmdproc = swboard->cmdproc;
 
 		msn_cmdproc_send_quick(cmdproc, "OUT", NULL, NULL);
 
--- a/src/protocols/msn/switchboard.h	Fri Dec 31 15:34:18 2004 +0000
+++ b/src/protocols/msn/switchboard.h	Fri Dec 31 16:34:22 2004 +0000
@@ -57,6 +57,7 @@
 {
 	MsnSession *session;
 	MsnServConn *servconn;
+	MsnCmdProc *cmdproc;
 	char *im_user;
 
 	char *auth_key;