changeset 20812:88aa557b997f

propagate from branch 'im.pidgin.pidgin' (head 017296ee954fb91349806c809983c916842603da) to branch 'im.pidgin.cpw.resiak.disconnectreason' (head 8648cc67b0f11cdb0c5d48a703bca11b56606a16)
author Will Thompson <will.thompson@collabora.co.uk>
date Sun, 07 Oct 2007 10:28:32 +0000
parents 368d79355aba (current diff) 682543aced31 (diff)
children 66e7b104b4ea
files libpurple/connection.h libpurple/protocols/irc/msgs.c libpurple/protocols/irc/parse.c
diffstat 33 files changed, 647 insertions(+), 224 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/connection.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/connection.c	Sun Oct 07 10:28:32 2007 +0000
@@ -488,29 +488,101 @@
 void
 purple_connection_error(PurpleConnection *gc, const char *text)
 {
+	purple_connection_error_reason (gc, PURPLE_REASON_OTHER_ERROR, text);
+}
+
+void
+purple_connection_error_reason (PurpleConnection *gc,
+                                PurpleDisconnectReason reason,
+                                const char *description)
+{
 	PurpleConnectionUiOps *ops;
+	gboolean fatal;
 
 	g_return_if_fail(gc   != NULL);
 
-	if (text == NULL) {
-		purple_debug_error("connection", "purple_connection_error: check `text != NULL' failed\n");
-		text = _("Unknown error");
+	if (description == NULL) {
+		purple_debug_error("connection", "purple_connection_error_reason: check `description != NULL' failed\n");
+		description = _("Unknown error");
 	}
 
+	g_assert (reason < PURPLE_NUM_REASONS);
+
+	/* This should probably be removed at some point */
+	fatal = purple_connection_reason_is_fatal (reason);
+	if (fatal != gc->wants_to_die)
+		purple_debug_warning ("connection",
+			"reason %u is %sfatal but wants_to_die is %u",
+			reason, (fatal ? "" : "not "), gc->wants_to_die);
+
 	/* If we've already got one error, we don't need any more */
 	if (gc->disconnect_timeout)
 		return;
 
 	ops = purple_connections_get_ui_ops();
 
-	if (ops != NULL && ops->report_disconnect != NULL)
-		ops->report_disconnect(gc, text);
+	if (ops != NULL)
+	{
+		if (ops->report_disconnect_reason != NULL)
+			ops->report_disconnect_reason (gc, reason, description);
+		if (ops->report_disconnect != NULL)
+			ops->report_disconnect (gc, description);
+	}
 
 	gc->disconnect_timeout = purple_timeout_add(0, purple_connection_disconnect_cb,
 			purple_connection_get_account(gc));
 }
 
 void
+purple_connection_ssl_error (PurpleConnection *gc,
+                             PurpleSslErrorType ssl_error)
+{
+	PurpleDisconnectReason reason;
+
+	switch (ssl_error) {
+		case PURPLE_SSL_HANDSHAKE_FAILED:
+		case PURPLE_SSL_CONNECT_FAILED:
+			reason = PURPLE_REASON_ENCRYPTION_ERROR;
+			break;
+		case PURPLE_SSL_CERTIFICATE_INVALID:
+			/* TODO: maybe PURPLE_SSL_* should be more specific? */
+			reason = PURPLE_REASON_CERT_OTHER_ERROR;
+			break;
+		default:
+			g_assert_not_reached ();
+			reason = PURPLE_REASON_ENCRYPTION_ERROR;
+	}
+
+	purple_connection_error_reason (gc, reason, purple_ssl_strerror(ssl_error));
+}
+
+gboolean
+purple_connection_reason_is_fatal (PurpleDisconnectReason reason)
+{
+	switch (reason)
+	{
+		case PURPLE_REASON_NETWORK_ERROR:
+		case PURPLE_REASON_AUTHENTICATION_IMPOSSIBLE:
+		case PURPLE_REASON_CERT_NOT_PROVIDED:
+		case PURPLE_REASON_CERT_UNTRUSTED:
+		case PURPLE_REASON_CERT_EXPIRED:
+		case PURPLE_REASON_CERT_NOT_ACTIVATED:
+		case PURPLE_REASON_CERT_HOSTNAME_MISMATCH:
+		case PURPLE_REASON_CERT_FINGERPRINT_MISMATCH:
+		case PURPLE_REASON_CERT_SELF_SIGNED:
+		case PURPLE_REASON_CERT_OTHER_ERROR:
+			return FALSE;
+		case PURPLE_REASON_AUTHENTICATION_FAILED:
+		case PURPLE_REASON_NO_SSL_SUPPORT:
+		case PURPLE_REASON_ENCRYPTION_ERROR:
+		case PURPLE_REASON_NAME_IN_USE:
+		case PURPLE_REASON_INVALID_SETTINGS:
+		case PURPLE_REASON_OTHER_ERROR:
+			return TRUE;
+	}
+}
+
+void
 purple_connections_disconnect_all(void)
 {
 	GList *l;
--- a/libpurple/connection.h	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/connection.h	Sun Oct 07 10:28:32 2007 +0000
@@ -54,11 +54,82 @@
 
 } PurpleConnectionState;
 
+/** Possible errors that can cause a connection to be closed. */
+typedef enum
+{
+	/** There was an error sending or receiving on the network socket, or
+	 *  there was some protocol error (such as the server sending malformed
+	 *  data).
+	 */
+	PURPLE_REASON_NETWORK_ERROR = 0,
+	/** The username or password (or some other credential) was incorrect.
+	 */
+	PURPLE_REASON_AUTHENTICATION_FAILED,
+	/** libpurple doesn't speak any of the authentication methods the
+	 *  server offered.
+	 */
+	PURPLE_REASON_AUTHENTICATION_IMPOSSIBLE,
+	/** libpurple was built without SSL support, and the connection needs
+	 *  SSL.
+	 */
+	PURPLE_REASON_NO_SSL_SUPPORT,
+	/** There was an error negotiating SSL on this connection, or the
+	 *  server does not support encryption but an account option was set to
+	 *  require it.
+	 */
+	PURPLE_REASON_ENCRYPTION_ERROR,
+	/** Someone is already connected to the server using the name you are
+	 *  trying to connect with.
+	 */
+	PURPLE_REASON_NAME_IN_USE,
+
+	/** The username/server/other preference for the account isn't valid.
+	 *  For instance, on IRC the screen name cannot contain white space.
+	 *  This reason should not be used for incorrect passwords etc: use
+	 *  #PURPLE_REASON_AUTHENTICATION_FAILED for that.
+	 *
+	 *  @todo This reason really shouldn't be necessary.  Usernames and
+	 *        other account preferences should be validated when the
+	 *        account is created.
+	 */
+	PURPLE_REASON_INVALID_SETTINGS,
+
+	/** The server did not provide a SSL certificate. */
+	PURPLE_REASON_CERT_NOT_PROVIDED,
+	/** The server's SSL certificate could not be trusted. */
+	PURPLE_REASON_CERT_UNTRUSTED,
+	/** The server's SSL certificate has expired. */
+	PURPLE_REASON_CERT_EXPIRED,
+	/** The server's SSL certificate is not yet valid. */
+	PURPLE_REASON_CERT_NOT_ACTIVATED,
+	/** The server's SSL certificate did not match its hostname. */
+	PURPLE_REASON_CERT_HOSTNAME_MISMATCH,
+	/** The server's SSL certificate does not have the expected
+	 *  fingerprint.
+	 */
+	PURPLE_REASON_CERT_FINGERPRINT_MISMATCH,
+	/** The server's SSL certificate is self-signed.  */
+	PURPLE_REASON_CERT_SELF_SIGNED,
+	/** There was some other error validating the server's SSL certificate.
+	 */
+	PURPLE_REASON_CERT_OTHER_ERROR,
+
+	/** Some other error occured which fits into none of the other
+	 *  categories.
+	 */
+	PURPLE_REASON_OTHER_ERROR,
+
+	/** The number of PurpleDisconnectReason elements; not a valid reason.
+	 */
+	PURPLE_NUM_REASONS
+} PurpleDisconnectReason;
+
 #include <time.h>
 
 #include "account.h"
 #include "plugin.h"
 #include "status.h"
+#include "sslconn.h"
 
 /** Connection UI operations.  Used to notify the user of changes to
  *  connections, such as being disconnected, and to respond to the
@@ -73,11 +144,13 @@
 	 *  the UI of what is happening, as well as which @a step out of @a
 	 *  step_count has been reached (which might be displayed as a progress
 	 *  bar).
+	 *  @see #purple_connection_update_progress
 	 */
 	void (*connect_progress)(PurpleConnection *gc,
 	                         const char *text,
 	                         size_t step,
 	                         size_t step_count);
+
 	/** Called when a connection is established (just before the
 	 *  @ref signed-on signal).
 	 */
@@ -86,17 +159,23 @@
 	 *  and @ref signed-off signals).
 	 */
 	void (*disconnected)(PurpleConnection *gc);
+
 	/** Used to display connection-specific notices.  (Pidgin's Gtk user
 	 *  interface implements this as a no-op; #purple_connection_notice(),
 	 *  which uses this operation, is not used by any of the protocols
 	 *  shipped with libpurple.)
 	 */
 	void (*notice)(PurpleConnection *gc, const char *text);
+
 	/** Called when an error causes a connection to be disconnected.
 	 *  Called before #disconnected.
 	 *  @param text  a localized error message.
+	 *  @see #purple_connection_error
+	 *  @deprecated in favour of
+	 *              #PurpleConnectionUiOps.report_disconnect_reason.
 	 */
 	void (*report_disconnect)(PurpleConnection *gc, const char *text);
+
 	/** Called when libpurple discovers that the computer's network
 	 *  connection is active.  On Linux, this uses Network Manager if
 	 *  available; on Windows, it uses Win32's network change notification
@@ -108,10 +187,21 @@
 	 */
 	void (*network_disconnected)();
 
+	/** Called when a connection is disconnected, whether due to an
+	 *  error or to user request.  Called before #disconnected.
+	 *  @param reason  why the connection ended, if known, or
+	 *                 PURPLE_REASON_OTHER_ERROR, if not.
+	 *  @param text  a localized message describing the disconnection
+	 *               in more detail to the user.
+	 *  @see #purple_connection_error_reason
+	 */
+	void (*report_disconnect_reason)(PurpleConnection *gc,
+	                                 PurpleDisconnectReason reason,
+	                                 const char *text);
+
 	void (*_purple_reserved1)(void);
 	void (*_purple_reserved2)(void);
 	void (*_purple_reserved3)(void);
-	void (*_purple_reserved4)(void);
 } PurpleConnectionUiOps;
 
 struct _PurpleConnection
@@ -289,9 +379,53 @@
  *
  * @param gc     The connection.
  * @param reason The error text.
+ * @deprecated in favour of #purple_connection_error_reason.  Calling
+ *  @c purple_connection_error(gc, text) is equivalent to calling
+ *  @c purple_connection_error_reason(gc, PURPLE_REASON_OTHER_ERROR, text).
  */
 void purple_connection_error(PurpleConnection *gc, const char *reason);
 
+/**
+ * Closes a connection with an error and an optional description of the
+ * error.
+ *
+ * @param reason      why the connection is closing.
+ * @param description a localized description of the error.
+ */
+void
+purple_connection_error_reason (PurpleConnection *gc,
+                                PurpleDisconnectReason reason,
+                                const char *description);
+
+/**
+ * Closes a connection due to an SSL error; this is basically a shortcut to
+ * turning the #PurpleSslErrorType into a #PurpleDisconnectReason and a
+ * human-readable string and then calling purple_connection_error_reason().
+ */
+void
+purple_connection_ssl_error (PurpleConnection *gc,
+                             PurpleSslErrorType ssl_error);
+
+/**
+ * Reports whether a disconnection reason is fatal (in which case the account
+ * should probably not be automatically reconnected) or transient (so
+ * auto-reconnection is a good idea.
+ * For instance, #PURPLE_REASON_NETWORK_ERROR is a temporary
+ * error, which might be caused by losing the network connection, so
+ * @a purple_connection_reason_is_fatal(PURPLE_REASON_NETWORK_ERROR) is
+ * @a FALSE.  On the other hand, #PURPLE_REASON_AUTHENTICATION_FAILED probably
+ * indicates a misconfiguration of the account which needs the user to go fix
+ * it up, so @a
+ * purple_connection_reason_is_fatal(PURPLE_REASON_AUTHENTICATION_FAILED)
+ * is @a TRUE.
+ *
+ * (This function is meant to replace checking PurpleConnection.wants_to_die.)
+ *
+ * @return @a TRUE iff automatic reconnection is a bad idea.
+ */
+gboolean
+purple_connection_reason_is_fatal (PurpleDisconnectReason reason);
+
 /*@}*/
 
 /**************************************************************************/
--- a/libpurple/protocols/bonjour/bonjour.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/bonjour/bonjour.c	Sun Oct 07 10:28:32 2007 +0000
@@ -103,7 +103,7 @@
 #ifdef _WIN32
 	if (!dns_sd_available()) {
 		gc->wants_to_die = TRUE;
-		purple_connection_error(gc,
+		purple_connection_error_reason(gc, PURPLE_REASON_OTHER_ERROR,
 			_("The Apple Bonjour For Windows toolkit wasn't found, see the FAQ at: "
 			  "http://developer.pidgin.im/wiki/Using%20Pidgin#CanIusePidginforBonjourLink-LocalMessaging"
 			  " for more information."));
@@ -121,7 +121,8 @@
 
 	if (bonjour_jabber_start(bd->jabber_data) == -1) {
 		/* Send a message about the connection error */
-		purple_connection_error(gc, _("Unable to listen for incoming IM connections\n"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Unable to listen for incoming IM connections\n"));
 		return;
 	}
 
@@ -146,7 +147,8 @@
 	bd->dns_sd_data->account = account;
 	if (!bonjour_dns_sd_start(bd->dns_sd_data))
 	{
-		purple_connection_error(gc, _("Unable to establish connection with the local mDNS server.  Is it running?"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Unable to establish connection with the local mDNS server.  Is it running?"));
 		return;
 	}
 
--- a/libpurple/protocols/bonjour/jabber.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Sun Oct 07 10:28:32 2007 +0000
@@ -580,7 +580,8 @@
 	if ((data->socket = socket(PF_INET, SOCK_STREAM, 0)) < 0)
 	{
 		purple_debug_error("bonjour", "Cannot open socket: %s\n", strerror(errno));
-		purple_connection_error(data->account->gc, _("Cannot open socket"));
+		purple_connection_error_reason (data->account->gc,
+			PURPLE_REASON_NETWORK_ERROR, _("Cannot open socket"));
 		return -1;
 	}
 
@@ -588,7 +589,8 @@
 	if (setsockopt(data->socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0)
 	{
 		purple_debug_error("bonjour", "Error setting socket options: %s\n", strerror(errno));
-		purple_connection_error(data->account->gc, _("Error setting socket options"));
+		purple_connection_error_reason (data->account->gc,
+			PURPLE_REASON_NETWORK_ERROR, _("Error setting socket options"));
 		return -1;
 	}
 
@@ -612,7 +614,8 @@
 	if (!bind_successful)
 	{
 		purple_debug_error("bonjour", "Cannot bind socket: %s\n", strerror(errno));
-		purple_connection_error(data->account->gc, _("Could not bind socket to port"));
+		purple_connection_error_reason (data->account->gc,
+			PURPLE_REASON_NETWORK_ERROR, _("Could not bind socket to port"));
 		return -1;
 	}
 
@@ -620,7 +623,8 @@
 	if (listen(data->socket, 10) != 0)
 	{
 		purple_debug_error("bonjour", "Cannot listen on socket: %s\n", strerror(errno));
-		purple_connection_error(data->account->gc, _("Could not listen on socket"));
+		purple_connection_error_reason (data->account->gc,
+			PURPLE_REASON_NETWORK_ERROR, _("Could not listen on socket"));
 		return -1;
 	}
 
--- a/libpurple/protocols/gg/gg.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/gg/gg.c	Sun Oct 07 10:28:32 2007 +0000
@@ -381,12 +381,15 @@
 
 	if (email == NULL || p1 == NULL || p2 == NULL || t == NULL ||
 	    *email == '\0' || *p1 == '\0' || *p2 == '\0' || *t == '\0') {
-		purple_connection_error(gc, _("Fill in the registration fields."));
+		purple_connection_error_reason (gc, PURPLE_REASON_OTHER_ERROR,
+			_("Fill in the registration fields."));
 		goto exit_err;
 	}
 
 	if (g_utf8_collate(p1, p2) != 0) {
-		purple_connection_error(gc, _("Passwords do not match."));
+		purple_connection_error_reason (gc,
+			PURPLE_REASON_AUTHENTICATION_FAILED,
+			_("Passwords do not match."));
 		goto exit_err;
 	}
 
@@ -394,7 +397,7 @@
 			token->id, t);
 	h = gg_register3(email, p1, token->id, t, 0);
 	if (h == NULL || !(s = h->data) || !s->success) {
-		purple_connection_error(gc,
+		purple_connection_error_reason (gc, PURPLE_REASON_OTHER_ERROR,
 			_("Unable to register new account. Error occurred.\n"));
 		goto exit_err;
 	}
@@ -1307,7 +1310,8 @@
 	if (!(ev = gg_watch_fd(info->session))) {
 		purple_debug_error("gg",
 			"ggp_callback_recv: gg_watch_fd failed -- CRITICAL!\n");
-		purple_connection_error(gc, _("Unable to read socket"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Unable to read socket"));
 		return;
 	}
 
@@ -1460,7 +1464,8 @@
 
 	if (!(ev = gg_watch_fd(info->session))) {
 		purple_debug_error("gg", "login_handler: gg_watch_fd failed!\n");
-		purple_connection_error(gc, _("Unable to read socket"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Unable to read socket"));
 		return;
 	}
 	purple_debug_info("gg", "login_handler: session->fd = %d\n", info->session->fd);
@@ -1506,7 +1511,9 @@
 		case GG_EVENT_CONN_FAILED:
 			purple_input_remove(gc->inpa);
 			gc->inpa = 0;
-			purple_connection_error(gc, _("Connection failed."));
+			purple_connection_error_reason (gc,
+				PURPLE_REASON_NETWORK_ERROR,
+				_("Connection failed."));
 			break;
 		default:
 			purple_debug_error("gg", "strange event: %d\n", ev->type);
@@ -1712,7 +1719,8 @@
 
 	info->session = gg_login(glp);
 	if (info->session == NULL) {
-		purple_connection_error(gc, _("Connection failed."));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Connection failed."));
 		g_free(glp);
 		return;
 	}
@@ -1995,7 +2003,8 @@
 	if (gg_ping(info->session) < 0) {
 		purple_debug_info("gg", "Not connected to the server "
 				"or gg_session is not correct\n");
-		purple_connection_error(gc, _("Not connected to the server."));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Not connected to the server."));
 	}
 }
 /* }}} */
--- a/libpurple/protocols/irc/irc.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/irc/irc.c	Sun Oct 07 10:28:32 2007 +0000
@@ -123,8 +123,9 @@
 	if (ret < 0 && errno == EAGAIN)
 		return;
 	else if (ret <= 0) {
-		purple_connection_error(purple_account_get_connection(irc->account),
-			      _("Server has disconnected"));
+		PurpleConnection *gc = purple_account_get_connection(irc->account);
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Server has disconnected"));
 		return;
 	}
 
@@ -161,8 +162,9 @@
 	/* purple_debug(PURPLE_DEBUG_MISC, "irc", "sent%s: %s",
 		irc->gsc ? " (ssl)" : "", tosend); */
 	if (ret <= 0 && errno != EAGAIN) {
-		purple_connection_error(purple_account_get_connection(irc->account),
-				      _("Server has disconnected"));
+		PurpleConnection *gc = purple_account_get_connection(irc->account);
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Server has disconnected"));
 	} else if (ret < buflen) {
 		if (ret < 0)
 			ret = 0;
@@ -295,7 +297,9 @@
 	gc->flags |= PURPLE_CONNECTION_NO_NEWLINES;
 
 	if (strpbrk(username, " \t\v\r\n") != NULL) {
-		purple_connection_error(gc, _("IRC nicks may not contain whitespace"));
+		gc->wants_to_die = TRUE;
+		purple_connection_error_reason (gc, PURPLE_REASON_INVALID_SETTINGS,
+			_("IRC nicks may not contain whitespace"));
 		return;
 	}
 
@@ -324,7 +328,9 @@
 					purple_account_get_int(account, "port", IRC_DEFAULT_SSL_PORT),
 					irc_login_cb_ssl, irc_ssl_connect_failure, gc);
 		} else {
-			purple_connection_error(gc, _("SSL support unavailable"));
+			gc->wants_to_die = TRUE;
+			purple_connection_error_reason (gc, PURPLE_REASON_NO_SSL_SUPPORT,
+				_("SSL support unavailable"));
 			return;
 		}
 	}
@@ -335,7 +341,8 @@
 				 purple_account_get_int(account, "port", IRC_DEFAULT_PORT),
 				 irc_login_cb, gc) == NULL)
 		{
-			purple_connection_error(gc, _("Couldn't create socket"));
+			purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+				_("Couldn't create socket"));
 			return;
 		}
 	}
@@ -352,7 +359,6 @@
 	if (pass && *pass) {
 		buf = irc_format(irc, "vv", "PASS", pass);
 		if (irc_send(irc, buf) < 0) {
-/*			purple_connection_error(gc, "Error sending password"); */
 			g_free(buf);
 			return FALSE;
 		}
@@ -384,14 +390,12 @@
 			      strlen(realname) ? realname : IRC_DEFAULT_ALIAS);
 	g_free(tmp);
 	if (irc_send(irc, buf) < 0) {
-/*		purple_connection_error(gc, "Error registering with server");*/
 		g_free(buf);
 		return FALSE;
 	}
 	g_free(buf);
 	buf = irc_format(irc, "vn", "NICK", purple_connection_get_display_name(gc));
 	if (irc_send(irc, buf) < 0) {
-/*		purple_connection_error(gc, "Error sending nickname");*/
 		g_free(buf);
 		return FALSE;
 	}
@@ -418,7 +422,8 @@
 	struct irc_conn *irc = gc->proto_data;
 
 	if (source < 0) {
-		purple_connection_error(gc, _("Couldn't connect to host"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Couldn't connect to host"));
 		return;
 	}
 
@@ -438,7 +443,7 @@
 
 	irc->gsc = NULL;
 
-	purple_connection_error(gc, purple_ssl_strerror(error));
+	purple_connection_ssl_error (gc, error);
 }
 
 static void irc_close(PurpleConnection *gc)
@@ -606,10 +611,12 @@
 		/* Try again later */
 		return;
 	} else if (len < 0) {
-		purple_connection_error(gc, _("Read error"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Read error"));
 		return;
 	} else if (len == 0) {
-		purple_connection_error(gc, _("Server has disconnected"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Server has disconnected"));
 		return;
 	}
 
@@ -631,10 +638,12 @@
 	if (len < 0 && errno == EAGAIN) {
 		return;
 	} else if (len < 0) {
-		purple_connection_error(gc, _("Read error"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Read error"));
 		return;
 	} else if (len == 0) {
-		purple_connection_error(gc, _("Server has disconnected"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Server has disconnected"));
 		return;
 	}
 
--- a/libpurple/protocols/irc/msgs.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/irc/msgs.c	Sun Oct 07 10:28:32 2007 +0000
@@ -914,8 +914,8 @@
 
 	} else {
 		gc->wants_to_die = TRUE;
-		purple_connection_error(purple_account_get_connection(irc->account),
-				      _("Your selected account name was rejected by the server.  It probably contains invalid characters."));
+		purple_connection_error_reason (gc, PURPLE_REASON_INVALID_SETTINGS,
+				  _("Your selected account name was rejected by the server.  It probably contains invalid characters."));
 	}
 }
 
--- a/libpurple/protocols/irc/parse.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/irc/parse.c	Sun Oct 07 10:28:32 2007 +0000
@@ -612,6 +612,7 @@
 	struct _irc_msg *msgent;
 	char *cur, *end, *tmp, *from, *msgname, *fmt, **args, *msg;
 	guint i;
+	PurpleConnection *gc = purple_account_get_connection(irc->account);
 
 	irc->recv_time = time(NULL);
 
@@ -620,7 +621,7 @@
 	 * TODO: It should be passed as an array of bytes and a length
 	 * instead of a null terminated string.
 	 */
-	purple_signal_emit(_irc_plugin, "irc-receiving-text", purple_account_get_connection(irc->account), &input);
+	purple_signal_emit(_irc_plugin, "irc-receiving-text", gc, &input);
 	
 	if (!strncmp(input, "PING ", 5)) {
 		msg = irc_format(irc, "vv", "PONG", input + 5);
@@ -630,10 +631,11 @@
 	} else if (!strncmp(input, "ERROR ", 6)) {
 		if (g_utf8_validate(input, -1, NULL)) {
 			char *tmp = g_strdup_printf("%s\n%s", _("Disconnected."), input);
-			purple_connection_error(purple_account_get_connection(irc->account), tmp);
+			purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR, tmp);
 			g_free(tmp);
 		} else
-			purple_connection_error(purple_account_get_connection(irc->account), _("Disconnected."));
+			purple_connection_error_reason (gc,
+				PURPLE_REASON_NETWORK_ERROR, _("Disconnected."));
 		return;
 	}
 
--- a/libpurple/protocols/jabber/auth.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/jabber/auth.c	Sun Oct 07 10:28:32 2007 +0000
@@ -50,7 +50,9 @@
 					"<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>", -1);
 			return TRUE;
 		} else if(xmlnode_get_child(starttls, "required")) {
-			purple_connection_error(js->gc, _("Server requires TLS/SSL for login.  No TLS/SSL support found."));
+			js->gc->wants_to_die = TRUE;
+			purple_connection_error_reason (js->gc, PURPLE_REASON_NO_SSL_SUPPORT,
+				_("Server requires TLS/SSL for login.  No TLS/SSL support found."));
 			return TRUE;
 		}
 	}
@@ -113,7 +115,9 @@
 
 static void disallow_plaintext_auth(PurpleAccount *account)
 {
-	purple_connection_error(account->gc, _("Server requires plaintext authentication over an unencrypted stream"));
+	account->gc->wants_to_die = TRUE;
+	purple_connection_error_reason (account->gc, PURPLE_REASON_ENCRYPTION_ERROR,
+		_("Server requires plaintext authentication over an unencrypted stream"));
 }
 
 #ifdef HAVE_CYRUS_SASL
@@ -331,7 +335,9 @@
 				 * error here.
 				 */
 				} else {
-					purple_connection_error(js->gc, _("Server does not use any supported authentication method"));
+					purple_connection_error_reason (js->gc,
+						PURPLE_REASON_AUTHENTICATION_IMPOSSIBLE,
+						_("Server does not use any supported authentication method"));
 					return;
 				}
 				/* not reached */
@@ -386,7 +392,9 @@
 		jabber_send(js, auth);
 		xmlnode_free(auth);
 	} else {
-		purple_connection_error(js->gc, "SASL authentication failed\n");
+		purple_connection_error_reason (js->gc,
+			PURPLE_REASON_AUTHENTICATION_IMPOSSIBLE,
+			"SASL authentication failed\n");
 	}
 }
 
@@ -459,7 +467,8 @@
 	mechs = xmlnode_get_child(packet, "mechanisms");
 
 	if(!mechs) {
-		purple_connection_error(js->gc, _("Invalid response from server."));
+		purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Invalid response from server."));
 		return;
 	}
 
@@ -519,7 +528,7 @@
 		}
 		finish_plaintext_authentication(js);
 	} else {
-		purple_connection_error(js->gc,
+		purple_connection_error_reason (js->gc, PURPLE_REASON_AUTHENTICATION_IMPOSSIBLE,
 				_("Server does not use any supported authentication method"));
 	}
 #endif
@@ -535,17 +544,19 @@
 		char *msg = jabber_parse_error(js, packet);
 		xmlnode *error;
 		const char *err_code;
+		PurpleDisconnectReason reason = PURPLE_REASON_NETWORK_ERROR;
 
 		if((error = xmlnode_get_child(packet, "error")) &&
 					(err_code = xmlnode_get_attrib(error, "code")) &&
 					!strcmp(err_code, "401")) {
 			js->gc->wants_to_die = TRUE;
+			reason = PURPLE_REASON_AUTHENTICATION_FAILED;
 			/* Clear the pasword if it isn't being saved */
 			if (!purple_account_get_remember_password(js->gc->account))
 				purple_account_set_password(js->gc->account, NULL);
 		}
 
-		purple_connection_error(js->gc, msg);
+		purple_connection_error_reason (js->gc, reason, msg);
 		g_free(msg);
 	}
 }
@@ -558,11 +569,13 @@
 	const char *pw = purple_connection_get_password(js->gc);
 
 	if(!type) {
-		purple_connection_error(js->gc, _("Invalid response from server."));
+		purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Invalid response from server."));
 		return;
 	} else if(!strcmp(type, "error")) {
 		char *msg = jabber_parse_error(js, packet);
-		purple_connection_error(js->gc, msg);
+		purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+			msg);
 		g_free(msg);
 	} else if(!strcmp(type, "result")) {
 		query = xmlnode_get_child(packet, "query");
@@ -606,8 +619,9 @@
 			}
 			finish_plaintext_authentication(js);
 		} else {
-			purple_connection_error(js->gc,
-					_("Server does not use any supported authentication method"));
+			purple_connection_error_reason (js->gc,
+				PURPLE_REASON_AUTHENTICATION_IMPOSSIBLE,
+				_("Server does not use any supported authentication method"));
 			return;
 		}
 	}
@@ -773,7 +787,8 @@
 		GHashTable *parts;
 
 		if(!enc_in) {
-			purple_connection_error(js->gc, _("Invalid response from server."));
+			purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+				_("Invalid response from server."));
 			return;
 		}
 
@@ -794,7 +809,8 @@
 						"<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl' />",
 						-1);
 			} else {
-				purple_connection_error(js->gc, _("Invalid challenge from server"));
+				purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+					_("Invalid challenge from server"));
 			}
 			g_free(js->expected_rspauth);
 		} else {
@@ -817,7 +833,8 @@
 				realm = js->user->domain;
 
 			if (nonce == NULL || realm == NULL)
-				purple_connection_error(js->gc, _("Invalid challenge from server"));
+				purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+					_("Invalid challenge from server"));
 			else {
 				GString *response = g_string_new("");
 				char *a2;
@@ -889,7 +906,8 @@
 		g_free(dec_in);
 		if (js->sasl_state != SASL_CONTINUE && js->sasl_state != SASL_OK) {
 			purple_debug_error("jabber", "Error is %d : %s\n",js->sasl_state,sasl_errdetail(js->sasl));
-			purple_connection_error(js->gc, _("SASL error"));
+			purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+				_("SASL error"));
 			return;
 		} else {
 			response = xmlnode_new("response");
@@ -914,7 +932,8 @@
 #endif
 
 	if(!ns || strcmp(ns, "urn:ietf:params:xml:ns:xmpp-sasl")) {
-		purple_connection_error(js->gc, _("Invalid response from server."));
+		purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Invalid response from server."));
 		return;
 	}
 
@@ -939,7 +958,8 @@
 
 		if (js->sasl_state != SASL_OK) {
 			/* This should never happen! */
-			purple_connection_error(js->gc, _("Invalid response from server."));
+			purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+				_("Invalid response from server."));
 		}
 	}
 	/* If we've negotiated a security layer, we need to enable it */
@@ -958,9 +978,11 @@
 	char *msg = jabber_parse_error(js, packet);
 
 	if(!msg) {
-		purple_connection_error(js->gc, _("Invalid response from server."));
+		purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Invalid response from server."));
 	} else {
-		purple_connection_error(js->gc, msg);
+		purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+			msg);
 		g_free(msg);
 	}
 }
--- a/libpurple/protocols/jabber/jabber.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Sun Oct 07 10:28:32 2007 +0000
@@ -89,7 +89,8 @@
 		if(js->unregistration)
 			jabber_unregister_account_cb(js);
 	} else {
-		purple_connection_error(js->gc, _("Error initializing session"));
+		purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+			("Error initializing session"));
 	}
 }
 
@@ -120,7 +121,8 @@
 			JabberBuddy *my_jb = NULL;
 			jabber_id_free(js->user);
 			if(!(js->user = jabber_id_new(full_jid))) {
-				purple_connection_error(js->gc, _("Invalid response from server."));
+				purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+					_("Invalid response from server."));
 			}
 			if((my_jb = jabber_buddy_find(js, full_jid, TRUE)))
 				my_jb->subscription |= JABBER_SUB_BOTH;
@@ -128,7 +130,7 @@
 		}
 	} else {
 		char *msg = jabber_parse_error(js, packet);
-		purple_connection_error(js->gc, msg);
+		purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR, msg);
 		g_free(msg);
 	}
 
@@ -142,7 +144,8 @@
 			return;
 	} else if(purple_account_get_bool(js->gc->account, "require_tls", FALSE) && !js->gsc) {
 		js->gc->wants_to_die = TRUE;
-		purple_connection_error(js->gc, _("You require encryption, but it is not available on this server."));
+		purple_connection_error_reason (js->gc, PURPLE_REASON_ENCRYPTION_ERROR,
+			_("You require encryption, but it is not available on this server."));
 		return;
 	}
 
@@ -175,7 +178,10 @@
 {
 	char *msg = jabber_parse_error(js, packet);
 
-	purple_connection_error(js->gc, msg);
+	if (js->gc->wants_to_die)
+		purple_connection_error_reason (js->gc, PURPLE_REASON_OTHER_ERROR, msg);
+	else
+		purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR, msg);
 	g_free(msg);
 }
 
@@ -256,7 +262,8 @@
 	if (ret < 0 && errno == EAGAIN)
 		return;
 	else if (ret <= 0) {
-		purple_connection_error(js->gc, _("Write error"));
+		purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Write error"));
 		return;
 	}
 
@@ -309,7 +316,9 @@
 			}
 
 			if (ret < 0 && errno != EAGAIN)
-				purple_connection_error(js->gc, _("Write error"));
+				purple_connection_error_reason (js->gc,
+					PURPLE_REASON_NETWORK_ERROR,
+					_("Write error"));
 			else if (ret < olen) {
 				if (ret < 0)
 					ret = 0;
@@ -337,7 +346,9 @@
 	}
 
 	if (ret < 0 && errno != EAGAIN)
-		purple_connection_error(js->gc, _("Write error"));
+		purple_connection_error_reason (js->gc,
+			PURPLE_REASON_NETWORK_ERROR,
+			_("Write error"));
 	else if (ret < len) {
 		if (ret < 0)
 			ret = 0;
@@ -405,7 +416,9 @@
 	if(errno == EAGAIN)
 		return;
 	else
-		purple_connection_error(gc, _("Read Error"));
+		purple_connection_error_reason (js->gc,
+			PURPLE_REASON_NETWORK_ERROR,
+			_("Read Error"));
 }
 
 static void
@@ -442,7 +455,9 @@
 	} else if(errno == EAGAIN) {
 		return;
 	} else {
-		purple_connection_error(gc, _("Read Error"));
+		purple_connection_error_reason (js->gc,
+			PURPLE_REASON_NETWORK_ERROR,
+			_("Read Error"));
 	}
 }
 
@@ -481,7 +496,7 @@
 		gchar *tmp;
 		tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"),
 				error);
-		purple_connection_error(gc, tmp);
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR, tmp);
 		g_free(tmp);
 		return;
 	}
@@ -509,7 +524,7 @@
 	js = gc->proto_data;
 	js->gsc = NULL;
 
-	purple_connection_error(gc, purple_ssl_strerror(error));
+	purple_connection_ssl_error (gc, error);
 }
 
 static void tls_init(JabberStream *js)
@@ -526,7 +541,8 @@
 
 	if (purple_proxy_connect(js->gc, js->gc->account, host,
 			port, jabber_login_callback, js->gc) == NULL)
-		purple_connection_error(js->gc, _("Unable to create socket"));
+		purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Unable to create socket"));
 }
 
 static void srv_resolved_cb(PurpleSrvResponse *resp, int results, gpointer data)
@@ -572,12 +588,16 @@
 	js->old_length = -1;
 
 	if(!js->user) {
-		purple_connection_error(gc, _("Invalid XMPP ID"));
+		gc->wants_to_die = TRUE;
+		purple_connection_error_reason (gc, PURPLE_REASON_INVALID_SETTINGS,
+			_("Invalid XMPP ID"));
 		return;
 	}
 	
 	if (!js->user->domain || *(js->user->domain) == '\0') {
-		purple_connection_error(gc, _("Invalid XMPP ID. Domain must be set."));
+		gc->wants_to_die = TRUE;
+		purple_connection_error_reason (gc, PURPLE_REASON_INVALID_SETTINGS,
+			_("Invalid XMPP ID. Domain must be set."));
 		return;
 	}
 	
@@ -607,7 +627,9 @@
 					purple_account_get_int(account, "port", 5223), jabber_login_callback_ssl,
 					jabber_ssl_connect_failure, js->gc);
 		} else {
-			purple_connection_error(js->gc, _("SSL support unavailable"));
+			js->gc->wants_to_die = TRUE;
+			purple_connection_error_reason (js->gc, PURPLE_REASON_NO_SSL_SUPPORT,
+				_("SSL support unavailable"));
 		}
 	}
 
@@ -1060,7 +1082,9 @@
 	js->old_length = -1;
 
 	if(!js->user) {
-		purple_connection_error(gc, _("Invalid XMPP ID"));
+		gc->wants_to_die = TRUE;
+		purple_connection_error_reason (gc, PURPLE_REASON_INVALID_SETTINGS,
+			_("Invalid XMPP ID"));
 		return;
 	}
 
@@ -1092,7 +1116,9 @@
 					purple_account_get_int(account, "port", 5222),
 					jabber_login_callback_ssl, jabber_ssl_connect_failure, gc);
 		} else {
-			purple_connection_error(gc, _("SSL support unavailable"));
+			gc->wants_to_die = TRUE;
+			purple_connection_error_reason (gc, PURPLE_REASON_NO_SSL_SUPPORT,
+				_("SSL support unavailable"));
 		}
 	}
 
--- a/libpurple/protocols/jabber/parser.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/jabber/parser.c	Sun Oct 07 10:28:32 2007 +0000
@@ -193,7 +193,8 @@
 		js->context = xmlCreatePushParserCtxt(&jabber_parser_libxml, js, buf, len, NULL);
 		xmlParseChunk(js->context, "", 0, 0);
 	} else if (xmlParseChunk(js->context, buf, len, 0) < 0) {
-		purple_connection_error(js->gc, _("XML Parse error"));
+		purple_connection_error_reason (js->gc, PURPLE_REASON_NETWORK_ERROR,
+			_("XML Parse error"));
 	}
 }
 
--- a/libpurple/protocols/msn/contact.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/msn/contact.c	Sun Oct 07 10:28:32 2007 +0000
@@ -945,7 +945,7 @@
 		msn_get_address_book(contact, NULL, NULL);
 		*/
 		msn_session_disconnect(session);
-		purple_connection_error(session->account->gc, _("Unable to retrieve MSN Address Book"));
+		purple_connection_error_reason(session->account->gc, PURPLE_REASON_NETWORK_ERROR, _("Unable to retrieve MSN Address Book"));
 		return FALSE;
 	}
 }
--- a/libpurple/protocols/msn/msn.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/msn/msn.c	Sun Oct 07 10:28:32 2007 +0000
@@ -800,7 +800,7 @@
 	if (!purple_ssl_is_supported())
 	{
 		gc->wants_to_die = TRUE;
-		purple_connection_error(gc,
+		purple_connection_error_reason (gc, PURPLE_REASON_NO_SSL_SUPPORT,
 			_("SSL support is needed for MSN. Please install a supported "
 			  "SSL library."));
 		return;
@@ -829,7 +829,8 @@
 		purple_account_set_username(account, username);
 
 	if (!msn_session_connect(session, host, port, http_method))
-		purple_connection_error(gc, _("Failed to connect to server."));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Failed to connect to server."));
 }
 
 static void
--- a/libpurple/protocols/msn/session.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/msn/session.c	Sun Oct 07 10:28:32 2007 +0000
@@ -325,6 +325,7 @@
 					  const char *info)
 {
 	PurpleConnection *gc;
+	PurpleDisconnectReason reason;
 	char *msg;
 
 	gc = purple_account_get_connection(session->account);
@@ -332,49 +333,58 @@
 	switch (error)
 	{
 		case MSN_ERROR_SERVCONN:
+			reason = PURPLE_REASON_NETWORK_ERROR;
 			msg = g_strdup(info);
 			break;
 		case MSN_ERROR_UNSUPPORTED_PROTOCOL:
+			reason = PURPLE_REASON_NETWORK_ERROR;
 			msg = g_strdup(_("Our protocol is not supported by the "
 							 "server."));
 			break;
 		case MSN_ERROR_HTTP_MALFORMED:
+			reason = PURPLE_REASON_NETWORK_ERROR;
 			msg = g_strdup(_("Error parsing HTTP."));
 			break;
 		case MSN_ERROR_SIGN_OTHER:
 			gc->wants_to_die = TRUE;
+			reason = PURPLE_REASON_NAME_IN_USE;
 			msg = g_strdup(_("You have signed on from another location."));
 			if (!purple_account_get_remember_password(session->account))
 				purple_account_set_password(session->account, NULL);
 			break;
 		case MSN_ERROR_SERV_UNAVAILABLE:
+			reason = PURPLE_REASON_NETWORK_ERROR;
 			msg = g_strdup(_("The MSN servers are temporarily "
 							 "unavailable. Please wait and try "
 							 "again."));
 			break;
 		case MSN_ERROR_SERV_DOWN:
+			reason = PURPLE_REASON_NETWORK_ERROR;
 			msg = g_strdup(_("The MSN servers are going down "
 							 "temporarily."));
 			break;
 		case MSN_ERROR_AUTH:
+			reason = PURPLE_REASON_AUTHENTICATION_FAILED;
 			gc->wants_to_die = TRUE;
 			msg = g_strdup_printf(_("Unable to authenticate: %s"),
 								  (info == NULL ) ?
 								  _("Unknown error") : info);
 			break;
 		case MSN_ERROR_BAD_BLIST:
+			reason = PURPLE_REASON_NETWORK_ERROR;
 			msg = g_strdup(_("Your MSN buddy list is temporarily "
 							 "unavailable. Please wait and try "
 							 "again."));
 			break;
 		default:
+			reason = PURPLE_REASON_NETWORK_ERROR;
 			msg = g_strdup(_("Unknown error."));
 			break;
 	}
 
 	msn_session_disconnect(session);
 
-	purple_connection_error(gc, msg);
+	purple_connection_error_reason (gc, reason, msg);
 
 	g_free(msg);
 }
--- a/libpurple/protocols/myspace/myspace.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/myspace/myspace.c	Sun Oct 07 10:28:32 2007 +0000
@@ -292,7 +292,8 @@
 		purple_notify_error(acct, _("MySpaceIM Error"), str, NULL);
 
 		gc->wants_to_die = TRUE;
-		purple_connection_error(gc, str);
+		purple_connection_error_reason (gc,
+			PURPLE_REASON_AUTHENTICATION_FAILED, str);
 		g_free(str);
 		return;
 	}
@@ -315,7 +316,8 @@
 	if (!purple_proxy_connect(gc, acct, host, port, msim_connect_cb, gc)) {
 		/* TODO: try other ports if in auto mode, then save
 		 * working port and try that first next time. */
-		purple_connection_error(gc, _("Couldn't create socket"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Couldn't create socket"));
 		return;
 	}
 }
@@ -353,7 +355,8 @@
 
 	if (nc_len != MSIM_AUTH_CHALLENGE_LENGTH) {
 		purple_debug_info("msim", "bad nc length: %x != 0x%x\n", nc_len, MSIM_AUTH_CHALLENGE_LENGTH);
-		purple_connection_error(session->gc, _("Unexpected challenge length from server"));
+		purple_connection_error_reason (session->gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Unexpected challenge length from server"));
 		return FALSE;
 	}
 
@@ -826,7 +829,6 @@
 	serv_got_typing_stopped(session->gc, username);
 
 	g_free(username);
-	g_free(text);
 
 	return TRUE;
 }
@@ -1290,7 +1292,8 @@
 
 		purple_debug_info("msim", "msim_check_alive: %s > interval of %d, presumed dead\n",
 				errmsg, MSIM_KEEPALIVE_INTERVAL);
-		purple_connection_error(session->gc, errmsg);
+		purple_connection_error_reason (session->gc,
+				PURPLE_REASON_NETWORK_ERROR, errmsg);
 
 		purple_notify_error(session->gc, NULL, errmsg, NULL);
 
@@ -1556,7 +1559,8 @@
 		purple_notify_error(session->account, 
 				_("No username set"),
 				_("Please go to http://editprofile.myspace.com/index.cfm?fuseaction=profile.username and choose a username and try to login again."), NULL);
-		purple_connection_error(session->gc, _("No username set"));
+		session->gc->wants_to_die = TRUE;
+		purple_connection_error_reason (session->gc, PURPLE_REASON_AUTHENTICATION_FAILED, _("No username set"));
 		return FALSE;
 	}
 
@@ -1792,16 +1796,23 @@
 
 	/* Destroy session if fatal. */
 	if (msim_msg_get(msg, "fatal")) {
+		PurpleDisconnectReason reason = PURPLE_REASON_NETWORK_ERROR;
 		purple_debug_info("msim", "fatal error, closing\n");
 		switch (err) {
 			case 260: /* Incorrect password */
+				reason = PURPLE_REASON_AUTHENTICATION_FAILED;
+				session->gc->wants_to_die = TRUE;
+				if (!purple_account_get_remember_password(session->account))
+					purple_account_set_password(session->account, NULL);
+				break;
 			case 6: /* Logged in elsewhere */
+				reason = PURPLE_REASON_NAME_IN_USE;
 				session->gc->wants_to_die = TRUE;
 				if (!purple_account_get_remember_password(session->account))
 					purple_account_set_password(session->account, NULL);
 				break;
 		}
-		purple_connection_error(session->gc, full_errmsg);
+		purple_connection_error_reason (session->gc, reason, full_errmsg);
 	} else {
 		purple_notify_error(session->account, _("MySpaceIM Error"), full_errmsg, NULL);
 	}
@@ -1871,7 +1882,6 @@
 		purple_blist_add_buddy(buddy, NULL, NULL, NULL);
 
 		user = msim_get_user_from_buddy(buddy);
-		/* TODO: free user. memory leak? */
 
 		/* All buddies on list should have 'uid' integer associated with them. */
 		purple_blist_node_set_int(&buddy->node, "UserID", msim_msg_get_integer(msg, "f"));
@@ -2317,7 +2327,8 @@
 	/* libpurple/eventloop.h only defines these two */
 	if (cond != PURPLE_INPUT_READ && cond != PURPLE_INPUT_WRITE) {
 		purple_debug_info("msim_input_cb", "unknown condition=%d\n", cond);
-		purple_connection_error(gc, _("Invalid input condition"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Invalid input condition"));
 		return;
 	}
 
@@ -2335,7 +2346,8 @@
 		purple_debug_error("msim", 
 				"msim_input_cb: %d-byte read buffer full! rxoff=%d\n",
 				MSIM_READ_BUF_SIZE, session->rxoff);
-		purple_connection_error(gc, _("Read buffer full"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+				_("Read buffer full"));
 		return;
 	}
 
@@ -2354,11 +2366,13 @@
 		purple_debug_error("msim", "msim_input_cb: read error, ret=%d, "
 			"error=%s, source=%d, fd=%d (%X))\n", 
 			n, strerror(errno), source, session->fd, session->fd);
-		purple_connection_error(gc, _("Read error"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Read error"));
 		return;
 	} else if (n == 0) {
 		purple_debug_info("msim", "msim_input_cb: server disconnected\n");
-		purple_connection_error(gc, _("Server has disconnected"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Server has disconnected"));
 		return;
 	}
 
@@ -2366,7 +2380,8 @@
 		purple_debug_info("msim_input_cb", "received %d bytes, pushing rxoff to %d, over buffer size of %d\n",
 				n, n + session->rxoff, MSIM_READ_BUF_SIZE);
 		/* TODO: g_realloc like msn, yahoo, irc, jabber? */
-		purple_connection_error(gc, _("Read buffer full"));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Read buffer full"));
 	}
 
 	/* Null terminate */
@@ -2381,7 +2396,8 @@
 		purple_debug_info("msim", "msim_input_cb: strlen=%d, but read %d bytes"
 				"--null byte encountered?\n", 
 				strlen(session->rxbuf + session->rxoff), n);
-		//purple_connection_error(gc, "Invalid message - null byte on input");
+		/*purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+				"Invalid message - null byte on input"); */
 		return;
 	}
 #endif
@@ -2404,7 +2420,8 @@
 		msg = msim_parse(g_strdup(session->rxbuf));
 		if (!msg) {
 			purple_debug_info("msim", "msim_input_cb: couldn't parse rxbuf\n");
-			purple_connection_error(gc, _("Unparseable message"));
+			purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+				_("Unparseable message"));
 		} else {
 			/* Process message and then free it (processing function should
 			 * clone message if it wants to keep it afterwards.) */
@@ -2471,9 +2488,8 @@
 	session = (MsimSession *)gc->proto_data;
 
 	if (source < 0) {
-		purple_connection_error(gc, _("Couldn't connect to host"));
-		purple_connection_error(gc, g_strdup_printf(
-					_("Couldn't connect to host: %s (%d)"), 
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			g_strdup_printf(_("Couldn't connect to host: %s (%d)"), 
 					error_message ? error_message : "no message given", 
 					source));
 		return;
@@ -2674,7 +2690,6 @@
 	/* TODO: other fields, store in 'user' */
 
 	msim_msg_free(contact_info);
-	g_free(username);
 }
 
 /** Add first ContactID in contact_info to buddy's list. Used to add
--- a/libpurple/protocols/novell/novell.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/novell/novell.c	Sun Oct 07 10:28:32 2007 +0000
@@ -120,21 +120,28 @@
 		_check_for_disconnect(user, rc);
 
 	} else {
-
+		PurpleDisconnectReason reason;
 		char *err = g_strdup_printf(_("Login failed (%s)."),
 					    nm_error_to_string (ret_code));
 
-		/* Don't attempt to auto-reconnect if our password
-		 * was invalid.
-		 */
-		if (ret_code == NMERR_AUTHENTICATION_FAILED ||
-			ret_code == NMERR_CREDENTIALS_MISSING ||
-			ret_code == NMERR_PASSWORD_INVALID) {
-			if (!purple_account_get_remember_password(gc->account))
-				purple_account_set_password(gc->account, NULL);
-			gc->wants_to_die = TRUE;
+		switch (ret_code) {
+			case NMERR_AUTHENTICATION_FAILED:
+			case NMERR_CREDENTIALS_MISSING:
+			case NMERR_PASSWORD_INVALID:
+				/* Don't attempt to auto-reconnect if our
+				 * password was invalid.
+				 */
+				if (!purple_account_get_remember_password(gc->account))
+					purple_account_set_password(gc->account, NULL);
+				gc->wants_to_die = TRUE;
+				reason = PURPLE_REASON_AUTHENTICATION_FAILED;
+				break;
+			default:
+				/* FIXME: There are other reasons login could fail */
+				reason = PURPLE_REASON_NETWORK_ERROR;
 		}
-		purple_connection_error(gc, err);
+
+		purple_connection_error_reason (gc, reason, err);
 		g_free(err);
 	}
 }
@@ -1120,8 +1127,8 @@
 
 	if (_is_disconnect_error(err)) {
 
-		purple_connection_error(gc, _("Error communicating with server."
-									" Closing connection."));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Error communicating with server. Closing connection."));
 		return TRUE;
 
 	}
@@ -1667,7 +1674,7 @@
 	user = gc->proto_data;
 	user->conn->ssl_conn->data = NULL;
 
-	purple_connection_error(gc, _("Unable to make SSL connection to server."));
+	purple_connection_ssl_error (gc, error);
 }
 
 static void
@@ -1690,9 +1697,9 @@
 
 		if (_is_disconnect_error(rc)) {
 
-			purple_connection_error(gc,
-								  _("Error communicating with server."
-									" Closing connection."));
+			purple_connection_error_reason (gc,
+				PURPLE_REASON_NETWORK_ERROR,
+				_("Error communicating with server. Closing connection."));
 		} else {
 			purple_debug(PURPLE_DEBUG_INFO, "novell",
 					   "Error processing event or response (%d).\n", rc);
@@ -1731,7 +1738,8 @@
 		conn->connected = TRUE;
 		purple_ssl_input_add(gsc, novell_ssl_recv_cb, gc);
 	} else {
-		purple_connection_error(gc, _("Unable to connect to server."));
+		purple_connection_error_reason (gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Unable to connect to server."));
 	}
 
 	purple_connection_update_progress(gc, _("Waiting for response..."),
@@ -2014,7 +2022,8 @@
 		gc->wants_to_die = TRUE; /* we don't want to reconnect in this case */
 		if (!purple_account_get_remember_password(account))
 			purple_account_set_password(account, NULL);
-		purple_connection_error(gc, _("You have been logged out because you"
+		purple_connection_error_reason (gc, PURPLE_REASON_NAME_IN_USE,
+									_("You have been logged out because you"
 									" logged in at another workstation."));
 	}
 }
@@ -2169,9 +2178,10 @@
 		 */
 
 		/* ...but for now just error out with a nice message. */
-		purple_connection_error(gc, _("Unable to connect to server."
-									" Please enter the address of the server"
-									" you wish to connect to."));
+		gc->wants_to_die = TRUE;
+		purple_connection_error_reason (gc, PURPLE_REASON_INVALID_SETTINGS,
+			_("Unable to connect to server. Please enter the "
+			  "address of the server you wish to connect to."));
 		return;
 	}
 
@@ -2197,8 +2207,10 @@
 													  user->conn->addr, user->conn->port,
 													  novell_ssl_connected_cb, novell_ssl_connect_error, gc);
 		if (user->conn->ssl_conn->data == NULL) {
-			purple_connection_error(gc, _("Error."
-										" SSL support is not installed."));
+			gc->wants_to_die = TRUE;
+			purple_connection_error_reason (gc,
+				PURPLE_REASON_NO_SSL_SUPPORT,
+				_("Error. SSL support is not installed."));
 		}
 	}
 }
--- a/libpurple/protocols/oscar/flap_connection.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/oscar/flap_connection.c	Sun Oct 07 10:28:32 2007 +0000
@@ -380,7 +380,10 @@
 	{
 		/* No more FLAP connections!  Sign off this PurpleConnection! */
 		gchar *tmp;
+		PurpleDisconnectReason reason = PURPLE_REASON_NETWORK_ERROR;
+
 		if (conn->disconnect_code == 0x0001) {
+			reason = PURPLE_REASON_NAME_IN_USE;
 			tmp = g_strdup(_("You have signed on from another location."));
 			if (!purple_account_get_remember_password(account))
 				purple_account_set_password(account, NULL);
@@ -404,7 +407,7 @@
 
 		if (tmp != NULL)
 		{
-			purple_connection_error(od->gc, tmp);
+			purple_connection_error_reason(od->gc, reason, tmp);
 			g_free(tmp);
 		}
 	}
--- a/libpurple/protocols/oscar/oscar.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/oscar/oscar.c	Sun Oct 07 10:28:32 2007 +0000
@@ -994,7 +994,7 @@
 			gchar *msg;
 			msg = g_strdup_printf(_("Could not connect to authentication server:\n%s"),
 					error_message);
-			purple_connection_error(gc, msg);
+			purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR, msg);
 			g_free(msg);
 		}
 		else if (conn->type == SNAC_FAMILY_LOCATE)
@@ -1002,7 +1002,7 @@
 			gchar *msg;
 			msg = g_strdup_printf(_("Could not connect to BOS server:\n%s"),
 					error_message);
-			purple_connection_error(gc, msg);
+			purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR, msg);
 			g_free(msg);
 		}
 		else
@@ -1259,7 +1259,7 @@
 		gchar *buf;
 		buf = g_strdup_printf(_("Unable to login: Could not sign on as %s because the screen name is invalid.  Screen names must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers."), purple_account_get_username(account));
 		gc->wants_to_die = TRUE;
-		purple_connection_error(gc, buf);
+		purple_connection_error_reason(gc, PURPLE_REASON_INVALID_SETTINGS, buf);
 		g_free(buf);
 	}
 
@@ -1280,7 +1280,8 @@
 			connection_established_cb, newconn);
 	if (newconn->connect_data == NULL)
 	{
-		purple_connection_error(gc, _("Couldn't connect to host"));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+				_("Couldn't connect to host"));
 		return;
 	}
 
@@ -1342,42 +1343,43 @@
 		case 0x01:
 			/* Unregistered screen name */
 			gc->wants_to_die = TRUE;
-			purple_connection_error(gc, _("Invalid screen name."));
+			purple_connection_error_reason(gc, PURPLE_REASON_AUTHENTICATION_FAILED, _("Invalid screen name."));
 			break;
 		case 0x05:
 			/* Incorrect password */
 			gc->wants_to_die = TRUE;
 			if (!purple_account_get_remember_password(account))
 				purple_account_set_password(account, NULL);
-			purple_connection_error(gc, _("Incorrect password."));
+			purple_connection_error_reason(gc, PURPLE_REASON_AUTHENTICATION_FAILED, _("Incorrect password."));
 			break;
 		case 0x11:
 			/* Suspended account */
 			gc->wants_to_die = TRUE;
-			purple_connection_error(gc, _("Your account is currently suspended."));
+			purple_connection_error_reason(gc, PURPLE_REASON_AUTHENTICATION_FAILED, _("Your account is currently suspended."));
 			break;
 		case 0x14:
 			/* service temporarily unavailable */
-			purple_connection_error(gc, _("The AOL Instant Messenger service is temporarily unavailable."));
+			purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR, _("The AOL Instant Messenger service is temporarily unavailable."));
 			break;
 		case 0x18:
 			/* screen name connecting too frequently */
 			gc->wants_to_die = TRUE;
-			purple_connection_error(gc, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));
+			purple_connection_error_reason(gc, PURPLE_REASON_OTHER_ERROR, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));
 			break;
 		case 0x1c:
 			/* client too old */
 			gc->wants_to_die = TRUE;
 			g_snprintf(buf, sizeof(buf), _("The client version you are using is too old. Please upgrade at %s"), PURPLE_WEBSITE);
-			purple_connection_error(gc, buf);
+			purple_connection_error_reason(gc, PURPLE_REASON_OTHER_ERROR, buf);
 			break;
 		case 0x1d:
 			/* IP address connecting too frequently */
 			gc->wants_to_die = TRUE;
-			purple_connection_error(gc, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));
+			purple_connection_error_reason(gc, PURPLE_REASON_OTHER_ERROR, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));
 			break;
 		default:
-			purple_connection_error(gc, _("Authentication failed"));
+			gc->wants_to_die = TRUE;
+			purple_connection_error_reason(gc, PURPLE_REASON_AUTHENTICATION_FAILED, _("Authentication failed"));
 			break;
 		}
 		purple_debug_info("oscar", "Login Error Code 0x%04hx\n", info->errorcode);
@@ -1407,7 +1409,7 @@
 	g_free(host);
 	if (newconn->connect_data == NULL)
 	{
-		purple_connection_error(gc, _("Could Not Connect"));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR, _("Could Not Connect"));
 		return 0;
 	}
 
@@ -1433,7 +1435,8 @@
 
 	/* Disconnect */
 	gc->wants_to_die = TRUE;
-	purple_connection_error(gc, _("The SecurID key entered is invalid."));
+	purple_connection_error_reason(gc, PURPLE_REASON_AUTHENTICATION_FAILED,
+		_("The SecurID key entered is invalid."));
 }
 
 static int
--- a/libpurple/protocols/qq/keep_alive.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/qq/keep_alive.c	Sun Oct 07 10:28:32 2007 +0000
@@ -84,7 +84,8 @@
 		/* segments[0] and segment[1] are all 0x30 ("0") */
 		qd->all_online = strtol(segments[2], NULL, 10);
 		if(0 == qd->all_online)
-			purple_connection_error(gc, _("Keep alive error"));
+			purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+					_("Keep alive error"));
 		g_free(qd->my_ip);
 		qd->my_ip = g_strdup(segments[3]);
 		qd->my_port = strtol(segments[4], NULL, 10);
--- a/libpurple/protocols/qq/login_logout.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/qq/login_logout.c	Sun Oct 07 10:28:32 2007 +0000
@@ -405,7 +405,7 @@
 				">>> %d bytes -> [default] decrypt and dump\n%s",
 				buf_len, hex_dump);
 		try_dump_as_gbk(buf, buf_len);
-		purple_connection_error(gc, _("Error requesting login token"));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR, _("Error requesting login token"));
 	}
 	g_free(hex_dump);
 }
@@ -482,10 +482,12 @@
 		gc->wants_to_die = TRUE;
 		if (!purple_account_get_remember_password(gc->account))
 			purple_account_set_password(gc->account, NULL);
-		purple_connection_error(gc, _("Incorrect password."));
+		purple_connection_error_reason(gc,
+			PURPLE_REASON_AUTHENTICATION_FAILED, _("Incorrect password."));
 		break;
 	case QQ_LOGIN_REPLY_MISC_ERROR:
-		purple_connection_error(gc, _("Unable to login, check debug log"));
+		purple_connection_error_reason(gc,
+			PURPLE_REASON_NETWORK_ERROR, _("Unable to login, check debug log"));
 		break;
 	case QQ_LOGIN_REPLY_OK:
 		purple_debug(PURPLE_DEBUG_INFO, "QQ", "Login replys OK, everything is fine\n");
--- a/libpurple/protocols/qq/qq.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/qq/qq.c	Sun Oct 07 10:28:32 2007 +0000
@@ -136,7 +136,8 @@
 	purple_connection_update_progress(gc, _("Connecting"), 0, QQ_CONNECT_STEPS);
 
 	if (qq_connect(account, qq_server, strtol(qq_port, NULL, 10), use_tcp, FALSE) < 0)
-		purple_connection_error(gc, _("Unable to connect."));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Unable to connect."));
 }
 
 /* directly goes for qq_disconnect */
--- a/libpurple/protocols/qq/qq_proxy.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/qq/qq_proxy.c	Sun Oct 07 10:28:32 2007 +0000
@@ -139,7 +139,7 @@
 	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
 
 	if (source < 0) {	/* socket returns -1 */
-		purple_connection_error(gc, error_message);
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR, error_message);
 		return;
 	}
 
@@ -494,7 +494,7 @@
 		ret = send(qd->fd, data, len, 0);
 	}
 	if (ret == -1)
-		purple_connection_error(qd->gc, strerror(errno));
+		purple_connection_error_reason(qd->gc, PURPLE_REASON_NETWORK_ERROR, strerror(errno));
 
 	return ret;
 }
--- a/libpurple/protocols/qq/recv_core.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/qq/recv_core.c	Sun Oct 07 10:28:32 2007 +0000
@@ -306,7 +306,8 @@
 	gc = (PurpleConnection *) data;
 
 	if(cond != PURPLE_INPUT_READ) {
-		purple_connection_error(gc, _("Socket error"));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Socket error"));
 		return;
 	}
 
@@ -316,7 +317,8 @@
 	/* here we have UDP proxy suppport */
 	len = qq_proxy_read(qd, buf, MAX_PACKET_SIZE);
 	if (len <= 0) {
-		purple_connection_error(gc, _("Unable to read from socket"));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Unable to read from socket"));
 		return;
 	} else {
 		_qq_packet_process(buf, len, gc);
--- a/libpurple/protocols/qq/sendqueue.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/qq/sendqueue.c	Sun Oct 07 10:28:32 2007 +0000
@@ -120,7 +120,8 @@
 			case QQ_CMD_KEEP_ALIVE:
 				if (qd->logged_in) {
 					purple_debug(PURPLE_DEBUG_ERROR, "QQ", "Connection lost!\n");
-					purple_connection_error(gc, _("Connection lost"));
+					purple_connection_error_reason(gc,
+						PURPLE_REASON_NETWORK_ERROR, _("Connection lost"));
 					qd->logged_in = FALSE;
 				}
 				p->resend_times = -1;
@@ -128,7 +129,8 @@
 			case QQ_CMD_LOGIN:
 			case QQ_CMD_REQUEST_LOGIN_TOKEN:
 				if (!qd->logged_in)	/* cancel login progress */
-					purple_connection_error(gc, _("Login failed, no reply"));
+					purple_connection_error_reason(gc,
+						PURPLE_REASON_NETWORK_ERROR, _("Login failed, no reply"));
 				p->resend_times = -1;
 				break;
 			default:{
--- a/libpurple/protocols/sametime/sametime.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/sametime/sametime.c	Sun Oct 07 10:28:32 2007 +0000
@@ -414,7 +414,8 @@
 
   } else if(len > 0) {
     DEBUG_ERROR("write returned %i, %i bytes left unwritten\n", ret, len);
-    purple_connection_error(pd->gc, _("Connection closed (writing)"));
+    purple_connection_error_reason(pd->gc, PURPLE_REASON_NETWORK_ERROR,
+                                   _("Connection closed (writing)"));
 
 #if 0
     close(pd->socket);
@@ -1552,7 +1553,41 @@
 
     if(GPOINTER_TO_UINT(info) & ERR_FAILURE) {
       char *err = mwError(GPOINTER_TO_UINT(info));
-      purple_connection_error(gc, err);
+      PurpleDisconnectReason reason;
+      switch (GPOINTER_TO_UINT(info)) {
+      case VERSION_MISMATCH:
+        reason = PURPLE_REASON_OTHER_ERROR;
+        break;
+
+      case USER_RESTRICTED:
+      case INCORRECT_LOGIN:
+      case USER_UNREGISTERED:
+      case GUEST_IN_USE:
+        gc->wants_to_die = TRUE;
+        reason = PURPLE_REASON_AUTHENTICATION_FAILED;
+        break;
+
+      case ENCRYPT_MISMATCH:
+      case ERR_ENCRYPT_NO_SUPPORT:
+      case ERR_NO_COMMON_ENCRYPT:
+        gc->wants_to_die = TRUE;
+        reason = PURPLE_REASON_ENCRYPTION_ERROR;
+        break;
+
+      case VERIFICATION_DOWN:
+        reason = PURPLE_REASON_AUTHENTICATION_IMPOSSIBLE;
+        break;
+
+      case MULTI_SERVER_LOGIN:
+      case MULTI_SERVER_LOGIN2:
+        gc->wants_to_die = TRUE;
+        reason = PURPLE_REASON_NAME_IN_USE;
+        break;
+
+      default:
+        reason = PURPLE_REASON_NETWORK_ERROR;
+      }
+      purple_connection_error_reason(gc, reason, err);
       g_free(err);
     }
     break;
@@ -1698,8 +1733,9 @@
   }
 
   if(! ret) {
+    const char *msg = _("Connection reset");
     DEBUG_INFO("connection reset\n");
-    purple_connection_error(pd->gc, _("Connection reset"));
+    purple_connection_error_reason(pd->gc, PURPLE_REASON_NETWORK_ERROR, msg);
 
   } else if(ret < 0) {
     char *msg = strerror(err);
@@ -1707,7 +1743,7 @@
     DEBUG_INFO("error in read callback: %s\n", msg);
 
     msg = g_strdup_printf(_("Error reading from socket: %s"), msg);
-    purple_connection_error(pd->gc, msg);
+    purple_connection_error_reason(pd->gc, PURPLE_REASON_NETWORK_ERROR, msg);
     g_free(msg);
   }
 }
@@ -1729,7 +1765,8 @@
 
     } else {
       /* this is a regular connect, error out */
-      purple_connection_error(pd->gc, _("Unable to connect to host"));
+      const char *msg = _("Unable to connect to host");
+      purple_connection_error_reason(pd->gc, PURPLE_REASON_NETWORK_ERROR, msg);
     }
 
     return;
@@ -3611,7 +3648,9 @@
 
 
 static void prompt_host_cancel_cb(PurpleConnection *gc) {
-  purple_connection_error(gc, _("No Sametime Community Server specified"));
+  const char *msg = _("No Sametime Community Server specified");
+  gc->wants_to_die = TRUE;
+  purple_connection_error_reason(gc, PURPLE_REASON_INVALID_SETTINGS, msg);
 }
 
 
@@ -3723,7 +3762,8 @@
   purple_connection_update_progress(gc, _("Connecting"), 1, MW_CONNECT_STEPS);
 
   if (purple_proxy_connect(gc, account, host, port, connect_cb, pd) == NULL) {
-    purple_connection_error(gc, _("Unable to connect to host"));
+    purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+                                   _("Unable to connect to host"));
   }
 }
 
--- a/libpurple/protocols/silc/silc.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/silc/silc.c	Sun Oct 07 10:28:32 2007 +0000
@@ -214,34 +214,43 @@
 
 		/* Close the connection */
 		if (!sg->detaching)
-		  purple_connection_error(gc, _("Disconnected by server"));
+		  purple_connection_error_reason(gc,
+		                                 PURPLE_REASON_NETWORK_ERROR,
+		                                 _("Disconnected by server"));
 		else
 		  /* TODO: Does this work correctly? Maybe we need to set wants_to_die? */
 		  purple_account_disconnect(purple_connection_get_account(gc));
 		break;
 
 	case SILC_CLIENT_CONN_ERROR:
-		purple_connection_error(gc, _("Error during connecting to SILC Server"));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+		                             _("Error during connecting to SILC Server"));
 		g_unlink(silcpurple_session_file(purple_account_get_username(sg->account)));
 		break;
 
 	case SILC_CLIENT_CONN_ERROR_KE:
-		purple_connection_error(gc, _("Key Exchange failed"));
+		gc->wants_to_die = TRUE;
+		purple_connection_error_reason(gc, PURPLE_REASON_ENCRYPTION_ERROR,
+		                             _("Key Exchange failed"));
 		break;
 
 	case SILC_CLIENT_CONN_ERROR_AUTH:
-		purple_connection_error(gc, _("Authentication failed"));
+		gc->wants_to_die = TRUE;
+		purple_connection_error_reason(gc, PURPLE_REASON_AUTHENTICATION_FAILED,
+		                             _("Authentication failed"));
 		break;
 
 	case SILC_CLIENT_CONN_ERROR_RESUME:
-		purple_connection_error(gc,
-				      _("Resuming detached session failed. "
-					"Press Reconnect to create new connection."));
+		gc->wants_to_die = TRUE;
+		purple_connection_error_reason(gc, PURPLE_REASON_OTHER_ERROR,
+		                             _("Resuming detached session failed. "
+		                               "Press Reconnect to create new connection."));
 		g_unlink(silcpurple_session_file(purple_account_get_username(sg->account)));
 		break;
 
 	case SILC_CLIENT_CONN_ERROR_TIMEOUT:
-		purple_connection_error(gc, _("Connection Timeout"));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+		                             _("Connection Timeout"));
 		break;
 	}
 
@@ -262,7 +271,8 @@
 	sg = gc->proto_data;
 
 	if (status != SILC_SOCKET_OK) {
-		purple_connection_error(gc, _("Connection failed"));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+		                             _("Connection failed"));
 		silc_pkcs_public_key_free(sg->public_key);
 		silc_pkcs_private_key_free(sg->private_key);
 		silc_free(sg);
@@ -308,7 +318,8 @@
 	sg = gc->proto_data;
 
 	if (source < 0) {
-		purple_connection_error(gc, _("Connection failed"));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+		                             _("Connection failed"));
 		silc_pkcs_public_key_free(sg->public_key);
 		silc_pkcs_private_key_free(sg->private_key);
 		silc_free(sg);
@@ -349,8 +360,9 @@
 				(char *)purple_account_get_string(account, "private-key", prd),
 				(gc->password == NULL) ? "" : gc->password,
 				&sg->public_key, &sg->private_key)) {
-		g_snprintf(pkd, sizeof(pkd), _("Could not load SILC key pair"));
-		purple_connection_error(gc, pkd);
+		gc->wants_to_die = TRUE;
+		purple_connection_error_reason(gc, PURPLE_REASON_OTHER_ERROR,
+		                             _("Could not load SILC key pair"));
 		gc->proto_data = NULL;
 		silc_free(sg);
 		return;
@@ -363,7 +375,8 @@
 				 purple_account_get_int(account, "port", 706),
 				 silcpurple_login_connected, gc) == NULL)
 	{
-		purple_connection_error(gc, _("Unable to create connection"));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+		                             _("Unable to create connection"));
 		gc->proto_data = NULL;
 		silc_free(sg);
 		return;
@@ -392,7 +405,8 @@
 	/* Allocate SILC client */
 	client = silc_client_alloc(&ops, &params, gc, NULL);
 	if (!client) {
-		purple_connection_error(gc, _("Out of memory"));
+		purple_connection_error_reason(gc, PURPLE_REASON_OTHER_ERROR,
+		                             _("Out of memory"));
 		return;
 	}
 
@@ -435,14 +449,16 @@
 	if (!silc_client_init(client, username, hostname, realname,
 			      silcpurple_running, account)) {
 		gc->wants_to_die = TRUE;
-		purple_connection_error(gc, _("Cannot initialize SILC protocol"));
+		purple_connection_error_reason(gc, PURPLE_REASON_OTHER_ERROR,
+		                             _("Cannot initialize SILC protocol"));
 		return;
 	}
 
 	/* Check the ~/.silc dir and create it, and new key pair if necessary. */
 	if (!silcpurple_check_silc_dir(gc)) {
 		gc->wants_to_die = TRUE;
-		purple_connection_error(gc, _("Error loading SILC key pair"));
+		purple_connection_error_reason(gc, PURPLE_REASON_OTHER_ERROR,
+		                             _("Error loading SILC key pair"));
 		return;
 	}
 
--- a/libpurple/protocols/silc/util.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/silc/util.c	Sun Oct 07 10:28:32 2007 +0000
@@ -212,7 +212,8 @@
 						  (gc->password == NULL)
 						  ? "" : gc->password,
 						  NULL, NULL, FALSE)) {
-				purple_connection_error(gc, _("Cannot create SILC key pair\n"));
+				purple_connection_error_reason(gc, PURPLE_REASON_OTHER_ERROR,
+				                             _("Cannot create SILC key pair\n"));
 				return FALSE;
 			}
 
@@ -254,7 +255,8 @@
 						  (gc->password == NULL)
 						  ? "" : gc->password,
 						  NULL, NULL, FALSE)) {
-				purple_connection_error(gc, _("Cannot create SILC key pair\n"));
+				purple_connection_error_reason(gc, PURPLE_REASON_OTHER_ERROR,
+				                             _("Cannot create SILC key pair\n"));
 				return FALSE;
 			}
 
--- a/libpurple/protocols/simple/simple.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/simple/simple.c	Sun Oct 07 10:28:32 2007 +0000
@@ -413,7 +413,8 @@
 		written = 0;
 	else if(written <= 0) {
 		/*TODO: do we really want to disconnect on a failure to write?*/
-		purple_connection_error(gc, _("Could not write"));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Could not write"));
 		return;
 	}
 
@@ -435,7 +436,8 @@
 	}
 
 	if(source < 0) {
-		purple_connection_error(gc, _("Could not connect"));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Could not connect"));
 		return;
 	}
 
@@ -461,7 +463,7 @@
 	if(!sip->connecting) {
 		purple_debug_info("simple", "connecting to %s port %d\n", sip->realhostname ? sip->realhostname : "{NULL}", sip->realport);
 		if (purple_proxy_connect(gc, sip->account, sip->realhostname, sip->realport, send_later_cb, gc) == NULL) {
-			purple_connection_error(gc, _("Couldn't create socket"));
+			purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR, _("Couldn't create socket"));
 		}
 		sip->connecting = TRUE;
 	}
@@ -1044,7 +1046,9 @@
 					sip->gc->wants_to_die = TRUE;
 					if (!purple_account_get_remember_password(sip->gc->account))
 						purple_account_set_password(sip->gc->account, NULL);
-					purple_connection_error(sip->gc, _("Incorrect password."));
+					purple_connection_error_reason(sip->gc,
+						PURPLE_REASON_AUTHENTICATION_FAILED,
+						_("Incorrect password."));
 					return TRUE;
 				}
 				tmp = sipmsg_find_header(msg, "WWW-Authenticate");
@@ -1058,7 +1062,8 @@
 				purple_debug_info("simple", "Unrecognized return code for REGISTER.\n");
 				if (sip->registrar.retries > SIMPLE_REGISTER_RETRY_MAX) {
 					sip->gc->wants_to_die = TRUE;
-					purple_connection_error(sip->gc, _("Unknown server response."));
+					purple_connection_error_reason(sip->gc, PURPLE_REASON_OTHER_ERROR,
+						_("Unknown server response."));
 					return TRUE;
 				}
 				sip->registerstatus = SIMPLE_REGISTER_RETRY;
@@ -1528,7 +1533,8 @@
 	}
 
 	if(source < 0) {
-		purple_connection_error(gc, _("Could not connect"));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Could not connect"));
 		return;
 	}
 
@@ -1562,7 +1568,8 @@
 	sip->listen_data = NULL;
 
 	if(listenfd == -1) {
-		purple_connection_error(sip->gc, _("Could not create listen socket"));
+		purple_connection_error_reason(sip->gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Could not create listen socket"));
 		return;
 	}
 
@@ -1585,7 +1592,9 @@
 	sip->query_data = NULL;
 
 	if (!hosts || !hosts->data) {
-		purple_connection_error(sip->gc, _("Couldn't resolve host"));
+		purple_connection_error_reason(sip->gc,
+			PURPLE_REASON_NETWORK_ERROR,
+			_("Couldn't resolve host"));
 		return;
 	}
 
@@ -1604,7 +1613,9 @@
 	sip->listen_data = purple_network_listen_range(5060, 5160, SOCK_DGRAM,
 				simple_udp_host_resolved_listen_cb, sip);
 	if (sip->listen_data == NULL) {
-		purple_connection_error(sip->gc, _("Could not create listen socket"));
+		purple_connection_error_reason(sip->gc,
+			PURPLE_REASON_NETWORK_ERROR,
+			_("Could not create listen socket"));
 		return;
 	}
 }
@@ -1617,7 +1628,9 @@
 
 	sip->listenfd = listenfd;
 	if(sip->listenfd == -1) {
-		purple_connection_error(sip->gc, _("Could not create listen socket"));
+		purple_connection_error_reason(sip->gc,
+			PURPLE_REASON_NETWORK_ERROR,
+			_("Could not create listen socket"));
 		return;
 	}
 
@@ -1630,7 +1643,9 @@
 	/* open tcp connection to the server */
 	if (purple_proxy_connect(sip->gc, sip->account, sip->realhostname,
 			sip->realport, login_cb, sip->gc) == NULL) {
-		purple_connection_error(sip->gc, _("Couldn't create socket"));
+		purple_connection_error_reason(sip->gc,
+			PURPLE_REASON_NETWORK_ERROR,
+			_("Couldn't create socket"));
 	}
 }
 
@@ -1668,7 +1683,8 @@
 		sip->listen_data = purple_network_listen_range(5060, 5160, SOCK_STREAM,
 					simple_tcp_connect_listen_cb, sip);
 		if (sip->listen_data == NULL) {
-			purple_connection_error(sip->gc, _("Could not create listen socket"));
+			purple_connection_error_reason(sip->gc, PURPLE_REASON_NETWORK_ERROR,
+				_("Could not create listen socket"));
 			return;
 		}
 	} else { /* UDP */
@@ -1676,7 +1692,8 @@
 
 		sip->query_data = purple_dnsquery_a(hostname, port, simple_udp_host_resolved, sip);
 		if (sip->query_data == NULL) {
-			purple_connection_error(sip->gc, _("Could not resolve hostname"));
+			purple_connection_error_reason(sip->gc, PURPLE_REASON_NETWORK_ERROR,
+				_("Could not resolve hostname"));
 		}
 	}
 }
@@ -1693,7 +1710,8 @@
 
 	if (strpbrk(username, " \t\v\r\n") != NULL) {
 		gc->wants_to_die = TRUE;
-		purple_connection_error(gc, _("SIP screen names may not contain whitespaces or @ symbols"));
+		purple_connection_error_reason(gc, PURPLE_REASON_INVALID_SETTINGS,
+			_("SIP screen names may not contain whitespaces or @ symbols"));
 		return;
 	}
 
--- a/libpurple/protocols/yahoo/yahoo.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/yahoo/yahoo.c	Sun Oct 07 10:28:32 2007 +0000
@@ -204,7 +204,8 @@
 		gc->wants_to_die = TRUE;
 		if (!purple_account_get_remember_password(account))
 			purple_account_set_password(account, NULL);
-		purple_connection_error(gc, _("You have signed on from another location."));
+		purple_connection_error_reason(gc, PURPLE_REASON_NAME_IN_USE,
+			_("You have signed on from another location."));
 		return;
 	}
 
@@ -2140,7 +2141,7 @@
 		fullmsg = g_strdup(msg);
 
 	gc->wants_to_die = TRUE;
-	purple_connection_error(gc, fullmsg);
+	purple_connection_error_reason(gc, PURPLE_REASON_AUTHENTICATION_FAILED, fullmsg);
 	g_free(msg);
 	g_free(fullmsg);
 }
@@ -2464,11 +2465,12 @@
 
 		tmp = g_strdup_printf(_("Lost connection with server:\n%s"),
 				strerror(errno));
-		purple_connection_error(gc, tmp);
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR, tmp);
 		g_free(tmp);
 		return;
 	} else if (len == 0) {
-		purple_connection_error(gc, _("Server closed the connection."));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+				_("Server closed the connection."));
 		return;
 	}
 
@@ -2559,7 +2561,7 @@
 		gchar *tmp;
 		tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"),
 				error_message);
-		purple_connection_error(gc, tmp);
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR, tmp);
 		g_free(tmp);
 		return;
 	}
@@ -2591,7 +2593,7 @@
 		gchar *tmp;
 		tmp = g_strdup_printf(_("Could not establish a connection with the server:\n%s"),
 				error_message);
-		purple_connection_error(gc, tmp);
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR, tmp);
 		g_free(tmp);
 		return;
 	}
@@ -2631,11 +2633,12 @@
 
 		tmp = g_strdup_printf(_("Lost connection with server:\n%s"),
 				strerror(errno));
-		purple_connection_error(gc, tmp);
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR, tmp);
 		g_free(tmp);
 		return;
 	} else if (len == 0) {
-		purple_connection_error(gc, _("Server closed the connection."));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Server closed the connection."));
 		return;
 	}
 
@@ -2650,7 +2653,8 @@
 
 	if ((strncmp(buf, "HTTP/1.0 302", strlen("HTTP/1.0 302")) &&
 			  strncmp(buf, "HTTP/1.1 302", strlen("HTTP/1.1 302")))) {
-		purple_connection_error(gc, _("Received unexpected HTTP response from server."));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+			_("Received unexpected HTTP response from server."));
 		return;
 	}
 
@@ -2672,9 +2676,10 @@
 	yd->rxlen = 0;
 	/* Now we have our cookies to login with.  I'll go get the milk. */
 	if (purple_proxy_connect(gc, account, "wcs2.msg.dcn.yahoo.com",
-			       purple_account_get_int(account, "port", YAHOO_PAGER_PORT),
-			       yahoo_got_web_connected, gc) == NULL) {
-		purple_connection_error(gc, _("Connection problem"));
+	                         purple_account_get_int(account, "port", YAHOO_PAGER_PORT),
+	                         yahoo_got_web_connected, gc) == NULL) {
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+		                               _("Connection problem"));
 		return;
 	}
 }
@@ -2702,7 +2707,7 @@
 		gc->inpa = 0;
 		tmp = g_strdup_printf(_("Lost connection with %s:\n%s"),
 				"login.yahoo.com:80", strerror(errno));
-		purple_connection_error(gc, tmp);
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR, tmp);
 		g_free(tmp);
 		return;
 	}
@@ -2727,7 +2732,7 @@
 		gchar *tmp;
 		tmp = g_strdup_printf(_("Could not establish a connection with %s:\n%s"),
 				"login.yahoo.com:80", error_message);
-		purple_connection_error(gc, tmp);
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR, tmp);
 		g_free(tmp);
 		return;
 	}
@@ -2811,7 +2816,8 @@
 
 	if (error_message != NULL)
 	{
-		purple_connection_error(gc, error_message);
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+		                               error_message);
 		return;
 	}
 
@@ -2860,7 +2866,8 @@
 	g_hash_table_destroy(hash);
 	yd->auth = g_string_free(url, FALSE);
 	if (purple_proxy_connect(gc, account, "login.yahoo.com", 80, yahoo_got_cookies, gc) == NULL) {
-		purple_connection_error(gc, _("Connection problem"));
+		purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+		                               _("Connection problem"));
 		return;
 	}
 
@@ -2963,7 +2970,8 @@
 		                       purple_account_get_int(account, "port", YAHOO_PAGER_PORT),
 		                       yahoo_got_connected, gc) == NULL)
 		{
-			purple_connection_error(gc, _("Connection problem"));
+			purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+			                               _("Connection problem"));
 			return;
 		}
 	} else {
@@ -2973,7 +2981,8 @@
 		                       purple_account_get_int(account, "port", YAHOO_PAGER_PORT),
 		                       yahoo_got_connected, gc) == NULL)
 		{
-			purple_connection_error(gc, _("Connection problem"));
+			purple_connection_error_reason(gc, PURPLE_REASON_NETWORK_ERROR,
+			                               _("Connection problem"));
 			return;
 		}
 	}
--- a/libpurple/protocols/yahoo/yahoo_packet.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/yahoo/yahoo_packet.c	Sun Oct 07 10:28:32 2007 +0000
@@ -304,7 +304,8 @@
 		return;
 	else if (ret < 0) {
 		/* TODO: what to do here - do we really have to disconnect? */
-		purple_connection_error(yd->gc, _("Write Error"));
+		purple_connection_error_reason(yd->gc, PURPLE_REASON_NETWORK_ERROR,
+		                               _("Write Error"));
 		return;
 	}
 
--- a/libpurple/protocols/yahoo/ycht.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/protocols/yahoo/ycht.c	Sun Oct 07 10:28:32 2007 +0000
@@ -285,7 +285,8 @@
 	else if (ret <= 0) {
 		/* TODO: error handling */
 /*
-		purple_connection_error(purple_account_get_connection(irc->account),
+		purple_connection_error_reason(purple_account_get_connection(irc->account),
+			      PURPLE_REASON_NETWORK_ERROR,
 			      _("Server has disconnected"));
 */
 		return;
--- a/libpurple/sslconn.h	Sun Oct 07 00:49:17 2007 +0000
+++ b/libpurple/sslconn.h	Sun Oct 07 10:28:32 2007 +0000
@@ -26,11 +26,6 @@
 #ifndef _PURPLE_SSLCONN_H_
 #define _PURPLE_SSLCONN_H_
 
-#include "certificate.h"
-#include "proxy.h"
-
-#define PURPLE_SSL_DEFAULT_PORT 443
-
 /** Possible SSL errors. */
 typedef enum
 {
@@ -39,6 +34,11 @@
 	PURPLE_SSL_CERTIFICATE_INVALID = 3
 } PurpleSslErrorType;
 
+#include "certificate.h"
+#include "proxy.h"
+
+#define PURPLE_SSL_DEFAULT_PORT 443
+
 typedef struct _PurpleSslConnection PurpleSslConnection;
 
 typedef void (*PurpleSslInputFunction)(gpointer, PurpleSslConnection *,
@@ -126,9 +126,9 @@
 	/** Obtains the certificate chain provided by the peer
 	 *
 	 * @param gsc   Connection context
-	 * @return      A newly allocated list of #PurpleCertificate containing the
-	 *              certificates the peer provided.
-	 * @see purple_ssl_get_peer_certificates
+	 * @return      A newly allocated list containing the certificates
+	 *              the peer provided.
+	 * @see PurpleCertificate
 	 * @todo        Decide whether the ordering of certificates in this
 	 *              list can be guaranteed.
 	 */
--- a/pidgin/gtkconn.c	Sun Oct 07 00:49:17 2007 +0000
+++ b/pidgin/gtkconn.c	Sun Oct 07 10:28:32 2007 +0000
@@ -42,6 +42,7 @@
 #define INITIAL_RECON_DELAY_MAX 60000
 
 #define MAX_RECON_DELAY 600000
+#define MAX_RACCOON_DELAY "shorter in urban areas"
 
 typedef struct {
 	int delay;
@@ -137,7 +138,9 @@
 }
 
 static void
-pidgin_connection_report_disconnect(PurpleConnection *gc, const char *text)
+pidgin_connection_report_disconnect_reason (PurpleConnection *gc,
+                                            PurpleDisconnectReason reason,
+                                            const char *text)
 {
 	PurpleAccount *account = NULL;
 	PidginAutoRecon *info;
@@ -147,7 +150,7 @@
 	info = g_hash_table_lookup(auto_reconns, account);
 
 	pidgin_blist_update_account_error_state(account, text);
-	if (!gc->wants_to_die) {
+	if (!purple_connection_reason_is_fatal (reason)) {
 		if (info == NULL) {
 			info = g_new0(PidginAutoRecon, 1);
 			g_hash_table_insert(auto_reconns, account, info);
@@ -259,10 +262,10 @@
 	pidgin_connection_connected,
 	pidgin_connection_disconnected,
 	pidgin_connection_notice,
-	pidgin_connection_report_disconnect,
+	NULL, /* report_disconnect */
 	pidgin_connection_network_connected,
 	pidgin_connection_network_disconnected,
-	NULL,
+	pidgin_connection_report_disconnect_reason,
 	NULL,
 	NULL,
 	NULL