]> jfr.im git - irc/rqf/shadowircd.git/blob - modules/m_resv.c
Remove some more references to parv[0] in comments.
[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: 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 "logger.h"
40
41 static int mo_resv(struct Client *, struct Client *, int, const char **);
42 static int ms_resv(struct Client *, struct Client *, int, const char **);
43 static int me_resv(struct Client *, struct Client *, int, const char **);
44 static int mo_unresv(struct Client *, struct Client *, int, const char **);
45 static int ms_unresv(struct Client *, struct Client *, int, const char **);
46 static int me_unresv(struct Client *, struct Client *, int, const char **);
47
48 struct 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 };
52 struct 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
57 mapi_clist_av1 resv_clist[] = { &resv_msgtab, &unresv_msgtab, NULL };
58 DECLARE_MODULE_AV1(resv, NULL, NULL, resv_clist, NULL, NULL, "$Revision: 3045 $");
59
60 static void parse_resv(struct Client *source_p, const char *name,
61 const char *reason, int temp_time);
62 static void propagate_resv(struct Client *source_p, const char *target,
63 int temp_time, const char *name, const char *reason);
64 static void cluster_resv(struct Client *source_p, int temp_time,
65 const char *name, const char *reason);
66
67 static void handle_remote_unresv(struct Client *source_p, const char *name);
68 static void remove_resv(struct Client *source_p, const char *name);
69 static int remove_resv_from_file(struct Client *source_p, const char *name);
70
71 /*
72 * mo_resv()
73 * parv[1] = channel/nick to forbid
74 * parv[2] = reason
75 */
76 static int
77 mo_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
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
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 }
133 else if(rb_dlink_list_length(&cluster_conf_list) > 0)
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()
142 * parv[1] = target server
143 * parv[2] = channel/nick to forbid
144 * parv[3] = reason
145 */
146 static int
147 ms_resv(struct Client *client_p, struct Client *source_p,
148 int parc, const char *parv[])
149 {
150 /* source_p 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
165 static int
166 me_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 */
185 static void
186 parse_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,
193 source_p->servptr->name,
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;
224 aconf->name = rb_strdup(name);
225 aconf->passwd = rb_strdup(reason);
226 add_to_resv_hash(aconf->name, aconf);
227
228 if(temp_time > 0)
229 {
230 aconf->hold = rb_current_time() + temp_time;
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
243 write_confitem(RESV_TYPE, source_p, NULL, aconf->name,
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
271 if(find_nick_resv_mask(name))
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;
282 aconf->name = rb_strdup(name);
283 aconf->passwd = rb_strdup(reason);
284 rb_dlinkAddAlloc(aconf, &resv_conf_list);
285
286 if(temp_time > 0)
287 {
288 aconf->hold = rb_current_time() + temp_time;
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
301 write_confitem(RESV_TYPE, source_p, NULL, aconf->name,
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
310 static void
311 propagate_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
332 static void
333 cluster_resv(struct Client *source_p, int temp_time, const char *name,
334 const char *reason)
335 {
336 struct remote_conf *shared_p;
337 rb_dlink_node *ptr;
338
339 RB_DLINK_FOREACH(ptr, cluster_conf_list.head)
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()
371 * parv[1] = channel/nick to unforbid
372 */
373 static int
374 mo_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
375 {
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
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 }
398 else if(rb_dlink_list_length(&cluster_conf_list) > 0)
399 cluster_generic(source_p, "UNRESV", SHARED_UNRESV, CAP_CLUSTER,
400 "%s", parv[1]);
401
402 remove_resv(source_p, parv[1]);
403 return 0;
404 }
405
406 /* ms_unresv()
407 * parv[1] = target server
408 * parv[2] = resv to remove
409 */
410 static int
411 ms_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
412 {
413 /* source_p 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
429 static int
430 me_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
440 static void
441 handle_remote_unresv(struct Client *source_p, const char *name)
442 {
443 if(!find_shared_conf(source_p->username, source_p->host,
444 source_p->servptr->name, SHARED_UNRESV))
445 return;
446
447 remove_resv(source_p, name);
448
449 return;
450 }
451
452 static void
453 remove_resv(struct Client *source_p, const char *name)
454 {
455 struct ConfItem *aconf = NULL;
456
457 if(IsChannelName(name))
458 {
459 if((aconf = hash_find_resv(name)) == NULL)
460 {
461 sendto_one_notice(source_p, ":No RESV for %s", name);
462 return;
463 }
464
465 if(!aconf->hold)
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 }
478 del_from_resv_hash(name, aconf);
479 }
480 else
481 {
482 rb_dlink_node *ptr;
483
484 RB_DLINK_FOREACH(ptr, resv_conf_list.head)
485 {
486 aconf = ptr->data;
487
488 if(irccmp(aconf->name, name))
489 aconf = NULL;
490 else
491 break;
492 }
493
494 if(aconf == NULL)
495 {
496 sendto_one_notice(source_p, ":No RESV for %s", name);
497 return;
498 }
499
500 if(!aconf->hold)
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 }
513 /* already have ptr from the loop above.. */
514 rb_dlinkDestroy(ptr, &resv_conf_list);
515 }
516 free_conf(aconf);
517
518 return;
519 }
520
521 /* remove_resv_from_file()
522 *
523 * inputs - client removing the resv
524 * - resv to remove
525 * outputs -
526 * side effects - resv if found, is removed from conf
527 * - does not touch resv hash or resv_conf_list
528 */
529 static int
530 remove_resv_from_file(struct Client *source_p, const char *name)
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
542 rb_sprintf(temppath, "%s.tmp", ConfigFileEntry.resvfile);
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);
548 return 0;
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);
558 return 0;
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
575 rb_strlcpy(buff, buf, sizeof(buff));
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");
609 return 0;
610 }
611 else if(!found_resv)
612 {
613 sendto_one_notice(source_p, ":Cannot find RESV for %s in file", name);
614
615 if(temppath != NULL)
616 (void) unlink(temppath);
617
618 return 0;
619 }
620
621 if (rename(temppath, filename))
622 {
623 sendto_one_notice(source_p, ":Couldn't rename temp file, aborted");
624 return 0;
625 }
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);
631
632 return 1;
633 }