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