]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blame - welcome.patch
welcome: removed unneeded include from welcome.h: sys/types.h
[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
084779ef 382@@ -0,0 +1,292 @@
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+ */
463+#include "config.h"
464+
465+#include "channel.h"
466+#include "client.h"
467+#include "hash.h"
468+#include "ircd.h"
a87bc2c2 469+#include "ircd_features.h"
cddf800b 470+#include "ircd_log.h"
471+#include "ircd_reply.h"
5bb41778 472+#include "ircd_snprintf.h"
cddf800b 473+#include "ircd_string.h"
474+#include "msg.h"
475+#include "numeric.h"
476+#include "numnicks.h"
477+#include "s_user.h"
478+#include "send.h"
a87bc2c2 479+#include "welcome.h"
cddf800b 480+
481+/* #include <assert.h> -- Now using assert in ircd_log.h */
482+
483+/*
484+ * m_welcome - local generic message handler
485+ *
486+ * parv[0] = Send prefix
6dd3e24f 487+ * parv[1] = [remote server to query]
cddf800b 488+ */
489+int m_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
490+{
a87bc2c2 491+ /* feature disabled */
492+ if (!feature_bool(FEAT_WELCOME))
493+ return send_reply(sptr, ERR_DISABLED, "WELCOME");
6dd3e24f 494+
495+ /* only opers can set the welcome messages */
496+ if (parc > 2)
497+ return send_reply(sptr, ERR_NOPRIVILEGES);
498+
499+ /* remote listing request, see if it is for me or a remote server
500+ * check FEAT_HIS_REMOTE to decide if an ordinary user can do this
501+ */
5632b943 502+ if ((parc > 1) && (hunt_server_cmd(sptr, CMD_WELCOME, cptr, feature_int(FEAT_HIS_REMOTE),
503+ "%C", 1, parc, parv) != HUNTED_ISME))
504+ return 0;
6dd3e24f 505+
5632b943 506+ /* local listing */
a87bc2c2 507+ return welcome_list(sptr, 0);
cddf800b 508+}
509+
510+
511+/*
512+ * mo_welcome - oper message handler
513+ *
514+ * listing:
515+ * parv[0] = Send prefix
516+ *
517+ * remote listing:
518+ * parv[0] = Send prefix
519+ * parv[1] = Target
520+ *
521+ * set global or on remote server:
522+ * parv[0] = Send prefix
6dd3e24f 523+ * parv[1] = Target: server or * for global (or left out for this server)
a87bc2c2 524+ * parv[2] = Name
525+ * parv[3] = Text
cddf800b 526+ */
527+int mo_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
528+{
cb0b5df1 529+ char *target, *name, *who, *text, pattern[BUFSIZE];
a87bc2c2 530+ time_t timestamp;
531+ unsigned int flags = 0;
6dd3e24f 532+ int local = 0;
a87bc2c2 533+
534+ /* feature disabled */
535+ if (!feature_bool(FEAT_WELCOME))
536+ return send_reply(sptr, ERR_DISABLED, "WELCOME");
537+
4e89d808 538+ /* TODO: move feature check here? */
a87bc2c2 539+ /* remote listing request, see if it is for me or a remote server */
5632b943 540+ if ((parc == 2) && (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME))
541+ return 0;
542+
543+ /* local listing */
544+ if (parc <= 2)
a87bc2c2 545+ return welcome_list(sptr, 0);
4e89d808 546+
547+ /* check PRIVS */
548+ /* local - need PRIV LOCAL_WELCOME or WELCOME */
549+ if (parc == 3 && !HasPriv(sptr,PRIV_LOCAL_WELCOME) && !HasPriv(sptr,PRIV_WELCOME))
550+ return send_reply(sptr, ERR_NOPRIVILEGES);
551+
552+ /* global or remote - need PRIV WELCOME */
553+ if (parc >= 4 && !HasPriv(sptr,PRIV_WELCOME))
554+ return send_reply(sptr, ERR_NOPRIVILEGES);
555+
a87bc2c2 556+ /* set the parameters */
6dd3e24f 557+
558+ /* target not given, only name - setting local welcome */
a87bc2c2 559+ if (parc < 4) {
560+ local++;
561+ target = cli_name(&me);
562+ name = parv[1];
563+ flags |= WELCOME_LOCAL;
6dd3e24f 564+
565+ /* target and name given */
566+ } else {
a87bc2c2 567+ target = parv[1];
568+ name = parv[2];
569+ }
570+ timestamp = TStime();
571+ who = cli_user(sptr)->opername;
572+ text = parv[parc - 1];
573+
574+ /* target is not global */
575+ if (!(target[0] == '*' && target[1] == '\0') && !local) {
6dd3e24f 576+
a87bc2c2 577+ /* build a pattern for hunt_server_cmd since we do not have all we need in parv */
578+ ircd_snprintf(0, pattern, sizeof(pattern), "%s %s %Tu %s :%s", "%C", name, timestamp, who, text);
579+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, pattern, 1, 2, parv) != HUNTED_ISME)
580+ return 0;
6dd3e24f 581+
582+ /* else it is a local welcome, for me */
583+ flags |= WELCOME_LOCAL;
a87bc2c2 584+ }
585+
586+ /* check for anounce prefix */
542f45ba 587+ if (*name == '$') {
a87bc2c2 588+ name++;
084779ef 589+ /* only allow announce by oper for local welcome */
590+ if (flags & WELCOME_LOCAL)
591+ flags |= WELCOME_ANNOUNCE;
a87bc2c2 592+ }
95de96cd 593+
594+ /* check for insert prefix */
595+ if (*name == '+') {
596+ name++;
597+ flags |= WELCOME_INSERT;
598+ }
599+
a87bc2c2 600+ /* and do it */
c13e4602 601+ return welcome_do(cptr, sptr, name, timestamp, who, text, flags);
cddf800b 602+}
603+
604+
605+/*
606+ * ms_welcome - server message handler
607+ *
608+ * parv[0] = Send prefix
609+ * parv[1] = Target: server numeric or * for global
a87bc2c2 610+ * parv[2] = Name
611+ * parv[3] = Timestamp
612+ * parv[4] = Who
613+ * parv[5] = Text
cddf800b 614+ */
615+int ms_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
616+{
cb0b5df1 617+ char *target, *name, *who, *text;
a87bc2c2 618+ time_t timestamp;
619+ unsigned int flags = 0;
620+
6dd3e24f 621+ /* not enough - complain */
622+ if (parc < 2) {
623+ protocol_violation(sptr, "Too few parameters for WELCOME (got %d - need 2)", parc);
a87bc2c2 624+ return need_more_params(sptr, "WELCOME");
6dd3e24f 625+ }
a87bc2c2 626+
627+ /* remote listing request, see if it is for me or a remote server */
628+ if (parc == 2) {
d2e4469e 629+ if (IsServer(sptr))
630+ return protocol_violation(cptr, "WELCOME listing request from server %C", sptr);
6dd3e24f 631+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME)
632+ return 0;
633+ return welcome_list(sptr, 0);
a87bc2c2 634+ }
635+
6dd3e24f 636+ /* we need at least 6 parameters to continue - complain */
637+ if (parc < 6) {
638+ protocol_violation(sptr, "Too few parameters for WELCOME (got %d - need 6)", parc);
a87bc2c2 639+ return need_more_params(sptr, "WELCOME");
6dd3e24f 640+ }
a87bc2c2 641+
642+ /* set the parameters */
643+ target = parv[1];
644+ name = parv[2];
645+ timestamp = atoi(parv[3]);
646+ who = parv[4];
6dd3e24f 647+ text = parv[parc - 1]; /* parse reason as last parameter */
a87bc2c2 648+
649+ /* target is not global */
650+ if (!(target[0] == '*' && target[1] == '\0')) {
6dd3e24f 651+
a87bc2c2 652+ /* not for me, and forward it */
653+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C %s %s %s :%s", 1, parc, parv) != HUNTED_ISME)
654+ return 0;
6dd3e24f 655+
656+ /* local welcome for me */
657+ flags |= WELCOME_LOCAL;
a87bc2c2 658+ }
659+
660+ /* check for anounce prefix */
542f45ba 661+ if (*name == '$') {
a87bc2c2 662+ name++;
663+ flags |= WELCOME_ANNOUNCE;
664+ }
665+
95de96cd 666+ /* check for insert prefix */
667+ if (*name == '+') {
668+ name++;
669+ flags |= WELCOME_INSERT;
670+ }
671+
a87bc2c2 672+ /* and do it */
c13e4602 673+ return welcome_do(cptr, sptr, name, timestamp, who, text, flags);
a87bc2c2 674+}
40fd40a6 675diff -r 8bf1b05cdfe7 ircd/parse.c
5632b943 676--- a/ircd/parse.c
677+++ b/ircd/parse.c
f0f686d6 678@@ -661,6 +661,15 @@
679 /* UNREG, CLIENT, SERVER, OPER, SERVICE */
680 { m_unregistered, m_not_oper, ms_check, mo_check, m_ignore }
cddf800b 681 },
682+
683+ /* add command for WELCOME */
684+ {
685+ MSG_WELCOME,
686+ TOK_WELCOME,
687+ 0, MAXPARA, MFLG_SLOW, 0, NULL,
a87bc2c2 688+ /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */
308d3fca 689+ { m_unregistered, m_welcome, ms_welcome, mo_welcome, m_ignore }
cddf800b 690+ },
691
692 /* This command is an alias for QUIT during the unregistered part of
693 * of the server. This is because someone jumping via a broken web
40fd40a6 694diff -r 8bf1b05cdfe7 ircd/s_debug.c
5736cfdb 695--- a/ircd/s_debug.c
696+++ b/ircd/s_debug.c
697@@ -50,6 +50,7 @@
698 #include "send.h"
699 #include "struct.h"
700 #include "sys.h"
701+#include "welcome.h"
702 #include "whowas.h"
703
704 /* #include <assert.h> -- Now using assert in ircd_log.h */
705@@ -231,7 +232,8 @@
706 aw = 0, /* aways set */
707 wwa = 0, /* whowas aways */
708 gl = 0, /* glines */
709- ju = 0; /* jupes */
710+ ju = 0, /* jupes */
711+ we = 0; /* welcomes */
712
713 size_t chm = 0, /* memory used by channels */
714 chbm = 0, /* memory used by channel bans */
715@@ -244,6 +246,7 @@
716 wwm = 0, /* whowas array memory used */
717 glm = 0, /* memory used by glines */
718 jum = 0, /* memory used by jupes */
719+ wem = 0, /* memory used by welcomes */
720 com = 0, /* memory used by conf lines */
721 dbufs_allocated = 0, /* memory used by dbufs */
722 dbufs_used = 0, /* memory used by dbufs */
723@@ -351,6 +354,10 @@
724 send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
725 ":Glines %d(%zu) Jupes %d(%zu)", gl, glm, ju, jum);
726
727+ we = welcome_memory_count(&wem);
728+ send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
729+ ":Welcomes %d(%zu)", we, wem);
730+
731 send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
732 ":Hash: client %d(%zu), chan is the same", HASHSIZE,
733 sizeof(void *) * HASHSIZE);
40fd40a6 734diff -r 8bf1b05cdfe7 ircd/s_err.c
5632b943 735--- a/ircd/s_err.c
736+++ b/ircd/s_err.c
a87bc2c2 737@@ -486,7 +486,7 @@
738 /* 226 */
739 { RPL_STATSALINE, "%s", "226" },
740 /* 227 */
741- { 0 },
742+ { RPL_STATSWELCOME, "W %d %s %s %Tu :%s", "227" },
743 /* 228 */
744 { RPL_STATSQLINE, "Q %s :%s", "228" },
745 /* 229 */
746@@ -1050,7 +1050,7 @@
747 /* 508 */
748 { 0 },
749 /* 509 */
750- { 0 },
751+ { ERR_NOSUCHWELCOME, "%s :No such welcome", "509" },
752 /* 510 */
753 { 0 },
754 /* 511 */
40fd40a6 755diff -r 8bf1b05cdfe7 ircd/s_serv.c
5632b943 756--- a/ircd/s_serv.c
757+++ b/ircd/s_serv.c
a87bc2c2 758@@ -57,6 +57,7 @@
759 #include "struct.h"
760 #include "sys.h"
761 #include "userload.h"
762+#include "welcome.h"
763
764 /* #include <assert.h> -- Now using assert in ircd_log.h */
765 #include <stdlib.h>
766@@ -196,6 +197,7 @@
767 */
768 gline_burst(cptr);
769 jupe_burst(cptr);
770+ welcome_burst(cptr);
771
772 /*
773 * Pass on my client information to the new server
40fd40a6 774diff -r 8bf1b05cdfe7 ircd/s_stats.c
5632b943 775--- a/ircd/s_stats.c
776+++ b/ircd/s_stats.c
a87bc2c2 777@@ -54,6 +54,7 @@
778 #include "send.h"
779 #include "struct.h"
780 #include "userload.h"
781+#include "welcome.h"
782
783 #include <stdio.h>
784 #include <stdlib.h>
a23c2a71 785@@ -650,9 +651,12 @@
a87bc2c2 786 { 'V', "vserversmach", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_v,
787 stats_servers_verbose, 0,
788 "Verbose server information." },
789- { 'w', "userload", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
790+ { 'w', "userload", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_w,
791 calc_load, 0,
792 "Userload statistics." },
793+ { 'W', "welcome", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_W,
794+ welcome_stats, 0,
795+ "Welcome messages." },
796 { 'x', "memusage", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
797 stats_meminfo, 0,
798 "List usage information." },
40fd40a6 799diff -r 8bf1b05cdfe7 ircd/s_user.c
5632b943 800--- a/ircd/s_user.c
801+++ b/ircd/s_user.c
a87bc2c2 802@@ -63,6 +63,7 @@
803 #include "userload.h"
804 #include "version.h"
805 #include "whowas.h"
806+#include "welcome.h"
807
808 #include "handlers.h" /* m_motd and m_lusers */
809
a23c2a71 810@@ -402,6 +403,10 @@
a87bc2c2 811
812 IPcheck_connect_succeeded(sptr);
a23c2a71 813
814+ /* send welcome */
a87bc2c2 815+ if (feature_bool(FEAT_WELCOME))
816+ welcome_list(sptr, 1);
a23c2a71 817+
818 /* TODO: */
819 /* apply auto sethost if needed */
820 apply_spoofblock(sptr);
40fd40a6 821diff -r 8bf1b05cdfe7 ircd/welcome.c
5632b943 822--- /dev/null
823+++ b/ircd/welcome.c
40fd40a6 824@@ -0,0 +1,647 @@
cddf800b 825+/*
a87bc2c2 826+ * IRC - Internet Relay Chat, ircd/welcome.c
cddf800b 827+ * Copyright (C) 1990 Jarkko Oikarinen and
828+ * University of Oulu, Finland
829+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
830+ *
831+ * This program is free software; you can redistribute it and/or modify
832+ * it under the terms of the GNU General Public License as published by
833+ * the Free Software Foundation; either version 1, or (at your option)
834+ * any later version.
835+ *
836+ * This program is distributed in the hope that it will be useful,
837+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
838+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
839+ * GNU General Public License for more details.
840+ *
841+ * You should have received a copy of the GNU General Public License
842+ * along with this program; if not, write to the Free Software
843+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
844+ */
845+/** @file
a87bc2c2 846+ * @brief Implementation of welcome message handling functions.
cddf800b 847+ */
848+#include "config.h"
849+
850+#include "client.h"
851+#include "hash.h"
852+#include "ircd.h"
853+#include "ircd_alloc.h"
854+#include "ircd_features.h"
855+#include "ircd_log.h"
856+#include "ircd_reply.h"
857+#include "ircd_string.h"
858+#include "match.h"
859+#include "msg.h"
860+#include "numeric.h"
861+#include "numnicks.h"
862+#include "s_bsd.h"
a87bc2c2 863+#include "s_debug.h"
cddf800b 864+#include "s_misc.h"
865+#include "send.h"
866+#include "struct.h"
867+#include "sys.h" /* FALSE bleah */
868+#include "welcome.h"
869+
870+/* #include <assert.h> -- Now using assert in ircd_log.h */
871+#include <string.h>
872+
cddf800b 873+
cb0b5df1 874+/** List of welcome messages - first MAX for global, second MAX for local */
6dd3e24f 875+static struct Welcome WelcomeArray[WELCOME_MAX_ENTRIES * 2] = { { 0 } };
cddf800b 876+
cddf800b 877+
a87bc2c2 878+/** Allocate a new welcome with the given parameters.
879+ * @param[in] name Name of the welcome message.
880+ * @param[in] text The welcome message.
881+ * @param[in] who Who set it.
882+ * @param[in] timestamp When it was set.
cb0b5df1 883+ * @return name Array number of the welcome set.
cddf800b 884+ */
cb0b5df1 885+static int
886+welcome_make(int name, char *text, char *who, time_t timestamp)
cddf800b 887+{
d6da6cd7 888+ assert(WelcomeIsValid(name));
98143e8a 889+ assert(NULL != text);
890+ assert(NULL != who);
cb0b5df1 891+
892+ /* store it */
38c95254 893+ ircd_strncpy(WelcomeArray[name].text, text, WELCOMELEN);
cb0b5df1 894+ ircd_strncpy(WelcomeArray[name].who, who, ACCOUNTLEN);
895+ WelcomeArray[name].timestamp = timestamp;
896+
897+ return name;
cddf800b 898+}
899+
cddf800b 900+
c13e4602 901+/** Propagate a welcome message.
a87bc2c2 902+ * @param[in] cptr Local client that sent us the welcome.
903+ * @param[in] sptr Originator of the welcome.
c13e4602 904+ * @param[in] nameint Name of the message.
a87bc2c2 905+ * @param[in] timestamp Timestamp of when the message was set.
c13e4602 906+ * @param[in] who Who set this message.
907+ * @param[in] text The welcome message.
a87bc2c2 908+ * @param[in] flags Flags to set on welcome.
909+ * @return Zero
cddf800b 910+ */
911+int
c13e4602 912+welcome_propagate(struct Client *cptr, struct Client *sptr, int nameint,
913+ time_t timestamp, char *who, char *text, unsigned int flags)
cddf800b 914+{
b27ac6fc 915+ assert(NULL != sptr);
916+ assert(NULL != cptr);
98143e8a 917+ assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
918+ assert(!(flags & WELCOME_LOCAL));
6dd3e24f 919+
c13e4602 920+ sendcmdto_serv_butone(sptr, CMD_WELCOME, cptr, "* %s%s%d %Tu %s :%s",
542f45ba 921+ (flags & WELCOME_ANNOUNCE) ? "$" : "", (flags & WELCOME_INSERT) ? "+" : "",
c13e4602 922+ nameint, timestamp, who, text);
a87bc2c2 923+
c13e4602 924+ return 0;
925+}
371f9aee 926+
cddf800b 927+
b27ac6fc 928+/** Resend a welcome message.
929+ * @param[in] cptr Local client that sent us the welcome.
930+ * @param[in] nameint Name of the message.
931+ * @param[in] namearray Name of the array item.
932+ * @return Zero
933+ */
934+int
935+welcome_resend(struct Client *cptr, int nameint, int namearray)
936+{
b27ac6fc 937+ assert(NULL != cptr);
938+ assert(IsServer(cptr));
98143e8a 939+ assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
940+ assert(WelcomeIsValid(namearray));
b27ac6fc 941+
942+ sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %s :%s",
943+ nameint, WelcomeTS(namearray), WelcomeWho(namearray), WelcomeText(namearray));
944+
945+ return 0;
946+}
947+
948+
469e14e1 949+/** Log a welcome message.
950+ * @param[in] sptr Originator of the welcome.
951+ * @param[in] msg The message to show.
469e14e1 952+ * @param[in] flags Flags to set on welcome.
953+ * @return Zero
954+ */
955+int
a717ac9f 956+welcome_log(struct Client *sptr, char *msg, unsigned int flags)
469e14e1 957+{
2f08b785 958+ assert(NULL != sptr);
959+ assert(NULL != msg);
469e14e1 960+
961+ /* inform ops */
962+ sendto_opmask_butone(0, SNO_OLDSNO, "%s %s",
963+ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
964+ get_client_name_and_opername(sptr) : cli_name((cli_user(sptr))->server), msg);
965+
966+ /* log it */
a717ac9f 967+ log_write(LS_NETWORK, L_INFO, LOG_NOSNOTICE, "%s %s", get_client_name_and_opername(sptr), msg);
469e14e1 968+
40fd40a6 969+ /* welcome by remote oper, inform of success */
d014176e 970+ if ((flags & WELCOME_LOCAL) && IsUser(sptr) && !MyConnect(sptr)) {
469e14e1 971+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s",
972+ sptr, get_client_name_and_opername(sptr), msg);
973+
974+ /* TODO: wallops all local changes, by both local and remote opers? */
975+ /* tell all opers about the local message being set remotely */
976+ sendwallto_group_butone(&me, WALL_WALLOPS, 0, "%s %s", get_client_name_and_opername(sptr), msg);
977+ }
978+
979+ return 0;
980+}
981+
982+
40fd40a6 983+/** Announce a welcome message to local clients.
984+ * @param[in] name Welcome message to announce.
985+ * @param[in] flags Flags to set on welcome.
986+ */
987+void
988+welcome_announce(int name, unsigned int flags)
989+{
990+ struct Client *acptr;
991+ struct MsgBuf *msgbuf;
992+ int i;
993+
994+ /* announce, valid range, set and not empty */
995+ assert(flags & WELCOME_ANNOUNCE);
996+ assert(WelcomeIsValid(name));
997+ assert(WelcomeIsSet(name));
998+ assert(!WelcomeIsEmpty(name));
999+
1000+ /* build msgbuf */
1001+ msgbuf = msgq_make(0, ":%C %s $%s :[%s] %s", &me, MSG_NOTICE,
1002+ (flags & WELCOME_LOCAL) ? cli_name(&me) : "*",
1003+ (flags & WELCOME_LOCAL) ? cli_name(&me) : feature_str(FEAT_NETWORK),
1004+ WelcomeText(name));
1005+
1006+ /* go over local clients */
1007+ for (i = HighestFd; i > 0; --i) {
1008+
1009+ /* skip unregistered clients, skip servers */
1010+ if (!(acptr = LocalClientArray[i]) || !IsRegistered(acptr) || IsServer(acptr))
1011+ continue;
1012+
1013+ /* send it away */
1014+ send_buffer(acptr, msgbuf, 0);
1015+ }
1016+}
1017+
1018+
c13e4602 1019+/** Set a welcome message.
1020+ * @param[in] cptr Local client that sent us the welcome.
1021+ * @param[in] sptr Originator of the welcome.
1022+ * @param[in] nameint Name of the message.
1023+ * @param[in] namearray Array entry.
1024+ * @param[in] timestamp Timestamp of when the message was set.
1025+ * @param[in] who Who set this message.
1026+ * @param[in] text The message.
1027+ * @param[in] flags Flags to set on welcome.
1028+ * @return Zero
1029+ */
1030+int
1031+welcome_set(struct Client *cptr, struct Client *sptr, int nameint,
1032+ int namearray, time_t timestamp, char *who, char *text, unsigned int flags)
1033+{
536d09ac 1034+ char msg[BUFSIZE]; /* msg for logging */
c13e4602 1035+ int new = 0;
a87bc2c2 1036+
98143e8a 1037+ assert(NULL != cptr);
1038+ assert(NULL != sptr);
1039+ assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
1040+ assert(WelcomeIsValid(namearray));
1041+
c13e4602 1042+ /* debug */
1043+ Debug((DEBUG_DEBUG, "welcome_set(\"%s\", \"%s\", %d, %d, %Tu, \"%s\", \"%s\", 0x%04x)",
1044+ cli_name(cptr), cli_name(sptr), nameint, namearray, timestamp, who, text, flags));
6dd3e24f 1045+
c13e4602 1046+ /* not set */
eabbc644 1047+ if (WelcomeIsEmpty(namearray))
c13e4602 1048+ new = 1;
6dd3e24f 1049+
c13e4602 1050+ /* update */
1051+ welcome_make(namearray, text, who, timestamp);
cddf800b 1052+
536d09ac 1053+ /* create msg for log */
a717ac9f 1054+ ircd_snprintf(0, msg, 0, "%s%s%s WELCOME %d \"%s\" %s [%Tu]",
c13e4602 1055+ new ? "setting" : "changing",
1056+ (flags & WELCOME_ANNOUNCE) ? " and announcing " : " ",
1057+ (flags & WELCOME_LOCAL) ? "local" : "global",
6270d9ef 1058+ nameint, WelcomeText(namearray), WelcomeWho(namearray), timestamp);
6dd3e24f 1059+
c13e4602 1060+ /* log it */
a717ac9f 1061+ welcome_log(sptr, msg, flags);
cddf800b 1062+
c13e4602 1063+ /* propagate it */
1064+ if (!(flags & WELCOME_LOCAL))
1065+ welcome_propagate(cptr, sptr, nameint, timestamp, who, text, flags);
6dd3e24f 1066+
c13e4602 1067+ /* announce it */
1068+ if (flags & WELCOME_ANNOUNCE)
40fd40a6 1069+ welcome_announce(namearray, flags);
6dd3e24f 1070+
c13e4602 1071+ return 0;
1072+}
6dd3e24f 1073+
c13e4602 1074+
1075+/** Unset a welcome message.
1076+ * @param[in] cptr Local client that sent us the welcome.
1077+ * @param[in] sptr Originator of the welcome.
1078+ * @param[in] nameint Name of the message.
1079+ * @param[in] namearray Array entry.
1080+ * @param[in] timestamp Timestamp of when the message was set.
1081+ * @param[in] who Who set this message.
1082+ * @param[in] flags Flags to set on welcome.
1083+ * @return Zero
1084+ */
1085+int
1086+welcome_unset(struct Client *cptr, struct Client *sptr, int nameint,
1087+ int namearray, time_t timestamp, char *who, unsigned int flags)
1088+{
536d09ac 1089+ char msg[BUFSIZE]; /* msg for logging */
3da53d64 1090+ int i; /* loop variable */
eabbc644 1091+ int empty = namearray; /* first empty spot in array after namearray */
3da53d64 1092+ int end = WELCOME_MAX_ENTRIES -1; /* last element to check in array */
c13e4602 1093+
98143e8a 1094+ assert(NULL != cptr);
1095+ assert(NULL != sptr);
1096+ assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
1097+ assert(WelcomeIsValid(namearray));
1098+
c13e4602 1099+ /* debug */
1100+ Debug((DEBUG_DEBUG, "welcome_unset(\"%s\", \"%s\", %d, %d, %Tu, \"%s\", 0x%04x)",
1101+ cli_name(cptr), cli_name(sptr), nameint, namearray, timestamp, who, flags));
1102+
536d09ac 1103+ /* create msg for log */
a717ac9f 1104+ ircd_snprintf(0, msg, 0, "unsetting %s WELCOME %d \"%s\" %s [%Tu]",
6270d9ef 1105+ (flags & WELCOME_LOCAL) ? "local" : "global",
1106+ nameint, WelcomeText(namearray), WelcomeWho(namearray), timestamp);
a87bc2c2 1107+
1108+ /* log it */
a717ac9f 1109+ welcome_log(sptr, msg, flags);
cddf800b 1110+
6270d9ef 1111+ /* update */
1112+ welcome_make(namearray, "", who, timestamp);
1113+
c13e4602 1114+ /* propagate it, but not when inserting */
1115+ if (!(flags & (WELCOME_LOCAL|WELCOME_INSERT)))
1116+ welcome_propagate(cptr, sptr, nameint, timestamp, who, "", flags);
a87bc2c2 1117+
3da53d64 1118+ /* correct end for local offset */
1119+ if (flags & WELCOME_LOCAL)
1120+ end += WELCOME_MAX_ENTRIES;
1121+
536d09ac 1122+ /* move entries up, update timestamp */
3da53d64 1123+ for (i = namearray; i < end; i++)
6eab3e57 1124+ welcome_make(i, WelcomeText(i+1), WelcomeWho(i+1), timestamp);
3da53d64 1125+
536d09ac 1126+ /* clear last entry, update timestamp */
3da53d64 1127+ welcome_make(end, "", who, timestamp);
1128+
a87bc2c2 1129+ return 0;
cddf800b 1130+}
1131+
a87bc2c2 1132+
c13e4602 1133+/** Insert a welcome message.
95de96cd 1134+ * @param[in] cptr Local client that sent us the welcome.
1135+ * @param[in] sptr Originator of the welcome.
95de96cd 1136+ * @param[in] nameint Name of the message.
1137+ * @param[in] namearray Array entry.
95de96cd 1138+ * @param[in] timestamp Timestamp of when the message was set.
c13e4602 1139+ * @param[in] who Who set this message.
1140+ * @param[in] text The welcome message.
95de96cd 1141+ * @param[in] flags Flags to set on welcome.
1142+ * @return Zero
1143+ */
1144+int
c13e4602 1145+welcome_insert(struct Client *cptr, struct Client *sptr, int nameint,
1146+ int namearray, time_t timestamp, char *who, char *text, unsigned int flags)
95de96cd 1147+{
536d09ac 1148+ char msg[BUFSIZE]; /* msg for logging */
95de96cd 1149+ int i; /* loop variable */
eabbc644 1150+ int empty = -1; /* first empty spot in array after namearray */
95de96cd 1151+ int end = WELCOME_MAX_ENTRIES -1; /* last element to check in array */
c13e4602 1152+ int last = end; /* last welcome message to feed to welcome_unset */
95de96cd 1153+
98143e8a 1154+ assert(NULL != cptr);
1155+ assert(NULL != sptr);
1156+ assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
1157+ assert(WelcomeIsValid(namearray));
1158+
95de96cd 1159+ /* debug */
c13e4602 1160+ Debug((DEBUG_DEBUG, "welcome_insert(\"%s\", \"%s\", %d, %d, %Tu, \"%s\", \"%s\", 0x%04x)",
1161+ cli_name(cptr), cli_name(sptr), nameint, namearray, timestamp, who, text, flags));
95de96cd 1162+
95de96cd 1163+ /* correct end for local offset */
1164+ if (flags & WELCOME_LOCAL)
1165+ end += WELCOME_MAX_ENTRIES;
1166+
536d09ac 1167+ /* find first empty spot */
95de96cd 1168+ for (i = namearray; i <= end; i++) {
eabbc644 1169+ if (WelcomeIsEmpty(i)) {
95de96cd 1170+ empty = i;
1171+ break;
1172+ }
1173+ }
1174+
c13e4602 1175+ /* no empty spot, need to unset last */
95de96cd 1176+ if (empty == -1) {
c13e4602 1177+ welcome_unset(cptr, sptr, end, namearray, timestamp, who, flags);
95de96cd 1178+ empty = end;
1179+ }
1180+
c13e4602 1181+ /* move entries down, update timestamp */
95de96cd 1182+ for (i = empty; i > namearray; i--)
6eab3e57 1183+ welcome_make(i, WelcomeText(i-1), WelcomeWho(i-1), timestamp);
95de96cd 1184+
1185+ /* correct empty for local offset */
1186+ if (flags & WELCOME_LOCAL)
1187+ empty -= WELCOME_MAX_ENTRIES;
1188+
536d09ac 1189+ /* create msg for log */
95de96cd 1190+ if (nameint == empty)
1191+ ircd_snprintf(0, msg, 0, "moving %s WELCOME message %d one place down",
1192+ (flags & WELCOME_LOCAL) ? "local" : "global", nameint);
1193+ else
1194+ ircd_snprintf(0, msg, 0, "moving %s WELCOME message %d %s %d one place down",
1195+ (flags & WELCOME_LOCAL) ? "local" : "global", nameint, (empty - nameint > 1) ? "to" : "and" , empty);
1196+
95de96cd 1197+ /* log it */
a717ac9f 1198+ welcome_log(sptr, msg, flags);
c13e4602 1199+
1200+ /* set it */
1201+ welcome_set(cptr, sptr, nameint, namearray, timestamp, who, text, flags);
1202+
95de96cd 1203+ return 0;
1204+}
1205+
1206+
c13e4602 1207+/** Change a welcome message.
1208+ * @param[in] cptr Local client that sent us the welcome.
1209+ * @param[in] sptr Originator of the welcome.
1210+ * @param[in] name Name of the message.
1211+ * @param[in] timestamp Timestamp of when the message was set.
1212+ * @param[in] who Who set this message.
1213+ * @param[in] text The welcome message.
1214+ * @param[in] flags Flags to set on welcome.
1215+ * @return Zero
1216+ */
1217+int
1218+welcome_do(struct Client *cptr, struct Client *sptr, char *name,
1219+ time_t timestamp, char *who, char *text, unsigned int flags)
1220+{
1221+ int nameint = atoi(name); /* transform to int */
1222+ int namearray = nameint - 1; /* used to test the array element */
c13e4602 1223+
1224+ assert(NULL != cptr);
1225+ assert(NULL != sptr);
1226+ assert(NULL != name);
1227+ assert(NULL != text);
1228+ assert(NULL != who);
1229+
1230+ /* debug */
1231+ Debug((DEBUG_DEBUG, "welcome_do(\"%s\", \"%s\", \"%s\", %Tu, \"%s\", \"%s\", 0x%04x)",
1232+ cli_name(cptr), cli_name(sptr), name, timestamp, who, text, flags));
1233+
9223cb06 1234+ /* if for some reason timestamp is 0, increase it */
1235+ if (timestamp == 0)
1236+ timestamp++;
1237+
c13e4602 1238+ /* name empty after taking off the prefixes? */
1239+ if (EmptyString(name)) {
1240+ if (IsUser(sptr))
5a15ece2 1241+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Welcome: No message number given", sptr);
c13e4602 1242+ else
1243+ protocol_violation(cptr, "WELCOME: No message number given by %C", sptr);
1244+ return 0;
1245+ }
1246+
1247+ /* check name */
d9e2917e 1248+ if (!WelcomeIsValid(namearray)) {
c13e4602 1249+ if (IsUser(sptr))
1250+ sendcmdto_one(&me, CMD_NOTICE, sptr,
5a15ece2 1251+ "%C :Welcome: Invalid message number %s - should between 1 and %d",
98143e8a 1252+ sptr, name, WELCOME_MAX_ENTRIES);
b27ac6fc 1253+ else
1254+ protocol_violation(cptr,
1255+ "WELCOME: Invalid message number %s from %C - should be between 1 and %d",
98143e8a 1256+ name, sptr, WELCOME_MAX_ENTRIES);
c13e4602 1257+ return 0;
1258+ }
1259+
7f642bb5 1260+ /* source is user, and is myuser or welcome is local, check length of the message */
d014176e 1261+ if (IsUser(sptr) && (MyConnect(sptr) || (flags & WELCOME_LOCAL)) && (strlen(text) > WELCOMELEN)) {
7f642bb5 1262+ sendcmdto_one(&me, CMD_NOTICE, sptr,
5a15ece2 1263+ "%C :Welcome: The message is too long with %d chars - max is %d chars",
7f642bb5 1264+ sptr, strlen(text), WELCOMELEN);
1265+ ircd_strncpy(text, text, WELCOMELEN);
1266+ sendcmdto_one(&me, CMD_NOTICE, sptr,
5a15ece2 1267+ "%C :Welcome: Change or truncate the message to: \"%s\"", sptr, text);
7f642bb5 1268+ return 0;
1269+ }
1270+
c13e4602 1271+ /* correct namearray for local offset */
1272+ if (flags & WELCOME_LOCAL)
1273+ namearray += WELCOME_MAX_ENTRIES;
1274+
1275+ /* must be true by now */
d6da6cd7 1276+ assert(WelcomeIsValid(namearray));
98143e8a 1277+ assert(nameint > 0 && nameint <= WELCOME_MAX_ENTRIES);
c13e4602 1278+
1279+ /* cannot unset welcome that is not set */
eabbc644 1280+ if (!WelcomeIsSet(namearray) && EmptyString(text)) {
c13e4602 1281+
1282+ /* from user, throw error */
1283+ if (IsUser(sptr))
1284+ return send_reply(sptr, ERR_NOSUCHWELCOME, name);
1285+
1286+ /* new local welcome from server, but empty - ignore
1287+ * we do accept a new global welcome message that is empty
1288+ */
1289+ if (flags & WELCOME_LOCAL)
1290+ return 0;
1291+ }
1292+
1293+ /* check if there is something to change */
1294+ /* we got a record for it */
eabbc644 1295+ if (WelcomeIsSet(namearray)) {
c13e4602 1296+
1297+ /* global */
1298+ if (!(flags & WELCOME_LOCAL)) {
1299+
b27ac6fc 1300+ /* myuser changes it,
1301+ * welcomeTS greater than or equal to timestamp, take welcomeTS+1 as timestamp
1302+ * else the change is not accepted upstream because of the older TS
c13e4602 1303+ */
edf9cf79 1304+ if (MyUser(sptr)) {
1305+ if (WelcomeTS(namearray) >= timestamp)
1306+ timestamp = WelcomeTS(namearray) +1;
1307+ }
b27ac6fc 1308+
1309+ /* compare timestamps, ignore welcome when:
1310+ * we got a newer one
5fbab47d 1311+ * or when timestamps are the same and our text is 'smaller'
b27ac6fc 1312+ */
bc99f6da 1313+ else if ((timestamp < WelcomeTS(namearray)) || /* we got a newer one */
1314+ ((timestamp == WelcomeTS(namearray)) && /* same timestamp */
1315+ (strcmp(WelcomeText(namearray), text) < 0))) { /* our text is 'smaller' */
b27ac6fc 1316+ /* burst or burst ack, cptr gets our version from the burst */
1317+ if (IsBurstOrBurstAck(cptr))
1318+ return 0;
1319+ /* sync server */
1320+ return welcome_resend(cptr, nameint, namearray);
1321+ }
c13e4602 1322+
1323+ /* local welcome - we use our idea of the time */
1324+ } else
1325+ timestamp = TStime();
1326+
b27ac6fc 1327+ /* new global welcome from my user or local welcome
1328+ * compare new message with old message
1329+ */
d014176e 1330+ if (IsUser(sptr) && (MyConnect(sptr) || (flags & WELCOME_LOCAL))) {
bc99f6da 1331+ if (strcmp(text, WelcomeText(namearray)) == 0) { /* use strcmp because the user may wish to change case */
c13e4602 1332+ sendcmdto_one(&me, CMD_NOTICE, sptr,
5a15ece2 1333+ "%C :Welcome: Cannot change %s message for %s - nothing to change",
c13e4602 1334+ sptr, (flags & WELCOME_LOCAL) ? "local" : "global", name);
b27ac6fc 1335+ return 0;
1336+ }
c13e4602 1337+ }
1338+ }
1339+
4fef2533 1340+ /* do not insert for last global/local entry and when not set yet */
98143e8a 1341+ if ((flags & WELCOME_INSERT) &&
1342+ ((!WelcomeIsSet(namearray)) || (nameint == WELCOME_MAX_ENTRIES)))
d9e2917e 1343+ flags &= ~WELCOME_INSERT;
4fef2533 1344+
c13e4602 1345+ /* unset */
1346+ if (EmptyString(text)) {
4fef2533 1347+ /* clear insert flag,
b34e1931 1348+ * when this flag is set, welcome_unset() assumes it is being called from welcome_insert()
4fef2533 1349+ * and wont propagate the change
1350+ */
c13e4602 1351+ flags &= ~WELCOME_INSERT;
1352+ return welcome_unset(cptr, sptr, nameint, namearray, timestamp, who, flags);
1353+ }
1354+
1355+ /* insert */
1356+ if (flags & WELCOME_INSERT)
1357+ return welcome_insert(cptr, sptr, nameint, namearray, timestamp, who, text, flags);
1358+
1359+ /* new or change */
1360+ return welcome_set(cptr, sptr, nameint, namearray, timestamp, who, text, flags);
1361+}
1362+
1363+
a87bc2c2 1364+/** Send the full list of welcome message to \a cptr.
1365+ * @param[in] cptr Local server to send welcomes to.
cddf800b 1366+ */
1367+void
a87bc2c2 1368+welcome_burst(struct Client *cptr)
cddf800b 1369+{
cb0b5df1 1370+ int name;
a87bc2c2 1371+
6dd3e24f 1372+ assert(NULL != cptr);
1373+
cb0b5df1 1374+ /* loop over global entries - 0 to max - 1*/
1375+ for (name = 0; name <= WELCOME_MAX_ENTRIES - 1; name++) {
eabbc644 1376+ if (WelcomeIsSet(name))
a87bc2c2 1377+ sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %s :%s",
6eab3e57 1378+ name + 1, WelcomeTS(name), WelcomeWho(name), WelcomeText(name));
cddf800b 1379+ }
1380+}
1381+
a87bc2c2 1382+
a87bc2c2 1383+/** List welcome messages.
1384+ * @param[in] sptr Client requesting the listing.
1385+ * @param[in] connect When non zero do not report no welcome is set
cddf800b 1386+ * @return Zero.
1387+ */
1388+int
a87bc2c2 1389+welcome_list(struct Client *sptr, int connect)
cddf800b 1390+{
cb0b5df1 1391+ int found = 0, local = 0, name;
a87bc2c2 1392+
6dd3e24f 1393+ assert(NULL != sptr);
1394+
cb0b5df1 1395+ /* loop over all entries - range 0 to 2 * max - 1 */
1396+ for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
a87bc2c2 1397+
cb0b5df1 1398+ /* local entries now */
1399+ if (name == WELCOME_MAX_ENTRIES)
1400+ local = 1;
a87bc2c2 1401+
cb0b5df1 1402+ /* not set or empty - skip */
eabbc644 1403+ if (!WelcomeIsSet(name) || WelcomeIsEmpty(name))
a87bc2c2 1404+ continue;
cb0b5df1 1405+
1406+ /* got one */
a87bc2c2 1407+ found++;
cb0b5df1 1408+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :[%s] %s",
6eab3e57 1409+ sptr, local ? cli_name(&me) : feature_str(FEAT_NETWORK), WelcomeText(name));
a87bc2c2 1410+ }
cb0b5df1 1411+
1412+ /* nothing set */
a87bc2c2 1413+ if (!found && !connect)
cb0b5df1 1414+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :No welcome message set.", sptr);
1415+
a87bc2c2 1416+ return 0;
1417+}
cddf800b 1418+
cddf800b 1419+
a87bc2c2 1420+/** Statistics callback to list Welcome messages.
1421+ * @param[in] sptr Client requesting statistics.
1422+ * @param[in] sd Stats descriptor for request (ignored).
1423+ * @param[in] param Extra parameter from user (ignored).
1424+ */
1425+void
1426+welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param)
1427+{
cb0b5df1 1428+ int name, local = 0;
a87bc2c2 1429+
6dd3e24f 1430+ assert(NULL != sptr);
1431+
cb0b5df1 1432+ /* loop over all entries - range 0 to 2 * max - 1*/
1433+ for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
cddf800b 1434+
cb0b5df1 1435+ /* local entries now */
1436+ if (name == WELCOME_MAX_ENTRIES)
1437+ local = 1;
a87bc2c2 1438+
cb0b5df1 1439+ /* not set */
eabbc644 1440+ if (!WelcomeIsSet(name))
cb0b5df1 1441+ continue;
cddf800b 1442+
cb0b5df1 1443+ /* send it */
1444+ send_reply(sptr, RPL_STATSWELCOME,
6dd3e24f 1445+ local ? name + 1 - WELCOME_MAX_ENTRIES : name + 1,
1446+ local ? cli_name(&me) : "*",
6eab3e57 1447+ WelcomeWho(name), WelcomeTS(name),
1448+ WelcomeIsEmpty(name) ? "<Empty>" : WelcomeText(name));
cddf800b 1449+ }
cddf800b 1450+}
5736cfdb 1451+
1452+
1453+/** Count welcome messages and memory used by them.
1454+ * @param[out] we_size Receives total number of bytes allocated for welcomes.
1455+ * @return Number of welcome messages currently allocated.
1456+ */
1457+int
1458+welcome_memory_count(size_t *we_size)
1459+{
1460+ int name;
1461+ unsigned int we = 0;
1462+
1463+ for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
1464+ if (!WelcomeIsSet(name))
1465+ continue;
1466+ we++;
1467+ *we_size += WelcomeText(name) ? (strlen(WelcomeText(name)) + 1) : 0;
1468+ *we_size += WelcomeWho(name) ? (strlen(WelcomeWho(name)) + 1) : 0;
1469+ }
1470+ return we;
1471+}