Support caching WHO replies.
authorJelmer Vernooij <jelmer@samba.org>
Wed, 6 Dec 2006 18:31:12 +0000 (19:31 +0100)
committerJelmer Vernooij <jelmer@samba.org>
Wed, 6 Dec 2006 18:31:12 +0000 (19:31 +0100)
NEWS
src/cache.c
src/settings.c
src/settings.h

diff --git a/NEWS b/NEWS
index 1fabd727aea9a76847bfe565f50f6b525257b796..dbdd630f2c3ea5cddc4eab8473e1b0ba43c8541f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,11 @@ Ctrlproxy 3.0.1 UNRELEASED
 
        * 324 and 329 replies are now cached.
 
+       * 352 and 315 replies are now (optionally) cached. The "max_who_age" 
+         setting can be set to the number of seconds that results should be cached.
+         This prevents "Excess Flood" errors when connecting using several xchat clients
+         at once.
+
 Ctrlproxy 3.0  UNRELEASED
 
   This list is not complete. Several subsystems in ctrlproxy have been 
index 86b3a15f2f2db26a27d3bf2abf0f70243475464f..cb3df1f6e28ec75d1414813a98d3b87e9c26bf0a 100644 (file)
@@ -148,6 +148,68 @@ static gboolean client_try_cache_topic(struct client *c, struct line *l)
        return TRUE;
 }
 
+static gboolean client_try_cache_who(struct client *c, struct line *l)
+{
+       struct channel_state *ch;
+       int max_who_age;
+       time_t now;
+       GList *gl;
+
+       g_assert(l);
+       g_assert(c);
+
+       if (l->argc < 2) return FALSE;
+       
+       /* Only optimize easy queries... */
+       if (strchr(l->args[1], ',')) return FALSE;
+       if (strchr(l->args[1], '*')) return FALSE;
+
+       max_who_age = c->network->global->config->max_who_age;
+
+       /* Never cache when max_who_age is set to 0 */
+       if (max_who_age == 0)
+               return FALSE;
+
+       if (l->argc != 2) 
+               return FALSE;
+
+       g_assert(c->network);
+       g_assert(c->network->state);
+
+       ch = find_channel(c->network->state, l->args[1]);
+       if (ch == NULL)
+               return FALSE;
+
+       now = time(NULL);
+
+       /* Check that the cache data hasn't expired yet */
+       for (gl = ch->nicks; gl; gl = gl->next) {
+               struct channel_nick *cn = gl->data;
+               struct network_nick *nn = cn->global_nick;
+               
+               if (nn->last_update == 0)
+                       return FALSE;
+
+               if ((nn->last_update + max_who_age) <= now)
+                       return FALSE;
+       }
+
+       for (gl = ch->nicks; gl; gl = gl->next) {
+               struct channel_nick *cn = gl->data;
+               struct network_nick *nn = cn->global_nick;
+               char *info = g_strdup_printf("%d %s", nn->last_hops, nn->fullname);
+               
+               client_send_response(c, RPL_WHOREPLY, l->args[1], nn->username, nn->hostname, nn->server, nn->nick, 
+                                                        nn->last_flags, info, NULL);
+
+               g_free(info);
+       }
+
+       client_send_response(c, RPL_ENDOFWHO, l->args[1], "End of /WHO list.", NULL);
+
+       return TRUE;
+}
+
 static gboolean client_try_cache_names(struct client *c, struct line *l)
 {
        struct channel_state *ch;
@@ -181,6 +243,7 @@ struct cache_command {
        { "MODE", client_try_cache_mode },
        { "NAMES", client_try_cache_names },
        { "TOPIC", client_try_cache_topic },
+       { "WHO", client_try_cache_who },
        { NULL, NULL }
 };
 
index 8a924965b47152ff44ba48e9ca3b4828eb925156..c6e06ca011804b9a9d78447a3e4888d36f1d9378 100644 (file)
@@ -182,6 +182,7 @@ void save_configuration(struct ctrlproxy_config *cfg, const char *configuration_
        g_key_file_set_boolean(cfg->keyfile, "global", "autosave", cfg->autosave);
        g_key_file_set_boolean(cfg->keyfile, "admin", "without_privmsg", cfg->admin_noprivmsg);
        g_key_file_set_boolean(cfg->keyfile, "admin", "log", cfg->admin_log);
+       g_key_file_set_integer(cfg->keyfile, "global", "max_who_age", cfg->max_who_age);
 
        g_key_file_set_string(cfg->keyfile, "client", "charset", cfg->client_charset);
        if (cfg->replication)
@@ -471,6 +472,9 @@ struct ctrlproxy_config *load_configuration(const char *dir)
                !g_key_file_get_boolean(kf, "global", "autosave", NULL))
                cfg->autosave = FALSE;
 
+       if (g_key_file_has_key(kf, "global", "max_who_age", NULL))
+               cfg->max_who_age = g_key_file_get_integer(kf, "global", "max_who_age", NULL);
+
        cfg->replication = g_key_file_get_string(kf, "global", "replication", NULL);
        cfg->linestack_backend = g_key_file_get_string(kf, "global", "linestack", NULL);
 
index 316c5f1c71719b7bceca065915135eb2e2aa612e..663b9c99526f36b7978aa4b81d4d757b2814b0df 100644 (file)
@@ -97,6 +97,7 @@ struct ctrlproxy_config {
        gboolean admin_log;
        gboolean admin_noprivmsg;
        gboolean report_time;
+       int max_who_age;
        GKeyFile *keyfile;
 };