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