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