]> jfr.im git - irc/rqf/shadowircd.git/blob - modules/m_set.c
[svn] - the new plan:
[irc/rqf/shadowircd.git] / modules / m_set.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_set.c: Sets a server parameter.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 *
24 * $Id: m_set.c 494 2006-01-15 16:08:28Z jilles $
25 */
26
27 /* rewritten by jdc */
28
29 #include "stdinc.h"
30 #include "client.h"
31 #include "event.h"
32 #include "irc_string.h"
33 #include "sprintf_irc.h"
34 #include "ircd.h"
35 #include "numeric.h"
36 #include "commio.h"
37 #include "s_serv.h"
38 #include "send.h"
39 #include "common.h"
40 #include "channel.h"
41 #include "s_conf.h"
42 #include "s_newconf.h"
43 #include "msg.h"
44 #include "parse.h"
45 #include "modules.h"
46
47 static int mo_set(struct Client *, struct Client *, int, const char **);
48
49 struct Message set_msgtab = {
50 "SET", 0, 0, 0, MFLG_SLOW,
51 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_set, 0}}
52 };
53
54 mapi_clist_av1 set_clist[] = { &set_msgtab, NULL };
55 DECLARE_MODULE_AV1(set, NULL, NULL, set_clist, NULL, NULL, "$Revision: 494 $");
56
57 /* Structure used for the SET table itself */
58 struct SetStruct
59 {
60 const char *name;
61 void (*handler) ();
62 int wants_char; /* 1 if it expects (char *, [int]) */
63 int wants_int; /* 1 if it expects ([char *], int) */
64
65 /* eg: 0, 1 == only an int arg
66 * eg: 1, 1 == char and int args */
67 };
68
69
70 static void quote_adminstring(struct Client *, const char *);
71 static void quote_autoconn(struct Client *, char *, int);
72 static void quote_autoconnall(struct Client *, int);
73 static void quote_floodcount(struct Client *, int);
74 static void quote_identtimeout(struct Client *, int);
75 static void quote_idletime(struct Client *, int);
76 static void quote_max(struct Client *, int);
77 static void quote_operstring(struct Client *, const char *);
78 static void quote_spamnum(struct Client *, int);
79 static void quote_spamtime(struct Client *, int);
80 static void quote_splitmode(struct Client *, char *);
81 static void quote_splitnum(struct Client *, int);
82 static void quote_splitusers(struct Client *, int);
83 static void list_quote_commands(struct Client *);
84
85
86 /*
87 * If this ever needs to be expanded to more than one arg of each
88 * type, want_char/want_int could be the count of the arguments,
89 * instead of just a boolean flag...
90 *
91 * -davidt
92 */
93
94 static struct SetStruct set_cmd_table[] = {
95 /* name function string arg int arg */
96 /* -------------------------------------------------------- */
97 {"ADMINSTRING", quote_adminstring, 1, 0 },
98 {"AUTOCONN", quote_autoconn, 1, 1 },
99 {"AUTOCONNALL", quote_autoconnall, 0, 1 },
100 {"FLOODCOUNT", quote_floodcount, 0, 1 },
101 {"IDENTTIMEOUT", quote_identtimeout, 0, 1 },
102 {"IDLETIME", quote_idletime, 0, 1 },
103 {"MAX", quote_max, 0, 1 },
104 {"MAXCLIENTS", quote_max, 0, 1 },
105 {"OPERSTRING", quote_operstring, 1, 0 },
106 {"SPAMNUM", quote_spamnum, 0, 1 },
107 {"SPAMTIME", quote_spamtime, 0, 1 },
108 {"SPLITMODE", quote_splitmode, 1, 0 },
109 {"SPLITNUM", quote_splitnum, 0, 1 },
110 {"SPLITUSERS", quote_splitusers, 0, 1 },
111 /* -------------------------------------------------------- */
112 {(char *) 0, (void (*)()) 0, 0, 0}
113 };
114
115
116 /*
117 * list_quote_commands() sends the client all the available commands.
118 * Four to a line for now.
119 */
120 static void
121 list_quote_commands(struct Client *source_p)
122 {
123 int i;
124 int j = 0;
125 const char *names[4];
126
127 sendto_one(source_p, ":%s NOTICE %s :Available QUOTE SET commands:",
128 me.name, source_p->name);
129
130 names[0] = names[1] = names[2] = names[3] = "";
131
132 for (i = 0; set_cmd_table[i].handler; i++)
133 {
134 names[j++] = set_cmd_table[i].name;
135
136 if(j > 3)
137 {
138 sendto_one(source_p, ":%s NOTICE %s :%s %s %s %s",
139 me.name, source_p->name, names[0], names[1], names[2], names[3]);
140 j = 0;
141 names[0] = names[1] = names[2] = names[3] = "";
142 }
143
144 }
145 if(j)
146 sendto_one(source_p, ":%s NOTICE %s :%s %s %s %s",
147 me.name, source_p->name, names[0], names[1], names[2], names[3]);
148 }
149
150 /* SET AUTOCONN */
151 static void
152 quote_autoconn(struct Client *source_p, char *arg, int newval)
153 {
154 set_server_conf_autoconn(source_p, arg, newval);
155 }
156
157 /* SET AUTOCONNALL */
158 static void
159 quote_autoconnall(struct Client *source_p, int newval)
160 {
161 if(newval >= 0)
162 {
163 sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s has changed AUTOCONNALL to %i",
164 source_p->name, newval);
165
166 GlobalSetOptions.autoconn = newval;
167 }
168 else
169 {
170 sendto_one(source_p, ":%s NOTICE %s :AUTOCONNALL is currently %i",
171 me.name, source_p->name, GlobalSetOptions.autoconn);
172 }
173 }
174
175
176 /* SET FLOODCOUNT */
177 static void
178 quote_floodcount(struct Client *source_p, int newval)
179 {
180 if(newval >= 0)
181 {
182 GlobalSetOptions.floodcount = newval;
183 sendto_realops_snomask(SNO_GENERAL, L_ALL,
184 "%s has changed FLOODCOUNT to %i", source_p->name,
185 GlobalSetOptions.floodcount);
186 }
187 else
188 {
189 sendto_one(source_p, ":%s NOTICE %s :FLOODCOUNT is currently %i",
190 me.name, source_p->name, GlobalSetOptions.floodcount);
191 }
192 }
193
194 /* SET IDENTTIMEOUT */
195 static void
196 quote_identtimeout(struct Client *source_p, int newval)
197 {
198 if(!IsOperAdmin(source_p))
199 {
200 sendto_one(source_p, form_str(ERR_NOPRIVS),
201 me.name, source_p->name, "admin");
202 return;
203 }
204
205 if(newval > 0)
206 {
207 sendto_realops_snomask(SNO_GENERAL, L_ALL,
208 "%s has changed IDENTTIMEOUT to %d",
209 get_oper_name(source_p), newval);
210 GlobalSetOptions.ident_timeout = newval;
211 }
212 else
213 sendto_one(source_p, ":%s NOTICE %s :IDENTTIMEOUT is currently %d",
214 me.name, source_p->name, GlobalSetOptions.ident_timeout);
215 }
216
217 /* SET IDLETIME */
218 static void
219 quote_idletime(struct Client *source_p, int newval)
220 {
221 if(newval >= 0)
222 {
223 if(newval == 0)
224 {
225 sendto_realops_snomask(SNO_GENERAL, L_ALL,
226 "%s has disabled idletime checking", source_p->name);
227 GlobalSetOptions.idletime = 0;
228 }
229 else
230 {
231 sendto_realops_snomask(SNO_GENERAL, L_ALL,
232 "%s has changed IDLETIME to %i",
233 source_p->name, newval);
234 GlobalSetOptions.idletime = (newval * 60);
235 }
236 }
237 else
238 {
239 sendto_one(source_p, ":%s NOTICE %s :IDLETIME is currently %i",
240 me.name, source_p->name, GlobalSetOptions.idletime / 60);
241 }
242 }
243
244 /* SET MAX */
245 static void
246 quote_max(struct Client *source_p, int newval)
247 {
248 if(newval > 0)
249 {
250 if(newval > MASTER_MAX)
251 {
252 sendto_one(source_p,
253 ":%s NOTICE %s :You cannot set MAXCLIENTS to > MASTER_MAX (%d)",
254 me.name, source_p->name, MASTER_MAX);
255 return;
256 }
257
258 if(newval < 32)
259 {
260 sendto_one(source_p,
261 ":%s NOTICE %s :You cannot set MAXCLIENTS to < 32 (%d:%d)",
262 me.name, source_p->name, GlobalSetOptions.maxclients,
263 highest_fd);
264 return;
265 }
266
267 GlobalSetOptions.maxclients = newval;
268
269 sendto_realops_snomask(SNO_GENERAL, L_ALL,
270 "%s!%s@%s set new MAXCLIENTS to %d (%lu current)",
271 source_p->name, source_p->username, source_p->host,
272 GlobalSetOptions.maxclients,
273 dlink_list_length(&lclient_list));
274
275 return;
276 }
277 else
278 {
279 sendto_one(source_p, ":%s NOTICE %s :Current Maxclients = %d (%lu)",
280 me.name, source_p->name, GlobalSetOptions.maxclients,
281 dlink_list_length(&lclient_list));
282 }
283 }
284
285 /* SET OPERSTRING */
286 static void
287 quote_operstring(struct Client *source_p, const char *arg)
288 {
289 if(EmptyString(arg))
290 {
291 sendto_one(source_p, ":%s NOTICE %s :OPERSTRING is currently '%s'",
292 me.name, source_p->name, GlobalSetOptions.operstring);
293 }
294 else
295 {
296 strlcpy(GlobalSetOptions.operstring, arg,
297 sizeof(GlobalSetOptions.operstring));
298
299 sendto_realops_snomask(SNO_GENERAL, L_ALL,
300 "%s has changed OPERSTRING to '%s'",
301 get_oper_name(source_p), arg);
302 }
303 }
304
305 /* SET ADMINSTRING */
306 static void
307 quote_adminstring(struct Client *source_p, const char *arg)
308 {
309 if(EmptyString(arg))
310 {
311 sendto_one(source_p, ":%s NOTICE %s :ADMINSTRING is currently '%s'",
312 me.name, source_p->name, GlobalSetOptions.adminstring);
313 }
314 else
315 {
316 strlcpy(GlobalSetOptions.adminstring, arg,
317 sizeof(GlobalSetOptions.adminstring));
318
319 sendto_realops_snomask(SNO_GENERAL, L_ALL,
320 "%s has changed ADMINSTRING to '%s'",
321 get_oper_name(source_p), arg);
322 }
323 }
324
325 /* SET SPAMNUM */
326 static void
327 quote_spamnum(struct Client *source_p, int newval)
328 {
329 if(newval > 0)
330 {
331 if(newval == 0)
332 {
333 sendto_realops_snomask(SNO_GENERAL, L_ALL,
334 "%s has disabled ANTI_SPAMBOT", source_p->name);
335 GlobalSetOptions.spam_num = newval;
336 return;
337 }
338 if(newval < MIN_SPAM_NUM)
339 {
340 GlobalSetOptions.spam_num = MIN_SPAM_NUM;
341 }
342 else /* if (newval < MIN_SPAM_NUM) */
343 {
344 GlobalSetOptions.spam_num = newval;
345 }
346 sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s has changed SPAMNUM to %i",
347 source_p->name, GlobalSetOptions.spam_num);
348 }
349 else
350 {
351 sendto_one(source_p, ":%s NOTICE %s :SPAMNUM is currently %i",
352 me.name, source_p->name, GlobalSetOptions.spam_num);
353 }
354 }
355
356 /* SET SPAMTIME */
357 static void
358 quote_spamtime(struct Client *source_p, int newval)
359 {
360 if(newval > 0)
361 {
362 if(newval < MIN_SPAM_TIME)
363 {
364 GlobalSetOptions.spam_time = MIN_SPAM_TIME;
365 }
366 else /* if (newval < MIN_SPAM_TIME) */
367 {
368 GlobalSetOptions.spam_time = newval;
369 }
370 sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s has changed SPAMTIME to %i",
371 source_p->name, GlobalSetOptions.spam_time);
372 }
373 else
374 {
375 sendto_one(source_p, ":%s NOTICE %s :SPAMTIME is currently %i",
376 me.name, source_p->name, GlobalSetOptions.spam_time);
377 }
378 }
379
380 /* this table is what splitmode may be set to */
381 static const char *splitmode_values[] = {
382 "OFF",
383 "ON",
384 "AUTO",
385 NULL
386 };
387
388 /* this table is what splitmode may be */
389 static const char *splitmode_status[] = {
390 "OFF",
391 "AUTO (OFF)",
392 "ON",
393 "AUTO (ON)",
394 NULL
395 };
396
397 /* SET SPLITMODE */
398 static void
399 quote_splitmode(struct Client *source_p, char *charval)
400 {
401 if(charval)
402 {
403 int newval;
404
405 for (newval = 0; splitmode_values[newval]; newval++)
406 {
407 if(!irccmp(splitmode_values[newval], charval))
408 break;
409 }
410
411 /* OFF */
412 if(newval == 0)
413 {
414 sendto_realops_snomask(SNO_GENERAL, L_ALL,
415 "%s is disabling splitmode", get_oper_name(source_p));
416
417 splitmode = 0;
418 splitchecking = 0;
419
420 eventDelete(check_splitmode, NULL);
421 }
422 /* ON */
423 else if(newval == 1)
424 {
425 sendto_realops_snomask(SNO_GENERAL, L_ALL,
426 "%s is enabling and activating splitmode",
427 get_oper_name(source_p));
428
429 splitmode = 1;
430 splitchecking = 0;
431
432 /* we might be deactivating an automatic splitmode, so pull the event */
433 eventDelete(check_splitmode, NULL);
434 }
435 /* AUTO */
436 else if(newval == 2)
437 {
438 sendto_realops_snomask(SNO_GENERAL, L_ALL,
439 "%s is enabling automatic splitmode",
440 get_oper_name(source_p));
441
442 splitchecking = 1;
443 check_splitmode(NULL);
444 }
445 }
446 else
447 /* if we add splitchecking to splitmode*2 we get a unique table to
448 * pull values back out of, splitmode can be four states - but you can
449 * only set to three, which means we cant use the same table --fl_
450 */
451 sendto_one(source_p, ":%s NOTICE %s :SPLITMODE is currently %s",
452 me.name, source_p->name,
453 splitmode_status[(splitchecking + (splitmode * 2))]);
454 }
455
456 /* SET SPLITNUM */
457 static void
458 quote_splitnum(struct Client *source_p, int newval)
459 {
460 if(newval >= 0)
461 {
462 sendto_realops_snomask(SNO_GENERAL, L_ALL,
463 "%s has changed SPLITNUM to %i", source_p->name, newval);
464 split_servers = newval;
465
466 if(splitchecking)
467 check_splitmode(NULL);
468 }
469 else
470 sendto_one(source_p, ":%s NOTICE %s :SPLITNUM is currently %i",
471 me.name, source_p->name, split_servers);
472 }
473
474 /* SET SPLITUSERS */
475 static void
476 quote_splitusers(struct Client *source_p, int newval)
477 {
478 if(newval >= 0)
479 {
480 sendto_realops_snomask(SNO_GENERAL, L_ALL,
481 "%s has changed SPLITUSERS to %i", source_p->name, newval);
482 split_users = newval;
483
484 if(splitchecking)
485 check_splitmode(NULL);
486 }
487 else
488 sendto_one(source_p, ":%s NOTICE %s :SPLITUSERS is currently %i",
489 me.name, source_p->name, split_users);
490 }
491
492 /*
493 * mo_set - SET command handler
494 * set options while running
495 */
496 static int
497 mo_set(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
498 {
499 int newval;
500 int i, n;
501 const char *arg = NULL;
502 const char *intarg = NULL;
503
504 if(parc > 1)
505 {
506 /*
507 * Go through all the commands in set_cmd_table, until one is
508 * matched. I realize strcmp() is more intensive than a numeric
509 * lookup, but at least it's better than a big-ass switch/case
510 * statement.
511 */
512 for (i = 0; set_cmd_table[i].handler; i++)
513 {
514 if(!irccmp(set_cmd_table[i].name, parv[1]))
515 {
516 /*
517 * Command found; now execute the code
518 */
519 n = 2;
520
521 if(set_cmd_table[i].wants_char)
522 {
523 arg = parv[n++];
524 }
525
526 if(set_cmd_table[i].wants_int)
527 {
528 intarg = parv[n++];
529 }
530
531 if((n - 1) > parc)
532 {
533 sendto_one(source_p,
534 ":%s NOTICE %s :SET %s expects (\"%s%s\") args",
535 me.name, source_p->name,
536 set_cmd_table[i].name,
537 (set_cmd_table[i].
538 wants_char ? "string, " : ""),
539 (set_cmd_table[i].
540 wants_char ? "int" : ""));
541 return 0;
542 }
543
544 if(parc <= 2)
545 {
546 arg = NULL;
547 intarg = NULL;
548 }
549
550 if(set_cmd_table[i].wants_int && (parc > 2))
551 {
552 if(intarg)
553 {
554 if(!irccmp(intarg, "yes") || !irccmp(intarg, "on"))
555 newval = 1;
556 else if(!irccmp(intarg, "no")
557 || !irccmp(intarg, "off"))
558 newval = 0;
559 else
560 newval = atoi(intarg);
561 }
562 else
563 {
564 newval = -1;
565 }
566
567 if(newval < 0)
568 {
569 sendto_one(source_p,
570 ":%s NOTICE %s :Value less than 0 illegal for %s",
571 me.name, source_p->name,
572 set_cmd_table[i].name);
573
574 return 0;
575 }
576 }
577 else
578 newval = -1;
579
580 if(set_cmd_table[i].wants_char)
581 {
582 if(set_cmd_table[i].wants_int)
583 set_cmd_table[i].handler(source_p, arg, newval);
584 else
585 set_cmd_table[i].handler(source_p, arg);
586 return 0;
587 }
588 else
589 {
590 if(set_cmd_table[i].wants_int)
591 set_cmd_table[i].handler(source_p, newval);
592 else
593 /* Just in case someone actually wants a
594 * set function that takes no args.. *shrug* */
595 set_cmd_table[i].handler(source_p);
596 return 0;
597 }
598 }
599 }
600
601 /*
602 * Code here will be executed when a /QUOTE SET command is not
603 * found within set_cmd_table.
604 */
605 sendto_one(source_p, ":%s NOTICE %s :Variable not found.", me.name, parv[0]);
606 return 0;
607 }
608
609 list_quote_commands(source_p);
610
611 return 0;
612 }