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