degesch: rework registration

Also fixed the annoying reconnect bug.
This commit is contained in:
Přemysl Eric Janouch 2015-05-15 05:54:03 +02:00
parent ebf9403872
commit 30191c76c8
1 changed files with 63 additions and 47 deletions

110
degesch.c
View File

@ -3057,8 +3057,11 @@ on_irc_disconnected (struct server *s)
while ((channel = str_map_iter_next (&iter)))
irc_left_channel (channel);
user_unref (s->irc_user);
s->irc_user = NULL;
if (s->irc_user)
{
user_unref (s->irc_user);
s->irc_user = NULL;
}
free (s->irc_user_mode);
s->irc_user_mode = NULL;
@ -3251,14 +3254,6 @@ irc_register (struct server *s)
irc_send (s, "NICK %s", nickname);
// IRC servers may ignore the last argument if it's empty
irc_send (s, "USER %s 8 * :%s", username, *realname ? realname : " ");
// XXX: maybe we should wait for the first message from the server
// FIXME: the user may exist already after we've reconnected. Either
// make sure that there's no reference of this nick upon disconnection,
// or search in "irc_users" first... or something.
s->irc_user = irc_make_user (s, xstrdup (nickname));
s->irc_user_mode = xstrdup ("");
s->irc_user_host = NULL;
}
static void
@ -3507,6 +3502,8 @@ make_prompt (struct app_context *ctx, struct str *output)
str_append_c (output, ' ');
if (!irc_is_connected (s))
str_append (output, "(disconnected)");
else if (s->state != IRC_REGISTERED)
str_append (output, "(unregistered)");
else
{
str_append (output, s->irc_user->nickname);
@ -3561,6 +3558,11 @@ irc_find_userhost (const char *prefix)
static bool
irc_is_this_us (struct server *s, const char *prefix)
{
// This shouldn't be called before successfully registering.
// Better safe than sorry, though.
if (!s->irc_user)
return false;
char *nick = irc_cut_nickname (prefix);
bool result = !irc_strcmp (nick, s->irc_user->nickname);
free (nick);
@ -3610,6 +3612,10 @@ irc_get_buffer_for_message (struct server *s,
static bool
irc_is_highlight (struct server *s, const char *message)
{
// This may be called by notices before even successfully registering
if (!s->irc_user)
return false;
// Well, this is rather crude but it should make most users happy.
// Ideally we could do this at least in proper Unicode.
char *copy = xstrdup (message);
@ -4204,6 +4210,28 @@ irc_try_parse_welcome_for_userhost (struct server *s, const char *m)
str_vector_free (&v);
}
static void
irc_on_registered (struct server *s, const char *nickname)
{
s->irc_user = irc_get_or_make_user (s, nickname);
s->irc_user_mode = xstrdup ("");
s->irc_user_host = NULL;
s->state = IRC_REGISTERED;
refresh_prompt (s->ctx);
// TODO: parse any response and store the result for us in app_context;
// this enables proper message splitting on output;
// we can also use WHOIS if it's not supported (optional by RFC 2812)
irc_send (s, "USERHOST %s", s->irc_user->nickname);
const char *autojoin = get_config_string (s->ctx, "server.autojoin");
if (autojoin)
irc_send (s, "JOIN :%s", autojoin);
// TODO: rejoin all current channels (mark those we've left manually?)
}
static void
irc_process_numeric (struct server *s,
const struct irc_message *msg, unsigned long numeric)
@ -4211,6 +4239,8 @@ irc_process_numeric (struct server *s,
// Numerics typically have human-readable information
// TODO: try to output certain replies in more specific buffers
// TODO: fail the connection if there's no first parameter
// Get rid of the first parameter, if there's any at all,
// as it contains our nickname and is of no practical use to the user
struct str_vector copy;
@ -4228,6 +4258,8 @@ irc_process_numeric (struct server *s,
switch (numeric)
{
case IRC_RPL_WELCOME:
irc_on_registered (s, msg->params.vector[0]);
// We still issue a USERHOST anyway as this is in general unreliable
if (msg->params.len == 2)
irc_try_parse_welcome_for_userhost (s, msg->params.vector[1]);
@ -4270,28 +4302,6 @@ irc_process_message (const struct irc_message *msg,
input_show (&s->ctx->input);
}
// XXX: or is the 001 numeric enough? For what?
if (s->state == IRC_CONNECTED && (!strcasecmp (msg->command, "MODE")
|| !strcasecmp (msg->command, "376") // RPL_ENDOFMOTD
|| !strcasecmp (msg->command, "422"))) // ERR_NOMOTD
{
// XXX: should we really print this?
buffer_send_status (s->ctx, s->buffer, "Successfully connected");
s->state = IRC_REGISTERED;
refresh_prompt (s->ctx);
// TODO: parse any response and store the result for us in app_context;
// this enables proper message splitting on output;
// we can also use WHOIS if it's not supported (optional by RFC 2812)
irc_send (s, "USERHOST %s", s->irc_user->nickname);
const char *autojoin = get_config_string (s->ctx, "server.autojoin");
if (autojoin)
irc_send (s, "JOIN :%s", autojoin);
// TODO: rejoin all current channels (mark those we've left manually?)
}
struct irc_handler key = { .name = msg->command };
struct irc_handler *handler = bsearch (&key, g_irc_handlers,
N_ELEMENTS (g_irc_handlers), sizeof key, irc_handler_cmp_by_name);
@ -4402,7 +4412,7 @@ irc_autosplit_message (struct server *s, const char *message,
{
// :<nick>!<user>@<host> <fixed-part><message>
int space_in_one_message = 0;
if (s->irc_user_host)
if (s->irc_user && s->irc_user_host)
space_in_one_message = 510
- 1 - (int) strlen (s->irc_user->nickname)
- 1 - (int) strlen (s->irc_user_host)
@ -4468,7 +4478,7 @@ log_outcoming_action (struct server *s,
{
(void) a;
if (buffer)
if (buffer && soft_assert (s->irc_user))
buffer_send (s->ctx, buffer, BUFFER_LINE_ACTION, 0,
.who = irc_to_utf8 (s->ctx, s->irc_user->nickname),
.text = irc_to_utf8 (s->ctx, line));
@ -4485,7 +4495,7 @@ static void
log_outcoming_privmsg (struct server *s,
struct send_autosplit_args *a, struct buffer *buffer, const char *line)
{
if (buffer)
if (buffer && soft_assert (s->irc_user))
buffer_send (s->ctx, buffer, BUFFER_LINE_PRIVMSG, 0,
.who = irc_to_utf8 (s->ctx, s->irc_user->nickname),
.text = irc_to_utf8 (s->ctx, line));
@ -4503,7 +4513,7 @@ static void
log_outcoming_notice (struct server *s,
struct send_autosplit_args *a, struct buffer *buffer, const char *line)
{
if (buffer)
if (buffer && soft_assert (s->irc_user))
buffer_send (s->ctx, buffer, BUFFER_LINE_NOTICE, 0,
.who = irc_to_utf8 (s->ctx, s->irc_user->nickname),
.text = irc_to_utf8 (s->ctx, line));
@ -4693,8 +4703,12 @@ try_decode_buffer (struct app_context *ctx, const char *word)
}
static bool
server_command_check (struct app_context *ctx, const char *action)
server_command_check (struct app_context *ctx, const char *action,
bool need_registration)
{
// "need_registration" is primarily for message sending commands,
// as they may want to log buffer lines and use our current nickname
if (ctx->current_buffer->type == BUFFER_GLOBAL)
buffer_send_error (ctx, ctx->current_buffer,
"Can't do this from a global buffer (%s)", action);
@ -4703,6 +4717,8 @@ server_command_check (struct app_context *ctx, const char *action)
struct server *s = ctx->current_buffer->server;
if (!irc_is_connected (s))
buffer_send_error (ctx, s->buffer, "Not connected");
else if (s->state != IRC_REGISTERED && need_registration)
buffer_send_error (ctx, s->buffer, "Not registered");
else
return true;
}
@ -4973,7 +4989,7 @@ handle_command_save (struct app_context *ctx, char *arguments)
static bool
handle_command_msg (struct app_context *ctx, char *arguments)
{
if (!server_command_check (ctx, "send messages"))
if (!server_command_check (ctx, "send messages", true))
return true;
if (!*arguments)
return false;
@ -4990,7 +5006,7 @@ handle_command_msg (struct app_context *ctx, char *arguments)
static bool
handle_command_query (struct app_context *ctx, char *arguments)
{
if (!server_command_check (ctx, "send messages"))
if (!server_command_check (ctx, "send messages", true))
return true;
if (!*arguments)
return false;
@ -5012,7 +5028,7 @@ handle_command_query (struct app_context *ctx, char *arguments)
static bool
handle_command_notice (struct app_context *ctx, char *arguments)
{
if (!server_command_check (ctx, "send messages"))
if (!server_command_check (ctx, "send messages", true))
return true;
if (!*arguments)
return false;
@ -5029,7 +5045,7 @@ handle_command_notice (struct app_context *ctx, char *arguments)
static bool
handle_command_ctcp (struct app_context *ctx, char *arguments)
{
if (!server_command_check (ctx, "send messages"))
if (!server_command_check (ctx, "send messages", true))
return true;
if (!*arguments)
return false;
@ -5056,7 +5072,7 @@ handle_command_ctcp (struct app_context *ctx, char *arguments)
static bool
handle_command_me (struct app_context *ctx, char *arguments)
{
if (!server_command_check (ctx, "send messages"))
if (!server_command_check (ctx, "send messages", true))
return true;
struct server *s = ctx->current_buffer->server;
@ -5087,7 +5103,7 @@ handle_command_quit (struct app_context *ctx, char *arguments)
static bool
handle_command_join (struct app_context *ctx, char *arguments)
{
if (!server_command_check (ctx, "join"))
if (!server_command_check (ctx, "join", true))
return true;
struct server *s = ctx->current_buffer->server;
@ -5116,7 +5132,7 @@ handle_command_join (struct app_context *ctx, char *arguments)
static bool
handle_command_part (struct app_context *ctx, char *arguments)
{
if (!server_command_check (ctx, "part"))
if (!server_command_check (ctx, "part", true))
return true;
struct server *s = ctx->current_buffer->server;
@ -5178,7 +5194,7 @@ handle_command_disconnect (struct app_context *ctx, char *arguments)
static bool
handle_command_list (struct app_context *ctx, char *arguments)
{
if (!server_command_check (ctx, "list channels"))
if (!server_command_check (ctx, "list channels", true))
return true;
struct server *s = ctx->current_buffer->server;
@ -5192,7 +5208,7 @@ handle_command_list (struct app_context *ctx, char *arguments)
static bool
handle_command_nick (struct app_context *ctx, char *arguments)
{
if (!server_command_check (ctx, "change nickname"))
if (!server_command_check (ctx, "change nickname", false))
return true;
if (!*arguments)
return false;
@ -5205,7 +5221,7 @@ handle_command_nick (struct app_context *ctx, char *arguments)
static bool
handle_command_quote (struct app_context *ctx, char *arguments)
{
if (!server_command_check (ctx, "quote"))
if (!server_command_check (ctx, "quote", true))
return true;
struct server *s = ctx->current_buffer->server;