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