]> jfr.im git - irc/quakenet/snircd.git/blob - ircd/jupe.c
Initial import of 2.10.12.01
[irc/quakenet/snircd.git] / ircd / jupe.c
1 /*
2 * IRC - Internet Relay Chat, ircd/jupe.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Finland
5 * Copyright (C) 2000 Kevin L. Mitchell <klmitch@mit.edu>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 1, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 /** @file
22 * @brief Implementation of juped server handling functions.
23 * @version $Id: jupe.c,v 1.20 2004/12/11 05:13:45 klmitch Exp $
24 */
25 #include "config.h"
26
27 #include "jupe.h"
28 #include "client.h"
29 #include "hash.h"
30 #include "ircd.h"
31 #include "ircd_alloc.h"
32 #include "ircd_features.h"
33 #include "ircd_log.h"
34 #include "ircd_reply.h"
35 #include "ircd_string.h"
36 #include "match.h"
37 #include "msg.h"
38 #include "numeric.h"
39 #include "numnicks.h"
40 #include "s_bsd.h"
41 #include "s_misc.h"
42 #include "send.h"
43 #include "struct.h"
44 #include "sys.h" /* FALSE bleah */
45
46 /* #include <assert.h> -- Now using assert in ircd_log.h */
47 #include <string.h>
48
49 /** List of jupes. */
50 static struct Jupe *GlobalJupeList = 0;
51
52 /** Allocate a new jupe with the given parameters.
53 * @param[in] server Server name to jupe.
54 * @param[in] reason Reason for jupe.
55 * @param[in] expire Expiration time for jupe.
56 * @param[in] lastmod Last modification time for jupe.
57 * @param[in] flags Flags to set for the jupe.
58 */
59 static struct Jupe *
60 make_jupe(char *server, char *reason, time_t expire, time_t lastmod,
61 unsigned int flags)
62 {
63 struct Jupe *ajupe;
64
65 ajupe = (struct Jupe*) MyMalloc(sizeof(struct Jupe)); /* alloc memory */
66 assert(0 != ajupe);
67
68 DupString(ajupe->ju_server, server); /* copy vital information */
69 DupString(ajupe->ju_reason, reason);
70 ajupe->ju_expire = expire;
71 ajupe->ju_lastmod = lastmod;
72 ajupe->ju_flags = flags & JUPE_MASK; /* set jupe flags */
73
74 ajupe->ju_next = GlobalJupeList; /* link it into the list */
75 ajupe->ju_prev_p = &GlobalJupeList;
76 if (GlobalJupeList)
77 GlobalJupeList->ju_prev_p = &ajupe->ju_next;
78 GlobalJupeList = ajupe;
79
80 return ajupe;
81 }
82
83 /** Apply a jupe.
84 * @param[in] cptr Local client that sent us the jupe.
85 * @param[in] sptr Originator of the jupe.
86 * @param[in] jupe Jupe to check.
87 */
88 static int
89 do_jupe(struct Client *cptr, struct Client *sptr, struct Jupe *jupe)
90 {
91 struct Client *acptr;
92
93 if (!JupeIsActive(jupe)) /* no action to be taken on inactive jupes */
94 return 0;
95
96 acptr = FindServer(jupe->ju_server);
97
98 /* server isn't online or isn't local or is me */
99 if (!acptr || !MyConnect(acptr) || IsMe(acptr))
100 return 0;
101
102 return exit_client_msg(cptr, acptr, &me, "Juped: %s", jupe->ju_reason);
103 }
104
105 /** Forward a jupe to another server.
106 * @param[in] cptr Local client that sent us the jupe.
107 * @param[in] sptr Originator of the jupe.
108 * @param[in] jupe Jupe to forward.
109 */
110 static void
111 propagate_jupe(struct Client *cptr, struct Client *sptr, struct Jupe *jupe)
112 {
113 if (JupeIsLocal(jupe)) /* don't propagate local jupes */
114 return;
115
116 sendcmdto_serv_butone(sptr, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
117 JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
118 jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
119 jupe->ju_reason);
120 }
121
122 /** Add a new server jupe.
123 * @param[in] cptr Local client that sent us the jupe.
124 * @param[in] sptr Originator of the jupe.
125 * @param[in] server Server name to jupe.
126 * @param[in] reason Reason for the jupe.
127 * @param[in] expire Jupe duration in seconds.
128 * @param[in] lastmod Last modification timestamp (or NULL).
129 * @param[in] flags Flags to set on jupe.
130 * @return Zero, unless the jupe causes \a cptr to be SQUIT, in which
131 * case CPTR_KILLED.
132 */
133 int
134 jupe_add(struct Client *cptr, struct Client *sptr, char *server, char *reason,
135 time_t expire, time_t lastmod, unsigned int flags)
136 {
137 struct Jupe *ajupe;
138
139 assert(0 != server);
140 assert(0 != reason);
141
142 /*
143 * You cannot set a negative (or zero) expire time, nor can you set an
144 * expiration time for greater than JUPE_MAX_EXPIRE.
145 */
146 if (expire <= 0 || expire > JUPE_MAX_EXPIRE) {
147 if (!IsServer(cptr) && MyConnect(cptr))
148 send_reply(cptr, ERR_BADEXPIRE, expire);
149 return 0;
150 }
151
152 expire += CurrentTime; /* convert from lifetime to timestamp */
153
154 /* Inform ops and log it */
155 sendto_opmask_butone(0, SNO_NETWORK, "%s adding %sJUPE for %s, expiring at "
156 "%Tu: %s",
157 (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
158 cli_name(sptr) :
159 cli_name((cli_user(sptr))->server),
160 flags & JUPE_LOCAL ? "local " : "", server,
161 expire + TSoffset, reason);
162
163 log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
164 "%#C adding %sJUPE for %s, expiring at %Tu: %s", sptr,
165 flags & JUPE_LOCAL ? "local " : "", server, expire + TSoffset,
166 reason);
167
168 /* make the jupe */
169 ajupe = make_jupe(server, reason, expire, lastmod, flags);
170
171 propagate_jupe(cptr, sptr, ajupe);
172
173 return do_jupe(cptr, sptr, ajupe); /* remove server if necessary */
174 }
175
176 /** Activate a jupe, optionally changing its lastmod and flags.
177 * @param[in] cptr Local client that sent us the jupe.
178 * @param[in] sptr Originator of the jupe.
179 * @param[in] jupe Jupe to activate.
180 * @param[in] lastmod New timestamp for last modification of the jupe.
181 * @param[in] flags Flags to set on the jupe.
182 * @return Zero, unless the jupe causes \a cptr to be SQUIT, in which
183 * case CPTR_KILLED.
184 */
185 int
186 jupe_activate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe,
187 time_t lastmod, unsigned int flags)
188 {
189 unsigned int saveflags = 0;
190
191 assert(0 != jupe);
192
193 saveflags = jupe->ju_flags;
194
195 if (flags & JUPE_LOCAL)
196 jupe->ju_flags &= ~JUPE_LDEACT;
197 else {
198 jupe->ju_flags |= JUPE_ACTIVE;
199
200 if (jupe->ju_lastmod >= lastmod) /* force lastmod to increase */
201 jupe->ju_lastmod++;
202 else
203 jupe->ju_lastmod = lastmod;
204 }
205
206 if ((saveflags & JUPE_ACTMASK) == JUPE_ACTIVE)
207 return 0; /* was active to begin with */
208
209 /* Inform ops and log it */
210 sendto_opmask_butone(0, SNO_NETWORK, "%s activating JUPE for %s, expiring "
211 "at %Tu: %s",
212 (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
213 cli_name(sptr) :
214 cli_name((cli_user(sptr))->server),
215 jupe->ju_server, jupe->ju_expire + TSoffset,
216 jupe->ju_reason);
217
218 log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
219 "%#C activating JUPE for %s, expiring at %Tu: %s",sptr,
220 jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason);
221
222 if (!(flags & JUPE_LOCAL)) /* don't propagate local changes */
223 propagate_jupe(cptr, sptr, jupe);
224
225 return do_jupe(cptr, sptr, jupe);
226 }
227
228 /** Deactivate a jupe.
229 * @param[in] cptr Local client that sent us the jupe.
230 * @param[in] sptr Originator of the jupe.
231 * @param[in] jupe Jupe to deactivate.
232 * @param[in] lastmod New timestamp for last modification of the jupe.
233 * @param[in] flags Flags to set on the jupe.
234 * @return Zero.
235 */
236 int
237 jupe_deactivate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe,
238 time_t lastmod, unsigned int flags)
239 {
240 unsigned int saveflags = 0;
241
242 assert(0 != jupe);
243
244 saveflags = jupe->ju_flags;
245
246 if (!JupeIsLocal(jupe)) {
247 if (flags & JUPE_LOCAL)
248 jupe->ju_flags |= JUPE_LDEACT;
249 else {
250 jupe->ju_flags &= ~JUPE_ACTIVE;
251
252 if (jupe->ju_lastmod >= lastmod) /* force lastmod to increase */
253 jupe->ju_lastmod++;
254 else
255 jupe->ju_lastmod = lastmod;
256 }
257
258 if ((saveflags & JUPE_ACTMASK) != JUPE_ACTIVE)
259 return 0; /* was inactive to begin with */
260 }
261
262 /* Inform ops and log it */
263 sendto_opmask_butone(0, SNO_NETWORK, "%s %s JUPE for %s, expiring at %Tu: "
264 "%s",
265 (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
266 cli_name(sptr) :
267 cli_name((cli_user(sptr))->server),
268 JupeIsLocal(jupe) ? "removing local" : "deactivating",
269 jupe->ju_server, jupe->ju_expire + TSoffset,
270 jupe->ju_reason);
271
272 log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
273 "%#C %s JUPE for %s, expiring at %Tu: %s", sptr,
274 JupeIsLocal(jupe) ? "removing local" : "deactivating",
275 jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason);
276
277 if (JupeIsLocal(jupe))
278 jupe_free(jupe);
279 else if (!(flags & JUPE_LOCAL)) /* don't propagate local changes */
280 propagate_jupe(cptr, sptr, jupe);
281
282 return 0;
283 }
284
285 /** Find a jupe by name.
286 * @param[in] server %Jupe name to search for.
287 * @return Matching jupe (or NULL if none match).
288 */
289 struct Jupe *
290 jupe_find(char *server)
291 {
292 struct Jupe* jupe;
293 struct Jupe* sjupe;
294
295 for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
296 sjupe = jupe->ju_next;
297
298 if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
299 jupe_free(jupe);
300 else if (0 == ircd_strcmp(server, jupe->ju_server)) /* found it yet? */
301 return jupe;
302 }
303
304 return 0;
305 }
306
307 /** Unlink and free an unused jupe.
308 * @param[in] jupe Server jupe to free.
309 */
310 void
311 jupe_free(struct Jupe* jupe)
312 {
313 assert(0 != jupe);
314
315 *jupe->ju_prev_p = jupe->ju_next; /* squeeze this jupe out */
316 if (jupe->ju_next)
317 jupe->ju_next->ju_prev_p = jupe->ju_prev_p;
318
319 MyFree(jupe->ju_server); /* and free up the memory */
320 MyFree(jupe->ju_reason);
321 MyFree(jupe);
322 }
323
324 /** Send the full list of active global jupes to \a cptr.
325 * @param[in] cptr Local server to send jupes to.
326 */
327 void
328 jupe_burst(struct Client *cptr)
329 {
330 struct Jupe *jupe;
331 struct Jupe *sjupe;
332
333 for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
334 sjupe = jupe->ju_next;
335
336 if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
337 jupe_free(jupe);
338 else if (!JupeIsLocal(jupe)) /* forward global jupes */
339 sendcmdto_one(&me, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
340 JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
341 jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
342 jupe->ju_reason);
343 }
344 }
345
346 /** Forward a jupe to another server.
347 * @param[in] cptr %Server to send jupe to.
348 * @param[in] jupe Jupe to forward.
349 */
350 int
351 jupe_resend(struct Client *cptr, struct Jupe *jupe)
352 {
353 if (JupeIsLocal(jupe)) /* don't propagate local jupes */
354 return 0;
355
356 sendcmdto_one(&me, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
357 JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
358 jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
359 jupe->ju_reason);
360
361 return 0;
362 }
363
364 /** Send a jupe (or a list of jupes) to a server.
365 * @param[in] sptr Client searching for jupes.
366 * @param[in] server Name of jupe to search for (if NULL, list all).
367 * @return Zero.
368 */
369 int
370 jupe_list(struct Client *sptr, char *server)
371 {
372 struct Jupe *jupe;
373 struct Jupe *sjupe;
374
375 if (server) {
376 if (!(jupe = jupe_find(server))) /* no such jupe */
377 return send_reply(sptr, ERR_NOSUCHJUPE, server);
378
379 /* send jupe information along */
380 send_reply(sptr, RPL_JUPELIST, jupe->ju_server, jupe->ju_expire + TSoffset,
381 JupeIsLocal(jupe) ? cli_name(&me) : "*",
382 JupeIsActive(jupe) ? '+' : '-', jupe->ju_reason);
383 } else {
384 for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
385 sjupe = jupe->ju_next;
386
387 if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
388 jupe_free(jupe);
389 else /* send jupe information along */
390 send_reply(sptr, RPL_JUPELIST, jupe->ju_server,
391 jupe->ju_expire + TSoffset,
392 JupeIsLocal(jupe) ? cli_name(&me) : "*",
393 JupeIsActive(jupe) ? '+' : '-', jupe->ju_reason);
394 }
395 }
396
397 /* end of jupe information */
398 return send_reply(sptr, RPL_ENDOFJUPELIST);
399 }
400
401 /** Count jupes and memory used by them.
402 * @param[out] ju_size Receives total number of bytes allocated for jupes.
403 * @return Number of jupes currently allocated.
404 */
405 int
406 jupe_memory_count(size_t *ju_size)
407 {
408 struct Jupe *jupe;
409 unsigned int ju = 0;
410
411 for (jupe = GlobalJupeList; jupe; jupe = jupe->ju_next)
412 {
413 ju++;
414 *ju_size += sizeof(struct Jupe);
415 *ju_size += jupe->ju_server ? (strlen(jupe->ju_server) + 1) : 0;
416 *ju_size += jupe->ju_reason ? (strlen(jupe->ju_reason) + 1) : 0;
417 }
418 return ju;
419 }