]> jfr.im git - irc/rqf/shadowircd.git/blame - modules/m_resv.c
bork bork bork
[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 *
23 * $Id: m_resv.c 3045 2006-12-26 23:16:57Z jilles $
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 "s_log.h"
40#include "sprintf_irc.h"
41
42static int mo_resv(struct Client *, struct Client *, int, const char **);
43static int ms_resv(struct Client *, struct Client *, int, const char **);
44static int me_resv(struct Client *, struct Client *, int, const char **);
45static int mo_unresv(struct Client *, struct Client *, int, const char **);
46static int ms_unresv(struct Client *, struct Client *, int, const char **);
47static int me_unresv(struct Client *, struct Client *, int, const char **);
48
49struct Message resv_msgtab = {
50 "RESV", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
51 {mg_ignore, mg_not_oper, {ms_resv, 4}, {ms_resv, 4}, {me_resv, 5}, {mo_resv, 3}}
52};
53struct Message unresv_msgtab = {
54 "UNRESV", 0, 0, 0, MFLG_SLOW | MFLG_UNREG,
55 {mg_ignore, mg_not_oper, {ms_unresv, 3}, {ms_unresv, 3}, {me_unresv, 2}, {mo_unresv, 2}}
56};
57
58mapi_clist_av1 resv_clist[] = { &resv_msgtab, &unresv_msgtab, NULL };
59DECLARE_MODULE_AV1(resv, NULL, NULL, resv_clist, NULL, NULL, "$Revision: 3045 $");
60
61static void parse_resv(struct Client *source_p, const char *name,
62 const char *reason, int temp_time);
63static void propagate_resv(struct Client *source_p, const char *target,
64 int temp_time, const char *name, const char *reason);
65static void cluster_resv(struct Client *source_p, int temp_time,
66 const char *name, const char *reason);
67
68static void handle_remote_unresv(struct Client *source_p, const char *name);
69static void remove_resv(struct Client *source_p, const char *name);
1328da86 70static int remove_resv_from_file(struct Client *source_p, const char *name);
212380e3 71
72/*
73 * mo_resv()
74 * parv[0] = sender prefix
75 * parv[1] = channel/nick to forbid
76 * parv[2] = reason
77 */
78static int
79mo_resv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
80{
81 const char *name;
82 const char *reason;
83 const char *target_server = NULL;
84 int temp_time;
85 int loc = 1;
86
1ebe6ffc
JT
87 if(!IsOperResv(source_p))
88 {
89 sendto_one(source_p, form_str(ERR_NOPRIVS),
90 me.name, source_p->name, "resv");
91 return 0;
92 }
93
212380e3 94 /* RESV [time] <name> [ON <server>] :<reason> */
95
96 if((temp_time = valid_temp_time(parv[loc])) >= 0)
97 loc++;
98 /* we just set temp_time to -1! */
99 else
100 temp_time = 0;
101
102 name = parv[loc];
103 loc++;
104
105 if((parc >= loc+2) && (irccmp(parv[loc], "ON") == 0))
106 {
107 if(!IsOperRemoteBan(source_p))
108 {
109 sendto_one(source_p, form_str(ERR_NOPRIVS),
110 me.name, source_p->name, "remoteban");
111 return 0;
112 }
113
114 target_server = parv[loc+1];
115 loc += 2;
116 }
117
118 if(parc <= loc || EmptyString(parv[loc]))
119 {
120 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
121 me.name, source_p->name, "RESV");
122 return 0;
123 }
124
125 reason = parv[loc];
126
127 /* remote resv.. */
128 if(target_server)
129 {
130 propagate_resv(source_p, target_server, temp_time, name, reason);
131
132 if(match(target_server, me.name) == 0)
133 return 0;
134 }
135 else if(dlink_list_length(&cluster_conf_list) > 0)
136 cluster_resv(source_p, temp_time, name, reason);
137
138 parse_resv(source_p, name, reason, temp_time);
139
140 return 0;
141}
142
143/* ms_resv()
144 * parv[0] = sender prefix
145 * parv[1] = target server
146 * parv[2] = channel/nick to forbid
147 * parv[3] = reason
148 */
149static int
150ms_resv(struct Client *client_p, struct Client *source_p,
151 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
168static int
169me_resv(struct Client *client_p, struct Client *source_p,
170 int parc, const char *parv[])
171{
172 /* time name 0 :reason */
173 if(!IsPerson(source_p))
174 return 0;
175
176 parse_resv(source_p, parv[2], parv[4], atoi(parv[1]));
177 return 0;
178}
179
180/* parse_resv()
181 *
182 * inputs - source_p if error messages wanted
183 * - thing to resv
184 * - reason for resv
185 * outputs -
186 * side effects - will parse the resv and create it if valid
187 */
188static void
189parse_resv(struct Client *source_p, const char *name,
190 const char *reason, int temp_time)
191{
192 struct ConfItem *aconf;
193
194 if(!MyClient(source_p) &&
195 !find_shared_conf(source_p->username, source_p->host,
c88cdb00 196 source_p->servptr->name,
212380e3 197 (temp_time > 0) ? SHARED_TRESV : SHARED_PRESV))
198 return;
199
200 if(IsChannelName(name))
201 {
202 if(hash_find_resv(name))
203 {
204 sendto_one_notice(source_p,
205 ":A RESV has already been placed on channel: %s",
206 name);
207 return;
208 }
209
210 if(strlen(name) > CHANNELLEN)
211 {
212 sendto_one_notice(source_p, ":Invalid RESV length: %s",
213 name);
214 return;
215 }
216
217 if(strchr(reason, '"'))
218 {
219 sendto_one_notice(source_p,
220 ":Invalid character '\"' in comment");
221 return;
222 }
223
224 aconf = make_conf();
225 aconf->status = CONF_RESV_CHANNEL;
226 aconf->port = 0;
227 DupString(aconf->name, name);
228 DupString(aconf->passwd, reason);
229 add_to_resv_hash(aconf->name, aconf);
230
231 if(temp_time > 0)
232 {
233 aconf->hold = CurrentTime + temp_time;
234
235 sendto_realops_snomask(SNO_GENERAL, L_ALL,
236 "%s added temporary %d min. RESV for [%s] [%s]",
237 get_oper_name(source_p), temp_time / 60,
238 name, reason);
239 ilog(L_KLINE, "R %s %d %s %s",
240 get_oper_name(source_p), temp_time / 60,
241 name, reason);
242 sendto_one_notice(source_p, ":Added temporary %d min. RESV [%s]",
243 temp_time / 60, name);
244 }
245 else
246 write_confitem(RESV_TYPE, source_p, NULL, aconf->name,
247 aconf->passwd, NULL, NULL, 0);
248 }
249 else if(clean_resv_nick(name))
250 {
251 if(strlen(name) > NICKLEN*2)
252 {
253 sendto_one_notice(source_p, ":Invalid RESV length: %s",
254 name);
255 return;
256 }
257
258 if(strchr(reason, '"'))
259 {
260 sendto_one_notice(source_p,
261 ":Invalid character '\"' in comment");
262 return;
263 }
264
265 if(!valid_wild_card_simple(name))
266 {
267 sendto_one_notice(source_p,
268 ":Please include at least %d non-wildcard "
269 "characters with the resv",
270 ConfigFileEntry.min_nonwildcard_simple);
271 return;
272 }
273
0fdb2570 274 if(find_nick_resv_mask(name))
212380e3 275 {
276 sendto_one_notice(source_p,
277 ":A RESV has already been placed on nick: %s",
278 name);
279 return;
280 }
281
282 aconf = make_conf();
283 aconf->status = CONF_RESV_NICK;
284 aconf->port = 0;
285 DupString(aconf->name, name);
286 DupString(aconf->passwd, reason);
287 dlinkAddAlloc(aconf, &resv_conf_list);
288
289 if(temp_time > 0)
290 {
291 aconf->hold = CurrentTime + temp_time;
292
293 sendto_realops_snomask(SNO_GENERAL, L_ALL,
294 "%s added temporary %d min. RESV for [%s] [%s]",
295 get_oper_name(source_p), temp_time / 60,
296 name, reason);
297 ilog(L_KLINE, "R %s %d %s %s",
298 get_oper_name(source_p), temp_time / 60,
299 name, reason);
300 sendto_one_notice(source_p, ":Added temporary %d min. RESV [%s]",
301 temp_time / 60, name);
302 }
303 else
304 write_confitem(RESV_TYPE, source_p, NULL, aconf->name,
305 aconf->passwd, NULL, NULL, 0);
306 }
307 else
308 sendto_one_notice(source_p,
309 ":You have specified an invalid resv: [%s]",
310 name);
311}
312
313static void
314propagate_resv(struct Client *source_p, const char *target,
315 int temp_time, const char *name, const char *reason)
316{
317 if(!temp_time)
318 {
319 sendto_match_servs(source_p, target,
320 CAP_CLUSTER, NOCAPS,
321 "RESV %s %s :%s",
322 target, name, reason);
323 sendto_match_servs(source_p, target,
324 CAP_ENCAP, CAP_CLUSTER,
325 "ENCAP %s RESV %d %s 0 :%s",
326 target, temp_time, name, reason);
327 }
328 else
329 sendto_match_servs(source_p, target,
330 CAP_ENCAP, NOCAPS,
331 "ENCAP %s RESV %d %s 0 :%s",
332 target, temp_time, name, reason);
333}
334
335static void
336cluster_resv(struct Client *source_p, int temp_time, const char *name,
337 const char *reason)
338{
339 struct remote_conf *shared_p;
340 dlink_node *ptr;
341
342 DLINK_FOREACH(ptr, cluster_conf_list.head)
343 {
344 shared_p = ptr->data;
345
346 /* old protocol cant handle temps, and we dont really want
347 * to convert them to perm.. --fl
348 */
349 if(!temp_time)
350 {
351 if(!(shared_p->flags & SHARED_PRESV))
352 continue;
353
354 sendto_match_servs(source_p, shared_p->server,
355 CAP_CLUSTER, NOCAPS,
356 "RESV %s %s :%s",
357 shared_p->server, name, reason);
358 sendto_match_servs(source_p, shared_p->server,
359 CAP_ENCAP, CAP_CLUSTER,
360 "ENCAP %s RESV 0 %s 0 :%s",
361 shared_p->server, name, reason);
362 }
363 else if(shared_p->flags & SHARED_TRESV)
364 sendto_match_servs(source_p, shared_p->server,
365 CAP_ENCAP, NOCAPS,
366 "ENCAP %s RESV %d %s 0 :%s",
367 shared_p->server, temp_time, name, reason);
368 }
369}
370
371
372/*
373 * mo_unresv()
374 * parv[0] = sender prefix
375 * parv[1] = channel/nick to unforbid
376 */
377static int
378mo_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
379{
1ebe6ffc
JT
380 if(!IsOperResv(source_p))
381 {
382 sendto_one(source_p, form_str(ERR_NOPRIVS),
383 me.name, source_p->name, "resv");
384 return 0;
385 }
386
212380e3 387 if((parc == 4) && (irccmp(parv[2], "ON") == 0))
388 {
389 if(!IsOperRemoteBan(source_p))
390 {
391 sendto_one(source_p, form_str(ERR_NOPRIVS),
392 me.name, source_p->name, "remoteban");
393 return 0;
394 }
395
396 propagate_generic(source_p, "UNRESV", parv[3], CAP_CLUSTER,
397 "%s", parv[1]);
398
399 if(match(parv[3], me.name) == 0)
400 return 0;
401 }
402 else if(dlink_list_length(&cluster_conf_list) > 0)
403 cluster_generic(source_p, "UNRESV", SHARED_UNRESV, CAP_CLUSTER,
404 "%s", parv[1]);
405
212380e3 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 */
415static int
416ms_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,
422 "%s", parv[2]);
423
424 if(!match(parv[1], me.name))
425 return 0;
426
427 if(!IsPerson(source_p))
428 return 0;
429
430 handle_remote_unresv(source_p, parv[2]);
431 return 0;
432}
433
434static int
435me_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
436{
437 /* name */
438 if(!IsPerson(source_p))
439 return 0;
440
441 handle_remote_unresv(source_p, parv[1]);
442 return 0;
443}
444
445static void
446handle_remote_unresv(struct Client *source_p, const char *name)
447{
448 if(!find_shared_conf(source_p->username, source_p->host,
c88cdb00 449 source_p->servptr->name, SHARED_UNRESV))
212380e3 450 return;
451
212380e3 452 remove_resv(source_p, name);
453
454 return;
455}
456
1328da86
JT
457static void
458remove_resv(struct Client *source_p, const char *name)
212380e3 459{
460 struct ConfItem *aconf = NULL;
461
462 if(IsChannelName(name))
463 {
464 if((aconf = hash_find_resv(name)) == NULL)
1328da86
JT
465 {
466 sendto_one_notice(source_p, ":No RESV for %s", name);
467 return;
468 }
212380e3 469
212380e3 470 if(!aconf->hold)
1328da86
JT
471 {
472 if (!remove_resv_from_file(source_p, name))
473 return;
474 }
475 else
476 {
477 sendto_one_notice(source_p, ":RESV for [%s] is removed", name);
478 sendto_realops_snomask(SNO_GENERAL, L_ALL,
479 "%s has removed the RESV for: [%s]",
480 get_oper_name(source_p), name);
481 ilog(L_KLINE, "UR %s %s", get_oper_name(source_p), name);
482 }
212380e3 483 del_from_resv_hash(name, aconf);
212380e3 484 }
485 else
486 {
487 dlink_node *ptr;
488
489 DLINK_FOREACH(ptr, resv_conf_list.head)
490 {
491 aconf = ptr->data;
492
493 if(irccmp(aconf->name, name))
494 aconf = NULL;
495 else
496 break;
497 }
498
499 if(aconf == NULL)
1328da86
JT
500 {
501 sendto_one_notice(source_p, ":No RESV for %s", name);
502 return;
503 }
212380e3 504
212380e3 505 if(!aconf->hold)
1328da86
JT
506 {
507 if (!remove_resv_from_file(source_p, name))
508 return;
509 }
510 else
511 {
512 sendto_one_notice(source_p, ":RESV for [%s] is removed", name);
513 sendto_realops_snomask(SNO_GENERAL, L_ALL,
514 "%s has removed the RESV for: [%s]",
515 get_oper_name(source_p), name);
516 ilog(L_KLINE, "UR %s %s", get_oper_name(source_p), name);
517 }
212380e3 518 /* already have ptr from the loop above.. */
519 dlinkDestroy(ptr, &resv_conf_list);
212380e3 520 }
1328da86 521 free_conf(aconf);
212380e3 522
1328da86 523 return;
212380e3 524}
525
1328da86 526/* remove_resv_from_file()
212380e3 527 *
528 * inputs - client removing the resv
529 * - resv to remove
530 * outputs -
1328da86
JT
531 * side effects - resv if found, is removed from conf
532 * - does not touch resv hash or resv_conf_list
212380e3 533 */
1328da86
JT
534static int
535remove_resv_from_file(struct Client *source_p, const char *name)
212380e3 536{
537 FILE *in, *out;
538 char buf[BUFSIZE];
539 char buff[BUFSIZE];
540 char temppath[BUFSIZE];
541 const char *filename;
542 mode_t oldumask;
543 char *p;
544 int error_on_write = 0;
545 int found_resv = 0;
546
547 ircsprintf(temppath, "%s.tmp", ConfigFileEntry.resvfile);
548 filename = get_conf_name(RESV_TYPE);
549
550 if((in = fopen(filename, "r")) == NULL)
551 {
552 sendto_one_notice(source_p, ":Cannot open %s", filename);
1328da86 553 return 0;
212380e3 554 }
555
556 oldumask = umask(0);
557
558 if((out = fopen(temppath, "w")) == NULL)
559 {
560 sendto_one_notice(source_p, ":Cannot open %s", temppath);
561 fclose(in);
562 umask(oldumask);
1328da86 563 return 0;
212380e3 564 }
565
566 umask(oldumask);
567
568 while (fgets(buf, sizeof(buf), in))
569 {
570 const char *resv_name;
571
572 if(error_on_write)
573 {
574 if(temppath != NULL)
575 (void) unlink(temppath);
576
577 break;
578 }
579
580 strlcpy(buff, buf, sizeof(buff));
581
582 if((p = strchr(buff, '\n')) != NULL)
583 *p = '\0';
584
585 if((*buff == '\0') || (*buff == '#'))
586 {
587 error_on_write = (fputs(buf, out) < 0) ? YES : NO;
588 continue;
589 }
590
591 if((resv_name = getfield(buff)) == NULL)
592 {
593 error_on_write = (fputs(buf, out) < 0) ? YES : NO;
594 continue;
595 }
596
597 if(irccmp(resv_name, name) == 0)
598 {
599 found_resv++;
600 }
601 else
602 {
603 error_on_write = (fputs(buf, out) < 0) ? YES : NO;
604 }
605 }
606
607 fclose(in);
608 if (fclose(out))
609 error_on_write = YES;
610
611 if(error_on_write)
612 {
613 sendto_one_notice(source_p, ":Couldn't write temp resv file, aborted");
1328da86 614 return 0;
212380e3 615 }
616 else if(!found_resv)
617 {
1328da86 618 sendto_one_notice(source_p, ":Cannot find RESV for %s in file", name);
212380e3 619
620 if(temppath != NULL)
621 (void) unlink(temppath);
622
1328da86 623 return 0;
212380e3 624 }
625
626 if (rename(temppath, filename))
627 {
628 sendto_one_notice(source_p, ":Couldn't rename temp file, aborted");
1328da86 629 return 0;
212380e3 630 }
212380e3 631
632 sendto_one_notice(source_p, ":RESV for [%s] is removed", name);
633 sendto_realops_snomask(SNO_GENERAL, L_ALL,
634 "%s has removed the RESV for: [%s]", get_oper_name(source_p), name);
635 ilog(L_KLINE, "UR %s %s", get_oper_name(source_p), name);
1328da86
JT
636
637 return 1;
212380e3 638}