changeset 10345:2e01c503aa4f

[gaim-migrate @ 11556] Patch 1078151 from Felipe Contreras to fix some more MSN bugs: "User Dislpay messages, and other less used, did not set an slpcall, so the callback that should not be called, was called (in some very special cases)." ... "Here it goes the real real one, as far as I can tell. Cleaning + organizing + documentation + hard bug fix = big patch." -- Felipe Contreras I also fixed drag-and-drop to conversation window file transfers (which I had broken when I fixed some other dnd thing), made the debug output of the autoreconnect plugin more useful, and stopped the message notification plugin notifying you for messages sent by ignored users. committer: Tailor Script <tailor@pidgin.im>
author Stu Tomlinson <stu@nosnilmot.com>
date Sat, 11 Dec 2004 20:01:58 +0000
parents 5976491e07a7
children bbf738a0ce7b
files COPYRIGHT plugins/autorecon.c plugins/notify.c src/gtkimhtml.c src/gtkimhtml.h src/protocols/msn/cmdproc.c src/protocols/msn/msg.c src/protocols/msn/msg.h src/protocols/msn/msn.c src/protocols/msn/nexus.c src/protocols/msn/notification.c src/protocols/msn/session.c src/protocols/msn/slp.c src/protocols/msn/slp.h src/protocols/msn/slpcall.c src/protocols/msn/slplink.c src/protocols/msn/slplink.h src/protocols/msn/slpmsg.c src/protocols/msn/slpmsg.h src/protocols/msn/switchboard.c src/protocols/msn/switchboard.h src/protocols/msn/table.c src/protocols/msn/table.h
diffstat 23 files changed, 757 insertions(+), 570 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Sat Dec 11 00:06:06 2004 +0000
+++ b/COPYRIGHT	Sat Dec 11 20:01:58 2004 +0000
@@ -68,6 +68,7 @@
 Ignacy Gawedzki
 Michael Golden
 Ryan C. Gordon
+Miah Gregory
 Christian Hammond
 Andy Harrison
 Andrew Hart (arhart)
@@ -77,6 +78,7 @@
 Fernando Herrera
 Casey Ho
 Iain Holmes
+Nigel Horne
 Karsten Huneycutt
 Rian Hunter
 Henry Jen
--- a/plugins/autorecon.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/plugins/autorecon.c	Sat Dec 11 20:01:58 2004 +0000
@@ -108,14 +108,14 @@
 			&& gaim_prefs_get_bool(OPT_HIDE_CONNECTED)) {
 		/* this is a connected error, and we're hiding those */
 		gaim_debug(GAIM_DEBUG_INFO, "autorecon",
-				"hid disconnect error message\n");
+				"hid disconnect error message (%s)\n", text);
 		return;
 
 	} else if(gc->state == GAIM_CONNECTING
 			&& gaim_prefs_get_bool(OPT_HIDE_CONNECTING)) {
 		/* this is a connecting error, and we're hiding those */
 		gaim_debug(GAIM_DEBUG_INFO, "autorecon",
-			"hid error message while connecting\n");
+			"hid error message while connecting (%s)\n", text);
 		return;
 	}
 
--- a/plugins/notify.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/plugins/notify.c	Sat Dec 11 20:01:58 2004 +0000
@@ -224,6 +224,9 @@
 chat_recv_im(GaimAccount *account, char *sender, char *message,
              GaimConversation *conv, int *flags)
 {
+	if (gaim_conv_chat_is_user_ignored(GAIM_CONV_CHAT(conv), sender))
+			return FALSE;
+
 	notify(conv, TRUE);
 
 	return FALSE;
--- a/src/gtkimhtml.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/gtkimhtml.c	Sat Dec 11 20:01:58 2004 +0000
@@ -1350,6 +1350,9 @@
 					/* Ignore blank lines */
 				} else {
 					/* Special reasons, aka images being put in via other tag, etc. */
+					/* ... don't pretend we handled it if we didn't */
+					gtk_drag_finish(dc, FALSE, FALSE, t);
+					return;
 				}
 			}
 			break;
--- a/src/gtkimhtml.h	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/gtkimhtml.h	Sat Dec 11 20:01:58 2004 +0000
@@ -200,11 +200,11 @@
 };
 
 #define GTK_IMHTML_DND_TARGETS	\
+	{ "text/uri-list", 0, GTK_IMHTML_DRAG_URL }, \
 	{ "_NETSCAPE_URL", 0, GTK_IMHTML_DRAG_URL }, \
 	{ "text/html", 0, GTK_IMHTML_DRAG_HTML }, \
 	{ "x-url/ftp", 0, GTK_IMHTML_DRAG_URL }, \
 	{ "x-url/http", 0, GTK_IMHTML_DRAG_URL }, \
-	{ "text/uri-list", 0, GTK_IMHTML_DRAG_URL }, \
 	{ "UTF8_STRING", 0, GTK_IMHTML_DRAG_UTF8_STRING }, \
 	{ "COMPOUND_TEXT", 0, GTK_IMHTML_DRAG_COMPOUND_TEXT }, \
 	{ "STRING", 0, GTK_IMHTML_DRAG_STRING }, \
--- a/src/protocols/msn/cmdproc.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/cmdproc.c	Sat Dec 11 20:01:58 2004 +0000
@@ -222,7 +222,7 @@
 void
 msn_cmdproc_process_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
 {
-	MsnMsgCb cb;
+	MsnMsgTypeCb cb;
 
 	if (msn_message_get_content_type(msg) == NULL)
 	{
--- a/src/protocols/msn/msg.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/msg.c	Sat Dec 11 20:01:58 2004 +0000
@@ -32,6 +32,10 @@
 	msg = g_new0(MsnMessage, 1);
 	msg->type = type;
 
+#ifdef MSN_DEBUG_MSG
+	gaim_debug_info("msn", "message new (%p)(%d)\n", msg, type);
+#endif
+
 	msg->attr_table = g_hash_table_new_full(g_str_hash, g_str_equal,
 											g_free, g_free);
 
@@ -40,6 +44,78 @@
 	return msg;
 }
 
+void
+msn_message_destroy(MsnMessage *msg)
+{
+	g_return_if_fail(msg != NULL);
+
+	if (msg->ref_count > 0)
+	{
+		msn_message_unref(msg);
+
+		return;
+	}
+
+#ifdef MSN_DEBUG_MSG
+	gaim_debug_info("msn", "message destroy (%p)\n", msg);
+#endif
+
+	if (msg->remote_user != NULL)
+		g_free(msg->remote_user);
+
+	if (msg->body != NULL)
+		g_free(msg->body);
+
+	if (msg->content_type != NULL)
+		g_free(msg->content_type);
+
+	if (msg->charset != NULL)
+		g_free(msg->charset);
+
+	g_hash_table_destroy(msg->attr_table);
+	g_list_free(msg->attr_list);
+
+	g_free(msg);
+}
+
+MsnMessage *
+msn_message_ref(MsnMessage *msg)
+{
+	g_return_val_if_fail(msg != NULL, NULL);
+
+	msg->ref_count++;
+
+#ifdef MSN_DEBUG_MSG
+	gaim_debug_info("msn", "message ref (%p)[%d]\n", msg, msg->ref_count);
+#endif
+
+	return msg;
+}
+
+MsnMessage *
+msn_message_unref(MsnMessage *msg)
+{
+	g_return_val_if_fail(msg != NULL, NULL);
+
+	if (msg->ref_count <= 0)
+		return NULL;
+
+	msg->ref_count--;
+
+#ifdef MSN_DEBUG_MSG
+	gaim_debug_info("msn", "message unref (%p)[%d]\n", msg, msg->ref_count);
+#endif
+
+	if (msg->ref_count == 0)
+	{
+		msn_message_destroy(msg);
+
+		return NULL;
+	}
+
+	return msg;
+}
+
 MsnMessage *
 msn_message_new_plain(const char *message)
 {
@@ -241,66 +317,6 @@
 	return msg;
 }
 
-void
-msn_message_destroy(MsnMessage *msg)
-{
-	g_return_if_fail(msg != NULL);
-
-	if (msg->ref_count > 0)
-	{
-		msn_message_unref(msg);
-
-		return;
-	}
-
-	if (msg->remote_user != NULL)
-		g_free(msg->remote_user);
-
-	if (msg->body != NULL)
-		g_free(msg->body);
-
-	if (msg->content_type != NULL)
-		g_free(msg->content_type);
-
-	if (msg->charset != NULL)
-		g_free(msg->charset);
-
-	g_hash_table_destroy(msg->attr_table);
-	g_list_free(msg->attr_list);
-
-	g_free(msg);
-}
-
-MsnMessage *
-msn_message_ref(MsnMessage *msg)
-{
-	g_return_val_if_fail(msg != NULL, NULL);
-
-	msg->ref_count++;
-
-	return msg;
-}
-
-MsnMessage *
-msn_message_unref(MsnMessage *msg)
-{
-	g_return_val_if_fail(msg != NULL, NULL);
-
-	if (msg->ref_count <= 0)
-		return NULL;
-
-	msg->ref_count--;
-
-	if (msg->ref_count == 0)
-	{
-		msn_message_destroy(msg);
-
-		return NULL;
-	}
-
-	return msg;
-}
-
 char *
 msn_message_gen_slp_body(MsnMessage *msg, size_t *ret_size)
 {
@@ -691,7 +707,7 @@
 		g_string_append_printf(str, "SUB ID:     %u\r\n", msg->msnslp_header.ack_sub_id);
 		g_string_append_printf(str, "ACK Size:   %" G_GUINT64_FORMAT "\r\n", msg->msnslp_header.ack_size);
 
-#ifdef DEBUG_SLP_VERBOSE
+#ifdef MSN_DEBUG_SLP_VERBOSE
 		if (body != NULL)
 		{
 			if (text_body)
--- a/src/protocols/msn/msg.h	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/msg.h	Sat Dec 11 20:01:58 2004 +0000
@@ -32,7 +32,7 @@
 #include "command.h"
 #include "transaction.h"
 
-typedef void (*MsnCb)(void *data);
+typedef void (*MsnMsgCb)(MsnMessage *, void *data);
 
 /*
 typedef enum
@@ -54,6 +54,16 @@
 
 } MsnMsgType;
 
+typedef enum
+{
+	MSN_MSG_ERROR_NONE, /**< No error. */
+	MSN_MSG_ERROR_TIMEOUT, /**< The message timedout. */
+	MSN_MSG_ERROR_NAK, /**< The message could not be sent. */
+	MSN_MSG_ERROR_SB, /**< The error comes from the switchboard. */
+	MSN_MSG_ERROR_UNKNOWN /**< An unknown error occured. */
+
+} MsnMsgErrorType;
+
 typedef struct
 {
 	guint32 session_id;
@@ -102,8 +112,13 @@
 	MsnCommand *cmd;
 	MsnTransaction *trans;
 
-	MsnCb ack_cb;
-	void *ack_data;
+	MsnMsgCb ack_cb; /**< The callback to call when we receive an ACK of this
+					message. */
+	MsnMsgCb nak_cb; /**< The callback to call when we receive a NAK of this
+					message. */
+	void *ack_data; /**< The data used by callbacks. */
+
+	MsnMsgErrorType error; /**< The error of the message. */
 };
 
 /**
--- a/src/protocols/msn/msn.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/msn.c	Sat Dec 11 20:01:58 2004 +0000
@@ -757,9 +757,7 @@
 		session = gc->proto_data;
 		swboard = msn_session_get_swboard(session, who);
 
-
-		if (!g_queue_is_empty(swboard->im_queue) ||
-			!swboard->user_joined)
+		if (!g_queue_is_empty(swboard->im_queue) || swboard->empty)
 		{
 			msn_switchboard_queue_msg(swboard, msg);
 		}
@@ -767,7 +765,6 @@
 		{
 			msn_switchboard_send_msg(swboard, msg);
 		}
-
 	}
 	else
 	{
@@ -824,7 +821,7 @@
 	if (swboard == NULL)
 		return 0;
 
-	if (!swboard->user_joined)
+	if (swboard->empty)
 		return 0;
 
 	msg = msn_message_new(MSN_MSG_TYPING);
@@ -834,7 +831,16 @@
 						 gaim_account_get_username(account));
 	msn_message_set_bin_data(msg, "\r\n", 2);
 
-	msn_switchboard_send_msg(swboard, msg);
+	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_message_destroy(msg);
 
@@ -1155,30 +1161,30 @@
 	if (swboard == NULL)
 		return -EINVAL;
 
-	if (swboard->ready)
-	{
-		msn_import_html(message, &msgformat, &msgtext);
-
-		if (strlen(msgtext) + strlen(msgformat) + strlen(VERSION) > 1564)
-		{
-			g_free(msgformat);
-			g_free(msgtext);
+	if (!swboard->ready)
+		return 0;
 
-			return -E2BIG;
-		}
+	msn_import_html(message, &msgformat, &msgtext);
 
-		msg = msn_message_new_plain(msgtext);
-		msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat);
-		msn_switchboard_send_msg(swboard, msg);
-		msn_message_destroy(msg);
-
+	if (strlen(msgtext) + strlen(msgformat) + strlen(VERSION) > 1564)
+	{
 		g_free(msgformat);
 		g_free(msgtext);
 
-		serv_got_chat_in(gc, id, gaim_account_get_username(account), 0,
-						 message, time(NULL));
+		return -E2BIG;
 	}
 
+	msg = msn_message_new_plain(msgtext);
+	msn_message_set_attr(msg, "X-MMS-IM-Format", msgformat);
+	msn_switchboard_send_msg(swboard, msg);
+	msn_message_destroy(msg);
+
+	g_free(msgformat);
+	g_free(msgtext);
+
+	serv_got_chat_in(gc, id, gaim_account_get_username(account), 0,
+					 message, time(NULL));
+
 	return 0;
 }
 
--- a/src/protocols/msn/nexus.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/nexus.c	Sat Dec 11 20:01:58 2004 +0000
@@ -132,7 +132,7 @@
 		(char *)g_hash_table_lookup(nexus->challenge_data, "tpf"),
 		nexus->login_host);
 
-	gaim_debug(GAIM_DEBUG_MISC, "msn", "Sending: {%s}\n", request_str);
+	gaim_debug_misc("msn", "Sending: {%s}\n", request_str);
 
 	g_free(username);
 	g_free(password);
@@ -151,7 +151,7 @@
 
 	gaim_ssl_close(gsc);
 
-	gaim_debug(GAIM_DEBUG_MISC, "msn", "ssl buffer: {%s}", buffer);
+	gaim_debug_misc("msn", "ssl buffer: {%s}", buffer);
 
 	if (strstr(buffer, "HTTP/1.1 302") != NULL)
 	{
--- a/src/protocols/msn/notification.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/notification.c	Sat Dec 11 20:01:58 2004 +0000
@@ -810,9 +810,9 @@
 
 	if ((fd = gaim_mkstemp(&session->passport_info.file, FALSE)) == NULL)
 	{
-		gaim_debug(GAIM_DEBUG_ERROR, "msn",
-				   "Error opening temp passport file: %s\n",
-				   strerror(errno));
+		gaim_debug_error("msn",
+						 "Error opening temp passport file: %s\n",
+						 strerror(errno));
 	}
 	else
 	{
--- a/src/protocols/msn/session.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/session.c	Sat Dec 11 20:01:58 2004 +0000
@@ -25,8 +25,6 @@
 #include "session.h"
 #include "notification.h"
 
-#include "slplink.h"
-
 #include "dialog.h"
 
 MsnSession *
--- a/src/protocols/msn/slp.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/slp.c	Sat Dec 11 20:01:58 2004 +0000
@@ -205,7 +205,7 @@
 								"MSNSLP/1.0 200 OK",
 								branch, type, content);
 
-#ifdef DEBUG_SLP
+#ifdef MSN_DEBUG_SLP
 	slpmsg->info = "SLP 200 OK";
 	slpmsg->text_body = TRUE;
 #endif
@@ -229,7 +229,7 @@
 								"MSNSLP/1.0 603 Decline",
 								branch, type, content);
 
-#ifdef DEBUG_SLP
+#ifdef MSN_DEBUG_SLP
 	slpmsg->info = "SLP 603 Decline";
 	slpmsg->text_body = TRUE;
 #endif
@@ -295,19 +295,21 @@
 
 		/* DATA PREP */
 		slpmsg = msn_slpmsg_new(slplink);
+		slpmsg->slpcall = slpcall;
 		slpmsg->slpsession = slpsession;
 		slpmsg->session_id = slpsession->id;
 		msn_slpmsg_set_body(slpmsg, NULL, 4);
-#ifdef DEBUG_SLP
+#ifdef MSN_DEBUG_SLP
 		slpmsg->info = "SLP DATA PREP";
 #endif
 		msn_slplink_queue_slpmsg(slplink, slpmsg);
 
 		/* DATA */
 		slpmsg = msn_slpmsg_new(slplink);
+		slpmsg->slpcall = slpcall;
 		slpmsg->slpsession = slpsession;
 		slpmsg->flags = 0x20;
-#ifdef DEBUG_SLP
+#ifdef MSN_DEBUG_SLP
 		slpmsg->info = "SLP DATA";
 #endif
 		msn_slpmsg_open_file(slpmsg, file_name);
@@ -383,7 +385,7 @@
 								"\r\n");
 	g_free(header);
 
-#ifdef DEBUG_SLP
+#ifdef MSN_DEBUG_SLP
 	slpmsg->info = "SLP BYE";
 	slpmsg->text_body = TRUE;
 #endif
@@ -553,7 +555,7 @@
 										"application/x-msnmsgr-transreqbody",
 										content);
 
-#ifdef DEBUG_SLP
+#ifdef MSN_DEBUG_SLP
 			slpmsg->info = "SLP INVITE";
 			slpmsg->text_body = TRUE;
 #endif
--- a/src/protocols/msn/slp.h	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/slp.h	Sat Dec 11 20:01:58 2004 +0000
@@ -24,9 +24,12 @@
 #ifndef _MSN_SLP_H_
 #define _MSN_SLP_H_
 
-/* #define DEBUG_SLP 1 */
-/* #define DEBUG_SLP_VERBOSE 1 */
-/* #define DEBUG_SLP_FILES 1 */
+/* #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"
 
--- a/src/protocols/msn/slpcall.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/slpcall.c	Sat Dec 11 20:01:58 2004 +0000
@@ -68,27 +68,6 @@
 }
 
 void
-msn_slp_call_init(MsnSlpCall *slpcall, MsnSlpCallType type)
-{
-	slpcall->session_id = rand() % 0xFFFFFF00 + 4;
-	slpcall->id = rand_guid();
-	slpcall->type = type;
-}
-
-void
-msn_slp_call_session_init(MsnSlpCall *slpcall)
-{
-	MsnSlpSession *slpsession;
-
-	slpsession = msn_slp_session_new(slpcall);
-
-	if (slpcall->session_init_cb)
-		slpcall->session_init_cb(slpsession);
-
-	slpcall->started = TRUE;
-}
-
-void
 msn_slp_call_destroy(MsnSlpCall *slpcall)
 {
 	GList *e;
@@ -117,14 +96,11 @@
 
 		g_return_if_fail(slpmsg != NULL);
 
+		gaim_debug_info("msn", "slpcall destroy: tryping slp_msg (%p)\n",
+						slpmsg);
+
 		if (slpmsg->slpcall == slpcall)
-		{
-#if 1
 			msn_slpmsg_destroy(slpmsg);
-#else
-			slpmsg->wasted = TRUE;
-#endif
-		}
 	}
 
 	if (slpcall->end_cb != NULL)
@@ -134,6 +110,27 @@
 }
 
 void
+msn_slp_call_init(MsnSlpCall *slpcall, MsnSlpCallType type)
+{
+	slpcall->session_id = rand() % 0xFFFFFF00 + 4;
+	slpcall->id = rand_guid();
+	slpcall->type = type;
+}
+
+void
+msn_slp_call_session_init(MsnSlpCall *slpcall)
+{
+	MsnSlpSession *slpsession;
+
+	slpsession = msn_slp_session_new(slpcall);
+
+	if (slpcall->session_init_cb)
+		slpcall->session_init_cb(slpsession);
+
+	slpcall->started = TRUE;
+}
+
+void
 msn_slp_call_invite(MsnSlpCall *slpcall, const char *euf_guid,
 					int app_id, const char *context)
 {
@@ -164,7 +161,7 @@
 
 	slpmsg = msn_slpmsg_sip_new(slpcall, 0, header, slpcall->branch,
 								"application/x-msnmsgr-sessionreqbody", content);
-#ifdef DEBUG_SLP
+#ifdef MSN_DEBUG_SLP
 	slpmsg->info = "SLP INVITE";
 	slpmsg->text_body = TRUE;
 #endif
--- a/src/protocols/msn/slplink.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/slplink.c	Sat Dec 11 20:01:58 2004 +0000
@@ -29,7 +29,7 @@
 
 void msn_slplink_send_msgpart(MsnSlpLink *slplink, MsnSlpMessage *slpmsg);
 
-#ifdef DEBUG_SLP_FILES
+#ifdef MSN_DEBUG_SLP_FILES
 static int m_sc = 0;
 static int m_rc = 0;
 
@@ -84,6 +84,9 @@
 
 	g_return_if_fail(slplink != NULL);
 
+	if (slplink->swboard != NULL)
+		slplink->swboard->slplink = NULL;
+
 	session = slplink->session;
 
 	if (slplink->local_user != NULL)
@@ -198,29 +201,33 @@
 	}
 	else
 	{
-		MsnSwitchBoard *swboard;
+		if (slplink->swboard == NULL)
+		{
+			slplink->swboard = msn_session_get_swboard(slplink->session,
+													   slplink->remote_user);
 
-		swboard = msn_session_get_swboard(slplink->session,
-										  slplink->remote_user);
+			if (slplink->swboard == NULL)
+				return;
 
-		if (swboard == NULL)
-			return;
+			/* If swboard is destroyed we will too */
+			slplink->swboard->slplink = slplink;
+		}
 
-		if (!g_queue_is_empty(swboard->im_queue) ||
-			!swboard->user_joined)
+		if (!g_queue_is_empty(slplink->swboard->im_queue) ||
+			slplink->swboard->empty)
 		{
-			msn_switchboard_queue_msg(swboard, msg);
+			msn_switchboard_queue_msg(slplink->swboard, msg);
 		}
 		else
 		{
-			msn_switchboard_send_msg(swboard, msg);
+			msn_switchboard_send_msg(slplink->swboard, msg);
 		}
 	}
 }
 
-/* We have received the message receive ack */
+/* We have received the message ack */
 static void
-msg_ack(void *data)
+msg_ack(MsnMessage *msg, void *data)
 {
 	MsnSlpMessage *slpmsg;
 	long long real_size;
@@ -229,6 +236,8 @@
 
 	real_size = (slpmsg->flags == 0x2) ? 0 : slpmsg->size;
 
+	slpmsg->offset += msg->msnslp_header.length;
+
 	if (slpmsg->offset < real_size)
 	{
 		msn_slplink_send_msgpart(slpmsg->slplink, slpmsg);
@@ -245,9 +254,22 @@
 				slpmsg->slpcall->cb(slpmsg->slpcall, NULL, 0);
 			}
 		}
+	}
 
-		msn_slpmsg_destroy(slpmsg);
-	}
+	slpmsg->msgs = g_list_remove(slpmsg->msgs, msg);
+}
+
+/* We have received the message nak. */
+static void
+msg_nak(MsnMessage *msg, void *data)
+{
+	MsnSlpMessage *slpmsg;
+
+	slpmsg = data;
+
+	msn_slplink_send_msgpart(slpmsg->slplink, slpmsg);
+
+	slpmsg->msgs = g_list_remove(slpmsg->msgs, msg);
 }
 
 void
@@ -257,6 +279,8 @@
 	long long real_size;
 	size_t len = 0;
 
+	/* Maybe we will want to create a new msg for this slpmsg instead of
+	 * reusing the same one all the time. */
 	msg = slpmsg->msg;
 
 	real_size = (slpmsg->flags == 0x2) ? 0 : slpmsg->size;
@@ -283,17 +307,20 @@
 		msg->msnslp_header.length = len;
 	}
 
-#ifdef DEBUG_SLP
+#ifdef MSN_DEBUG_SLP
 	msn_message_show_readable(msg, slpmsg->info, slpmsg->text_body);
 #endif
 
-#ifdef DEBUG_SLP_FILES
+#ifdef MSN_DEBUG_SLP_FILES
 	debug_msg_to_file(msg, TRUE);
 #endif
 
+	slpmsg->msgs =
+		g_list_append(slpmsg->msgs, msg);
 	msn_slplink_send_msg(slplink, msg);
 
-	if ((slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) && (slpmsg->slpcall != NULL))
+	if ((slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) &&
+		(slpmsg->slpcall != NULL))
 	{
 		slpmsg->slpcall->progress = TRUE;
 
@@ -304,11 +331,11 @@
 		}
 	}
 
-	slpmsg->offset += len;
+	/* slpmsg->offset += len; */
 }
 
 void
-msn_slplink_release_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
+msn_slplink_release_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
 {
 	MsnMessage *msg;
 
@@ -350,6 +377,7 @@
 	msn_message_set_attr(msg, "P2P-Dest", slplink->remote_user);
 
 	msg->ack_cb = msg_ack;
+	msg->nak_cb = msg_nak;
 	msg->ack_data = slpmsg;
 
 	msn_slplink_send_msgpart(slplink, slpmsg);
@@ -370,7 +398,7 @@
 {
 	slpmsg->id = slplink->slp_seq_id++;
 
-	msn_slplink_release_msg(slplink, slpmsg);
+	msn_slplink_release_slpmsg(slplink, slpmsg);
 }
 
 void
@@ -381,7 +409,9 @@
 	/* Send the queued msgs in the order they came. */
 
 	while ((slpmsg = g_queue_pop_tail(slplink->slp_msg_queue)) != NULL)
-		msn_slplink_release_msg(slplink, slpmsg);
+	{
+		msn_slplink_release_slpmsg(slplink, slpmsg);
+	}
 }
 
 void
@@ -398,7 +428,7 @@
 	slpmsg->ack_sub_id = msg->msnslp_header.ack_id;
 	slpmsg->ack_size   = msg->msnslp_header.total_size;
 
-#ifdef DEBUG_SLP
+#ifdef MSN_DEBUG_SLP
 	slpmsg->info = "SLP ACK";
 #endif
 
@@ -413,12 +443,12 @@
 
 	slpcall = slpsession->slpcall;
 	slpmsg = msn_slpmsg_new(slpcall->slplink);
+	slpmsg->slpcall = slpcall;
 	slpmsg->flags = 0x1000030;
 	slpmsg->slpsession = slpsession;
-#ifdef DEBUG_SLP
+#ifdef MSN_DEBUG_SLP
 	slpmsg->info = "SLP FILE";
 #endif
-	slpmsg->slpcall = slpcall;
 	msn_slpmsg_open_file(slpmsg, gaim_xfer_get_local_filename(slpcall->xfer));
 
 	msn_slplink_send_slpmsg(slpcall->slplink, slpmsg);
@@ -432,11 +462,11 @@
 	gsize offset;
 	gsize len;
 
-#ifdef DEBUG_SLP
+#ifdef MSN_DEBUG_SLP
 	msn_slpmsg_show(msg);
 #endif
 
-#ifdef DEBUG_SLP_FILES
+#ifdef MSN_DEBUG_SLP_FILES
 	debug_msg_to_file(msg, FALSE);
 #endif
 
@@ -501,31 +531,31 @@
 		slpmsg = msn_slplink_message_find(slplink, msg->msnslp_header.session_id, msg->msnslp_header.id);
 	}
 
-	if (slpmsg != NULL)
+	if (slpmsg == NULL)
 	{
-		if (slpmsg->fp)
-		{
-			/* fseek(slpmsg->fp, offset, SEEK_SET); */
-			len = fwrite(data, 1, len, slpmsg->fp);
-		}
-		else if (slpmsg->size)
-		{
-			if ((offset + len) > slpmsg->size)
-			{
-				gaim_debug_error("msn", "Oversized slpmsg\n");
-				g_return_if_reached();
-			}
-			else
-				memcpy(slpmsg->buffer + offset, data, len);
-		}
-	}
-	else
-	{
+		/* Probably the transfer was canceled */
 		gaim_debug_error("msn", "Couldn't find slpmsg\n");
-		g_return_if_reached();
+		return;
 	}
 
-	if ((slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) && (slpmsg->slpcall != NULL))
+	if (slpmsg->fp)
+	{
+		/* fseek(slpmsg->fp, offset, SEEK_SET); */
+		len = fwrite(data, 1, len, slpmsg->fp);
+	}
+	else if (slpmsg->size)
+	{
+		if ((offset + len) > slpmsg->size)
+		{
+			gaim_debug_error("msn", "Oversized slpmsg\n");
+			g_return_if_reached();
+		}
+		else
+			memcpy(slpmsg->buffer + offset, data, len);
+	}
+
+	if ((slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) &&
+		(slpmsg->slpcall != NULL))
 	{
 		slpmsg->slpcall->progress = TRUE;
 
--- a/src/protocols/msn/slplink.h	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/slplink.h	Sat Dec 11 20:01:58 2004 +0000
@@ -31,11 +31,14 @@
 #include "slpcall.h"
 #include "slpmsg.h"
 
+#include "switchboard.h"
+
 #include "ft.h"
 
 struct _MsnSlpLink
 {
 	MsnSession *session;
+	MsnSwitchBoard *swboard;
 
 	char *local_user;
 	char *remote_user;
@@ -54,33 +57,33 @@
 MsnSlpLink *msn_slplink_new(MsnSession *session, const char *username);
 void msn_slplink_destroy(MsnSlpLink *slplink);
 MsnSlpLink *msn_session_find_slplink(MsnSession *session,
-									   const char *who);
+									 const char *who);
 MsnSlpLink *msn_session_get_slplink(MsnSession *session, const char *username);
 MsnSlpSession *msn_slplink_find_slp_session(MsnSlpLink *slplink,
-											  long session_id);
+											long session_id);
 MsnSlpCall *msn_slplink_find_slp_call(MsnSlpLink *slplink,
-									   const char *id);
+									  const char *id);
 MsnSlpCall *msn_slplink_find_slp_call_with_session_id(MsnSlpLink *slplink, long id);
 void msn_slplink_send_msg(MsnSlpLink *slplink, MsnMessage *msg);
-void msn_slplink_release_msg(MsnSlpLink *slplink,
-							  MsnSlpMessage *slpmsg);
+void msn_slplink_release_slpmsg(MsnSlpLink *slplink,
+								MsnSlpMessage *slpmsg);
 void msn_slplink_queue_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg);
 void msn_slplink_send_slpmsg(MsnSlpLink *slplink,
-							  MsnSlpMessage *slpmsg);
+							 MsnSlpMessage *slpmsg);
 void msn_slplink_unleash(MsnSlpLink *slplink);
 void msn_slplink_send_ack(MsnSlpLink *slplink, MsnMessage *msg);
 void msn_slplink_process_msg(MsnSlpLink *slplink, MsnMessage *msg);
 MsnSlpMessage *msn_slplink_message_find(MsnSlpLink *slplink, long session_id, long id);
 void msn_slplink_append_slp_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg);
 void msn_slplink_remove_slp_msg(MsnSlpLink *slplink,
-								 MsnSlpMessage *slpmsg);
+								MsnSlpMessage *slpmsg);
 void msn_slplink_request_ft(MsnSlpLink *slplink, GaimXfer *xfer);
 
 void msn_slplink_request_object(MsnSlpLink *slplink,
-								 const char *info,
-								 MsnSlpCb cb,
-								 MsnSlpEndCb end_cb,
-								 const MsnObject *obj);
+								const char *info,
+								MsnSlpCb cb,
+								MsnSlpEndCb end_cb,
+								const MsnObject *obj);
 
 MsnSlpCall *msn_slp_process_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg);
 
--- a/src/protocols/msn/slpmsg.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/slpmsg.c	Sat Dec 11 20:01:58 2004 +0000
@@ -33,8 +33,13 @@
 msn_slpmsg_new(MsnSlpLink *slplink)
 {
 	MsnSlpMessage *slpmsg;
+
 	slpmsg = g_new0(MsnSlpMessage, 1);
 
+#ifdef MSN_DEBUG_SLPMSG
+	gaim_debug_info("msn", "slpmsg new (%p)\n", slpmsg);
+#endif
+
 	slpmsg->slplink = slplink;
 
 	slplink->slp_msgs =
@@ -47,6 +52,13 @@
 msn_slpmsg_destroy(MsnSlpMessage *slpmsg)
 {
 	MsnSlpLink *slplink;
+	GList *cur;
+
+	g_return_if_fail(slpmsg != NULL);
+
+#ifdef MSN_DEBUG_SLPMSG
+	gaim_debug_info("msn", "slpmsg destroy (%p)\n", slpmsg);
+#endif
 
 	slplink = slpmsg->slplink;
 
@@ -56,42 +68,31 @@
 	if (slpmsg->buffer != NULL)
 		g_free(slpmsg->buffer);
 
-#ifdef DEBUG_SLP
+#ifdef MSN_DEBUG_SLP
 	/*
 	if (slpmsg->info != NULL)
 		g_free(slpmsg->info);
 	*/
 #endif
 
-	if (slpmsg->msg != NULL)
+	for (cur = slpmsg->msgs; cur != NULL; cur = cur->next)
 	{
 		/* Something is pointing to this slpmsg, so we should remove that
 		 * pointer to prevent a crash. */
 		/* Ex: a user goes offline and after that we receive an ACK */
 
-		gaim_debug_info("msn", "Unlink slpmsg callbacks.\n");
-
-		slpmsg->msg->ack_cb = NULL;
-		slpmsg->msg->ack_data = NULL;
-
-#if 0
-		MsnTransaction *trans;
-
-		trans = slpmsg->msg->trans;
+		MsnMessage *msg = cur->data;
 
-		if (trans != NULL)
-		{
-			if (trans->callbacks != NULL && trans->has_custom_callbacks)
-				g_hash_table_destroy(trans->callbacks);
-			
-			trans->callbacks = NULL;
-			trans->data = NULL;
-		}
+#ifdef MSN_DEBUG_SLPMSG
+		gaim_debug_info("msn", "Unlink slpmsg callbacks.\n");
 #endif
+
+		msg->ack_cb = NULL;
+		msg->nak_cb = NULL;
+		msg->ack_data = NULL;
 	}
 
-	slplink->slp_msgs =
-		g_list_remove(slplink->slp_msgs, slpmsg);
+	slplink->slp_msgs = g_list_remove(slplink->slp_msgs, slpmsg);
 
 	g_free(slpmsg);
 }
@@ -119,7 +120,7 @@
 		slpmsg->size = st.st_size;
 }
 
-#ifdef DEBUG_SLP
+#ifdef MSN_DEBUG_SLP
 const void
 msn_slpmsg_show(MsnMessage *msg)
 {
@@ -203,6 +204,7 @@
 	msn_slpmsg_set_body(slpmsg, body, body_len);
 
 	slpmsg->sip = TRUE;
+	slpmsg->slpcall = slpcall;
 
 	g_free(body);
 
--- a/src/protocols/msn/slpmsg.h	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/slpmsg.h	Sat Dec 11 20:01:58 2004 +0000
@@ -34,11 +34,15 @@
 
 #include "slp.h"
 
+/**
+ * A SLP Message  This contains everything that we will need to send a SLP
+ * Message even if has to be sent in several parts.
+ */
 struct _MsnSlpMessage
 {
 	MsnSlpSession *slpsession;
-	MsnSlpCall *slpcall;
-	MsnSlpLink *slplink;
+	MsnSlpCall *slpcall; /**< The slpcall to which this slp message belongs (if applicable). */
+	MsnSlpLink *slplink; /**< The slplink through which this slp message is being sent. */
 	MsnSession *session;
 
 	long session_id;
@@ -48,10 +52,8 @@
 	long long ack_size;
 	long app_id;
 
-	gboolean sip;
-#if 0
-	gboolean wasted;
-#endif
+	gboolean sip; /**< A flag that states if this is a SIP slp message. */
+	int ref_count; /**< The reference count. */
 	long flags;
 
 	FILE *fp;
@@ -59,16 +61,33 @@
 	long long offset;
 	long long size;
 
-	MsnMessage *msg; /* The temporary real message that will be sent */
+	GList *msgs; /**< The real messages. */
 
-#ifdef DEBUG_SLP
+#if 1
+	MsnMessage *msg; /**< The temporary real message that will be sent. */
+#endif
+
+#ifdef MSN_DEBUG_SLP
 	char *info;
 	gboolean text_body;
 #endif
 };
 
+/**
+ * Creates a new slp message
+ *
+ * @param slplink The slplink through which this slp message will be sent.
+ * @return The created slp message.
+ */
 MsnSlpMessage *msn_slpmsg_new(MsnSlpLink *slplink);
+
+/**
+ * Destroys a slp message
+ *
+ * @param slpmsg The slp message to destory.
+ */
 void msn_slpmsg_destroy(MsnSlpMessage *slpmsg);
+
 void msn_slpmsg_set_body(MsnSlpMessage *slpmsg, const char *body,
 						 long long size);
 void msn_slpmsg_open_file(MsnSlpMessage *slpmsg,
@@ -79,7 +98,7 @@
 								   const char *content_type,
 								   const char *content);
 
-#ifdef DEBUG_SLP
+#ifdef MSN_DEBUG_SLP
 const void msn_slpmsg_show(MsnMessage *msg);
 #endif
 
--- a/src/protocols/msn/switchboard.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/switchboard.c	Sat Dec 11 20:01:58 2004 +0000
@@ -31,7 +31,144 @@
 
 static MsnTable *cbs_table;
 
-static void cal_error(MsnCmdProc *cmdproc, MsnTransaction *trans, int error);
+static void msg_error_helper(MsnCmdProc *cmdproc, MsnMessage *msg,
+							 MsnMsgErrorType error);
+
+/**************************************************************************
+ * Main stuff
+ **************************************************************************/
+MsnSwitchBoard *
+msn_switchboard_new(MsnSession *session)
+{
+	MsnSwitchBoard *swboard;
+	MsnServConn *servconn;
+	MsnCmdProc *cmdproc;
+
+	g_return_val_if_fail(session != NULL, NULL);
+
+	swboard = g_new0(MsnSwitchBoard, 1);
+
+	swboard->session = session;
+	swboard->servconn = servconn = msn_servconn_new(session, MSN_SERVER_SB);
+	cmdproc = servconn->cmdproc;
+
+	swboard->im_queue = g_queue_new();
+	swboard->empty = TRUE;
+
+	servconn->data = swboard;
+
+	session->switches = g_list_append(session->switches, swboard);
+
+	cmdproc->cbs_table = cbs_table;
+
+	return swboard;
+}
+
+void
+msn_switchboard_destroy(MsnSwitchBoard *swboard)
+{
+	MsnSession *session;
+	MsnMessage *msg;
+	GList *l;
+
+	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)
+	{
+		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,
+							 MSN_MSG_ERROR_SB);
+		}
+		msn_message_destroy(msg);
+	}
+
+	g_queue_free(swboard->im_queue);
+
+	if (swboard->im_user != NULL)
+		g_free(swboard->im_user);
+
+	if (swboard->auth_key != NULL)
+		g_free(swboard->auth_key);
+
+	if (swboard->session_id != NULL)
+		g_free(swboard->session_id);
+
+	for (l = swboard->users; l != NULL; l = l->next)
+		g_free(l->data);
+
+	session = swboard->session;
+	session->switches = g_list_remove(session->switches, swboard);
+
+	if (swboard->servconn != NULL)
+		msn_servconn_destroy(swboard->servconn);
+
+	g_free(swboard);
+}
+
+void
+msn_switchboard_set_auth_key(MsnSwitchBoard *swboard, const char *key)
+{
+	g_return_if_fail(swboard != NULL);
+	g_return_if_fail(key != NULL);
+
+	swboard->auth_key = g_strdup(key);
+}
+
+const char *
+msn_switchboard_get_auth_key(MsnSwitchBoard *swboard)
+{
+	g_return_val_if_fail(swboard != NULL, NULL);
+
+	return swboard->auth_key;
+}
+
+void
+msn_switchboard_set_session_id(MsnSwitchBoard *swboard, const char *id)
+{
+	g_return_if_fail(swboard != NULL);
+	g_return_if_fail(id != NULL);
+
+	if (swboard->session_id != NULL)
+		g_free(swboard->session_id);
+
+	swboard->session_id = g_strdup(id);
+}
+
+const char *
+msn_switchboard_get_session_id(MsnSwitchBoard *swboard)
+{
+	g_return_val_if_fail(swboard != NULL, NULL);
+
+	return swboard->session_id;
+}
+
+void
+msn_switchboard_set_invited(MsnSwitchBoard *swboard, gboolean invited)
+{
+	g_return_if_fail(swboard != NULL);
+
+	swboard->invited = invited;
+}
+
+gboolean
+msn_switchboard_is_invited(MsnSwitchBoard *swboard)
+{
+	g_return_val_if_fail(swboard != NULL, FALSE);
+
+	return swboard->invited;
+}
 
 /**************************************************************************
  * Utility functions
@@ -68,9 +205,11 @@
 	/* gaim_debug_info("msn", "user=[%s], total=%d\n", user,
 	 * swboard->current_users); */
 
-	if ((swboard->conv != NULL) && (gaim_conversation_get_type(swboard->conv) == GAIM_CONV_CHAT))
+	if ((swboard->conv != NULL) &&
+		(gaim_conversation_get_type(swboard->conv) == GAIM_CONV_CHAT))
 	{
-		gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->conv), user, NULL, GAIM_CBFLAGS_NONE, TRUE);
+		gaim_conv_chat_add_user(GAIM_CONV_CHAT(swboard->conv), user, NULL,
+								GAIM_CBFLAGS_NONE, TRUE);
 	}
 	else if (swboard->current_users > 1 || swboard->total_users > 1)
 	{
@@ -127,18 +266,6 @@
 	}
 }
 
-/**************************************************************************
- * Switchboard Commands
- **************************************************************************/
-static void
-ans_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
-{
-	MsnSwitchBoard *swboard;
-
-	swboard = cmdproc->servconn->data;
-	swboard->ready = TRUE;
-}
-
 GaimConversation *
 msn_switchboard_get_conv(MsnSwitchBoard *swboard)
 {
@@ -149,6 +276,8 @@
 	if (swboard->conv != NULL)
 		return swboard->conv;
 
+	gaim_debug_error("msn", "Switchboard with unnasigned conversation\n");
+
 	account = swboard->session->account;
 
 	/* XXX - I think this should probably be GAIM_CONV_IM, but I'm hedging */
@@ -171,6 +300,126 @@
 }
 
 static void
+swboard_error_helper(MsnSwitchBoard *swboard, int reason, const char *passport)
+{
+	gaim_debug_info("msg", "Error: Unable to call the user %s\n", passport);
+
+	if (swboard->total_users == 0)
+	{
+		swboard->error = reason;
+		msn_switchboard_destroy(swboard);
+	}
+}
+
+static void
+cal_error_helper(MsnTransaction *trans, int reason)
+{
+	MsnSwitchBoard *swboard;
+	const char *passport;
+	char **params;
+
+	params = g_strsplit(trans->params, " ", 0);
+
+	passport = params[0];
+
+	swboard = trans->data;
+
+	swboard_error_helper(swboard, reason, passport);
+
+	g_strfreev(params);
+}
+
+static void
+msg_error_helper(MsnCmdProc *cmdproc, MsnMessage *msg, MsnMsgErrorType error)
+{
+	g_return_if_fail(cmdproc != NULL);
+	g_return_if_fail(msg     != NULL);
+
+	if (msg->nak_cb != NULL)
+		msg->nak_cb(msg, msg->ack_data);
+
+	if (msg->type == MSN_MSG_TEXT)
+	{
+		MsnSwitchBoard *swboard;
+		char *body;
+		char *report;
+		char *str_reason;
+
+		swboard = cmdproc->servconn->data;
+
+#if 0
+		if (swboard->conv == NULL)
+		{
+			msn_message_unref(msg);
+			return;
+		}
+#endif
+
+		if (msg->error == MSN_MSG_ERROR_TIMEOUT)
+		{
+			str_reason = _("Message may have not been sent "
+						   "because a time out occured.");
+		}
+		else if (msg->error == MSN_MSG_ERROR_SB)
+		{
+			switch (swboard->error)
+			{
+				case MSN_SB_ERROR_OFFLINE:
+					str_reason = _("Message could not be sent, "
+								   "not allowed while invisible");
+					break;
+				case MSN_SB_ERROR_USER_OFFLINE:
+					str_reason = _("Message could not be sent "
+								   "because the user is offline");
+					break;
+				case MSN_SB_ERROR_CONNECTION:
+					str_reason = _("Message could not be sent "
+								   "because a connection error occured");
+					break;
+				default:
+					str_reason = _("Message could not be sent "
+								   "because an error with "
+								   "the switchboard occured");
+					break;
+			}
+		}
+		else
+		{
+			str_reason = _("Message may have not been sent "
+						   "because an unkwown error occured");
+		}
+
+		body = msn_message_to_string(msg);
+		report = g_strdup_printf(_("%s:\n%s"), str_reason, body);
+
+		msn_switchboard_report_user(cmdproc->servconn->data,
+									GAIM_MESSAGE_ERROR, report);
+
+		g_free(report);
+		g_free(body);
+
+		msn_message_unref(msg);
+	}
+	else if (msg->type == MSN_MSG_SLP)
+	{
+		msn_message_unref(msg);
+	}
+
+}
+
+/**************************************************************************
+ * Switchboard Commands
+ **************************************************************************/
+static void
+ans_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
+{
+	MsnSwitchBoard *swboard;
+
+	swboard = cmdproc->servconn->data;
+	swboard->ready = TRUE;
+}
+
+static void
 bye_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnSwitchBoard *swboard;
@@ -179,15 +428,20 @@
 	swboard = cmdproc->servconn->data;
 	user = cmd->params[0];
 
-	if (swboard->hidden)
-		return;
-
-	if (swboard->current_users > 1)
+	if (swboard->conv == NULL)
 	{
+		/* This is a helper switchboard */
+		msn_switchboard_disconnect(swboard);
+	}
+	else if (swboard->current_users > 1)
+	{
+		/* This is a switchboard used for a chat */
 		gaim_conv_chat_remove_user(GAIM_CONV_CHAT(swboard->conv), user, NULL);
 	}
 	else
 	{
+		/* This is a switchboard used for a im session */
+
 		char *str = NULL;
 
 		if (cmd->param_count == 2 && atoi(cmd->params[1]) == 1)
@@ -261,9 +515,7 @@
 
 	msn_switchboard_add_user(swboard, passport);
 
-	swboard->user_joined = TRUE;
-
-	/* msn_cmdproc_process_queue(cmdproc); */
+	swboard->empty = FALSE;
 
 	msn_switchboard_process_queue(swboard);
 
@@ -299,28 +551,25 @@
 static void
 nak_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
-	/*
-	gaim_notify_error(cmdproc->session->account->gc, NULL,
-					  _("A MSN message may not have been received."), NULL);
-	 */
+	MsnMessage *msg;
+
+	msg = cmd->trans->data;
+	g_return_if_fail(msg != NULL);
+
+	msg_error_helper(cmdproc, msg, MSN_MSG_ERROR_NAK);
 }
 
 static void
 ack_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
-#if 0
 	MsnMessage *msg;
-	const char *body;
 
-	msg = msn_message_new();
-	msn_message_parse_payload(msg, cmd->trans->payload, cmd->trans->payload_len);
+	msg = cmd->trans->data;
 
-	body = msn_message_get_body(msg);
+	if (msg->ack_cb != NULL)
+		msg->ack_cb(msg, msg->ack_data);
 
-	gaim_debug_info("msn", "ACK: {%s}\n", body);
-
-	msn_message_destroy(msg);
-#endif
+	msn_message_unref(msg);
 }
 
 static void
@@ -362,7 +611,7 @@
 }
 
 /**************************************************************************
- * Message Types
+ * Message Handlers
  **************************************************************************/
 static void
 plain_msg(MsnCmdProc *cmdproc, MsnMessage *msg)
@@ -467,63 +716,31 @@
 #endif
 }
 
-static void
-msg_error_helper(MsnCmdProc *cmdproc, MsnMessage *msg)
-{
-	if (msg->type == MSN_MSG_TEXT)
-	{
-		MsnSwitchBoard *swboard;
-		char *body;
-		char *report;
-		char *str_reason;
-
-		swboard = cmdproc->servconn->data;
-
-		switch (swboard->error)
-		{
-			case MSN_SB_ERROR_OFFLINE:
-				str_reason = _("Message could not be sent, not allowed while invisible");
-				break;
-			case MSN_SB_ERROR_USER_OFFLINE:
-				str_reason = _("Message could not be sent because the user is offline");
-				break;
-			case MSN_SB_ERROR_CONNECTION:
-				str_reason = _("Message could not be sent because a connection error occured");
-				break;
-			default:
-				str_reason = _("Message could not be sent for an unknown reason");
-				break;
-		}
-
-		body = msn_message_to_string(msg);
-		report = g_strdup_printf(_("%s:\n%s"), str_reason, body);
-		gaim_debug_info("msn", "%s\n", report);
-		msn_switchboard_report_user(cmdproc->servconn->data, GAIM_MESSAGE_ERROR, report);
-		g_free(report);
-		g_free(body);
-	}
-}
-
+/**************************************************************************
+ * Message stuff
+ **************************************************************************/
+/** Called when a message times out. */
 static void
 msg_timeout(MsnCmdProc *cmdproc, MsnTransaction *trans)
 {
 	MsnMessage *msg;
 
 	msg = trans->data;
-	g_return_if_fail(msg != NULL);
 
-	gaim_debug_info("msn", "msg_timeout\n");
-	msg_error_helper(cmdproc, msg);
+	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);
+	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)
+msg_ack(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
 	MsnMessage *msg;
 
@@ -535,6 +752,18 @@
 	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)
 {
@@ -557,15 +786,24 @@
 
 	/* Data for callbacks */
 	msn_transaction_set_data(trans, msg);
-	msn_message_ref(msg);
 
-	if (msg->ack_cb != NULL)
+	if (msg->type == MSN_MSG_TEXT)
 	{
-		msn_transaction_add_cb(trans, "ACK", msg_ack);
+		msn_message_ref(msg);
 		msn_transaction_set_timeout_cb(trans, msg_timeout);
 	}
-	else if (msg->type == MSN_MSG_TEXT)
+	else if (msg->type == MSN_MSG_SLP)
+	{
+		msn_message_ref(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;
@@ -624,7 +862,7 @@
 	swboard = servconn->data;
 	g_return_if_fail(swboard != NULL);
 
-	swboard->user_joined = TRUE;
+	swboard->empty = FALSE;
 
 	if (msn_switchboard_is_invited(swboard))
 	{
@@ -651,138 +889,29 @@
 	msn_switchboard_destroy(swboard);
 }
 
-void
-msn_switchboard_init(void)
+gboolean
+msn_switchboard_connect(MsnSwitchBoard *swboard, const char *host, int port)
 {
-	cbs_table = msn_table_new();
-
-	msn_table_add_cmd(cbs_table, "ANS", "ANS", ans_cmd);
-	msn_table_add_cmd(cbs_table, "ANS", "IRO", iro_cmd);
-
-	msn_table_add_cmd(cbs_table, "MSG", "ACK", ack_cmd);
-	msn_table_add_cmd(cbs_table, "MSG", "NAK", nak_cmd);
-
-	msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd);
-
-	msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd);
-	msn_table_add_cmd(cbs_table, NULL, "JOI", joi_cmd);
-	msn_table_add_cmd(cbs_table, NULL, "BYE", bye_cmd);
-	msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd);
+	g_return_val_if_fail(swboard != NULL, FALSE);
 
-#if 0
-	/* They might skip the history */
-	msn_table_add_cmd(cbs_table, NULL, "ACK", NULL);
-#endif
-
-	msn_table_add_error(cbs_table, "MSG", msg_error);
-	msn_table_add_error(cbs_table, "CAL", cal_error);
+	msn_servconn_set_connect_cb(swboard->servconn, connect_cb);
 
-	/* Register the message type callbacks. */
-	msn_table_add_msg_type(cbs_table, "text/plain",
-						   plain_msg);
-	msn_table_add_msg_type(cbs_table, "text/x-msmsgscontrol",
-						   control_msg);
-	msn_table_add_msg_type(cbs_table, "text/x-clientcaps",
-						   clientcaps_msg);
-	msn_table_add_msg_type(cbs_table, "text/x-clientinfo",
-						   clientcaps_msg);
-	msn_table_add_msg_type(cbs_table, "application/x-msnmsgrp2p",
-						   msn_p2p_msg);
-	msn_table_add_msg_type(cbs_table, "text/x-mms-emoticon",
-						   msn_emoticon_msg);
-#if 0
-	msn_table_add_msg_type(cbs_table, "text/x-msmmsginvite",
-						   msn_invite_msg);
-#endif
+	return msn_servconn_connect(swboard->servconn, host, port);
 }
 
 void
-msn_switchboard_end(void)
-{
-	msn_table_destroy(cbs_table);
-}
-
-MsnSwitchBoard *
-msn_switchboard_new(MsnSession *session)
+msn_switchboard_disconnect(MsnSwitchBoard *swboard)
 {
-	MsnSwitchBoard *swboard;
-	MsnServConn *servconn;
-	MsnCmdProc *cmdproc;
-
-	g_return_val_if_fail(session != NULL, NULL);
-
-	swboard = g_new0(MsnSwitchBoard, 1);
+	g_return_if_fail(swboard != NULL);
 
-	swboard->session = session;
-	swboard->servconn = servconn = msn_servconn_new(session, MSN_SERVER_SB);
-	cmdproc = servconn->cmdproc;
-
-	swboard->im_queue = g_queue_new();
+	msn_servconn_set_disconnect_cb(swboard->servconn, disconnect_cb);
 
-	if (session->http_method)
-		servconn->http_data->server_type = "SB";
-	else
-		msn_servconn_set_connect_cb(servconn, connect_cb);
-
-	msn_servconn_set_disconnect_cb(servconn, disconnect_cb);
-
-	servconn->data = swboard;
-
-	session->switches = g_list_append(session->switches, swboard);
-
-	cmdproc->cbs_table = cbs_table;
-
-	return swboard;
+	msn_servconn_disconnect(swboard->servconn);
 }
 
-void
-msn_switchboard_destroy(MsnSwitchBoard *swboard)
-{
-	MsnSession *session;
-	MsnMessage *msg;
-	GList *l;
-
-	g_return_if_fail(swboard != NULL);
-
-	if (swboard->destroying)
-		return;
-
-	swboard->destroying = TRUE;
-
-	/* Destroy the message queue */
-	while ((msg = g_queue_pop_head(swboard->im_queue)) != NULL)
-	{
-		if (swboard->error > 0)
-		{
-			/* The messages could not be sent due to an error */
-			msg_error_helper(swboard->servconn->cmdproc, msg);
-		}
-		msn_message_destroy(msg);
-	}
-
-	g_queue_free(swboard->im_queue);
-
-	if (swboard->im_user != NULL)
-		g_free(swboard->im_user);
-
-	if (swboard->auth_key != NULL)
-		g_free(swboard->auth_key);
-
-	if (swboard->session_id != NULL)
-		g_free(swboard->session_id);
-
-	for (l = swboard->users; l != NULL; l = l->next)
-		g_free(l->data);
-
-	session = swboard->session;
-	session->switches = g_list_remove(session->switches, swboard);
-
-	if (swboard->servconn != NULL)
-		msn_servconn_destroy(swboard->servconn);
-
-	g_free(swboard);
-}
-
+/**************************************************************************
+ * Call stuff
+ **************************************************************************/
 #if 0
 static void
 got_cal(MsnCmdProc *cmdproc, MsnCommand *cmd)
@@ -799,36 +928,6 @@
 #endif
 
 static void
-swboard_error_helper(MsnSwitchBoard *swboard, int reason, const char *passport)
-{
-	gaim_debug_info("msg", "Error: Unable to call the user %s\n", passport);
-
-	if (swboard->total_users == 0)
-	{
-		swboard->error = reason;
-		msn_switchboard_destroy(swboard);
-	}
-}
-
-static void
-cal_error_helper(MsnTransaction *trans, int reason)
-{
-	MsnSwitchBoard *swboard;
-	const char *passport;
-	char **params;
-
-	params = g_strsplit(trans->params, " ", 0);
-
-	passport = params[0];
-
-	swboard = trans->data;
-
-	swboard_error_helper(swboard, reason, passport);
-
-	g_strfreev(params);
-}
-
-static void
 cal_timeout(MsnCmdProc *cmdproc, MsnTransaction *trans)
 {
 	cal_error_helper(trans, MSN_SB_ERROR_UNKNOWN);
@@ -867,75 +966,9 @@
 		msn_cmdproc_queue_trans(cmdproc, trans);
 }
 
-void
-msn_switchboard_set_auth_key(MsnSwitchBoard *swboard, const char *key)
-{
-	g_return_if_fail(swboard != NULL);
-	g_return_if_fail(key != NULL);
-
-	swboard->auth_key = g_strdup(key);
-}
-
-const char *
-msn_switchboard_get_auth_key(MsnSwitchBoard *swboard)
-{
-	g_return_val_if_fail(swboard != NULL, NULL);
-
-	return swboard->auth_key;
-}
-
-void
-msn_switchboard_set_session_id(MsnSwitchBoard *swboard, const char *id)
-{
-	g_return_if_fail(swboard != NULL);
-	g_return_if_fail(id != NULL);
-
-	if (swboard->session_id != NULL)
-		g_free(swboard->session_id);
-
-	swboard->session_id = g_strdup(id);
-}
-
-const char *
-msn_switchboard_get_session_id(MsnSwitchBoard *swboard)
-{
-	g_return_val_if_fail(swboard != NULL, NULL);
-
-	return swboard->session_id;
-}
-
-void
-msn_switchboard_set_invited(MsnSwitchBoard *swboard, gboolean invited)
-{
-	g_return_if_fail(swboard != NULL);
-
-	swboard->invited = invited;
-}
-
-gboolean
-msn_switchboard_is_invited(MsnSwitchBoard *swboard)
-{
-	g_return_val_if_fail(swboard != NULL, FALSE);
-
-	return swboard->invited;
-}
-
-gboolean
-msn_switchboard_connect(MsnSwitchBoard *swboard, const char *host, int port)
-{
-	g_return_val_if_fail(swboard != NULL, FALSE);
-
-	return msn_servconn_connect(swboard->servconn, host, port);
-}
-
-void
-msn_switchboard_disconnect(MsnSwitchBoard *swboard)
-{
-	g_return_if_fail(swboard != NULL);
-
-	msn_servconn_disconnect(swboard->servconn);
-}
-
+/**************************************************************************
+ * Create & Transfer stuff
+ **************************************************************************/
 static void
 got_swboard(MsnCmdProc *cmdproc, MsnCommand *cmd)
 {
@@ -960,7 +993,7 @@
 		servconn = swboard->servconn;
 		account = session->account;
 
-		swboard->user_joined = TRUE;
+		swboard->empty = FALSE;
 
 		servconn->http_data->gateway_host = g_strdup(host);
 
@@ -1019,3 +1052,57 @@
 
 	msn_cmdproc_send_trans(cmdproc, trans);
 }
+
+/**************************************************************************
+ * Init stuff
+ **************************************************************************/
+void
+msn_switchboard_init(void)
+{
+	cbs_table = msn_table_new();
+
+	msn_table_add_cmd(cbs_table, "ANS", "ANS", ans_cmd);
+	msn_table_add_cmd(cbs_table, "ANS", "IRO", iro_cmd);
+
+	msn_table_add_cmd(cbs_table, "MSG", "ACK", ack_cmd);
+	msn_table_add_cmd(cbs_table, "MSG", "NAK", nak_cmd);
+
+	msn_table_add_cmd(cbs_table, "USR", "USR", usr_cmd);
+
+	msn_table_add_cmd(cbs_table, NULL, "MSG", msg_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "JOI", joi_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "BYE", bye_cmd);
+	msn_table_add_cmd(cbs_table, NULL, "OUT", out_cmd);
+
+#if 0
+	/* They might skip the history */
+	msn_table_add_cmd(cbs_table, NULL, "ACK", NULL);
+#endif
+
+	msn_table_add_error(cbs_table, "MSG", msg_error);
+	msn_table_add_error(cbs_table, "CAL", cal_error);
+
+	/* Register the message type callbacks. */
+	msn_table_add_msg_type(cbs_table, "text/plain",
+						   plain_msg);
+	msn_table_add_msg_type(cbs_table, "text/x-msmsgscontrol",
+						   control_msg);
+	msn_table_add_msg_type(cbs_table, "text/x-clientcaps",
+						   clientcaps_msg);
+	msn_table_add_msg_type(cbs_table, "text/x-clientinfo",
+						   clientcaps_msg);
+	msn_table_add_msg_type(cbs_table, "application/x-msnmsgrp2p",
+						   msn_p2p_msg);
+	msn_table_add_msg_type(cbs_table, "text/x-mms-emoticon",
+						   msn_emoticon_msg);
+#if 0
+	msn_table_add_msg_type(cbs_table, "text/x-msmmsginvite",
+						   msn_invite_msg);
+#endif
+}
+
+void
+msn_switchboard_end(void)
+{
+	msn_table_destroy(cbs_table);
+}
--- a/src/protocols/msn/switchboard.h	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/switchboard.h	Sat Dec 11 20:01:58 2004 +0000
@@ -33,17 +33,26 @@
 
 #include "servconn.h"
 
+#include "slplink.h"
+
+/*
+ * A switchboard error
+ */
 typedef enum
 {
-	MSN_SB_ERROR_NONE,
-	MSN_SB_ERROR_CAL, /* The user could not join (answer the call) */
-	MSN_SB_ERROR_OFFLINE, /* The account is offline */
-	MSN_SB_ERROR_USER_OFFLINE, /* The user to call is offline */
-	MSN_SB_ERROR_CONNECTION, /* There was a connection error */
-	MSN_SB_ERROR_UNKNOWN
+	MSN_SB_ERROR_NONE, /**< No error */
+	MSN_SB_ERROR_CAL, /**< The user could not join (answer the call) */
+	MSN_SB_ERROR_OFFLINE, /**< The account is offline */
+	MSN_SB_ERROR_USER_OFFLINE, /**< The user to call is offline */
+	MSN_SB_ERROR_CONNECTION, /**< There was a connection error */
+	MSN_SB_ERROR_UNKNOWN /**< An unknown error occured */
 
 } MsnSBErrorType;
 
+/*
+ * A switchboard  A place where a bunch of users send messages to the rest
+ * of the users.
+ */
 struct _MsnSwitchBoard
 {
 	MsnSession *session;
@@ -53,13 +62,18 @@
 	char *auth_key;
 	char *session_id;
 
-	gboolean invited;
-	gboolean destroying;
+	GaimConversation *conv; /**< The conversation that displays the
+							  messages of this switchboard, or @c NULL if
+							  this is a helper switchboard. */
 
-	GaimConversation *conv;
-
-	gboolean ready; /* When it's actually usable */
-	/* gboolean in_use; */
+	gboolean empty;      /**< A flag that states if the swithcboard has no
+						   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 his switchboard is
+						   ready to be used. */
 
 	int current_users;
 	int total_users;
@@ -67,12 +81,11 @@
 
 	int chat_id;
 
-	gboolean hidden;
-
-	gboolean user_joined;
 	GQueue *im_queue;
 
-	int error;
+	MsnSBErrorType error; /**< The error that occured in this switchboard
+							(if applicable). */
+	MsnSlpLink *slplink; /**< The slplink that is using this switchboard. */
 };
 
 /**
@@ -101,25 +114,6 @@
  */
 void msn_switchboard_destroy(MsnSwitchBoard *swboard);
 
-#if 0
-/**
- * Sets the user the switchboard is supposed to connect to.
- *
- * @param swboard The switchboard.
- * @param user    The user.
- */
-void msn_switchboard_set_user(MsnSwitchBoard *swboard, const char *user);
-
-/**
- * Returns the user the switchboard is supposed to connect to.
- *
- * @param swboard The switchboard.
- *
- * @return The user.
- */
-const char *msn_switchboard_get_user(MsnSwitchBoard *swboard);
-#endif
-
 /**
  * Sets the auth key the switchboard must use when connecting.
  *
@@ -155,7 +149,7 @@
 const char *msn_switchboard_get_session_id(MsnSwitchBoard *swboard);
 
 /**
- * Sets whether or not the user was invited to this switchboard.
+ * Sets whether or not we were invited to this switchboard.
  *
  * @param swboard The switchboard.
  * @param invite  @c TRUE if invited, @c FALSE otherwise.
@@ -163,7 +157,7 @@
 void msn_switchboard_set_invited(MsnSwitchBoard *swboard, gboolean invited);
 
 /**
- * Returns whether or not the user was invited to this switchboard.
+ * Returns whether or not we were invited to this switchboard.
  *
  * @param swboard The switchboard.
  *
@@ -182,16 +176,23 @@
  */
 gboolean msn_switchboard_connect(MsnSwitchBoard *swboard,
 								 const char *host, int port);
+
+/**
+ * Disconnects from a switchboard.
+ *
+ * @param swboard The switchboard to disconnect from.
+ */
 void msn_switchboard_disconnect(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);
 
 gboolean msn_switchboard_chat_leave(MsnSwitchBoard *swboard);
 gboolean msn_switchboard_chat_invite(MsnSwitchBoard *swboard, const char *who);
 
 void msn_switchboard_request(MsnSwitchBoard *swboard);
 void msn_switchboard_request_add_user(MsnSwitchBoard *swboard, const char *user);
-void msn_switchboard_queue_msg(MsnSwitchBoard *swboard, MsnMessage *msg);
-void msn_switchboard_process_queue(MsnSwitchBoard *swboard);
 
 /**
  * Processes application/x-msnmsgrp2p messages.
--- a/src/protocols/msn/table.c	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/table.c	Sat Dec 11 20:01:58 2004 +0000
@@ -117,7 +117,7 @@
 
 void
 msn_table_add_msg_type(MsnTable *table,
-					   char *type, MsnMsgCb cb)
+					   char *type, MsnMsgTypeCb cb)
 {
 	g_return_if_fail(table != NULL);
 	g_return_if_fail(type  != NULL);
--- a/src/protocols/msn/table.h	Sat Dec 11 00:06:06 2004 +0000
+++ b/src/protocols/msn/table.h	Sat Dec 11 20:01:58 2004 +0000
@@ -30,7 +30,7 @@
 #include "transaction.h"
 #include "msg.h"
 
-typedef void (*MsnMsgCb)(MsnCmdProc *cmdproc, MsnMessage *msg);
+typedef void (*MsnMsgTypeCb)(MsnCmdProc *cmdproc, MsnMessage *msg);
 
 struct _MsnTable
 {
@@ -48,6 +48,6 @@
 void msn_table_add_cmd(MsnTable *table, char *command, char *answer,
 					   MsnTransCb cb);
 void msn_table_add_error(MsnTable *table, char *answer, MsnErrorCb cb);
-void msn_table_add_msg_type(MsnTable *table, char *type, MsnMsgCb cb);
+void msn_table_add_msg_type(MsnTable *table, char *type, MsnMsgTypeCb cb);
 
 #endif /* _MSN_TABLE_H_ */