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