]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blame - split.patch
done some work on cansendtochan.patch, added nserverflag.patch, and probably some...
[irc/quakenet/snircd-patchqueue.git] / split.patch
CommitLineData
12e82c05 1work in progress
2Add split functionality into ircd
3Add /split command
4Add /stats S/split (make /STATS s/S case sensitive, s spoofhosts)
5Add feature SPLIT
6Add split.c split.h m_split.c
7
7efbed3b 8NOTE: feature SPLIT is default enabled as that is just easier when working on this patch.
9
10diff -r bc3532fbd97a include/handlers.h
11--- a/include/handlers.h Tue Jan 20 17:24:09 2009 +0100
12+++ b/include/handlers.h Tue Jan 20 17:25:52 2009 +0100
12e82c05 13@@ -139,6 +139,7 @@
14 extern int m_registered(struct Client*, struct Client*, int, char*[]);
15 extern int m_sethost(struct Client*, struct Client*, int, char*[]);
16 extern int m_silence(struct Client*, struct Client*, int, char*[]);
17+extern int m_split(struct Client*, struct Client*, int, char*[]);
18 extern int m_stats(struct Client*, struct Client*, int, char*[]);
19 extern int m_time(struct Client*, struct Client*, int, char*[]);
20 extern int m_topic(struct Client*, struct Client*, int, char*[]);
21@@ -178,6 +179,7 @@
22 extern int mo_rping(struct Client*, struct Client*, int, char*[]);
23 extern int mo_set(struct Client*, struct Client*, int, char*[]);
24 extern int mo_settime(struct Client*, struct Client*, int, char*[]);
25+extern int mo_split(struct Client*, struct Client*, int, char*[]);
26 extern int mo_squit(struct Client*, struct Client*, int, char*[]);
27 extern int mo_stats(struct Client*, struct Client*, int, char*[]);
28 extern int mo_trace(struct Client*, struct Client*, int, char*[]);
29@@ -232,6 +234,7 @@
30 extern int ms_sethost(struct Client*, struct Client*, int, char*[]);
31 extern int ms_settime(struct Client*, struct Client*, int, char*[]);
32 extern int ms_silence(struct Client*, struct Client*, int, char*[]);
33+extern int ms_split(struct Client*, struct Client*, int, char*[]);
34 extern int ms_squit(struct Client*, struct Client*, int, char*[]);
35 extern int ms_stats(struct Client*, struct Client*, int, char*[]);
36 extern int ms_topic(struct Client*, struct Client*, int, char*[]);
7efbed3b 37diff -r bc3532fbd97a include/ircd_features.h
38--- a/include/ircd_features.h Tue Jan 20 17:24:09 2009 +0100
39+++ b/include/ircd_features.h Tue Jan 20 17:25:52 2009 +0100
65b70298 40@@ -110,6 +110,10 @@
12e82c05 41 FEAT_SETHOST_USER,
42 FEAT_SETHOST_AUTO,
12e82c05 43
65b70298 44+ /* SPLIT */
45+ FEAT_SPLIT,
46+ FEAT_SPLIT_AUTO_EXPIRE,
47+
12e82c05 48 /* HEAD_IN_SAND Features */
49 FEAT_HIS_SNOTICES,
65b70298 50 FEAT_HIS_SNOTICES_OPER_ONLY,
51@@ -137,6 +141,7 @@
12e82c05 52 FEAT_HIS_STATS_q,
53 FEAT_HIS_STATS_R,
54 FEAT_HIS_STATS_r,
55+ FEAT_HIS_STATS_S,
56 FEAT_HIS_STATS_s,
57 FEAT_HIS_STATS_t,
58 FEAT_HIS_STATS_T,
7efbed3b 59diff -r bc3532fbd97a include/msg.h
60--- a/include/msg.h Tue Jan 20 17:24:09 2009 +0100
61+++ b/include/msg.h Tue Jan 20 17:25:53 2009 +0100
12e82c05 62@@ -332,6 +332,10 @@
63 #define TOK_JUPE "JU"
64 #define CMD_JUPE MSG_JUPE, TOK_JUPE
65
66+#define MSG_SPLIT "SPLIT" /* SPLIT */
67+#define TOK_SPLIT "SP"
68+#define CMD_SPLIT MSG_SPLIT, TOK_SPLIT
69+
70 #define MSG_OPMODE "OPMODE" /* OPMO */
71 #define TOK_OPMODE "OM"
72 #define CMD_OPMODE MSG_OPMODE, TOK_OPMODE
7efbed3b 73diff -r bc3532fbd97a include/numeric.h
74--- a/include/numeric.h Tue Jan 20 17:24:09 2009 +0100
75+++ b/include/numeric.h Tue Jan 20 17:25:53 2009 +0100
12e82c05 76@@ -117,6 +117,7 @@
77 RPL_STATSVLINE 227 unreal */
78 #define RPL_STATSALINE 226 /* Hybrid, Undernet */
79 #define RPL_STATSQLINE 228 /* Undernet extension */
80+#define RPL_STATSSPLIT 229 /* QuakeNet extension */
65b70298 81 #define RPL_STATSHEADER 230 /* QuakeNet extension */
12e82c05 82
83 /* RPL_SERVICEINFO 231 unused */
65b70298 84@@ -178,6 +179,8 @@
12e82c05 85 #define RPL_STATSDLINE 275 /* Undernet extension */
86 #define RPL_STATSRLINE 276 /* Undernet extension */
87
88+#define RPL_SPLITLIST 278 /* QuakeNet extension */
89+#define RPL_ENDOFSPLITLIST 279 /* QuakeNet extension */
90 #define RPL_GLIST 280 /* Undernet extension */
91 #define RPL_ENDOFGLIST 281 /* Undernet extension */
92 #define RPL_JUPELIST 282 /* Undernet extension - jupe -Kev */
65b70298 93@@ -441,6 +444,7 @@
12e82c05 94 /* ERR_GHOSTEDCLIENT 503 efnet */
95 /* ERR_VWORLDWARN 503 austnet */
96
97+#define ERR_NOSUCHSPLIT 510 /* QuakeNet extension */
98 #define ERR_SILELISTFULL 511 /* Undernet extension */
99 /* ERR_NOTIFYFULL 512 aircd */
100 /* ERR_TOOMANYWATCH 512 Numeric List: Dalnet */
7efbed3b 101diff -r bc3532fbd97a include/split.h
12e82c05 102--- /dev/null Thu Jan 01 00:00:00 1970 +0000
7efbed3b 103+++ b/include/split.h Tue Jan 20 17:25:53 2009 +0100
65b70298 104@@ -0,0 +1,120 @@
12e82c05 105+/* TODO: ifndef ? */
106+#ifndef INCLUDED_jupe_h
107+#define INCLUDED_jupe_h
108+/*
109+ * IRC - Internet Relay Chat, include/split.h
110+ * Copyright (C) 1990 Jarkko Oikarinen and
111+ * University of Oulu, Computing Center
112+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
113+ *
114+ * This program is free software; you can redistribute it and/or modify
115+ * it under the terms of the GNU General Public License as published by
116+ * the Free Software Foundation; either version 2, or (at your option)
117+ * any later version.
118+ *
119+ * This program is distributed in the hope that it will be useful,
120+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
121+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
122+ * GNU General Public License for more details.
123+ *
124+ * You should have received a copy of the GNU General Public License
125+ * along with this program; if not, write to the Free Software
126+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
127+ */
128+/** @file
129+ * @brief Interface and declarations for split server handling.
130+ * @version $Id: jupe.h 1208 2004-10-03 14:12:35Z entrope $
131+ */
132+/* TODO: ifndef ? */
133+#ifndef INCLUDED_sys_types_h
134+#include <sys/types.h>
135+#define INCLUDED_sys_types_h
136+#endif
137+
138+
139+struct Client;
140+struct StatDesc;
141+
65b70298 142+#define SPLIT_MAX_EXPIRE 2419200 /**< Maximum split expiration time (4 weeks). */
12e82c05 143+
144+/* Describes a SPLIT server entry. */
145+struct Split {
146+ struct Split* sp_next; /**< Pointer to next Split. */
147+ struct Split** sp_prev_p; /**< Pointer to previous next pointer. */
148+ char* sp_server; /**< Name of server. */
149+ char* sp_reason; /**< Reason. */
150+ time_t sp_creation; /**< TODO: Creation time. What are we using this for then? */
151+ time_t sp_expire; /**< Expiration time. */
152+ time_t sp_lastmod; /**< Last modification time. */
153+ time_t sp_lifetime; /**< Life time. */
154+ unsigned int sp_flags; /**< Status flags. */
155+};
156+
157+/** Split state flags. */
158+#define SPLIT_ACTIVE 0x0001 /**< Split is active. */
159+#define SPLIT_REMOVING 0x0002 /**< Split is about to be destroyed. */
160+
161+/* TODO: these ; after } needed ? */
162+/* Actions to perform on a SPLIT. */
163+enum SplitAction {
164+ SPLIT_ACTIVATE, /**< SPLIT should be activated. */
165+ SPLIT_DEACTIVATE, /**< SPLIT should be deactivated. */
166+ SPLIT_MODIFY, /**< SPLIT should be modified. */
167+ SPLIT_REMOVE /**< SPLIT should be removed. */
168+};
169+
170+/* TODO: what values to use here? */
171+/* Split update flags. */
172+#define SPLIT_EXPIRE 0x0002 /**< Expiration time update. */
173+#define SPLIT_LIFETIME 0x0004 /**< Record lifetime update. */
174+#define SPLIT_REASON 0x0008 /**< Reason update. */
175+#define SPLIT_CREATION 0x0010 /**< Creation time update. */
176+#define SPLIT_MODIFY 0x0020 /**< No state change. */
177+
178+/* mask for Split update flags. */
179+#define SPLIT_UPDATE (SPLIT_EXPIRE | SPLIT_LIFETIME | SPLIT_REASON)
180+
181+/* test whether a split entry is active. */
182+#define SplitIsActive(s) ((s)->sp_flags & SPLIT_ACTIVE)
183+/* test whether a split entry is marked for forecd removal. */
184+#define SplitIsRemoving(s) ((s)->sp_flags & SPLIT_REMOVING)
185+
186+/* TODO: these are not used? some are, check! */
187+/* get the server name for a split entry. */
188+#define SplitServer(s) ((s)->sp_server)
189+/* get the reason for a split entry. */
190+#define SplitReason(s) ((s)->sp_reason)
191+/* get the creation time for split entry. */
192+#define SplitCreation(s) ((s)->sp_creation)
193+/* get the expiration time for split entry. */
194+#define SplitExpire(s) ((s)->sp_expire)
195+/* get the last modification time for split entry. */
196+#define SplitLastMod(s) ((s)->sp_lastmod)
197+/* get the life time for split entry. */
198+#define SplitLifeTime(s) ((s)->sp_lifetime)
199+
200+extern int split_add(struct Client *cptr, struct Client *sptr,
201+ char *server, const char *reason,
202+ time_t creation, time_t expire, time_t lastmod, time_t lifetime,
203+ unsigned int flags);
204+extern int split_modify(struct Client *cptr, struct Client *sptr,
205+ struct Split *split, enum SplitAction action, const char *reason,
206+ time_t creation, time_t expire, time_t lastmod, time_t lifetime,
207+ unsigned int flags);
208+extern int split_remove(struct Client *cptr, struct Client *sptr,
209+ struct Split *split, const char *reason);
210+
211+extern struct Split* split_find(char *server);
212+extern void split_free(struct Split *split);
213+extern int split_expire(struct Split* split);
214+extern void split_burst(struct Client *cptr);
215+extern int split_resend(struct Client *cptr, struct Split *split);
216+extern int split_list(struct Client *sptr, char *server);
217+extern int split_merge(struct Client *server);
218+extern int split_break(struct Client *server, const char *reason);
219+extern void split_conf();
220+extern void split_stats(struct Client *sptr, const struct StatDesc *sd, char *param);
221+extern int split_memory_count(size_t *sp_size);
222+
223+/* TODO: endif ? */
224+#endif /* INCLUDED_jupe_h */
7efbed3b 225diff -r bc3532fbd97a ircd/Makefile.in
226--- a/ircd/Makefile.in Tue Jan 20 17:24:09 2009 +0100
227+++ b/ircd/Makefile.in Tue Jan 20 17:25:53 2009 +0100
12e82c05 228@@ -173,6 +173,7 @@
229 m_sethost.c \
230 m_settime.c \
231 m_silence.c \
232+ m_split.c \
233 m_squit.c \
234 m_stats.c \
235 m_time.c \
236@@ -212,6 +213,7 @@
237 s_stats.c \
238 s_user.c \
239 send.c \
240+ split.c \
241 uping.c \
242 userload.c \
243 whocmds.c \
244@@ -1052,6 +1054,15 @@
245 ../include/ircd_chattr.h ../include/list.h ../include/msg.h \
246 ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
247 ../include/send.h ../include/struct.h
248+m_split.o: m_split.c ../config.h ../include/client.h ../include/ircd_defs.h \
249+ ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
250+ ../config.h ../include/ircd_handler.h ../include/res.h \
251+ ../include/capab.h ../include/split.h ../include/hash.h \
252+ ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
253+ ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
254+ ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
255+ ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
256+ ../include/client.h ../include/s_misc.h ../include/send.h
257 m_squit.o: m_squit.c ../config.h ../include/client.h \
258 ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
259 ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
260@@ -1325,6 +1336,7 @@
261 ../include/msgq.h ../include/numeric.h ../include/numnicks.h \
262 ../include/res.h ../include/s_bsd.h ../include/s_conf.h \
263 ../include/s_user.h ../include/s_stats.h ../include/send.h \
264+ ../include/split.h \
265 ../include/struct.h ../include/sys.h ../include/whowas.h
266 s_err.o: s_err.c ../config.h ../include/numeric.h ../include/ircd_log.h \
267 ../include/s_debug.h ../config.h ../include/ircd_defs.h
268@@ -1410,6 +1422,16 @@
269 ../include/msg.h ../include/numnicks.h ../include/parse.h \
270 ../include/s_bsd.h ../include/s_debug.h ../include/s_misc.h \
271 ../include/s_user.h ../include/struct.h ../include/sys.h
272+split.o: split.c ../config.h ../include/split.h ../include/client.h \
273+ ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
274+ ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
275+ ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
276+ ../include/struct.h ../include/ircd_alloc.h ../include/ircd_features.h \
277+ ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
278+ ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
279+ ../include/numeric.h ../include/numnicks.h ../include/s_bsd.h \
280+ ../include/s_misc.h ../include/send.h ../include/struct.h \
281+ ../include/sys.h
282 uping.o: uping.c ../config.h ../include/uping.h ../include/ircd_defs.h \
283 ../include/ircd_events.h ../config.h ../include/res.h \
284 ../include/client.h ../include/dbuf.h ../include/msgq.h \
7efbed3b 285diff -r bc3532fbd97a ircd/ircd.c
286--- a/ircd/ircd.c Tue Jan 20 17:24:09 2009 +0100
287+++ b/ircd/ircd.c Tue Jan 20 17:25:53 2009 +0100
12e82c05 288@@ -55,6 +55,7 @@
289 #include "s_misc.h"
290 #include "s_stats.h"
291 #include "send.h"
292+#include "split.h"
293 #include "sys.h"
294 #include "uping.h"
295 #include "userload.h"
296@@ -763,6 +764,9 @@
297 Debug((DEBUG_NOTICE, "Server ready..."));
298 log_write(LS_SYSTEM, L_NOTICE, 0, "Server Ready");
299
300+ /* create SPLITs */
301+ split_conf();
302+
303 event_loop();
304
305 return 0;
7efbed3b 306diff -r bc3532fbd97a ircd/ircd_features.c
307--- a/ircd/ircd_features.c Tue Jan 20 17:24:09 2009 +0100
308+++ b/ircd/ircd_features.c Tue Jan 20 17:25:53 2009 +0100
65b70298 309@@ -364,6 +364,10 @@
12e82c05 310 F_B(SETHOST_USER, 0, 0, 0),
311 F_B(SETHOST_AUTO, 0, 0, 0),
12e82c05 312
65b70298 313+ /* SPLIT */
314+ F_B(SPLIT, 0, 1, 0),
315+ F_I(SPLIT_AUTO_EXPIRE, 0, 604800, 0),
316+
12e82c05 317 /* HEAD_IN_SAND Features */
318 F_B(HIS_SNOTICES, 0, 1, 0),
65b70298 319 F_B(HIS_SNOTICES_OPER_ONLY, 0, 1, 0),
320@@ -391,6 +395,7 @@
12e82c05 321 F_B(HIS_STATS_q, 0, 1, 0),
322 F_B(HIS_STATS_R, 0, 1, 0),
323 F_B(HIS_STATS_r, 0, 1, 0),
324+ F_B(HIS_STATS_S, 0, 1, 0),
325 F_B(HIS_STATS_s, 0, 1, 0),
326 F_B(HIS_STATS_t, 0, 1, 0),
327 F_B(HIS_STATS_T, 0, 1, 0),
7efbed3b 328diff -r bc3532fbd97a ircd/m_endburst.c
329--- a/ircd/m_endburst.c Tue Jan 20 17:24:09 2009 +0100
330+++ b/ircd/m_endburst.c Tue Jan 20 17:25:53 2009 +0100
12e82c05 331@@ -85,6 +85,7 @@
332 #include "client.h"
333 #include "hash.h"
334 #include "ircd.h"
335+#include "ircd_features.h"
336 #include "ircd_log.h"
337 #include "ircd_reply.h"
338 #include "ircd_string.h"
339@@ -92,6 +93,7 @@
340 #include "numeric.h"
341 #include "numnicks.h"
342 #include "send.h"
343+#include "split.h"
344
345 /* #include <assert.h> -- Now using assert in ircd_log.h */
346
347@@ -125,6 +127,7 @@
348 int ms_end_of_burst(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
349 {
350 struct Channel *chan, *next_chan;
351+ int split;
352
353 assert(0 != cptr);
354 assert(0 != sptr);
355@@ -135,6 +138,10 @@
356 dump_map(sptr, "*", 0, report_new_links, 0);
357 sendto_opmask_butone(0, SNO_NETWORK, "Completed net.burst from %C.",
358 sptr);
359+ /* cleanup SPLITs, but only bother ops when FEAT_SPLIT is enabled. */
360+ split = split_merge(sptr);
361+ if (feature_bool(FEAT_SPLIT))
362+ sendto_opmask_butone(0, SNO_NETWORK, "Removed %d SPLIT entries.", split);
363 if (MyConnect(sptr))
364 sendcmdto_one(&me, CMD_END_OF_BURST_ACK, sptr, "");
365
7efbed3b 366diff -r bc3532fbd97a ircd/m_reburst.c
367--- a/ircd/m_reburst.c Tue Jan 20 17:24:09 2009 +0100
368+++ b/ircd/m_reburst.c Tue Jan 20 17:25:53 2009 +0100
12e82c05 369@@ -102,6 +102,7 @@
370 #include "ircd_snprintf.h"
371 #include "gline.h"
372 #include "jupe.h"
373+#include "split.h"
374
375 /* #include <assert.h> -- Now using assert in ircd_log.h */
376 #include <stdlib.h>
377@@ -130,6 +131,10 @@
378 case 'J':
379 jupe_burst(sptr);
380 break;
381+ case 's':
382+ case 'S':
383+ split_burst(sptr);
384+ break;
385 default:
386 break;
387 }
7efbed3b 388diff -r bc3532fbd97a ircd/m_split.c
12e82c05 389--- /dev/null Thu Jan 01 00:00:00 1970 +0000
7efbed3b 390+++ b/ircd/m_split.c Tue Jan 20 17:25:53 2009 +0100
12e82c05 391@@ -0,0 +1,374 @@
392+/*
393+ * IRC - Internet Relay Chat, ircd/m_split.c
394+ * Copyright (C) 1990 Jarkko Oikarinen and
395+ * University of Oulu, Computing Center
396+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
397+ *
398+ * See file AUTHORS in IRC package for additional names of
399+ * the programmers.
400+ *
401+ * This program is free software; you can redistribute it and/or modify
402+ * it under the terms of the GNU General Public License as published by
403+ * the Free Software Foundation; either version 1, or (at your option)
404+ * any later version.
405+ *
406+ * This program is distributed in the hope that it will be useful,
407+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
408+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
409+ * GNU General Public License for more details.
410+ *
411+ * You should have received a copy of the GNU General Public License
412+ * along with this program; if not, write to the Free Software
413+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
414+ *
415+ * $Id: m_split.c 1737 2006-12-19 05:20:48Z entrope $
416+ */
417+
418+/*
419+ * m_functions execute protocol messages on this server:
420+ *
421+ * cptr is always NON-NULL, pointing to a *LOCAL* client
422+ * structure (with an open socket connected!). This
423+ * identifies the physical socket where the message
424+ * originated (or which caused the m_function to be
425+ * executed--some m_functions may call others...).
426+ *
427+ * sptr is the source of the message, defined by the
428+ * prefix part of the message if present. If not
429+ * or prefix not found, then sptr==cptr.
430+ *
431+ * (!IsServer(cptr)) => (cptr == sptr), because
432+ * prefixes are taken *only* from servers...
433+ *
434+ * (IsServer(cptr))
435+ * (sptr == cptr) => the message didn't
436+ * have the prefix.
437+ *
438+ * (sptr != cptr && IsServer(sptr) means
439+ * the prefix specified servername. (?)
440+ *
441+ * (sptr != cptr && !IsServer(sptr) means
442+ * that message originated from a remote
443+ * user (not local).
444+ *
445+ * combining
446+ *
447+ * (!IsServer(sptr)) means that, sptr can safely
448+ * taken as defining the target structure of the
449+ * message in this server.
450+ *
451+ * *Always* true (if 'parse' and others are working correct):
452+ *
453+ * 1) sptr->from == cptr (note: cptr->from == cptr)
454+ *
455+ * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
456+ * *cannot* be a local connection, unless it's
457+ * actually cptr!). [MyConnect(x) should probably
458+ * be defined as (x == x->from) --msa ]
459+ *
460+ * parc number of variable parameter strings (if zero,
461+ * parv is allowed to be NULL)
462+ *
463+ * parv a NULL terminated list of parameter pointers,
464+ *
465+ * parv[0], sender (prefix string), if not present
466+ * this points to an empty string.
467+ * parv[1]...parv[parc-1]
468+ * pointers to additional parameters
469+ * parv[parc] == NULL, *always*
470+ *
471+ * note: it is guaranteed that parv[0]..parv[parc-1] are all
472+ * non-NULL pointers.
473+ */
474+#include "config.h"
475+
476+#include "client.h"
477+#include "split.h"
478+#include "hash.h"
479+#include "ircd.h"
480+#include "ircd_features.h"
481+#include "ircd_log.h"
482+#include "ircd_reply.h"
483+#include "ircd_string.h"
484+#include "match.h"
485+#include "msg.h"
486+#include "numeric.h"
487+#include "numnicks.h"
488+#include "s_conf.h"
489+#include "s_debug.h"
490+#include "s_misc.h"
491+#include "send.h"
492+
493+/* #include <assert.h> -- Now using assert in ircd_log.h */
494+#include <stdlib.h>
495+#include <string.h>
496+
497+/*
498+ * ms_split - server message handler
499+ *
500+ * parv[0] = Send prefix
501+ * parv[1] = (+|-)<server name>
502+ * parv[2] = Creation time
503+ * parv[3] = Expiration time
504+ * parv[4] = Last modification time
505+ * parv[5] = Life time
506+ * parv[6] = Comment
507+ *
508+ */
509+int ms_split(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
510+{
511+ struct Client *acptr = 0;
512+ struct Split *asplit = 0;
513+ unsigned int flags = 0;
514+ enum SplitAction action = SPLIT_MODIFY;
515+ time_t creation = 0, expire = 0, lastmod = 0, lifetime = 0;
516+ char *server = parv[1], *tmp = 0;
517+ const char *reason = "No reason";
518+
519+ /* TODO: perhaps make some fields optional? reason? */
520+ if (parc < 6)
521+ return need_more_params(sptr, "SPLIT");
522+
523+ if (*server == '!') {
524+ server++;
525+ action = SPLIT_REMOVE; /* removing entry */
526+ }
527+
528+ switch (*server) { /* handle + and - */
529+ case '+': /* activate the split entry */
530+ if (action != SPLIT_REMOVE)
531+ action = SPLIT_ACTIVATE;
532+ server++;
533+ break;
534+
535+ case '-': /* deactivate the entry */
536+ if (action != SPLIT_REMOVE)
537+ action = SPLIT_DEACTIVATE;
538+ server++;
539+ break;
540+ }
541+
542+ /* Next, try to find the split entry... */
543+ asplit = split_find(server);
544+
545+ /* We now have all the pieces to tell us what we've got; let's put
546+ * it all together and convert the rest of the arguments.
547+ */
548+
549+ /* can't modify a split entry that doesn't exist, so remap to activate */
550+ if (!asplit && action == SPLIT_MODIFY)
551+ action = SPLIT_ACTIVATE;
552+
553+ /* OK, let's figure out what other parameters we may have... */
554+ creation = atoi(parv[2]);
555+ expire = atoi(parv[3]);
556+ lastmod = atoi(parv[4]);
557+ lifetime = atoi(parv[5]);
558+ reason = parv[parc - 1];
559+
560+ Debug((DEBUG_DEBUG, "I have a SPLIT I am acting upon now; "
561+ "server %s, action %s, creation %Tu, expire %Tu, "
562+ "lastmod %Tu, lifetime %Tu, reason: %s; split %s!", server,
563+ action == SPLIT_REMOVE ? "!-" :
564+ (action == SPLIT_ACTIVATE ? "+" :
565+ (action == SPLIT_DEACTIVATE ? "-" : "(MODIFY)")),
566+ creation, expire, lastmod, lifetime, reason,
567+ asplit ? "EXISTS" : "does not exist"));
568+
569+ /* OK, at this point, we have converted all available parameters.
570+ * Let's actually do the action!
571+ */
572+ if (asplit) {
573+ if (action == SPLIT_REMOVE)
574+ return split_remove(cptr, sptr, asplit, reason);
575+ return split_modify(cptr, sptr, asplit, action, reason, creation, expire,
576+ lastmod, lifetime, flags);
577+ }
578+
579+ assert(action != SPLIT_MODIFY);
580+
581+ return split_add(cptr, sptr, server, reason, creation, expire, lastmod, lifetime,
582+ flags | ((action == SPLIT_ACTIVATE) ? SPLIT_ACTIVE : 0));
583+}
584+
585+
586+/*
587+ * mo_split - oper message handler
588+ *
589+ * Local listing: 1 or 2 params
590+ * parv[0] = Send prefix
591+ * parv[1] = [Server or mask to match]
592+ *
593+ * Add or modify entry: 3, 4 or 5 params (3 is * then)
594+ * parv[0] = Send prefix
595+ * parv[1] = [+|-]<server name>
596+ * parv[2] = [Expiration offset] (required for new)
597+ * parv[3] = [Comment] (required for new)
598+ *
599+ */
600+int mo_split(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
601+{
602+ struct Client *acptr = 0;
603+ struct Split *asplit = 0;
604+ unsigned int flags = 0;
605+ enum SplitAction action = SPLIT_MODIFY;
606+ time_t expire = 0, lastmod = CurrentTime, creation = CurrentTime;
607+ char *server = parv[1], *end;
608+ const char *reason = NULL;
609+
610+ if (parc < 2) {
611+ if (!HasPriv(sptr, PRIV_ROUTEINFO))
612+ return send_reply(sptr, ERR_NOPRIVILEGES);
613+ else
614+ return split_list(sptr, 0);
615+ }
616+
617+ if (*server == '!') {
618+ server++;
619+ action = SPLIT_REMOVE; /* force removal */
620+ }
621+
622+ switch (*server) { /* handle + and - */
623+ case '+': /* activate the split entry */
624+ if (action != SPLIT_REMOVE)
625+ action = SPLIT_ACTIVATE;
626+ server++;
627+ break;
628+
629+ case '-': /* deactivate the split entry */
630+ if (action != SPLIT_REMOVE)
631+ action = SPLIT_DEACTIVATE;
632+ server++;
633+ break;
634+ }
635+
636+ /* OK, let's figure out the parameters... */
637+ switch (action) {
638+ /* no specific action */
639+ case SPLIT_MODIFY:
640+ /* user wants a listing of a specific SPLIT */
641+ if (parc == 2)
642+ return split_list(sptr, server);
643+ expire = strtol(parv[2], &end, 10) + CurrentTime; /* and the expiration */
644+ if (*end != '\0')
645+ return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE,
646+ "%s :Bad expire time", parv[2]);
647+
648+ flags |= SPLIT_EXPIRE; /* remember that we got an expire time */
649+
650+ if (parc > 3) { /* also got a reason... */
651+ reason = parv[parc - 1];
652+ flags |= SPLIT_REASON;
653+ }
654+ break;
655+
656+ case SPLIT_REMOVE: /* TODO: require reason for this, but not expire? */
657+ if (parc < 4)
658+ return need_more_params(sptr, "SPLIT");
659+ reason = parv[parc - 1];
660+ flags |= SPLIT_REASON;
661+ break;
662+
663+ case SPLIT_ACTIVATE: /* TODO: require expire and reason when new */
664+ if (parc > 2) {
665+ expire = strtol(parv[2], &end, 10) + CurrentTime; /* and the expiration */
666+ if (*end != '\0')
667+ return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE,
668+ "%s :Bad expire time", parv[2]);
669+ flags |= SPLIT_EXPIRE; /* remember that we got an expire time */
670+ }
671+
672+ if (parc > 3) { /* also got a reason... */
673+ reason = parv[parc - 1];
674+ flags |= SPLIT_REASON;
675+ }
676+ break;
677+
678+ case SPLIT_DEACTIVATE: /* TODO: duplicate code? must be a cleaner way */
679+ if (parc > 2) {
680+ expire = strtol(parv[2], &end, 10) + CurrentTime; /* and the expiration */
681+ if (*end != '\0')
682+ return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE,
683+ "%s :Bad expire time", parv[2]);
684+ flags |= SPLIT_EXPIRE; /* remember that we got an expire time */
685+ }
686+
687+ if (parc > 3) { /* also got a reason... */
688+ reason = parv[parc - 1];
689+ flags |= SPLIT_REASON;
690+ }
691+ break;
692+ }
693+
694+
695+ /* check for permissions... */
696+ if (!feature_bool(FEAT_SPLIT)) /* TODO: but allow force removal? */
697+ return send_reply(sptr, ERR_DISABLED, "SPLIT");
698+ else if (!HasPriv(sptr, PRIV_SERVERINFO)) /* TODO: create PRIV_SPLIT - need help there */
699+ return send_reply(sptr, ERR_NOPRIVILEGES);
700+
701+ /* Next, try to find the SPLIT... */
702+ asplit = split_find(server);
703+
704+ /* We now have all the pieces to tell us what we've got; let's put
705+ * it all together and convert the rest of the arguments.
706+ */
707+
708+ /* SPLIT not found and thus we:
709+ * cannot remove SPLIT we do not have
710+ * cannot add new SPLIT without expire and reason
711+ */
712+ if (!asplit &&
713+ ((action == SPLIT_REMOVE) ||
714+ (action == SPLIT_ACTIVATE && !reason) ||
715+ (action == SPLIT_DEACTIVATE && !reason) ||
716+ (action == SPLIT_MODIFY && !reason)))
717+ return send_reply(sptr, ERR_NOSUCHSPLIT, server);
718+
719+ /* can't modify a split entry that doesn't exist, so remap to activate */
720+ if (!asplit && action == SPLIT_MODIFY)
721+ action = SPLIT_ACTIVATE;
722+
723+ Debug((DEBUG_DEBUG, "I have a SPLIT I am acting upon now; "
724+ "server %s, action %s, expire %Tu, "
725+ "reason: %s; split %s! (fields present: %s %s)", server,
726+ action == SPLIT_REMOVE ? "!-" :
727+ (action == SPLIT_ACTIVATE ? "+" :
728+ (action == SPLIT_DEACTIVATE ? "-" : "(MODIFY)")),
729+ expire, reason, asplit ? "EXISTS" : "does not exist",
730+ flags & SPLIT_EXPIRE ? "expire" : "",
731+ flags & SPLIT_REASON ? "reason" : ""));
732+
733+ if (asplit) { /* modifying an existing SPLIT */
734+ if (action == SPLIT_REMOVE)
735+ return split_remove(cptr, sptr, asplit, reason);
736+ return split_modify(cptr, sptr, asplit, action, reason,
737+ asplit->sp_creation, expire, lastmod, asplit->sp_lifetime, flags);
738+ }
739+
740+ assert(action != SPLIT_MODIFY);
741+ assert(action != SPLIT_REMOVE);
742+
743+ /* create a new SPLIT */
744+ return split_add(cptr, sptr, server, reason,
745+ creation, expire, lastmod, expire,
746+ flags | ((action == SPLIT_ACTIVATE) ? SPLIT_ACTIVE : 0));
747+}
748+
749+/*
750+ * m_split - user message handler
751+ *
752+ * parv[0] = Send prefix
753+ *
754+ * From user:
755+ *
756+ * parv[1] = [<server name>]
757+ *
758+ */
759+int m_split(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
760+{
761+ if (parc < 2)
762+ return split_list(sptr, 0);
763+
764+ return split_list(sptr, parv[1]);
765+}
7efbed3b 766diff -r bc3532fbd97a ircd/parse.c
767--- a/ircd/parse.c Tue Jan 20 17:24:09 2009 +0100
768+++ b/ircd/parse.c Tue Jan 20 17:25:53 2009 +0100
12e82c05 769@@ -505,6 +505,13 @@
770 0, MAXPARA, MFLG_SLOW, 0, NULL,
771 /* UNREG, CLIENT, SERVER, OPER, SERVICE */
772 { m_unregistered, m_not_oper, ms_jupe, mo_jupe, m_ignore }
773+ },
774+ {
775+ MSG_SPLIT,
776+ TOK_SPLIT,
777+ 0, MAXPARA, MFLG_SLOW, 0, NULL,
778+ /* UNREG, CLIENT, SERVER, OPER, SERVICE */
779+ { m_unregistered, m_not_oper, ms_split, mo_split, m_ignore }
780 },
781 {
782 MSG_OPMODE,
7efbed3b 783diff -r bc3532fbd97a ircd/s_conf.c
784--- a/ircd/s_conf.c Tue Jan 20 17:24:09 2009 +0100
785+++ b/ircd/s_conf.c Tue Jan 20 17:25:53 2009 +0100
12e82c05 786@@ -53,6 +53,7 @@
787 #include "s_debug.h"
788 #include "s_misc.h"
789 #include "send.h"
790+#include "split.h"
791 #include "struct.h"
792 #include "sys.h"
793
794@@ -1005,6 +1006,7 @@
795 }
796
797 attach_conf_uworld(&me);
798+ split_conf();
799
800 return ret;
801 }
7efbed3b 802diff -r bc3532fbd97a ircd/s_debug.c
803--- a/ircd/s_debug.c Tue Jan 20 17:24:09 2009 +0100
804+++ b/ircd/s_debug.c Tue Jan 20 17:25:53 2009 +0100
12e82c05 805@@ -48,6 +48,7 @@
806 #include "s_user.h"
807 #include "s_stats.h"
808 #include "send.h"
809+#include "split.h"
810 #include "struct.h"
811 #include "sys.h"
812 #include "whowas.h"
813@@ -231,7 +232,8 @@
814 aw = 0, /* aways set */
815 wwa = 0, /* whowas aways */
816 gl = 0, /* glines */
817- ju = 0; /* jupes */
818+ ju = 0, /* jupes */
819+ sp = 0; /* split entries */
820
821 size_t chm = 0, /* memory used by channels */
822 chbm = 0, /* memory used by channel bans */
823@@ -244,6 +246,7 @@
824 wwm = 0, /* whowas array memory used */
825 glm = 0, /* memory used by glines */
826 jum = 0, /* memory used by jupes */
827+ spm = 0, /* memory used by split entries */
828 com = 0, /* memory used by conf lines */
829 dbufs_allocated = 0, /* memory used by dbufs */
830 dbufs_used = 0, /* memory used by dbufs */
831@@ -348,8 +351,9 @@
832
833 gl = gline_memory_count(&glm);
834 ju = jupe_memory_count(&jum);
835+ sp = split_memory_count(&spm);
836 send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
837- ":Glines %d(%zu) Jupes %d(%zu)", gl, glm, ju, jum);
838+ ":Glines %d(%zu) Jupes %d(%zu) Splits %d(%zu)", gl, glm, ju, jum, sp, spm);
839
840 send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
841 ":Hash: client %d(%zu), chan is the same", HASHSIZE,
7efbed3b 842diff -r bc3532fbd97a ircd/s_err.c
843--- a/ircd/s_err.c Tue Jan 20 17:24:09 2009 +0100
844+++ b/ircd/s_err.c Tue Jan 20 17:25:53 2009 +0100
12e82c05 845@@ -490,7 +490,7 @@
846 /* 228 */
847 { RPL_STATSQLINE, "Q %s :%s", "228" },
848 /* 229 */
849- { 0 },
850+ { RPL_STATSSPLIT, "S %s %d %d %d %d %c :%s", "229" },
851 /* 230 */
65b70298 852 { RPL_STATSHEADER, 0, "230" },
12e82c05 853 /* 231 */
854@@ -588,9 +588,9 @@
855 /* 277 */
856 { 0 },
857 /* 278 */
858- { 0 },
859+ { RPL_SPLITLIST, "%s %Tu %Tu %Tu %Tu %c :%s", "278" },
860 /* 279 */
861- { 0 },
862+ { RPL_ENDOFSPLITLIST, ":End of Split List", "279" },
863 /* 280 */
65b70298 864 { RPL_GLIST, "%s%s%s%s%s %Tu %Tu %Tu %s %s%s%c :%s", "280" },
12e82c05 865 /* 281 */
866@@ -1052,7 +1052,7 @@
867 /* 509 */
868 { 0 },
869 /* 510 */
870- { 0 },
871+ { ERR_NOSUCHSPLIT, "%s :No such split", "510" },
872 /* 511 */
873 { ERR_SILELISTFULL, "%s :Your silence list is full", "511" },
874 /* 512 */
7efbed3b 875diff -r bc3532fbd97a ircd/s_misc.c
876--- a/ircd/s_misc.c Tue Jan 20 17:24:09 2009 +0100
877+++ b/ircd/s_misc.c Tue Jan 20 17:25:53 2009 +0100
12e82c05 878@@ -53,6 +53,7 @@
879 #include "s_stats.h"
880 #include "s_user.h"
881 #include "send.h"
882+#include "split.h"
883 #include "struct.h"
884 #include "sys.h"
885 #include "uping.h"
886@@ -391,6 +392,7 @@
887 time_t on_for;
888
889 char comment1[HOSTLEN + HOSTLEN + 2];
890+ char splitreason[BUFSIZE];
891 assert(killer);
892 if (MyConnect(victim))
893 {
7efbed3b 894@@ -497,6 +499,15 @@
12e82c05 895 sendto_opmask_butone(0, SNO_NETWORK, "Net break: %C %C (%s)",
896 cli_serv(victim)->up, victim, comment);
897 dump_map(victim, "*", 0, report_lost_links, 0);
898+ if (feature_bool(FEAT_SPLIT)) {
7efbed3b 899+ /* TODO: remote & local SQUIT ? servername oper is on? */
12e82c05 900+ ircd_snprintf(0, splitreason, sizeof(splitreason),
901+ "Net break: %C %C (%s%s%s%s)", cli_serv(victim)->up, victim,
902+ IsUser(killer) ? "SQUIT by " : "", IsUser(killer) ? cli_name(killer) : "",
903+ IsUser(killer) ? ": " : "", comment);
904+ sendto_opmask_butone(0, SNO_NETWORK, "Created %d SPLIT entries.",
905+ split_break(victim, splitreason));
906+ }
907 }
908
909 /*
7efbed3b 910diff -r bc3532fbd97a ircd/s_serv.c
911--- a/ircd/s_serv.c Tue Jan 20 17:24:09 2009 +0100
912+++ b/ircd/s_serv.c Tue Jan 20 17:25:53 2009 +0100
12e82c05 913@@ -54,6 +54,7 @@
914 #include "s_misc.h"
915 #include "s_user.h"
916 #include "send.h"
917+#include "split.h"
918 #include "struct.h"
919 #include "sys.h"
920 #include "userload.h"
921@@ -196,6 +197,7 @@
922 */
923 gline_burst(cptr);
924 jupe_burst(cptr);
925+ split_burst(cptr);
926
927 /*
928 * Pass on my client information to the new server
7efbed3b 929diff -r bc3532fbd97a ircd/s_stats.c
930--- a/ircd/s_stats.c Tue Jan 20 17:24:09 2009 +0100
931+++ b/ircd/s_stats.c Tue Jan 20 17:25:53 2009 +0100
12e82c05 932@@ -52,6 +52,7 @@
933 #include "s_stats.h"
934 #include "s_user.h"
935 #include "send.h"
936+#include "split.h"
937 #include "struct.h"
938 #include "userload.h"
939
65b70298 940@@ -668,7 +669,10 @@
12e82c05 941 send_usage, 0,
942 "System resource usage (Debug only)." },
943 #endif
944- { 's', "spoofhosts", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_s,
945+ { 'S', "splits", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_S,
946+ split_stats, 0,
947+ "Server SPLITs information."},
948+ { 's', "spoofhosts", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_s,
949 stats_sline, 0,
950 "Spoofed hosts information." },
951 { 'T', "motds", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T,
7efbed3b 952diff -r bc3532fbd97a ircd/split.c
12e82c05 953--- /dev/null Thu Jan 01 00:00:00 1970 +0000
7efbed3b 954+++ b/ircd/split.c Tue Jan 20 17:25:53 2009 +0100
65b70298 955@@ -0,0 +1,771 @@
12e82c05 956+/*
957+ * IRC - Internet Relay Chat, ircd/split.c
958+ * Copyright (C) 1990 Jarkko Oikarinen and
959+ * University of Oulu, Finland
960+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
961+ *
962+ * This program is free software; you can redistribute it and/or modify
963+ * it under the terms of the GNU General Public License as published by
964+ * the Free Software Foundation; either version 1, or (at your option)
965+ * any later version.
966+ *
967+ * This program is distributed in the hope that it will be useful,
968+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
969+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
970+ * GNU General Public License for more details.
971+ *
972+ * You should have received a copy of the GNU General Public License
973+ * along with this program; if not, write to the Free Software
974+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
975+ */
976+/** @file
977+ * @brief Implementation of split server handling functions.
978+ * @version $Id: split.c 1633 2006-03-25 03:46:56Z entrope $
979+ */
980+#include "config.h"
981+
982+#include "split.h"
983+#include "client.h"
984+#include "hash.h"
985+#include "ircd.h"
986+#include "ircd_alloc.h"
987+#include "ircd_features.h"
988+#include "ircd_log.h"
989+#include "ircd_reply.h"
990+#include "ircd_string.h"
991+#include "list.h"
992+#include "match.h"
993+#include "msg.h"
994+#include "numeric.h"
995+#include "numnicks.h"
996+#include "s_conf.h"
997+#include "s_bsd.h"
998+#include "s_debug.h"
999+#include "s_misc.h"
1000+#include "send.h"
1001+#include "struct.h"
1002+#include "sys.h" /* FALSE bleah */
1003+
1004+/* #include <assert.h> -- Now using assert in ircd_log.h */
1005+#include <string.h>
1006+
1007+/** List of split entries. */
1008+static struct Split *GlobalSplitList = 0;
1009+
1010+/** Allocate a new Split entry with the given parameters.
1011+ * @param[in] server Server name for split entry.
1012+ * @param[in] reason Reason for the split entry.
1013+ * @param[in] creation Creation time for split entry.
1014+ * @param[in] expire Expiration time for split entry.
1015+ * @param[in] lastmod Last modification time for split entry.
1016+ * @param[in] lifetime Life time for split entry.
1017+ * @param[in] flags Flags to set for the split entry.
1018+ */
1019+static struct Split *
1020+split_make(char *server, const char *reason,
1021+ time_t creation, time_t expire, time_t lastmod, time_t lifetime,
1022+ unsigned int flags)
1023+{
1024+ struct Split *asplit;
1025+
1026+ asplit = (struct Split*) MyMalloc(sizeof(struct Split)); /* alloc memory */
1027+ assert(0 != asplit);
1028+
1029+ memset(asplit, 0, sizeof(*asplit));
1030+ /* TODO: some limit for servername length? HOSTLEN? */
1031+ DupString(asplit->sp_server, server); /* copy vital information */
1032+ /* TODO: some limit for reason length? QUITLEN TOPICLEN? */
65b70298 1033+ /* TODO: prefix the reason here with the opername/ID? */
12e82c05 1034+ DupString(asplit->sp_reason, reason);
1035+ /* TODO: what we use creation for and do we need it? */
1036+ asplit->sp_creation = creation;
1037+ asplit->sp_expire = expire;
1038+ /* TODO: are we using nettime etc.? CurrentTime is used. */
65b70298 1039+ /* TODO: TStime() is CurrentTime + TSoffset */
12e82c05 1040+ asplit->sp_lastmod = lastmod;
1041+ asplit->sp_lifetime = lifetime;
1042+ /* CHECK: does this make it active upon creation regardless of the flags given? */
1043+ asplit->sp_flags = flags & SPLIT_ACTIVE; /* set split flags */
1044+
1045+ asplit->sp_next = GlobalSplitList; /* link it into the list */
1046+ asplit->sp_prev_p = &GlobalSplitList;
1047+ if (GlobalSplitList)
1048+ GlobalSplitList->sp_prev_p = &asplit->sp_next;
1049+ GlobalSplitList = asplit;
1050+
1051+ return asplit;
1052+}
1053+
1054+/** Forward a split entry to another server.
1055+ * @param[in] cptr Local client that sent us the split entry.
1056+ * @param[in] sptr Originator of the split entry.
1057+ * @param[in] split Split entry to forward.
1058+ * @param[in] reason Reason to send upstream (used by split_remove)
1059+ */
1060+static void
1061+split_propagate(struct Client *cptr, struct Client *sptr,
1062+ struct Split *split, const char *reason)
1063+{
1064+ sendcmdto_serv_butone(sptr, CMD_SPLIT, cptr, "%s%c%s %Tu %Tu %Tu %Tu :%s",
1065+ SplitIsRemoving(split) ? "!" : "",
1066+ SplitIsActive(split) && !SplitIsRemoving(split) ? '+' : '-', /* always !- not !+ */
1067+ split->sp_server, split->sp_creation, split->sp_expire,
1068+ split->sp_lastmod, split->sp_lifetime,
65b70298 1069+ /* TODO: does reason ? reason : split->sp_reason work too? */
12e82c05 1070+ reason != NULL ? reason : split->sp_reason);
1071+}
1072+
1073+/** Add a new server split entry.
1074+ * @param[in] cptr Local client that sent us the split entry.
1075+ * @param[in] sptr Originator of the split entry.
1076+ * @param[in] server Server name to split entry.
1077+ * @param[in] reason Reason for the split entry.
1078+ * @param[in] expire Expiration timestamp.
1079+ * @param[in] lastmod Last modification timestamp.
1080+ * @param[in] flags Flags to set on the split entry.
1081+ * @return Zero
1082+ */
1083+int
1084+split_add(struct Client *cptr, struct Client *sptr, char *server, const char *reason,
1085+ time_t creation, time_t expire, time_t lastmod, time_t lifetime,
1086+ unsigned int flags)
1087+{
1088+
1089+ /* TODO: check for proper masks - at least one dot and no wildcards? */
1090+ struct Split *asplit;
1091+ struct Client *acptr;
1092+
1093+ assert(0 != server);
1094+ assert(0 != reason);
1095+ assert(NULL != cptr);
1096+ assert(NULL != sptr);
1097+
1098+ Debug((DEBUG_DEBUG, "split_add(\"%s\", \"%s\", \"%s\", \"%s\", %Tu, %Tu, %Tu, "
1099+ "%Tu, 0x%04x)", cli_name(cptr), cli_name(sptr), server, reason,
1100+ creation, expire, lastmod, lifetime, flags));
1101+
1102+ /* not adding SPLIT for server that is linked
1103+ * if sptr is my user throw error
1104+ * otherwise ignore - SERVER and SPLIT messages can cross,
1105+ * or a server is bursting and it will see our end and destroy the SPLITs
1106+ */
1107+ if ((acptr = FindServer(server))) {
1108+ if (MyUser(sptr))
1109+ sendcmdto_one(&me, CMD_NOTICE, sptr,
1110+ "%C :Cannot add SPLIT %s - server is linked.", sptr, server);
1111+ return 0;
1112+ }
1113+
1114+ /*
1115+ * You cannot set a negative (or zero) duration, nor can you set an
1116+ * duration greater than SPLIT_MAX_EXPIRE.
1117+ */
1118+ if (expire - CurrentTime <= 0 || expire - CurrentTime > SPLIT_MAX_EXPIRE) {
1119+ if (!IsServer(cptr) && MyConnect(cptr))
1120+ return send_reply(cptr, ERR_BADEXPIRE, expire - CurrentTime);
1121+ if (expire <= CurrentTime) /* no point going further */
1122+ /* TODO: check lifetime then ? because the SPLIT may simply be deactivated
1123+ * and we did not see it before
1124+ * if it were to be activated again we would get it again
1125+ * but should we not keep the same state on each server?
1126+ */
1127+ /* CHECK: sptr may have the wrong idea about the nettime?
1128+ * or we could be wrong?
1129+ * SETTIME ? could be dangerous and mess up things..
1130+ * perhaps raise some sort of warning to ops
1131+ * maybe if the difference is larger than a poor RTT over the network?
1132+ * 60 seconds?
1133+ * no no no! - see above
1134+ */
65b70298 1135+ /* TODO: raise error with timestamps to SNO_OLDSNO?
1136+ * in the form of
1137+ * Nick collision on nick (nick 1232368192 <- hub.xx.quakenet.org 1232368192 (Same user@host))
1138+ */
12e82c05 1139+ return 0;
1140+ }
1141+
65b70298 1142+ /* TODO: add opername */
12e82c05 1143+ /* inform ops and log it */
1144+ sendto_opmask_butone(0, SNO_NETWORK, "%s adding%sSPLIT for %s, expiring at %Tu: %s",
1145+ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
1146+ cli_name(sptr) : cli_name((cli_user(sptr))->server),
1147+ !(flags & SPLIT_ACTIVE) ? " deactivated " : " ",
1148+ server, expire, reason);
1149+
1150+ /* TODO: add SPLIT log stuff or use JUPE? */
1151+ log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
1152+ "%#C adding%sSPLIT for %s, expiring at %Tu: %s",
1153+ sptr, !(flags & SPLIT_ACTIVE) ? " deactivated " : " ",
1154+ server, expire, reason);
1155+
1156+ /* make the split entry */
1157+ asplit = split_make(server, reason, creation, expire, lastmod, lifetime, flags);
1158+
1159+ assert(asplit);
1160+
1161+ /* and propagate it */
1162+ split_propagate(cptr, sptr, asplit, NULL);
1163+
1164+ return 0;
1165+}
1166+
1167+
1168+/** Modify a split entry.
1169+ * @param[in] cptr Client that sent us the split modification.
1170+ * @param[in] sptr Client that originated the split modification.
1171+ * @param[in] split Split entry being modified.
1172+ * @param[in] action Resultant status of the G-line.
1173+ * @param[in] reason Reason.
1174+ * @param[in] expire Expiration time.
1175+ * @param[in] lastmod Last modification time.
1176+ * @param[in] lifetime Lifetime.
1177+ * @param[in] flags Bitwise combination of SPLIT_* flags.
1178+ * @return Zero.
1179+ */
1180+int
1181+split_modify(struct Client *cptr, struct Client *sptr, struct Split *split,
1182+ enum SplitAction action, const char *reason,
1183+ time_t creation, time_t expire, time_t lastmod, time_t lifetime,
1184+ unsigned int flags)
1185+{
1186+ struct Client* acptr;
1187+ char buf[BUFSIZE];
1188+ int pos = 0;
1189+
1190+ assert(split);
1191+ assert(NULL != cptr);
1192+ assert(NULL != sptr);
1193+
1194+ /* TODO: add action in the debug notice too */
1195+ Debug((DEBUG_DEBUG, "split_modify(\"%s\", \"%s\", \"%s\", \"%s\", %Tu, %Tu, %Tu, "
1196+ "%Tu, 0x%04x)", cli_name(cptr), cli_name(sptr), split->sp_server, reason,
1197+ creation, expire, lastmod, lifetime, flags));
1198+
1199+ /* not modifying SPLIT for server that is linked
1200+ * if sptr is my user throw error
1201+ * otherwise ignore - SERVER and SPLIT messages can cross.
1202+ *
1203+ * note: we cleanup SPLIT entries at end of burst,
1204+ * and not when a server is introduced.
1205+ * so between net junction and end of burst,
1206+ * we can get SPLITs for a linked server.
65b70298 1207+ * also more than one server can be bursting at a time.
12e82c05 1208+ */
1209+ /* TODO: should we free it here or let that be done in end of burst?
1210+ * only when that is the ONLY situation we can get to this point!
1211+ * but if we free here and it is a burst, the count is incorrect in
1212+ * split_netmerge
1213+ * IsBurst() is that true for only that single server or for all its downlinks?
1214+ * I would guess single server only.. argh!
1215+ */
1216+ if ((acptr = FindServer(split->sp_server))) {
1217+ if (MyUser(sptr))
1218+ sendcmdto_one(&me, CMD_NOTICE, sptr,
1219+ "%C :Cannot modify SPLIT %s - server is linked.", sptr, split->sp_server);
1220+ split_free(split); /* and free it */
1221+ return 0;
1222+ }
1223+
1224+ /* First, let's check lastmod... */
1225+ if (SplitLastMod(split) > lastmod) { /* we have a more recent version */
1226+ if (IsBurstOrBurstAck(cptr))
1227+ return 0; /* middle of a burst, it'll resync on its own */
1228+ return split_resend(cptr, split); /* resync the server */
1229+ } else if (SplitLastMod(split) == lastmod)
1230+ return 0; /* we have that version of the split entry... */
1231+
1232+ /* All right, we know that there's a change of some sort. What is it? */
1233+ /* first, check out the expiration time... */
1234+ /* TODO: expire != 0 or NULL - check that we have something? */
1235+ if (expire != 0 && expire != split->sp_expire) {
1236+ if (expire - CurrentTime <= 0 || expire - CurrentTime > SPLIT_MAX_EXPIRE) {
1237+ if (!IsServer(sptr) && MyConnect(sptr)) /* bad expiration time */
1238+ send_reply(sptr, ERR_BADEXPIRE, expire - CurrentTime);
1239+ if (expire - CurrentTime <= 0) /* no point in going further */
1240+ /* TODO: same as in split_add - check lifetime? */
1241+ return 0;
1242+ }
1243+ flags |= SPLIT_EXPIRE;
1244+ } else
1245+ flags &= ~SPLIT_EXPIRE;
1246+
1247+ /* Next, check out lifetime */
1248+ if (!(flags & SPLIT_LIFETIME) || !lifetime)
1249+ lifetime = split->sp_lifetime; /* use Split lifetime */
1250+
1251+ lifetime = IRCD_MAX(lifetime, expire); /* set lifetime to the max */
1252+
1253+ /* OK, let's see which is greater... */
1254+ if (lifetime > split->sp_lifetime)
1255+ flags |= SPLIT_LIFETIME; /* have to update lifetime */
1256+ else {
1257+ flags &= ~SPLIT_LIFETIME; /* no change to lifetime */
1258+ lifetime = 0;
1259+ }
1260+
1261+ /* Finally, let's see if the reason needs to be updated */
1262+ /* TODO: (reason) or use != NULL / 0 ? */
1263+ if ((flags & SPLIT_REASON) && reason &&
1264+ ircd_strcmp(split->sp_reason, reason) != 0)
1265+ flags &= ~SPLIT_REASON; /* no changes to the reason */
1266+
1267+ /* OK, now let's take a look at the action... */
1268+ if ((action == SPLIT_ACTIVATE && SplitIsActive(split)) ||
1269+ (action == SPLIT_DEACTIVATE && !SplitIsActive(split)) ||
1270+ /* can't activate an expired split entry */
1271+ (IRCD_MAX(split->sp_expire, expire) <= CurrentTime))
1272+ action = SPLIT_MODIFY; /* no activity state modifications */
1273+
1274+ Debug((DEBUG_DEBUG, "About to perform changes; flags 0x%04x, action %s",
1275+ flags, action == SPLIT_ACTIVATE ? "SPLIT_ACTIVATE" :
1276+ (action == SPLIT_DEACTIVATE ? "SPLIT_DEACTIVATE" :
1277+ (action == SPLIT_MODIFY ? "SPLIT_MODIFY" : "<UNKNOWN>"))));
1278+
1279+ /* If there are no changes to perform, do no changes */
1280+ if (!(flags & SPLIT_UPDATE) && action == SPLIT_MODIFY)
1281+ return 0;
1282+
1283+ /* Start by updating lastmod, if indicated... */
1284+ split->sp_lastmod = lastmod;
1285+
1286+ /* Then move on to activity status changes... */
1287+ switch (action) {
1288+ case SPLIT_ACTIVATE: /* activating split entry */
1289+ split->sp_flags |= SPLIT_ACTIVE; /* make it active... */
1290+ pos += ircd_snprintf(0, buf, sizeof(buf), " activating SPLIT");
1291+ break;
1292+
1293+ case SPLIT_DEACTIVATE: /* deactivating split entry */
1294+ split->sp_flags &= ~SPLIT_ACTIVE; /* make it inactive... */
1295+ pos += ircd_snprintf(0, buf, sizeof(buf), " deactivating SPLIT");
1296+ break;
1297+
1298+ case SPLIT_MODIFY: /* no change to activity status */
1299+ break;
1300+ }
1301+
1302+ /* Handle expiration changes... */
1303+ if (flags & SPLIT_EXPIRE) {
1304+ split->sp_expire = expire; /* save new expiration time */
1305+ if (pos < BUFSIZE)
1306+ pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
1307+ "%s%s changing expiration time to %Tu",
1308+ pos ? ";" : "",
1309+ pos && !(flags & (SPLIT_LIFETIME | SPLIT_REASON)) ?
1310+ " and" : "", expire);
1311+ }
1312+
1313+ /* Next, handle lifetime changes... */
1314+ if (flags & SPLIT_LIFETIME) {
1315+ split->sp_lifetime = lifetime; /* save new lifetime */
1316+ if (pos < BUFSIZE)
1317+ pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
1318+ "%s%s extending record lifetime to %Tu",
1319+ pos ? ";" : "", pos && !(flags & SPLIT_REASON) ?
1320+ " and" : "", lifetime);
1321+ }
1322+
1323+ /* Now, handle reason changes... */
1324+ if (flags & SPLIT_REASON) {
1325+ MyFree(split->sp_reason); /* release old reason */
1326+ DupString(split->sp_reason, reason); /* store new reason */
1327+ if (pos < BUFSIZE)
1328+ pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
1329+ "%s%s changing reason to \"%s\"",
1330+ pos ? ";" : "", pos ? " and" : "", reason);
1331+ }
1332+
65b70298 1333+ /* TODO: add opername */
12e82c05 1334+ /* All right, inform ops... */
1335+ sendto_opmask_butone(0, SNO_NETWORK, "%s modifying SPLIT for %s:%s",
1336+ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
1337+ cli_name(sptr) : cli_name((cli_user(sptr))->server),
1338+ split->sp_server, buf);
1339+
1340+ /* TODO: add SPLIT log stuff or use JUPE? */
1341+ /* and log the change */
1342+ log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
1343+ "%#C modifying SPLIT for %s:%s",
1344+ sptr, split->sp_server, buf);
1345+
1346+ /* and propagate it */
1347+ split_propagate(cptr, sptr, split, NULL);
1348+
1349+ return 0;
1350+}
1351+
1352+
1353+/** Remove a split entry.
1354+ * @param[in] cptr Local client that sent us the split entry.
1355+ * @param[in] sptr Originator of the split entry.
1356+ * @param[in] split Split entry to remove.
1357+ * @param[in] reason Reason for removing this split entry.
1358+ * @return Zero.
1359+ */
1360+int
1361+split_remove(struct Client *cptr, struct Client *sptr, struct Split *split, const char *reason)
1362+{
1363+ unsigned int saveflags = 0;
1364+
1365+ assert(0 != split);
1366+ assert(NULL != cptr);
1367+ assert(NULL != sptr);
1368+
1369+ Debug((DEBUG_DEBUG, "split_remove(\"%s\", \"%s\", \"%s\", \"%s\")",
1370+ cli_name(cptr), cli_name(sptr), split->sp_server, reason));
1371+
1372+ /* deactivate entry and mark it for removal (used in split_propagate) */
1373+ split->sp_flags |= SPLIT_REMOVING;
1374+ /* CHECK: turn bit SPLIT_ACTIVE off? */
1375+ split->sp_flags |= SPLIT_ACTIVE;
1376+
65b70298 1377+ /* TODO: add opername? */
12e82c05 1378+ /* inform ops and log it */
1379+ sendto_opmask_butone(0, SNO_NETWORK, "%s removing SPLIT for %s, expiring at %Tu: %s (%s)",
1380+ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
1381+ cli_name(sptr) : cli_name((cli_user(sptr))->server),
1382+ split->sp_server, split->sp_expire, split->sp_reason, reason);
1383+
1384+ /* TODO: add SPLIT log stuff or use JUPE? */
1385+ log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
1386+ "%#C removing SPLIT for %s, expiring at %Tu: %s (%s)",
1387+ sptr, split->sp_server, split->sp_expire, split->sp_reason, reason);
1388+
12e82c05 1389+ /* propagate it */
1390+ split_propagate(cptr, sptr, split, reason);
1391+
1392+ /* destroy it */
1393+ split_free(split);
1394+
1395+ return 0;
1396+}
1397+
1398+
1399+/** Find a split entry by name.
1400+ * @param[in] server Split entry name to search for.
1401+ * @return Matching split entry (or NULL if none match).
1402+ */
1403+struct Split *
1404+split_find(char *server)
1405+{
1406+ struct Split* split;
1407+ struct Split* ssplit;
1408+
1409+ for (split = GlobalSplitList; split; split = ssplit) { /* go through splits */
1410+ ssplit = split->sp_next;
1411+
1412+ if (split_expire(split)) /* expire any that need expiring */
1413+ split_free(split);
1414+ else if (0 == ircd_strcmp(server, split->sp_server)) /* found it yet? */
1415+ return split;
1416+ }
1417+ /* TODO: we return 0 not NULL? */
1418+ return 0;
1419+}
1420+
1421+/** Unlink and free an unused split entry.
1422+ * @param[in] split Server split entry to free.
1423+ */
1424+void
1425+split_free(struct Split* split)
1426+{
1427+ /* TODO: use 0 or NULL ? */
1428+ assert(0 != split);
1429+
1430+ *split->sp_prev_p = split->sp_next; /* squeeze this split entry out */
1431+ if (split->sp_next)
1432+ split->sp_next->sp_prev_p = split->sp_prev_p;
1433+
1434+ /* CHECK: the other fields in this struct are destroyed with MyFree() call? */
1435+ MyFree(split->sp_server); /* and free up the memory */
1436+ MyFree(split->sp_reason);
1437+ MyFree(split);
1438+}
1439+
1440+
1441+/** Check whether a split entry has past its life time.
1442+ * when entry is active and past expire time, but not life time, deactivate it
1443+ * @param[in] split Server split entry to check.
1444+ * @return 1 when entry can be free'd, 0 otherwise.
1445+ */
1446+int
1447+split_expire(struct Split* split)
1448+{
1449+ assert(0 != split);
1450+
65b70298 1451+ /* TODO: also check if the server in SPLIT entry is linked atm? */
12e82c05 1452+ /* past lifetime */
1453+ if (split->sp_lifetime <= CurrentTime)
1454+ return 1;
1455+
1456+ /* past expire time, deactivate entry if it is active */
1457+ if ((split->sp_expire <= CurrentTime) && SplitIsActive(split))
1458+ /* CHECK: turn bit SPLIT_ACTIVE off */
1459+ split->sp_flags &= SPLIT_ACTIVE;
1460+
1461+ return 0;
1462+}
1463+
1464+/** Send the full list of split entries to \a cptr.
1465+ * @param[in] cptr Local server to send split entries to.
1466+ */
1467+void
1468+split_burst(struct Client *cptr)
1469+{
1470+ struct Split *split;
1471+ struct Split *ssplit;
1472+
1473+ assert(NULL != cptr);
1474+
1475+ for (split = GlobalSplitList; split; split = ssplit) { /* go through splits */
1476+ ssplit = split->sp_next;
1477+
1478+ /* expire any that need expiring */
1479+ if (split_expire(split))
1480+ split_free(split);
1481+ /* if we have an entry for cptr, dont send it - but do not free here yet
1482+ * free it at end of burst, to get the correct count for SPLITs removed.
1483+ */
1484+ else if (ircd_strcmp(split->sp_server, cli_name(cptr)) == 0)
1485+ continue;
1486+ else
1487+ sendcmdto_one(&me, CMD_SPLIT, cptr, "%c%s %Tu %Tu %Tu %Tu :%s",
1488+ SplitIsActive(split) ? '+' : '-', split->sp_server,
1489+ split->sp_creation, split->sp_expire,
1490+ split->sp_lastmod, split->sp_lifetime,
1491+ split->sp_reason);
1492+ }
1493+}
1494+
1495+/** Forward a split to another server.
1496+ * @param[in] cptr Server to send split entries to.
1497+ * @param[in] split Split to forward.
1498+ * @return Zero.
1499+ */
1500+int
1501+split_resend(struct Client *cptr, struct Split *split)
1502+{
1503+ sendcmdto_one(&me, CMD_SPLIT, cptr, "%c%s %Tu %Tu %Tu %Tu :%s",
1504+ SplitIsActive(split) ? '+' : '-', split->sp_server,
1505+ split->sp_creation, split->sp_expire,
1506+ split->sp_lastmod, split->sp_lifetime,
1507+ split->sp_reason);
1508+
1509+ return 0;
1510+}
1511+
1512+/** Send a split entry (or a list of split entries) to a server.
1513+ * @param[in] sptr Client searching for split entries.
1514+ * @param[in] server Name of split entry to search for (if NULL, list all).
1515+ * @return Zero.
1516+ */
1517+int
1518+split_list(struct Client *sptr, char *server)
1519+{
1520+ struct Split *split;
1521+ struct Split *ssplit;
1522+
1523+ assert(NULL != sptr);
1524+
1525+ /* TODO: wildcard matching? */
1526+ if (server) {
1527+ if (!(split = split_find(server))) /* no such split */
1528+ return send_reply(sptr, ERR_NOSUCHSPLIT, server);
1529+
1530+ /* send split information along */
1531+ send_reply(sptr, RPL_SPLITLIST, split->sp_server,
1532+ split->sp_creation, split->sp_expire,
1533+ split->sp_lastmod, split->sp_lifetime,
1534+ SplitIsActive(split) ? '+' : '-', split->sp_reason);
1535+ } else {
1536+ for (split = GlobalSplitList; split; split = ssplit) { /* go through splits */
1537+ ssplit = split->sp_next;
1538+
1539+ if (split_expire(split)) /* expire any that need expiring */
1540+ split_free(split);
1541+ else /* send split information along */
1542+ send_reply(sptr, RPL_SPLITLIST, split->sp_server,
1543+ split->sp_creation, split->sp_expire,
1544+ split->sp_lastmod, split->sp_lifetime,
1545+ SplitIsActive(split) ? '+' : '-', split->sp_reason);
1546+ }
1547+ }
1548+
1549+ /* end of splitlist information */
1550+ return send_reply(sptr, RPL_ENDOFSPLITLIST);
1551+}
1552+
1553+
1554+/** Auto destroy SPLITs for servers gained in a netmerge
1555+ * @param[in] cptr Server that link to the network
1556+ * @return Number of destroyed SPLITs
1557+ */
1558+int
1559+split_merge(struct Client *server)
1560+{
1561+ struct DLink *lp;
1562+ struct Split *split;
1563+ int count = 0;
1564+
1565+ assert(NULL != server);
1566+
1567+ Debug((DEBUG_DEBUG, "split_merge(\"%s\")", cli_name(server)));
1568+
1569+ /* find the SPLIT for this server */
1570+ if ((split = split_find(cli_name(server)))) {
1571+ split_free(split);
1572+ count++;
1573+ }
1574+
1575+ /* go over its downlinks */
1576+ for (lp = cli_serv(server)->down; lp; lp = lp->next)
1577+ count += split_merge(lp->value.cptr);
1578+ return count;
1579+}
1580+
1581+
1582+/** Auto create SPLITs for servers lost in a netbreak
1583+ * @param[in] server Server that lost link to network
1584+ * @param[in] reason Reason to add to SPLITs
1585+ * @return Number of created SPLITs
1586+ */
1587+int
1588+split_break(struct Client *server, const char *reason)
1589+{
1590+ struct DLink *lp;
1591+ struct Split *split;
1592+ int count = 0;
65b70298 1593+ time_t creation = CurrentTime, expire = CurrentTime + feature_int(FEAT_SPLIT_AUTO_EXPIRE),
12e82c05 1594+ lastmod = CurrentTime, lifetime = expire;
1595+ unsigned int flags = SPLIT_ACTIVE;
1596+
1597+ assert(NULL != server);
1598+
1599+ Debug((DEBUG_DEBUG, "split_break(\"%s\", \"%s\")", cli_name(server), reason));
1600+
65b70298 1601+ /* bad auto expire value */
1602+ if (feature_int(FEAT_SPLIT_AUTO_EXPIRE) <= 0)
1603+ return 0;
1604+
12e82c05 1605+ /* find the SPLIT for this server */
1606+ if (!(split = split_find(cli_name(server)))) {
1607+ split_make(cli_name(server), reason, creation, expire, lastmod, lifetime, flags);
1608+ count++;
1609+ }
1610+
1611+ /* go over its downlinks */
1612+ for (lp = cli_serv(server)->down; lp; lp = lp->next)
1613+ count += split_break(lp->value.cptr, reason);
1614+ return count;
1615+}
1616+
1617+
1618+/** Auto create SPLITs for servers we have a Connect Block for
1619+ *
1620+ */
1621+void
1622+split_conf()
1623+{
1624+ struct ConfItem *conf;
1625+ struct Client *server;
1626+ struct Split *split;
1627+ struct Split *asplit;
65b70298 1628+ time_t creation = CurrentTime, expire = CurrentTime + feature_int(FEAT_SPLIT_AUTO_EXPIRE),
12e82c05 1629+ lastmod = CurrentTime, lifetime = expire;
1630+ unsigned int flags = SPLIT_ACTIVE;
1631+ char reason[BUFSIZE];
1632+
1633+ Debug((DEBUG_DEBUG, "split_conf()"));
1634+
1635+ /* we are not set to generate SPLITs */
1636+ if (!feature_bool(FEAT_SPLIT))
1637+ return;
1638+
65b70298 1639+ /* bad auto expire value */
1640+ if (feature_int(FEAT_SPLIT_AUTO_EXPIRE) <= 0)
1641+ return;
1642+
12e82c05 1643+ ircd_snprintf(0, reason, sizeof(reason),
1644+ "Generated upon loading conf file on %s", cli_name(&me));
1645+
1646+ /* go over the conf contents */
1647+ for (conf = GlobalConfList; conf; conf = conf->next) {
1648+ /* not a Connect Block */
1649+ if (CONF_SERVER != conf->status)
1650+ continue;
1651+ /* server is linked */
1652+ if (server = FindServer(conf->name))
1653+ continue;
1654+ /* we have a SPLIT for this server already */
1655+ if (split = split_find(conf->name))
1656+ continue;
65b70298 1657+ /* TODO: use SNO_OLDSNO here?
1658+ * just like nickcollisions on local users go there?
1659+ * or at least change the source / message format?
1660+ * /REHASH goes to SNO_OLDSNO? so this too?
1661+ * if oper did rehash, add his name here?
1662+ */
12e82c05 1663+ /* inform ops and log it */
1664+ sendto_opmask_butone(0, SNO_NETWORK, "%C adding SPLIT for %s, expiring at %Tu: %s",
1665+ &me, conf->name, expire, reason);
1666+
1667+ /* TODO: add SPLIT log stuff or use JUPE? */
1668+ log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
1669+ "%C adding SPLIT for %s, expiring at %Tu: %s",
1670+ &me, conf->name, expire, reason);
1671+
1672+ /* make the split entry */
1673+ asplit = split_make(conf->name, reason, creation, expire, lastmod, lifetime, flags);
1674+
1675+ assert(asplit);
1676+
1677+ /* and propagate it */
1678+ split_propagate(&me, &me, asplit, NULL);
1679+ }
1680+}
1681+
1682+
1683+/** Statistics callback to list SPLITs.
1684+ * @param[in] sptr Client requesting statistics.
1685+ * @param[in] sd Stats descriptor for request (ignored).
1686+ * @param[in] param Extra parameter from user (ignored).
1687+ */
1688+void
1689+split_stats(struct Client *sptr, const struct StatDesc *sd,
1690+ char *param)
1691+{
1692+ struct Split *split;
1693+ struct Split *ssplit;
1694+
65b70298 1695+ /* send header so the client knows what we are showing */
1696+ send_reply(sptr, SND_EXPLICIT | RPL_STATSHEADER,
1697+ "S Server Creation Expire Lastmod Lifetime Status :Reason");
1698+
12e82c05 1699+ for (split = GlobalSplitList; split; split = split->sp_next)
1700+ send_reply(sptr, RPL_STATSSPLIT, split->sp_server,
1701+ split->sp_creation, split->sp_expire, split->sp_lastmod, split->sp_lifetime,
1702+ SplitIsActive(split) ? '+' : '-', split->sp_reason);
1703+}
1704+
1705+
1706+/** Count split entries and memory used by them.
1707+ * @param[out] sp_size Receives total number of bytes allocated for split entries.
1708+ * @return Number of split entries currently allocated.
1709+ */
1710+int
1711+split_memory_count(size_t *sp_size)
1712+{
1713+ struct Split *split;
1714+ unsigned int sp = 0;
1715+
1716+ /* TODO: check for expired entries? */
1717+ for (split = GlobalSplitList; split; split = split->sp_next)
1718+ {
1719+ sp++;
1720+ *sp_size += sizeof(struct Split);
1721+ *sp_size += split->sp_server ? (strlen(split->sp_server) + 1) : 0;
1722+ *sp_size += split->sp_reason ? (strlen(split->sp_reason) + 1) : 0;
1723+ }
1724+ return sp;
1725+}
1726+