Author: Kev <klmitch@undernet.org>
[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;        /* 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                         JupeIsActive(jupe) ? '+' : '-', jupe->ju_server,
94                         jupe->ju_expire - TStime(), 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, int local, int active)
101 {
102   struct Jupe *ajupe;
103   unsigned int flags = 0;
104
105   assert(0 != server);
106   assert(0 != reason);
107
108   /*
109    * You cannot set a negative (or zero) expire time, nor can you set an
110    * expiration time for greater than JUPE_MAX_EXPIRE.
111    */
112   if (expire <= 0 || expire > JUPE_MAX_EXPIRE) {
113     if (!IsServer(cptr) && MyConnect(cptr))
114       send_error_to_client(cptr, ERR_BADEXPIRE, expire);
115     return 0;
116   }
117
118   expire += TStime(); /* convert from lifetime to timestamp */
119
120   /* Inform ops and log it */
121   if (IsServer(sptr)) {
122     sendto_op_mask(SNO_NETWORK, "%s adding %sJUPE for %s, expiring at "
123                    TIME_T_FMT ": %s", sptr->name, local ? "local " : "",
124                    server, expire, reason);
125 #ifdef JPATH
126     write_log(JPATH, TIME_T_FMT " %s adding %sJUPE for %s, expiring at "
127               TIME_T_FMT ": %s\n", TStime(), sptr->name,
128               local ? "local " : "", server, expire, reason);
129 #endif /* JPATH */
130   } else {
131     sendto_op_mask(SNO_NETWORK, "%s adding %sJUPE for %s, expiring at "
132                    TIME_T_FMT ": %s", sptr->user->server->name,
133                    local ? "local " : "", server, expire,
134                    reason);
135 #ifdef JPATH
136     write_log(JPATH, TIME_T_FMT, " %s!%s@%s adding %sJUPE for %s, expiring at "
137               TIME_T_FMT ": %s\n", TStime(), sptr->name, sptr->user->username,
138               sptr->user->host, local ? "local " : "", server, expire, reason);
139 #endif /* JPATH */
140   }
141
142   if (active) /* compute initial flags */
143     flags |= JUPE_ACTIVE;
144   if (local)
145     flags |= JUPE_LOCAL;
146
147   /* make the jupe */
148   ajupe = make_jupe(server, reason, expire, lastmod, flags);
149
150   propagate_jupe(cptr, sptr, ajupe);
151
152   return do_jupe(cptr, sptr, ajupe); /* remove server if necessary */
153 }
154
155 int
156 jupe_activate(struct Client *cptr, struct Client *sptr, struct Jupe *jupe,
157               time_t lastmod)
158 {
159   assert(0 != jupe);
160
161   jupe->ju_flags |= JUPE_ACTIVE;
162   jupe->ju_lastmod = lastmod;
163
164   /* Inform ops and log it */
165   if (IsServer(sptr)) {
166     sendto_op_mask(SNO_NETWORK, "%s activating %sJUPE for %s, expiring at "
167                    TIME_T_FMT ": %s", sptr->name, JupeIsLocal(jupe) ?
168                    "local " : "", jupe->ju_server, jupe->ju_expire,
169                    jupe->ju_reason);
170 #ifdef JPATH
171     write_log(JPATH, TIME_T_FMT " %s activating %sJUPE for %s, expiring at "
172               TIME_T_FMT ": %s\n", TStime(), sptr->name, JupeIsLocal(jupe) ?
173               "local " : "", jupe->ju_server, jupe->ju_expire,
174               jupe->ju_reason);
175 #endif /* JPATH */
176   } else {
177     sendto_op_mask(SNO_NETWORK, "%s activating %sJUPE for %s, expiring at "
178                    TIME_T_FMT ": %s", sptr->user->server->name,
179                    JupeIsLocal(jupe) ? "local " : "", jupe->ju_server,
180                    jupe->ju_expire, jupe->ju_reason);
181 #ifdef JPATH
182     write_log(JPATH, TIME_T_FMT, " %s!%s@%s activating %sJUPE for %s, "
183               "expiring at " TIME_T_FMT ": %s\n", TStime(), sptr->name,
184               sptr->user->username, sptr->user->host, JupeIsLocal(jupe) ?
185               "local " : "", jupe->ju_server, jupe->ju_expire,
186               jupe->ju_reason);
187 #endif /* JPATH */
188   }
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)
198 {
199   assert(0 != jupe);
200
201   jupe->ju_flags &= ~JUPE_ACTIVE;
202   jupe->ju_lastmod = lastmod;
203
204   /* Inform ops and log it */
205   if (IsServer(sptr)) {
206     sendto_op_mask(SNO_NETWORK, "%s deactivating %sJUPE for %s, expiring at "
207                    TIME_T_FMT ": %s", sptr->name, JupeIsLocal(jupe) ?
208                    "local " : "", jupe->ju_server, jupe->ju_expire,
209                    jupe->ju_reason);
210 #ifdef JPATH
211     write_log(JPATH, TIME_T_FMT " %s deactivating %sJUPE for %s, expiring at "
212               TIME_T_FMT ": %s\n", TStime(), sptr->name, JupeIsLocal(jupe) ?
213               "local " : "", jupe->ju_server, jupe->ju_expire,
214               jupe->ju_reason);
215 #endif /* JPATH */
216   } else {
217     sendto_op_mask(SNO_NETWORK, "%s deactivating %sJUPE for %s, expiring at "
218                    TIME_T_FMT ": %s", sptr->user->server->name,
219                    JupeIsLocal(jupe) ? "local " : "", jupe->ju_server,
220                    jupe->ju_expire, jupe->ju_reason);
221 #ifdef JPATH
222     write_log(JPATH, TIME_T_FMT, " %s!%s@%s deactivating %sJUPE for %s, "
223               "expiring at " TIME_T_FMT ": %s\n", TStime(), sptr->name,
224               sptr->user->username, sptr->user->host, JupeIsLocal(jupe) ?
225               "local " : "", jupe->ju_server, jupe->ju_expire,
226               jupe->ju_reason);
227 #endif /* JPATH */
228   }
229
230   propagate_jupe(cptr, sptr, jupe);
231
232   return 0;
233 }
234
235 struct Jupe *
236 jupe_find(char *server)
237 {
238   struct Jupe* jupe;
239   struct Jupe* sjupe;
240
241   for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
242     sjupe = jupe->ju_next;
243
244     if (jupe->ju_expire <= TStime()) /* expire any that need expiring */
245       jupe_free(jupe);
246     else if (0 == ircd_strcmp(server, jupe->ju_server)) /* found it yet? */
247       return jupe;
248   }
249
250   return 0;
251 }
252
253 void
254 jupe_free(struct Jupe* jupe)
255 {
256   assert(0 != jupe);
257
258   *jupe->ju_prev_p = jupe->ju_next; /* squeeze this jupe out */
259   if (jupe->ju_next)
260     jupe->ju_next->ju_prev_p = jupe->ju_prev_p;
261
262   MyFree(jupe->ju_server);  /* and free up the memory */
263   MyFree(jupe->ju_reason);
264   MyFree(jupe);
265 }
266
267 void
268 jupe_burst(struct Client *cptr)
269 {
270   struct Jupe *jupe;
271   struct Jupe *sjupe;
272
273   for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
274     sjupe = jupe->ju_next;
275
276     if (jupe->ju_expire <= TStime()) /* expire any that need expiring */
277       jupe_free(jupe);
278     else if (!JupeIsLocal(jupe)) /* forward global jupes */
279       sendcmdto_one(cptr, CMD_JUPE, &me, "* %c%s %Tu %Tu :%s",
280                     JupeIsActive(jupe) ? '+' : '-', jupe->ju_server,
281                     jupe->ju_expire - TStime(), jupe->ju_lastmod,
282                     jupe->ju_reason);
283   }
284 }
285
286 int
287 jupe_resend(struct Client *cptr, struct Jupe *jupe)
288 {
289   if (JupeIsLocal(jupe)) /* don't propagate local jupes */
290     return 0;
291
292   sendcmdto_one(cptr, CMD_JUPE, &me, "* %c%s %Tu %Tu :%s",
293                 JupeIsActive(jupe) ? '+' : '-', jupe->ju_server,
294                 jupe->ju_expire - TStime(), jupe->ju_lastmod, jupe->ju_reason);
295
296   return 0;
297 }
298
299 int
300 jupe_list(struct Client *sptr, char *server)
301 {
302   struct Jupe *jupe;
303   struct Jupe *sjupe;
304
305   if (server) {
306     if (!(jupe = jupe_find(server))) /* no such jupe */
307       return send_error_to_client(sptr, ERR_NOSUCHJUPE, server);
308
309     /* send jupe information along */
310     sendto_one(sptr, rpl_str(RPL_JUPELIST), me.name, sptr->name,
311                jupe->ju_server, jupe->ju_expire, JupeIsLocal(jupe) ?
312                me.name : "*", JupeIsActive(jupe) ? '+' : '-', jupe->ju_reason);
313   } else {
314     for (jupe = GlobalJupeList; jupe; jupe = sjupe) { /* go through jupes */
315       sjupe = jupe->ju_next;
316
317       if (jupe->ju_expire <= TStime()) /* expire any that need expiring */
318         jupe_free(jupe);
319       else /* send jupe information along */
320         sendto_one(sptr, rpl_str(RPL_JUPELIST), me.name, sptr->name,
321                    jupe->ju_server, jupe->ju_expire, JupeIsLocal(jupe) ?
322                    me.name : "*", JupeIsActive(jupe) ? '+' : '-',
323                    jupe->ju_reason);
324     }
325   }
326
327   /* end of jupe information */
328   sendto_one(sptr, rpl_str(RPL_ENDOFJUPELIST), me.name, sptr->name);
329   return 0;
330 }