]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blame - welcome.patch
Update patchset for latest ircu changes
[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
e721b9bb 80diff -r 0e1d8ae7ca15 include/client.h
81--- a/include/client.h Sun Feb 15 16:04:36 2009 +0100
82+++ b/include/client.h Sun Feb 15 16:05:56 2009 +0100
dcd0ea31 83@@ -149,6 +149,8 @@
84 PRIV_GLINE_LOOKUP, /* staff can use /GLINE to lookup a gline */
85 PRIV_HIDE_CHANS, /* oper can set usermode +n */
86 PRIV_CHECK_CHANNEL, /* staff can /CHECK #channel */
4e89d808 87+ PRIV_WELCOME, /* oper can WELCOME */
88+ PRIV_LOCAL_WELCOME, /* oper can local WELCOME */
89 PRIV_LAST_PRIV /**< number of privileges */
90 };
91
e721b9bb 92diff -r 0e1d8ae7ca15 include/handlers.h
93--- a/include/handlers.h Sun Feb 15 16:04:36 2009 +0100
94+++ b/include/handlers.h Sun Feb 15 16:05:56 2009 +0100
dcd0ea31 95@@ -154,6 +154,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*[]);
dcd0ea31 103@@ -189,6 +190,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*[]);
108 extern int mr_error(struct Client*, struct Client*, int, char*[]);
109 extern int mr_error(struct Client*, struct Client*, int, char*[]);
110 extern int mr_pong(struct Client*, struct Client*, int, char*[]);
dcd0ea31 111@@ -247,6 +249,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*[]);
117
a87bc2c2 118 extern int mh_nohelp(struct Client*, struct Client*, int, char*[]);
dcd0ea31 119@@ -313,6 +316,7 @@
a87bc2c2 120 extern int mh_wallops(struct Client*, struct Client*, int, char*[]);
121 extern int mh_wallusers(struct Client*, struct Client*, int, char*[]);
122 extern int mh_wallvoices(struct Client*, struct Client*, int, char*[]);
123+extern int mh_welcome(struct Client*, struct Client*, int, char*[]);
124 extern int mh_who(struct Client*, struct Client*, int, char*[]);
125 extern int mh_whois(struct Client*, struct Client*, int, char*[]);
126 extern int mh_whowas(struct Client*, struct Client*, int, char*[]);
e721b9bb 127diff -r 0e1d8ae7ca15 include/ircd_features.h
128--- a/include/ircd_features.h Sun Feb 15 16:04:36 2009 +0100
129+++ b/include/ircd_features.h Sun Feb 15 16:05:56 2009 +0100
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,
138@@ -143,6 +144,7 @@
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,
e721b9bb 146diff -r 0e1d8ae7ca15 include/msg.h
147--- a/include/msg.h Sun Feb 15 16:04:36 2009 +0100
148+++ b/include/msg.h Sun Feb 15 16:05:56 2009 +0100
dcd0ea31 149@@ -200,6 +200,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
e721b9bb 160diff -r 0e1d8ae7ca15 include/numeric.h
161--- a/include/numeric.h Sun Feb 15 16:04:36 2009 +0100
162+++ b/include/numeric.h Sun Feb 15 16:05:56 2009 +0100
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 */
169 #define RPL_STATSHEADER 230 /* QuakeNet extension */
170
cb0b5df1 171@@ -445,6 +446,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 */
e721b9bb 180diff -r 0e1d8ae7ca15 include/welcome.h
cddf800b 181--- /dev/null Thu Jan 01 00:00:00 1970 +0000
e721b9bb 182+++ b/include/welcome.h Sun Feb 15 16:05:56 2009 +0100
6dd3e24f 183@@ -0,0 +1,60 @@
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+ */
209+#ifndef INCLUDED_sys_types_h
210+#include <sys/types.h>
211+#define INCLUDED_sys_types_h
212+#endif
213+
a87bc2c2 214+struct Client;
215+struct StatDesc;
216+
cb0b5df1 217+/* Maximum number of welcome entries (per type; X global, X local) */
6dd3e24f 218+#define WELCOME_MAX_ENTRIES 10
219+/* Maximum timestamp drift in seconds allowed ahead of our idea of nettime
220+ * before we throw a warning to ops
221+ */
222+#define WELCOME_MAX_DRIFT 600
a87bc2c2 223+
224+/* Describes a Welcome message entry. */
225+struct Welcome {
6dd3e24f 226+ time_t timestamp; /**< Timestamp of the welcome */
227+ char text[TOPICLEN + 1]; /**< Message */
228+ char who[ACCOUNTLEN + 1]; /**< Who set it */
a87bc2c2 229+};
230+
cb0b5df1 231+/** Welcome type flags */
a87bc2c2 232+#define WELCOME_LOCAL 0x01 /**< welcome is local */
233+/** Welcome action flags */
234+#define WELCOME_ANNOUNCE 0x02 /**< announce change to users */
235+
a87bc2c2 236+extern int welcome_do(struct Client *cptr, struct Client *sptr, char *name, char *text,
237+ char *who, time_t timestamp, unsigned int flags);
cb0b5df1 238+extern void welcome_announce(int name);
cddf800b 239+extern void welcome_burst(struct Client *cptr);
a87bc2c2 240+extern int welcome_list(struct Client *sptr, int connect);
241+extern void welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param);
cddf800b 242+
243+#endif /* INCLUDED_welcome_h */
e721b9bb 244diff -r 0e1d8ae7ca15 ircd/Makefile.in
245--- a/ircd/Makefile.in Sun Feb 15 16:04:36 2009 +0100
246+++ b/ircd/Makefile.in Sun Feb 15 16:05:56 2009 +0100
dcd0ea31 247@@ -188,6 +188,7 @@
a87bc2c2 248 m_wallops.c \
249 m_wallusers.c \
250 m_wallvoices.c \
251+ m_welcome.c \
252 m_who.c \
253 m_whois.c \
254 m_whowas.c \
dcd0ea31 255@@ -215,6 +216,7 @@
a87bc2c2 256 send.c \
257 uping.c \
258 userload.c \
259+ welcome.c \
260 whocmds.c \
261 whowas.c \
262 y.tab.c
dcd0ea31 263@@ -1180,6 +1182,11 @@
a87bc2c2 264 ../include/ircd_reply.h ../include/ircd_string.h \
265 ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
266 ../include/numnicks.h ../include/s_user.h ../include/send.h
267+m_welcome.o: m_welcome.c ../config.h ../include/channel.h \
268+ ../include/client.h ../include/hash.h ../include/ircd.h ../include/ircd_log.h \
269+ ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
270+ ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
271+ ../include/send.h ../include/welcome.h
272 m_who.o: m_who.c ../config.h ../include/channel.h ../include/ircd_defs.h \
273 ../include/res.h ../config.h ../include/client.h ../include/dbuf.h \
274 ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
dcd0ea31 275@@ -1441,6 +1448,13 @@
a87bc2c2 276 ../include/numnicks.h ../include/querycmds.h ../include/ircd_features.h \
277 ../include/s_misc.h ../include/s_stats.h ../include/send.h \
278 ../include/struct.h ../include/sys.h
279+welcome.o: welcome.c ../config.h ../include/client.h \
280+ ../include/hash.h ../include/ircd.h ../include/ircd_alloc.h \
281+ ../include/ircd_features.h ../include/ircd_log.h ../include/ircd_reply.h \
282+ ../include/match.h ../include/msg.h ../include/numeric.h \
283+ ../include/numnicks.h ../include/s_debug.h ../include/s_bsd.h \
284+ ../include/s_misc.h ../include/send.h ../include/struct.h \
285+ ../include/sys.h ../include/welcome.h
286 whocmds.o: whocmds.c ../config.h ../include/whocmds.h \
287 ../include/channel.h ../include/ircd_defs.h ../include/res.h \
288 ../config.h ../include/client.h ../include/dbuf.h ../include/msgq.h \
e721b9bb 289diff -r 0e1d8ae7ca15 ircd/client.c
290--- a/ircd/client.c Sun Feb 15 16:04:36 2009 +0100
291+++ b/ircd/client.c Sun Feb 15 16:05:56 2009 +0100
dcd0ea31 292@@ -184,6 +184,7 @@
4e89d808 293 FlagSet(&privs_local, PRIV_WHOX);
294 FlagSet(&privs_local, PRIV_DISPLAY);
295 FlagSet(&privs_local, PRIV_FORCE_LOCAL_OPMODE);
296+ FlagSet(&privs_local, PRIV_LOCAL_WELCOME);
dcd0ea31 297 FlagClr(&privs_local, PRIV_STAFF);
298 FlagClr(&privs_local, PRIV_CLAIM_NICK);
299 FlagClr(&privs_local, PRIV_GLINE_LOOKUP);
e721b9bb 300@@ -247,6 +248,7 @@
4e89d808 301 ClrPriv(client, PRIV_OPMODE);
302 ClrPriv(client, PRIV_OPKICK);
303 ClrPriv(client, PRIV_BADCHAN);
304+ ClrPriv(client, PRIV_WELCOME);
305 }
e721b9bb 306 /* TODO: better way than this? */
307 /* do not let staff have privs they should not have */
308@@ -283,6 +285,7 @@
4e89d808 309 P(USER_PRIVACY),
dcd0ea31 310 P(STAFF), P(CLAIM_NICK), P(GLINE_LOOKUP), P(HIDE_CHANS),
311 P(CHECK_CHANNEL),
4e89d808 312+ P(WELCOME), P(LOCAL_WELCOME),
313 #undef P
314 { 0, 0 }
315 };
e721b9bb 316diff -r 0e1d8ae7ca15 ircd/ircd_features.c
317--- a/ircd/ircd_features.c Sun Feb 15 16:04:36 2009 +0100
318+++ b/ircd/ircd_features.c Sun Feb 15 16:05:56 2009 +0100
319@@ -366,6 +366,7 @@
a87bc2c2 320 F_I(IRCD_RES_TIMEOUT, 0, 4, 0),
321 F_I(AUTH_TIMEOUT, 0, 9, 0),
322 F_B(ANNOUNCE_INVITES, 0, 0, 0),
323+ F_B(WELCOME, 0, 1, 0),
324
325 /* features that affect all operators */
326 F_B(EXTENDED_CHECKCMD, 0, 0, 0),
e721b9bb 327@@ -408,6 +409,7 @@
a87bc2c2 328 F_B(HIS_STATS_u, 0, 1, 0),
329 F_B(HIS_STATS_U, 0, 1, 0),
330 F_B(HIS_STATS_v, 0, 1, 0),
331+ F_B(HIS_STATS_W, 0, 1, 0),
332 F_B(HIS_STATS_w, 0, 1, 0),
333 F_B(HIS_STATS_x, 0, 1, 0),
334 F_B(HIS_STATS_y, 0, 1, 0),
e721b9bb 335diff -r 0e1d8ae7ca15 ircd/ircd_lexer.l
336--- a/ircd/ircd_lexer.l Sun Feb 15 16:04:36 2009 +0100
337+++ b/ircd/ircd_lexer.l Sun Feb 15 16:05:56 2009 +0100
dcd0ea31 338@@ -173,6 +173,8 @@
339 { "gline_lookup", TPRIV_GLINE_LOOKUP },
340 { "hide_chans", TPRIV_HIDE_CHANS },
341 { "check_channel", TPRIV_CHECK_CHANNEL },
4e89d808 342+ { "local_welcome", TPRIV_LOCAL_WELCOME },
343+ { "welcome", TPRIV_WELCOME },
344 { NULL, 0 }
345 };
346 static int ntokens;
e721b9bb 347diff -r 0e1d8ae7ca15 ircd/ircd_parser.y
348--- a/ircd/ircd_parser.y Sun Feb 15 16:04:36 2009 +0100
349+++ b/ircd/ircd_parser.y Sun Feb 15 16:05:56 2009 +0100
dcd0ea31 350@@ -192,6 +192,7 @@
351 %token TPRIV_CHANNEL_PRIVACY TPRIV_USER_PRIVACY TPRIV_LIST_CHAN
352 %token TPRIV_STAFF TPRIV_CLAIM_NICK TPRIV_GLINE_LOOKUP TPRIV_HIDE_CHANS
353 %token TPRIV_CHECK_CHANNEL
354+%token TPRIV_LOCAL_WELCOME TPRIV_WELCOME
4e89d808 355 /* and some types... */
356 %type <num> sizespec
357 %type <num> timespec timefactor factoredtimes factoredtime
e721b9bb 358@@ -715,6 +716,8 @@
dcd0ea31 359 TPRIV_GLINE_LOOKUP { $$ = PRIV_GLINE_LOOKUP; } |
360 TPRIV_CHECK_CHANNEL { $$ = PRIV_CHECK_CHANNEL; } |
361 TPRIV_HIDE_CHANS { $$ = PRIV_HIDE_CHANS; } |
4e89d808 362+ TPRIV_LOCAL_WELCOME { $$ = PRIV_LOCAL_WELCOME; } |
363+ TPRIV_WELCOME { $$ = PRIV_WELCOME; } |
364 TPRIV_PARANOID { $$ = PRIV_PARANOID; } ;
365 yesorno: YES { $$ = 1; } | NO { $$ = 0; };
366
e721b9bb 367diff -r 0e1d8ae7ca15 ircd/m_welcome.c
cddf800b 368--- /dev/null Thu Jan 01 00:00:00 1970 +0000
e721b9bb 369+++ b/ircd/m_welcome.c Sun Feb 15 16:05:56 2009 +0100
4e89d808 370@@ -0,0 +1,308 @@
cddf800b 371+/*
372+ * IRC - Internet Relay Chat, ircd/m_welcome.c
373+ * Copyright (C) 1990 Jarkko Oikarinen and
374+ * University of Oulu, Computing Center
375+ *
376+ * See file AUTHORS in IRC package for additional names of
377+ * the programmers.
378+ *
379+ * This program is free software; you can redistribute it and/or modify
380+ * it under the terms of the GNU General Public License as published by
381+ * the Free Software Foundation; either version 1, or (at your option)
382+ * any later version.
383+ *
384+ * This program is distributed in the hope that it will be useful,
385+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
386+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
387+ * GNU General Public License for more details.
388+ *
389+ * You should have received a copy of the GNU General Public License
390+ * along with this program; if not, write to the Free Software
391+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
392+ *
cddf800b 393+ */
394+
395+/*
396+ * m_functions execute protocol messages on this server:
397+ *
398+ * cptr is always NON-NULL, pointing to a *LOCAL* client
399+ * structure (with an open socket connected!). This
400+ * identifies the physical socket where the message
401+ * originated (or which caused the m_function to be
402+ * executed--some m_functions may call others...).
403+ *
404+ * sptr is the source of the message, defined by the
405+ * prefix part of the message if present. If not
406+ * or prefix not found, then sptr==cptr.
407+ *
408+ * (!IsServer(cptr)) => (cptr == sptr), because
409+ * prefixes are taken *only* from servers...
410+ *
411+ * (IsServer(cptr))
412+ * (sptr == cptr) => the message didn't
413+ * have the prefix.
414+ *
415+ * (sptr != cptr && IsServer(sptr) means
416+ * the prefix specified servername. (?)
417+ *
418+ * (sptr != cptr && !IsServer(sptr) means
419+ * that message originated from a remote
420+ * user (not local).
421+ *
422+ * combining
423+ *
424+ * (!IsServer(sptr)) means that, sptr can safely
425+ * taken as defining the target structure of the
426+ * message in this server.
427+ *
428+ * *Always* true (if 'parse' and others are working correct):
429+ *
430+ * 1) sptr->from == cptr (note: cptr->from == cptr)
431+ *
432+ * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
433+ * *cannot* be a local connection, unless it's
434+ * actually cptr!). [MyConnect(x) should probably
435+ * be defined as (x == x->from) --msa ]
436+ *
437+ * parc number of variable parameter strings (if zero,
438+ * parv is allowed to be NULL)
439+ *
440+ * parv a NULL terminated list of parameter pointers,
441+ *
442+ * parv[0], sender (prefix string), if not present
443+ * this points to an empty string.
444+ * parv[1]...parv[parc-1]
445+ * pointers to additional parameters
446+ * parv[parc] == NULL, *always*
447+ *
448+ * note: it is guaranteed that parv[0]..parv[parc-1] are all
449+ * non-NULL pointers.
450+ */
451+#include "config.h"
452+
453+#include "channel.h"
454+#include "client.h"
455+#include "hash.h"
456+#include "ircd.h"
a87bc2c2 457+#include "ircd_features.h"
cddf800b 458+#include "ircd_log.h"
459+#include "ircd_reply.h"
5bb41778 460+#include "ircd_snprintf.h"
cddf800b 461+#include "ircd_string.h"
462+#include "msg.h"
463+#include "numeric.h"
464+#include "numnicks.h"
465+#include "s_user.h"
466+#include "send.h"
a87bc2c2 467+#include "welcome.h"
cddf800b 468+
469+/* #include <assert.h> -- Now using assert in ircd_log.h */
470+
471+/*
472+ * m_welcome - local generic message handler
473+ *
474+ * parv[0] = Send prefix
6dd3e24f 475+ * parv[1] = [remote server to query]
cddf800b 476+ */
477+int m_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
478+{
a87bc2c2 479+ /* feature disabled */
480+ if (!feature_bool(FEAT_WELCOME))
481+ return send_reply(sptr, ERR_DISABLED, "WELCOME");
6dd3e24f 482+
483+ /* only opers can set the welcome messages */
484+ if (parc > 2)
485+ return send_reply(sptr, ERR_NOPRIVILEGES);
486+
487+ /* remote listing request, see if it is for me or a remote server
488+ * check FEAT_HIS_REMOTE to decide if an ordinary user can do this
489+ */
490+ if (parc == 2) {
491+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, feature_int(FEAT_HIS_REMOTE),
492+ "%C", 1, parc, parv) != HUNTED_ISME)
493+ return 0;
494+ return welcome_list(sptr, 0);
495+ }
496+
497+ /* just local listing */
a87bc2c2 498+ return welcome_list(sptr, 0);
cddf800b 499+}
500+
501+
502+/*
503+ * mo_welcome - oper message handler
504+ *
505+ * listing:
506+ * parv[0] = Send prefix
507+ *
508+ * remote listing:
509+ * parv[0] = Send prefix
510+ * parv[1] = Target
511+ *
512+ * set global or on remote server:
513+ * parv[0] = Send prefix
6dd3e24f 514+ * parv[1] = Target: server or * for global (or left out for this server)
a87bc2c2 515+ * parv[2] = Name
516+ * parv[3] = Text
cddf800b 517+ */
518+int mo_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
519+{
cb0b5df1 520+ char *target, *name, *who, *text, pattern[BUFSIZE];
a87bc2c2 521+ time_t timestamp;
522+ unsigned int flags = 0;
6dd3e24f 523+ int local = 0;
a87bc2c2 524+
525+ /* feature disabled */
526+ if (!feature_bool(FEAT_WELCOME))
527+ return send_reply(sptr, ERR_DISABLED, "WELCOME");
528+
529+ /* listing */
530+ if (parc < 2)
531+ return welcome_list(sptr, 0);
532+
4e89d808 533+ /* TODO: move feature check here? */
a87bc2c2 534+ /* remote listing request, see if it is for me or a remote server */
535+ if (parc == 2) {
536+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME)
537+ return 0;
538+ return welcome_list(sptr, 0);
539+ }
4e89d808 540+
541+ /* check PRIVS */
542+ /* local - need PRIV LOCAL_WELCOME or WELCOME */
543+ if (parc == 3 && !HasPriv(sptr,PRIV_LOCAL_WELCOME) && !HasPriv(sptr,PRIV_WELCOME))
544+ return send_reply(sptr, ERR_NOPRIVILEGES);
545+
546+ /* global or remote - need PRIV WELCOME */
547+ if (parc >= 4 && !HasPriv(sptr,PRIV_WELCOME))
548+ return send_reply(sptr, ERR_NOPRIVILEGES);
549+
a87bc2c2 550+ /* set the parameters */
6dd3e24f 551+
552+ /* target not given, only name - setting local welcome */
a87bc2c2 553+ if (parc < 4) {
554+ local++;
555+ target = cli_name(&me);
556+ name = parv[1];
557+ flags |= WELCOME_LOCAL;
6dd3e24f 558+
559+ /* target and name given */
560+ } else {
a87bc2c2 561+ target = parv[1];
562+ name = parv[2];
563+ }
564+ timestamp = TStime();
565+ who = cli_user(sptr)->opername;
566+ text = parv[parc - 1];
567+
568+ /* target is not global */
569+ if (!(target[0] == '*' && target[1] == '\0') && !local) {
6dd3e24f 570+
a87bc2c2 571+ /* build a pattern for hunt_server_cmd since we do not have all we need in parv */
572+ ircd_snprintf(0, pattern, sizeof(pattern), "%s %s %Tu %s :%s", "%C", name, timestamp, who, text);
573+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, pattern, 1, 2, parv) != HUNTED_ISME)
574+ return 0;
6dd3e24f 575+
576+ /* else it is a local welcome, for me */
577+ flags |= WELCOME_LOCAL;
a87bc2c2 578+ }
579+
cb0b5df1 580+ /* TODO: disallow global announcement from oper?
581+ * as PRIVMSG/NOTICE to $* is not allowed either by the ircd
582+ * when PRIV for that is added, use that here? PRIV_BROADCAST or something
4e89d808 583+ *
584+ * change prefix to $ ?
cb0b5df1 585+ */
a87bc2c2 586+ /* check for anounce prefix */
587+ if (*name == '!') {
588+ name++;
589+ flags |= WELCOME_ANNOUNCE;
590+ }
591+
592+ /* and do it */
593+ return welcome_do(cptr, sptr, name, text, who, timestamp, flags);
cddf800b 594+}
595+
596+
597+/*
598+ * ms_welcome - server message handler
599+ *
600+ * parv[0] = Send prefix
601+ * parv[1] = Target: server numeric or * for global
a87bc2c2 602+ * parv[2] = Name
603+ * parv[3] = Timestamp
604+ * parv[4] = Who
605+ * parv[5] = Text
cddf800b 606+ */
607+int ms_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
608+{
cb0b5df1 609+ char *target, *name, *who, *text;
a87bc2c2 610+ time_t timestamp;
611+ unsigned int flags = 0;
612+
6dd3e24f 613+ /* not enough - complain */
614+ if (parc < 2) {
615+ protocol_violation(sptr, "Too few parameters for WELCOME (got %d - need 2)", parc);
a87bc2c2 616+ return need_more_params(sptr, "WELCOME");
6dd3e24f 617+ }
a87bc2c2 618+
619+ /* remote listing request, see if it is for me or a remote server */
620+ if (parc == 2) {
6dd3e24f 621+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME)
622+ return 0;
623+ return welcome_list(sptr, 0);
a87bc2c2 624+ }
625+
6dd3e24f 626+ /* we need at least 6 parameters to continue - complain */
627+ if (parc < 6) {
628+ protocol_violation(sptr, "Too few parameters for WELCOME (got %d - need 6)", parc);
a87bc2c2 629+ return need_more_params(sptr, "WELCOME");
6dd3e24f 630+ }
a87bc2c2 631+
632+ /* set the parameters */
633+ target = parv[1];
634+ name = parv[2];
635+ timestamp = atoi(parv[3]);
636+ who = parv[4];
6dd3e24f 637+ text = parv[parc - 1]; /* parse reason as last parameter */
a87bc2c2 638+
639+ /* target is not global */
640+ if (!(target[0] == '*' && target[1] == '\0')) {
6dd3e24f 641+
a87bc2c2 642+ /* not for me, and forward it */
643+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C %s %s %s :%s", 1, parc, parv) != HUNTED_ISME)
644+ return 0;
6dd3e24f 645+
646+ /* local welcome for me */
647+ flags |= WELCOME_LOCAL;
a87bc2c2 648+ }
649+
650+ /* check for anounce prefix */
651+ if (*name == '!') {
652+ name++;
653+ flags |= WELCOME_ANNOUNCE;
654+ }
655+
656+ /* and do it */
657+ return welcome_do(cptr, sptr, name, text, who, timestamp, flags);
658+}
659+
660+
661+/*
662+ * mh_welcome - help message handler
663+ */
664+int mh_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
665+{
666+ if (!IsAnOper(sptr)) {
667+ send_reply(sptr, SND_EXPLICIT | RPL_HELP,
668+ "WELCOME :WELCOME");
669+ send_reply(sptr, SND_EXPLICIT | RPL_HELP,
670+ "WELCOME :Shows welcome messages set on the server.");
671+ } else {
672+ send_reply(sptr, SND_EXPLICIT | RPL_HELP,
673+ "WELCOME :WELCOME [<target>] [[!]<name> :<message>]");
674+ send_reply(sptr, SND_EXPLICIT | RPL_HELP,
675+ "WELCOME :Shows or sets welcome messages on a server.");
676+ }
cddf800b 677+ return 0;
678+}
e721b9bb 679diff -r 0e1d8ae7ca15 ircd/parse.c
680--- a/ircd/parse.c Sun Feb 15 16:04:36 2009 +0100
681+++ b/ircd/parse.c Sun Feb 15 16:05:56 2009 +0100
dcd0ea31 682@@ -674,6 +674,15 @@
a87bc2c2 683 /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */
684 { m_unregistered, m_not_oper, ms_opkick, mo_opkick, m_ignore, mh_nohelp }
cddf800b 685 },
686+
687+ /* add command for WELCOME */
688+ {
689+ MSG_WELCOME,
690+ TOK_WELCOME,
691+ 0, MAXPARA, MFLG_SLOW, 0, NULL,
a87bc2c2 692+ /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */
693+ { m_unregistered, m_welcome, ms_welcome, mo_welcome, m_ignore, mh_welcome }
cddf800b 694+ },
695
696 /* This command is an alias for QUIT during the unregistered part of
697 * of the server. This is because someone jumping via a broken web
e721b9bb 698diff -r 0e1d8ae7ca15 ircd/s_err.c
699--- a/ircd/s_err.c Sun Feb 15 16:04:36 2009 +0100
700+++ b/ircd/s_err.c Sun Feb 15 16:05:56 2009 +0100
a87bc2c2 701@@ -486,7 +486,7 @@
702 /* 226 */
703 { RPL_STATSALINE, "%s", "226" },
704 /* 227 */
705- { 0 },
706+ { RPL_STATSWELCOME, "W %d %s %s %Tu :%s", "227" },
707 /* 228 */
708 { RPL_STATSQLINE, "Q %s :%s", "228" },
709 /* 229 */
710@@ -1050,7 +1050,7 @@
711 /* 508 */
712 { 0 },
713 /* 509 */
714- { 0 },
715+ { ERR_NOSUCHWELCOME, "%s :No such welcome", "509" },
716 /* 510 */
717 { 0 },
718 /* 511 */
e721b9bb 719diff -r 0e1d8ae7ca15 ircd/s_serv.c
720--- a/ircd/s_serv.c Sun Feb 15 16:04:36 2009 +0100
721+++ b/ircd/s_serv.c Sun Feb 15 16:05:56 2009 +0100
a87bc2c2 722@@ -57,6 +57,7 @@
723 #include "struct.h"
724 #include "sys.h"
725 #include "userload.h"
726+#include "welcome.h"
727
728 /* #include <assert.h> -- Now using assert in ircd_log.h */
729 #include <stdlib.h>
730@@ -196,6 +197,7 @@
731 */
732 gline_burst(cptr);
733 jupe_burst(cptr);
734+ welcome_burst(cptr);
735
736 /*
737 * Pass on my client information to the new server
e721b9bb 738diff -r 0e1d8ae7ca15 ircd/s_stats.c
739--- a/ircd/s_stats.c Sun Feb 15 16:04:36 2009 +0100
740+++ b/ircd/s_stats.c Sun Feb 15 16:05:56 2009 +0100
a87bc2c2 741@@ -54,6 +54,7 @@
742 #include "send.h"
743 #include "struct.h"
744 #include "userload.h"
745+#include "welcome.h"
746
747 #include <stdio.h>
748 #include <stdlib.h>
e721b9bb 749@@ -691,9 +692,12 @@
a87bc2c2 750 { 'V', "vserversmach", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_v,
751 stats_servers_verbose, 0,
752 "Verbose server information." },
753- { 'w', "userload", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
754+ { 'w', "userload", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_w,
755 calc_load, 0,
756 "Userload statistics." },
757+ { 'W', "welcome", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_W,
758+ welcome_stats, 0,
759+ "Welcome messages." },
760 { 'x', "memusage", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
761 stats_meminfo, 0,
762 "List usage information." },
e721b9bb 763diff -r 0e1d8ae7ca15 ircd/s_user.c
764--- a/ircd/s_user.c Sun Feb 15 16:04:36 2009 +0100
765+++ b/ircd/s_user.c Sun Feb 15 16:05:56 2009 +0100
a87bc2c2 766@@ -63,6 +63,7 @@
767 #include "userload.h"
768 #include "version.h"
769 #include "whowas.h"
770+#include "welcome.h"
771
772 #include "handlers.h" /* m_motd and m_lusers */
773
dcd0ea31 774@@ -413,6 +414,9 @@
a87bc2c2 775 cli_info(sptr), NumNick(cptr) /* two %s's */);
776
777 IPcheck_connect_succeeded(sptr);
778+
779+ if (feature_bool(FEAT_WELCOME))
780+ welcome_list(sptr, 1);
781 }
782 else {
783 struct Client *acptr = user->server;
e721b9bb 784diff -r 0e1d8ae7ca15 ircd/welcome.c
cddf800b 785--- /dev/null Thu Jan 01 00:00:00 1970 +0000
e721b9bb 786+++ b/ircd/welcome.c Sun Feb 15 16:05:56 2009 +0100
6dd3e24f 787@@ -0,0 +1,373 @@
cddf800b 788+/*
a87bc2c2 789+ * IRC - Internet Relay Chat, ircd/welcome.c
cddf800b 790+ * Copyright (C) 1990 Jarkko Oikarinen and
791+ * University of Oulu, Finland
792+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
793+ *
794+ * This program is free software; you can redistribute it and/or modify
795+ * it under the terms of the GNU General Public License as published by
796+ * the Free Software Foundation; either version 1, or (at your option)
797+ * any later version.
798+ *
799+ * This program is distributed in the hope that it will be useful,
800+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
801+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
802+ * GNU General Public License for more details.
803+ *
804+ * You should have received a copy of the GNU General Public License
805+ * along with this program; if not, write to the Free Software
806+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
807+ */
808+/** @file
a87bc2c2 809+ * @brief Implementation of welcome message handling functions.
cddf800b 810+ */
811+#include "config.h"
812+
813+#include "client.h"
814+#include "hash.h"
815+#include "ircd.h"
816+#include "ircd_alloc.h"
817+#include "ircd_features.h"
818+#include "ircd_log.h"
819+#include "ircd_reply.h"
820+#include "ircd_string.h"
821+#include "match.h"
822+#include "msg.h"
823+#include "numeric.h"
824+#include "numnicks.h"
825+#include "s_bsd.h"
a87bc2c2 826+#include "s_debug.h"
cddf800b 827+#include "s_misc.h"
828+#include "send.h"
829+#include "struct.h"
830+#include "sys.h" /* FALSE bleah */
831+#include "welcome.h"
832+
833+/* #include <assert.h> -- Now using assert in ircd_log.h */
834+#include <string.h>
835+
cddf800b 836+
cb0b5df1 837+/** List of welcome messages - first MAX for global, second MAX for local */
6dd3e24f 838+static struct Welcome WelcomeArray[WELCOME_MAX_ENTRIES * 2] = { { 0 } };
cddf800b 839+
cddf800b 840+
a87bc2c2 841+/** Allocate a new welcome with the given parameters.
842+ * @param[in] name Name of the welcome message.
843+ * @param[in] text The welcome message.
844+ * @param[in] who Who set it.
845+ * @param[in] timestamp When it was set.
cb0b5df1 846+ * @return name Array number of the welcome set.
cddf800b 847+ */
cb0b5df1 848+static int
849+welcome_make(int name, char *text, char *who, time_t timestamp)
cddf800b 850+{
cb0b5df1 851+ /* range 0 to 2 * max - 1 */
852+ assert(name >= 0 && name <= 2 * WELCOME_MAX_ENTRIES - 1);
853+
854+ /* store it */
855+ ircd_strncpy(WelcomeArray[name].text, text, TOPICLEN);
856+ ircd_strncpy(WelcomeArray[name].who, who, ACCOUNTLEN);
857+ WelcomeArray[name].timestamp = timestamp;
858+
859+ return name;
cddf800b 860+}
861+
cddf800b 862+
a87bc2c2 863+/** Change a welcome message.
864+ * @param[in] cptr Local client that sent us the welcome.
865+ * @param[in] sptr Originator of the welcome.
866+ * @param[in] name Name of the message.
867+ * @param[in] text The welcome message.
868+ * @param[in] timestamp Timestamp of when the message was set.
869+ * @param[in] flags Flags to set on welcome.
870+ * @return Zero
cddf800b 871+ */
872+int
a87bc2c2 873+welcome_do(struct Client *cptr, struct Client *sptr, char *name, char *text,
874+ char *who, time_t timestamp, unsigned int flags)
cddf800b 875+{
cb0b5df1 876+ int nameint = atoi(name); /* transform to int */
877+ int namearray = nameint - 1; /* used to test the array element */
6dd3e24f 878+ char oldtext[TOPICLEN + 1]; /* save old text when unsetting */
879+ static time_t rate;
880+
881+ assert(NULL != cptr);
882+ assert(NULL != sptr);
883+ assert(NULL != name);
884+ assert(NULL != text);
885+ assert(NULL != who);
a87bc2c2 886+
cb0b5df1 887+ /* debug */
a87bc2c2 888+ Debug((DEBUG_DEBUG, "welcome_do(\"%s\", \"%s\", \"%s\", \"%s\" \"%s\", %Tu, 0x%04x)",
889+ cli_name(cptr), cli_name(sptr), name, text, who, timestamp, flags));
890+
891+ /* check name */
cb0b5df1 892+ if (nameint < 1 || nameint > WELCOME_MAX_ENTRIES) {
a87bc2c2 893+ if (IsUser(sptr))
894+ sendcmdto_one(&me, CMD_NOTICE, sptr,
895+ "%C :WELCOME: Invalid message number %s - should between 1 and %d",
896+ sptr, name, WELCOME_MAX_ENTRIES);
cddf800b 897+ return 0;
898+ }
899+
cb0b5df1 900+ /* correct namearray for local offset */
901+ if (flags & WELCOME_LOCAL)
902+ namearray += WELCOME_MAX_ENTRIES;
a87bc2c2 903+
904+ /* cannot unset welcome that is not set */
6dd3e24f 905+ if (WelcomeArray[namearray].timestamp == 0 && EmptyString(text)) {
906+
a87bc2c2 907+ /* from user, throw error */
908+ if (IsUser(sptr))
909+ return send_reply(sptr, ERR_NOSUCHWELCOME, name);
6dd3e24f 910+
911+ /* new local welcome from server, but empty - ignore
912+ * we do accept a new global welcome message that is empty
913+ */
a87bc2c2 914+ if (flags & WELCOME_LOCAL)
915+ return 0;
a87bc2c2 916+ }
cddf800b 917+
a87bc2c2 918+ /* check if there is something to change */
6dd3e24f 919+ /* we got a record for it */
920+ if (WelcomeArray[namearray].timestamp != 0) {
921+
922+ /* global */
923+ if (namearray < WELCOME_MAX_ENTRIES) {
924+
925+ /* netburst and we got the same or a newer one
926+ *
927+ * we only use the timestamp for resolving conflicts in net burst
928+ * outside of netburst, we simply parse whatever we get
929+ * this way we will not get stuck with a welcome message set by a server
930+ * running ahead with the time
931+ */
932+ if (IsBurstOrBurstAck(cptr) && timestamp <= WelcomeArray[namearray].timestamp)
a87bc2c2 933+ return 0;
6dd3e24f 934+
935+ /* local welcome - we use our idea of the time */
cb0b5df1 936+ } else
a87bc2c2 937+ timestamp = TStime();
cb0b5df1 938+
a87bc2c2 939+ /* compare new message with old message */
cb0b5df1 940+ if (ircd_strcmp(text, WelcomeArray[namearray].text) == 0) {
a87bc2c2 941+ if (IsUser(sptr))
942+ sendcmdto_one(&me, CMD_NOTICE, sptr,
cb0b5df1 943+ "%C :WELCOME: Cannot change %smessage for %s - nothing to change.",
944+ sptr, (flags & WELCOME_LOCAL) ? "local " : "", name);
a87bc2c2 945+ return 0;
946+ }
947+ }
cddf800b 948+
6dd3e24f 949+ /* TODO: rate limited for what? max 10 welcome messages..? */
950+ /* possible timestamp drift - warn ops */
951+ if (timestamp - TStime() > WELCOME_MAX_DRIFT) {
952+ sendto_opmask_butone_ratelimited(0, SNO_NETWORK, &rate,
953+ "Possible timestamp drift from %C; timestamp in WELCOME message is %is ahead of time",
954+ IsServer(sptr) ? sptr : cli_user(sptr)->server, timestamp - TStime());
955+
956+ /* warn remote oper too */
957+ if (IsUser(sptr))
958+ sendcmdto_one(&me, CMD_NOTICE, sptr,
959+ "%C :Possible timestamp drift from %C; timestamp in WELCOME message is %is ahead of time",
960+ sptr, cli_user(sptr)->server, timestamp - TStime());
961+ }
962+
963+ /* unsetting - do not announce, save text */
964+ if (EmptyString(text)) {
965+ flags &= ~WELCOME_ANNOUNCE;
966+ ircd_strncpy(oldtext, WelcomeArray[namearray].text, TOPICLEN);
967+ }
968+
cb0b5df1 969+ /* update */
970+ welcome_make(namearray, text, who, timestamp);
971+
cb0b5df1 972+ /* inform ops */
6dd3e24f 973+ sendto_opmask_butone(0, SNO_OLDSNO, "%s %s%s%sWELCOME %d \"%s\" [%Tu]",
a87bc2c2 974+ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
975+ get_client_name_and_opername(sptr) : cli_name((cli_user(sptr))->server),
6dd3e24f 976+ EmptyString(text) ? "unsetting" : "changing",
977+ (flags & WELCOME_ANNOUNCE) ? " and announcing " : " ",
978+ (flags & WELCOME_LOCAL) ? "local " : "",
979+ nameint,
980+ EmptyString(text) ? oldtext : WelcomeArray[namearray].text,
981+ WelcomeArray[namearray].timestamp);
a87bc2c2 982+
983+ /* log it */
6dd3e24f 984+ log_write(LS_NETWORK, L_INFO, LOG_NOSNOTICE, "%#C (%s) %s%s%sWELCOME %d \"%s\" [%Tu]",
985+ sptr, WelcomeArray[namearray].who,
986+ EmptyString(text) ? "unsetting" : "changing",
987+ (flags & WELCOME_ANNOUNCE) ? " and announcing " : " ",
988+ (flags & WELCOME_LOCAL) ? "local " : "",
989+ nameint,
990+ EmptyString(text) ? oldtext : WelcomeArray[namearray].text,
cb0b5df1 991+ WelcomeArray[namearray].timestamp);
a87bc2c2 992+
993+ /* welcome set by remote user, inform oper of success */
6dd3e24f 994+ if ((flags & WELCOME_LOCAL) && IsUser(sptr) && !MyUser(sptr)) {
995+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s%s local WELCOME %d \"%s\" [%Tu]",
996+ sptr, get_client_name_and_opername(sptr),
997+ EmptyString(text) ? "unsetting" : "changing",
998+ (flags & WELCOME_ANNOUNCE) ? " and announcing" : "",
999+ nameint,
1000+ EmptyString(text) ? oldtext : WelcomeArray[namearray].text,
1001+ WelcomeArray[namearray].timestamp);
1002+
1003+ /* TODO: wallops all local changes, by both local and remote opers? */
1004+ /* tell all opers about the local message being set remotely */
1005+ sendwallto_group_butone(&me, WALL_WALLOPS, 0,
1006+ "%s %s%s local WELCOME %d \"%s\" [%Tu]",
1007+ get_client_name_and_opername(sptr),
1008+ EmptyString(text) ? "unsetting" : "changing",
1009+ (flags & WELCOME_ANNOUNCE) ? " and announcing" : "",
1010+ nameint,
1011+ EmptyString(text) ? oldtext : WelcomeArray[namearray].text,
1012+ WelcomeArray[namearray].timestamp);
1013+ }
cddf800b 1014+
cb0b5df1 1015+ /* propagate it */
a87bc2c2 1016+ if (!(flags & WELCOME_LOCAL))
1017+ sendcmdto_serv_butone(sptr, CMD_WELCOME, cptr, "* %s%d %Tu %s :%s",
cb0b5df1 1018+ (flags & WELCOME_ANNOUNCE) ? "!" : "", nameint,
1019+ WelcomeArray[namearray].timestamp, WelcomeArray[namearray].who,
1020+ WelcomeArray[namearray].text);
cddf800b 1021+
a87bc2c2 1022+ /* announce it */
6dd3e24f 1023+ if (flags & WELCOME_ANNOUNCE)
cb0b5df1 1024+ welcome_announce(namearray);
a87bc2c2 1025+
1026+ return 0;
cddf800b 1027+}
1028+
a87bc2c2 1029+
1030+/** Announce a welcome message to local clients.
cb0b5df1 1031+ * @param[in] name Welcome message to announce.
cddf800b 1032+ */
a87bc2c2 1033+void
cb0b5df1 1034+welcome_announce(int name)
cddf800b 1035+{
a87bc2c2 1036+ struct Client *acptr;
1037+ struct MsgBuf *msgbuf;
6dd3e24f 1038+ int i;
a87bc2c2 1039+
cb0b5df1 1040+ /* range 0 to 2 * max - 1 */
1041+ assert(name >= 0 && name <= 2 * WELCOME_MAX_ENTRIES - 1);
a87bc2c2 1042+
cb0b5df1 1043+ /* TODO: target is $* as if it were a global broadcast
1044+ * could make it $servername for local message announcement
1045+ * but the type is shown between [ ] already
1046+ * either [Network] or [servername] - using $* is just shorter.
1047+ */
a87bc2c2 1048+ /* build msgbuf */
1049+ msgbuf = msgq_make(0, ":%C %s $* :[%s] %s", &me, MSG_NOTICE,
cb0b5df1 1050+ name >= WELCOME_MAX_ENTRIES ? cli_name(&me) : feature_str(FEAT_NETWORK),
1051+ WelcomeArray[name].text);
a87bc2c2 1052+
6dd3e24f 1053+ /* go over local clients */
1054+ for (i = HighestFd; i > 0; --i) {
cb0b5df1 1055+
6dd3e24f 1056+ /* skip unregistered clients - they see the message during login
1057+ * skip servers
a87bc2c2 1058+ */
6dd3e24f 1059+ if (!(acptr = LocalClientArray[i]) || !IsRegistered(acptr) || IsServer(acptr))
a87bc2c2 1060+ continue;
cb0b5df1 1061+
6dd3e24f 1062+ /* send it away */
a87bc2c2 1063+ send_buffer(acptr, msgbuf, 0);
cddf800b 1064+ }
cddf800b 1065+}
1066+
a87bc2c2 1067+
a87bc2c2 1068+/** Send the full list of welcome message to \a cptr.
1069+ * @param[in] cptr Local server to send welcomes to.
cddf800b 1070+ */
1071+void
a87bc2c2 1072+welcome_burst(struct Client *cptr)
cddf800b 1073+{
cb0b5df1 1074+ int name;
a87bc2c2 1075+
6dd3e24f 1076+ assert(NULL != cptr);
1077+
cb0b5df1 1078+ /* loop over global entries - 0 to max - 1*/
1079+ for (name = 0; name <= WELCOME_MAX_ENTRIES - 1; name++) {
1080+ if (WelcomeArray[name].timestamp != 0)
a87bc2c2 1081+ sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %s :%s",
cb0b5df1 1082+ name + 1, WelcomeArray[name].timestamp, WelcomeArray[name].who,
1083+ WelcomeArray[name].text);
cddf800b 1084+ }
1085+}
1086+
a87bc2c2 1087+
a87bc2c2 1088+/** List welcome messages.
1089+ * @param[in] sptr Client requesting the listing.
1090+ * @param[in] connect When non zero do not report no welcome is set
cddf800b 1091+ * @return Zero.
1092+ */
1093+int
a87bc2c2 1094+welcome_list(struct Client *sptr, int connect)
cddf800b 1095+{
cb0b5df1 1096+ int found = 0, local = 0, name;
a87bc2c2 1097+
6dd3e24f 1098+ assert(NULL != sptr);
1099+
cb0b5df1 1100+ /* loop over all entries - range 0 to 2 * max - 1 */
1101+ for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
a87bc2c2 1102+
cb0b5df1 1103+ /* local entries now */
1104+ if (name == WELCOME_MAX_ENTRIES)
1105+ local = 1;
a87bc2c2 1106+
cb0b5df1 1107+ /* not set or empty - skip */
6dd3e24f 1108+ /* TODO: EmptyString? */
cb0b5df1 1109+ if (WelcomeArray[name].timestamp == 0 || *WelcomeArray[name].text == 0)
a87bc2c2 1110+ continue;
cb0b5df1 1111+
1112+ /* got one */
a87bc2c2 1113+ found++;
cb0b5df1 1114+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :[%s] %s",
1115+ sptr, local ? cli_name(&me) : feature_str(FEAT_NETWORK), WelcomeArray[name].text);
a87bc2c2 1116+ }
cb0b5df1 1117+
1118+ /* nothing set */
a87bc2c2 1119+ if (!found && !connect)
cb0b5df1 1120+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :No welcome message set.", sptr);
1121+
a87bc2c2 1122+ return 0;
1123+}
cddf800b 1124+
cddf800b 1125+
a87bc2c2 1126+/** Statistics callback to list Welcome messages.
1127+ * @param[in] sptr Client requesting statistics.
1128+ * @param[in] sd Stats descriptor for request (ignored).
1129+ * @param[in] param Extra parameter from user (ignored).
1130+ */
1131+void
1132+welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param)
1133+{
cb0b5df1 1134+ int name, local = 0;
a87bc2c2 1135+
6dd3e24f 1136+ assert(NULL != sptr);
1137+
a87bc2c2 1138+ /* send header so the client knows what we are showing */
1139+ send_reply(sptr, SND_EXPLICIT | RPL_STATSHEADER,
6dd3e24f 1140+ "W Name Target Opername Timestamp :Message");
a87bc2c2 1141+
cb0b5df1 1142+ /* loop over all entries - range 0 to 2 * max - 1*/
1143+ for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
cddf800b 1144+
cb0b5df1 1145+ /* local entries now */
1146+ if (name == WELCOME_MAX_ENTRIES)
1147+ local = 1;
a87bc2c2 1148+
cb0b5df1 1149+ /* not set */
1150+ if (WelcomeArray[name].timestamp == 0)
1151+ continue;
cddf800b 1152+
cb0b5df1 1153+ /* send it */
1154+ send_reply(sptr, RPL_STATSWELCOME,
6dd3e24f 1155+ local ? name + 1 - WELCOME_MAX_ENTRIES : name + 1,
1156+ local ? cli_name(&me) : "*",
cb0b5df1 1157+ WelcomeArray[name].who, WelcomeArray[name].timestamp,
6dd3e24f 1158+ EmptyString(WelcomeArray[name].text) ? "<Empty>" : WelcomeArray[name].text);
cddf800b 1159+ }
cddf800b 1160+}