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