Clean.
[seven-1.x.git] / modules / m_resv.c
blob9683f5db549cb1b298a3d42f82dd0f8323889afa
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_resv.c: Reserves(jupes) a nickname or channel.
5 * Copyright (C) 2001-2002 Hybrid Development Team
6 * Copyright (C) 2002-2005 ircd-ratbox development team
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.
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.
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
23 * $Id: m_resv.c 125 2006-11-12 19:39:18Z spb $
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"
42 static int mo_resv(struct Client *, struct Client *, int, const char **);
43 static int ms_resv(struct Client *, struct Client *, int, const char **);
44 static int me_resv(struct Client *, struct Client *, int, const char **);
45 static int mo_unresv(struct Client *, struct Client *, int, const char **);
46 static int ms_unresv(struct Client *, struct Client *, int, const char **);
47 static int me_unresv(struct Client *, struct Client *, int, const char **);
49 struct 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}}
53 struct 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}}
58 mapi_clist_av1 resv_clist[] = { &resv_msgtab, &unresv_msgtab, NULL };
59 DECLARE_MODULE_AV1(resv, NULL, NULL, resv_clist, NULL, NULL, "$Revision: 125 $");
61 static void parse_resv(struct Client *source_p, const char *name,
62 const char *reason, int temp_time);
63 static void propagate_resv(struct Client *source_p, const char *target,
64 int temp_time, const char *name, const char *reason);
65 static void cluster_resv(struct Client *source_p, int temp_time,
66 const char *name, const char *reason);
68 static void handle_remote_unresv(struct Client *source_p, const char *name);
69 static void remove_resv(struct Client *source_p, const char *name);
70 static int remove_temp_resv(struct Client *source_p, const char *name);
73 * mo_resv()
74 * parv[0] = sender prefix
75 * parv[1] = channel/nick to forbid
76 * parv[2] = reason
78 static int
79 mo_resv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
81 const char *name;
82 const char *reason;
83 const char *target_server = NULL;
84 int temp_time;
85 int loc = 1;
87 if(!IsOperResv(source_p))
89 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "resv");
90 return 0;
93 /* RESV [time] <name> [ON <server>] :<reason> */
95 if((temp_time = valid_temp_time(parv[loc])) >= 0)
96 loc++;
97 /* we just set temp_time to -1! */
98 else
99 temp_time = 0;
101 name = parv[loc];
102 loc++;
104 if((parc >= loc+2) && (irccmp(parv[loc], "ON") == 0))
106 target_server = parv[loc+1];
107 loc += 2;
110 if(parc <= loc || EmptyString(parv[loc]))
112 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
113 me.name, source_p->name, "RESV");
114 return 0;
117 reason = parv[loc];
119 /* remote resv.. */
120 if(target_server)
122 if(!IsOperRemoteBan(source_p))
124 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name,
125 "remoteban");
126 return 0;
129 if(temp_time > 0)
130 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
131 "%s is setting a temporary %d-minute RESV for %s on %s",
132 get_oper_name(source_p), temp_time, name, target_server);
133 else
134 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
135 "%s is setting a RESV for %s on %s",
136 get_oper_name(source_p), name, target_server);
139 propagate_resv(source_p, target_server, temp_time, name, reason);
141 if(match(target_server, me.name) == 0)
142 return 0;
144 else if(dlink_list_length(&cluster_conf_list) > 0)
145 cluster_resv(source_p, temp_time, name, reason);
147 parse_resv(source_p, name, reason, temp_time);
149 return 0;
152 /* ms_resv()
153 * parv[0] = sender prefix
154 * parv[1] = target server
155 * parv[2] = channel/nick to forbid
156 * parv[3] = reason
158 static int
159 ms_resv(struct Client *client_p, struct Client *source_p,
160 int parc, const char *parv[])
162 /* parv[0] parv[1] parv[2] parv[3]
163 * oper target server resv reason
165 propagate_resv(source_p, parv[1], 0, parv[2], parv[3]);
167 if(!match(parv[1], me.name))
168 return 0;
170 if(!IsPerson(source_p))
171 return 0;
173 parse_resv(source_p, parv[2], parv[3], 0);
174 return 0;
177 static int
178 me_resv(struct Client *client_p, struct Client *source_p,
179 int parc, const char *parv[])
181 /* time name 0 :reason */
182 if(!IsPerson(source_p))
183 return 0;
185 parse_resv(source_p, parv[2], parv[4], atoi(parv[1]));
186 return 0;
189 /* parse_resv()
191 * inputs - source_p if error messages wanted
192 * - thing to resv
193 * - reason for resv
194 * outputs -
195 * side effects - will parse the resv and create it if valid
197 static void
198 parse_resv(struct Client *source_p, const char *name,
199 const char *reason, int temp_time)
201 struct ConfItem *aconf;
203 if(!MyClient(source_p) &&
204 !find_shared_conf(source_p->username, source_p->host,
205 source_p->user->server,
206 (temp_time > 0) ? SHARED_TRESV : SHARED_PRESV))
207 return;
209 if(IsChannelName(name))
211 if(hash_find_resv(name))
213 sendto_one_notice(source_p,
214 ":A RESV has already been placed on channel: %s",
215 name);
216 return;
219 if(strlen(name) > CHANNELLEN)
221 sendto_one_notice(source_p, ":Invalid RESV length: %s",
222 name);
223 return;
226 if(strchr(reason, '"'))
228 sendto_one_notice(source_p,
229 ":Invalid character '\"' in comment");
230 return;
233 aconf = make_conf();
234 aconf->status = CONF_RESV_CHANNEL;
235 aconf->port = 0;
236 DupString(aconf->name, name);
237 DupString(aconf->passwd, reason);
238 add_to_resv_hash(aconf->name, aconf);
240 if(temp_time > 0)
242 aconf->hold = CurrentTime + temp_time;
244 sendto_realops_snomask(SNO_GENERAL, L_ALL,
245 "%s added temporary %d min. RESV for [%s] [%s]",
246 get_oper_name(source_p), temp_time / 60,
247 name, reason);
248 ilog(L_KLINE, "R %s %d %s %s",
249 get_oper_name(source_p), temp_time / 60,
250 name, reason);
251 sendto_one_notice(source_p, ":Added temporary %d min. RESV [%s]",
252 temp_time / 60, name);
254 else
255 write_confitem(RESV_TYPE, source_p, NULL, aconf->name,
256 aconf->passwd, NULL, NULL, 0);
258 else if(clean_resv_nick(name))
260 if(strlen(name) > NICKLEN*2)
262 sendto_one_notice(source_p, ":Invalid RESV length: %s",
263 name);
264 return;
267 if(strchr(reason, '"'))
269 sendto_one_notice(source_p,
270 ":Invalid character '\"' in comment");
271 return;
274 if(!valid_wild_card_simple(name))
276 sendto_one_notice(source_p,
277 ":Please include at least %d non-wildcard "
278 "characters with the resv",
279 ConfigFileEntry.min_nonwildcard_simple);
280 return;
283 if(find_nick_resv(name))
285 sendto_one_notice(source_p,
286 ":A RESV has already been placed on nick: %s",
287 name);
288 return;
291 aconf = make_conf();
292 aconf->status = CONF_RESV_NICK;
293 aconf->port = 0;
294 DupString(aconf->name, name);
295 DupString(aconf->passwd, reason);
296 dlinkAddAlloc(aconf, &resv_conf_list);
298 if(temp_time > 0)
300 aconf->hold = CurrentTime + temp_time;
302 sendto_realops_snomask(SNO_GENERAL, L_ALL,
303 "%s added temporary %d min. RESV for [%s] [%s]",
304 get_oper_name(source_p), temp_time / 60,
305 name, reason);
306 ilog(L_KLINE, "R %s %d %s %s",
307 get_oper_name(source_p), temp_time / 60,
308 name, reason);
309 sendto_one_notice(source_p, ":Added temporary %d min. RESV [%s]",
310 temp_time / 60, name);
312 else
313 write_confitem(RESV_TYPE, source_p, NULL, aconf->name,
314 aconf->passwd, NULL, NULL, 0);
316 else
317 sendto_one_notice(source_p,
318 ":You have specified an invalid resv: [%s]",
319 name);
322 static void
323 propagate_resv(struct Client *source_p, const char *target,
324 int temp_time, const char *name, const char *reason)
326 if(!temp_time)
328 sendto_match_servs(source_p, target,
329 CAP_CLUSTER, NOCAPS,
330 "RESV %s %s :%s",
331 target, name, reason);
332 sendto_match_servs(source_p, target,
333 CAP_ENCAP, CAP_CLUSTER,
334 "ENCAP %s RESV %d %s 0 :%s",
335 target, temp_time, name, reason);
337 else
338 sendto_match_servs(source_p, target,
339 CAP_ENCAP, NOCAPS,
340 "ENCAP %s RESV %d %s 0 :%s",
341 target, temp_time, name, reason);
344 static void
345 cluster_resv(struct Client *source_p, int temp_time, const char *name,
346 const char *reason)
348 struct remote_conf *shared_p;
349 dlink_node *ptr;
351 DLINK_FOREACH(ptr, cluster_conf_list.head)
353 shared_p = ptr->data;
355 /* old protocol cant handle temps, and we dont really want
356 * to convert them to perm.. --fl
358 if(!temp_time)
360 if(!(shared_p->flags & SHARED_PRESV))
361 continue;
363 sendto_match_servs(source_p, shared_p->server,
364 CAP_CLUSTER, NOCAPS,
365 "RESV %s %s :%s",
366 shared_p->server, name, reason);
367 sendto_match_servs(source_p, shared_p->server,
368 CAP_ENCAP, CAP_CLUSTER,
369 "ENCAP %s RESV 0 %s 0 :%s",
370 shared_p->server, name, reason);
372 else if(shared_p->flags & SHARED_TRESV)
373 sendto_match_servs(source_p, shared_p->server,
374 CAP_ENCAP, NOCAPS,
375 "ENCAP %s RESV %d %s 0 :%s",
376 shared_p->server, temp_time, name, reason);
382 * mo_unresv()
383 * parv[0] = sender prefix
384 * parv[1] = channel/nick to unforbid
386 static int
387 mo_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
389 if(!IsOperResv(source_p))
391 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "resv");
392 return 0;
395 if((parc == 4) && (irccmp(parv[2], "ON") == 0))
397 if(!IsOperRemoteBan(source_p))
399 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name,
400 "remoteban");
402 propagate_generic(source_p, "UNRESV", parv[3], CAP_CLUSTER,
403 "%s", parv[1]);
405 if(match(parv[3], me.name) == 0)
406 return 0;
409 else if(dlink_list_length(&cluster_conf_list) > 0)
410 cluster_generic(source_p, "UNRESV", SHARED_UNRESV, CAP_CLUSTER,
411 "%s", parv[1]);
413 if(remove_temp_resv(source_p, parv[1]))
414 return 0;
416 remove_resv(source_p, parv[1]);
417 return 0;
420 /* ms_unresv()
421 * parv[0] = sender prefix
422 * parv[1] = target server
423 * parv[2] = resv to remove
425 static int
426 ms_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
428 /* parv[0] parv[1] parv[2]
429 * oper target server resv to remove
431 propagate_generic(source_p, "UNRESV", parv[1], CAP_CLUSTER,
432 "%s", parv[2]);
434 if(!match(parv[1], me.name))
435 return 0;
437 if(!IsPerson(source_p))
438 return 0;
440 handle_remote_unresv(source_p, parv[2]);
441 return 0;
444 static int
445 me_unresv(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
447 /* name */
448 if(!IsPerson(source_p))
449 return 0;
451 handle_remote_unresv(source_p, parv[1]);
452 return 0;
455 static void
456 handle_remote_unresv(struct Client *source_p, const char *name)
458 if(!find_shared_conf(source_p->username, source_p->host,
459 source_p->user->server, SHARED_UNRESV))
460 return;
462 if(remove_temp_resv(source_p, name))
463 return;
465 remove_resv(source_p, name);
467 return;
470 static int
471 remove_temp_resv(struct Client *source_p, const char *name)
473 struct ConfItem *aconf = NULL;
475 if(IsChannelName(name))
477 if((aconf = hash_find_resv(name)) == NULL)
478 return 0;
480 /* its permanent, let remove_resv do it properly */
481 if(!aconf->hold)
482 return 0;
484 del_from_resv_hash(name, aconf);
485 free_conf(aconf);
487 else
489 dlink_node *ptr;
491 DLINK_FOREACH(ptr, resv_conf_list.head)
493 aconf = ptr->data;
495 if(irccmp(aconf->name, name))
496 aconf = NULL;
497 else
498 break;
501 if(aconf == NULL)
502 return 0;
504 /* permanent, remove_resv() needs to do it properly */
505 if(!aconf->hold)
506 return 0;
508 /* already have ptr from the loop above.. */
509 dlinkDestroy(ptr, &resv_conf_list);
510 free_conf(aconf);
513 sendto_one_notice(source_p, ":RESV for [%s] is removed", name);
514 sendto_realops_snomask(SNO_GENERAL, L_ALL,
515 "%s has removed the RESV for: [%s]",
516 get_oper_name(source_p), name);
517 ilog(L_KLINE, "UR %s %s", get_oper_name(source_p), name);
519 return 1;
522 /* remove_resv()
524 * inputs - client removing the resv
525 * - resv to remove
526 * outputs -
527 * side effects - resv if found, is removed
529 static void
530 remove_resv(struct Client *source_p, const char *name)
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;
542 ircsprintf(temppath, "%s.tmp", ConfigFileEntry.resvfile);
543 filename = get_conf_name(RESV_TYPE);
545 if((in = fopen(filename, "r")) == NULL)
547 sendto_one_notice(source_p, ":Cannot open %s", filename);
548 return;
551 oldumask = umask(0);
553 if((out = fopen(temppath, "w")) == NULL)
555 sendto_one_notice(source_p, ":Cannot open %s", temppath);
556 fclose(in);
557 umask(oldumask);
558 return;
561 umask(oldumask);
563 while (fgets(buf, sizeof(buf), in))
565 const char *resv_name;
567 if(error_on_write)
569 if(temppath != NULL)
570 (void) unlink(temppath);
572 break;
575 strlcpy(buff, buf, sizeof(buff));
577 if((p = strchr(buff, '\n')) != NULL)
578 *p = '\0';
580 if((*buff == '\0') || (*buff == '#'))
582 error_on_write = (fputs(buf, out) < 0) ? YES : NO;
583 continue;
586 if((resv_name = getfield(buff)) == NULL)
588 error_on_write = (fputs(buf, out) < 0) ? YES : NO;
589 continue;
592 if(irccmp(resv_name, name) == 0)
594 found_resv++;
596 else
598 error_on_write = (fputs(buf, out) < 0) ? YES : NO;
602 fclose(in);
603 fclose(out);
605 if(error_on_write)
607 sendto_one_notice(source_p, ":Couldn't write temp resv file, aborted");
608 return;
610 else if(!found_resv)
612 sendto_one_notice(source_p, ":No RESV for %s", name);
614 if(temppath != NULL)
615 (void) unlink(temppath);
617 return;
620 (void) rename(temppath, filename);
621 rehash_bans(0);
623 sendto_one_notice(source_p, ":RESV for [%s] is removed", name);
624 sendto_realops_snomask(SNO_GENERAL, L_ALL,
625 "%s has removed the RESV for: [%s]", get_oper_name(source_p), name);
626 ilog(L_KLINE, "UR %s %s", get_oper_name(source_p), name);