]> jfr.im git - irc/rqf/shadowircd.git/blame - modules/m_resv.c
BAN: Avoid fake direction.
[irc/rqf/shadowircd.git] / modules / m_resv.c
CommitLineData
212380e3 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 *
d8a4c5f6 23 * $Id$
212380e3 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"
d3455e2c 39#include "logger.h"
d8a4c5f6 40#include "bandbi.h"
a0f4c418 41#include "operhash.h"
212380e3 42
43static int mo_resv(struct Client *, struct Client *, int, const char **);
44static int ms_resv(struct Client *, struct Client *, int, const char **);
45static int me_resv(struct Client *, struct Client *, int, const char **);
46static int mo_unresv(struct Client *, struct Client *, int, const char **);
47static int ms_unresv(struct Client *, struct Client *, int, const char **);
48static int me_unresv(struct Client *, struct Client *, int, const char **);
49
50struct 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};
d8a4c5f6 54
212380e3 55struct 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
d8a4c5f6
WP
60mapi_clist_av1 resv_clist[] = { &resv_msgtab, &unresv_msgtab, NULL };
61
62DECLARE_MODULE_AV1(resv, NULL, NULL, resv_clist, NULL, NULL, "$Revision$");
212380e3 63
64static void parse_resv(struct Client *source_p, const char *name,
d8a4c5f6 65 const char *reason, int temp_time);
212380e3 66static void propagate_resv(struct Client *source_p, const char *target,
d8a4c5f6
WP
67 int temp_time, const char *name, const char *reason);
68static void cluster_resv(struct Client *source_p, int temp_time,
69 const char *name, const char *reason);
212380e3 70
71static void handle_remote_unresv(struct Client *source_p, const char *name);
72static void remove_resv(struct Client *source_p, const char *name);
609a0d55 73static void resv_chan_forcepart(const char *name, const char *reason, int temp_time);
212380e3 74
75/*
76 * mo_resv()
d8a4c5f6 77 * parv[0] = sender prefix
212380e3 78 * parv[1] = channel/nick to forbid
79 * parv[2] = reason
80 */
81static int
82mo_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
1ebe6ffc
JT
90 if(!IsOperResv(source_p))
91 {
d8a4c5f6 92 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "resv");
1ebe6ffc
JT
93 return 0;
94 }
95
212380e3 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
d8a4c5f6 107 if((parc >= loc + 2) && (irccmp(parv[loc], "ON") == 0))
212380e3 108 {
109 if(!IsOperRemoteBan(source_p))
110 {
111 sendto_one(source_p, form_str(ERR_NOPRIVS),
d8a4c5f6 112 me.name, source_p->name, "remoteban");
212380e3 113 return 0;
114 }
115
d8a4c5f6 116 target_server = parv[loc + 1];
212380e3 117 loc += 2;
118 }
119
120 if(parc <= loc || EmptyString(parv[loc]))
121 {
d8a4c5f6 122 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS), me.name, source_p->name, "RESV");
212380e3 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 }
08d11e34 136 else if(rb_dlink_list_length(&cluster_conf_list) > 0)
212380e3 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()
d8a4c5f6 145 * parv[0] = sender prefix
212380e3 146 * parv[1] = target server
147 * parv[2] = channel/nick to forbid
148 * parv[3] = reason
149 */
150static int
d8a4c5f6 151ms_resv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3 152{
d8a4c5f6
WP
153 /* parv[0] parv[1] parv[2] parv[3]
154 * oper target server resv reason
212380e3 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
168static int
d8a4c5f6 169me_resv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3 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 */
187static void
d8a4c5f6 188parse_resv(struct Client *source_p, const char *name, const char *reason, int temp_time)
212380e3 189{
190 struct ConfItem *aconf;
191
d8a4c5f6 192 if(!MyClient(source_p) &&
212380e3 193 !find_shared_conf(source_p->username, source_p->host,
d8a4c5f6
WP
194 source_p->servptr->name,
195 (temp_time > 0) ? SHARED_TRESV : SHARED_PRESV))
212380e3 196 return;
197
198 if(IsChannelName(name))
199 {
200 if(hash_find_resv(name))
201 {
202 sendto_one_notice(source_p,
d8a4c5f6 203 ":A RESV has already been placed on channel: %s", name);
212380e3 204 return;
205 }
206
207 if(strlen(name) > CHANNELLEN)
208 {
d8a4c5f6 209 sendto_one_notice(source_p, ":Invalid RESV length: %s", name);
6e5b8a5d
JT
210 return;
211 }
212380e3 212
213 if(strchr(reason, '"'))
214 {
d8a4c5f6 215 sendto_one_notice(source_p, ":Invalid character '\"' in comment");
212380e3 216 return;
217 }
218
219 aconf = make_conf();
220 aconf->status = CONF_RESV_CHANNEL;
221 aconf->port = 0;
ce60772d 222 aconf->created = rb_current_time();
ff0482a9 223 aconf->host = rb_strdup(name);
62d28946 224 aconf->passwd = rb_strdup(reason);
a0f4c418 225 aconf->info.oper = operhash_add(get_oper_name(source_p));
ff0482a9 226 add_to_resv_hash(aconf->host, aconf);
609a0d55 227 resv_chan_forcepart(aconf->host, aconf->passwd, temp_time);
212380e3 228
229 if(temp_time > 0)
230 {
9f6bbe3c 231 aconf->hold = rb_current_time() + temp_time;
212380e3 232
233 sendto_realops_snomask(SNO_GENERAL, L_ALL,
d8a4c5f6
WP
234 "%s added temporary %d min. RESV for [%s] [%s]",
235 get_oper_name(source_p), temp_time / 60,
236 name, reason);
212380e3 237 ilog(L_KLINE, "R %s %d %s %s",
d8a4c5f6 238 get_oper_name(source_p), temp_time / 60, name, reason);
212380e3 239 sendto_one_notice(source_p, ":Added temporary %d min. RESV [%s]",
d8a4c5f6 240 temp_time / 60, name);
212380e3 241 }
242 else
4cb3ae78
WP
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
ff0482a9 251 bandb_add(BANDB_RESV, source_p, aconf->host, NULL, aconf->passwd, NULL, 0);
4cb3ae78 252 }
212380e3 253 }
254 else if(clean_resv_nick(name))
255 {
d8a4c5f6 256 if(strlen(name) > NICKLEN * 2)
212380e3 257 {
d8a4c5f6 258 sendto_one_notice(source_p, ":Invalid RESV length: %s", name);
212380e3 259 return;
260 }
261
262 if(strchr(reason, '"'))
263 {
d8a4c5f6 264 sendto_one_notice(source_p, ":Invalid character '\"' in comment");
212380e3 265 return;
266 }
267
268 if(!valid_wild_card_simple(name))
269 {
270 sendto_one_notice(source_p,
d8a4c5f6
WP
271 ":Please include at least %d non-wildcard "
272 "characters with the resv",
273 ConfigFileEntry.min_nonwildcard_simple);
212380e3 274 return;
275 }
276
0fdb2570 277 if(find_nick_resv_mask(name))
212380e3 278 {
279 sendto_one_notice(source_p,
d8a4c5f6 280 ":A RESV has already been placed on nick: %s", name);
212380e3 281 return;
282 }
283
284 aconf = make_conf();
285 aconf->status = CONF_RESV_NICK;
286 aconf->port = 0;
ce60772d 287 aconf->created = rb_current_time();
ff0482a9 288 aconf->host = rb_strdup(name);
62d28946 289 aconf->passwd = rb_strdup(reason);
a0f4c418 290 aconf->info.oper = operhash_add(get_oper_name(source_p));
7f4fa195 291 rb_dlinkAddAlloc(aconf, &resv_conf_list);
212380e3 292
293 if(temp_time > 0)
294 {
9f6bbe3c 295 aconf->hold = rb_current_time() + temp_time;
212380e3 296
297 sendto_realops_snomask(SNO_GENERAL, L_ALL,
d8a4c5f6
WP
298 "%s added temporary %d min. RESV for [%s] [%s]",
299 get_oper_name(source_p), temp_time / 60,
300 name, reason);
212380e3 301 ilog(L_KLINE, "R %s %d %s %s",
d8a4c5f6 302 get_oper_name(source_p), temp_time / 60, name, reason);
212380e3 303 sendto_one_notice(source_p, ":Added temporary %d min. RESV [%s]",
d8a4c5f6 304 temp_time / 60, name);
212380e3 305 }
306 else
4cb3ae78
WP
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
ff0482a9 315 bandb_add(BANDB_RESV, source_p, aconf->host, NULL, aconf->passwd, NULL, 0);
4cb3ae78 316 }
212380e3 317 }
318 else
d8a4c5f6 319 sendto_one_notice(source_p, ":You have specified an invalid resv: [%s]", name);
212380e3 320}
321
d8a4c5f6 322static void
212380e3 323propagate_resv(struct Client *source_p, const char *target,
d8a4c5f6 324 int temp_time, const char *name, const char *reason)
212380e3 325{
326 if(!temp_time)
327 {
328 sendto_match_servs(source_p, target,
d8a4c5f6 329 CAP_CLUSTER, NOCAPS, "RESV %s %s :%s", target, name, reason);
212380e3 330 sendto_match_servs(source_p, target,
d8a4c5f6
WP
331 CAP_ENCAP, CAP_CLUSTER,
332 "ENCAP %s RESV %d %s 0 :%s", target, temp_time, name, reason);
212380e3 333 }
334 else
335 sendto_match_servs(source_p, target,
d8a4c5f6
WP
336 CAP_ENCAP, NOCAPS,
337 "ENCAP %s RESV %d %s 0 :%s", target, temp_time, name, reason);
212380e3 338}
339
340static void
d8a4c5f6 341cluster_resv(struct Client *source_p, int temp_time, const char *name, const char *reason)
212380e3 342{
343 struct remote_conf *shared_p;
08d11e34 344 rb_dlink_node *ptr;
212380e3 345
08d11e34 346 RB_DLINK_FOREACH(ptr, cluster_conf_list.head)
212380e3 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,
d8a4c5f6
WP
359 CAP_CLUSTER, NOCAPS,
360 "RESV %s %s :%s", shared_p->server, name, reason);
212380e3 361 sendto_match_servs(source_p, shared_p->server,
d8a4c5f6
WP
362 CAP_ENCAP, CAP_CLUSTER,
363 "ENCAP %s RESV 0 %s 0 :%s",
364 shared_p->server, name, reason);
212380e3 365 }
366 else if(shared_p->flags & SHARED_TRESV)
367 sendto_match_servs(source_p, shared_p->server,
d8a4c5f6
WP
368 CAP_ENCAP, NOCAPS,
369 "ENCAP %s RESV %d %s 0 :%s",
370 shared_p->server, temp_time, name, reason);
212380e3 371 }
372}
373
374
375/*
376 * mo_unresv()
d8a4c5f6 377 * parv[0] = sender prefix
212380e3 378 * parv[1] = channel/nick to unforbid
379 */
380static int
381mo_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
382{
1ebe6ffc
JT
383 if(!IsOperResv(source_p))
384 {
d8a4c5f6 385 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "resv");
1ebe6ffc
JT
386 return 0;
387 }
388
212380e3 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),
d8a4c5f6 394 me.name, source_p->name, "remoteban");
212380e3 395 return 0;
396 }
397
d8a4c5f6 398 propagate_generic(source_p, "UNRESV", parv[3], CAP_CLUSTER, "%s", parv[1]);
212380e3 399
400 if(match(parv[3], me.name) == 0)
401 return 0;
402 }
08d11e34 403 else if(rb_dlink_list_length(&cluster_conf_list) > 0)
d8a4c5f6 404 cluster_generic(source_p, "UNRESV", SHARED_UNRESV, CAP_CLUSTER, "%s", parv[1]);
212380e3 405
212380e3 406 remove_resv(source_p, parv[1]);
407 return 0;
408}
409
410/* ms_unresv()
d8a4c5f6 411 * parv[0] = sender prefix
212380e3 412 * parv[1] = target server
413 * parv[2] = resv to remove
414 */
415static int
416ms_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
417{
d8a4c5f6
WP
418 /* parv[0] parv[1] parv[2]
419 * oper target server resv to remove
212380e3 420 */
d8a4c5f6 421 propagate_generic(source_p, "UNRESV", parv[1], CAP_CLUSTER, "%s", parv[2]);
212380e3 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
433static int
434me_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
444static void
445handle_remote_unresv(struct Client *source_p, const char *name)
446{
447 if(!find_shared_conf(source_p->username, source_p->host,
d8a4c5f6 448 source_p->servptr->name, SHARED_UNRESV))
212380e3 449 return;
450
212380e3 451 remove_resv(source_p, name);
452
453 return;
454}
455
1328da86
JT
456static void
457remove_resv(struct Client *source_p, const char *name)
212380e3 458{
459 struct ConfItem *aconf = NULL;
460
461 if(IsChannelName(name))
462 {
463 if((aconf = hash_find_resv(name)) == NULL)
1328da86
JT
464 {
465 sendto_one_notice(source_p, ":No RESV for %s", name);
466 return;
467 }
212380e3 468
ddbd4a81
JT
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);
212380e3 471 if(!aconf->hold)
4d9be1a6 472 {
d8a4c5f6 473 bandb_del(BANDB_RESV, aconf->host, NULL);
4d9be1a6
JT
474 sendto_realops_snomask(SNO_GENERAL, L_ALL,
475 "%s has removed the RESV for: [%s]",
476 get_oper_name(source_p), name);
4d9be1a6 477 }
1328da86
JT
478 else
479 {
1328da86 480 sendto_realops_snomask(SNO_GENERAL, L_ALL,
ddbd4a81 481 "%s has removed the temporary RESV for: [%s]",
d8a4c5f6 482 get_oper_name(source_p), name);
1328da86 483 }
212380e3 484 del_from_resv_hash(name, aconf);
212380e3 485 }
486 else
487 {
08d11e34 488 rb_dlink_node *ptr;
212380e3 489
08d11e34 490 RB_DLINK_FOREACH(ptr, resv_conf_list.head)
212380e3 491 {
492 aconf = ptr->data;
493
ff0482a9 494 if(irccmp(aconf->host, name))
212380e3 495 aconf = NULL;
496 else
497 break;
498 }
499
500 if(aconf == NULL)
1328da86
JT
501 {
502 sendto_one_notice(source_p, ":No RESV for %s", name);
503 return;
504 }
212380e3 505
212380e3 506 if(!aconf->hold)
d8a4c5f6 507 bandb_del(BANDB_RESV, aconf->host, NULL);
1328da86
JT
508 else
509 {
510 sendto_one_notice(source_p, ":RESV for [%s] is removed", name);
511 sendto_realops_snomask(SNO_GENERAL, L_ALL,
d8a4c5f6
WP
512 "%s has removed the RESV for: [%s]",
513 get_oper_name(source_p), name);
1328da86
JT
514 ilog(L_KLINE, "UR %s %s", get_oper_name(source_p), name);
515 }
212380e3 516 /* already have ptr from the loop above.. */
9f6c3353 517 rb_dlinkDestroy(ptr, &resv_conf_list);
212380e3 518 }
1328da86 519 free_conf(aconf);
212380e3 520
1328da86 521 return;
212380e3 522}
609a0d55
JT
523
524static void
525resv_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}