Miscellaneous, cleanup
Went through the entire source of degesch and made changes along the way.
This commit is contained in:
parent
05c6bf63bb
commit
aa39445afb
1
README
1
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
|
||||
-------
|
||||
|
|
330
degesch.c
330
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,66 +4264,30 @@ 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)
|
||||
{
|
||||
struct str modes;
|
||||
str_init (&modes);
|
||||
if (channel->no_param_modes.len)
|
||||
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;
|
||||
}
|
||||
|
||||
static void
|
||||
make_prompt (struct app_context *ctx, struct str *output)
|
||||
make_chanmode_postfix (struct channel *channel, struct str *modes)
|
||||
{
|
||||
struct buffer *buffer = ctx->current_buffer;
|
||||
if (!buffer)
|
||||
return;
|
||||
if (channel->no_param_modes.len)
|
||||
str_append (modes, channel->no_param_modes.str);
|
||||
|
||||
str_append_c (output, '[');
|
||||
struct str_map_iter iter;
|
||||
str_map_iter_init (&iter, &channel->param_modes);
|
||||
|
||||
char *unseen_prefix = make_unseen_prefix (ctx);
|
||||
if (unseen_prefix)
|
||||
str_append_printf (output, "(%s) ", unseen_prefix);
|
||||
free (unseen_prefix);
|
||||
|
||||
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);
|
||||
char *param;
|
||||
while ((param = str_map_iter_next (&iter)))
|
||||
str_append_c (modes, iter.link->key[0]);
|
||||
}
|
||||
|
||||
if (buffer != ctx->global_buffer)
|
||||
static void
|
||||
make_server_postfix (struct buffer *buffer, struct str *output)
|
||||
{
|
||||
struct server *s = buffer->server;
|
||||
str_append_c (output, ' ');
|
||||
|
@ -4303,6 +4309,36 @@ make_prompt (struct app_context *ctx, struct str *output)
|
|||
str_append_printf (output, "(%s)", s->irc_user_mode.str);
|
||||
}
|
||||
}
|
||||
static void
|
||||
make_prompt (struct app_context *ctx, struct str *output)
|
||||
{
|
||||
struct buffer *buffer = ctx->current_buffer;
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
str_append_c (output, '[');
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue