]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blob - welcome.patch
add checkoutput.patch - made a few changes
[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 ed0f71fe7e22 include/handlers.h
75 --- a/include/handlers.h Wed Jan 28 14:01:58 2009 +0100
76 +++ b/include/handlers.h Wed Jan 28 15:15:51 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 ed0f71fe7e22 include/ircd_features.h
110 --- a/include/ircd_features.h Wed Jan 28 14:01:58 2009 +0100
111 +++ b/include/ircd_features.h Wed Jan 28 15:15:51 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 ed0f71fe7e22 include/msg.h
129 --- a/include/msg.h Wed Jan 28 14:01:58 2009 +0100
130 +++ b/include/msg.h Wed Jan 28 15:15:51 2009 +0100
131 @@ -195,6 +195,10 @@
132 #define MSG_NOTICE "NOTICE" /* NOTI */
133 #define TOK_NOTICE "O"
134 #define CMD_NOTICE MSG_NOTICE, TOK_NOTICE
135 +
136 +#define MSG_WELCOME "WELCOME" /* WELC */
137 +#define TOK_WELCOME "WE"
138 +#define CMD_WELCOME MSG_WELCOME, TOK_WELCOME
139
140 #define MSG_WALLCHOPS "WALLCHOPS" /* WC */
141 #define TOK_WALLCHOPS "WC"
142 diff -r ed0f71fe7e22 include/numeric.h
143 --- a/include/numeric.h Wed Jan 28 14:01:58 2009 +0100
144 +++ b/include/numeric.h Wed Jan 28 15:15:51 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 ed0f71fe7e22 include/welcome.h
163 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
164 +++ b/include/welcome.h Wed Jan 28 15:15:51 2009 +0100
165 @@ -0,0 +1,56 @@
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 +
202 +/* Describes a Welcome message entry. */
203 +struct Welcome {
204 + char text[TOPICLEN]; /**< Message */
205 + char who[ACCOUNTLEN]; /**< Who set it */
206 + time_t timestamp; /**< Timestamp of the welcome */
207 +};
208 +
209 +/** Welcome type flags */
210 +#define WELCOME_LOCAL 0x01 /**< welcome is local */
211 +/** Welcome action flags */
212 +#define WELCOME_ANNOUNCE 0x02 /**< announce change to users */
213 +
214 +extern int welcome_do(struct Client *cptr, struct Client *sptr, char *name, char *text,
215 + char *who, time_t timestamp, unsigned int flags);
216 +extern void welcome_announce(int name);
217 +extern void welcome_burst(struct Client *cptr);
218 +extern int welcome_list(struct Client *sptr, int connect);
219 +extern void welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param);
220 +
221 +#endif /* INCLUDED_welcome_h */
222 \ No newline at end of file
223 diff -r ed0f71fe7e22 ircd/Makefile.in
224 --- a/ircd/Makefile.in Wed Jan 28 14:01:58 2009 +0100
225 +++ b/ircd/Makefile.in Wed Jan 28 15:15:51 2009 +0100
226 @@ -187,6 +187,7 @@
227 m_wallops.c \
228 m_wallusers.c \
229 m_wallvoices.c \
230 + m_welcome.c \
231 m_who.c \
232 m_whois.c \
233 m_whowas.c \
234 @@ -214,6 +215,7 @@
235 send.c \
236 uping.c \
237 userload.c \
238 + welcome.c \
239 whocmds.c \
240 whowas.c \
241 y.tab.c
242 @@ -1168,6 +1170,11 @@
243 ../include/ircd_reply.h ../include/ircd_string.h \
244 ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
245 ../include/numnicks.h ../include/s_user.h ../include/send.h
246 +m_welcome.o: m_welcome.c ../config.h ../include/channel.h \
247 + ../include/client.h ../include/hash.h ../include/ircd.h ../include/ircd_log.h \
248 + ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
249 + ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
250 + ../include/send.h ../include/welcome.h
251 m_who.o: m_who.c ../config.h ../include/channel.h ../include/ircd_defs.h \
252 ../include/res.h ../config.h ../include/client.h ../include/dbuf.h \
253 ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
254 @@ -1429,6 +1436,13 @@
255 ../include/numnicks.h ../include/querycmds.h ../include/ircd_features.h \
256 ../include/s_misc.h ../include/s_stats.h ../include/send.h \
257 ../include/struct.h ../include/sys.h
258 +welcome.o: welcome.c ../config.h ../include/client.h \
259 + ../include/hash.h ../include/ircd.h ../include/ircd_alloc.h \
260 + ../include/ircd_features.h ../include/ircd_log.h ../include/ircd_reply.h \
261 + ../include/match.h ../include/msg.h ../include/numeric.h \
262 + ../include/numnicks.h ../include/s_debug.h ../include/s_bsd.h \
263 + ../include/s_misc.h ../include/send.h ../include/struct.h \
264 + ../include/sys.h ../include/welcome.h
265 whocmds.o: whocmds.c ../config.h ../include/whocmds.h \
266 ../include/channel.h ../include/ircd_defs.h ../include/res.h \
267 ../config.h ../include/client.h ../include/dbuf.h ../include/msgq.h \
268 diff -r ed0f71fe7e22 ircd/ircd_features.c
269 --- a/ircd/ircd_features.c Wed Jan 28 14:01:58 2009 +0100
270 +++ b/ircd/ircd_features.c Wed Jan 28 15:15:51 2009 +0100
271 @@ -355,6 +355,7 @@
272 F_I(IRCD_RES_TIMEOUT, 0, 4, 0),
273 F_I(AUTH_TIMEOUT, 0, 9, 0),
274 F_B(ANNOUNCE_INVITES, 0, 0, 0),
275 + F_B(WELCOME, 0, 1, 0),
276
277 /* features that affect all operators */
278 F_B(EXTENDED_CHECKCMD, 0, 0, 0),
279 @@ -397,6 +398,7 @@
280 F_B(HIS_STATS_u, 0, 1, 0),
281 F_B(HIS_STATS_U, 0, 1, 0),
282 F_B(HIS_STATS_v, 0, 1, 0),
283 + F_B(HIS_STATS_W, 0, 1, 0),
284 F_B(HIS_STATS_w, 0, 1, 0),
285 F_B(HIS_STATS_x, 0, 1, 0),
286 F_B(HIS_STATS_y, 0, 1, 0),
287 diff -r ed0f71fe7e22 ircd/m_welcome.c
288 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
289 +++ b/ircd/m_welcome.c Wed Jan 28 15:15:51 2009 +0100
290 @@ -0,0 +1,269 @@
291 +/*
292 + * IRC - Internet Relay Chat, ircd/m_welcome.c
293 + * Copyright (C) 1990 Jarkko Oikarinen and
294 + * University of Oulu, Computing Center
295 + *
296 + * See file AUTHORS in IRC package for additional names of
297 + * the programmers.
298 + *
299 + * This program is free software; you can redistribute it and/or modify
300 + * it under the terms of the GNU General Public License as published by
301 + * the Free Software Foundation; either version 1, or (at your option)
302 + * any later version.
303 + *
304 + * This program is distributed in the hope that it will be useful,
305 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
306 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
307 + * GNU General Public License for more details.
308 + *
309 + * You should have received a copy of the GNU General Public License
310 + * along with this program; if not, write to the Free Software
311 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
312 + *
313 + */
314 +
315 +/*
316 + * m_functions execute protocol messages on this server:
317 + *
318 + * cptr is always NON-NULL, pointing to a *LOCAL* client
319 + * structure (with an open socket connected!). This
320 + * identifies the physical socket where the message
321 + * originated (or which caused the m_function to be
322 + * executed--some m_functions may call others...).
323 + *
324 + * sptr is the source of the message, defined by the
325 + * prefix part of the message if present. If not
326 + * or prefix not found, then sptr==cptr.
327 + *
328 + * (!IsServer(cptr)) => (cptr == sptr), because
329 + * prefixes are taken *only* from servers...
330 + *
331 + * (IsServer(cptr))
332 + * (sptr == cptr) => the message didn't
333 + * have the prefix.
334 + *
335 + * (sptr != cptr && IsServer(sptr) means
336 + * the prefix specified servername. (?)
337 + *
338 + * (sptr != cptr && !IsServer(sptr) means
339 + * that message originated from a remote
340 + * user (not local).
341 + *
342 + * combining
343 + *
344 + * (!IsServer(sptr)) means that, sptr can safely
345 + * taken as defining the target structure of the
346 + * message in this server.
347 + *
348 + * *Always* true (if 'parse' and others are working correct):
349 + *
350 + * 1) sptr->from == cptr (note: cptr->from == cptr)
351 + *
352 + * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
353 + * *cannot* be a local connection, unless it's
354 + * actually cptr!). [MyConnect(x) should probably
355 + * be defined as (x == x->from) --msa ]
356 + *
357 + * parc number of variable parameter strings (if zero,
358 + * parv is allowed to be NULL)
359 + *
360 + * parv a NULL terminated list of parameter pointers,
361 + *
362 + * parv[0], sender (prefix string), if not present
363 + * this points to an empty string.
364 + * parv[1]...parv[parc-1]
365 + * pointers to additional parameters
366 + * parv[parc] == NULL, *always*
367 + *
368 + * note: it is guaranteed that parv[0]..parv[parc-1] are all
369 + * non-NULL pointers.
370 + */
371 +#include "config.h"
372 +
373 +#include "channel.h"
374 +#include "client.h"
375 +#include "hash.h"
376 +#include "ircd.h"
377 +#include "ircd_features.h"
378 +#include "ircd_log.h"
379 +#include "ircd_reply.h"
380 +#include "ircd_string.h"
381 +#include "msg.h"
382 +#include "numeric.h"
383 +#include "numnicks.h"
384 +#include "s_user.h"
385 +#include "send.h"
386 +#include "welcome.h"
387 +
388 +/* #include <assert.h> -- Now using assert in ircd_log.h */
389 +
390 +/*
391 + * m_welcome - local generic message handler
392 + *
393 + * parv[0] = Send prefix
394 + */
395 +int m_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
396 +{
397 + /* feature disabled */
398 + if (!feature_bool(FEAT_WELCOME))
399 + return send_reply(sptr, ERR_DISABLED, "WELCOME");
400 + return welcome_list(sptr, 0);
401 +}
402 +
403 +
404 +/*
405 + * mo_welcome - oper message handler
406 + *
407 + * listing:
408 + * parv[0] = Send prefix
409 + *
410 + * remote listing:
411 + * parv[0] = Send prefix
412 + * parv[1] = Target
413 + *
414 + * set global or on remote server:
415 + * parv[0] = Send prefix
416 + * parv[1] = Target: server or * for global
417 + * parv[2] = Name
418 + * parv[3] = Text
419 + */
420 +int mo_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
421 +{
422 + char *target, *name, *who, *text, pattern[BUFSIZE];
423 + time_t timestamp;
424 + unsigned int flags = 0;
425 + int local = 0; /* 1 when it is for me */
426 +
427 + /* feature disabled */
428 + if (!feature_bool(FEAT_WELCOME))
429 + return send_reply(sptr, ERR_DISABLED, "WELCOME");
430 +
431 + /* listing */
432 + if (parc < 2)
433 + return welcome_list(sptr, 0);
434 +
435 + /* TODO: add PRIV_WELCOME? */
436 + /* check PRIVS */
437 + if (!HasPriv(sptr,PRIV_SERVERINFO))
438 + return send_reply(sptr, ERR_NOPRIVILEGES);
439 +
440 + /* remote listing request, see if it is for me or a remote server */
441 + if (parc == 2) {
442 + if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME)
443 + return 0;
444 + return welcome_list(sptr, 0);
445 + }
446 +
447 + /* set the parameters */
448 + /* less than 4 parameters, assume target was left out, making it local for me */
449 + if (parc < 4) {
450 + local++;
451 + target = cli_name(&me);
452 + name = parv[1];
453 + flags |= WELCOME_LOCAL;
454 + } else { /* otherwise set as it should */
455 + target = parv[1];
456 + name = parv[2];
457 + }
458 + timestamp = TStime();
459 + who = cli_user(sptr)->opername;
460 + text = parv[parc - 1];
461 +
462 + /* target is not global */
463 + if (!(target[0] == '*' && target[1] == '\0') && !local) {
464 + /* build a pattern for hunt_server_cmd since we do not have all we need in parv */
465 + ircd_snprintf(0, pattern, sizeof(pattern), "%s %s %Tu %s :%s", "%C", name, timestamp, who, text);
466 + if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, pattern, 1, 2, parv) != HUNTED_ISME)
467 + return 0;
468 + flags |= WELCOME_LOCAL; /* local welcome, for me */
469 + }
470 +
471 + /* TODO: disallow global announcement from oper?
472 + * as PRIVMSG/NOTICE to $* is not allowed either by the ircd
473 + * when PRIV for that is added, use that here? PRIV_BROADCAST or something
474 + */
475 + /* check for anounce prefix */
476 + if (*name == '!') {
477 + name++;
478 + flags |= WELCOME_ANNOUNCE;
479 + }
480 +
481 + /* and do it */
482 + return welcome_do(cptr, sptr, name, text, who, timestamp, flags);
483 +}
484 +
485 +
486 +/*
487 + * ms_welcome - server message handler
488 + *
489 + * parv[0] = Send prefix
490 + * parv[1] = Target: server numeric or * for global
491 + * parv[2] = Name
492 + * parv[3] = Timestamp
493 + * parv[4] = Who
494 + * parv[5] = Text
495 + */
496 +int ms_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
497 +{
498 + char *target, *name, *who, *text;
499 + time_t timestamp;
500 + unsigned int flags = 0;
501 +
502 + /* not enough */
503 + if (parc < 2)
504 + return need_more_params(sptr, "WELCOME");
505 +
506 + /* remote listing request, see if it is for me or a remote server */
507 + if (parc == 2) {
508 + if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) == HUNTED_ISME)
509 + return welcome_list(sptr, 0);
510 + }
511 +
512 + /* we need at least 6 parameters to continue */
513 + if (parc < 6)
514 + return need_more_params(sptr, "WELCOME");
515 +
516 + /* set the parameters */
517 + target = parv[1];
518 + name = parv[2];
519 + timestamp = atoi(parv[3]);
520 + who = parv[4];
521 + text = parv[parc - 1];
522 +
523 + /* target is not global */
524 + if (!(target[0] == '*' && target[1] == '\0')) {
525 + /* not for me, and forward it */
526 + if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C %s %s %s :%s", 1, parc, parv) != HUNTED_ISME)
527 + return 0;
528 + flags |= WELCOME_LOCAL; /* local welcome, for me */
529 + }
530 +
531 + /* check for anounce prefix */
532 + if (*name == '!') {
533 + name++;
534 + flags |= WELCOME_ANNOUNCE;
535 + }
536 +
537 + /* and do it */
538 + return welcome_do(cptr, sptr, name, text, who, timestamp, flags);
539 +}
540 +
541 +
542 +/*
543 + * mh_welcome - help message handler
544 + */
545 +int mh_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
546 +{
547 + if (!IsAnOper(sptr)) {
548 + send_reply(sptr, SND_EXPLICIT | RPL_HELP,
549 + "WELCOME :WELCOME");
550 + send_reply(sptr, SND_EXPLICIT | RPL_HELP,
551 + "WELCOME :Shows welcome messages set on the server.");
552 + } else {
553 + send_reply(sptr, SND_EXPLICIT | RPL_HELP,
554 + "WELCOME :WELCOME [<target>] [[!]<name> :<message>]");
555 + send_reply(sptr, SND_EXPLICIT | RPL_HELP,
556 + "WELCOME :Shows or sets welcome messages on a server.");
557 + }
558 + return 0;
559 +}
560 diff -r ed0f71fe7e22 ircd/parse.c
561 --- a/ircd/parse.c Wed Jan 28 14:01:58 2009 +0100
562 +++ b/ircd/parse.c Wed Jan 28 15:15:51 2009 +0100
563 @@ -667,6 +667,15 @@
564 /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */
565 { m_unregistered, m_not_oper, ms_opkick, mo_opkick, m_ignore, mh_nohelp }
566 },
567 +
568 + /* add command for WELCOME */
569 + {
570 + MSG_WELCOME,
571 + TOK_WELCOME,
572 + 0, MAXPARA, MFLG_SLOW, 0, NULL,
573 + /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */
574 + { m_unregistered, m_welcome, ms_welcome, mo_welcome, m_ignore, mh_welcome }
575 + },
576
577 /* This command is an alias for QUIT during the unregistered part of
578 * of the server. This is because someone jumping via a broken web
579 diff -r ed0f71fe7e22 ircd/s_err.c
580 --- a/ircd/s_err.c Wed Jan 28 14:01:58 2009 +0100
581 +++ b/ircd/s_err.c Wed Jan 28 15:15:51 2009 +0100
582 @@ -486,7 +486,7 @@
583 /* 226 */
584 { RPL_STATSALINE, "%s", "226" },
585 /* 227 */
586 - { 0 },
587 + { RPL_STATSWELCOME, "W %d %s %s %Tu :%s", "227" },
588 /* 228 */
589 { RPL_STATSQLINE, "Q %s :%s", "228" },
590 /* 229 */
591 @@ -1050,7 +1050,7 @@
592 /* 508 */
593 { 0 },
594 /* 509 */
595 - { 0 },
596 + { ERR_NOSUCHWELCOME, "%s :No such welcome", "509" },
597 /* 510 */
598 { 0 },
599 /* 511 */
600 diff -r ed0f71fe7e22 ircd/s_serv.c
601 --- a/ircd/s_serv.c Wed Jan 28 14:01:58 2009 +0100
602 +++ b/ircd/s_serv.c Wed Jan 28 15:15:51 2009 +0100
603 @@ -57,6 +57,7 @@
604 #include "struct.h"
605 #include "sys.h"
606 #include "userload.h"
607 +#include "welcome.h"
608
609 /* #include <assert.h> -- Now using assert in ircd_log.h */
610 #include <stdlib.h>
611 @@ -196,6 +197,7 @@
612 */
613 gline_burst(cptr);
614 jupe_burst(cptr);
615 + welcome_burst(cptr);
616
617 /*
618 * Pass on my client information to the new server
619 diff -r ed0f71fe7e22 ircd/s_stats.c
620 --- a/ircd/s_stats.c Wed Jan 28 14:01:58 2009 +0100
621 +++ b/ircd/s_stats.c Wed Jan 28 15:15:51 2009 +0100
622 @@ -54,6 +54,7 @@
623 #include "send.h"
624 #include "struct.h"
625 #include "userload.h"
626 +#include "welcome.h"
627
628 #include <stdio.h>
629 #include <stdlib.h>
630 @@ -689,9 +690,12 @@
631 { 'V', "vserversmach", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_v,
632 stats_servers_verbose, 0,
633 "Verbose server information." },
634 - { 'w', "userload", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
635 + { 'w', "userload", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_w,
636 calc_load, 0,
637 "Userload statistics." },
638 + { 'W', "welcome", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_W,
639 + welcome_stats, 0,
640 + "Welcome messages." },
641 { 'x', "memusage", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
642 stats_meminfo, 0,
643 "List usage information." },
644 diff -r ed0f71fe7e22 ircd/s_user.c
645 --- a/ircd/s_user.c Wed Jan 28 14:01:58 2009 +0100
646 +++ b/ircd/s_user.c Wed Jan 28 15:15:51 2009 +0100
647 @@ -63,6 +63,7 @@
648 #include "userload.h"
649 #include "version.h"
650 #include "whowas.h"
651 +#include "welcome.h"
652
653 #include "handlers.h" /* m_motd and m_lusers */
654
655 @@ -411,6 +412,9 @@
656 cli_info(sptr), NumNick(cptr) /* two %s's */);
657
658 IPcheck_connect_succeeded(sptr);
659 +
660 + if (feature_bool(FEAT_WELCOME))
661 + welcome_list(sptr, 1);
662 }
663 else {
664 struct Client *acptr = user->server;
665 diff -r ed0f71fe7e22 ircd/welcome.c
666 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
667 +++ b/ircd/welcome.c Wed Jan 28 15:15:51 2009 +0100
668 @@ -0,0 +1,355 @@
669 +/*
670 + * IRC - Internet Relay Chat, ircd/welcome.c
671 + * Copyright (C) 1990 Jarkko Oikarinen and
672 + * University of Oulu, Finland
673 + * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
674 + *
675 + * This program is free software; you can redistribute it and/or modify
676 + * it under the terms of the GNU General Public License as published by
677 + * the Free Software Foundation; either version 1, or (at your option)
678 + * any later version.
679 + *
680 + * This program is distributed in the hope that it will be useful,
681 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
682 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
683 + * GNU General Public License for more details.
684 + *
685 + * You should have received a copy of the GNU General Public License
686 + * along with this program; if not, write to the Free Software
687 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
688 + */
689 +/** @file
690 + * @brief Implementation of welcome message handling functions.
691 + */
692 +#include "config.h"
693 +
694 +#include "client.h"
695 +#include "hash.h"
696 +#include "ircd.h"
697 +#include "ircd_alloc.h"
698 +#include "ircd_features.h"
699 +#include "ircd_log.h"
700 +#include "ircd_reply.h"
701 +#include "ircd_string.h"
702 +#include "match.h"
703 +#include "msg.h"
704 +#include "numeric.h"
705 +#include "numnicks.h"
706 +#include "s_bsd.h"
707 +#include "s_debug.h"
708 +#include "s_misc.h"
709 +#include "send.h"
710 +#include "struct.h"
711 +#include "sys.h" /* FALSE bleah */
712 +#include "welcome.h"
713 +
714 +/* #include <assert.h> -- Now using assert in ircd_log.h */
715 +#include <string.h>
716 +
717 +
718 +/** List of welcome messages - first MAX for global, second MAX for local */
719 +static struct Welcome WelcomeArray[WELCOME_MAX_ENTRIES * 2];
720 +
721 +
722 +
723 +/** Allocate a new welcome with the given parameters.
724 + * @param[in] name Name of the welcome message.
725 + * @param[in] text The welcome message.
726 + * @param[in] who Who set it.
727 + * @param[in] timestamp When it was set.
728 + * @return name Array number of the welcome set.
729 + */
730 +static int
731 +welcome_make(int name, char *text, char *who, time_t timestamp)
732 +{
733 + /* range 0 to 2 * max - 1 */
734 + assert(name >= 0 && name <= 2 * WELCOME_MAX_ENTRIES - 1);
735 +
736 + /* store it */
737 + ircd_strncpy(WelcomeArray[name].text, text, TOPICLEN);
738 + ircd_strncpy(WelcomeArray[name].who, who, ACCOUNTLEN);
739 + WelcomeArray[name].timestamp = timestamp;
740 +
741 + return name;
742 +}
743 +
744 +
745 +/** Change a welcome message.
746 + * @param[in] cptr Local client that sent us the welcome.
747 + * @param[in] sptr Originator of the welcome.
748 + * @param[in] name Name of the message.
749 + * @param[in] text The welcome message.
750 + * @param[in] timestamp Timestamp of when the message was set.
751 + * @param[in] flags Flags to set on welcome.
752 + * @return Zero
753 + */
754 +int
755 +welcome_do(struct Client *cptr, struct Client *sptr, char *name, char *text,
756 + char *who, time_t timestamp, unsigned int flags)
757 +{
758 + int nameint = atoi(name); /* transform to int */
759 + int namearray = nameint - 1; /* used to test the array element */
760 + int notext = (text[0] == '\0') ? 1 : 0; /* 1 when text is empty */
761 + char *action; /* used for logging */
762 + /* TODO: these needed? */
763 + /*
764 + who[ACCOUNTLEN-1] = 0;
765 + text[WELCOMELEN-1] = 0;
766 + */
767 +
768 + /* TODO: NULL or 0 ? they are pointers, so NULL? */
769 + assert(0 != cptr);
770 + assert(0 != sptr);
771 + assert(0 != name);
772 + /* TODO: assert(0 != text); */
773 + assert(0 != who);
774 +
775 + /* debug */
776 + Debug((DEBUG_DEBUG, "welcome_do(\"%s\", \"%s\", \"%s\", \"%s\" \"%s\", %Tu, 0x%04x)",
777 + cli_name(cptr), cli_name(sptr), name, text, who, timestamp, flags));
778 +
779 + /* check name */
780 + if (nameint < 1 || nameint > WELCOME_MAX_ENTRIES) {
781 + if (IsUser(sptr))
782 + sendcmdto_one(&me, CMD_NOTICE, sptr,
783 + "%C :WELCOME: Invalid message number %s - should between 1 and %d",
784 + sptr, name, WELCOME_MAX_ENTRIES);
785 + return 0;
786 + }
787 +
788 + /* correct namearray for local offset */
789 + if (flags & WELCOME_LOCAL)
790 + namearray += WELCOME_MAX_ENTRIES;
791 +
792 + /* cannot unset welcome that is not set */
793 + if (WelcomeArray[namearray].timestamp == 0 && notext) {
794 + /* from user, throw error */
795 + if (IsUser(sptr))
796 + return send_reply(sptr, ERR_NOSUCHWELCOME, name);
797 + /* new local welcome from server, but empty - ignore */
798 + if (flags & WELCOME_LOCAL)
799 + return 0;
800 + /* new global welcome message, but empty, accept from server
801 + * otherwise we do not have the same state as them
802 + */
803 + }
804 +
805 + /* TODO: check if we receive an entry with a timestamp >> TStime()
806 + * ..so from the future
807 + * something is wrong there - either side is wrong about the time (or both)
808 + *
809 + * if we accept a global welcome message with a timestamp far into the future
810 + * it will not be possible to change it - well, not until we pass that point in time
811 + * or /settime to get to it, or hack with a service..
812 + *
813 + * how to handle this - like CREATE and settime? hm, or throw error to ops?
814 + */
815 + /* check if there is something to change */
816 + if (WelcomeArray[namearray].timestamp != 0) { /* we got a record for it */
817 + if (namearray < WELCOME_MAX_ENTRIES) { /* global */
818 + if (timestamp == WelcomeArray[namearray].timestamp) /* we got this version already */
819 + return 0;
820 + if (timestamp < WelcomeArray[namearray].timestamp) { /* we got a later version */
821 + if (IsBurstOrBurstAck(cptr)) /* middle of a burst, it will resync on its own */
822 + return 0;
823 + return welcome_resend(cptr, namearray); /* resync the server */
824 + }
825 + } else
826 + /* local welcome, set timestamp to nettime, accept any change
827 + * we parse local welcome messages in the order we receive them
828 + * they cannot cross on the network and are not bursted,
829 + * and thus timestamp is not required for conflict resolving.
830 + */
831 + timestamp = TStime();
832 +
833 + /* compare new message with old message */
834 + if (ircd_strcmp(text, WelcomeArray[namearray].text) == 0) {
835 + if (IsUser(sptr))
836 + sendcmdto_one(&me, CMD_NOTICE, sptr,
837 + "%C :WELCOME: Cannot change %smessage for %s - nothing to change.",
838 + sptr, (flags & WELCOME_LOCAL) ? "local " : "", name);
839 + return 0;
840 + }
841 + }
842 +
843 + /* update */
844 + welcome_make(namearray, text, who, timestamp);
845 +
846 + /* set action */
847 + if (flags & WELCOME_LOCAL)
848 + action = notext ? "removing local" : "changing local";
849 + else
850 + action = notext ? "unsetting" : "changing";
851 +
852 + /* TODO: WALLOPS for local welcome messages, so that all operators know about it? */
853 + /* inform ops */
854 + sendto_opmask_butone(0, SNO_OLDSNO, "%s %s WELCOME for %d%s%s",
855 + (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
856 + get_client_name_and_opername(sptr) : cli_name((cli_user(sptr))->server),
857 + action, nameint, notext ? "" : " to :", notext ? "" : WelcomeArray[namearray].text);
858 +
859 + /* log it */
860 + log_write(LS_NETWORK, L_INFO, LOG_NOSNOTICE, "%#C (%s) %s WELCOME for %d%s%s [%Tu]",
861 + sptr, WelcomeArray[namearray].who, action, nameint,
862 + notext ? "" : " to :", notext ? "" : WelcomeArray[namearray].text,
863 + WelcomeArray[namearray].timestamp);
864 +
865 + /* TODO: or WALLOPS here, local message remotely set? */
866 + /* welcome set by remote user, inform oper of success */
867 + if ((flags & WELCOME_LOCAL) && IsUser(sptr) && !MyUser(sptr))
868 + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s WELCOME for %d%s%s",
869 + sptr, get_client_name_and_opername(sptr), action, nameint,
870 + notext ? "" : " to :", notext ? "" : WelcomeArray[namearray].text);
871 +
872 + /* propagate it */
873 + if (!(flags & WELCOME_LOCAL))
874 + sendcmdto_serv_butone(sptr, CMD_WELCOME, cptr, "* %s%d %Tu %s :%s",
875 + (flags & WELCOME_ANNOUNCE) ? "!" : "", nameint,
876 + WelcomeArray[namearray].timestamp, WelcomeArray[namearray].who,
877 + WelcomeArray[namearray].text);
878 +
879 + /* announce it */
880 + if ((flags & WELCOME_ANNOUNCE) && !notext)
881 + welcome_announce(namearray);
882 +
883 + return 0;
884 +}
885 +
886 +
887 +/** Announce a welcome message to local clients.
888 + * @param[in] name Welcome message to announce.
889 + */
890 +void
891 +welcome_announce(int name)
892 +{
893 + struct Client *acptr;
894 + struct MsgBuf *msgbuf;
895 +
896 + /* range 0 to 2 * max - 1 */
897 + assert(name >= 0 && name <= 2 * WELCOME_MAX_ENTRIES - 1);
898 +
899 + /* TODO: target is $* as if it were a global broadcast
900 + * could make it $servername for local message announcement
901 + * but the type is shown between [ ] already
902 + * either [Network] or [servername] - using $* is just shorter.
903 + */
904 + /* build msgbuf */
905 + msgbuf = msgq_make(0, ":%C %s $* :[%s] %s", &me, MSG_NOTICE,
906 + name >= WELCOME_MAX_ENTRIES ? cli_name(&me) : feature_str(FEAT_NETWORK),
907 + WelcomeArray[name].text);
908 +
909 + /* go over clients */
910 + for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
911 +
912 + /* skip remote users
913 + * skip unregistered clients - they see the message during login
914 + */
915 + if (!MyUser(acptr) || !IsRegistered(acptr))
916 + continue;
917 +
918 + /* send it away */
919 + send_buffer(acptr, msgbuf, 0);
920 + }
921 +}
922 +
923 +
924 +/** Send the full list of welcome message to \a cptr.
925 + * @param[in] cptr Local server to send welcomes to.
926 + */
927 +void
928 +welcome_burst(struct Client *cptr)
929 +{
930 + int name;
931 +
932 + /* loop over global entries - 0 to max - 1*/
933 + for (name = 0; name <= WELCOME_MAX_ENTRIES - 1; name++) {
934 + if (WelcomeArray[name].timestamp != 0)
935 + sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %s :%s",
936 + name + 1, WelcomeArray[name].timestamp, WelcomeArray[name].who,
937 + WelcomeArray[name].text);
938 + }
939 +}
940 +
941 +
942 +/** Forward a welcome to another server.
943 + * @param[in] cptr %Server to send welcome to.
944 + * @param[in] welcome Welcome to forward.
945 + */
946 +int
947 +welcome_resend(struct Client *cptr, int name)
948 +{
949 + sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %s :%s",
950 + name + 1, WelcomeArray[name].timestamp, WelcomeArray[name].who,
951 + WelcomeArray[name].text);
952 + return 0;
953 +}
954 +
955 +
956 +/** List welcome messages.
957 + * @param[in] sptr Client requesting the listing.
958 + * @param[in] connect When non zero do not report no welcome is set
959 + * @return Zero.
960 + */
961 +int
962 +welcome_list(struct Client *sptr, int connect)
963 +{
964 + int found = 0, local = 0, name;
965 +
966 + /* loop over all entries - range 0 to 2 * max - 1 */
967 + for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
968 +
969 + /* local entries now */
970 + if (name == WELCOME_MAX_ENTRIES)
971 + local = 1;
972 +
973 + /* not set or empty - skip */
974 + if (WelcomeArray[name].timestamp == 0 || *WelcomeArray[name].text == 0)
975 + continue;
976 +
977 + /* got one */
978 + found++;
979 + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :[%s] %s",
980 + sptr, local ? cli_name(&me) : feature_str(FEAT_NETWORK), WelcomeArray[name].text);
981 + }
982 +
983 + /* nothing set */
984 + if (!found && !connect)
985 + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :No welcome message set.", sptr);
986 +
987 + return 0;
988 +}
989 +
990 +
991 +/** Statistics callback to list Welcome messages.
992 + * @param[in] sptr Client requesting statistics.
993 + * @param[in] sd Stats descriptor for request (ignored).
994 + * @param[in] param Extra parameter from user (ignored).
995 + */
996 +void
997 +welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param)
998 +{
999 + int name, local = 0;
1000 +
1001 + /* TODO: change "Who" to "Opername" or "OperID" as that is what it is? */
1002 + /* send header so the client knows what we are showing */
1003 + send_reply(sptr, SND_EXPLICIT | RPL_STATSHEADER,
1004 + "W Name Target Who Timestamp :Message");
1005 +
1006 + /* loop over all entries - range 0 to 2 * max - 1*/
1007 + for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
1008 +
1009 + /* local entries now */
1010 + if (name == WELCOME_MAX_ENTRIES)
1011 + local = 1;
1012 +
1013 + /* not set */
1014 + if (WelcomeArray[name].timestamp == 0)
1015 + continue;
1016 +
1017 + /* send it */
1018 + send_reply(sptr, RPL_STATSWELCOME,
1019 + local ? name + 1 - WELCOME_MAX_ENTRIES : name + 1, local ? cli_name(&me) : "*",
1020 + WelcomeArray[name].who, WelcomeArray[name].timestamp,
1021 + (*WelcomeArray[name].text == 0) ? "<Empty>" : WelcomeArray[name].text);
1022 + }
1023 +}