1 Add welcome message functionality.
6 shows welcome messages set, same is shown on connect
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
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
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
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.
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.
41 add m_welcome mo_welcome ms_welcome mh_welcome functions
45 add features FEAT_WELCOME and FEAT_HIS_STATS_W
48 add MSG_WELCOME TOK_WELCOME CMD_WELCOME
51 add welcome message functions
55 add RPL_STATSWELCOME ERR_NOSUCHWELCOME
63 add welcome.c and m_welcome.c files
66 add burst welcome message
72 add showing of welcome messages on connect
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
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*[]);
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*[]);
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*[]);
100 extern int mh_nohelp(struct Client*, struct Client*, int, char*[]);
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
113 FEAT_IRCD_RES_TIMEOUT,
115 FEAT_ANNOUNCE_INVITES,
118 /* features that affect all operators */
119 FEAT_EXTENDED_CHECKCMD,
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
132 #define MSG_NOTICE "NOTICE" /* NOTI */
133 #define TOK_NOTICE "O"
134 #define CMD_NOTICE MSG_NOTICE, TOK_NOTICE
136 +#define MSG_WELCOME "WELCOME" /* WELC */
137 +#define TOK_WELCOME "WE"
138 +#define CMD_WELCOME MSG_WELCOME, TOK_WELCOME
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
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 */
154 /* ERR_GHOSTEDCLIENT 503 efnet */
155 /* ERR_VWORLDWARN 503 austnet */
157 +#define ERR_NOSUCHWELCOME 509 /* QuakeNet extension */
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
166 +#ifndef INCLUDED_welcome_h
167 +#define INCLUDED_welcome_h
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>
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.
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.
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.
189 + * @brief Interface and declarations for welcome message handling.
191 +#ifndef INCLUDED_sys_types_h
192 +#include <sys/types.h>
193 +#define INCLUDED_sys_types_h
199 +/* Maximum number of welcome entries (per type; X global, X local) */
200 +#define WELCOME_MAX_ENTRIES 10
202 +/* Describes a Welcome message entry. */
204 + char text[TOPICLEN]; /**< Message */
205 + char who[ACCOUNTLEN]; /**< Who set it */
206 + time_t timestamp; /**< Timestamp of the welcome */
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 */
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);
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
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
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),
277 /* features that affect all operators */
278 F_B(EXTENDED_CHECKCMD, 0, 0, 0),
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
292 + * IRC - Internet Relay Chat, ircd/m_welcome.c
293 + * Copyright (C) 1990 Jarkko Oikarinen and
294 + * University of Oulu, Computing Center
296 + * See file AUTHORS in IRC package for additional names of
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.
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.
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.
316 + * m_functions execute protocol messages on this server:
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...).
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.
328 + * (!IsServer(cptr)) => (cptr == sptr), because
329 + * prefixes are taken *only* from servers...
332 + * (sptr == cptr) => the message didn't
335 + * (sptr != cptr && IsServer(sptr) means
336 + * the prefix specified servername. (?)
338 + * (sptr != cptr && !IsServer(sptr) means
339 + * that message originated from a remote
340 + * user (not local).
344 + * (!IsServer(sptr)) means that, sptr can safely
345 + * taken as defining the target structure of the
346 + * message in this server.
348 + * *Always* true (if 'parse' and others are working correct):
350 + * 1) sptr->from == cptr (note: cptr->from == cptr)
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 ]
357 + * parc number of variable parameter strings (if zero,
358 + * parv is allowed to be NULL)
360 + * parv a NULL terminated list of parameter pointers,
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*
368 + * note: it is guaranteed that parv[0]..parv[parc-1] are all
369 + * non-NULL pointers.
373 +#include "channel.h"
377 +#include "ircd_features.h"
378 +#include "ircd_log.h"
379 +#include "ircd_reply.h"
380 +#include "ircd_string.h"
382 +#include "numeric.h"
383 +#include "numnicks.h"
386 +#include "welcome.h"
388 +/* #include <assert.h> -- Now using assert in ircd_log.h */
391 + * m_welcome - local generic message handler
393 + * parv[0] = Send prefix
395 +int m_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
397 + /* feature disabled */
398 + if (!feature_bool(FEAT_WELCOME))
399 + return send_reply(sptr, ERR_DISABLED, "WELCOME");
400 + return welcome_list(sptr, 0);
405 + * mo_welcome - oper message handler
408 + * parv[0] = Send prefix
411 + * parv[0] = Send prefix
414 + * set global or on remote server:
415 + * parv[0] = Send prefix
416 + * parv[1] = Target: server or * for global
420 +int mo_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
422 + char *target, *name, *who, *text, pattern[BUFSIZE];
424 + unsigned int flags = 0;
425 + int local = 0; /* 1 when it is for me */
427 + /* feature disabled */
428 + if (!feature_bool(FEAT_WELCOME))
429 + return send_reply(sptr, ERR_DISABLED, "WELCOME");
433 + return welcome_list(sptr, 0);
435 + /* TODO: add PRIV_WELCOME? */
437 + if (!HasPriv(sptr,PRIV_SERVERINFO))
438 + return send_reply(sptr, ERR_NOPRIVILEGES);
440 + /* remote listing request, see if it is for me or a remote server */
442 + if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME)
444 + return welcome_list(sptr, 0);
447 + /* set the parameters */
448 + /* less than 4 parameters, assume target was left out, making it local for me */
451 + target = cli_name(&me);
453 + flags |= WELCOME_LOCAL;
454 + } else { /* otherwise set as it should */
458 + timestamp = TStime();
459 + who = cli_user(sptr)->opername;
460 + text = parv[parc - 1];
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)
468 + flags |= WELCOME_LOCAL; /* local welcome, for me */
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
475 + /* check for anounce prefix */
476 + if (*name == '!') {
478 + flags |= WELCOME_ANNOUNCE;
482 + return welcome_do(cptr, sptr, name, text, who, timestamp, flags);
487 + * ms_welcome - server message handler
489 + * parv[0] = Send prefix
490 + * parv[1] = Target: server numeric or * for global
492 + * parv[3] = Timestamp
496 +int ms_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
498 + char *target, *name, *who, *text;
500 + unsigned int flags = 0;
504 + return need_more_params(sptr, "WELCOME");
506 + /* remote listing request, see if it is for me or a remote server */
508 + if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) == HUNTED_ISME)
509 + return welcome_list(sptr, 0);
512 + /* we need at least 6 parameters to continue */
514 + return need_more_params(sptr, "WELCOME");
516 + /* set the parameters */
519 + timestamp = atoi(parv[3]);
521 + text = parv[parc - 1];
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)
528 + flags |= WELCOME_LOCAL; /* local welcome, for me */
531 + /* check for anounce prefix */
532 + if (*name == '!') {
534 + flags |= WELCOME_ANNOUNCE;
538 + return welcome_do(cptr, sptr, name, text, who, timestamp, flags);
543 + * mh_welcome - help message handler
545 +int mh_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
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.");
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.");
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
564 /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */
565 { m_unregistered, m_not_oper, ms_opkick, mo_opkick, m_ignore, mh_nohelp }
568 + /* add command for 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 }
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
584 { RPL_STATSALINE, "%s", "226" },
587 + { RPL_STATSWELCOME, "W %d %s %s %Tu :%s", "227" },
589 { RPL_STATSQLINE, "Q %s :%s", "228" },
591 @@ -1050,7 +1050,7 @@
596 + { ERR_NOSUCHWELCOME, "%s :No such welcome", "509" },
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
606 #include "userload.h"
607 +#include "welcome.h"
609 /* #include <assert.h> -- Now using assert in ircd_log.h */
615 + welcome_burst(cptr);
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
625 #include "userload.h"
626 +#include "welcome.h"
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,
637 "Userload statistics." },
638 + { 'W', "welcome", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_W,
640 + "Welcome messages." },
641 { 'x', "memusage", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
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
648 #include "userload.h"
651 +#include "welcome.h"
653 #include "handlers.h" /* m_motd and m_lusers */
656 cli_info(sptr), NumNick(cptr) /* two %s's */);
658 IPcheck_connect_succeeded(sptr);
660 + if (feature_bool(FEAT_WELCOME))
661 + welcome_list(sptr, 1);
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
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>
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.
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.
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.
690 + * @brief Implementation of welcome message handling functions.
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"
704 +#include "numeric.h"
705 +#include "numnicks.h"
707 +#include "s_debug.h"
711 +#include "sys.h" /* FALSE bleah */
712 +#include "welcome.h"
714 +/* #include <assert.h> -- Now using assert in ircd_log.h */
718 +/** List of welcome messages - first MAX for global, second MAX for local */
719 +static struct Welcome WelcomeArray[WELCOME_MAX_ENTRIES * 2];
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.
731 +welcome_make(int name, char *text, char *who, time_t timestamp)
733 + /* range 0 to 2 * max - 1 */
734 + assert(name >= 0 && name <= 2 * WELCOME_MAX_ENTRIES - 1);
737 + ircd_strncpy(WelcomeArray[name].text, text, TOPICLEN);
738 + ircd_strncpy(WelcomeArray[name].who, who, ACCOUNTLEN);
739 + WelcomeArray[name].timestamp = timestamp;
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.
755 +welcome_do(struct Client *cptr, struct Client *sptr, char *name, char *text,
756 + char *who, time_t timestamp, unsigned int flags)
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? */
764 + who[ACCOUNTLEN-1] = 0;
765 + text[WELCOMELEN-1] = 0;
768 + /* TODO: NULL or 0 ? they are pointers, so NULL? */
772 + /* TODO: assert(0 != text); */
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));
780 + if (nameint < 1 || nameint > WELCOME_MAX_ENTRIES) {
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);
788 + /* correct namearray for local offset */
789 + if (flags & WELCOME_LOCAL)
790 + namearray += WELCOME_MAX_ENTRIES;
792 + /* cannot unset welcome that is not set */
793 + if (WelcomeArray[namearray].timestamp == 0 && notext) {
794 + /* from user, throw error */
796 + return send_reply(sptr, ERR_NOSUCHWELCOME, name);
797 + /* new local welcome from server, but empty - ignore */
798 + if (flags & WELCOME_LOCAL)
800 + /* new global welcome message, but empty, accept from server
801 + * otherwise we do not have the same state as them
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)
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..
813 + * how to handle this - like CREATE and settime? hm, or throw error to ops?
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 */
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 */
823 + return welcome_resend(cptr, namearray); /* resync the server */
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.
831 + timestamp = TStime();
833 + /* compare new message with old message */
834 + if (ircd_strcmp(text, WelcomeArray[namearray].text) == 0) {
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);
844 + welcome_make(namearray, text, who, timestamp);
847 + if (flags & WELCOME_LOCAL)
848 + action = notext ? "removing local" : "changing local";
850 + action = notext ? "unsetting" : "changing";
852 + /* TODO: WALLOPS for local welcome messages, so that all operators know about it? */
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);
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);
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);
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);
880 + if ((flags & WELCOME_ANNOUNCE) && !notext)
881 + welcome_announce(namearray);
887 +/** Announce a welcome message to local clients.
888 + * @param[in] name Welcome message to announce.
891 +welcome_announce(int name)
893 + struct Client *acptr;
894 + struct MsgBuf *msgbuf;
896 + /* range 0 to 2 * max - 1 */
897 + assert(name >= 0 && name <= 2 * WELCOME_MAX_ENTRIES - 1);
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.
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);
909 + /* go over clients */
910 + for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
912 + /* skip remote users
913 + * skip unregistered clients - they see the message during login
915 + if (!MyUser(acptr) || !IsRegistered(acptr))
919 + send_buffer(acptr, msgbuf, 0);
924 +/** Send the full list of welcome message to \a cptr.
925 + * @param[in] cptr Local server to send welcomes to.
928 +welcome_burst(struct Client *cptr)
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);
942 +/** Forward a welcome to another server.
943 + * @param[in] cptr %Server to send welcome to.
944 + * @param[in] welcome Welcome to forward.
947 +welcome_resend(struct Client *cptr, int name)
949 + sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %s :%s",
950 + name + 1, WelcomeArray[name].timestamp, WelcomeArray[name].who,
951 + WelcomeArray[name].text);
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
962 +welcome_list(struct Client *sptr, int connect)
964 + int found = 0, local = 0, name;
966 + /* loop over all entries - range 0 to 2 * max - 1 */
967 + for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
969 + /* local entries now */
970 + if (name == WELCOME_MAX_ENTRIES)
973 + /* not set or empty - skip */
974 + if (WelcomeArray[name].timestamp == 0 || *WelcomeArray[name].text == 0)
979 + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :[%s] %s",
980 + sptr, local ? cli_name(&me) : feature_str(FEAT_NETWORK), WelcomeArray[name].text);
984 + if (!found && !connect)
985 + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :No welcome message set.", sptr);
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).
997 +welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param)
999 + int name, local = 0;
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");
1006 + /* loop over all entries - range 0 to 2 * max - 1*/
1007 + for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
1009 + /* local entries now */
1010 + if (name == WELCOME_MAX_ENTRIES)
1014 + if (WelcomeArray[name].timestamp == 0)
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);