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