# HG changeset patch
# Node ID 0537d4c37571c65a82b6ae5f018d7ac637fca998
# Parent  8a528b3b471e04cd917fab7f5d15f4b63d3634d8
diff --git a/ibis-cli/ibiscli.c b/ibis-cli/ibiscli.c
--- a/ibis-cli/ibiscli.c
+++ b/ibis-cli/ibiscli.c
@@ -35,6 +35,7 @@
 /******************************************************************************
  * Command line options
  *****************************************************************************/
+static char *alt_nick = NULL;
 static char *join_channels = NULL;
 static char *nick = NULL;
 static char *server = NULL;
@@ -49,6 +50,13 @@
 
 static GOptionEntry cli_options[] = {
 	{
+		.long_name = "alt-nick",
+		.short_name = 'a',
+		.arg = G_OPTION_ARG_STRING,
+		.arg_data = &alt_nick,
+		.description = N_("An alternate nickname to use."),
+		.arg_description = N_("NICK"),
+	}, {
 		.long_name = "join-channels",
 		.short_name = 'j',
 		.arg = G_OPTION_ARG_STRING,
@@ -148,7 +156,11 @@
 	/* Hold the application so we stick around. */
 	g_application_hold(application);
 
-	ibis_client_set_nick(client, nick);
+	if(!ibis_str_is_empty(nick)) {
+		ibis_client_set_nick(client, nick);
+	}
+
+	ibis_client_set_alt_nick(client, alt_nick);
 
 	if(require_sasl) {
 		HaslContext *hasl_context = hasl_context_new();
@@ -315,6 +327,7 @@
 	}
 	g_clear_object(&client);
 
+	g_clear_pointer(&alt_nick, g_free);
 	g_clear_pointer(&join_channels, g_free);
 	g_clear_pointer(&nick, g_free);
 	g_clear_pointer(&password, g_free);
diff --git a/ibis/ibisclient.c b/ibis/ibisclient.c
--- a/ibis/ibisclient.c
+++ b/ibis/ibisclient.c
@@ -121,6 +121,42 @@
 	}
 }
 
+static const char *
+ibis_client_get_usable_realname(IbisClient *client) {
+	if(!ibis_str_is_empty(client->realname)) {
+		return client->realname;
+	}
+
+	if(!ibis_str_is_empty(client->nick)) {
+		return client->nick;
+	}
+
+	if(!ibis_str_is_empty(client->alt_nick)) {
+		return client->alt_nick;
+	}
+
+	return _("unknown");
+}
+
+static const char *
+ibis_client_get_usable_username(IbisClient *client) {
+	g_return_val_if_fail(IBIS_IS_CLIENT(client), NULL);
+
+	if(!ibis_str_is_empty(client->username)) {
+		return client->username;
+	}
+
+	if(!ibis_str_is_empty(client->nick)) {
+		return client->nick;
+	}
+
+	if(!ibis_str_is_empty(client->alt_nick)) {
+		return client->alt_nick;
+	}
+
+	return _("unknown");
+}
+
 static void
 ibis_client_set_connected(IbisClient *client, gboolean connected) {
 	g_return_if_fail(IBIS_IS_CLIENT(client));
@@ -183,6 +219,45 @@
 }
 
 static void
+ibis_client_attempt_nick(IbisClient *client) {
+	const char *candidate_nick = NULL;
+
+	/* This should only be called by the read callback, but we still make sure
+	 * registration hasn't completed before we attempt to automatically change
+	 * the user's nickname.
+	 */
+	if(client->registered) {
+		return;
+	}
+
+	if(ibis_str_is_empty(client->active_nick)) {
+		candidate_nick = client->nick;
+	}
+
+	if(ibis_str_is_empty(candidate_nick) &&
+	   ibis_str_equal(client->active_nick, client->nick))
+	{
+		candidate_nick = client->alt_nick;
+	}
+
+	if(!ibis_str_is_empty(candidate_nick)) {
+		IbisMessage *message = NULL;
+
+		ibis_client_set_active_nick(client, candidate_nick);
+
+		message = ibis_message_new(IBIS_MSG_NICK);
+		ibis_message_set_params(message, candidate_nick, NULL);
+		ibis_client_write(client, message);
+	} else {
+		GError *error = g_error_new_literal(IBIS_CLIENT_ERROR, 0,
+		                                    _("no more nicks to try"));
+
+		ibis_client_stop(client, error);
+	}
+}
+
+
+static void
 ibis_client_register(IbisClient *client, const char *password) {
 	IbisMessage *message = NULL;
 
@@ -197,13 +272,15 @@
 	}
 
 	message = ibis_message_new(IBIS_MSG_USER);
-	ibis_message_set_params(message, ibis_client_get_username(client), "0",
-	                        "*", ibis_client_get_realname(client), NULL);
+	ibis_message_set_params(message,
+	                        ibis_client_get_usable_username(client),
+	                        "0",
+	                        "*",
+	                        ibis_client_get_usable_realname(client),
+	                        NULL);
 	ibis_client_write(client, message);
 
-	message = ibis_message_new(IBIS_MSG_NICK);
-	ibis_message_set_params(message, client->nick, NULL);
-	ibis_client_write(client, message);
+	ibis_client_attempt_nick(client);
 }
 
 /******************************************************************************
@@ -303,6 +380,15 @@
 			ibis_message_set_source(message, client->server_name);
 		}
 
+		if(!client->registered) {
+			if(ibis_str_equal(command, IBIS_ERR_ERRONEUSNICKNAME) ||
+			   ibis_str_equal(command, IBIS_ERR_NICKNAMEINUSE) ||
+			   ibis_str_equal(command, IBIS_ERR_NONICKNAMEGIVEN))
+			{
+				ibis_client_attempt_nick(client);
+			}
+		}
+
 		g_signal_emit(client, signals[SIG_MESSAGE], quark, command, message,
 		              &handled);
 
@@ -938,7 +1024,6 @@
 void
 ibis_client_set_alt_nick(IbisClient *client, const char *alt_nick) {
 	g_return_if_fail(IBIS_IS_CLIENT(client));
-	g_return_if_fail(alt_nick == NULL || alt_nick[0] != '\0');
 
 	if(g_set_str(&client->alt_nick, alt_nick)) {
 		g_object_notify_by_pspec(G_OBJECT(client), properties[PROP_ALT_NICK]);
@@ -1025,11 +1110,7 @@
 ibis_client_get_realname(IbisClient *client) {
 	g_return_val_if_fail(IBIS_IS_CLIENT(client), NULL);
 
-	if(client->realname != NULL) {
-		return client->realname;
-	}
-
-	return client->nick;
+	return client->realname;
 }
 
 gboolean
@@ -1068,11 +1149,7 @@
 ibis_client_get_username(IbisClient *client) {
 	g_return_val_if_fail(IBIS_IS_CLIENT(client), NULL);
 
-	if(client->username != NULL) {
-		return client->username;
-	}
-
-	return client->nick;
+	return client->username;
 }
 
 void
diff --git a/ibis/ibisclient.h b/ibis/ibisclient.h
--- a/ibis/ibisclient.h
+++ b/ibis/ibisclient.h
@@ -281,8 +281,9 @@
  *
  * Gets the realname that is being used when sending the `USER` command.
  *
- * If [property@Client:realname] has not been set, this will return the value
- * of [property@Client:nick].
+ * Before version 0.11.1 this used to fall back to [property@Client:nick] if it
+ * was unset. Since then it only returns the actual value of
+ * [property@Client:realname].
  *
  * Returns: The realname.
  *
@@ -337,8 +338,9 @@
  *
  * Gets the username that is being used when sending the `USER` command.
  *
- * If [property@Client:username] has not been set, this will return the value
- * of [property@Client:nick].
+ * Before version 0.11.1 this used to fall back to [property@Client:nick] if it
+ * was unset. Since then it only returns the actual value of
+ * [property@Client:username].
  *
  * Returns: The username.
  *
diff --git a/ibis/tests/test_client.c b/ibis/tests/test_client.c
--- a/ibis/tests/test_client.c
+++ b/ibis/tests/test_client.c
@@ -17,6 +17,7 @@
  */
 
 #include <glib.h>
+#include <glib/gi18n.h>
 
 #include <ibis.h>
 
@@ -85,7 +86,7 @@
 }
 
 static void
-test_ibis_client_alt_nick_null(void) {
+test_ibis_client_alt_nick(void) {
 	IbisClient *client = NULL;
 	const char *alt_nick = NULL;
 
@@ -99,22 +100,11 @@
 	alt_nick = ibis_client_get_alt_nick(client);
 	g_assert_null(alt_nick);
 
-	g_assert_finalize_object(client);
-}
-
-static void
-test_ibis_client_alt_nick_empty(void) {
-	if(g_test_subprocess()) {
-		IbisClient *client = NULL;
+	ibis_client_set_alt_nick(client, "");
+	alt_nick = ibis_client_get_alt_nick(client);
+	g_assert_cmpstr(alt_nick, ==, "");
 
-		client = ibis_client_new();
-		ibis_client_set_alt_nick(client, "");
-
-		g_assert_finalize_object(client);
-	}
-
-	g_test_trap_subprocess(NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
-	g_test_trap_assert_stderr("*alt_nick[0] != '\\0'*");
+	g_assert_finalize_object(client);
 }
 
 static void
@@ -151,24 +141,6 @@
 }
 
 static void
-test_ibis_client_realname_fallback(void) {
-	IbisClient *client = NULL;
-	const char *realname = NULL;
-
-	client = ibis_client_new();
-
-	realname = ibis_client_get_realname(client);
-	g_assert_null(realname);
-
-	ibis_client_set_nick(client, "nick");
-
-	realname = ibis_client_get_realname(client);
-	g_assert_cmpstr(realname, ==, "nick");
-
-	g_assert_finalize_object(client);
-}
-
-static void
 test_ibis_client_username_null(void) {
 	IbisClient *client = NULL;
 	const char *username = NULL;
@@ -202,24 +174,6 @@
 }
 
 static void
-test_ibis_client_username_fallback(void) {
-	IbisClient *client = NULL;
-	const char *username = NULL;
-
-	client = ibis_client_new();
-
-	username = ibis_client_get_username(client);
-	g_assert_null(username);
-
-	ibis_client_set_nick(client, "nick");
-
-	username = ibis_client_get_username(client);
-	g_assert_cmpstr(username, ==, "nick");
-
-	g_assert_finalize_object(client);
-}
-
-static void
 test_ibis_client_is_channel_default(void) {
 	IbisClient *client = NULL;
 
@@ -378,24 +332,18 @@
 
 	g_test_add_func("/ibis/client/properties", test_ibis_client_properties);
 
-	g_test_add_func("/ibis/client/alt-nick/null",
-	                test_ibis_client_alt_nick_null);
-	g_test_add_func("/ibis/client/alt-nick/empty",
-	                test_ibis_client_alt_nick_empty);
+	g_test_add_func("/ibis/client/alt-nick",
+	                test_ibis_client_alt_nick);
 
 	g_test_add_func("/ibis/client/realname/null",
 	                test_ibis_client_realname_null);
 	g_test_add_func("/ibis/client/realname/empty",
 	                test_ibis_client_realname_empty);
-	g_test_add_func("/ibis/client/realname/fallback",
-	                test_ibis_client_realname_fallback);
 
 	g_test_add_func("/ibis/client/username/null",
 	                test_ibis_client_username_null);
 	g_test_add_func("/ibis/client/username/empty",
 	                test_ibis_client_username_empty);
-	g_test_add_func("/ibis/client/username/fallback",
-	                test_ibis_client_username_fallback);
 
 	g_test_add_func("/ibis/client/is-channel/default",
 	                test_ibis_client_is_channel_default);
