diff options
Diffstat (limited to 'modules/m_resv.c')
-rw-r--r-- | modules/m_resv.c | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/modules/m_resv.c b/modules/m_resv.c new file mode 100644 index 0000000..e733ddc --- /dev/null +++ b/modules/m_resv.c @@ -0,0 +1,434 @@ +/* + * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). + * m_resv.c: Reserves(jupes) a nickname or channel. + * + * Copyright (C) 2001-2002 Hybrid Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * $Id$ + */ + +#include "stdinc.h" +#include "client.h" +#include "channel.h" +#include "ircd.h" +#include "irc_string.h" +#include "numeric.h" +#include "s_serv.h" +#include "send.h" +#include "parse.h" +#include "modules.h" +#include "conf.h" +#include "log.h" +#include "resv.h" +#include "hash.h" + + +static void parse_resv(struct Client *, char *, int, char *); +static void remove_resv(struct Client *, const char *); + + +/* mo_resv() + * parv[0] = sender prefix + * parv[1] = channel/nick to forbid + */ +static void +mo_resv(struct Client *client_p, struct Client *source_p, + int parc, char *parv[]) +{ + char *resv = NULL; + char *reason = NULL; + char *target_server = NULL; + time_t tkline_time = 0; + + /* RESV #channel ON irc.server.com :abuse + * RESV kiddie ON irc.server.com :abuse + */ + if (parse_aline("RESV", source_p, parc, parv, + AWILD, &resv, NULL, &tkline_time, &target_server, &reason) < 0) + return; + + if (target_server != NULL) + { + /* if a given expire time is given, ENCAP it */ + if (tkline_time != 0) + sendto_match_servs(source_p, target_server, CAP_ENCAP, + "ENCAP %s RESV %d %s 0 :%s", + target_server, (int)tkline_time, resv, reason); + else + sendto_match_servs(source_p, target_server, CAP_CLUSTER, + "RESV %s %s :%s", + target_server, resv, reason); + /* Allow ON to apply local resv as well if it matches */ + if (!match(target_server, me.name)) + return; + } + else + { + /* RESV #channel :abuse + * RESV kiddie :abuse + */ + if (tkline_time != 0) + cluster_a_line(source_p, "ENCAP", CAP_ENCAP, SHARED_RESV, + "RESV %d %s 0 : %s", (int)tkline_time, resv, reason); + else + cluster_a_line(source_p, "RESV", CAP_KLN, SHARED_RESV, + "%s : %s", resv, reason); + } + + parse_resv(source_p, resv, (int)tkline_time, reason); +} + +/* me_resv() + * + * inputs - server + * - client (oper) + * - parc number of arguments + * - parv list of arguments + * via parv[] + * parv[0] = client name applying resv + * parv[1] = tkline_time + * parv[2] = name + * parv[3] = 0 + * parv[4] = reason + * parc should be 5 + * + * outputs - NONE + * side effects - + */ +static void +me_resv(struct Client *client_p, struct Client *source_p, + int parc, char *parv[]) +{ + if (parc != 5 || !IsClient(source_p)) + return; + + parse_resv(source_p, parv[2], atoi(parv[1]), parv[4]); +} + +/* ms_resv() + * parv[0] = sender prefix + * parv[1] = target server + * parv[2] = channel/nick to resv + * parv[3] = reason + */ +static void +ms_resv(struct Client *client_p, struct Client *source_p, + int parc, char *parv[]) +{ + if ((parc != 4) || EmptyString(parv[3])) + return; + + sendto_match_servs(source_p, parv[1], CAP_CLUSTER, + "RESV %s %s :%s", + parv[1], parv[2], parv[3]); + + if (!IsClient(source_p) || !match(parv[1], me.name)) + return; + + if (HasFlag(source_p, FLAGS_SERVICE) || find_matching_name_conf(ULINE_TYPE, source_p->servptr->name, + source_p->username, source_p->host, + SHARED_RESV)) + parse_resv(source_p, parv[2], 0, parv[3]); +} + +/* mo_unresv() + * parv[0] = sender prefix + * parv[1] = channel/nick to unforbid + */ +static void +mo_unresv(struct Client *client_p, struct Client *source_p, + int parc, char *parv[]) +{ + char *resv = NULL; + char *reason = NULL; + char *target_server = NULL; + + /* UNRESV #channel ON irc.server.com */ + /* UNRESV kiddie ON irc.server.com */ + if (parse_aline("UNRESV", source_p, parc, parv, + 0, &resv, NULL, NULL, &target_server, &reason) < 0) + return; + + if (target_server != NULL) + { + sendto_match_servs(source_p, target_server, CAP_CLUSTER, + "UNRESV %s %s", + target_server, resv); + + /* Allow ON to apply local unresv as well if it matches */ + if (!match(target_server, me.name)) + return; + } + else + cluster_a_line(source_p, "UNRESV", CAP_KLN, SHARED_UNRESV, resv); + + remove_resv(source_p, resv); +} + +/* ms_unresv() + * parv[0] = sender prefix + * parv[1] = target server + * parv[2] = resv to remove + */ +static void +ms_unresv(struct Client *client_p, struct Client *source_p, + int parc, char *parv[]) +{ + if ((parc != 3) || EmptyString(parv[2])) + return; + + sendto_match_servs(source_p, parv[1], CAP_CLUSTER, + "UNRESV %s %s", + parv[1], parv[2]); + + if (!IsClient(source_p) || !match(parv[1], me.name)) + return; + + if (HasFlag(source_p, FLAGS_SERVICE) || find_matching_name_conf(ULINE_TYPE, source_p->servptr->name, + source_p->username, source_p->host, + SHARED_UNRESV)) + remove_resv(source_p, parv[2]); +} + +/* parse_resv() + * + * inputs - source_p, NULL supported + * - thing to resv + * - time_t if tkline + * - reason + * outputs - none + * side effects - parse resv, create if valid + */ +static void +parse_resv(struct Client *source_p, char *name, int tkline_time, char *reason) +{ + struct ConfItem *conf = NULL; + + if (IsChanPrefix(*name)) + { + struct ResvChannel *resv_p; + + if ((conf = create_channel_resv(name, reason, 0)) == NULL) + { + sendto_one(source_p, + ":%s NOTICE %s :A RESV has already been placed on channel: %s", + me.name, source_p->name, name); + return; + } + + resv_p = map_to_conf(conf); + + if (tkline_time != 0) + { + sendto_one(source_p, + ":%s NOTICE %s :A %d minute %s RESV has been placed on channel: %s", + me.name, source_p->name, + tkline_time/60, + (MyClient(source_p) ? "local" : "remote"), name); + sendto_realops_flags(UMODE_ALL, L_ALL, + "%s has placed a %d minute %s RESV on channel: %s [%s]", + get_oper_name(source_p), + tkline_time/60, + (MyClient(source_p) ? "local" : "remote"), + resv_p->name, resv_p->reason); + ilog(LOG_TYPE_IRCD, "%s added temporary %d min. RESV for [%s] [%s]", + source_p->name, (int)tkline_time/60, + conf->name, resv_p->reason); + resv_p->hold = CurrentTime + tkline_time; + add_temp_line(conf); + } + else + { + sendto_one(source_p, + ":%s NOTICE %s :A %s RESV has been placed on channel %s", + me.name, source_p->name, + (MyClient(source_p) ? "local" : "remote"), name); + sendto_realops_flags(UMODE_ALL, L_ALL, + "%s has placed a %s RESV on channel %s : [%s]", + get_oper_name(source_p), + (MyClient(source_p) ? "local" : "remote"), + resv_p->name, resv_p->reason); + write_conf_line(source_p, conf, NULL /* not used */, 0 /* not used */); + } + } + else + { + struct MatchItem *resv_p = NULL; + + if (!valid_wild_card_simple(name)) + { + sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the resv", + me.name, source_p->name, ConfigFileEntry.min_nonwildcard_simple); + return; + } + + if (!HasUMode(source_p, UMODE_ADMIN) && strpbrk(name, "*?#")) + { + sendto_one(source_p, ":%s NOTICE %s :You must be an admin to perform a " + "wildcard RESV", me.name, source_p->name); + return; + } + + if ((conf = create_nick_resv(name, reason, 0)) == NULL) + { + sendto_one(source_p, + ":%s NOTICE %s :A RESV has already been placed on nick %s", + me.name, source_p->name, name); + return; + } + + resv_p = map_to_conf(conf); + + if (tkline_time != 0) + { + sendto_one(source_p, + ":%s NOTICE %s :A %d minute %s RESV has been placed on nick %s : [%s]", + me.name, source_p->name, + tkline_time/60, + (MyClient(source_p) ? "local" : "remote"), + conf->name, resv_p->reason); + sendto_realops_flags(UMODE_ALL, L_ALL, + "%s has placed a %d minute %s RESV on nick %s : [%s]", + get_oper_name(source_p), + tkline_time/60, + (MyClient(source_p) ? "local" : "remote"), + conf->name, resv_p->reason); + ilog(LOG_TYPE_IRCD, "%s added temporary %d min. RESV for [%s] [%s]", + source_p->name, (int)tkline_time/60, + conf->name, resv_p->reason); + resv_p->hold = CurrentTime + tkline_time; + add_temp_line(conf); + } + else + { + sendto_one(source_p, + ":%s NOTICE %s :A %s RESV has been placed on nick %s : [%s]", + me.name, source_p->name, + (MyClient(source_p) ? "local" : "remote"), + conf->name, resv_p->reason); + sendto_realops_flags(UMODE_ALL, L_ALL, + "%s has placed a %s RESV on nick %s : [%s]", + get_oper_name(source_p), + (MyClient(source_p) ? "local" : "remote"), + conf->name, resv_p->reason); + write_conf_line(source_p, conf, NULL /* not used */, 0 /* not used */); + } + } +} + +static void +remove_resv(struct Client *source_p, const char *name) +{ + struct ConfItem *conf = NULL; + + if (IsChanPrefix(*name)) + { + struct ResvChannel *resv_p; + + if (resv_channel_list.head == NULL || + !(resv_p = hash_find_resv(name))) + { + sendto_one(source_p, + ":%s NOTICE %s :A RESV does not exist for channel: %s", + me.name, source_p->name, name); + return; + } + + if (resv_p->conf) + { + sendto_one(source_p, + ":%s NOTICE %s :The RESV for channel: %s is in ircd.conf and must be removed by hand.", + me.name, source_p->name, name); + return; + } + + delete_channel_resv(resv_p); + remove_conf_line(CRESV_TYPE, source_p, name, NULL); + + sendto_one(source_p, + ":%s NOTICE %s :The RESV has been removed on channel: %s", + me.name, source_p->name, name); + sendto_realops_flags(UMODE_ALL, L_ALL, + "%s has removed the RESV for channel: %s", + get_oper_name(source_p), name); + } + else + { + struct MatchItem *resv_p = NULL; + + if ((conf = find_exact_name_conf(NRESV_TYPE, NULL, name, NULL, NULL)) == NULL) + { + sendto_one(source_p, ":%s NOTICE %s :A RESV does not exist for nick: %s", + me.name, source_p->name, name); + return; + } + + resv_p = map_to_conf(conf); + + if (resv_p->action) + { + sendto_one(source_p, + ":%s NOTICE %s :The RESV for nick: %s is in ircd.conf and must be removed by hand.", + me.name, source_p->name, name); + return; + } + + delete_conf_item(conf); + remove_conf_line(NRESV_TYPE, source_p, name, NULL); + + sendto_one(source_p, ":%s NOTICE %s :The RESV has been removed on nick: %s", + me.name, source_p->name, name); + sendto_realops_flags(UMODE_ALL, L_ALL, + "%s has removed the RESV for nick: %s", + get_oper_name(source_p), name); + } +} + +static struct Message resv_msgtab = { + "RESV", 0, 0, 3, MAXPARA, MFLG_SLOW, 0, + { m_ignore, m_not_oper, ms_resv, me_resv, mo_resv, m_ignore } +}; + +static struct Message unresv_msgtab = { + "UNRESV", 0, 0, 2, MAXPARA, MFLG_SLOW, 0, + { m_ignore, m_not_oper, ms_unresv, m_ignore, mo_unresv, m_ignore } +}; + +static void +module_init(void) +{ + mod_add_cmd(&resv_msgtab); + mod_add_cmd(&unresv_msgtab); +} + +static void +module_exit(void) +{ + mod_del_cmd(&resv_msgtab); + mod_del_cmd(&unresv_msgtab); +} + +struct module module_entry = { + .node = { NULL, NULL, NULL }, + .name = NULL, + .version = "$Revision$", + .handle = NULL, + .modinit = module_init, + .modexit = module_exit, + .flags = 0 +}; |