diff --git a/NEWS b/NEWS index 1c1a528..cbc1807 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,8 @@ * degesch: now supporting IRCv3.2 capability negotiation, including CAP DEL + * degesch: added support for IRCv3 chghost + 1.1.0 (2020-10-31) "What Do You Mean By 'This Isn't Germany'?" diff --git a/degesch.c b/degesch.c index 2033497..0c4310b 100644 --- a/degesch.c +++ b/degesch.c @@ -2341,7 +2341,7 @@ static struct config_schema g_config_server[] = .type = CONFIG_ITEM_STRING_ARRAY, .validate = config_validate_nonjunk_string, .default_ = "\"multi-prefix,invite-notify,server-time,echo-message," - "message-tags,away-notify,cap-notify\"" }, + "message-tags,away-notify,cap-notify,chghost\"" }, { .name = "tls", .comment = "Whether to use TLS", @@ -4035,6 +4035,13 @@ log_full (struct app_context *ctx, struct server *s, struct buffer *buffer, log_server ((s), (buffer), BUFFER_LINE_STATUS | BUFFER_LINE_UNIMPORTANT, \ "#n is now known as #n", (old), (new_)) +#define log_chghost_self(s, buffer, new_) \ + log_server ((s), (buffer), BUFFER_LINE_STATUS | BUFFER_LINE_UNIMPORTANT, \ + "You are now #N", (new_)) +#define log_chghost(s, buffer, old, new_) \ + log_server ((s), (buffer), BUFFER_LINE_STATUS | BUFFER_LINE_UNIMPORTANT, \ + "#N is now #N", (old), (new_)) + #define log_outcoming_notice(s, buffer, who, text) \ log_server_status ((s), (buffer), "#s(#n): #m", "Notice", (who), (text)) #define log_outcoming_privmsg(s, buffer, prefixes, who, text) \ @@ -6669,6 +6676,52 @@ irc_handle_cap (struct server *s, const struct irc_message *msg) strv_free (&v); } +static void +irc_handle_chghost (struct server *s, const struct irc_message *msg) +{ + if (!msg->prefix || msg->params.len < 2) + return; + + char *nickname = irc_cut_nickname (msg->prefix); + struct user *user = str_map_find (&s->irc_users, nickname); + free (nickname); + if (!user) + return; + + // We don't remember the userhost part, we only log the change + char *new_prefix = xstrdup_printf ("%s!%s@%s", user->nickname, + msg->params.vector[0], msg->params.vector[1]); + + if (irc_is_this_us (s, msg->prefix)) + { + log_chghost_self (s, s->buffer, new_prefix); + + // Log a message in all open buffers on this server + struct str_map_iter iter = str_map_iter_make (&s->irc_buffer_map); + struct buffer *buffer; + while ((buffer = str_map_iter_next (&iter))) + log_chghost_self (s, buffer, new_prefix); + } + else + { + // Log a message in any PM buffer + struct buffer *buffer = + str_map_find (&s->irc_buffer_map, user->nickname); + if (buffer) + log_chghost (s, buffer, msg->prefix, new_prefix); + + // Log a message in all channels the user is in + LIST_FOR_EACH (struct user_channel, iter, user->channels) + { + buffer = str_map_find (&s->irc_buffer_map, iter->channel->name); + hard_assert (buffer != NULL); + log_chghost (s, buffer, msg->prefix, new_prefix); + } + } + + free (new_prefix); +} + static void irc_handle_error (struct server *s, const struct irc_message *msg) { @@ -7310,6 +7363,7 @@ static struct irc_handler g_irc_handlers[] = { "AUTHENTICATE", irc_handle_authenticate }, { "AWAY", irc_handle_away }, { "CAP", irc_handle_cap }, + { "CHGHOST", irc_handle_chghost }, { "ERROR", irc_handle_error }, { "INVITE", irc_handle_invite }, { "JOIN", irc_handle_join },