Fix memory counting bugs for jupes and glines.
[ircu2.10.12-pk.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  * $Id$
22  */
23 #include "config.h"
24
25 #include "jupe.h"
26 #include "client.h"
27 #include "hash.h"
28 #include "ircd.h"
29 #include "ircd_alloc.h"
30 #include "ircd_features.h"
31 #include "ircd_log.h"
32 #include "ircd_reply.h"
33 #include "ircd_string.h"
34 #include "match.h"
35 #include "msg.h"
36 #include "numeric.h"
37 #include "numnicks.h"
38 #include "s_bsd.h"
39 #include "s_misc.h"
40 #include "send.h"
41 #include "struct.h"
42 #include "support.h"
43 #include "sys.h"    /* FALSE bleah */
44
45 #include <assert.h>
46 #include <string.h>
47
48 static struct Jupe *GlobalJupeList = 0;
49
50 static struct Jupe *
51 make_jupe(char *server, char *reason, time_t expire, time_t lastmod,
52           unsigned int flags)
53 {
54   struct Jupe *ajupe;
55
56   ajupe = (struct Jupe*) MyMalloc(sizeof(struct Jupe)); /* alloc memory */
57   assert(0 != ajupe);
58
59   DupString(ajupe->ju_server, server); /* copy vital information */
60   DupString(ajupe->ju_reason, reason);
61   ajupe->ju_expire = expire;
62   ajupe->ju_lastmod = lastmod;
63   ajupe->ju_flags = flags & JUPE_MASK; /* set jupe flags */
64
65   ajupe->ju_next = GlobalJupeList; /* link it into the list */
66   ajupe->ju_prev_p = &GlobalJupeList;
67   if (GlobalJupeList)
68     GlobalJupeList->ju_prev_p = &ajupe->ju_next;
69   GlobalJupeList = ajupe;
70
71   return ajupe;
72 }
73
74 static int
75 do_jupe(struct Client *cptr, struct Client *sptr, struct Jupe *jupe)
76 {
77   struct Client *acptr;
78
79   if (!JupeIsActive(jupe)) /* no action to be taken on inactive jupes */
80     return 0;
81
82   acptr = FindServer(jupe->ju_server);
83
84   /* server isn't online or isn't local or is me */
85   if (!acptr || !MyConnect(acptr) || IsMe(acptr))
86     return 0;
87
88   return exit_client_msg(cptr, acptr, &me, "Juped: %s", jupe->ju_reason);
89 }
90
91 static void
92 propagate_jupe(struct Client *cptr, struct Client *sptr, struct Jupe *jupe)
93 {
94   if (JupeIsLocal(jupe)) /* don't propagate local jupes */
95     return;
96
97   sendcmdto_serv_butone(sptr, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
98                         JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
99                         jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
100                         jupe->ju_reason);
101 }
102
103 int
104 jupe_add(struct Client *cptr, struct Client *sptr, char *server, char *reason,
105          time_t expire, time_t lastmod, unsigned int flags)
106 {
107   struct Jupe *ajupe;
108
109   assert(0 != server);
110   assert(0 != reason);
111
112   /*
113    * You cannot set a negative (or zero) expire time, nor can you set an
114    * expiration time for greater than JUPE_MAX_EXPIRE.
115    */
116   if (expire <= 0 || expire > JUPE_MAX_EXPIRE) {
117     if (!IsServer(cptr) && MyConnect(cptr))
118       send_reply(cptr, ERR_BADEXPIRE, expire);
119     return 0;
120   }
121
122   expire += CurrentTime; /* convert from lifetime to timestamp */
123
124   /* Inform ops and log it */
125   sendto_opmask_butone(0, SNO_NETWORK, "%s adding %sJUPE for %s, expiring at "
126                        "%Tu: %s",
127                        (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
128                          cli_name(sptr) :
129                          cli_name((cli_user(sptr))->server),
130                        flags & JUPE_LOCAL ? "local " : "", server,
131                        expire + TSoffset, reason);
132
133   log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
134             "%#C adding %sJUPE for %s, expiring at %Tu: %s", sptr,
135             flags & JUPE_LOCAL ? "local " : "", server, expire + TSoffset,
136             reason);
137
138   /* make the jupe */
139   ajupe = make_jupe(server, reason, expire, lastmod, flags);
140
141   propagate_jupe(cptr, sptr, ajupe);
142
143   return do_jupe(cptr, sptr, ajupe); /* remove server if necessary */
144 }
145
146 int
147 jupe_activate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe,
148               time_t lastmod, unsigned int flags)
149 {
150   unsigned int saveflags = 0;
151
152   assert(0 != jupe);
153
154   saveflags = jupe->ju_flags;
155
156   if (flags & JUPE_LOCAL)
157     jupe->ju_flags &= ~JUPE_LDEACT;
158   else {
159     jupe->ju_flags |= JUPE_ACTIVE;
160
161     if (jupe->ju_lastmod >= lastmod) /* force lastmod to increase */
162       jupe->ju_lastmod++;
163     else
164       jupe->ju_lastmod = lastmod;
165   }
166
167   if ((saveflags & JUPE_ACTMASK) == JUPE_ACTIVE)
168     return 0; /* was active to begin with */
169
170   /* Inform ops and log it */
171   sendto_opmask_butone(0, SNO_NETWORK, "%s activating JUPE for %s, expiring "
172                        "at %Tu: %s",
173                        (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
174                          cli_name(sptr) :
175                          cli_name((cli_user(sptr))->server),
176                        jupe->ju_server, jupe->ju_expire + TSoffset,
177                        jupe->ju_reason);
178
179   log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
180             "%#C activating JUPE for %s, expiring at %Tu: %s",sptr,
181             jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason);
182
183   if (!(flags & JUPE_LOCAL)) /* don't propagate local changes */
184     propagate_jupe(cptr, sptr, jupe);
185
186   return do_jupe(cptr, sptr, jupe);
187 }
188
189 int
190 jupe_deactivate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe,
191                 time_t lastmod, unsigned int flags)
192 {
193   unsigned int saveflags = 0;
194
195   assert(0 != jupe);
196
197   saveflags = jupe->ju_flags;
198
199   if (!JupeIsLocal(jupe)) {
200     if (flags & JUPE_LOCAL)
201       jupe->ju_flags |= JUPE_LDEACT;
202     else {
203       jupe->ju_flags &= ~JUPE_ACTIVE;
204
205       if (jupe->ju_lastmod >= lastmod) /* force lastmod to increase */
206         jupe->ju_lastmod++;
207       else
208         jupe->ju_lastmod = lastmod;
209     }
210
211     if ((saveflags & JUPE_ACTMASK) != JUPE_ACTIVE)
212       return 0; /* was inactive to begin with */
213   }
214
215   /* Inform ops and log it */
216   sendto_opmask_butone(0, SNO_NETWORK, "%s %s JUPE for %s, expiring at %Tu: "
217                        "%s",
218                        (feature_bool(FEAT_HIS_SNOTICES) || IsServer(sptr)) ?
219                          cli_name(sptr) :
220                          cli_name((cli_user(sptr))->server),
221                        JupeIsLocal(jupe) ? "removing local" : "deactivating",
222                        jupe->ju_server, jupe->ju_expire + TSoffset,
223                        jupe->ju_reason);
224
225   log_write(LS_JUPE, L_INFO, LOG_NOSNOTICE,
226             "%#C %s JUPE for %s, expiring at %Tu: %s", sptr,
227             JupeIsLocal(jupe) ? "removing local" : "deactivating",
228             jupe->ju_server, jupe->ju_expire + TSoffset, jupe->ju_reason);
229
230   if (JupeIsLocal(jupe))
231     jupe_free(jupe);
232   else if (!(flags & JUPE_LOCAL)) /* don't propagate local changes */
233     propagate_jupe(cptr, sptr, jupe);
234
235   return 0;
236 }
237
238 struct Jupe *
239 jupe_find(char *server)
240 {
241   struct Jupe* jupe;
242   struct Jupe* sjupe;
243
244   for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
245     sjupe = jupe->ju_next;
246
247     if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
248       jupe_free(jupe);
249     else if (0 == ircd_strcmp(server, jupe->ju_server)) /* found it yet? */
250       return jupe;
251   }
252
253   return 0;
254 }
255
256 void
257 jupe_free(struct Jupe* jupe)
258 {
259   assert(0 != jupe);
260
261   *jupe->ju_prev_p = jupe->ju_next; /* squeeze this jupe out */
262   if (jupe->ju_next)
263     jupe->ju_next->ju_prev_p = jupe->ju_prev_p;
264
265   MyFree(jupe->ju_server);  /* and free up the memory */
266   MyFree(jupe->ju_reason);
267   MyFree(jupe);
268 }
269
270 void
271 jupe_burst(struct Client *cptr)
272 {
273   struct Jupe *jupe;
274   struct Jupe *sjupe;
275
276   for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
277     sjupe = jupe->ju_next;
278
279     if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
280       jupe_free(jupe);
281     else if (!JupeIsLocal(jupe)) /* forward global jupes */
282       sendcmdto_one(&me, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
283                     JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
284                     jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
285                     jupe->ju_reason);
286   }
287 }
288
289 int
290 jupe_resend(struct Client *cptr, struct Jupe *jupe)
291 {
292   if (JupeIsLocal(jupe)) /* don't propagate local jupes */
293     return 0;
294
295   sendcmdto_one(&me, CMD_JUPE, cptr, "* %c%s %Tu %Tu :%s",
296                 JupeIsRemActive(jupe) ? '+' : '-', jupe->ju_server,
297                 jupe->ju_expire - CurrentTime, jupe->ju_lastmod,
298                 jupe->ju_reason);
299
300   return 0;
301 }
302
303 int
304 jupe_list(struct Client *sptr, char *server)
305 {
306   struct Jupe *jupe;
307   struct Jupe *sjupe;
308
309   if (server) {
310     if (!(jupe = jupe_find(server))) /* no such jupe */
311       return send_reply(sptr, ERR_NOSUCHJUPE, server);
312
313     /* send jupe information along */
314     send_reply(sptr, RPL_JUPELIST, jupe->ju_server, jupe->ju_expire + TSoffset,
315                JupeIsLocal(jupe) ? cli_name(&me) : "*",
316                JupeIsActive(jupe) ? '+' : '-', jupe->ju_reason);
317   } else {
318     for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
319       sjupe = jupe->ju_next;
320
321       if (jupe->ju_expire <= CurrentTime) /* expire any that need expiring */
322         jupe_free(jupe);
323       else /* send jupe information along */
324         send_reply(sptr, RPL_JUPELIST, jupe->ju_server,
325                    jupe->ju_expire + TSoffset,
326                    JupeIsLocal(jupe) ? cli_name(&me) : "*",
327                    JupeIsActive(jupe) ? '+' : '-', jupe->ju_reason);
328     }
329   }
330
331   /* end of jupe information */
332   return send_reply(sptr, RPL_ENDOFJUPELIST);
333 }
334
335 int
336 jupe_memory_count(size_t *ju_size)
337 {
338   struct Jupe *jupe;
339   unsigned int ju = 0;
340
341   for (jupe = GlobalJupeList; jupe; jupe = jupe->ju_next)
342   {
343     ju++;
344     *ju_size += sizeof(struct Jupe);
345     *ju_size += jupe->ju_server ? (strlen(jupe->ju_server) + 1) : 0;
346     *ju_size += jupe->ju_reason ? (strlen(jupe->ju_reason) + 1) : 0;
347   }
348   return ju;
349 }