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