]> jfr.im git - irc/quakenet/snircd-patchqueue.git/blame - welcome.patch
cmdhelp.patch almost finished
[irc/quakenet/snircd-patchqueue.git] / welcome.patch
CommitLineData
cddf800b 1diff -r a662d02e9a76 include/handlers.h
2--- a/include/handlers.h Sat Jan 24 21:39:56 2009 +0100
3+++ b/include/handlers.h Sat Jan 24 22:38:10 2009 +0100
4@@ -151,6 +151,7 @@
5 extern int m_version(struct Client*, struct Client*, int, char*[]);
6 extern int m_wallchops(struct Client*, struct Client*, int, char*[]);
7 extern int m_wallvoices(struct Client*, struct Client*, int, char*[]);
8+extern int m_welcome(struct Client*, struct Client*, int, char*[]);
9 extern int m_who(struct Client*, struct Client*, int, char*[]);
10 extern int m_whois(struct Client*, struct Client*, int, char*[]);
11 extern int m_whowas(struct Client*, struct Client*, int, char*[]);
12@@ -185,6 +186,7 @@
13 extern int mo_version(struct Client*, struct Client*, int, char*[]);
14 extern int mo_wallops(struct Client*, struct Client*, int, char*[]);
15 extern int mo_wallusers(struct Client*, struct Client*, int, char*[]);
16+extern int mo_welcome(struct Client*, struct Client*, int, char*[]);
17 extern int mr_error(struct Client*, struct Client*, int, char*[]);
18 extern int mr_error(struct Client*, struct Client*, int, char*[]);
19 extern int mr_pong(struct Client*, struct Client*, int, char*[]);
20@@ -242,6 +244,7 @@
21 extern int ms_wallops(struct Client*, struct Client*, int, char*[]);
22 extern int ms_wallusers(struct Client*, struct Client*, int, char*[]);
23 extern int ms_wallvoices(struct Client*, struct Client*, int, char*[]);
24+extern int ms_welcome(struct Client*, struct Client*, int, char*[]);
25 extern int ms_whois(struct Client*, struct Client*, int, char*[]);
26
27 #endif /* INCLUDED_handlers_h */
28diff -r a662d02e9a76 include/msg.h
29--- a/include/msg.h Sat Jan 24 21:39:56 2009 +0100
30+++ b/include/msg.h Sat Jan 24 22:38:10 2009 +0100
31@@ -195,6 +195,10 @@
32 #define MSG_NOTICE "NOTICE" /* NOTI */
33 #define TOK_NOTICE "O"
34 #define CMD_NOTICE MSG_NOTICE, TOK_NOTICE
35+
36+#define MSG_WELCOME "WELCOME" /* WELC */
37+#define TOK_WELCOME "WE"
38+#define CMD_WELCOME MSG_WELCOME, TOK_WELCOME
39
40 #define MSG_WALLCHOPS "WALLCHOPS" /* WC */
41 #define TOK_WALLCHOPS "WC"
42diff -r a662d02e9a76 include/welcome.h
43--- /dev/null Thu Jan 01 00:00:00 1970 +0000
44+++ b/include/welcome.h Sat Jan 24 22:38:10 2009 +0100
45@@ -0,0 +1,43 @@
46+#ifndef INCLUDED_welcome_h
47+#define INCLUDED_welcome_h
48+/*
49+ * IRC - Internet Relay Chat, include/welcome.h
50+ * Copyright (C) 1990 Jarkko Oikarinen and
51+ * University of Oulu, Computing Center
52+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
53+ *
54+ * This program is free software; you can redistribute it and/or modify
55+ * it under the terms of the GNU General Public License as published by
56+ * the Free Software Foundation; either version 2, or (at your option)
57+ * any later version.
58+ *
59+ * This program is distributed in the hope that it will be useful,
60+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
61+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
62+ * GNU General Public License for more details.
63+ *
64+ * You should have received a copy of the GNU General Public License
65+ * along with this program; if not, write to the Free Software
66+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
67+ */
68+/** @file
69+ * @brief Interface and declarations for welcome server handling.
70+ * @version $Id: jupe.h 1208 2004-10-03 14:12:35Z entrope $
71+ */
72+#ifndef INCLUDED_sys_types_h
73+#include <sys/types.h>
74+#define INCLUDED_sys_types_h
75+#endif
76+
77+
78+
79+
80+
81+extern int welcome_set(struct Client *cptr, struct Client *sptr,
82+ char *reason, time_t lastmod);
83+extern void welcome_burst(struct Client *cptr);
84+extern int welcome_resend(struct Client *cptr);
85+extern int welcome_list(struct Client *sptr);
86+extern int welcome_memory_count(size_t *ju_size);
87+
88+#endif /* INCLUDED_welcome_h */
89\ No newline at end of file
90diff -r a662d02e9a76 ircd/m_welcome.c
91--- /dev/null Thu Jan 01 00:00:00 1970 +0000
92+++ b/ircd/m_welcome.c Sat Jan 24 22:38:10 2009 +0100
93@@ -0,0 +1,142 @@
94+/*
95+ * IRC - Internet Relay Chat, ircd/m_welcome.c
96+ * Copyright (C) 1990 Jarkko Oikarinen and
97+ * University of Oulu, Computing Center
98+ *
99+ * See file AUTHORS in IRC package for additional names of
100+ * the programmers.
101+ *
102+ * This program is free software; you can redistribute it and/or modify
103+ * it under the terms of the GNU General Public License as published by
104+ * the Free Software Foundation; either version 1, or (at your option)
105+ * any later version.
106+ *
107+ * This program is distributed in the hope that it will be useful,
108+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
109+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
110+ * GNU General Public License for more details.
111+ *
112+ * You should have received a copy of the GNU General Public License
113+ * along with this program; if not, write to the Free Software
114+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
115+ *
116+ * $Id: m_welcome.c 1903 2009-01-13 03:54:45Z entrope $
117+ */
118+
119+/*
120+ * m_functions execute protocol messages on this server:
121+ *
122+ * cptr is always NON-NULL, pointing to a *LOCAL* client
123+ * structure (with an open socket connected!). This
124+ * identifies the physical socket where the message
125+ * originated (or which caused the m_function to be
126+ * executed--some m_functions may call others...).
127+ *
128+ * sptr is the source of the message, defined by the
129+ * prefix part of the message if present. If not
130+ * or prefix not found, then sptr==cptr.
131+ *
132+ * (!IsServer(cptr)) => (cptr == sptr), because
133+ * prefixes are taken *only* from servers...
134+ *
135+ * (IsServer(cptr))
136+ * (sptr == cptr) => the message didn't
137+ * have the prefix.
138+ *
139+ * (sptr != cptr && IsServer(sptr) means
140+ * the prefix specified servername. (?)
141+ *
142+ * (sptr != cptr && !IsServer(sptr) means
143+ * that message originated from a remote
144+ * user (not local).
145+ *
146+ * combining
147+ *
148+ * (!IsServer(sptr)) means that, sptr can safely
149+ * taken as defining the target structure of the
150+ * message in this server.
151+ *
152+ * *Always* true (if 'parse' and others are working correct):
153+ *
154+ * 1) sptr->from == cptr (note: cptr->from == cptr)
155+ *
156+ * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
157+ * *cannot* be a local connection, unless it's
158+ * actually cptr!). [MyConnect(x) should probably
159+ * be defined as (x == x->from) --msa ]
160+ *
161+ * parc number of variable parameter strings (if zero,
162+ * parv is allowed to be NULL)
163+ *
164+ * parv a NULL terminated list of parameter pointers,
165+ *
166+ * parv[0], sender (prefix string), if not present
167+ * this points to an empty string.
168+ * parv[1]...parv[parc-1]
169+ * pointers to additional parameters
170+ * parv[parc] == NULL, *always*
171+ *
172+ * note: it is guaranteed that parv[0]..parv[parc-1] are all
173+ * non-NULL pointers.
174+ */
175+#include "config.h"
176+
177+#include "channel.h"
178+#include "client.h"
179+#include "hash.h"
180+#include "ircd.h"
181+#include "ircd_log.h"
182+#include "ircd_reply.h"
183+#include "ircd_string.h"
184+#include "msg.h"
185+#include "numeric.h"
186+#include "numnicks.h"
187+#include "s_user.h"
188+#include "send.h"
189+
190+/* #include <assert.h> -- Now using assert in ircd_log.h */
191+
192+/*
193+ * m_welcome - local generic message handler
194+ *
195+ * parv[0] = Send prefix
196+ */
197+int m_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
198+{
199+ return 0;
200+}
201+
202+
203+/*
204+ * mo_welcome - oper message handler
205+ *
206+ * listing:
207+ * parv[0] = Send prefix
208+ *
209+ * remote listing:
210+ * parv[0] = Send prefix
211+ * parv[1] = Target
212+ *
213+ * set global or on remote server:
214+ * parv[0] = Send prefix
215+ * parv[1] = Target: server or * for global
216+ * parv[2] = Text
217+ */
218+int mo_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
219+{
220+ return 0;
221+}
222+
223+
224+/*
225+ * ms_welcome - server message handler
226+ *
227+ * parv[0] = Send prefix
228+ * parv[1] = Target: server numeric or * for global
229+ * parv[2] = Timestamp
230+ * parv[3] = Text
231+ */
232+int ms_welcome(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
233+{
234+ return 0;
235+}
236diff -r a662d02e9a76 ircd/parse.c
237--- a/ircd/parse.c Sat Jan 24 21:39:56 2009 +0100
238+++ b/ircd/parse.c Sat Jan 24 22:38:10 2009 +0100
239@@ -668,6 +668,15 @@
240 /* UNREG, CLIENT, SERVER, OPER, SERVICE */
241 { m_unregistered, m_not_oper, ms_opkick, mo_opkick, m_ignore }
242 },
243+
244+ /* add command for WELCOME */
245+ {
246+ MSG_WELCOME,
247+ TOK_WELCOME,
248+ 0, MAXPARA, MFLG_SLOW, 0, NULL,
249+ /* UNREG, CLIENT, SERVER, OPER, SERVICE */
250+ { m_unregistered, m_welcome, ms_welcome, mo_welcome, m_ignore }
251+ },
252
253 /* This command is an alias for QUIT during the unregistered part of
254 * of the server. This is because someone jumping via a broken web
255diff -r a662d02e9a76 ircd/welcome.c
256--- /dev/null Thu Jan 01 00:00:00 1970 +0000
257+++ b/ircd/welcome.c Sat Jan 24 22:38:10 2009 +0100
258@@ -0,0 +1,430 @@
259+/*
260+ * IRC - Internet Relay Chat, ircd/jupe.c
261+ * Copyright (C) 1990 Jarkko Oikarinen and
262+ * University of Oulu, Finland
263+ * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
264+ *
265+ * This program is free software; you can redistribute it and/or modify
266+ * it under the terms of the GNU General Public License as published by
267+ * the Free Software Foundation; either version 1, or (at your option)
268+ * any later version.
269+ *
270+ * This program is distributed in the hope that it will be useful,
271+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
272+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
273+ * GNU General Public License for more details.
274+ *
275+ * You should have received a copy of the GNU General Public License
276+ * along with this program; if not, write to the Free Software
277+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
278+ */
279+/** @file
280+ * @brief Implementation of juped server handling functions.
281+ * @version $Id: jupe.c 1633 2006-03-25 03:46:56Z entrope $
282+ */
283+#include "config.h"
284+
285+#include "client.h"
286+#include "hash.h"
287+#include "ircd.h"
288+#include "ircd_alloc.h"
289+#include "ircd_features.h"
290+#include "ircd_log.h"
291+#include "ircd_reply.h"
292+#include "ircd_string.h"
293+#include "match.h"
294+#include "msg.h"
295+#include "numeric.h"
296+#include "numnicks.h"
297+#include "s_bsd.h"
298+#include "s_misc.h"
299+#include "send.h"
300+#include "struct.h"
301+#include "sys.h" /* FALSE bleah */
302+#include "welcome.h"
303+
304+/* #include <assert.h> -- Now using assert in ircd_log.h */
305+#include <string.h>
306+
307+/** List of jupes. */
308+static struct Jupe *GlobalJupeList = 0;
309+
310+/** Allocate a new jupe with the given parameters.
311+ * @param[in] server Server name to jupe.
312+ * @param[in] reason Reason for jupe.
313+ * @param[in] expire Expiration time for jupe.
314+ * @param[in] lastmod Last modification time for jupe.
315+ * @param[in] flags Flags to set for the jupe.
316+ */
317+static struct Jupe *
318+make_jupe(char *server, char *reason, time_t expire, time_t lastmod,
319+ unsigned int flags)
320+{
321+ struct Jupe *ajupe;
322+
323+ ajupe = (struct Jupe*) MyMalloc(sizeof(struct Jupe)); /* alloc memory */
324+ assert(0 != ajupe);
325+
326+ memset(ajupe, 0, sizeof(*ajupe));
327+ DupString(ajupe->ju_server, server); /* copy vital information */
328+ DupString(ajupe->ju_reason, reason);
329+ ajupe->ju_expire = expire;
330+ ajupe->ju_lastmod = lastmod;
331+ ajupe->ju_flags = flags & JUPE_MASK; /* set jupe flags */
332+
333+ ajupe->ju_next = GlobalJupeList; /* link it into the list */
334+ ajupe->ju_prev_p = &GlobalJupeList;
335+ if (GlobalJupeList)
336+ GlobalJupeList->ju_prev_p = &ajupe->ju_next;
337+ GlobalJupeList = ajupe;
338+
339+ return ajupe;
340+}
341+
342+/** Apply a jupe.
343+ * @param[in] cptr Local client that sent us the jupe.
344+ * @param[in] sptr Originator of the jupe.
345+ * @param[in] jupe Jupe to check.
346+ */
347+static int
348+do_jupe(struct Client *cptr, struct Client *sptr, struct Jupe *jupe)
349+{
350+ struct Client *acptr;
351+
352+ if (!JupeIsActive(jupe)) /* no action to be taken on inactive jupes */
353+ return 0;
354+
355+ acptr = FindServer(jupe->ju_server);
356+
357+ /* server isn't online or isn't local or is me */
358+ if (!acptr || !MyConnect(acptr) || IsMe(acptr))
359+ return 0;
360+
361+ return exit_client_msg(cptr, acptr, &me, "Juped: %s", jupe->ju_reason);
362+}
363+
364+/** Forward a jupe to another server.
365+ * @param[in] cptr Local client that sent us the jupe.
366+ * @param[in] sptr Originator of the jupe.
367+ * @param[in] jupe Jupe to forward.
368+ */
369+static void
370+propagate_jupe(struct Client *cptr, struct Client *sptr, struct Jupe *jupe)
371+{
372+ if (JupeIsLocal(jupe)) /* don't propagate local jupes */
373+ return;
374+
375+ sendcmdto_serv_butone(sptr, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
376+ JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
377+ jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
378+ jupe->ju_reason);
379+}
380+
381+/** Add a new server jupe.
382+ * @param[in] cptr Local client that sent us the jupe.
383+ * @param[in] sptr Originator of the jupe.
384+ * @param[in] server Server name to jupe.
385+ * @param[in] reason Reason for the jupe.
386+ * @param[in] expire Jupe duration in seconds.
387+ * @param[in] lastmod Last modification timestamp (or NULL).
388+ * @param[in] flags Flags to set on jupe.
389+ * @return Zero, unless the jupe causes \a cptr to be SQUIT, in which
390+ * case CPTR_KILLED.
391+ */
392+int
393+jupe_add(struct Client *cptr, struct Client *sptr, char *server, char *reason,
394+ time_t expire, time_t lastmod, unsigned int flags)
395+{
396+ struct Jupe *ajupe;
397+
398+ assert(0 != server);
399+ assert(0 != reason);
400+
401+ /*
402+ * You cannot set a negative (or zero) expire time, nor can you set an
403+ * expiration time for greater than JUPE_MAX_EXPIRE.
404+ */
405+ if (expire <= 0 || expire > JUPE_MAX_EXPIRE) {
406+ if (!IsServer(cptr) && MyConnect(cptr))
407+ send_reply(cptr, ERR_BADEXPIRE, expire);
408+ return 0;
409+ }
410+
411+ expire += CurrentTime; /* convert from lifetime to timestamp */
412+
413+ /* Inform ops and log it */
414+ sendto_opmask_butone(0, SNO_NETWORK, "%s adding %sJUPE for %s, expiring at "
415+ "%Tu: %s",
416+ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
417+ get_client_name_and_opername(sptr) :
418+ cli_name((cli_user(sptr))->server),
419+ flags & JUPE_LOCAL ? "local " : "", server,
420+ expire + TSoffset, reason);
421+
422+ log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
423+ "%#C adding %sJUPE for %s, expiring at %Tu: %s", sptr,
424+ flags & JUPE_LOCAL ? "local " : "", server, expire + TSoffset,
425+ reason);
426+
427+ /* local jupe set by remote user, inform oper of success */
428+ if ((flags & JUPE_LOCAL) && IsUser(sptr) && !MyUser(sptr))
429+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s adding local JUPE for %s, expiring at %Tu: %s",
430+ sptr, cli_name(sptr), server, expire + TSoffset, reason);
431+
432+ /* make the jupe */
433+ ajupe = make_jupe(server, reason, expire, lastmod, flags);
434+
435+ propagate_jupe(cptr, sptr, ajupe);
436+
437+ return do_jupe(cptr, sptr, ajupe); /* remove server if necessary */
438+}
439+
440+/** Activate a jupe, optionally changing its lastmod and flags.
441+ * @param[in] cptr Local client that sent us the jupe.
442+ * @param[in] sptr Originator of the jupe.
443+ * @param[in] jupe Jupe to activate.
444+ * @param[in] lastmod New timestamp for last modification of the jupe.
445+ * @param[in] flags Flags to set on the jupe.
446+ * @return Zero, unless the jupe causes \a cptr to be SQUIT, in which
447+ * case CPTR_KILLED.
448+ */
449+int
450+jupe_activate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe,
451+ time_t lastmod, unsigned int flags)
452+{
453+ unsigned int saveflags = 0;
454+
455+ assert(0 != jupe);
456+
457+ saveflags = jupe->ju_flags;
458+
459+ if (flags & JUPE_LOCAL)
460+ jupe->ju_flags &= ~JUPE_LDEACT;
461+ else {
462+ jupe->ju_flags |= JUPE_ACTIVE;
463+
464+ if (jupe->ju_lastmod >= lastmod) /* force lastmod to increase */
465+ jupe->ju_lastmod++;
466+ else
467+ jupe->ju_lastmod = lastmod;
468+ }
469+
470+ if ((saveflags & JUPE_ACTMASK) == JUPE_ACTIVE)
471+ return 0; /* was active to begin with */
472+
473+ /* Inform ops and log it */
474+ sendto_opmask_butone(0, SNO_NETWORK, "%s activating JUPE for %s, expiring "
475+ "at %Tu: %s",
476+ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
477+ get_client_name_and_opername(sptr) :
478+ cli_name((cli_user(sptr))->server),
479+ jupe->ju_server, jupe->ju_expire + TSoffset,
480+ jupe->ju_reason);
481+
482+ log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
483+ "%#C activating JUPE for %s, expiring at %Tu: %s",sptr,
484+ jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason);
485+
486+ if (!(flags & JUPE_LOCAL)) /* don't propagate local changes */
487+ propagate_jupe(cptr, sptr, jupe);
488+
489+ return do_jupe(cptr, sptr, jupe);
490+}
491+
492+/** Deactivate a jupe.
493+ * @param[in] cptr Local client that sent us the jupe.
494+ * @param[in] sptr Originator of the jupe.
495+ * @param[in] jupe Jupe to deactivate.
496+ * @param[in] lastmod New timestamp for last modification of the jupe.
497+ * @param[in] flags Flags to set on the jupe.
498+ * @return Zero.
499+ */
500+int
501+jupe_deactivate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe,
502+ time_t lastmod, unsigned int flags)
503+{
504+ unsigned int saveflags = 0;
505+
506+ assert(0 != jupe);
507+
508+ saveflags = jupe->ju_flags;
509+
510+ if (!JupeIsLocal(jupe)) {
511+ if (flags & JUPE_LOCAL)
512+ jupe->ju_flags |= JUPE_LDEACT;
513+ else {
514+ jupe->ju_flags &= ~JUPE_ACTIVE;
515+
516+ if (jupe->ju_lastmod >= lastmod) /* force lastmod to increase */
517+ jupe->ju_lastmod++;
518+ else
519+ jupe->ju_lastmod = lastmod;
520+ }
521+
522+ if ((saveflags & JUPE_ACTMASK) != JUPE_ACTIVE)
523+ return 0; /* was inactive to begin with */
524+ }
525+
526+ /* Inform ops and log it */
527+ sendto_opmask_butone(0, SNO_NETWORK, "%s %s JUPE for %s, expiring at %Tu: "
528+ "%s",
529+ (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
530+ get_client_name_and_opername(sptr) :
531+ cli_name((cli_user(sptr))->server),
532+ JupeIsLocal(jupe) ? "removing local" : "deactivating",
533+ jupe->ju_server, jupe->ju_expire + TSoffset,
534+ jupe->ju_reason);
535+
536+ log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
537+ "%#C %s JUPE for %s, expiring at %Tu: %s", sptr,
538+ JupeIsLocal(jupe) ? "removing local" : "deactivating",
539+ jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason);
540+
541+ /* local jupe removed by remote user, inform oper of success */
542+ if ((flags & JUPE_LOCAL) && IsUser(sptr) && !MyUser(sptr))
543+ sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :%s removing local JUPE for %s, expiring at %Tu: %s",
544+ sptr, cli_name(sptr), jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason);
545+
546+ if (JupeIsLocal(jupe))
547+ jupe_free(jupe);
548+ else if (!(flags & JUPE_LOCAL)) /* don't propagate local changes */
549+ propagate_jupe(cptr, sptr, jupe);
550+
551+ return 0;
552+}
553+
554+/** Find a jupe by name.
555+ * @param[in] server %Jupe name to search for.
556+ * @return Matching jupe (or NULL if none match).
557+ */
558+struct Jupe *
559+jupe_find(char *server)
560+{
561+ struct Jupe* jupe;
562+ struct Jupe* sjupe;
563+
564+ for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
565+ sjupe = jupe->ju_next;
566+
567+ if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
568+ jupe_free(jupe);
569+ else if (0 == ircd_strcmp(server, jupe->ju_server)) /* found it yet? */
570+ return jupe;
571+ }
572+
573+ return 0;
574+}
575+
576+/** Unlink and free an unused jupe.
577+ * @param[in] jupe Server jupe to free.
578+ */
579+void
580+jupe_free(struct Jupe* jupe)
581+{
582+ assert(0 != jupe);
583+
584+ *jupe->ju_prev_p = jupe->ju_next; /* squeeze this jupe out */
585+ if (jupe->ju_next)
586+ jupe->ju_next->ju_prev_p = jupe->ju_prev_p;
587+
588+ MyFree(jupe->ju_server); /* and free up the memory */
589+ MyFree(jupe->ju_reason);
590+ MyFree(jupe);
591+}
592+
593+/** Send the full list of active global jupes to \a cptr.
594+ * @param[in] cptr Local server to send jupes to.
595+ */
596+void
597+jupe_burst(struct Client *cptr)
598+{
599+ struct Jupe *jupe;
600+ struct Jupe *sjupe;
601+
602+ for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
603+ sjupe = jupe->ju_next;
604+
605+ if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
606+ jupe_free(jupe);
607+ else if (!JupeIsLocal(jupe)) /* forward global jupes */
608+ sendcmdto_one(&me, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
609+ JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
610+ jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
611+ jupe->ju_reason);
612+ }
613+}
614+
615+/** Forward a jupe to another server.
616+ * @param[in] cptr %Server to send jupe to.
617+ * @param[in] jupe Jupe to forward.
618+ */
619+int
620+jupe_resend(struct Client *cptr, struct Jupe *jupe)
621+{
622+ if (JupeIsLocal(jupe)) /* don't propagate local jupes */
623+ return 0;
624+
625+ sendcmdto_one(&me, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
626+ JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
627+ jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
628+ jupe->ju_reason);
629+
630+ return 0;
631+}
632+
633+/** Send a jupe (or a list of jupes) to a server.
634+ * @param[in] sptr Client searching for jupes.
635+ * @param[in] server Name of jupe to search for (if NULL, list all).
636+ * @return Zero.
637+ */
638+int
639+jupe_list(struct Client *sptr, char *server)
640+{
641+ struct Jupe *jupe;
642+ struct Jupe *sjupe;
643+
644+ if (server) {
645+ if (!(jupe = jupe_find(server))) /* no such jupe */
646+ return send_reply(sptr, ERR_NOSUCHJUPE, server);
647+
648+ /* send jupe information along */
649+ send_reply(sptr, RPL_JUPELIST, jupe->ju_server, jupe->ju_expire + TSoffset,
650+ JupeIsLocal(jupe) ? cli_name(&me) : "*",
651+ JupeIsActive(jupe) ? '+' : '-', jupe->ju_reason);
652+ } else {
653+ for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
654+ sjupe = jupe->ju_next;
655+
656+ if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
657+ jupe_free(jupe);
658+ else /* send jupe information along */
659+ send_reply(sptr, RPL_JUPELIST, jupe->ju_server,
660+ jupe->ju_expire + TSoffset,
661+ JupeIsLocal(jupe) ? cli_name(&me) : "*",
662+ JupeIsActive(jupe) ? '+' : '-', jupe->ju_reason);
663+ }
664+ }
665+
666+ /* end of jupe information */
667+ return send_reply(sptr, RPL_ENDOFJUPELIST);
668+}
669+
670+/** Count welcome and memory used by it.
671+ * @param[out] we_size Receives total number of bytes allocated for welcome.
672+ * @return Number of welcomes currently allocated.
673+ */
674+int
675+welcome_memory_count(size_t *we_size)
676+{
677+ struct Jupe *jupe;
678+ unsigned int ju = 0;
679+
680+ for (jupe = GlobalJupeList; jupe; jupe = jupe->ju_next)
681+ {
682+ ju++;
683+ *ju_size += sizeof(struct Jupe);
684+ *ju_size += jupe->ju_server ? (strlen(jupe->ju_server) + 1) : 0;
685+ *ju_size += jupe->ju_reason ? (strlen(jupe->ju_reason) + 1) : 0;
686+ }
687+ return ju;
688+}
689\ No newline at end of file