From: wiebe Date: Sun, 18 Jan 2009 16:53:15 +0000 (+0100) Subject: some more patches: split functionality, make stats output clearer, start to add ... X-Git-Url: https://jfr.im/git/irc/quakenet/snircd-patchqueue.git/commitdiff_plain/12e82c0560263d6046740a039ce6ad2cef944023?hp=88a737dbe8bb00aa5d6419ace01faf991cb2301d some more patches: split functionality, make stats output clearer, start to add /HELP , etc. --- diff --git a/cmdhelp.patch b/cmdhelp.patch new file mode 100644 index 0000000..e982ddc --- /dev/null +++ b/cmdhelp.patch @@ -0,0 +1,26 @@ +make /HELP work - oper only feature? +need to make small test case to see how hard/easy this would be to add. + +diff -r ce13b0a1253e ircd/m_help.c +--- a/ircd/m_help.c Wed Jan 14 14:19:43 2009 +0100 ++++ b/ircd/m_help.c Wed Jan 14 15:01:46 2009 +0100 +@@ -100,7 +100,7 @@ + int m_help(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) + { + int i; +- ++/* check here for param and find command, then call the function set for that entry? */ + for (i = 0; msgtab[i].cmd; i++) + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s", sptr, msgtab[i].cmd); + return 0; +diff -r ce13b0a1253e ircd/parse.c +--- a/ircd/parse.c Wed Jan 14 14:19:43 2009 +0100 ++++ b/ircd/parse.c Wed Jan 14 15:01:46 2009 +0100 +@@ -105,6 +105,7 @@ + static struct MessageTree tok_tree; + + /** Array of all supported commands. */ ++/* add mh_ here? mh = message help */ + struct Message msgtab[] = { + { + MSG_PRIVATE, diff --git a/glinesnomask.patch b/glinesnomask.patch index f970e80..4917714 100644 --- a/glinesnomask.patch +++ b/glinesnomask.patch @@ -1,4 +1,7 @@ SNO_GLINE and SNO_AUTO + +change of plans. + before, glines with reason starting with "AUTO" end up in SNO_AUTO, all other in SNO_GLINE now /* figure out what snomask to send to, send to SNO_GLINE when: diff --git a/opername.patch b/opername.patch index 9e1dfaa..20a6c67 100644 --- a/opername.patch +++ b/opername.patch @@ -1,8 +1,8 @@ Add opername to snomask, remote connect wallops, and logging -diff -r 897950943d34 include/client.h ---- a/include/client.h Mon Jan 12 18:45:19 2009 +0100 -+++ b/include/client.h Mon Jan 12 19:23:07 2009 +0100 +diff -r dffb1fdabb12 include/client.h +--- a/include/client.h Wed Jan 14 14:19:42 2009 +0100 ++++ b/include/client.h Wed Jan 14 15:27:42 2009 +0100 @@ -806,6 +806,7 @@ #define IPV6USERBITS 64 @@ -11,10 +11,10 @@ diff -r 897950943d34 include/client.h extern const char* client_get_default_umode(const struct Client* sptr); extern int client_get_ping(const struct Client* local_client); extern void client_drop_sendq(struct Connection* con); -diff -r 897950943d34 ircd/channel.c ---- a/ircd/channel.c Mon Jan 12 18:45:19 2009 +0100 -+++ b/ircd/channel.c Mon Jan 12 19:23:07 2009 +0100 -@@ -1850,8 +1850,8 @@ +diff -r dffb1fdabb12 ircd/channel.c +--- a/ircd/channel.c Wed Jan 14 14:19:42 2009 +0100 ++++ b/ircd/channel.c Wed Jan 14 15:27:43 2009 +0100 +@@ -1848,8 +1848,8 @@ if (mbuf->mb_dest & MODEBUF_DEST_HACK4) sendto_opmask_butone(0, SNO_HACK4, "HACK(4): %s MODE %s %s%s%s%s%s%s " "[%Tu]", @@ -25,19 +25,10 @@ diff -r 897950943d34 ircd/channel.c mbuf->mb_channel->chname, rembuf_i ? "-" : "", rembuf, addbuf_i ? "+" : "", addbuf, remstr, addstr, -@@ -1859,7 +1859,7 @@ - - if (mbuf->mb_dest & MODEBUF_DEST_LOG) - log_write(LS_OPERMODE, L_INFO, LOG_NOSNOTICE, -- "%#C OPMODE %H %s%s%s%s%s%s", mbuf->mb_source, -+ "%s OPMODE %H %s%s%s%s%s%s", get_client_name_and_opername(mbuf->mb_source), - mbuf->mb_channel, rembuf_i ? "-" : "", rembuf, - addbuf_i ? "+" : "", addbuf, remstr, addstr); - -diff -r 897950943d34 ircd/gline.c ---- a/ircd/gline.c Mon Jan 12 18:45:19 2009 +0100 -+++ b/ircd/gline.c Mon Jan 12 19:23:07 2009 +0100 -@@ -566,7 +566,7 @@ +diff -r dffb1fdabb12 ircd/gline.c +--- a/ircd/gline.c Wed Jan 14 14:19:42 2009 +0100 ++++ b/ircd/gline.c Wed Jan 14 15:27:43 2009 +0100 +@@ -577,7 +577,7 @@ sendto_opmask_butone(0, snomask, "%s adding %s %s for %s%s%s%s%s, expiring at " "%Tu: %s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? @@ -46,16 +37,7 @@ diff -r 897950943d34 ircd/gline.c cli_name((cli_user(sptr))->server), (flags & GLINE_LOCAL) ? "local" : "global", (flags & GLINE_BADCHAN) ? "BADCHAN" : "GLINE", -@@ -579,7 +579,7 @@ - - /* and log it */ - log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE, -- "%#C adding %s %s for %s%s%s%s%s, expiring at %Tu: %s", sptr, -+ "%s adding %s %s for %s%s%s%s%s, expiring at %Tu: %s", get_client_name_and_opername(sptr), - flags & GLINE_LOCAL ? "local" : "global", - flags & GLINE_BADCHAN ? "BADCHAN" : "GLINE", - flags & (GLINE_BADCHAN|GLINE_REALNAME) ? "" : nick, -@@ -652,7 +652,7 @@ +@@ -663,7 +663,7 @@ sendto_opmask_butone(0, SNO_GLINE, "%s activating global %s for %s%s%s%s%s, " "expiring at %Tu: %s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? @@ -64,16 +46,7 @@ diff -r 897950943d34 ircd/gline.c cli_name((cli_user(sptr))->server), GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", GlineIsBadChan(gline)|GlineIsRealName(gline) ? "" : gline->gl_nick, -@@ -662,7 +662,7 @@ - gline->gl_expire + TSoffset, gline->gl_reason); - - log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE, -- "%#C activating global %s for %s%s%s%s%s, expiring at %Tu: %s", sptr, -+ "%s activating global %s for %s%s%s%s%s, expiring at %Tu: %s", get_client_name_and_opername(sptr), - GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", - GlineIsBadChan(gline)|GlineIsRealName(gline) ? "" : gline->gl_nick, - GlineIsBadChan(gline)|GlineIsRealName(gline) ? "" : "!", -@@ -725,7 +725,7 @@ +@@ -736,7 +736,7 @@ sendto_opmask_butone(0, SNO_GLINE, "%s %s %s for %s%s%s%s%s, expiring at %Tu: " "%s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? @@ -82,16 +55,7 @@ diff -r 897950943d34 ircd/gline.c cli_name((cli_user(sptr))->server), msg, GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", GlineIsBadChan(gline)|GlineIsRealName(gline) ? "" : gline->gl_nick, -@@ -735,7 +735,7 @@ - gline->gl_expire + TSoffset, gline->gl_reason); - - log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE, -- "%#C %s %s for %s%s%s%s%s, expiring at %Tu: %s", sptr, msg, -+ "%s %s %s for %s%s%s%s%s, expiring at %Tu: %s", get_client_name_and_opername(sptr), msg, - GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", - GlineIsBadChan(gline)|GlineIsRealName(gline) ? "" : gline->gl_nick, - GlineIsBadChan(gline)|GlineIsRealName(gline) ? "" : "!", -@@ -940,7 +940,7 @@ +@@ -987,7 +987,7 @@ /* All right, inform ops... */ sendto_opmask_butone(0, SNO_GLINE, "%s modifying global %s for %s%s%s%s%s:%s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? @@ -100,16 +64,7 @@ diff -r 897950943d34 ircd/gline.c GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", GlineIsBadChan(gline)|GlineIsRealName(gline) ? "" : gline->gl_nick, GlineIsBadChan(gline)|GlineIsRealName(gline) ? "" : "!", -@@ -949,7 +949,7 @@ - - /* and log the change */ - log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE, -- "%#C modifying global %s for %s%s%s:%s", sptr, -+ "%s modifying global %s for %s%s%s:%s", get_client_name_and_opername(sptr), - GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", gline->gl_user, - gline->gl_host ? "@" : "", gline->gl_host ? gline->gl_host : "", - buf); -@@ -997,14 +997,14 @@ +@@ -1044,7 +1044,7 @@ /* Inform ops and log it */ sendto_opmask_butone(0, SNO_GLINE, "%s removing local %s for %s%s%s%s%s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? @@ -118,36 +73,10 @@ diff -r 897950943d34 ircd/gline.c GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", GlineIsBadChan(gline)|GlineIsRealName(gline) ? "" : gline->gl_nick, GlineIsBadChan(gline)|GlineIsRealName(gline) ? "" : "!", - gline->gl_user, gline->gl_host ? "@" : "", - gline->gl_host ? gline->gl_host : ""); - log_write(LS_GLINE, L_INFO, LOG_NOSNOTICE, -- "%#C removing local %s for %s%s%s%s%s", sptr, -+ "%s removing local %s for %s%s%s%s%s", get_client_name_and_opername(sptr), - GlineIsBadChan(gline) ? "BADCHAN" : "GLINE", - GlineIsBadChan(gline)|GlineIsRealName(gline) ? "" : gline->gl_nick, - GlineIsBadChan(gline)|GlineIsRealName(gline) ? "" : "!", -diff -r 897950943d34 ircd/ircd_log.c ---- a/ircd/ircd_log.c Mon Jan 12 18:45:19 2009 +0100 -+++ b/ircd/ircd_log.c Mon Jan 12 19:23:07 2009 +0100 -@@ -469,11 +469,11 @@ - { - if (MyUser(victim)) - log_write(IsServer(killer) ? LS_SERVKILL : LS_OPERKILL, L_TRACE, 0, -- "A local client %#C KILLED by %#C Path: %s!%s %s", -- victim, killer, inpath, path, msg); -+ "A local client %#C KILLED by %s Path: %s!%s %s", -+ victim, get_client_name_and_opername(killer), inpath, path, msg); - else - log_write(IsServer(killer) ? LS_SERVKILL : LS_OPERKILL, L_TRACE, 0, -- "KILL from %C For %C Path: %s!%s %s", killer, victim, inpath, -+ "KILL from %s For %C Path: %s!%s %s", get_client_name_and_opername(killer), victim, inpath, - path, msg); - } - -diff -r 897950943d34 ircd/jupe.c ---- a/ircd/jupe.c Mon Jan 12 18:45:19 2009 +0100 -+++ b/ircd/jupe.c Mon Jan 12 19:23:07 2009 +0100 -@@ -156,13 +156,13 @@ +diff -r dffb1fdabb12 ircd/jupe.c +--- a/ircd/jupe.c Wed Jan 14 14:19:42 2009 +0100 ++++ b/ircd/jupe.c Wed Jan 14 15:27:43 2009 +0100 +@@ -156,7 +156,7 @@ sendto_opmask_butone(0, SNO_NETWORK, "%s adding %sJUPE for %s, expiring at " "%Tu: %s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? @@ -156,14 +85,7 @@ diff -r 897950943d34 ircd/jupe.c cli_name((cli_user(sptr))->server), flags & JUPE_LOCAL ? "local " : "", server, expire + TSoffset, reason); - - log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE, -- "%#C adding %sJUPE for %s, expiring at %Tu: %s", sptr, -+ "%s adding %sJUPE for %s, expiring at %Tu: %s", get_client_name_and_opername(sptr), - flags & JUPE_LOCAL ? "local " : "", server, expire + TSoffset, - reason); - -@@ -216,13 +216,13 @@ +@@ -216,7 +216,7 @@ sendto_opmask_butone(0, SNO_NETWORK, "%s activating JUPE for %s, expiring " "at %Tu: %s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? @@ -172,14 +94,7 @@ diff -r 897950943d34 ircd/jupe.c cli_name((cli_user(sptr))->server), jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason); - - log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE, -- "%#C activating JUPE for %s, expiring at %Tu: %s",sptr, -+ "%s activating JUPE for %s, expiring at %Tu: %s", get_client_name_and_opername(sptr), - jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason); - - if (!(flags & JUPE_LOCAL)) /* don't propagate local changes */ -@@ -269,14 +269,14 @@ +@@ -269,7 +269,7 @@ sendto_opmask_butone(0, SNO_NETWORK, "%s %s JUPE for %s, expiring at %Tu: " "%s", (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? @@ -188,32 +103,21 @@ diff -r 897950943d34 ircd/jupe.c cli_name((cli_user(sptr))->server), JupeIsLocal(jupe) ? "removing local" : "deactivating", jupe->ju_server, jupe->ju_expire + TSoffset, - jupe->ju_reason); - - log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE, -- "%#C %s JUPE for %s, expiring at %Tu: %s", sptr, -+ "%s %s JUPE for %s, expiring at %Tu: %s", get_client_name_and_opername(sptr), - JupeIsLocal(jupe) ? "removing local" : "deactivating", - jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason); - -diff -r 897950943d34 ircd/m_connect.c ---- a/ircd/m_connect.c Mon Jan 12 18:45:19 2009 +0100 -+++ b/ircd/m_connect.c Mon Jan 12 19:23:07 2009 +0100 -@@ -197,8 +197,9 @@ +diff -r dffb1fdabb12 ircd/m_connect.c +--- a/ircd/m_connect.c Wed Jan 14 14:19:42 2009 +0100 ++++ b/ircd/m_connect.c Wed Jan 14 15:27:43 2009 +0100 +@@ -197,7 +197,7 @@ sendwallto_group_butone(&me, WALL_WALLOPS, 0, "Remote CONNECT %s %s from %s", aconf->name, parv[2] ? parv[2] : "", - get_client_name(sptr, HIDE_IP)); -- log_write(LS_NETWORK, L_INFO, 0, "CONNECT From %C : %s %s", sptr, aconf->name, + get_client_name_and_opername(sptr)); -+ log_write(LS_NETWORK, L_INFO, 0, "CONNECT From %s : %s %s", -+ get_client_name_and_opername(sptr), aconf->name, + log_write(LS_NETWORK, L_INFO, 0, "CONNECT From %C : %s %s", sptr, aconf->name, parv[2] ? parv[2] : ""); - if (connect_server(aconf, sptr)) { -diff -r 897950943d34 ircd/m_join.c ---- a/ircd/m_join.c Mon Jan 12 18:45:19 2009 +0100 -+++ b/ircd/m_join.c Mon Jan 12 19:23:07 2009 +0100 +diff -r dffb1fdabb12 ircd/m_join.c +--- a/ircd/m_join.c Wed Jan 14 14:19:42 2009 +0100 ++++ b/ircd/m_join.c Wed Jan 14 15:27:43 2009 +0100 @@ -242,8 +242,8 @@ } /* send accountability notice */ @@ -225,9 +129,9 @@ diff -r 897950943d34 ircd/m_join.c err = 0; } -diff -r 897950943d34 ircd/m_kill.c ---- a/ircd/m_kill.c Mon Jan 12 18:45:19 2009 +0100 -+++ b/ircd/m_kill.c Mon Jan 12 19:23:07 2009 +0100 +diff -r dffb1fdabb12 ircd/m_kill.c +--- a/ircd/m_kill.c Wed Jan 14 14:19:42 2009 +0100 ++++ b/ircd/m_kill.c Wed Jan 14 15:27:43 2009 +0100 @@ -127,7 +127,7 @@ */ sendto_opmask_butone(0, snomask, @@ -237,10 +141,10 @@ diff -r 897950943d34 ircd/m_kill.c inpath, path, msg); log_write_kill(victim, sptr, inpath, path, msg); -diff -r 897950943d34 ircd/m_rehash.c ---- a/ircd/m_rehash.c Mon Jan 12 18:45:19 2009 +0100 -+++ b/ircd/m_rehash.c Mon Jan 12 19:23:07 2009 +0100 -@@ -121,10 +121,10 @@ +diff -r dffb1fdabb12 ircd/m_rehash.c +--- a/ircd/m_rehash.c Wed Jan 14 14:19:42 2009 +0100 ++++ b/ircd/m_rehash.c Wed Jan 14 15:27:43 2009 +0100 +@@ -121,8 +121,8 @@ } send_reply(sptr, RPL_REHASHING, configfile); @@ -249,14 +153,11 @@ diff -r 897950943d34 ircd/m_rehash.c + sendto_opmask_butone(0, SNO_OLDSNO, "%s is rehashing Server config file", + get_client_name_and_opername(sptr)); -- log_write(LS_SYSTEM, L_INFO, 0, "REHASH From %#C", sptr); -+ log_write(LS_SYSTEM, L_INFO, 0, "REHASH From %s", get_client_name_and_opername(sptr)); + log_write(LS_SYSTEM, L_INFO, 0, "REHASH From %#C", sptr); - return rehash(cptr, flag); - } -diff -r 897950943d34 ircd/m_settime.c ---- a/ircd/m_settime.c Mon Jan 12 18:45:19 2009 +0100 -+++ b/ircd/m_settime.c Mon Jan 12 19:23:07 2009 +0100 +diff -r dffb1fdabb12 ircd/m_settime.c +--- a/ircd/m_settime.c Wed Jan 14 14:19:42 2009 +0100 ++++ b/ircd/m_settime.c Wed Jan 14 15:27:43 2009 +0100 @@ -177,7 +177,7 @@ else /* tell opers about time change */ { @@ -275,9 +176,9 @@ diff -r 897950943d34 ircd/m_settime.c (dt < 0) ? "forwards" : "backwards"); TSoffset -= dt; /* apply time change */ if (IsUser(sptr)) /* let user know what we did */ -diff -r 897950943d34 ircd/s_misc.c ---- a/ircd/s_misc.c Mon Jan 12 18:45:19 2009 +0100 -+++ b/ircd/s_misc.c Mon Jan 12 19:23:07 2009 +0100 +diff -r dffb1fdabb12 ircd/s_misc.c +--- a/ircd/s_misc.c Wed Jan 14 14:19:42 2009 +0100 ++++ b/ircd/s_misc.c Wed Jan 14 15:27:43 2009 +0100 @@ -169,6 +169,20 @@ ircd_snprintf(0, nbuf, sizeof(nbuf), "%s[%s@%s]", cli_name(sptr), IsIdented(sptr) ? cli_username(sptr) : "", diff --git a/series b/series index 50781ea..bb886f0 100644 --- a/series +++ b/series @@ -1,3 +1,4 @@ +statsheader.patch addnickchasetomodenick.patch #+nickchase chanopaccountabilityforkickdelayedjoin.patch addopkickcmd.patch #+opkick @@ -12,3 +13,5 @@ commonchansumode.patch remoteglinejupe.patch whoban.patch opername.patch +cmdhelp.patch +split.patch diff --git a/split.patch b/split.patch new file mode 100644 index 0000000..92a35cd --- /dev/null +++ b/split.patch @@ -0,0 +1,1693 @@ +work in progress +Add split functionality into ircd +Add /split command +Add /stats S/split (make /STATS s/S case sensitive, s spoofhosts) +Add feature SPLIT +Add split.c split.h m_split.c + +diff -r 2da61ac38fa1 include/handlers.h +--- a/include/handlers.h Sun Jan 18 14:18:36 2009 +0100 ++++ b/include/handlers.h Sun Jan 18 15:26:56 2009 +0100 +@@ -139,6 +139,7 @@ + extern int m_registered(struct Client*, struct Client*, int, char*[]); + extern int m_sethost(struct Client*, struct Client*, int, char*[]); + extern int m_silence(struct Client*, struct Client*, int, char*[]); ++extern int m_split(struct Client*, struct Client*, int, char*[]); + extern int m_stats(struct Client*, struct Client*, int, char*[]); + extern int m_time(struct Client*, struct Client*, int, char*[]); + extern int m_topic(struct Client*, struct Client*, int, char*[]); +@@ -178,6 +179,7 @@ + extern int mo_rping(struct Client*, struct Client*, int, char*[]); + extern int mo_set(struct Client*, struct Client*, int, char*[]); + extern int mo_settime(struct Client*, struct Client*, int, char*[]); ++extern int mo_split(struct Client*, struct Client*, int, char*[]); + extern int mo_squit(struct Client*, struct Client*, int, char*[]); + extern int mo_stats(struct Client*, struct Client*, int, char*[]); + extern int mo_trace(struct Client*, struct Client*, int, char*[]); +@@ -232,6 +234,7 @@ + extern int ms_sethost(struct Client*, struct Client*, int, char*[]); + extern int ms_settime(struct Client*, struct Client*, int, char*[]); + extern int ms_silence(struct Client*, struct Client*, int, char*[]); ++extern int ms_split(struct Client*, struct Client*, int, char*[]); + extern int ms_squit(struct Client*, struct Client*, int, char*[]); + extern int ms_stats(struct Client*, struct Client*, int, char*[]); + extern int ms_topic(struct Client*, struct Client*, int, char*[]); +diff -r 2da61ac38fa1 include/ircd_features.h +--- a/include/ircd_features.h Sun Jan 18 14:18:36 2009 +0100 ++++ b/include/ircd_features.h Sun Jan 18 15:26:56 2009 +0100 +@@ -109,6 +109,7 @@ + FEAT_SETHOST, + FEAT_SETHOST_USER, + FEAT_SETHOST_AUTO, ++ FEAT_SPLIT, + + /* HEAD_IN_SAND Features */ + FEAT_HIS_SNOTICES, +@@ -137,6 +138,7 @@ + FEAT_HIS_STATS_q, + FEAT_HIS_STATS_R, + FEAT_HIS_STATS_r, ++ FEAT_HIS_STATS_S, + FEAT_HIS_STATS_s, + FEAT_HIS_STATS_t, + FEAT_HIS_STATS_T, +diff -r 2da61ac38fa1 include/msg.h +--- a/include/msg.h Sun Jan 18 14:18:36 2009 +0100 ++++ b/include/msg.h Sun Jan 18 15:26:56 2009 +0100 +@@ -332,6 +332,10 @@ + #define TOK_JUPE "JU" + #define CMD_JUPE MSG_JUPE, TOK_JUPE + ++#define MSG_SPLIT "SPLIT" /* SPLIT */ ++#define TOK_SPLIT "SP" ++#define CMD_SPLIT MSG_SPLIT, TOK_SPLIT ++ + #define MSG_OPMODE "OPMODE" /* OPMO */ + #define TOK_OPMODE "OM" + #define CMD_OPMODE MSG_OPMODE, TOK_OPMODE +diff -r 2da61ac38fa1 include/numeric.h +--- a/include/numeric.h Sun Jan 18 14:18:36 2009 +0100 ++++ b/include/numeric.h Sun Jan 18 15:26:56 2009 +0100 +@@ -117,6 +117,7 @@ + RPL_STATSVLINE 227 unreal */ + #define RPL_STATSALINE 226 /* Hybrid, Undernet */ + #define RPL_STATSQLINE 228 /* Undernet extension */ ++#define RPL_STATSSPLIT 229 /* QuakeNet extension */ + + /* RPL_SERVICEINFO 231 unused */ + /* RPL_ENDOFSERVICES 232 unused */ +@@ -177,6 +178,8 @@ + #define RPL_STATSDLINE 275 /* Undernet extension */ + #define RPL_STATSRLINE 276 /* Undernet extension */ + ++#define RPL_SPLITLIST 278 /* QuakeNet extension */ ++#define RPL_ENDOFSPLITLIST 279 /* QuakeNet extension */ + #define RPL_GLIST 280 /* Undernet extension */ + #define RPL_ENDOFGLIST 281 /* Undernet extension */ + #define RPL_JUPELIST 282 /* Undernet extension - jupe -Kev */ +@@ -440,6 +443,7 @@ + /* ERR_GHOSTEDCLIENT 503 efnet */ + /* ERR_VWORLDWARN 503 austnet */ + ++#define ERR_NOSUCHSPLIT 510 /* QuakeNet extension */ + #define ERR_SILELISTFULL 511 /* Undernet extension */ + /* ERR_NOTIFYFULL 512 aircd */ + /* ERR_TOOMANYWATCH 512 Numeric List: Dalnet */ +diff -r 2da61ac38fa1 include/split.h +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/include/split.h Sun Jan 18 15:26:56 2009 +0100 +@@ -0,0 +1,121 @@ ++/* TODO: ifndef ? */ ++#ifndef INCLUDED_jupe_h ++#define INCLUDED_jupe_h ++/* ++ * IRC - Internet Relay Chat, include/split.h ++ * Copyright (C) 1990 Jarkko Oikarinen and ++ * University of Oulu, Computing Center ++ * Copyright (C) 2000 Kevin L. Mitchell ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/** @file ++ * @brief Interface and declarations for split server handling. ++ * @version $Id: jupe.h 1208 2004-10-03 14:12:35Z entrope $ ++ */ ++/* TODO: ifndef ? */ ++#ifndef INCLUDED_sys_types_h ++#include ++#define INCLUDED_sys_types_h ++#endif ++ ++ ++struct Client; ++struct StatDesc; ++ ++#define SPLIT_MAX_EXPIRE 604800 /**< Maximum split expiration time (7 days). */ ++#define SPLIT_AUTO_EXPIRE 604800 /**< Expireation time used for auto created entries. */ ++ ++/* Describes a SPLIT server entry. */ ++struct Split { ++ struct Split* sp_next; /**< Pointer to next Split. */ ++ struct Split** sp_prev_p; /**< Pointer to previous next pointer. */ ++ char* sp_server; /**< Name of server. */ ++ char* sp_reason; /**< Reason. */ ++ time_t sp_creation; /**< TODO: Creation time. What are we using this for then? */ ++ time_t sp_expire; /**< Expiration time. */ ++ time_t sp_lastmod; /**< Last modification time. */ ++ time_t sp_lifetime; /**< Life time. */ ++ unsigned int sp_flags; /**< Status flags. */ ++}; ++ ++/** Split state flags. */ ++#define SPLIT_ACTIVE 0x0001 /**< Split is active. */ ++#define SPLIT_REMOVING 0x0002 /**< Split is about to be destroyed. */ ++ ++/* TODO: these ; after } needed ? */ ++/* Actions to perform on a SPLIT. */ ++enum SplitAction { ++ SPLIT_ACTIVATE, /**< SPLIT should be activated. */ ++ SPLIT_DEACTIVATE, /**< SPLIT should be deactivated. */ ++ SPLIT_MODIFY, /**< SPLIT should be modified. */ ++ SPLIT_REMOVE /**< SPLIT should be removed. */ ++}; ++ ++/* TODO: what values to use here? */ ++/* Split update flags. */ ++#define SPLIT_EXPIRE 0x0002 /**< Expiration time update. */ ++#define SPLIT_LIFETIME 0x0004 /**< Record lifetime update. */ ++#define SPLIT_REASON 0x0008 /**< Reason update. */ ++#define SPLIT_CREATION 0x0010 /**< Creation time update. */ ++#define SPLIT_MODIFY 0x0020 /**< No state change. */ ++ ++/* mask for Split update flags. */ ++#define SPLIT_UPDATE (SPLIT_EXPIRE | SPLIT_LIFETIME | SPLIT_REASON) ++ ++/* test whether a split entry is active. */ ++#define SplitIsActive(s) ((s)->sp_flags & SPLIT_ACTIVE) ++/* test whether a split entry is marked for forecd removal. */ ++#define SplitIsRemoving(s) ((s)->sp_flags & SPLIT_REMOVING) ++ ++/* TODO: these are not used? some are, check! */ ++/* get the server name for a split entry. */ ++#define SplitServer(s) ((s)->sp_server) ++/* get the reason for a split entry. */ ++#define SplitReason(s) ((s)->sp_reason) ++/* get the creation time for split entry. */ ++#define SplitCreation(s) ((s)->sp_creation) ++/* get the expiration time for split entry. */ ++#define SplitExpire(s) ((s)->sp_expire) ++/* get the last modification time for split entry. */ ++#define SplitLastMod(s) ((s)->sp_lastmod) ++/* get the life time for split entry. */ ++#define SplitLifeTime(s) ((s)->sp_lifetime) ++ ++extern int split_add(struct Client *cptr, struct Client *sptr, ++ char *server, const char *reason, ++ time_t creation, time_t expire, time_t lastmod, time_t lifetime, ++ unsigned int flags); ++extern int split_modify(struct Client *cptr, struct Client *sptr, ++ struct Split *split, enum SplitAction action, const char *reason, ++ time_t creation, time_t expire, time_t lastmod, time_t lifetime, ++ unsigned int flags); ++extern int split_remove(struct Client *cptr, struct Client *sptr, ++ struct Split *split, const char *reason); ++ ++extern struct Split* split_find(char *server); ++extern void split_free(struct Split *split); ++extern int split_expire(struct Split* split); ++extern void split_burst(struct Client *cptr); ++extern int split_resend(struct Client *cptr, struct Split *split); ++extern int split_list(struct Client *sptr, char *server); ++extern int split_merge(struct Client *server); ++extern int split_break(struct Client *server, const char *reason); ++extern void split_conf(); ++extern void split_stats(struct Client *sptr, const struct StatDesc *sd, char *param); ++extern int split_memory_count(size_t *sp_size); ++ ++/* TODO: endif ? */ ++#endif /* INCLUDED_jupe_h */ +diff -r 2da61ac38fa1 ircd/Makefile.in +--- a/ircd/Makefile.in Sun Jan 18 14:18:36 2009 +0100 ++++ b/ircd/Makefile.in Sun Jan 18 15:26:56 2009 +0100 +@@ -173,6 +173,7 @@ + m_sethost.c \ + m_settime.c \ + m_silence.c \ ++ m_split.c \ + m_squit.c \ + m_stats.c \ + m_time.c \ +@@ -212,6 +213,7 @@ + s_stats.c \ + s_user.c \ + send.c \ ++ split.c \ + uping.c \ + userload.c \ + whocmds.c \ +@@ -1052,6 +1054,15 @@ + ../include/ircd_chattr.h ../include/list.h ../include/msg.h \ + ../include/numeric.h ../include/numnicks.h ../include/s_user.h \ + ../include/send.h ../include/struct.h ++m_split.o: m_split.c ../config.h ../include/client.h ../include/ircd_defs.h \ ++ ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \ ++ ../config.h ../include/ircd_handler.h ../include/res.h \ ++ ../include/capab.h ../include/split.h ../include/hash.h \ ++ ../include/ircd.h ../include/struct.h ../include/ircd_features.h \ ++ ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \ ++ ../include/ircd_chattr.h ../include/match.h ../include/msg.h \ ++ ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \ ++ ../include/client.h ../include/s_misc.h ../include/send.h + m_squit.o: m_squit.c ../config.h ../include/client.h \ + ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \ + ../include/ircd_events.h ../config.h ../include/ircd_handler.h \ +@@ -1325,6 +1336,7 @@ + ../include/msgq.h ../include/numeric.h ../include/numnicks.h \ + ../include/res.h ../include/s_bsd.h ../include/s_conf.h \ + ../include/s_user.h ../include/s_stats.h ../include/send.h \ ++ ../include/split.h \ + ../include/struct.h ../include/sys.h ../include/whowas.h + s_err.o: s_err.c ../config.h ../include/numeric.h ../include/ircd_log.h \ + ../include/s_debug.h ../config.h ../include/ircd_defs.h +@@ -1410,6 +1422,16 @@ + ../include/msg.h ../include/numnicks.h ../include/parse.h \ + ../include/s_bsd.h ../include/s_debug.h ../include/s_misc.h \ + ../include/s_user.h ../include/struct.h ../include/sys.h ++split.o: split.c ../config.h ../include/split.h ../include/client.h \ ++ ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \ ++ ../include/ircd_events.h ../config.h ../include/ircd_handler.h \ ++ ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \ ++ ../include/struct.h ../include/ircd_alloc.h ../include/ircd_features.h \ ++ ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \ ++ ../include/ircd_chattr.h ../include/match.h ../include/msg.h \ ++ ../include/numeric.h ../include/numnicks.h ../include/s_bsd.h \ ++ ../include/s_misc.h ../include/send.h ../include/struct.h \ ++ ../include/sys.h + uping.o: uping.c ../config.h ../include/uping.h ../include/ircd_defs.h \ + ../include/ircd_events.h ../config.h ../include/res.h \ + ../include/client.h ../include/dbuf.h ../include/msgq.h \ +diff -r 2da61ac38fa1 ircd/ircd.c +--- a/ircd/ircd.c Sun Jan 18 14:18:36 2009 +0100 ++++ b/ircd/ircd.c Sun Jan 18 15:26:56 2009 +0100 +@@ -55,6 +55,7 @@ + #include "s_misc.h" + #include "s_stats.h" + #include "send.h" ++#include "split.h" + #include "sys.h" + #include "uping.h" + #include "userload.h" +@@ -763,6 +764,9 @@ + Debug((DEBUG_NOTICE, "Server ready...")); + log_write(LS_SYSTEM, L_NOTICE, 0, "Server Ready"); + ++ /* create SPLITs */ ++ split_conf(); ++ + event_loop(); + + return 0; +diff -r 2da61ac38fa1 ircd/ircd_features.c +--- a/ircd/ircd_features.c Sun Jan 18 14:18:36 2009 +0100 ++++ b/ircd/ircd_features.c Sun Jan 18 15:26:56 2009 +0100 +@@ -363,6 +363,7 @@ + F_B(SETHOST, 0, 0, 0), + F_B(SETHOST_USER, 0, 0, 0), + F_B(SETHOST_AUTO, 0, 0, 0), ++ F_B(SPLIT, 0, 1, 0), + + /* HEAD_IN_SAND Features */ + F_B(HIS_SNOTICES, 0, 1, 0), +@@ -391,6 +392,7 @@ + F_B(HIS_STATS_q, 0, 1, 0), + F_B(HIS_STATS_R, 0, 1, 0), + F_B(HIS_STATS_r, 0, 1, 0), ++ F_B(HIS_STATS_S, 0, 1, 0), + F_B(HIS_STATS_s, 0, 1, 0), + F_B(HIS_STATS_t, 0, 1, 0), + F_B(HIS_STATS_T, 0, 1, 0), +diff -r 2da61ac38fa1 ircd/m_endburst.c +--- a/ircd/m_endburst.c Sun Jan 18 14:18:36 2009 +0100 ++++ b/ircd/m_endburst.c Sun Jan 18 15:26:56 2009 +0100 +@@ -85,6 +85,7 @@ + #include "client.h" + #include "hash.h" + #include "ircd.h" ++#include "ircd_features.h" + #include "ircd_log.h" + #include "ircd_reply.h" + #include "ircd_string.h" +@@ -92,6 +93,7 @@ + #include "numeric.h" + #include "numnicks.h" + #include "send.h" ++#include "split.h" + + /* #include -- Now using assert in ircd_log.h */ + +@@ -125,6 +127,7 @@ + int ms_end_of_burst(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) + { + struct Channel *chan, *next_chan; ++ int split; + + assert(0 != cptr); + assert(0 != sptr); +@@ -135,6 +138,10 @@ + dump_map(sptr, "*", 0, report_new_links, 0); + sendto_opmask_butone(0, SNO_NETWORK, "Completed net.burst from %C.", + sptr); ++ /* cleanup SPLITs, but only bother ops when FEAT_SPLIT is enabled. */ ++ split = split_merge(sptr); ++ if (feature_bool(FEAT_SPLIT)) ++ sendto_opmask_butone(0, SNO_NETWORK, "Removed %d SPLIT entries.", split); + if (MyConnect(sptr)) + sendcmdto_one(&me, CMD_END_OF_BURST_ACK, sptr, ""); + +diff -r 2da61ac38fa1 ircd/m_reburst.c +--- a/ircd/m_reburst.c Sun Jan 18 14:18:36 2009 +0100 ++++ b/ircd/m_reburst.c Sun Jan 18 15:26:56 2009 +0100 +@@ -102,6 +102,7 @@ + #include "ircd_snprintf.h" + #include "gline.h" + #include "jupe.h" ++#include "split.h" + + /* #include -- Now using assert in ircd_log.h */ + #include +@@ -130,6 +131,10 @@ + case 'J': + jupe_burst(sptr); + break; ++ case 's': ++ case 'S': ++ split_burst(sptr); ++ break; + default: + break; + } +diff -r 2da61ac38fa1 ircd/m_split.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/ircd/m_split.c Sun Jan 18 15:26:56 2009 +0100 +@@ -0,0 +1,374 @@ ++/* ++ * IRC - Internet Relay Chat, ircd/m_split.c ++ * Copyright (C) 1990 Jarkko Oikarinen and ++ * University of Oulu, Computing Center ++ * Copyright (C) 2000 Kevin L. Mitchell ++ * ++ * See file AUTHORS in IRC package for additional names of ++ * the programmers. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 1, or (at your option) ++ * any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * $Id: m_split.c 1737 2006-12-19 05:20:48Z entrope $ ++ */ ++ ++/* ++ * m_functions execute protocol messages on this server: ++ * ++ * cptr is always NON-NULL, pointing to a *LOCAL* client ++ * structure (with an open socket connected!). This ++ * identifies the physical socket where the message ++ * originated (or which caused the m_function to be ++ * executed--some m_functions may call others...). ++ * ++ * sptr is the source of the message, defined by the ++ * prefix part of the message if present. If not ++ * or prefix not found, then sptr==cptr. ++ * ++ * (!IsServer(cptr)) => (cptr == sptr), because ++ * prefixes are taken *only* from servers... ++ * ++ * (IsServer(cptr)) ++ * (sptr == cptr) => the message didn't ++ * have the prefix. ++ * ++ * (sptr != cptr && IsServer(sptr) means ++ * the prefix specified servername. (?) ++ * ++ * (sptr != cptr && !IsServer(sptr) means ++ * that message originated from a remote ++ * user (not local). ++ * ++ * combining ++ * ++ * (!IsServer(sptr)) means that, sptr can safely ++ * taken as defining the target structure of the ++ * message in this server. ++ * ++ * *Always* true (if 'parse' and others are working correct): ++ * ++ * 1) sptr->from == cptr (note: cptr->from == cptr) ++ * ++ * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr ++ * *cannot* be a local connection, unless it's ++ * actually cptr!). [MyConnect(x) should probably ++ * be defined as (x == x->from) --msa ] ++ * ++ * parc number of variable parameter strings (if zero, ++ * parv is allowed to be NULL) ++ * ++ * parv a NULL terminated list of parameter pointers, ++ * ++ * parv[0], sender (prefix string), if not present ++ * this points to an empty string. ++ * parv[1]...parv[parc-1] ++ * pointers to additional parameters ++ * parv[parc] == NULL, *always* ++ * ++ * note: it is guaranteed that parv[0]..parv[parc-1] are all ++ * non-NULL pointers. ++ */ ++#include "config.h" ++ ++#include "client.h" ++#include "split.h" ++#include "hash.h" ++#include "ircd.h" ++#include "ircd_features.h" ++#include "ircd_log.h" ++#include "ircd_reply.h" ++#include "ircd_string.h" ++#include "match.h" ++#include "msg.h" ++#include "numeric.h" ++#include "numnicks.h" ++#include "s_conf.h" ++#include "s_debug.h" ++#include "s_misc.h" ++#include "send.h" ++ ++/* #include -- Now using assert in ircd_log.h */ ++#include ++#include ++ ++/* ++ * ms_split - server message handler ++ * ++ * parv[0] = Send prefix ++ * parv[1] = (+|-) ++ * parv[2] = Creation time ++ * parv[3] = Expiration time ++ * parv[4] = Last modification time ++ * parv[5] = Life time ++ * parv[6] = Comment ++ * ++ */ ++int ms_split(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) ++{ ++ struct Client *acptr = 0; ++ struct Split *asplit = 0; ++ unsigned int flags = 0; ++ enum SplitAction action = SPLIT_MODIFY; ++ time_t creation = 0, expire = 0, lastmod = 0, lifetime = 0; ++ char *server = parv[1], *tmp = 0; ++ const char *reason = "No reason"; ++ ++ /* TODO: perhaps make some fields optional? reason? */ ++ if (parc < 6) ++ return need_more_params(sptr, "SPLIT"); ++ ++ if (*server == '!') { ++ server++; ++ action = SPLIT_REMOVE; /* removing entry */ ++ } ++ ++ switch (*server) { /* handle + and - */ ++ case '+': /* activate the split entry */ ++ if (action != SPLIT_REMOVE) ++ action = SPLIT_ACTIVATE; ++ server++; ++ break; ++ ++ case '-': /* deactivate the entry */ ++ if (action != SPLIT_REMOVE) ++ action = SPLIT_DEACTIVATE; ++ server++; ++ break; ++ } ++ ++ /* Next, try to find the split entry... */ ++ asplit = split_find(server); ++ ++ /* We now have all the pieces to tell us what we've got; let's put ++ * it all together and convert the rest of the arguments. ++ */ ++ ++ /* can't modify a split entry that doesn't exist, so remap to activate */ ++ if (!asplit && action == SPLIT_MODIFY) ++ action = SPLIT_ACTIVATE; ++ ++ /* OK, let's figure out what other parameters we may have... */ ++ creation = atoi(parv[2]); ++ expire = atoi(parv[3]); ++ lastmod = atoi(parv[4]); ++ lifetime = atoi(parv[5]); ++ reason = parv[parc - 1]; ++ ++ Debug((DEBUG_DEBUG, "I have a SPLIT I am acting upon now; " ++ "server %s, action %s, creation %Tu, expire %Tu, " ++ "lastmod %Tu, lifetime %Tu, reason: %s; split %s!", server, ++ action == SPLIT_REMOVE ? "!-" : ++ (action == SPLIT_ACTIVATE ? "+" : ++ (action == SPLIT_DEACTIVATE ? "-" : "(MODIFY)")), ++ creation, expire, lastmod, lifetime, reason, ++ asplit ? "EXISTS" : "does not exist")); ++ ++ /* OK, at this point, we have converted all available parameters. ++ * Let's actually do the action! ++ */ ++ if (asplit) { ++ if (action == SPLIT_REMOVE) ++ return split_remove(cptr, sptr, asplit, reason); ++ return split_modify(cptr, sptr, asplit, action, reason, creation, expire, ++ lastmod, lifetime, flags); ++ } ++ ++ assert(action != SPLIT_MODIFY); ++ ++ return split_add(cptr, sptr, server, reason, creation, expire, lastmod, lifetime, ++ flags | ((action == SPLIT_ACTIVATE) ? SPLIT_ACTIVE : 0)); ++} ++ ++ ++/* ++ * mo_split - oper message handler ++ * ++ * Local listing: 1 or 2 params ++ * parv[0] = Send prefix ++ * parv[1] = [Server or mask to match] ++ * ++ * Add or modify entry: 3, 4 or 5 params (3 is * then) ++ * parv[0] = Send prefix ++ * parv[1] = [+|-] ++ * parv[2] = [Expiration offset] (required for new) ++ * parv[3] = [Comment] (required for new) ++ * ++ */ ++int mo_split(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) ++{ ++ struct Client *acptr = 0; ++ struct Split *asplit = 0; ++ unsigned int flags = 0; ++ enum SplitAction action = SPLIT_MODIFY; ++ time_t expire = 0, lastmod = CurrentTime, creation = CurrentTime; ++ char *server = parv[1], *end; ++ const char *reason = NULL; ++ ++ if (parc < 2) { ++ if (!HasPriv(sptr, PRIV_ROUTEINFO)) ++ return send_reply(sptr, ERR_NOPRIVILEGES); ++ else ++ return split_list(sptr, 0); ++ } ++ ++ if (*server == '!') { ++ server++; ++ action = SPLIT_REMOVE; /* force removal */ ++ } ++ ++ switch (*server) { /* handle + and - */ ++ case '+': /* activate the split entry */ ++ if (action != SPLIT_REMOVE) ++ action = SPLIT_ACTIVATE; ++ server++; ++ break; ++ ++ case '-': /* deactivate the split entry */ ++ if (action != SPLIT_REMOVE) ++ action = SPLIT_DEACTIVATE; ++ server++; ++ break; ++ } ++ ++ /* OK, let's figure out the parameters... */ ++ switch (action) { ++ /* no specific action */ ++ case SPLIT_MODIFY: ++ /* user wants a listing of a specific SPLIT */ ++ if (parc == 2) ++ return split_list(sptr, server); ++ expire = strtol(parv[2], &end, 10) + CurrentTime; /* and the expiration */ ++ if (*end != '\0') ++ return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE, ++ "%s :Bad expire time", parv[2]); ++ ++ flags |= SPLIT_EXPIRE; /* remember that we got an expire time */ ++ ++ if (parc > 3) { /* also got a reason... */ ++ reason = parv[parc - 1]; ++ flags |= SPLIT_REASON; ++ } ++ break; ++ ++ case SPLIT_REMOVE: /* TODO: require reason for this, but not expire? */ ++ if (parc < 4) ++ return need_more_params(sptr, "SPLIT"); ++ reason = parv[parc - 1]; ++ flags |= SPLIT_REASON; ++ break; ++ ++ case SPLIT_ACTIVATE: /* TODO: require expire and reason when new */ ++ if (parc > 2) { ++ expire = strtol(parv[2], &end, 10) + CurrentTime; /* and the expiration */ ++ if (*end != '\0') ++ return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE, ++ "%s :Bad expire time", parv[2]); ++ flags |= SPLIT_EXPIRE; /* remember that we got an expire time */ ++ } ++ ++ if (parc > 3) { /* also got a reason... */ ++ reason = parv[parc - 1]; ++ flags |= SPLIT_REASON; ++ } ++ break; ++ ++ case SPLIT_DEACTIVATE: /* TODO: duplicate code? must be a cleaner way */ ++ if (parc > 2) { ++ expire = strtol(parv[2], &end, 10) + CurrentTime; /* and the expiration */ ++ if (*end != '\0') ++ return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE, ++ "%s :Bad expire time", parv[2]); ++ flags |= SPLIT_EXPIRE; /* remember that we got an expire time */ ++ } ++ ++ if (parc > 3) { /* also got a reason... */ ++ reason = parv[parc - 1]; ++ flags |= SPLIT_REASON; ++ } ++ break; ++ } ++ ++ ++ /* check for permissions... */ ++ if (!feature_bool(FEAT_SPLIT)) /* TODO: but allow force removal? */ ++ return send_reply(sptr, ERR_DISABLED, "SPLIT"); ++ else if (!HasPriv(sptr, PRIV_SERVERINFO)) /* TODO: create PRIV_SPLIT - need help there */ ++ return send_reply(sptr, ERR_NOPRIVILEGES); ++ ++ /* Next, try to find the SPLIT... */ ++ asplit = split_find(server); ++ ++ /* We now have all the pieces to tell us what we've got; let's put ++ * it all together and convert the rest of the arguments. ++ */ ++ ++ /* SPLIT not found and thus we: ++ * cannot remove SPLIT we do not have ++ * cannot add new SPLIT without expire and reason ++ */ ++ if (!asplit && ++ ((action == SPLIT_REMOVE) || ++ (action == SPLIT_ACTIVATE && !reason) || ++ (action == SPLIT_DEACTIVATE && !reason) || ++ (action == SPLIT_MODIFY && !reason))) ++ return send_reply(sptr, ERR_NOSUCHSPLIT, server); ++ ++ /* can't modify a split entry that doesn't exist, so remap to activate */ ++ if (!asplit && action == SPLIT_MODIFY) ++ action = SPLIT_ACTIVATE; ++ ++ Debug((DEBUG_DEBUG, "I have a SPLIT I am acting upon now; " ++ "server %s, action %s, expire %Tu, " ++ "reason: %s; split %s! (fields present: %s %s)", server, ++ action == SPLIT_REMOVE ? "!-" : ++ (action == SPLIT_ACTIVATE ? "+" : ++ (action == SPLIT_DEACTIVATE ? "-" : "(MODIFY)")), ++ expire, reason, asplit ? "EXISTS" : "does not exist", ++ flags & SPLIT_EXPIRE ? "expire" : "", ++ flags & SPLIT_REASON ? "reason" : "")); ++ ++ if (asplit) { /* modifying an existing SPLIT */ ++ if (action == SPLIT_REMOVE) ++ return split_remove(cptr, sptr, asplit, reason); ++ return split_modify(cptr, sptr, asplit, action, reason, ++ asplit->sp_creation, expire, lastmod, asplit->sp_lifetime, flags); ++ } ++ ++ assert(action != SPLIT_MODIFY); ++ assert(action != SPLIT_REMOVE); ++ ++ /* create a new SPLIT */ ++ return split_add(cptr, sptr, server, reason, ++ creation, expire, lastmod, expire, ++ flags | ((action == SPLIT_ACTIVATE) ? SPLIT_ACTIVE : 0)); ++} ++ ++/* ++ * m_split - user message handler ++ * ++ * parv[0] = Send prefix ++ * ++ * From user: ++ * ++ * parv[1] = [] ++ * ++ */ ++int m_split(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) ++{ ++ if (parc < 2) ++ return split_list(sptr, 0); ++ ++ return split_list(sptr, parv[1]); ++} +diff -r 2da61ac38fa1 ircd/parse.c +--- a/ircd/parse.c Sun Jan 18 14:18:36 2009 +0100 ++++ b/ircd/parse.c Sun Jan 18 15:26:56 2009 +0100 +@@ -505,6 +505,13 @@ + 0, MAXPARA, MFLG_SLOW, 0, NULL, + /* UNREG, CLIENT, SERVER, OPER, SERVICE */ + { m_unregistered, m_not_oper, ms_jupe, mo_jupe, m_ignore } ++ }, ++ { ++ MSG_SPLIT, ++ TOK_SPLIT, ++ 0, MAXPARA, MFLG_SLOW, 0, NULL, ++ /* UNREG, CLIENT, SERVER, OPER, SERVICE */ ++ { m_unregistered, m_not_oper, ms_split, mo_split, m_ignore } + }, + { + MSG_OPMODE, +diff -r 2da61ac38fa1 ircd/s_conf.c +--- a/ircd/s_conf.c Sun Jan 18 14:18:36 2009 +0100 ++++ b/ircd/s_conf.c Sun Jan 18 15:26:56 2009 +0100 +@@ -53,6 +53,7 @@ + #include "s_debug.h" + #include "s_misc.h" + #include "send.h" ++#include "split.h" + #include "struct.h" + #include "sys.h" + +@@ -1005,6 +1006,7 @@ + } + + attach_conf_uworld(&me); ++ split_conf(); + + return ret; + } +diff -r 2da61ac38fa1 ircd/s_debug.c +--- a/ircd/s_debug.c Sun Jan 18 14:18:36 2009 +0100 ++++ b/ircd/s_debug.c Sun Jan 18 15:26:57 2009 +0100 +@@ -48,6 +48,7 @@ + #include "s_user.h" + #include "s_stats.h" + #include "send.h" ++#include "split.h" + #include "struct.h" + #include "sys.h" + #include "whowas.h" +@@ -231,7 +232,8 @@ + aw = 0, /* aways set */ + wwa = 0, /* whowas aways */ + gl = 0, /* glines */ +- ju = 0; /* jupes */ ++ ju = 0, /* jupes */ ++ sp = 0; /* split entries */ + + size_t chm = 0, /* memory used by channels */ + chbm = 0, /* memory used by channel bans */ +@@ -244,6 +246,7 @@ + wwm = 0, /* whowas array memory used */ + glm = 0, /* memory used by glines */ + jum = 0, /* memory used by jupes */ ++ spm = 0, /* memory used by split entries */ + com = 0, /* memory used by conf lines */ + dbufs_allocated = 0, /* memory used by dbufs */ + dbufs_used = 0, /* memory used by dbufs */ +@@ -348,8 +351,9 @@ + + gl = gline_memory_count(&glm); + ju = jupe_memory_count(&jum); ++ sp = split_memory_count(&spm); + send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, +- ":Glines %d(%zu) Jupes %d(%zu)", gl, glm, ju, jum); ++ ":Glines %d(%zu) Jupes %d(%zu) Splits %d(%zu)", gl, glm, ju, jum, sp, spm); + + send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, + ":Hash: client %d(%zu), chan is the same", HASHSIZE, +diff -r 2da61ac38fa1 ircd/s_err.c +--- a/ircd/s_err.c Sun Jan 18 14:18:36 2009 +0100 ++++ b/ircd/s_err.c Sun Jan 18 15:26:57 2009 +0100 +@@ -490,7 +490,7 @@ + /* 228 */ + { RPL_STATSQLINE, "Q %s :%s", "228" }, + /* 229 */ +- { 0 }, ++ { RPL_STATSSPLIT, "S %s %d %d %d %d %c :%s", "229" }, + /* 230 */ + { 0 }, + /* 231 */ +@@ -588,9 +588,9 @@ + /* 277 */ + { 0 }, + /* 278 */ +- { 0 }, ++ { RPL_SPLITLIST, "%s %Tu %Tu %Tu %Tu %c :%s", "278" }, + /* 279 */ +- { 0 }, ++ { RPL_ENDOFSPLITLIST, ":End of Split List", "279" }, + /* 280 */ + { RPL_GLIST, "%s%s%s%s%s %Tu %Tu %Tu %s %s%c :%s", "280" }, + /* 281 */ +@@ -1052,7 +1052,7 @@ + /* 509 */ + { 0 }, + /* 510 */ +- { 0 }, ++ { ERR_NOSUCHSPLIT, "%s :No such split", "510" }, + /* 511 */ + { ERR_SILELISTFULL, "%s :Your silence list is full", "511" }, + /* 512 */ +diff -r 2da61ac38fa1 ircd/s_misc.c +--- a/ircd/s_misc.c Sun Jan 18 14:18:36 2009 +0100 ++++ b/ircd/s_misc.c Sun Jan 18 15:26:57 2009 +0100 +@@ -53,6 +53,7 @@ + #include "s_stats.h" + #include "s_user.h" + #include "send.h" ++#include "split.h" + #include "struct.h" + #include "sys.h" + #include "uping.h" +@@ -391,6 +392,7 @@ + time_t on_for; + + char comment1[HOSTLEN + HOSTLEN + 2]; ++ char splitreason[BUFSIZE]; + assert(killer); + if (MyConnect(victim)) + { +@@ -497,6 +499,14 @@ + sendto_opmask_butone(0, SNO_NETWORK, "Net break: %C %C (%s)", + cli_serv(victim)->up, victim, comment); + dump_map(victim, "*", 0, report_lost_links, 0); ++ if (feature_bool(FEAT_SPLIT)) { ++ ircd_snprintf(0, splitreason, sizeof(splitreason), ++ "Net break: %C %C (%s%s%s%s)", cli_serv(victim)->up, victim, ++ IsUser(killer) ? "SQUIT by " : "", IsUser(killer) ? cli_name(killer) : "", ++ IsUser(killer) ? ": " : "", comment); ++ sendto_opmask_butone(0, SNO_NETWORK, "Created %d SPLIT entries.", ++ split_break(victim, splitreason)); ++ } + } + + /* +diff -r 2da61ac38fa1 ircd/s_serv.c +--- a/ircd/s_serv.c Sun Jan 18 14:18:36 2009 +0100 ++++ b/ircd/s_serv.c Sun Jan 18 15:26:57 2009 +0100 +@@ -54,6 +54,7 @@ + #include "s_misc.h" + #include "s_user.h" + #include "send.h" ++#include "split.h" + #include "struct.h" + #include "sys.h" + #include "userload.h" +@@ -196,6 +197,7 @@ + */ + gline_burst(cptr); + jupe_burst(cptr); ++ split_burst(cptr); + + /* + * Pass on my client information to the new server +diff -r 2da61ac38fa1 ircd/s_stats.c +--- a/ircd/s_stats.c Sun Jan 18 14:18:36 2009 +0100 ++++ b/ircd/s_stats.c Sun Jan 18 15:26:57 2009 +0100 +@@ -52,6 +52,7 @@ + #include "s_stats.h" + #include "s_user.h" + #include "send.h" ++#include "split.h" + #include "struct.h" + #include "userload.h" + +@@ -633,7 +634,10 @@ + send_usage, 0, + "System resource usage (Debug only)." }, + #endif +- { 's', "spoofhosts", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_s, ++ { 'S', "splits", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_S, ++ split_stats, 0, ++ "Server SPLITs information."}, ++ { 's', "spoofhosts", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_s, + stats_sline, 0, + "Spoofed hosts information." }, + { 'T', "motds", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T, +diff -r 2da61ac38fa1 ircd/split.c +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/ircd/split.c Sun Jan 18 15:26:57 2009 +0100 +@@ -0,0 +1,746 @@ ++/* ++ * IRC - Internet Relay Chat, ircd/split.c ++ * Copyright (C) 1990 Jarkko Oikarinen and ++ * University of Oulu, Finland ++ * Copyright (C) 2000 Kevin L. Mitchell ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 1, or (at your option) ++ * any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++/** @file ++ * @brief Implementation of split server handling functions. ++ * @version $Id: split.c 1633 2006-03-25 03:46:56Z entrope $ ++ */ ++#include "config.h" ++ ++#include "split.h" ++#include "client.h" ++#include "hash.h" ++#include "ircd.h" ++#include "ircd_alloc.h" ++#include "ircd_features.h" ++#include "ircd_log.h" ++#include "ircd_reply.h" ++#include "ircd_string.h" ++#include "list.h" ++#include "match.h" ++#include "msg.h" ++#include "numeric.h" ++#include "numnicks.h" ++#include "s_conf.h" ++#include "s_bsd.h" ++#include "s_debug.h" ++#include "s_misc.h" ++#include "send.h" ++#include "struct.h" ++#include "sys.h" /* FALSE bleah */ ++ ++/* #include -- Now using assert in ircd_log.h */ ++#include ++ ++/** List of split entries. */ ++static struct Split *GlobalSplitList = 0; ++ ++/** Allocate a new Split entry with the given parameters. ++ * @param[in] server Server name for split entry. ++ * @param[in] reason Reason for the split entry. ++ * @param[in] creation Creation time for split entry. ++ * @param[in] expire Expiration time for split entry. ++ * @param[in] lastmod Last modification time for split entry. ++ * @param[in] lifetime Life time for split entry. ++ * @param[in] flags Flags to set for the split entry. ++ */ ++static struct Split * ++split_make(char *server, const char *reason, ++ time_t creation, time_t expire, time_t lastmod, time_t lifetime, ++ unsigned int flags) ++{ ++ struct Split *asplit; ++ ++ asplit = (struct Split*) MyMalloc(sizeof(struct Split)); /* alloc memory */ ++ assert(0 != asplit); ++ ++ memset(asplit, 0, sizeof(*asplit)); ++ /* TODO: some limit for servername length? HOSTLEN? */ ++ DupString(asplit->sp_server, server); /* copy vital information */ ++ /* TODO: some limit for reason length? QUITLEN TOPICLEN? */ ++ DupString(asplit->sp_reason, reason); ++ /* TODO: what we use creation for and do we need it? */ ++ asplit->sp_creation = creation; ++ asplit->sp_expire = expire; ++ /* TODO: are we using nettime etc.? CurrentTime is used. */ ++ asplit->sp_lastmod = lastmod; ++ asplit->sp_lifetime = lifetime; ++ /* CHECK: does this make it active upon creation regardless of the flags given? */ ++ asplit->sp_flags = flags & SPLIT_ACTIVE; /* set split flags */ ++ ++ asplit->sp_next = GlobalSplitList; /* link it into the list */ ++ asplit->sp_prev_p = &GlobalSplitList; ++ if (GlobalSplitList) ++ GlobalSplitList->sp_prev_p = &asplit->sp_next; ++ GlobalSplitList = asplit; ++ ++ return asplit; ++} ++ ++/** Forward a split entry to another server. ++ * @param[in] cptr Local client that sent us the split entry. ++ * @param[in] sptr Originator of the split entry. ++ * @param[in] split Split entry to forward. ++ * @param[in] reason Reason to send upstream (used by split_remove) ++ */ ++static void ++split_propagate(struct Client *cptr, struct Client *sptr, ++ struct Split *split, const char *reason) ++{ ++ sendcmdto_serv_butone(sptr, CMD_SPLIT, cptr, "%s%c%s %Tu %Tu %Tu %Tu :%s", ++ SplitIsRemoving(split) ? "!" : "", ++ SplitIsActive(split) && !SplitIsRemoving(split) ? '+' : '-', /* always !- not !+ */ ++ split->sp_server, split->sp_creation, split->sp_expire, ++ split->sp_lastmod, split->sp_lifetime, ++ reason != NULL ? reason : split->sp_reason); ++} ++ ++/** Add a new server split entry. ++ * @param[in] cptr Local client that sent us the split entry. ++ * @param[in] sptr Originator of the split entry. ++ * @param[in] server Server name to split entry. ++ * @param[in] reason Reason for the split entry. ++ * @param[in] expire Expiration timestamp. ++ * @param[in] lastmod Last modification timestamp. ++ * @param[in] flags Flags to set on the split entry. ++ * @return Zero ++ */ ++int ++split_add(struct Client *cptr, struct Client *sptr, char *server, const char *reason, ++ time_t creation, time_t expire, time_t lastmod, time_t lifetime, ++ unsigned int flags) ++{ ++ ++ /* TODO: check for proper masks - at least one dot and no wildcards? */ ++ struct Split *asplit; ++ struct Client *acptr; ++ ++ assert(0 != server); ++ assert(0 != reason); ++ assert(NULL != cptr); ++ assert(NULL != sptr); ++ ++ Debug((DEBUG_DEBUG, "split_add(\"%s\", \"%s\", \"%s\", \"%s\", %Tu, %Tu, %Tu, " ++ "%Tu, 0x%04x)", cli_name(cptr), cli_name(sptr), server, reason, ++ creation, expire, lastmod, lifetime, flags)); ++ ++ /* not adding SPLIT for server that is linked ++ * if sptr is my user throw error ++ * otherwise ignore - SERVER and SPLIT messages can cross, ++ * or a server is bursting and it will see our end and destroy the SPLITs ++ */ ++ if ((acptr = FindServer(server))) { ++ if (MyUser(sptr)) ++ sendcmdto_one(&me, CMD_NOTICE, sptr, ++ "%C :Cannot add SPLIT %s - server is linked.", sptr, server); ++ return 0; ++ } ++ ++ /* ++ * You cannot set a negative (or zero) duration, nor can you set an ++ * duration greater than SPLIT_MAX_EXPIRE. ++ */ ++ if (expire - CurrentTime <= 0 || expire - CurrentTime > SPLIT_MAX_EXPIRE) { ++ if (!IsServer(cptr) && MyConnect(cptr)) ++ return send_reply(cptr, ERR_BADEXPIRE, expire - CurrentTime); ++ if (expire <= CurrentTime) /* no point going further */ ++ /* TODO: check lifetime then ? because the SPLIT may simply be deactivated ++ * and we did not see it before ++ * if it were to be activated again we would get it again ++ * but should we not keep the same state on each server? ++ */ ++ /* CHECK: sptr may have the wrong idea about the nettime? ++ * or we could be wrong? ++ * SETTIME ? could be dangerous and mess up things.. ++ * perhaps raise some sort of warning to ops ++ * maybe if the difference is larger than a poor RTT over the network? ++ * 60 seconds? ++ * no no no! - see above ++ */ ++ return 0; ++ } ++ ++ /* inform ops and log it */ ++ sendto_opmask_butone(0, SNO_NETWORK, "%s adding%sSPLIT for %s, expiring at %Tu: %s", ++ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? ++ cli_name(sptr) : cli_name((cli_user(sptr))->server), ++ !(flags & SPLIT_ACTIVE) ? " deactivated " : " ", ++ server, expire, reason); ++ ++ /* TODO: add SPLIT log stuff or use JUPE? */ ++ log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE, ++ "%#C adding%sSPLIT for %s, expiring at %Tu: %s", ++ sptr, !(flags & SPLIT_ACTIVE) ? " deactivated " : " ", ++ server, expire, reason); ++ ++ /* make the split entry */ ++ asplit = split_make(server, reason, creation, expire, lastmod, lifetime, flags); ++ ++ assert(asplit); ++ ++ /* and propagate it */ ++ split_propagate(cptr, sptr, asplit, NULL); ++ ++ return 0; ++} ++ ++ ++/** Modify a split entry. ++ * @param[in] cptr Client that sent us the split modification. ++ * @param[in] sptr Client that originated the split modification. ++ * @param[in] split Split entry being modified. ++ * @param[in] action Resultant status of the G-line. ++ * @param[in] reason Reason. ++ * @param[in] expire Expiration time. ++ * @param[in] lastmod Last modification time. ++ * @param[in] lifetime Lifetime. ++ * @param[in] flags Bitwise combination of SPLIT_* flags. ++ * @return Zero. ++ */ ++int ++split_modify(struct Client *cptr, struct Client *sptr, struct Split *split, ++ enum SplitAction action, const char *reason, ++ time_t creation, time_t expire, time_t lastmod, time_t lifetime, ++ unsigned int flags) ++{ ++ struct Client* acptr; ++ char buf[BUFSIZE]; ++ int pos = 0; ++ ++ assert(split); ++ assert(NULL != cptr); ++ assert(NULL != sptr); ++ ++ /* TODO: add action in the debug notice too */ ++ Debug((DEBUG_DEBUG, "split_modify(\"%s\", \"%s\", \"%s\", \"%s\", %Tu, %Tu, %Tu, " ++ "%Tu, 0x%04x)", cli_name(cptr), cli_name(sptr), split->sp_server, reason, ++ creation, expire, lastmod, lifetime, flags)); ++ ++ /* not modifying SPLIT for server that is linked ++ * if sptr is my user throw error ++ * otherwise ignore - SERVER and SPLIT messages can cross. ++ * ++ * note: we cleanup SPLIT entries at end of burst, ++ * and not when a server is introduced. ++ * so between net junction and end of burst, ++ * we can get SPLITs for a linked server. ++ */ ++ /* TODO: should we free it here or let that be done in end of burst? ++ * only when that is the ONLY situation we can get to this point! ++ * but if we free here and it is a burst, the count is incorrect in ++ * split_netmerge ++ * IsBurst() is that true for only that single server or for all its downlinks? ++ * I would guess single server only.. argh! ++ */ ++ if ((acptr = FindServer(split->sp_server))) { ++ if (MyUser(sptr)) ++ sendcmdto_one(&me, CMD_NOTICE, sptr, ++ "%C :Cannot modify SPLIT %s - server is linked.", sptr, split->sp_server); ++ split_free(split); /* and free it */ ++ return 0; ++ } ++ ++ /* First, let's check lastmod... */ ++ if (SplitLastMod(split) > lastmod) { /* we have a more recent version */ ++ if (IsBurstOrBurstAck(cptr)) ++ return 0; /* middle of a burst, it'll resync on its own */ ++ return split_resend(cptr, split); /* resync the server */ ++ } else if (SplitLastMod(split) == lastmod) ++ return 0; /* we have that version of the split entry... */ ++ ++ /* All right, we know that there's a change of some sort. What is it? */ ++ /* first, check out the expiration time... */ ++ /* TODO: expire != 0 or NULL - check that we have something? */ ++ if (expire != 0 && expire != split->sp_expire) { ++ if (expire - CurrentTime <= 0 || expire - CurrentTime > SPLIT_MAX_EXPIRE) { ++ if (!IsServer(sptr) && MyConnect(sptr)) /* bad expiration time */ ++ send_reply(sptr, ERR_BADEXPIRE, expire - CurrentTime); ++ if (expire - CurrentTime <= 0) /* no point in going further */ ++ /* TODO: same as in split_add - check lifetime? */ ++ return 0; ++ } ++ flags |= SPLIT_EXPIRE; ++ } else ++ flags &= ~SPLIT_EXPIRE; ++ ++ /* Next, check out lifetime */ ++ if (!(flags & SPLIT_LIFETIME) || !lifetime) ++ lifetime = split->sp_lifetime; /* use Split lifetime */ ++ ++ lifetime = IRCD_MAX(lifetime, expire); /* set lifetime to the max */ ++ ++ /* OK, let's see which is greater... */ ++ if (lifetime > split->sp_lifetime) ++ flags |= SPLIT_LIFETIME; /* have to update lifetime */ ++ else { ++ flags &= ~SPLIT_LIFETIME; /* no change to lifetime */ ++ lifetime = 0; ++ } ++ ++ /* Finally, let's see if the reason needs to be updated */ ++ /* TODO: (reason) or use != NULL / 0 ? */ ++ if ((flags & SPLIT_REASON) && reason && ++ ircd_strcmp(split->sp_reason, reason) != 0) ++ flags &= ~SPLIT_REASON; /* no changes to the reason */ ++ ++ /* OK, now let's take a look at the action... */ ++ if ((action == SPLIT_ACTIVATE && SplitIsActive(split)) || ++ (action == SPLIT_DEACTIVATE && !SplitIsActive(split)) || ++ /* can't activate an expired split entry */ ++ (IRCD_MAX(split->sp_expire, expire) <= CurrentTime)) ++ action = SPLIT_MODIFY; /* no activity state modifications */ ++ ++ Debug((DEBUG_DEBUG, "About to perform changes; flags 0x%04x, action %s", ++ flags, action == SPLIT_ACTIVATE ? "SPLIT_ACTIVATE" : ++ (action == SPLIT_DEACTIVATE ? "SPLIT_DEACTIVATE" : ++ (action == SPLIT_MODIFY ? "SPLIT_MODIFY" : "")))); ++ ++ /* If there are no changes to perform, do no changes */ ++ if (!(flags & SPLIT_UPDATE) && action == SPLIT_MODIFY) ++ return 0; ++ ++ /* Start by updating lastmod, if indicated... */ ++ split->sp_lastmod = lastmod; ++ ++ /* Then move on to activity status changes... */ ++ switch (action) { ++ case SPLIT_ACTIVATE: /* activating split entry */ ++ split->sp_flags |= SPLIT_ACTIVE; /* make it active... */ ++ pos += ircd_snprintf(0, buf, sizeof(buf), " activating SPLIT"); ++ break; ++ ++ case SPLIT_DEACTIVATE: /* deactivating split entry */ ++ split->sp_flags &= ~SPLIT_ACTIVE; /* make it inactive... */ ++ pos += ircd_snprintf(0, buf, sizeof(buf), " deactivating SPLIT"); ++ break; ++ ++ case SPLIT_MODIFY: /* no change to activity status */ ++ break; ++ } ++ ++ /* Handle expiration changes... */ ++ if (flags & SPLIT_EXPIRE) { ++ split->sp_expire = expire; /* save new expiration time */ ++ if (pos < BUFSIZE) ++ pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos, ++ "%s%s changing expiration time to %Tu", ++ pos ? ";" : "", ++ pos && !(flags & (SPLIT_LIFETIME | SPLIT_REASON)) ? ++ " and" : "", expire); ++ } ++ ++ /* Next, handle lifetime changes... */ ++ if (flags & SPLIT_LIFETIME) { ++ split->sp_lifetime = lifetime; /* save new lifetime */ ++ if (pos < BUFSIZE) ++ pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos, ++ "%s%s extending record lifetime to %Tu", ++ pos ? ";" : "", pos && !(flags & SPLIT_REASON) ? ++ " and" : "", lifetime); ++ } ++ ++ /* Now, handle reason changes... */ ++ if (flags & SPLIT_REASON) { ++ MyFree(split->sp_reason); /* release old reason */ ++ DupString(split->sp_reason, reason); /* store new reason */ ++ if (pos < BUFSIZE) ++ pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos, ++ "%s%s changing reason to \"%s\"", ++ pos ? ";" : "", pos ? " and" : "", reason); ++ } ++ ++ /* All right, inform ops... */ ++ sendto_opmask_butone(0, SNO_NETWORK, "%s modifying SPLIT for %s:%s", ++ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? ++ cli_name(sptr) : cli_name((cli_user(sptr))->server), ++ split->sp_server, buf); ++ ++ /* TODO: add SPLIT log stuff or use JUPE? */ ++ /* and log the change */ ++ log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE, ++ "%#C modifying SPLIT for %s:%s", ++ sptr, split->sp_server, buf); ++ ++ /* and propagate it */ ++ split_propagate(cptr, sptr, split, NULL); ++ ++ return 0; ++} ++ ++ ++/** Remove a split entry. ++ * @param[in] cptr Local client that sent us the split entry. ++ * @param[in] sptr Originator of the split entry. ++ * @param[in] split Split entry to remove. ++ * @param[in] reason Reason for removing this split entry. ++ * @return Zero. ++ */ ++int ++split_remove(struct Client *cptr, struct Client *sptr, struct Split *split, const char *reason) ++{ ++ unsigned int saveflags = 0; ++ ++ assert(0 != split); ++ assert(NULL != cptr); ++ assert(NULL != sptr); ++ ++ Debug((DEBUG_DEBUG, "split_remove(\"%s\", \"%s\", \"%s\", \"%s\")", ++ cli_name(cptr), cli_name(sptr), split->sp_server, reason)); ++ ++ /* deactivate entry and mark it for removal (used in split_propagate) */ ++ split->sp_flags |= SPLIT_REMOVING; ++ /* CHECK: turn bit SPLIT_ACTIVE off? */ ++ split->sp_flags |= SPLIT_ACTIVE; ++ ++ /* inform ops and log it */ ++ sendto_opmask_butone(0, SNO_NETWORK, "%s removing SPLIT for %s, expiring at %Tu: %s (%s)", ++ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ? ++ cli_name(sptr) : cli_name((cli_user(sptr))->server), ++ split->sp_server, split->sp_expire, split->sp_reason, reason); ++ ++ /* TODO: add SPLIT log stuff or use JUPE? */ ++ log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE, ++ "%#C removing SPLIT for %s, expiring at %Tu: %s (%s)", ++ sptr, split->sp_server, split->sp_expire, split->sp_reason, reason); ++ ++ /* TODO: the reason supplied for removing this SPLIT does not go upstream ++ * either propagate manually here, or update the record or? ++ */ ++ /* propagate it */ ++ split_propagate(cptr, sptr, split, reason); ++ ++ /* destroy it */ ++ split_free(split); ++ ++ return 0; ++} ++ ++ ++/** Find a split entry by name. ++ * @param[in] server Split entry name to search for. ++ * @return Matching split entry (or NULL if none match). ++ */ ++struct Split * ++split_find(char *server) ++{ ++ struct Split* split; ++ struct Split* ssplit; ++ ++ for (split = GlobalSplitList; split; split = ssplit) { /* go through splits */ ++ ssplit = split->sp_next; ++ ++ if (split_expire(split)) /* expire any that need expiring */ ++ split_free(split); ++ else if (0 == ircd_strcmp(server, split->sp_server)) /* found it yet? */ ++ return split; ++ } ++ /* TODO: we return 0 not NULL? */ ++ return 0; ++} ++ ++/** Unlink and free an unused split entry. ++ * @param[in] split Server split entry to free. ++ */ ++void ++split_free(struct Split* split) ++{ ++ /* TODO: use 0 or NULL ? */ ++ assert(0 != split); ++ ++ *split->sp_prev_p = split->sp_next; /* squeeze this split entry out */ ++ if (split->sp_next) ++ split->sp_next->sp_prev_p = split->sp_prev_p; ++ ++ /* CHECK: the other fields in this struct are destroyed with MyFree() call? */ ++ MyFree(split->sp_server); /* and free up the memory */ ++ MyFree(split->sp_reason); ++ MyFree(split); ++} ++ ++ ++/** Check whether a split entry has past its life time. ++ * when entry is active and past expire time, but not life time, deactivate it ++ * @param[in] split Server split entry to check. ++ * @return 1 when entry can be free'd, 0 otherwise. ++ */ ++int ++split_expire(struct Split* split) ++{ ++ assert(0 != split); ++ ++ /* past lifetime */ ++ if (split->sp_lifetime <= CurrentTime) ++ return 1; ++ ++ /* past expire time, deactivate entry if it is active */ ++ if ((split->sp_expire <= CurrentTime) && SplitIsActive(split)) ++ /* CHECK: turn bit SPLIT_ACTIVE off */ ++ split->sp_flags &= SPLIT_ACTIVE; ++ ++ return 0; ++} ++ ++/** Send the full list of split entries to \a cptr. ++ * @param[in] cptr Local server to send split entries to. ++ */ ++void ++split_burst(struct Client *cptr) ++{ ++ struct Split *split; ++ struct Split *ssplit; ++ ++ assert(NULL != cptr); ++ ++ for (split = GlobalSplitList; split; split = ssplit) { /* go through splits */ ++ ssplit = split->sp_next; ++ ++ /* expire any that need expiring */ ++ if (split_expire(split)) ++ split_free(split); ++ /* if we have an entry for cptr, dont send it - but do not free here yet ++ * free it at end of burst, to get the correct count for SPLITs removed. ++ */ ++ else if (ircd_strcmp(split->sp_server, cli_name(cptr)) == 0) ++ continue; ++ else ++ sendcmdto_one(&me, CMD_SPLIT, cptr, "%c%s %Tu %Tu %Tu %Tu :%s", ++ SplitIsActive(split) ? '+' : '-', split->sp_server, ++ split->sp_creation, split->sp_expire, ++ split->sp_lastmod, split->sp_lifetime, ++ split->sp_reason); ++ } ++} ++ ++/** Forward a split to another server. ++ * @param[in] cptr Server to send split entries to. ++ * @param[in] split Split to forward. ++ * @return Zero. ++ */ ++int ++split_resend(struct Client *cptr, struct Split *split) ++{ ++ sendcmdto_one(&me, CMD_SPLIT, cptr, "%c%s %Tu %Tu %Tu %Tu :%s", ++ SplitIsActive(split) ? '+' : '-', split->sp_server, ++ split->sp_creation, split->sp_expire, ++ split->sp_lastmod, split->sp_lifetime, ++ split->sp_reason); ++ ++ return 0; ++} ++ ++/** Send a split entry (or a list of split entries) to a server. ++ * @param[in] sptr Client searching for split entries. ++ * @param[in] server Name of split entry to search for (if NULL, list all). ++ * @return Zero. ++ */ ++int ++split_list(struct Client *sptr, char *server) ++{ ++ struct Split *split; ++ struct Split *ssplit; ++ ++ assert(NULL != sptr); ++ ++ /* TODO: wildcard matching? */ ++ if (server) { ++ if (!(split = split_find(server))) /* no such split */ ++ return send_reply(sptr, ERR_NOSUCHSPLIT, server); ++ ++ /* send split information along */ ++ send_reply(sptr, RPL_SPLITLIST, split->sp_server, ++ split->sp_creation, split->sp_expire, ++ split->sp_lastmod, split->sp_lifetime, ++ SplitIsActive(split) ? '+' : '-', split->sp_reason); ++ } else { ++ for (split = GlobalSplitList; split; split = ssplit) { /* go through splits */ ++ ssplit = split->sp_next; ++ ++ if (split_expire(split)) /* expire any that need expiring */ ++ split_free(split); ++ else /* send split information along */ ++ send_reply(sptr, RPL_SPLITLIST, split->sp_server, ++ split->sp_creation, split->sp_expire, ++ split->sp_lastmod, split->sp_lifetime, ++ SplitIsActive(split) ? '+' : '-', split->sp_reason); ++ } ++ } ++ ++ /* end of splitlist information */ ++ return send_reply(sptr, RPL_ENDOFSPLITLIST); ++} ++ ++ ++/** Auto destroy SPLITs for servers gained in a netmerge ++ * @param[in] cptr Server that link to the network ++ * @return Number of destroyed SPLITs ++ */ ++int ++split_merge(struct Client *server) ++{ ++ struct DLink *lp; ++ struct Split *split; ++ int count = 0; ++ ++ assert(NULL != server); ++ ++ Debug((DEBUG_DEBUG, "split_merge(\"%s\")", cli_name(server))); ++ ++ /* find the SPLIT for this server */ ++ if ((split = split_find(cli_name(server)))) { ++ split_free(split); ++ count++; ++ } ++ ++ /* go over its downlinks */ ++ for (lp = cli_serv(server)->down; lp; lp = lp->next) ++ count += split_merge(lp->value.cptr); ++ return count; ++} ++ ++ ++/** Auto create SPLITs for servers lost in a netbreak ++ * @param[in] server Server that lost link to network ++ * @param[in] reason Reason to add to SPLITs ++ * @return Number of created SPLITs ++ */ ++int ++split_break(struct Client *server, const char *reason) ++{ ++ struct DLink *lp; ++ struct Split *split; ++ int count = 0; ++ time_t creation = CurrentTime, expire = CurrentTime + SPLIT_AUTO_EXPIRE, ++ lastmod = CurrentTime, lifetime = expire; ++ unsigned int flags = SPLIT_ACTIVE; ++ ++ assert(NULL != server); ++ ++ Debug((DEBUG_DEBUG, "split_break(\"%s\", \"%s\")", cli_name(server), reason)); ++ ++ /* find the SPLIT for this server */ ++ if (!(split = split_find(cli_name(server)))) { ++ split_make(cli_name(server), reason, creation, expire, lastmod, lifetime, flags); ++ count++; ++ } ++ ++ /* go over its downlinks */ ++ for (lp = cli_serv(server)->down; lp; lp = lp->next) ++ count += split_break(lp->value.cptr, reason); ++ return count; ++} ++ ++ ++/** Auto create SPLITs for servers we have a Connect Block for ++ * ++ */ ++void ++split_conf() ++{ ++ struct ConfItem *conf; ++ struct Client *server; ++ struct Split *split; ++ struct Split *asplit; ++ time_t creation = CurrentTime, expire = CurrentTime + SPLIT_AUTO_EXPIRE, ++ lastmod = CurrentTime, lifetime = expire; ++ unsigned int flags = SPLIT_ACTIVE; ++ char reason[BUFSIZE]; ++ ++ Debug((DEBUG_DEBUG, "split_conf()")); ++ ++ /* we are not set to generate SPLITs */ ++ if (!feature_bool(FEAT_SPLIT)) ++ return; ++ ++ ircd_snprintf(0, reason, sizeof(reason), ++ "Generated upon loading conf file on %s", cli_name(&me)); ++ ++ /* go over the conf contents */ ++ for (conf = GlobalConfList; conf; conf = conf->next) { ++ /* not a Connect Block */ ++ if (CONF_SERVER != conf->status) ++ continue; ++ /* server is linked */ ++ if (server = FindServer(conf->name)) ++ continue; ++ /* we have a SPLIT for this server already */ ++ if (split = split_find(conf->name)) ++ continue; ++ /* inform ops and log it */ ++ sendto_opmask_butone(0, SNO_NETWORK, "%C adding SPLIT for %s, expiring at %Tu: %s", ++ &me, conf->name, expire, reason); ++ ++ /* TODO: add SPLIT log stuff or use JUPE? */ ++ log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE, ++ "%C adding SPLIT for %s, expiring at %Tu: %s", ++ &me, conf->name, expire, reason); ++ ++ /* make the split entry */ ++ asplit = split_make(conf->name, reason, creation, expire, lastmod, lifetime, flags); ++ ++ assert(asplit); ++ ++ /* and propagate it */ ++ split_propagate(&me, &me, asplit, NULL); ++ } ++} ++ ++ ++/** Statistics callback to list SPLITs. ++ * @param[in] sptr Client requesting statistics. ++ * @param[in] sd Stats descriptor for request (ignored). ++ * @param[in] param Extra parameter from user (ignored). ++ */ ++void ++split_stats(struct Client *sptr, const struct StatDesc *sd, ++ char *param) ++{ ++ struct Split *split; ++ struct Split *ssplit; ++ ++ send_reply(sptr, SND_EXPLICIT | RPL_STATSSPLIT, ++ "S servername creation expire lastmod lifetime active :reason"); ++ for (split = GlobalSplitList; split; split = split->sp_next) ++ send_reply(sptr, RPL_STATSSPLIT, split->sp_server, ++ split->sp_creation, split->sp_expire, split->sp_lastmod, split->sp_lifetime, ++ SplitIsActive(split) ? '+' : '-', split->sp_reason); ++} ++ ++ ++/** Count split entries and memory used by them. ++ * @param[out] sp_size Receives total number of bytes allocated for split entries. ++ * @return Number of split entries currently allocated. ++ */ ++int ++split_memory_count(size_t *sp_size) ++{ ++ struct Split *split; ++ unsigned int sp = 0; ++ ++ /* TODO: check for expired entries? */ ++ for (split = GlobalSplitList; split; split = split->sp_next) ++ { ++ sp++; ++ *sp_size += sizeof(struct Split); ++ *sp_size += split->sp_server ? (strlen(split->sp_server) + 1) : 0; ++ *sp_size += split->sp_reason ? (strlen(split->sp_reason) + 1) : 0; ++ } ++ return sp; ++} ++ diff --git a/statsheader.patch b/statsheader.patch new file mode 100644 index 0000000..62f0e83 --- /dev/null +++ b/statsheader.patch @@ -0,0 +1,138 @@ +add header to /STATS output and make TOTAL: line in /STATS z more clear. + +diff -r 92f6cb6562e2 include/numeric.h +--- a/include/numeric.h Tue Jan 13 22:17:04 2009 +0000 ++++ b/include/numeric.h Sun Jan 18 17:44:05 2009 +0100 +@@ -117,6 +117,7 @@ + RPL_STATSVLINE 227 unreal */ + #define RPL_STATSALINE 226 /* Hybrid, Undernet */ + #define RPL_STATSQLINE 228 /* Undernet extension */ ++#define RPL_STATSHEADER 230 /* QuakeNet extension */ + + /* RPL_SERVICEINFO 231 unused */ + /* RPL_ENDOFSERVICES 232 unused */ +diff -r 92f6cb6562e2 ircd/ircd_res.c +--- a/ircd/ircd_res.c Tue Jan 13 22:17:04 2009 +0000 ++++ b/ircd/ircd_res.c Sun Jan 18 17:44:05 2009 +0100 +@@ -917,6 +917,10 @@ + int i; + char ipaddr[128]; + ++ /* send header so the client knows what we are showing */ ++ send_reply(source_p, SND_EXPLICIT | RPL_STATSHEADER, ++ "A DNS-server"); ++ + for (i = 0; i < irc_nscount; i++) + { + ircd_ntoa_r(ipaddr, &irc_nsaddr_list[i].addr); +diff -r 92f6cb6562e2 ircd/s_debug.c +--- a/ircd/s_debug.c Tue Jan 13 22:17:04 2009 +0000 ++++ b/ircd/s_debug.c Sun Jan 18 17:44:05 2009 +0100 +@@ -389,7 +389,7 @@ + #endif + + send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, +- ":Total: ww %zu ch %zu cl %zu co %zu db %zu ms %zu mb %zu", ++ ":Total: Whowas %zu Channels %zu Clients %zu Config %zu DBufs %zu Msgs %zu MsgBufs %zu", + totww, totch, totcl, com, dbufs_allocated, msg_allocated, + msgbuf_allocated); + } +diff -r 92f6cb6562e2 ircd/s_err.c +--- a/ircd/s_err.c Tue Jan 13 22:17:04 2009 +0000 ++++ b/ircd/s_err.c Sun Jan 18 17:44:05 2009 +0100 +@@ -492,7 +492,7 @@ + /* 229 */ + { 0 }, + /* 230 */ +- { 0 }, ++ { RPL_STATSHEADER, 0, "230" }, + /* 231 */ + { 0 }, + /* 232 */ +diff -r 92f6cb6562e2 ircd/s_stats.c +--- a/ircd/s_stats.c Tue Jan 13 22:17:04 2009 +0000 ++++ b/ircd/s_stats.c Sun Jan 18 17:44:05 2009 +0100 +@@ -92,6 +92,16 @@ + int maximum; + char *host, *pass, *name, *username, *hub_limit; + ++ /* send header so the client knows what we are showing */ ++ if (sd->sd_funcdata == CONF_UWORLD) ++ send_reply(sptr, SND_EXPLICIT | RPL_STATSHEADER, "U server"); ++ else if (sd->sd_funcdata == CONF_SERVER) ++ send_reply(sptr, SND_EXPLICIT | RPL_STATSHEADER, ++ "C server * port hoplimit hubmask class"); ++ else if (sd->sd_funcdata == CONF_OPERATOR) ++ send_reply(sptr, SND_EXPLICIT | RPL_STATSHEADER, ++ "O user@host * name class"); ++ + for (tmp = GlobalConfList; tmp; tmp = tmp->next) + { + if ((tmp->status & sd->sd_funcdata)) +@@ -137,6 +147,10 @@ + { + const struct CRuleConf* p = conf_get_crule_list(); + ++ /* send header so the client knows what we are showing */ ++ send_reply(to, SND_EXPLICIT | RPL_STATSHEADER, ++ "%c server rule", p->type & CRULE_ALL ? 'D' : 'd'); ++ + for ( ; p; p = p->next) + { + if (p->type & sd->sd_funcdata) +@@ -167,6 +181,10 @@ + int wilds = 0; + int count = 1000; + ++ /* send header so the client knows what we are showing */ ++ send_reply(to, SND_EXPLICIT | RPL_STATSHEADER, ++ "I [user@]hostmask maximum IPmask port class"); ++ + if (!param) + { + stats_configured_links(to, sd, param); +@@ -204,6 +222,11 @@ + report_deny_list(struct Client* to) + { + const struct DenyConf* p = conf_get_deny_list(); ++ ++ /* send header so the client knows what we are showing */ ++ send_reply(to, SND_EXPLICIT | RPL_STATSHEADER, ++ "K user@host \"message or path/file\" \"realname\" 0 0"); ++ + for ( ; p; p = p->next) + send_reply(to, RPL_STATSKLINE, p->bits > 0 ? 'k' : 'K', + p->usermask ? p->usermask : "*", +@@ -251,6 +274,10 @@ + } + else + host = mask; ++ ++ /* send header so the client knows what we are showing */ ++ send_reply(sptr, SND_EXPLICIT | RPL_STATSHEADER, ++ "K user@host \"message or path/file\" \"realname\" 0 0"); + + for (conf = conf_get_deny_list(); conf; conf = conf->next) + { +@@ -377,6 +404,10 @@ + { + struct Message *mptr; + ++ /* send header so the client knows what we are showing */ ++ send_reply(to, SND_EXPLICIT | RPL_STATSHEADER, ++ "m command count bytes"); ++ + for (mptr = msgtab; mptr->cmd; mptr++) + if (mptr->count) + send_reply(to, RPL_STATSCOMMANDS, mptr->cmd, mptr->count, mptr->bytes); +@@ -391,6 +422,10 @@ + stats_quarantine(struct Client* to, const struct StatDesc* sd, char* param) + { + struct qline *qline; ++ ++ /* send header so the client knows what we are showing */ ++ send_reply(to, SND_EXPLICIT | RPL_STATSHEADER, ++ "Q channel reason"); + + for (qline = GlobalQuarantineList; qline; qline = qline->next) + {