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