# HG changeset patch
# Node ID 42587dfc4129
# Parent  bead065eac93
diff --git a/ibis/ibiscapabilities.c b/ibis/ibiscapabilities.c
--- a/ibis/ibiscapabilities.c
+++ b/ibis/ibiscapabilities.c
@@ -62,6 +62,10 @@
 	gatomicrefcount wait_counters;
 };
 
+static gboolean
+ibis_capabilities_message_cb(IbisClient *client, const char *command,
+                             IbisMessage *message, gpointer data);
+
 /******************************************************************************
  * Helpers
  *****************************************************************************/
@@ -74,6 +78,12 @@
 	if(g_set_object(&capabilities->client, client)) {
 		g_object_notify_by_pspec(G_OBJECT(capabilities),
 		                         properties[PROP_CLIENT]);
+
+		if(IBIS_IS_CLIENT(capabilities->client)) {
+			g_signal_connect_object(capabilities->client, "message::CAP",
+			                        G_CALLBACK(ibis_capabilities_message_cb),
+			                        capabilities, G_CONNECT_DEFAULT);
+		}
 	}
 }
 
@@ -103,6 +113,90 @@
 }
 
 /******************************************************************************
+ * Command handlers
+ *****************************************************************************/
+static void
+ibis_capabilities_handle_list(IbisCapabilities *capabilities, guint n_params,
+                              GStrv params)
+{
+	gboolean done = TRUE;
+	gchar **parts = NULL;
+
+	/* Check if we have more messages coming. */
+	if(n_params > 1 && ibis_str_equal(params[0], "*")) {
+		parts = g_strsplit(params[1], " ", -1);
+		done = FALSE;
+	} else {
+		parts = g_strsplit(params[0], " ", -1);
+	}
+
+	/* Add each capability to our hash table, splitting the keys and values. */
+	for(int i = 0; parts[i] != NULL; i++) {
+		ibis_capabilities_add(capabilities, parts[i]);
+	}
+
+	g_strfreev(parts);
+
+	if(done) {
+		g_signal_emit(capabilities, signals[SIG_READY], 0, signals[SIG_READY]);
+
+		/* If no capabilities were requested after we emitted the ready signal
+		 * we're done with capability negotiation.
+		 */
+		if(capabilities->requests->len == 0) {
+			ibis_capabilities_remove_wait(capabilities);
+		}
+	}
+}
+
+static void
+ibis_capabilities_handle_ack_nak(IbisCapabilities *capabilities, GStrv params,
+                                 guint sig, const char *method, GError **error)
+{
+	char *caps = g_strjoinv(" ", params);
+	guint index = 0;
+	gboolean found = FALSE;
+
+	g_signal_emit(capabilities, sig, g_quark_from_string(caps), caps);
+
+	found = g_ptr_array_find_with_equal_func(capabilities->requests, caps,
+	                                         g_str_equal, &index);
+	if(found) {
+		g_ptr_array_remove_index(capabilities->requests, index);
+	} else {
+		g_set_error(error, IBIS_DOMAIN, 0,
+		            "received CAP %s for unknown capability %s", method, caps);
+	}
+	g_free(caps);
+
+	if(capabilities->requests->len == 0) {
+		ibis_capabilities_remove_wait(capabilities);
+	}
+}
+
+static void
+ibis_capabilities_handle_new(IbisCapabilities *capabilities, guint n_params,
+                             GStrv params)
+{
+	for(guint i = 0; i < n_params; i++) {
+		ibis_capabilities_add(capabilities, params[i]);
+	}
+
+	g_signal_emit(capabilities, signals[SIG_NEW], 0, params);
+}
+
+static void
+ibis_capabilities_handle_del(IbisCapabilities *capabilities, guint n_params,
+                             GStrv params)
+{
+	for(guint i = 0; i < n_params; i++) {
+		g_hash_table_remove(capabilities->caps, params[i]);
+	}
+
+	g_signal_emit(capabilities, signals[SIG_DEL], 0, params);
+}
+
+/******************************************************************************
  * Callbacks
  *****************************************************************************/
 static void
@@ -114,6 +208,77 @@
 	ibis_capabilities_lookup_and_request(capabilities, "msgid");
 }
 
+static gboolean
+ibis_capabilities_message_cb(IbisClient *client,
+                             G_GNUC_UNUSED const char *command,
+                             IbisMessage *message, gpointer data)
+{
+	IbisCapabilities *capabilities = data;
+	GError *error = NULL;
+	GStrv params = NULL;
+	GStrv subparams = NULL;
+	char *subcommand = NULL;
+	guint n_params = 0;
+	guint n_subparams = 0;
+
+	params = ibis_message_get_params(message);
+	if(params != NULL) {
+		n_params = g_strv_length(params);
+	}
+
+	if(n_params < 2) {
+		return FALSE;
+	}
+
+	capabilities = ibis_client_get_capabilities(client);
+
+	/* 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 = g_utf8_strup(params[1], -1);
+	n_subparams = n_params - 2;
+	subparams = params + 2;
+
+	/* Dispatch the subcommand. */
+	if(ibis_str_equal(subcommand, "LS") || ibis_str_equal(subcommand, "LIST"))
+	{
+		ibis_capabilities_handle_list(capabilities, n_subparams, subparams);
+	} else if(ibis_str_equal(subcommand, "ACK")) {
+		ibis_capabilities_handle_ack_nak(capabilities, subparams,
+		                                 signals[SIG_ACK], "ACK", &error);
+	} else if(ibis_str_equal(subcommand, "NAK")) {
+		ibis_capabilities_handle_ack_nak(capabilities, subparams,
+		                                 signals[SIG_NAK], "NAK", &error);
+	} else if(ibis_str_equal(subcommand, "NEW")) {
+		ibis_capabilities_handle_new(capabilities, n_subparams, subparams);
+	} else if(ibis_str_equal(subcommand, "DEL")) {
+		ibis_capabilities_handle_del(capabilities, n_subparams, subparams);
+	} else {
+		error = g_error_new(IBIS_DOMAIN, 0,
+		                    "No handler for CAP subcommand '%s'", subcommand);
+	}
+
+	if(error != NULL) {
+		ibis_message_take_error(message, error);
+	}
+
+	g_clear_pointer(&subcommand, g_free);
+
+	return TRUE;
+}
+
 /******************************************************************************
  * IbisCapabilities Implementation
  *****************************************************************************/
@@ -369,100 +534,6 @@
 }
 
 /******************************************************************************
- * Command handlers
- *****************************************************************************/
-static gboolean
-ibis_capabilities_handle_list(IbisCapabilities *capabilities, guint n_params,
-                              GStrv params, G_GNUC_UNUSED GError **error)
-{
-	gboolean done = TRUE;
-	gchar **parts = NULL;
-
-	/* Check if we have more messages coming. */
-	if(n_params > 1 && ibis_str_equal(params[0], "*")) {
-		parts = g_strsplit(params[1], " ", -1);
-		done = FALSE;
-	} else {
-		parts = g_strsplit(params[0], " ", -1);
-	}
-
-	/* Add each capability to our hash table, splitting the keys and values. */
-	for(int i = 0; parts[i] != NULL; i++) {
-		ibis_capabilities_add(capabilities, parts[i]);
-	}
-
-	g_strfreev(parts);
-
-	if(done) {
-		g_signal_emit(capabilities, signals[SIG_READY], 0, signals[SIG_READY]);
-
-		/* If no capabilities were requested after we emitted the ready signal
-		 * we're done with capability negotiation.
-		 */
-		if(capabilities->requests->len == 0) {
-			ibis_capabilities_remove_wait(capabilities);
-		}
-	}
-
-	return TRUE;
-}
-
-static gboolean
-ibis_capabilities_handle_ack_nak(IbisCapabilities *capabilities, GStrv params,
-                                 guint sig, const char *method, GError **error)
-{
-	char *caps = g_strjoinv(" ", params);
-	guint index = 0;
-	gboolean found = FALSE;
-	gboolean ret = TRUE;
-
-	g_signal_emit(capabilities, sig, g_quark_from_string(caps), caps);
-
-	found = g_ptr_array_find_with_equal_func(capabilities->requests, caps,
-	                                         g_str_equal, &index);
-	if(found) {
-		g_ptr_array_remove_index(capabilities->requests, index);
-	} else {
-		g_set_error(error, IBIS_DOMAIN, 0,
-		            "received CAP %s for unknown capability %s", method, caps);
-		ret = FALSE;
-	}
-	g_free(caps);
-
-	if(capabilities->requests->len == 0) {
-		ibis_capabilities_remove_wait(capabilities);
-	}
-
-	return ret;
-}
-
-static gboolean
-ibis_capabilities_handle_new(IbisCapabilities *capabilities, guint n_params,
-                             GStrv params, G_GNUC_UNUSED GError **error)
-{
-	for(guint i = 0; i < n_params; i++) {
-		ibis_capabilities_add(capabilities, params[i]);
-	}
-
-	g_signal_emit(capabilities, signals[SIG_NEW], 0, params);
-
-	return TRUE;
-}
-
-static gboolean
-ibis_capabilities_handle_del(IbisCapabilities *capabilities, guint n_params,
-                             GStrv params, G_GNUC_UNUSED GError **error)
-{
-	for(guint i = 0; i < n_params; i++) {
-		g_hash_table_remove(capabilities->caps, params[i]);
-	}
-
-	g_signal_emit(capabilities, signals[SIG_DEL], 0, params);
-
-	return TRUE;
-}
-
-/******************************************************************************
  * Public API
  *****************************************************************************/
 IbisCapabilities *
@@ -483,75 +554,6 @@
 	ibis_client_write(capabilities->client, message);
 }
 
-gboolean
-ibis_capabilities_message_handler(IbisMessage *message, GError **error,
-                                  gpointer data)
-{
-	IbisClient *client = data;
-	IbisCapabilities *capabilities = NULL;
-	GStrv params = NULL;
-	GStrv subparams = NULL;
-	const char *subcommand = NULL;
-	guint n_params = 0;
-	guint n_subparams = 0;
-
-	params = ibis_message_get_params(message);
-	if(params != NULL) {
-		n_params = g_strv_length(params);
-	}
-
-	if(n_params < 2) {
-		return FALSE;
-	}
-
-	capabilities = ibis_client_get_capabilities(client);
-
-	/* 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(ibis_str_equal(subcommand, "LS") || ibis_str_equal(subcommand, "LIST"))
-	{
-		return ibis_capabilities_handle_list(capabilities, n_subparams,
-		                                     subparams, error);
-	} else if(ibis_str_equal(subcommand, "ACK")) {
-		return ibis_capabilities_handle_ack_nak(capabilities, subparams,
-		                                        signals[SIG_ACK], "ACK",
-		                                        error);
-	} else if(ibis_str_equal(subcommand, "NAK")) {
-		return ibis_capabilities_handle_ack_nak(capabilities, subparams,
-		                                        signals[SIG_NAK], "NAK",
-		                                        error);
-	} else if(ibis_str_equal(subcommand, "NEW")) {
-		return ibis_capabilities_handle_new(capabilities, n_subparams,
-		                                    subparams, error);
-	} else if(ibis_str_equal(subcommand, "DEL")) {
-		return ibis_capabilities_handle_del(capabilities, n_subparams,
-		                                    subparams, error);
-	}
-
-	g_set_error(error, IBIS_DOMAIN, 0,
-	            "No handler for CAP subcommand %s", subcommand);
-
-	return FALSE;
-}
-
 IbisClient *
 ibis_capabilities_get_client(IbisCapabilities *capabilities) {
 	g_return_val_if_fail(IBIS_IS_CAPABILITIES(capabilities), NULL);
