This needs a lot of testing, obviously.
#define INCLUDED_serv_h
#include "config.h"
+#include "capability.h"
/*
* The number of seconds between calls to try_connections(). Fiddle with
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
* 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 */
#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);
return 0;
}
+#ifdef NOTYET
/* check to ensure any "required" caps are set. --nenolod */
for (cap = captab; cap->name; cap++)
{
return 0;
}
}
+#endif
/* Now we just have to call check_server and everything should be
* check for us... -A1kmm. */
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;
{
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;
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;
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;
}
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;
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)
* 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,
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;
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;
int testing_conf = 0;
time_t startup_time;
-int default_server_capabs = CAP_MASK;
+int default_server_capabs;
int splitmode;
int splitchecking;
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;
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);
exit(EXIT_SUCCESS);
}
-
-
setup_signals();
if (testing_conf)
seed_random(NULL);
+ init_builtin_capabs();
+ default_server_capabs = CAP_MASK;
+
init_main_logfile();
newconf_init();
init_s_conf();
#include "msg.h"
#include "reject.h"
#include "sslproc.h"
+#include "capability.h"
#ifndef INADDR_NONE
#define INADDR_NONE ((unsigned int) 0xffffffff)
* 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;
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]);
/*
*
*/
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
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));
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;
}
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);