/** * flags.C: This file contains code for the ChanServ FLAGS functions. * * 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-2007 William Pitcock, et al. * Rights to this code are as documented in doc/pod/license.pod. * * $Id: flags.C,v 1.10 2007/09/22 14:27:27 pippijn Exp $ */ #include "atheme.h" #include #include #include #include #include #include #include "template.h" static char const rcsid[] = "$Id: flags.C,v 1.10 2007/09/22 14:27:27 pippijn Exp $"; REGISTER_MODULE ("chanserv/flags", false, "The Ermyth Team "); static void cs_cmd_flags (sourceinfo_t *si, int parc, char *parv[]); command_t const cs_flags = { "FLAGS", N_("Manipulates specific permissions on a channel."), AC_NONE, 3, cs_cmd_flags }; E cmdvec cs_cmdtree; E helpvec cs_helptree; bool _modinit (module *m) { cs_cmdtree << cs_flags; help_addentry (cs_helptree, "FLAGS", "help/chanserv/flags", NULL); return true; } void _moddeinit () { cs_cmdtree >> cs_flags; help_delentry (cs_helptree, "FLAGS"); } static char const * const get_template_name (mychan_t *mc, unsigned int level) { metadata *md; char const *p, *q, *r; char *s; char ss[40]; static char flagname[400]; md = mc->find_metadata ("private:templates"); if (md != NULL) { p = md->value; while (p != NULL) { while (*p == ' ') p++; q = strchr (p, '='); if (q == NULL) break; r = strchr (q, ' '); if (r != NULL && r < q) break; strlcpy (ss, q, sizeof ss); if (r != NULL && r - q < (int) (sizeof ss - 1)) { ss[r - q] = '\0'; } if (level == flags_to_bitmask (ss, chanacs_flags, 0)) { strlcpy (flagname, p, sizeof flagname); s = strchr (flagname, '='); if (s != NULL) *s = '\0'; return flagname; } p = r; } } if (level == chansvs.ca_sop) return "SOP"; if (level == chansvs.ca_aop) return "AOP"; /* if vop==hop, prefer vop */ if (level == chansvs.ca_vop) return "VOP"; if (level == chansvs.ca_hop) return "HOP"; return NULL; } /* FLAGS [user] [flags] */ static void cs_cmd_flags (sourceinfo_t *si, int parc, char *parv[]) { chanacs_t *ca; node_t *n; int operoverride = 0; char *channel = parv[0]; char *target = parv[1]; char const *str1; char const *str2; unsigned int addflags, removeflags, restrictflags; if (parc < 1) { command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "FLAGS"); command_fail (si, fault::needmoreparams, _("Syntax: FLAGS [target] [flags]")); return; } if (!target) { mychan_t *mc = mychan_t::find (channel); unsigned int i = 1; if (!mc) { command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), channel); return; } if (!chanacs_source_has_flag (mc, si, CA_ACLVIEW)) { if (has_priv (si, PRIV_CHAN_AUSPEX)) operoverride = 1; else { command_fail (si, fault::noprivs, _("You are not authorized to perform this operation.")); return; } } if (mc->find_metadata ("private:close:closer") && !has_priv (si, PRIV_CHAN_AUSPEX)) { command_fail (si, fault::noprivs, _("\2%s\2 is closed."), channel); return; } command_success_nodata (si, _("Entry Nickname/Host Flags")); command_success_nodata (si, "----- ---------------------- -----"); LIST_FOREACH (n, mc->chanacs.head) { ca = static_cast (n->data); str1 = get_template_name (mc, ca->level); str2 = ca->ts ? time_ago (ca->ts) : "?"; if (str1 != NULL) command_success_nodata (si, _("%-5d %-22s %s (%s) [modified %s ago]"), i, ca->myuser ? ca->myuser->name : ca->host, bitmask_to_flags (ca->level, chanacs_flags), str1, str2); else command_success_nodata (si, _("%-5d %-22s %s [modified %s ago]"), i, ca->myuser ? ca->myuser->name : ca->host, bitmask_to_flags (ca->level, chanacs_flags), str2); i++; } command_success_nodata (si, "----- ---------------------- -----"); command_success_nodata (si, _("End of \2%s\2 FLAGS listing."), channel); if (operoverride) logcommand (si, CMDLOG_ADMIN, "%s FLAGS (oper override)", mc->name); else logcommand (si, CMDLOG_GET, "%s FLAGS", mc->name); } else { mychan_t *mc = mychan_t::find (channel); myuser_t *tmu; char *flagstr = parv[2]; if (!si->smu) { command_fail (si, fault::noprivs, _("You are not logged in.")); return; } if (!mc) { command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), channel); return; } if (mc->find_metadata ("private:close:closer")) { command_fail (si, fault::noprivs, _("\2%s\2 is closed."), channel); return; } if (!target) { command_fail (si, fault::needmoreparams, _("Usage: FLAGS %s [target] [flags]"), channel); return; } if (!flagstr) { if (!chanacs_source_has_flag (mc, si, CA_ACLVIEW)) { command_fail (si, fault::noprivs, _("You are not authorized to execute this command.")); return; } if (validhostmask (target)) ca = chanacs_find_host_literal (mc, target, 0); else { if (!(tmu = myuser_t::find_ext (target))) { command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), target); return; } target = tmu->name; ca = chanacs_find (mc, tmu, 0); } if (ca != NULL) { str1 = bitmask_to_flags2 (ca->level, 0, chanacs_flags); command_success_string (si, str1, _("Flags for \2%s\2 in \2%s\2 are \2%s\2."), target, channel, str1); } else command_success_string (si, "", _("No flags for \2%s\2 in \2%s\2."), target, channel); logcommand (si, CMDLOG_GET, "%s FLAGS %s", mc->name, target); return; } /* founder may always set flags -- jilles */ restrictflags = chanacs_source_flags (mc, si); if (restrictflags & CA_FOUNDER) restrictflags = ca_all; else { if (!(restrictflags & CA_FLAGS)) { /* allow a user to remove their own access * even without +f */ if (restrictflags & CA_AKICK || si->smu == NULL || irccasecmp (target, si->smu->name) || strcmp (flagstr, "-*")) { command_fail (si, fault::noprivs, _("You are not authorized to execute this command.")); return; } } restrictflags = allow_flags (restrictflags); } if (*flagstr == '+' || *flagstr == '-' || *flagstr == '=') { flags_make_bitmasks (flagstr, chanacs_flags, &addflags, &removeflags); if (addflags == 0 && removeflags == 0) { command_fail (si, fault::badparams, _("No valid flags given, use /%s%s HELP FLAGS for a list"), ircd->uses_rcommand ? "" : "msg ", chansvs.disp); return; } } else { addflags = get_template_flags (mc, flagstr); if (addflags == 0) { /* Hack -- jilles */ if (*target == '+' || *target == '-' || *target == '=') command_fail (si, fault::badparams, _("Usage: FLAGS %s [target] [flags]"), mc->name); else command_fail (si, fault::badparams, _("Invalid template name given, use /%s%s TEMPLATE %s for a list"), ircd->uses_rcommand ? "" : "msg ", chansvs.disp, mc->name); return; } removeflags = ca_all & ~addflags; } if (!validhostmask (target)) { if (!(tmu = myuser_t::find_ext (target))) { command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), target); return; } target = tmu->name; ca = chanacs_open (mc, tmu, NULL, true); if (ca->level & CA_FOUNDER && removeflags & CA_FLAGS && !(removeflags & CA_FOUNDER)) { command_fail (si, fault::noprivs, _("You may not remove a founder's +f access.")); return; } if (ca->level & CA_FOUNDER && removeflags & CA_FOUNDER && mc->num_founders () == 1) { command_fail (si, fault::noprivs, _("You may not remove the last founder.")); return; } if (!(ca->level & CA_FOUNDER) && addflags & CA_FOUNDER) { if (mc->num_founders () >= chansvs.maxfounders) { command_fail (si, fault::noprivs, _("Only %d founders allowed per channel."), chansvs.maxfounders); chanacs_close (ca); return; } if ((tmu->num_channels () >= me.maxchans) && !has_priv_myuser (tmu, PRIV_REG_NOLIMIT)) { command_fail (si, fault::toomany, _("\2%s\2 has too many channels registered."), tmu->name); return; } } if (addflags & CA_FOUNDER) addflags |= CA_FLAGS, removeflags &= ~CA_FLAGS; /* If NEVEROP is set, don't allow adding new entries * except sole +b. Adding flags if the current level * is +b counts as adding an entry. * -- jilles */ if (tmu->flags & MU_NEVEROP && addflags != CA_AKICK && addflags != 0 && (ca->level == 0 || ca->level == CA_AKICK)) { command_fail (si, fault::noprivs, _("\2%s\2 does not wish to be added to access lists (NEVEROP set)."), tmu->name); chanacs_close (ca); return; } if (ca->level == 0 && chanacs_is_table_full (ca)) { command_fail (si, fault::toomany, _("Channel %s access list is full."), mc->name); chanacs_close (ca); return; } if (!chanacs_modify (ca, &addflags, &removeflags, restrictflags)) { command_fail (si, fault::noprivs, _("You are not allowed to set \2%s\2 on \2%s\2 in \2%s\2."), bitmask_to_flags2 (addflags, removeflags, chanacs_flags), tmu->name, mc->name); chanacs_close (ca); return; } chanacs_close (ca); } else { if (addflags & CA_FOUNDER) { command_fail (si, fault::badparams, _("You may not set founder status on a hostmask.")); return; } ca = chanacs_open (mc, NULL, target, true); if (ca->level == 0 && chanacs_is_table_full (ca)) { command_fail (si, fault::toomany, _("Channel %s access list is full."), mc->name); chanacs_close (ca); return; } if (!chanacs_modify (ca, &addflags, &removeflags, restrictflags)) { command_fail (si, fault::noprivs, _("You are not allowed to set \2%s\2 on \2%s\2 in \2%s\2."), bitmask_to_flags2 (addflags, removeflags, chanacs_flags), target, mc->name); chanacs_close (ca); return; } chanacs_close (ca); } if ((addflags | removeflags) == 0) { command_fail (si, fault::nochange, _("Channel access to \2%s\2 for \2%s\2 unchanged."), channel, target); return; } flagstr = bitmask_to_flags2 (addflags, removeflags, chanacs_flags); command_success_nodata (si, _("Flags \2%s\2 were set on \2%s\2 in \2%s\2."), flagstr, target, channel); logcommand (si, CMDLOG_SET, "%s FLAGS %s %s", mc->name, target, flagstr); verbose (mc, "\2%s\2 set flags \2%s\2 on \2%s\2.", get_source_name (si), flagstr, target); } } /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs * vim:ts=8 * vim:sw=8 * vim:noexpandtab */