ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/chanserv/set.C
Revision: 1.10
Committed: Sun Sep 16 18:54:43 2007 UTC (19 years, 1 month ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.9: +10 -5 lines
Log Message:
#defines to enum

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