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