]> jfr.im git - irc/rqf/shadowircd.git/blame - modules/m_set.c
[svn] Change code that checks maxclients limit: allow exactly
[irc/rqf/shadowircd.git] / modules / m_set.c
CommitLineData
212380e3 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 *
35237302 24 * $Id: m_set.c 3253 2007-03-05 19:01:05Z nenolod $
212380e3 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
47static int mo_set(struct Client *, struct Client *, int, const char **);
48
49struct 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
54mapi_clist_av1 set_clist[] = { &set_msgtab, NULL };
35237302 55DECLARE_MODULE_AV1(set, NULL, NULL, set_clist, NULL, NULL, "$Revision: 3253 $");
212380e3 56
57/* Structure used for the SET table itself */
58struct 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
70static void quote_adminstring(struct Client *, const char *);
71static void quote_autoconn(struct Client *, char *, int);
72static void quote_autoconnall(struct Client *, int);
73static void quote_floodcount(struct Client *, int);
74static void quote_identtimeout(struct Client *, int);
75static void quote_idletime(struct Client *, int);
76static void quote_max(struct Client *, int);
77static void quote_operstring(struct Client *, const char *);
78static void quote_spamnum(struct Client *, int);
79static void quote_spamtime(struct Client *, int);
80static void quote_splitmode(struct Client *, char *);
81static void quote_splitnum(struct Client *, int);
82static void quote_splitusers(struct Client *, int);
83static 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
94static 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 */
120static void
121list_quote_commands(struct Client *source_p)
122{
123 int i;
124 int j = 0;
125 const char *names[4];
126
5366977b 127 sendto_one_notice(source_p, ":Available QUOTE SET commands:");
212380e3 128
129 names[0] = names[1] = names[2] = names[3] = "";
130
131 for (i = 0; set_cmd_table[i].handler; i++)
132 {
133 names[j++] = set_cmd_table[i].name;
134
135 if(j > 3)
136 {
5366977b 137 sendto_one_notice(source_p, ":%s %s %s %s",
138 names[0], names[1], names[2], names[3]);
212380e3 139 j = 0;
140 names[0] = names[1] = names[2] = names[3] = "";
141 }
142
143 }
144 if(j)
5366977b 145 sendto_one_notice(source_p, ":%s %s %s %s",
146 names[0], names[1], names[2], names[3]);
212380e3 147}
148
149/* SET AUTOCONN */
150static void
151quote_autoconn(struct Client *source_p, char *arg, int newval)
152{
153 set_server_conf_autoconn(source_p, arg, newval);
154}
155
156/* SET AUTOCONNALL */
157static void
158quote_autoconnall(struct Client *source_p, int newval)
159{
160 if(newval >= 0)
161 {
162 sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s has changed AUTOCONNALL to %i",
163 source_p->name, newval);
164
165 GlobalSetOptions.autoconn = newval;
166 }
167 else
168 {
5366977b 169 sendto_one_notice(source_p, ":AUTOCONNALL is currently %i",
170 GlobalSetOptions.autoconn);
212380e3 171 }
172}
173
174
175/* SET FLOODCOUNT */
176static void
177quote_floodcount(struct Client *source_p, int newval)
178{
179 if(newval >= 0)
180 {
181 GlobalSetOptions.floodcount = newval;
182 sendto_realops_snomask(SNO_GENERAL, L_ALL,
183 "%s has changed FLOODCOUNT to %i", source_p->name,
184 GlobalSetOptions.floodcount);
185 }
186 else
187 {
5366977b 188 sendto_one_notice(source_p, ":FLOODCOUNT is currently %i",
189 GlobalSetOptions.floodcount);
212380e3 190 }
191}
192
193/* SET IDENTTIMEOUT */
194static void
195quote_identtimeout(struct Client *source_p, int newval)
196{
197 if(!IsOperAdmin(source_p))
198 {
199 sendto_one(source_p, form_str(ERR_NOPRIVS),
200 me.name, source_p->name, "admin");
201 return;
202 }
203
204 if(newval > 0)
205 {
206 sendto_realops_snomask(SNO_GENERAL, L_ALL,
207 "%s has changed IDENTTIMEOUT to %d",
208 get_oper_name(source_p), newval);
209 GlobalSetOptions.ident_timeout = newval;
210 }
211 else
5366977b 212 sendto_one_notice(source_p, ":IDENTTIMEOUT is currently %d",
213 GlobalSetOptions.ident_timeout);
212380e3 214}
215
216/* SET IDLETIME */
217static void
218quote_idletime(struct Client *source_p, int newval)
219{
220 if(newval >= 0)
221 {
222 if(newval == 0)
223 {
224 sendto_realops_snomask(SNO_GENERAL, L_ALL,
225 "%s has disabled idletime checking", source_p->name);
226 GlobalSetOptions.idletime = 0;
227 }
228 else
229 {
230 sendto_realops_snomask(SNO_GENERAL, L_ALL,
231 "%s has changed IDLETIME to %i",
232 source_p->name, newval);
233 GlobalSetOptions.idletime = (newval * 60);
234 }
235 }
236 else
237 {
5366977b 238 sendto_one_notice(source_p, ":IDLETIME is currently %i",
239 GlobalSetOptions.idletime / 60);
212380e3 240 }
241}
242
243/* SET MAX */
244static void
245quote_max(struct Client *source_p, int newval)
246{
247 if(newval > 0)
248 {
212380e3 249 if(newval < 32)
250 {
5366977b 251 sendto_one_notice(source_p, ":You cannot set MAXCLIENTS to < 32 (%d:%d)",
252 GlobalSetOptions.maxclients, highest_fd);
212380e3 253 return;
254 }
255
256 GlobalSetOptions.maxclients = newval;
257
258 sendto_realops_snomask(SNO_GENERAL, L_ALL,
259 "%s!%s@%s set new MAXCLIENTS to %d (%lu current)",
260 source_p->name, source_p->username, source_p->host,
261 GlobalSetOptions.maxclients,
262 dlink_list_length(&lclient_list));
263
264 return;
265 }
266 else
267 {
5366977b 268 sendto_one_notice(source_p, ":Current Maxclients = %d (%lu)",
269 GlobalSetOptions.maxclients, dlink_list_length(&lclient_list));
212380e3 270 }
271}
272
273/* SET OPERSTRING */
274static void
275quote_operstring(struct Client *source_p, const char *arg)
276{
277 if(EmptyString(arg))
278 {
5366977b 279 sendto_one_notice(source_p, ":OPERSTRING is currently '%s'", GlobalSetOptions.operstring);
212380e3 280 }
281 else
282 {
283 strlcpy(GlobalSetOptions.operstring, arg,
284 sizeof(GlobalSetOptions.operstring));
285
286 sendto_realops_snomask(SNO_GENERAL, L_ALL,
287 "%s has changed OPERSTRING to '%s'",
288 get_oper_name(source_p), arg);
289 }
290}
291
292/* SET ADMINSTRING */
293static void
294quote_adminstring(struct Client *source_p, const char *arg)
295{
296 if(EmptyString(arg))
297 {
5366977b 298 sendto_one_notice(source_p, ":ADMINSTRING is currently '%s'", GlobalSetOptions.adminstring);
212380e3 299 }
300 else
301 {
302 strlcpy(GlobalSetOptions.adminstring, arg,
303 sizeof(GlobalSetOptions.adminstring));
304
305 sendto_realops_snomask(SNO_GENERAL, L_ALL,
306 "%s has changed ADMINSTRING to '%s'",
307 get_oper_name(source_p), arg);
308 }
309}
310
311/* SET SPAMNUM */
312static void
313quote_spamnum(struct Client *source_p, int newval)
314{
315 if(newval > 0)
316 {
317 if(newval == 0)
318 {
319 sendto_realops_snomask(SNO_GENERAL, L_ALL,
320 "%s has disabled ANTI_SPAMBOT", source_p->name);
321 GlobalSetOptions.spam_num = newval;
322 return;
323 }
324 if(newval < MIN_SPAM_NUM)
325 {
326 GlobalSetOptions.spam_num = MIN_SPAM_NUM;
327 }
328 else /* if (newval < MIN_SPAM_NUM) */
329 {
330 GlobalSetOptions.spam_num = newval;
331 }
332 sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s has changed SPAMNUM to %i",
333 source_p->name, GlobalSetOptions.spam_num);
334 }
335 else
336 {
5366977b 337 sendto_one_notice(source_p, ":SPAMNUM is currently %i", GlobalSetOptions.spam_num);
212380e3 338 }
339}
340
341/* SET SPAMTIME */
342static void
343quote_spamtime(struct Client *source_p, int newval)
344{
345 if(newval > 0)
346 {
347 if(newval < MIN_SPAM_TIME)
348 {
349 GlobalSetOptions.spam_time = MIN_SPAM_TIME;
350 }
351 else /* if (newval < MIN_SPAM_TIME) */
352 {
353 GlobalSetOptions.spam_time = newval;
354 }
355 sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s has changed SPAMTIME to %i",
356 source_p->name, GlobalSetOptions.spam_time);
357 }
358 else
359 {
5366977b 360 sendto_one_notice(source_p, ":SPAMTIME is currently %i", GlobalSetOptions.spam_time);
212380e3 361 }
362}
363
364/* this table is what splitmode may be set to */
365static const char *splitmode_values[] = {
366 "OFF",
367 "ON",
368 "AUTO",
369 NULL
370};
371
372/* this table is what splitmode may be */
373static const char *splitmode_status[] = {
374 "OFF",
375 "AUTO (OFF)",
376 "ON",
377 "AUTO (ON)",
378 NULL
379};
380
381/* SET SPLITMODE */
382static void
383quote_splitmode(struct Client *source_p, char *charval)
384{
385 if(charval)
386 {
387 int newval;
388
389 for (newval = 0; splitmode_values[newval]; newval++)
390 {
391 if(!irccmp(splitmode_values[newval], charval))
392 break;
393 }
394
395 /* OFF */
396 if(newval == 0)
397 {
398 sendto_realops_snomask(SNO_GENERAL, L_ALL,
399 "%s is disabling splitmode", get_oper_name(source_p));
400
401 splitmode = 0;
402 splitchecking = 0;
403
404 eventDelete(check_splitmode, NULL);
405 }
406 /* ON */
407 else if(newval == 1)
408 {
409 sendto_realops_snomask(SNO_GENERAL, L_ALL,
410 "%s is enabling and activating splitmode",
411 get_oper_name(source_p));
412
413 splitmode = 1;
414 splitchecking = 0;
415
416 /* we might be deactivating an automatic splitmode, so pull the event */
417 eventDelete(check_splitmode, NULL);
418 }
419 /* AUTO */
420 else if(newval == 2)
421 {
422 sendto_realops_snomask(SNO_GENERAL, L_ALL,
423 "%s is enabling automatic splitmode",
424 get_oper_name(source_p));
425
426 splitchecking = 1;
427 check_splitmode(NULL);
428 }
429 }
430 else
431 /* if we add splitchecking to splitmode*2 we get a unique table to
432 * pull values back out of, splitmode can be four states - but you can
433 * only set to three, which means we cant use the same table --fl_
434 */
5366977b 435 sendto_one_notice(source_p, ":SPLITMODE is currently %s",
212380e3 436 splitmode_status[(splitchecking + (splitmode * 2))]);
437}
438
439/* SET SPLITNUM */
440static void
441quote_splitnum(struct Client *source_p, int newval)
442{
443 if(newval >= 0)
444 {
445 sendto_realops_snomask(SNO_GENERAL, L_ALL,
446 "%s has changed SPLITNUM to %i", source_p->name, newval);
447 split_servers = newval;
448
449 if(splitchecking)
450 check_splitmode(NULL);
451 }
452 else
5366977b 453 sendto_one_notice(source_p, ":SPLITNUM is currently %i", split_servers);
212380e3 454}
455
456/* SET SPLITUSERS */
457static void
458quote_splitusers(struct Client *source_p, int newval)
459{
460 if(newval >= 0)
461 {
462 sendto_realops_snomask(SNO_GENERAL, L_ALL,
463 "%s has changed SPLITUSERS to %i", source_p->name, newval);
464 split_users = newval;
465
466 if(splitchecking)
467 check_splitmode(NULL);
468 }
469 else
5366977b 470 sendto_one_notice(source_p, ":SPLITUSERS is currently %i", split_users);
212380e3 471}
472
473/*
474 * mo_set - SET command handler
475 * set options while running
476 */
477static int
478mo_set(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
479{
480 int newval;
481 int i, n;
482 const char *arg = NULL;
483 const char *intarg = NULL;
484
485 if(parc > 1)
486 {
487 /*
488 * Go through all the commands in set_cmd_table, until one is
489 * matched. I realize strcmp() is more intensive than a numeric
490 * lookup, but at least it's better than a big-ass switch/case
491 * statement.
492 */
493 for (i = 0; set_cmd_table[i].handler; i++)
494 {
495 if(!irccmp(set_cmd_table[i].name, parv[1]))
496 {
497 /*
498 * Command found; now execute the code
499 */
500 n = 2;
501
502 if(set_cmd_table[i].wants_char)
503 {
504 arg = parv[n++];
505 }
506
507 if(set_cmd_table[i].wants_int)
508 {
509 intarg = parv[n++];
510 }
511
512 if((n - 1) > parc)
513 {
5366977b 514 sendto_one_notice(source_p,
515 ":SET %s expects (\"%s%s\") args",
212380e3 516 set_cmd_table[i].name,
517 (set_cmd_table[i].
518 wants_char ? "string, " : ""),
519 (set_cmd_table[i].
520 wants_char ? "int" : ""));
521 return 0;
522 }
523
524 if(parc <= 2)
525 {
526 arg = NULL;
527 intarg = NULL;
528 }
529
530 if(set_cmd_table[i].wants_int && (parc > 2))
531 {
532 if(intarg)
533 {
534 if(!irccmp(intarg, "yes") || !irccmp(intarg, "on"))
535 newval = 1;
536 else if(!irccmp(intarg, "no")
537 || !irccmp(intarg, "off"))
538 newval = 0;
539 else
540 newval = atoi(intarg);
541 }
542 else
543 {
544 newval = -1;
545 }
546
547 if(newval < 0)
548 {
5366977b 549 sendto_one_notice(source_p,
550 ":Value less than 0 illegal for %s",
212380e3 551 set_cmd_table[i].name);
552
553 return 0;
554 }
555 }
556 else
557 newval = -1;
558
559 if(set_cmd_table[i].wants_char)
560 {
561 if(set_cmd_table[i].wants_int)
562 set_cmd_table[i].handler(source_p, arg, newval);
563 else
564 set_cmd_table[i].handler(source_p, arg);
565 return 0;
566 }
567 else
568 {
569 if(set_cmd_table[i].wants_int)
570 set_cmd_table[i].handler(source_p, newval);
571 else
572 /* Just in case someone actually wants a
573 * set function that takes no args.. *shrug* */
574 set_cmd_table[i].handler(source_p);
575 return 0;
576 }
577 }
578 }
579
580 /*
581 * Code here will be executed when a /QUOTE SET command is not
582 * found within set_cmd_table.
583 */
5366977b 584 sendto_one_notice(source_p, ":Variable not found.");
212380e3 585 return 0;
586 }
587
588 list_quote_commands(source_p);
589
590 return 0;
591}