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