]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blame - welcome.patch
rename patch files
[irc/quakenet/snircd-patchqueue.git] / welcome.patch
CommitLineData
a87bc2c2 1Add welcome message functionality.
2
87baaf82 3To inform our users about events we currently have 3 means at our disposal.
4
5Outside of IRC like our website and other external/3rd party means such as facebook/twitter/whatever.
6I never visit the website, and I cannot imagine many people do just so they wont miss that lonely newspost every couple of months.
7(If it were an RSS newsfeed, then maybe it would reach more people..., but that's a different topic altogether.)
8
9Within the IRC world there are two ways to mass relay information to users.
10
11The first is the MOTD (Message of the Day).
12This is a misleading name, it simply is a text file played to connecting clients, and in practice never changes
13(our MOTDs display outdated information, and done so for years..., but again, that's a different topic altogether).
14The MOTD cannot be altered from IRC, so it cannot be used to inform users about upcoming events or news.
15
16The second are message on IRC sent to many recipients,
17broadcasts to all users on the network/server/country/host,
18and WALLUSERS to all users with mode +w set.
19They are not suitable to inform users about upcoming events or news:
20
21They only reach users which are connected at that time, and not everyone is connected to IRC all the time.
22Doing a broadcast one time a few days in advance and again a few minutes in advance, simply does not reach all of our users.
23Doing multiple broadcasts to make up of this, is annoying for users
24(as seen in the past when several broadcasts were made for a tutorial session) and thus not an option.
25
26Broadcasts are rather intrusive, and sending many of them probably wont be appreciated,
27leading to people adding the service(s) to ignore or filtering them.
28
29WALLUSERS is only received by a very small portion of our userbase, 1 to 2% of users on the network have set mode +w.
30We could make +w a default usermode (opt-out instead of opt-in), but we are left with the same problem as with broadcasts.
31
32
33We need a way to be able to announce news to all users,
34in a timely manner straight from IRC (so not the website, not the MOTD),
35in a non-intrusive way with a message on connect, and when people want to see it by command (so not broadcasts or wallusers).
36
37This is where WELCOME comes in.
38Messages set on IRC.
39Messages set per server (mostly for maintenance) or global (for news/pr/and such).
40Messages announced to connecting clients, and shown when users use /welcome.
41
42
43Why not use a service for this?
44Implemented in the IRCd it only uses local traffic, that is from server to client,
45instead of traffic over server links from service to server, and then server to client.
46Implemented in the IRCd it is not affected by netsplits as it would when done by a service.
47
48
49(But even if this patch is accepted, it will not be on quakenet any time soon.
50So it may still be worth it to create service for this in the mean time.)
51
52
53
54
55
a87bc2c2 56client commands:
57user:
f49eea8e 58/WELCOME [<server>]
a87bc2c2 59shows welcome messages set, same is shown on connect
f49eea8e 60feature HIS_REMOTE controls whether ordinary users can request a listing from a remote server
a87bc2c2 61
87baaf82 62operator:
7eaacf11 63/WELCOME [<server>] [[$][!][+|-]<N> :<message>]
a87bc2c2 64to view welcome messages from a remote server
65to set a local welcome message on this server or a remote server
f49eea8e 66set a global welcome message (server *)
67the $ prefix makes the server annouce the welcome message to its clients when setting
7eaacf11 68the ! prefix forces the change, bypassing lastmod checks
f49eea8e 69the + prefix moves message in N and all after that one spot down, and inserts the new message
70in spot N, if there is no room, the last entry is deleted
7eaacf11 71the - prefix is used when an entry is cleared (no text), then all entries after it are moved on place up, so all empty
72spots are at the end (this prefix is always used when an oper clears the text)
a87bc2c2 73
74server:
7eaacf11 75:<source> WE <target> [[$][!][+|-]<N> <timestamp> <lastmod> <who> :<text>]
a87bc2c2 76who is who set the message, the server puts in the opername when a client sets it.
f49eea8e 77:<N> is a number 1 to WELCOME_MAX_ENTRIES - currently set at 10 (should be more than we ever need)
a87bc2c2 78that means there is room for 10 local and 10 global entries
a87bc2c2 79
cb0b5df1 80STATS W/welcome (/STATS w/userload made case sensitive)
7eaacf11 81:server 227 nick W # Target Who Timestamp LastMod :Text
82:server 227 nick W 1 * opername 1233072583 1233072583 :Latest news: testing this welcome patch :)
83:server 227 nick W 2 * opername 1233072583 1233072583 :
84:server 227 nick W 1 servername opername 1233072590 1233072590 :This is a test server, expect restarts.
a87bc2c2 85:server 219 nick W :End of /STATS report
86
87listing welcomes or on connect:
88:server NOTICE nick :[QuakeNet] Latest news: testing this welcome patch :)
89:server NOTICE nick :[server] This is a test server, expect restarts.
90
f49eea8e 91announcement is done by a notice by the local server to $* ($servername for local) with the same message
a87bc2c2 92format as for listing welcome messages.
93:server NOTICE $* :[QuakeNet] Latest news: testing this welcome patch :)
f49eea8e 94:server NOTICE $server :[server] This is a test server, expect restarts.
a87bc2c2 95
96
87baaf82 97
a87bc2c2 98Files:
99
100include/handlers.h
f49eea8e 101add m_welcome mo_welcome ms_welcome functions
a87bc2c2 102
103include/features.h
104ircd/features.c
105add features FEAT_WELCOME and FEAT_HIS_STATS_W
106
107include/msg.h
108add MSG_WELCOME TOK_WELCOME CMD_WELCOME
109
110ircd/parse.c
111add welcome message functions
112
113include/numeric.h
114ircd/s_err.c
115add RPL_STATSWELCOME ERR_NOSUCHWELCOME
116
117include/welcome.h
118ircd/welcome.c
119ircd/m_welcome.c
120new
121
122ircd/Makefile.in
123add welcome.c and m_welcome.c files
124
a87bc2c2 125ircd/s_serv.c
126add burst welcome message
127
128ircd/s_stats.c
129add /STATS W/welcome
130
131ircd/s_user.c
132add showing of welcome messages on connect
133
f49eea8e 134ircd/s_debug.c
135add count and memusage of welcome messages
136
db0ccf80 137include/client.h
138ircd/client.c
139ircd/ircd_lexer.l
140ircd/ircd_parser.y
141add PRIV_LOCAL_WELCOME PRIV_WELCOME
142
3975cc60
P
143diff -r 9096546c6212 include/client.h
144--- a/include/client.h Sat Jul 20 12:00:51 2013 +0100
145+++ b/include/client.h Sat Jul 20 12:00:55 2013 +0100
308d3fca 146@@ -142,6 +142,8 @@
147 PRIV_USER_PRIVACY, /* oper can bypass user privacy +x etc gives i.e. see real ip's */
3975cc60 148 PRIV_CHANNEL_PRIVACY, /* oper can bypass channel privacy i.e. can see modes on channels they are not on and channel keys */
308d3fca 149 PRIV_SERVERINFO, /* oper can use /get, /stats, /hash, retrieve remote information */
4e89d808 150+ PRIV_WELCOME, /* oper can WELCOME */
151+ PRIV_LOCAL_WELCOME, /* oper can local WELCOME */
152 PRIV_LAST_PRIV /**< number of privileges */
153 };
154
3975cc60
P
155diff -r 9096546c6212 include/handlers.h
156--- a/include/handlers.h Sat Jul 20 12:00:51 2013 +0100
157+++ b/include/handlers.h Sat Jul 20 12:00:55 2013 +0100
f0f686d6 158@@ -138,6 +138,7 @@
cddf800b 159 extern int m_version(struct Client*, struct Client*, int, char*[]);
160 extern int m_wallchops(struct Client*, struct Client*, int, char*[]);
161 extern int m_wallvoices(struct Client*, struct Client*, int, char*[]);
162+extern int m_welcome(struct Client*, struct Client*, int, char*[]);
163 extern int m_who(struct Client*, struct Client*, int, char*[]);
164 extern int m_whois(struct Client*, struct Client*, int, char*[]);
165 extern int m_whowas(struct Client*, struct Client*, int, char*[]);
f0f686d6 166@@ -172,6 +173,7 @@
cddf800b 167 extern int mo_version(struct Client*, struct Client*, int, char*[]);
168 extern int mo_wallops(struct Client*, struct Client*, int, char*[]);
169 extern int mo_wallusers(struct Client*, struct Client*, int, char*[]);
170+extern int mo_welcome(struct Client*, struct Client*, int, char*[]);
308d3fca 171 extern int mo_xquery(struct Client*, struct Client*, int, char*[]);
cddf800b 172 extern int mr_error(struct Client*, struct Client*, int, char*[]);
173 extern int mr_error(struct Client*, struct Client*, int, char*[]);
3975cc60 174@@ -231,6 +233,7 @@
cddf800b 175 extern int ms_wallops(struct Client*, struct Client*, int, char*[]);
176 extern int ms_wallusers(struct Client*, struct Client*, int, char*[]);
177 extern int ms_wallvoices(struct Client*, struct Client*, int, char*[]);
178+extern int ms_welcome(struct Client*, struct Client*, int, char*[]);
179 extern int ms_whois(struct Client*, struct Client*, int, char*[]);
308d3fca 180 extern int ms_xquery(struct Client*, struct Client*, int, char*[]);
181 extern int ms_xreply(struct Client*, struct Client*, int, char*[]);
3975cc60
P
182diff -r 9096546c6212 include/ircd_features.h
183--- a/include/ircd_features.h Sat Jul 20 12:00:51 2013 +0100
184+++ b/include/ircd_features.h Sat Jul 20 12:00:55 2013 +0100
a87bc2c2 185@@ -101,6 +101,7 @@
186 FEAT_IRCD_RES_TIMEOUT,
187 FEAT_AUTH_TIMEOUT,
188 FEAT_ANNOUNCE_INVITES,
189+ FEAT_WELCOME,
190
191 /* features that affect all operators */
192 FEAT_EXTENDED_CHECKCMD,
308d3fca 193@@ -142,6 +143,7 @@
a87bc2c2 194 FEAT_HIS_STATS_u,
195 FEAT_HIS_STATS_U,
196 FEAT_HIS_STATS_v,
197+ FEAT_HIS_STATS_W,
198 FEAT_HIS_STATS_w,
199 FEAT_HIS_STATS_x,
200 FEAT_HIS_STATS_y,
3975cc60
P
201diff -r 9096546c6212 include/msg.h
202--- a/include/msg.h Sat Jul 20 12:00:51 2013 +0100
203+++ b/include/msg.h Sat Jul 20 12:00:55 2013 +0100
308d3fca 204@@ -196,6 +196,10 @@
cddf800b 205 #define TOK_NOTICE "O"
206 #define CMD_NOTICE MSG_NOTICE, TOK_NOTICE
100a7f47 207
cddf800b 208+#define MSG_WELCOME "WELCOME" /* WELC */
209+#define TOK_WELCOME "WE"
210+#define CMD_WELCOME MSG_WELCOME, TOK_WELCOME
100a7f47 211+
cddf800b 212 #define MSG_WALLCHOPS "WALLCHOPS" /* WC */
213 #define TOK_WALLCHOPS "WC"
100a7f47 214 #define CMD_WALLCHOPS MSG_WALLCHOPS, TOK_WALLCHOPS
3975cc60
P
215diff -r 9096546c6212 include/numeric.h
216--- a/include/numeric.h Sat Jul 20 12:00:51 2013 +0100
217+++ b/include/numeric.h Sat Jul 20 12:00:55 2013 +0100
a87bc2c2 218@@ -116,6 +116,7 @@
219 RPL_STATSGLINE 227 Dalnet
220 RPL_STATSVLINE 227 unreal */
221 #define RPL_STATSALINE 226 /* Hybrid, Undernet */
222+#define RPL_STATSWELCOME 227 /* QuakeNet extension */
223 #define RPL_STATSQLINE 228 /* Undernet extension */
a87bc2c2 224
308d3fca 225 /* RPL_SERVICEINFO 231 unused */
226@@ -440,6 +441,8 @@
a87bc2c2 227 /* ERR_GHOSTEDCLIENT 503 efnet */
228 /* ERR_VWORLDWARN 503 austnet */
229
230+#define ERR_NOSUCHWELCOME 509 /* QuakeNet extension */
231+
232 #define ERR_SILELISTFULL 511 /* Undernet extension */
233 /* ERR_NOTIFYFULL 512 aircd */
234 /* ERR_TOOMANYWATCH 512 Numeric List: Dalnet */
3975cc60
P
235diff -r 9096546c6212 include/welcome.h
236--- /dev/null Thu Jan 01 00:00:00 1970 +0000
237+++ b/include/welcome.h Sat Jul 20 12:00:55 2013 +0100
f516f28e 238@@ -0,0 +1,86 @@
cddf800b 239+#ifndef INCLUDED_welcome_h
240+#define INCLUDED_welcome_h
241+/*
242+ * IRC - Internet Relay Chat, include/welcome.h
243+ * Copyright (C) 1990 Jarkko Oikarinen and
244+ * University of Oulu, Computing Center
245+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
246+ *
247+ * This program is free software; you can redistribute it and/or modify
248+ * it under the terms of the GNU General Public License as published by
249+ * the Free Software Foundation; either version 2, or (at your option)
250+ * any later version.
251+ *
252+ * This program is distributed in the hope that it will be useful,
253+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
254+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
255+ * GNU General Public License for more details.
256+ *
257+ * You should have received a copy of the GNU General Public License
258+ * along with this program; if not, write to the Free Software
259+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
260+ */
261+/** @file
a87bc2c2 262+ * @brief Interface and declarations for welcome message handling.
cddf800b 263+ */
cddf800b 264+
a87bc2c2 265+struct Client;
266+struct StatDesc;
267+
cb0b5df1 268+/* Maximum number of welcome entries (per type; X global, X local) */
6dd3e24f 269+#define WELCOME_MAX_ENTRIES 10
f516f28e 270+/* Maximum length of a welcome message
271+ * the maximum value for this is 300
272+ * when set larger, this could lead to truncation when announcing
273+ * ":server.name NOTICE $server.name :[server.name] text"
274+ * 510 - (1+63+1+6+1+1+63+1+1+1+63+1+1) = 306 for text
275+ * max length of a servername is 63 HOSTLEN
276+ */
277+#define WELCOMELEN 300
b27ac6fc 278+
a87bc2c2 279+
6eab3e57 280+/* Test if a welcome entry is in a valid range */
72b9a1d2 281+#define WelcomeArrayIsValid(x) ((unsigned) (x) <= 2 * WELCOME_MAX_ENTRIES -1)
282+/* Test if a welcome name is in a valid range */
283+#define WelcomeNameIsValid(x) ((unsigned) (x) <= WELCOME_MAX_ENTRIES)
6eab3e57 284+/* Test if a welcome entry is set */
5943bc4b 285+#define WelcomeIsSet(x) (WelcomeArray[(x)].lastmod > 0)
6eab3e57 286+/* Test if a welcome entry is empty */
72b9a1d2 287+#define WelcomeIsEmpty(x) (*WelcomeArray[(x)].text == 0)
d6da6cd7 288+
5943bc4b 289+/* Get welcome create timestamp */
290+#define WelcomeCreate(x) (WelcomeArray[(x)].create)
291+/* Get welcome lastmod timestamp */
292+#define WelcomeLastMod(x) (WelcomeArray[(x)].lastmod)
6eab3e57 293+/* Get welcome who info */
72b9a1d2 294+#define WelcomeWho(x) (WelcomeArray[(x)].who)
5943bc4b 295+/* Get welcome text */
296+#define WelcomeText(x) (WelcomeArray[(x)].text)
6eab3e57 297+
298+
a87bc2c2 299+/* Describes a Welcome message entry. */
300+struct Welcome {
5943bc4b 301+ time_t create; /**< When it was set */
302+ time_t lastmod; /**< Last modification timestamp (used for resolving conflicts in burst) */
a7f8ae30 303+ char text[WELCOMELEN + 1]; /**< Message */
6dd3e24f 304+ char who[ACCOUNTLEN + 1]; /**< Who set it */
a87bc2c2 305+};
306+
cb0b5df1 307+/** Welcome type flags */
309b0db2 308+#define WELCOME_LOCAL 0x01 /**< welcome is local */
a87bc2c2 309+/** Welcome action flags */
309b0db2 310+#define WELCOME_ANNOUNCE 0x02 /**< announce new welcome to users */
07e9e7ea 311+#define WELCOME_UNSET 0x04 /**< unset welcome */
312+#define WELCOME_INSERT 0x08 /**< insert welcome message, move down all others one place */
313+#define WELCOME_DELETE 0x10 /**< delete welcome message, move up all others one place */
314+#define WELCOME_INCLASTMOD 0x20 /**< increase lastmod if needed */
315+#define WELCOME_FORCE 0x40 /**< force change, bypass lastmod check */
a87bc2c2 316+
c13e4602 317+extern int welcome_do(struct Client *cptr, struct Client *sptr, char *name,
5943bc4b 318+ time_t create, time_t lastmod, char *who, char *text, unsigned int flags);
cddf800b 319+extern void welcome_burst(struct Client *cptr);
a87bc2c2 320+extern int welcome_list(struct Client *sptr, int connect);
321+extern void welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param);
5736cfdb 322+extern int welcome_memory_count(size_t *we_size);
cddf800b 323+
324+#endif /* INCLUDED_welcome_h */
3975cc60
P
325diff -r 9096546c6212 ircd/Makefile.in
326--- a/ircd/Makefile.in Sat Jul 20 12:00:51 2013 +0100
327+++ b/ircd/Makefile.in Sat Jul 20 12:00:55 2013 +0100
328@@ -187,6 +187,7 @@
a87bc2c2 329 m_wallops.c \
330 m_wallusers.c \
331 m_wallvoices.c \
332+ m_welcome.c \
333 m_who.c \
334 m_whois.c \
335 m_whowas.c \
3975cc60 336@@ -216,6 +217,7 @@
a87bc2c2 337 send.c \
338 uping.c \
339 userload.c \
340+ welcome.c \
341 whocmds.c \
342 whowas.c \
343 y.tab.c
3975cc60 344@@ -1162,6 +1164,11 @@
a87bc2c2 345 ../include/ircd_reply.h ../include/ircd_string.h \
346 ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
347 ../include/numnicks.h ../include/s_user.h ../include/send.h
348+m_welcome.o: m_welcome.c ../config.h ../include/channel.h \
349+ ../include/client.h ../include/hash.h ../include/ircd.h ../include/ircd_log.h \
350+ ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
351+ ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
352+ ../include/send.h ../include/welcome.h
353 m_who.o: m_who.c ../config.h ../include/channel.h ../include/ircd_defs.h \
354 ../include/res.h ../config.h ../include/client.h ../include/dbuf.h \
355 ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
3975cc60 356@@ -1423,6 +1430,13 @@
a87bc2c2 357 ../include/numnicks.h ../include/querycmds.h ../include/ircd_features.h \
358 ../include/s_misc.h ../include/s_stats.h ../include/send.h \
359 ../include/struct.h ../include/sys.h
360+welcome.o: welcome.c ../config.h ../include/client.h \
361+ ../include/hash.h ../include/ircd.h ../include/ircd_alloc.h \
362+ ../include/ircd_features.h ../include/ircd_log.h ../include/ircd_reply.h \
363+ ../include/match.h ../include/msg.h ../include/numeric.h \
364+ ../include/numnicks.h ../include/s_debug.h ../include/s_bsd.h \
365+ ../include/s_misc.h ../include/send.h ../include/struct.h \
366+ ../include/sys.h ../include/welcome.h
367 whocmds.o: whocmds.c ../config.h ../include/whocmds.h \
368 ../include/channel.h ../include/ircd_defs.h ../include/res.h \
369 ../config.h ../include/client.h ../include/dbuf.h ../include/msgq.h \
3975cc60
P
370diff -r 9096546c6212 ircd/client.c
371--- a/ircd/client.c Sat Jul 20 12:00:51 2013 +0100
372+++ b/ircd/client.c Sat Jul 20 12:00:55 2013 +0100
308d3fca 373@@ -177,6 +177,7 @@
4e89d808 374 FlagSet(&privs_local, PRIV_WHOX);
375 FlagSet(&privs_local, PRIV_DISPLAY);
376 FlagSet(&privs_local, PRIV_FORCE_LOCAL_OPMODE);
377+ FlagSet(&privs_local, PRIV_LOCAL_WELCOME);
308d3fca 378
379 privs_defaults_set = 1;
380 }
381@@ -223,6 +224,7 @@
382 ClrPriv(client, PRIV_JUPE);
4e89d808 383 ClrPriv(client, PRIV_OPMODE);
4e89d808 384 ClrPriv(client, PRIV_BADCHAN);
385+ ClrPriv(client, PRIV_WELCOME);
386 }
308d3fca 387 }
388
389@@ -244,7 +246,7 @@
390 P(CHANSERV), P(XTRA_OPER), P(NOIDLE), P(FREEFORM),
391 P(PARANOID), P(CHECK), P(WALL), P(CLOSE),
392 P(ROUTE), P(ROUTEINFO), P(SERVERINFO), P(CHANNEL_PRIVACY),
393- P(USER_PRIVACY),
394+ P(USER_PRIVACY), P(WELCOME), P(LOCAL_WELCOME),
4e89d808 395 #undef P
396 { 0, 0 }
397 };
3975cc60
P
398diff -r 9096546c6212 ircd/ircd_features.c
399--- a/ircd/ircd_features.c Sat Jul 20 12:00:51 2013 +0100
400+++ b/ircd/ircd_features.c Sat Jul 20 12:00:55 2013 +0100
e721b9bb 401@@ -366,6 +366,7 @@
a87bc2c2 402 F_I(IRCD_RES_TIMEOUT, 0, 4, 0),
403 F_I(AUTH_TIMEOUT, 0, 9, 0),
404 F_B(ANNOUNCE_INVITES, 0, 0, 0),
405+ F_B(WELCOME, 0, 1, 0),
406
407 /* features that affect all operators */
408 F_B(EXTENDED_CHECKCMD, 0, 0, 0),
308d3fca 409@@ -407,6 +408,7 @@
a87bc2c2 410 F_B(HIS_STATS_u, 0, 1, 0),
411 F_B(HIS_STATS_U, 0, 1, 0),
412 F_B(HIS_STATS_v, 0, 1, 0),
413+ F_B(HIS_STATS_W, 0, 1, 0),
414 F_B(HIS_STATS_w, 0, 1, 0),
415 F_B(HIS_STATS_x, 0, 1, 0),
416 F_B(HIS_STATS_y, 0, 1, 0),
3975cc60
P
417diff -r 9096546c6212 ircd/ircd_lexer.l
418--- a/ircd/ircd_lexer.l Sat Jul 20 12:00:51 2013 +0100
419+++ b/ircd/ircd_lexer.l Sat Jul 20 12:00:55 2013 +0100
308d3fca 420@@ -166,6 +166,8 @@
421 { "serverinfo", TPRIV_SERVERINFO },
422 { "user_privacy", TPRIV_USER_PRIVACY },
423 { "channel_privacy", TPRIV_CHANNEL_PRIVACY },
4e89d808 424+ { "local_welcome", TPRIV_LOCAL_WELCOME },
425+ { "welcome", TPRIV_WELCOME },
426 { NULL, 0 }
427 };
428 static int ntokens;
3975cc60
P
429diff -r 9096546c6212 ircd/ircd_parser.y
430--- a/ircd/ircd_parser.y Sat Jul 20 12:00:51 2013 +0100
431+++ b/ircd/ircd_parser.y Sat Jul 20 12:00:55 2013 +0100
308d3fca 432@@ -189,6 +189,7 @@
433 %token TPRIV_CHANSERV TPRIV_XTRA_OPER TPRIV_NOIDLE TPRIV_FREEFORM TPRIV_PARANOID
434 %token TPRIV_CHECK TPRIV_WALL TPRIV_CLOSE TPRIV_ROUTE TPRIV_ROUTEINFO TPRIV_SERVERINFO
435 %token TPRIV_CHANNEL_PRIVACY TPRIV_USER_PRIVACY TPRIV_LIST_CHAN
dcd0ea31 436+%token TPRIV_LOCAL_WELCOME TPRIV_WELCOME
4e89d808 437 /* and some types... */
438 %type <num> sizespec
439 %type <num> timespec timefactor factoredtimes factoredtime
308d3fca 440@@ -703,6 +704,8 @@
441 TPRIV_SERVERINFO { $$ = PRIV_SERVERINFO ; } |
442 TPRIV_CHANNEL_PRIVACY { $$ = PRIV_CHANNEL_PRIVACY ; } |
443 TPRIV_USER_PRIVACY { $$ = PRIV_USER_PRIVACY ; } |
4e89d808 444+ TPRIV_LOCAL_WELCOME { $$ = PRIV_LOCAL_WELCOME; } |
445+ TPRIV_WELCOME { $$ = PRIV_WELCOME; } |
446 TPRIV_PARANOID { $$ = PRIV_PARANOID; } ;
4e89d808 447
3975cc60
P
448 yesorno: YES { $$ = 1; } | NO { $$ = 0; };
449diff -r 9096546c6212 ircd/m_welcome.c
450--- /dev/null Thu Jan 01 00:00:00 1970 +0000
451+++ b/ircd/m_welcome.c Sat Jul 20 12:00:55 2013 +0100
a2e9b9c8 452@@ -0,0 +1,360 @@
cddf800b 453+/*
454+ * IRC - Internet Relay Chat, ircd/m_welcome.c
455+ * Copyright (C) 1990 Jarkko Oikarinen and
456+ * University of Oulu, Computing Center
457+ *
458+ * See file AUTHORS in IRC package for additional names of
459+ * the programmers.
460+ *
461+ * This program is free software; you can redistribute it and/or modify
462+ * it under the terms of the GNU General Public License as published by
463+ * the Free Software Foundation; either version 1, or (at your option)
464+ * any later version.
465+ *
466+ * This program is distributed in the hope that it will be useful,
467+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
468+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
469+ * GNU General Public License for more details.
470+ *
471+ * You should have received a copy of the GNU General Public License
472+ * along with this program; if not, write to the Free Software
473+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
474+ *
cddf800b 475+ */
476+
477+/*
478+ * m_functions execute protocol messages on this server:
479+ *
480+ * cptr is always NON-NULL, pointing to a *LOCAL* client
481+ * structure (with an open socket connected!). This
482+ * identifies the physical socket where the message
483+ * originated (or which caused the m_function to be
484+ * executed--some m_functions may call others...).
485+ *
486+ * sptr is the source of the message, defined by the
487+ * prefix part of the message if present. If not
488+ * or prefix not found, then sptr==cptr.
489+ *
490+ * (!IsServer(cptr)) => (cptr == sptr), because
491+ * prefixes are taken *only* from servers...
492+ *
493+ * (IsServer(cptr))
494+ * (sptr == cptr) => the message didn't
495+ * have the prefix.
496+ *
497+ * (sptr != cptr && IsServer(sptr) means
498+ * the prefix specified servername. (?)
499+ *
500+ * (sptr != cptr && !IsServer(sptr) means
501+ * that message originated from a remote
502+ * user (not local).
503+ *
504+ * combining
505+ *
506+ * (!IsServer(sptr)) means that, sptr can safely
507+ * taken as defining the target structure of the
508+ * message in this server.
509+ *
510+ * *Always* true (if 'parse' and others are working correct):
511+ *
512+ * 1) sptr->from == cptr (note: cptr->from == cptr)
513+ *
514+ * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
515+ * *cannot* be a local connection, unless it's
516+ * actually cptr!). [MyConnect(x) should probably
517+ * be defined as (x == x->from) --msa ]
518+ *
519+ * parc number of variable parameter strings (if zero,
520+ * parv is allowed to be NULL)
521+ *
522+ * parv a NULL terminated list of parameter pointers,
523+ *
524+ * parv[0], sender (prefix string), if not present
525+ * this points to an empty string.
526+ * parv[1]...parv[parc-1]
527+ * pointers to additional parameters
528+ * parv[parc] == NULL, *always*
529+ *
530+ * note: it is guaranteed that parv[0]..parv[parc-1] are all
531+ * non-NULL pointers.
532+ */
cddf800b 533+
cddf800b 534+#include "client.h"
cddf800b 535+#include "ircd.h"
a87bc2c2 536+#include "ircd_features.h"
cddf800b 537+#include "msg.h"
538+#include "numeric.h"
cddf800b 539+#include "s_user.h"
a87bc2c2 540+#include "welcome.h"
cddf800b 541+
9e65418c 542+
cddf800b 543+/*
544+ * m_welcome - local generic message handler
545+ *
6e311ed5 546+ *
547+ * WELCOME
548+ *
549+ * listing:
550+ * parv[0] = Send prefix
551+ *
552+ *
553+ * WELCOME [<server>]
554+ *
555+ * remote listing:
556+ * parv[0] = Send prefix
557+ * parv[1] = Target
558+ *
cddf800b 559+ */
560+int m_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
561+{
a87bc2c2 562+ /* feature disabled */
563+ if (!feature_bool(FEAT_WELCOME))
564+ return send_reply(sptr, ERR_DISABLED, "WELCOME");
6dd3e24f 565+
566+ /* only opers can set the welcome messages */
567+ if (parc > 2)
568+ return send_reply(sptr, ERR_NOPRIVILEGES);
569+
570+ /* remote listing request, see if it is for me or a remote server
571+ * check FEAT_HIS_REMOTE to decide if an ordinary user can do this
572+ */
5632b943 573+ if ((parc > 1) && (hunt_server_cmd(sptr, CMD_WELCOME, cptr, feature_int(FEAT_HIS_REMOTE),
574+ "%C", 1, parc, parv) != HUNTED_ISME))
575+ return 0;
6dd3e24f 576+
5632b943 577+ /* local listing */
a87bc2c2 578+ return welcome_list(sptr, 0);
cddf800b 579+}
580+
581+
582+/*
583+ * mo_welcome - oper message handler
584+ *
6e311ed5 585+ *
586+ * WELCOME
587+ *
cddf800b 588+ * listing:
0823dcbb 589+ * parv[0] = Send prefix
cddf800b 590+ *
6e311ed5 591+ *
592+ * WELCOME <server>
593+ *
cddf800b 594+ * remote listing:
0823dcbb 595+ * parv[0] = Send prefix
596+ * parv[1] = Target
cddf800b 597+ *
6e311ed5 598+ *
599+ * WELCOME <server> <name> :<text>
600+ *
cddf800b 601+ * set global or on remote server:
0823dcbb 602+ * parv[0] = Send prefix
603+ * parv[1] = Target: server or * for global (or left out for this server)
604+ * parv[2] = Name
0809a41d 605+ * parv[parc - 1] = Text
6e311ed5 606+ *
cddf800b 607+ */
608+int mo_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
609+{
cb0b5df1 610+ char *target, *name, *who, *text, pattern[BUFSIZE];
5943bc4b 611+ time_t create, lastmod;
a87bc2c2 612+ unsigned int flags = 0;
6dd3e24f 613+ int local = 0;
a87bc2c2 614+
615+ /* feature disabled */
616+ if (!feature_bool(FEAT_WELCOME))
617+ return send_reply(sptr, ERR_DISABLED, "WELCOME");
618+
4e89d808 619+ /* TODO: move feature check here? */
a87bc2c2 620+ /* remote listing request, see if it is for me or a remote server */
5632b943 621+ if ((parc == 2) && (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME))
622+ return 0;
623+
624+ /* local listing */
625+ if (parc <= 2)
a87bc2c2 626+ return welcome_list(sptr, 0);
4e89d808 627+
628+ /* check PRIVS */
629+ /* local - need PRIV LOCAL_WELCOME or WELCOME */
630+ if (parc == 3 && !HasPriv(sptr,PRIV_LOCAL_WELCOME) && !HasPriv(sptr,PRIV_WELCOME))
631+ return send_reply(sptr, ERR_NOPRIVILEGES);
632+
633+ /* global or remote - need PRIV WELCOME */
634+ if (parc >= 4 && !HasPriv(sptr,PRIV_WELCOME))
635+ return send_reply(sptr, ERR_NOPRIVILEGES);
636+
a87bc2c2 637+ /* set the parameters */
6dd3e24f 638+
639+ /* target not given, only name - setting local welcome */
a87bc2c2 640+ if (parc < 4) {
641+ local++;
642+ target = cli_name(&me);
643+ name = parv[1];
644+ flags |= WELCOME_LOCAL;
6dd3e24f 645+
646+ /* target and name given */
647+ } else {
a87bc2c2 648+ target = parv[1];
649+ name = parv[2];
650+ }
5943bc4b 651+ create = TStime();
652+ lastmod = TStime();
a87bc2c2 653+ who = cli_user(sptr)->opername;
654+ text = parv[parc - 1];
655+
656+ /* target is not global */
657+ if (!(target[0] == '*' && target[1] == '\0') && !local) {
6dd3e24f 658+
a87bc2c2 659+ /* build a pattern for hunt_server_cmd since we do not have all we need in parv */
5943bc4b 660+ ircd_snprintf(0, pattern, sizeof(pattern), "%s %s %Tu %Tu %s :%s", "%C", name, create, lastmod, who, text);
a87bc2c2 661+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, pattern, 1, 2, parv) != HUNTED_ISME)
662+ return 0;
6dd3e24f 663+
664+ /* else it is a local welcome, for me */
665+ flags |= WELCOME_LOCAL;
a87bc2c2 666+ }
667+
668+ /* check for anounce prefix */
542f45ba 669+ if (*name == '$') {
a87bc2c2 670+ name++;
084779ef 671+ /* only allow announce by oper for local welcome */
672+ if (flags & WELCOME_LOCAL)
673+ flags |= WELCOME_ANNOUNCE;
a87bc2c2 674+ }
95de96cd 675+
c499291b 676+ /* check for force prefix */
677+ if (*name == '!') {
678+ name++;
679+ flags |= WELCOME_FORCE;
680+ }
681+
95de96cd 682+ /* check for insert prefix */
683+ if (*name == '+') {
684+ name++;
685+ flags |= WELCOME_INSERT;
686+ }
687+
309b0db2 688+ /* check for delete prefix */
689+ else if (*name == '-') {
690+ name++;
691+ flags |= WELCOME_DELETE;
692+ }
693+
07e9e7ea 694+ /* empty text, set unset and delete flag */
695+ if (*text == 0) {
696+ flags |= WELCOME_UNSET;
309b0db2 697+ flags |= WELCOME_DELETE;
07e9e7ea 698+ }
309b0db2 699+
a87bc2c2 700+ /* and do it */
5943bc4b 701+ return welcome_do(cptr, sptr, name, create, lastmod, who, text, flags);
cddf800b 702+}
703+
704+
705+/*
706+ * ms_welcome - server message handler
707+ *
6e311ed5 708+ *
709+ * <source> WE <target>
710+ *
0823dcbb 711+ * remote listing:
712+ * parv[0] = Send prefix
713+ * parv[1] = Target: server numeric or * for global
714+ *
6e311ed5 715+ *
5943bc4b 716+ * <source> WE <target> <name> <create> <lastmod> <who> :<text>
6e311ed5 717+ *
0823dcbb 718+ * set global or on remote server:
719+ * parv[0] = Send prefix
720+ * parv[1] = Target: server numeric or * for global
721+ * parv[2] = Name
5943bc4b 722+ * parv[3] = Create
723+ * parv[4] = LastMod
724+ * parv[5] = Who
0809a41d 725+ * parv[parc - 1] = Text
6e311ed5 726+ *
cddf800b 727+ */
728+int ms_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
729+{
cb0b5df1 730+ char *target, *name, *who, *text;
5943bc4b 731+ time_t create, lastmod;
a87bc2c2 732+ unsigned int flags = 0;
733+
6dd3e24f 734+ /* not enough - complain */
735+ if (parc < 2) {
c51b6069 736+ protocol_violation(cptr, "Received too few parameters for WELCOME from %C (got %d - need 2)", sptr, parc);
a87bc2c2 737+ return need_more_params(sptr, "WELCOME");
6dd3e24f 738+ }
a87bc2c2 739+
740+ /* remote listing request, see if it is for me or a remote server */
741+ if (parc == 2) {
d2e4469e 742+ if (IsServer(sptr))
c51b6069 743+ return protocol_violation(cptr, "Received WELCOME listing request from server %C", sptr);
6dd3e24f 744+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME)
745+ return 0;
746+ return welcome_list(sptr, 0);
a87bc2c2 747+ }
748+
5943bc4b 749+ /* we need at least 7 parameters to continue - complain */
750+ if (parc < 7) {
751+ protocol_violation(cptr, "Received too few parameters for WELCOME from %C (got %d - need 7)", sptr, parc);
a87bc2c2 752+ return need_more_params(sptr, "WELCOME");
6dd3e24f 753+ }
a87bc2c2 754+
755+ /* set the parameters */
756+ target = parv[1];
757+ name = parv[2];
5943bc4b 758+ create = atoi(parv[3]);
759+ lastmod = atoi(parv[4]);
760+ who = parv[5];
6dd3e24f 761+ text = parv[parc - 1]; /* parse reason as last parameter */
a87bc2c2 762+
a2e9b9c8 763+ /* check if create is valid - create is 0 but parv[3] is not */
764+ if (create == 0 && !(parv[3][0] == '0' && parv[3][1] == '\0'))
765+ return protocol_violation(cptr, "Received WELCOME with invalid create timestamp %s from %C", parv[3], sptr);
766+
767+ /* check if lastmod is valid - lastmod is 0 but parv[4] is not */
768+ if (lastmod == 0 && !(parv[4][0] == '0' && parv[4][1] == '\0'))
769+ return protocol_violation(cptr, "Received WELCOME with invalid lastmod timestamp %s from %C", parv[4], sptr);
770+
a87bc2c2 771+ /* target is not global */
772+ if (!(target[0] == '*' && target[1] == '\0')) {
6dd3e24f 773+
a87bc2c2 774+ /* not for me, and forward it */
5943bc4b 775+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C %s %s %s %s :%s", 1, parc, parv) != HUNTED_ISME)
a87bc2c2 776+ return 0;
6dd3e24f 777+
778+ /* local welcome for me */
779+ flags |= WELCOME_LOCAL;
a87bc2c2 780+ }
781+
782+ /* check for anounce prefix */
542f45ba 783+ if (*name == '$') {
a87bc2c2 784+ name++;
785+ flags |= WELCOME_ANNOUNCE;
786+ }
787+
c499291b 788+ /* check for force prefix */
789+ if (*name == '!') {
790+ name++;
791+ flags |= WELCOME_FORCE;
792+ }
793+
95de96cd 794+ /* check for insert prefix */
795+ if (*name == '+') {
796+ name++;
797+ flags |= WELCOME_INSERT;
798+ }
799+
309b0db2 800+ /* check for delete prefix */
801+ else if (*name == '-') {
802+ name++;
803+ flags |= WELCOME_DELETE;
804+ }
805+
0809a41d 806+ /* empty text, set unset flag */
07e9e7ea 807+ if (*text == 0)
808+ flags |= WELCOME_UNSET;
809+
a87bc2c2 810+ /* and do it */
5943bc4b 811+ return welcome_do(cptr, sptr, name, create, lastmod, who, text, flags);
a87bc2c2 812+}
3975cc60
P
813diff -r 9096546c6212 ircd/parse.c
814--- a/ircd/parse.c Sat Jul 20 12:00:51 2013 +0100
815+++ b/ircd/parse.c Sat Jul 20 12:00:55 2013 +0100
816@@ -668,6 +668,15 @@
f0f686d6 817 /* UNREG, CLIENT, SERVER, OPER, SERVICE */
818 { m_unregistered, m_not_oper, ms_check, mo_check, m_ignore }
cddf800b 819 },
820+
821+ /* add command for WELCOME */
822+ {
823+ MSG_WELCOME,
824+ TOK_WELCOME,
825+ 0, MAXPARA, MFLG_SLOW, 0, NULL,
a87bc2c2 826+ /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */
308d3fca 827+ { m_unregistered, m_welcome, ms_welcome, mo_welcome, m_ignore }
cddf800b 828+ },
829
830 /* This command is an alias for QUIT during the unregistered part of
831 * of the server. This is because someone jumping via a broken web
3975cc60
P
832diff -r 9096546c6212 ircd/s_debug.c
833--- a/ircd/s_debug.c Sat Jul 20 12:00:51 2013 +0100
834+++ b/ircd/s_debug.c Sat Jul 20 12:00:55 2013 +0100
5736cfdb 835@@ -50,6 +50,7 @@
836 #include "send.h"
837 #include "struct.h"
838 #include "sys.h"
839+#include "welcome.h"
840 #include "whowas.h"
841
842 /* #include <assert.h> -- Now using assert in ircd_log.h */
843@@ -231,7 +232,8 @@
844 aw = 0, /* aways set */
845 wwa = 0, /* whowas aways */
846 gl = 0, /* glines */
847- ju = 0; /* jupes */
848+ ju = 0, /* jupes */
849+ we = 0; /* welcomes */
850
851 size_t chm = 0, /* memory used by channels */
852 chbm = 0, /* memory used by channel bans */
853@@ -244,6 +246,7 @@
854 wwm = 0, /* whowas array memory used */
855 glm = 0, /* memory used by glines */
856 jum = 0, /* memory used by jupes */
857+ wem = 0, /* memory used by welcomes */
858 com = 0, /* memory used by conf lines */
859 dbufs_allocated = 0, /* memory used by dbufs */
860 dbufs_used = 0, /* memory used by dbufs */
861@@ -351,6 +354,10 @@
862 send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
863 ":Glines %d(%zu) Jupes %d(%zu)", gl, glm, ju, jum);
864
865+ we = welcome_memory_count(&wem);
866+ send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
867+ ":Welcomes %d(%zu)", we, wem);
868+
869 send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
870 ":Hash: client %d(%zu), chan is the same", HASHSIZE,
871 sizeof(void *) * HASHSIZE);
3975cc60
P
872diff -r 9096546c6212 ircd/s_err.c
873--- a/ircd/s_err.c Sat Jul 20 12:00:51 2013 +0100
874+++ b/ircd/s_err.c Sat Jul 20 12:00:55 2013 +0100
a87bc2c2 875@@ -486,7 +486,7 @@
876 /* 226 */
877 { RPL_STATSALINE, "%s", "226" },
878 /* 227 */
879- { 0 },
5943bc4b 880+ { RPL_STATSWELCOME, "W %d %s %s %Tu %Tu :%s", "227" },
a87bc2c2 881 /* 228 */
882 { RPL_STATSQLINE, "Q %s :%s", "228" },
883 /* 229 */
884@@ -1050,7 +1050,7 @@
885 /* 508 */
886 { 0 },
887 /* 509 */
888- { 0 },
889+ { ERR_NOSUCHWELCOME, "%s :No such welcome", "509" },
890 /* 510 */
891 { 0 },
892 /* 511 */
3975cc60
P
893diff -r 9096546c6212 ircd/s_serv.c
894--- a/ircd/s_serv.c Sat Jul 20 12:00:51 2013 +0100
895+++ b/ircd/s_serv.c Sat Jul 20 12:00:55 2013 +0100
a87bc2c2 896@@ -57,6 +57,7 @@
897 #include "struct.h"
898 #include "sys.h"
899 #include "userload.h"
900+#include "welcome.h"
901
902 /* #include <assert.h> -- Now using assert in ircd_log.h */
903 #include <stdlib.h>
904@@ -196,6 +197,7 @@
905 */
906 gline_burst(cptr);
907 jupe_burst(cptr);
908+ welcome_burst(cptr);
909
910 /*
911 * Pass on my client information to the new server
3975cc60
P
912diff -r 9096546c6212 ircd/s_stats.c
913--- a/ircd/s_stats.c Sat Jul 20 12:00:51 2013 +0100
914+++ b/ircd/s_stats.c Sat Jul 20 12:00:55 2013 +0100
a87bc2c2 915@@ -54,6 +54,7 @@
916 #include "send.h"
917 #include "struct.h"
918 #include "userload.h"
919+#include "welcome.h"
920
921 #include <stdio.h>
922 #include <stdlib.h>
a23c2a71 923@@ -650,9 +651,12 @@
a87bc2c2 924 { 'V', "vserversmach", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_v,
925 stats_servers_verbose, 0,
926 "Verbose server information." },
927- { 'w', "userload", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
928+ { 'w', "userload", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_w,
929 calc_load, 0,
930 "Userload statistics." },
931+ { 'W', "welcome", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_W,
932+ welcome_stats, 0,
933+ "Welcome messages." },
934 { 'x', "memusage", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
935 stats_meminfo, 0,
936 "List usage information." },
3975cc60
P
937diff -r 9096546c6212 ircd/s_user.c
938--- a/ircd/s_user.c Sat Jul 20 12:00:51 2013 +0100
939+++ b/ircd/s_user.c Sat Jul 20 12:00:55 2013 +0100
a87bc2c2 940@@ -63,6 +63,7 @@
941 #include "userload.h"
942 #include "version.h"
943 #include "whowas.h"
944+#include "welcome.h"
945
946 #include "handlers.h" /* m_motd and m_lusers */
947
a23c2a71 948@@ -402,6 +403,10 @@
a87bc2c2 949
950 IPcheck_connect_succeeded(sptr);
a23c2a71 951
952+ /* send welcome */
a87bc2c2 953+ if (feature_bool(FEAT_WELCOME))
954+ welcome_list(sptr, 1);
a23c2a71 955+
956 /* TODO: */
957 /* apply auto sethost if needed */
958 apply_spoofblock(sptr);
3975cc60
P
959diff -r 9096546c6212 ircd/welcome.c
960--- /dev/null Thu Jan 01 00:00:00 1970 +0000
961+++ b/ircd/welcome.c Sat Jul 20 12:00:55 2013 +0100
98a11794 962@@ -0,0 +1,877 @@
cddf800b 963+/*
a87bc2c2 964+ * IRC - Internet Relay Chat, ircd/welcome.c
cddf800b 965+ * Copyright (C) 1990 Jarkko Oikarinen and
966+ * University of Oulu, Finland
967+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
968+ *
969+ * This program is free software; you can redistribute it and/or modify
970+ * it under the terms of the GNU General Public License as published by
971+ * the Free Software Foundation; either version 1, or (at your option)
972+ * any later version.
973+ *
974+ * This program is distributed in the hope that it will be useful,
975+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
976+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
977+ * GNU General Public License for more details.
978+ *
979+ * You should have received a copy of the GNU General Public License
980+ * along with this program; if not, write to the Free Software
981+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
982+ */
983+/** @file
a87bc2c2 984+ * @brief Implementation of welcome message handling functions.
cddf800b 985+ */
cddf800b 986+
987+#include "client.h"
cddf800b 988+#include "ircd.h"
cddf800b 989+#include "ircd_features.h"
990+#include "ircd_log.h"
7ceb849c 991+#include "ircd_reply.h"
cddf800b 992+#include "ircd_string.h"
cddf800b 993+#include "msg.h"
994+#include "numeric.h"
cddf800b 995+#include "s_bsd.h"
a87bc2c2 996+#include "s_debug.h"
cddf800b 997+#include "send.h"
cddf800b 998+#include "welcome.h"
999+
cddf800b 1000+
cb0b5df1 1001+/** List of welcome messages - first MAX for global, second MAX for local */
6dd3e24f 1002+static struct Welcome WelcomeArray[WELCOME_MAX_ENTRIES * 2] = { { 0 } };
cddf800b 1003+
cddf800b 1004+
a87bc2c2 1005+/** Allocate a new welcome with the given parameters.
1006+ * @param[in] name Name of the welcome message.
1007+ * @param[in] text The welcome message.
1008+ * @param[in] who Who set it.
5943bc4b 1009+ * @param[in] create When it was set.
1010+ * @param[in] lastmod Last modification timestamp.
cb0b5df1 1011+ * @return name Array number of the welcome set.
cddf800b 1012+ */
cb0b5df1 1013+static int
b24b1c61 1014+welcome_make(int name, char *text, char *who, time_t create, time_t lastmod, unsigned int flags)
cddf800b 1015+{
b24b1c61 1016+
0823dcbb 1017+ /* assert */
72b9a1d2 1018+ assert(WelcomeArrayIsValid(name));
98143e8a 1019+ assert(NULL != text);
1020+ assert(NULL != who);
b9483f73 1021+ assert(flags & WELCOME_FORCE || lastmod > 0); /* lastmod must not be 0 unless forced */
d94ac9db 1022+ assert(flags & WELCOME_LOCAL ||
1023+ flags & WELCOME_FORCE ||
1024+ lastmod >= WelcomeLastMod(name)); /* lastmod may not decrease for global welcome unless forced */
b24b1c61 1025+
1026+ /* debug */
e4e904c0 1027+ Debug((DEBUG_DEBUG, "welcome_make(name=%d, text=\"%s\", who=%s, create=%Tu, lastmod=%Tu, "
07e9e7ea 1028+ "FLAGS(0x%04x): local=%s announce=%s force=%s unset=%s insert=%s delete=%s inclastmod=%s)",
b24b1c61 1029+ name, text, who, create, lastmod, flags,
1030+ (flags & WELCOME_LOCAL) ? "yes" : "no",
1031+ (flags & WELCOME_ANNOUNCE) ? "yes" : "no",
c499291b 1032+ (flags & WELCOME_FORCE) ? "yes" : "no",
07e9e7ea 1033+ (flags & WELCOME_UNSET) ? "yes" : "no",
309b0db2 1034+ (flags & WELCOME_INSERT) ? "yes" : "no",
1035+ (flags & WELCOME_DELETE) ? "yes" : "no",
1036+ (flags & WELCOME_INCLASTMOD) ? "yes" : "no"));
cb0b5df1 1037+
c499291b 1038+ /* forced and lastmod is zero, clear text and who */
1039+ if (flags & WELCOME_FORCE && lastmod == 0) {
1040+ text = "";
1041+ who = "";
1042+ }
1043+
cb0b5df1 1044+ /* store it */
38c95254 1045+ ircd_strncpy(WelcomeArray[name].text, text, WELCOMELEN);
cb0b5df1 1046+ ircd_strncpy(WelcomeArray[name].who, who, ACCOUNTLEN);
c499291b 1047+
b9483f73 1048+ if (flags & WELCOME_INCLASTMOD && /* take current lastmod+1 if needed */
c499291b 1049+ !(flags & WELCOME_FORCE) && /* not forced */
b9483f73 1050+ WelcomeLastMod(name) >= lastmod) /* current lastmod greater or equal than lastmod */
309b0db2 1051+ WelcomeArray[name].lastmod = WelcomeLastMod(name) +1;
309b0db2 1052+ else
1053+ WelcomeArray[name].lastmod = lastmod;
c499291b 1054+
5943bc4b 1055+ WelcomeArray[name].create = create;
cb0b5df1 1056+
1057+ return name;
cddf800b 1058+}
1059+
cddf800b 1060+
c13e4602 1061+/** Propagate a welcome message.
a87bc2c2 1062+ * @param[in] cptr Local client that sent us the welcome.
1063+ * @param[in] sptr Originator of the welcome.
c13e4602 1064+ * @param[in] nameint Name of the message.
5943bc4b 1065+ * @param[in] create When it was set.
1066+ * @param[in] lastmod Last modification timestamp.
c13e4602 1067+ * @param[in] who Who set this message.
1068+ * @param[in] text The welcome message.
a87bc2c2 1069+ * @param[in] flags Flags to set on welcome.
1070+ * @return Zero
cddf800b 1071+ */
1072+int
c13e4602 1073+welcome_propagate(struct Client *cptr, struct Client *sptr, int nameint,
5943bc4b 1074+ time_t create, time_t lastmod, char *who, char *text, unsigned int flags)
cddf800b 1075+{
0823dcbb 1076+ /* assert */
b27ac6fc 1077+ assert(NULL != sptr);
1078+ assert(NULL != cptr);
72b9a1d2 1079+ assert(WelcomeNameIsValid(nameint));
c499291b 1080+ assert(lastmod > 0 || flags & WELCOME_FORCE); /* lastmod must not be 0 unless forced */
1081+ assert(!(flags & WELCOME_LOCAL)); /* must not be local */
6dd3e24f 1082+
c499291b 1083+ sendcmdto_serv_butone(sptr, CMD_WELCOME, cptr, "* %s%s%s%s%d %Tu %Tu %s :%s",
5943bc4b 1084+ (flags & WELCOME_ANNOUNCE) ? "$" : "",
c499291b 1085+ (flags & WELCOME_FORCE) ? "!" : "",
5943bc4b 1086+ (flags & WELCOME_INSERT) ? "+" : "",
309b0db2 1087+ (flags & WELCOME_DELETE) ? "-" : "",
5943bc4b 1088+ nameint, create, lastmod, who, text);
a87bc2c2 1089+
c13e4602 1090+ return 0;
1091+}
371f9aee 1092+
cddf800b 1093+
b27ac6fc 1094+/** Resend a welcome message.
1095+ * @param[in] cptr Local client that sent us the welcome.
1096+ * @param[in] nameint Name of the message.
1097+ * @param[in] namearray Name of the array item.
c499291b 1098+ * @param[in] flags Flags to set on welcome.
b27ac6fc 1099+ * @return Zero
1100+ */
1101+int
c499291b 1102+welcome_resend(struct Client *cptr, int nameint, int namearray, unsigned int flags)
b27ac6fc 1103+{
c499291b 1104+
1105+ int name; /* loop variable */
1106+
0823dcbb 1107+ /* assert */
b27ac6fc 1108+ assert(NULL != cptr);
1109+ assert(IsServer(cptr));
72b9a1d2 1110+ assert(WelcomeNameIsValid(nameint));
1111+ assert(WelcomeArrayIsValid(namearray));
1112+ assert(nameint - 1 == namearray);
c499291b 1113+ assert(!(flags & WELCOME_LOCAL)); /* must not be local */
1114+ assert(!(flags & WELCOME_FORCE)); /* must not be forced */
b27ac6fc 1115+
c499291b 1116+ /* send our version */
5943bc4b 1117+ sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %Tu %s :%s",
1118+ nameint,
1119+ WelcomeCreate(namearray), WelcomeLastMod(namearray),
1120+ WelcomeWho(namearray), WelcomeText(namearray));
b27ac6fc 1121+
c499291b 1122+ /* bad welcome did not have insert or delete prefix */
1123+ if (!(flags & (WELCOME_INSERT|WELCOME_DELETE)))
1124+ return 0;
1125+
89d85a91 1126+ /* loop over global entries - namearray +1 to max - 1 */
c499291b 1127+ for (name = namearray +1; name <= WELCOME_MAX_ENTRIES - 1; name++) {
9a3c88e6 1128+
1129+ /* not set, force it to be unset on the other end */
1130+ if (!WelcomeIsSet(name))
c499291b 1131+ sendcmdto_one(&me, CMD_WELCOME, cptr, "* !%d 0 0 0 :", name +1);
9a3c88e6 1132+
1133+ /* set, force change here too
1134+ * other side may have this lastmod+1, without force it would be ignored
1135+ */
1136+ else
1137+ sendcmdto_one(&me, CMD_WELCOME, cptr, "* !%d %Tu %Tu %s :%s",
c499291b 1138+ name +1,
1139+ WelcomeCreate(name), WelcomeLastMod(name),
1140+ WelcomeWho(name), WelcomeText(name));
1141+ }
1142+
b27ac6fc 1143+ return 0;
1144+}
1145+
1146+
469e14e1 1147+/** Log a welcome message.
1148+ * @param[in] sptr Originator of the welcome.
1149+ * @param[in] msg The message to show.
469e14e1 1150+ * @param[in] flags Flags to set on welcome.
1151+ * @return Zero
1152+ */
1153+int
a717ac9f 1154+welcome_log(struct Client *sptr, char *msg, unsigned int flags)
469e14e1 1155+{
0823dcbb 1156+ /* assert */
2f08b785 1157+ assert(NULL != sptr);
1158+ assert(NULL != msg);
469e14e1 1159+
1160+ /* inform ops */
1161+ sendto_opmask_butone(0, SNO_OLDSNO, "%s %s",
1162+ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
1163+ get_client_name_and_opername(sptr) : cli_name((cli_user(sptr))->server), msg);
1164+
1165+ /* log it */
a717ac9f 1166+ log_write(LS_NETWORK, L_INFO, LOG_NOSNOTICE, "%s %s", get_client_name_and_opername(sptr), msg);
469e14e1 1167+
40fd40a6 1168+ /* welcome by remote oper, inform of success */
d014176e 1169+ if ((flags & WELCOME_LOCAL) && IsUser(sptr) && !MyConnect(sptr)) {
469e14e1 1170+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s",
1171+ sptr, get_client_name_and_opername(sptr), msg);
1172+
1173+ /* TODO: wallops all local changes, by both local and remote opers? */
1174+ /* tell all opers about the local message being set remotely */
1175+ sendwallto_group_butone(&me, WALL_WALLOPS, 0, "%s %s", get_client_name_and_opername(sptr), msg);
1176+ }
1177+
1178+ return 0;
1179+}
1180+
1181+
40fd40a6 1182+/** Announce a welcome message to local clients.
1183+ * @param[in] name Welcome message to announce.
1184+ * @param[in] flags Flags to set on welcome.
1185+ */
1186+void
1187+welcome_announce(int name, unsigned int flags)
1188+{
0823dcbb 1189+ struct Client *acptr; /* local user */
1190+ struct MsgBuf *msgbuf; /* message to send */
1191+ int i; /* loop variable */
40fd40a6 1192+
0823dcbb 1193+ /* assert */
40fd40a6 1194+ assert(flags & WELCOME_ANNOUNCE);
72b9a1d2 1195+ assert(WelcomeArrayIsValid(name));
40fd40a6 1196+ assert(WelcomeIsSet(name));
1197+ assert(!WelcomeIsEmpty(name));
1198+
1199+ /* build msgbuf */
1200+ msgbuf = msgq_make(0, ":%C %s $%s :[%s] %s", &me, MSG_NOTICE,
1201+ (flags & WELCOME_LOCAL) ? cli_name(&me) : "*",
1202+ (flags & WELCOME_LOCAL) ? cli_name(&me) : feature_str(FEAT_NETWORK),
1203+ WelcomeText(name));
1204+
1205+ /* go over local clients */
1206+ for (i = HighestFd; i > 0; --i) {
1207+
1208+ /* skip unregistered clients, skip servers */
1209+ if (!(acptr = LocalClientArray[i]) || !IsRegistered(acptr) || IsServer(acptr))
1210+ continue;
1211+
1212+ /* send it away */
1213+ send_buffer(acptr, msgbuf, 0);
1214+ }
1215+}
1216+
1217+
c13e4602 1218+/** Set a welcome message.
1219+ * @param[in] cptr Local client that sent us the welcome.
1220+ * @param[in] sptr Originator of the welcome.
1221+ * @param[in] nameint Name of the message.
1222+ * @param[in] namearray Array entry.
5943bc4b 1223+ * @param[in] create When it was set.
1224+ * @param[in] lastmod Last modification timestamp.
c13e4602 1225+ * @param[in] who Who set this message.
1226+ * @param[in] text The message.
1227+ * @param[in] flags Flags to set on welcome.
1228+ * @return Zero
1229+ */
1230+int
1231+welcome_set(struct Client *cptr, struct Client *sptr, int nameint,
5943bc4b 1232+ int namearray, time_t create, time_t lastmod, char *who, char *text, unsigned int flags)
c13e4602 1233+{
536d09ac 1234+ char msg[BUFSIZE]; /* msg for logging */
0823dcbb 1235+ int new = 0; /* welcome is new - not set yet */
a87bc2c2 1236+
0823dcbb 1237+ /* assert */
98143e8a 1238+ assert(NULL != cptr);
1239+ assert(NULL != sptr);
72b9a1d2 1240+ assert(WelcomeNameIsValid(nameint));
1241+ assert(WelcomeArrayIsValid(namearray));
c499291b 1242+ assert(lastmod > 0 || flags & WELCOME_FORCE); /* lastmod must not be 0 unless forced */
6d21d074 1243+ assert(NULL != who);
1244+ assert(NULL != text);
07e9e7ea 1245+ assert(!(flags & WELCOME_UNSET)); /* must not be unset */
98143e8a 1246+
c13e4602 1247+ /* debug */
e4e904c0 1248+ Debug((DEBUG_DEBUG, "welcome_set(cptr=%s, sptr=%s, nameint=%d, namearray=%d, "
1249+ "create=%Tu, lastmod=%Tu, who=%s, text=\"%s\", "
07e9e7ea 1250+ "FLAGS(0x%04x): local=%s announce=%s force=%s unset=%s insert=%s delete=%s)",
5943bc4b 1251+ cli_name(cptr), cli_name(sptr), nameint, namearray, create, lastmod, who, text, flags,
475b32df 1252+ (flags & WELCOME_LOCAL) ? "yes" : "no",
1253+ (flags & WELCOME_ANNOUNCE) ? "yes" : "no",
c499291b 1254+ (flags & WELCOME_FORCE) ? "yes" : "no",
07e9e7ea 1255+ (flags & WELCOME_UNSET) ? "yes" : "no",
309b0db2 1256+ (flags & WELCOME_INSERT) ? "yes" : "no",
1257+ (flags & WELCOME_DELETE) ? "yes" : "no"));
6dd3e24f 1258+
c13e4602 1259+ /* not set */
eabbc644 1260+ if (WelcomeIsEmpty(namearray))
c13e4602 1261+ new = 1;
6dd3e24f 1262+
c13e4602 1263+ /* update */
b24b1c61 1264+ welcome_make(namearray, text, who, create, lastmod, flags);
cddf800b 1265+
536d09ac 1266+ /* create msg for log */
04e84be1 1267+ ircd_snprintf(0, msg, 0, "%s%s%s%s WELCOME %d \"%s\" %s [%Tu]",
1268+ (flags & WELCOME_FORCE) ? "force " : "",
c13e4602 1269+ new ? "setting" : "changing",
1270+ (flags & WELCOME_ANNOUNCE) ? " and announcing " : " ",
1271+ (flags & WELCOME_LOCAL) ? "local" : "global",
5943bc4b 1272+ nameint, WelcomeText(namearray), WelcomeWho(namearray), create);
6dd3e24f 1273+
c13e4602 1274+ /* log it */
a717ac9f 1275+ welcome_log(sptr, msg, flags);
cddf800b 1276+
c13e4602 1277+ /* propagate it */
1278+ if (!(flags & WELCOME_LOCAL))
5943bc4b 1279+ welcome_propagate(cptr, sptr, nameint, create, lastmod, who, text, flags);
6dd3e24f 1280+
c13e4602 1281+ /* announce it */
1282+ if (flags & WELCOME_ANNOUNCE)
40fd40a6 1283+ welcome_announce(namearray, flags);
6dd3e24f 1284+
c13e4602 1285+ return 0;
1286+}
6dd3e24f 1287+
c13e4602 1288+
1289+/** Unset a welcome message.
1290+ * @param[in] cptr Local client that sent us the welcome.
1291+ * @param[in] sptr Originator of the welcome.
1292+ * @param[in] nameint Name of the message.
1293+ * @param[in] namearray Array entry.
5943bc4b 1294+ * @param[in] create When it was set.
1295+ * @param[in] lastmod Last modification timestamp.
c13e4602 1296+ * @param[in] who Who set this message.
1297+ * @param[in] flags Flags to set on welcome.
1298+ * @return Zero
1299+ */
1300+int
1301+welcome_unset(struct Client *cptr, struct Client *sptr, int nameint,
5943bc4b 1302+ int namearray, time_t create, time_t lastmod, char *who, unsigned int flags)
c13e4602 1303+{
536d09ac 1304+ char msg[BUFSIZE]; /* msg for logging */
c13e4602 1305+
0823dcbb 1306+ /* assert */
98143e8a 1307+ assert(NULL != cptr);
1308+ assert(NULL != sptr);
72b9a1d2 1309+ assert(WelcomeNameIsValid(nameint));
1310+ assert(WelcomeArrayIsValid(namearray));
c499291b 1311+ assert(lastmod > 0 || flags & WELCOME_FORCE); /* lastmod must not be 0 unless forced */
6d21d074 1312+ assert(NULL != who);
07e9e7ea 1313+ assert(flags & (WELCOME_UNSET|WELCOME_INSERT|WELCOME_DELETE)); /* must be unset, insert or delete */
98143e8a 1314+
c13e4602 1315+ /* debug */
e4e904c0 1316+ Debug((DEBUG_DEBUG, "welcome_unset(cptr=%s, sptr=%s, nameint=%d, namearray=%d, "
1317+ "create=%Tu, lastmod=%Tu, who=%s, "
07e9e7ea 1318+ "FLAGS(0x%04x): local=%s announce=%s force=%s unset=%s insert=%s delete=%s)",
5943bc4b 1319+ cli_name(cptr), cli_name(sptr), nameint, namearray, create, lastmod, who, flags,
475b32df 1320+ (flags & WELCOME_LOCAL) ? "yes" : "no",
1321+ (flags & WELCOME_ANNOUNCE) ? "yes" : "no",
c499291b 1322+ (flags & WELCOME_FORCE) ? "yes" : "no",
07e9e7ea 1323+ (flags & WELCOME_UNSET) ? "yes" : "no",
309b0db2 1324+ (flags & WELCOME_INSERT) ? "yes" : "no",
1325+ (flags & WELCOME_DELETE) ? "yes" : "no"));
c13e4602 1326+
536d09ac 1327+ /* create msg for log */
04e84be1 1328+ ircd_snprintf(0, msg, 0, "%sunsetting %s WELCOME %d \"%s\" %s [%Tu]",
1329+ (flags & WELCOME_FORCE) ? "force " : "",
6270d9ef 1330+ (flags & WELCOME_LOCAL) ? "local" : "global",
5943bc4b 1331+ nameint, WelcomeText(namearray), WelcomeWho(namearray), create);
a87bc2c2 1332+
c499291b 1333+ /* log it but only if it was set
2acd71cb 1334+ * welcome unset could have crossed with another welcome unset,
1335+ * still need to update lastmod
c499291b 1336+ * can be a forced unset on a welcome that is not set
1337+ */
1338+ if (!WelcomeIsEmpty(namearray))
1339+ welcome_log(sptr, msg, flags);
cddf800b 1340+
309b0db2 1341+ /* update,
b9483f73 1342+ * not when inserting, welcome_insert() handles that by calling welcome_set()
309b0db2 1343+ * not when deleting, welcome_delete() handles that
1344+ */
1345+ if (!(flags & (WELCOME_INSERT|WELCOME_DELETE)))
b24b1c61 1346+ welcome_make(namearray, "", who, create, lastmod, flags);
6270d9ef 1347+
c13e4602 1348+ /* propagate it, but not when inserting */
1349+ if (!(flags & (WELCOME_LOCAL|WELCOME_INSERT)))
5943bc4b 1350+ welcome_propagate(cptr, sptr, nameint, create, lastmod, who, "", flags);
a87bc2c2 1351+
1352+ return 0;
cddf800b 1353+}
1354+
a87bc2c2 1355+
c13e4602 1356+/** Insert a welcome message.
95de96cd 1357+ * @param[in] cptr Local client that sent us the welcome.
1358+ * @param[in] sptr Originator of the welcome.
95de96cd 1359+ * @param[in] nameint Name of the message.
1360+ * @param[in] namearray Array entry.
5943bc4b 1361+ * @param[in] create When it was set.
1362+ * @param[in] lastmod Last modification timestamp.
c13e4602 1363+ * @param[in] who Who set this message.
1364+ * @param[in] text The welcome message.
95de96cd 1365+ * @param[in] flags Flags to set on welcome.
1366+ * @return Zero
1367+ */
1368+int
c13e4602 1369+welcome_insert(struct Client *cptr, struct Client *sptr, int nameint,
5943bc4b 1370+ int namearray, time_t create, time_t lastmod, char *who, char *text, unsigned int flags)
95de96cd 1371+{
536d09ac 1372+ char msg[BUFSIZE]; /* msg for logging */
95de96cd 1373+ int i; /* loop variable */
eabbc644 1374+ int empty = -1; /* first empty spot in array after namearray */
95de96cd 1375+ int end = WELCOME_MAX_ENTRIES -1; /* last element to check in array */
c13e4602 1376+ int last = end; /* last welcome message to feed to welcome_unset */
95de96cd 1377+
0823dcbb 1378+ /* assert */
98143e8a 1379+ assert(NULL != cptr);
1380+ assert(NULL != sptr);
72b9a1d2 1381+ assert(WelcomeNameIsValid(nameint));
1382+ assert(WelcomeArrayIsValid(namearray));
c499291b 1383+ assert(lastmod > 0 || flags & WELCOME_FORCE); /* lastmod must not be 0 unless forced */
6d21d074 1384+ assert(NULL != who);
1385+ assert(NULL != text);
c499291b 1386+ assert(flags & WELCOME_INSERT); /* must be insert */
98143e8a 1387+
95de96cd 1388+ /* debug */
e4e904c0 1389+ Debug((DEBUG_DEBUG, "welcome_insert(cptr=%s, sptr=%s, nameint=%d, namearray=%d, "
1390+ "create=%Tu, lastmod=%Tu, who=%s, text=\"%s\", "
07e9e7ea 1391+ "FLAGS(0x%04x): local=%s announce=%s force=%s unset=%s insert=%s delete=%s)",
5943bc4b 1392+ cli_name(cptr), cli_name(sptr), nameint, namearray, create, lastmod, who, text, flags,
475b32df 1393+ (flags & WELCOME_LOCAL) ? "yes" : "no",
1394+ (flags & WELCOME_ANNOUNCE) ? "yes" : "no",
c499291b 1395+ (flags & WELCOME_FORCE) ? "yes" : "no",
07e9e7ea 1396+ (flags & WELCOME_UNSET) ? "yes" : "no",
309b0db2 1397+ (flags & WELCOME_INSERT) ? "yes" : "no",
1398+ (flags & WELCOME_DELETE) ? "yes" : "no"));
95de96cd 1399+
95de96cd 1400+ /* correct end for local offset */
1401+ if (flags & WELCOME_LOCAL)
1402+ end += WELCOME_MAX_ENTRIES;
1403+
536d09ac 1404+ /* find first empty spot */
95de96cd 1405+ for (i = namearray; i <= end; i++) {
eabbc644 1406+ if (WelcomeIsEmpty(i)) {
95de96cd 1407+ empty = i;
1408+ break;
1409+ }
1410+ }
1411+
c13e4602 1412+ /* no empty spot, need to unset last */
95de96cd 1413+ if (empty == -1) {
b24b1c61 1414+ welcome_unset(cptr, sptr, end +1, end, create, lastmod, who, flags);
95de96cd 1415+ empty = end;
1416+ }
1417+
2acd71cb 1418+ /* move entries down, update lastmod */
95de96cd 1419+ for (i = empty; i > namearray; i--)
0cee9545 1420+ welcome_make(i, WelcomeText(i-1), WelcomeWho(i-1), WelcomeCreate(i-1),
309b0db2 1421+ lastmod, flags | WELCOME_INCLASTMOD);
95de96cd 1422+
1423+ /* correct empty for local offset */
1424+ if (flags & WELCOME_LOCAL)
1425+ empty -= WELCOME_MAX_ENTRIES;
1426+
536d09ac 1427+ /* create msg for log */
95de96cd 1428+ if (nameint == empty)
1429+ ircd_snprintf(0, msg, 0, "moving %s WELCOME message %d one place down",
1430+ (flags & WELCOME_LOCAL) ? "local" : "global", nameint);
1431+ else
1432+ ircd_snprintf(0, msg, 0, "moving %s WELCOME message %d %s %d one place down",
1433+ (flags & WELCOME_LOCAL) ? "local" : "global", nameint, (empty - nameint > 1) ? "to" : "and" , empty);
1434+
95de96cd 1435+ /* log it */
a717ac9f 1436+ welcome_log(sptr, msg, flags);
c13e4602 1437+
1438+ /* set it */
5943bc4b 1439+ welcome_set(cptr, sptr, nameint, namearray, create, lastmod, who, text, flags);
c13e4602 1440+
95de96cd 1441+ return 0;
1442+}
1443+
1444+
309b0db2 1445+/** Delete a welcome message.
1446+ * @param[in] cptr Local client that sent us the welcome.
1447+ * @param[in] sptr Originator of the welcome.
1448+ * @param[in] nameint Name of the message.
1449+ * @param[in] namearray Array entry.
1450+ * @param[in] create When it was set.
1451+ * @param[in] lastmod Last modification timestamp.
1452+ * @param[in] who Who set this message.
1453+ * @param[in] flags Flags to set on welcome.
1454+ * @return Zero
1455+ */
1456+int
1457+welcome_delete(struct Client *cptr, struct Client *sptr, int nameint,
1458+ int namearray, time_t create, time_t lastmod, char *who, unsigned int flags)
1459+{
1460+ int i; /* loop variable */
1461+ int empty = namearray; /* first empty spot in array after namearray */
1462+ int end = WELCOME_MAX_ENTRIES -1; /* last element to check in array */
1463+
1464+ /* assert */
1465+ assert(NULL != cptr);
1466+ assert(NULL != sptr);
1467+ assert(WelcomeNameIsValid(nameint));
1468+ assert(WelcomeArrayIsValid(namearray));
c499291b 1469+ assert(lastmod > 0 || flags & WELCOME_FORCE); /* lastmod must not be 0 unless forced */
309b0db2 1470+ assert(NULL != who);
07e9e7ea 1471+ assert(flags & WELCOME_UNSET); /* must be unset */
c499291b 1472+ assert(flags & WELCOME_DELETE); /* must be delete */
309b0db2 1473+
1474+ /* debug */
e4e904c0 1475+ Debug((DEBUG_DEBUG, "welcome_delete(cptr=%s, sptr=%s, nameint=%d, namearray=%d, "
1476+ "create=%Tu, lastmod=%Tu, who=%s, "
07e9e7ea 1477+ "FLAGS(0x%04x): local=%s announce=%s force=%s unset=%s insert=%s delete=%s)",
309b0db2 1478+ cli_name(cptr), cli_name(sptr), nameint, namearray, create, lastmod, who, flags,
1479+ (flags & WELCOME_LOCAL) ? "yes" : "no",
1480+ (flags & WELCOME_ANNOUNCE) ? "yes" : "no",
c499291b 1481+ (flags & WELCOME_FORCE) ? "yes" : "no",
07e9e7ea 1482+ (flags & WELCOME_UNSET) ? "yes" : "no",
309b0db2 1483+ (flags & WELCOME_INSERT) ? "yes" : "no",
1484+ (flags & WELCOME_DELETE) ? "yes" : "no"));
1485+
1486+ /* unset it */
1487+ welcome_unset(cptr, sptr, nameint, namearray, create, lastmod, who, flags);
1488+
1489+ /* correct end for local offset */
1490+ if (flags & WELCOME_LOCAL)
1491+ end += WELCOME_MAX_ENTRIES;
1492+
1493+ /* move entries up, update lastmod */
1494+ for (i = namearray; i < end; i++) {
1495+ if (!WelcomeIsSet(i+1))
1496+ break;
1497+ welcome_make(i, WelcomeText(i+1), WelcomeWho(i+1), WelcomeCreate(i+1),
1498+ lastmod, flags | WELCOME_INCLASTMOD);
1499+ }
1500+
1501+ /* clear last entry */
1502+ if (i == end)
1503+ welcome_make(i, "", who, create, lastmod, flags | WELCOME_INCLASTMOD);
1504+
1505+ /* nothing was moved, clear entry */
1506+ if (i == namearray)
1507+ welcome_make(i, "", who, create, lastmod, flags);
1508+
1509+ return 0;
1510+}
1511+
1512+
c13e4602 1513+/** Change a welcome message.
1514+ * @param[in] cptr Local client that sent us the welcome.
1515+ * @param[in] sptr Originator of the welcome.
1516+ * @param[in] name Name of the message.
5943bc4b 1517+ * @param[in] create When it was set.
1518+ * @param[in] lastmod Last modification timestamp.
c13e4602 1519+ * @param[in] who Who set this message.
1520+ * @param[in] text The welcome message.
1521+ * @param[in] flags Flags to set on welcome.
1522+ * @return Zero
1523+ */
1524+int
1525+welcome_do(struct Client *cptr, struct Client *sptr, char *name,
5943bc4b 1526+ time_t create, time_t lastmod, char *who, char *text, unsigned int flags)
c13e4602 1527+{
1528+ int nameint = atoi(name); /* transform to int */
1529+ int namearray = nameint - 1; /* used to test the array element */
b9483f73 1530+ int start = 0; /* this is the first server setting this welcome message from a user */
c13e4602 1531+
0823dcbb 1532+ /* assert */
c13e4602 1533+ assert(NULL != cptr);
1534+ assert(NULL != sptr);
1535+ assert(NULL != name);
1536+ assert(NULL != text);
1537+ assert(NULL != who);
1538+
1539+ /* debug */
e4e904c0 1540+ Debug((DEBUG_DEBUG, "welcome_do(cptr=%s, sptr=%s, name=%s, "
1541+ "create=%Tu, lastmod=%Tu, who=%s, text=\"%s\", "
07e9e7ea 1542+ "FLAGS(0x%04x): local=%s announce=%s force=%s unset=%s insert=%s delete=%s)",
5943bc4b 1543+ cli_name(cptr), cli_name(sptr), name, create, lastmod, who, text, flags,
475b32df 1544+ (flags & WELCOME_LOCAL) ? "yes" : "no",
1545+ (flags & WELCOME_ANNOUNCE) ? "yes" : "no",
c499291b 1546+ (flags & WELCOME_FORCE) ? "yes" : "no",
07e9e7ea 1547+ (flags & WELCOME_UNSET) ? "yes" : "no",
309b0db2 1548+ (flags & WELCOME_INSERT) ? "yes" : "no",
1549+ (flags & WELCOME_DELETE) ? "yes" : "no"));
c13e4602 1550+
79c29720 1551+ /* welcome from my user, or a local welcome from a local/remote user */
1552+ start = (IsUser(sptr) && (MyConnect(sptr) || flags & WELCOME_LOCAL));
1553+
c13e4602 1554+ /* name empty after taking off the prefixes? */
869b8245 1555+ if (*name == 0) {
79c29720 1556+ if (start)
5a15ece2 1557+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Welcome: No message number given", sptr);
c13e4602 1558+ else
c51b6069 1559+ protocol_violation(cptr, "Received WELCOME with no message number from %C", sptr);
c13e4602 1560+ return 0;
1561+ }
1562+
1563+ /* check name */
72b9a1d2 1564+ if (!WelcomeArrayIsValid(namearray)) {
79c29720 1565+ if (start)
c13e4602 1566+ sendcmdto_one(&me, CMD_NOTICE, sptr,
5a15ece2 1567+ "%C :Welcome: Invalid message number %s - should between 1 and %d",
98143e8a 1568+ sptr, name, WELCOME_MAX_ENTRIES);
b27ac6fc 1569+ else
1570+ protocol_violation(cptr,
c51b6069 1571+ "Received WELCOME with invalid message number %s from %C - should be between 1 and %d",
98143e8a 1572+ name, sptr, WELCOME_MAX_ENTRIES);
c13e4602 1573+ return 0;
1574+ }
1575+
5943bc4b 1576+ /* invalid lastmod */
1577+ if (lastmod <= 0) {
af8d2d9c 1578+ /* from my user - must be a glitch,
1579+ * someone set (my) network time to 0 ?
1580+ */
1581+ if (MyUser(sptr))
2d741126 1582+ lastmod = 1;
c499291b 1583+ /* not forced or negative, it is a protocol violation */
1584+ else if (!(flags & WELCOME_FORCE) || lastmod < 0)
5943bc4b 1585+ return protocol_violation(cptr, "Received WELCOME with invalid lastmod timestamp %Tu from %C", lastmod, sptr);
af8d2d9c 1586+ }
1587+
7f642bb5 1588+ /* source is user, and is myuser or welcome is local, check length of the message */
b9483f73 1589+ if (start && strlen(text) > WELCOMELEN) {
7f642bb5 1590+ sendcmdto_one(&me, CMD_NOTICE, sptr,
5a15ece2 1591+ "%C :Welcome: The message is too long with %d chars - max is %d chars",
7f642bb5 1592+ sptr, strlen(text), WELCOMELEN);
1593+ ircd_strncpy(text, text, WELCOMELEN);
1594+ sendcmdto_one(&me, CMD_NOTICE, sptr,
5a15ece2 1595+ "%C :Welcome: Change or truncate the message to: \"%s\"", sptr, text);
7f642bb5 1596+ return 0;
1597+ }
1598+
c13e4602 1599+ /* correct namearray for local offset */
1600+ if (flags & WELCOME_LOCAL)
1601+ namearray += WELCOME_MAX_ENTRIES;
1602+
1603+ /* must be true by now */
72b9a1d2 1604+ assert(WelcomeArrayIsValid(namearray));
1605+ assert(WelcomeNameIsValid(nameint));
c13e4602 1606+
1607+ /* cannot unset welcome that is not set */
07e9e7ea 1608+ if (!WelcomeIsSet(namearray) && flags & WELCOME_UNSET) {
c13e4602 1609+
1610+ /* from user, throw error */
79c29720 1611+ if (start)
c13e4602 1612+ return send_reply(sptr, ERR_NOSUCHWELCOME, name);
1613+
1614+ /* new local welcome from server, but empty - ignore
1615+ * we do accept a new global welcome message that is empty
1616+ */
1617+ if (flags & WELCOME_LOCAL)
1618+ return 0;
1619+ }
1620+
1621+ /* check if there is something to change */
1622+ /* we got a record for it */
eabbc644 1623+ if (WelcomeIsSet(namearray)) {
c13e4602 1624+
c499291b 1625+ /* global and not forced */
1626+ if (!(flags & (WELCOME_LOCAL|WELCOME_FORCE))) {
c13e4602 1627+
b27ac6fc 1628+ /* myuser changes it,
5943bc4b 1629+ * WelcomeLastMod greater than or equal to lastmod, take WelcomeLastMod+1 as lastmod
b27ac6fc 1630+ * else the change is not accepted upstream because of the older TS
c13e4602 1631+ */
edf9cf79 1632+ if (MyUser(sptr)) {
5943bc4b 1633+ if (WelcomeLastMod(namearray) >= lastmod)
1634+ lastmod = WelcomeLastMod(namearray) +1;
edf9cf79 1635+ }
b27ac6fc 1636+
5943bc4b 1637+ /* compare lastmod, ignore welcome when:
0823dcbb 1638+ * we got a newer one
5943bc4b 1639+ * or when lastmod is the same and our text is 'smaller'
b27ac6fc 1640+ */
b9483f73 1641+ else if (lastmod < WelcomeLastMod(namearray) || /* we got a newer one */
1642+ (lastmod == WelcomeLastMod(namearray) && /* same lastmod */
1643+ strcmp(WelcomeText(namearray), text) < 0)) { /* our text is 'smaller' */
b27ac6fc 1644+ /* burst or burst ack, cptr gets our version from the burst */
1645+ if (IsBurstOrBurstAck(cptr))
1646+ return 0;
1647+ /* sync server */
c499291b 1648+ return welcome_resend(cptr, nameint, namearray, flags);
b27ac6fc 1649+ }
c13e4602 1650+
1651+ /* local welcome - we use our idea of the time */
c499291b 1652+ } else if (flags & WELCOME_LOCAL) {
5943bc4b 1653+ create = TStime();
1654+ lastmod = TStime();
1655+ }
c13e4602 1656+
79c29720 1657+ /* welcome from my user or local welcome from local/remote user
b27ac6fc 1658+ * compare new message with old message
b9483f73 1659+ * use strcmp instead of ircd_strcmp - oper may wish to change case
b27ac6fc 1660+ */
b9483f73 1661+ if (start && strcmp(text, WelcomeText(namearray)) == 0) {
1662+ sendcmdto_one(&me, CMD_NOTICE, sptr,
1663+ "%C :Welcome: Cannot change %s message for %s - nothing to change",
1664+ sptr, (flags & WELCOME_LOCAL) ? "local" : "global", name);
1665+ return 0;
c13e4602 1666+ }
1667+ }
1668+
79c29720 1669+ /* welcome from my user, or local welcome from local/remote user
1670+ * forcing and unsetting, set create and lastmod to 0
1671+ * clear delete flag
1672+ */
b9483f73 1673+ if (start && (flags & WELCOME_FORCE) && (flags & WELCOME_UNSET)) {
79c29720 1674+ flags &= ~WELCOME_DELETE;
1675+ create = 0;
1676+ lastmod = 0;
1677+ }
1678+
b9483f73 1679+ /* clear insert flag
1680+ * when this flag is set, welcome_unset() assumes it is being called from welcome_insert()
1681+ * and does not propagate the change - welcome_delete() also calls welcome_unset()
1682+ * do not insert last global/local welcome
1683+ * do not insert when entry is not set
1684+ *
1685+ */
1686+ if (flags & WELCOME_INSERT &&
1687+ (flags & WELCOME_UNSET || !WelcomeIsSet(namearray) || nameint == WELCOME_MAX_ENTRIES))
d9e2917e 1688+ flags &= ~WELCOME_INSERT;
4fef2533 1689+
b9483f73 1690+ /* clear delete flag when not unsetting so we do not propagate the - delete prefix */
ad8e941d 1691+ if (flags & WELCOME_DELETE && !(flags & WELCOME_UNSET))
2acd71cb 1692+ flags &= ~WELCOME_DELETE;
1693+
c13e4602 1694+ /* unset */
07e9e7ea 1695+ if (flags & WELCOME_UNSET) {
309b0db2 1696+
309b0db2 1697+ /* delete */
1698+ if (flags & WELCOME_DELETE)
1699+ return welcome_delete(cptr, sptr, nameint, namearray, create, lastmod, who, flags);
1700+
1701+ /* unset */
5943bc4b 1702+ return welcome_unset(cptr, sptr, nameint, namearray, create, lastmod, who, flags);
c13e4602 1703+ }
1704+
1705+ /* insert */
1706+ if (flags & WELCOME_INSERT)
5943bc4b 1707+ return welcome_insert(cptr, sptr, nameint, namearray, create, lastmod, who, text, flags);
c13e4602 1708+
1709+ /* new or change */
5943bc4b 1710+ return welcome_set(cptr, sptr, nameint, namearray, create, lastmod, who, text, flags);
c13e4602 1711+}
1712+
1713+
a87bc2c2 1714+/** Send the full list of welcome message to \a cptr.
1715+ * @param[in] cptr Local server to send welcomes to.
cddf800b 1716+ */
1717+void
a87bc2c2 1718+welcome_burst(struct Client *cptr)
cddf800b 1719+{
0823dcbb 1720+ int name; /* loop variable */
a87bc2c2 1721+
0823dcbb 1722+ /* assert */
6dd3e24f 1723+ assert(NULL != cptr);
1724+
0823dcbb 1725+ /* loop over global entries - 0 to max - 1 */
cb0b5df1 1726+ for (name = 0; name <= WELCOME_MAX_ENTRIES - 1; name++) {
eabbc644 1727+ if (WelcomeIsSet(name))
5943bc4b 1728+ sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %Tu %s :%s",
1729+ name + 1,
1730+ WelcomeCreate(name), WelcomeLastMod(name),
1731+ WelcomeWho(name), WelcomeText(name));
cddf800b 1732+ }
1733+}
1734+
a87bc2c2 1735+
a87bc2c2 1736+/** List welcome messages.
1737+ * @param[in] sptr Client requesting the listing.
1738+ * @param[in] connect When non zero do not report no welcome is set
cddf800b 1739+ * @return Zero.
1740+ */
1741+int
a87bc2c2 1742+welcome_list(struct Client *sptr, int connect)
cddf800b 1743+{
0823dcbb 1744+ int name; /* loop variable */
1745+ int found = 0; /* number of welcome messages set */
1746+ int local = 0; /* welcome is local or global */
a87bc2c2 1747+
0823dcbb 1748+ /* assert */
6dd3e24f 1749+ assert(NULL != sptr);
1750+
cb0b5df1 1751+ /* loop over all entries - range 0 to 2 * max - 1 */
1752+ for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
a87bc2c2 1753+
cb0b5df1 1754+ /* local entries now */
1755+ if (name == WELCOME_MAX_ENTRIES)
1756+ local = 1;
a87bc2c2 1757+
cb0b5df1 1758+ /* not set or empty - skip */
eabbc644 1759+ if (!WelcomeIsSet(name) || WelcomeIsEmpty(name))
a87bc2c2 1760+ continue;
cb0b5df1 1761+
1762+ /* got one */
a87bc2c2 1763+ found++;
cb0b5df1 1764+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :[%s] %s",
6eab3e57 1765+ sptr, local ? cli_name(&me) : feature_str(FEAT_NETWORK), WelcomeText(name));
a87bc2c2 1766+ }
cb0b5df1 1767+
1768+ /* nothing set */
a87bc2c2 1769+ if (!found && !connect)
cb0b5df1 1770+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :No welcome message set.", sptr);
1771+
a87bc2c2 1772+ return 0;
1773+}
cddf800b 1774+
cddf800b 1775+
a87bc2c2 1776+/** Statistics callback to list Welcome messages.
1777+ * @param[in] sptr Client requesting statistics.
1778+ * @param[in] sd Stats descriptor for request (ignored).
1779+ * @param[in] param Extra parameter from user (ignored).
1780+ */
1781+void
1782+welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param)
1783+{
0823dcbb 1784+ int name; /* loop variable */
1785+ int local = 0; /* welcome is local or global */
a87bc2c2 1786+
0823dcbb 1787+ /* assert */
6dd3e24f 1788+ assert(NULL != sptr);
1789+
7ceb849c 1790+ /* stats header */
1791+ send_reply(sptr, SND_EXPLICIT | RPL_STATSWELCOME,
5dea59ea 1792+ "W # Target Who Timestamp LastMod :Text");
7ceb849c 1793+
0823dcbb 1794+ /* loop over all entries - range 0 to 2 * max - 1 */
cb0b5df1 1795+ for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
cddf800b 1796+
cb0b5df1 1797+ /* local entries now */
1798+ if (name == WELCOME_MAX_ENTRIES)
1799+ local = 1;
a87bc2c2 1800+
cb0b5df1 1801+ /* not set */
eabbc644 1802+ if (!WelcomeIsSet(name))
cb0b5df1 1803+ continue;
cddf800b 1804+
cb0b5df1 1805+ /* send it */
1806+ send_reply(sptr, RPL_STATSWELCOME,
6dd3e24f 1807+ local ? name + 1 - WELCOME_MAX_ENTRIES : name + 1,
1808+ local ? cli_name(&me) : "*",
5943bc4b 1809+ WelcomeWho(name),
1810+ WelcomeCreate(name), WelcomeLastMod(name),
6eab3e57 1811+ WelcomeIsEmpty(name) ? "<Empty>" : WelcomeText(name));
cddf800b 1812+ }
cddf800b 1813+}
5736cfdb 1814+
1815+
1816+/** Count welcome messages and memory used by them.
1817+ * @param[out] we_size Receives total number of bytes allocated for welcomes.
1818+ * @return Number of welcome messages currently allocated.
1819+ */
1820+int
1821+welcome_memory_count(size_t *we_size)
1822+{
0823dcbb 1823+ int name; /* loop variable */
1824+ unsigned int we = 0; /* number of welcome messages set */
5736cfdb 1825+
0823dcbb 1826+ /* loop over all entries - range 0 to 2 * max - 1 */
5736cfdb 1827+ for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
0823dcbb 1828+
1829+ /* not set */
5736cfdb 1830+ if (!WelcomeIsSet(name))
1831+ continue;
0823dcbb 1832+
1833+ /* count */
5736cfdb 1834+ we++;
1835+ *we_size += WelcomeText(name) ? (strlen(WelcomeText(name)) + 1) : 0;
1836+ *we_size += WelcomeWho(name) ? (strlen(WelcomeWho(name)) + 1) : 0;
1837+ }
1838+ return we;
1839+}