aboutsummaryrefslogtreecommitdiff
path: root/degesch.c
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2015-07-09 02:46:31 +0200
committerPřemysl Janouch <p.janouch@gmail.com>2015-07-09 02:46:31 +0200
commit5e7f9882dd5edfb8050d8fc487ba1378cbcb27dd (patch)
tree831685bb11277f154bf7ef2ef3cb3edc41d597d8 /degesch.c
parent2b2da0beab8dc24c79b94b40fed2f9bf08999d82 (diff)
downloadxK-5e7f9882dd5edfb8050d8fc487ba1378cbcb27dd.tar.gz
xK-5e7f9882dd5edfb8050d8fc487ba1378cbcb27dd.tar.xz
xK-5e7f9882dd5edfb8050d8fc487ba1378cbcb27dd.zip
degesch: "nickname" -> "nicks"
Now you can specify multiple nicknames to try.
Diffstat (limited to 'degesch.c')
-rw-r--r--degesch.c72
1 files changed, 59 insertions, 13 deletions
diff --git a/degesch.c b/degesch.c
index ef77c2a..26a1cbd 100644
--- a/degesch.c
+++ b/degesch.c
@@ -1138,6 +1138,7 @@ struct server
struct str_map irc_buffer_map; ///< Maps IRC identifiers to buffers
struct user *irc_user; ///< Our own user
+ int nick_counter; ///< Iterates "nicks" when registering
struct str irc_user_mode; ///< Our current user modes
char *irc_user_host; ///< Our current user@host
@@ -1488,9 +1489,9 @@ config_validate_nonnegative
static struct config_schema g_config_server[] =
{
- { .name = "nickname",
+ { .name = "nicks",
.comment = "IRC nickname",
- .type = CONFIG_ITEM_STRING,
+ .type = CONFIG_ITEM_STRING_ARRAY,
.validate = config_validate_nonjunk_string },
{ .name = "username",
.comment = "IRC user name",
@@ -4003,11 +4004,11 @@ static struct transport g_transport_tls =
static bool
irc_autofill_user_info (struct server *s, struct error **e)
{
- const char *nickname = get_config_string (s->config, "nickname");
+ const char *nicks = get_config_string (s->config, "nicks");
const char *username = get_config_string (s->config, "username");
const char *realname = get_config_string (s->config, "realname");
- if (nickname && username && realname)
+ if (nicks && *nicks && username && *username && realname)
return true;
// Read POSIX user info and fill the configuration if needed
@@ -4016,9 +4017,9 @@ irc_autofill_user_info (struct server *s, struct error **e)
FAIL ("cannot retrieve user information: %s", strerror (errno));
// FIXME: set_config_strings() writes errors on its own
- if (!nickname)
- set_config_string (s->config, "nickname", pwd->pw_name);
- if (!username)
+ if (!nicks || !*nicks)
+ set_config_string (s->config, "nicks", pwd->pw_name);
+ if (!username || !*username)
set_config_string (s->config, "username", pwd->pw_name);
// Not all systems have the GECOS field but the vast majority does
@@ -4037,16 +4038,33 @@ irc_autofill_user_info (struct server *s, struct error **e)
return true;
}
+static char *
+irc_fetch_next_nickname (struct server *s)
+{
+ struct str_vector v;
+ str_vector_init (&v);
+ split_str_ignore_empty (get_config_string (s->config, "nicks"), ',', &v);
+
+ char *result = NULL;
+ if (s->nick_counter >= 0 && s->nick_counter < v.len)
+ result = str_vector_steal (&v, s->nick_counter++);
+ if (s->nick_counter >= v.len)
+ // Exhausted all nicknames
+ s->nick_counter = -1;
+
+ str_vector_free (&v);
+ return result;
+}
+
static void
irc_register (struct server *s)
{
// Fill in user information automatically if needed
irc_autofill_user_info (s, NULL);
- const char *nickname = get_config_string (s->config, "nickname");
const char *username = get_config_string (s->config, "username");
const char *realname = get_config_string (s->config, "realname");
- hard_assert (nickname && username && realname);
+ hard_assert (username && realname);
// Start IRCv3.1 capability negotiation;
// at worst the server will ignore this or send a harmless error message
@@ -4056,7 +4074,15 @@ irc_register (struct server *s)
if (password)
irc_send (s, "PASS :%s", password);
- irc_send (s, "NICK %s", nickname);
+ s->nick_counter = 0;
+
+ char *nickname = irc_fetch_next_nickname (s);
+ if (nickname)
+ irc_send (s, "NICK :%s", nickname);
+ else
+ log_server_error (s, s->buffer, "No nicks present in configuration");
+ free (nickname);
+
// IRC servers may ignore the last argument if it's empty
irc_send (s, "USER %s 8 * :%s", username, *realname ? realname : " ");
}
@@ -5647,6 +5673,28 @@ irc_handle_rpl_inviting (struct server *s, const struct irc_message *msg)
"You have invited #n to #S", nickname, channel_name);
}
+static void
+irc_handle_err_nicknameinuse (struct server *s, const struct irc_message *msg)
+{
+ if (msg->params.len < 2)
+ return;
+
+ log_server_error (s, s->buffer,
+ "Nickname is already in use: #S", msg->params.vector[1]);
+
+ // Only do this while we haven't successfully registered yet
+ if (s->state != IRC_CONNECTED)
+ return;
+
+ char *nickname = irc_fetch_next_nickname (s);
+ if (nickname)
+ {
+ log_server_status (s, s->buffer, "Retrying with #s...", nickname);
+ irc_send (s, "NICK :%s", nickname);
+ free (nickname);
+ }
+}
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void
@@ -5848,9 +5896,7 @@ irc_process_numeric (struct server *s,
irc_handle_rpl_inviting (s, msg); buffer = NULL; break;
case IRC_ERR_NICKNAMEINUSE:
- // TODO: if (state == IRC_CONNECTED), use a different nick;
- // either use a number suffix, or accept commas in "nickname" config
- break;
+ irc_handle_err_nicknameinuse (s, msg); buffer = NULL; break;
case IRC_RPL_LIST:
case IRC_RPL_WHOREPLY: