]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blob - welcome.patch
enforceinvisible: refresh for changes by sethost patch
[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 cec5aa51927e include/client.h
81 --- a/include/client.h
82 +++ b/include/client.h
83 @@ -142,6 +142,8 @@
84 PRIV_USER_PRIVACY, /* oper can bypass user privacy +x etc gives i.e. see real ip's */
85 PRIV_CHANNEL_PRIVACY, /* oper can bypass channel privacy i.e. can see modes on channels they are not on and channel keys */
86 PRIV_SERVERINFO, /* oper can use /get, /stats, /hash, retrieve remote information */
87 + PRIV_WELCOME, /* oper can WELCOME */
88 + PRIV_LOCAL_WELCOME, /* oper can local WELCOME */
89 PRIV_LAST_PRIV /**< number of privileges */
90 };
91
92 diff -r cec5aa51927e include/handlers.h
93 --- a/include/handlers.h
94 +++ b/include/handlers.h
95 @@ -138,6 +138,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 @@ -172,6 +173,7 @@
104 extern int mo_version(struct Client*, struct Client*, int, char*[]);
105 extern int mo_wallops(struct Client*, struct Client*, int, char*[]);
106 extern int mo_wallusers(struct Client*, struct Client*, int, char*[]);
107 +extern int mo_welcome(struct Client*, struct Client*, int, char*[]);
108 extern int mo_xquery(struct Client*, struct Client*, int, char*[]);
109 extern int mr_error(struct Client*, struct Client*, int, char*[]);
110 extern int mr_error(struct Client*, struct Client*, int, char*[]);
111 @@ -230,6 +232,7 @@
112 extern int ms_wallops(struct Client*, struct Client*, int, char*[]);
113 extern int ms_wallusers(struct Client*, struct Client*, int, char*[]);
114 extern int ms_wallvoices(struct Client*, struct Client*, int, char*[]);
115 +extern int ms_welcome(struct Client*, struct Client*, int, char*[]);
116 extern int ms_whois(struct Client*, struct Client*, int, char*[]);
117 extern int ms_xquery(struct Client*, struct Client*, int, char*[]);
118 extern int ms_xreply(struct Client*, struct Client*, int, char*[]);
119 diff -r cec5aa51927e include/ircd_features.h
120 --- a/include/ircd_features.h
121 +++ b/include/ircd_features.h
122 @@ -101,6 +101,7 @@
123 FEAT_IRCD_RES_TIMEOUT,
124 FEAT_AUTH_TIMEOUT,
125 FEAT_ANNOUNCE_INVITES,
126 + FEAT_WELCOME,
127
128 /* features that affect all operators */
129 FEAT_EXTENDED_CHECKCMD,
130 @@ -142,6 +143,7 @@
131 FEAT_HIS_STATS_u,
132 FEAT_HIS_STATS_U,
133 FEAT_HIS_STATS_v,
134 + FEAT_HIS_STATS_W,
135 FEAT_HIS_STATS_w,
136 FEAT_HIS_STATS_x,
137 FEAT_HIS_STATS_y,
138 diff -r cec5aa51927e include/msg.h
139 --- a/include/msg.h
140 +++ b/include/msg.h
141 @@ -196,6 +196,10 @@
142 #define TOK_NOTICE "O"
143 #define CMD_NOTICE MSG_NOTICE, TOK_NOTICE
144
145 +#define MSG_WELCOME "WELCOME" /* WELC */
146 +#define TOK_WELCOME "WE"
147 +#define CMD_WELCOME MSG_WELCOME, TOK_WELCOME
148 +
149 #define MSG_WALLCHOPS "WALLCHOPS" /* WC */
150 #define TOK_WALLCHOPS "WC"
151 #define CMD_WALLCHOPS MSG_WALLCHOPS, TOK_WALLCHOPS
152 diff -r cec5aa51927e include/numeric.h
153 --- a/include/numeric.h
154 +++ b/include/numeric.h
155 @@ -116,6 +116,7 @@
156 RPL_STATSGLINE 227 Dalnet
157 RPL_STATSVLINE 227 unreal */
158 #define RPL_STATSALINE 226 /* Hybrid, Undernet */
159 +#define RPL_STATSWELCOME 227 /* QuakeNet extension */
160 #define RPL_STATSQLINE 228 /* Undernet extension */
161
162 /* RPL_SERVICEINFO 231 unused */
163 @@ -440,6 +441,8 @@
164 /* ERR_GHOSTEDCLIENT 503 efnet */
165 /* ERR_VWORLDWARN 503 austnet */
166
167 +#define ERR_NOSUCHWELCOME 509 /* QuakeNet extension */
168 +
169 #define ERR_SILELISTFULL 511 /* Undernet extension */
170 /* ERR_NOTIFYFULL 512 aircd */
171 /* ERR_TOOMANYWATCH 512 Numeric List: Dalnet */
172 diff -r cec5aa51927e include/welcome.h
173 --- /dev/null
174 +++ b/include/welcome.h
175 @@ -0,0 +1,76 @@
176 +#ifndef INCLUDED_welcome_h
177 +#define INCLUDED_welcome_h
178 +/*
179 + * IRC - Internet Relay Chat, include/welcome.h
180 + * Copyright (C) 1990 Jarkko Oikarinen and
181 + * University of Oulu, Computing Center
182 + * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
183 + *
184 + * This program is free software; you can redistribute it and/or modify
185 + * it under the terms of the GNU General Public License as published by
186 + * the Free Software Foundation; either version 2, or (at your option)
187 + * any later version.
188 + *
189 + * This program is distributed in the hope that it will be useful,
190 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
191 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
192 + * GNU General Public License for more details.
193 + *
194 + * You should have received a copy of the GNU General Public License
195 + * along with this program; if not, write to the Free Software
196 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
197 + */
198 +/** @file
199 + * @brief Interface and declarations for welcome message handling.
200 + */
201 +#ifndef INCLUDED_sys_types_h
202 +#include <sys/types.h>
203 +#define INCLUDED_sys_types_h
204 +#endif
205 +
206 +struct Client;
207 +struct StatDesc;
208 +
209 +/* Maximum number of welcome entries (per type; X global, X local) */
210 +#define WELCOME_MAX_ENTRIES 10
211 +/* Maximum length of a welcome message */
212 +#define WELCOMELEN TOPICLEN
213 +
214 +
215 +/* Test if a welcome entry is in a valid range */
216 +#define WelcomeIsValid(x) ((unsigned) (x) <= 2 * WELCOME_MAX_ENTRIES -1)
217 +/* Test if a welcome entry is set */
218 +#define WelcomeIsSet(x) (WelcomeArray[(x)].timestamp > 0)
219 +/* Test if a welcome entry is empty */
220 +#define WelcomeIsEmpty(x) (*WelcomeArray[(x)].text == 0)
221 +
222 +/* Get welcome timestamp */
223 +#define WelcomeTS(x) (WelcomeArray[(x)].timestamp)
224 +/* Get welcome text */
225 +#define WelcomeText(x) (WelcomeArray[(x)].text)
226 +/* Get welcome who info */
227 +#define WelcomeWho(x) (WelcomeArray[(x)].who)
228 +
229 +
230 +/* Describes a Welcome message entry. */
231 +struct Welcome {
232 + time_t timestamp; /**< Timestamp of the welcome */
233 + char text[WELCOMELEN + 1]; /**< Message */
234 + char who[ACCOUNTLEN + 1]; /**< Who set it */
235 +};
236 +
237 +/** Welcome type flags */
238 +#define WELCOME_LOCAL 0x01 /**< welcome is local */
239 +/** Welcome action flags */
240 +#define WELCOME_ANNOUNCE 0x02 /**< announce change to users */
241 +#define WELCOME_INSERT 0x04 /**< insert welcome message, move down all others one place */
242 +
243 +extern int welcome_do(struct Client *cptr, struct Client *sptr, char *name,
244 + time_t timestamp, char *who, char *text, unsigned int flags);
245 +extern void welcome_announce(int name);
246 +extern void welcome_burst(struct Client *cptr);
247 +extern int welcome_list(struct Client *sptr, int connect);
248 +extern void welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param);
249 +extern int welcome_memory_count(size_t *we_size);
250 +
251 +#endif /* INCLUDED_welcome_h */
252 diff -r cec5aa51927e ircd/Makefile.in
253 --- a/ircd/Makefile.in
254 +++ b/ircd/Makefile.in
255 @@ -186,6 +186,7 @@
256 m_wallops.c \
257 m_wallusers.c \
258 m_wallvoices.c \
259 + m_welcome.c \
260 m_who.c \
261 m_whois.c \
262 m_whowas.c \
263 @@ -215,6 +216,7 @@
264 send.c \
265 uping.c \
266 userload.c \
267 + welcome.c \
268 whocmds.c \
269 whowas.c \
270 y.tab.c
271 @@ -1161,6 +1163,11 @@
272 ../include/ircd_reply.h ../include/ircd_string.h \
273 ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
274 ../include/numnicks.h ../include/s_user.h ../include/send.h
275 +m_welcome.o: m_welcome.c ../config.h ../include/channel.h \
276 + ../include/client.h ../include/hash.h ../include/ircd.h ../include/ircd_log.h \
277 + ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
278 + ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
279 + ../include/send.h ../include/welcome.h
280 m_who.o: m_who.c ../config.h ../include/channel.h ../include/ircd_defs.h \
281 ../include/res.h ../config.h ../include/client.h ../include/dbuf.h \
282 ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
283 @@ -1422,6 +1429,13 @@
284 ../include/numnicks.h ../include/querycmds.h ../include/ircd_features.h \
285 ../include/s_misc.h ../include/s_stats.h ../include/send.h \
286 ../include/struct.h ../include/sys.h
287 +welcome.o: welcome.c ../config.h ../include/client.h \
288 + ../include/hash.h ../include/ircd.h ../include/ircd_alloc.h \
289 + ../include/ircd_features.h ../include/ircd_log.h ../include/ircd_reply.h \
290 + ../include/match.h ../include/msg.h ../include/numeric.h \
291 + ../include/numnicks.h ../include/s_debug.h ../include/s_bsd.h \
292 + ../include/s_misc.h ../include/send.h ../include/struct.h \
293 + ../include/sys.h ../include/welcome.h
294 whocmds.o: whocmds.c ../config.h ../include/whocmds.h \
295 ../include/channel.h ../include/ircd_defs.h ../include/res.h \
296 ../config.h ../include/client.h ../include/dbuf.h ../include/msgq.h \
297 diff -r cec5aa51927e ircd/client.c
298 --- a/ircd/client.c
299 +++ b/ircd/client.c
300 @@ -177,6 +177,7 @@
301 FlagSet(&privs_local, PRIV_WHOX);
302 FlagSet(&privs_local, PRIV_DISPLAY);
303 FlagSet(&privs_local, PRIV_FORCE_LOCAL_OPMODE);
304 + FlagSet(&privs_local, PRIV_LOCAL_WELCOME);
305
306 privs_defaults_set = 1;
307 }
308 @@ -223,6 +224,7 @@
309 ClrPriv(client, PRIV_JUPE);
310 ClrPriv(client, PRIV_OPMODE);
311 ClrPriv(client, PRIV_BADCHAN);
312 + ClrPriv(client, PRIV_WELCOME);
313 }
314 }
315
316 @@ -244,7 +246,7 @@
317 P(CHANSERV), P(XTRA_OPER), P(NOIDLE), P(FREEFORM),
318 P(PARANOID), P(CHECK), P(WALL), P(CLOSE),
319 P(ROUTE), P(ROUTEINFO), P(SERVERINFO), P(CHANNEL_PRIVACY),
320 - P(USER_PRIVACY),
321 + P(USER_PRIVACY), P(WELCOME), P(LOCAL_WELCOME),
322 #undef P
323 { 0, 0 }
324 };
325 diff -r cec5aa51927e ircd/ircd_features.c
326 --- a/ircd/ircd_features.c
327 +++ b/ircd/ircd_features.c
328 @@ -366,6 +366,7 @@
329 F_I(IRCD_RES_TIMEOUT, 0, 4, 0),
330 F_I(AUTH_TIMEOUT, 0, 9, 0),
331 F_B(ANNOUNCE_INVITES, 0, 0, 0),
332 + F_B(WELCOME, 0, 1, 0),
333
334 /* features that affect all operators */
335 F_B(EXTENDED_CHECKCMD, 0, 0, 0),
336 @@ -407,6 +408,7 @@
337 F_B(HIS_STATS_u, 0, 1, 0),
338 F_B(HIS_STATS_U, 0, 1, 0),
339 F_B(HIS_STATS_v, 0, 1, 0),
340 + F_B(HIS_STATS_W, 0, 1, 0),
341 F_B(HIS_STATS_w, 0, 1, 0),
342 F_B(HIS_STATS_x, 0, 1, 0),
343 F_B(HIS_STATS_y, 0, 1, 0),
344 diff -r cec5aa51927e ircd/ircd_lexer.l
345 --- a/ircd/ircd_lexer.l
346 +++ b/ircd/ircd_lexer.l
347 @@ -166,6 +166,8 @@
348 { "serverinfo", TPRIV_SERVERINFO },
349 { "user_privacy", TPRIV_USER_PRIVACY },
350 { "channel_privacy", TPRIV_CHANNEL_PRIVACY },
351 + { "local_welcome", TPRIV_LOCAL_WELCOME },
352 + { "welcome", TPRIV_WELCOME },
353 { NULL, 0 }
354 };
355 static int ntokens;
356 diff -r cec5aa51927e ircd/ircd_parser.y
357 --- a/ircd/ircd_parser.y
358 +++ b/ircd/ircd_parser.y
359 @@ -189,6 +189,7 @@
360 %token TPRIV_CHANSERV TPRIV_XTRA_OPER TPRIV_NOIDLE TPRIV_FREEFORM TPRIV_PARANOID
361 %token TPRIV_CHECK TPRIV_WALL TPRIV_CLOSE TPRIV_ROUTE TPRIV_ROUTEINFO TPRIV_SERVERINFO
362 %token TPRIV_CHANNEL_PRIVACY TPRIV_USER_PRIVACY TPRIV_LIST_CHAN
363 +%token TPRIV_LOCAL_WELCOME TPRIV_WELCOME
364 /* and some types... */
365 %type <num> sizespec
366 %type <num> timespec timefactor factoredtimes factoredtime
367 @@ -703,6 +704,8 @@
368 TPRIV_SERVERINFO { $$ = PRIV_SERVERINFO ; } |
369 TPRIV_CHANNEL_PRIVACY { $$ = PRIV_CHANNEL_PRIVACY ; } |
370 TPRIV_USER_PRIVACY { $$ = PRIV_USER_PRIVACY ; } |
371 + TPRIV_LOCAL_WELCOME { $$ = PRIV_LOCAL_WELCOME; } |
372 + TPRIV_WELCOME { $$ = PRIV_WELCOME; } |
373 TPRIV_PARANOID { $$ = PRIV_PARANOID; } ;
374 yesorno: YES { $$ = 1; } | NO { $$ = 0; };
375
376 diff -r cec5aa51927e ircd/m_welcome.c
377 --- /dev/null
378 +++ b/ircd/m_welcome.c
379 @@ -0,0 +1,292 @@
380 +/*
381 + * IRC - Internet Relay Chat, ircd/m_welcome.c
382 + * Copyright (C) 1990 Jarkko Oikarinen and
383 + * University of Oulu, Computing Center
384 + *
385 + * See file AUTHORS in IRC package for additional names of
386 + * the programmers.
387 + *
388 + * This program is free software; you can redistribute it and/or modify
389 + * it under the terms of the GNU General Public License as published by
390 + * the Free Software Foundation; either version 1, or (at your option)
391 + * any later version.
392 + *
393 + * This program is distributed in the hope that it will be useful,
394 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
395 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
396 + * GNU General Public License for more details.
397 + *
398 + * You should have received a copy of the GNU General Public License
399 + * along with this program; if not, write to the Free Software
400 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
401 + *
402 + */
403 +
404 +/*
405 + * m_functions execute protocol messages on this server:
406 + *
407 + * cptr is always NON-NULL, pointing to a *LOCAL* client
408 + * structure (with an open socket connected!). This
409 + * identifies the physical socket where the message
410 + * originated (or which caused the m_function to be
411 + * executed--some m_functions may call others...).
412 + *
413 + * sptr is the source of the message, defined by the
414 + * prefix part of the message if present. If not
415 + * or prefix not found, then sptr==cptr.
416 + *
417 + * (!IsServer(cptr)) => (cptr == sptr), because
418 + * prefixes are taken *only* from servers...
419 + *
420 + * (IsServer(cptr))
421 + * (sptr == cptr) => the message didn't
422 + * have the prefix.
423 + *
424 + * (sptr != cptr && IsServer(sptr) means
425 + * the prefix specified servername. (?)
426 + *
427 + * (sptr != cptr && !IsServer(sptr) means
428 + * that message originated from a remote
429 + * user (not local).
430 + *
431 + * combining
432 + *
433 + * (!IsServer(sptr)) means that, sptr can safely
434 + * taken as defining the target structure of the
435 + * message in this server.
436 + *
437 + * *Always* true (if 'parse' and others are working correct):
438 + *
439 + * 1) sptr->from == cptr (note: cptr->from == cptr)
440 + *
441 + * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
442 + * *cannot* be a local connection, unless it's
443 + * actually cptr!). [MyConnect(x) should probably
444 + * be defined as (x == x->from) --msa ]
445 + *
446 + * parc number of variable parameter strings (if zero,
447 + * parv is allowed to be NULL)
448 + *
449 + * parv a NULL terminated list of parameter pointers,
450 + *
451 + * parv[0], sender (prefix string), if not present
452 + * this points to an empty string.
453 + * parv[1]...parv[parc-1]
454 + * pointers to additional parameters
455 + * parv[parc] == NULL, *always*
456 + *
457 + * note: it is guaranteed that parv[0]..parv[parc-1] are all
458 + * non-NULL pointers.
459 + */
460 +#include "config.h"
461 +
462 +#include "channel.h"
463 +#include "client.h"
464 +#include "hash.h"
465 +#include "ircd.h"
466 +#include "ircd_features.h"
467 +#include "ircd_log.h"
468 +#include "ircd_reply.h"
469 +#include "ircd_snprintf.h"
470 +#include "ircd_string.h"
471 +#include "msg.h"
472 +#include "numeric.h"
473 +#include "numnicks.h"
474 +#include "s_user.h"
475 +#include "send.h"
476 +#include "welcome.h"
477 +
478 +/* #include <assert.h> -- Now using assert in ircd_log.h */
479 +
480 +/*
481 + * m_welcome - local generic message handler
482 + *
483 + * parv[0] = Send prefix
484 + * parv[1] = [remote server to query]
485 + */
486 +int m_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
487 +{
488 + /* feature disabled */
489 + if (!feature_bool(FEAT_WELCOME))
490 + return send_reply(sptr, ERR_DISABLED, "WELCOME");
491 +
492 + /* only opers can set the welcome messages */
493 + if (parc > 2)
494 + return send_reply(sptr, ERR_NOPRIVILEGES);
495 +
496 + /* remote listing request, see if it is for me or a remote server
497 + * check FEAT_HIS_REMOTE to decide if an ordinary user can do this
498 + */
499 + if ((parc > 1) && (hunt_server_cmd(sptr, CMD_WELCOME, cptr, feature_int(FEAT_HIS_REMOTE),
500 + "%C", 1, parc, parv) != HUNTED_ISME))
501 + return 0;
502 +
503 + /* local listing */
504 + return welcome_list(sptr, 0);
505 +}
506 +
507 +
508 +/*
509 + * mo_welcome - oper message handler
510 + *
511 + * listing:
512 + * parv[0] = Send prefix
513 + *
514 + * remote listing:
515 + * parv[0] = Send prefix
516 + * parv[1] = Target
517 + *
518 + * set global or on remote server:
519 + * parv[0] = Send prefix
520 + * parv[1] = Target: server or * for global (or left out for this server)
521 + * parv[2] = Name
522 + * parv[3] = Text
523 + */
524 +int mo_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
525 +{
526 + char *target, *name, *who, *text, pattern[BUFSIZE];
527 + time_t timestamp;
528 + unsigned int flags = 0;
529 + int local = 0;
530 +
531 + /* feature disabled */
532 + if (!feature_bool(FEAT_WELCOME))
533 + return send_reply(sptr, ERR_DISABLED, "WELCOME");
534 +
535 + /* TODO: move feature check here? */
536 + /* remote listing request, see if it is for me or a remote server */
537 + if ((parc == 2) && (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME))
538 + return 0;
539 +
540 + /* local listing */
541 + if (parc <= 2)
542 + return welcome_list(sptr, 0);
543 +
544 + /* check PRIVS */
545 + /* local - need PRIV LOCAL_WELCOME or WELCOME */
546 + if (parc == 3 && !HasPriv(sptr,PRIV_LOCAL_WELCOME) && !HasPriv(sptr,PRIV_WELCOME))
547 + return send_reply(sptr, ERR_NOPRIVILEGES);
548 +
549 + /* global or remote - need PRIV WELCOME */
550 + if (parc >= 4 && !HasPriv(sptr,PRIV_WELCOME))
551 + return send_reply(sptr, ERR_NOPRIVILEGES);
552 +
553 + /* set the parameters */
554 +
555 + /* target not given, only name - setting local welcome */
556 + if (parc < 4) {
557 + local++;
558 + target = cli_name(&me);
559 + name = parv[1];
560 + flags |= WELCOME_LOCAL;
561 +
562 + /* target and name given */
563 + } else {
564 + target = parv[1];
565 + name = parv[2];
566 + }
567 + timestamp = TStime();
568 + who = cli_user(sptr)->opername;
569 + text = parv[parc - 1];
570 +
571 + /* target is not global */
572 + if (!(target[0] == '*' && target[1] == '\0') && !local) {
573 +
574 + /* build a pattern for hunt_server_cmd since we do not have all we need in parv */
575 + ircd_snprintf(0, pattern, sizeof(pattern), "%s %s %Tu %s :%s", "%C", name, timestamp, who, text);
576 + if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, pattern, 1, 2, parv) != HUNTED_ISME)
577 + return 0;
578 +
579 + /* else it is a local welcome, for me */
580 + flags |= WELCOME_LOCAL;
581 + }
582 +
583 + /* check for anounce prefix */
584 + if (*name == '$') {
585 + name++;
586 + /* only allow announce by oper for local welcome */
587 + if (flags & WELCOME_LOCAL)
588 + flags |= WELCOME_ANNOUNCE;
589 + }
590 +
591 + /* check for insert prefix */
592 + if (*name == '+') {
593 + name++;
594 + flags |= WELCOME_INSERT;
595 + }
596 +
597 + /* and do it */
598 + return welcome_do(cptr, sptr, name, timestamp, who, text, flags);
599 +}
600 +
601 +
602 +/*
603 + * ms_welcome - server message handler
604 + *
605 + * parv[0] = Send prefix
606 + * parv[1] = Target: server numeric or * for global
607 + * parv[2] = Name
608 + * parv[3] = Timestamp
609 + * parv[4] = Who
610 + * parv[5] = Text
611 + */
612 +int ms_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
613 +{
614 + char *target, *name, *who, *text;
615 + time_t timestamp;
616 + unsigned int flags = 0;
617 +
618 + /* not enough - complain */
619 + if (parc < 2) {
620 + protocol_violation(sptr, "Too few parameters for WELCOME (got %d - need 2)", parc);
621 + return need_more_params(sptr, "WELCOME");
622 + }
623 +
624 + /* remote listing request, see if it is for me or a remote server */
625 + if (parc == 2) {
626 + if (IsServer(sptr))
627 + return protocol_violation(cptr, "WELCOME listing request from server %C", sptr);
628 + if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME)
629 + return 0;
630 + return welcome_list(sptr, 0);
631 + }
632 +
633 + /* we need at least 6 parameters to continue - complain */
634 + if (parc < 6) {
635 + protocol_violation(sptr, "Too few parameters for WELCOME (got %d - need 6)", parc);
636 + return need_more_params(sptr, "WELCOME");
637 + }
638 +
639 + /* set the parameters */
640 + target = parv[1];
641 + name = parv[2];
642 + timestamp = atoi(parv[3]);
643 + who = parv[4];
644 + text = parv[parc - 1]; /* parse reason as last parameter */
645 +
646 + /* target is not global */
647 + if (!(target[0] == '*' && target[1] == '\0')) {
648 +
649 + /* not for me, and forward it */
650 + if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C %s %s %s :%s", 1, parc, parv) != HUNTED_ISME)
651 + return 0;
652 +
653 + /* local welcome for me */
654 + flags |= WELCOME_LOCAL;
655 + }
656 +
657 + /* check for anounce prefix */
658 + if (*name == '$') {
659 + name++;
660 + flags |= WELCOME_ANNOUNCE;
661 + }
662 +
663 + /* check for insert prefix */
664 + if (*name == '+') {
665 + name++;
666 + flags |= WELCOME_INSERT;
667 + }
668 +
669 + /* and do it */
670 + return welcome_do(cptr, sptr, name, timestamp, who, text, flags);
671 +}
672 diff -r cec5aa51927e ircd/parse.c
673 --- a/ircd/parse.c
674 +++ b/ircd/parse.c
675 @@ -661,6 +661,15 @@
676 /* UNREG, CLIENT, SERVER, OPER, SERVICE */
677 { m_unregistered, m_not_oper, ms_check, mo_check, m_ignore }
678 },
679 +
680 + /* add command for WELCOME */
681 + {
682 + MSG_WELCOME,
683 + TOK_WELCOME,
684 + 0, MAXPARA, MFLG_SLOW, 0, NULL,
685 + /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */
686 + { m_unregistered, m_welcome, ms_welcome, mo_welcome, m_ignore }
687 + },
688
689 /* This command is an alias for QUIT during the unregistered part of
690 * of the server. This is because someone jumping via a broken web
691 diff -r cec5aa51927e ircd/s_debug.c
692 --- a/ircd/s_debug.c
693 +++ b/ircd/s_debug.c
694 @@ -50,6 +50,7 @@
695 #include "send.h"
696 #include "struct.h"
697 #include "sys.h"
698 +#include "welcome.h"
699 #include "whowas.h"
700
701 /* #include <assert.h> -- Now using assert in ircd_log.h */
702 @@ -231,7 +232,8 @@
703 aw = 0, /* aways set */
704 wwa = 0, /* whowas aways */
705 gl = 0, /* glines */
706 - ju = 0; /* jupes */
707 + ju = 0, /* jupes */
708 + we = 0; /* welcomes */
709
710 size_t chm = 0, /* memory used by channels */
711 chbm = 0, /* memory used by channel bans */
712 @@ -244,6 +246,7 @@
713 wwm = 0, /* whowas array memory used */
714 glm = 0, /* memory used by glines */
715 jum = 0, /* memory used by jupes */
716 + wem = 0, /* memory used by welcomes */
717 com = 0, /* memory used by conf lines */
718 dbufs_allocated = 0, /* memory used by dbufs */
719 dbufs_used = 0, /* memory used by dbufs */
720 @@ -351,6 +354,10 @@
721 send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
722 ":Glines %d(%zu) Jupes %d(%zu)", gl, glm, ju, jum);
723
724 + we = welcome_memory_count(&wem);
725 + send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
726 + ":Welcomes %d(%zu)", we, wem);
727 +
728 send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
729 ":Hash: client %d(%zu), chan is the same", HASHSIZE,
730 sizeof(void *) * HASHSIZE);
731 diff -r cec5aa51927e ircd/s_err.c
732 --- a/ircd/s_err.c
733 +++ b/ircd/s_err.c
734 @@ -486,7 +486,7 @@
735 /* 226 */
736 { RPL_STATSALINE, "%s", "226" },
737 /* 227 */
738 - { 0 },
739 + { RPL_STATSWELCOME, "W %d %s %s %Tu :%s", "227" },
740 /* 228 */
741 { RPL_STATSQLINE, "Q %s :%s", "228" },
742 /* 229 */
743 @@ -1050,7 +1050,7 @@
744 /* 508 */
745 { 0 },
746 /* 509 */
747 - { 0 },
748 + { ERR_NOSUCHWELCOME, "%s :No such welcome", "509" },
749 /* 510 */
750 { 0 },
751 /* 511 */
752 diff -r cec5aa51927e ircd/s_serv.c
753 --- a/ircd/s_serv.c
754 +++ b/ircd/s_serv.c
755 @@ -57,6 +57,7 @@
756 #include "struct.h"
757 #include "sys.h"
758 #include "userload.h"
759 +#include "welcome.h"
760
761 /* #include <assert.h> -- Now using assert in ircd_log.h */
762 #include <stdlib.h>
763 @@ -196,6 +197,7 @@
764 */
765 gline_burst(cptr);
766 jupe_burst(cptr);
767 + welcome_burst(cptr);
768
769 /*
770 * Pass on my client information to the new server
771 diff -r cec5aa51927e ircd/s_stats.c
772 --- a/ircd/s_stats.c
773 +++ b/ircd/s_stats.c
774 @@ -54,6 +54,7 @@
775 #include "send.h"
776 #include "struct.h"
777 #include "userload.h"
778 +#include "welcome.h"
779
780 #include <stdio.h>
781 #include <stdlib.h>
782 @@ -654,9 +655,12 @@
783 { 'V', "vserversmach", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_v,
784 stats_servers_verbose, 0,
785 "Verbose server information." },
786 - { 'w', "userload", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
787 + { 'w', "userload", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_w,
788 calc_load, 0,
789 "Userload statistics." },
790 + { 'W', "welcome", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_W,
791 + welcome_stats, 0,
792 + "Welcome messages." },
793 { 'x', "memusage", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
794 stats_meminfo, 0,
795 "List usage information." },
796 diff -r cec5aa51927e ircd/s_user.c
797 --- a/ircd/s_user.c
798 +++ b/ircd/s_user.c
799 @@ -63,6 +63,7 @@
800 #include "userload.h"
801 #include "version.h"
802 #include "whowas.h"
803 +#include "welcome.h"
804
805 #include "handlers.h" /* m_motd and m_lusers */
806
807 @@ -410,6 +411,9 @@
808 cli_info(sptr), NumNick(cptr) /* two %s's */);
809
810 IPcheck_connect_succeeded(sptr);
811 +
812 + if (feature_bool(FEAT_WELCOME))
813 + welcome_list(sptr, 1);
814 }
815 else {
816 struct Client *acptr = user->server;
817 diff -r cec5aa51927e ircd/welcome.c
818 --- /dev/null
819 +++ b/ircd/welcome.c
820 @@ -0,0 +1,649 @@
821 +/*
822 + * IRC - Internet Relay Chat, ircd/welcome.c
823 + * Copyright (C) 1990 Jarkko Oikarinen and
824 + * University of Oulu, Finland
825 + * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
826 + *
827 + * This program is free software; you can redistribute it and/or modify
828 + * it under the terms of the GNU General Public License as published by
829 + * the Free Software Foundation; either version 1, or (at your option)
830 + * any later version.
831 + *
832 + * This program is distributed in the hope that it will be useful,
833 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
834 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
835 + * GNU General Public License for more details.
836 + *
837 + * You should have received a copy of the GNU General Public License
838 + * along with this program; if not, write to the Free Software
839 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
840 + */
841 +/** @file
842 + * @brief Implementation of welcome message handling functions.
843 + */
844 +#include "config.h"
845 +
846 +#include "client.h"
847 +#include "hash.h"
848 +#include "ircd.h"
849 +#include "ircd_alloc.h"
850 +#include "ircd_features.h"
851 +#include "ircd_log.h"
852 +#include "ircd_reply.h"
853 +#include "ircd_string.h"
854 +#include "match.h"
855 +#include "msg.h"
856 +#include "numeric.h"
857 +#include "numnicks.h"
858 +#include "s_bsd.h"
859 +#include "s_debug.h"
860 +#include "s_misc.h"
861 +#include "send.h"
862 +#include "struct.h"
863 +#include "sys.h" /* FALSE bleah */
864 +#include "welcome.h"
865 +
866 +/* #include <assert.h> -- Now using assert in ircd_log.h */
867 +#include <string.h>
868 +
869 +
870 +/** List of welcome messages - first MAX for global, second MAX for local */
871 +static struct Welcome WelcomeArray[WELCOME_MAX_ENTRIES * 2] = { { 0 } };
872 +
873 +
874 +/** Allocate a new welcome with the given parameters.
875 + * @param[in] name Name of the welcome message.
876 + * @param[in] text The welcome message.
877 + * @param[in] who Who set it.
878 + * @param[in] timestamp When it was set.
879 + * @return name Array number of the welcome set.
880 + */
881 +static int
882 +welcome_make(int name, char *text, char *who, time_t timestamp)
883 +{
884 + assert(WelcomeIsValid(name));
885 + assert(NULL != text);
886 + assert(NULL != who);
887 +
888 + /* store it */
889 + ircd_strncpy(WelcomeArray[name].text, text, WELCOMELEN);
890 + ircd_strncpy(WelcomeArray[name].who, who, ACCOUNTLEN);
891 + WelcomeArray[name].timestamp = timestamp;
892 +
893 + return name;
894 +}
895 +
896 +
897 +/** Propagate a welcome message.
898 + * @param[in] cptr Local client that sent us the welcome.
899 + * @param[in] sptr Originator of the welcome.
900 + * @param[in] nameint Name of the message.
901 + * @param[in] timestamp Timestamp of when the message was set.
902 + * @param[in] who Who set this message.
903 + * @param[in] text The welcome message.
904 + * @param[in] flags Flags to set on welcome.
905 + * @return Zero
906 + */
907 +int
908 +welcome_propagate(struct Client *cptr, struct Client *sptr, int nameint,
909 + time_t timestamp, char *who, char *text, unsigned int flags)
910 +{
911 + assert(NULL != sptr);
912 + assert(NULL != cptr);
913 + assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
914 + assert(!(flags & WELCOME_LOCAL));
915 +
916 + sendcmdto_serv_butone(sptr, CMD_WELCOME, cptr, "* %s%s%d %Tu %s :%s",
917 + (flags & WELCOME_ANNOUNCE) ? "$" : "", (flags & WELCOME_INSERT) ? "+" : "",
918 + nameint, timestamp, who, text);
919 +
920 + return 0;
921 +}
922 +
923 +
924 +/** Resend a welcome message.
925 + * @param[in] cptr Local client that sent us the welcome.
926 + * @param[in] nameint Name of the message.
927 + * @param[in] namearray Name of the array item.
928 + * @return Zero
929 + */
930 +int
931 +welcome_resend(struct Client *cptr, int nameint, int namearray)
932 +{
933 + assert(NULL != cptr);
934 + assert(IsServer(cptr));
935 + assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
936 + assert(WelcomeIsValid(namearray));
937 +
938 + sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %s :%s",
939 + nameint, WelcomeTS(namearray), WelcomeWho(namearray), WelcomeText(namearray));
940 +
941 + return 0;
942 +}
943 +
944 +
945 +/** Log a welcome message.
946 + * @param[in] sptr Originator of the welcome.
947 + * @param[in] msg The message to show.
948 + * @param[in] flags Flags to set on welcome.
949 + * @return Zero
950 + */
951 +int
952 +welcome_log(struct Client *sptr, char *msg, unsigned int flags)
953 +{
954 + assert(NULL != sptr);
955 + assert(NULL != msg);
956 +
957 + /* inform ops */
958 + sendto_opmask_butone(0, SNO_OLDSNO, "%s %s",
959 + (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
960 + get_client_name_and_opername(sptr) : cli_name((cli_user(sptr))->server), msg);
961 +
962 + /* log it */
963 + log_write(LS_NETWORK, L_INFO, LOG_NOSNOTICE, "%s %s", get_client_name_and_opername(sptr), msg);
964 +
965 + /* welcome by remote user, inform oper of success */
966 + if ((flags & WELCOME_LOCAL) && IsUser(sptr) && !MyUser(sptr)) {
967 + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s",
968 + sptr, get_client_name_and_opername(sptr), msg);
969 +
970 + /* TODO: wallops all local changes, by both local and remote opers? */
971 + /* tell all opers about the local message being set remotely */
972 + sendwallto_group_butone(&me, WALL_WALLOPS, 0, "%s %s", get_client_name_and_opername(sptr), msg);
973 + }
974 +
975 + return 0;
976 +}
977 +
978 +
979 +/** Set a welcome message.
980 + * @param[in] cptr Local client that sent us the welcome.
981 + * @param[in] sptr Originator of the welcome.
982 + * @param[in] nameint Name of the message.
983 + * @param[in] namearray Array entry.
984 + * @param[in] timestamp Timestamp of when the message was set.
985 + * @param[in] who Who set this message.
986 + * @param[in] text The message.
987 + * @param[in] flags Flags to set on welcome.
988 + * @return Zero
989 + */
990 +int
991 +welcome_set(struct Client *cptr, struct Client *sptr, int nameint,
992 + int namearray, time_t timestamp, char *who, char *text, unsigned int flags)
993 +{
994 + char msg[BUFSIZE]; /* msg for logging */
995 + int new = 0;
996 +
997 + assert(NULL != cptr);
998 + assert(NULL != sptr);
999 + assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
1000 + assert(WelcomeIsValid(namearray));
1001 +
1002 + /* debug */
1003 + Debug((DEBUG_DEBUG, "welcome_set(\"%s\", \"%s\", %d, %d, %Tu, \"%s\", \"%s\", 0x%04x)",
1004 + cli_name(cptr), cli_name(sptr), nameint, namearray, timestamp, who, text, flags));
1005 +
1006 + /* not set */
1007 + if (WelcomeIsEmpty(namearray))
1008 + new = 1;
1009 +
1010 + /* update */
1011 + welcome_make(namearray, text, who, timestamp);
1012 +
1013 + /* create msg for log */
1014 + ircd_snprintf(0, msg, 0, "%s%s%s WELCOME %d \"%s\" %s [%Tu]",
1015 + new ? "setting" : "changing",
1016 + (flags & WELCOME_ANNOUNCE) ? " and announcing " : " ",
1017 + (flags & WELCOME_LOCAL) ? "local" : "global",
1018 + nameint, WelcomeText(namearray), WelcomeWho(namearray), timestamp);
1019 +
1020 + /* log it */
1021 + welcome_log(sptr, msg, flags);
1022 +
1023 + /* propagate it */
1024 + if (!(flags & WELCOME_LOCAL))
1025 + welcome_propagate(cptr, sptr, nameint, timestamp, who, text, flags);
1026 +
1027 + /* announce it */
1028 + if (flags & WELCOME_ANNOUNCE)
1029 + welcome_announce(namearray);
1030 +
1031 + return 0;
1032 +}
1033 +
1034 +
1035 +/** Unset a welcome message.
1036 + * @param[in] cptr Local client that sent us the welcome.
1037 + * @param[in] sptr Originator of the welcome.
1038 + * @param[in] nameint Name of the message.
1039 + * @param[in] namearray Array entry.
1040 + * @param[in] timestamp Timestamp of when the message was set.
1041 + * @param[in] who Who set this message.
1042 + * @param[in] flags Flags to set on welcome.
1043 + * @return Zero
1044 + */
1045 +int
1046 +welcome_unset(struct Client *cptr, struct Client *sptr, int nameint,
1047 + int namearray, time_t timestamp, char *who, unsigned int flags)
1048 +{
1049 + char msg[BUFSIZE]; /* msg for logging */
1050 + int i; /* loop variable */
1051 + int empty = namearray; /* first empty spot in array after namearray */
1052 + int end = WELCOME_MAX_ENTRIES -1; /* last element to check in array */
1053 +
1054 + assert(NULL != cptr);
1055 + assert(NULL != sptr);
1056 + assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
1057 + assert(WelcomeIsValid(namearray));
1058 +
1059 + /* debug */
1060 + Debug((DEBUG_DEBUG, "welcome_unset(\"%s\", \"%s\", %d, %d, %Tu, \"%s\", 0x%04x)",
1061 + cli_name(cptr), cli_name(sptr), nameint, namearray, timestamp, who, flags));
1062 +
1063 + /* create msg for log */
1064 + ircd_snprintf(0, msg, 0, "unsetting %s WELCOME %d \"%s\" %s [%Tu]",
1065 + (flags & WELCOME_LOCAL) ? "local" : "global",
1066 + nameint, WelcomeText(namearray), WelcomeWho(namearray), timestamp);
1067 +
1068 + /* log it */
1069 + welcome_log(sptr, msg, flags);
1070 +
1071 + /* update */
1072 + welcome_make(namearray, "", who, timestamp);
1073 +
1074 + /* propagate it, but not when inserting */
1075 + if (!(flags & (WELCOME_LOCAL|WELCOME_INSERT)))
1076 + welcome_propagate(cptr, sptr, nameint, timestamp, who, "", flags);
1077 +
1078 + /* correct end for local offset */
1079 + if (flags & WELCOME_LOCAL)
1080 + end += WELCOME_MAX_ENTRIES;
1081 +
1082 + /* move entries up, update timestamp */
1083 + for (i = namearray; i < end; i++)
1084 + welcome_make(i, WelcomeText(i+1), WelcomeWho(i+1), timestamp);
1085 +
1086 + /* clear last entry, update timestamp */
1087 + welcome_make(end, "", who, timestamp);
1088 +
1089 + return 0;
1090 +}
1091 +
1092 +
1093 +/** Insert a welcome message.
1094 + * @param[in] cptr Local client that sent us the welcome.
1095 + * @param[in] sptr Originator of the welcome.
1096 + * @param[in] nameint Name of the message.
1097 + * @param[in] namearray Array entry.
1098 + * @param[in] timestamp Timestamp of when the message was set.
1099 + * @param[in] who Who set this message.
1100 + * @param[in] text The welcome message.
1101 + * @param[in] flags Flags to set on welcome.
1102 + * @return Zero
1103 + */
1104 +int
1105 +welcome_insert(struct Client *cptr, struct Client *sptr, int nameint,
1106 + int namearray, time_t timestamp, char *who, char *text, unsigned int flags)
1107 +{
1108 + char msg[BUFSIZE]; /* msg for logging */
1109 + int i; /* loop variable */
1110 + int empty = -1; /* first empty spot in array after namearray */
1111 + int end = WELCOME_MAX_ENTRIES -1; /* last element to check in array */
1112 + int last = end; /* last welcome message to feed to welcome_unset */
1113 +
1114 + assert(NULL != cptr);
1115 + assert(NULL != sptr);
1116 + assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
1117 + assert(WelcomeIsValid(namearray));
1118 +
1119 + /* debug */
1120 + Debug((DEBUG_DEBUG, "welcome_insert(\"%s\", \"%s\", %d, %d, %Tu, \"%s\", \"%s\", 0x%04x)",
1121 + cli_name(cptr), cli_name(sptr), nameint, namearray, timestamp, who, text, flags));
1122 +
1123 + /* correct end for local offset */
1124 + if (flags & WELCOME_LOCAL)
1125 + end += WELCOME_MAX_ENTRIES;
1126 +
1127 + /* find first empty spot */
1128 + for (i = namearray; i <= end; i++) {
1129 + if (WelcomeIsEmpty(i)) {
1130 + empty = i;
1131 + break;
1132 + }
1133 + }
1134 +
1135 + /* no empty spot, need to unset last */
1136 + if (empty == -1) {
1137 + welcome_unset(cptr, sptr, end, namearray, timestamp, who, flags);
1138 + empty = end;
1139 + }
1140 +
1141 + /* move entries down, update timestamp */
1142 + for (i = empty; i > namearray; i--)
1143 + welcome_make(i, WelcomeText(i-1), WelcomeWho(i-1), timestamp);
1144 +
1145 + /* correct empty for local offset */
1146 + if (flags & WELCOME_LOCAL)
1147 + empty -= WELCOME_MAX_ENTRIES;
1148 +
1149 + /* create msg for log */
1150 + if (nameint == empty)
1151 + ircd_snprintf(0, msg, 0, "moving %s WELCOME message %d one place down",
1152 + (flags & WELCOME_LOCAL) ? "local" : "global", nameint);
1153 + else
1154 + ircd_snprintf(0, msg, 0, "moving %s WELCOME message %d %s %d one place down",
1155 + (flags & WELCOME_LOCAL) ? "local" : "global", nameint, (empty - nameint > 1) ? "to" : "and" , empty);
1156 +
1157 + /* log it */
1158 + welcome_log(sptr, msg, flags);
1159 +
1160 + /* set it */
1161 + welcome_set(cptr, sptr, nameint, namearray, timestamp, who, text, flags);
1162 +
1163 + return 0;
1164 +}
1165 +
1166 +
1167 +/** Change a welcome message.
1168 + * @param[in] cptr Local client that sent us the welcome.
1169 + * @param[in] sptr Originator of the welcome.
1170 + * @param[in] name Name of the message.
1171 + * @param[in] timestamp Timestamp of when the message was set.
1172 + * @param[in] who Who set this message.
1173 + * @param[in] text The welcome message.
1174 + * @param[in] flags Flags to set on welcome.
1175 + * @return Zero
1176 + */
1177 +int
1178 +welcome_do(struct Client *cptr, struct Client *sptr, char *name,
1179 + time_t timestamp, char *who, char *text, unsigned int flags)
1180 +{
1181 + int nameint = atoi(name); /* transform to int */
1182 + int namearray = nameint - 1; /* used to test the array element */
1183 +
1184 + assert(NULL != cptr);
1185 + assert(NULL != sptr);
1186 + assert(NULL != name);
1187 + assert(NULL != text);
1188 + assert(NULL != who);
1189 +
1190 + /* debug */
1191 + Debug((DEBUG_DEBUG, "welcome_do(\"%s\", \"%s\", \"%s\", %Tu, \"%s\", \"%s\", 0x%04x)",
1192 + cli_name(cptr), cli_name(sptr), name, timestamp, who, text, flags));
1193 +
1194 + /* if for some reason timestamp is 0, increase it */
1195 + if (timestamp == 0)
1196 + timestamp++;
1197 +
1198 + /* name empty after taking off the prefixes? */
1199 + if (EmptyString(name)) {
1200 + if (IsUser(sptr))
1201 + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :WELCOME: No message number given", sptr);
1202 + else
1203 + protocol_violation(cptr, "WELCOME: No message number given by %C", sptr);
1204 + return 0;
1205 + }
1206 +
1207 + /* check name */
1208 + if (!WelcomeIsValid(namearray)) {
1209 + if (IsUser(sptr))
1210 + sendcmdto_one(&me, CMD_NOTICE, sptr,
1211 + "%C :WELCOME: Invalid message number %s - should between 1 and %d",
1212 + sptr, name, WELCOME_MAX_ENTRIES);
1213 + else
1214 + protocol_violation(cptr,
1215 + "WELCOME: Invalid message number %s from %C - should be between 1 and %d",
1216 + name, sptr, WELCOME_MAX_ENTRIES);
1217 + return 0;
1218 + }
1219 +
1220 + /* source is user, and is myuser or welcome is local, check length of the message */
1221 + if ((IsUser(sptr)) && ((MyUser(sptr)) || (flags & WELCOME_LOCAL)) && (strlen(text) > WELCOMELEN)) {
1222 + sendcmdto_one(&me, CMD_NOTICE, sptr,
1223 + "%C :WELCOME: The message is too long with %d chars - max is %d chars",
1224 + sptr, strlen(text), WELCOMELEN);
1225 + ircd_strncpy(text, text, WELCOMELEN);
1226 + sendcmdto_one(&me, CMD_NOTICE, sptr,
1227 + "%C :WELCOME: Change or truncate the message to: \"%s\"", sptr, text);
1228 + return 0;
1229 + }
1230 +
1231 + /* correct namearray for local offset */
1232 + if (flags & WELCOME_LOCAL)
1233 + namearray += WELCOME_MAX_ENTRIES;
1234 +
1235 + /* must be true by now */
1236 + assert(WelcomeIsValid(namearray));
1237 + assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
1238 +
1239 + /* cannot unset welcome that is not set */
1240 + if (!WelcomeIsSet(namearray) && EmptyString(text)) {
1241 +
1242 + /* from user, throw error */
1243 + if (IsUser(sptr))
1244 + return send_reply(sptr, ERR_NOSUCHWELCOME, name);
1245 +
1246 + /* new local welcome from server, but empty - ignore
1247 + * we do accept a new global welcome message that is empty
1248 + */
1249 + if (flags & WELCOME_LOCAL)
1250 + return 0;
1251 + }
1252 +
1253 + /* check if there is something to change */
1254 + /* we got a record for it */
1255 + if (WelcomeIsSet(namearray)) {
1256 +
1257 + /* global */
1258 + if (!(flags & WELCOME_LOCAL)) {
1259 +
1260 + /* myuser changes it,
1261 + * welcomeTS greater than or equal to timestamp, take welcomeTS+1 as timestamp
1262 + * else the change is not accepted upstream because of the older TS
1263 + */
1264 + if (MyUser(sptr)) {
1265 + if (WelcomeTS(namearray) >= timestamp)
1266 + timestamp = WelcomeTS(namearray) +1;
1267 + }
1268 +
1269 + /* compare timestamps, ignore welcome when:
1270 + * we got a newer one
1271 + * or when timestamps are the same and our text is 'smaller'
1272 + */
1273 + else if ((timestamp < WelcomeTS(namearray)) || /* we got a newer one */
1274 + ((timestamp == WelcomeTS(namearray)) && /* same timestamp */
1275 + (strcmp(WelcomeText(namearray), text) < 0))) { /* our text is 'smaller' */
1276 + /* burst or burst ack, cptr gets our version from the burst */
1277 + if (IsBurstOrBurstAck(cptr))
1278 + return 0;
1279 + /* sync server */
1280 + return welcome_resend(cptr, nameint, namearray);
1281 + }
1282 +
1283 + /* local welcome - we use our idea of the time */
1284 + } else
1285 + timestamp = TStime();
1286 +
1287 + /* new global welcome from my user or local welcome
1288 + * compare new message with old message
1289 + */
1290 + if (IsUser(sptr) && (MyUser(sptr) || (flags & WELCOME_LOCAL))) {
1291 + if (strcmp(text, WelcomeText(namearray)) == 0) { /* use strcmp because the user may wish to change case */
1292 + sendcmdto_one(&me, CMD_NOTICE, sptr,
1293 + "%C :WELCOME: Cannot change %s message for %s - nothing to change",
1294 + sptr, (flags & WELCOME_LOCAL) ? "local" : "global", name);
1295 + return 0;
1296 + }
1297 + }
1298 + }
1299 +
1300 + /* do not insert for last global/local entry and when not set yet */
1301 + if ((flags & WELCOME_INSERT) &&
1302 + ((!WelcomeIsSet(namearray)) || (nameint == WELCOME_MAX_ENTRIES)))
1303 + flags &= ~WELCOME_INSERT;
1304 +
1305 + /* unset */
1306 + if (EmptyString(text)) {
1307 + /* clear insert flag,
1308 + * when this flag is set, welcome_unset() assumes it is being called from welcome_insert()
1309 + * and wont propagate the change
1310 + */
1311 + flags &= ~WELCOME_INSERT;
1312 + return welcome_unset(cptr, sptr, nameint, namearray, timestamp, who, flags);
1313 + }
1314 +
1315 + /* insert */
1316 + if (flags & WELCOME_INSERT)
1317 + return welcome_insert(cptr, sptr, nameint, namearray, timestamp, who, text, flags);
1318 +
1319 + /* new or change */
1320 + return welcome_set(cptr, sptr, nameint, namearray, timestamp, who, text, flags);
1321 +}
1322 +
1323 +
1324 +/** Announce a welcome message to local clients.
1325 + * @param[in] name Welcome message to announce.
1326 + */
1327 +void
1328 +welcome_announce(int name)
1329 +{
1330 + struct Client *acptr;
1331 + struct MsgBuf *msgbuf;
1332 + int i;
1333 +
1334 + /* valid range, set and not empty */
1335 + assert(WelcomeIsValid(name));
1336 + assert(WelcomeIsSet(name));
1337 + assert(!WelcomeIsEmpty(name));
1338 +
1339 + /* TODO: target is $* as if it were a global broadcast
1340 + * could make it $servername for local message announcement
1341 + * but the type is shown between [ ] already
1342 + * either [Network] or [servername] - using $* is just shorter.
1343 + */
1344 + /* build msgbuf */
1345 + msgbuf = msgq_make(0, ":%C %s $* :[%s] %s", &me, MSG_NOTICE,
1346 + name >= WELCOME_MAX_ENTRIES ? cli_name(&me) : feature_str(FEAT_NETWORK),
1347 + WelcomeText(name));
1348 +
1349 + /* go over local clients */
1350 + for (i = HighestFd; i > 0; --i) {
1351 +
1352 + /* skip unregistered clients, skip servers */
1353 + if (!(acptr = LocalClientArray[i]) || !IsRegistered(acptr) || IsServer(acptr))
1354 + continue;
1355 +
1356 + /* send it away */
1357 + send_buffer(acptr, msgbuf, 0);
1358 + }
1359 +}
1360 +
1361 +
1362 +/** Send the full list of welcome message to \a cptr.
1363 + * @param[in] cptr Local server to send welcomes to.
1364 + */
1365 +void
1366 +welcome_burst(struct Client *cptr)
1367 +{
1368 + int name;
1369 +
1370 + assert(NULL != cptr);
1371 +
1372 + /* loop over global entries - 0 to max - 1*/
1373 + for (name = 0; name <= WELCOME_MAX_ENTRIES - 1; name++) {
1374 + if (WelcomeIsSet(name))
1375 + sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %s :%s",
1376 + name + 1, WelcomeTS(name), WelcomeWho(name), WelcomeText(name));
1377 + }
1378 +}
1379 +
1380 +
1381 +/** List welcome messages.
1382 + * @param[in] sptr Client requesting the listing.
1383 + * @param[in] connect When non zero do not report no welcome is set
1384 + * @return Zero.
1385 + */
1386 +int
1387 +welcome_list(struct Client *sptr, int connect)
1388 +{
1389 + int found = 0, local = 0, name;
1390 +
1391 + assert(NULL != sptr);
1392 +
1393 + /* loop over all entries - range 0 to 2 * max - 1 */
1394 + for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
1395 +
1396 + /* local entries now */
1397 + if (name == WELCOME_MAX_ENTRIES)
1398 + local = 1;
1399 +
1400 + /* not set or empty - skip */
1401 + if (!WelcomeIsSet(name) || WelcomeIsEmpty(name))
1402 + continue;
1403 +
1404 + /* got one */
1405 + found++;
1406 + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :[%s] %s",
1407 + sptr, local ? cli_name(&me) : feature_str(FEAT_NETWORK), WelcomeText(name));
1408 + }
1409 +
1410 + /* nothing set */
1411 + if (!found && !connect)
1412 + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :No welcome message set.", sptr);
1413 +
1414 + return 0;
1415 +}
1416 +
1417 +
1418 +/** Statistics callback to list Welcome messages.
1419 + * @param[in] sptr Client requesting statistics.
1420 + * @param[in] sd Stats descriptor for request (ignored).
1421 + * @param[in] param Extra parameter from user (ignored).
1422 + */
1423 +void
1424 +welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param)
1425 +{
1426 + int name, local = 0;
1427 +
1428 + assert(NULL != sptr);
1429 +
1430 + /* loop over all entries - range 0 to 2 * max - 1*/
1431 + for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
1432 +
1433 + /* local entries now */
1434 + if (name == WELCOME_MAX_ENTRIES)
1435 + local = 1;
1436 +
1437 + /* not set */
1438 + if (!WelcomeIsSet(name))
1439 + continue;
1440 +
1441 + /* send it */
1442 + send_reply(sptr, RPL_STATSWELCOME,
1443 + local ? name + 1 - WELCOME_MAX_ENTRIES : name + 1,
1444 + local ? cli_name(&me) : "*",
1445 + WelcomeWho(name), WelcomeTS(name),
1446 + WelcomeIsEmpty(name) ? "<Empty>" : WelcomeText(name));
1447 + }
1448 +}
1449 +
1450 +
1451 +/** Count welcome messages and memory used by them.
1452 + * @param[out] we_size Receives total number of bytes allocated for welcomes.
1453 + * @return Number of welcome messages currently allocated.
1454 + */
1455 +int
1456 +welcome_memory_count(size_t *we_size)
1457 +{
1458 + int name;
1459 + unsigned int we = 0;
1460 +
1461 + for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
1462 + if (!WelcomeIsSet(name))
1463 + continue;
1464 + we++;
1465 + *we_size += WelcomeText(name) ? (strlen(WelcomeText(name)) + 1) : 0;
1466 + *we_size += WelcomeWho(name) ? (strlen(WelcomeWho(name)) + 1) : 0;
1467 + }
1468 + return we;
1469 +}