diff --git a/degesch.c b/degesch.c index 6e30bbf..916ecbb 100644 --- a/degesch.c +++ b/degesch.c @@ -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, { // :!@ 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;