emehta-contrib/cs_access_alias.c

216 lines
5.6 KiB
C

/*
* Copyright (c) 2007 Jilles Tjoelker, et al.
* Rights to this code are as documented in doc/LICENSE.
*
* ChanServ ACCESS command
*
* $Id$
*/
#include "atheme-compat.h"
#include "template.h"
DECLARE_MODULE_V1
(
"contrib/cs_access_alias", FALSE, _modinit, _moddeinit,
"$Id$",
"freenode <http://www.freenode.net>"
);
static void cs_cmd_access(sourceinfo_t *si, int parc, char *parv[]);
command_t cs_access = { "ACCESS", "Manipulates channel access lists.",
AC_NONE, 4, cs_cmd_access, { .path = "contrib/access" } };
void _modinit(module_t *m)
{
service_named_bind_command("chanserv", &cs_access);
}
void _moddeinit(module_unload_intent_t intent)
{
service_named_unbind_command("chanserv", &cs_access);
}
static void compat_cmd(sourceinfo_t *si, const char *cmdname, char *channel, char *arg1, char *arg2, char *arg3)
{
int newparc;
char *newparv[5];
command_t *cmd;
newparv[0] = channel;
newparv[1] = arg1;
newparv[2] = arg2;
newparv[3] = arg3;
newparv[4] = NULL;
/* this assumes arg3!=NULL implies arg2!=NULL implies arg1!=NULL */
newparc = 1 + (arg1 != NULL) + (arg2 != NULL) + (arg3 != NULL);
cmd = command_find(si->service->commands, cmdname);
if (cmd != NULL)
command_exec(si->service, si, cmd, newparc, newparv);
else
command_fail(si, fault_unimplemented, _("Command \2%s\2 not loaded?"), cmdname);
}
typedef struct {
const char *res;
unsigned int level;
} template_iter_t;
static int global_template_search(const char *key, void *data, void *privdata)
{
template_iter_t *iter = privdata;
default_template_t *def_t = data;
if (def_t->flags == iter->level)
iter->res = key;
return 0;
}
static const char *get_template_name(mychan_t *mc, unsigned int level)
{
metadata_t *md;
const char *p, *q, *r;
char *s;
char ss[40];
static char flagname[400];
template_iter_t iter;
md = metadata_find(mc, "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;
mowgli_strlcpy(ss, q, sizeof ss);
if (r != NULL && r - q < (int)(sizeof ss - 1))
{
ss[r - q] = '\0';
}
if (level == flags_to_bitmask(ss, 0))
{
mowgli_strlcpy(flagname, p, sizeof flagname);
s = strchr(flagname, '=');
if (s != NULL)
*s = '\0';
return flagname;
}
p = r;
}
}
iter.res = NULL;
iter.level = level;
mowgli_patricia_foreach(global_template_dict, global_template_search, &iter);
return iter.res;
}
static void access_list(sourceinfo_t *si, mychan_t *mc, int parc, char *parv[])
{
mowgli_node_t *n;
chanacs_t *ca;
const char *str1, *str2;
int i = 1;
bool operoverride = false;
/* Copied from modules/chanserv/flags.c */
/* Note: This overrides the normal need of +A access unless private */
if (use_channel_private && mc->flags & MC_PRIVATE &&
!chanacs_source_has_flag(mc, si, CA_ACLVIEW))
{
if (has_priv(si, PRIV_CHAN_AUSPEX))
operoverride = true;
else
{
command_fail(si, fault_noprivs, _("You are not authorized to perform this operation."));
return;
}
}
command_success_nodata(si, _("Entry Nickname/Host Flags"));
command_success_nodata(si, "----- ---------------------- -----");
MOWGLI_ITER_FOREACH(n, mc->chanacs.head)
{
ca = n->data;
/* Change: don't show akicks */
if (ca->level == CA_AKICK)
continue;
str1 = get_template_name(mc, ca->level);
str2 = ca->tmodified ? time_ago(ca->tmodified) : "?";
if (str1 != NULL)
command_success_nodata(si, _("%-5d %-22s %s (%s) [modified %s ago]"), i, ca->entity ? ca->entity->name : ca->host, bitmask_to_flags(ca->level), str1,
str2);
else
command_success_nodata(si, _("%-5d %-22s %s [modified %s ago]"), i, ca->entity ? ca->entity->name : ca->host, bitmask_to_flags(ca->level),
str2);
i++;
}
command_success_nodata(si, "----- ---------------------- -----");
command_success_nodata(si, _("End of \2%s\2 FLAGS listing."), mc->name);
if (operoverride)
logcommand(si, CMDLOG_ADMIN, "%s ACCESS LIST (oper override)", mc->name);
else
logcommand(si, CMDLOG_GET, "%s ACCESS LIST", mc->name);
}
static void cs_cmd_access(sourceinfo_t *si, int parc, char *parv[])
{
char *chan, *cmd;
mychan_t *mc;
char killit[] = "-*";
char deftemplate[] = "OP";
char defaccess[] = "=votirA";
if (parc < 2)
{
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "ACCESS");
command_fail(si, fault_needmoreparams, _("Syntax: ACCESS <#channel> ADD|DEL|LIST [nick] [level]"));
return;
}
if (parv[0][0] == '#')
chan = parv[0], cmd = parv[1];
else if (parv[1][0] == '#')
cmd = parv[0], chan = parv[1];
else
{
command_fail(si, fault_badparams, STR_INVALID_PARAMS, "ACCESS");
command_fail(si, fault_badparams, _("Syntax: ACCESS <#channel> ADD|DEL|LIST [nick] [level]"));
return;
}
mc = mychan_find(chan);
if (mc == NULL)
{
command_fail(si, fault_nosuch_target, _("\2%s\2 is not registered."), chan);
return;
}
if (!strcasecmp(cmd, "LIST"))
access_list(si, mc, parc - 2, parv + 2);
else if (parc < 3)
{
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "ACCESS");
command_fail(si, fault_needmoreparams, _("Syntax: ACCESS <#channel> ADD|DEL <nick> [level]"));
return;
}
else if (!strcasecmp(cmd, "ADD"))
compat_cmd(si, "FLAGS", chan, parv[2], parc > 3 ? parv[3] : (get_template_flags(mc, deftemplate) ? deftemplate : defaccess), NULL);
else if (!strcasecmp(cmd, "DEL"))
compat_cmd(si, "FLAGS", chan, parv[2], killit, NULL);
else
command_fail(si, fault_badparams, _("Invalid command. Use \2/%s%s help\2 for a command listing."), (ircd->uses_rcommand == FALSE) ? "msg " : "", si->service->disp);
}