]> jfr.im git - irc/blitzed-org/charybdis.git/commitdiff
Migrate capability negotiation code to new dynamic capability management API.
authorWilliam Pitcock <redacted>
Sat, 4 Feb 2012 07:47:46 +0000 (01:47 -0600)
committerWilliam Pitcock <redacted>
Sat, 4 Feb 2012 07:47:46 +0000 (01:47 -0600)
This needs a lot of testing, obviously.

include/s_serv.h
modules/core/m_server.c
modules/m_capab.c
src/channel.c
src/client.c
src/ircd.c
src/s_serv.c

index 16d9e066ae91f7e8cf85637e46a3367266436b15..bf733bcb7993f52a4d8adcdb6848b3906c65016c 100644 (file)
@@ -28,6 +28,7 @@
 #define INCLUDED_serv_h
 
 #include "config.h"
+#include "capability.h"
 
 /*
  * The number of seconds between calls to try_connections(). Fiddle with
@@ -47,40 +48,35 @@ struct server_conf;
 struct Channel;
 
 /* Capabilities */
-struct Capability
-{
-       const char *name;       /* name of capability */
-       unsigned int cap;       /* mask value */
-       unsigned int required;  /* 1 if required, 0 if not */
-};
-
-#define CAP_CAP         0x00001        /* received a CAP to begin with */
-#define CAP_QS          0x00002        /* Can handle quit storm removal */
-#define CAP_EX          0x00004        /* Can do channel +e exemptions */
-#define CAP_CHW         0x00008        /* Can do channel wall @# */
-#define CAP_IE          0x00010        /* Can do invite exceptions */
-#define CAP_KLN                0x00040 /* Can do KLINE message */
-#define CAP_ZIP         0x00100        /* Can do ZIPlinks */
-#define CAP_KNOCK      0x00400 /* supports KNOCK */
-#define CAP_TB         0x00800 /* supports TBURST */
-#define CAP_UNKLN       0x01000        /* supports remote unkline */
-#define CAP_CLUSTER     0x02000        /* supports cluster stuff */
-#define CAP_ENCAP      0x04000 /* supports ENCAP */
-#define CAP_TS6                0x08000 /* supports TS6 or above */
-#define CAP_SERVICE    0x10000
-#define CAP_RSFNC      0x20000 /* rserv FNC */
-#define CAP_SAVE       0x40000 /* supports SAVE (nick collision FNC) */
-#define CAP_EUID       0x80000 /* supports EUID (ext UID + nonencap CHGHOST) */
-#define CAP_EOPMOD     0x100000 /* supports EOPMOD (ext +z + ext topic) */
-#define CAP_BAN                0x200000 /* supports propagated bans */
-#define CAP_MLOCK      0x400000 /* supports MLOCK messages */
-
-#define CAP_MASK        (CAP_QS  | CAP_EX   | CAP_CHW  | \
-                         CAP_IE  | CAP_KLN  | CAP_SERVICE |\
-                         CAP_CLUSTER | CAP_ENCAP | \
-                         CAP_ZIP  | CAP_KNOCK  | CAP_UNKLN | \
-                        CAP_RSFNC | CAP_SAVE | CAP_EUID | CAP_EOPMOD | \
-                        CAP_BAN | CAP_MLOCK)
+extern struct CapabilityIndex *serv_capindex;
+
+/*
+ * XXX: this is kind of ugly, but this allows us to have backwards
+ * API-compatibility.
+ */
+extern unsigned int CAP_CAP;                   /* received a CAP to begin with */
+extern unsigned int CAP_QS;                    /* Can handle quit storm removal */
+extern unsigned int CAP_EX;                    /* Can do channel +e exemptions */
+extern unsigned int CAP_CHW;                   /* Can do channel wall @# */
+extern unsigned int CAP_IE;                    /* Can do invite exceptions */
+extern unsigned int CAP_KLN;                   /* Can do KLINE message */
+extern unsigned int CAP_ZIP;                   /* Can do ZIPlinks */
+extern unsigned int CAP_KNOCK;                 /* supports KNOCK */
+extern unsigned int CAP_TB;                    /* supports TBURST */
+extern unsigned int CAP_UNKLN;                 /* supports remote unkline */
+extern unsigned int CAP_CLUSTER;               /* supports cluster stuff */
+extern unsigned int CAP_ENCAP;                 /* supports ENCAP */
+extern unsigned int CAP_TS6;                   /* supports TS6 or above */
+extern unsigned int CAP_SERVICE;               /* supports services */
+extern unsigned int CAP_RSFNC;                 /* rserv FNC */
+extern unsigned int CAP_SAVE;                  /* supports SAVE (nick collision FNC) */
+extern unsigned int CAP_EUID;                  /* supports EUID (ext UID + nonencap CHGHOST) */
+extern unsigned int CAP_EOPMOD;                        /* supports EOPMOD (ext +z + ext topic) */
+extern unsigned int CAP_BAN;                   /* supports propagated bans */
+extern unsigned int CAP_MLOCK;                 /* supports MLOCK messages */
+
+/* XXX: added for backwards compatibility. --nenolod */
+#define CAP_MASK       (capability_index_mask(serv_capindex) & ~(CAP_TS6 | CAP_CAP))
 
 #ifdef HAVE_LIBZ
 #define CAP_ZIP_SUPPORTED       CAP_ZIP
@@ -103,8 +99,6 @@ struct Capability
  * because all servers that we talk to already do TS, and the kludged
  * extra argument to "PASS" takes care of checking that.  -orabidoo
  */
-extern struct Capability captab[];
-
 extern int MaxClientCount;     /* GLOBAL - highest number of clients */
 extern int MaxConnectionCount; /* GLOBAL - highest number of connections */
 
@@ -117,11 +111,12 @@ extern int refresh_user_links;
 #define HUNTED_ISME     0      /* if this server should execute the command */
 #define HUNTED_PASS     1      /* if message passed onwards successfully */
 
+extern void init_builtin_capabs(void);
 
 extern int hunt_server(struct Client *client_pt,
                       struct Client *source_pt,
                       const char *command, int server, int parc, const char **parv);
-extern void send_capabilities(struct Client *, int);
+extern void send_capabilities(struct Client *, unsigned int);
 extern const char *show_capabilities(struct Client *client);
 extern void try_connections(void *unused);
 
index 839757f79736427d37edb73fd526224b0d493857..a957b871c92f0a0462d1ad208902d2f187798012 100644 (file)
@@ -109,6 +109,7 @@ mr_server(struct Client *client_p, struct Client *source_p, int parc, const char
                return 0;
        }
 
+#ifdef NOTYET
        /* check to ensure any "required" caps are set. --nenolod */
        for (cap = captab; cap->name; cap++)
        {
@@ -125,6 +126,7 @@ mr_server(struct Client *client_p, struct Client *source_p, int parc, const char
                        return 0;
                }
        }
+#endif
 
        /* Now we just have to call check_server and everything should be
         * check for us... -A1kmm. */
index 227a9972f4e6b5109644338e3b2437e0281d56c3..54e9a53f72e7f121511db16cb37185b8460934bc 100644 (file)
@@ -56,7 +56,6 @@ DECLARE_MODULE_AV1(capab, NULL, NULL, capab_clist, NULL, NULL, "$Revision: 1295
 static int
 mr_capab(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
 {
-       struct Capability *cap;
        int i;
        char *p;
        char *s;
@@ -84,16 +83,7 @@ mr_capab(struct Client *client_p, struct Client *source_p, int parc, const char
        {
                char *t = LOCAL_COPY(parv[i]);
                for (s = rb_strtok_r(t, " ", &p); s; s = rb_strtok_r(NULL, " ", &p))
-               {
-                       for (cap = captab; cap->name; cap++)
-                       {
-                               if(!irccmp(cap->name, s))
-                               {
-                                       client_p->localClient->caps |= cap->cap;
-                                       break;
-                               }
-                       }
-               }
+                       client_p->localClient->caps |= capability_get(serv_capindex, s);
        }
 
        return 0;
@@ -103,7 +93,6 @@ static int
 me_gcap(struct Client *client_p, struct Client *source_p,
                int parc, const char *parv[])
 {
-       struct Capability *cap;
        char *t = LOCAL_COPY(parv[1]);
        char *s;
        char *p;
@@ -121,16 +110,7 @@ me_gcap(struct Client *client_p, struct Client *source_p,
        source_p->serv->fullcaps = rb_strdup(parv[1]);
 
        for (s = rb_strtok_r(t, " ", &p); s; s = rb_strtok_r(NULL, " ", &p))
-       {
-               for (cap = captab; cap->name; cap++)
-               {
-                       if(!irccmp(cap->name, s))
-                       {
-                               source_p->serv->caps |= cap->cap;
-                               break;
-                       }
-               }
-       }
+               source_p->serv->caps |= capability_get(serv_capindex, s);
 
        return 0;
 }
index 2c4b41f73e9f2d24cfaba5b3f32778125a983e91..20c0dc2c53f29ace90b286fbc28464c708b0658a 100644 (file)
@@ -50,16 +50,6 @@ static rb_bh *ban_heap;
 static rb_bh *topic_heap;
 static rb_bh *member_heap;
 
-static int channel_capabs[] = { CAP_EX, CAP_IE,
-       CAP_SERVICE,
-       CAP_TS6
-};
-
-#define NCHCAPS         (sizeof(channel_capabs)/sizeof(int))
-#define NCHCAP_COMBOS   (1 << NCHCAPS)
-
-static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
-
 static void free_topic(struct Channel *chptr);
 
 static int h_can_join;
@@ -1198,102 +1188,6 @@ channel_modes(struct Channel *chptr, struct Client *client_p)
        return final;
 }
 
-/* Now lets do some stuff to keep track of what combinations of
- * servers exist...
- * Note that the number of combinations doubles each time you add
- * something to this list. Each one is only quick if no servers use that
- * combination, but if the numbers get too high here MODE will get too
- * slow. I suggest if you get more than 7 here, you consider getting rid
- * of some and merging or something. If it wasn't for irc+cs we would
- * probably not even need to bother about most of these, but unfortunately
- * we do. -A1kmm
- */
-
-/* void init_chcap_usage_counts(void)
- *
- * Inputs      - none
- * Output      - none
- * Side-effects        - Initialises the usage counts to zero. Fills in the
- *                chcap_yes and chcap_no combination tables.
- */
-void
-init_chcap_usage_counts(void)
-{
-       unsigned long m, c, y, n;
-
-       memset(chcap_combos, 0, sizeof(chcap_combos));
-
-       /* For every possible combination */
-       for (m = 0; m < NCHCAP_COMBOS; m++)
-       {
-               /* Check each capab */
-               for (c = y = n = 0; c < NCHCAPS; c++)
-               {
-                       if((m & (1 << c)) == 0)
-                               n |= channel_capabs[c];
-                       else
-                               y |= channel_capabs[c];
-               }
-               chcap_combos[m].cap_yes = y;
-               chcap_combos[m].cap_no = n;
-       }
-}
-
-/* void set_chcap_usage_counts(struct Client *serv_p)
- * Input: serv_p; The client whose capabs to register.
- * Output: none
- * Side-effects: Increments the usage counts for the correct capab
- *               combination.
- */
-void
-set_chcap_usage_counts(struct Client *serv_p)
-{
-       int n;
-
-       for (n = 0; n < NCHCAP_COMBOS; n++)
-       {
-               if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
-                  NotCapable(serv_p, chcap_combos[n].cap_no))
-               {
-                       chcap_combos[n].count++;
-                       return;
-               }
-       }
-
-       /* This should be impossible -A1kmm. */
-       s_assert(0);
-}
-
-/* void set_chcap_usage_counts(struct Client *serv_p)
- *
- * Inputs      - serv_p; The client whose capabs to register.
- * Output      - none
- * Side-effects        - Decrements the usage counts for the correct capab
- *                combination.
- */
-void
-unset_chcap_usage_counts(struct Client *serv_p)
-{
-       int n;
-
-       for (n = 0; n < NCHCAP_COMBOS; n++)
-       {
-               if(IsCapable(serv_p, chcap_combos[n].cap_yes) &&
-                  NotCapable(serv_p, chcap_combos[n].cap_no))
-               {
-                       /* Hopefully capabs can't change dynamically or anything... */
-                       s_assert(chcap_combos[n].count > 0);
-
-                       if(chcap_combos[n].count > 0)
-                               chcap_combos[n].count--;
-                       return;
-               }
-       }
-
-       /* This should be impossible -A1kmm. */
-       s_assert(0);
-}
-
 /* void send_cap_mode_changes(struct Client *client_p,
  *                        struct Client *source_p,
  *                        struct Channel *chptr, int cap, int nocap)
@@ -1305,6 +1199,9 @@ unset_chcap_usage_counts(struct Client *serv_p)
  * Reverted back to my original design, except that we now keep a count
  * of the number of servers which each combination as an optimisation, so
  * the capabs combinations which are not needed are not worked out. -A1kmm
+ *
+ * Removed most code here because we don't need to be compatible with ircd
+ * 2.8.21+CSr and stuff.  --nenolod
  */
 void
 send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
@@ -1315,109 +1212,100 @@ send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
        int i, mbl, pbl, nc, mc, preflen, len;
        char *pbuf;
        const char *arg;
-       int dir;
-       int j;
        int cap;
        int nocap;
+       int dir;
        int arglen;
 
        /* Now send to servers... */
-       for (j = 0; j < NCHCAP_COMBOS; j++)
+       mc = 0;
+       nc = 0;
+       pbl = 0;
+       parabuf[0] = 0;
+       pbuf = parabuf;
+       dir = MODE_QUERY;
+
+       mbl = preflen = rb_sprintf(modebuf, ":%s TMODE %ld %s ",
+                                  use_id(source_p), (long) chptr->channelts,
+                                  chptr->chname);
+
+       /* loop the list of - modes we have */
+       for (i = 0; i < mode_count; i++)
        {
-               if(chcap_combos[j].count == 0)
+               /* if they dont support the cap we need, or they do support a cap they
+                * cant have, then dont add it to the modebuf.. that way they wont see
+                * the mode
+                */
+               if (mode_changes[i].letter == 0)
                        continue;
 
-               mc = 0;
-               nc = 0;
-               pbl = 0;
-               parabuf[0] = 0;
-               pbuf = parabuf;
-               dir = MODE_QUERY;
+               cap = mode_changes[i].caps;
+               nocap = mode_changes[i].nocaps;
 
-               cap = chcap_combos[j].cap_yes;
-               nocap = chcap_combos[j].cap_no;
-
-               mbl = preflen = rb_sprintf(modebuf, ":%s TMODE %ld %s ",
-                                          use_id(source_p), (long) chptr->channelts,
-                                          chptr->chname);
+               if (!EmptyString(mode_changes[i].id))
+                       arg = mode_changes[i].id;
+               else
+                       arg = mode_changes[i].arg;
 
-               /* loop the list of - modes we have */
-               for (i = 0; i < mode_count; i++)
+               if(arg)
                {
-                       /* if they dont support the cap we need, or they do support a cap they
-                        * cant have, then dont add it to the modebuf.. that way they wont see
-                        * the mode
-                        */
-                       if((mode_changes[i].letter == 0) ||
-                          ((cap & mode_changes[i].caps) != mode_changes[i].caps)
-                          || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
-                               continue;
+                       arglen = strlen(arg);
 
-                       if(!EmptyString(mode_changes[i].id))
-                               arg = mode_changes[i].id;
-                       else
-                               arg = mode_changes[i].arg;
-
-                       if(arg)
-                       {
-                               arglen = strlen(arg);
-
-                               /* dont even think about it! --fl */
-                               if(arglen > MODEBUFLEN - 5)
-                                       continue;
-                       }
+                       /* dont even think about it! --fl */
+                       if(arglen > MODEBUFLEN - 5)
+                               continue;
+               }
 
-                       /* if we're creeping past the buf size, we need to send it and make
-                        * another line for the other modes
-                        * XXX - this could give away server topology with uids being
-                        * different lengths, but not much we can do, except possibly break
-                        * them as if they were the longest of the nick or uid at all times,
-                        * which even then won't work as we don't always know the uid -A1kmm.
-                        */
-                       if(arg && ((mc == MAXMODEPARAMSSERV) ||
-                                  ((mbl + pbl + arglen + 4) > (BUFSIZE - 3))))
-                       {
-                               if(nc != 0)
-                                       sendto_server(client_p, chptr, cap, nocap,
-                                                     "%s %s", modebuf, parabuf);
-                               nc = 0;
-                               mc = 0;
-
-                               mbl = preflen;
-                               pbl = 0;
-                               pbuf = parabuf;
-                               parabuf[0] = 0;
-                               dir = MODE_QUERY;
-                       }
+               /* if we're creeping past the buf size, we need to send it and make
+                * another line for the other modes
+                * XXX - this could give away server topology with uids being
+                * different lengths, but not much we can do, except possibly break
+                * them as if they were the longest of the nick or uid at all times,
+                * which even then won't work as we don't always know the uid -A1kmm.
+                */
+               if(arg && ((mc == MAXMODEPARAMSSERV) ||
+                          ((mbl + pbl + arglen + 4) > (BUFSIZE - 3))))
+               {
+                       if(nc != 0)
+                               sendto_server(client_p, chptr, cap, nocap,
+                                             "%s %s", modebuf, parabuf);
+                       nc = 0;
+                       mc = 0;
+
+                       mbl = preflen;
+                       pbl = 0;
+                       pbuf = parabuf;
+                       parabuf[0] = 0;
+                       dir = MODE_QUERY;
+               }
 
-                       if(dir != mode_changes[i].dir)
-                       {
-                               modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
-                               dir = mode_changes[i].dir;
-                       }
+               if(dir != mode_changes[i].dir)
+               {
+                       modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
+                       dir = mode_changes[i].dir;
+               }
 
-                       modebuf[mbl++] = mode_changes[i].letter;
-                       modebuf[mbl] = 0;
-                       nc++;
+               modebuf[mbl++] = mode_changes[i].letter;
+               modebuf[mbl] = 0;
+               nc++;
 
-                       if(arg != NULL)
-                       {
-                               len = rb_sprintf(pbuf, "%s ", arg);
-                               pbuf += len;
-                               pbl += len;
-                               mc++;
-                       }
+               if(arg != NULL)
+               {
+                       len = rb_sprintf(pbuf, "%s ", arg);
+                       pbuf += len;
+                       pbl += len;
+                       mc++;
                }
+       }
 
-               if(pbl && parabuf[pbl - 1] == ' ')
-                       parabuf[pbl - 1] = 0;
+       if(pbl && parabuf[pbl - 1] == ' ')
+               parabuf[pbl - 1] = 0;
 
-               if(nc != 0)
-                       sendto_server(client_p, chptr, cap, nocap, "%s %s", modebuf, parabuf);
-       }
+       if(nc != 0)
+               sendto_server(client_p, chptr, cap, nocap, "%s %s", modebuf, parabuf);
 }
 
-void 
+void
 resv_chan_forcepart(const char *name, const char *reason, int temp_time)
 {
        rb_dlink_node *ptr;
index 892c88cd5eb96a435112f478f177a4f4f5804908..4f8012778d2fc97cd5eb1a77536149d0ea67f9f9 100644 (file)
@@ -1326,7 +1326,6 @@ exit_local_server(struct Client *client_p, struct Client *source_p, struct Clien
        rb_dlinkDelete(&source_p->localClient->tnode, &serv_list);
        rb_dlinkFindDestroy(source_p, &global_serv_list);
        
-       unset_chcap_usage_counts(source_p);
        sendk = source_p->localClient->sendK;
        recvk = source_p->localClient->receiveK;
 
index b7448a5b85f7ca6f7ac0f3b88ceb388201f4ae04..cec470e9332147ae88937d5c87ae2ec9393ac96a 100644 (file)
@@ -112,7 +112,7 @@ int zlib_ok = 1;
 int testing_conf = 0;
 time_t startup_time;
 
-int default_server_capabs = CAP_MASK;
+int default_server_capabs;
 
 int splitmode;
 int splitchecking;
@@ -546,7 +546,7 @@ main(int argc, char *argv[])
        ConfigFileEntry.dpath = DPATH;
        ConfigFileEntry.configfile = CPATH;     /* Server configuration file */
        ConfigFileEntry.connect_timeout = 30;   /* Default to 30 */
-       
+
        umask(077);             /* better safe than sorry --SRB */
 
        myargv = argv;
@@ -584,9 +584,6 @@ main(int argc, char *argv[])
        memset(&AdminInfo, 0, sizeof(AdminInfo));
        memset(&ServerStats, 0, sizeof(struct ServerStatistics));
 
-       /* Initialise the channel capability usage counts... */
-       init_chcap_usage_counts();
-
        if(printVersion)
        {
                printf("ircd: version %s(%s)\n", ircd_version, serno);
@@ -597,8 +594,6 @@ main(int argc, char *argv[])
                exit(EXIT_SUCCESS);
        }
 
-
-
        setup_signals();
 
        if (testing_conf)
@@ -637,6 +632,9 @@ main(int argc, char *argv[])
 
        seed_random(NULL);
 
+       init_builtin_capabs();
+       default_server_capabs = CAP_MASK;
+
        init_main_logfile();
        newconf_init();
        init_s_conf();
index 02632bbf6e6787c248959f547fb9618102962881..311d3a6dff4c315c4e2026d3810792a5ff21f967 100644 (file)
@@ -54,6 +54,7 @@
 #include "msg.h"
 #include "reject.h"
 #include "sslproc.h"
+#include "capability.h"
 
 #ifndef INADDR_NONE
 #define INADDR_NONE ((unsigned int) 0xffffffff)
@@ -70,28 +71,56 @@ static char buf[BUFSIZE];
  * because all servers that we talk to already do TS, and the kludged
  * extra argument to "PASS" takes care of checking that.  -orabidoo
  */
-struct Capability captab[] = {
-/*  name     cap     */
-       { "QS",         CAP_QS },
-       { "EX",         CAP_EX },
-       { "CHW",        CAP_CHW},
-       { "IE",         CAP_IE},
-       { "KLN",        CAP_KLN},
-       { "KNOCK",      CAP_KNOCK},
-       { "ZIP",        CAP_ZIP},
-       { "TB",         CAP_TB},
-       { "UNKLN",      CAP_UNKLN},
-       { "CLUSTER",    CAP_CLUSTER},
-       { "ENCAP",      CAP_ENCAP },
-       { "SERVICES",   CAP_SERVICE },
-       { "RSFNC",      CAP_RSFNC },
-       { "SAVE",       CAP_SAVE },
-       { "EUID",       CAP_EUID },
-       { "EOPMOD",     CAP_EOPMOD },
-       { "BAN",        CAP_BAN },
-       { "MLOCK",      CAP_MLOCK },
-       {0, 0}
-};
+struct CapabilityIndex *serv_capindex = NULL;
+
+unsigned int CAP_CAP;
+unsigned int CAP_QS;
+unsigned int CAP_EX;
+unsigned int CAP_CHW;
+unsigned int CAP_IE;
+unsigned int CAP_KLN;
+unsigned int CAP_ZIP;
+unsigned int CAP_KNOCK;
+unsigned int CAP_TB;
+unsigned int CAP_UNKLN;
+unsigned int CAP_CLUSTER;
+unsigned int CAP_ENCAP;
+unsigned int CAP_TS6;
+unsigned int CAP_SERVICE;
+unsigned int CAP_RSFNC;
+unsigned int CAP_SAVE;
+unsigned int CAP_EUID;
+unsigned int CAP_EOPMOD;
+unsigned int CAP_BAN;
+unsigned int CAP_MLOCK;
+
+/*
+ * initialize our builtin capability table. --nenolod
+ */
+void
+init_builtin_capabs(void)
+{
+       serv_capindex = capability_index_create();
+
+       CAP_QS = capability_put(serv_capindex, "QS");
+       CAP_EX = capability_put(serv_capindex, "EX");
+       CAP_CHW = capability_put(serv_capindex, "CHW");
+       CAP_IE = capability_put(serv_capindex, "IE");
+       CAP_KLN = capability_put(serv_capindex, "KLN");
+       CAP_KNOCK = capability_put(serv_capindex, "KNOCK");
+       CAP_ZIP = capability_put(serv_capindex, "ZIP");
+       CAP_TB = capability_put(serv_capindex, "TB");
+       CAP_UNKLN = capability_put(serv_capindex, "UNKLN");
+       CAP_CLUSTER = capability_put(serv_capindex, "CLUSTER");
+       CAP_ENCAP = capability_put(serv_capindex, "ENCAP");
+       CAP_SERVICE = capability_put(serv_capindex, "SERVICES");
+       CAP_RSFNC = capability_put(serv_capindex, "RSFNC");
+       CAP_SAVE = capability_put(serv_capindex, "SAVE");
+       CAP_EUID = capability_put(serv_capindex, "EUID");
+       CAP_EOPMOD = capability_put(serv_capindex, "EOPMOD");
+       CAP_BAN = capability_put(serv_capindex, "BAN");
+       CAP_MLOCK = capability_put(serv_capindex, "MLOCK");
+}
 
 static CNCB serv_connect_callback;
 static CNCB serv_connect_ssl_callback;
@@ -131,7 +160,7 @@ hunt_server(struct Client *client_p, struct Client *source_p,
        if(parc <= server || EmptyString(parv[server]) ||
           match(parv[server], me.name) || (strcmp(parv[server], me.id) == 0))
                return (HUNTED_ISME);
-       
+
        new = LOCAL_COPY(parv[server]);
 
        /*
@@ -380,28 +409,9 @@ check_server(const char *name, struct Client *client_p)
  *
  */
 void
-send_capabilities(struct Client *client_p, int cap_can_send)
+send_capabilities(struct Client *client_p, unsigned int cap_can_send)
 {
-       struct Capability *cap;
-       char msgbuf[BUFSIZE];
-       char *t;
-       int tl;
-
-       t = msgbuf;
-
-       for (cap = captab; cap->name; ++cap)
-       {
-               if(cap->cap & cap_can_send)
-               {
-                       tl = rb_sprintf(t, "%s ", cap->name);
-                       t += tl;
-               }
-       }
-
-       t--;
-       *t = '\0';
-
-       sendto_one(client_p, "CAPAB :%s", msgbuf);
+       sendto_one(client_p, "CAPAB :%s", capability_index_list(serv_capindex, cap_can_send));
 }
 
 static void
@@ -693,7 +703,8 @@ const char *
 show_capabilities(struct Client *target_p)
 {
        static char msgbuf[BUFSIZE];
-       struct Capability *cap;
+
+       *msgbuf = '\0';
 
        if(has_id(target_p))
                rb_strlcpy(msgbuf, " TS6", sizeof(msgbuf));
@@ -704,11 +715,7 @@ show_capabilities(struct Client *target_p)
        if(!IsServer(target_p) || !target_p->serv->caps)        /* short circuit if no caps */
                return msgbuf + 1;
 
-       for (cap = captab; cap->cap; ++cap)
-       {
-               if(cap->cap & target_p->serv->caps)
-                       rb_snprintf_append(msgbuf, sizeof(msgbuf), " %s", cap->name);
-       }
+       rb_strlcat(msgbuf, capability_index_list(serv_capindex, target_p->serv->caps), sizeof(msgbuf));
 
        return msgbuf + 1;
 }
@@ -804,9 +811,6 @@ server_estab(struct Client *client_p)
 
        SetServer(client_p);
 
-       /* Update the capability combination usage counts */
-       set_chcap_usage_counts(client_p);
-
        rb_dlinkAdd(client_p, &client_p->lnode, &me.serv->servers);
        rb_dlinkMoveNode(&client_p->localClient->tnode, &unknown_list, &serv_list);
        rb_dlinkAddTailAlloc(client_p, &global_serv_list);