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