ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/modules/chanserv/flags.C
Revision: 1.10
Committed: Sat Sep 22 14:27:27 2007 UTC (19 years ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.9: +5 -3 lines
Log Message:
split up ermyth into ermyth-modules, libermyth (currently just ermyth-util) and ermyth-core

File Contents

# User Rev Content
1 pippijn 1.9 /**
2     * flags.C: This file contains code for the ChanServ FLAGS functions.
3     *
4     * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team
5     * Rights to this code are as documented in COPYING.
6     *
7     *
8     * Portions of this file were derived from sources bearing the following license:
9 pippijn 1.5 * Copyright © 2005-2007 William Pitcock, et al.
10 pippijn 1.2 * Rights to this code are as documented in doc/pod/license.pod.
11 pippijn 1.1 *
12 pippijn 1.10 * $Id: flags.C,v 1.9 2007-09-16 18:54:42 pippijn Exp $
13 pippijn 1.1 */
14    
15     #include "atheme.h"
16 pippijn 1.10 #include <util/time.h>
17     #include <util/time.h>
18 pippijn 1.5 #include <ermyth/module.h>
19 pippijn 1.1 #include <account/mychan.h>
20     #include <account/myuser.h>
21     #include <account/chanacs.h>
22     #include "template.h"
23    
24 pippijn 1.10 static char const rcsid[] = "$Id: flags.C,v 1.9 2007-09-16 18:54:42 pippijn Exp $";
25 pippijn 1.1
26 pippijn 1.10 REGISTER_MODULE ("chanserv/flags", false, "The Ermyth Team <http://ermyth.xinutec.org>");
27 pippijn 1.1
28     static void cs_cmd_flags (sourceinfo_t *si, int parc, char *parv[]);
29    
30 pippijn 1.5 command_t const cs_flags = { "FLAGS", N_("Manipulates specific permissions on a channel."), AC_NONE, 3, cs_cmd_flags };
31 pippijn 1.1
32 pippijn 1.5 E cmdvec cs_cmdtree;
33     E helpvec cs_helptree;
34 pippijn 1.1
35 pippijn 1.5 bool
36     _modinit (module *m)
37 pippijn 1.1 {
38     cs_cmdtree << cs_flags;
39 pippijn 1.4 help_addentry (cs_helptree, "FLAGS", "help/chanserv/flags", NULL);
40 pippijn 1.5
41     return true;
42 pippijn 1.1 }
43    
44     void
45     _moddeinit ()
46     {
47     cs_cmdtree >> cs_flags;
48     help_delentry (cs_helptree, "FLAGS");
49     }
50    
51 pippijn 1.5 static char const * const
52 pippijn 1.1 get_template_name (mychan_t *mc, unsigned int level)
53     {
54 pippijn 1.8 metadata *md;
55 pippijn 1.5 char const *p, *q, *r;
56 pippijn 1.1 char *s;
57     char ss[40];
58     static char flagname[400];
59    
60     md = mc->find_metadata ("private:templates");
61     if (md != NULL)
62     {
63     p = md->value;
64     while (p != NULL)
65     {
66     while (*p == ' ')
67     p++;
68     q = strchr (p, '=');
69     if (q == NULL)
70     break;
71     r = strchr (q, ' ');
72     if (r != NULL && r < q)
73     break;
74     strlcpy (ss, q, sizeof ss);
75     if (r != NULL && r - q < (int) (sizeof ss - 1))
76     {
77     ss[r - q] = '\0';
78     }
79     if (level == flags_to_bitmask (ss, chanacs_flags, 0))
80     {
81     strlcpy (flagname, p, sizeof flagname);
82     s = strchr (flagname, '=');
83     if (s != NULL)
84     *s = '\0';
85     return flagname;
86     }
87     p = r;
88     }
89     }
90     if (level == chansvs.ca_sop)
91     return "SOP";
92     if (level == chansvs.ca_aop)
93     return "AOP";
94     /* if vop==hop, prefer vop */
95     if (level == chansvs.ca_vop)
96     return "VOP";
97     if (level == chansvs.ca_hop)
98     return "HOP";
99     return NULL;
100     }
101    
102     /* FLAGS <channel> [user] [flags] */
103     static void
104     cs_cmd_flags (sourceinfo_t *si, int parc, char *parv[])
105     {
106     chanacs_t *ca;
107     node_t *n;
108     int operoverride = 0;
109     char *channel = parv[0];
110     char *target = parv[1];
111 pippijn 1.5 char const *str1;
112     char const *str2;
113 pippijn 1.1 unsigned int addflags, removeflags, restrictflags;
114    
115     if (parc < 1)
116     {
117 pippijn 1.7 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "FLAGS");
118     command_fail (si, fault::needmoreparams, _("Syntax: FLAGS <channel> [target] [flags]"));
119 pippijn 1.1 return;
120     }
121    
122     if (!target)
123     {
124 pippijn 1.7 mychan_t *mc = mychan_t::find (channel);
125 pippijn 1.1 unsigned int i = 1;
126    
127     if (!mc)
128     {
129 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), channel);
130 pippijn 1.1 return;
131     }
132    
133     if (!chanacs_source_has_flag (mc, si, CA_ACLVIEW))
134     {
135     if (has_priv (si, PRIV_CHAN_AUSPEX))
136     operoverride = 1;
137     else
138     {
139 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not authorized to perform this operation."));
140 pippijn 1.1 return;
141     }
142     }
143    
144     if (mc->find_metadata ("private:close:closer") && !has_priv (si, PRIV_CHAN_AUSPEX))
145     {
146 pippijn 1.7 command_fail (si, fault::noprivs, _("\2%s\2 is closed."), channel);
147 pippijn 1.1 return;
148     }
149    
150     command_success_nodata (si, _("Entry Nickname/Host Flags"));
151     command_success_nodata (si, "----- ---------------------- -----");
152    
153     LIST_FOREACH (n, mc->chanacs.head)
154     {
155     ca = static_cast<chanacs_t *> (n->data);
156     str1 = get_template_name (mc, ca->level);
157     str2 = ca->ts ? time_ago (ca->ts) : "?";
158     if (str1 != NULL)
159     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);
160     else
161     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);
162     i++;
163     }
164    
165     command_success_nodata (si, "----- ---------------------- -----");
166     command_success_nodata (si, _("End of \2%s\2 FLAGS listing."), channel);
167     if (operoverride)
168     logcommand (si, CMDLOG_ADMIN, "%s FLAGS (oper override)", mc->name);
169     else
170     logcommand (si, CMDLOG_GET, "%s FLAGS", mc->name);
171     }
172     else
173     {
174 pippijn 1.7 mychan_t *mc = mychan_t::find (channel);
175 pippijn 1.1 myuser_t *tmu;
176     char *flagstr = parv[2];
177    
178     if (!si->smu)
179     {
180 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not logged in."));
181 pippijn 1.1 return;
182     }
183    
184     if (!mc)
185     {
186 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), channel);
187 pippijn 1.1 return;
188     }
189    
190     if (mc->find_metadata ("private:close:closer"))
191     {
192 pippijn 1.7 command_fail (si, fault::noprivs, _("\2%s\2 is closed."), channel);
193 pippijn 1.1 return;
194     }
195    
196     if (!target)
197     {
198 pippijn 1.7 command_fail (si, fault::needmoreparams, _("Usage: FLAGS %s [target] [flags]"), channel);
199 pippijn 1.1 return;
200     }
201    
202     if (!flagstr)
203     {
204     if (!chanacs_source_has_flag (mc, si, CA_ACLVIEW))
205     {
206 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not authorized to execute this command."));
207 pippijn 1.1 return;
208     }
209     if (validhostmask (target))
210     ca = chanacs_find_host_literal (mc, target, 0);
211     else
212     {
213 pippijn 1.6 if (!(tmu = myuser_t::find_ext (target)))
214 pippijn 1.1 {
215 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), target);
216 pippijn 1.1 return;
217     }
218     target = tmu->name;
219     ca = chanacs_find (mc, tmu, 0);
220     }
221     if (ca != NULL)
222     {
223     str1 = bitmask_to_flags2 (ca->level, 0, chanacs_flags);
224     command_success_string (si, str1, _("Flags for \2%s\2 in \2%s\2 are \2%s\2."), target, channel, str1);
225     }
226     else
227     command_success_string (si, "", _("No flags for \2%s\2 in \2%s\2."), target, channel);
228     logcommand (si, CMDLOG_GET, "%s FLAGS %s", mc->name, target);
229     return;
230     }
231    
232     /* founder may always set flags -- jilles */
233 pippijn 1.5 restrictflags = chanacs_source_flags (mc, si);
234     if (restrictflags & CA_FOUNDER)
235 pippijn 1.1 restrictflags = ca_all;
236     else
237     {
238     if (!(restrictflags & CA_FLAGS))
239     {
240     /* allow a user to remove their own access
241     * even without +f */
242     if (restrictflags & CA_AKICK || si->smu == NULL || irccasecmp (target, si->smu->name) || strcmp (flagstr, "-*"))
243     {
244 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not authorized to execute this command."));
245 pippijn 1.1 return;
246     }
247     }
248     restrictflags = allow_flags (restrictflags);
249     }
250    
251     if (*flagstr == '+' || *flagstr == '-' || *flagstr == '=')
252     {
253     flags_make_bitmasks (flagstr, chanacs_flags, &addflags, &removeflags);
254     if (addflags == 0 && removeflags == 0)
255     {
256 pippijn 1.7 command_fail (si, fault::badparams, _("No valid flags given, use /%s%s HELP FLAGS for a list"), ircd->uses_rcommand ? "" : "msg ", chansvs.disp);
257 pippijn 1.1 return;
258     }
259     }
260     else
261     {
262     addflags = get_template_flags (mc, flagstr);
263     if (addflags == 0)
264     {
265     /* Hack -- jilles */
266     if (*target == '+' || *target == '-' || *target == '=')
267 pippijn 1.7 command_fail (si, fault::badparams, _("Usage: FLAGS %s [target] [flags]"), mc->name);
268 pippijn 1.1 else
269 pippijn 1.7 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);
270 pippijn 1.1 return;
271     }
272     removeflags = ca_all & ~addflags;
273     }
274    
275     if (!validhostmask (target))
276 pippijn 1.5 {
277 pippijn 1.6 if (!(tmu = myuser_t::find_ext (target)))
278 pippijn 1.5 {
279 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), target);
280 pippijn 1.5 return;
281     }
282     target = tmu->name;
283    
284     ca = chanacs_open (mc, tmu, NULL, true);
285    
286     if (ca->level & CA_FOUNDER && removeflags & CA_FLAGS && !(removeflags & CA_FOUNDER))
287     {
288 pippijn 1.7 command_fail (si, fault::noprivs, _("You may not remove a founder's +f access."));
289 pippijn 1.5 return;
290     }
291 pippijn 1.7 if (ca->level & CA_FOUNDER && removeflags & CA_FOUNDER && mc->num_founders () == 1)
292 pippijn 1.5 {
293 pippijn 1.7 command_fail (si, fault::noprivs, _("You may not remove the last founder."));
294 pippijn 1.5 return;
295     }
296     if (!(ca->level & CA_FOUNDER) && addflags & CA_FOUNDER)
297     {
298 pippijn 1.7 if (mc->num_founders () >= chansvs.maxfounders)
299 pippijn 1.5 {
300 pippijn 1.7 command_fail (si, fault::noprivs, _("Only %d founders allowed per channel."), chansvs.maxfounders);
301 pippijn 1.5 chanacs_close (ca);
302     return;
303     }
304 pippijn 1.6 if ((tmu->num_channels () >= me.maxchans) && !has_priv_myuser (tmu, PRIV_REG_NOLIMIT))
305 pippijn 1.5 {
306 pippijn 1.7 command_fail (si, fault::toomany, _("\2%s\2 has too many channels registered."), tmu->name);
307 pippijn 1.5 return;
308     }
309     }
310     if (addflags & CA_FOUNDER)
311     addflags |= CA_FLAGS, removeflags &= ~CA_FLAGS;
312 pippijn 1.1
313     /* If NEVEROP is set, don't allow adding new entries
314     * except sole +b. Adding flags if the current level
315     * is +b counts as adding an entry.
316     * -- jilles */
317 pippijn 1.8 if (tmu->flags & MU_NEVEROP && addflags != CA_AKICK && addflags != 0 && (ca->level == 0 || ca->level == CA_AKICK))
318 pippijn 1.1 {
319 pippijn 1.7 command_fail (si, fault::noprivs, _("\2%s\2 does not wish to be added to access lists (NEVEROP set)."), tmu->name);
320 pippijn 1.1 chanacs_close (ca);
321     return;
322     }
323    
324     if (ca->level == 0 && chanacs_is_table_full (ca))
325     {
326 pippijn 1.7 command_fail (si, fault::toomany, _("Channel %s access list is full."), mc->name);
327 pippijn 1.1 chanacs_close (ca);
328     return;
329     }
330    
331     if (!chanacs_modify (ca, &addflags, &removeflags, restrictflags))
332     {
333 pippijn 1.7 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);
334 pippijn 1.1 chanacs_close (ca);
335     return;
336     }
337     chanacs_close (ca);
338     }
339     else
340     {
341 pippijn 1.5 if (addflags & CA_FOUNDER)
342     {
343 pippijn 1.7 command_fail (si, fault::badparams, _("You may not set founder status on a hostmask."));
344 pippijn 1.5 return;
345     }
346     ca = chanacs_open (mc, NULL, target, true);
347     if (ca->level == 0 && chanacs_is_table_full (ca))
348 pippijn 1.1 {
349 pippijn 1.7 command_fail (si, fault::toomany, _("Channel %s access list is full."), mc->name);
350 pippijn 1.1 chanacs_close (ca);
351     return;
352     }
353     if (!chanacs_modify (ca, &addflags, &removeflags, restrictflags))
354     {
355 pippijn 1.7 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);
356 pippijn 1.1 chanacs_close (ca);
357     return;
358     }
359     chanacs_close (ca);
360     }
361    
362     if ((addflags | removeflags) == 0)
363     {
364 pippijn 1.7 command_fail (si, fault::nochange, _("Channel access to \2%s\2 for \2%s\2 unchanged."), channel, target);
365 pippijn 1.1 return;
366     }
367     flagstr = bitmask_to_flags2 (addflags, removeflags, chanacs_flags);
368     command_success_nodata (si, _("Flags \2%s\2 were set on \2%s\2 in \2%s\2."), flagstr, target, channel);
369     logcommand (si, CMDLOG_SET, "%s FLAGS %s %s", mc->name, target, flagstr);
370     verbose (mc, "\2%s\2 set flags \2%s\2 on \2%s\2.", get_source_name (si), flagstr, target);
371     }
372     }
373    
374     /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
375     * vim:ts=8
376     * vim:sw=8
377     * vim:noexpandtab
378     */