]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blame - welcome.patch
welcome: add define WELCOMELEN instead of directly using TOPICLEN
[irc/quakenet/snircd-patchqueue.git] / welcome.patch
CommitLineData
a87bc2c2 1Add welcome message functionality.
2
3client commands:
4user:
5/WELCOME
6shows welcome messages set, same is shown on connect
7
8oper:
9/WELCOME [<target>] [[!]<name> :<message>]
10to view welcome messages from a remote server
11to set a local welcome message on this server or a remote server
12set a global welcome message (target *)
13the ! prefix makes the server annouce the welcome message to its clients when setting
14
15server:
cb0b5df1 16:<source> WE <target> [[!]<name> <timestamp> <who> :<text>]
a87bc2c2 17who is who set the message, the server puts in the opername when a client sets it.
cb0b5df1 18:<name> is a number 1 to WELCOME_MAX_ENTRIES - currently set at 10 (should be more than we ever need)
a87bc2c2 19that means there is room for 10 local and 10 global entries
a87bc2c2 20
cb0b5df1 21STATS W/welcome (/STATS w/userload made case sensitive)
a87bc2c2 22:server 230 nick W Name Target Who Timestamp :Message
23:server 227 nick W 1 * opername 1233072583 :Latest news: testing this welcome patch :)
24:server 227 nick W 2 * opername 1233072583 :
25:server 227 nick W 1 servername opername 1233072590 :This is a test server, expect restarts.
26:server 219 nick W :End of /STATS report
27
28listing welcomes or on connect:
29:server NOTICE nick :[QuakeNet] Latest news: testing this welcome patch :)
30:server NOTICE nick :[server] This is a test server, expect restarts.
31
32announcement is done by a notice by the local server to $* with the same message
33format as for listing welcome messages.
34:server NOTICE $* :[QuakeNet] Latest news: testing this welcome patch :)
35:server NOTICE $* :[server] This is a test server, expect restarts.
36
37
38Files:
39
40include/handlers.h
41add m_welcome mo_welcome ms_welcome mh_welcome functions
42
43include/features.h
44ircd/features.c
45add features FEAT_WELCOME and FEAT_HIS_STATS_W
46
47include/msg.h
48add MSG_WELCOME TOK_WELCOME CMD_WELCOME
49
50ircd/parse.c
51add welcome message functions
52
53include/numeric.h
54ircd/s_err.c
55add RPL_STATSWELCOME ERR_NOSUCHWELCOME
56
57include/welcome.h
58ircd/welcome.c
59ircd/m_welcome.c
60new
61
62ircd/Makefile.in
63add welcome.c and m_welcome.c files
64
a87bc2c2 65ircd/s_serv.c
66add burst welcome message
67
68ircd/s_stats.c
69add /STATS W/welcome
70
71ircd/s_user.c
72add showing of welcome messages on connect
73
db0ccf80 74include/client.h
75ircd/client.c
76ircd/ircd_lexer.l
77ircd/ircd_parser.y
78add PRIV_LOCAL_WELCOME PRIV_WELCOME
79
182f0f64 80diff -r 211f48754a7f include/client.h
5632b943 81--- a/include/client.h
82+++ b/include/client.h
308d3fca 83@@ -142,6 +142,8 @@
84 PRIV_USER_PRIVACY, /* oper can bypass user privacy +x etc gives i.e. see real ip's */
85 PRIV_CHANNEL_PRIVACY, /* oper can bypass channel privacy i.e. can see modes on channels they are not on and channel keys */
86 PRIV_SERVERINFO, /* oper can use /get, /stats, /hash, retrieve remote information */
4e89d808 87+ PRIV_WELCOME, /* oper can WELCOME */
88+ PRIV_LOCAL_WELCOME, /* oper can local WELCOME */
89 PRIV_LAST_PRIV /**< number of privileges */
90 };
91
182f0f64 92diff -r 211f48754a7f include/handlers.h
5632b943 93--- a/include/handlers.h
94+++ b/include/handlers.h
f0f686d6 95@@ -138,6 +138,7 @@
cddf800b 96 extern int m_version(struct Client*, struct Client*, int, char*[]);
97 extern int m_wallchops(struct Client*, struct Client*, int, char*[]);
98 extern int m_wallvoices(struct Client*, struct Client*, int, char*[]);
99+extern int m_welcome(struct Client*, struct Client*, int, char*[]);
100 extern int m_who(struct Client*, struct Client*, int, char*[]);
101 extern int m_whois(struct Client*, struct Client*, int, char*[]);
102 extern int m_whowas(struct Client*, struct Client*, int, char*[]);
f0f686d6 103@@ -172,6 +173,7 @@
cddf800b 104 extern int mo_version(struct Client*, struct Client*, int, char*[]);
105 extern int mo_wallops(struct Client*, struct Client*, int, char*[]);
106 extern int mo_wallusers(struct Client*, struct Client*, int, char*[]);
107+extern int mo_welcome(struct Client*, struct Client*, int, char*[]);
308d3fca 108 extern int mo_xquery(struct Client*, struct Client*, int, char*[]);
cddf800b 109 extern int mr_error(struct Client*, struct Client*, int, char*[]);
110 extern int mr_error(struct Client*, struct Client*, int, char*[]);
f0f686d6 111@@ -230,6 +232,7 @@
cddf800b 112 extern int ms_wallops(struct Client*, struct Client*, int, char*[]);
113 extern int ms_wallusers(struct Client*, struct Client*, int, char*[]);
114 extern int ms_wallvoices(struct Client*, struct Client*, int, char*[]);
115+extern int ms_welcome(struct Client*, struct Client*, int, char*[]);
116 extern int ms_whois(struct Client*, struct Client*, int, char*[]);
308d3fca 117 extern int ms_xquery(struct Client*, struct Client*, int, char*[]);
118 extern int ms_xreply(struct Client*, struct Client*, int, char*[]);
182f0f64 119diff -r 211f48754a7f include/ircd_features.h
5632b943 120--- a/include/ircd_features.h
121+++ b/include/ircd_features.h
a87bc2c2 122@@ -101,6 +101,7 @@
123 FEAT_IRCD_RES_TIMEOUT,
124 FEAT_AUTH_TIMEOUT,
125 FEAT_ANNOUNCE_INVITES,
126+ FEAT_WELCOME,
127
128 /* features that affect all operators */
129 FEAT_EXTENDED_CHECKCMD,
308d3fca 130@@ -142,6 +143,7 @@
a87bc2c2 131 FEAT_HIS_STATS_u,
132 FEAT_HIS_STATS_U,
133 FEAT_HIS_STATS_v,
134+ FEAT_HIS_STATS_W,
135 FEAT_HIS_STATS_w,
136 FEAT_HIS_STATS_x,
137 FEAT_HIS_STATS_y,
182f0f64 138diff -r 211f48754a7f include/msg.h
5632b943 139--- a/include/msg.h
140+++ b/include/msg.h
308d3fca 141@@ -196,6 +196,10 @@
cddf800b 142 #define TOK_NOTICE "O"
143 #define CMD_NOTICE MSG_NOTICE, TOK_NOTICE
100a7f47 144
cddf800b 145+#define MSG_WELCOME "WELCOME" /* WELC */
146+#define TOK_WELCOME "WE"
147+#define CMD_WELCOME MSG_WELCOME, TOK_WELCOME
100a7f47 148+
cddf800b 149 #define MSG_WALLCHOPS "WALLCHOPS" /* WC */
150 #define TOK_WALLCHOPS "WC"
100a7f47 151 #define CMD_WALLCHOPS MSG_WALLCHOPS, TOK_WALLCHOPS
182f0f64 152diff -r 211f48754a7f include/numeric.h
5632b943 153--- a/include/numeric.h
154+++ b/include/numeric.h
a87bc2c2 155@@ -116,6 +116,7 @@
156 RPL_STATSGLINE 227 Dalnet
157 RPL_STATSVLINE 227 unreal */
158 #define RPL_STATSALINE 226 /* Hybrid, Undernet */
159+#define RPL_STATSWELCOME 227 /* QuakeNet extension */
160 #define RPL_STATSQLINE 228 /* Undernet extension */
a87bc2c2 161
308d3fca 162 /* RPL_SERVICEINFO 231 unused */
163@@ -440,6 +441,8 @@
a87bc2c2 164 /* ERR_GHOSTEDCLIENT 503 efnet */
165 /* ERR_VWORLDWARN 503 austnet */
166
167+#define ERR_NOSUCHWELCOME 509 /* QuakeNet extension */
168+
169 #define ERR_SILELISTFULL 511 /* Undernet extension */
170 /* ERR_NOTIFYFULL 512 aircd */
171 /* ERR_TOOMANYWATCH 512 Numeric List: Dalnet */
182f0f64 172diff -r 211f48754a7f include/welcome.h
5632b943 173--- /dev/null
174+++ b/include/welcome.h
a7f8ae30 175@@ -0,0 +1,62 @@
cddf800b 176+#ifndef INCLUDED_welcome_h
177+#define INCLUDED_welcome_h
178+/*
179+ * IRC - Internet Relay Chat, include/welcome.h
180+ * Copyright (C) 1990 Jarkko Oikarinen and
181+ * University of Oulu, Computing Center
182+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
183+ *
184+ * This program is free software; you can redistribute it and/or modify
185+ * it under the terms of the GNU General Public License as published by
186+ * the Free Software Foundation; either version 2, or (at your option)
187+ * any later version.
188+ *
189+ * This program is distributed in the hope that it will be useful,
190+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
191+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
192+ * GNU General Public License for more details.
193+ *
194+ * You should have received a copy of the GNU General Public License
195+ * along with this program; if not, write to the Free Software
196+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
197+ */
198+/** @file
a87bc2c2 199+ * @brief Interface and declarations for welcome message handling.
cddf800b 200+ */
201+#ifndef INCLUDED_sys_types_h
202+#include <sys/types.h>
203+#define INCLUDED_sys_types_h
204+#endif
205+
a87bc2c2 206+struct Client;
207+struct StatDesc;
208+
cb0b5df1 209+/* Maximum number of welcome entries (per type; X global, X local) */
6dd3e24f 210+#define WELCOME_MAX_ENTRIES 10
a7f8ae30 211+/* Maximum length of a welcome message */
212+#define WELCOMELEN TOPICLEN
6dd3e24f 213+/* Maximum timestamp drift in seconds allowed ahead of our idea of nettime
214+ * before we throw a warning to ops
215+ */
216+#define WELCOME_MAX_DRIFT 600
a87bc2c2 217+
218+/* Describes a Welcome message entry. */
219+struct Welcome {
6dd3e24f 220+ time_t timestamp; /**< Timestamp of the welcome */
a7f8ae30 221+ char text[WELCOMELEN + 1]; /**< Message */
6dd3e24f 222+ char who[ACCOUNTLEN + 1]; /**< Who set it */
a87bc2c2 223+};
224+
cb0b5df1 225+/** Welcome type flags */
a87bc2c2 226+#define WELCOME_LOCAL 0x01 /**< welcome is local */
227+/** Welcome action flags */
228+#define WELCOME_ANNOUNCE 0x02 /**< announce change to users */
229+
a87bc2c2 230+extern int welcome_do(struct Client *cptr, struct Client *sptr, char *name, char *text,
231+ char *who, time_t timestamp, unsigned int flags);
cb0b5df1 232+extern void welcome_announce(int name);
cddf800b 233+extern void welcome_burst(struct Client *cptr);
a87bc2c2 234+extern int welcome_list(struct Client *sptr, int connect);
235+extern void welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param);
cddf800b 236+
237+#endif /* INCLUDED_welcome_h */
182f0f64 238diff -r 211f48754a7f ircd/Makefile.in
5632b943 239--- a/ircd/Makefile.in
240+++ b/ircd/Makefile.in
308d3fca 241@@ -186,6 +186,7 @@
a87bc2c2 242 m_wallops.c \
243 m_wallusers.c \
244 m_wallvoices.c \
245+ m_welcome.c \
246 m_who.c \
247 m_whois.c \
248 m_whowas.c \
dcd0ea31 249@@ -215,6 +216,7 @@
a87bc2c2 250 send.c \
251 uping.c \
252 userload.c \
253+ welcome.c \
254 whocmds.c \
255 whowas.c \
256 y.tab.c
308d3fca 257@@ -1161,6 +1163,11 @@
a87bc2c2 258 ../include/ircd_reply.h ../include/ircd_string.h \
259 ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
260 ../include/numnicks.h ../include/s_user.h ../include/send.h
261+m_welcome.o: m_welcome.c ../config.h ../include/channel.h \
262+ ../include/client.h ../include/hash.h ../include/ircd.h ../include/ircd_log.h \
263+ ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
264+ ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
265+ ../include/send.h ../include/welcome.h
266 m_who.o: m_who.c ../config.h ../include/channel.h ../include/ircd_defs.h \
267 ../include/res.h ../config.h ../include/client.h ../include/dbuf.h \
268 ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
308d3fca 269@@ -1422,6 +1429,13 @@
a87bc2c2 270 ../include/numnicks.h ../include/querycmds.h ../include/ircd_features.h \
271 ../include/s_misc.h ../include/s_stats.h ../include/send.h \
272 ../include/struct.h ../include/sys.h
273+welcome.o: welcome.c ../config.h ../include/client.h \
274+ ../include/hash.h ../include/ircd.h ../include/ircd_alloc.h \
275+ ../include/ircd_features.h ../include/ircd_log.h ../include/ircd_reply.h \
276+ ../include/match.h ../include/msg.h ../include/numeric.h \
277+ ../include/numnicks.h ../include/s_debug.h ../include/s_bsd.h \
278+ ../include/s_misc.h ../include/send.h ../include/struct.h \
279+ ../include/sys.h ../include/welcome.h
280 whocmds.o: whocmds.c ../config.h ../include/whocmds.h \
281 ../include/channel.h ../include/ircd_defs.h ../include/res.h \
282 ../config.h ../include/client.h ../include/dbuf.h ../include/msgq.h \
182f0f64 283diff -r 211f48754a7f ircd/client.c
5632b943 284--- a/ircd/client.c
285+++ b/ircd/client.c
308d3fca 286@@ -177,6 +177,7 @@
4e89d808 287 FlagSet(&privs_local, PRIV_WHOX);
288 FlagSet(&privs_local, PRIV_DISPLAY);
289 FlagSet(&privs_local, PRIV_FORCE_LOCAL_OPMODE);
290+ FlagSet(&privs_local, PRIV_LOCAL_WELCOME);
308d3fca 291
292 privs_defaults_set = 1;
293 }
294@@ -223,6 +224,7 @@
295 ClrPriv(client, PRIV_JUPE);
4e89d808 296 ClrPriv(client, PRIV_OPMODE);
4e89d808 297 ClrPriv(client, PRIV_BADCHAN);
298+ ClrPriv(client, PRIV_WELCOME);
299 }
308d3fca 300 }
301
302@@ -244,7 +246,7 @@
303 P(CHANSERV), P(XTRA_OPER), P(NOIDLE), P(FREEFORM),
304 P(PARANOID), P(CHECK), P(WALL), P(CLOSE),
305 P(ROUTE), P(ROUTEINFO), P(SERVERINFO), P(CHANNEL_PRIVACY),
306- P(USER_PRIVACY),
307+ P(USER_PRIVACY), P(WELCOME), P(LOCAL_WELCOME),
4e89d808 308 #undef P
309 { 0, 0 }
310 };
182f0f64 311diff -r 211f48754a7f ircd/ircd_features.c
5632b943 312--- a/ircd/ircd_features.c
313+++ b/ircd/ircd_features.c
e721b9bb 314@@ -366,6 +366,7 @@
a87bc2c2 315 F_I(IRCD_RES_TIMEOUT, 0, 4, 0),
316 F_I(AUTH_TIMEOUT, 0, 9, 0),
317 F_B(ANNOUNCE_INVITES, 0, 0, 0),
318+ F_B(WELCOME, 0, 1, 0),
319
320 /* features that affect all operators */
321 F_B(EXTENDED_CHECKCMD, 0, 0, 0),
308d3fca 322@@ -407,6 +408,7 @@
a87bc2c2 323 F_B(HIS_STATS_u, 0, 1, 0),
324 F_B(HIS_STATS_U, 0, 1, 0),
325 F_B(HIS_STATS_v, 0, 1, 0),
326+ F_B(HIS_STATS_W, 0, 1, 0),
327 F_B(HIS_STATS_w, 0, 1, 0),
328 F_B(HIS_STATS_x, 0, 1, 0),
329 F_B(HIS_STATS_y, 0, 1, 0),
182f0f64 330diff -r 211f48754a7f ircd/ircd_lexer.l
5632b943 331--- a/ircd/ircd_lexer.l
332+++ b/ircd/ircd_lexer.l
308d3fca 333@@ -166,6 +166,8 @@
334 { "serverinfo", TPRIV_SERVERINFO },
335 { "user_privacy", TPRIV_USER_PRIVACY },
336 { "channel_privacy", TPRIV_CHANNEL_PRIVACY },
4e89d808 337+ { "local_welcome", TPRIV_LOCAL_WELCOME },
338+ { "welcome", TPRIV_WELCOME },
339 { NULL, 0 }
340 };
341 static int ntokens;
182f0f64 342diff -r 211f48754a7f ircd/ircd_parser.y
5632b943 343--- a/ircd/ircd_parser.y
344+++ b/ircd/ircd_parser.y
308d3fca 345@@ -189,6 +189,7 @@
346 %token TPRIV_CHANSERV TPRIV_XTRA_OPER TPRIV_NOIDLE TPRIV_FREEFORM TPRIV_PARANOID
347 %token TPRIV_CHECK TPRIV_WALL TPRIV_CLOSE TPRIV_ROUTE TPRIV_ROUTEINFO TPRIV_SERVERINFO
348 %token TPRIV_CHANNEL_PRIVACY TPRIV_USER_PRIVACY TPRIV_LIST_CHAN
dcd0ea31 349+%token TPRIV_LOCAL_WELCOME TPRIV_WELCOME
4e89d808 350 /* and some types... */
351 %type <num> sizespec
352 %type <num> timespec timefactor factoredtimes factoredtime
308d3fca 353@@ -703,6 +704,8 @@
354 TPRIV_SERVERINFO { $$ = PRIV_SERVERINFO ; } |
355 TPRIV_CHANNEL_PRIVACY { $$ = PRIV_CHANNEL_PRIVACY ; } |
356 TPRIV_USER_PRIVACY { $$ = PRIV_USER_PRIVACY ; } |
4e89d808 357+ TPRIV_LOCAL_WELCOME { $$ = PRIV_LOCAL_WELCOME; } |
358+ TPRIV_WELCOME { $$ = PRIV_WELCOME; } |
359 TPRIV_PARANOID { $$ = PRIV_PARANOID; } ;
360 yesorno: YES { $$ = 1; } | NO { $$ = 0; };
361
182f0f64 362diff -r 211f48754a7f ircd/m_welcome.c
5632b943 363--- /dev/null
364+++ b/ircd/m_welcome.c
d2e4469e 365@@ -0,0 +1,284 @@
cddf800b 366+/*
367+ * IRC - Internet Relay Chat, ircd/m_welcome.c
368+ * Copyright (C) 1990 Jarkko Oikarinen and
369+ * University of Oulu, Computing Center
370+ *
371+ * See file AUTHORS in IRC package for additional names of
372+ * the programmers.
373+ *
374+ * This program is free software; you can redistribute it and/or modify
375+ * it under the terms of the GNU General Public License as published by
376+ * the Free Software Foundation; either version 1, or (at your option)
377+ * any later version.
378+ *
379+ * This program is distributed in the hope that it will be useful,
380+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
381+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
382+ * GNU General Public License for more details.
383+ *
384+ * You should have received a copy of the GNU General Public License
385+ * along with this program; if not, write to the Free Software
386+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
387+ *
cddf800b 388+ */
389+
390+/*
391+ * m_functions execute protocol messages on this server:
392+ *
393+ * cptr is always NON-NULL, pointing to a *LOCAL* client
394+ * structure (with an open socket connected!). This
395+ * identifies the physical socket where the message
396+ * originated (or which caused the m_function to be
397+ * executed--some m_functions may call others...).
398+ *
399+ * sptr is the source of the message, defined by the
400+ * prefix part of the message if present. If not
401+ * or prefix not found, then sptr==cptr.
402+ *
403+ * (!IsServer(cptr)) => (cptr == sptr), because
404+ * prefixes are taken *only* from servers...
405+ *
406+ * (IsServer(cptr))
407+ * (sptr == cptr) => the message didn't
408+ * have the prefix.
409+ *
410+ * (sptr != cptr && IsServer(sptr) means
411+ * the prefix specified servername. (?)
412+ *
413+ * (sptr != cptr && !IsServer(sptr) means
414+ * that message originated from a remote
415+ * user (not local).
416+ *
417+ * combining
418+ *
419+ * (!IsServer(sptr)) means that, sptr can safely
420+ * taken as defining the target structure of the
421+ * message in this server.
422+ *
423+ * *Always* true (if 'parse' and others are working correct):
424+ *
425+ * 1) sptr->from == cptr (note: cptr->from == cptr)
426+ *
427+ * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
428+ * *cannot* be a local connection, unless it's
429+ * actually cptr!). [MyConnect(x) should probably
430+ * be defined as (x == x->from) --msa ]
431+ *
432+ * parc number of variable parameter strings (if zero,
433+ * parv is allowed to be NULL)
434+ *
435+ * parv a NULL terminated list of parameter pointers,
436+ *
437+ * parv[0], sender (prefix string), if not present
438+ * this points to an empty string.
439+ * parv[1]...parv[parc-1]
440+ * pointers to additional parameters
441+ * parv[parc] == NULL, *always*
442+ *
443+ * note: it is guaranteed that parv[0]..parv[parc-1] are all
444+ * non-NULL pointers.
445+ */
446+#include "config.h"
447+
448+#include "channel.h"
449+#include "client.h"
450+#include "hash.h"
451+#include "ircd.h"
a87bc2c2 452+#include "ircd_features.h"
cddf800b 453+#include "ircd_log.h"
454+#include "ircd_reply.h"
5bb41778 455+#include "ircd_snprintf.h"
cddf800b 456+#include "ircd_string.h"
457+#include "msg.h"
458+#include "numeric.h"
459+#include "numnicks.h"
460+#include "s_user.h"
461+#include "send.h"
a87bc2c2 462+#include "welcome.h"
cddf800b 463+
464+/* #include <assert.h> -- Now using assert in ircd_log.h */
465+
466+/*
467+ * m_welcome - local generic message handler
468+ *
469+ * parv[0] = Send prefix
6dd3e24f 470+ * parv[1] = [remote server to query]
cddf800b 471+ */
472+int m_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
473+{
a87bc2c2 474+ /* feature disabled */
475+ if (!feature_bool(FEAT_WELCOME))
476+ return send_reply(sptr, ERR_DISABLED, "WELCOME");
6dd3e24f 477+
478+ /* only opers can set the welcome messages */
479+ if (parc > 2)
480+ return send_reply(sptr, ERR_NOPRIVILEGES);
481+
482+ /* remote listing request, see if it is for me or a remote server
483+ * check FEAT_HIS_REMOTE to decide if an ordinary user can do this
484+ */
5632b943 485+ if ((parc > 1) && (hunt_server_cmd(sptr, CMD_WELCOME, cptr, feature_int(FEAT_HIS_REMOTE),
486+ "%C", 1, parc, parv) != HUNTED_ISME))
487+ return 0;
6dd3e24f 488+
5632b943 489+ /* local listing */
a87bc2c2 490+ return welcome_list(sptr, 0);
cddf800b 491+}
492+
493+
494+/*
495+ * mo_welcome - oper message handler
496+ *
497+ * listing:
498+ * parv[0] = Send prefix
499+ *
500+ * remote listing:
501+ * parv[0] = Send prefix
502+ * parv[1] = Target
503+ *
504+ * set global or on remote server:
505+ * parv[0] = Send prefix
6dd3e24f 506+ * parv[1] = Target: server or * for global (or left out for this server)
a87bc2c2 507+ * parv[2] = Name
508+ * parv[3] = Text
cddf800b 509+ */
510+int mo_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
511+{
cb0b5df1 512+ char *target, *name, *who, *text, pattern[BUFSIZE];
a87bc2c2 513+ time_t timestamp;
514+ unsigned int flags = 0;
6dd3e24f 515+ int local = 0;
a87bc2c2 516+
517+ /* feature disabled */
518+ if (!feature_bool(FEAT_WELCOME))
519+ return send_reply(sptr, ERR_DISABLED, "WELCOME");
520+
4e89d808 521+ /* TODO: move feature check here? */
a87bc2c2 522+ /* remote listing request, see if it is for me or a remote server */
5632b943 523+ if ((parc == 2) && (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME))
524+ return 0;
525+
526+ /* local listing */
527+ if (parc <= 2)
a87bc2c2 528+ return welcome_list(sptr, 0);
4e89d808 529+
530+ /* check PRIVS */
531+ /* local - need PRIV LOCAL_WELCOME or WELCOME */
532+ if (parc == 3 && !HasPriv(sptr,PRIV_LOCAL_WELCOME) && !HasPriv(sptr,PRIV_WELCOME))
533+ return send_reply(sptr, ERR_NOPRIVILEGES);
534+
535+ /* global or remote - need PRIV WELCOME */
536+ if (parc >= 4 && !HasPriv(sptr,PRIV_WELCOME))
537+ return send_reply(sptr, ERR_NOPRIVILEGES);
538+
a87bc2c2 539+ /* set the parameters */
6dd3e24f 540+
541+ /* target not given, only name - setting local welcome */
a87bc2c2 542+ if (parc < 4) {
543+ local++;
544+ target = cli_name(&me);
545+ name = parv[1];
546+ flags |= WELCOME_LOCAL;
6dd3e24f 547+
548+ /* target and name given */
549+ } else {
a87bc2c2 550+ target = parv[1];
551+ name = parv[2];
552+ }
553+ timestamp = TStime();
554+ who = cli_user(sptr)->opername;
555+ text = parv[parc - 1];
556+
557+ /* target is not global */
558+ if (!(target[0] == '*' && target[1] == '\0') && !local) {
6dd3e24f 559+
a87bc2c2 560+ /* build a pattern for hunt_server_cmd since we do not have all we need in parv */
561+ ircd_snprintf(0, pattern, sizeof(pattern), "%s %s %Tu %s :%s", "%C", name, timestamp, who, text);
562+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, pattern, 1, 2, parv) != HUNTED_ISME)
563+ return 0;
6dd3e24f 564+
565+ /* else it is a local welcome, for me */
566+ flags |= WELCOME_LOCAL;
a87bc2c2 567+ }
568+
cb0b5df1 569+ /* TODO: disallow global announcement from oper?
570+ * as PRIVMSG/NOTICE to $* is not allowed either by the ircd
571+ * when PRIV for that is added, use that here? PRIV_BROADCAST or something
4e89d808 572+ *
573+ * change prefix to $ ?
cb0b5df1 574+ */
a87bc2c2 575+ /* check for anounce prefix */
576+ if (*name == '!') {
577+ name++;
578+ flags |= WELCOME_ANNOUNCE;
579+ }
580+
581+ /* and do it */
582+ return welcome_do(cptr, sptr, name, text, who, timestamp, flags);
cddf800b 583+}
584+
585+
586+/*
587+ * ms_welcome - server message handler
588+ *
589+ * parv[0] = Send prefix
590+ * parv[1] = Target: server numeric or * for global
a87bc2c2 591+ * parv[2] = Name
592+ * parv[3] = Timestamp
593+ * parv[4] = Who
594+ * parv[5] = Text
cddf800b 595+ */
596+int ms_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
597+{
cb0b5df1 598+ char *target, *name, *who, *text;
a87bc2c2 599+ time_t timestamp;
600+ unsigned int flags = 0;
601+
6dd3e24f 602+ /* not enough - complain */
603+ if (parc < 2) {
604+ protocol_violation(sptr, "Too few parameters for WELCOME (got %d - need 2)", parc);
a87bc2c2 605+ return need_more_params(sptr, "WELCOME");
6dd3e24f 606+ }
a87bc2c2 607+
608+ /* remote listing request, see if it is for me or a remote server */
609+ if (parc == 2) {
d2e4469e 610+ if (IsServer(sptr))
611+ return protocol_violation(cptr, "WELCOME listing request from server %C", sptr);
6dd3e24f 612+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME)
613+ return 0;
614+ return welcome_list(sptr, 0);
a87bc2c2 615+ }
616+
6dd3e24f 617+ /* we need at least 6 parameters to continue - complain */
618+ if (parc < 6) {
619+ protocol_violation(sptr, "Too few parameters for WELCOME (got %d - need 6)", parc);
a87bc2c2 620+ return need_more_params(sptr, "WELCOME");
6dd3e24f 621+ }
a87bc2c2 622+
623+ /* set the parameters */
624+ target = parv[1];
625+ name = parv[2];
626+ timestamp = atoi(parv[3]);
627+ who = parv[4];
6dd3e24f 628+ text = parv[parc - 1]; /* parse reason as last parameter */
a87bc2c2 629+
630+ /* target is not global */
631+ if (!(target[0] == '*' && target[1] == '\0')) {
6dd3e24f 632+
a87bc2c2 633+ /* not for me, and forward it */
634+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C %s %s %s :%s", 1, parc, parv) != HUNTED_ISME)
635+ return 0;
6dd3e24f 636+
637+ /* local welcome for me */
638+ flags |= WELCOME_LOCAL;
a87bc2c2 639+ }
640+
641+ /* check for anounce prefix */
642+ if (*name == '!') {
643+ name++;
644+ flags |= WELCOME_ANNOUNCE;
645+ }
646+
647+ /* and do it */
648+ return welcome_do(cptr, sptr, name, text, who, timestamp, flags);
649+}
182f0f64 650diff -r 211f48754a7f ircd/parse.c
5632b943 651--- a/ircd/parse.c
652+++ b/ircd/parse.c
f0f686d6 653@@ -661,6 +661,15 @@
654 /* UNREG, CLIENT, SERVER, OPER, SERVICE */
655 { m_unregistered, m_not_oper, ms_check, mo_check, m_ignore }
cddf800b 656 },
657+
658+ /* add command for WELCOME */
659+ {
660+ MSG_WELCOME,
661+ TOK_WELCOME,
662+ 0, MAXPARA, MFLG_SLOW, 0, NULL,
a87bc2c2 663+ /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */
308d3fca 664+ { m_unregistered, m_welcome, ms_welcome, mo_welcome, m_ignore }
cddf800b 665+ },
666
667 /* This command is an alias for QUIT during the unregistered part of
668 * of the server. This is because someone jumping via a broken web
182f0f64 669diff -r 211f48754a7f ircd/s_err.c
5632b943 670--- a/ircd/s_err.c
671+++ b/ircd/s_err.c
a87bc2c2 672@@ -486,7 +486,7 @@
673 /* 226 */
674 { RPL_STATSALINE, "%s", "226" },
675 /* 227 */
676- { 0 },
677+ { RPL_STATSWELCOME, "W %d %s %s %Tu :%s", "227" },
678 /* 228 */
679 { RPL_STATSQLINE, "Q %s :%s", "228" },
680 /* 229 */
681@@ -1050,7 +1050,7 @@
682 /* 508 */
683 { 0 },
684 /* 509 */
685- { 0 },
686+ { ERR_NOSUCHWELCOME, "%s :No such welcome", "509" },
687 /* 510 */
688 { 0 },
689 /* 511 */
182f0f64 690diff -r 211f48754a7f ircd/s_serv.c
5632b943 691--- a/ircd/s_serv.c
692+++ b/ircd/s_serv.c
a87bc2c2 693@@ -57,6 +57,7 @@
694 #include "struct.h"
695 #include "sys.h"
696 #include "userload.h"
697+#include "welcome.h"
698
699 /* #include <assert.h> -- Now using assert in ircd_log.h */
700 #include <stdlib.h>
701@@ -196,6 +197,7 @@
702 */
703 gline_burst(cptr);
704 jupe_burst(cptr);
705+ welcome_burst(cptr);
706
707 /*
708 * Pass on my client information to the new server
182f0f64 709diff -r 211f48754a7f ircd/s_stats.c
5632b943 710--- a/ircd/s_stats.c
711+++ b/ircd/s_stats.c
a87bc2c2 712@@ -54,6 +54,7 @@
713 #include "send.h"
714 #include "struct.h"
715 #include "userload.h"
716+#include "welcome.h"
717
718 #include <stdio.h>
719 #include <stdlib.h>
308d3fca 720@@ -654,9 +655,12 @@
a87bc2c2 721 { 'V', "vserversmach", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_v,
722 stats_servers_verbose, 0,
723 "Verbose server information." },
724- { 'w', "userload", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
725+ { 'w', "userload", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_w,
726 calc_load, 0,
727 "Userload statistics." },
728+ { 'W', "welcome", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_W,
729+ welcome_stats, 0,
730+ "Welcome messages." },
731 { 'x', "memusage", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
732 stats_meminfo, 0,
733 "List usage information." },
182f0f64 734diff -r 211f48754a7f ircd/s_user.c
5632b943 735--- a/ircd/s_user.c
736+++ b/ircd/s_user.c
a87bc2c2 737@@ -63,6 +63,7 @@
738 #include "userload.h"
739 #include "version.h"
740 #include "whowas.h"
741+#include "welcome.h"
742
743 #include "handlers.h" /* m_motd and m_lusers */
744
f0f686d6 745@@ -410,6 +411,9 @@
a87bc2c2 746 cli_info(sptr), NumNick(cptr) /* two %s's */);
747
748 IPcheck_connect_succeeded(sptr);
749+
750+ if (feature_bool(FEAT_WELCOME))
751+ welcome_list(sptr, 1);
752 }
753 else {
754 struct Client *acptr = user->server;
182f0f64 755diff -r 211f48754a7f ircd/welcome.c
5632b943 756--- /dev/null
757+++ b/ircd/welcome.c
6c894401 758@@ -0,0 +1,371 @@
cddf800b 759+/*
a87bc2c2 760+ * IRC - Internet Relay Chat, ircd/welcome.c
cddf800b 761+ * Copyright (C) 1990 Jarkko Oikarinen and
762+ * University of Oulu, Finland
763+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
764+ *
765+ * This program is free software; you can redistribute it and/or modify
766+ * it under the terms of the GNU General Public License as published by
767+ * the Free Software Foundation; either version 1, or (at your option)
768+ * any later version.
769+ *
770+ * This program is distributed in the hope that it will be useful,
771+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
772+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
773+ * GNU General Public License for more details.
774+ *
775+ * You should have received a copy of the GNU General Public License
776+ * along with this program; if not, write to the Free Software
777+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
778+ */
779+/** @file
a87bc2c2 780+ * @brief Implementation of welcome message handling functions.
cddf800b 781+ */
782+#include "config.h"
783+
784+#include "client.h"
785+#include "hash.h"
786+#include "ircd.h"
787+#include "ircd_alloc.h"
788+#include "ircd_features.h"
789+#include "ircd_log.h"
790+#include "ircd_reply.h"
791+#include "ircd_string.h"
792+#include "match.h"
793+#include "msg.h"
794+#include "numeric.h"
795+#include "numnicks.h"
796+#include "s_bsd.h"
a87bc2c2 797+#include "s_debug.h"
cddf800b 798+#include "s_misc.h"
799+#include "send.h"
800+#include "struct.h"
801+#include "sys.h" /* FALSE bleah */
802+#include "welcome.h"
803+
804+/* #include <assert.h> -- Now using assert in ircd_log.h */
805+#include <string.h>
806+
cddf800b 807+
cb0b5df1 808+/** List of welcome messages - first MAX for global, second MAX for local */
6dd3e24f 809+static struct Welcome WelcomeArray[WELCOME_MAX_ENTRIES * 2] = { { 0 } };
cddf800b 810+
cddf800b 811+
a87bc2c2 812+/** Allocate a new welcome with the given parameters.
813+ * @param[in] name Name of the welcome message.
814+ * @param[in] text The welcome message.
815+ * @param[in] who Who set it.
816+ * @param[in] timestamp When it was set.
cb0b5df1 817+ * @return name Array number of the welcome set.
cddf800b 818+ */
cb0b5df1 819+static int
820+welcome_make(int name, char *text, char *who, time_t timestamp)
cddf800b 821+{
cb0b5df1 822+ /* range 0 to 2 * max - 1 */
823+ assert(name >= 0 && name <= 2 * WELCOME_MAX_ENTRIES - 1);
824+
825+ /* store it */
826+ ircd_strncpy(WelcomeArray[name].text, text, TOPICLEN);
827+ ircd_strncpy(WelcomeArray[name].who, who, ACCOUNTLEN);
828+ WelcomeArray[name].timestamp = timestamp;
829+
830+ return name;
cddf800b 831+}
832+
cddf800b 833+
a87bc2c2 834+/** Change a welcome message.
835+ * @param[in] cptr Local client that sent us the welcome.
836+ * @param[in] sptr Originator of the welcome.
837+ * @param[in] name Name of the message.
838+ * @param[in] text The welcome message.
839+ * @param[in] timestamp Timestamp of when the message was set.
840+ * @param[in] flags Flags to set on welcome.
841+ * @return Zero
cddf800b 842+ */
843+int
a87bc2c2 844+welcome_do(struct Client *cptr, struct Client *sptr, char *name, char *text,
845+ char *who, time_t timestamp, unsigned int flags)
cddf800b 846+{
cb0b5df1 847+ int nameint = atoi(name); /* transform to int */
848+ int namearray = nameint - 1; /* used to test the array element */
6dd3e24f 849+ char oldtext[TOPICLEN + 1]; /* save old text when unsetting */
850+ static time_t rate;
851+
852+ assert(NULL != cptr);
853+ assert(NULL != sptr);
854+ assert(NULL != name);
855+ assert(NULL != text);
856+ assert(NULL != who);
a87bc2c2 857+
cb0b5df1 858+ /* debug */
a87bc2c2 859+ Debug((DEBUG_DEBUG, "welcome_do(\"%s\", \"%s\", \"%s\", \"%s\" \"%s\", %Tu, 0x%04x)",
860+ cli_name(cptr), cli_name(sptr), name, text, who, timestamp, flags));
861+
862+ /* check name */
cb0b5df1 863+ if (nameint < 1 || nameint > WELCOME_MAX_ENTRIES) {
a87bc2c2 864+ if (IsUser(sptr))
865+ sendcmdto_one(&me, CMD_NOTICE, sptr,
866+ "%C :WELCOME: Invalid message number %s - should between 1 and %d",
6c894401 867+ sptr, name, WELCOME_MAX_ENTRIES);
868+ else
869+ protocol_violation(cptr, "WELCOME: Invalid message number %s from %C", name, sptr);
cddf800b 870+ return 0;
871+ }
872+
cb0b5df1 873+ /* correct namearray for local offset */
874+ if (flags & WELCOME_LOCAL)
875+ namearray += WELCOME_MAX_ENTRIES;
a87bc2c2 876+
877+ /* cannot unset welcome that is not set */
6dd3e24f 878+ if (WelcomeArray[namearray].timestamp == 0 && EmptyString(text)) {
879+
a87bc2c2 880+ /* from user, throw error */
881+ if (IsUser(sptr))
882+ return send_reply(sptr, ERR_NOSUCHWELCOME, name);
6dd3e24f 883+
884+ /* new local welcome from server, but empty - ignore
885+ * we do accept a new global welcome message that is empty
886+ */
a87bc2c2 887+ if (flags & WELCOME_LOCAL)
888+ return 0;
a87bc2c2 889+ }
cddf800b 890+
a87bc2c2 891+ /* check if there is something to change */
6dd3e24f 892+ /* we got a record for it */
893+ if (WelcomeArray[namearray].timestamp != 0) {
894+
895+ /* global */
182f0f64 896+ if (!(flags & WELCOME_LOCAL)) {
6dd3e24f 897+
898+ /* netburst and we got the same or a newer one
899+ *
900+ * we only use the timestamp for resolving conflicts in net burst
901+ * outside of netburst, we simply parse whatever we get
902+ * this way we will not get stuck with a welcome message set by a server
903+ * running ahead with the time
904+ */
905+ if (IsBurstOrBurstAck(cptr) && timestamp <= WelcomeArray[namearray].timestamp)
a87bc2c2 906+ return 0;
6dd3e24f 907+
908+ /* local welcome - we use our idea of the time */
cb0b5df1 909+ } else
a87bc2c2 910+ timestamp = TStime();
cb0b5df1 911+
a87bc2c2 912+ /* compare new message with old message */
cb0b5df1 913+ if (ircd_strcmp(text, WelcomeArray[namearray].text) == 0) {
a87bc2c2 914+ if (IsUser(sptr))
915+ sendcmdto_one(&me, CMD_NOTICE, sptr,
4e94a910 916+ "%C :WELCOME: Cannot change %s message for %s - nothing to change.",
917+ sptr, (flags & WELCOME_LOCAL) ? "local" : "global", name);
a87bc2c2 918+ return 0;
919+ }
920+ }
cddf800b 921+
6dd3e24f 922+ /* TODO: rate limited for what? max 10 welcome messages..? */
923+ /* possible timestamp drift - warn ops */
924+ if (timestamp - TStime() > WELCOME_MAX_DRIFT) {
925+ sendto_opmask_butone_ratelimited(0, SNO_NETWORK, &rate,
926+ "Possible timestamp drift from %C; timestamp in WELCOME message is %is ahead of time",
927+ IsServer(sptr) ? sptr : cli_user(sptr)->server, timestamp - TStime());
928+
929+ /* warn remote oper too */
930+ if (IsUser(sptr))
931+ sendcmdto_one(&me, CMD_NOTICE, sptr,
932+ "%C :Possible timestamp drift from %C; timestamp in WELCOME message is %is ahead of time",
933+ sptr, cli_user(sptr)->server, timestamp - TStime());
934+ }
935+
936+ /* unsetting - do not announce, save text */
937+ if (EmptyString(text)) {
938+ flags &= ~WELCOME_ANNOUNCE;
939+ ircd_strncpy(oldtext, WelcomeArray[namearray].text, TOPICLEN);
940+ }
941+
cb0b5df1 942+ /* update */
943+ welcome_make(namearray, text, who, timestamp);
944+
cb0b5df1 945+ /* inform ops */
4e94a910 946+ sendto_opmask_butone(0, SNO_OLDSNO, "%s %s%s%s WELCOME %d \"%s\" [%Tu]",
a87bc2c2 947+ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
948+ get_client_name_and_opername(sptr) : cli_name((cli_user(sptr))->server),
6dd3e24f 949+ EmptyString(text) ? "unsetting" : "changing",
950+ (flags & WELCOME_ANNOUNCE) ? " and announcing " : " ",
4e94a910 951+ (flags & WELCOME_LOCAL) ? "local" : "global",
6dd3e24f 952+ nameint,
953+ EmptyString(text) ? oldtext : WelcomeArray[namearray].text,
954+ WelcomeArray[namearray].timestamp);
a87bc2c2 955+
956+ /* log it */
4e94a910 957+ log_write(LS_NETWORK, L_INFO, LOG_NOSNOTICE, "%#C (%s) %s%s%s WELCOME %d \"%s\" [%Tu]",
6dd3e24f 958+ sptr, WelcomeArray[namearray].who,
959+ EmptyString(text) ? "unsetting" : "changing",
960+ (flags & WELCOME_ANNOUNCE) ? " and announcing " : " ",
4e94a910 961+ (flags & WELCOME_LOCAL) ? "local" : "global",
6dd3e24f 962+ nameint,
963+ EmptyString(text) ? oldtext : WelcomeArray[namearray].text,
cb0b5df1 964+ WelcomeArray[namearray].timestamp);
a87bc2c2 965+
966+ /* welcome set by remote user, inform oper of success */
6dd3e24f 967+ if ((flags & WELCOME_LOCAL) && IsUser(sptr) && !MyUser(sptr)) {
968+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s%s local WELCOME %d \"%s\" [%Tu]",
969+ sptr, get_client_name_and_opername(sptr),
970+ EmptyString(text) ? "unsetting" : "changing",
971+ (flags & WELCOME_ANNOUNCE) ? " and announcing" : "",
972+ nameint,
973+ EmptyString(text) ? oldtext : WelcomeArray[namearray].text,
974+ WelcomeArray[namearray].timestamp);
975+
976+ /* TODO: wallops all local changes, by both local and remote opers? */
977+ /* tell all opers about the local message being set remotely */
978+ sendwallto_group_butone(&me, WALL_WALLOPS, 0,
979+ "%s %s%s local WELCOME %d \"%s\" [%Tu]",
980+ get_client_name_and_opername(sptr),
981+ EmptyString(text) ? "unsetting" : "changing",
982+ (flags & WELCOME_ANNOUNCE) ? " and announcing" : "",
983+ nameint,
984+ EmptyString(text) ? oldtext : WelcomeArray[namearray].text,
985+ WelcomeArray[namearray].timestamp);
986+ }
cddf800b 987+
cb0b5df1 988+ /* propagate it */
a87bc2c2 989+ if (!(flags & WELCOME_LOCAL))
990+ sendcmdto_serv_butone(sptr, CMD_WELCOME, cptr, "* %s%d %Tu %s :%s",
cb0b5df1 991+ (flags & WELCOME_ANNOUNCE) ? "!" : "", nameint,
992+ WelcomeArray[namearray].timestamp, WelcomeArray[namearray].who,
993+ WelcomeArray[namearray].text);
cddf800b 994+
a87bc2c2 995+ /* announce it */
6dd3e24f 996+ if (flags & WELCOME_ANNOUNCE)
cb0b5df1 997+ welcome_announce(namearray);
a87bc2c2 998+
999+ return 0;
cddf800b 1000+}
1001+
a87bc2c2 1002+
1003+/** Announce a welcome message to local clients.
cb0b5df1 1004+ * @param[in] name Welcome message to announce.
cddf800b 1005+ */
a87bc2c2 1006+void
cb0b5df1 1007+welcome_announce(int name)
cddf800b 1008+{
a87bc2c2 1009+ struct Client *acptr;
1010+ struct MsgBuf *msgbuf;
6dd3e24f 1011+ int i;
a87bc2c2 1012+
cb0b5df1 1013+ /* range 0 to 2 * max - 1 */
1014+ assert(name >= 0 && name <= 2 * WELCOME_MAX_ENTRIES - 1);
a87bc2c2 1015+
cb0b5df1 1016+ /* TODO: target is $* as if it were a global broadcast
1017+ * could make it $servername for local message announcement
1018+ * but the type is shown between [ ] already
1019+ * either [Network] or [servername] - using $* is just shorter.
1020+ */
a87bc2c2 1021+ /* build msgbuf */
1022+ msgbuf = msgq_make(0, ":%C %s $* :[%s] %s", &me, MSG_NOTICE,
cb0b5df1 1023+ name >= WELCOME_MAX_ENTRIES ? cli_name(&me) : feature_str(FEAT_NETWORK),
1024+ WelcomeArray[name].text);
a87bc2c2 1025+
6dd3e24f 1026+ /* go over local clients */
1027+ for (i = HighestFd; i > 0; --i) {
cb0b5df1 1028+
6dd3e24f 1029+ /* skip unregistered clients - they see the message during login
1030+ * skip servers
a87bc2c2 1031+ */
6dd3e24f 1032+ if (!(acptr = LocalClientArray[i]) || !IsRegistered(acptr) || IsServer(acptr))
a87bc2c2 1033+ continue;
cb0b5df1 1034+
6dd3e24f 1035+ /* send it away */
a87bc2c2 1036+ send_buffer(acptr, msgbuf, 0);
cddf800b 1037+ }
cddf800b 1038+}
1039+
a87bc2c2 1040+
a87bc2c2 1041+/** Send the full list of welcome message to \a cptr.
1042+ * @param[in] cptr Local server to send welcomes to.
cddf800b 1043+ */
1044+void
a87bc2c2 1045+welcome_burst(struct Client *cptr)
cddf800b 1046+{
cb0b5df1 1047+ int name;
a87bc2c2 1048+
6dd3e24f 1049+ assert(NULL != cptr);
1050+
cb0b5df1 1051+ /* loop over global entries - 0 to max - 1*/
1052+ for (name = 0; name <= WELCOME_MAX_ENTRIES - 1; name++) {
1053+ if (WelcomeArray[name].timestamp != 0)
a87bc2c2 1054+ sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %s :%s",
cb0b5df1 1055+ name + 1, WelcomeArray[name].timestamp, WelcomeArray[name].who,
1056+ WelcomeArray[name].text);
cddf800b 1057+ }
1058+}
1059+
a87bc2c2 1060+
a87bc2c2 1061+/** List welcome messages.
1062+ * @param[in] sptr Client requesting the listing.
1063+ * @param[in] connect When non zero do not report no welcome is set
cddf800b 1064+ * @return Zero.
1065+ */
1066+int
a87bc2c2 1067+welcome_list(struct Client *sptr, int connect)
cddf800b 1068+{
cb0b5df1 1069+ int found = 0, local = 0, name;
a87bc2c2 1070+
6dd3e24f 1071+ assert(NULL != sptr);
1072+
cb0b5df1 1073+ /* loop over all entries - range 0 to 2 * max - 1 */
1074+ for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
a87bc2c2 1075+
cb0b5df1 1076+ /* local entries now */
1077+ if (name == WELCOME_MAX_ENTRIES)
1078+ local = 1;
a87bc2c2 1079+
cb0b5df1 1080+ /* not set or empty - skip */
6dd3e24f 1081+ /* TODO: EmptyString? */
cb0b5df1 1082+ if (WelcomeArray[name].timestamp == 0 || *WelcomeArray[name].text == 0)
a87bc2c2 1083+ continue;
cb0b5df1 1084+
1085+ /* got one */
a87bc2c2 1086+ found++;
cb0b5df1 1087+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :[%s] %s",
1088+ sptr, local ? cli_name(&me) : feature_str(FEAT_NETWORK), WelcomeArray[name].text);
a87bc2c2 1089+ }
cb0b5df1 1090+
1091+ /* nothing set */
a87bc2c2 1092+ if (!found && !connect)
cb0b5df1 1093+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :No welcome message set.", sptr);
1094+
a87bc2c2 1095+ return 0;
1096+}
cddf800b 1097+
cddf800b 1098+
a87bc2c2 1099+/** Statistics callback to list Welcome messages.
1100+ * @param[in] sptr Client requesting statistics.
1101+ * @param[in] sd Stats descriptor for request (ignored).
1102+ * @param[in] param Extra parameter from user (ignored).
1103+ */
1104+void
1105+welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param)
1106+{
cb0b5df1 1107+ int name, local = 0;
a87bc2c2 1108+
6dd3e24f 1109+ assert(NULL != sptr);
1110+
cb0b5df1 1111+ /* loop over all entries - range 0 to 2 * max - 1*/
1112+ for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
cddf800b 1113+
cb0b5df1 1114+ /* local entries now */
1115+ if (name == WELCOME_MAX_ENTRIES)
1116+ local = 1;
a87bc2c2 1117+
cb0b5df1 1118+ /* not set */
1119+ if (WelcomeArray[name].timestamp == 0)
1120+ continue;
cddf800b 1121+
cb0b5df1 1122+ /* send it */
1123+ send_reply(sptr, RPL_STATSWELCOME,
6dd3e24f 1124+ local ? name + 1 - WELCOME_MAX_ENTRIES : name + 1,
1125+ local ? cli_name(&me) : "*",
cb0b5df1 1126+ WelcomeArray[name].who, WelcomeArray[name].timestamp,
6dd3e24f 1127+ EmptyString(WelcomeArray[name].text) ? "<Empty>" : WelcomeArray[name].text);
cddf800b 1128+ }
cddf800b 1129+}