From aa39445afb93b8c3c426f37c7cda5afe984e8912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Mon, 6 Jul 2015 01:54:02 +0200 Subject: [PATCH] Miscellaneous, cleanup Went through the entire source of degesch and made changes along the way. --- README | 1 + degesch.c | 332 ++++++++++++++++++++++++------------------------------ 2 files changed, 151 insertions(+), 182 deletions(-) diff --git a/README b/README index 2313c78..50cb6fa 100644 --- a/README +++ b/README @@ -32,6 +32,7 @@ Notable features: - SSL/TLS autodetection (why doesn't everyone have this?) - IRCop authentication through SSL/TLS client certificates - epoll support on Linux; it should be able to handle quite a number of users + - partial IRCv3 support ZyklonB ------- diff --git a/degesch.c b/degesch.c index 3ed0e48..6c8d1f5 100644 --- a/degesch.c +++ b/degesch.c @@ -526,7 +526,7 @@ input_set_prompt (struct input *self, char *prompt) free (self->prompt); self->prompt = prompt; - if (self->prompt_shown) + if (self->prompt_shown > 0) input_redisplay (self); } @@ -568,7 +568,7 @@ input_insert_c (struct input *self, int c) char s[2] = { c, 0 }; el_insertstr (self->editline, s); - if (self->prompt_shown) + if (self->prompt_shown > 0) input_redisplay (self); } @@ -1409,12 +1409,7 @@ app_context_free (struct app_context *self) input_free (&self->input); } -// TODO: see if we can reorder the code to get rid of these static void refresh_prompt (struct app_context *ctx); -static char *irc_cut_nickname (const char *prefix); -static const char *irc_find_userhost (const char *prefix); -static char *irc_to_utf8 (struct app_context *ctx, const char *text); -static bool irc_is_this_us (struct server *s, const char *prefix); // --- Configuration ----------------------------------------------------------- @@ -2119,6 +2114,90 @@ attribute_printer_update (struct attribute_printer *self) self->dirty = true; } +// --- Helpers ----------------------------------------------------------------- + +static int +irc_server_strcmp (struct server *s, const char *a, const char *b) +{ + int x; + while (*a || *b) + if ((x = s->irc_tolower (*a++) - s->irc_tolower (*b++))) + return x; + return 0; +} + +static int +irc_server_strncmp (struct server *s, const char *a, const char *b, size_t n) +{ + int x; + while (n-- && (*a || *b)) + if ((x = s->irc_tolower (*a++) - s->irc_tolower (*b++))) + return x; + return 0; +} + +static char * +irc_cut_nickname (const char *prefix) +{ + return xstrndup (prefix, strcspn (prefix, "!@")); +} + +static const char * +irc_find_userhost (const char *prefix) +{ + const char *p = strchr (prefix, '!'); + return p ? p + 1 : NULL; +} + +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_server_strcmp (s, nick, s->irc_user->nickname); + free (nick); + return result; +} + +static bool +irc_is_channel (struct server *s, const char *ident) +{ + return *ident + && (!!strchr (s->irc_chantypes, *ident) || + !!strchr (s->irc_idchan_prefixes, *ident)); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +// As of 2015, everything should be in UTF-8. And if it's not, we'll decode it +// as ISO Latin 1. This function should not be called on the whole message. +static char * +irc_to_utf8 (struct app_context *ctx, const char *text) +{ + if (!text) + return NULL; + size_t len = strlen (text) + 1; + if (utf8_validate (text, len)) + return xstrdup (text); + return iconv_xstrdup (ctx->latin1_to_utf8, (char *) text, len, NULL); +} + +// This function is used to output debugging IRC traffic to the terminal. +// It's far from ideal, as any non-UTF-8 text degrades the entire line to +// ISO Latin 1. But it should work good enough most of the time. +static char * +irc_to_term (struct app_context *ctx, const char *text) +{ + char *utf8 = irc_to_utf8 (ctx, text); + char *term = iconv_xstrdup (ctx->term_from_utf8, utf8, -1, NULL); + free (utf8); + return term; +} + // --- Output formatter -------------------------------------------------------- // This complicated piece of code makes attributed text formatting simple. @@ -2778,6 +2857,8 @@ static void buffer_remove (struct app_context *ctx, struct buffer *buffer) { hard_assert (buffer != ctx->current_buffer); + hard_assert (buffer != ctx->global_buffer); + hard_assert (buffer->type != BUFFER_SERVER); input_destroy_buffer (&ctx->input, buffer->input_data); buffer->input_data = NULL; @@ -2789,13 +2870,6 @@ buffer_remove (struct app_context *ctx, struct buffer *buffer) if (buffer->user) str_map_set (&s->irc_buffer_map, buffer->user->nickname, NULL); - // It's not a good idea to remove these buffers, but it's even a worse - // one to leave the pointers point to invalid memory - if (buffer == ctx->global_buffer) - ctx->global_buffer = NULL; - if (buffer->type == BUFFER_SERVER) - buffer->server->buffer = NULL; - if (buffer == ctx->last_buffer) ctx->last_buffer = NULL; @@ -2851,7 +2925,6 @@ buffer_merge (struct app_context *ctx, { // XXX: anything better to do? This situation is arguably rare and I'm // not entirely sure what action to take. - // XXX: what good is log_*_status() when we can't use it? log_full (ctx, NULL, buffer, BUFFER_LINE_STATUS, "Buffer #s was merged into this buffer", merged->name); @@ -3118,7 +3191,6 @@ irc_remove_user_from_channel (struct user *user, struct channel *channel) static void irc_left_channel (struct channel *channel) { - // TODO: shouldn't we decrease reference count on the channel? LIST_FOR_EACH (struct channel_user, iter, channel->users) irc_channel_unlink_user (channel, iter); } @@ -3295,33 +3367,6 @@ irc_queue_reconnect (struct server *s) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// As of 2015, everything should be in UTF-8. And if it's not, we'll decode it -// as ISO Latin 1. This function should not be called on the whole message. -static char * -irc_to_utf8 (struct app_context *ctx, const char *text) -{ - if (!text) - return NULL; - size_t len = strlen (text) + 1; - if (utf8_validate (text, len)) - return xstrdup (text); - return iconv_xstrdup (ctx->latin1_to_utf8, (char *) text, len, NULL); -} - -// This function is used to output debugging IRC traffic to the terminal. -// It's far from ideal, as any non-UTF-8 text degrades the entire line to -// ISO Latin 1. But it should work good enough most of the time. -static char * -irc_to_term (struct app_context *ctx, const char *text) -{ - char *utf8 = irc_to_utf8 (ctx, text); - char *term = iconv_xstrdup (ctx->term_from_utf8, utf8, -1, NULL); - free (utf8); - return term; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static void irc_send (struct server *s, const char *format, ...) ATTRIBUTE_PRINTF (2, 3); @@ -3750,7 +3795,7 @@ transport_tls_init_ctx (struct server *s, SSL_CTX *ssl_ctx, struct error **e) goto ca_error; } - // XXX: maybe we should call SSL_CTX_set_options() for some workarounds + // TODO: allow specifying SSL_CTX_set_cipher_list() SSL_CTX_set_mode (ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); return true; @@ -4209,12 +4254,9 @@ irc_initiate_connect (struct server *s) // --- Input prompt ------------------------------------------------------------ -static char * -make_unseen_prefix (struct app_context *ctx) +static void +make_unseen_prefix (struct app_context *ctx, struct str *active_buffers) { - struct str active_buffers; - str_init (&active_buffers); - size_t i = 0; LIST_FOR_EACH (struct buffer, iter, ctx->buffers) { @@ -4222,41 +4264,51 @@ make_unseen_prefix (struct app_context *ctx) if (!iter->unseen_messages_count) continue; - if (active_buffers.len) - str_append_c (&active_buffers, ','); + if (active_buffers->len) + str_append_c (active_buffers, ','); if (iter->highlighted) - str_append_c (&active_buffers, '!'); - str_append_printf (&active_buffers, "%zu", i); + str_append_c (active_buffers, '!'); + str_append_printf (active_buffers, "%zu", i); } - - if (active_buffers.len) - return str_steal (&active_buffers); - - str_free (&active_buffers); - return NULL; } -static char * -make_chanmode_postfix (struct channel *channel) +static void +make_chanmode_postfix (struct channel *channel, struct str *modes) { - struct str modes; - str_init (&modes); if (channel->no_param_modes.len) - str_append (&modes, channel->no_param_modes.str); + str_append (modes, channel->no_param_modes.str); struct str_map_iter iter; str_map_iter_init (&iter, &channel->param_modes); + char *param; while ((param = str_map_iter_next (&iter))) - str_append_c (&modes, iter.link->key[0]); - - if (modes.len) - return str_steal (&modes); - - str_free (&modes); - return NULL; + str_append_c (modes, iter.link->key[0]); } +static void +make_server_postfix (struct buffer *buffer, struct str *output) +{ + struct server *s = buffer->server; + str_append_c (output, ' '); + if (!irc_is_connected (s)) + str_append (output, "(disconnected)"); + else if (s->state != IRC_REGISTERED) + str_append (output, "(unregistered)"); + else + { + if (buffer->type == BUFFER_CHANNEL) + { + struct channel_user *channel_user = + irc_channel_get_user (buffer->channel, s->irc_user); + if (channel_user) + str_append (output, channel_user->prefixes.str); + } + str_append (output, s->irc_user->nickname); + if (s->irc_user_mode.len) + str_append_printf (output, "(%s)", s->irc_user_mode.str); + } +} static void make_prompt (struct app_context *ctx, struct str *output) { @@ -4266,43 +4318,27 @@ make_prompt (struct app_context *ctx, struct str *output) str_append_c (output, '['); - char *unseen_prefix = make_unseen_prefix (ctx); - if (unseen_prefix) - str_append_printf (output, "(%s) ", unseen_prefix); - free (unseen_prefix); + struct str active_buffers; + str_init (&active_buffers); + make_unseen_prefix (ctx, &active_buffers); + if (active_buffers.len) + str_append_printf (output, "(%s) ", active_buffers.str); + str_free (&active_buffers); str_append_printf (output, "%d:%s", buffer_get_index (ctx, buffer), buffer->name); if (buffer->type == BUFFER_CHANNEL) { - char *modes = make_chanmode_postfix (buffer->channel); - if (modes) - str_append_printf (output, "(+%s)", modes); - free (modes); + struct str modes; + str_init (&modes); + make_chanmode_postfix (buffer->channel, &modes); + if (modes.len) + str_append_printf (output, "(+%s)", modes.str); + str_free (&modes); } if (buffer != ctx->global_buffer) - { - struct server *s = buffer->server; - str_append_c (output, ' '); - if (!irc_is_connected (s)) - str_append (output, "(disconnected)"); - else if (s->state != IRC_REGISTERED) - str_append (output, "(unregistered)"); - else - { - if (buffer->type == BUFFER_CHANNEL) - { - struct channel_user *channel_user = - irc_channel_get_user (buffer->channel, s->irc_user); - if (channel_user) - str_append (output, channel_user->prefixes.str); - } - str_append (output, s->irc_user->nickname); - if (s->irc_user_mode.len) - str_append_printf (output, "(%s)", s->irc_user_mode.str); - } - } + make_server_postfix (buffer, output); str_append_c (output, ']'); } @@ -4334,63 +4370,6 @@ refresh_prompt (struct app_context *ctx) // --- Helpers ----------------------------------------------------------------- -static int -irc_server_strcmp (struct server *s, const char *a, const char *b) -{ - int x; - while (*a || *b) - if ((x = s->irc_tolower (*a++) - s->irc_tolower (*b++))) - return x; - return 0; -} - -static int -irc_server_strncmp (struct server *s, const char *a, const char *b, size_t n) -{ - int x; - while (n-- && (*a || *b)) - if ((x = s->irc_tolower (*a++) - s->irc_tolower (*b++))) - return x; - return 0; -} - -static char * -irc_cut_nickname (const char *prefix) -{ - return xstrndup (prefix, strcspn (prefix, "!@")); -} - -static const char * -irc_find_userhost (const char *prefix) -{ - const char *p = strchr (prefix, '!'); - return p ? p + 1 : NULL; -} - -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_server_strcmp (s, nick, s->irc_user->nickname); - free (nick); - return result; -} - -static bool -irc_is_channel (struct server *s, const char *ident) -{ - return *ident - && (!!strchr (s->irc_chantypes, *ident) || - !!strchr (s->irc_idchan_prefixes, *ident)); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static struct buffer * irc_get_buffer_for_message (struct server *s, const struct irc_message *msg, const char *target) @@ -4435,11 +4414,11 @@ irc_is_highlight (struct server *s, const char *message) // Ideally we could do this at least in proper Unicode. char *copy = xstrdup (message); for (char *p = copy; *p; p++) - *p = irc_tolower (*p); + *p = s->irc_tolower (*p); char *nick = xstrdup (s->irc_user->nickname); for (char *p = nick; *p; p++) - *p = irc_tolower (*p); + *p = s->irc_tolower (*p); // Special characters allowed in nicknames by RFC 2812: []\`_^{|} and - // Also excluded from the ASCII: common user channel prefixes: +%@&~ @@ -4855,10 +4834,6 @@ irc_handle_mode (struct server *s, const struct irc_message *msg) log_server_status (s, s->buffer, "User mode [#S] by #n", modes, msg->prefix); } - else - { - // XXX: this shouldn't happen, reconnect? - } free (modes); @@ -4928,7 +4903,7 @@ irc_handle_nick (struct server *s, const struct irc_message *msg) pm_buffer = buffer_collision; } - // The colliding user should be completely destroyed by now + // The colliding user should be completely gone by now if (lexicographically_different) hard_assert (!str_map_find (&s->irc_users, new_nickname)); @@ -5234,7 +5209,7 @@ irc_handle_quit (struct server *s, const struct irc_message *msg) if (!msg->prefix) return; - // What the fuck + // What the fuck, the server never sends this back if (irc_is_this_us (s, msg->prefix)) return; @@ -5450,7 +5425,7 @@ irc_handle_rpl_namreply (struct server *s, const struct irc_message *msg) const char *channel_name = msg->params.vector[2]; const char *nicks = msg->params.vector[3]; - // Just push the nicknames to a string vector for later processing + // Just push the nicknames to a string vector to process later struct channel *channel = str_map_find (&s->irc_channels, channel_name); if (channel) split_str_ignore_empty (nicks, ' ', &channel->names_buf); @@ -5518,7 +5493,6 @@ irc_process_names (struct server *s, struct channel *channel) char *all_users = join_str_vector (&v, ' '); str_vector_free (&v); - // XXX: only do this after joining the channel? struct buffer *buffer = str_map_find (&s->irc_buffer_map, channel->name); if (buffer) { @@ -5837,9 +5811,6 @@ irc_process_numeric (struct server *s, const struct irc_message *msg, unsigned long numeric) { // 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 @@ -5896,10 +5867,10 @@ irc_process_numeric (struct server *s, default: // If the second parameter is something we have a buffer for - // (a channel, a PM buffer), log it in that buffer. This is very basic - // and we should whitelist/blacklist a lot more replies here. - // TODO: if this happens, we should either strip the first parameter - // from the buffer line, or at least put it in brackets + // (a channel, a PM buffer), log it in that buffer. This is very basic. + // TODO: whitelist/blacklist a lot more replies in here. + // TODO: we should either strip the first parameter from the resulting + // buffer line, or at least put it in brackets if (msg->params.len > 1) { struct buffer *x; @@ -5910,8 +5881,7 @@ irc_process_numeric (struct server *s, if (buffer) { - // Join the parameter vector back, recode it to our internal encoding - // and send it to the server buffer + // Join the parameter vector back and send it to the server buffer log_server (s, buffer, BUFFER_LINE_STATUS, "#&m", join_str_vector (©, ' ')); } @@ -7675,11 +7645,6 @@ send_message_to_current_buffer (struct app_context *ctx, char *message) switch (buffer->type) { - case BUFFER_GLOBAL: - case BUFFER_SERVER: - log_full (ctx, NULL, buffer, BUFFER_LINE_ERROR, - "This buffer is not a channel"); - break; case BUFFER_CHANNEL: send_message_to_target (buffer->server, buffer->channel->name, message, buffer); @@ -7688,6 +7653,9 @@ send_message_to_current_buffer (struct app_context *ctx, char *message) send_message_to_target (buffer->server, buffer->user->nickname, message, buffer); break; + default: + log_full (ctx, NULL, buffer, BUFFER_LINE_ERROR, + "This buffer is not a channel"); } } @@ -8211,7 +8179,7 @@ on_readline_input (char *line) if (*line) add_history (line); - // The text is deleted _afterwards_ + // Normally, the text is deleted _afterwards_ rl_replace_line ("", false); process_input (ctx, line); free (line);