aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/kike.c333
1 files changed, 170 insertions, 163 deletions
diff --git a/src/kike.c b/src/kike.c
index cda6984..7639248 100644
--- a/src/kike.c
+++ b/src/kike.c
@@ -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;