From 56d0036f39305dd0408a91f29db0ef806f334956 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <rishi@gnu.org>
Date: Fri, 25 Mar 2011 16:48:44 +0200
Subject: [PATCH] Handle ERROR messages

A new MessageSpec was added for it.

Fixes: https://bugs.freedesktop.org/35239
---
 src/idle-connection.c |   52 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/idle-parser.c     |    1 +
 src/idle-parser.h     |    3 +-
 3 files changed, 55 insertions(+), 1 deletions(-)

diff --git a/src/idle-connection.c b/src/idle-connection.c
index d8fada9..da7d408 100644
--- a/src/idle-connection.c
+++ b/src/idle-connection.c
@@ -28,6 +28,7 @@
 #define DBUS_API_SUBJECT_TO_CHANGE
 #include <dbus/dbus-glib.h>
 
+#include <telepathy-glib/dbus.h>
 #include <telepathy-glib/enums.h>
 #include <telepathy-glib/errors.h>
 #include <telepathy-glib/interfaces.h>
@@ -190,6 +191,7 @@ static void _iface_disconnected(TpBaseConnection *self);
 static void _iface_shut_down(TpBaseConnection *self);
 static gboolean _iface_start_connecting(TpBaseConnection *self, GError **error);
 
+static IdleParserHandlerResult _error_handler(IdleParser *parser, IdleParserMessageCode code, GValueArray *args, gpointer user_data);
 static IdleParserHandlerResult _erroneous_nickname_handler(IdleParser *parser, IdleParserMessageCode code, GValueArray *args, gpointer user_data);
 static IdleParserHandlerResult _nick_handler(IdleParser *parser, IdleParserMessageCode code, GValueArray *args, gpointer user_data);
 static IdleParserHandlerResult _nickname_in_use_handler(IdleParser *parser, IdleParserMessageCode code, GValueArray *args, gpointer user_data);
@@ -636,6 +638,7 @@ static void _start_connecting_continue(IdleConnection *conn) {
 
 	g_signal_connect(sconn, "received", (GCallback)(sconn_received_cb), conn);
 
+	idle_parser_add_handler(conn->parser, IDLE_PARSER_CMD_ERROR, _error_handler, conn);
 	idle_parser_add_handler(conn->parser, IDLE_PARSER_NUMERIC_ERRONEOUSNICKNAME, _erroneous_nickname_handler, conn);
 	idle_parser_add_handler(conn->parser, IDLE_PARSER_NUMERIC_NICKNAMEINUSE, _nickname_in_use_handler, conn);
 	idle_parser_add_handler(conn->parser, IDLE_PARSER_NUMERIC_WELCOME, _welcome_handler, conn);
@@ -851,6 +854,55 @@ idle_connection_get_max_message_length(IdleConnection *conn)
 	return IRC_MSG_MAXLEN - 100;
 }
 
+static IdleParserHandlerResult _error_handler(IdleParser *parser, IdleParserMessageCode code, GValueArray *args, gpointer user_data) {
+	IdleConnection *conn = IDLE_CONNECTION(user_data);
+	GHashTable *details = NULL;
+	TpConnectionStatus status = conn->parent.status;
+	TpConnectionStatusReason reason;
+	const gchar *msg;
+	const gchar *begin;
+	const gchar *end;
+	const gchar *error_name;
+
+	if (status == TP_CONNECTION_STATUS_DISCONNECTED)
+		return IDLE_PARSER_HANDLER_RESULT_HANDLED;
+
+	switch (status) {
+		case TP_CONNECTION_STATUS_CONNECTING:
+			reason = TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED;
+			error_name = TP_ERROR_STR_AUTHENTICATION_FAILED;
+			break;
+
+		default:
+			reason = TP_CONNECTION_STATUS_REASON_NETWORK_ERROR;
+			error_name = TP_ERROR_STR_NETWORK_ERROR;
+			break;
+	}
+
+	msg = g_value_get_string(g_value_array_get_nth(args, 0));
+	begin = strchr(msg, '(');
+	end = strrchr(msg, ')');
+
+	if (begin != NULL && end != NULL && begin < end - 1) {
+		gchar *server_msg;
+		guint length;
+
+		begin++;
+		end--;
+		length = end - begin + 1;
+		server_msg = g_strndup(begin, length);
+		details = tp_asv_new ("server-message", G_TYPE_STRING, server_msg, NULL);
+		g_free(server_msg);
+	}
+
+	tp_base_connection_disconnect_with_dbus_error(TP_BASE_CONNECTION(conn), error_name, details, reason);
+
+	if (details != NULL)
+		g_hash_table_unref(details);
+
+	return IDLE_PARSER_HANDLER_RESULT_HANDLED;
+}
+
 static IdleParserHandlerResult _erroneous_nickname_handler(IdleParser *parser, IdleParserMessageCode code, GValueArray *args, gpointer user_data) {
 	IdleConnection *conn = IDLE_CONNECTION(user_data);
 
diff --git a/src/idle-parser.c b/src/idle-parser.c
index 5fba70c..446d43f 100644
--- a/src/idle-parser.c
+++ b/src/idle-parser.c
@@ -72,6 +72,7 @@ struct _MessageSpec {
  * '.' - Same as ':', but optional
  */
 static const MessageSpec message_specs[] = {
+	{"ERROR", "I:", IDLE_PARSER_CMD_ERROR},
 	{"PING", "Is", IDLE_PARSER_CMD_PING},
 
 	{"INVITE", "cIcr", IDLE_PARSER_PREFIXCMD_INVITE},
diff --git a/src/idle-parser.h b/src/idle-parser.h
index 47e97b8..f5053cb 100644
--- a/src/idle-parser.h
+++ b/src/idle-parser.h
@@ -46,7 +46,8 @@ G_BEGIN_DECLS
 	(G_TYPE_INSTANCE_GET_CLASS((obj), IDLE_TYPE_PARSER, IdleParserClass))
 
 typedef enum {
-	IDLE_PARSER_CMD_PING = 0,
+	IDLE_PARSER_CMD_ERROR = 0,
+	IDLE_PARSER_CMD_PING,
 
 	IDLE_PARSER_PREFIXCMD_INVITE,
 	IDLE_PARSER_PREFIXCMD_JOIN,
-- 
1.7.4