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