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