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