2 Add split functionality into ircd
4 Add /stats S/split (make /STATS s/S case sensitive, s spoofhosts)
6 Add split.c split.h m_split.c
8 NOTE: feature SPLIT is default enabled as that is just easier when working on this patch.
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
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*[]);
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*[]);
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
46 + FEAT_SPLIT_AUTO_EXPIRE,
48 /* HEAD_IN_SAND Features */
50 FEAT_HIS_SNOTICES_OPER_ONLY,
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
64 #define CMD_JUPE MSG_JUPE, TOK_JUPE
66 +#define MSG_SPLIT "SPLIT" /* SPLIT */
67 +#define TOK_SPLIT "SP"
68 +#define CMD_SPLIT MSG_SPLIT, TOK_SPLIT
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
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 */
83 /* RPL_SERVICEINFO 231 unused */
85 #define RPL_STATSDLINE 275 /* Undernet extension */
86 #define RPL_STATSRLINE 276 /* Undernet extension */
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 */
94 /* ERR_GHOSTEDCLIENT 503 efnet */
95 /* ERR_VWORLDWARN 503 austnet */
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
105 +/* TODO: ifndef ? */
106 +#ifndef INCLUDED_jupe_h
107 +#define INCLUDED_jupe_h
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>
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.
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.
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.
129 + * @brief Interface and declarations for split server handling.
130 + * @version $Id: jupe.h 1208 2004-10-03 14:12:35Z entrope $
132 +/* TODO: ifndef ? */
133 +#ifndef INCLUDED_sys_types_h
134 +#include <sys/types.h>
135 +#define INCLUDED_sys_types_h
142 +#define SPLIT_MAX_EXPIRE 2419200 /**< Maximum split expiration time (4 weeks). */
144 +/* Describes a SPLIT server entry. */
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. */
157 +/** Split state flags. */
158 +#define SPLIT_ACTIVE 0x0001 /**< Split is active. */
159 +#define SPLIT_REMOVING 0x0002 /**< Split is about to be destroyed. */
161 +/* TODO: these ; after } needed ? */
162 +/* Actions to perform on a SPLIT. */
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. */
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. */
178 +/* mask for Split update flags. */
179 +#define SPLIT_UPDATE (SPLIT_EXPIRE | SPLIT_LIFETIME | SPLIT_REASON)
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)
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)
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);
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);
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
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 \
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
295 #include "userload.h"
297 Debug((DEBUG_NOTICE, "Server ready..."));
298 log_write(LS_SYSTEM, L_NOTICE, 0, "Server Ready");
300 + /* create SPLITs */
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
310 F_B(SETHOST_USER, 0, 0, 0),
311 F_B(SETHOST_AUTO, 0, 0, 0),
314 + F_B(SPLIT, 0, 1, 0),
315 + F_I(SPLIT_AUTO_EXPIRE, 0, 604800, 0),
317 /* HEAD_IN_SAND Features */
318 F_B(HIS_SNOTICES, 0, 1, 0),
319 F_B(HIS_SNOTICES_OPER_ONLY, 0, 1, 0),
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
335 +#include "ircd_features.h"
336 #include "ircd_log.h"
337 #include "ircd_reply.h"
338 #include "ircd_string.h"
341 #include "numnicks.h"
345 /* #include <assert.h> -- Now using assert in ircd_log.h */
348 int ms_end_of_burst(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
350 struct Channel *chan, *next_chan;
356 dump_map(sptr, "*", 0, report_new_links, 0);
357 sendto_opmask_butone(0, SNO_NETWORK, "Completed net.burst from %C.",
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);
364 sendcmdto_one(&me, CMD_END_OF_BURST_ACK, sptr, "");
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
370 #include "ircd_snprintf.h"
375 /* #include <assert.h> -- Now using assert in ircd_log.h */
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
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>
398 + * See file AUTHORS in IRC package for additional names of
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.
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.
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.
415 + * $Id: m_split.c 1737 2006-12-19 05:20:48Z entrope $
419 + * m_functions execute protocol messages on this server:
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...).
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.
431 + * (!IsServer(cptr)) => (cptr == sptr), because
432 + * prefixes are taken *only* from servers...
435 + * (sptr == cptr) => the message didn't
438 + * (sptr != cptr && IsServer(sptr) means
439 + * the prefix specified servername. (?)
441 + * (sptr != cptr && !IsServer(sptr) means
442 + * that message originated from a remote
443 + * user (not local).
447 + * (!IsServer(sptr)) means that, sptr can safely
448 + * taken as defining the target structure of the
449 + * message in this server.
451 + * *Always* true (if 'parse' and others are working correct):
453 + * 1) sptr->from == cptr (note: cptr->from == cptr)
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 ]
460 + * parc number of variable parameter strings (if zero,
461 + * parv is allowed to be NULL)
463 + * parv a NULL terminated list of parameter pointers,
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*
471 + * note: it is guaranteed that parv[0]..parv[parc-1] are all
472 + * non-NULL pointers.
480 +#include "ircd_features.h"
481 +#include "ircd_log.h"
482 +#include "ircd_reply.h"
483 +#include "ircd_string.h"
486 +#include "numeric.h"
487 +#include "numnicks.h"
489 +#include "s_debug.h"
493 +/* #include <assert.h> -- Now using assert in ircd_log.h */
498 + * ms_split - server message handler
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
509 +int ms_split(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
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";
519 + /* TODO: perhaps make some fields optional? reason? */
521 + return need_more_params(sptr, "SPLIT");
523 + if (*server == '!') {
525 + action = SPLIT_REMOVE; /* removing entry */
528 + switch (*server) { /* handle + and - */
529 + case '+': /* activate the split entry */
530 + if (action != SPLIT_REMOVE)
531 + action = SPLIT_ACTIVATE;
535 + case '-': /* deactivate the entry */
536 + if (action != SPLIT_REMOVE)
537 + action = SPLIT_DEACTIVATE;
542 + /* Next, try to find the split entry... */
543 + asplit = split_find(server);
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.
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;
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];
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"));
569 + /* OK, at this point, we have converted all available parameters.
570 + * Let's actually do the action!
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);
579 + assert(action != SPLIT_MODIFY);
581 + return split_add(cptr, sptr, server, reason, creation, expire, lastmod, lifetime,
582 + flags | ((action == SPLIT_ACTIVATE) ? SPLIT_ACTIVE : 0));
587 + * mo_split - oper message handler
589 + * Local listing: 1 or 2 params
590 + * parv[0] = Send prefix
591 + * parv[1] = [Server or mask to match]
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)
600 +int mo_split(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
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;
611 + if (!HasPriv(sptr, PRIV_ROUTEINFO))
612 + return send_reply(sptr, ERR_NOPRIVILEGES);
614 + return split_list(sptr, 0);
617 + if (*server == '!') {
619 + action = SPLIT_REMOVE; /* force removal */
622 + switch (*server) { /* handle + and - */
623 + case '+': /* activate the split entry */
624 + if (action != SPLIT_REMOVE)
625 + action = SPLIT_ACTIVATE;
629 + case '-': /* deactivate the split entry */
630 + if (action != SPLIT_REMOVE)
631 + action = SPLIT_DEACTIVATE;
636 + /* OK, let's figure out the parameters... */
638 + /* no specific action */
640 + /* user wants a listing of a specific SPLIT */
642 + return split_list(sptr, server);
643 + expire = strtol(parv[2], &end, 10) + CurrentTime; /* and the expiration */
645 + return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE,
646 + "%s :Bad expire time", parv[2]);
648 + flags |= SPLIT_EXPIRE; /* remember that we got an expire time */
650 + if (parc > 3) { /* also got a reason... */
651 + reason = parv[parc - 1];
652 + flags |= SPLIT_REASON;
656 + case SPLIT_REMOVE: /* TODO: require reason for this, but not expire? */
658 + return need_more_params(sptr, "SPLIT");
659 + reason = parv[parc - 1];
660 + flags |= SPLIT_REASON;
663 + case SPLIT_ACTIVATE: /* TODO: require expire and reason when new */
665 + expire = strtol(parv[2], &end, 10) + CurrentTime; /* and the expiration */
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 */
672 + if (parc > 3) { /* also got a reason... */
673 + reason = parv[parc - 1];
674 + flags |= SPLIT_REASON;
678 + case SPLIT_DEACTIVATE: /* TODO: duplicate code? must be a cleaner way */
680 + expire = strtol(parv[2], &end, 10) + CurrentTime; /* and the expiration */
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 */
687 + if (parc > 3) { /* also got a reason... */
688 + reason = parv[parc - 1];
689 + flags |= SPLIT_REASON;
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);
701 + /* Next, try to find the SPLIT... */
702 + asplit = split_find(server);
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.
708 + /* SPLIT not found and thus we:
709 + * cannot remove SPLIT we do not have
710 + * cannot add new SPLIT without expire and reason
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);
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;
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" : ""));
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);
740 + assert(action != SPLIT_MODIFY);
741 + assert(action != SPLIT_REMOVE);
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));
750 + * m_split - user message handler
752 + * parv[0] = Send prefix
756 + * parv[1] = [<server name>]
759 +int m_split(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
762 + return split_list(sptr, 0);
764 + return split_list(sptr, parv[1]);
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
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 }
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 }
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
794 @@ -1005,6 +1006,7 @@
797 attach_conf_uworld(&me);
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
814 aw = 0, /* aways set */
815 wwa = 0, /* whowas aways */
817 - ju = 0; /* jupes */
818 + ju = 0, /* jupes */
819 + sp = 0; /* split entries */
821 size_t chm = 0, /* memory used by channels */
822 chbm = 0, /* memory used by channel bans */
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 */
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);
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
847 { RPL_STATSQLINE, "Q %s :%s", "228" },
850 + { RPL_STATSSPLIT, "S %s %d %d %d %d %c :%s", "229" },
852 { RPL_STATSHEADER, 0, "230" },
859 + { RPL_SPLITLIST, "%s %Tu %Tu %Tu %Tu %c :%s", "278" },
862 + { RPL_ENDOFSPLITLIST, ":End of Split List", "279" },
864 { RPL_GLIST, "%s%s%s%s%s %Tu %Tu %Tu %s %s%s%c :%s", "280" },
866 @@ -1052,7 +1052,7 @@
871 + { ERR_NOSUCHSPLIT, "%s :No such split", "510" },
873 { ERR_SILELISTFULL, "%s :Your silence list is full", "511" },
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
889 char comment1[HOSTLEN + HOSTLEN + 2];
890 + char splitreason[BUFSIZE];
892 if (MyConnect(victim))
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));
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
920 #include "userload.h"
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
938 #include "userload.h"
942 "System resource usage (Debug only)." },
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,
947 + "Server SPLITs information."},
948 + { 's', "spoofhosts", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_s,
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
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>
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.
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.
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.
977 + * @brief Implementation of split server handling functions.
978 + * @version $Id: split.c 1633 2006-03-25 03:46:56Z entrope $
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"
994 +#include "numeric.h"
995 +#include "numnicks.h"
998 +#include "s_debug.h"
1001 +#include "struct.h"
1002 +#include "sys.h" /* FALSE bleah */
1004 +/* #include <assert.h> -- Now using assert in ircd_log.h */
1005 +#include <string.h>
1007 +/** List of split entries. */
1008 +static struct Split *GlobalSplitList = 0;
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.
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)
1024 + struct Split *asplit;
1026 + asplit = (struct Split*) MyMalloc(sizeof(struct Split)); /* alloc memory */
1027 + assert(0 != asplit);
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 */
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;
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)
1061 +split_propagate(struct Client *cptr, struct Client *sptr,
1062 + struct Split *split, const char *reason)
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);
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.
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)
1089 + /* TODO: check for proper masks - at least one dot and no wildcards? */
1090 + struct Split *asplit;
1091 + struct Client *acptr;
1093 + assert(0 != server);
1094 + assert(0 != reason);
1095 + assert(NULL != cptr);
1096 + assert(NULL != sptr);
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));
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
1107 + if ((acptr = FindServer(server))) {
1109 + sendcmdto_one(&me, CMD_NOTICE, sptr,
1110 + "%C :Cannot add SPLIT %s - server is linked.", sptr, server);
1115 + * You cannot set a negative (or zero) duration, nor can you set an
1116 + * duration greater than SPLIT_MAX_EXPIRE.
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?
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?
1133 + * no no no! - see above
1135 + /* TODO: raise error with timestamps to SNO_OLDSNO?
1137 + * Nick collision on nick (nick 1232368192 <- hub.xx.quakenet.org 1232368192 (Same user@host))
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);
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);
1156 + /* make the split entry */
1157 + asplit = split_make(server, reason, creation, expire, lastmod, lifetime, flags);
1161 + /* and propagate it */
1162 + split_propagate(cptr, sptr, asplit, NULL);
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.
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)
1186 + struct Client* acptr;
1187 + char buf[BUFSIZE];
1191 + assert(NULL != cptr);
1192 + assert(NULL != sptr);
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));
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.
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.
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
1213 + * IsBurst() is that true for only that single server or for all its downlinks?
1214 + * I would guess single server only.. argh!
1216 + if ((acptr = FindServer(split->sp_server))) {
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 */
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... */
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? */
1243 + flags |= SPLIT_EXPIRE;
1245 + flags &= ~SPLIT_EXPIRE;
1247 + /* Next, check out lifetime */
1248 + if (!(flags & SPLIT_LIFETIME) || !lifetime)
1249 + lifetime = split->sp_lifetime; /* use Split lifetime */
1251 + lifetime = IRCD_MAX(lifetime, expire); /* set lifetime to the max */
1253 + /* OK, let's see which is greater... */
1254 + if (lifetime > split->sp_lifetime)
1255 + flags |= SPLIT_LIFETIME; /* have to update lifetime */
1257 + flags &= ~SPLIT_LIFETIME; /* no change to lifetime */
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 */
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 */
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>"))));
1279 + /* If there are no changes to perform, do no changes */
1280 + if (!(flags & SPLIT_UPDATE) && action == SPLIT_MODIFY)
1283 + /* Start by updating lastmod, if indicated... */
1284 + split->sp_lastmod = lastmod;
1286 + /* Then move on to activity status changes... */
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");
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");
1298 + case SPLIT_MODIFY: /* no change to activity status */
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",
1309 + pos && !(flags & (SPLIT_LIFETIME | SPLIT_REASON)) ?
1310 + " and" : "", expire);
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);
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);
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);
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);
1346 + /* and propagate it */
1347 + split_propagate(cptr, sptr, split, NULL);
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.
1361 +split_remove(struct Client *cptr, struct Client *sptr, struct Split *split, const char *reason)
1363 + unsigned int saveflags = 0;
1365 + assert(0 != split);
1366 + assert(NULL != cptr);
1367 + assert(NULL != sptr);
1369 + Debug((DEBUG_DEBUG, "split_remove(\"%s\", \"%s\", \"%s\", \"%s\")",
1370 + cli_name(cptr), cli_name(sptr), split->sp_server, reason));
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;
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);
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);
1389 + /* propagate it */
1390 + split_propagate(cptr, sptr, split, reason);
1393 + split_free(split);
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).
1404 +split_find(char *server)
1406 + struct Split* split;
1407 + struct Split* ssplit;
1409 + for (split = GlobalSplitList; split; split = ssplit) { /* go through splits */
1410 + ssplit = split->sp_next;
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? */
1417 + /* TODO: we return 0 not NULL? */
1421 +/** Unlink and free an unused split entry.
1422 + * @param[in] split Server split entry to free.
1425 +split_free(struct Split* split)
1427 + /* TODO: use 0 or NULL ? */
1428 + assert(0 != split);
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;
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);
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.
1447 +split_expire(struct Split* split)
1449 + assert(0 != split);
1451 + /* TODO: also check if the server in SPLIT entry is linked atm? */
1452 + /* past lifetime */
1453 + if (split->sp_lifetime <= CurrentTime)
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;
1464 +/** Send the full list of split entries to \a cptr.
1465 + * @param[in] cptr Local server to send split entries to.
1468 +split_burst(struct Client *cptr)
1470 + struct Split *split;
1471 + struct Split *ssplit;
1473 + assert(NULL != cptr);
1475 + for (split = GlobalSplitList; split; split = ssplit) { /* go through splits */
1476 + ssplit = split->sp_next;
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.
1484 + else if (ircd_strcmp(split->sp_server, cli_name(cptr)) == 0)
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);
1495 +/** Forward a split to another server.
1496 + * @param[in] cptr Server to send split entries to.
1497 + * @param[in] split Split to forward.
1501 +split_resend(struct Client *cptr, struct Split *split)
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);
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).
1518 +split_list(struct Client *sptr, char *server)
1520 + struct Split *split;
1521 + struct Split *ssplit;
1523 + assert(NULL != sptr);
1525 + /* TODO: wildcard matching? */
1527 + if (!(split = split_find(server))) /* no such split */
1528 + return send_reply(sptr, ERR_NOSUCHSPLIT, server);
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);
1536 + for (split = GlobalSplitList; split; split = ssplit) { /* go through splits */
1537 + ssplit = split->sp_next;
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);
1549 + /* end of splitlist information */
1550 + return send_reply(sptr, RPL_ENDOFSPLITLIST);
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
1559 +split_merge(struct Client *server)
1562 + struct Split *split;
1565 + assert(NULL != server);
1567 + Debug((DEBUG_DEBUG, "split_merge(\"%s\")", cli_name(server)));
1569 + /* find the SPLIT for this server */
1570 + if ((split = split_find(cli_name(server)))) {
1571 + split_free(split);
1575 + /* go over its downlinks */
1576 + for (lp = cli_serv(server)->down; lp; lp = lp->next)
1577 + count += split_merge(lp->value.cptr);
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
1588 +split_break(struct Client *server, const char *reason)
1591 + struct Split *split;
1593 + time_t creation = CurrentTime, expire = CurrentTime + feature_int(FEAT_SPLIT_AUTO_EXPIRE),
1594 + lastmod = CurrentTime, lifetime = expire;
1595 + unsigned int flags = SPLIT_ACTIVE;
1597 + assert(NULL != server);
1599 + Debug((DEBUG_DEBUG, "split_break(\"%s\", \"%s\")", cli_name(server), reason));
1601 + /* bad auto expire value */
1602 + if (feature_int(FEAT_SPLIT_AUTO_EXPIRE) <= 0)
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);
1611 + /* go over its downlinks */
1612 + for (lp = cli_serv(server)->down; lp; lp = lp->next)
1613 + count += split_break(lp->value.cptr, reason);
1618 +/** Auto create SPLITs for servers we have a Connect Block for
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];
1633 + Debug((DEBUG_DEBUG, "split_conf()"));
1635 + /* we are not set to generate SPLITs */
1636 + if (!feature_bool(FEAT_SPLIT))
1639 + /* bad auto expire value */
1640 + if (feature_int(FEAT_SPLIT_AUTO_EXPIRE) <= 0)
1643 + ircd_snprintf(0, reason, sizeof(reason),
1644 + "Generated upon loading conf file on %s", cli_name(&me));
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)
1651 + /* server is linked */
1652 + if (server = FindServer(conf->name))
1654 + /* we have a SPLIT for this server already */
1655 + if (split = split_find(conf->name))
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?
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);
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);
1672 + /* make the split entry */
1673 + asplit = split_make(conf->name, reason, creation, expire, lastmod, lifetime, flags);
1677 + /* and propagate it */
1678 + split_propagate(&me, &me, asplit, NULL);
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).
1689 +split_stats(struct Client *sptr, const struct StatDesc *sd,
1692 + struct Split *split;
1693 + struct Split *ssplit;
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");
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);
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.
1711 +split_memory_count(size_t *sp_size)
1713 + struct Split *split;
1714 + unsigned int sp = 0;
1716 + /* TODO: check for expired entries? */
1717 + for (split = GlobalSplitList; split; split = split->sp_next)
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;