]> jfr.im git - irc/rqf/shadowircd.git/blob - modules/m_resv.c
Add code to expire "propagated" bans.
[irc/rqf/shadowircd.git] / modules / m_resv.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_resv.c: Reserves(jupes) a nickname or channel.
4 *
5 * Copyright (C) 2001-2002 Hybrid Development Team
6 * Copyright (C) 2002-2005 ircd-ratbox development team
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 *
23 * $Id$
24 */
25
26 #include "stdinc.h"
27 #include "client.h"
28 #include "channel.h"
29 #include "ircd.h"
30 #include "numeric.h"
31 #include "s_serv.h"
32 #include "send.h"
33 #include "msg.h"
34 #include "parse.h"
35 #include "modules.h"
36 #include "s_conf.h"
37 #include "s_newconf.h"
38 #include "hash.h"
39 #include "logger.h"
40 #include "bandbi.h"
41 #include "operhash.h"
42
43 static int mo_resv(struct Client *, struct Client *, int, const char **);
44 static int ms_resv(struct Client *, struct Client *, int, const char **);
45 static int me_resv(struct Client *, struct Client *, int, const char **);
46 static int mo_unresv(struct Client *, struct Client *, int, const char **);
47 static int ms_unresv(struct Client *, struct Client *, int, const char **);
48 static int me_unresv(struct Client *, struct Client *, int, const char **);
49
50 struct Message resv_msgtab = {
51 "RESV", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
52 {mg_ignore, mg_not_oper, {ms_resv, 4}, {ms_resv, 4}, {me_resv, 5}, {mo_resv, 3}}
53 };
54
55 struct Message unresv_msgtab = {
56 "UNRESV", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
57 {mg_ignore, mg_not_oper, {ms_unresv, 3}, {ms_unresv, 3}, {me_unresv, 2}, {mo_unresv, 2}}
58 };
59
60 mapi_clist_av1 resv_clist[] = { &resv_msgtab, &unresv_msgtab, NULL };
61
62 DECLARE_MODULE_AV1(resv, NULL, NULL, resv_clist, NULL, NULL, "$Revision$");
63
64 static void parse_resv(struct Client *source_p, const char *name,
65 const char *reason, int temp_time);
66 static void propagate_resv(struct Client *source_p, const char *target,
67 int temp_time, const char *name, const char *reason);
68 static void cluster_resv(struct Client *source_p, int temp_time,
69 const char *name, const char *reason);
70
71 static void handle_remote_unresv(struct Client *source_p, const char *name);
72 static void remove_resv(struct Client *source_p, const char *name);
73 static void resv_chan_forcepart(const char *name, const char *reason, int temp_time);
74
75 /*
76 * mo_resv()
77 * parv[0] = sender prefix
78 * parv[1] = channel/nick to forbid
79 * parv[2] = reason
80 */
81 static int
82 mo_resv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
83 {
84 const char *name;
85 const char *reason;
86 const char *target_server = NULL;
87 int temp_time;
88 int loc = 1;
89
90 if(!IsOperResv(source_p))
91 {
92 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "resv");
93 return 0;
94 }
95
96 /* RESV [time] <name> [ON <server>] :<reason> */
97
98 if((temp_time = valid_temp_time(parv[loc])) >= 0)
99 loc++;
100 /* we just set temp_time to -1! */
101 else
102 temp_time = 0;
103
104 name = parv[loc];
105 loc++;
106
107 if((parc >= loc + 2) && (irccmp(parv[loc], "ON") == 0))
108 {
109 if(!IsOperRemoteBan(source_p))
110 {
111 sendto_one(source_p, form_str(ERR_NOPRIVS),
112 me.name, source_p->name, "remoteban");
113 return 0;
114 }
115
116 target_server = parv[loc + 1];
117 loc += 2;
118 }
119
120 if(parc <= loc || EmptyString(parv[loc]))
121 {
122 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "RESV");
123 return 0;
124 }
125
126 reason = parv[loc];
127
128 /* remote resv.. */
129 if(target_server)
130 {
131 propagate_resv(source_p, target_server, temp_time, name, reason);
132
133 if(match(target_server, me.name) == 0)
134 return 0;
135 }
136 else if(rb_dlink_list_length(&cluster_conf_list) > 0)
137 cluster_resv(source_p, temp_time, name, reason);
138
139 parse_resv(source_p, name, reason, temp_time);
140
141 return 0;
142 }
143
144 /* ms_resv()
145 * parv[0] = sender prefix
146 * parv[1] = target server
147 * parv[2] = channel/nick to forbid
148 * parv[3] = reason
149 */
150 static int
151 ms_resv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
152 {
153 /* parv[0] parv[1] parv[2] parv[3]
154 * oper target server resv reason
155 */
156 propagate_resv(source_p, parv[1], 0, parv[2], parv[3]);
157
158 if(!match(parv[1], me.name))
159 return 0;
160
161 if(!IsPerson(source_p))
162 return 0;
163
164 parse_resv(source_p, parv[2], parv[3], 0);
165 return 0;
166 }
167
168 static int
169 me_resv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
170 {
171 /* time name 0 :reason */
172 if(!IsPerson(source_p))
173 return 0;
174
175 parse_resv(source_p, parv[2], parv[4], atoi(parv[1]));
176 return 0;
177 }
178
179 /* parse_resv()
180 *
181 * inputs - source_p if error messages wanted
182 * - thing to resv
183 * - reason for resv
184 * outputs -
185 * side effects - will parse the resv and create it if valid
186 */
187 static void
188 parse_resv(struct Client *source_p, const char *name, const char *reason, int temp_time)
189 {
190 struct ConfItem *aconf;
191
192 if(!MyClient(source_p) &&
193 !find_shared_conf(source_p->username, source_p->host,
194 source_p->servptr->name,
195 (temp_time > 0) ? SHARED_TRESV : SHARED_PRESV))
196 return;
197
198 if(IsChannelName(name))
199 {
200 if(hash_find_resv(name))
201 {
202 sendto_one_notice(source_p,
203 ":A RESV has already been placed on channel: %s", name);
204 return;
205 }
206
207 if(strlen(name) > CHANNELLEN)
208 {
209 sendto_one_notice(source_p, ":Invalid RESV length: %s", name);
210 return;
211 }
212
213 if(strchr(reason, '"'))
214 {
215 sendto_one_notice(source_p, ":Invalid character '\"' in comment");
216 return;
217 }
218
219 aconf = make_conf();
220 aconf->status = CONF_RESV_CHANNEL;
221 aconf->port = 0;
222 aconf->created = rb_current_time();
223 aconf->host = rb_strdup(name);
224 aconf->passwd = rb_strdup(reason);
225 aconf->info.oper = operhash_add(get_oper_name(source_p));
226 add_to_resv_hash(aconf->host, aconf);
227 resv_chan_forcepart(aconf->host, aconf->passwd, temp_time);
228
229 if(temp_time > 0)
230 {
231 aconf->hold = rb_current_time() + temp_time;
232
233 sendto_realops_snomask(SNO_GENERAL, L_ALL,
234 "%s added temporary %d min. RESV for [%s] [%s]",
235 get_oper_name(source_p), temp_time / 60,
236 name, reason);
237 ilog(L_KLINE, "R %s %d %s %s",
238 get_oper_name(source_p), temp_time / 60, name, reason);
239 sendto_one_notice(source_p, ":Added temporary %d min. RESV [%s]",
240 temp_time / 60, name);
241 }
242 else
243 {
244 sendto_realops_snomask(SNO_GENERAL, L_ALL,
245 "%s added RESV for [%s] [%s]",
246 get_oper_name(source_p), name, reason);
247 ilog(L_KLINE, "R %s 0 %s %s",
248 get_oper_name(source_p), name, reason);
249 sendto_one_notice(source_p, ":Added RESV [%s]", name);
250
251 bandb_add(BANDB_RESV, source_p, aconf->host, NULL, aconf->passwd, NULL, 0);
252 }
253 }
254 else if(clean_resv_nick(name))
255 {
256 if(strlen(name) > NICKLEN * 2)
257 {
258 sendto_one_notice(source_p, ":Invalid RESV length: %s", name);
259 return;
260 }
261
262 if(strchr(reason, '"'))
263 {
264 sendto_one_notice(source_p, ":Invalid character '\"' in comment");
265 return;
266 }
267
268 if(!valid_wild_card_simple(name))
269 {
270 sendto_one_notice(source_p,
271 ":Please include at least %d non-wildcard "
272 "characters with the resv",
273 ConfigFileEntry.min_nonwildcard_simple);
274 return;
275 }
276
277 if(find_nick_resv_mask(name))
278 {
279 sendto_one_notice(source_p,
280 ":A RESV has already been placed on nick: %s", name);
281 return;
282 }
283
284 aconf = make_conf();
285 aconf->status = CONF_RESV_NICK;
286 aconf->port = 0;
287 aconf->created = rb_current_time();
288 aconf->host = rb_strdup(name);
289 aconf->passwd = rb_strdup(reason);
290 aconf->info.oper = operhash_add(get_oper_name(source_p));
291 rb_dlinkAddAlloc(aconf, &resv_conf_list);
292
293 if(temp_time > 0)
294 {
295 aconf->hold = rb_current_time() + temp_time;
296
297 sendto_realops_snomask(SNO_GENERAL, L_ALL,
298 "%s added temporary %d min. RESV for [%s] [%s]",
299 get_oper_name(source_p), temp_time / 60,
300 name, reason);
301 ilog(L_KLINE, "R %s %d %s %s",
302 get_oper_name(source_p), temp_time / 60, name, reason);
303 sendto_one_notice(source_p, ":Added temporary %d min. RESV [%s]",
304 temp_time / 60, name);
305 }
306 else
307 {
308 sendto_realops_snomask(SNO_GENERAL, L_ALL,
309 "%s added RESV for [%s] [%s]",
310 get_oper_name(source_p), name, reason);
311 ilog(L_KLINE, "R %s 0 %s %s",
312 get_oper_name(source_p), name, reason);
313 sendto_one_notice(source_p, ":Added RESV [%s]", name);
314
315 bandb_add(BANDB_RESV, source_p, aconf->host, NULL, aconf->passwd, NULL, 0);
316 }
317 }
318 else
319 sendto_one_notice(source_p, ":You have specified an invalid resv: [%s]", name);
320 }
321
322 static void
323 propagate_resv(struct Client *source_p, const char *target,
324 int temp_time, const char *name, const char *reason)
325 {
326 if(!temp_time)
327 {
328 sendto_match_servs(source_p, target,
329 CAP_CLUSTER, NOCAPS, "RESV %s %s :%s", target, name, reason);
330 sendto_match_servs(source_p, target,
331 CAP_ENCAP, CAP_CLUSTER,
332 "ENCAP %s RESV %d %s 0 :%s", target, temp_time, name, reason);
333 }
334 else
335 sendto_match_servs(source_p, target,
336 CAP_ENCAP, NOCAPS,
337 "ENCAP %s RESV %d %s 0 :%s", target, temp_time, name, reason);
338 }
339
340 static void
341 cluster_resv(struct Client *source_p, int temp_time, const char *name, const char *reason)
342 {
343 struct remote_conf *shared_p;
344 rb_dlink_node *ptr;
345
346 RB_DLINK_FOREACH(ptr, cluster_conf_list.head)
347 {
348 shared_p = ptr->data;
349
350 /* old protocol cant handle temps, and we dont really want
351 * to convert them to perm.. --fl
352 */
353 if(!temp_time)
354 {
355 if(!(shared_p->flags & SHARED_PRESV))
356 continue;
357
358 sendto_match_servs(source_p, shared_p->server,
359 CAP_CLUSTER, NOCAPS,
360 "RESV %s %s :%s", shared_p->server, name, reason);
361 sendto_match_servs(source_p, shared_p->server,
362 CAP_ENCAP, CAP_CLUSTER,
363 "ENCAP %s RESV 0 %s 0 :%s",
364 shared_p->server, name, reason);
365 }
366 else if(shared_p->flags & SHARED_TRESV)
367 sendto_match_servs(source_p, shared_p->server,
368 CAP_ENCAP, NOCAPS,
369 "ENCAP %s RESV %d %s 0 :%s",
370 shared_p->server, temp_time, name, reason);
371 }
372 }
373
374
375 /*
376 * mo_unresv()
377 * parv[0] = sender prefix
378 * parv[1] = channel/nick to unforbid
379 */
380 static int
381 mo_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
382 {
383 if(!IsOperResv(source_p))
384 {
385 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "resv");
386 return 0;
387 }
388
389 if((parc == 4) && (irccmp(parv[2], "ON") == 0))
390 {
391 if(!IsOperRemoteBan(source_p))
392 {
393 sendto_one(source_p, form_str(ERR_NOPRIVS),
394 me.name, source_p->name, "remoteban");
395 return 0;
396 }
397
398 propagate_generic(source_p, "UNRESV", parv[3], CAP_CLUSTER, "%s", parv[1]);
399
400 if(match(parv[3], me.name) == 0)
401 return 0;
402 }
403 else if(rb_dlink_list_length(&cluster_conf_list) > 0)
404 cluster_generic(source_p, "UNRESV", SHARED_UNRESV, CAP_CLUSTER, "%s", parv[1]);
405
406 remove_resv(source_p, parv[1]);
407 return 0;
408 }
409
410 /* ms_unresv()
411 * parv[0] = sender prefix
412 * parv[1] = target server
413 * parv[2] = resv to remove
414 */
415 static int
416 ms_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
417 {
418 /* parv[0] parv[1] parv[2]
419 * oper target server resv to remove
420 */
421 propagate_generic(source_p, "UNRESV", parv[1], CAP_CLUSTER, "%s", parv[2]);
422
423 if(!match(parv[1], me.name))
424 return 0;
425
426 if(!IsPerson(source_p))
427 return 0;
428
429 handle_remote_unresv(source_p, parv[2]);
430 return 0;
431 }
432
433 static int
434 me_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
435 {
436 /* name */
437 if(!IsPerson(source_p))
438 return 0;
439
440 handle_remote_unresv(source_p, parv[1]);
441 return 0;
442 }
443
444 static void
445 handle_remote_unresv(struct Client *source_p, const char *name)
446 {
447 if(!find_shared_conf(source_p->username, source_p->host,
448 source_p->servptr->name, SHARED_UNRESV))
449 return;
450
451 remove_resv(source_p, name);
452
453 return;
454 }
455
456 static void
457 remove_resv(struct Client *source_p, const char *name)
458 {
459 struct ConfItem *aconf = NULL;
460
461 if(IsChannelName(name))
462 {
463 if((aconf = hash_find_resv(name)) == NULL)
464 {
465 sendto_one_notice(source_p, ":No RESV for %s", name);
466 return;
467 }
468
469 sendto_one_notice(source_p, ":RESV for [%s] is removed", name);
470 ilog(L_KLINE, "UR %s %s", get_oper_name(source_p), name);
471 if(!aconf->hold)
472 {
473 bandb_del(BANDB_RESV, aconf->host, NULL);
474 sendto_realops_snomask(SNO_GENERAL, L_ALL,
475 "%s has removed the RESV for: [%s]",
476 get_oper_name(source_p), name);
477 }
478 else
479 {
480 sendto_realops_snomask(SNO_GENERAL, L_ALL,
481 "%s has removed the temporary RESV for: [%s]",
482 get_oper_name(source_p), name);
483 }
484 del_from_resv_hash(name, aconf);
485 }
486 else
487 {
488 rb_dlink_node *ptr;
489
490 RB_DLINK_FOREACH(ptr, resv_conf_list.head)
491 {
492 aconf = ptr->data;
493
494 if(irccmp(aconf->host, name))
495 aconf = NULL;
496 else
497 break;
498 }
499
500 if(aconf == NULL)
501 {
502 sendto_one_notice(source_p, ":No RESV for %s", name);
503 return;
504 }
505
506 if(!aconf->hold)
507 bandb_del(BANDB_RESV, aconf->host, NULL);
508 else
509 {
510 sendto_one_notice(source_p, ":RESV for [%s] is removed", name);
511 sendto_realops_snomask(SNO_GENERAL, L_ALL,
512 "%s has removed the RESV for: [%s]",
513 get_oper_name(source_p), name);
514 ilog(L_KLINE, "UR %s %s", get_oper_name(source_p), name);
515 }
516 /* already have ptr from the loop above.. */
517 rb_dlinkDestroy(ptr, &resv_conf_list);
518 }
519 free_conf(aconf);
520
521 return;
522 }
523
524 static void
525 resv_chan_forcepart(const char *name, const char *reason, int temp_time)
526 {
527 rb_dlink_node *ptr;
528 rb_dlink_node *next_ptr;
529 struct Channel *chptr;
530 struct membership *msptr;
531 struct Client *target_p;
532
533 if(!ConfigChannel.resv_forcepart)
534 return;
535
536 /* for each user on our server in the channel list
537 * send them a PART, and notify opers.
538 */
539 chptr = find_channel(name);
540 if(chptr != NULL)
541 {
542 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, chptr->locmembers.head)
543 {
544 msptr = ptr->data;
545 target_p = msptr->client_p;
546
547 if(IsExemptResv(target_p))
548 continue;
549
550 sendto_server(target_p, chptr, CAP_TS6, NOCAPS,
551 ":%s PART %s", target_p->id, chptr->chname);
552
553 sendto_channel_local(ALL_MEMBERS, chptr, ":%s!%s@%s PART %s :%s",
554 target_p->name, target_p->username,
555 target_p->host, chptr->chname, target_p->name);
556
557 remove_user_from_channel(msptr);
558
559 /* notify opers & user they were removed from the channel */
560 sendto_realops_snomask(SNO_GENERAL, L_ALL,
561 "Forced PART for %s!%s@%s from %s (%s)",
562 target_p->name, target_p->username,
563 target_p->host, name, reason);
564
565 if(temp_time > 0)
566 sendto_one_notice(target_p, ":*** Channel %s is temporarily unavailable on this server.",
567 name);
568 else
569 sendto_one_notice(target_p, ":*** Channel %s is no longer available on this server.",
570 name);
571 }
572 }
573 }