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 diff -r 2da61ac38fa1 include/handlers.h
9 --- a/include/handlers.h Sun Jan 18 14:18:36 2009 +0100
10 +++ b/include/handlers.h Sun Jan 18 15:26:56 2009 +0100
12 extern int m_registered(struct Client*, struct Client*, int, char*[]);
13 extern int m_sethost(struct Client*, struct Client*, int, char*[]);
14 extern int m_silence(struct Client*, struct Client*, int, char*[]);
15 +extern int m_split(struct Client*, struct Client*, int, char*[]);
16 extern int m_stats(struct Client*, struct Client*, int, char*[]);
17 extern int m_time(struct Client*, struct Client*, int, char*[]);
18 extern int m_topic(struct Client*, struct Client*, int, char*[]);
20 extern int mo_rping(struct Client*, struct Client*, int, char*[]);
21 extern int mo_set(struct Client*, struct Client*, int, char*[]);
22 extern int mo_settime(struct Client*, struct Client*, int, char*[]);
23 +extern int mo_split(struct Client*, struct Client*, int, char*[]);
24 extern int mo_squit(struct Client*, struct Client*, int, char*[]);
25 extern int mo_stats(struct Client*, struct Client*, int, char*[]);
26 extern int mo_trace(struct Client*, struct Client*, int, char*[]);
28 extern int ms_sethost(struct Client*, struct Client*, int, char*[]);
29 extern int ms_settime(struct Client*, struct Client*, int, char*[]);
30 extern int ms_silence(struct Client*, struct Client*, int, char*[]);
31 +extern int ms_split(struct Client*, struct Client*, int, char*[]);
32 extern int ms_squit(struct Client*, struct Client*, int, char*[]);
33 extern int ms_stats(struct Client*, struct Client*, int, char*[]);
34 extern int ms_topic(struct Client*, struct Client*, int, char*[]);
35 diff -r 2da61ac38fa1 include/ircd_features.h
36 --- a/include/ircd_features.h Sun Jan 18 14:18:36 2009 +0100
37 +++ b/include/ircd_features.h Sun Jan 18 15:26:56 2009 +0100
44 /* HEAD_IN_SAND Features */
54 diff -r 2da61ac38fa1 include/msg.h
55 --- a/include/msg.h Sun Jan 18 14:18:36 2009 +0100
56 +++ b/include/msg.h Sun Jan 18 15:26:56 2009 +0100
59 #define CMD_JUPE MSG_JUPE, TOK_JUPE
61 +#define MSG_SPLIT "SPLIT" /* SPLIT */
62 +#define TOK_SPLIT "SP"
63 +#define CMD_SPLIT MSG_SPLIT, TOK_SPLIT
65 #define MSG_OPMODE "OPMODE" /* OPMO */
66 #define TOK_OPMODE "OM"
67 #define CMD_OPMODE MSG_OPMODE, TOK_OPMODE
68 diff -r 2da61ac38fa1 include/numeric.h
69 --- a/include/numeric.h Sun Jan 18 14:18:36 2009 +0100
70 +++ b/include/numeric.h Sun Jan 18 15:26:56 2009 +0100
72 RPL_STATSVLINE 227 unreal */
73 #define RPL_STATSALINE 226 /* Hybrid, Undernet */
74 #define RPL_STATSQLINE 228 /* Undernet extension */
75 +#define RPL_STATSSPLIT 229 /* QuakeNet extension */
77 /* RPL_SERVICEINFO 231 unused */
78 /* RPL_ENDOFSERVICES 232 unused */
80 #define RPL_STATSDLINE 275 /* Undernet extension */
81 #define RPL_STATSRLINE 276 /* Undernet extension */
83 +#define RPL_SPLITLIST 278 /* QuakeNet extension */
84 +#define RPL_ENDOFSPLITLIST 279 /* QuakeNet extension */
85 #define RPL_GLIST 280 /* Undernet extension */
86 #define RPL_ENDOFGLIST 281 /* Undernet extension */
87 #define RPL_JUPELIST 282 /* Undernet extension - jupe -Kev */
89 /* ERR_GHOSTEDCLIENT 503 efnet */
90 /* ERR_VWORLDWARN 503 austnet */
92 +#define ERR_NOSUCHSPLIT 510 /* QuakeNet extension */
93 #define ERR_SILELISTFULL 511 /* Undernet extension */
94 /* ERR_NOTIFYFULL 512 aircd */
95 /* ERR_TOOMANYWATCH 512 Numeric List: Dalnet */
96 diff -r 2da61ac38fa1 include/split.h
97 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
98 +++ b/include/split.h Sun Jan 18 15:26:56 2009 +0100
100 +/* TODO: ifndef ? */
101 +#ifndef INCLUDED_jupe_h
102 +#define INCLUDED_jupe_h
104 + * IRC - Internet Relay Chat, include/split.h
105 + * Copyright (C) 1990 Jarkko Oikarinen and
106 + * University of Oulu, Computing Center
107 + * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
109 + * This program is free software; you can redistribute it and/or modify
110 + * it under the terms of the GNU General Public License as published by
111 + * the Free Software Foundation; either version 2, or (at your option)
112 + * any later version.
114 + * This program is distributed in the hope that it will be useful,
115 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
116 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
117 + * GNU General Public License for more details.
119 + * You should have received a copy of the GNU General Public License
120 + * along with this program; if not, write to the Free Software
121 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
124 + * @brief Interface and declarations for split server handling.
125 + * @version $Id: jupe.h 1208 2004-10-03 14:12:35Z entrope $
127 +/* TODO: ifndef ? */
128 +#ifndef INCLUDED_sys_types_h
129 +#include <sys/types.h>
130 +#define INCLUDED_sys_types_h
137 +#define SPLIT_MAX_EXPIRE 604800 /**< Maximum split expiration time (7 days). */
138 +#define SPLIT_AUTO_EXPIRE 604800 /**< Expireation time used for auto created entries. */
140 +/* Describes a SPLIT server entry. */
142 + struct Split* sp_next; /**< Pointer to next Split. */
143 + struct Split** sp_prev_p; /**< Pointer to previous next pointer. */
144 + char* sp_server; /**< Name of server. */
145 + char* sp_reason; /**< Reason. */
146 + time_t sp_creation; /**< TODO: Creation time. What are we using this for then? */
147 + time_t sp_expire; /**< Expiration time. */
148 + time_t sp_lastmod; /**< Last modification time. */
149 + time_t sp_lifetime; /**< Life time. */
150 + unsigned int sp_flags; /**< Status flags. */
153 +/** Split state flags. */
154 +#define SPLIT_ACTIVE 0x0001 /**< Split is active. */
155 +#define SPLIT_REMOVING 0x0002 /**< Split is about to be destroyed. */
157 +/* TODO: these ; after } needed ? */
158 +/* Actions to perform on a SPLIT. */
160 + SPLIT_ACTIVATE, /**< SPLIT should be activated. */
161 + SPLIT_DEACTIVATE, /**< SPLIT should be deactivated. */
162 + SPLIT_MODIFY, /**< SPLIT should be modified. */
163 + SPLIT_REMOVE /**< SPLIT should be removed. */
166 +/* TODO: what values to use here? */
167 +/* Split update flags. */
168 +#define SPLIT_EXPIRE 0x0002 /**< Expiration time update. */
169 +#define SPLIT_LIFETIME 0x0004 /**< Record lifetime update. */
170 +#define SPLIT_REASON 0x0008 /**< Reason update. */
171 +#define SPLIT_CREATION 0x0010 /**< Creation time update. */
172 +#define SPLIT_MODIFY 0x0020 /**< No state change. */
174 +/* mask for Split update flags. */
175 +#define SPLIT_UPDATE (SPLIT_EXPIRE | SPLIT_LIFETIME | SPLIT_REASON)
177 +/* test whether a split entry is active. */
178 +#define SplitIsActive(s) ((s)->sp_flags & SPLIT_ACTIVE)
179 +/* test whether a split entry is marked for forecd removal. */
180 +#define SplitIsRemoving(s) ((s)->sp_flags & SPLIT_REMOVING)
182 +/* TODO: these are not used? some are, check! */
183 +/* get the server name for a split entry. */
184 +#define SplitServer(s) ((s)->sp_server)
185 +/* get the reason for a split entry. */
186 +#define SplitReason(s) ((s)->sp_reason)
187 +/* get the creation time for split entry. */
188 +#define SplitCreation(s) ((s)->sp_creation)
189 +/* get the expiration time for split entry. */
190 +#define SplitExpire(s) ((s)->sp_expire)
191 +/* get the last modification time for split entry. */
192 +#define SplitLastMod(s) ((s)->sp_lastmod)
193 +/* get the life time for split entry. */
194 +#define SplitLifeTime(s) ((s)->sp_lifetime)
196 +extern int split_add(struct Client *cptr, struct Client *sptr,
197 + char *server, const char *reason,
198 + time_t creation, time_t expire, time_t lastmod, time_t lifetime,
199 + unsigned int flags);
200 +extern int split_modify(struct Client *cptr, struct Client *sptr,
201 + struct Split *split, enum SplitAction action, const char *reason,
202 + time_t creation, time_t expire, time_t lastmod, time_t lifetime,
203 + unsigned int flags);
204 +extern int split_remove(struct Client *cptr, struct Client *sptr,
205 + struct Split *split, const char *reason);
207 +extern struct Split* split_find(char *server);
208 +extern void split_free(struct Split *split);
209 +extern int split_expire(struct Split* split);
210 +extern void split_burst(struct Client *cptr);
211 +extern int split_resend(struct Client *cptr, struct Split *split);
212 +extern int split_list(struct Client *sptr, char *server);
213 +extern int split_merge(struct Client *server);
214 +extern int split_break(struct Client *server, const char *reason);
215 +extern void split_conf();
216 +extern void split_stats(struct Client *sptr, const struct StatDesc *sd, char *param);
217 +extern int split_memory_count(size_t *sp_size);
220 +#endif /* INCLUDED_jupe_h */
221 diff -r 2da61ac38fa1 ircd/Makefile.in
222 --- a/ircd/Makefile.in Sun Jan 18 14:18:36 2009 +0100
223 +++ b/ircd/Makefile.in Sun Jan 18 15:26:56 2009 +0100
240 @@ -1052,6 +1054,15 @@
241 ../include/ircd_chattr.h ../include/list.h ../include/msg.h \
242 ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
243 ../include/send.h ../include/struct.h
244 +m_split.o: m_split.c ../config.h ../include/client.h ../include/ircd_defs.h \
245 + ../include/dbuf.h ../include/msgq.h ../include/ircd_events.h \
246 + ../config.h ../include/ircd_handler.h ../include/res.h \
247 + ../include/capab.h ../include/split.h ../include/hash.h \
248 + ../include/ircd.h ../include/struct.h ../include/ircd_features.h \
249 + ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
250 + ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
251 + ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
252 + ../include/client.h ../include/s_misc.h ../include/send.h
253 m_squit.o: m_squit.c ../config.h ../include/client.h \
254 ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
255 ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
256 @@ -1325,6 +1336,7 @@
257 ../include/msgq.h ../include/numeric.h ../include/numnicks.h \
258 ../include/res.h ../include/s_bsd.h ../include/s_conf.h \
259 ../include/s_user.h ../include/s_stats.h ../include/send.h \
260 + ../include/split.h \
261 ../include/struct.h ../include/sys.h ../include/whowas.h
262 s_err.o: s_err.c ../config.h ../include/numeric.h ../include/ircd_log.h \
263 ../include/s_debug.h ../config.h ../include/ircd_defs.h
264 @@ -1410,6 +1422,16 @@
265 ../include/msg.h ../include/numnicks.h ../include/parse.h \
266 ../include/s_bsd.h ../include/s_debug.h ../include/s_misc.h \
267 ../include/s_user.h ../include/struct.h ../include/sys.h
268 +split.o: split.c ../config.h ../include/split.h ../include/client.h \
269 + ../include/ircd_defs.h ../include/dbuf.h ../include/msgq.h \
270 + ../include/ircd_events.h ../config.h ../include/ircd_handler.h \
271 + ../include/res.h ../include/capab.h ../include/hash.h ../include/ircd.h \
272 + ../include/struct.h ../include/ircd_alloc.h ../include/ircd_features.h \
273 + ../include/ircd_log.h ../include/ircd_reply.h ../include/ircd_string.h \
274 + ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
275 + ../include/numeric.h ../include/numnicks.h ../include/s_bsd.h \
276 + ../include/s_misc.h ../include/send.h ../include/struct.h \
278 uping.o: uping.c ../config.h ../include/uping.h ../include/ircd_defs.h \
279 ../include/ircd_events.h ../config.h ../include/res.h \
280 ../include/client.h ../include/dbuf.h ../include/msgq.h \
281 diff -r 2da61ac38fa1 ircd/ircd.c
282 --- a/ircd/ircd.c Sun Jan 18 14:18:36 2009 +0100
283 +++ b/ircd/ircd.c Sun Jan 18 15:26:56 2009 +0100
291 #include "userload.h"
293 Debug((DEBUG_NOTICE, "Server ready..."));
294 log_write(LS_SYSTEM, L_NOTICE, 0, "Server Ready");
296 + /* create SPLITs */
302 diff -r 2da61ac38fa1 ircd/ircd_features.c
303 --- a/ircd/ircd_features.c Sun Jan 18 14:18:36 2009 +0100
304 +++ b/ircd/ircd_features.c Sun Jan 18 15:26:56 2009 +0100
306 F_B(SETHOST, 0, 0, 0),
307 F_B(SETHOST_USER, 0, 0, 0),
308 F_B(SETHOST_AUTO, 0, 0, 0),
309 + F_B(SPLIT, 0, 1, 0),
311 /* HEAD_IN_SAND Features */
312 F_B(HIS_SNOTICES, 0, 1, 0),
314 F_B(HIS_STATS_q, 0, 1, 0),
315 F_B(HIS_STATS_R, 0, 1, 0),
316 F_B(HIS_STATS_r, 0, 1, 0),
317 + F_B(HIS_STATS_S, 0, 1, 0),
318 F_B(HIS_STATS_s, 0, 1, 0),
319 F_B(HIS_STATS_t, 0, 1, 0),
320 F_B(HIS_STATS_T, 0, 1, 0),
321 diff -r 2da61ac38fa1 ircd/m_endburst.c
322 --- a/ircd/m_endburst.c Sun Jan 18 14:18:36 2009 +0100
323 +++ b/ircd/m_endburst.c Sun Jan 18 15:26:56 2009 +0100
328 +#include "ircd_features.h"
329 #include "ircd_log.h"
330 #include "ircd_reply.h"
331 #include "ircd_string.h"
334 #include "numnicks.h"
338 /* #include <assert.h> -- Now using assert in ircd_log.h */
341 int ms_end_of_burst(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
343 struct Channel *chan, *next_chan;
349 dump_map(sptr, "*", 0, report_new_links, 0);
350 sendto_opmask_butone(0, SNO_NETWORK, "Completed net.burst from %C.",
352 + /* cleanup SPLITs, but only bother ops when FEAT_SPLIT is enabled. */
353 + split = split_merge(sptr);
354 + if (feature_bool(FEAT_SPLIT))
355 + sendto_opmask_butone(0, SNO_NETWORK, "Removed %d SPLIT entries.", split);
357 sendcmdto_one(&me, CMD_END_OF_BURST_ACK, sptr, "");
359 diff -r 2da61ac38fa1 ircd/m_reburst.c
360 --- a/ircd/m_reburst.c Sun Jan 18 14:18:36 2009 +0100
361 +++ b/ircd/m_reburst.c Sun Jan 18 15:26:56 2009 +0100
363 #include "ircd_snprintf.h"
368 /* #include <assert.h> -- Now using assert in ircd_log.h */
381 diff -r 2da61ac38fa1 ircd/m_split.c
382 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
383 +++ b/ircd/m_split.c Sun Jan 18 15:26:56 2009 +0100
386 + * IRC - Internet Relay Chat, ircd/m_split.c
387 + * Copyright (C) 1990 Jarkko Oikarinen and
388 + * University of Oulu, Computing Center
389 + * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
391 + * See file AUTHORS in IRC package for additional names of
394 + * This program is free software; you can redistribute it and/or modify
395 + * it under the terms of the GNU General Public License as published by
396 + * the Free Software Foundation; either version 1, or (at your option)
397 + * any later version.
399 + * This program is distributed in the hope that it will be useful,
400 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
401 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
402 + * GNU General Public License for more details.
404 + * You should have received a copy of the GNU General Public License
405 + * along with this program; if not, write to the Free Software
406 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
408 + * $Id: m_split.c 1737 2006-12-19 05:20:48Z entrope $
412 + * m_functions execute protocol messages on this server:
414 + * cptr is always NON-NULL, pointing to a *LOCAL* client
415 + * structure (with an open socket connected!). This
416 + * identifies the physical socket where the message
417 + * originated (or which caused the m_function to be
418 + * executed--some m_functions may call others...).
420 + * sptr is the source of the message, defined by the
421 + * prefix part of the message if present. If not
422 + * or prefix not found, then sptr==cptr.
424 + * (!IsServer(cptr)) => (cptr == sptr), because
425 + * prefixes are taken *only* from servers...
428 + * (sptr == cptr) => the message didn't
431 + * (sptr != cptr && IsServer(sptr) means
432 + * the prefix specified servername. (?)
434 + * (sptr != cptr && !IsServer(sptr) means
435 + * that message originated from a remote
436 + * user (not local).
440 + * (!IsServer(sptr)) means that, sptr can safely
441 + * taken as defining the target structure of the
442 + * message in this server.
444 + * *Always* true (if 'parse' and others are working correct):
446 + * 1) sptr->from == cptr (note: cptr->from == cptr)
448 + * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
449 + * *cannot* be a local connection, unless it's
450 + * actually cptr!). [MyConnect(x) should probably
451 + * be defined as (x == x->from) --msa ]
453 + * parc number of variable parameter strings (if zero,
454 + * parv is allowed to be NULL)
456 + * parv a NULL terminated list of parameter pointers,
458 + * parv[0], sender (prefix string), if not present
459 + * this points to an empty string.
460 + * parv[1]...parv[parc-1]
461 + * pointers to additional parameters
462 + * parv[parc] == NULL, *always*
464 + * note: it is guaranteed that parv[0]..parv[parc-1] are all
465 + * non-NULL pointers.
473 +#include "ircd_features.h"
474 +#include "ircd_log.h"
475 +#include "ircd_reply.h"
476 +#include "ircd_string.h"
479 +#include "numeric.h"
480 +#include "numnicks.h"
482 +#include "s_debug.h"
486 +/* #include <assert.h> -- Now using assert in ircd_log.h */
491 + * ms_split - server message handler
493 + * parv[0] = Send prefix
494 + * parv[1] = (+|-)<server name>
495 + * parv[2] = Creation time
496 + * parv[3] = Expiration time
497 + * parv[4] = Last modification time
498 + * parv[5] = Life time
499 + * parv[6] = Comment
502 +int ms_split(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
504 + struct Client *acptr = 0;
505 + struct Split *asplit = 0;
506 + unsigned int flags = 0;
507 + enum SplitAction action = SPLIT_MODIFY;
508 + time_t creation = 0, expire = 0, lastmod = 0, lifetime = 0;
509 + char *server = parv[1], *tmp = 0;
510 + const char *reason = "No reason";
512 + /* TODO: perhaps make some fields optional? reason? */
514 + return need_more_params(sptr, "SPLIT");
516 + if (*server == '!') {
518 + action = SPLIT_REMOVE; /* removing entry */
521 + switch (*server) { /* handle + and - */
522 + case '+': /* activate the split entry */
523 + if (action != SPLIT_REMOVE)
524 + action = SPLIT_ACTIVATE;
528 + case '-': /* deactivate the entry */
529 + if (action != SPLIT_REMOVE)
530 + action = SPLIT_DEACTIVATE;
535 + /* Next, try to find the split entry... */
536 + asplit = split_find(server);
538 + /* We now have all the pieces to tell us what we've got; let's put
539 + * it all together and convert the rest of the arguments.
542 + /* can't modify a split entry that doesn't exist, so remap to activate */
543 + if (!asplit && action == SPLIT_MODIFY)
544 + action = SPLIT_ACTIVATE;
546 + /* OK, let's figure out what other parameters we may have... */
547 + creation = atoi(parv[2]);
548 + expire = atoi(parv[3]);
549 + lastmod = atoi(parv[4]);
550 + lifetime = atoi(parv[5]);
551 + reason = parv[parc - 1];
553 + Debug((DEBUG_DEBUG, "I have a SPLIT I am acting upon now; "
554 + "server %s, action %s, creation %Tu, expire %Tu, "
555 + "lastmod %Tu, lifetime %Tu, reason: %s; split %s!", server,
556 + action == SPLIT_REMOVE ? "!-" :
557 + (action == SPLIT_ACTIVATE ? "+" :
558 + (action == SPLIT_DEACTIVATE ? "-" : "(MODIFY)")),
559 + creation, expire, lastmod, lifetime, reason,
560 + asplit ? "EXISTS" : "does not exist"));
562 + /* OK, at this point, we have converted all available parameters.
563 + * Let's actually do the action!
566 + if (action == SPLIT_REMOVE)
567 + return split_remove(cptr, sptr, asplit, reason);
568 + return split_modify(cptr, sptr, asplit, action, reason, creation, expire,
569 + lastmod, lifetime, flags);
572 + assert(action != SPLIT_MODIFY);
574 + return split_add(cptr, sptr, server, reason, creation, expire, lastmod, lifetime,
575 + flags | ((action == SPLIT_ACTIVATE) ? SPLIT_ACTIVE : 0));
580 + * mo_split - oper message handler
582 + * Local listing: 1 or 2 params
583 + * parv[0] = Send prefix
584 + * parv[1] = [Server or mask to match]
586 + * Add or modify entry: 3, 4 or 5 params (3 is * then)
587 + * parv[0] = Send prefix
588 + * parv[1] = [+|-]<server name>
589 + * parv[2] = [Expiration offset] (required for new)
590 + * parv[3] = [Comment] (required for new)
593 +int mo_split(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
595 + struct Client *acptr = 0;
596 + struct Split *asplit = 0;
597 + unsigned int flags = 0;
598 + enum SplitAction action = SPLIT_MODIFY;
599 + time_t expire = 0, lastmod = CurrentTime, creation = CurrentTime;
600 + char *server = parv[1], *end;
601 + const char *reason = NULL;
604 + if (!HasPriv(sptr, PRIV_ROUTEINFO))
605 + return send_reply(sptr, ERR_NOPRIVILEGES);
607 + return split_list(sptr, 0);
610 + if (*server == '!') {
612 + action = SPLIT_REMOVE; /* force removal */
615 + switch (*server) { /* handle + and - */
616 + case '+': /* activate the split entry */
617 + if (action != SPLIT_REMOVE)
618 + action = SPLIT_ACTIVATE;
622 + case '-': /* deactivate the split entry */
623 + if (action != SPLIT_REMOVE)
624 + action = SPLIT_DEACTIVATE;
629 + /* OK, let's figure out the parameters... */
631 + /* no specific action */
633 + /* user wants a listing of a specific SPLIT */
635 + return split_list(sptr, server);
636 + expire = strtol(parv[2], &end, 10) + CurrentTime; /* and the expiration */
638 + return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE,
639 + "%s :Bad expire time", parv[2]);
641 + flags |= SPLIT_EXPIRE; /* remember that we got an expire time */
643 + if (parc > 3) { /* also got a reason... */
644 + reason = parv[parc - 1];
645 + flags |= SPLIT_REASON;
649 + case SPLIT_REMOVE: /* TODO: require reason for this, but not expire? */
651 + return need_more_params(sptr, "SPLIT");
652 + reason = parv[parc - 1];
653 + flags |= SPLIT_REASON;
656 + case SPLIT_ACTIVATE: /* TODO: require expire and reason when new */
658 + expire = strtol(parv[2], &end, 10) + CurrentTime; /* and the expiration */
660 + return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE,
661 + "%s :Bad expire time", parv[2]);
662 + flags |= SPLIT_EXPIRE; /* remember that we got an expire time */
665 + if (parc > 3) { /* also got a reason... */
666 + reason = parv[parc - 1];
667 + flags |= SPLIT_REASON;
671 + case SPLIT_DEACTIVATE: /* TODO: duplicate code? must be a cleaner way */
673 + expire = strtol(parv[2], &end, 10) + CurrentTime; /* and the expiration */
675 + return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE,
676 + "%s :Bad expire time", parv[2]);
677 + flags |= SPLIT_EXPIRE; /* remember that we got an expire time */
680 + if (parc > 3) { /* also got a reason... */
681 + reason = parv[parc - 1];
682 + flags |= SPLIT_REASON;
688 + /* check for permissions... */
689 + if (!feature_bool(FEAT_SPLIT)) /* TODO: but allow force removal? */
690 + return send_reply(sptr, ERR_DISABLED, "SPLIT");
691 + else if (!HasPriv(sptr, PRIV_SERVERINFO)) /* TODO: create PRIV_SPLIT - need help there */
692 + return send_reply(sptr, ERR_NOPRIVILEGES);
694 + /* Next, try to find the SPLIT... */
695 + asplit = split_find(server);
697 + /* We now have all the pieces to tell us what we've got; let's put
698 + * it all together and convert the rest of the arguments.
701 + /* SPLIT not found and thus we:
702 + * cannot remove SPLIT we do not have
703 + * cannot add new SPLIT without expire and reason
706 + ((action == SPLIT_REMOVE) ||
707 + (action == SPLIT_ACTIVATE && !reason) ||
708 + (action == SPLIT_DEACTIVATE && !reason) ||
709 + (action == SPLIT_MODIFY && !reason)))
710 + return send_reply(sptr, ERR_NOSUCHSPLIT, server);
712 + /* can't modify a split entry that doesn't exist, so remap to activate */
713 + if (!asplit && action == SPLIT_MODIFY)
714 + action = SPLIT_ACTIVATE;
716 + Debug((DEBUG_DEBUG, "I have a SPLIT I am acting upon now; "
717 + "server %s, action %s, expire %Tu, "
718 + "reason: %s; split %s! (fields present: %s %s)", server,
719 + action == SPLIT_REMOVE ? "!-" :
720 + (action == SPLIT_ACTIVATE ? "+" :
721 + (action == SPLIT_DEACTIVATE ? "-" : "(MODIFY)")),
722 + expire, reason, asplit ? "EXISTS" : "does not exist",
723 + flags & SPLIT_EXPIRE ? "expire" : "",
724 + flags & SPLIT_REASON ? "reason" : ""));
726 + if (asplit) { /* modifying an existing SPLIT */
727 + if (action == SPLIT_REMOVE)
728 + return split_remove(cptr, sptr, asplit, reason);
729 + return split_modify(cptr, sptr, asplit, action, reason,
730 + asplit->sp_creation, expire, lastmod, asplit->sp_lifetime, flags);
733 + assert(action != SPLIT_MODIFY);
734 + assert(action != SPLIT_REMOVE);
736 + /* create a new SPLIT */
737 + return split_add(cptr, sptr, server, reason,
738 + creation, expire, lastmod, expire,
739 + flags | ((action == SPLIT_ACTIVATE) ? SPLIT_ACTIVE : 0));
743 + * m_split - user message handler
745 + * parv[0] = Send prefix
749 + * parv[1] = [<server name>]
752 +int m_split(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
755 + return split_list(sptr, 0);
757 + return split_list(sptr, parv[1]);
759 diff -r 2da61ac38fa1 ircd/parse.c
760 --- a/ircd/parse.c Sun Jan 18 14:18:36 2009 +0100
761 +++ b/ircd/parse.c Sun Jan 18 15:26:56 2009 +0100
763 0, MAXPARA, MFLG_SLOW, 0, NULL,
764 /* UNREG, CLIENT, SERVER, OPER, SERVICE */
765 { m_unregistered, m_not_oper, ms_jupe, mo_jupe, m_ignore }
770 + 0, MAXPARA, MFLG_SLOW, 0, NULL,
771 + /* UNREG, CLIENT, SERVER, OPER, SERVICE */
772 + { m_unregistered, m_not_oper, ms_split, mo_split, m_ignore }
776 diff -r 2da61ac38fa1 ircd/s_conf.c
777 --- a/ircd/s_conf.c Sun Jan 18 14:18:36 2009 +0100
778 +++ b/ircd/s_conf.c Sun Jan 18 15:26:56 2009 +0100
787 @@ -1005,6 +1006,7 @@
790 attach_conf_uworld(&me);
795 diff -r 2da61ac38fa1 ircd/s_debug.c
796 --- a/ircd/s_debug.c Sun Jan 18 14:18:36 2009 +0100
797 +++ b/ircd/s_debug.c Sun Jan 18 15:26:57 2009 +0100
807 aw = 0, /* aways set */
808 wwa = 0, /* whowas aways */
810 - ju = 0; /* jupes */
811 + ju = 0, /* jupes */
812 + sp = 0; /* split entries */
814 size_t chm = 0, /* memory used by channels */
815 chbm = 0, /* memory used by channel bans */
817 wwm = 0, /* whowas array memory used */
818 glm = 0, /* memory used by glines */
819 jum = 0, /* memory used by jupes */
820 + spm = 0, /* memory used by split entries */
821 com = 0, /* memory used by conf lines */
822 dbufs_allocated = 0, /* memory used by dbufs */
823 dbufs_used = 0, /* memory used by dbufs */
826 gl = gline_memory_count(&glm);
827 ju = jupe_memory_count(&jum);
828 + sp = split_memory_count(&spm);
829 send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
830 - ":Glines %d(%zu) Jupes %d(%zu)", gl, glm, ju, jum);
831 + ":Glines %d(%zu) Jupes %d(%zu) Splits %d(%zu)", gl, glm, ju, jum, sp, spm);
833 send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
834 ":Hash: client %d(%zu), chan is the same", HASHSIZE,
835 diff -r 2da61ac38fa1 ircd/s_err.c
836 --- a/ircd/s_err.c Sun Jan 18 14:18:36 2009 +0100
837 +++ b/ircd/s_err.c Sun Jan 18 15:26:57 2009 +0100
840 { RPL_STATSQLINE, "Q %s :%s", "228" },
843 + { RPL_STATSSPLIT, "S %s %d %d %d %d %c :%s", "229" },
852 + { RPL_SPLITLIST, "%s %Tu %Tu %Tu %Tu %c :%s", "278" },
855 + { RPL_ENDOFSPLITLIST, ":End of Split List", "279" },
857 { RPL_GLIST, "%s%s%s%s%s %Tu %Tu %Tu %s %s%c :%s", "280" },
859 @@ -1052,7 +1052,7 @@
864 + { ERR_NOSUCHSPLIT, "%s :No such split", "510" },
866 { ERR_SILELISTFULL, "%s :Your silence list is full", "511" },
868 diff -r 2da61ac38fa1 ircd/s_misc.c
869 --- a/ircd/s_misc.c Sun Jan 18 14:18:36 2009 +0100
870 +++ b/ircd/s_misc.c Sun Jan 18 15:26:57 2009 +0100
882 char comment1[HOSTLEN + HOSTLEN + 2];
883 + char splitreason[BUFSIZE];
885 if (MyConnect(victim))
888 sendto_opmask_butone(0, SNO_NETWORK, "Net break: %C %C (%s)",
889 cli_serv(victim)->up, victim, comment);
890 dump_map(victim, "*", 0, report_lost_links, 0);
891 + if (feature_bool(FEAT_SPLIT)) {
892 + ircd_snprintf(0, splitreason, sizeof(splitreason),
893 + "Net break: %C %C (%s%s%s%s)", cli_serv(victim)->up, victim,
894 + IsUser(killer) ? "SQUIT by " : "", IsUser(killer) ? cli_name(killer) : "",
895 + IsUser(killer) ? ": " : "", comment);
896 + sendto_opmask_butone(0, SNO_NETWORK, "Created %d SPLIT entries.",
897 + split_break(victim, splitreason));
902 diff -r 2da61ac38fa1 ircd/s_serv.c
903 --- a/ircd/s_serv.c Sun Jan 18 14:18:36 2009 +0100
904 +++ b/ircd/s_serv.c Sun Jan 18 15:26:57 2009 +0100
912 #include "userload.h"
920 * Pass on my client information to the new server
921 diff -r 2da61ac38fa1 ircd/s_stats.c
922 --- a/ircd/s_stats.c Sun Jan 18 14:18:36 2009 +0100
923 +++ b/ircd/s_stats.c Sun Jan 18 15:26:57 2009 +0100
930 #include "userload.h"
934 "System resource usage (Debug only)." },
936 - { 's', "spoofhosts", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_s,
937 + { 'S', "splits", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_S,
939 + "Server SPLITs information."},
940 + { 's', "spoofhosts", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_s,
942 "Spoofed hosts information." },
943 { 'T', "motds", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T,
944 diff -r 2da61ac38fa1 ircd/split.c
945 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
946 +++ b/ircd/split.c Sun Jan 18 15:26:57 2009 +0100
949 + * IRC - Internet Relay Chat, ircd/split.c
950 + * Copyright (C) 1990 Jarkko Oikarinen and
951 + * University of Oulu, Finland
952 + * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
954 + * This program is free software; you can redistribute it and/or modify
955 + * it under the terms of the GNU General Public License as published by
956 + * the Free Software Foundation; either version 1, or (at your option)
957 + * any later version.
959 + * This program is distributed in the hope that it will be useful,
960 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
961 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
962 + * GNU General Public License for more details.
964 + * You should have received a copy of the GNU General Public License
965 + * along with this program; if not, write to the Free Software
966 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
969 + * @brief Implementation of split server handling functions.
970 + * @version $Id: split.c 1633 2006-03-25 03:46:56Z entrope $
978 +#include "ircd_alloc.h"
979 +#include "ircd_features.h"
980 +#include "ircd_log.h"
981 +#include "ircd_reply.h"
982 +#include "ircd_string.h"
986 +#include "numeric.h"
987 +#include "numnicks.h"
990 +#include "s_debug.h"
994 +#include "sys.h" /* FALSE bleah */
996 +/* #include <assert.h> -- Now using assert in ircd_log.h */
999 +/** List of split entries. */
1000 +static struct Split *GlobalSplitList = 0;
1002 +/** Allocate a new Split entry with the given parameters.
1003 + * @param[in] server Server name for split entry.
1004 + * @param[in] reason Reason for the split entry.
1005 + * @param[in] creation Creation time for split entry.
1006 + * @param[in] expire Expiration time for split entry.
1007 + * @param[in] lastmod Last modification time for split entry.
1008 + * @param[in] lifetime Life time for split entry.
1009 + * @param[in] flags Flags to set for the split entry.
1011 +static struct Split *
1012 +split_make(char *server, const char *reason,
1013 + time_t creation, time_t expire, time_t lastmod, time_t lifetime,
1014 + unsigned int flags)
1016 + struct Split *asplit;
1018 + asplit = (struct Split*) MyMalloc(sizeof(struct Split)); /* alloc memory */
1019 + assert(0 != asplit);
1021 + memset(asplit, 0, sizeof(*asplit));
1022 + /* TODO: some limit for servername length? HOSTLEN? */
1023 + DupString(asplit->sp_server, server); /* copy vital information */
1024 + /* TODO: some limit for reason length? QUITLEN TOPICLEN? */
1025 + DupString(asplit->sp_reason, reason);
1026 + /* TODO: what we use creation for and do we need it? */
1027 + asplit->sp_creation = creation;
1028 + asplit->sp_expire = expire;
1029 + /* TODO: are we using nettime etc.? CurrentTime is used. */
1030 + asplit->sp_lastmod = lastmod;
1031 + asplit->sp_lifetime = lifetime;
1032 + /* CHECK: does this make it active upon creation regardless of the flags given? */
1033 + asplit->sp_flags = flags & SPLIT_ACTIVE; /* set split flags */
1035 + asplit->sp_next = GlobalSplitList; /* link it into the list */
1036 + asplit->sp_prev_p = &GlobalSplitList;
1037 + if (GlobalSplitList)
1038 + GlobalSplitList->sp_prev_p = &asplit->sp_next;
1039 + GlobalSplitList = asplit;
1044 +/** Forward a split entry to another server.
1045 + * @param[in] cptr Local client that sent us the split entry.
1046 + * @param[in] sptr Originator of the split entry.
1047 + * @param[in] split Split entry to forward.
1048 + * @param[in] reason Reason to send upstream (used by split_remove)
1051 +split_propagate(struct Client *cptr, struct Client *sptr,
1052 + struct Split *split, const char *reason)
1054 + sendcmdto_serv_butone(sptr, CMD_SPLIT, cptr, "%s%c%s %Tu %Tu %Tu %Tu :%s",
1055 + SplitIsRemoving(split) ? "!" : "",
1056 + SplitIsActive(split) && !SplitIsRemoving(split) ? '+' : '-', /* always !- not !+ */
1057 + split->sp_server, split->sp_creation, split->sp_expire,
1058 + split->sp_lastmod, split->sp_lifetime,
1059 + reason != NULL ? reason : split->sp_reason);
1062 +/** Add a new server split entry.
1063 + * @param[in] cptr Local client that sent us the split entry.
1064 + * @param[in] sptr Originator of the split entry.
1065 + * @param[in] server Server name to split entry.
1066 + * @param[in] reason Reason for the split entry.
1067 + * @param[in] expire Expiration timestamp.
1068 + * @param[in] lastmod Last modification timestamp.
1069 + * @param[in] flags Flags to set on the split entry.
1073 +split_add(struct Client *cptr, struct Client *sptr, char *server, const char *reason,
1074 + time_t creation, time_t expire, time_t lastmod, time_t lifetime,
1075 + unsigned int flags)
1078 + /* TODO: check for proper masks - at least one dot and no wildcards? */
1079 + struct Split *asplit;
1080 + struct Client *acptr;
1082 + assert(0 != server);
1083 + assert(0 != reason);
1084 + assert(NULL != cptr);
1085 + assert(NULL != sptr);
1087 + Debug((DEBUG_DEBUG, "split_add(\"%s\", \"%s\", \"%s\", \"%s\", %Tu, %Tu, %Tu, "
1088 + "%Tu, 0x%04x)", cli_name(cptr), cli_name(sptr), server, reason,
1089 + creation, expire, lastmod, lifetime, flags));
1091 + /* not adding SPLIT for server that is linked
1092 + * if sptr is my user throw error
1093 + * otherwise ignore - SERVER and SPLIT messages can cross,
1094 + * or a server is bursting and it will see our end and destroy the SPLITs
1096 + if ((acptr = FindServer(server))) {
1098 + sendcmdto_one(&me, CMD_NOTICE, sptr,
1099 + "%C :Cannot add SPLIT %s - server is linked.", sptr, server);
1104 + * You cannot set a negative (or zero) duration, nor can you set an
1105 + * duration greater than SPLIT_MAX_EXPIRE.
1107 + if (expire - CurrentTime <= 0 || expire - CurrentTime > SPLIT_MAX_EXPIRE) {
1108 + if (!IsServer(cptr) && MyConnect(cptr))
1109 + return send_reply(cptr, ERR_BADEXPIRE, expire - CurrentTime);
1110 + if (expire <= CurrentTime) /* no point going further */
1111 + /* TODO: check lifetime then ? because the SPLIT may simply be deactivated
1112 + * and we did not see it before
1113 + * if it were to be activated again we would get it again
1114 + * but should we not keep the same state on each server?
1116 + /* CHECK: sptr may have the wrong idea about the nettime?
1117 + * or we could be wrong?
1118 + * SETTIME ? could be dangerous and mess up things..
1119 + * perhaps raise some sort of warning to ops
1120 + * maybe if the difference is larger than a poor RTT over the network?
1122 + * no no no! - see above
1127 + /* inform ops and log it */
1128 + sendto_opmask_butone(0, SNO_NETWORK, "%s adding%sSPLIT for %s, expiring at %Tu: %s",
1129 + (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
1130 + cli_name(sptr) : cli_name((cli_user(sptr))->server),
1131 + !(flags & SPLIT_ACTIVE) ? " deactivated " : " ",
1132 + server, expire, reason);
1134 + /* TODO: add SPLIT log stuff or use JUPE? */
1135 + log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
1136 + "%#C adding%sSPLIT for %s, expiring at %Tu: %s",
1137 + sptr, !(flags & SPLIT_ACTIVE) ? " deactivated " : " ",
1138 + server, expire, reason);
1140 + /* make the split entry */
1141 + asplit = split_make(server, reason, creation, expire, lastmod, lifetime, flags);
1145 + /* and propagate it */
1146 + split_propagate(cptr, sptr, asplit, NULL);
1152 +/** Modify a split entry.
1153 + * @param[in] cptr Client that sent us the split modification.
1154 + * @param[in] sptr Client that originated the split modification.
1155 + * @param[in] split Split entry being modified.
1156 + * @param[in] action Resultant status of the G-line.
1157 + * @param[in] reason Reason.
1158 + * @param[in] expire Expiration time.
1159 + * @param[in] lastmod Last modification time.
1160 + * @param[in] lifetime Lifetime.
1161 + * @param[in] flags Bitwise combination of SPLIT_* flags.
1165 +split_modify(struct Client *cptr, struct Client *sptr, struct Split *split,
1166 + enum SplitAction action, const char *reason,
1167 + time_t creation, time_t expire, time_t lastmod, time_t lifetime,
1168 + unsigned int flags)
1170 + struct Client* acptr;
1171 + char buf[BUFSIZE];
1175 + assert(NULL != cptr);
1176 + assert(NULL != sptr);
1178 + /* TODO: add action in the debug notice too */
1179 + Debug((DEBUG_DEBUG, "split_modify(\"%s\", \"%s\", \"%s\", \"%s\", %Tu, %Tu, %Tu, "
1180 + "%Tu, 0x%04x)", cli_name(cptr), cli_name(sptr), split->sp_server, reason,
1181 + creation, expire, lastmod, lifetime, flags));
1183 + /* not modifying SPLIT for server that is linked
1184 + * if sptr is my user throw error
1185 + * otherwise ignore - SERVER and SPLIT messages can cross.
1187 + * note: we cleanup SPLIT entries at end of burst,
1188 + * and not when a server is introduced.
1189 + * so between net junction and end of burst,
1190 + * we can get SPLITs for a linked server.
1192 + /* TODO: should we free it here or let that be done in end of burst?
1193 + * only when that is the ONLY situation we can get to this point!
1194 + * but if we free here and it is a burst, the count is incorrect in
1196 + * IsBurst() is that true for only that single server or for all its downlinks?
1197 + * I would guess single server only.. argh!
1199 + if ((acptr = FindServer(split->sp_server))) {
1201 + sendcmdto_one(&me, CMD_NOTICE, sptr,
1202 + "%C :Cannot modify SPLIT %s - server is linked.", sptr, split->sp_server);
1203 + split_free(split); /* and free it */
1207 + /* First, let's check lastmod... */
1208 + if (SplitLastMod(split) > lastmod) { /* we have a more recent version */
1209 + if (IsBurstOrBurstAck(cptr))
1210 + return 0; /* middle of a burst, it'll resync on its own */
1211 + return split_resend(cptr, split); /* resync the server */
1212 + } else if (SplitLastMod(split) == lastmod)
1213 + return 0; /* we have that version of the split entry... */
1215 + /* All right, we know that there's a change of some sort. What is it? */
1216 + /* first, check out the expiration time... */
1217 + /* TODO: expire != 0 or NULL - check that we have something? */
1218 + if (expire != 0 && expire != split->sp_expire) {
1219 + if (expire - CurrentTime <= 0 || expire - CurrentTime > SPLIT_MAX_EXPIRE) {
1220 + if (!IsServer(sptr) && MyConnect(sptr)) /* bad expiration time */
1221 + send_reply(sptr, ERR_BADEXPIRE, expire - CurrentTime);
1222 + if (expire - CurrentTime <= 0) /* no point in going further */
1223 + /* TODO: same as in split_add - check lifetime? */
1226 + flags |= SPLIT_EXPIRE;
1228 + flags &= ~SPLIT_EXPIRE;
1230 + /* Next, check out lifetime */
1231 + if (!(flags & SPLIT_LIFETIME) || !lifetime)
1232 + lifetime = split->sp_lifetime; /* use Split lifetime */
1234 + lifetime = IRCD_MAX(lifetime, expire); /* set lifetime to the max */
1236 + /* OK, let's see which is greater... */
1237 + if (lifetime > split->sp_lifetime)
1238 + flags |= SPLIT_LIFETIME; /* have to update lifetime */
1240 + flags &= ~SPLIT_LIFETIME; /* no change to lifetime */
1244 + /* Finally, let's see if the reason needs to be updated */
1245 + /* TODO: (reason) or use != NULL / 0 ? */
1246 + if ((flags & SPLIT_REASON) && reason &&
1247 + ircd_strcmp(split->sp_reason, reason) != 0)
1248 + flags &= ~SPLIT_REASON; /* no changes to the reason */
1250 + /* OK, now let's take a look at the action... */
1251 + if ((action == SPLIT_ACTIVATE && SplitIsActive(split)) ||
1252 + (action == SPLIT_DEACTIVATE && !SplitIsActive(split)) ||
1253 + /* can't activate an expired split entry */
1254 + (IRCD_MAX(split->sp_expire, expire) <= CurrentTime))
1255 + action = SPLIT_MODIFY; /* no activity state modifications */
1257 + Debug((DEBUG_DEBUG, "About to perform changes; flags 0x%04x, action %s",
1258 + flags, action == SPLIT_ACTIVATE ? "SPLIT_ACTIVATE" :
1259 + (action == SPLIT_DEACTIVATE ? "SPLIT_DEACTIVATE" :
1260 + (action == SPLIT_MODIFY ? "SPLIT_MODIFY" : "<UNKNOWN>"))));
1262 + /* If there are no changes to perform, do no changes */
1263 + if (!(flags & SPLIT_UPDATE) && action == SPLIT_MODIFY)
1266 + /* Start by updating lastmod, if indicated... */
1267 + split->sp_lastmod = lastmod;
1269 + /* Then move on to activity status changes... */
1271 + case SPLIT_ACTIVATE: /* activating split entry */
1272 + split->sp_flags |= SPLIT_ACTIVE; /* make it active... */
1273 + pos += ircd_snprintf(0, buf, sizeof(buf), " activating SPLIT");
1276 + case SPLIT_DEACTIVATE: /* deactivating split entry */
1277 + split->sp_flags &= ~SPLIT_ACTIVE; /* make it inactive... */
1278 + pos += ircd_snprintf(0, buf, sizeof(buf), " deactivating SPLIT");
1281 + case SPLIT_MODIFY: /* no change to activity status */
1285 + /* Handle expiration changes... */
1286 + if (flags & SPLIT_EXPIRE) {
1287 + split->sp_expire = expire; /* save new expiration time */
1288 + if (pos < BUFSIZE)
1289 + pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
1290 + "%s%s changing expiration time to %Tu",
1292 + pos && !(flags & (SPLIT_LIFETIME | SPLIT_REASON)) ?
1293 + " and" : "", expire);
1296 + /* Next, handle lifetime changes... */
1297 + if (flags & SPLIT_LIFETIME) {
1298 + split->sp_lifetime = lifetime; /* save new lifetime */
1299 + if (pos < BUFSIZE)
1300 + pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
1301 + "%s%s extending record lifetime to %Tu",
1302 + pos ? ";" : "", pos && !(flags & SPLIT_REASON) ?
1303 + " and" : "", lifetime);
1306 + /* Now, handle reason changes... */
1307 + if (flags & SPLIT_REASON) {
1308 + MyFree(split->sp_reason); /* release old reason */
1309 + DupString(split->sp_reason, reason); /* store new reason */
1310 + if (pos < BUFSIZE)
1311 + pos += ircd_snprintf(0, buf + pos, sizeof(buf) - pos,
1312 + "%s%s changing reason to \"%s\"",
1313 + pos ? ";" : "", pos ? " and" : "", reason);
1316 + /* All right, inform ops... */
1317 + sendto_opmask_butone(0, SNO_NETWORK, "%s modifying SPLIT for %s:%s",
1318 + (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
1319 + cli_name(sptr) : cli_name((cli_user(sptr))->server),
1320 + split->sp_server, buf);
1322 + /* TODO: add SPLIT log stuff or use JUPE? */
1323 + /* and log the change */
1324 + log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
1325 + "%#C modifying SPLIT for %s:%s",
1326 + sptr, split->sp_server, buf);
1328 + /* and propagate it */
1329 + split_propagate(cptr, sptr, split, NULL);
1335 +/** Remove a split entry.
1336 + * @param[in] cptr Local client that sent us the split entry.
1337 + * @param[in] sptr Originator of the split entry.
1338 + * @param[in] split Split entry to remove.
1339 + * @param[in] reason Reason for removing this split entry.
1343 +split_remove(struct Client *cptr, struct Client *sptr, struct Split *split, const char *reason)
1345 + unsigned int saveflags = 0;
1347 + assert(0 != split);
1348 + assert(NULL != cptr);
1349 + assert(NULL != sptr);
1351 + Debug((DEBUG_DEBUG, "split_remove(\"%s\", \"%s\", \"%s\", \"%s\")",
1352 + cli_name(cptr), cli_name(sptr), split->sp_server, reason));
1354 + /* deactivate entry and mark it for removal (used in split_propagate) */
1355 + split->sp_flags |= SPLIT_REMOVING;
1356 + /* CHECK: turn bit SPLIT_ACTIVE off? */
1357 + split->sp_flags |= SPLIT_ACTIVE;
1359 + /* inform ops and log it */
1360 + sendto_opmask_butone(0, SNO_NETWORK, "%s removing SPLIT for %s, expiring at %Tu: %s (%s)",
1361 + (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
1362 + cli_name(sptr) : cli_name((cli_user(sptr))->server),
1363 + split->sp_server, split->sp_expire, split->sp_reason, reason);
1365 + /* TODO: add SPLIT log stuff or use JUPE? */
1366 + log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
1367 + "%#C removing SPLIT for %s, expiring at %Tu: %s (%s)",
1368 + sptr, split->sp_server, split->sp_expire, split->sp_reason, reason);
1370 + /* TODO: the reason supplied for removing this SPLIT does not go upstream
1371 + * either propagate manually here, or update the record or?
1373 + /* propagate it */
1374 + split_propagate(cptr, sptr, split, reason);
1377 + split_free(split);
1383 +/** Find a split entry by name.
1384 + * @param[in] server Split entry name to search for.
1385 + * @return Matching split entry (or NULL if none match).
1388 +split_find(char *server)
1390 + struct Split* split;
1391 + struct Split* ssplit;
1393 + for (split = GlobalSplitList; split; split = ssplit) { /* go through splits */
1394 + ssplit = split->sp_next;
1396 + if (split_expire(split)) /* expire any that need expiring */
1397 + split_free(split);
1398 + else if (0 == ircd_strcmp(server, split->sp_server)) /* found it yet? */
1401 + /* TODO: we return 0 not NULL? */
1405 +/** Unlink and free an unused split entry.
1406 + * @param[in] split Server split entry to free.
1409 +split_free(struct Split* split)
1411 + /* TODO: use 0 or NULL ? */
1412 + assert(0 != split);
1414 + *split->sp_prev_p = split->sp_next; /* squeeze this split entry out */
1415 + if (split->sp_next)
1416 + split->sp_next->sp_prev_p = split->sp_prev_p;
1418 + /* CHECK: the other fields in this struct are destroyed with MyFree() call? */
1419 + MyFree(split->sp_server); /* and free up the memory */
1420 + MyFree(split->sp_reason);
1425 +/** Check whether a split entry has past its life time.
1426 + * when entry is active and past expire time, but not life time, deactivate it
1427 + * @param[in] split Server split entry to check.
1428 + * @return 1 when entry can be free'd, 0 otherwise.
1431 +split_expire(struct Split* split)
1433 + assert(0 != split);
1435 + /* past lifetime */
1436 + if (split->sp_lifetime <= CurrentTime)
1439 + /* past expire time, deactivate entry if it is active */
1440 + if ((split->sp_expire <= CurrentTime) && SplitIsActive(split))
1441 + /* CHECK: turn bit SPLIT_ACTIVE off */
1442 + split->sp_flags &= SPLIT_ACTIVE;
1447 +/** Send the full list of split entries to \a cptr.
1448 + * @param[in] cptr Local server to send split entries to.
1451 +split_burst(struct Client *cptr)
1453 + struct Split *split;
1454 + struct Split *ssplit;
1456 + assert(NULL != cptr);
1458 + for (split = GlobalSplitList; split; split = ssplit) { /* go through splits */
1459 + ssplit = split->sp_next;
1461 + /* expire any that need expiring */
1462 + if (split_expire(split))
1463 + split_free(split);
1464 + /* if we have an entry for cptr, dont send it - but do not free here yet
1465 + * free it at end of burst, to get the correct count for SPLITs removed.
1467 + else if (ircd_strcmp(split->sp_server, cli_name(cptr)) == 0)
1470 + sendcmdto_one(&me, CMD_SPLIT, cptr, "%c%s %Tu %Tu %Tu %Tu :%s",
1471 + SplitIsActive(split) ? '+' : '-', split->sp_server,
1472 + split->sp_creation, split->sp_expire,
1473 + split->sp_lastmod, split->sp_lifetime,
1474 + split->sp_reason);
1478 +/** Forward a split to another server.
1479 + * @param[in] cptr Server to send split entries to.
1480 + * @param[in] split Split to forward.
1484 +split_resend(struct Client *cptr, struct Split *split)
1486 + sendcmdto_one(&me, CMD_SPLIT, cptr, "%c%s %Tu %Tu %Tu %Tu :%s",
1487 + SplitIsActive(split) ? '+' : '-', split->sp_server,
1488 + split->sp_creation, split->sp_expire,
1489 + split->sp_lastmod, split->sp_lifetime,
1490 + split->sp_reason);
1495 +/** Send a split entry (or a list of split entries) to a server.
1496 + * @param[in] sptr Client searching for split entries.
1497 + * @param[in] server Name of split entry to search for (if NULL, list all).
1501 +split_list(struct Client *sptr, char *server)
1503 + struct Split *split;
1504 + struct Split *ssplit;
1506 + assert(NULL != sptr);
1508 + /* TODO: wildcard matching? */
1510 + if (!(split = split_find(server))) /* no such split */
1511 + return send_reply(sptr, ERR_NOSUCHSPLIT, server);
1513 + /* send split information along */
1514 + send_reply(sptr, RPL_SPLITLIST, split->sp_server,
1515 + split->sp_creation, split->sp_expire,
1516 + split->sp_lastmod, split->sp_lifetime,
1517 + SplitIsActive(split) ? '+' : '-', split->sp_reason);
1519 + for (split = GlobalSplitList; split; split = ssplit) { /* go through splits */
1520 + ssplit = split->sp_next;
1522 + if (split_expire(split)) /* expire any that need expiring */
1523 + split_free(split);
1524 + else /* send split information along */
1525 + send_reply(sptr, RPL_SPLITLIST, split->sp_server,
1526 + split->sp_creation, split->sp_expire,
1527 + split->sp_lastmod, split->sp_lifetime,
1528 + SplitIsActive(split) ? '+' : '-', split->sp_reason);
1532 + /* end of splitlist information */
1533 + return send_reply(sptr, RPL_ENDOFSPLITLIST);
1537 +/** Auto destroy SPLITs for servers gained in a netmerge
1538 + * @param[in] cptr Server that link to the network
1539 + * @return Number of destroyed SPLITs
1542 +split_merge(struct Client *server)
1545 + struct Split *split;
1548 + assert(NULL != server);
1550 + Debug((DEBUG_DEBUG, "split_merge(\"%s\")", cli_name(server)));
1552 + /* find the SPLIT for this server */
1553 + if ((split = split_find(cli_name(server)))) {
1554 + split_free(split);
1558 + /* go over its downlinks */
1559 + for (lp = cli_serv(server)->down; lp; lp = lp->next)
1560 + count += split_merge(lp->value.cptr);
1565 +/** Auto create SPLITs for servers lost in a netbreak
1566 + * @param[in] server Server that lost link to network
1567 + * @param[in] reason Reason to add to SPLITs
1568 + * @return Number of created SPLITs
1571 +split_break(struct Client *server, const char *reason)
1574 + struct Split *split;
1576 + time_t creation = CurrentTime, expire = CurrentTime + SPLIT_AUTO_EXPIRE,
1577 + lastmod = CurrentTime, lifetime = expire;
1578 + unsigned int flags = SPLIT_ACTIVE;
1580 + assert(NULL != server);
1582 + Debug((DEBUG_DEBUG, "split_break(\"%s\", \"%s\")", cli_name(server), reason));
1584 + /* find the SPLIT for this server */
1585 + if (!(split = split_find(cli_name(server)))) {
1586 + split_make(cli_name(server), reason, creation, expire, lastmod, lifetime, flags);
1590 + /* go over its downlinks */
1591 + for (lp = cli_serv(server)->down; lp; lp = lp->next)
1592 + count += split_break(lp->value.cptr, reason);
1597 +/** Auto create SPLITs for servers we have a Connect Block for
1603 + struct ConfItem *conf;
1604 + struct Client *server;
1605 + struct Split *split;
1606 + struct Split *asplit;
1607 + time_t creation = CurrentTime, expire = CurrentTime + SPLIT_AUTO_EXPIRE,
1608 + lastmod = CurrentTime, lifetime = expire;
1609 + unsigned int flags = SPLIT_ACTIVE;
1610 + char reason[BUFSIZE];
1612 + Debug((DEBUG_DEBUG, "split_conf()"));
1614 + /* we are not set to generate SPLITs */
1615 + if (!feature_bool(FEAT_SPLIT))
1618 + ircd_snprintf(0, reason, sizeof(reason),
1619 + "Generated upon loading conf file on %s", cli_name(&me));
1621 + /* go over the conf contents */
1622 + for (conf = GlobalConfList; conf; conf = conf->next) {
1623 + /* not a Connect Block */
1624 + if (CONF_SERVER != conf->status)
1626 + /* server is linked */
1627 + if (server = FindServer(conf->name))
1629 + /* we have a SPLIT for this server already */
1630 + if (split = split_find(conf->name))
1632 + /* inform ops and log it */
1633 + sendto_opmask_butone(0, SNO_NETWORK, "%C adding SPLIT for %s, expiring at %Tu: %s",
1634 + &me, conf->name, expire, reason);
1636 + /* TODO: add SPLIT log stuff or use JUPE? */
1637 + log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
1638 + "%C adding SPLIT for %s, expiring at %Tu: %s",
1639 + &me, conf->name, expire, reason);
1641 + /* make the split entry */
1642 + asplit = split_make(conf->name, reason, creation, expire, lastmod, lifetime, flags);
1646 + /* and propagate it */
1647 + split_propagate(&me, &me, asplit, NULL);
1652 +/** Statistics callback to list SPLITs.
1653 + * @param[in] sptr Client requesting statistics.
1654 + * @param[in] sd Stats descriptor for request (ignored).
1655 + * @param[in] param Extra parameter from user (ignored).
1658 +split_stats(struct Client *sptr, const struct StatDesc *sd,
1661 + struct Split *split;
1662 + struct Split *ssplit;
1664 + send_reply(sptr, SND_EXPLICIT | RPL_STATSSPLIT,
1665 + "S servername creation expire lastmod lifetime active :reason");
1666 + for (split = GlobalSplitList; split; split = split->sp_next)
1667 + send_reply(sptr, RPL_STATSSPLIT, split->sp_server,
1668 + split->sp_creation, split->sp_expire, split->sp_lastmod, split->sp_lifetime,
1669 + SplitIsActive(split) ? '+' : '-', split->sp_reason);
1673 +/** Count split entries and memory used by them.
1674 + * @param[out] sp_size Receives total number of bytes allocated for split entries.
1675 + * @return Number of split entries currently allocated.
1678 +split_memory_count(size_t *sp_size)
1680 + struct Split *split;
1681 + unsigned int sp = 0;
1683 + /* TODO: check for expired entries? */
1684 + for (split = GlobalSplitList; split; split = split->sp_next)
1687 + *sp_size += sizeof(struct Split);
1688 + *sp_size += split->sp_server ? (strlen(split->sp_server) + 1) : 0;
1689 + *sp_size += split->sp_reason ? (strlen(split->sp_reason) + 1) : 0;