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