1 /*
2 * Copyright (c) 2007 Jilles Tjoelker, et al.
3 * Rights to this code are as documented in doc/LICENSE.
4 *
5 * ChanServ ACCESS command
6 *
7 * $Id$
8 */
9
10 #include "atheme-compat.h"
11 #include "template.h"
12
13 DECLARE_MODULE_V1
14 (
15 "contrib/cs_access_alias", FALSE, _modinit, _moddeinit,
16 "$Id$",
17 "freenode <http://www.freenode.net>"
18 );
19
20 static void cs_cmd_access(sourceinfo_t *si, int parc, char *parv[]);
21
22 command_t cs_access = { "ACCESS", "Manipulates channel access lists.",
23 AC_NONE, 4, cs_cmd_access, { .path = "contrib/access" } };
24
_modinit(module_t * m)25 void _modinit(module_t *m)
26 {
27 service_named_bind_command("chanserv", &cs_access);
28 }
29
_moddeinit(module_unload_intent_t intent)30 void _moddeinit(module_unload_intent_t intent)
31 {
32 service_named_unbind_command("chanserv", &cs_access);
33 }
34
compat_cmd(sourceinfo_t * si,const char * cmdname,char * channel,char * arg1,char * arg2,char * arg3)35 static void compat_cmd(sourceinfo_t *si, const char *cmdname, char *channel, char *arg1, char *arg2, char *arg3)
36 {
37 int newparc;
38 char *newparv[5];
39 command_t *cmd;
40
41 newparv[0] = channel;
42 newparv[1] = arg1;
43 newparv[2] = arg2;
44 newparv[3] = arg3;
45 newparv[4] = NULL;
46 /* this assumes arg3!=NULL implies arg2!=NULL implies arg1!=NULL */
47 newparc = 1 + (arg1 != NULL) + (arg2 != NULL) + (arg3 != NULL);
48 cmd = command_find(si->service->commands, cmdname);
49 if (cmd != NULL)
50 command_exec(si->service, si, cmd, newparc, newparv);
51 else
52 command_fail(si, fault_unimplemented, _("Command \2%s\2 not loaded?"), cmdname);
53 }
54
55 typedef struct {
56 const char *res;
57 unsigned int level;
58 } template_iter_t;
59
global_template_search(const char * key,void * data,void * privdata)60 static int global_template_search(const char *key, void *data, void *privdata)
61 {
62 template_iter_t *iter = privdata;
63 default_template_t *def_t = data;
64
65 if (def_t->flags == iter->level)
66 iter->res = key;
67
68 return 0;
69 }
70
get_template_name(mychan_t * mc,unsigned int level)71 static const char *get_template_name(mychan_t *mc, unsigned int level)
72 {
73 metadata_t *md;
74 const char *p, *q, *r;
75 char *s;
76 char ss[40];
77 static char flagname[400];
78 template_iter_t iter;
79
80 md = metadata_find(mc, "private:templates");
81 if (md != NULL)
82 {
83 p = md->value;
84 while (p != NULL)
85 {
86 while (*p == ' ')
87 p++;
88 q = strchr(p, '=');
89 if (q == NULL)
90 break;
91 r = strchr(q, ' ');
92 if (r != NULL && r < q)
93 break;
94 mowgli_strlcpy(ss, q, sizeof ss);
95 if (r != NULL && r - q < (int)(sizeof ss - 1))
96 {
97 ss[r - q] = '\0';
98 }
99 if (level == flags_to_bitmask(ss, 0))
100 {
101 mowgli_strlcpy(flagname, p, sizeof flagname);
102 s = strchr(flagname, '=');
103 if (s != NULL)
104 *s = '\0';
105 return flagname;
106 }
107 p = r;
108 }
109 }
110
111 iter.res = NULL;
112 iter.level = level;
113 mowgli_patricia_foreach(global_template_dict, global_template_search, &iter);
114
115 return iter.res;
116 }
117
access_list(sourceinfo_t * si,mychan_t * mc,int parc,char * parv[])118 static void access_list(sourceinfo_t *si, mychan_t *mc, int parc, char *parv[])
119 {
120 mowgli_node_t *n;
121 chanacs_t *ca;
122 const char *str1, *str2;
123 int i = 1;
124 bool operoverride = false;
125
126 /* Copied from modules/chanserv/flags.c */
127 /* Note: This overrides the normal need of +A access unless private */
128 if (use_channel_private && mc->flags & MC_PRIVATE &&
129 !chanacs_source_has_flag(mc, si, CA_ACLVIEW))
130 {
131 if (has_priv(si, PRIV_CHAN_AUSPEX))
132 operoverride = true;
133 else
134 {
135 command_fail(si, fault_noprivs, _("You are not authorized to perform this operation."));
136 return;
137 }
138 }
139
140 command_success_nodata(si, _("Entry Nickname/Host Flags"));
141 command_success_nodata(si, "----- ---------------------- -----");
142
143 MOWGLI_ITER_FOREACH(n, mc->chanacs.head)
144 {
145 ca = n->data;
146 /* Change: don't show akicks */
147 if (ca->level == CA_AKICK)
148 continue;
149 str1 = get_template_name(mc, ca->level);
150 str2 = ca->tmodified ? time_ago(ca->tmodified) : "?";
151 if (str1 != NULL)
152 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,
153 str2);
154 else
155 command_success_nodata(si, _("%-5d %-22s %s [modified %s ago]"), i, ca->entity ? ca->entity->name : ca->host, bitmask_to_flags(ca->level),
156 str2);
157 i++;
158 }
159
160 command_success_nodata(si, "----- ---------------------- -----");
161 command_success_nodata(si, _("End of \2%s\2 FLAGS listing."), mc->name);
162
163 if (operoverride)
164 logcommand(si, CMDLOG_ADMIN, "%s ACCESS LIST (oper override)", mc->name);
165 else
166 logcommand(si, CMDLOG_GET, "%s ACCESS LIST", mc->name);
167 }
168
cs_cmd_access(sourceinfo_t * si,int parc,char * parv[])169 static void cs_cmd_access(sourceinfo_t *si, int parc, char *parv[])
170 {
171 char *chan, *cmd;
172 mychan_t *mc;
173 char killit[] = "-*";
174 char deftemplate[] = "OP";
175 char defaccess[] = "=votirA";
176
177 if (parc < 2)
178 {
179 command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "ACCESS");
180 command_fail(si, fault_needmoreparams, _("Syntax: ACCESS <#channel> ADD|DEL|LIST [nick] [level]"));
181 return;
182 }
183 if (parv[0][0] == '#')
184 chan = parv[0], cmd = parv[1];
185 else if (parv[1][0] == '#')
186 cmd = parv[0], chan = parv[1];
187 else
188 {
189 command_fail(si, fault_badparams, STR_INVALID_PARAMS, "ACCESS");
190 command_fail(si, fault_badparams, _("Syntax: ACCESS <#channel> ADD|DEL|LIST [nick] [level]"));
191 return;
192 }
193
194 mc = mychan_find(chan);
195 if (mc == NULL)
196 {
197 command_fail(si, fault_nosuch_target, _("\2%s\2 is not registered."), chan);
198 return;
199 }
200
201 if (!strcasecmp(cmd, "LIST"))
202 access_list(si, mc, parc - 2, parv + 2);
203 else if (parc < 3)
204 {
205 command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "ACCESS");
206 command_fail(si, fault_needmoreparams, _("Syntax: ACCESS <#channel> ADD|DEL <nick> [level]"));
207 return;
208 }
209 else if (!strcasecmp(cmd, "ADD"))
210 compat_cmd(si, "FLAGS", chan, parv[2], parc > 3 ? parv[3] : (get_template_flags(mc, deftemplate) ? deftemplate : defaccess), NULL);
211 else if (!strcasecmp(cmd, "DEL"))
212 compat_cmd(si, "FLAGS", chan, parv[2], killit, NULL);
213 else
214 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);
215 }
216