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