diff --git a/libpurple/protocols/ircv3/purpleircv3connection.h b/libpurple/protocols/ircv3/purpleircv3connection.h
--- a/libpurple/protocols/ircv3/purpleircv3connection.h
+++ b/libpurple/protocols/ircv3/purpleircv3connection.h
@@ -49,6 +49,18 @@
 
 G_GNUC_INTERNAL void purple_ircv3_connection_writef(PurpleIRCv3Connection *connection, const char *format, ...) G_GNUC_PRINTF(2, 3);
 
+/**
+ * purple_ircv3_connection_get_capabilities:
+ * @connection: The instance.
+ *
+ * Gets the list of capabilities that the server supplied during registration.
+ *
+ * Returns: The list of capabilities that the server supports.
+ */
+const char *purple_ircv3_connection_get_capabilities(PurpleIRCv3Connection *connection);
+
+G_GNUC_INTERNAL void purple_ircv3_connection_append_capabilities(PurpleIRCv3Connection *connection, const char *capabilities);
+
 G_END_DECLS
 
 #endif /* PURPLE_IRCV3_CONNECTION_H */
# HG changeset patch
# Node ID 52c7819dc472
# Parent  ebe4ff278b02
diff --git a/libpurple/protocols/ircv3/purpleircv3connection.c b/libpurple/protocols/ircv3/purpleircv3connection.c
--- a/libpurple/protocols/ircv3/purpleircv3connection.c
+++ b/libpurple/protocols/ircv3/purpleircv3connection.c
@@ -27,6 +27,7 @@
 	PROP_0,
 	PROP_ACCOUNT,
 	PROP_CANCELLABLE,
+	PROP_CAPABILITIES,
 	N_PROPERTIES,
 };
 static GParamSpec *properties[N_PROPERTIES] = {NULL, };
@@ -46,6 +47,8 @@
 	PurpleQueuedOutputStream *output;
 
 	PurpleIRCv3Parser *parser;
+
+	gchar *capabilities;
 };
 
 G_DEFINE_DYNAMIC_TYPE(PurpleIRCv3Connection, purple_ircv3_connection,
@@ -232,6 +235,8 @@
 	                                    purple_connection);
 
 	/* Send our registration commands. */
+	purple_ircv3_connection_writef(connection, "CAP LS %s",
+	                               PURPLE_IRCV3_CONNECTION_CAP_VERSION);
 	purple_ircv3_connection_send_user_command(connection);
 	purple_ircv3_connection_send_nick_command(connection);
 }
@@ -254,6 +259,10 @@
 			g_value_set_object(value,
 			                   purple_ircv3_connection_get_cancellable(connection));
 			break;
+		case PROP_CAPABILITIES:
+			g_value_set_string(value,
+			                   purple_ircv3_connection_get_capabilities(connection));
+			break;
 		default:
 			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
 			break;
@@ -300,6 +309,8 @@
 	g_clear_error(&connection->validate_error);
 	g_clear_pointer(&connection->server_name, g_free);
 
+	g_clear_pointer(&connection->capabilities, g_free);
+
 	G_OBJECT_CLASS(purple_ircv3_connection_parent_class)->finalize(obj);
 }
 
@@ -381,6 +392,22 @@
 		G_TYPE_CANCELLABLE,
 		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
+	/**
+	 * PurpleIRCv3Connection:capabilties:
+	 *
+	 * The capablities that the server supports.
+	 *
+	 * This is is created during registration of the connection and is useful
+	 * for troubleshooting or just reporting them to end users.
+	 *
+	 * Since: 3.0.0
+	 */
+	properties[PROP_CAPABILITIES] = g_param_spec_string(
+		"capabilities", "capabilities",
+		"The capabilities that the server supports",
+		NULL,
+		G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
 	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
 }
 
@@ -529,3 +556,33 @@
 
 	g_bytes_unref(bytes);
 }
+
+const char *
+purple_ircv3_connection_get_capabilities(PurpleIRCv3Connection *connection) {
+	g_return_val_if_fail(PURPLE_IRCV3_IS_CONNECTION(connection), NULL);
+
+	return connection->capabilities;
+}
+
+void
+purple_ircv3_connection_append_capabilities(PurpleIRCv3Connection *connection,
+                                            const char *capabilities)
+{
+	g_return_if_fail(PURPLE_IRCV3_IS_CONNECTION(connection));
+	g_return_if_fail(capabilities != NULL);
+
+	if(connection->capabilities == NULL) {
+		connection->capabilities = g_strdup(capabilities);
+	} else {
+		char *tmp = connection->capabilities;
+
+		connection->capabilities = g_strdup_printf("%s %s",
+		                                           connection->capabilities,
+		                                           capabilities);
+
+		g_free(tmp);
+	}
+
+	g_object_notify_by_pspec(G_OBJECT(connection),
+	                         properties[PROP_CAPABILITIES]);
+}
diff --git a/libpurple/protocols/ircv3/purpleircv3core.h b/libpurple/protocols/ircv3/purpleircv3core.h
--- a/libpurple/protocols/ircv3/purpleircv3core.h
+++ b/libpurple/protocols/ircv3/purpleircv3core.h
@@ -29,4 +29,6 @@
 
 #define PURPLE_IRCV3_CONNECTION_KEY "ircv3-connection"
 
+#define PURPLE_IRCV3_CONNECTION_CAP_VERSION "302"
+
 #endif /* PURPLE_IRCV3_CORE_H */
diff --git a/libpurple/protocols/ircv3/purpleircv3messagehandlers.h b/libpurple/protocols/ircv3/purpleircv3messagehandlers.h
--- a/libpurple/protocols/ircv3/purpleircv3messagehandlers.h
+++ b/libpurple/protocols/ircv3/purpleircv3messagehandlers.h
@@ -55,6 +55,8 @@
 
 G_GNUC_INTERNAL gboolean purple_ircv3_messager_handler_ping(GHashTable *tags, const char *source, const char *command, guint n_params, GStrv params, GError **error, gpointer data);
 
+G_GNUC_INTERNAL gboolean purple_ircv3_messager_handler_cap(GHashTable *tags, const char *source, const char *command, guint n_params, GStrv params, GError **error, gpointer data);
+
 G_END_DECLS
 
 #endif /* PURPLE_IRCV3_MESSAGE_HANDLERS_H */
diff --git a/libpurple/protocols/ircv3/purpleircv3messagehandlers.c b/libpurple/protocols/ircv3/purpleircv3messagehandlers.c
--- a/libpurple/protocols/ircv3/purpleircv3messagehandlers.c
+++ b/libpurple/protocols/ircv3/purpleircv3messagehandlers.c
@@ -19,7 +19,11 @@
 #include "purpleircv3messagehandlers.h"
 
 #include "purpleircv3connection.h"
+#include "purpleircv3core.h"
 
+/******************************************************************************
+ * Fallback
+ *****************************************************************************/
 gboolean
 purple_ircv3_messager_handler_fallback(GHashTable *tags, const char *source,
                                        const char *command, guint n_params,
@@ -39,6 +43,9 @@
 	return TRUE;
 }
 
+/******************************************************************************
+ * Ping
+ *****************************************************************************/
 gboolean
 purple_ircv3_messager_handler_ping(GHashTable *tags, const char *source,
                                    const char *command, guint n_params,
@@ -55,3 +62,73 @@
 
 	return TRUE;
 }
+
+/******************************************************************************
+ * Capablities
+ *****************************************************************************/
+static gboolean
+purple_ircv3_messager_handler_cap_list(guint n_params, GStrv params,
+                                       GError **error, gpointer data)
+{
+	PurpleIRCv3Connection *connection = data;
+
+	/* Check if we have more messages comming. */
+	if(n_params > 1 && purple_strequal(params[0], "*")) {
+		purple_ircv3_connection_append_capabilities(connection, params[1]);
+	} else {
+		purple_ircv3_connection_append_capabilities(connection, params[0]);
+
+		g_message("**** capabilities-list: %s",
+		          purple_ircv3_connection_get_capabilities(connection));
+
+		purple_ircv3_connection_writef(connection, "CAP END");
+	}
+
+	return TRUE;
+}
+
+gboolean
+purple_ircv3_messager_handler_cap(GHashTable *tags, const char *source,
+                                  const char *command, guint n_params,
+                                  GStrv params, GError **error, gpointer data)
+{
+	const char *subcommand = NULL;
+	guint n_subparams = 0;
+	GStrv subparams = NULL;
+
+	if(n_params < 2) {
+		return FALSE;
+	}
+
+	/* Initialize some variables to make it easier to call our sub command
+	 * handlers.
+	 *
+	 * params[0] is the nick or * if it hasn't been negotiated yet, we don't
+	 * have a need for this, so we ignore it.
+	 *
+	 * params[1] is the CAP subcommand sent from the server. We use it here
+	 * purely for dispatching to our subcommand handlers.
+	 *
+	 * params[2] and higher are the parameters to the subcommand. To make the
+	 * code a bit easier all around, we subtract 2 from n_params to remove
+	 * references to the nick and subcommand name. Like wise, we add 2 to the
+	 * params GStrv which will now point to the second item in the array again
+	 * ignoring the nick and subcommand.
+	 */
+	subcommand = params[1];
+	n_subparams = n_params - 2;
+	subparams = params + 2;
+
+	/* Dispatch the subcommand. */
+	if(purple_strequal(subcommand, "LS") ||
+	   purple_strequal(subcommand, "LIST"))
+	{
+		return purple_ircv3_messager_handler_cap_list(n_subparams, subparams,
+		                                              error, data);
+	}
+
+	g_set_error(error, PURPLE_IRCV3_DOMAIN, 0,
+	            "No handler for CAP subcommand %s", subcommand);
+
+	return FALSE;
+}
diff --git a/libpurple/protocols/ircv3/purpleircv3parser.c b/libpurple/protocols/ircv3/purpleircv3parser.c
--- a/libpurple/protocols/ircv3/purpleircv3parser.c
+++ b/libpurple/protocols/ircv3/purpleircv3parser.c
@@ -356,4 +356,6 @@
 
 	purple_ircv3_parser_add_handler(parser, "PING",
 	                                purple_ircv3_messager_handler_ping);
+	purple_ircv3_parser_add_handler(parser, "CAP",
+	                                purple_ircv3_messager_handler_cap);
 }
