/** * close.C: Closing for channels. * * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team * Rights to this code are as documented in COPYING. * * * Portions of this file were derived from sources bearing the following license: * Copyright © 2005-2006 Atheme Development Group * Rights to this code are as documented in doc/pod/license.pod. * * $Id: close.C,v 1.8 2007/09/22 14:27:27 pippijn Exp $ */ #include "atheme.h" #include #include #include #include static char const rcsid[] = "$Id: close.C,v 1.8 2007/09/22 14:27:27 pippijn Exp $"; REGISTER_MODULE ("chanserv/close", false, "The Ermyth Team "); static void cs_cmd_close (sourceinfo_t *si, int parc, char *parv[]); /* CLOSE ON|OFF -- don't pollute the root with REOPEN */ command_t const cs_close = { "CLOSE", N_("Closes a channel."), PRIV_CHAN_ADMIN, 3, cs_cmd_close }; E cmdvec cs_cmdtree; E helpvec cs_helptree; static bool close_check_join (chanuser_t *cu) { mychan_t *mc; if (cu == NULL || is_internal_client (cu->user)) return true; mc = mychan_t::find (cu->chan->name); if (mc == NULL) return true; if (mc->find_metadata ("private:close:closer")) { /* don't join if we're already in there */ if (!chanuser_find (cu->chan, user_find_named (chansvs.nick))) join (cu->chan->name, chansvs.nick); /* stay for a bit to stop rejoin floods */ mc->flags |= MC_INHABIT; /* lock it down */ channel_mode_va (chansvs.me->me, cu->chan, 3, "+isbl", "*!*@*", "1"); /* clear the channel */ phandler->kick (chansvs.nick, cu->chan->name, cu->user->nick, "This channel has been closed"); return false; } return true; } static void cs_cmd_close (sourceinfo_t *si, int parc, char *parv[]) { char *target = parv[0]; char *action = parv[1]; char *reason = parv[2]; mychan_t *mc; channel_t *c; chanuser_t *cu; node_t *n; if (!target || !action) { command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "CLOSE"); command_fail (si, fault::needmoreparams, _("Usage: CLOSE <#channel> [reason]")); return; } if (!(mc = mychan_t::find (target))) { command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), target); return; } if (!strcasecmp (action, "ON")) { if (!reason) { command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "CLOSE"); command_fail (si, fault::needmoreparams, _("Usage: CLOSE <#channel> ON ")); return; } if (config_options.chan && !irccasecmp (config_options.chan, target)) { command_fail (si, fault::noprivs, _("\2%s\2 cannot be closed."), target); return; } if (mc->find_metadata ("private:close:closer")) { command_fail (si, fault::nochange, _("\2%s\2 is already closed."), target); return; } mc->add_metadata ("private:close:closer", si->su->nick); mc->add_metadata ("private:close:reason", reason); mc->add_metadata ("private:close:timestamp", itoa (NOW)); if ((c = channel_find (target))) { if (!chanuser_find (c, user_find_named (chansvs.nick))) join (target, chansvs.nick); /* stay for a bit to stop rejoin floods */ mc->flags |= MC_INHABIT; /* lock it down */ channel_mode_va (chansvs.me->me, c, 3, "+isbl", "*!*@*", "1"); /* clear the channel */ LIST_FOREACH (n, c->members.head) { cu = (chanuser_t *) n->data; if (!is_internal_client (cu->user)) phandler->kick (chansvs.nick, target, cu->user->nick, "This channel has been closed"); } } wallops ("%s closed the channel \2%s\2 (%s).", get_oper_name (si), target, reason); snoop ("CLOSE:ON: \2%s\2 by \2%s\2 (%s)", target, get_oper_name (si), reason); logcommand (si, CMDLOG_ADMIN, "%s CLOSE ON %s", target, reason); command_success_nodata (si, _("\2%s\2 is now closed."), target); } else if (!strcasecmp (action, "OFF")) { if (!mc->find_metadata ("private:close:closer")) { command_fail (si, fault::nochange, _("\2%s\2 is not closed."), target); return; } mc->del_metadata ("private:close:closer"); mc->del_metadata ("private:close:reason"); mc->del_metadata ("private:close:timestamp"); mc->flags &= ~MC_INHABIT; c = channel_find (target); if (c != NULL) if (chanuser_find (c, user_find_named (chansvs.nick))) part (c->name, chansvs.nick); c = channel_find (target); if (c != NULL) { /* hmm, channel still exists, probably permanent? */ channel_mode_va (chansvs.me->me, c, 2, "-isbl", "*!*@*"); check_modes (mc, true); } wallops ("%s reopened the channel \2%s\2.", get_oper_name (si), target); snoop ("CLOSE:OFF: \2%s\2 by \2%s\2", target, get_oper_name (si)); logcommand (si, CMDLOG_ADMIN, "%s CLOSE OFF", target); command_success_nodata (si, _("\2%s\2 has been reopened."), target); } else { command_fail (si, fault::badparams, STR_INVALID_PARAMS, "CLOSE"); command_fail (si, fault::badparams, _("Usage: CLOSE <#channel> [reason]")); } } bool _modinit (module *m) { cs_cmdtree << cs_close; chanuser_t::callback.join.attach (close_check_join); help_addentry (cs_helptree, "CLOSE", "help/chanserv/close", NULL); return true; } void _moddeinit () { cs_cmdtree >> cs_close; chanuser_t::callback.join.detach (close_check_join); help_delentry (cs_helptree, "CLOSE"); }