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