]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blob - split.patch
done some work on cansendtochan.patch, added nserverflag.patch, and probably some...
[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 NOTE: feature SPLIT is default enabled as that is just easier when working on this patch.
9
10 diff -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
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*[]);
37 diff -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
40 @@ -110,6 +110,10 @@
41 FEAT_SETHOST_USER,
42 FEAT_SETHOST_AUTO,
43
44 + /* SPLIT */
45 + FEAT_SPLIT,
46 + FEAT_SPLIT_AUTO_EXPIRE,
47 +
48 /* HEAD_IN_SAND Features */
49 FEAT_HIS_SNOTICES,
50 FEAT_HIS_SNOTICES_OPER_ONLY,
51 @@ -137,6 +141,7 @@
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,
59 diff -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
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
73 diff -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
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 */
81 #define RPL_STATSHEADER 230 /* QuakeNet extension */
82
83 /* RPL_SERVICEINFO 231 unused */
84 @@ -178,6 +179,8 @@
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 */
93 @@ -441,6 +444,7 @@
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 */
101 diff -r bc3532fbd97a include/split.h
102 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
103 +++ b/include/split.h Tue Jan 20 17:25:53 2009 +0100
104 @@ -0,0 +1,120 @@
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 +
142 +#define SPLIT_MAX_EXPIRE 2419200 /**< Maximum split expiration time (4 weeks). */
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 */
225 diff -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
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 \
285 diff -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
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;
306 diff -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
309 @@ -364,6 +364,10 @@
310 F_B(SETHOST_USER, 0, 0, 0),
311 F_B(SETHOST_AUTO, 0, 0, 0),
312
313 + /* SPLIT */
314 + F_B(SPLIT, 0, 1, 0),
315 + F_I(SPLIT_AUTO_EXPIRE, 0, 604800, 0),
316 +
317 /* HEAD_IN_SAND Features */
318 F_B(HIS_SNOTICES, 0, 1, 0),
319 F_B(HIS_SNOTICES_OPER_ONLY, 0, 1, 0),
320 @@ -391,6 +395,7 @@
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),
328 diff -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
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
366 diff -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
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 }
388 diff -r bc3532fbd97a ircd/m_split.c
389 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
390 +++ b/ircd/m_split.c Tue Jan 20 17:25:53 2009 +0100
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 +}
766 diff -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
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,
783 diff -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
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 }
802 diff -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
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,
842 diff -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
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 */
852 { RPL_STATSHEADER, 0, "230" },
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 */
864 { RPL_GLIST, "%s%s%s%s%s %Tu %Tu %Tu %s %s%s%c :%s", "280" },
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 */
875 diff -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
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 {
894 @@ -497,6 +499,15 @@
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)) {
899 + /* TODO: remote & local SQUIT ? servername oper is on? */
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 /*
910 diff -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
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
929 diff -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
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
940 @@ -668,7 +669,10 @@
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,
952 diff -r bc3532fbd97a ircd/split.c
953 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
954 +++ b/ircd/split.c Tue Jan 20 17:25:53 2009 +0100
955 @@ -0,0 +1,771 @@
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? */
1033 + /* TODO: prefix the reason here with the opername/ID? */
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. */
1039 + /* TODO: TStime() is CurrentTime + TSoffset */
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,
1069 + /* TODO: does reason ? reason : split->sp_reason work too? */
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 + */
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 + */
1139 + return 0;
1140 + }
1141 +
1142 + /* TODO: add opername */
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.
1207 + * also more than one server can be bursting at a time.
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 +
1333 + /* TODO: add opername */
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 +
1377 + /* TODO: add opername? */
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 +
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 +
1451 + /* TODO: also check if the server in SPLIT entry is linked atm? */
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;
1593 + time_t creation = CurrentTime, expire = CurrentTime + feature_int(FEAT_SPLIT_AUTO_EXPIRE),
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 +
1601 + /* bad auto expire value */
1602 + if (feature_int(FEAT_SPLIT_AUTO_EXPIRE) <= 0)
1603 + return 0;
1604 +
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;
1628 + time_t creation = CurrentTime, expire = CurrentTime + feature_int(FEAT_SPLIT_AUTO_EXPIRE),
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 +
1639 + /* bad auto expire value */
1640 + if (feature_int(FEAT_SPLIT_AUTO_EXPIRE) <= 0)
1641 + return;
1642 +
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;
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 + */
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 +
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 +
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 +