]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blame - welcome.patch
cmdhelp.patch - added empty line at end of file for m_help.c and m_defaults.c
[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
100a7f47 74diff -r 5dc1ce46a213 include/handlers.h
75--- a/include/handlers.h Thu Jan 29 14:02:56 2009 +0100
76+++ b/include/handlers.h Thu Jan 29 20:07:03 2009 +0100
cddf800b 77@@ -151,6 +151,7 @@
78 extern int m_version(struct Client*, struct Client*, int, char*[]);
79 extern int m_wallchops(struct Client*, struct Client*, int, char*[]);
80 extern int m_wallvoices(struct Client*, struct Client*, int, char*[]);
81+extern int m_welcome(struct Client*, struct Client*, int, char*[]);
82 extern int m_who(struct Client*, struct Client*, int, char*[]);
83 extern int m_whois(struct Client*, struct Client*, int, char*[]);
84 extern int m_whowas(struct Client*, struct Client*, int, char*[]);
85@@ -185,6 +186,7 @@
86 extern int mo_version(struct Client*, struct Client*, int, char*[]);
87 extern int mo_wallops(struct Client*, struct Client*, int, char*[]);
88 extern int mo_wallusers(struct Client*, struct Client*, int, char*[]);
89+extern int mo_welcome(struct Client*, struct Client*, int, char*[]);
90 extern int mr_error(struct Client*, struct Client*, int, char*[]);
91 extern int mr_error(struct Client*, struct Client*, int, char*[]);
92 extern int mr_pong(struct Client*, struct Client*, int, char*[]);
93@@ -242,6 +244,7 @@
94 extern int ms_wallops(struct Client*, struct Client*, int, char*[]);
95 extern int ms_wallusers(struct Client*, struct Client*, int, char*[]);
96 extern int ms_wallvoices(struct Client*, struct Client*, int, char*[]);
97+extern int ms_welcome(struct Client*, struct Client*, int, char*[]);
98 extern int ms_whois(struct Client*, struct Client*, int, char*[]);
99
a87bc2c2 100 extern int mh_nohelp(struct Client*, struct Client*, int, char*[]);
101@@ -308,6 +311,7 @@
102 extern int mh_wallops(struct Client*, struct Client*, int, char*[]);
103 extern int mh_wallusers(struct Client*, struct Client*, int, char*[]);
104 extern int mh_wallvoices(struct Client*, struct Client*, int, char*[]);
105+extern int mh_welcome(struct Client*, struct Client*, int, char*[]);
106 extern int mh_who(struct Client*, struct Client*, int, char*[]);
107 extern int mh_whois(struct Client*, struct Client*, int, char*[]);
108 extern int mh_whowas(struct Client*, struct Client*, int, char*[]);
100a7f47 109diff -r 5dc1ce46a213 include/ircd_features.h
110--- a/include/ircd_features.h Thu Jan 29 14:02:56 2009 +0100
111+++ b/include/ircd_features.h Thu Jan 29 20:07:03 2009 +0100
a87bc2c2 112@@ -101,6 +101,7 @@
113 FEAT_IRCD_RES_TIMEOUT,
114 FEAT_AUTH_TIMEOUT,
115 FEAT_ANNOUNCE_INVITES,
116+ FEAT_WELCOME,
117
118 /* features that affect all operators */
119 FEAT_EXTENDED_CHECKCMD,
120@@ -143,6 +144,7 @@
121 FEAT_HIS_STATS_u,
122 FEAT_HIS_STATS_U,
123 FEAT_HIS_STATS_v,
124+ FEAT_HIS_STATS_W,
125 FEAT_HIS_STATS_w,
126 FEAT_HIS_STATS_x,
127 FEAT_HIS_STATS_y,
100a7f47 128diff -r 5dc1ce46a213 include/msg.h
129--- a/include/msg.h Thu Jan 29 14:02:56 2009 +0100
130+++ b/include/msg.h Thu Jan 29 20:07:03 2009 +0100
131@@ -196,6 +196,10 @@
cddf800b 132 #define TOK_NOTICE "O"
133 #define CMD_NOTICE MSG_NOTICE, TOK_NOTICE
100a7f47 134
cddf800b 135+#define MSG_WELCOME "WELCOME" /* WELC */
136+#define TOK_WELCOME "WE"
137+#define CMD_WELCOME MSG_WELCOME, TOK_WELCOME
100a7f47 138+
cddf800b 139 #define MSG_WALLCHOPS "WALLCHOPS" /* WC */
140 #define TOK_WALLCHOPS "WC"
100a7f47 141 #define CMD_WALLCHOPS MSG_WALLCHOPS, TOK_WALLCHOPS
142diff -r 5dc1ce46a213 include/numeric.h
143--- a/include/numeric.h Thu Jan 29 14:02:56 2009 +0100
144+++ b/include/numeric.h Thu Jan 29 20:07:03 2009 +0100
a87bc2c2 145@@ -116,6 +116,7 @@
146 RPL_STATSGLINE 227 Dalnet
147 RPL_STATSVLINE 227 unreal */
148 #define RPL_STATSALINE 226 /* Hybrid, Undernet */
149+#define RPL_STATSWELCOME 227 /* QuakeNet extension */
150 #define RPL_STATSQLINE 228 /* Undernet extension */
151 #define RPL_STATSHEADER 230 /* QuakeNet extension */
152
cb0b5df1 153@@ -445,6 +446,8 @@
a87bc2c2 154 /* ERR_GHOSTEDCLIENT 503 efnet */
155 /* ERR_VWORLDWARN 503 austnet */
156
157+#define ERR_NOSUCHWELCOME 509 /* QuakeNet extension */
158+
159 #define ERR_SILELISTFULL 511 /* Undernet extension */
160 /* ERR_NOTIFYFULL 512 aircd */
161 /* ERR_TOOMANYWATCH 512 Numeric List: Dalnet */
100a7f47 162diff -r 5dc1ce46a213 include/welcome.h
cddf800b 163--- /dev/null Thu Jan 01 00:00:00 1970 +0000
100a7f47 164+++ b/include/welcome.h Thu Jan 29 20:07:03 2009 +0100
cb0b5df1 165@@ -0,0 +1,56 @@
cddf800b 166+#ifndef INCLUDED_welcome_h
167+#define INCLUDED_welcome_h
168+/*
169+ * IRC - Internet Relay Chat, include/welcome.h
170+ * Copyright (C) 1990 Jarkko Oikarinen and
171+ * University of Oulu, Computing Center
172+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
173+ *
174+ * This program is free software; you can redistribute it and/or modify
175+ * it under the terms of the GNU General Public License as published by
176+ * the Free Software Foundation; either version 2, or (at your option)
177+ * any later version.
178+ *
179+ * This program is distributed in the hope that it will be useful,
180+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
181+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
182+ * GNU General Public License for more details.
183+ *
184+ * You should have received a copy of the GNU General Public License
185+ * along with this program; if not, write to the Free Software
186+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
187+ */
188+/** @file
a87bc2c2 189+ * @brief Interface and declarations for welcome message handling.
cddf800b 190+ */
191+#ifndef INCLUDED_sys_types_h
192+#include <sys/types.h>
193+#define INCLUDED_sys_types_h
194+#endif
195+
a87bc2c2 196+struct Client;
197+struct StatDesc;
198+
cb0b5df1 199+/* Maximum number of welcome entries (per type; X global, X local) */
200+#define WELCOME_MAX_ENTRIES 10
a87bc2c2 201+
202+/* Describes a Welcome message entry. */
203+struct Welcome {
cb0b5df1 204+ char text[TOPICLEN]; /**< Message */
205+ char who[ACCOUNTLEN]; /**< Who set it */
206+ time_t timestamp; /**< Timestamp of the welcome */
a87bc2c2 207+};
208+
cb0b5df1 209+/** Welcome type flags */
a87bc2c2 210+#define WELCOME_LOCAL 0x01 /**< welcome is local */
211+/** Welcome action flags */
212+#define WELCOME_ANNOUNCE 0x02 /**< announce change to users */
213+
a87bc2c2 214+extern int welcome_do(struct Client *cptr, struct Client *sptr, char *name, char *text,
215+ char *who, time_t timestamp, unsigned int flags);
cb0b5df1 216+extern void welcome_announce(int name);
cddf800b 217+extern void welcome_burst(struct Client *cptr);
a87bc2c2 218+extern int welcome_list(struct Client *sptr, int connect);
219+extern void welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param);
cddf800b 220+
221+#endif /* INCLUDED_welcome_h */
100a7f47 222diff -r 5dc1ce46a213 ircd/Makefile.in
223--- a/ircd/Makefile.in Thu Jan 29 14:02:56 2009 +0100
224+++ b/ircd/Makefile.in Thu Jan 29 20:07:03 2009 +0100
a87bc2c2 225@@ -187,6 +187,7 @@
226 m_wallops.c \
227 m_wallusers.c \
228 m_wallvoices.c \
229+ m_welcome.c \
230 m_who.c \
231 m_whois.c \
232 m_whowas.c \
233@@ -214,6 +215,7 @@
234 send.c \
235 uping.c \
236 userload.c \
237+ welcome.c \
238 whocmds.c \
239 whowas.c \
240 y.tab.c
241@@ -1168,6 +1170,11 @@
242 ../include/ircd_reply.h ../include/ircd_string.h \
243 ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
244 ../include/numnicks.h ../include/s_user.h ../include/send.h
245+m_welcome.o: m_welcome.c ../config.h ../include/channel.h \
246+ ../include/client.h ../include/hash.h ../include/ircd.h ../include/ircd_log.h \
247+ ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
248+ ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
249+ ../include/send.h ../include/welcome.h
250 m_who.o: m_who.c ../config.h ../include/channel.h ../include/ircd_defs.h \
251 ../include/res.h ../config.h ../include/client.h ../include/dbuf.h \
252 ../include/msgq.h ../include/ircd_events.h ../include/ircd_handler.h \
253@@ -1429,6 +1436,13 @@
254 ../include/numnicks.h ../include/querycmds.h ../include/ircd_features.h \
255 ../include/s_misc.h ../include/s_stats.h ../include/send.h \
256 ../include/struct.h ../include/sys.h
257+welcome.o: welcome.c ../config.h ../include/client.h \
258+ ../include/hash.h ../include/ircd.h ../include/ircd_alloc.h \
259+ ../include/ircd_features.h ../include/ircd_log.h ../include/ircd_reply.h \
260+ ../include/match.h ../include/msg.h ../include/numeric.h \
261+ ../include/numnicks.h ../include/s_debug.h ../include/s_bsd.h \
262+ ../include/s_misc.h ../include/send.h ../include/struct.h \
263+ ../include/sys.h ../include/welcome.h
264 whocmds.o: whocmds.c ../config.h ../include/whocmds.h \
265 ../include/channel.h ../include/ircd_defs.h ../include/res.h \
266 ../config.h ../include/client.h ../include/dbuf.h ../include/msgq.h \
100a7f47 267diff -r 5dc1ce46a213 ircd/ircd_features.c
268--- a/ircd/ircd_features.c Thu Jan 29 14:02:56 2009 +0100
269+++ b/ircd/ircd_features.c Thu Jan 29 20:07:03 2009 +0100
a87bc2c2 270@@ -355,6 +355,7 @@
271 F_I(IRCD_RES_TIMEOUT, 0, 4, 0),
272 F_I(AUTH_TIMEOUT, 0, 9, 0),
273 F_B(ANNOUNCE_INVITES, 0, 0, 0),
274+ F_B(WELCOME, 0, 1, 0),
275
276 /* features that affect all operators */
277 F_B(EXTENDED_CHECKCMD, 0, 0, 0),
278@@ -397,6 +398,7 @@
279 F_B(HIS_STATS_u, 0, 1, 0),
280 F_B(HIS_STATS_U, 0, 1, 0),
281 F_B(HIS_STATS_v, 0, 1, 0),
282+ F_B(HIS_STATS_W, 0, 1, 0),
283 F_B(HIS_STATS_w, 0, 1, 0),
284 F_B(HIS_STATS_x, 0, 1, 0),
285 F_B(HIS_STATS_y, 0, 1, 0),
100a7f47 286diff -r 5dc1ce46a213 ircd/m_welcome.c
cddf800b 287--- /dev/null Thu Jan 01 00:00:00 1970 +0000
100a7f47 288+++ b/ircd/m_welcome.c Thu Jan 29 20:07:03 2009 +0100
cb0b5df1 289@@ -0,0 +1,269 @@
cddf800b 290+/*
291+ * IRC - Internet Relay Chat, ircd/m_welcome.c
292+ * Copyright (C) 1990 Jarkko Oikarinen and
293+ * University of Oulu, Computing Center
294+ *
295+ * See file AUTHORS in IRC package for additional names of
296+ * the programmers.
297+ *
298+ * This program is free software; you can redistribute it and/or modify
299+ * it under the terms of the GNU General Public License as published by
300+ * the Free Software Foundation; either version 1, or (at your option)
301+ * any later version.
302+ *
303+ * This program is distributed in the hope that it will be useful,
304+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
305+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
306+ * GNU General Public License for more details.
307+ *
308+ * You should have received a copy of the GNU General Public License
309+ * along with this program; if not, write to the Free Software
310+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
311+ *
cddf800b 312+ */
313+
314+/*
315+ * m_functions execute protocol messages on this server:
316+ *
317+ * cptr is always NON-NULL, pointing to a *LOCAL* client
318+ * structure (with an open socket connected!). This
319+ * identifies the physical socket where the message
320+ * originated (or which caused the m_function to be
321+ * executed--some m_functions may call others...).
322+ *
323+ * sptr is the source of the message, defined by the
324+ * prefix part of the message if present. If not
325+ * or prefix not found, then sptr==cptr.
326+ *
327+ * (!IsServer(cptr)) => (cptr == sptr), because
328+ * prefixes are taken *only* from servers...
329+ *
330+ * (IsServer(cptr))
331+ * (sptr == cptr) => the message didn't
332+ * have the prefix.
333+ *
334+ * (sptr != cptr && IsServer(sptr) means
335+ * the prefix specified servername. (?)
336+ *
337+ * (sptr != cptr && !IsServer(sptr) means
338+ * that message originated from a remote
339+ * user (not local).
340+ *
341+ * combining
342+ *
343+ * (!IsServer(sptr)) means that, sptr can safely
344+ * taken as defining the target structure of the
345+ * message in this server.
346+ *
347+ * *Always* true (if 'parse' and others are working correct):
348+ *
349+ * 1) sptr->from == cptr (note: cptr->from == cptr)
350+ *
351+ * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
352+ * *cannot* be a local connection, unless it's
353+ * actually cptr!). [MyConnect(x) should probably
354+ * be defined as (x == x->from) --msa ]
355+ *
356+ * parc number of variable parameter strings (if zero,
357+ * parv is allowed to be NULL)
358+ *
359+ * parv a NULL terminated list of parameter pointers,
360+ *
361+ * parv[0], sender (prefix string), if not present
362+ * this points to an empty string.
363+ * parv[1]...parv[parc-1]
364+ * pointers to additional parameters
365+ * parv[parc] == NULL, *always*
366+ *
367+ * note: it is guaranteed that parv[0]..parv[parc-1] are all
368+ * non-NULL pointers.
369+ */
370+#include "config.h"
371+
372+#include "channel.h"
373+#include "client.h"
374+#include "hash.h"
375+#include "ircd.h"
a87bc2c2 376+#include "ircd_features.h"
cddf800b 377+#include "ircd_log.h"
378+#include "ircd_reply.h"
379+#include "ircd_string.h"
380+#include "msg.h"
381+#include "numeric.h"
382+#include "numnicks.h"
383+#include "s_user.h"
384+#include "send.h"
a87bc2c2 385+#include "welcome.h"
cddf800b 386+
387+/* #include <assert.h> -- Now using assert in ircd_log.h */
388+
389+/*
390+ * m_welcome - local generic message handler
391+ *
392+ * parv[0] = Send prefix
393+ */
394+int m_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
395+{
a87bc2c2 396+ /* feature disabled */
397+ if (!feature_bool(FEAT_WELCOME))
398+ return send_reply(sptr, ERR_DISABLED, "WELCOME");
399+ return welcome_list(sptr, 0);
cddf800b 400+}
401+
402+
403+/*
404+ * mo_welcome - oper message handler
405+ *
406+ * listing:
407+ * parv[0] = Send prefix
408+ *
409+ * remote listing:
410+ * parv[0] = Send prefix
411+ * parv[1] = Target
412+ *
413+ * set global or on remote server:
414+ * parv[0] = Send prefix
415+ * parv[1] = Target: server or * for global
a87bc2c2 416+ * parv[2] = Name
417+ * parv[3] = Text
cddf800b 418+ */
419+int mo_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
420+{
cb0b5df1 421+ char *target, *name, *who, *text, pattern[BUFSIZE];
a87bc2c2 422+ time_t timestamp;
423+ unsigned int flags = 0;
424+ int local = 0; /* 1 when it is for me */
a87bc2c2 425+
426+ /* feature disabled */
427+ if (!feature_bool(FEAT_WELCOME))
428+ return send_reply(sptr, ERR_DISABLED, "WELCOME");
429+
430+ /* listing */
431+ if (parc < 2)
432+ return welcome_list(sptr, 0);
433+
cb0b5df1 434+ /* TODO: add PRIV_WELCOME? */
a87bc2c2 435+ /* check PRIVS */
436+ if (!HasPriv(sptr,PRIV_SERVERINFO))
437+ return send_reply(sptr, ERR_NOPRIVILEGES);
438+
439+ /* remote listing request, see if it is for me or a remote server */
440+ if (parc == 2) {
441+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) != HUNTED_ISME)
442+ return 0;
443+ return welcome_list(sptr, 0);
444+ }
445+
446+ /* set the parameters */
447+ /* less than 4 parameters, assume target was left out, making it local for me */
448+ if (parc < 4) {
449+ local++;
450+ target = cli_name(&me);
451+ name = parv[1];
452+ flags |= WELCOME_LOCAL;
453+ } else { /* otherwise set as it should */
454+ target = parv[1];
455+ name = parv[2];
456+ }
457+ timestamp = TStime();
458+ who = cli_user(sptr)->opername;
459+ text = parv[parc - 1];
460+
461+ /* target is not global */
462+ if (!(target[0] == '*' && target[1] == '\0') && !local) {
463+ /* build a pattern for hunt_server_cmd since we do not have all we need in parv */
464+ ircd_snprintf(0, pattern, sizeof(pattern), "%s %s %Tu %s :%s", "%C", name, timestamp, who, text);
465+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, pattern, 1, 2, parv) != HUNTED_ISME)
466+ return 0;
467+ flags |= WELCOME_LOCAL; /* local welcome, for me */
468+ }
469+
cb0b5df1 470+ /* TODO: disallow global announcement from oper?
471+ * as PRIVMSG/NOTICE to $* is not allowed either by the ircd
472+ * when PRIV for that is added, use that here? PRIV_BROADCAST or something
473+ */
a87bc2c2 474+ /* check for anounce prefix */
475+ if (*name == '!') {
476+ name++;
477+ flags |= WELCOME_ANNOUNCE;
478+ }
479+
480+ /* and do it */
481+ return welcome_do(cptr, sptr, name, text, who, timestamp, flags);
cddf800b 482+}
483+
484+
485+/*
486+ * ms_welcome - server message handler
487+ *
488+ * parv[0] = Send prefix
489+ * parv[1] = Target: server numeric or * for global
a87bc2c2 490+ * parv[2] = Name
491+ * parv[3] = Timestamp
492+ * parv[4] = Who
493+ * parv[5] = Text
cddf800b 494+ */
495+int ms_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
496+{
cb0b5df1 497+ char *target, *name, *who, *text;
a87bc2c2 498+ time_t timestamp;
499+ unsigned int flags = 0;
500+
501+ /* not enough */
502+ if (parc < 2)
503+ return need_more_params(sptr, "WELCOME");
504+
505+ /* remote listing request, see if it is for me or a remote server */
506+ if (parc == 2) {
507+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C", 1, parc, parv) == HUNTED_ISME)
508+ return welcome_list(sptr, 0);
509+ }
510+
511+ /* we need at least 6 parameters to continue */
512+ if (parc < 6)
513+ return need_more_params(sptr, "WELCOME");
514+
515+ /* set the parameters */
516+ target = parv[1];
517+ name = parv[2];
518+ timestamp = atoi(parv[3]);
519+ who = parv[4];
520+ text = parv[parc - 1];
521+
522+ /* target is not global */
523+ if (!(target[0] == '*' && target[1] == '\0')) {
524+ /* not for me, and forward it */
525+ if (hunt_server_cmd(sptr, CMD_WELCOME, cptr, 0, "%C %s %s %s :%s", 1, parc, parv) != HUNTED_ISME)
526+ return 0;
527+ flags |= WELCOME_LOCAL; /* local welcome, for me */
528+ }
529+
530+ /* check for anounce prefix */
531+ if (*name == '!') {
532+ name++;
533+ flags |= WELCOME_ANNOUNCE;
534+ }
535+
536+ /* and do it */
537+ return welcome_do(cptr, sptr, name, text, who, timestamp, flags);
538+}
539+
540+
541+/*
542+ * mh_welcome - help message handler
543+ */
544+int mh_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
545+{
546+ if (!IsAnOper(sptr)) {
547+ send_reply(sptr, SND_EXPLICIT | RPL_HELP,
548+ "WELCOME :WELCOME");
549+ send_reply(sptr, SND_EXPLICIT | RPL_HELP,
550+ "WELCOME :Shows welcome messages set on the server.");
551+ } else {
552+ send_reply(sptr, SND_EXPLICIT | RPL_HELP,
553+ "WELCOME :WELCOME [<target>] [[!]<name> :<message>]");
554+ send_reply(sptr, SND_EXPLICIT | RPL_HELP,
555+ "WELCOME :Shows or sets welcome messages on a server.");
556+ }
cddf800b 557+ return 0;
558+}
100a7f47 559diff -r 5dc1ce46a213 ircd/parse.c
560--- a/ircd/parse.c Thu Jan 29 14:02:56 2009 +0100
561+++ b/ircd/parse.c Thu Jan 29 20:07:03 2009 +0100
a87bc2c2 562@@ -667,6 +667,15 @@
563 /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */
564 { m_unregistered, m_not_oper, ms_opkick, mo_opkick, m_ignore, mh_nohelp }
cddf800b 565 },
566+
567+ /* add command for WELCOME */
568+ {
569+ MSG_WELCOME,
570+ TOK_WELCOME,
571+ 0, MAXPARA, MFLG_SLOW, 0, NULL,
a87bc2c2 572+ /* UNREG, CLIENT, SERVER, OPER, SERVICE, HELP */
573+ { m_unregistered, m_welcome, ms_welcome, mo_welcome, m_ignore, mh_welcome }
cddf800b 574+ },
575
576 /* This command is an alias for QUIT during the unregistered part of
577 * of the server. This is because someone jumping via a broken web
100a7f47 578diff -r 5dc1ce46a213 ircd/s_err.c
579--- a/ircd/s_err.c Thu Jan 29 14:02:56 2009 +0100
580+++ b/ircd/s_err.c Thu Jan 29 20:07:03 2009 +0100
a87bc2c2 581@@ -486,7 +486,7 @@
582 /* 226 */
583 { RPL_STATSALINE, "%s", "226" },
584 /* 227 */
585- { 0 },
586+ { RPL_STATSWELCOME, "W %d %s %s %Tu :%s", "227" },
587 /* 228 */
588 { RPL_STATSQLINE, "Q %s :%s", "228" },
589 /* 229 */
590@@ -1050,7 +1050,7 @@
591 /* 508 */
592 { 0 },
593 /* 509 */
594- { 0 },
595+ { ERR_NOSUCHWELCOME, "%s :No such welcome", "509" },
596 /* 510 */
597 { 0 },
598 /* 511 */
100a7f47 599diff -r 5dc1ce46a213 ircd/s_serv.c
600--- a/ircd/s_serv.c Thu Jan 29 14:02:56 2009 +0100
601+++ b/ircd/s_serv.c Thu Jan 29 20:07:03 2009 +0100
a87bc2c2 602@@ -57,6 +57,7 @@
603 #include "struct.h"
604 #include "sys.h"
605 #include "userload.h"
606+#include "welcome.h"
607
608 /* #include <assert.h> -- Now using assert in ircd_log.h */
609 #include <stdlib.h>
610@@ -196,6 +197,7 @@
611 */
612 gline_burst(cptr);
613 jupe_burst(cptr);
614+ welcome_burst(cptr);
615
616 /*
617 * Pass on my client information to the new server
100a7f47 618diff -r 5dc1ce46a213 ircd/s_stats.c
619--- a/ircd/s_stats.c Thu Jan 29 14:02:56 2009 +0100
620+++ b/ircd/s_stats.c Thu Jan 29 20:07:03 2009 +0100
a87bc2c2 621@@ -54,6 +54,7 @@
622 #include "send.h"
623 #include "struct.h"
624 #include "userload.h"
625+#include "welcome.h"
626
627 #include <stdio.h>
628 #include <stdlib.h>
629@@ -689,9 +690,12 @@
630 { 'V', "vserversmach", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_v,
631 stats_servers_verbose, 0,
632 "Verbose server information." },
633- { 'w', "userload", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
634+ { 'w', "userload", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_w,
635 calc_load, 0,
636 "Userload statistics." },
637+ { 'W', "welcome", STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS, FEAT_HIS_STATS_W,
638+ welcome_stats, 0,
639+ "Welcome messages." },
640 { 'x', "memusage", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
641 stats_meminfo, 0,
642 "List usage information." },
100a7f47 643diff -r 5dc1ce46a213 ircd/s_user.c
644--- a/ircd/s_user.c Thu Jan 29 14:02:56 2009 +0100
645+++ b/ircd/s_user.c Thu Jan 29 20:07:03 2009 +0100
a87bc2c2 646@@ -63,6 +63,7 @@
647 #include "userload.h"
648 #include "version.h"
649 #include "whowas.h"
650+#include "welcome.h"
651
652 #include "handlers.h" /* m_motd and m_lusers */
653
654@@ -411,6 +412,9 @@
655 cli_info(sptr), NumNick(cptr) /* two %s's */);
656
657 IPcheck_connect_succeeded(sptr);
658+
659+ if (feature_bool(FEAT_WELCOME))
660+ welcome_list(sptr, 1);
661 }
662 else {
663 struct Client *acptr = user->server;
100a7f47 664diff -r 5dc1ce46a213 ircd/welcome.c
cddf800b 665--- /dev/null Thu Jan 01 00:00:00 1970 +0000
100a7f47 666+++ b/ircd/welcome.c Thu Jan 29 20:07:03 2009 +0100
cb0b5df1 667@@ -0,0 +1,355 @@
cddf800b 668+/*
a87bc2c2 669+ * IRC - Internet Relay Chat, ircd/welcome.c
cddf800b 670+ * Copyright (C) 1990 Jarkko Oikarinen and
671+ * University of Oulu, Finland
672+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
673+ *
674+ * This program is free software; you can redistribute it and/or modify
675+ * it under the terms of the GNU General Public License as published by
676+ * the Free Software Foundation; either version 1, or (at your option)
677+ * any later version.
678+ *
679+ * This program is distributed in the hope that it will be useful,
680+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
681+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
682+ * GNU General Public License for more details.
683+ *
684+ * You should have received a copy of the GNU General Public License
685+ * along with this program; if not, write to the Free Software
686+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
687+ */
688+/** @file
a87bc2c2 689+ * @brief Implementation of welcome message handling functions.
cddf800b 690+ */
691+#include "config.h"
692+
693+#include "client.h"
694+#include "hash.h"
695+#include "ircd.h"
696+#include "ircd_alloc.h"
697+#include "ircd_features.h"
698+#include "ircd_log.h"
699+#include "ircd_reply.h"
700+#include "ircd_string.h"
701+#include "match.h"
702+#include "msg.h"
703+#include "numeric.h"
704+#include "numnicks.h"
705+#include "s_bsd.h"
a87bc2c2 706+#include "s_debug.h"
cddf800b 707+#include "s_misc.h"
708+#include "send.h"
709+#include "struct.h"
710+#include "sys.h" /* FALSE bleah */
711+#include "welcome.h"
712+
713+/* #include <assert.h> -- Now using assert in ircd_log.h */
714+#include <string.h>
715+
cddf800b 716+
cb0b5df1 717+/** List of welcome messages - first MAX for global, second MAX for local */
718+static struct Welcome WelcomeArray[WELCOME_MAX_ENTRIES * 2];
719+
cddf800b 720+
cddf800b 721+
a87bc2c2 722+/** Allocate a new welcome with the given parameters.
723+ * @param[in] name Name of the welcome message.
724+ * @param[in] text The welcome message.
725+ * @param[in] who Who set it.
726+ * @param[in] timestamp When it was set.
cb0b5df1 727+ * @return name Array number of the welcome set.
cddf800b 728+ */
cb0b5df1 729+static int
730+welcome_make(int name, char *text, char *who, time_t timestamp)
cddf800b 731+{
cb0b5df1 732+ /* range 0 to 2 * max - 1 */
733+ assert(name >= 0 && name <= 2 * WELCOME_MAX_ENTRIES - 1);
734+
735+ /* store it */
736+ ircd_strncpy(WelcomeArray[name].text, text, TOPICLEN);
737+ ircd_strncpy(WelcomeArray[name].who, who, ACCOUNTLEN);
738+ WelcomeArray[name].timestamp = timestamp;
739+
740+ return name;
cddf800b 741+}
742+
cddf800b 743+
a87bc2c2 744+/** Change a welcome message.
745+ * @param[in] cptr Local client that sent us the welcome.
746+ * @param[in] sptr Originator of the welcome.
747+ * @param[in] name Name of the message.
748+ * @param[in] text The welcome message.
749+ * @param[in] timestamp Timestamp of when the message was set.
750+ * @param[in] flags Flags to set on welcome.
751+ * @return Zero
cddf800b 752+ */
753+int
a87bc2c2 754+welcome_do(struct Client *cptr, struct Client *sptr, char *name, char *text,
755+ char *who, time_t timestamp, unsigned int flags)
cddf800b 756+{
cb0b5df1 757+ int nameint = atoi(name); /* transform to int */
758+ int namearray = nameint - 1; /* used to test the array element */
759+ int notext = (text[0] == '\0') ? 1 : 0; /* 1 when text is empty */
760+ char *action; /* used for logging */
761+ /* TODO: these needed? */
762+ /*
763+ who[ACCOUNTLEN-1] = 0;
764+ text[WELCOMELEN-1] = 0;
765+ */
a87bc2c2 766+
cb0b5df1 767+ /* TODO: NULL or 0 ? they are pointers, so NULL? */
a87bc2c2 768+ assert(0 != cptr);
769+ assert(0 != sptr);
770+ assert(0 != name);
cb0b5df1 771+ /* TODO: assert(0 != text); */
772+ assert(0 != who);
a87bc2c2 773+
cb0b5df1 774+ /* debug */
a87bc2c2 775+ Debug((DEBUG_DEBUG, "welcome_do(\"%s\", \"%s\", \"%s\", \"%s\" \"%s\", %Tu, 0x%04x)",
776+ cli_name(cptr), cli_name(sptr), name, text, who, timestamp, flags));
777+
778+ /* check name */
cb0b5df1 779+ if (nameint < 1 || nameint > WELCOME_MAX_ENTRIES) {
a87bc2c2 780+ if (IsUser(sptr))
781+ sendcmdto_one(&me, CMD_NOTICE, sptr,
782+ "%C :WELCOME: Invalid message number %s - should between 1 and %d",
783+ sptr, name, WELCOME_MAX_ENTRIES);
cddf800b 784+ return 0;
785+ }
786+
cb0b5df1 787+ /* correct namearray for local offset */
788+ if (flags & WELCOME_LOCAL)
789+ namearray += WELCOME_MAX_ENTRIES;
a87bc2c2 790+
791+ /* cannot unset welcome that is not set */
cb0b5df1 792+ if (WelcomeArray[namearray].timestamp == 0 && notext) {
a87bc2c2 793+ /* from user, throw error */
794+ if (IsUser(sptr))
795+ return send_reply(sptr, ERR_NOSUCHWELCOME, name);
796+ /* new local welcome from server, but empty - ignore */
797+ if (flags & WELCOME_LOCAL)
798+ return 0;
799+ /* new global welcome message, but empty, accept from server
800+ * otherwise we do not have the same state as them
801+ */
802+ }
cddf800b 803+
cb0b5df1 804+ /* TODO: check if we receive an entry with a timestamp >> TStime()
805+ * ..so from the future
806+ * something is wrong there - either side is wrong about the time (or both)
807+ *
808+ * if we accept a global welcome message with a timestamp far into the future
809+ * it will not be possible to change it - well, not until we pass that point in time
810+ * or /settime to get to it, or hack with a service..
811+ *
812+ * how to handle this - like CREATE and settime? hm, or throw error to ops?
813+ */
a87bc2c2 814+ /* check if there is something to change */
cb0b5df1 815+ if (WelcomeArray[namearray].timestamp != 0) { /* we got a record for it */
816+ if (namearray < WELCOME_MAX_ENTRIES) { /* global */
817+ if (timestamp == WelcomeArray[namearray].timestamp) /* we got this version already */
a87bc2c2 818+ return 0;
cb0b5df1 819+ if (timestamp < WelcomeArray[namearray].timestamp) { /* we got a later version */
a87bc2c2 820+ if (IsBurstOrBurstAck(cptr)) /* middle of a burst, it will resync on its own */
821+ return 0;
cb0b5df1 822+ return welcome_resend(cptr, namearray); /* resync the server */
a87bc2c2 823+ }
cb0b5df1 824+ } else
825+ /* local welcome, set timestamp to nettime, accept any change
826+ * we parse local welcome messages in the order we receive them
827+ * they cannot cross on the network and are not bursted,
828+ * and thus timestamp is not required for conflict resolving.
829+ */
a87bc2c2 830+ timestamp = TStime();
cb0b5df1 831+
a87bc2c2 832+ /* compare new message with old message */
cb0b5df1 833+ if (ircd_strcmp(text, WelcomeArray[namearray].text) == 0) {
a87bc2c2 834+ if (IsUser(sptr))
835+ sendcmdto_one(&me, CMD_NOTICE, sptr,
cb0b5df1 836+ "%C :WELCOME: Cannot change %smessage for %s - nothing to change.",
837+ sptr, (flags & WELCOME_LOCAL) ? "local " : "", name);
a87bc2c2 838+ return 0;
839+ }
840+ }
cddf800b 841+
cb0b5df1 842+ /* update */
843+ welcome_make(namearray, text, who, timestamp);
844+
a87bc2c2 845+ /* set action */
846+ if (flags & WELCOME_LOCAL)
847+ action = notext ? "removing local" : "changing local";
848+ else
849+ action = notext ? "unsetting" : "changing";
850+
851+ /* TODO: WALLOPS for local welcome messages, so that all operators know about it? */
cb0b5df1 852+ /* inform ops */
853+ sendto_opmask_butone(0, SNO_OLDSNO, "%s %s WELCOME for %d%s%s",
a87bc2c2 854+ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
855+ get_client_name_and_opername(sptr) : cli_name((cli_user(sptr))->server),
cb0b5df1 856+ action, nameint, notext ? "" : " to :", notext ? "" : WelcomeArray[namearray].text);
a87bc2c2 857+
858+ /* log it */
cb0b5df1 859+ log_write(LS_NETWORK, L_INFO, LOG_NOSNOTICE, "%#C (%s) %s WELCOME for %d%s%s [%Tu]",
860+ sptr, WelcomeArray[namearray].who, action, nameint,
861+ notext ? "" : " to :", notext ? "" : WelcomeArray[namearray].text,
862+ WelcomeArray[namearray].timestamp);
a87bc2c2 863+
cb0b5df1 864+ /* TODO: or WALLOPS here, local message remotely set? */
a87bc2c2 865+ /* welcome set by remote user, inform oper of success */
866+ if ((flags & WELCOME_LOCAL) && IsUser(sptr) && !MyUser(sptr))
cb0b5df1 867+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s %s WELCOME for %d%s%s",
868+ sptr, get_client_name_and_opername(sptr), action, nameint,
869+ notext ? "" : " to :", notext ? "" : WelcomeArray[namearray].text);
cddf800b 870+
cb0b5df1 871+ /* propagate it */
a87bc2c2 872+ if (!(flags & WELCOME_LOCAL))
873+ sendcmdto_serv_butone(sptr, CMD_WELCOME, cptr, "* %s%d %Tu %s :%s",
cb0b5df1 874+ (flags & WELCOME_ANNOUNCE) ? "!" : "", nameint,
875+ WelcomeArray[namearray].timestamp, WelcomeArray[namearray].who,
876+ WelcomeArray[namearray].text);
cddf800b 877+
a87bc2c2 878+ /* announce it */
879+ if ((flags & WELCOME_ANNOUNCE) && !notext)
cb0b5df1 880+ welcome_announce(namearray);
a87bc2c2 881+
882+ return 0;
cddf800b 883+}
884+
a87bc2c2 885+
886+/** Announce a welcome message to local clients.
cb0b5df1 887+ * @param[in] name Welcome message to announce.
cddf800b 888+ */
a87bc2c2 889+void
cb0b5df1 890+welcome_announce(int name)
cddf800b 891+{
a87bc2c2 892+ struct Client *acptr;
893+ struct MsgBuf *msgbuf;
894+
cb0b5df1 895+ /* range 0 to 2 * max - 1 */
896+ assert(name >= 0 && name <= 2 * WELCOME_MAX_ENTRIES - 1);
a87bc2c2 897+
cb0b5df1 898+ /* TODO: target is $* as if it were a global broadcast
899+ * could make it $servername for local message announcement
900+ * but the type is shown between [ ] already
901+ * either [Network] or [servername] - using $* is just shorter.
902+ */
a87bc2c2 903+ /* build msgbuf */
904+ msgbuf = msgq_make(0, ":%C %s $* :[%s] %s", &me, MSG_NOTICE,
cb0b5df1 905+ name >= WELCOME_MAX_ENTRIES ? cli_name(&me) : feature_str(FEAT_NETWORK),
906+ WelcomeArray[name].text);
a87bc2c2 907+
908+ /* go over clients */
909+ for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) {
cb0b5df1 910+
a87bc2c2 911+ /* skip remote users
cb0b5df1 912+ * skip unregistered clients - they see the message during login
a87bc2c2 913+ */
914+ if (!MyUser(acptr) || !IsRegistered(acptr))
915+ continue;
cb0b5df1 916+
a87bc2c2 917+ /* send it away */
918+ send_buffer(acptr, msgbuf, 0);
cddf800b 919+ }
cddf800b 920+}
921+
a87bc2c2 922+
a87bc2c2 923+/** Send the full list of welcome message to \a cptr.
924+ * @param[in] cptr Local server to send welcomes to.
cddf800b 925+ */
926+void
a87bc2c2 927+welcome_burst(struct Client *cptr)
cddf800b 928+{
cb0b5df1 929+ int name;
a87bc2c2 930+
cb0b5df1 931+ /* loop over global entries - 0 to max - 1*/
932+ for (name = 0; name <= WELCOME_MAX_ENTRIES - 1; name++) {
933+ if (WelcomeArray[name].timestamp != 0)
a87bc2c2 934+ sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %s :%s",
cb0b5df1 935+ name + 1, WelcomeArray[name].timestamp, WelcomeArray[name].who,
936+ WelcomeArray[name].text);
cddf800b 937+ }
938+}
939+
a87bc2c2 940+
941+/** Forward a welcome to another server.
942+ * @param[in] cptr %Server to send welcome to.
943+ * @param[in] welcome Welcome to forward.
cddf800b 944+ */
945+int
cb0b5df1 946+welcome_resend(struct Client *cptr, int name)
cddf800b 947+{
a87bc2c2 948+ sendcmdto_one(&me, CMD_WELCOME, cptr, "* %d %Tu %s :%s",
cb0b5df1 949+ name + 1, WelcomeArray[name].timestamp, WelcomeArray[name].who,
950+ WelcomeArray[name].text);
cddf800b 951+ return 0;
952+}
953+
a87bc2c2 954+
955+/** List welcome messages.
956+ * @param[in] sptr Client requesting the listing.
957+ * @param[in] connect When non zero do not report no welcome is set
cddf800b 958+ * @return Zero.
959+ */
960+int
a87bc2c2 961+welcome_list(struct Client *sptr, int connect)
cddf800b 962+{
cb0b5df1 963+ int found = 0, local = 0, name;
a87bc2c2 964+
cb0b5df1 965+ /* loop over all entries - range 0 to 2 * max - 1 */
966+ for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
a87bc2c2 967+
cb0b5df1 968+ /* local entries now */
969+ if (name == WELCOME_MAX_ENTRIES)
970+ local = 1;
a87bc2c2 971+
cb0b5df1 972+ /* not set or empty - skip */
973+ if (WelcomeArray[name].timestamp == 0 || *WelcomeArray[name].text == 0)
a87bc2c2 974+ continue;
cb0b5df1 975+
976+ /* got one */
a87bc2c2 977+ found++;
cb0b5df1 978+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :[%s] %s",
979+ sptr, local ? cli_name(&me) : feature_str(FEAT_NETWORK), WelcomeArray[name].text);
a87bc2c2 980+ }
cb0b5df1 981+
982+ /* nothing set */
a87bc2c2 983+ if (!found && !connect)
cb0b5df1 984+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :No welcome message set.", sptr);
985+
a87bc2c2 986+ return 0;
987+}
cddf800b 988+
cddf800b 989+
a87bc2c2 990+/** Statistics callback to list Welcome messages.
991+ * @param[in] sptr Client requesting statistics.
992+ * @param[in] sd Stats descriptor for request (ignored).
993+ * @param[in] param Extra parameter from user (ignored).
994+ */
995+void
996+welcome_stats(struct Client *sptr, const struct StatDesc *sd, char *param)
997+{
cb0b5df1 998+ int name, local = 0;
a87bc2c2 999+
cb0b5df1 1000+ /* TODO: change "Who" to "Opername" or "OperID" as that is what it is? */
a87bc2c2 1001+ /* send header so the client knows what we are showing */
1002+ send_reply(sptr, SND_EXPLICIT | RPL_STATSHEADER,
1003+ "W Name Target Who Timestamp :Message");
1004+
cb0b5df1 1005+ /* loop over all entries - range 0 to 2 * max - 1*/
1006+ for (name = 0; name <= 2 * WELCOME_MAX_ENTRIES - 1; name++) {
cddf800b 1007+
cb0b5df1 1008+ /* local entries now */
1009+ if (name == WELCOME_MAX_ENTRIES)
1010+ local = 1;
a87bc2c2 1011+
cb0b5df1 1012+ /* not set */
1013+ if (WelcomeArray[name].timestamp == 0)
1014+ continue;
cddf800b 1015+
cb0b5df1 1016+ /* send it */
1017+ send_reply(sptr, RPL_STATSWELCOME,
1018+ local ? name + 1 - WELCOME_MAX_ENTRIES : name + 1, local ? cli_name(&me) : "*",
1019+ WelcomeArray[name].who, WelcomeArray[name].timestamp,
1020+ (*WelcomeArray[name].text == 0) ? "<Empty>" : WelcomeArray[name].text);
cddf800b 1021+ }
cddf800b 1022+}