diff options
Diffstat (limited to 'src/kike.c')
-rw-r--r-- | src/kike.c | 333 |
1 files changed, 170 insertions, 163 deletions
@@ -490,13 +490,6 @@ server_context_free (struct server_context *self) catclose (self->catalog); } -// --- Main program ------------------------------------------------------------ - -static void client_cancel_timers (struct client *); -static void client_set_kill_timer (struct client *); -static void client_update_poller (struct client *, const struct pollfd *); -static void client_unregister (struct client *, const char *); - static void irc_try_finish_quit (struct server_context *ctx) { @@ -504,30 +497,83 @@ irc_try_finish_quit (struct server_context *ctx) ctx->polling = false; } +static const char * +irc_get_text (struct server_context *ctx, int id, const char *def) +{ + if (!soft_assert (def != NULL)) + def = ""; + if (ctx->catalog == (nl_catd) -1) + return def; + return catgets (ctx->catalog, 1, id, def); +} + +// --- Channels ---------------------------------------------------------------- + +static struct channel_user * +channel_get_user (const struct channel *chan, const struct client *c) +{ + for (struct channel_user *iter = chan->users; iter; iter = iter->next) + if (!irc_strcmp (iter->nickname, c->nickname)) + return iter; + return NULL; +} + +static struct channel_user * +channel_add_user (struct channel *chan, const struct client *c) +{ + size_t nick_len = strlen (c->nickname); + struct channel_user *link = xcalloc (1, sizeof *link + nick_len + 1); + memcpy (link->nickname, c->nickname, nick_len + 1); + LIST_PREPEND (chan->users, link); + return link; +} + static void -client_kill (struct client *c, const char *reason) +channel_remove_user (struct channel *chan, struct channel_user *user) { - client_unregister (c, reason ? reason : "Client exited"); + LIST_UNLINK (chan->users, user); + free (user); +} - struct server_context *ctx = c->ctx; - ssize_t i = poller_find_by_fd (&ctx->poller, c->socket_fd); - if (i != -1) - poller_remove_at_index (&ctx->poller, i); - client_cancel_timers (c); +static size_t +channel_user_count (const struct channel *chan) +{ + size_t result = 0; + for (struct channel_user *iter = chan->users; iter; iter = iter->next) + result++; + return result; +} - if (c->ssl) - (void) SSL_shutdown (c->ssl); - xclose (c->socket_fd); - c->socket_fd = -1; - client_free (c); - LIST_UNLINK (ctx->clients, c); - ctx->n_clients--; - free (c); +static struct channel * +channel_create (struct server_context *ctx, const char *name) +{ + struct channel *chan = xcalloc (1, sizeof *chan); + channel_init (chan); + str_map_set (&ctx->channels, name, chan); - irc_try_finish_quit (ctx); + chan->ctx = ctx; + chan->name = xstrdup (name); + return chan; } static void +channel_destroy_if_empty (struct server_context *ctx, struct channel *chan) +{ + if (!chan->users) + { + str_map_set (&ctx->channels, chan->name, NULL); + channel_free (chan); + free (chan); + } +} + +// --- Clients ----------------------------------------------------------------- + +static void client_cancel_timers (struct client *); +static void client_set_kill_timer (struct client *); +static void client_update_poller (struct client *, const struct pollfd *); + +static void irc_send_str (struct client *c, const struct str *s) { hard_assert (c->initialized && !c->closing_link); @@ -559,14 +605,87 @@ irc_send (struct client *c, const char *format, ...) str_free (&tmp); } -static const char * -irc_get_text (struct server_context *ctx, int id, const char *def) +static void +client_send_to_roommates (struct client *c, const char *message) { - if (!soft_assert (def != NULL)) - def = ""; - if (ctx->catalog == (nl_catd) -1) - return def; - return catgets (ctx->catalog, 1, id, def); + struct str_map targets; + str_map_init (&targets); + targets.key_xfrm = irc_strxfrm; + + struct str_map_iter iter; + str_map_iter_init (&iter, &c->ctx->channels); + struct channel *chan; + while ((chan = str_map_iter_next (&iter))) + { + if (chan->modes & IRC_CHAN_MODE_QUIET + || !channel_get_user (chan, c)) + continue; + + // When we're unregistering, the str_map_find() will return zero, + // which will prevent sending the QUIT message to ourselves. + for (struct channel_user *iter = chan->users; iter; iter = iter->next) + str_map_set (&targets, iter->nickname, + str_map_find (&c->ctx->users, iter->nickname)); + } + + str_map_iter_init (&iter, &targets); + struct client *target; + while ((target = str_map_iter_next (&iter))) + irc_send (target, "%s", message); +} + +static void +client_unregister (struct client *c, const char *reason) +{ + if (!c->registered) + return; + + // Make the user effectively non-existent + str_map_set (&c->ctx->users, c->nickname, NULL); + + char *message = xstrdup_printf (":%s!%s@%s QUIT :%s", + c->nickname, c->username, c->hostname, reason); + client_send_to_roommates (c, message); + free (message); + + struct str_map_iter iter; + str_map_iter_init (&iter, &c->ctx->channels); + struct channel *chan; + while ((chan = str_map_iter_next (&iter))) + { + struct channel_user *user; + if (!(user = channel_get_user (chan, c))) + continue; + channel_remove_user (chan, user); + channel_destroy_if_empty (c->ctx, chan); + } + + free (c->nickname); + c->nickname = NULL; + c->registered = false; +} + +static void +client_kill (struct client *c, const char *reason) +{ + client_unregister (c, reason ? reason : "Client exited"); + + struct server_context *ctx = c->ctx; + ssize_t i = poller_find_by_fd (&ctx->poller, c->socket_fd); + if (i != -1) + poller_remove_at_index (&ctx->poller, i); + client_cancel_timers (c); + + if (c->ssl) + (void) SSL_shutdown (c->ssl); + xclose (c->socket_fd); + c->socket_fd = -1; + client_free (c); + LIST_UNLINK (ctx->clients, c); + ctx->n_clients--; + free (c); + + irc_try_finish_quit (ctx); } static void @@ -587,6 +706,26 @@ irc_close_link (struct client *c, const char *reason) client_set_kill_timer (c); } +static bool +client_in_mask_list (const struct client *c, const struct str_vector *mask) +{ + struct str client; + str_init (&client); + str_append_printf (&client, "%s!%s@%s", + c->nickname, c->username, c->hostname); + irc_strxfrm (client.str, client.str, client.len); + bool result = false; + for (size_t i = 0; i < mask->len; i++) + // FIXME: irc_strxfrm() for the mask (save in canonical format?) + if (!fnmatch (client.str, mask->vector[i], 0)) + { + result = true; + break; + } + str_free (&client); + return result; +} + // --- Timers ------------------------------------------------------------------ static void @@ -814,132 +953,6 @@ irc_send_motd (struct client *c) irc_send_reply (c, IRC_RPL_ENDOFMOTD); } -static struct channel_user * -channel_get_user (const struct channel *chan, const struct client *c) -{ - for (struct channel_user *iter = chan->users; iter; iter = iter->next) - if (!irc_strcmp (iter->nickname, c->nickname)) - return iter; - return NULL; -} - -static struct channel_user * -channel_add_user (struct channel *chan, const struct client *c) -{ - size_t nick_len = strlen (c->nickname); - struct channel_user *link = xcalloc (1, sizeof *link + nick_len + 1); - memcpy (link->nickname, c->nickname, nick_len + 1); - LIST_PREPEND (chan->users, link); - return link; -} - -static void -channel_remove_user (struct channel *chan, struct channel_user *user) -{ - LIST_UNLINK (chan->users, user); - free (user); -} - -static size_t -channel_user_count (const struct channel *chan) -{ - size_t result = 0; - for (struct channel_user *iter = chan->users; iter; iter = iter->next) - result++; - return result; -} - -static void -channel_destroy_if_empty (struct server_context *ctx, struct channel *chan) -{ - if (!chan->users) - { - str_map_set (&ctx->channels, chan->name, NULL); - channel_free (chan); - free (chan); - } -} - -static bool -client_in_mask_list (const struct client *c, const struct str_vector *mask) -{ - struct str client; - str_init (&client); - str_append_printf (&client, "%s!%s@%s", - c->nickname, c->username, c->hostname); - irc_strxfrm (client.str, client.str, client.len); - bool result = false; - for (size_t i = 0; i < mask->len; i++) - // FIXME: irc_strxfrm() for the mask (save in canonical format?) - if (!fnmatch (client.str, mask->vector[i], 0)) - { - result = true; - break; - } - str_free (&client); - return result; -} - -static void -client_send_to_roommates (struct client *c, const char *message) -{ - struct str_map targets; - str_map_init (&targets); - targets.key_xfrm = irc_strxfrm; - - struct str_map_iter iter; - str_map_iter_init (&iter, &c->ctx->channels); - struct channel *chan; - while ((chan = str_map_iter_next (&iter))) - { - if (chan->modes & IRC_CHAN_MODE_QUIET - || !channel_get_user (chan, c)) - continue; - - // When we're unregistering, the str_map_find() will return zero, - // which will prevent sending the QUIT message to ourselves. - for (struct channel_user *iter = chan->users; iter; iter = iter->next) - str_map_set (&targets, iter->nickname, - str_map_find (&c->ctx->users, iter->nickname)); - } - - str_map_iter_init (&iter, &targets); - struct client *target; - while ((target = str_map_iter_next (&iter))) - irc_send (target, "%s", message); -} - -static void -client_unregister (struct client *c, const char *reason) -{ - if (!c->registered) - return; - - // Make the user effectively non-existent - str_map_set (&c->ctx->users, c->nickname, NULL); - - char *message = xstrdup_printf (":%s!%s@%s QUIT :%s", - c->nickname, c->username, c->hostname, reason); - client_send_to_roommates (c, message); - free (message); - - struct str_map_iter iter; - str_map_iter_init (&iter, &c->ctx->channels); - struct channel *chan; - while ((chan = str_map_iter_next (&iter))) - { - struct channel_user *user; - if (!(user = channel_get_user (chan, c))) - continue; - channel_remove_user (chan, user); - channel_destroy_if_empty (c->ctx, chan); - } - - free (c->nickname); - c->nickname = NULL; - c->registered = false; -} - static void irc_send_lusers (struct client *c) { @@ -1539,14 +1552,8 @@ irc_try_join (struct client *c, const char *channel_name, const char *key) { if (irc_validate_channel_name (channel_name) != VALIDATION_OK) RETURN_WITH_REPLY (c, IRC_ERR_BADCHANMASK, channel_name); + chan = channel_create (c->ctx, channel_name); user_mode = IRC_CHAN_MODE_OPERATOR; - - chan = xcalloc (1, sizeof *chan); - channel_init (chan); - str_map_set (&c->ctx->channels, channel_name, chan); - - chan->ctx = c->ctx; - chan->name = xstrdup (channel_name); } else if (channel_get_user (chan, c)) return; |