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