ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/chanserv/set.C
Revision: 1.11
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.10: +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.10 /**
2     * set.C: This file contains routines to handle the ChanServ SET command.
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 © 2003-2004 E. Will et al.
10 pippijn 1.2 * Rights to this code are documented in doc/pod/license.pod.
11 pippijn 1.1 *
12 pippijn 1.11 * $Id: set.C,v 1.10 2007-09-16 18:54:43 pippijn Exp $
13 pippijn 1.1 */
14    
15     #include "atheme.h"
16 pippijn 1.11 #include <util/numeric.h>
17     #include <libermyth.h>
18 pippijn 1.9 #include "confparse.h"
19 pippijn 1.5 #include <ermyth/module.h>
20 pippijn 1.1 #include <account/myuser.h>
21     #include <account/chanacs.h>
22     #include <account/mychan.h>
23    
24 pippijn 1.11 static char const rcsid[] = "$Id: set.C,v 1.10 2007-09-16 18:54:43 pippijn Exp $";
25 pippijn 1.1
26 pippijn 1.5 static void on_config_ready (void);
27 pippijn 1.1
28 pippijn 1.11 REGISTER_MODULE ("chanserv/set", false, "The Ermyth Team <http://ermyth.xinutec.org>");
29 pippijn 1.1
30     static void cs_help_set (sourceinfo_t *si);
31     static void cs_cmd_set (sourceinfo_t *si, int parc, char *parv[]);
32    
33     static void cs_cmd_set_email (sourceinfo_t *si, int parc, char *parv[]);
34     static void cs_cmd_set_url (sourceinfo_t *si, int parc, char *parv[]);
35     static void cs_cmd_set_entrymsg (sourceinfo_t *si, int parc, char *parv[]);
36     static void cs_cmd_set_founder (sourceinfo_t *si, int parc, char *parv[]);
37     static void cs_cmd_set_mlock (sourceinfo_t *si, int parc, char *parv[]);
38     static void cs_cmd_set_keeptopic (sourceinfo_t *si, int parc, char *parv[]);
39     static void cs_cmd_set_topiclock (sourceinfo_t *si, int parc, char *parv[]);
40     static void cs_cmd_set_secure (sourceinfo_t *si, int parc, char *parv[]);
41     static void cs_cmd_set_verbose (sourceinfo_t *si, int parc, char *parv[]);
42     static void cs_cmd_set_fantasy (sourceinfo_t *si, int parc, char *parv[]);
43     static void cs_cmd_set_staffonly (sourceinfo_t *si, int parc, char *parv[]);
44     static void cs_cmd_set_property (sourceinfo_t *si, int parc, char *parv[]);
45     static void cs_cmd_set_guard (sourceinfo_t *si, int parc, char *parv[]);
46    
47 pippijn 1.5 command_t const cs_set = { "SET", N_("Sets various control flags."), AC_NONE, 3, cs_cmd_set };
48 pippijn 1.1
49 pippijn 1.5 command_t const cs_set_founder = { "FOUNDER", N_("Transfers foundership of a channel."), AC_NONE, 2, cs_cmd_set_founder };
50     command_t const cs_set_mlock = { "MLOCK", N_("Sets channel mode lock."), AC_NONE, 2, cs_cmd_set_mlock };
51     command_t const cs_set_secure = { "SECURE", N_("Prevents unauthorized users from gaining operator status."), AC_NONE, 2, cs_cmd_set_secure };
52     command_t const cs_set_verbose = { "VERBOSE", N_("Notifies channel about access list modifications."), AC_NONE, 2, cs_cmd_set_verbose };
53     command_t const cs_set_url = { "URL", N_("Sets the channel URL."), AC_NONE, 2, cs_cmd_set_url };
54     command_t const cs_set_entrymsg = { "ENTRYMSG", N_("Sets the channel's entry message."), AC_NONE, 2, cs_cmd_set_entrymsg };
55     command_t const cs_set_property = { "PROPERTY", N_("Manipulates channel metadata."), AC_NONE, 2, cs_cmd_set_property };
56     command_t const cs_set_email = { "EMAIL", N_("Sets the channel e-mail address."), AC_NONE, 2, cs_cmd_set_email };
57     command_t const cs_set_keeptopic = { "KEEPTOPIC", N_("Enables topic retention."), AC_NONE, 2, cs_cmd_set_keeptopic };
58     command_t const cs_set_topiclock = { "TOPICLOCK", N_("Restricts who can change the topic."), AC_NONE, 2, cs_cmd_set_topiclock };
59 pippijn 1.1 command_t cs_set_guard = { "GUARD", N_("Sets whether or not services will inhabit the channel."), AC_NONE, 2, cs_cmd_set_guard };
60 pippijn 1.5 command_t const cs_set_fantasy = { "FANTASY", N_("Allows or disallows in-channel commands."), AC_NONE, 2, cs_cmd_set_fantasy };
61     command_t const cs_set_staffonly = { "STAFFONLY", N_("Sets the channel as staff-only. (Non staff is kickbanned.)"), PRIV_CHAN_ADMIN, 2, cs_cmd_set_staffonly };
62 pippijn 1.1
63     command_t const *cs_set_commands[] = {
64     &cs_set_founder,
65     &cs_set_mlock,
66     &cs_set_secure,
67     &cs_set_verbose,
68     &cs_set_url,
69     &cs_set_entrymsg,
70     &cs_set_property,
71     &cs_set_email,
72     &cs_set_keeptopic,
73     &cs_set_topiclock,
74     &cs_set_guard,
75     &cs_set_fantasy,
76     &cs_set_staffonly,
77     NULL
78     };
79    
80 pippijn 1.5 E cmdvec cs_cmdtree;
81     E helpvec cs_helptree;
82 pippijn 1.1 cmdvec cs_set_cmdtree;
83    
84     static void
85 pippijn 1.5 on_config_ready (void)
86 pippijn 1.1 {
87     if (config_options.join_chans)
88     cs_set_guard.access = NULL;
89     else
90     cs_set_guard.access = PRIV_ADMIN;
91     }
92    
93     static void
94     cs_help_set (sourceinfo_t *si)
95     {
96     command_success_nodata (si, _("Help for \2SET\2:"));
97     command_success_nodata (si, " ");
98     command_success_nodata (si, _("SET allows you to set various control flags"));
99     command_success_nodata (si, _("for channels that change the way certain"));
100     command_success_nodata (si, _("operations are performed on them."));
101     command_success_nodata (si, " ");
102 pippijn 1.5 command_help (si, cs_set_cmdtree);
103 pippijn 1.1 command_success_nodata (si, " ");
104     command_success_nodata (si, _("For more specific help use \2/msg %s HELP SET \37command\37\2."), si->service->disp);
105     }
106    
107     /* SET <#channel> <setting> <parameters> */
108     static void
109     cs_cmd_set (sourceinfo_t *si, int parc, char *parv[])
110     {
111     char *chan;
112     char *cmd;
113     command_t const *c;
114    
115     if (parc < 3)
116     {
117 pippijn 1.7 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "SET");
118     command_fail (si, fault::needmoreparams, _("Syntax: SET <#channel> <setting> <parameters>"));
119 pippijn 1.1 return;
120     }
121    
122     if (parv[0][0] == '#')
123     chan = parv[0], cmd = parv[1];
124     else if (parv[1][0] == '#')
125     cmd = parv[0], chan = parv[1];
126     else
127     {
128 pippijn 1.7 command_fail (si, fault::badparams, STR_INVALID_PARAMS, "SET");
129     command_fail (si, fault::badparams, _("Syntax: SET <#channel> <setting> <parameters>"));
130 pippijn 1.1 return;
131     }
132    
133     c = cs_set_cmdtree.find (cmd);
134     if (c == NULL)
135     {
136 pippijn 1.7 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);
137 pippijn 1.1 return;
138     }
139    
140     parv[1] = chan;
141     c->exec (si->service, si, parc - 1, parv + 1);
142     }
143    
144     static void
145     cs_cmd_set_email (sourceinfo_t *si, int parc, char *parv[])
146     {
147     mychan_t *mc;
148     char *mail = parv[1];
149    
150 pippijn 1.7 if (!(mc = mychan_t::find (parv[0])))
151 pippijn 1.1 {
152 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), parv[0]);
153 pippijn 1.1 return;
154     }
155    
156     if (!chanacs_source_has_flag (mc, si, CA_SET))
157     {
158 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not authorized to execute this command."));
159 pippijn 1.1 return;
160     }
161    
162     if (!mail || !strcasecmp (mail, "NONE") || !strcasecmp (mail, "OFF"))
163     {
164     if (mc->find_metadata ("email"))
165     {
166     mc->del_metadata ("email");
167     command_success_nodata (si, _("The e-mail address for \2%s\2 was deleted."), mc->name);
168     logcommand (si, CMDLOG_SET, "%s SET EMAIL NONE", mc->name);
169     return;
170     }
171    
172 pippijn 1.7 command_fail (si, fault::nochange, _("The e-mail address for \2%s\2 was not set."), mc->name);
173 pippijn 1.1 return;
174     }
175    
176     if (strlen (mail) >= EMAILLEN)
177     {
178 pippijn 1.7 command_fail (si, fault::badparams, STR_INVALID_PARAMS, "EMAIL");
179 pippijn 1.1 return;
180     }
181    
182     if (!validemail (mail))
183     {
184 pippijn 1.7 command_fail (si, fault::badparams, _("\2%s\2 is not a valid e-mail address."), mail);
185 pippijn 1.1 return;
186     }
187    
188     /* we'll overwrite any existing metadata */
189     mc->add_metadata ("email", mail);
190    
191     logcommand (si, CMDLOG_SET, "%s SET EMAIL %s", mc->name, mail);
192     command_success_nodata (si, _("The e-mail address for \2%s\2 has been set to \2%s\2."), parv[0], mail);
193     }
194    
195     static void
196     cs_cmd_set_url (sourceinfo_t *si, int parc, char *parv[])
197     {
198     mychan_t *mc;
199     char *url = parv[1];
200    
201 pippijn 1.7 if (!(mc = mychan_t::find (parv[0])))
202 pippijn 1.1 {
203 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), parv[0]);
204 pippijn 1.1 return;
205     }
206    
207     if (!chanacs_source_has_flag (mc, si, CA_SET))
208     {
209 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not authorized to execute this command."));
210 pippijn 1.1 return;
211     }
212    
213     /* XXX: I'd like to be able to use /CS SET #channel URL to clear but CS SET won't let me... */
214     if (!url || !strcasecmp ("OFF", url) || !strcasecmp ("NONE", url))
215     {
216     /* not in a namespace to allow more natural use of SET PROPERTY.
217     * they may be able to introduce spaces, though. c'est la vie.
218     */
219     if (mc->find_metadata ("url"))
220     {
221     mc->del_metadata ("url");
222     logcommand (si, CMDLOG_SET, "%s SET URL NONE", mc->name);
223     command_success_nodata (si, _("The URL for \2%s\2 has been cleared."), parv[0]);
224     return;
225     }
226    
227 pippijn 1.7 command_fail (si, fault::nochange, _("The URL for \2%s\2 was not set."), parv[0]);
228 pippijn 1.1 return;
229     }
230    
231     /* we'll overwrite any existing metadata */
232     mc->add_metadata ("url", url);
233    
234     logcommand (si, CMDLOG_SET, "%s SET URL %s", mc->name, url);
235     command_success_nodata (si, _("The URL of \2%s\2 has been set to \2%s\2."), parv[0], url);
236     }
237    
238     static void
239     cs_cmd_set_entrymsg (sourceinfo_t *si, int parc, char *parv[])
240     {
241     mychan_t *mc;
242    
243 pippijn 1.7 if (!(mc = mychan_t::find (parv[0])))
244 pippijn 1.1 {
245 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), parv[0]);
246 pippijn 1.1 return;
247     }
248    
249     if (!chanacs_source_has_flag (mc, si, CA_SET))
250     {
251 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not authorized to execute this command."));
252 pippijn 1.1 return;
253     }
254    
255     /* XXX: I'd like to be able to use /CS SET #channel ENTRYMSG to clear but CS SET won't let me... */
256     if (!parv[1] || !strcasecmp ("OFF", parv[1]) || !strcasecmp ("NONE", parv[1]))
257     {
258     /* entrymsg is private because users won't see it if they're AKICKED,
259     * if the channel is +i, or if the channel is STAFFONLY
260     */
261     if (mc->find_metadata ("private:entrymsg"))
262     {
263     mc->del_metadata ("private:entrymsg");
264     logcommand (si, CMDLOG_SET, "%s SET ENTRYMSG NONE", mc->name, parv[1]);
265     command_success_nodata (si, _("The entry message for \2%s\2 has been cleared."), parv[0]);
266     return;
267     }
268    
269 pippijn 1.7 command_fail (si, fault::nochange, _("The entry message for \2%s\2 was not set."), parv[0]);
270 pippijn 1.1 return;
271     }
272    
273     /* we'll overwrite any existing metadata */
274     mc->add_metadata ("private:entrymsg", parv[1]);
275    
276     logcommand (si, CMDLOG_SET, "%s SET ENTRYMSG %s", mc->name, parv[1]);
277     command_success_nodata (si, _("The entry message for \2%s\2 has been set to \2%s\2"), parv[0], parv[1]);
278     }
279    
280     /*
281     * This is how CS SET FOUNDER behaves in the absence of channel passwords:
282     *
283     * To transfer a channel, the original founder (OF) issues the command:
284     * /CS SET #chan FOUNDER NF
285     * where NF is the new founder of the channel.
286     *
287     * Then, to complete the transfer, the NF must issue the command:
288     * /CS SET #chan FOUNDER NF
289     *
290     * To cancel the transfer before it completes, the OF can issue the command:
291     * /CS SET #chan FOUNDER OF
292     *
293     * The purpose of the confirmation step is to prevent users from giving away
294     * undesirable channels (e.g. registering #kidsex and transferring to an
295     * innocent user.) Originally, we used channel passwords for this purpose.
296     */
297     static void
298     cs_cmd_set_founder (sourceinfo_t *si, int parc, char *parv[])
299     {
300     char *newfounder = parv[1];
301     myuser_t *tmu;
302     mychan_t *mc;
303    
304     if (!si->smu)
305     {
306 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not logged in."));
307 pippijn 1.1 return;
308     }
309    
310 pippijn 1.6 if (!(tmu = myuser_t::find_ext (newfounder)))
311 pippijn 1.1 {
312 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), newfounder);
313 pippijn 1.1 return;
314     }
315    
316 pippijn 1.7 if (!(mc = mychan_t::find (parv[0])))
317 pippijn 1.1 {
318 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), parv[0]);
319 pippijn 1.1 return;
320     }
321    
322 pippijn 1.5 if (!si->smu->is_founder (mc))
323 pippijn 1.1 {
324     /* User is not currently the founder.
325     * Maybe he is trying to complete a transfer?
326     */
327 pippijn 1.8 metadata *md;
328 pippijn 1.1
329     /* XXX is it portable to compare times like that? */
330     if ((si->smu == tmu) && (md = mc->find_metadata ("private:verify:founderchg:newfounder")) && !irccasecmp (md->value, si->smu->name) && (md = mc->find_metadata ("private:verify:founderchg:timestamp")) && (atol (md->value) >= si->smu->registered))
331     {
332     node_t *n;
333     chanacs_t *ca;
334    
335 pippijn 1.6 if ((tmu->num_channels () >= me.maxchans) && !has_priv_myuser (tmu, PRIV_REG_NOLIMIT))
336 pippijn 1.1 {
337 pippijn 1.7 command_fail (si, fault::toomany, _("\2%s\2 has too many channels registered."), tmu->name);
338 pippijn 1.1 return;
339     }
340    
341     if (mc->find_metadata ("private:close:closer"))
342     {
343 pippijn 1.7 command_fail (si, fault::noprivs, _("\2%s\2 is closed; it cannot be transferred."), mc->name);
344 pippijn 1.1 return;
345     }
346    
347 pippijn 1.7 logcommand (si, CMDLOG_REGISTER, "%s SET FOUNDER %s (completing transfer from %s)", mc->name, tmu->name, mc->founder_names ());
348     verbose (mc, "Foundership transferred from \2%s\2 to \2%s\2.", mc->founder_names (), tmu->name);
349 pippijn 1.1
350     /* add target as founder... */
351 pippijn 1.5 LIST_FOREACH (n, mc->chanacs.head)
352     {
353     ca = static_cast<chanacs_t *> (n->data);
354     /* CA_FLAGS is always on if CA_FOUNDER is on, this just
355     * ensures we don't crash if not -- jilles
356     */
357     if (ca->myuser != NULL && ca->level & CA_FOUNDER)
358     chanacs_modify_simple (ca, CA_FLAGS, CA_FOUNDER);
359     }
360     chanacs_change_simple (mc, tmu, NULL, CA_FOUNDER_0, 0);
361    
362     /* delete transfer metadata */
363     mc->del_metadata ("private:verify:founderchg:newfounder");
364     mc->del_metadata ("private:verify:founderchg:timestamp");
365 pippijn 1.1
366     /* done! */
367     snoop ("SET:FOUNDER: \2%s\2 -> \2%s\2", mc->name, tmu->name);
368     command_success_nodata (si, _("Transfer complete: \2%s\2 has been set as founder for \2%s\2."), tmu->name, mc->name);
369    
370     return;
371     }
372    
373 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not the founder of \2%s\2."), mc->name);
374 pippijn 1.1 return;
375     }
376    
377 pippijn 1.5 if (tmu->is_founder (mc))
378 pippijn 1.1 {
379     /* User is currently the founder and
380     * trying to transfer back to himself.
381     * Maybe he is trying to cancel a transfer?
382     */
383    
384     if (mc->find_metadata ("private:verify:founderchg:newfounder"))
385     {
386     mc->del_metadata ("private:verify:founderchg:newfounder");
387     mc->del_metadata ("private:verify:founderchg:timestamp");
388    
389     logcommand (si, CMDLOG_REGISTER, "%s SET FOUNDER %s (cancelling transfer)", mc->name, tmu->name);
390     command_success_nodata (si, _("The transfer of \2%s\2 has been cancelled."), mc->name);
391    
392     return;
393     }
394    
395 pippijn 1.7 command_fail (si, fault::nochange, _("\2%s\2 is already the founder of \2%s\2."), tmu->name, mc->name);
396 pippijn 1.1 return;
397     }
398    
399     /* If the target user does not have access yet, this may overflow
400     * the access list. Check at this time because that is more convenient
401     * for users.
402     * -- jilles
403     */
404     if (!chanacs_find (mc, tmu, 0))
405     {
406     chanacs_t *ca;
407    
408     ca = chanacs_open (mc, tmu, NULL, true);
409     if (ca->level == 0 && chanacs_is_table_full (ca))
410     {
411 pippijn 1.7 command_fail (si, fault::toomany, _("Channel %s access list is full."), mc->name);
412 pippijn 1.1 chanacs_close (ca);
413     return;
414     }
415     chanacs_close (ca);
416     }
417    
418     /* check for lazy cancellation of outstanding requests */
419     if (mc->find_metadata ("private:verify:founderchg:newfounder"))
420     {
421     logcommand (si, CMDLOG_REGISTER, "%s SET FOUNDER %s (cancelling old transfer and initializing transfer)", mc->name, tmu->name);
422     command_success_nodata (si, _("The previous transfer request for \2%s\2 has been cancelled."), mc->name);
423     }
424     else
425     logcommand (si, CMDLOG_REGISTER, "%s SET FOUNDER %s (initializing transfer)", mc->name, tmu->name);
426    
427     mc->add_metadata ("private:verify:founderchg:newfounder", tmu->name);
428 pippijn 1.5 mc->add_metadata ("private:verify:founderchg:timestamp", itoa (NOW));
429 pippijn 1.1
430     command_success_nodata (si, _("\2%s\2 can now take ownership of \2%s\2."), tmu->name, mc->name);
431     command_success_nodata (si, _("In order to complete the transfer, \2%s\2 must perform the following command:"), tmu->name);
432     command_success_nodata (si, " \2/msg %s SET %s FOUNDER %s\2", chansvs.nick, mc->name, tmu->name);
433     command_success_nodata (si, _("After that command is issued, the channel will be transferred."), mc->name);
434 pippijn 1.5 command_success_nodata (si, _("To cancel the transfer, use \2/msg %s SET %s FOUNDER %s\2"), chansvs.nick, mc->name, si->smu->name);
435 pippijn 1.1 }
436    
437     static void
438     cs_cmd_set_mlock (sourceinfo_t *si, int parc, char *parv[])
439     {
440     mychan_t *mc;
441     char modebuf[32], *end, c;
442     int add = -1;
443     int newlock_on = 0, newlock_off = 0, newlock_limit = 0, flag = 0;
444     int mask;
445     char newlock_key[KEYLEN];
446     char newlock_ext[MAXEXTMODES][512];
447     bool newlock_ext_off[MAXEXTMODES];
448     char newext[512];
449     char ext_plus[MAXEXTMODES + 1], ext_minus[MAXEXTMODES + 1];
450     int i;
451     char *letters = strtok (parv[1], " ");
452     char *arg;
453    
454     if (!letters)
455     {
456 pippijn 1.7 command_fail (si, fault::badparams, STR_INVALID_PARAMS, "MLOCK");
457 pippijn 1.1 return;
458     }
459    
460 pippijn 1.7 if (!(mc = mychan_t::find (parv[0])))
461 pippijn 1.1 {
462 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), parv[0]);
463 pippijn 1.1 return;
464     }
465    
466     if (!chanacs_source_has_flag (mc, si, CA_SET))
467     {
468 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not authorized to perform this command."));
469 pippijn 1.1 return;
470     }
471    
472     for (i = 0; i < MAXEXTMODES; i++)
473     {
474     newlock_ext[i][0] = '\0';
475     newlock_ext_off[i] = false;
476     }
477     ext_plus[0] = '\0';
478     ext_minus[0] = '\0';
479     newlock_key[0] = '\0';
480    
481     mask = has_priv (si, PRIV_CHAN_CMODES) ? 0 : ircd->oper_only_modes;
482    
483     while (*letters)
484     {
485     if (*letters != '+' && *letters != '-' && add < 0)
486     {
487     letters++;
488     continue;
489     }
490    
491     switch ((c = *letters++))
492     {
493     case '+':
494     add = 1;
495     break;
496    
497     case '-':
498     add = 0;
499     break;
500    
501     case 'k':
502     if (add)
503     {
504     arg = strtok (NULL, " ");
505     if (!arg)
506     {
507 pippijn 1.7 command_fail (si, fault::badparams, _("You need to specify which key to MLOCK."));
508 pippijn 1.1 return;
509     }
510     else if (strlen (arg) >= KEYLEN)
511     {
512 pippijn 1.7 command_fail (si, fault::badparams, _("MLOCK key is too long (%d > %d)."), strlen (arg), KEYLEN - 1);
513 pippijn 1.1 return;
514     }
515     else if (strchr (arg, ',') || arg[0] == ':')
516     {
517 pippijn 1.7 command_fail (si, fault::badparams, _("MLOCK key contains invalid characters."));
518 pippijn 1.1 return;
519     }
520    
521     strlcpy (newlock_key, arg, sizeof newlock_key);
522     newlock_off &= ~CMODE_KEY;
523     }
524     else
525     {
526     newlock_key[0] = '\0';
527     newlock_off |= CMODE_KEY;
528     }
529    
530     break;
531    
532     case 'l':
533     if (add)
534     {
535     arg = strtok (NULL, " ");
536     if (!arg)
537     {
538 pippijn 1.7 command_fail (si, fault::badparams, _("You need to specify what limit to MLOCK."));
539 pippijn 1.1 return;
540     }
541    
542     if (atol (arg) <= 0)
543     {
544 pippijn 1.7 command_fail (si, fault::badparams, _("You must specify a positive integer for limit."));
545 pippijn 1.1 return;
546     }
547    
548     newlock_limit = atol (arg);
549     newlock_off &= ~CMODE_LIMIT;
550     }
551     else
552     {
553     newlock_limit = 0;
554     newlock_off |= CMODE_LIMIT;
555     }
556    
557     break;
558    
559     default:
560     flag = mode_to_flag (c);
561    
562     if (flag)
563     {
564     if (add)
565     newlock_on |= flag, newlock_off &= ~flag;
566     else
567     newlock_off |= flag, newlock_on &= ~flag;
568     break;
569     }
570    
571     for (i = 0; ignore_mode_list[i].mode != '\0'; i++)
572     {
573     if (c == ignore_mode_list[i].mode)
574     {
575     if (add)
576     {
577     arg = strtok (NULL, " ");
578     if (!arg)
579     {
580 pippijn 1.7 command_fail (si, fault::badparams, _("You need to specify a value for mode +%c."), c);
581 pippijn 1.1 return;
582     }
583     if (strlen (arg) > 350)
584     {
585 pippijn 1.7 command_fail (si, fault::badparams, _("Invalid value \2%s\2 for mode +%c."), arg, c);
586 pippijn 1.1 return;
587     }
588     if ((mc->chan == NULL || mc->chan->extmodes[i] == NULL || strcmp (mc->chan->extmodes[i], arg)) && !ignore_mode_list[i].check (arg, mc->chan, mc, si->su, si->smu))
589     {
590 pippijn 1.7 command_fail (si, fault::badparams, _("Invalid value \2%s\2 for mode +%c."), arg, c);
591 pippijn 1.1 return;
592     }
593     strlcpy (newlock_ext[i], arg, sizeof newlock_ext[i]);
594     newlock_ext_off[i] = false;
595     }
596     else
597     {
598     newlock_ext[i][0] = '\0';
599     newlock_ext_off[i] = true;
600     }
601     }
602     }
603     }
604     }
605    
606     if (strlen (newext) > 450)
607     {
608 pippijn 1.7 command_fail (si, fault::badparams, _("Mode lock is too long."));
609 pippijn 1.1 return;
610     }
611    
612     /* save it to mychan */
613     /* leave the modes in mask unchanged -- jilles */
614     mc->mlock_on = (newlock_on & ~mask) | (mc->mlock_on & mask);
615     mc->mlock_off = (newlock_off & ~mask) | (mc->mlock_off & mask);
616     mc->mlock_limit = newlock_limit;
617    
618     if (mc->mlock_key)
619 pippijn 1.5 sfree (mc->mlock_key);
620 pippijn 1.1
621     mc->mlock_key = *newlock_key != '\0' ? sstrdup (newlock_key) : NULL;
622    
623     newext[0] = '\0';
624     for (i = 0; i < MAXEXTMODES; i++)
625     {
626     if (newlock_ext[i][0] != '\0' || newlock_ext_off[i])
627     {
628     if (*newext != '\0')
629     {
630     modebuf[0] = ' ';
631     modebuf[1] = '\0';
632     strlcat (newext, modebuf, sizeof newext);
633     }
634     modebuf[0] = ignore_mode_list[i].mode;
635     modebuf[1] = '\0';
636     strlcat (newext, modebuf, sizeof newext);
637     strlcat (newlock_ext_off[i] ? ext_minus : ext_plus, modebuf, MAXEXTMODES + 1);
638     if (!newlock_ext_off[i])
639     strlcat (newext, newlock_ext[i], sizeof newext);
640     }
641     }
642     if (newext[0] != '\0')
643     mc->add_metadata ("private:mlockext", newext);
644     else
645     mc->del_metadata ("private:mlockext");
646    
647     end = modebuf;
648     *end = 0;
649    
650     if (mc->mlock_on || mc->mlock_key || mc->mlock_limit || *ext_plus)
651     end += snprintf (end, sizeof (modebuf) - (end - modebuf), "+%s%s%s%s", flags_to_string (mc->mlock_on), mc->mlock_key ? "k" : "", mc->mlock_limit ? "l" : "", ext_plus);
652    
653     if (mc->mlock_off || *ext_minus)
654     end += snprintf (end, sizeof (modebuf) - (end - modebuf), "-%s%s%s%s", flags_to_string (mc->mlock_off), mc->mlock_off & CMODE_KEY ? "k" : "", mc->mlock_off & CMODE_LIMIT ? "l" : "", ext_minus);
655    
656     if (*modebuf)
657     {
658     command_success_nodata (si, _("The MLOCK for \2%s\2 has been set to \2%s\2."), mc->name, modebuf);
659     logcommand (si, CMDLOG_SET, "%s SET MLOCK %s", mc->name, modebuf);
660     }
661     else
662     {
663     command_success_nodata (si, _("The MLOCK for \2%s\2 has been removed."), mc->name);
664     logcommand (si, CMDLOG_SET, "%s SET MLOCK NONE", mc->name);
665     }
666    
667     check_modes (mc, true);
668    
669     return;
670     }
671    
672     static void
673     cs_cmd_set_keeptopic (sourceinfo_t *si, int parc, char *parv[])
674     {
675     mychan_t *mc;
676    
677 pippijn 1.7 if (!(mc = mychan_t::find (parv[0])))
678 pippijn 1.1 {
679 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), parv[0]);
680 pippijn 1.1 return;
681     }
682    
683     if (!chanacs_source_has_flag (mc, si, CA_SET))
684     {
685 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not authorized to perform this command."));
686 pippijn 1.1 return;
687     }
688    
689     if (!strcasecmp ("ON", parv[1]))
690     {
691     if (MC_KEEPTOPIC & mc->flags)
692     {
693 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is already set for \2%s\2."), "KEEPTOPIC", mc->name);
694 pippijn 1.1 return;
695     }
696    
697     logcommand (si, CMDLOG_SET, "%s SET KEEPTOPIC ON", mc->name);
698    
699     mc->flags |= MC_KEEPTOPIC;
700    
701     command_success_nodata (si, _("The \2%s\2 flag has been set for \2%s\2."), "KEEPTOPIC", mc->name);
702    
703     return;
704     }
705    
706     else if (!strcasecmp ("OFF", parv[1]))
707     {
708     if (!(MC_KEEPTOPIC & mc->flags))
709     {
710 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is not set for \2%s\2."), "KEEPTOPIC", mc->name);
711 pippijn 1.1 return;
712     }
713    
714     logcommand (si, CMDLOG_SET, "%s SET KEEPTOPIC OFF", mc->name);
715    
716     mc->flags &= ~(MC_KEEPTOPIC | MC_TOPICLOCK);
717    
718     command_success_nodata (si, _("The \2%s\2 flag has been removed for \2%s\2."), "KEEPTOPIC", mc->name);
719    
720     return;
721     }
722    
723     else
724     {
725 pippijn 1.7 command_fail (si, fault::badparams, STR_INVALID_PARAMS, "KEEPTOPIC");
726 pippijn 1.1 return;
727     }
728     }
729    
730     static void
731     cs_cmd_set_topiclock (sourceinfo_t *si, int parc, char *parv[])
732     {
733     mychan_t *mc;
734    
735 pippijn 1.7 if (!(mc = mychan_t::find (parv[0])))
736 pippijn 1.1 {
737 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), parv[0]);
738 pippijn 1.1 return;
739     }
740    
741     if (!chanacs_source_has_flag (mc, si, CA_SET))
742     {
743 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not authorized to perform this command."));
744 pippijn 1.1 return;
745     }
746    
747     if (!strcasecmp ("ON", parv[1]))
748     {
749     if (MC_TOPICLOCK & mc->flags)
750     {
751 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is already set for \2%s\2."), "TOPICLOCK", mc->name);
752 pippijn 1.1 return;
753     }
754    
755     logcommand (si, CMDLOG_SET, "%s SET TOPICLOCK ON", mc->name);
756    
757     mc->flags |= MC_KEEPTOPIC | MC_TOPICLOCK;
758    
759     command_success_nodata (si, _("The \2%s\2 flag has been set for \2%s\2."), "TOPICLOCK", mc->name);
760    
761     return;
762     }
763    
764     else if (!strcasecmp ("OFF", parv[1]))
765     {
766     if (!(MC_TOPICLOCK & mc->flags))
767     {
768 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is not set for \2%s\2."), "TOPICLOCK", mc->name);
769 pippijn 1.1 return;
770     }
771    
772     logcommand (si, CMDLOG_SET, "%s SET TOPICLOCK OFF", mc->name);
773    
774     mc->flags &= ~MC_TOPICLOCK;
775    
776     command_success_nodata (si, _("The \2%s\2 flag has been removed for \2%s\2."), "TOPICLOCK", mc->name);
777    
778     return;
779     }
780    
781     else
782     {
783 pippijn 1.7 command_fail (si, fault::badparams, STR_INVALID_PARAMS, "TOPICLOCK");
784 pippijn 1.1 return;
785     }
786     }
787    
788     static void
789     cs_cmd_set_secure (sourceinfo_t *si, int parc, char *parv[])
790     {
791     mychan_t *mc;
792    
793 pippijn 1.7 if (!(mc = mychan_t::find (parv[0])))
794 pippijn 1.1 {
795 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), parv[0]);
796 pippijn 1.1 return;
797     }
798    
799     if (!chanacs_source_has_flag (mc, si, CA_SET))
800     {
801 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not authorized to perform this command."));
802 pippijn 1.1 return;
803     }
804    
805     if (!strcasecmp ("ON", parv[1]))
806     {
807     if (MC_SECURE & mc->flags)
808     {
809 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is already set for \2%s\2."), "SECURE", mc->name);
810 pippijn 1.1 return;
811     }
812    
813     logcommand (si, CMDLOG_SET, "%s SET SECURE ON", mc->name);
814    
815     mc->flags |= MC_SECURE;
816    
817     command_success_nodata (si, _("The \2%s\2 flag has been set for \2%s\2."), "SECURE", mc->name);
818    
819     return;
820     }
821    
822     else if (!strcasecmp ("OFF", parv[1]))
823     {
824     if (!(MC_SECURE & mc->flags))
825     {
826 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is not set for \2%s\2."), "SECURE", mc->name);
827 pippijn 1.1 return;
828     }
829    
830     logcommand (si, CMDLOG_SET, "%s SET SECURE OFF", mc->name);
831    
832     mc->flags &= ~MC_SECURE;
833    
834     command_success_nodata (si, _("The \2%s\2 flag has been removed for \2%s\2."), "SECURE", mc->name);
835    
836     return;
837     }
838    
839     else
840     {
841 pippijn 1.7 command_fail (si, fault::badparams, STR_INVALID_PARAMS, "SECURE");
842 pippijn 1.1 return;
843     }
844     }
845    
846     static void
847     cs_cmd_set_verbose (sourceinfo_t *si, int parc, char *parv[])
848     {
849     mychan_t *mc;
850    
851 pippijn 1.7 if (!(mc = mychan_t::find (parv[0])))
852 pippijn 1.1 {
853 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), parv[0]);
854 pippijn 1.1 return;
855     }
856    
857     if (!chanacs_source_has_flag (mc, si, CA_SET))
858     {
859 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not authorized to perform this command."));
860 pippijn 1.1 return;
861     }
862    
863     if (!strcasecmp ("ON", parv[1]) || !strcasecmp ("ALL", parv[1]))
864     {
865     if (MC_VERBOSE & mc->flags)
866     {
867 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is already set for \2%s\2."), "VERBOSE", mc->name);
868 pippijn 1.1 return;
869     }
870    
871     logcommand (si, CMDLOG_SET, "%s SET VERBOSE ON", mc->name);
872    
873     mc->flags &= ~MC_VERBOSE_OPS;
874     mc->flags |= MC_VERBOSE;
875    
876     verbose (mc, "\2%s\2 enabled the VERBOSE flag", get_source_name (si));
877     command_success_nodata (si, _("The \2%s\2 flag has been set for \2%s\2."), "VERBOSE", mc->name);
878    
879     return;
880     }
881    
882     else if (!strcasecmp ("OPS", parv[1]))
883     {
884     if (MC_VERBOSE_OPS & mc->flags)
885     {
886 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is already set for \2%s\2."), "VERBOSE_OPS", mc->name);
887 pippijn 1.1 return;
888     }
889    
890     logcommand (si, CMDLOG_SET, "%s SET VERBOSE OPS", mc->name);
891    
892     if (mc->flags & MC_VERBOSE)
893     {
894     verbose (mc, "\2%s\2 restricted VERBOSE to chanops", get_source_name (si));
895     mc->flags &= ~MC_VERBOSE;
896     mc->flags |= MC_VERBOSE_OPS;
897     }
898     else
899     {
900     mc->flags |= MC_VERBOSE_OPS;
901     verbose (mc, "\2%s\2 enabled the VERBOSE_OPS flag", get_source_name (si));
902     }
903    
904     command_success_nodata (si, _("The \2%s\2 flag has been set for \2%s\2."), "VERBOSE_OPS", mc->name);
905    
906     return;
907     }
908     else if (!strcasecmp ("OFF", parv[1]))
909     {
910     if (!((MC_VERBOSE | MC_VERBOSE_OPS) & mc->flags))
911     {
912 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is not set for \2%s\2."), "VERBOSE", mc->name);
913 pippijn 1.1 return;
914     }
915    
916     logcommand (si, CMDLOG_SET, "%s SET VERBOSE OFF", mc->name);
917    
918     if (mc->flags & MC_VERBOSE)
919     verbose (mc, "\2%s\2 disabled the VERBOSE flag", get_source_name (si));
920     else
921     verbose (mc, "\2%s\2 disabled the VERBOSE_OPS flag", get_source_name (si));
922     mc->flags &= ~(MC_VERBOSE | MC_VERBOSE_OPS);
923    
924     command_success_nodata (si, _("The \2%s\2 flag has been removed for \2%s\2."), "VERBOSE", mc->name);
925    
926     return;
927     }
928    
929     else
930     {
931 pippijn 1.7 command_fail (si, fault::badparams, STR_INVALID_PARAMS, "VERBOSE");
932 pippijn 1.1 return;
933     }
934     }
935    
936     static void
937     cs_cmd_set_fantasy (sourceinfo_t *si, int parc, char *parv[])
938     {
939     mychan_t *mc;
940    
941 pippijn 1.7 if (!(mc = mychan_t::find (parv[0])))
942 pippijn 1.1 {
943 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), parv[0]);
944 pippijn 1.1 return;
945     }
946    
947     if (!chanacs_source_has_flag (mc, si, CA_SET))
948     {
949 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not authorized to perform this command."));
950 pippijn 1.1 return;
951     }
952    
953     if (!strcasecmp ("ON", parv[1]))
954     {
955 pippijn 1.8 metadata *md = mc->find_metadata ("disable_fantasy");
956 pippijn 1.1
957     if (!md)
958     {
959 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is already set for \2%s\2."), "FANTASY", mc->name);
960 pippijn 1.1 return;
961     }
962    
963     mc->del_metadata ("disable_fantasy");
964    
965     logcommand (si, CMDLOG_SET, "%s SET FANTASY ON", mc->name);
966     command_success_nodata (si, _("The \2%s\2 flag has been set for \2%s\2."), "FANTASY", mc->name);
967     return;
968     }
969     else if (!strcasecmp ("OFF", parv[1]))
970     {
971 pippijn 1.8 metadata *md = mc->find_metadata ("disable_fantasy");
972 pippijn 1.1
973     if (md)
974     {
975 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is not set for \2%s\2."), "FANTASY", mc->name);
976 pippijn 1.1 return;
977     }
978    
979     mc->add_metadata ("disable_fantasy", "on");
980    
981     logcommand (si, CMDLOG_SET, "%s SET FANTASY OFF", mc->name);
982     command_success_nodata (si, _("The \2%s\2 flag has been removed for \2%s\2."), "FANTASY", mc->name);
983     return;
984     }
985    
986     else
987     {
988 pippijn 1.7 command_fail (si, fault::badparams, STR_INVALID_PARAMS, "FANTASY");
989 pippijn 1.1 return;
990     }
991     }
992    
993     static void
994     cs_cmd_set_guard (sourceinfo_t *si, int parc, char *parv[])
995     {
996     mychan_t *mc;
997    
998 pippijn 1.7 if (!(mc = mychan_t::find (parv[0])))
999 pippijn 1.1 {
1000 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), parv[0]);
1001 pippijn 1.1 return;
1002     }
1003    
1004     if (!chanacs_source_has_flag (mc, si, CA_SET))
1005     {
1006 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not authorized to perform this command."));
1007 pippijn 1.1 return;
1008     }
1009    
1010     if (!strcasecmp ("ON", parv[1]))
1011     {
1012     if (MC_GUARD & mc->flags)
1013     {
1014 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is already set for \2%s\2."), "GUARD", mc->name);
1015 pippijn 1.1 return;
1016     }
1017    
1018     logcommand (si, CMDLOG_SET, "%s SET GUARD ON", mc->name);
1019    
1020     mc->flags |= MC_GUARD;
1021    
1022     if (!(mc->flags & MC_INHABIT))
1023     join (mc->name, chansvs.nick);
1024    
1025     command_success_nodata (si, _("The \2%s\2 flag has been set for \2%s\2."), "GUARD", mc->name);
1026    
1027     return;
1028     }
1029    
1030     else if (!strcasecmp ("OFF", parv[1]))
1031     {
1032     if (!(MC_GUARD & mc->flags))
1033     {
1034 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is not set for \2%s\2."), "GUARD", mc->name);
1035 pippijn 1.1 return;
1036     }
1037    
1038     logcommand (si, CMDLOG_SET, "%s SET GUARD OFF", mc->name);
1039    
1040     mc->flags &= ~MC_GUARD;
1041    
1042     if (!(mc->flags & MC_INHABIT) && (!config_options.chan || irccasecmp (config_options.chan, mc->name)))
1043     part (mc->name, chansvs.nick);
1044    
1045     command_success_nodata (si, _("The \2%s\2 flag has been removed for \2%s\2."), "GUARD", mc->name);
1046    
1047     return;
1048     }
1049    
1050     else
1051     {
1052 pippijn 1.7 command_fail (si, fault::badparams, STR_INVALID_PARAMS, "GUARD");
1053 pippijn 1.1 return;
1054     }
1055     }
1056    
1057     static void
1058     cs_cmd_set_staffonly (sourceinfo_t *si, int parc, char *parv[])
1059     {
1060     mychan_t *mc;
1061    
1062 pippijn 1.7 if (!(mc = mychan_t::find (parv[0])))
1063 pippijn 1.1 {
1064 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), parv[0]);
1065 pippijn 1.1 return;
1066     }
1067    
1068     if (!strcasecmp ("ON", parv[1]))
1069     {
1070     if (MC_STAFFONLY & mc->flags)
1071     {
1072 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is already set for \2%s\2."), "STAFFONLY", mc->name);
1073 pippijn 1.1 return;
1074     }
1075    
1076     snoop ("SET:STAFFONLY:ON: for \2%s\2 by \2%s\2", mc->name, get_oper_name (si));
1077     logcommand (si, CMDLOG_SET, "%s SET STAFFONLY ON", mc->name);
1078    
1079     mc->flags |= MC_STAFFONLY;
1080    
1081     command_success_nodata (si, _("The \2%s\2 flag has been set for \2%s\2."), "STAFFONLY", mc->name);
1082    
1083     return;
1084     }
1085    
1086     else if (!strcasecmp ("OFF", parv[1]))
1087     {
1088     if (!(MC_STAFFONLY & mc->flags))
1089     {
1090 pippijn 1.7 command_fail (si, fault::nochange, _("The \2%s\2 flag is not set for \2%s\2."), "STAFFONLY", mc->name);
1091 pippijn 1.1 return;
1092     }
1093    
1094     snoop ("SET:STAFFONLY:OFF: for \2%s\2 by \2%s\2", mc->name, get_oper_name (si));
1095     logcommand (si, CMDLOG_SET, "%s SET STAFFONLY OFF", mc->name);
1096    
1097     mc->flags &= ~MC_STAFFONLY;
1098    
1099     command_success_nodata (si, _("The \2%s\2 flag has been removed for \2%s\2."), "STAFFONLY", mc->name);
1100    
1101     return;
1102     }
1103    
1104     else
1105     {
1106 pippijn 1.7 command_fail (si, fault::badparams, STR_INVALID_PARAMS, "STAFFONLY");
1107 pippijn 1.1 return;
1108     }
1109     }
1110    
1111     static void
1112     cs_cmd_set_property (sourceinfo_t *si, int parc, char *parv[])
1113     {
1114     mychan_t *mc;
1115     char *property = strtok (parv[1], " ");
1116     char *value = strtok (NULL, "");
1117    
1118     if (!property)
1119     {
1120 pippijn 1.7 command_fail (si, fault::needmoreparams, _("Syntax: SET <#channel> PROPERTY <property> [value]"));
1121 pippijn 1.1 return;
1122     }
1123    
1124     /* do we really need to allow this? -- jilles */
1125     if (strchr (property, ':') && !has_priv (si, PRIV_METADATA))
1126     {
1127 pippijn 1.7 command_fail (si, fault::badparams, _("Invalid property name."));
1128 pippijn 1.1 return;
1129     }
1130    
1131 pippijn 1.7 if (!(mc = mychan_t::find (parv[0])))
1132 pippijn 1.1 {
1133 pippijn 1.7 command_fail (si, fault::nosuch_target, _("\2%s\2 is not registered."), parv[0]);
1134 pippijn 1.1 return;
1135     }
1136    
1137 pippijn 1.5 if (!si->smu->is_founder (mc))
1138 pippijn 1.1 {
1139 pippijn 1.7 command_fail (si, fault::noprivs, _("You are not authorized to perform this command."));
1140 pippijn 1.1 return;
1141     }
1142    
1143     if (mc->metadata.count >= me.mdlimit)
1144     {
1145 pippijn 1.7 command_fail (si, fault::toomany, _("Cannot add \2%s\2 to \2%s\2 metadata table, it is full."), property, parv[0]);
1146 pippijn 1.1 return;
1147     }
1148    
1149     if (strchr (property, ':'))
1150     snoop ("SET:PROPERTY: \2%s\2: \2%s\2/\2%s\2", mc->name, property, value);
1151    
1152     if (!value)
1153     {
1154 pippijn 1.8 metadata *md = mc->find_metadata (property);
1155 pippijn 1.1
1156     if (!md)
1157     {
1158 pippijn 1.7 command_fail (si, fault::nochange, _("Metadata entry \2%s\2 was not set."), property);
1159 pippijn 1.1 return;
1160     }
1161    
1162     mc->del_metadata (property);
1163     logcommand (si, CMDLOG_SET, "%s SET PROPERTY %s (deleted)", mc->name, property);
1164     command_success_nodata (si, _("Metadata entry \2%s\2 has been deleted."), property);
1165     return;
1166     }
1167    
1168     if (strlen (property) > 32 || strlen (value) > 300)
1169     {
1170 pippijn 1.7 command_fail (si, fault::badparams, _("Parameters are too long. Aborting."));
1171 pippijn 1.1 return;
1172     }
1173    
1174     mc->add_metadata (property, value);
1175     logcommand (si, CMDLOG_SET, "%s SET PROPERTY %s to %s", mc->name, property, value);
1176     command_success_nodata (si, _("Metadata entry \2%s\2 added."), property);
1177     }
1178    
1179 pippijn 1.5 bool
1180     _modinit (module *m)
1181     {
1182     cs_cmdtree << cs_set;
1183     cs_set_cmdtree << cs_set_commands;
1184    
1185     help_addentry (cs_helptree, "SET", NULL, cs_help_set);
1186     help_addentry (cs_helptree, "SET FOUNDER", "help/chanserv/set_founder", NULL);
1187     help_addentry (cs_helptree, "SET MLOCK", "help/chanserv/set_mlock", NULL);
1188     help_addentry (cs_helptree, "SET SECURE", "help/chanserv/set_secure", NULL);
1189     help_addentry (cs_helptree, "SET VERBOSE", "help/chanserv/set_verbose", NULL);
1190     help_addentry (cs_helptree, "SET URL", "help/chanserv/set_url", NULL);
1191     help_addentry (cs_helptree, "SET EMAIL", "help/chanserv/set_email", NULL);
1192     help_addentry (cs_helptree, "SET ENTRYMSG", "help/chanserv/set_entrymsg", NULL);
1193     help_addentry (cs_helptree, "SET PROPERTY", "help/chanserv/set_property", NULL);
1194     help_addentry (cs_helptree, "SET STAFFONLY", "help/chanserv/set_staffonly", NULL);
1195     help_addentry (cs_helptree, "SET KEEPTOPIC", "help/chanserv/set_keeptopic", NULL);
1196     help_addentry (cs_helptree, "SET TOPICLOCK", "help/chanserv/set_topiclock", NULL);
1197     help_addentry (cs_helptree, "SET FANTASY", "help/chanserv/set_fantasy", NULL);
1198     help_addentry (cs_helptree, "SET GUARD", "help/chanserv/set_guard", NULL);
1199    
1200     ConfTable::callback.ready.attach (on_config_ready);
1201    
1202     return true;
1203     }
1204    
1205     void
1206     _moddeinit ()
1207     {
1208     cs_cmdtree >> cs_set;
1209     cs_set_cmdtree >> cs_set_commands;
1210    
1211     help_delentry (cs_helptree, "SET");
1212     help_delentry (cs_helptree, "SET FOUNDER");
1213     help_delentry (cs_helptree, "SET MLOCK");
1214     help_delentry (cs_helptree, "SET SECURE");
1215     help_delentry (cs_helptree, "SET VERBOSE");
1216     help_delentry (cs_helptree, "SET URL");
1217     help_delentry (cs_helptree, "SET EMAIL");
1218     help_delentry (cs_helptree, "SET ENTRYMSG");
1219     help_delentry (cs_helptree, "SET PROPERTY");
1220     help_delentry (cs_helptree, "SET STAFFONLY");
1221     help_delentry (cs_helptree, "SET KEEPTOPIC");
1222     help_delentry (cs_helptree, "SET TOPICLOCK");
1223     help_delentry (cs_helptree, "SET FANTASY");
1224     help_delentry (cs_helptree, "SET GUARD");
1225    
1226     ConfTable::callback.ready.detach (on_config_ready);
1227     }