]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blame_incremental - welcome.patch
localoperkill: made condition simpler
[irc/quakenet/snircd-patchqueue.git] / welcome.patch
... / ...
CommitLineData
1Add welcome message functionality.
2
3client commands:
4user:
5/WELCOME
6shows welcome messages set, same is shown on connect
7
8oper:
9/WELCOME [<target>] [[!]<name> :<message>]
10to view welcome messages from a remote server
11to set a local welcome message on this server or a remote server
12set a global welcome message (target *)
13the ! prefix makes the server annouce the welcome message to its clients when setting
14
15server:
16:<source> WE <target> [[!]<name> <timestamp> <who> :<text>]
17who 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)
19that means there is room for 10 local and 10 global entries
20
21STATS 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
28listing 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
32announcement is done by a notice by the local server to $* with the same message
33format 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
38Files:
39
40include/handlers.h
41add m_welcome mo_welcome ms_welcome mh_welcome functions
42
43include/features.h
44ircd/features.c
45add features FEAT_WELCOME and FEAT_HIS_STATS_W
46
47include/msg.h
48add MSG_WELCOME TOK_WELCOME CMD_WELCOME
49
50ircd/parse.c
51add welcome message functions
52
53include/numeric.h
54ircd/s_err.c
55add RPL_STATSWELCOME ERR_NOSUCHWELCOME
56
57include/welcome.h
58ircd/welcome.c
59ircd/m_welcome.c
60new
61
62ircd/Makefile.in
63add welcome.c and m_welcome.c files
64
65ircd/s_serv.c
66add burst welcome message
67
68ircd/s_stats.c
69add /STATS W/welcome
70
71ircd/s_user.c
72add showing of welcome messages on connect
73
74include/client.h
75ircd/client.c
76ircd/ircd_lexer.l
77ircd/ircd_parser.y
78add PRIV_LOCAL_WELCOME PRIV_WELCOME
79
80diff -r 93eb31739cc6 include/client.h
81--- a/include/client.h
82+++ b/include/client.h
83@@ -142,6 +142,8 @@
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 */
90 };
91
92diff -r 93eb31739cc6 include/handlers.h
93--- a/include/handlers.h
94+++ b/include/handlers.h
95@@ -138,6 +138,7 @@
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*[]);
103@@ -172,6 +173,7 @@
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*[]);
111@@ -230,6 +232,7 @@
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*[]);
119diff -r 93eb31739cc6 include/ircd_features.h
120--- a/include/ircd_features.h
121+++ b/include/ircd_features.h
122@@ -101,6 +101,7 @@
123 FEAT_IRCD_RES_TIMEOUT,
124 FEAT_AUTH_TIMEOUT,
125 FEAT_ANNOUNCE_INVITES,
126+ FEAT_WELCOME,
127
128 /* features that affect all operators */
129 FEAT_EXTENDED_CHECKCMD,
130@@ -142,6 +143,7 @@
131 FEAT_HIS_STATS_u,
132 FEAT_HIS_STATS_U,
133 FEAT_HIS_STATS_v,
134+ FEAT_HIS_STATS_W,
135 FEAT_HIS_STATS_w,
136 FEAT_HIS_STATS_x,
137 FEAT_HIS_STATS_y,
138diff -r 93eb31739cc6 include/msg.h
139--- a/include/msg.h
140+++ b/include/msg.h
141@@ -196,6 +196,10 @@
142 #define TOK_NOTICE "O"
143 #define CMD_NOTICE MSG_NOTICE, TOK_NOTICE
144
145+#define MSG_WELCOME "WELCOME" /* WELC */
146+#define TOK_WELCOME "WE"
147+#define CMD_WELCOME MSG_WELCOME, TOK_WELCOME
148+
149 #define MSG_WALLCHOPS "WALLCHOPS" /* WC */
150 #define TOK_WALLCHOPS "WC"
151 #define CMD_WALLCHOPS MSG_WALLCHOPS, TOK_WALLCHOPS
152diff -r 93eb31739cc6 include/numeric.h
153--- a/include/numeric.h
154+++ b/include/numeric.h
155@@ -116,6 +116,7 @@
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 */
161
162 /* RPL_SERVICEINFO 231 unused */
163@@ -440,6 +441,8 @@
164 /* ERR_GHOSTEDCLIENT 503 efnet */
165 /* ERR_VWORLDWARN 503 austnet */
166
167+#define ERR_NOSUCHWELCOME 509 /* QuakeNet extension */
168+
169 #define ERR_SILELISTFULL 511 /* Undernet extension */
170 /* ERR_NOTIFYFULL 512 aircd */
171 /* ERR_TOOMANYWATCH 512 Numeric List: Dalnet */
172diff -r 93eb31739cc6 include/welcome.h
173--- /dev/null
174+++ b/include/welcome.h
175@@ -0,0 +1,75 @@
176+#ifndef INCLUDED_welcome_h
177+#define INCLUDED_welcome_h
178+/*
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>
183+ *
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.
188+ *
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.
193+ *
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.
197+ */
198+/** @file
199+ * @brief Interface and declarations for welcome message handling.
200+ */
201+#ifndef INCLUDED_sys_types_h
202+#include <sys/types.h>
203+#define INCLUDED_sys_types_h
204+#endif
205+
206+struct Client;
207+struct StatDesc;
208+
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+
214+
215+/* Test if a welcome entry is in a valid range */
216+#define WelcomeIsValid(x) ((unsigned) (x) <= 2 * WELCOME_MAX_ENTRIES -1)
217+/* Test if a welcome entry is set */
218+#define WelcomeIsSet(x) (WelcomeArray[(x)].timestamp > 0)
219+/* Test if a welcome entry is empty */
220+#define WelcomeIsEmpty(x) (*WelcomeArray[(x)].text == 0)
221+
222+/* Get welcome timestamp */
223+#define WelcomeTS(x) (WelcomeArray[(x)].timestamp)
224+/* Get welcome text */
225+#define WelcomeText(x) (WelcomeArray[(x)].text)
226+/* Get welcome who info */
227+#define WelcomeWho(x) (WelcomeArray[(x)].who)
228+
229+
230+/* Describes a Welcome message entry. */
231+struct Welcome {
232+ time_t timestamp; /**< Timestamp of the welcome */
233+ char text[WELCOMELEN + 1]; /**< Message */
234+ char who[ACCOUNTLEN + 1]; /**< Who set it */
235+};
236+
237+/** Welcome type flags */
238+#define WELCOME_LOCAL 0x01 /**< welcome is local */
239+/** Welcome action flags */
240+#define WELCOME_ANNOUNCE 0x02 /**< announce change to users */
241+#define WELCOME_INSERT 0x04 /**< insert welcome message, move down all others one place */
242+
243+extern int welcome_do(struct Client *cptr, struct Client *sptr, char *name,
244+ time_t timestamp, char *who, char *text, unsigned int flags);
245+extern void welcome_announce(int name);
246+extern void welcome_burst(struct Client *cptr);
247+extern int welcome_list(struct Client *sptr, int connect);
248+extern void welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param);
249+
250+#endif /* INCLUDED_welcome_h */
251diff -r 93eb31739cc6 ircd/Makefile.in
252--- a/ircd/Makefile.in
253+++ b/ircd/Makefile.in
254@@ -186,6 +186,7 @@
255 m_wallops.c \
256 m_wallusers.c \
257 m_wallvoices.c \
258+ m_welcome.c \
259 m_who.c \
260 m_whois.c \
261 m_whowas.c \
262@@ -215,6 +216,7 @@
263 send.c \
264 uping.c \
265 userload.c \
266+ welcome.c \
267 whocmds.c \
268 whowas.c \
269 y.tab.c
270@@ -1161,6 +1163,11 @@
271 ../include/ircd_reply.h ../include/ircd_string.h \
272 ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
273 ../include/numnicks.h ../include/s_user.h ../include/send.h
274+m_welcome.o: m_welcome.c ../config.h ../include/channel.h \
275+ ../include/client.h ../include/hash.h ../include/ircd.h ../include/ircd_log.h \
276+ ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
277+ ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
278+ ../include/send.h ../include/welcome.h
279 m_who.o: m_who.c ../config.h ../include/channel.h ../include/ircd_defs.h \
280 ../include/res.h ../config.h ../include/client.h ../include/dbuf.h \
281 ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
282@@ -1422,6 +1429,13 @@
283 ../include/numnicks.h ../include/querycmds.h ../include/ircd_features.h \
284 ../include/s_misc.h ../include/s_stats.h ../include/send.h \
285 ../include/struct.h ../include/sys.h
286+welcome.o: welcome.c ../config.h ../include/client.h \
287+ ../include/hash.h ../include/ircd.h ../include/ircd_alloc.h \
288+ ../include/ircd_features.h ../include/ircd_log.h ../include/ircd_reply.h \
289+ ../include/match.h ../include/msg.h ../include/numeric.h \
290+ ../include/numnicks.h ../include/s_debug.h ../include/s_bsd.h \
291+ ../include/s_misc.h ../include/send.h ../include/struct.h \
292+ ../include/sys.h ../include/welcome.h
293 whocmds.o: whocmds.c ../config.h ../include/whocmds.h \
294 ../include/channel.h ../include/ircd_defs.h ../include/res.h \
295 ../config.h ../include/client.h ../include/dbuf.h ../include/msgq.h \
296diff -r 93eb31739cc6 ircd/client.c
297--- a/ircd/client.c
298+++ b/ircd/client.c
299@@ -177,6 +177,7 @@
300 FlagSet(&privs_local, PRIV_WHOX);
301 FlagSet(&privs_local, PRIV_DISPLAY);
302 FlagSet(&privs_local, PRIV_FORCE_LOCAL_OPMODE);
303+ FlagSet(&privs_local, PRIV_LOCAL_WELCOME);
304
305 privs_defaults_set = 1;
306 }
307@@ -223,6 +224,7 @@
308 ClrPriv(client, PRIV_JUPE);
309 ClrPriv(client, PRIV_OPMODE);
310 ClrPriv(client, PRIV_BADCHAN);
311+ ClrPriv(client, PRIV_WELCOME);
312 }
313 }
314
315@@ -244,7 +246,7 @@
316 P(CHANSERV), P(XTRA_OPER), P(NOIDLE), P(FREEFORM),
317 P(PARANOID), P(CHECK), P(WALL), P(CLOSE),
318 P(ROUTE), P(ROUTEINFO), P(SERVERINFO), P(CHANNEL_PRIVACY),
319- P(USER_PRIVACY),
320+ P(USER_PRIVACY), P(WELCOME), P(LOCAL_WELCOME),
321 #undef P
322 { 0, 0 }
323 };
324diff -r 93eb31739cc6 ircd/ircd_features.c
325--- a/ircd/ircd_features.c
326+++ b/ircd/ircd_features.c
327@@ -366,6 +366,7 @@
328 F_I(IRCD_RES_TIMEOUT, 0, 4, 0),
329 F_I(AUTH_TIMEOUT, 0, 9, 0),
330 F_B(ANNOUNCE_INVITES, 0, 0, 0),
331+ F_B(WELCOME, 0, 1, 0),
332
333 /* features that affect all operators */
334 F_B(EXTENDED_CHECKCMD, 0, 0, 0),
335@@ -407,6 +408,7 @@
336 F_B(HIS_STATS_u, 0, 1, 0),
337 F_B(HIS_STATS_U, 0, 1, 0),
338 F_B(HIS_STATS_v, 0, 1, 0),
339+ F_B(HIS_STATS_W, 0, 1, 0),
340 F_B(HIS_STATS_w, 0, 1, 0),
341 F_B(HIS_STATS_x, 0, 1, 0),
342 F_B(HIS_STATS_y, 0, 1, 0),
343diff -r 93eb31739cc6 ircd/ircd_lexer.l
344--- a/ircd/ircd_lexer.l
345+++ b/ircd/ircd_lexer.l
346@@ -166,6 +166,8 @@
347 { "serverinfo", TPRIV_SERVERINFO },
348 { "user_privacy", TPRIV_USER_PRIVACY },
349 { "channel_privacy", TPRIV_CHANNEL_PRIVACY },
350+ { "local_welcome", TPRIV_LOCAL_WELCOME },
351+ { "welcome", TPRIV_WELCOME },
352 { NULL, 0 }
353 };
354 static int ntokens;
355diff -r 93eb31739cc6 ircd/ircd_parser.y
356--- a/ircd/ircd_parser.y
357+++ b/ircd/ircd_parser.y
358@@ -189,6 +189,7 @@
359 %token TPRIV_CHANSERV TPRIV_XTRA_OPER TPRIV_NOIDLE TPRIV_FREEFORM TPRIV_PARANOID
360 %token TPRIV_CHECK TPRIV_WALL TPRIV_CLOSE TPRIV_ROUTE TPRIV_ROUTEINFO TPRIV_SERVERINFO
361 %token TPRIV_CHANNEL_PRIVACY TPRIV_USER_PRIVACY TPRIV_LIST_CHAN
362+%token TPRIV_LOCAL_WELCOME TPRIV_WELCOME
363 /* and some types... */
364 %type <num> sizespec
365 %type <num> timespec timefactor factoredtimes factoredtime
366@@ -703,6 +704,8 @@
367 TPRIV_SERVERINFO { $$ = PRIV_SERVERINFO ; } |
368 TPRIV_CHANNEL_PRIVACY { $$ = PRIV_CHANNEL_PRIVACY ; } |
369 TPRIV_USER_PRIVACY { $$ = PRIV_USER_PRIVACY ; } |
370+ TPRIV_LOCAL_WELCOME { $$ = PRIV_LOCAL_WELCOME; } |
371+ TPRIV_WELCOME { $$ = PRIV_WELCOME; } |
372 TPRIV_PARANOID { $$ = PRIV_PARANOID; } ;
373 yesorno: YES { $$ = 1; } | NO { $$ = 0; };
374
375diff -r 93eb31739cc6 ircd/m_welcome.c
376--- /dev/null
377+++ b/ircd/m_welcome.c
378@@ -0,0 +1,292 @@
379+/*
380+ * IRC - Internet Relay Chat, ircd/m_welcome.c
381+ * Copyright (C) 1990 Jarkko Oikarinen and
382+ * University of Oulu, Computing Center
383+ *
384+ * See file AUTHORS in IRC package for additional names of
385+ * the programmers.
386+ *
387+ * This program is free software; you can redistribute it and/or modify
388+ * it under the terms of the GNU General Public License as published by
389+ * the Free Software Foundation; either version 1, or (at your option)
390+ * any later version.
391+ *
392+ * This program is distributed in the hope that it will be useful,
393+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
394+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
395+ * GNU General Public License for more details.
396+ *
397+ * You should have received a copy of the GNU General Public License
398+ * along with this program; if not, write to the Free Software
399+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
400+ *
401+ */
402+
403+/*
404+ * m_functions execute protocol messages on this server:
405+ *
406+ * cptr is always NON-NULL, pointing to a *LOCAL* client
407+ * structure (with an open socket connected!). This
408+ * identifies the physical socket where the message
409+ * originated (or which caused the m_function to be
410+ * executed--some m_functions may call others...).
411+ *
412+ * sptr is the source of the message, defined by the
413+ * prefix part of the message if present. If not
414+ * or prefix not found, then sptr==cptr.
415+ *
416+ * (!IsServer(cptr)) => (cptr == sptr), because
417+ * prefixes are taken *only* from servers...
418+ *
419+ * (IsServer(cptr))
420+ * (sptr == cptr) => the message didn't
421+ * have the prefix.
422+ *
423+ * (sptr != cptr && IsServer(sptr) means
424+ * the prefix specified servername. (?)
425+ *
426+ * (sptr != cptr && !IsServer(sptr) means
427+ * that message originated from a remote
428+ * user (not local).
429+ *
430+ * combining
431+ *
432+ * (!IsServer(sptr)) means that, sptr can safely
433+ * taken as defining the target structure of the
434+ * message in this server.
435+ *
436+ * *Always* true (if 'parse' and others are working correct):
437+ *
438+ * 1) sptr->from == cptr (note: cptr->from == cptr)
439+ *
440+ * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
441+ * *cannot* be a local connection, unless it's
442+ * actually cptr!). [MyConnect(x) should probably
443+ * be defined as (x == x->from) --msa ]
444+ *
445+ * parc number of variable parameter strings (if zero,
446+ * parv is allowed to be NULL)
447+ *
448+ * parv a NULL terminated list of parameter pointers,
449+ *
450+ * parv[0], sender (prefix string), if not present
451+ * this points to an empty string.
452+ * parv[1]...parv[parc-1]
453+ * pointers to additional parameters
454+ * parv[parc] == NULL, *always*
455+ *
456+ * note: it is guaranteed that parv[0]..parv[parc-1] are all
457+ * non-NULL pointers.
458+ */
459+#include "config.h"
460+
461+#include "channel.h"
462+#include "client.h"
463+#include "hash.h"
464+#include "ircd.h"
465+#include "ircd_features.h"
466+#include "ircd_log.h"
467+#include "ircd_reply.h"
468+#include "ircd_snprintf.h"
469+#include "ircd_string.h"
470+#include "msg.h"
471+#include "numeric.h"
472+#include "numnicks.h"
473+#include "s_user.h"
474+#include "send.h"
475+#include "welcome.h"
476+
477+/* #include <assert.h> -- Now using assert in ircd_log.h */
478+
479+/*
480+ * m_welcome - local generic message handler
481+ *
482+ * parv[0] = Send prefix
483+ * parv[1] = [remote server to query]
484+ */
485+int m_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
486+{
487+ /* feature disabled */
488+ if (!feature_bool(FEAT_WELCOME))
489+ return send_reply(sptr, ERR_DISABLED, "WELCOME");
490+
491+ /* only opers can set the welcome messages */
492+ if (parc > 2)
493+ return send_reply(sptr, ERR_NOPRIVILEGES);
494+
495+ /* remote listing request, see if it is for me or a remote server
496+ * check FEAT_HIS_REMOTE to decide if an ordinary user can do this
497+ */
498+ if ((parc > 1) && (hunt_server_cmd(sptr, CMD_WELCOME, cptr, feature_int(FEAT_HIS_REMOTE),
499+ "%C", 1, parc, parv) != HUNTED_ISME))
500+ return 0;
501+
502+ /* local listing */
503+ return welcome_list(sptr, 0);
504+}
505+
506+
507+/*
508+ * mo_welcome - oper message handler
509+ *
510+ * listing:
511+ * parv[0] = Send prefix
512+ *
513+ * remote listing:
514+ * parv[0] = Send prefix
515+ * parv[1] = Target
516+ *
517+ * set global or on remote server:
518+ * parv[0] = Send prefix
519+ * parv[1] = Target: server or * for global (or left out for this server)
520+ * parv[2] = Name
521+ * parv[3] = Text
522+ */
523+int mo_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
524+{
525+ char *target, *name, *who, *text, pattern[BUFSIZE];
526+ time_t timestamp;
527+ unsigned int flags = 0;
528+ int local = 0;
529+
530+ /* feature disabled */
531+ if (!feature_bool(FEAT_WELCOME))
532+ return send_reply(sptr, ERR_DISABLED, "WELCOME");
533+
534+ /* TODO: move feature check here? */
535+ /* remote listing request, see if it is for me or a remote server */
536+ if ((parc == 2) && (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME))
537+ return 0;
538+
539+ /* local listing */
540+ if (parc <= 2)
541+ return welcome_list(sptr, 0);
542+
543+ /* check PRIVS */
544+ /* local - need PRIV LOCAL_WELCOME or WELCOME */
545+ if (parc == 3 && !HasPriv(sptr,PRIV_LOCAL_WELCOME) && !HasPriv(sptr,PRIV_WELCOME))
546+ return send_reply(sptr, ERR_NOPRIVILEGES);
547+
548+ /* global or remote - need PRIV WELCOME */
549+ if (parc >= 4 && !HasPriv(sptr,PRIV_WELCOME))
550+ return send_reply(sptr, ERR_NOPRIVILEGES);
551+
552+ /* set the parameters */
553+
554+ /* target not given, only name - setting local welcome */
555+ if (parc < 4) {
556+ local++;
557+ target = cli_name(&me);
558+ name = parv[1];
559+ flags |= WELCOME_LOCAL;
560+
561+ /* target and name given */
562+ } else {
563+ target = parv[1];
564+ name = parv[2];
565+ }
566+ timestamp = TStime();
567+ who = cli_user(sptr)->opername;
568+ text = parv[parc - 1];
569+
570+ /* target is not global */
571+ if (!(target[0] == '*' && target[1] == '\0') && !local) {
572+
573+ /* build a pattern for hunt_server_cmd since we do not have all we need in parv */
574+ ircd_snprintf(0, pattern, sizeof(pattern), "%s %s %Tu %s :%s", "%C", name, timestamp, who, text);
575+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, pattern, 1, 2, parv) != HUNTED_ISME)
576+ return 0;
577+
578+ /* else it is a local welcome, for me */
579+ flags |= WELCOME_LOCAL;
580+ }
581+
582+ /* check for anounce prefix */
583+ if (*name == '$') {
584+ name++;
585+ /* only allow announce by oper for local welcome */
586+ if (flags & WELCOME_LOCAL)
587+ flags |= WELCOME_ANNOUNCE;
588+ }
589+
590+ /* check for insert prefix */
591+ if (*name == '+') {
592+ name++;
593+ flags |= WELCOME_INSERT;
594+ }
595+
596+ /* and do it */
597+ return welcome_do(cptr, sptr, name, timestamp, who, text, flags);
598+}
599+
600+
601+/*
602+ * ms_welcome - server message handler
603+ *
604+ * parv[0] = Send prefix
605+ * parv[1] = Target: server numeric or * for global
606+ * parv[2] = Name
607+ * parv[3] = Timestamp
608+ * parv[4] = Who
609+ * parv[5] = Text
610+ */
611+int ms_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
612+{
613+ char *target, *name, *who, *text;
614+ time_t timestamp;
615+ unsigned int flags = 0;
616+
617+ /* not enough - complain */
618+ if (parc < 2) {
619+ protocol_violation(sptr, "Too few parameters for WELCOME (got %d - need 2)", parc);
620+ return need_more_params(sptr, "WELCOME");
621+ }
622+
623+ /* remote listing request, see if it is for me or a remote server */
624+ if (parc == 2) {
625+ if (IsServer(sptr))
626+ return protocol_violation(cptr, "WELCOME listing request from server %C", sptr);
627+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME)
628+ return 0;
629+ return welcome_list(sptr, 0);
630+ }
631+
632+ /* we need at least 6 parameters to continue - complain */
633+ if (parc < 6) {
634+ protocol_violation(sptr, "Too few parameters for WELCOME (got %d - need 6)", parc);
635+ return need_more_params(sptr, "WELCOME");
636+ }
637+
638+ /* set the parameters */
639+ target = parv[1];
640+ name = parv[2];
641+ timestamp = atoi(parv[3]);
642+ who = parv[4];
643+ text = parv[parc - 1]; /* parse reason as last parameter */
644+
645+ /* target is not global */
646+ if (!(target[0] == '*' && target[1] == '\0')) {
647+
648+ /* not for me, and forward it */
649+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C %s %s %s :%s", 1, parc, parv) != HUNTED_ISME)
650+ return 0;
651+
652+ /* local welcome for me */
653+ flags |= WELCOME_LOCAL;
654+ }
655+
656+ /* check for anounce prefix */
657+ if (*name == '$') {
658+ name++;
659+ flags |= WELCOME_ANNOUNCE;
660+ }
661+
662+ /* check for insert prefix */
663+ if (*name == '+') {
664+ name++;
665+ flags |= WELCOME_INSERT;
666+ }
667+
668+ /* and do it */
669+ return welcome_do(cptr, sptr, name, timestamp, who, text, flags);
670+}
671diff -r 93eb31739cc6 ircd/parse.c
672--- a/ircd/parse.c
673+++ b/ircd/parse.c
674@@ -661,6 +661,15 @@
675 /* UNREG, CLIENT, SERVER, OPER, SERVICE */
676 { m_unregistered, m_not_oper, ms_check, mo_check, m_ignore }
677 },
678+
679+ /* add command for WELCOME */
680+ {
681+ MSG_WELCOME,
682+ TOK_WELCOME,
683+ 0, MAXPARA, MFLG_SLOW, 0, NULL,
684+ /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */
685+ { m_unregistered, m_welcome, ms_welcome, mo_welcome, m_ignore }
686+ },
687
688 /* This command is an alias for QUIT during the unregistered part of
689 * of the server. This is because someone jumping via a broken web
690diff -r 93eb31739cc6 ircd/s_err.c
691--- a/ircd/s_err.c
692+++ b/ircd/s_err.c
693@@ -486,7 +486,7 @@
694 /* 226 */
695 { RPL_STATSALINE, "%s", "226" },
696 /* 227 */
697- { 0 },
698+ { RPL_STATSWELCOME, "W %d %s %s %Tu :%s", "227" },
699 /* 228 */
700 { RPL_STATSQLINE, "Q %s :%s", "228" },
701 /* 229 */
702@@ -1050,7 +1050,7 @@
703 /* 508 */
704 { 0 },
705 /* 509 */
706- { 0 },
707+ { ERR_NOSUCHWELCOME, "%s :No such welcome", "509" },
708 /* 510 */
709 { 0 },
710 /* 511 */
711diff -r 93eb31739cc6 ircd/s_serv.c
712--- a/ircd/s_serv.c
713+++ b/ircd/s_serv.c
714@@ -57,6 +57,7 @@
715 #include "struct.h"
716 #include "sys.h"
717 #include "userload.h"
718+#include "welcome.h"
719
720 /* #include <assert.h> -- Now using assert in ircd_log.h */
721 #include <stdlib.h>
722@@ -196,6 +197,7 @@
723 */
724 gline_burst(cptr);
725 jupe_burst(cptr);
726+ welcome_burst(cptr);
727
728 /*
729 * Pass on my client information to the new server
730diff -r 93eb31739cc6 ircd/s_stats.c
731--- a/ircd/s_stats.c
732+++ b/ircd/s_stats.c
733@@ -54,6 +54,7 @@
734 #include "send.h"
735 #include "struct.h"
736 #include "userload.h"
737+#include "welcome.h"
738
739 #include <stdio.h>
740 #include <stdlib.h>
741@@ -654,9 +655,12 @@
742 { 'V', "vserversmach", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_v,
743 stats_servers_verbose, 0,
744 "Verbose server information." },
745- { 'w', "userload", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
746+ { 'w', "userload", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_w,
747 calc_load, 0,
748 "Userload statistics." },
749+ { 'W', "welcome", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_W,
750+ welcome_stats, 0,
751+ "Welcome messages." },
752 { 'x', "memusage", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
753 stats_meminfo, 0,
754 "List usage information." },
755diff -r 93eb31739cc6 ircd/s_user.c
756--- a/ircd/s_user.c
757+++ b/ircd/s_user.c
758@@ -63,6 +63,7 @@
759 #include "userload.h"
760 #include "version.h"
761 #include "whowas.h"
762+#include "welcome.h"
763
764 #include "handlers.h" /* m_motd and m_lusers */
765
766@@ -410,6 +411,9 @@
767 cli_info(sptr), NumNick(cptr) /* two %s's */);
768
769 IPcheck_connect_succeeded(sptr);
770+
771+ if (feature_bool(FEAT_WELCOME))
772+ welcome_list(sptr, 1);
773 }
774 else {
775 struct Client *acptr = user->server;
776diff -r 93eb31739cc6 ircd/welcome.c
777--- /dev/null
778+++ b/ircd/welcome.c
779@@ -0,0 +1,628 @@
780+/*
781+ * IRC - Internet Relay Chat, ircd/welcome.c
782+ * Copyright (C) 1990 Jarkko Oikarinen and
783+ * University of Oulu, Finland
784+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
785+ *
786+ * This program is free software; you can redistribute it and/or modify
787+ * it under the terms of the GNU General Public License as published by
788+ * the Free Software Foundation; either version 1, or (at your option)
789+ * any later version.
790+ *
791+ * This program is distributed in the hope that it will be useful,
792+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
793+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
794+ * GNU General Public License for more details.
795+ *
796+ * You should have received a copy of the GNU General Public License
797+ * along with this program; if not, write to the Free Software
798+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
799+ */
800+/** @file
801+ * @brief Implementation of welcome message handling functions.
802+ */
803+#include "config.h"
804+
805+#include "client.h"
806+#include "hash.h"
807+#include "ircd.h"
808+#include "ircd_alloc.h"
809+#include "ircd_features.h"
810+#include "ircd_log.h"
811+#include "ircd_reply.h"
812+#include "ircd_string.h"
813+#include "match.h"
814+#include "msg.h"
815+#include "numeric.h"
816+#include "numnicks.h"
817+#include "s_bsd.h"
818+#include "s_debug.h"
819+#include "s_misc.h"
820+#include "send.h"
821+#include "struct.h"
822+#include "sys.h" /* FALSE bleah */
823+#include "welcome.h"
824+
825+/* #include <assert.h> -- Now using assert in ircd_log.h */
826+#include <string.h>
827+
828+
829+/** List of welcome messages - first MAX for global, second MAX for local */
830+static struct Welcome WelcomeArray[WELCOME_MAX_ENTRIES * 2] = { { 0 } };
831+
832+
833+/** Allocate a new welcome with the given parameters.
834+ * @param[in] name Name of the welcome message.
835+ * @param[in] text The welcome message.
836+ * @param[in] who Who set it.
837+ * @param[in] timestamp When it was set.
838+ * @return name Array number of the welcome set.
839+ */
840+static int
841+welcome_make(int name, char *text, char *who, time_t timestamp)
842+{
843+ assert(WelcomeIsValid(name));
844+ assert(NULL != text);
845+ assert(NULL != who);
846+
847+ /* store it */
848+ ircd_strncpy(WelcomeArray[name].text, text, WELCOMELEN);
849+ ircd_strncpy(WelcomeArray[name].who, who, ACCOUNTLEN);
850+ WelcomeArray[name].timestamp = timestamp;
851+
852+ return name;
853+}
854+
855+
856+/** Propagate a welcome message.
857+ * @param[in] cptr Local client that sent us the welcome.
858+ * @param[in] sptr Originator of the welcome.
859+ * @param[in] nameint Name of the message.
860+ * @param[in] timestamp Timestamp of when the message was set.
861+ * @param[in] who Who set this message.
862+ * @param[in] text The welcome message.
863+ * @param[in] flags Flags to set on welcome.
864+ * @return Zero
865+ */
866+int
867+welcome_propagate(struct Client *cptr, struct Client *sptr, int nameint,
868+ time_t timestamp, char *who, char *text, unsigned int flags)
869+{
870+ assert(NULL != sptr);
871+ assert(NULL != cptr);
872+ assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
873+ assert(!(flags & WELCOME_LOCAL));
874+
875+ sendcmdto_serv_butone(sptr, CMD_WELCOME, cptr, "* %s%s%d %Tu %s :%s",
876+ (flags & WELCOME_ANNOUNCE) ? "$" : "", (flags & WELCOME_INSERT) ? "+" : "",
877+ nameint, timestamp, who, text);
878+
879+ return 0;
880+}
881+
882+
883+/** Resend a welcome message.
884+ * @param[in] cptr Local client that sent us the welcome.
885+ * @param[in] nameint Name of the message.
886+ * @param[in] namearray Name of the array item.
887+ * @return Zero
888+ */
889+int
890+welcome_resend(struct Client *cptr, int nameint, int namearray)
891+{
892+ assert(NULL != cptr);
893+ assert(IsServer(cptr));
894+ assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
895+ assert(WelcomeIsValid(namearray));
896+
897+ sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %s :%s",
898+ nameint, WelcomeTS(namearray), WelcomeWho(namearray), WelcomeText(namearray));
899+
900+ return 0;
901+}
902+
903+
904+/** Log a welcome message.
905+ * @param[in] sptr Originator of the welcome.
906+ * @param[in] msg The message to show.
907+ * @param[in] flags Flags to set on welcome.
908+ * @return Zero
909+ */
910+int
911+welcome_log(struct Client *sptr, char *msg, unsigned int flags)
912+{
913+ assert(NULL != sptr);
914+ assert(NULL != msg);
915+
916+ /* inform ops */
917+ sendto_opmask_butone(0, SNO_OLDSNO, "%s %s",
918+ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
919+ get_client_name_and_opername(sptr) : cli_name((cli_user(sptr))->server), msg);
920+
921+ /* log it */
922+ log_write(LS_NETWORK, L_INFO, LOG_NOSNOTICE, "%s %s", get_client_name_and_opername(sptr), msg);
923+
924+ /* welcome by remote user, inform oper of success */
925+ if ((flags & WELCOME_LOCAL) && IsUser(sptr) && !MyUser(sptr)) {
926+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s",
927+ sptr, get_client_name_and_opername(sptr), msg);
928+
929+ /* TODO: wallops all local changes, by both local and remote opers? */
930+ /* tell all opers about the local message being set remotely */
931+ sendwallto_group_butone(&me, WALL_WALLOPS, 0, "%s %s", get_client_name_and_opername(sptr), msg);
932+ }
933+
934+ return 0;
935+}
936+
937+
938+/** Set a welcome message.
939+ * @param[in] cptr Local client that sent us the welcome.
940+ * @param[in] sptr Originator of the welcome.
941+ * @param[in] nameint Name of the message.
942+ * @param[in] namearray Array entry.
943+ * @param[in] timestamp Timestamp of when the message was set.
944+ * @param[in] who Who set this message.
945+ * @param[in] text The message.
946+ * @param[in] flags Flags to set on welcome.
947+ * @return Zero
948+ */
949+int
950+welcome_set(struct Client *cptr, struct Client *sptr, int nameint,
951+ int namearray, time_t timestamp, char *who, char *text, unsigned int flags)
952+{
953+ char msg[BUFSIZE]; /* msg for logging */
954+ int new = 0;
955+
956+ assert(NULL != cptr);
957+ assert(NULL != sptr);
958+ assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
959+ assert(WelcomeIsValid(namearray));
960+
961+ /* debug */
962+ Debug((DEBUG_DEBUG, "welcome_set(\"%s\", \"%s\", %d, %d, %Tu, \"%s\", \"%s\", 0x%04x)",
963+ cli_name(cptr), cli_name(sptr), nameint, namearray, timestamp, who, text, flags));
964+
965+ /* not set */
966+ if (WelcomeIsEmpty(namearray))
967+ new = 1;
968+
969+ /* update */
970+ welcome_make(namearray, text, who, timestamp);
971+
972+ /* create msg for log */
973+ ircd_snprintf(0, msg, 0, "%s%s%s WELCOME %d \"%s\" %s [%Tu]",
974+ new ? "setting" : "changing",
975+ (flags & WELCOME_ANNOUNCE) ? " and announcing " : " ",
976+ (flags & WELCOME_LOCAL) ? "local" : "global",
977+ nameint, WelcomeText(namearray), WelcomeWho(namearray), timestamp);
978+
979+ /* log it */
980+ welcome_log(sptr, msg, flags);
981+
982+ /* propagate it */
983+ if (!(flags & WELCOME_LOCAL))
984+ welcome_propagate(cptr, sptr, nameint, timestamp, who, text, flags);
985+
986+ /* announce it */
987+ if (flags & WELCOME_ANNOUNCE)
988+ welcome_announce(namearray);
989+
990+ return 0;
991+}
992+
993+
994+/** Unset a welcome message.
995+ * @param[in] cptr Local client that sent us the welcome.
996+ * @param[in] sptr Originator of the welcome.
997+ * @param[in] nameint Name of the message.
998+ * @param[in] namearray Array entry.
999+ * @param[in] timestamp Timestamp of when the message was set.
1000+ * @param[in] who Who set this message.
1001+ * @param[in] flags Flags to set on welcome.
1002+ * @return Zero
1003+ */
1004+int
1005+welcome_unset(struct Client *cptr, struct Client *sptr, int nameint,
1006+ int namearray, time_t timestamp, char *who, unsigned int flags)
1007+{
1008+ char msg[BUFSIZE]; /* msg for logging */
1009+ int i; /* loop variable */
1010+ int empty = namearray; /* first empty spot in array after namearray */
1011+ int end = WELCOME_MAX_ENTRIES -1; /* last element to check in array */
1012+
1013+ assert(NULL != cptr);
1014+ assert(NULL != sptr);
1015+ assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
1016+ assert(WelcomeIsValid(namearray));
1017+
1018+ /* debug */
1019+ Debug((DEBUG_DEBUG, "welcome_unset(\"%s\", \"%s\", %d, %d, %Tu, \"%s\", 0x%04x)",
1020+ cli_name(cptr), cli_name(sptr), nameint, namearray, timestamp, who, flags));
1021+
1022+ /* create msg for log */
1023+ ircd_snprintf(0, msg, 0, "unsetting %s WELCOME %d \"%s\" %s [%Tu]",
1024+ (flags & WELCOME_LOCAL) ? "local" : "global",
1025+ nameint, WelcomeText(namearray), WelcomeWho(namearray), timestamp);
1026+
1027+ /* log it */
1028+ welcome_log(sptr, msg, flags);
1029+
1030+ /* update */
1031+ welcome_make(namearray, "", who, timestamp);
1032+
1033+ /* propagate it, but not when inserting */
1034+ if (!(flags & (WELCOME_LOCAL|WELCOME_INSERT)))
1035+ welcome_propagate(cptr, sptr, nameint, timestamp, who, "", flags);
1036+
1037+ /* correct end for local offset */
1038+ if (flags & WELCOME_LOCAL)
1039+ end += WELCOME_MAX_ENTRIES;
1040+
1041+ /* move entries up, update timestamp */
1042+ for (i = namearray; i < end; i++)
1043+ welcome_make(i, WelcomeText(i+1), WelcomeWho(i+1), timestamp);
1044+
1045+ /* clear last entry, update timestamp */
1046+ welcome_make(end, "", who, timestamp);
1047+
1048+ return 0;
1049+}
1050+
1051+
1052+/** Insert a welcome message.
1053+ * @param[in] cptr Local client that sent us the welcome.
1054+ * @param[in] sptr Originator of the welcome.
1055+ * @param[in] nameint Name of the message.
1056+ * @param[in] namearray Array entry.
1057+ * @param[in] timestamp Timestamp of when the message was set.
1058+ * @param[in] who Who set this message.
1059+ * @param[in] text The welcome message.
1060+ * @param[in] flags Flags to set on welcome.
1061+ * @return Zero
1062+ */
1063+int
1064+welcome_insert(struct Client *cptr, struct Client *sptr, int nameint,
1065+ int namearray, time_t timestamp, char *who, char *text, unsigned int flags)
1066+{
1067+ char msg[BUFSIZE]; /* msg for logging */
1068+ int i; /* loop variable */
1069+ int empty = -1; /* first empty spot in array after namearray */
1070+ int end = WELCOME_MAX_ENTRIES -1; /* last element to check in array */
1071+ int last = end; /* last welcome message to feed to welcome_unset */
1072+
1073+ assert(NULL != cptr);
1074+ assert(NULL != sptr);
1075+ assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
1076+ assert(WelcomeIsValid(namearray));
1077+
1078+ /* debug */
1079+ Debug((DEBUG_DEBUG, "welcome_insert(\"%s\", \"%s\", %d, %d, %Tu, \"%s\", \"%s\", 0x%04x)",
1080+ cli_name(cptr), cli_name(sptr), nameint, namearray, timestamp, who, text, flags));
1081+
1082+ /* correct end for local offset */
1083+ if (flags & WELCOME_LOCAL)
1084+ end += WELCOME_MAX_ENTRIES;
1085+
1086+ /* find first empty spot */
1087+ for (i = namearray; i <= end; i++) {
1088+ if (WelcomeIsEmpty(i)) {
1089+ empty = i;
1090+ break;
1091+ }
1092+ }
1093+
1094+ /* no empty spot, need to unset last */
1095+ if (empty == -1) {
1096+ welcome_unset(cptr, sptr, end, namearray, timestamp, who, flags);
1097+ empty = end;
1098+ }
1099+
1100+ /* move entries down, update timestamp */
1101+ for (i = empty; i > namearray; i--)
1102+ welcome_make(i, WelcomeText(i-1), WelcomeWho(i-1), timestamp);
1103+
1104+ /* correct empty for local offset */
1105+ if (flags & WELCOME_LOCAL)
1106+ empty -= WELCOME_MAX_ENTRIES;
1107+
1108+ /* create msg for log */
1109+ if (nameint == empty)
1110+ ircd_snprintf(0, msg, 0, "moving %s WELCOME message %d one place down",
1111+ (flags & WELCOME_LOCAL) ? "local" : "global", nameint);
1112+ else
1113+ ircd_snprintf(0, msg, 0, "moving %s WELCOME message %d %s %d one place down",
1114+ (flags & WELCOME_LOCAL) ? "local" : "global", nameint, (empty - nameint > 1) ? "to" : "and" , empty);
1115+
1116+ /* log it */
1117+ welcome_log(sptr, msg, flags);
1118+
1119+ /* set it */
1120+ welcome_set(cptr, sptr, nameint, namearray, timestamp, who, text, flags);
1121+
1122+ return 0;
1123+}
1124+
1125+
1126+/** Change a welcome message.
1127+ * @param[in] cptr Local client that sent us the welcome.
1128+ * @param[in] sptr Originator of the welcome.
1129+ * @param[in] name Name of the message.
1130+ * @param[in] timestamp Timestamp of when the message was set.
1131+ * @param[in] who Who set this message.
1132+ * @param[in] text The welcome message.
1133+ * @param[in] flags Flags to set on welcome.
1134+ * @return Zero
1135+ */
1136+int
1137+welcome_do(struct Client *cptr, struct Client *sptr, char *name,
1138+ time_t timestamp, char *who, char *text, unsigned int flags)
1139+{
1140+ int nameint = atoi(name); /* transform to int */
1141+ int namearray = nameint - 1; /* used to test the array element */
1142+
1143+ assert(NULL != cptr);
1144+ assert(NULL != sptr);
1145+ assert(NULL != name);
1146+ assert(NULL != text);
1147+ assert(NULL != who);
1148+
1149+ /* debug */
1150+ Debug((DEBUG_DEBUG, "welcome_do(\"%s\", \"%s\", \"%s\", %Tu, \"%s\", \"%s\", 0x%04x)",
1151+ cli_name(cptr), cli_name(sptr), name, timestamp, who, text, flags));
1152+
1153+ /* if for some reason timestamp is 0, increase it */
1154+ if (timestamp == 0)
1155+ timestamp++;
1156+
1157+ /* name empty after taking off the prefixes? */
1158+ if (EmptyString(name)) {
1159+ if (IsUser(sptr))
1160+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :WELCOME: No message number given", sptr);
1161+ else
1162+ protocol_violation(cptr, "WELCOME: No message number given by %C", sptr);
1163+ return 0;
1164+ }
1165+
1166+ /* check name */
1167+ if (!WelcomeIsValid(namearray)) {
1168+ if (IsUser(sptr))
1169+ sendcmdto_one(&me, CMD_NOTICE, sptr,
1170+ "%C :WELCOME: Invalid message number %s - should between 1 and %d",
1171+ sptr, name, WELCOME_MAX_ENTRIES);
1172+ else
1173+ protocol_violation(cptr,
1174+ "WELCOME: Invalid message number %s from %C - should be between 1 and %d",
1175+ name, sptr, WELCOME_MAX_ENTRIES);
1176+ return 0;
1177+ }
1178+
1179+ /* source is user, and is myuser or welcome is local, check length of the message */
1180+ if ((IsUser(sptr)) && ((MyUser(sptr)) || (flags & WELCOME_LOCAL)) && (strlen(text) > WELCOMELEN)) {
1181+ sendcmdto_one(&me, CMD_NOTICE, sptr,
1182+ "%C :WELCOME: The message is too long with %d chars - max is %d chars",
1183+ sptr, strlen(text), WELCOMELEN);
1184+ ircd_strncpy(text, text, WELCOMELEN);
1185+ sendcmdto_one(&me, CMD_NOTICE, sptr,
1186+ "%C :WELCOME: Change or truncate the message to: \"%s\"", sptr, text);
1187+ return 0;
1188+ }
1189+
1190+ /* correct namearray for local offset */
1191+ if (flags & WELCOME_LOCAL)
1192+ namearray += WELCOME_MAX_ENTRIES;
1193+
1194+ /* must be true by now */
1195+ assert(WelcomeIsValid(namearray));
1196+ assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
1197+
1198+ /* cannot unset welcome that is not set */
1199+ if (!WelcomeIsSet(namearray) && EmptyString(text)) {
1200+
1201+ /* from user, throw error */
1202+ if (IsUser(sptr))
1203+ return send_reply(sptr, ERR_NOSUCHWELCOME, name);
1204+
1205+ /* new local welcome from server, but empty - ignore
1206+ * we do accept a new global welcome message that is empty
1207+ */
1208+ if (flags & WELCOME_LOCAL)
1209+ return 0;
1210+ }
1211+
1212+ /* check if there is something to change */
1213+ /* we got a record for it */
1214+ if (WelcomeIsSet(namearray)) {
1215+
1216+ /* global */
1217+ if (!(flags & WELCOME_LOCAL)) {
1218+
1219+ /* myuser changes it,
1220+ * welcomeTS greater than or equal to timestamp, take welcomeTS+1 as timestamp
1221+ * else the change is not accepted upstream because of the older TS
1222+ */
1223+ if (MyUser(sptr)) {
1224+ if (WelcomeTS(namearray) >= timestamp)
1225+ timestamp = WelcomeTS(namearray) +1;
1226+ }
1227+
1228+ /* compare timestamps, ignore welcome when:
1229+ * we got a newer one
1230+ * or when timestamps are the same and our text is 'smaller'
1231+ */
1232+ else if ((timestamp < WelcomeTS(namearray)) || /* we got a newer one */
1233+ ((timestamp == WelcomeTS(namearray)) && /* same timestamp */
1234+ (strcmp(WelcomeText(namearray), text) < 0))) { /* our text is 'smaller' */
1235+ /* burst or burst ack, cptr gets our version from the burst */
1236+ if (IsBurstOrBurstAck(cptr))
1237+ return 0;
1238+ /* sync server */
1239+ return welcome_resend(cptr, nameint, namearray);
1240+ }
1241+
1242+ /* local welcome - we use our idea of the time */
1243+ } else
1244+ timestamp = TStime();
1245+
1246+ /* new global welcome from my user or local welcome
1247+ * compare new message with old message
1248+ */
1249+ if (IsUser(sptr) && (MyUser(sptr) || (flags & WELCOME_LOCAL))) {
1250+ if (strcmp(text, WelcomeText(namearray)) == 0) { /* use strcmp because the user may wish to change case */
1251+ sendcmdto_one(&me, CMD_NOTICE, sptr,
1252+ "%C :WELCOME: Cannot change %s message for %s - nothing to change",
1253+ sptr, (flags & WELCOME_LOCAL) ? "local" : "global", name);
1254+ return 0;
1255+ }
1256+ }
1257+ }
1258+
1259+ /* do not insert for last global/local entry and when not set yet */
1260+ if ((flags & WELCOME_INSERT) &&
1261+ ((!WelcomeIsSet(namearray)) || (nameint == WELCOME_MAX_ENTRIES)))
1262+ flags &= ~WELCOME_INSERT;
1263+
1264+ /* unset */
1265+ if (EmptyString(text)) {
1266+ /* clear insert flag,
1267+ * when this flag is set, welcome_unset() assumes it is being called from welcome_insert()
1268+ * and wont propagate the change
1269+ */
1270+ flags &= ~WELCOME_INSERT;
1271+ return welcome_unset(cptr, sptr, nameint, namearray, timestamp, who, flags);
1272+ }
1273+
1274+ /* insert */
1275+ if (flags & WELCOME_INSERT)
1276+ return welcome_insert(cptr, sptr, nameint, namearray, timestamp, who, text, flags);
1277+
1278+ /* new or change */
1279+ return welcome_set(cptr, sptr, nameint, namearray, timestamp, who, text, flags);
1280+}
1281+
1282+
1283+/** Announce a welcome message to local clients.
1284+ * @param[in] name Welcome message to announce.
1285+ */
1286+void
1287+welcome_announce(int name)
1288+{
1289+ struct Client *acptr;
1290+ struct MsgBuf *msgbuf;
1291+ int i;
1292+
1293+ /* valid range, set and not empty */
1294+ assert(WelcomeIsValid(name));
1295+ assert(WelcomeIsSet(name));
1296+ assert(!WelcomeIsEmpty(name));
1297+
1298+ /* TODO: target is $* as if it were a global broadcast
1299+ * could make it $servername for local message announcement
1300+ * but the type is shown between [ ] already
1301+ * either [Network] or [servername] - using $* is just shorter.
1302+ */
1303+ /* build msgbuf */
1304+ msgbuf = msgq_make(0, ":%C %s $* :[%s] %s", &me, MSG_NOTICE,
1305+ name >= WELCOME_MAX_ENTRIES ? cli_name(&me) : feature_str(FEAT_NETWORK),
1306+ WelcomeText(name));
1307+
1308+ /* go over local clients */
1309+ for (i = HighestFd; i > 0; --i) {
1310+
1311+ /* skip unregistered clients, skip servers */
1312+ if (!(acptr = LocalClientArray[i]) || !IsRegistered(acptr) || IsServer(acptr))
1313+ continue;
1314+
1315+ /* send it away */
1316+ send_buffer(acptr, msgbuf, 0);
1317+ }
1318+}
1319+
1320+
1321+/** Send the full list of welcome message to \a cptr.
1322+ * @param[in] cptr Local server to send welcomes to.
1323+ */
1324+void
1325+welcome_burst(struct Client *cptr)
1326+{
1327+ int name;
1328+
1329+ assert(NULL != cptr);
1330+
1331+ /* loop over global entries - 0 to max - 1*/
1332+ for (name = 0; name <= WELCOME_MAX_ENTRIES - 1; name++) {
1333+ if (WelcomeIsSet(name))
1334+ sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %s :%s",
1335+ name + 1, WelcomeTS(name), WelcomeWho(name), WelcomeText(name));
1336+ }
1337+}
1338+
1339+
1340+/** List welcome messages.
1341+ * @param[in] sptr Client requesting the listing.
1342+ * @param[in] connect When non zero do not report no welcome is set
1343+ * @return Zero.
1344+ */
1345+int
1346+welcome_list(struct Client *sptr, int connect)
1347+{
1348+ int found = 0, local = 0, name;
1349+
1350+ assert(NULL != sptr);
1351+
1352+ /* loop over all entries - range 0 to 2 * max - 1 */
1353+ for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
1354+
1355+ /* local entries now */
1356+ if (name == WELCOME_MAX_ENTRIES)
1357+ local = 1;
1358+
1359+ /* not set or empty - skip */
1360+ if (!WelcomeIsSet(name) || WelcomeIsEmpty(name))
1361+ continue;
1362+
1363+ /* got one */
1364+ found++;
1365+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :[%s] %s",
1366+ sptr, local ? cli_name(&me) : feature_str(FEAT_NETWORK), WelcomeText(name));
1367+ }
1368+
1369+ /* nothing set */
1370+ if (!found && !connect)
1371+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :No welcome message set.", sptr);
1372+
1373+ return 0;
1374+}
1375+
1376+
1377+/** Statistics callback to list Welcome messages.
1378+ * @param[in] sptr Client requesting statistics.
1379+ * @param[in] sd Stats descriptor for request (ignored).
1380+ * @param[in] param Extra parameter from user (ignored).
1381+ */
1382+void
1383+welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param)
1384+{
1385+ int name, local = 0;
1386+
1387+ assert(NULL != sptr);
1388+
1389+ /* loop over all entries - range 0 to 2 * max - 1*/
1390+ for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
1391+
1392+ /* local entries now */
1393+ if (name == WELCOME_MAX_ENTRIES)
1394+ local = 1;
1395+
1396+ /* not set */
1397+ if (!WelcomeIsSet(name))
1398+ continue;
1399+
1400+ /* send it */
1401+ send_reply(sptr, RPL_STATSWELCOME,
1402+ local ? name + 1 - WELCOME_MAX_ENTRIES : name + 1,
1403+ local ? cli_name(&me) : "*",
1404+ WelcomeWho(name), WelcomeTS(name),
1405+ WelcomeIsEmpty(name) ? "<Empty>" : WelcomeText(name));
1406+ }
1407+}