Revision a8c2b9a0511a8917d2466c48e33f2c7db96065c8

nosnilmot at pidgin.im nosnilmot at pidgin.im
Wed Apr 11 01:22:44 EDT 2007


o   -----------------------------------------------------------------
|   Revision: a8c2b9a0511a8917d2466c48e33f2c7db96065c8
|   Ancestor: d35d1a34b828fb7a08b7eb8bcb4ab333d7e640cc
|   Author: nosnilmot
|   Date: 2005-01-07T02:48:07
|   Branch: im.pidgin.gaim.oldstatus
|   
|   Modified files:
|           ChangeLog src/protocols/msn/cmdproc.c
|           src/protocols/msn/cmdproc.h src/protocols/msn/error.h
|           src/protocols/msn/httpconn.c src/protocols/msn/httpconn.h
|           src/protocols/msn/msg.c src/protocols/msn/msn.c
|           src/protocols/msn/msn.h src/protocols/msn/nexus.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/slp.h src/protocols/msn/slpcall.c
|           src/protocols/msn/slplink.c src/protocols/msn/state.c
|           src/protocols/msn/switchboard.c
|           src/protocols/msn/switchboard.h
|           src/protocols/msn/transaction.c
|   
|   ChangeLog: 
|   
|   [gaim-migrate @ 11768]
|   Patch 1093958 from Felipe Contreras. It fixes stuff.
|   
|   I also made some tweaks to make valgrind a bit happier.
|   ============================================================
|   --- ChangeLog	b712c8d8958c929a2e698eff8e307b36b5f6971a
|   +++ ChangeLog	44072951e090a6f76b484a890554456061101115
|   @@ -7,6 +7,7 @@ version 1.1.2:
|    	* Fix a crash inviting MSN user to a chat when they're already there
|    	* AIM SecurID login support
|    	* Fix configuration of Jabber chat rooms on some servers
|   +	* More MSN bug fixes (Felipe Contreras)
|    
|    version 1.1.1 (12/28/2004):
|    	* Allow SILC authentication via public key if your key is password
|   ============================================================
|   --- src/protocols/msn/cmdproc.c	7150f585520ede58759991963ef12c4ea6c7f48c
|   +++ src/protocols/msn/cmdproc.c	25e666a31f262345923a562e5eeb61a580824e3b
|   @@ -43,15 +43,13 @@ msn_cmdproc_destroy(MsnCmdProc *cmdproc)
|    {
|    	MsnTransaction *trans;
|    
|   -	if (cmdproc->last_trans != NULL)
|   -		g_free(cmdproc->last_trans);
|   -
|    	while ((trans = g_queue_pop_head(cmdproc->txqueue)) != NULL)
|    		msn_transaction_destroy(trans);
|    
|    	g_queue_free(cmdproc->txqueue);
|    
|    	msn_history_destroy(cmdproc->history);
|   +	g_free(cmdproc);
|    }
|    
|    void
|   @@ -59,11 +57,8 @@ msn_cmdproc_process_queue(MsnCmdProc *cm
|    {
|    	MsnTransaction *trans;
|    
|   -	while ((trans = g_queue_pop_head(cmdproc->txqueue)) != NULL &&
|   -		   cmdproc->error == 0)
|   -	{
|   +	while ((trans = g_queue_pop_head(cmdproc->txqueue)) != NULL)
|    		msn_cmdproc_send_trans(cmdproc, trans);
|   -	}
|    }
|    
|    void
|   @@ -109,19 +104,17 @@ msn_cmdproc_send_trans(MsnCmdProc *cmdpr
|    	size_t len;
|    
|    	g_return_if_fail(cmdproc != NULL);
|   -	g_return_if_fail(cmdproc->ready);
|    	g_return_if_fail(trans != NULL);
|    
|    	servconn = cmdproc->servconn;
|   +
|   +	if (!servconn->connected)
|   +		return;
|   +
|    	msn_history_add(cmdproc->history, trans);
|    
|    	data = msn_transaction_to_string(trans);
|    
|   -	if (cmdproc->last_trans != NULL)
|   -		g_free(cmdproc->last_trans);
|   -
|   -	cmdproc->last_trans = g_strdup(data);
|   -
|    	len = strlen(data);
|    
|    	show_debug_cmd(cmdproc, FALSE, data);
|   @@ -153,11 +146,13 @@ msn_cmdproc_send_quick(MsnCmdProc *cmdpr
|    	size_t len;
|    
|    	g_return_if_fail(cmdproc != NULL);
|   -	g_return_if_fail(cmdproc->ready);
|    	g_return_if_fail(command != NULL);
|    
|    	servconn = cmdproc->servconn;
|    
|   +	if (!servconn->connected)
|   +		return;
|   +
|    	if (format != NULL)
|    	{
|    		va_start(arg, format);
|   @@ -189,9 +184,11 @@ msn_cmdproc_send(MsnCmdProc *cmdproc, co
|    	va_list arg;
|    
|    	g_return_if_fail(cmdproc != NULL);
|   -	g_return_if_fail(cmdproc->ready);
|    	g_return_if_fail(command != NULL);
|    
|   +	if (!cmdproc->servconn->connected)
|   +		return;
|   +
|    	trans = g_new0(MsnTransaction, 1);
|    
|    	trans->command = g_strdup(command);
|   @@ -317,19 +314,8 @@ msn_cmdproc_process_cmd(MsnCmdProc *cmdp
|    						   cmd->command);
|    	}
|    
|   -#if 1
|   -	/* TODO this is really ugly */
|   -	/* Since commands have not stored payload and we need it for pendent
|   -	 * commands at the time we process again the same command we will try
|   -	 * to read again the payload of payload_len size but we will actually
|   -	 * read sometime else, and reading from server synchronization goes to
|   -	 * hell. */
|   -	/* Now we store the payload in the command when we queue them :D */
|   -
|    	if (trans != NULL && trans->pendent_cmd != NULL)
|   -		if (cmdproc->ready)
|   -			msn_transaction_unqueue_cmd(trans, cmdproc);
|   -#endif
|   +		msn_transaction_unqueue_cmd(trans, cmdproc);
|    }
|    
|    void
|   @@ -344,32 +330,3 @@ msn_cmdproc_process_cmd_text(MsnCmdProc 
|    
|    	msn_cmdproc_process_cmd(cmdproc, cmdproc->last_cmd);
|    }
|   -
|   -void
|   -msn_cmdproc_show_error(MsnCmdProc *cmdproc, int error)
|   -{
|   -	GaimConnection *gc =
|   -		gaim_account_get_connection(cmdproc->session->account);
|   -
|   -	char *tmp;
|   -
|   -	tmp = NULL;
|   -
|   -	switch (error)
|   -	{
|   -		case MSN_ERROR_MISC:
|   -			tmp = _("Miscellaneous error"); break;
|   -		case MSN_ERROR_SIGNOTHER:
|   -			gc->wants_to_die = TRUE;
|   -			tmp = _("You have signed on from another location."); break;
|   -		case MSN_ERROR_SERVDOWN:
|   -			tmp = _("The MSN servers are going down temporarily."); break;
|   -		default:
|   -			break;
|   -	}
|   -
|   -	if (tmp != NULL)
|   -	{
|   -		gaim_connection_error(gc, tmp);
|   -	}
|   -}
|   ============================================================
|   --- src/protocols/msn/cmdproc.h	a5f9b743ba99626816fe01d153ec8d92f8b5ff99
|   +++ src/protocols/msn/cmdproc.h	18c5f6b6a08237483746bcab9612d911c9a73dde
|   @@ -33,11 +33,6 @@ typedef struct _MsnCmdProc MsnCmdProc;
|    #include "table.h"
|    #include "history.h"
|    
|   -#if 0
|   -typedef void (*MsnPayloadCb)(MsnCmdProc *cmdproc, char *payload,
|   -							 size_t len);
|   -#endif
|   -
|    struct _MsnCmdProc
|    {
|    	MsnSession *session;
|   @@ -45,14 +40,9 @@ struct _MsnCmdProc
|    
|    	GQueue *txqueue;
|    
|   -	gboolean ready;
|   -	MsnErrorType error;
|   -
|    	MsnCommand *last_cmd;
|   -	char *last_trans;
|    
|    	MsnTable *cbs_table;
|   -	/* MsnPayloadCb payload_cb; */
|    
|    	MsnHistory *history;
|    
|   @@ -81,6 +71,4 @@ void msn_cmdproc_disconnect(MsnCmdProc *
|    
|    void msn_cmdproc_disconnect(MsnCmdProc *cmdproc);
|    
|   -void msn_cmdproc_show_error(MsnCmdProc *cmdproc, int error);
|   -
|    #endif /* _MSN_CMDPROC_H_ */
|   ============================================================
|   --- src/protocols/msn/error.h	ca6833b624efb539ff31a1e450ae8f72fdb88eef
|   +++ src/protocols/msn/error.h	51ba95e1afea1b124f47c0661a7dce52880ed950
|   @@ -24,18 +24,6 @@
|    #ifndef _MSN_ERROR_H_
|    #define _MSN_ERROR_H_
|    
|   -typedef enum
|   -{
|   -	MSN_ERROR_NONE,
|   -	MSN_ERROR_MISC,
|   -	MSN_ERROR_CONNECT,
|   -	MSN_ERROR_WRITE,
|   -	MSN_ERROR_READ,
|   -	MSN_ERROR_SIGNOTHER,
|   -	MSN_ERROR_SERVDOWN
|   -
|   -} MsnErrorType;
|   -
|    #include "session.h"
|    
|    /**
|   ============================================================
|   --- src/protocols/msn/httpconn.c	312604acf4f06a425d1674d9fd16c6ec88b37721
|   +++ src/protocols/msn/httpconn.c	25f4a0215f77010533e964644ea4e91cf7d92b67
|   @@ -28,7 +28,7 @@ typedef struct
|    typedef struct
|    {
|    	MsnHttpConn *httpconn;
|   -	char *buffer;
|   +	char *data;
|    	size_t size;
|    
|    } MsnHttpQueueData;
|   @@ -48,6 +48,8 @@ msn_httpconn_new(MsnServConn *servconn)
|    
|    	httpconn = g_new0(MsnHttpConn, 1);
|    
|   +	gaim_debug_info("msn", "new httpconn (%p)\n", httpconn);
|   +
|    	/* TODO: Remove this */
|    	httpconn->session = servconn->session;
|    
|   @@ -61,96 +63,64 @@ msn_httpconn_destroy(MsnHttpConn *httpco
|    {
|    	g_return_if_fail(httpconn != NULL);
|    
|   +	gaim_debug_info("msn", "destroy httpconn (%p)\n", httpconn);
|   +
|    	if (httpconn->connected)
|    		msn_httpconn_disconnect(httpconn);
|    
|   -	if (httpconn->host != NULL)
|   -		g_free(httpconn->host);
|   -
|    	g_free(httpconn);
|    }
|    
|   -static void
|   -show_error(MsnHttpConn *httpconn)
|   +static ssize_t
|   +write_raw(MsnHttpConn *httpconn, const char *header,
|   +		  const char *body, size_t body_len)
|    {
|   -	GaimConnection *gc;
|   -	char *tmp;
|   -	char *cmd;
|   +	char *buf;
|   +	size_t buf_len;
|    
|   -	const char *names[] = { "Notification", "Switchboard" };
|   -	const char *name;
|   +	ssize_t s;
|   +	ssize_t res; /* result of the write operation */
|    
|   -	gc = gaim_account_get_connection(httpconn->servconn->session->account);
|   -	name = names[httpconn->servconn->type];
|   +#ifdef MSN_DEBUG_HTTP
|   +	gaim_debug_misc("msn", "Writing HTTP (header): {%s}\n", header);
|   +#endif
|    
|   -	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;
|   -	}
|   +	buf = g_strdup_printf("%s\r\n", header);
|   +	buf_len = strlen(buf);
|    
|   -	if (httpconn->servconn->type == MSN_SERVER_NS)
|   +	if (body != NULL)
|    	{
|   -		gaim_connection_error(gc, tmp);
|   +		buf = g_realloc(buf, buf_len + body_len);
|   +		memcpy(buf + buf_len, body, body_len);
|   +		buf_len += body_len;
|    	}
|   -	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);
|   +		res = write(httpconn->fd, buf, buf_len);
|    		if (res >= 0)
|    		{
|    			s += res;
|    		}
|    		else if (errno != EAGAIN)
|    		{
|   -			httpconn->servconn->cmdproc->error = MSN_ERROR_WRITE;
|   -			show_error(httpconn);
|   +			msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_WRITE);
|    			return -1;
|    		}
|   -	} while (s < len);
|   +	} while (s < buf_len);
|    
|   +	g_free(buf);
|   +
|    	return s;
|    }
|    
|    void
|    msn_httpconn_poll(MsnHttpConn *httpconn)
|    {
|   +	char *header;
|    	int r;
|   -	char *temp;
|    
|    	g_return_if_fail(httpconn != NULL);
|    
|   @@ -160,7 +130,7 @@ msn_httpconn_poll(MsnHttpConn *httpconn)
|    		return;
|    	}
|    
|   -	temp = g_strdup_printf(
|   +	header = 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"
|   @@ -170,15 +140,14 @@ msn_httpconn_poll(MsnHttpConn *httpconn)
|    		"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",
|   +		"Content-Length: 0\r\n",
|    		httpconn->host,
|    		httpconn->full_session_id,
|    		httpconn->host);
|    
|   -	r = write_raw(httpconn, temp, strlen(temp));
|   +	r = write_raw(httpconn, header, NULL, -1);
|    
|   -	g_free(temp);
|   +	g_free(header);
|    
|    	if (r > 0)
|    	{
|   @@ -224,7 +193,7 @@ connect_cb(gpointer data, gint source, G
|    	else
|    	{
|    		gaim_debug_error("msn", "HTTP: Connection error\n");
|   -		show_error(httpconn);
|   +		msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_CONNECT);
|    	}
|    }
|    
|   @@ -257,8 +226,10 @@ msn_httpconn_disconnect(MsnHttpConn *htt
|    msn_httpconn_disconnect(MsnHttpConn *httpconn)
|    {
|    	g_return_if_fail(httpconn != NULL);
|   -	g_return_if_fail(httpconn->connected);
|    
|   +	if (!httpconn->connected)
|   +		return;
|   +
|    	if (httpconn->timer)
|    		gaim_timeout_remove(httpconn->timer);
|    
|   @@ -302,7 +273,7 @@ read_cb(gpointer data, gint source, Gaim
|    	if (len <= 0)
|    	{
|    		gaim_debug_error("msn", "HTTP: Read error\n");
|   -		show_error(httpconn);
|   +		msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_READ);
|    		msn_httpconn_disconnect(httpconn);
|    
|    		return;
|   @@ -329,7 +300,7 @@ read_cb(gpointer data, gint source, Gaim
|    	if (error)
|    	{
|    		gaim_debug_error("msn", "HTTP: Special error\n");
|   -		show_error(httpconn);
|   +		msn_servconn_got_error(httpconn->servconn, MSN_SERVCONN_ERROR_READ);
|    		msn_httpconn_disconnect(httpconn);
|    
|    		return;
|   @@ -341,6 +312,7 @@ read_cb(gpointer data, gint source, Gaim
|    #if 0
|    		gaim_debug_info("msn", "HTTP: nothing to do here\n");
|    #endif
|   +		g_free(result_msg);
|    		g_free(httpconn->rx_buf);
|    		httpconn->rx_buf = NULL;
|    		httpconn->rx_len = 0;
|   @@ -351,6 +323,7 @@ read_cb(gpointer data, gint source, Gaim
|    	httpconn->rx_buf = NULL;
|    	httpconn->rx_len = 0;
|    
|   +	g_free(servconn->rx_buf);
|    	servconn->rx_buf = result_msg;
|    	servconn->rx_len = result_len;
|    
|   @@ -425,10 +398,10 @@ msn_httpconn_process_queue(MsnHttpConn *
|    		httpconn->queue = g_list_remove(httpconn->queue, queue_data);
|    
|    		msn_httpconn_write(queue_data->httpconn,
|   -						   queue_data->buffer,
|   +						   queue_data->data,
|    						   queue_data->size);
|    
|   -		g_free(queue_data->buffer);
|   +		g_free(queue_data->data);
|    		g_free(queue_data);
|    	}
|    	else
|   @@ -438,22 +411,21 @@ size_t
|    }
|    
|    size_t
|   -msn_httpconn_write(MsnHttpConn *httpconn, const char *buf, size_t size)
|   +msn_httpconn_write(MsnHttpConn *httpconn, const char *data, size_t size)
|    {
|    	char *params;
|   -	char *temp;
|   +	char *header;
|    	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(data     != NULL, 0);
|    	g_return_val_if_fail(size      > 0,    0);
|    
|    	servconn = httpconn->servconn;
|   @@ -463,7 +435,7 @@ msn_httpconn_write(MsnHttpConn *httpconn
|    		MsnHttpQueueData *queue_data = g_new0(MsnHttpQueueData, 1);
|    
|    		queue_data->httpconn = httpconn;
|   -		queue_data->buffer   = g_memdup(buf, size);
|   +		queue_data->data     = g_memdup(data, size);
|    		queue_data->size     = size;
|    
|    		httpconn->queue = g_list_append(httpconn->queue, queue_data);
|   @@ -495,7 +467,7 @@ msn_httpconn_write(MsnHttpConn *httpconn
|    								 httpconn->full_session_id);
|    	}
|    
|   -	temp = g_strdup_printf(
|   +	header = g_strdup_printf(
|    		"POST http://%s/gateway/gateway.dll?%s HTTP/1.1\r\n"
|    		"Accept: */*\r\n"
|    		"Accept-Language: en-us\r\n"
|   @@ -505,8 +477,7 @@ msn_httpconn_write(MsnHttpConn *httpconn
|    		"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",
|   +		"Content-Length: %d\r\n",
|    		host,
|    		params,
|    		host,
|   @@ -514,16 +485,10 @@ msn_httpconn_write(MsnHttpConn *httpconn
|    
|    	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, header, data, size);
|    
|   -	r = write_raw(httpconn, temp, len);
|   +	g_free(header);
|    
|   -	g_free(temp);
|   -
|    	if (r > 0)
|    	{
|    		httpconn->virgin = FALSE;
|   @@ -541,7 +506,7 @@ msn_httpconn_parse_data(MsnHttpConn *htt
|    {
|    	GaimConnection *gc;
|    	const char *s, *c;
|   -	char *headers, *body;
|   +	char *header, *body;
|    	const char *body_start;
|    	char *tmp;
|    	size_t body_len = 0;
|   @@ -604,12 +569,12 @@ msn_httpconn_parse_data(MsnHttpConn *htt
|    	if ((s = strstr(buf, "\r\n\r\n")) == NULL)
|    		return FALSE;
|    
|   -	headers = g_strndup(buf, s - buf);
|   +	header = 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)
|   +	if ((s = strstr(header, "Content-Length: ")) != NULL)
|    	{
|    		int tmp_len;
|    
|   @@ -617,7 +582,7 @@ msn_httpconn_parse_data(MsnHttpConn *htt
|    
|    		if ((c = strchr(s, '\r')) == NULL)
|    		{
|   -			g_free(headers);
|   +			g_free(header);
|    
|    			return FALSE;
|    		}
|   @@ -628,7 +593,7 @@ msn_httpconn_parse_data(MsnHttpConn *htt
|    
|    		if (body_len != tmp_len)
|    		{
|   -			g_free(headers);
|   +			g_free(header);
|    
|    #if 0
|    			gaim_debug_warning("msn",
|   @@ -640,14 +605,16 @@ msn_httpconn_parse_data(MsnHttpConn *htt
|    		}
|    	}
|    
|   -	body = g_memdup(body_start, body_len);
|   +	body = g_malloc0(body_len + 1);
|   +	memcpy(body, body_start, body_len);
|    
|    #ifdef MSN_DEBUG_HTTP
|   -	gaim_debug_misc("msn", "Incoming HTTP buffer: {%s\r\n\r\n%s}\n", headers, body);
|   +	gaim_debug_misc("msn", "Incoming HTTP buffer (header): {%s\r\n}\n",
|   +					header);
|    #endif
|    
|    	/* Now we should be able to process the data. */
|   -	if ((s = strstr(headers, "X-MSN-Messenger: ")) != NULL)
|   +	if ((s = strstr(header, "X-MSN-Messenger: ")) != NULL)
|    	{
|    		char *full_session_id, *gw_ip, *session_action;
|    		char *t, *session_id;
|   @@ -659,10 +626,12 @@ msn_httpconn_parse_data(MsnHttpConn *htt
|    
|    		if ((c = strchr(s, '\r')) == NULL)
|    		{
|   -			gaim_connection_error(gc, "Malformed X-MSN-Messenger field.");
|   +			msn_session_set_error(httpconn->session,
|   +								  MSN_ERROR_HTTP_MALFORMED, NULL);
|    			gaim_debug_error("msn", "Malformed X-MSN-Messenger field.\n{%s}",
|    							 buf);
|    
|   +			g_free(body);
|    			return FALSE;
|    		}
|    
|   @@ -731,7 +700,7 @@ msn_httpconn_parse_data(MsnHttpConn *htt
|    		}
|    	}
|    
|   -	g_free(headers);
|   +	g_free(header);
|    
|    	*ret_buf  = body;
|    	*ret_size = body_len;
|   ============================================================
|   --- src/protocols/msn/httpconn.h	439f53ee3453fd0e85b101a4656e0a4f3b455abe
|   +++ src/protocols/msn/httpconn.h	7b3611f4ac46fb2d06db98ae7fabdea96b241f4b
|   @@ -28,101 +28,79 @@ typedef struct _MsnHttpConn MsnHttpConn;
|    
|    #include "servconn.h"
|    
|   +/**
|   + * An HTTP Connection.
|   + */
|    struct _MsnHttpConn
|    {
|   -	MsnSession *session;
|   -	MsnServConn *servconn;
|   +	MsnSession *session; /**< The MSN Session. */
|   +	MsnServConn *servconn; /**< The connection object. */
|    
|   -	char *full_session_id;
|   -	char *session_id;
|   +	char *full_session_id; /**< The full session id. */
|   +	char *session_id; /**< The trimmed session id. */
|    
|   -	int timer;
|   +	int timer; /**< The timer for polling. */
|    
|   -	gboolean waiting_response;
|   -	gboolean dirty; /**< The flag that states if we should poll. */
|   -	gboolean connected;
|   +	gboolean waiting_response; /**< The flag that states if we are waiting
|   +								 a response from the server. */
|   +	gboolean dirty;            /**< The flag that states if we should poll. */
|   +	gboolean connected;        /**< The flag that states if the connection is on. */
|   +	gboolean virgin;           /**< The flag that states if this connection
|   +								 should specify the host (not gateway) to
|   +								 connect to. */
|    
|   -	char *host;
|   -	GList *queue;
|   +	char *host; /**< The HTTP gateway host. */
|   +	GList *queue; /**< The queue of data chunks to write. */
|    
|   -	int fd;
|   -	int inpa;
|   +	int fd; /**< The connection's file descriptor. */
|   +	int inpa; /**< The connection's input handler. */
|    
|   -	char *rx_buf;
|   -	int rx_len;
|   -
|   -#if 0
|   -	GQueue *servconn_queue;
|   -#endif
|   -
|   -	gboolean virgin;
|   +	char *rx_buf; /**< The receive buffer. */
|   +	int rx_len; /**< The receive buffer lenght. */
|    };
|    
|   -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.
|   + * Creates a new HTTP connection object.
|     *
|   - * @param session The session.
|   + * @param servconn The connection object.
|   + *
|   + * @return The new object.
|     */
|   -void msn_http_session_init(MsnSession *session);
|   +MsnHttpConn *msn_httpconn_new(MsnServConn *servconn);
|    
|    /**
|   - * Uninitializes the HTTP data for a session.
|   + * Destroys an HTTP connection object.
|     *
|   - * @param session The session.
|   + * @param httpconn The HTTP connection object.
|     */
|   -void msn_http_session_uninit(MsnSession *session);
|   +void msn_httpconn_destroy(MsnHttpConn *httpconn);
|    
|    /**
|   - * Writes data to the server using the HTTP connection method.
|   + * Writes a chunk of data to the HTTP connection.
|     *
|     * @param servconn    The server connection.
|   - * @param buf         The data to write.
|   + * @param data        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);
|   +size_t msn_httpconn_write(MsnHttpConn *httpconn, const char *data, size_t size);
|    
|    /**
|   - * Polls the server for data.
|   + * Connects the HTTP connection object to a host.
|     *
|   - * @param servconn The server connection.
|   + * @param httpconn The HTTP connection object.
|   + * @param host The host to connect to.
|   + * @param port The port to connect to.
|     */
|   -void msn_http_servconn_poll(MsnServConn *servconn);
|   +gboolean msn_httpconn_connect(MsnHttpConn *httpconn,
|   +							  const char *host, int port);
|    
|    /**
|   - * Processes an incoming message and returns a string the rest of MSN
|   - * can deal with.
|   + * Disconnects the HTTP connection object.
|     *
|   - * @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.
|   + * @param httpconn The HTTP connection object.
|     */
|   -gboolean msn_http_servconn_parse_data(MsnServConn *servconn,
|   -									  const char *buf, size_t size,
|   -									  char **ret_buf, size_t *ret_size,
|   -									  gboolean *error);
|   -#endif
|   +void msn_httpconn_disconnect(MsnHttpConn *httpconn);
|    
|    #endif /* _MSN_HTTPCONN_H_ */
|   ============================================================
|   --- src/protocols/msn/msg.c	8ef3972be90725ec63e42aed7ca310ee17fe527b
|   +++ src/protocols/msn/msg.c	ee30626ec805c02e1b1a7467593dd8e36a760889
|   @@ -197,7 +197,8 @@ msn_message_parse_payload(MsnMessage *ms
|    
|    	g_return_if_fail(payload != NULL);
|    
|   -	tmp_base = tmp = g_memdup(payload, payload_len);
|   +	tmp_base = tmp = g_malloc0(payload_len + 1);
|   +	memcpy(tmp_base, payload, payload_len);
|    
|    	/* Parse the attributes. */
|    	end = strstr(tmp, "\r\n\r\n");
|   ============================================================
|   --- src/protocols/msn/msn.c	bcb1643b0a8018bacf8e59c1c8848f9a64893436
|   +++ src/protocols/msn/msn.c	86533d3f4656b13555453e39059309042bc4f153
|   @@ -631,22 +631,23 @@ msn_login(GaimAccount *account)
|    		http_method = TRUE;
|    
|    	host = gaim_account_get_string(account, "server", MSN_SERVER);
|   -	port = gaim_account_get_int(account,    "port",   MSN_PORT);
|   +	port = gaim_account_get_int(account, "port", MSN_PORT);
|    
|   -	session = msn_session_new(account, host, port, http_method);
|   +	session = msn_session_new(account);
|    
|    	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;
|    
|   -	gaim_connection_update_progress(gc, _("Connecting"), 0, MSN_CONNECT_STEPS);
|   +	msn_session_set_login_step(session, MSN_LOGIN_STEP_START);
|    
|    	/* Hmm, I don't like this. */
|   +	/* XXX shx: Me neither */
|    	username = msn_normalize(account, gaim_account_get_username(account));
|    
|    	if (strcmp(username, gaim_account_get_username(account)))
|    		gaim_account_set_username(account, username);
|    
|   -	msn_session_connect(session);
|   +	msn_session_connect(session, host, port, http_method);
|    }
|    
|    static void
|   @@ -698,14 +699,7 @@ msn_send_im(GaimConnection *gc, const ch
|    		session = gc->proto_data;
|    		swboard = msn_session_get_swboard(session, who);
|    
|   -		if (!g_queue_is_empty(swboard->im_queue) || swboard->empty)
|   -		{
|   -			msn_switchboard_queue_msg(swboard, msg);
|   -		}
|   -		else
|   -		{
|   -			msn_switchboard_send_msg(swboard, msg);
|   -		}
|   +		msn_switchboard_send_msg(swboard, msg, TRUE);
|    	}
|    	else
|    	{
|   @@ -760,15 +754,9 @@ msn_send_typing(GaimConnection *gc, cons
|    
|    	swboard = msn_session_find_swboard(session, who);
|    
|   -	if (swboard == NULL)
|   +	if (swboard == NULL || !msn_switchboard_can_send(swboard))
|    		return 0;
|    
|   -	if (swboard->empty)
|   -		return 0;
|   -
|   -	if (!g_queue_is_empty(swboard->im_queue))
|   -		return 0;
|   -
|    	msg = msn_message_new(MSN_MSG_TYPING);
|    	msn_message_set_content_type(msg, "text/x-msmsgscontrol");
|    	msn_message_set_flag(msg, 'U');
|   @@ -776,7 +764,7 @@ msn_send_typing(GaimConnection *gc, cons
|    						 gaim_account_get_username(account));
|    	msn_message_set_bin_data(msg, "\r\n", 2);
|    
|   -	msn_switchboard_send_msg(swboard, msg);
|   +	msn_switchboard_send_msg(swboard, msg, FALSE);
|    
|    	msn_message_destroy(msg);
|    
|   @@ -1124,7 +1112,7 @@ msn_chat_send(GaimConnection *gc, int id
|    
|    	msg = msn_message_new_plain(msgtext);
|    	msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat);
|   -	msn_switchboard_send_msg(swboard, msg);
|   +	msn_switchboard_send_msg(swboard, msg, FALSE);
|    	msn_message_destroy(msg);
|    
|    	g_free(msgformat);
|   @@ -1143,6 +1131,7 @@ msn_keepalive(GaimConnection *gc)
|    	MsnCmdProc *cmdproc;
|    
|    	session = gc->proto_data;
|   +
|    	cmdproc = session->notification->cmdproc;
|    
|    	if (!session->http_method)
|   ============================================================
|   --- src/protocols/msn/msn.h	33ebb47c5cc5e403e3637c6488be1ee91db0fb71
|   +++ src/protocols/msn/msn.h	2f37626407aa695f9ead618675675ba821fecdb6
|   @@ -45,9 +45,14 @@
|    
|    #include "ft.h"
|    
|   -/* XXX */
|   -#include "gaim.h"
|   +/* #define MSN_DEBUG_MSG 1 */
|   +/* #define MSN_DEBUG_SLPMSG 1 */
|   +/* #define MSN_DEBUG_HTTP 1 */
|    
|   +/* #define MSN_DEBUG_SLP 1 */
|   +/* #define MSN_DEBUG_SLP_VERBOSE 1 */
|   +/* #define MSN_DEBUG_SLP_FILES 1 */
|   +
|    #define MSN_BUF_LEN 8192
|    
|    #define USEROPT_MSNSERVER 3
|   @@ -67,8 +72,6 @@
|    
|    #define MSN_FT_GUID "{5D3E02AB-6190-11d3-BBBB-00C04F795683}"
|    
|   -#define MSN_CONNECT_STEPS 8
|   -
|    #define MSN_CLIENTINFO \
|    	"Client-Name: Gaim/" VERSION "\r\n" \
|    	"Chat-Logging: Y\r\n"
|   ============================================================
|   --- src/protocols/msn/nexus.c	83ed4afa08e58d80df293bcc96f306909c73d102
|   +++ src/protocols/msn/nexus.c	f54fd42744b2afe062d596b626c278dffa953431
|   @@ -26,6 +26,38 @@
|    #include "notification.h"
|    
|    /**************************************************************************
|   + * Main
|   + **************************************************************************/
|   +
|   +MsnNexus *
|   +msn_nexus_new(MsnSession *session)
|   +{
|   +	MsnNexus *nexus;
|   +
|   +	nexus = g_new0(MsnNexus, 1);
|   +	nexus->session = session;
|   +	nexus->challenge_data = g_hash_table_new_full(g_str_hash, g_str_equal,
|   +												  g_free, g_free);
|   +
|   +	return nexus;
|   +}
|   +
|   +void
|   +msn_nexus_destroy(MsnNexus *nexus)
|   +{
|   +	if (nexus->login_host != NULL)
|   +		g_free(nexus->login_host);
|   +
|   +	if (nexus->login_path != NULL)
|   +		g_free(nexus->login_path);
|   +
|   +	if (nexus->challenge_data != NULL)
|   +		g_hash_table_destroy(nexus->challenge_data);
|   +
|   +	g_free(nexus);
|   +}
|   +
|   +/**************************************************************************
|     * Util
|     **************************************************************************/
|    
|   @@ -76,7 +108,7 @@ login_error_cb(GaimSslConnection *gsc, G
|    	gc = gaim_account_get_connection(account);
|    	g_return_if_fail(gc != NULL);
|    
|   -	gaim_connection_error(gc, _("Unable to connect to server"));
|   +	msn_session_set_error(session, MSN_ERROR_AUTH, _("Unable to connect"));
|    
|    	msn_nexus_destroy(nexus);
|    	session->nexus = NULL;
|   @@ -100,6 +132,8 @@ login_connect_cb(gpointer data, GaimSslC
|    	session = nexus->session;
|    	g_return_if_fail(session != NULL);
|    
|   +	msn_session_set_login_step(session, MSN_LOGIN_STEP_GET_COOKIE);
|   +
|    	username =
|    		g_strdup(gaim_url_encode(gaim_account_get_username(session->account)));
|    
|   @@ -191,14 +225,15 @@ login_connect_cb(gpointer data, GaimSslC
|    	}
|    	else if (strstr(buffer, "HTTP/1.1 401 Unauthorized") != NULL)
|    	{
|   -		GaimConnection *gc;
|   -		const char *error, *c;
|   -		char *temp;
|   +		const char *error;
|    
|    		if ((error = strstr(buffer, "WWW-Authenticate")) != NULL)
|    		{
|    			if ((error = strstr(error, "cbtxt=")) != NULL)
|    			{
|   +				const char *c;
|   +				char *temp;
|   +
|    				error += strlen("cbtxt=");
|    
|    				if ((c = strchr(error, '\n')) == NULL)
|   @@ -210,16 +245,7 @@ login_connect_cb(gpointer data, GaimSslC
|    			}
|    		}
|    
|   -		gc = gaim_account_get_connection(session->account);
|   -
|   -		if (error == NULL)
|   -		{
|   -			gaim_connection_error(gc,
|   -				_("Unknown error when attempting to authorize with "
|   -				  "MSN login server."));
|   -		}
|   -		else
|   -			gaim_connection_error(gc, error);
|   +		msn_session_set_error(session, MSN_ERROR_AUTH, error);
|    	}
|    	else if (strstr(buffer, "HTTP/1.1 200 OK"))
|    	{
|   @@ -264,6 +290,10 @@ login_connect_cb(gpointer data, GaimSslC
|    	g_free(buffer);
|    }
|    
|   +/**************************************************************************
|   + * Connect
|   + **************************************************************************/
|   +
|    static void
|    nexus_connect_cb(gpointer data, GaimSslConnection *gsc,
|    				 GaimInputCondition cond)
|   @@ -282,6 +312,8 @@ nexus_connect_cb(gpointer data, GaimSslC
|    	session = nexus->session;
|    	g_return_if_fail(session != NULL);
|    
|   +	msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH);
|   +
|    	request_str = g_strdup_printf("GET /rdr/pprdr.asp\r\n\r\n");
|    
|    	if ((s = gaim_ssl_write(gsc, request_str, strlen(request_str))) <= 0)
|   @@ -332,39 +364,7 @@ nexus_connect_cb(gpointer data, GaimSslC
|    					 login_error_cb, nexus);
|    }
|    
|   -/**************************************************************************
|   - * Nexus
|   - **************************************************************************/
|   -
|   -MsnNexus *
|   -msn_nexus_new(MsnSession *session)
|   -{
|   -	MsnNexus *nexus;
|   -
|   -	nexus = g_new0(MsnNexus, 1);
|   -	nexus->session = session;
|   -	nexus->challenge_data = g_hash_table_new_full(g_str_hash, g_str_equal,
|   -												  g_free, g_free);
|   -
|   -	return nexus;
|   -}
|   -
|    void
|   -msn_nexus_destroy(MsnNexus *nexus)
|   -{
|   -	if (nexus->login_host != NULL)
|   -		g_free(nexus->login_host);
|   -
|   -	if (nexus->login_path != NULL)
|   -		g_free(nexus->login_path);
|   -
|   -	if (nexus->challenge_data != NULL)
|   -		g_hash_table_destroy(nexus->challenge_data);
|   -
|   -	g_free(nexus);
|   -}
|   -
|   -void
|    msn_nexus_connect(MsnNexus *nexus)
|    {
|    	gaim_ssl_connect(nexus->session->account, "nexus.passport.com",
|   ============================================================
|   --- src/protocols/msn/notification.c	556e5263194a4e7ef6cc95d194da6bb19d0ef460
|   +++ src/protocols/msn/notification.c	bd5b923eadf1ed1c3a3d747d3a286e7ee7a20325
|   @@ -32,13 +32,12 @@
|    #include "sync.h"
|    #include "slplink.h"
|    
|   -#define BUDDY_ALIAS_MAXLEN 388
|   -
|    static MsnTable *cbs_table;
|    
|    /**************************************************************************
|     * Main
|     **************************************************************************/
|   +
|    static void
|    destroy_cb(MsnServConn *servconn)
|    {
|   @@ -61,7 +60,7 @@ msn_notification_new(MsnSession *session
|    	notification = g_new0(MsnNotification, 1);
|    
|    	notification->session = session;
|   -	notification->servconn = servconn = msn_servconn_new(session, MSN_SERVER_NS);
|   +	notification->servconn = servconn = msn_servconn_new(session, MSN_SERVCONN_NS);
|    	msn_servconn_set_destroy_cb(servconn, destroy_cb);
|    
|    	notification->cmdproc = servconn->cmdproc;
|   @@ -74,20 +73,19 @@ msn_notification_destroy(MsnNotification
|    void
|    msn_notification_destroy(MsnNotification *notification)
|    {
|   -	if (notification->destroying)
|   -		return;
|   +	notification->cmdproc->data = NULL;
|    
|   -	notification->destroying = TRUE;
|   +	msn_servconn_set_destroy_cb(notification->servconn, NULL);
|    
|    	msn_servconn_destroy(notification->servconn);
|    
|   -	notification->session->notification = NULL;
|    	g_free(notification);
|    }
|    
|    /**************************************************************************
|     * Connect
|     **************************************************************************/
|   +
|    static void
|    connect_cb(MsnServConn *servconn)
|    {
|   @@ -113,17 +111,11 @@ connect_cb(MsnServConn *servconn)
|    
|    	vers = g_strjoinv(" ", a);
|    
|   +	msn_session_set_login_step(session, MSN_LOGIN_STEP_HANDSHAKE);
|    	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
|   @@ -155,6 +147,7 @@ msn_notification_disconnect(MsnNotificat
|    /**************************************************************************
|     * Util
|     **************************************************************************/
|   +
|    static void
|    group_error_helper(MsnSession *session, const char *msg, int group_id, int error)
|    {
|   @@ -198,6 +191,7 @@ group_error_helper(MsnSession *session, 
|    /**************************************************************************
|     * Login
|     **************************************************************************/
|   +
|    void
|    msn_got_login_params(MsnSession *session, const char *login_params)
|    {
|   @@ -205,6 +199,8 @@ msn_got_login_params(MsnSession *session
|    
|    	cmdproc = session->notification->cmdproc;
|    
|   +	msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_END);
|   +
|    	msn_cmdproc_send(cmdproc, "USR", "TWN S %s", login_params);
|    }
|    
|   @@ -220,31 +216,6 @@ static void
|    }
|    
|    static void
|   -inf_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
|   -{
|   -	GaimAccount *account;
|   -	GaimConnection *gc;
|   -
|   -	account = cmdproc->session->account;
|   -	gc = gaim_account_get_connection(account);
|   -
|   -	if (strcmp(cmd->params[1], "MD5"))
|   -	{
|   -		msn_cmdproc_show_error(cmdproc, MSN_ERROR_MISC);
|   -		return;
|   -	}
|   -
|   -	msn_cmdproc_send(cmdproc, "USR", "MD5 I %s",
|   -					 gaim_account_get_username(account));
|   -
|   -	if (cmdproc->error)
|   -		return;
|   -
|   -	gaim_connection_update_progress(gc, _("Requesting to send password"),
|   -									5, MSN_CONNECT_STEPS);
|   -}
|   -
|   -static void
|    usr_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
|    {
|    	MsnSession *session;
|   @@ -255,33 +226,22 @@ usr_cmd(MsnCmdProc *cmdproc, MsnCommand 
|    	account = session->account;
|    	gc = gaim_account_get_connection(account);
|    
|   -	/*
|   -	 * We're either getting the passport connect info (if we're on
|   -	 * MSNP8 or higher), or a challenge request (MSNP7 and lower).
|   -	 *
|   -	 * Let's find out.
|   -	 */
|    	if (!g_ascii_strcasecmp(cmd->params[1], "OK"))
|    	{
|   +		/* OK */
|    		const char *friendly = gaim_url_decode(cmd->params[3]);
|    
|   -		/* OK */
|   +		gaim_connection_set_display_name(gc, friendly);
|    
|   -		gaim_connection_set_display_name(gc, friendly);
|   +		msn_session_set_login_step(session, MSN_LOGIN_STEP_SYN);
|    
|    		msn_cmdproc_send(cmdproc, "SYN", "%s", "0");
|   -
|   -		if (cmdproc->error)
|   -			return;
|   -
|   -		gaim_connection_update_progress(gc, _("Retrieving buddy list"),
|   -										7, MSN_CONNECT_STEPS);
|    	}
|    	else if (!g_ascii_strcasecmp(cmd->params[1], "TWN"))
|    	{
|   +		/* Passport authentication */
|    		char **elems, **cur, **tokens;
|    
|   -		/* Passport authentication */
|    		session->nexus = msn_nexus_new(session);
|    
|    		/* Parse the challenge data. */
|   @@ -298,40 +258,10 @@ usr_cmd(MsnCmdProc *cmdproc, MsnCommand 
|    
|    		g_strfreev(elems);
|    
|   -		msn_nexus_connect(session->nexus);
|   +		msn_session_set_login_step(session, MSN_LOGIN_STEP_AUTH_START);
|    
|   -		gaim_connection_update_progress(gc, _("Password sent"),
|   -										6, MSN_CONNECT_STEPS);
|   +		msn_nexus_connect(session->nexus);
|    	}
|   -	else if (!g_ascii_strcasecmp(cmd->params[1], "MD5"))
|   -	{
|   -		/* Challenge */
|   -		const char *challenge;
|   -		const char *password;
|   -		char buf[33];
|   -		md5_state_t st;
|   -		md5_byte_t di[16];
|   -		int i;
|   -
|   -		challenge = cmd->params[3];
|   -		password = gaim_account_get_password(account);
|   -
|   -		md5_init(&st);
|   -		md5_append(&st, (const md5_byte_t *)challenge, strlen(challenge));
|   -		md5_append(&st, (const md5_byte_t *)password, strlen(password));
|   -		md5_finish(&st, di);
|   -
|   -		for (i = 0; i < 16; i++)
|   -			g_snprintf(buf + (i*2), 3, "%02x", di[i]);
|   -
|   -		msn_cmdproc_send(cmdproc, "USR", "MD5 S %s", buf);
|   -
|   -		if (cmdproc->error)
|   -			return;
|   -
|   -		gaim_connection_update_progress(gc, _("Password sent"),
|   -										6, MSN_CONNECT_STEPS);
|   -	}
|    }
|    
|    static void
|   @@ -359,7 +289,8 @@ ver_cmd(MsnCmdProc *cmdproc, MsnCommand 
|    
|    	if (!protocol_supported)
|    	{
|   -		msn_cmdproc_show_error(cmdproc, MSN_ERROR_MISC);
|   +		msn_session_set_error(session, MSN_ERROR_UNSUPORTED_PROTOCOL,
|   +							  NULL);
|    		return;
|    	}
|    
|   @@ -371,13 +302,15 @@ ver_cmd(MsnCmdProc *cmdproc, MsnCommand 
|    /**************************************************************************
|     * Log out
|     **************************************************************************/
|   +
|    static void
|    out_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
|    {
|    	if (!g_ascii_strcasecmp(cmd->params[0], "OTH"))
|   -		msn_cmdproc_show_error(cmdproc, MSN_ERROR_SIGNOTHER);
|   +		msn_session_set_error(cmdproc->session, MSN_ERROR_SIGN_OTHER,
|   +							  NULL);
|    	else if (!g_ascii_strcasecmp(cmd->params[0], "SSD"))
|   -		msn_cmdproc_show_error(cmdproc, MSN_ERROR_SERVDOWN);
|   +		msn_session_set_error(cmdproc->session, MSN_ERROR_SERV_DOWN, NULL);
|    }
|    
|    void
|   @@ -393,6 +326,7 @@ msn_notification_close(MsnNotification *
|    /**************************************************************************
|     * Messages
|     **************************************************************************/
|   +
|    static void
|    msg_cmd_post(MsnCmdProc *cmdproc, MsnCommand *cmd, char *payload,
|    			 size_t len)
|   @@ -431,6 +365,7 @@ msg_cmd(MsnCmdProc *cmdproc, MsnCommand 
|    /**************************************************************************
|     * Challenges
|     **************************************************************************/
|   +
|    static void
|    chl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
|    {
|   @@ -464,6 +399,7 @@ chl_cmd(MsnCmdProc *cmdproc, MsnCommand 
|    /**************************************************************************
|     * Buddy Lists
|     **************************************************************************/
|   +
|    static void
|    add_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
|    {
|   @@ -873,22 +809,13 @@ syn_cmd(MsnCmdProc *cmdproc, MsnCommand 
|    
|    	if (cmd->param_count == 2)
|    	{
|   -		char *buf;
|    		/*
|    		 * This can happen if we sent a SYN with an up-to-date
|    		 * buddy list revision, but we send 0 to get a full list.
|    		 * So, error out.
|    		 */
|   -		buf = g_strdup_printf(
|   -				_("Your MSN buddy list for %s is temporarily unavailable. "
|   -				  "Please wait and try again."),
|   -				gaim_account_get_username(session->account));
|    
|   -		gaim_connection_error(gaim_account_get_connection(session->account),
|   -							  buf);
|   -
|   -		g_free(buf);
|   -
|   +		msn_session_set_error(cmdproc->session, MSN_ERROR_BAD_BLIST, NULL);
|    		return;
|    	}
|    
|   @@ -915,6 +842,7 @@ syn_cmd(MsnCmdProc *cmdproc, MsnCommand 
|    /**************************************************************************
|     * Misc commands
|     **************************************************************************/
|   +
|    static void
|    url_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
|    {
|   @@ -1017,6 +945,7 @@ url_cmd(MsnCmdProc *cmdproc, MsnCommand 
|    /**************************************************************************
|     * Switchboards
|     **************************************************************************/
|   +
|    static void
|    rng_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
|    {
|   @@ -1055,7 +984,8 @@ xfr_cmd(MsnCmdProc *cmdproc, MsnCommand 
|    
|    	if (strcmp(cmd->params[1], "SB") && strcmp(cmd->params[1], "NS"))
|    	{
|   -		msn_cmdproc_show_error(cmdproc, MSN_ERROR_MISC);
|   +		/* Maybe we can have a generic bad command error. */
|   +		gaim_debug_error("msn", "Bad XFR command (%s)\n", cmd->params[1]);
|    		return;
|    	}
|    
|   @@ -1064,19 +994,6 @@ xfr_cmd(MsnCmdProc *cmdproc, MsnCommand 
|    	if (!strcmp(cmd->params[1], "SB"))
|    	{
|    		gaim_debug_error("msn", "This shouldn't be handled here.\n");
|   -#if 0
|   -		swboard = cmd->trans->data;
|   -
|   -		if (swboard != NULL)
|   -		{
|   -			msn_switchboard_set_auth_key(swboard, cmd->params[4]);
|   -
|   -			if (session->http_method)
|   -				port = 80;
|   -
|   -			msn_switchboard_connect(swboard, host, port);
|   -		}
|   -#endif
|    	}
|    	else if (!strcmp(cmd->params[1], "NS"))
|    	{
|   @@ -1084,6 +1001,9 @@ xfr_cmd(MsnCmdProc *cmdproc, MsnCommand 
|    
|    		session = cmdproc->session;
|    
|   +		if (!session->logged_in)
|   +			msn_session_set_login_step(session, MSN_LOGIN_STEP_TRANSFER);
|   +
|    		msn_notification_connect(session->notification, host, port);
|    	}
|    
|   @@ -1093,6 +1013,7 @@ xfr_cmd(MsnCmdProc *cmdproc, MsnCommand 
|    /**************************************************************************
|     * Message Types
|     **************************************************************************/
|   +
|    static void
|    profile_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
|    {
|   @@ -1342,6 +1263,7 @@ msn_notification_rem_buddy(MsnNotificati
|    /**************************************************************************
|     * Init
|     **************************************************************************/
|   +
|    void
|    msn_notification_init(void)
|    {
|   @@ -1359,7 +1281,6 @@ msn_notification_init(void)
|    	msn_table_add_cmd(cbs_table, "USR", "XFR", xfr_cmd);
|    	msn_table_add_cmd(cbs_table, "SYN", "SYN", syn_cmd);
|    	msn_table_add_cmd(cbs_table, "CVR", "CVR", cvr_cmd);
|   -	msn_table_add_cmd(cbs_table, "INF", "INF", inf_cmd);
|    	msn_table_add_cmd(cbs_table, "VER", "VER", ver_cmd);
|    	msn_table_add_cmd(cbs_table, "REA", "REA", rea_cmd);
|    	/* msn_table_add_cmd(cbs_table, "PRP", "PRP", prp_cmd); */
|   ============================================================
|   --- src/protocols/msn/notification.h	632f7c36affddbcc7f9b3cb387f2c3a1c22c4b22
|   +++ src/protocols/msn/notification.h	360279e0975110d80faf5468f768e23cbec5007d
|   @@ -36,9 +36,6 @@ struct _MsnNotification
|    	MsnCmdProc *cmdproc;
|    	MsnServConn *servconn;
|    
|   -	gboolean destroying;	/**< A flag that states if the notification is on
|   -							  the process of being destroyed. */
|   -
|    	gboolean in_use;
|    };
|    
|   ============================================================
|   --- src/protocols/msn/servconn.c	9c0aff4019343c183bffb448a67647c89894701e
|   +++ src/protocols/msn/servconn.c	c90ed444a410c540f48f1e0f411a3955f562ac70
|   @@ -27,6 +27,10 @@ static void read_cb(gpointer data, gint 
|    
|    static void read_cb(gpointer data, gint source, GaimInputCondition cond);
|    
|   +/**************************************************************************
|   + * Main
|   + **************************************************************************/
|   +
|    MsnServConn *
|    msn_servconn_new(MsnSession *session, MsnServConnType type)
|    {
|   @@ -42,8 +46,7 @@ msn_servconn_new(MsnSession *session, Ms
|    	servconn->cmdproc = msn_cmdproc_new(session);
|    	servconn->cmdproc->servconn = servconn;
|    
|   -	if (session->http_method)
|   -		servconn->httpconn = msn_httpconn_new(servconn);
|   +	servconn->httpconn = msn_httpconn_new(servconn);
|    
|    	servconn->num = session->servconns_count++;
|    
|   @@ -61,11 +64,6 @@ msn_servconn_destroy(MsnServConn *servco
|    		return;
|    	}
|    
|   -	if (servconn->destroying)
|   -		return;
|   -
|   -	servconn->destroying = TRUE;
|   -
|    	if (servconn->connected)
|    		msn_servconn_disconnect(servconn);
|    
|   @@ -82,52 +80,83 @@ msn_servconn_destroy(MsnServConn *servco
|    	g_free(servconn);
|    }
|    
|   -static void
|   -show_error(MsnServConn *servconn)
|   +void
|   +msn_servconn_set_connect_cb(MsnServConn *servconn,
|   +							void (*connect_cb)(MsnServConn *))
|    {
|   -	GaimConnection *gc;
|   +	g_return_if_fail(servconn != NULL);
|   +	servconn->connect_cb = connect_cb;
|   +}
|   +
|   +void
|   +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;
|   +}
|   +
|   +/**************************************************************************
|   + * Utility
|   + **************************************************************************/
|   +
|   +void
|   +msn_servconn_got_error(MsnServConn *servconn, MsnServConnError error)
|   +{
|    	char *tmp;
|   -	char *cmd;
|   +	const char *reason;
|    
|    	const char *names[] = { "Notification", "Switchboard" };
|    	const char *name;
|    
|   -	gc = gaim_account_get_connection(servconn->session->account);
|    	name = names[servconn->type];
|    
|   -	switch (servconn->cmdproc->error)
|   +	switch (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 = 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;
|   +		case MSN_SERVCONN_ERROR_CONNECT:
|   +			reason = _("Unable to connect"); break;
|   +		case MSN_SERVCONN_ERROR_WRITE:
|   +			reason = _("Writing error"); break;
|   +		case MSN_SERVCONN_ERROR_READ:
|   +			reason = _("Reading error"); break;
|    		default:
|   -			tmp = g_strdup_printf(_("Unknown error from %s server"), name);
|   -			break;
|   +			reason = _("Unknown error"); break;
|    	}
|    
|   -	if (servconn->type != MSN_SERVER_SB)
|   +	tmp = g_strdup_printf(_("Connection error from %s server (%s):\n%s"),
|   +						  name, servconn->host, reason);
|   +
|   +	if (servconn->type == MSN_SERVCONN_NS)
|    	{
|   -		gaim_connection_error(gc, tmp);
|   +		msn_session_set_error(servconn->session, MSN_ERROR_SERVCONN, tmp);
|    	}
|   -	else
|   +	else if (servconn->type == MSN_SERVCONN_SB)
|    	{
|    		MsnSwitchBoard *swboard;
|    		swboard = servconn->cmdproc->data;
|   -		swboard->error = MSN_SB_ERROR_CONNECTION;
|   +		if (swboard != NULL)
|   +			swboard->error = MSN_SB_ERROR_CONNECTION;
|    	}
|    
|   +	msn_servconn_disconnect(servconn);
|   +
|    	g_free(tmp);
|    }
|    
|   +/**************************************************************************
|   + * Connect
|   + **************************************************************************/
|   +
|    static void
|    connect_cb(gpointer data, gint source, GaimInputCondition cond)
|    {
|   @@ -146,7 +175,6 @@ connect_cb(gpointer data, gint source, G
|    	if (source > 0)
|    	{
|    		servconn->connected = TRUE;
|   -		servconn->cmdproc->ready = TRUE;
|    
|    		/* Someone wants to know we connected. */
|    		servconn->connect_cb(servconn);
|   @@ -155,8 +183,7 @@ connect_cb(gpointer data, gint source, G
|    	}
|    	else
|    	{
|   -		servconn->cmdproc->error = MSN_ERROR_CONNECT;
|   -		show_error(servconn);
|   +		msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_CONNECT);
|    	}
|    }
|    
|   @@ -188,7 +215,6 @@ msn_servconn_connect(MsnServConn *servco
|    			msn_httpconn_connect(servconn->httpconn, host, port);
|    
|    		servconn->connected = TRUE;
|   -		servconn->cmdproc->ready = TRUE;
|    		servconn->httpconn->virgin = TRUE;
|    
|    		/* Someone wants to know we connected. */
|   @@ -216,6 +242,7 @@ msn_servconn_disconnect(MsnServConn *ser
|    
|    	if (!servconn->connected)
|    	{
|   +		/* We could not connect. */
|    		if (servconn->disconnect_cb != NULL)
|    			servconn->disconnect_cb(servconn);
|    
|   @@ -224,7 +251,7 @@ msn_servconn_disconnect(MsnServConn *ser
|    
|    	if (servconn->session->http_method)
|    	{
|   -		/* Fake disconnection */
|   +		/* Fake disconnection. */
|    		if (servconn->disconnect_cb != NULL)
|    			servconn->disconnect_cb(servconn);
|    
|   @@ -244,48 +271,11 @@ msn_servconn_disconnect(MsnServConn *ser
|    	servconn->payload_len = 0;
|    
|    	servconn->connected = FALSE;
|   -	servconn->cmdproc->ready = FALSE;
|    
|    	if (servconn->disconnect_cb != NULL)
|    		servconn->disconnect_cb(servconn);
|    }
|    
|   -void
|   -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 *))
|   -{
|   -	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)
|   -{
|   -	g_return_if_fail(servconn != NULL);
|   -
|   -	show_error(servconn);
|   -
|   -	msn_servconn_disconnect(servconn);
|   -}
|   -
|    size_t
|    msn_servconn_write(MsnServConn *servconn, const char *buf, size_t len)
|    {
|   @@ -297,14 +287,16 @@ msn_servconn_write(MsnServConn *servconn
|    	{
|    		switch (servconn->type)
|    		{
|   -			case MSN_SERVER_NS:
|   -			case MSN_SERVER_SB:
|   +			case MSN_SERVCONN_NS:
|   +			case MSN_SERVCONN_SB:
|    				ret = write(servconn->fd, buf, len);
|    				break;
|   -			case MSN_SERVER_DC:
|   +#if 0
|   +			case MSN_SERVCONN_DC:
|    				ret = write(servconn->fd, &buf, sizeof(len));
|    				ret = write(servconn->fd, buf, len);
|    				break;
|   +#endif
|    			default:
|    				ret = write(servconn->fd, buf, len);
|    				break;
|   @@ -317,8 +309,7 @@ msn_servconn_write(MsnServConn *servconn
|    
|    	if (ret == -1)
|    	{
|   -		servconn->cmdproc->error = MSN_ERROR_WRITE;
|   -		failed_io(servconn);
|   +		msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_WRITE);
|    	}
|    
|    	return ret;
|   @@ -340,10 +331,8 @@ read_cb(gpointer data, gint source, Gaim
|    
|    	if (len <= 0)
|    	{
|   -		servconn->cmdproc->error = MSN_ERROR_READ;
|   +		msn_servconn_got_error(servconn, MSN_SERVCONN_ERROR_READ);
|    
|   -		failed_io(servconn);
|   -
|    		return;
|    	}
|    
|   ============================================================
|   --- src/protocols/msn/servconn.h	9e77af0c3ffcb14a64634462c94f385c7d523977
|   +++ src/protocols/msn/servconn.h	da44ea75ef03e06f6bb6f0d1115f24a141cfe407
|   @@ -32,21 +32,30 @@ typedef struct _MsnServConn MsnServConn;
|    #include "proxy.h"
|    #include "httpconn.h"
|    
|   -/*
|   - * Connection types
|   +/**
|   + * Connection error types.
|     */
|    typedef enum
|    {
|   -	MSN_SERVER_NS,
|   -	MSN_SERVER_SB,
|   -	MSN_SERVER_NX,
|   -	MSN_SERVER_DC,
|   -	MSN_SERVER_HT
|   +	MSN_SERVCONN_ERROR_NONE,
|   +	MSN_SERVCONN_ERROR_CONNECT,
|   +	MSN_SERVCONN_ERROR_WRITE,
|   +	MSN_SERVCONN_ERROR_READ,
|    
|   +} MsnServConnError;
|   +
|   +/**
|   + * Connection types.
|   + */
|   +typedef enum
|   +{
|   +	MSN_SERVCONN_NS,
|   +	MSN_SERVCONN_SB
|   +
|    } MsnServConnType;
|    
|   -/*
|   - * A Connection
|   +/**
|   + * A Connection.
|     */
|    struct _MsnServConn
|    {
|   @@ -58,8 +67,6 @@ struct _MsnServConn
|    	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. */
|    
|    	char *host; /**< The host this connection is connected or should be
|    				  connected to. */
|   @@ -148,4 +155,12 @@ size_t msn_servconn_write(MsnServConn *s
|    size_t msn_servconn_write(MsnServConn *servconn, const char *buf,
|    						  size_t size);
|    
|   +/**
|   + * Function to call whenever an error related to a switchboard occurs.
|   + *
|   + * @param servconn The servconn.
|   + * @param error The error that happened.
|   + */
|   +void msn_servconn_got_error(MsnServConn *servconn, MsnServConnError error);
|   +
|    #endif /* _MSN_SERVCONN_H_ */
|   ============================================================
|   --- src/protocols/msn/session.c	8d9b746cf7977992be741cb035bcbee43d4ff533
|   +++ src/protocols/msn/session.c	5bc0dfd60f8b8896ff24c6c083ae40d454001e93
|   @@ -28,8 +28,7 @@ MsnSession *
|    #include "dialog.h"
|    
|    MsnSession *
|   -msn_session_new(GaimAccount *account, const char *host, int port,
|   -				gboolean http_method)
|   +msn_session_new(GaimAccount *account)
|    {
|    	MsnSession *session;
|    
|   @@ -37,15 +36,14 @@ msn_session_new(GaimAccount *account, co
|    
|    	session = g_new0(MsnSession, 1);
|    
|   -	session->account       = account;
|   -	session->dispatch_host = g_strdup(host);
|   -	session->dispatch_port = port;
|   -	session->http_method   = http_method;
|   -
|   +	session->account = account;
|    	session->notification = msn_notification_new(session);
|    	session->userlist = msn_userlist_new(session);
|    	session->sync_userlist = msn_userlist_new(session);
|    
|   +	session->user = msn_user_new(session->userlist,
|   +								 gaim_account_get_username(account), NULL);
|   +
|    	session->protocol_ver = 9;
|    
|    	return session;
|   @@ -61,9 +59,6 @@ msn_session_destroy(MsnSession *session)
|    	if (session->connected)
|    		msn_session_disconnect(session);
|    
|   -	if (session->dispatch_host != NULL)
|   -		g_free(session->dispatch_host);
|   -
|    	if (session->notification != NULL)
|    		msn_notification_destroy(session->notification);
|    
|   @@ -102,16 +97,21 @@ msn_session_destroy(MsnSession *session)
|    	if (session->nexus != NULL)
|    		msn_nexus_destroy(session->nexus);
|    
|   +	if (session->user != NULL)
|   +		msn_user_destroy(session->user);
|   +
|    	g_free(session);
|    }
|    
|    gboolean
|   -msn_session_connect(MsnSession *session)
|   +msn_session_connect(MsnSession *session, const char *host, int port,
|   +					gboolean http_method)
|    {
|    	g_return_val_if_fail(session != NULL, FALSE);
|    	g_return_val_if_fail(!session->connected, TRUE);
|    
|    	session->connected = TRUE;
|   +	session->http_method = http_method;
|    
|    	if (session->notification == NULL)
|    	{
|   @@ -119,9 +119,7 @@ msn_session_connect(MsnSession *session)
|    		g_return_val_if_reached(FALSE);
|    	}
|    
|   -	if (msn_notification_connect(session->notification,
|   -								 session->dispatch_host,
|   -								 session->dispatch_port))
|   +	if (msn_notification_connect(session->notification, host, port))
|    	{
|    		return TRUE;
|    	}
|   @@ -135,13 +133,13 @@ msn_session_disconnect(MsnSession *sessi
|    	g_return_if_fail(session != NULL);
|    	g_return_if_fail(session->connected);
|    
|   +	session->connected = FALSE;
|   +
|    	while (session->switches != NULL)
|    		msn_switchboard_close(session->switches->data);
|    
|    	if (session->notification != NULL)
|    		msn_notification_close(session->notification);
|   -
|   -	session->connected = FALSE;
|    }
|    
|    /* TODO: This must go away when conversation is redesigned */
|   @@ -280,6 +278,86 @@ void
|    }
|    
|    void
|   +msn_session_set_error(MsnSession *session, MsnErrorType error,
|   +					  const char *info)
|   +{
|   +	GaimConnection *gc;
|   +	char *msg;
|   +
|   +	gc = session->account->gc;
|   +
|   +	switch (error)
|   +	{
|   +		case MSN_ERROR_SERVCONN:
|   +			msg = g_strdup(info);
|   +			break;
|   +		case MSN_ERROR_UNSUPORTED_PROTOCOL:
|   +			msg = g_strdup(_("Our protocol is not supported by the "
|   +							 "server."));
|   +			break;
|   +		case MSN_ERROR_HTTP_MALFORMED:
|   +			msg = g_strdup(_("Error parsing HTTP."));
|   +			break;
|   +		case MSN_ERROR_SIGN_OTHER:
|   +			gc->wants_to_die = TRUE;
|   +			msg = g_strdup(_("You have signed on from another location."));
|   +			break;
|   +		case MSN_ERROR_SERV_DOWN:
|   +			msg = g_strdup(_("The MSN servers are going down "
|   +							 "temporarily."));
|   +			break;
|   +		case MSN_ERROR_AUTH:
|   +			msg = g_strdup_printf(_("Unable to authenticate: %s"),
|   +								  (info == NULL ) ?
|   +								  _("Unknown error") : info);
|   +			break;
|   +		case MSN_ERROR_BAD_BLIST:
|   +			msg = g_strdup(_("Your MSN buddy list is temporarily "
|   +							 "unavailable. Please wait and try "
|   +							 "again."));
|   +			break;
|   +		default:
|   +			msg = g_strdup(_("Unknown error."));
|   +			break;
|   +	}
|   +
|   +	msn_session_disconnect(session);
|   +	gaim_connection_error(gc, msg);
|   +
|   +	g_free(msg);
|   +}
|   +
|   +static const char *
|   +get_login_step_text(MsnSession *session)
|   +{
|   +	const char *steps_text[] = {
|   +		_("Connecting"),
|   +		_("Handshaking"),
|   +		_("Transfering"),
|   +		_("Starting authentication"),
|   +		_("Getting cookie"),
|   +		_("Authenticating"),
|   +		_("Sending cookie"),
|   +		_("Retrieving buddy list")
|   +	};
|   +
|   +	return steps_text[session->login_step];
|   +}
|   +
|   +void
|   +msn_session_set_login_step(MsnSession *session, MsnLoginStep step)
|   +{
|   +	GaimConnection *gc;
|   +
|   +	gc = session->account->gc;
|   +
|   +	session->login_step = step;
|   +
|   +	gaim_connection_update_progress(gc, get_login_step_text(session), step,
|   +									MSN_LOGIN_STEPS);
|   +}
|   +
|   +void
|    msn_session_finish_login(MsnSession *session)
|    {
|    	GaimAccount *account;
|   ============================================================
|   --- src/protocols/msn/session.h	95401b94ff46d95388832a0c491dd4500fdacb8d
|   +++ src/protocols/msn/session.h	0c3930d575a930a9936f9b10d44878e13171e374
|   @@ -40,6 +40,40 @@ typedef struct _MsnSession MsnSession;
|    #include "userlist.h"
|    #include "sync.h"
|    
|   +/**
|   + * Types of errors.
|   + */
|   +typedef enum
|   +{
|   +	MSN_ERROR_SERVCONN,
|   +	MSN_ERROR_UNSUPORTED_PROTOCOL,
|   +	MSN_ERROR_HTTP_MALFORMED,
|   +	MSN_ERROR_AUTH,
|   +	MSN_ERROR_BAD_BLIST,
|   +	MSN_ERROR_SIGN_OTHER,
|   +	MSN_ERROR_SERV_DOWN
|   +
|   +} MsnErrorType;
|   +
|   +/**
|   + * Login steps.
|   + */
|   +typedef enum
|   +{
|   +	MSN_LOGIN_STEP_START,
|   +	MSN_LOGIN_STEP_HANDSHAKE,
|   +	MSN_LOGIN_STEP_TRANSFER,
|   +	MSN_LOGIN_STEP_AUTH_START,
|   +	MSN_LOGIN_STEP_AUTH,
|   +	MSN_LOGIN_STEP_GET_COOKIE,
|   +	MSN_LOGIN_STEP_AUTH_END,
|   +	MSN_LOGIN_STEP_SYN,
|   +	MSN_LOGIN_STEP_END
|   +
|   +} MsnLoginStep;
|   +
|   +#define MSN_LOGIN_STEPS MSN_LOGIN_STEP_END
|   +
|    struct _MsnSession
|    {
|    	GaimAccount *account;
|   @@ -48,27 +82,26 @@ struct _MsnSession
|    
|    	guint protocol_ver;
|    
|   -	char *dispatch_host;
|   -	int dispatch_port;
|   +	MsnLoginStep login_step; /**< The current step in the login process. */
|    
|    	gboolean connected;
|    	gboolean logged_in; /**< A temporal flag to ignore local buddy list adds. */
|    	gboolean destroying; /**< A flag that states if the session is being destroyed. */
|   +	gboolean http_method;
|    
|    	MsnNotification *notification;
|    	MsnNexus *nexus;
|   +	MsnSync *sync;
|    
|   -	gboolean http_method;
|   -	gint http_poll_timer;
|   -
|    	MsnUserList *userlist;
|    	MsnUserList *sync_userlist;
|    
|    	int servconns_count; /**< The count of server connections. */
|    	GList *switches; /**< The list of all the switchboards. */
|    	GList *directconns; /**< The list of all the directconnections. */
|   +	GList *slplinks; /**< The list of all the slplinks. */
|    
|   -	int conv_seq;
|   +	int conv_seq; /**< The current conversation sequence number. */
|    
|    	struct
|    	{
|   @@ -81,27 +114,16 @@ struct _MsnSession
|    		int client_port;
|    
|    	} passport_info;
|   -
|   -	/* You have no idea how much I hate all that is below. */
|   -	/* shx: What? ;) */
|   -
|   -	MsnSync *sync;
|   -
|   -	GList *slplinks;
|    };
|    
|    /**
|     * Creates an MSN session.
|     *
|     * @param account The account.
|   - * @param host    The dispatch server host.
|   - * @param port    The dispatch server port.
|     *
|     * @return The new MSN session.
|     */
|   -MsnSession *msn_session_new(GaimAccount *account,
|   -							const char *host, int port,
|   -							gboolean http_method);
|   +MsnSession *msn_session_new(GaimAccount *account);
|    
|    /**
|     * Destroys an MSN session.
|   @@ -113,11 +135,16 @@ void msn_session_destroy(MsnSession *ses
|    /**
|     * Connects to and initiates an MSN session.
|     *
|   - * @param session The MSN session.
|   + * @param session     The MSN session.
|   + * @param host        The dispatch server host.
|   + * @param port        The dispatch server port.
|   + * @param http_method Whether to use or not http_method.
|     *
|     * @return @c TRUE on success, @c FALSE on failure.
|     */
|   -gboolean msn_session_connect(MsnSession *session);
|   +gboolean msn_session_connect(MsnSession *session,
|   +							 const char *host, int port,
|   +							 gboolean http_method);
|    
|    /**
|     * Disconnects from an MSN session.
|   @@ -142,6 +169,29 @@ MsnSwitchBoard *msn_session_get_swboard(
|    MsnSwitchBoard *msn_session_get_swboard(MsnSession *session,
|    										const char *username);
|    
|   +/**
|   + * Sets an error for the MSN session.
|   + *
|   + * @param session The MSN session.
|   + * @param error The error.
|   + * @param info Extra information.
|   + */
|   +void msn_session_set_error(MsnSession *session, MsnErrorType error,
|   +						   const char *info);
|   +
|   +/**
|   + * Sets the current step in the login proccess.
|   + *
|   + * @param session The MSN session.
|   + * @param step The current step.
|   + */
|   +void msn_session_set_login_step(MsnSession *session, MsnLoginStep step);
|   +
|   +/**
|   + * Finish the login proccess.
|   + *
|   + * @param session The MSN session.
|   + */
|    void msn_session_finish_login(MsnSession *session);
|    
|    #endif /* _MSN_SESSION_H_ */
|   ============================================================
|   --- src/protocols/msn/slp.h	0cbf4f9e6b27d779fce798aa600e906b5d3efd25
|   +++ src/protocols/msn/slp.h	e82284a14294a4d7697fdc40503104f7ad07f4b4
|   @@ -24,13 +24,6 @@
|    #ifndef _MSN_SLP_H_
|    #define _MSN_SLP_H_
|    
|   -/* #define MSN_DEBUG_MSG 1 */
|   -/* #define MSN_DEBUG_SLPMSG 1 */
|   -
|   -/* #define MSN_DEBUG_SLP 1 */
|   -/* #define MSN_DEBUG_SLP_VERBOSE 1 */
|   -/* #define MSN_DEBUG_SLP_FILES 1 */
|   -
|    #include "slpcall.h"
|    
|    #include "ft.h"
|   ============================================================
|   --- src/protocols/msn/slpcall.c	202f415ff32ee1f76187122fc38fa5ce68798da0
|   +++ src/protocols/msn/slpcall.c	3fa8f263568cf95b79f591f989ff94f94fda1e8e
|   @@ -96,11 +96,15 @@ msn_slp_call_destroy(MsnSlpCall *slpcall
|    
|    		g_return_if_fail(slpmsg != NULL);
|    
|   +#if 0
|    		gaim_debug_info("msn", "slpcall destroy: trying slp_msg (%p)\n",
|    						slpmsg);
|   +#endif
|    
|    		if (slpmsg->slpcall == slpcall)
|   +		{
|    			msn_slpmsg_destroy(slpmsg);
|   +		}
|    	}
|    
|    	if (slpcall->end_cb != NULL)
|   @@ -188,7 +192,7 @@ msn_slp_call_timeout(gpointer data)
|    {
|    	MsnSlpCall *slpcall;
|    
|   -	gaim_debug_info("msn", "slpcall timeout\n");
|   +	gaim_debug_info("msn", "slpcall timeout (%p)\n", slpcall);
|    
|    	slpcall = data;
|    
|   ============================================================
|   --- src/protocols/msn/slplink.c	a4b1a2cc8527f507cfccb4831b39d27e2d7ad7d7
|   +++ src/protocols/msn/slplink.c	f0cdbc8162de40076e1672e43db94751e649477f
|   @@ -213,15 +213,7 @@ msn_slplink_send_msg(MsnSlpLink *slplink
|    			slplink->swboard->slplink = slplink;
|    		}
|    
|   -		if (!g_queue_is_empty(slplink->swboard->im_queue) ||
|   -			slplink->swboard->empty)
|   -		{
|   -			msn_switchboard_queue_msg(slplink->swboard, msg);
|   -		}
|   -		else
|   -		{
|   -			msn_switchboard_send_msg(slplink->swboard, msg);
|   -		}
|   +		msn_switchboard_send_msg(slplink->swboard, msg, TRUE);
|    	}
|    }
|    
|   ============================================================
|   --- src/protocols/msn/state.c	78d9483230de7cd6649427a2434a18667d0ebab6
|   +++ src/protocols/msn/state.c	6deb541d3bf0af8cd5b316dda2c433d5047e23f6
|   @@ -46,12 +46,13 @@ msn_change_status(MsnSession *session, M
|    	MsnObject *msnobj;
|    	const char *state_text;
|    
|   +	g_return_if_fail(session != NULL);
|   +	g_return_if_fail(session->notification != NULL);
|   +
|    	cmdproc = session->notification->cmdproc;
|    	user = session->user;
|    	state_text = msn_state_get_text(state);
|    
|   -	g_return_if_fail(session != NULL);
|   -
|    	msnobj = msn_user_get_object(user);
|    
|    	if (msnobj == NULL)
|   ============================================================
|   --- src/protocols/msn/switchboard.c	4004ab1e171612e21a078a1c0cae403cf7455fcc
|   +++ src/protocols/msn/switchboard.c	ec1aac7b5e388761f710c5cde899f20f9c31c302
|   @@ -35,8 +35,9 @@ static void msg_error_helper(MsnCmdProc 
|    							 MsnMsgErrorType error);
|    
|    /**************************************************************************
|   - * Main stuff
|   + * Main
|     **************************************************************************/
|   +
|    MsnSwitchBoard *
|    msn_switchboard_new(MsnSession *session)
|    {
|   @@ -48,10 +49,10 @@ msn_switchboard_new(MsnSession *session)
|    	swboard = g_new0(MsnSwitchBoard, 1);
|    
|    	swboard->session = session;
|   -	swboard->servconn = servconn = msn_servconn_new(session, MSN_SERVER_SB);
|   +	swboard->servconn = servconn = msn_servconn_new(session, MSN_SERVCONN_SB);
|    	swboard->cmdproc = servconn->cmdproc;
|    
|   -	swboard->im_queue = g_queue_new();
|   +	swboard->msg_queue = g_queue_new();
|    	swboard->empty = TRUE;
|    
|    	swboard->cmdproc->data = swboard;
|   @@ -71,17 +72,12 @@ msn_switchboard_destroy(MsnSwitchBoard *
|    
|    	g_return_if_fail(swboard != NULL);
|    
|   -	if (swboard->destroying)
|   -		return;
|   -
|   -	swboard->destroying = TRUE;
|   -
|    	/* If it linked us is because its looking for trouble */
|    	if (swboard->slplink != NULL)
|    		msn_slplink_destroy(swboard->slplink);
|    
|    	/* Destroy the message queue */
|   -	while ((msg = g_queue_pop_head(swboard->im_queue)) != NULL)
|   +	while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL)
|    	{
|    		if (swboard->error != MSN_SB_ERROR_NONE)
|    		{
|   @@ -92,7 +88,7 @@ msn_switchboard_destroy(MsnSwitchBoard *
|    		msn_message_unref(msg);
|    	}
|    
|   -	g_queue_free(swboard->im_queue);
|   +	g_queue_free(swboard->msg_queue);
|    
|    	for (l = swboard->ack_list; l != NULL; l = l->next)
|    		msn_message_unref(l->data);
|   @@ -112,9 +108,18 @@ msn_switchboard_destroy(MsnSwitchBoard *
|    	session = swboard->session;
|    	session->switches = g_list_remove(session->switches, swboard);
|    
|   +#if 0
|   +	/* This should never happen or we are in trouble. */
|    	if (swboard->servconn != NULL)
|    		msn_servconn_destroy(swboard->servconn);
|   +#endif
|    
|   +	swboard->cmdproc->data = NULL;
|   +
|   +	msn_servconn_set_disconnect_cb(swboard->servconn, NULL);
|   +
|   +	msn_servconn_destroy(swboard->servconn);
|   +
|    	g_free(swboard);
|    }
|    
|   @@ -172,8 +177,9 @@ msn_switchboard_is_invited(MsnSwitchBoar
|    }
|    
|    /**************************************************************************
|   - * Utility functions
|   + * Utility
|     **************************************************************************/
|   +
|    static void
|    send_clientcaps(MsnSwitchBoard *swboard)
|    {
|   @@ -184,7 +190,7 @@ send_clientcaps(MsnSwitchBoard *swboard)
|    	msn_message_set_flag(msg, 'U');
|    	msn_message_set_bin_data(msg, MSN_CLIENTINFO, strlen(MSN_CLIENTINFO));
|    
|   -	msn_switchboard_send_msg(swboard, msg);
|   +	msn_switchboard_send_msg(swboard, msg, TRUE);
|    
|    	msn_message_destroy(msg);
|    }
|   @@ -421,8 +427,165 @@ msg_error_helper(MsnCmdProc *cmdproc, Ms
|    }
|    
|    /**************************************************************************
|   + * Message Stuff
|   + **************************************************************************/
|   +
|   +/** Called when a message times out. */
|   +static void
|   +msg_timeout(MsnCmdProc *cmdproc, MsnTransaction *trans)
|   +{
|   +	MsnMessage *msg;
|   +
|   +	msg = trans->data;
|   +
|   +	msg_error_helper(cmdproc, msg, MSN_MSG_ERROR_TIMEOUT);
|   +}
|   +
|   +/** Called when we receive an error of a message. */
|   +static void
|   +msg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
|   +{
|   +	msg_error_helper(cmdproc, trans->data, MSN_MSG_ERROR_UNKNOWN);
|   +}
|   +
|   +#if 0
|   +/** Called when we receive an ack of a special message. */
|   +static void
|   +msg_ack(MsnCmdProc *cmdproc, MsnCommand *cmd)
|   +{
|   +	MsnMessage *msg;
|   +
|   +	msg = cmd->trans->data;
|   +
|   +	if (msg->ack_cb != NULL)
|   +		msg->ack_cb(msg->ack_data);
|   +
|   +	msn_message_unref(msg);
|   +}
|   +
|   +/** Called when we receive a nak of a special message. */
|   +static void
|   +msg_nak(MsnCmdProc *cmdproc, MsnCommand *cmd)
|   +{
|   +	MsnMessage *msg;
|   +
|   +	msg = cmd->trans->data;
|   +
|   +	msn_message_unref(msg);
|   +}
|   +#endif
|   +
|   +static void
|   +release_msg(MsnSwitchBoard *swboard, MsnMessage *msg)
|   +{
|   +	MsnCmdProc *cmdproc;
|   +	MsnTransaction *trans;
|   +	char *payload;
|   +	gsize payload_len;
|   +
|   +	g_return_if_fail(swboard != NULL);
|   +	g_return_if_fail(msg     != NULL);
|   +
|   +	cmdproc = swboard->cmdproc;
|   +
|   +	payload = msn_message_gen_payload(msg, &payload_len);
|   +
|   +	/* msn_message_show_readable(msg, "SB SEND", FALSE); */
|   +
|   +	trans = msn_transaction_new(cmdproc, "MSG", "%c %d",
|   +								msn_message_get_flag(msg), payload_len);
|   +
|   +	/* Data for callbacks */
|   +	msn_transaction_set_data(trans, msg);
|   +
|   +	if (msg->type == MSN_MSG_TEXT)
|   +	{
|   +		msg->ack_ref = TRUE;
|   +		msn_message_ref(msg);
|   +		swboard->ack_list = g_list_append(swboard->ack_list, msg);
|   +		msn_transaction_set_timeout_cb(trans, msg_timeout);
|   +	}
|   +	else if (msg->type == MSN_MSG_SLP)
|   +	{
|   +		msg->ack_ref = TRUE;
|   +		msn_message_ref(msg);
|   +		swboard->ack_list = g_list_append(swboard->ack_list, msg);
|   +		msn_transaction_set_timeout_cb(trans, msg_timeout);
|   +#if 0
|   +		if (msg->ack_cb != NULL)
|   +		{
|   +			msn_transaction_add_cb(trans, "ACK", msg_ack);
|   +			msn_transaction_add_cb(trans, "NAK", msg_nak);
|   +		}
|   +#endif
|   +	}
|   +
|   +	trans->payload = payload;
|   +	trans->payload_len = payload_len;
|   +
|   +	msg->trans = trans;
|   +
|   +	msn_cmdproc_send_trans(cmdproc, trans);
|   +}
|   +
|   +static void
|   +queue_msg(MsnSwitchBoard *swboard, MsnMessage *msg)
|   +{
|   +	g_return_if_fail(swboard != NULL);
|   +	g_return_if_fail(msg     != NULL);
|   +
|   +	gaim_debug_info("msn", "Appending message to queue.\n");
|   +
|   +	g_queue_push_tail(swboard->msg_queue, msg);
|   +
|   +	msn_message_ref(msg);
|   +}
|   +
|   +static void
|   +process_queue(MsnSwitchBoard *swboard)
|   +{
|   +	MsnMessage *msg;
|   +
|   +	g_return_if_fail(swboard != NULL);
|   +
|   +	gaim_debug_info("msn", "Processing queue\n");
|   +
|   +	while ((msg = g_queue_pop_head(swboard->msg_queue)) != NULL)
|   +	{
|   +		gaim_debug_info("msn", "Sending message\n");
|   +		release_msg(swboard, msg);
|   +		msn_message_unref(msg);
|   +	}
|   +}
|   +
|   +gboolean
|   +msn_switchboard_can_send(MsnSwitchBoard *swboard)
|   +{
|   +	g_return_val_if_fail(swboard != NULL, FALSE);
|   +
|   +	if (swboard->empty || !g_queue_is_empty(swboard->msg_queue))
|   +		return FALSE;
|   +
|   +	return TRUE;
|   +}
|   +
|   +void
|   +msn_switchboard_send_msg(MsnSwitchBoard *swboard, MsnMessage *msg,
|   +						 gboolean queue)
|   +{
|   +	g_return_if_fail(swboard != NULL);
|   +	g_return_if_fail(msg     != NULL);
|   +
|   +	if (msn_switchboard_can_send(swboard))
|   +		release_msg(swboard, msg);
|   +	else if (queue)
|   +		queue_msg(swboard, msg);
|   +}
|   +
|   +/**************************************************************************
|     * Switchboard Commands
|     **************************************************************************/
|   +
|    static void
|    ans_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
|    {
|   @@ -528,7 +691,7 @@ joi_cmd(MsnCmdProc *cmdproc, MsnCommand 
|    
|    	msn_switchboard_add_user(swboard, passport);
|    
|   -	msn_switchboard_process_queue(swboard);
|   +	process_queue(swboard);
|    
|    	if (!session->http_method)
|    		send_clientcaps(swboard);
|   @@ -735,137 +898,6 @@ clientcaps_msg(MsnCmdProc *cmdproc, MsnM
|    }
|    
|    /**************************************************************************
|   - * Message stuff
|   - **************************************************************************/
|   -/** Called when a message times out. */
|   -static void
|   -msg_timeout(MsnCmdProc *cmdproc, MsnTransaction *trans)
|   -{
|   -	MsnMessage *msg;
|   -
|   -	msg = trans->data;
|   -
|   -	msg_error_helper(cmdproc, msg, MSN_MSG_ERROR_TIMEOUT);
|   -}
|   -
|   -/** Called when we receive an error of a message. */
|   -static void
|   -msg_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error)
|   -{
|   -	msg_error_helper(cmdproc, trans->data, MSN_MSG_ERROR_UNKNOWN);
|   -}
|   -
|   -#if 0
|   -/** Called when we receive an ack of a special message. */
|   -static void
|   -msg_ack(MsnCmdProc *cmdproc, MsnCommand *cmd)
|   -{
|   -	MsnMessage *msg;
|   -
|   -	msg = cmd->trans->data;
|   -
|   -	if (msg->ack_cb != NULL)
|   -		msg->ack_cb(msg->ack_data);
|   -
|   -	msn_message_unref(msg);
|   -}
|   -
|   -/** Called when we receive a nak of a special message. */
|   -static void
|   -msg_nak(MsnCmdProc *cmdproc, MsnCommand *cmd)
|   -{
|   -	MsnMessage *msg;
|   -
|   -	msg = cmd->trans->data;
|   -
|   -	msn_message_unref(msg);
|   -}
|   -#endif
|   -
|   -void
|   -msn_switchboard_send_msg(MsnSwitchBoard *swboard, MsnMessage *msg)
|   -{
|   -	MsnCmdProc *cmdproc;
|   -	MsnTransaction *trans;
|   -	char *payload;
|   -	gsize payload_len;
|   -
|   -	g_return_if_fail(swboard != NULL);
|   -	g_return_if_fail(msg     != NULL);
|   -
|   -	cmdproc = swboard->cmdproc;
|   -
|   -	payload = msn_message_gen_payload(msg, &payload_len);
|   -
|   -	/* msn_message_show_readable(msg, "SB SEND", FALSE); */
|   -
|   -	trans = msn_transaction_new(cmdproc, "MSG", "%c %d",
|   -								msn_message_get_flag(msg), payload_len);
|   -
|   -	/* Data for callbacks */
|   -	msn_transaction_set_data(trans, msg);
|   -
|   -	if (msg->type == MSN_MSG_TEXT)
|   -	{
|   -		msg->ack_ref = TRUE;
|   -		msn_message_ref(msg);
|   -		swboard->ack_list = g_list_append(swboard->ack_list, msg);
|   -		msn_transaction_set_timeout_cb(trans, msg_timeout);
|   -	}
|   -	else if (msg->type == MSN_MSG_SLP)
|   -	{
|   -		msg->ack_ref = TRUE;
|   -		msn_message_ref(msg);
|   -		swboard->ack_list = g_list_append(swboard->ack_list, msg);
|   -		msn_transaction_set_timeout_cb(trans, msg_timeout);
|   -#if 0
|   -		if (msg->ack_cb != NULL)
|   -		{
|   -			msn_transaction_add_cb(trans, "ACK", msg_ack);
|   -			msn_transaction_add_cb(trans, "NAK", msg_nak);
|   -		}
|   -#endif
|   -	}
|   -
|   -	trans->payload = payload;
|   -	trans->payload_len = payload_len;
|   -
|   -	msg->trans = trans;
|   -
|   -	msn_cmdproc_send_trans(cmdproc, trans);
|   -}
|   -
|   -void
|   -msn_switchboard_queue_msg(MsnSwitchBoard *swboard, MsnMessage *msg)
|   -{
|   -	g_return_if_fail(swboard != NULL);
|   -	g_return_if_fail(msg     != NULL);
|   -
|   -	gaim_debug_info("msn", "Appending message to queue.\n");
|   -
|   -	g_queue_push_tail(swboard->im_queue, msg);
|   -
|   -	msn_message_ref(msg);
|   -}
|   -
|   -void
|   -msn_switchboard_process_queue(MsnSwitchBoard *swboard)
|   -{
|   -	MsnMessage *msg;
|   -
|   -	g_return_if_fail(swboard != NULL);
|   -
|   -	gaim_debug_info("msn", "Processing queue\n");
|   -
|   -	while ((msg = g_queue_pop_head(swboard->im_queue)) != NULL)
|   -	{
|   -		gaim_debug_info("msn", "Sending message\n");
|   -		msn_switchboard_send_msg(swboard, msg);
|   -		msn_message_unref(msg);
|   -	}
|   -}
|   -
|   -/**************************************************************************
|     * Connect stuff
|     **************************************************************************/
|    static void
|   @@ -878,8 +910,6 @@ connect_cb(MsnServConn *servconn)
|    	cmdproc = servconn->cmdproc;
|    	g_return_if_fail(cmdproc != NULL);
|    
|   -	cmdproc->ready = TRUE;
|   -
|    	account = cmdproc->session->account;
|    	swboard = cmdproc->data;
|    	g_return_if_fail(swboard != NULL);
|   @@ -908,6 +938,8 @@ disconnect_cb(MsnServConn *servconn)
|    	swboard = servconn->cmdproc->data;
|    	g_return_if_fail(swboard != NULL);
|    
|   +	msn_servconn_set_disconnect_cb(swboard->servconn, NULL);
|   +
|    	msn_switchboard_destroy(swboard);
|    }
|    
|   @@ -999,6 +1031,7 @@ msn_switchboard_request_add_user(MsnSwit
|    /**************************************************************************
|     * Create & Transfer stuff
|     **************************************************************************/
|   +
|    static void
|    got_swboard(MsnCmdProc *cmdproc, MsnCommand *cmd)
|    {
|   @@ -1058,23 +1091,29 @@ msn_switchboard_close(MsnSwitchBoard *sw
|    {
|    	g_return_if_fail(swboard != NULL);
|    
|   -	if (g_queue_is_empty(swboard->im_queue))
|   +	if (swboard->error != MSN_SB_ERROR_NONE)
|    	{
|   +		msn_switchboard_destroy(swboard);
|   +	}
|   +	else if (g_queue_is_empty(swboard->msg_queue) ||
|   +			 !swboard->session->connected)
|   +	{
|    		MsnCmdProc *cmdproc;
|   -
|    		cmdproc = swboard->cmdproc;
|   -
|    		msn_cmdproc_send_quick(cmdproc, "OUT", NULL, NULL);
|    
|    		msn_switchboard_destroy(swboard);
|    	}
|    	else
|   +	{
|    		swboard->closed = TRUE;
|   +	}
|    }
|    
|    /**************************************************************************
|     * Init stuff
|     **************************************************************************/
|   +
|    void
|    msn_switchboard_init(void)
|    {
|   ============================================================
|   --- src/protocols/msn/switchboard.h	703f8caf7c5712c129461c018b51531234587c18
|   +++ src/protocols/msn/switchboard.h	89eb281fe4fa362c65bda72f6ae55569fcc081db
|   @@ -35,8 +35,8 @@ typedef struct _MsnSwitchBoard MsnSwitch
|    
|    #include "slplink.h"
|    
|   -/*
|   - * A switchboard error
|   +/**
|   + * A switchboard error.
|     */
|    typedef enum
|    {
|   @@ -49,9 +49,10 @@ typedef enum
|    
|    } MsnSBErrorType;
|    
|   -/*
|   - * A switchboard  A place where a bunch of users send messages to the rest
|   - * of the users.
|   +/**
|   + * A switchboard.
|   + *
|   + * A place where a bunch of users send messages to the rest of the users.
|     */
|    struct _MsnSwitchBoard
|    {
|   @@ -71,8 +72,6 @@ struct _MsnSwitchBoard
|    							  users in it. */
|    	gboolean invited;		/**< A flag that states if we were invited to the
|    							  switchboard. */
|   -	gboolean destroying;	/**< A flag that states if the switchboard is on
|   -							  the process of being destroyed. */
|    	gboolean ready;			/**< A flag that states if this switchboard is
|    							  ready to be used. */
|    	gboolean closed;		/**< A flag that states if the switchboard has
|   @@ -84,7 +83,7 @@ struct _MsnSwitchBoard
|    
|    	int chat_id;
|    
|   -	GQueue *im_queue; /**< Queue of messages to send. */
|   +	GQueue *msg_queue; /**< Queue of messages to send. */
|    	GList *ack_list; /**< List of messages waiting for an ack. */
|    
|    	MsnSBErrorType error; /**< The error that occurred in this switchboard
|   @@ -197,10 +196,29 @@ void msn_switchboard_close(MsnSwitchBoar
|     */
|    void msn_switchboard_close(MsnSwitchBoard *swboard);
|    
|   -void msn_switchboard_send_msg(MsnSwitchBoard *swboard, MsnMessage *msg);
|   -void msn_switchboard_queue_msg(MsnSwitchBoard *swboard, MsnMessage *msg);
|   -void msn_switchboard_process_queue(MsnSwitchBoard *swboard);
|   +/**
|   + * Returns whether or not we currently can send a message through this
|   + * switchboard.
|   + *
|   + * @param swboard The switchboard.
|   + *
|   + * @return @c TRUE if a message can be sent, @c FALSE otherwise.
|   + */
|   +gboolean msn_switchboard_can_send(MsnSwitchBoard *swboard);
|    
|   +/**
|   + * Sends a message through this switchboard.
|   + *
|   + * @param swboard The switchboard.
|   + * @param msg The message.
|   + * @param queue A flag that states if we want this message to be queued (in
|   + * the case it cannot currently be sent).
|   + *
|   + * @return @c TRUE if a message can be sent, @c FALSE otherwise.
|   + */
|   +void msn_switchboard_send_msg(MsnSwitchBoard *swboard, MsnMessage *msg,
|   +							  gboolean queue);
|   +
|    gboolean msn_switchboard_chat_leave(MsnSwitchBoard *swboard);
|    gboolean msn_switchboard_chat_invite(MsnSwitchBoard *swboard, const char *who);
|    
|   @@ -208,13 +226,27 @@ void msn_switchboard_request_add_user(Ms
|    void msn_switchboard_request_add_user(MsnSwitchBoard *swboard, const char *user);
|    
|    /**
|   - * Processes application/x-msnmsgrp2p messages.
|   + * Processes peer to peer messages.
|     *
|     * @param cmdproc The command processor.
|     * @param msg     The message.
|     */
|    void msn_p2p_msg(MsnCmdProc *cmdproc, MsnMessage *msg);
|   +
|   +/**
|   + * Processes emoticon messages.
|   + *
|   + * @param cmdproc The command processor.
|   + * @param msg     The message.
|   + */
|    void msn_emoticon_msg(MsnCmdProc *cmdproc, MsnMessage *msg);
|   +
|   +/**
|   + * Processes INVITE messages.
|   + *
|   + * @param cmdproc The command processor.
|   + * @param msg     The message.
|   + */
|    void msn_invite_msg(MsnCmdProc *cmdproc, MsnMessage *msg);
|    
|    #endif /* _MSN_SWITCHBOARD_H_ */
|   ============================================================
|   --- src/protocols/msn/transaction.c	d42613fa99e4519b50f4d4ef146cbdd9936207a5
|   +++ src/protocols/msn/transaction.c	870253681feed9e2fd32d99cbae62a5c2eb138ee
|   @@ -112,6 +112,9 @@ msn_transaction_unqueue_cmd(MsnTransacti
|    {
|    	MsnCommand *cmd;
|    
|   +	if (!cmdproc->servconn->connected)
|   +		return;
|   +
|    	gaim_debug_info("msn", "unqueueing command.\n");
|    	cmd = trans->pendent_cmd;
|    

To get the patch for this revision, please do this:
mtn log --last 1 --diffs --from a8c2b9a0511a8917d2466c48e33f2c7db96065c8


More information about the Commits mailing list