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
78 add PRIV_LOCAL_WELCOME PRIV_WELCOME
80 diff -r 4676d2565f9b include/client.h
81 --- a/include/client.h
82 +++ b/include/client.h
84 PRIV_USER_PRIVACY, /* oper can bypass user privacy +x etc gives i.e. see real ip's */
85 PRIV_CHANNEL_PRIVACY, /* oper can bypass channel privacy i.e. can see modes on channels they are not on and channel keys */
86 PRIV_SERVERINFO, /* oper can use /get, /stats, /hash, retrieve remote information */
87 + PRIV_WELCOME, /* oper can WELCOME */
88 + PRIV_LOCAL_WELCOME, /* oper can local WELCOME */
89 PRIV_LAST_PRIV /**< number of privileges */
92 diff -r 4676d2565f9b include/handlers.h
93 --- a/include/handlers.h
94 +++ b/include/handlers.h
96 extern int m_version(struct Client*, struct Client*, int, char*[]);
97 extern int m_wallchops(struct Client*, struct Client*, int, char*[]);
98 extern int m_wallvoices(struct Client*, struct Client*, int, char*[]);
99 +extern int m_welcome(struct Client*, struct Client*, int, char*[]);
100 extern int m_who(struct Client*, struct Client*, int, char*[]);
101 extern int m_whois(struct Client*, struct Client*, int, char*[]);
102 extern int m_whowas(struct Client*, struct Client*, int, char*[]);
104 extern int mo_version(struct Client*, struct Client*, int, char*[]);
105 extern int mo_wallops(struct Client*, struct Client*, int, char*[]);
106 extern int mo_wallusers(struct Client*, struct Client*, int, char*[]);
107 +extern int mo_welcome(struct Client*, struct Client*, int, char*[]);
108 extern int mo_xquery(struct Client*, struct Client*, int, char*[]);
109 extern int mr_error(struct Client*, struct Client*, int, char*[]);
110 extern int mr_error(struct Client*, struct Client*, int, char*[]);
112 extern int ms_wallops(struct Client*, struct Client*, int, char*[]);
113 extern int ms_wallusers(struct Client*, struct Client*, int, char*[]);
114 extern int ms_wallvoices(struct Client*, struct Client*, int, char*[]);
115 +extern int ms_welcome(struct Client*, struct Client*, int, char*[]);
116 extern int ms_whois(struct Client*, struct Client*, int, char*[]);
117 extern int ms_xquery(struct Client*, struct Client*, int, char*[]);
118 extern int ms_xreply(struct Client*, struct Client*, int, char*[]);
119 diff -r 4676d2565f9b include/ircd_features.h
120 --- a/include/ircd_features.h
121 +++ b/include/ircd_features.h
123 FEAT_IRCD_RES_TIMEOUT,
125 FEAT_ANNOUNCE_INVITES,
128 /* features that affect all operators */
129 FEAT_EXTENDED_CHECKCMD,
138 diff -r 4676d2565f9b include/msg.h
142 #define TOK_NOTICE "O"
143 #define CMD_NOTICE MSG_NOTICE, TOK_NOTICE
145 +#define MSG_WELCOME "WELCOME" /* WELC */
146 +#define TOK_WELCOME "WE"
147 +#define CMD_WELCOME MSG_WELCOME, TOK_WELCOME
149 #define MSG_WALLCHOPS "WALLCHOPS" /* WC */
150 #define TOK_WALLCHOPS "WC"
151 #define CMD_WALLCHOPS MSG_WALLCHOPS, TOK_WALLCHOPS
152 diff -r 4676d2565f9b include/numeric.h
153 --- a/include/numeric.h
154 +++ b/include/numeric.h
156 RPL_STATSGLINE 227 Dalnet
157 RPL_STATSVLINE 227 unreal */
158 #define RPL_STATSALINE 226 /* Hybrid, Undernet */
159 +#define RPL_STATSWELCOME 227 /* QuakeNet extension */
160 #define RPL_STATSQLINE 228 /* Undernet extension */
162 /* RPL_SERVICEINFO 231 unused */
164 /* ERR_GHOSTEDCLIENT 503 efnet */
165 /* ERR_VWORLDWARN 503 austnet */
167 +#define ERR_NOSUCHWELCOME 509 /* QuakeNet extension */
169 #define ERR_SILELISTFULL 511 /* Undernet extension */
170 /* ERR_NOTIFYFULL 512 aircd */
171 /* ERR_TOOMANYWATCH 512 Numeric List: Dalnet */
172 diff -r 4676d2565f9b include/welcome.h
174 +++ b/include/welcome.h
176 +#ifndef INCLUDED_welcome_h
177 +#define INCLUDED_welcome_h
179 + * IRC - Internet Relay Chat, include/welcome.h
180 + * Copyright (C) 1990 Jarkko Oikarinen and
181 + * University of Oulu, Computing Center
182 + * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
184 + * This program is free software; you can redistribute it and/or modify
185 + * it under the terms of the GNU General Public License as published by
186 + * the Free Software Foundation; either version 2, or (at your option)
187 + * any later version.
189 + * This program is distributed in the hope that it will be useful,
190 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
191 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
192 + * GNU General Public License for more details.
194 + * You should have received a copy of the GNU General Public License
195 + * along with this program; if not, write to the Free Software
196 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
199 + * @brief Interface and declarations for welcome message handling.
201 +#ifndef INCLUDED_sys_types_h
202 +#include <sys/types.h>
203 +#define INCLUDED_sys_types_h
209 +/* Maximum number of welcome entries (per type; X global, X local) */
210 +#define WELCOME_MAX_ENTRIES 10
211 +/* Maximum length of a welcome message */
212 +#define WELCOMELEN TOPICLEN
213 +/* Maximum timestamp drift in seconds allowed ahead of our idea of nettime
214 + * before we throw a warning to ops
216 +#define WELCOME_MAX_DRIFT 600
218 +/* Describes a Welcome message entry. */
220 + time_t timestamp; /**< Timestamp of the welcome */
221 + char text[WELCOMELEN + 1]; /**< Message */
222 + char who[ACCOUNTLEN + 1]; /**< Who set it */
225 +/** Welcome type flags */
226 +#define WELCOME_LOCAL 0x01 /**< welcome is local */
227 +/** Welcome action flags */
228 +#define WELCOME_ANNOUNCE 0x02 /**< announce change to users */
229 +#define WELCOME_INSERT 0x04 /**< insert welcome message, move down all others one place */
231 +extern int welcome_do(struct Client *cptr, struct Client *sptr, char *name,
232 + time_t timestamp, char *who, char *text, unsigned int flags);
233 +extern void welcome_announce(int name);
234 +extern void welcome_burst(struct Client *cptr);
235 +extern int welcome_list(struct Client *sptr, int connect);
236 +extern void welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param);
238 +#endif /* INCLUDED_welcome_h */
239 diff -r 4676d2565f9b ircd/Makefile.in
240 --- a/ircd/Makefile.in
241 +++ b/ircd/Makefile.in
258 @@ -1161,6 +1163,11 @@
259 ../include/ircd_reply.h ../include/ircd_string.h \
260 ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
261 ../include/numnicks.h ../include/s_user.h ../include/send.h
262 +m_welcome.o: m_welcome.c ../config.h ../include/channel.h \
263 + ../include/client.h ../include/hash.h ../include/ircd.h ../include/ircd_log.h \
264 + ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
265 + ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
266 + ../include/send.h ../include/welcome.h
267 m_who.o: m_who.c ../config.h ../include/channel.h ../include/ircd_defs.h \
268 ../include/res.h ../config.h ../include/client.h ../include/dbuf.h \
269 ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
270 @@ -1422,6 +1429,13 @@
271 ../include/numnicks.h ../include/querycmds.h ../include/ircd_features.h \
272 ../include/s_misc.h ../include/s_stats.h ../include/send.h \
273 ../include/struct.h ../include/sys.h
274 +welcome.o: welcome.c ../config.h ../include/client.h \
275 + ../include/hash.h ../include/ircd.h ../include/ircd_alloc.h \
276 + ../include/ircd_features.h ../include/ircd_log.h ../include/ircd_reply.h \
277 + ../include/match.h ../include/msg.h ../include/numeric.h \
278 + ../include/numnicks.h ../include/s_debug.h ../include/s_bsd.h \
279 + ../include/s_misc.h ../include/send.h ../include/struct.h \
280 + ../include/sys.h ../include/welcome.h
281 whocmds.o: whocmds.c ../config.h ../include/whocmds.h \
282 ../include/channel.h ../include/ircd_defs.h ../include/res.h \
283 ../config.h ../include/client.h ../include/dbuf.h ../include/msgq.h \
284 diff -r 4676d2565f9b ircd/client.c
288 FlagSet(&privs_local, PRIV_WHOX);
289 FlagSet(&privs_local, PRIV_DISPLAY);
290 FlagSet(&privs_local, PRIV_FORCE_LOCAL_OPMODE);
291 + FlagSet(&privs_local, PRIV_LOCAL_WELCOME);
293 privs_defaults_set = 1;
296 ClrPriv(client, PRIV_JUPE);
297 ClrPriv(client, PRIV_OPMODE);
298 ClrPriv(client, PRIV_BADCHAN);
299 + ClrPriv(client, PRIV_WELCOME);
304 P(CHANSERV), P(XTRA_OPER), P(NOIDLE), P(FREEFORM),
305 P(PARANOID), P(CHECK), P(WALL), P(CLOSE),
306 P(ROUTE), P(ROUTEINFO), P(SERVERINFO), P(CHANNEL_PRIVACY),
308 + P(USER_PRIVACY), P(WELCOME), P(LOCAL_WELCOME),
312 diff -r 4676d2565f9b ircd/ircd_features.c
313 --- a/ircd/ircd_features.c
314 +++ b/ircd/ircd_features.c
316 F_I(IRCD_RES_TIMEOUT, 0, 4, 0),
317 F_I(AUTH_TIMEOUT, 0, 9, 0),
318 F_B(ANNOUNCE_INVITES, 0, 0, 0),
319 + F_B(WELCOME, 0, 1, 0),
321 /* features that affect all operators */
322 F_B(EXTENDED_CHECKCMD, 0, 0, 0),
324 F_B(HIS_STATS_u, 0, 1, 0),
325 F_B(HIS_STATS_U, 0, 1, 0),
326 F_B(HIS_STATS_v, 0, 1, 0),
327 + F_B(HIS_STATS_W, 0, 1, 0),
328 F_B(HIS_STATS_w, 0, 1, 0),
329 F_B(HIS_STATS_x, 0, 1, 0),
330 F_B(HIS_STATS_y, 0, 1, 0),
331 diff -r 4676d2565f9b ircd/ircd_lexer.l
332 --- a/ircd/ircd_lexer.l
333 +++ b/ircd/ircd_lexer.l
335 { "serverinfo", TPRIV_SERVERINFO },
336 { "user_privacy", TPRIV_USER_PRIVACY },
337 { "channel_privacy", TPRIV_CHANNEL_PRIVACY },
338 + { "local_welcome", TPRIV_LOCAL_WELCOME },
339 + { "welcome", TPRIV_WELCOME },
343 diff -r 4676d2565f9b ircd/ircd_parser.y
344 --- a/ircd/ircd_parser.y
345 +++ b/ircd/ircd_parser.y
347 %token TPRIV_CHANSERV TPRIV_XTRA_OPER TPRIV_NOIDLE TPRIV_FREEFORM TPRIV_PARANOID
348 %token TPRIV_CHECK TPRIV_WALL TPRIV_CLOSE TPRIV_ROUTE TPRIV_ROUTEINFO TPRIV_SERVERINFO
349 %token TPRIV_CHANNEL_PRIVACY TPRIV_USER_PRIVACY TPRIV_LIST_CHAN
350 +%token TPRIV_LOCAL_WELCOME TPRIV_WELCOME
351 /* and some types... */
353 %type <num> timespec timefactor factoredtimes factoredtime
355 TPRIV_SERVERINFO { $$ = PRIV_SERVERINFO ; } |
356 TPRIV_CHANNEL_PRIVACY { $$ = PRIV_CHANNEL_PRIVACY ; } |
357 TPRIV_USER_PRIVACY { $$ = PRIV_USER_PRIVACY ; } |
358 + TPRIV_LOCAL_WELCOME { $$ = PRIV_LOCAL_WELCOME; } |
359 + TPRIV_WELCOME { $$ = PRIV_WELCOME; } |
360 TPRIV_PARANOID { $$ = PRIV_PARANOID; } ;
361 yesorno: YES { $$ = 1; } | NO { $$ = 0; };
363 diff -r 4676d2565f9b ircd/m_welcome.c
365 +++ b/ircd/m_welcome.c
368 + * IRC - Internet Relay Chat, ircd/m_welcome.c
369 + * Copyright (C) 1990 Jarkko Oikarinen and
370 + * University of Oulu, Computing Center
372 + * See file AUTHORS in IRC package for additional names of
375 + * This program is free software; you can redistribute it and/or modify
376 + * it under the terms of the GNU General Public License as published by
377 + * the Free Software Foundation; either version 1, or (at your option)
378 + * any later version.
380 + * This program is distributed in the hope that it will be useful,
381 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
382 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
383 + * GNU General Public License for more details.
385 + * You should have received a copy of the GNU General Public License
386 + * along with this program; if not, write to the Free Software
387 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
392 + * m_functions execute protocol messages on this server:
394 + * cptr is always NON-NULL, pointing to a *LOCAL* client
395 + * structure (with an open socket connected!). This
396 + * identifies the physical socket where the message
397 + * originated (or which caused the m_function to be
398 + * executed--some m_functions may call others...).
400 + * sptr is the source of the message, defined by the
401 + * prefix part of the message if present. If not
402 + * or prefix not found, then sptr==cptr.
404 + * (!IsServer(cptr)) => (cptr == sptr), because
405 + * prefixes are taken *only* from servers...
408 + * (sptr == cptr) => the message didn't
411 + * (sptr != cptr && IsServer(sptr) means
412 + * the prefix specified servername. (?)
414 + * (sptr != cptr && !IsServer(sptr) means
415 + * that message originated from a remote
416 + * user (not local).
420 + * (!IsServer(sptr)) means that, sptr can safely
421 + * taken as defining the target structure of the
422 + * message in this server.
424 + * *Always* true (if 'parse' and others are working correct):
426 + * 1) sptr->from == cptr (note: cptr->from == cptr)
428 + * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
429 + * *cannot* be a local connection, unless it's
430 + * actually cptr!). [MyConnect(x) should probably
431 + * be defined as (x == x->from) --msa ]
433 + * parc number of variable parameter strings (if zero,
434 + * parv is allowed to be NULL)
436 + * parv a NULL terminated list of parameter pointers,
438 + * parv[0], sender (prefix string), if not present
439 + * this points to an empty string.
440 + * parv[1]...parv[parc-1]
441 + * pointers to additional parameters
442 + * parv[parc] == NULL, *always*
444 + * note: it is guaranteed that parv[0]..parv[parc-1] are all
445 + * non-NULL pointers.
449 +#include "channel.h"
453 +#include "ircd_features.h"
454 +#include "ircd_log.h"
455 +#include "ircd_reply.h"
456 +#include "ircd_snprintf.h"
457 +#include "ircd_string.h"
459 +#include "numeric.h"
460 +#include "numnicks.h"
463 +#include "welcome.h"
465 +/* #include <assert.h> -- Now using assert in ircd_log.h */
468 + * m_welcome - local generic message handler
470 + * parv[0] = Send prefix
471 + * parv[1] = [remote server to query]
473 +int m_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
475 + /* feature disabled */
476 + if (!feature_bool(FEAT_WELCOME))
477 + return send_reply(sptr, ERR_DISABLED, "WELCOME");
479 + /* only opers can set the welcome messages */
481 + return send_reply(sptr, ERR_NOPRIVILEGES);
483 + /* remote listing request, see if it is for me or a remote server
484 + * check FEAT_HIS_REMOTE to decide if an ordinary user can do this
486 + if ((parc > 1) && (hunt_server_cmd(sptr, CMD_WELCOME, cptr, feature_int(FEAT_HIS_REMOTE),
487 + "%C", 1, parc, parv) != HUNTED_ISME))
490 + /* local listing */
491 + return welcome_list(sptr, 0);
496 + * mo_welcome - oper message handler
499 + * parv[0] = Send prefix
502 + * parv[0] = Send prefix
505 + * set global or on remote server:
506 + * parv[0] = Send prefix
507 + * parv[1] = Target: server or * for global (or left out for this server)
511 +int mo_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
513 + char *target, *name, *who, *text, pattern[BUFSIZE];
515 + unsigned int flags = 0;
518 + /* feature disabled */
519 + if (!feature_bool(FEAT_WELCOME))
520 + return send_reply(sptr, ERR_DISABLED, "WELCOME");
522 + /* TODO: move feature check here? */
523 + /* remote listing request, see if it is for me or a remote server */
524 + if ((parc == 2) && (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME))
527 + /* local listing */
529 + return welcome_list(sptr, 0);
532 + /* local - need PRIV LOCAL_WELCOME or WELCOME */
533 + if (parc == 3 && !HasPriv(sptr,PRIV_LOCAL_WELCOME) && !HasPriv(sptr,PRIV_WELCOME))
534 + return send_reply(sptr, ERR_NOPRIVILEGES);
536 + /* global or remote - need PRIV WELCOME */
537 + if (parc >= 4 && !HasPriv(sptr,PRIV_WELCOME))
538 + return send_reply(sptr, ERR_NOPRIVILEGES);
540 + /* set the parameters */
542 + /* target not given, only name - setting local welcome */
545 + target = cli_name(&me);
547 + flags |= WELCOME_LOCAL;
549 + /* target and name given */
554 + timestamp = TStime();
555 + who = cli_user(sptr)->opername;
556 + text = parv[parc - 1];
558 + /* target is not global */
559 + if (!(target[0] == '*' && target[1] == '\0') && !local) {
561 + /* build a pattern for hunt_server_cmd since we do not have all we need in parv */
562 + ircd_snprintf(0, pattern, sizeof(pattern), "%s %s %Tu %s :%s", "%C", name, timestamp, who, text);
563 + if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, pattern, 1, 2, parv) != HUNTED_ISME)
566 + /* else it is a local welcome, for me */
567 + flags |= WELCOME_LOCAL;
570 + /* TODO: disallow global announcement from oper?
571 + * as PRIVMSG/NOTICE to $* is not allowed either by the ircd
572 + * when PRIV for that is added, use that here? PRIV_BROADCAST or something
574 + * change prefix to $ ?
576 + /* check for anounce prefix */
577 + if (*name == '!') {
579 + flags |= WELCOME_ANNOUNCE;
582 + /* check for insert prefix */
583 + if (*name == '+') {
585 + flags |= WELCOME_INSERT;
589 + return welcome_do(cptr, sptr, name, timestamp, who, text, flags);
594 + * ms_welcome - server message handler
596 + * parv[0] = Send prefix
597 + * parv[1] = Target: server numeric or * for global
599 + * parv[3] = Timestamp
603 +int ms_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
605 + char *target, *name, *who, *text;
607 + unsigned int flags = 0;
609 + /* not enough - complain */
611 + protocol_violation(sptr, "Too few parameters for WELCOME (got %d - need 2)", parc);
612 + return need_more_params(sptr, "WELCOME");
615 + /* remote listing request, see if it is for me or a remote server */
617 + if (IsServer(sptr))
618 + return protocol_violation(cptr, "WELCOME listing request from server %C", sptr);
619 + if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME)
621 + return welcome_list(sptr, 0);
624 + /* we need at least 6 parameters to continue - complain */
626 + protocol_violation(sptr, "Too few parameters for WELCOME (got %d - need 6)", parc);
627 + return need_more_params(sptr, "WELCOME");
630 + /* set the parameters */
633 + timestamp = atoi(parv[3]);
635 + text = parv[parc - 1]; /* parse reason as last parameter */
637 + /* target is not global */
638 + if (!(target[0] == '*' && target[1] == '\0')) {
640 + /* not for me, and forward it */
641 + if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C %s %s %s :%s", 1, parc, parv) != HUNTED_ISME)
644 + /* local welcome for me */
645 + flags |= WELCOME_LOCAL;
648 + /* check for anounce prefix */
649 + if (*name == '!') {
651 + flags |= WELCOME_ANNOUNCE;
654 + /* check for insert prefix */
655 + if (*name == '+') {
657 + flags |= WELCOME_INSERT;
661 + return welcome_do(cptr, sptr, name, timestamp, who, text, flags);
663 diff -r 4676d2565f9b ircd/parse.c
667 /* UNREG, CLIENT, SERVER, OPER, SERVICE */
668 { m_unregistered, m_not_oper, ms_check, mo_check, m_ignore }
671 + /* add command for WELCOME */
675 + 0, MAXPARA, MFLG_SLOW, 0, NULL,
676 + /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */
677 + { m_unregistered, m_welcome, ms_welcome, mo_welcome, m_ignore }
680 /* This command is an alias for QUIT during the unregistered part of
681 * of the server. This is because someone jumping via a broken web
682 diff -r 4676d2565f9b ircd/s_err.c
687 { RPL_STATSALINE, "%s", "226" },
690 + { RPL_STATSWELCOME, "W %d %s %s %Tu :%s", "227" },
692 { RPL_STATSQLINE, "Q %s :%s", "228" },
694 @@ -1050,7 +1050,7 @@
699 + { ERR_NOSUCHWELCOME, "%s :No such welcome", "509" },
703 diff -r 4676d2565f9b ircd/s_serv.c
709 #include "userload.h"
710 +#include "welcome.h"
712 /* #include <assert.h> -- Now using assert in ircd_log.h */
718 + welcome_burst(cptr);
721 * Pass on my client information to the new server
722 diff -r 4676d2565f9b ircd/s_stats.c
728 #include "userload.h"
729 +#include "welcome.h"
734 { 'V', "vserversmach", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_v,
735 stats_servers_verbose, 0,
736 "Verbose server information." },
737 - { 'w', "userload", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
738 + { 'w', "userload", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_w,
740 "Userload statistics." },
741 + { 'W', "welcome", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_W,
743 + "Welcome messages." },
744 { 'x', "memusage", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
746 "List usage information." },
747 diff -r 4676d2565f9b ircd/s_user.c
751 #include "userload.h"
754 +#include "welcome.h"
756 #include "handlers.h" /* m_motd and m_lusers */
759 cli_info(sptr), NumNick(cptr) /* two %s's */);
761 IPcheck_connect_succeeded(sptr);
763 + if (feature_bool(FEAT_WELCOME))
764 + welcome_list(sptr, 1);
767 struct Client *acptr = user->server;
768 diff -r 4676d2565f9b ircd/welcome.c
773 + * IRC - Internet Relay Chat, ircd/welcome.c
774 + * Copyright (C) 1990 Jarkko Oikarinen and
775 + * University of Oulu, Finland
776 + * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
778 + * This program is free software; you can redistribute it and/or modify
779 + * it under the terms of the GNU General Public License as published by
780 + * the Free Software Foundation; either version 1, or (at your option)
781 + * any later version.
783 + * This program is distributed in the hope that it will be useful,
784 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
785 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
786 + * GNU General Public License for more details.
788 + * You should have received a copy of the GNU General Public License
789 + * along with this program; if not, write to the Free Software
790 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
793 + * @brief Implementation of welcome message handling functions.
800 +#include "ircd_alloc.h"
801 +#include "ircd_features.h"
802 +#include "ircd_log.h"
803 +#include "ircd_reply.h"
804 +#include "ircd_string.h"
807 +#include "numeric.h"
808 +#include "numnicks.h"
810 +#include "s_debug.h"
814 +#include "sys.h" /* FALSE bleah */
815 +#include "welcome.h"
817 +/* #include <assert.h> -- Now using assert in ircd_log.h */
821 +/** List of welcome messages - first MAX for global, second MAX for local */
822 +static struct Welcome WelcomeArray[WELCOME_MAX_ENTRIES * 2] = { { 0 } };
825 +/** Allocate a new welcome with the given parameters.
826 + * @param[in] name Name of the welcome message.
827 + * @param[in] text The welcome message.
828 + * @param[in] who Who set it.
829 + * @param[in] timestamp When it was set.
830 + * @return name Array number of the welcome set.
833 +welcome_make(int name, char *text, char *who, time_t timestamp)
835 + /* range 0 to 2 * max - 1 */
836 + assert(name >= 0 && name <= 2 * WELCOME_MAX_ENTRIES - 1);
839 + ircd_strncpy(WelcomeArray[name].text, text, WELCOMELEN);
840 + ircd_strncpy(WelcomeArray[name].who, who, ACCOUNTLEN);
841 + WelcomeArray[name].timestamp = timestamp;
847 +/** Propagate a welcome message.
848 + * @param[in] cptr Local client that sent us the welcome.
849 + * @param[in] sptr Originator of the welcome.
850 + * @param[in] nameint Name of the message.
851 + * @param[in] timestamp Timestamp of when the message was set.
852 + * @param[in] who Who set this message.
853 + * @param[in] text The welcome message.
854 + * @param[in] flags Flags to set on welcome.
858 +welcome_propagate(struct Client *cptr, struct Client *sptr, int nameint,
859 + time_t timestamp, char *who, char *text, unsigned int flags)
861 + assert(!(flags & WELCOME_LOCAL));
863 + sendcmdto_serv_butone(sptr, CMD_WELCOME, cptr, "* %s%s%d %Tu %s :%s",
864 + (flags & WELCOME_ANNOUNCE) ? "!" : "", (flags & WELCOME_INSERT) ? "+" : "",
865 + nameint, timestamp, who, text);
871 +/** Log a welcome message.
872 + * @param[in] sptr Originator of the welcome.
873 + * @param[in] msg The message to show.
874 + * @param[in] who Who set this message.
875 + * @param[in] flags Flags to set on welcome.
879 +welcome_log(struct Client *sptr, char *msg, char *who, unsigned int flags)
883 + sendto_opmask_butone(0, SNO_OLDSNO, "%s %s",
884 + (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
885 + get_client_name_and_opername(sptr) : cli_name((cli_user(sptr))->server), msg);
888 + log_write(LS_NETWORK, L_INFO, LOG_NOSNOTICE, "%#C (%s) %s", sptr, who, msg);
890 + /* welcome by remote user, inform oper of success */
891 + if ((flags & WELCOME_LOCAL) && IsUser(sptr) && !MyUser(sptr)) {
892 + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s",
893 + sptr, get_client_name_and_opername(sptr), msg);
895 + /* TODO: wallops all local changes, by both local and remote opers? */
896 + /* tell all opers about the local message being set remotely */
897 + sendwallto_group_butone(&me, WALL_WALLOPS, 0, "%s %s", get_client_name_and_opername(sptr), msg);
904 +/** Set a welcome message.
905 + * @param[in] cptr Local client that sent us the welcome.
906 + * @param[in] sptr Originator of the welcome.
907 + * @param[in] nameint Name of the message.
908 + * @param[in] namearray Array entry.
909 + * @param[in] timestamp Timestamp of when the message was set.
910 + * @param[in] who Who set this message.
911 + * @param[in] text The message.
912 + * @param[in] flags Flags to set on welcome.
916 +welcome_set(struct Client *cptr, struct Client *sptr, int nameint,
917 + int namearray, time_t timestamp, char *who, char *text, unsigned int flags)
919 + char msg[BUFSIZE]; /* msg for snomask, logging, etc. */
923 + Debug((DEBUG_DEBUG, "welcome_set(\"%s\", \"%s\", %d, %d, %Tu, \"%s\", \"%s\", 0x%04x)",
924 + cli_name(cptr), cli_name(sptr), nameint, namearray, timestamp, who, text, flags));
927 + if (*WelcomeArray[namearray].text == 0)
931 + welcome_make(namearray, text, who, timestamp);
933 + /* create msg for snomask, logging, etc. */
934 + ircd_snprintf(0, msg, 0, "%s%s%s WELCOME %d \"%s\" [%Tu]",
935 + new ? "setting" : "changing",
936 + (flags & WELCOME_ANNOUNCE) ? " and announcing " : " ",
937 + (flags & WELCOME_LOCAL) ? "local" : "global",
938 + nameint, text, timestamp);
941 + welcome_log(sptr, msg, who, flags);
944 + if (!(flags & WELCOME_LOCAL))
945 + welcome_propagate(cptr, sptr, nameint, timestamp, who, text, flags);
948 + if (flags & WELCOME_ANNOUNCE)
949 + welcome_announce(namearray);
955 +/** Unset a welcome message.
956 + * @param[in] cptr Local client that sent us the welcome.
957 + * @param[in] sptr Originator of the welcome.
958 + * @param[in] nameint Name of the message.
959 + * @param[in] namearray Array entry.
960 + * @param[in] timestamp Timestamp of when the message was set.
961 + * @param[in] who Who set this message.
962 + * @param[in] flags Flags to set on welcome.
966 +welcome_unset(struct Client *cptr, struct Client *sptr, int nameint,
967 + int namearray, time_t timestamp, char *who, unsigned int flags)
969 + char msg[BUFSIZE]; /* msg for snomask, logging, etc. */
970 + char text[WELCOMELEN + 1]; /* save old text */
971 + int i; /* loop variable */
972 + int empty = namearray; /* first empty spot in array after arrayname */
973 + int end = WELCOME_MAX_ENTRIES -1; /* last element to check in array */
976 + Debug((DEBUG_DEBUG, "welcome_unset(\"%s\", \"%s\", %d, %d, %Tu, \"%s\", 0x%04x)",
977 + cli_name(cptr), cli_name(sptr), nameint, namearray, timestamp, who, flags));
980 + ircd_strncpy(text, WelcomeArray[namearray].text, WELCOMELEN);
983 + welcome_make(namearray, "", who, timestamp);
985 + /* create msg for snomask, logging, etc. */
986 + ircd_snprintf(0, msg, 0, "unsetting %s WELCOME %d \"%s\" [%Tu]",
987 + (flags & WELCOME_LOCAL) ? "local" : "global", nameint, text, timestamp);
990 + welcome_log(sptr, msg, who, flags);
992 + /* propagate it, but not when inserting */
993 + if (!(flags & (WELCOME_LOCAL|WELCOME_INSERT)))
994 + welcome_propagate(cptr, sptr, nameint, timestamp, who, "", flags);
996 + /* correct end for local offset */
997 + if (flags & WELCOME_LOCAL)
998 + end += WELCOME_MAX_ENTRIES;
1000 + /* found first empty spot */
1001 + for (i = namearray; i < end; i++)
1002 + welcome_make(i, WelcomeArray[i+1].text, WelcomeArray[i+1].who, timestamp);
1004 + /* clear last entry */
1005 + welcome_make(end, "", who, timestamp);
1011 +/** Insert a welcome message.
1012 + * @param[in] cptr Local client that sent us the welcome.
1013 + * @param[in] sptr Originator of the welcome.
1014 + * @param[in] nameint Name of the message.
1015 + * @param[in] namearray Array entry.
1016 + * @param[in] timestamp Timestamp of when the message was set.
1017 + * @param[in] who Who set this message.
1018 + * @param[in] text The welcome message.
1019 + * @param[in] flags Flags to set on welcome.
1023 +welcome_insert(struct Client *cptr, struct Client *sptr, int nameint,
1024 + int namearray, time_t timestamp, char *who, char *text, unsigned int flags)
1026 + char msg[BUFSIZE]; /* msg for snomask, logging, etc. */
1027 + int i; /* loop variable */
1028 + int empty = -1; /* first empty spot in array after arrayname */
1029 + int end = WELCOME_MAX_ENTRIES -1; /* last element to check in array */
1030 + int last = end; /* last welcome message to feed to welcome_unset */
1033 + Debug((DEBUG_DEBUG, "welcome_insert(\"%s\", \"%s\", %d, %d, %Tu, \"%s\", \"%s\", 0x%04x)",
1034 + cli_name(cptr), cli_name(sptr), nameint, namearray, timestamp, who, text, flags));
1036 + /* not set yet, do not insert */
1037 + if (WelcomeArray[namearray].timestamp == 0)
1040 + /* last global entry */
1041 + if (!(flags & WELCOME_LOCAL) && (nameint == WELCOME_MAX_ENTRIES))
1044 + /* last local entry */
1045 + if ((flags & WELCOME_LOCAL) && (nameint == 2 * WELCOME_MAX_ENTRIES))
1048 + /* correct end for local offset */
1049 + if (flags & WELCOME_LOCAL)
1050 + end += WELCOME_MAX_ENTRIES;
1052 + /* found first empty spot */
1053 + for (i = namearray; i <= end; i++) {
1054 + if (*WelcomeArray[i].text == 0) {
1060 + /* no empty spot, need to unset last */
1061 + if (empty == -1) {
1062 + welcome_unset(cptr, sptr, end, namearray, timestamp, who, flags);
1066 + /* move entries down, update timestamp */
1067 + for (i = empty; i > namearray; i--)
1068 + welcome_make(i, WelcomeArray[i-1].text, WelcomeArray[i-1].who, timestamp);
1070 + /* correct empty for local offset */
1071 + if (flags & WELCOME_LOCAL)
1072 + empty -= WELCOME_MAX_ENTRIES;
1074 + /* create msg for snomask, logging, etc. */
1075 + if (nameint == empty)
1076 + ircd_snprintf(0, msg, 0, "moving %s WELCOME message %d one place down",
1077 + (flags & WELCOME_LOCAL) ? "local" : "global", nameint);
1079 + ircd_snprintf(0, msg, 0, "moving %s WELCOME message %d %s %d one place down",
1080 + (flags & WELCOME_LOCAL) ? "local" : "global", nameint, (empty - nameint > 1) ? "to" : "and" , empty);
1083 + welcome_log(sptr, msg, who, flags);
1086 + welcome_set(cptr, sptr, nameint, namearray, timestamp, who, text, flags);
1092 +/** Change a welcome message.
1093 + * @param[in] cptr Local client that sent us the welcome.
1094 + * @param[in] sptr Originator of the welcome.
1095 + * @param[in] name Name of the message.
1096 + * @param[in] timestamp Timestamp of when the message was set.
1097 + * @param[in] who Who set this message.
1098 + * @param[in] text The welcome message.
1099 + * @param[in] flags Flags to set on welcome.
1103 +welcome_do(struct Client *cptr, struct Client *sptr, char *name,
1104 + time_t timestamp, char *who, char *text, unsigned int flags)
1106 + int nameint = atoi(name); /* transform to int */
1107 + int namearray = nameint - 1; /* used to test the array element */
1108 + static time_t rate; /* rate limit snomask message */
1110 + assert(NULL != cptr);
1111 + assert(NULL != sptr);
1112 + assert(NULL != name);
1113 + assert(NULL != text);
1114 + assert(NULL != who);
1117 + Debug((DEBUG_DEBUG, "welcome_do(\"%s\", \"%s\", \"%s\", %Tu, \"%s\", \"%s\", 0x%04x)",
1118 + cli_name(cptr), cli_name(sptr), name, timestamp, who, text, flags));
1120 + /* name empty after taking off the prefixes? */
1121 + if (EmptyString(name)) {
1123 + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :WELCOME: No message number given", sptr);
1125 + protocol_violation(cptr, "WELCOME: No message number given by %C", sptr);
1130 + if (nameint < 1 || nameint > WELCOME_MAX_ENTRIES) {
1132 + sendcmdto_one(&me, CMD_NOTICE, sptr,
1133 + "%C :WELCOME: Invalid message number %s - should between 1 and %d",
1134 + sptr, name, WELCOME_MAX_ENTRIES);
1136 + protocol_violation(cptr, "WELCOME: Invalid message number %s from %C - should be between 1 and %d",
1137 + name, sptr, WELCOME_MAX_ENTRIES);
1138 + /* nameint greater than MAX, perhaps we are upgrading, but used extra slots too soon?
1139 + * propagate it manually
1140 + * TODO: cant do announce here?
1142 + if (nameint > WELCOME_MAX_ENTRIES && !(flags & WELCOME_LOCAL))
1143 + welcome_propagate(cptr, sptr, nameint, timestamp, who, text, flags);
1148 + /* correct namearray for local offset */
1149 + if (flags & WELCOME_LOCAL)
1150 + namearray += WELCOME_MAX_ENTRIES;
1152 + /* must be true by now */
1153 + assert(namearray >= 0 && namearray <= 2 * WELCOME_MAX_ENTRIES - 1);
1155 + /* cannot unset welcome that is not set */
1156 + if (WelcomeArray[namearray].timestamp == 0 && EmptyString(text)) {
1158 + /* from user, throw error */
1160 + return send_reply(sptr, ERR_NOSUCHWELCOME, name);
1162 + /* new local welcome from server, but empty - ignore
1163 + * we do accept a new global welcome message that is empty
1165 + if (flags & WELCOME_LOCAL)
1169 + /* check if there is something to change */
1170 + /* we got a record for it */
1171 + if (WelcomeArray[namearray].timestamp != 0) {
1174 + if (!(flags & WELCOME_LOCAL)) {
1176 + /* netburst and we got the same or a newer one
1178 + * we only use the timestamp for resolving conflicts in net burst
1179 + * outside of netburst, we simply parse whatever we get
1180 + * this way we will not get stuck with a welcome message set by a server
1181 + * running ahead with the time
1183 + if (IsBurstOrBurstAck(cptr) && timestamp <= WelcomeArray[namearray].timestamp)
1186 + /* local welcome - we use our idea of the time */
1188 + timestamp = TStime();
1190 + /* compare new message with old message */
1191 + if (ircd_strcmp(text, WelcomeArray[namearray].text) == 0) {
1193 + sendcmdto_one(&me, CMD_NOTICE, sptr,
1194 + "%C :WELCOME: Cannot change %s message for %s - nothing to change.",
1195 + sptr, (flags & WELCOME_LOCAL) ? "local" : "global", name);
1200 + /* TODO: rate limited for what? max 10 welcome messages..? */
1201 + /* possible timestamp drift - warn ops */
1202 + if (timestamp - TStime() > WELCOME_MAX_DRIFT) {
1203 + sendto_opmask_butone_ratelimited(0, SNO_NETWORK, &rate,
1204 + "Possible timestamp drift from %C; timestamp in WELCOME message is %is ahead of time",
1205 + IsServer(sptr) ? sptr : cli_user(sptr)->server, timestamp - TStime());
1207 + /* warn remote oper too */
1209 + sendcmdto_one(&me, CMD_NOTICE, sptr,
1210 + "%C :Possible timestamp drift from %C; timestamp in WELCOME message is %is ahead of time",
1211 + sptr, cli_user(sptr)->server, timestamp - TStime());
1215 + if (EmptyString(text)) {
1216 + flags &= ~WELCOME_INSERT;
1217 + return welcome_unset(cptr, sptr, nameint, namearray, timestamp, who, flags);
1221 + if (flags & WELCOME_INSERT)
1222 + return welcome_insert(cptr, sptr, nameint, namearray, timestamp, who, text, flags);
1224 + /* new or change */
1225 + return welcome_set(cptr, sptr, nameint, namearray, timestamp, who, text, flags);
1229 +/** Announce a welcome message to local clients.
1230 + * @param[in] name Welcome message to announce.
1233 +welcome_announce(int name)
1235 + struct Client *acptr;
1236 + struct MsgBuf *msgbuf;
1239 + /* range 0 to 2 * max - 1 */
1240 + assert(name >= 0 && name <= 2 * WELCOME_MAX_ENTRIES - 1);
1242 + /* TODO: target is $* as if it were a global broadcast
1243 + * could make it $servername for local message announcement
1244 + * but the type is shown between [ ] already
1245 + * either [Network] or [servername] - using $* is just shorter.
1247 + /* build msgbuf */
1248 + msgbuf = msgq_make(0, ":%C %s $* :[%s] %s", &me, MSG_NOTICE,
1249 + name >= WELCOME_MAX_ENTRIES ? cli_name(&me) : feature_str(FEAT_NETWORK),
1250 + WelcomeArray[name].text);
1252 + /* go over local clients */
1253 + for (i = HighestFd; i > 0; --i) {
1255 + /* skip unregistered clients - they see the message during login
1258 + if (!(acptr = LocalClientArray[i]) || !IsRegistered(acptr) || IsServer(acptr))
1261 + /* send it away */
1262 + send_buffer(acptr, msgbuf, 0);
1267 +/** Send the full list of welcome message to \a cptr.
1268 + * @param[in] cptr Local server to send welcomes to.
1271 +welcome_burst(struct Client *cptr)
1275 + assert(NULL != cptr);
1277 + /* loop over global entries - 0 to max - 1*/
1278 + for (name = 0; name <= WELCOME_MAX_ENTRIES - 1; name++) {
1279 + if (WelcomeArray[name].timestamp != 0)
1280 + sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %s :%s",
1281 + name + 1, WelcomeArray[name].timestamp, WelcomeArray[name].who,
1282 + WelcomeArray[name].text);
1287 +/** List welcome messages.
1288 + * @param[in] sptr Client requesting the listing.
1289 + * @param[in] connect When non zero do not report no welcome is set
1293 +welcome_list(struct Client *sptr, int connect)
1295 + int found = 0, local = 0, name;
1297 + assert(NULL != sptr);
1299 + /* loop over all entries - range 0 to 2 * max - 1 */
1300 + for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
1302 + /* local entries now */
1303 + if (name == WELCOME_MAX_ENTRIES)
1306 + /* not set or empty - skip */
1307 + /* TODO: EmptyString? */
1308 + if (WelcomeArray[name].timestamp == 0 || *WelcomeArray[name].text == 0)
1313 + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :[%s] %s",
1314 + sptr, local ? cli_name(&me) : feature_str(FEAT_NETWORK), WelcomeArray[name].text);
1318 + if (!found && !connect)
1319 + sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :No welcome message set.", sptr);
1325 +/** Statistics callback to list Welcome messages.
1326 + * @param[in] sptr Client requesting statistics.
1327 + * @param[in] sd Stats descriptor for request (ignored).
1328 + * @param[in] param Extra parameter from user (ignored).
1331 +welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param)
1333 + int name, local = 0;
1335 + assert(NULL != sptr);
1337 + /* loop over all entries - range 0 to 2 * max - 1*/
1338 + for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
1340 + /* local entries now */
1341 + if (name == WELCOME_MAX_ENTRIES)
1345 + if (WelcomeArray[name].timestamp == 0)
1349 + send_reply(sptr, RPL_STATSWELCOME,
1350 + local ? name + 1 - WELCOME_MAX_ENTRIES : name + 1,
1351 + local ? cli_name(&me) : "*",
1352 + WelcomeArray[name].who, WelcomeArray[name].timestamp,
1353 + EmptyString(WelcomeArray[name].text) ? "<Empty>" : WelcomeArray[name].text);