]> jfr.im git - irc/rakaur/praxis.git/blob - src/core/config.c
Fixes from clang warnings.
[irc/rakaur/praxis.git] / src / core / config.c
1 /* praxis: services for TSora IRC networks.
2 * src/config.c: Configuration file parser.
3 *
4 * Copyright (c) 2004 Eric Will <rakaur@malkier.net>
5 * Copyright (c) 2003-2004 shrike development team.
6 *
7 * $Id$
8 */
9
10 #include "praxis.h"
11 #include "configparse.h"
12 #include "dlink.h"
13 #include "balloc.h"
14 #include "connection.h"
15 #include "ilog.h"
16 #include "imem.h"
17 #include "module.h"
18 #include "token.h"
19 #include "uplink.h"
20 #include "config.h"
21
22 static uchar c_serverinfo(ConfigEntry *);
23 static uchar c_si_name(ConfigEntry *);
24 static uchar c_si_description(ConfigEntry *);
25 static uchar c_si_sid(ConfigEntry *);
26 static uchar c_si_vhost(ConfigEntry *);
27 static uchar c_si_reconnect_time(ConfigEntry *);
28 static uchar c_si_ping_time(ConfigEntry *);
29 static uchar c_si_admin_name(ConfigEntry *);
30 static uchar c_si_admin_email(ConfigEntry *);
31
32 static uchar c_uplink(ConfigEntry *);
33
34 static uchar c_userserv(ConfigEntry *);
35 static uchar c_us_enable(ConfigEntry *);
36 static uchar c_us_nick(ConfigEntry *);
37 static uchar c_us_user(ConfigEntry *);
38 static uchar c_us_host(ConfigEntry *);
39 static uchar c_us_real(ConfigEntry *);
40 static uchar c_us_max_users(ConfigEntry *);
41 static uchar c_us_default_flags(ConfigEntry *);
42
43 static uchar c_chanserv(ConfigEntry *);
44 static uchar c_cs_enable(ConfigEntry *);
45 static uchar c_cs_nick(ConfigEntry *);
46 static uchar c_cs_user(ConfigEntry *);
47 static uchar c_cs_host(ConfigEntry *);
48 static uchar c_cs_real(ConfigEntry *);
49 static uchar c_cs_max_chans(ConfigEntry *);
50 static uchar c_cs_join_chans(ConfigEntry *);
51 static uchar c_cs_part_chans(ConfigEntry *);
52 static uchar c_cs_default_flags(ConfigEntry *);
53
54 static uchar c_modules(ConfigEntry *);
55 static uchar c_modules_path(ConfigEntry *);
56
57 /* *INDENT-OFF* */
58
59 static ConfigTable config_root_table[] =
60 {
61 { "SERVERINFO", 1, c_serverinfo },
62 { "UPLINK", 1, c_uplink },
63 { "USERSERV", 1, c_userserv },
64 { "CHANSERV", 1, c_chanserv },
65 { "MODULES", 1, c_modules },
66 { NULL, 0, NULL }
67 };
68
69 static ConfigTable config_si_table[] =
70 {
71 { "NAME", 0, c_si_name },
72 { "DESCRIPTION", 0, c_si_description },
73 { "SID", 0, c_si_sid },
74 { "VHOST", 0, c_si_vhost },
75 { "RECONNECT_TIME", 1, c_si_reconnect_time },
76 { "PING_TIME", 1, c_si_ping_time },
77 { "ADMIN_NAME", 1, c_si_admin_name },
78 { "ADMIN_EMAIL", 1, c_si_admin_email },
79 { NULL, 0, NULL }
80 };
81
82 static ConfigTable config_us_table[] =
83 {
84 { "ENABLE", 1, c_us_enable },
85 { "NICK", 1, c_us_nick },
86 { "USER", 0, c_us_user },
87 { "HOST", 0, c_us_host },
88 { "REAL", 0, c_us_real },
89 { "MAX_USERS", 1, c_us_max_users },
90 { "DEFAULT_FLAGS", 1, c_us_default_flags },
91 { NULL, 0, NULL }
92 };
93
94 static ConfigTable config_cs_table[] =
95 {
96 { "ENABLE", 1, c_cs_enable },
97 { "NICK", 1, c_cs_nick },
98 { "USER", 0, c_cs_user },
99 { "HOST", 0, c_cs_host },
100 { "REAL", 0, c_cs_real },
101 { "MAX_CHANS", 1, c_cs_max_chans },
102 { "JOIN_CHANS", 1, c_cs_join_chans },
103 { "PART_CHANS", 1, c_cs_part_chans },
104 { "DEFAULT_FLAGS", 1, c_cs_default_flags },
105 { NULL, 0, NULL }
106 };
107
108 static ConfigTable config_modules_table[] =
109 {
110 { "PATH", 1, c_modules_path },
111 { NULL, 0, NULL }
112 };
113
114 /* XXX uncomment this when i add chanserv/userserv
115 static Token config_uflags[] =
116 {
117 { "HIDEMAIL", MU_HIDEMAIL },
118 { "HOLD", MU_HOLD },
119 { "NEVEROP", MU_NEVEROP },
120 { "NOOP", MU_NOOP },
121 { NULL, 0 }
122 };
123
124 static Token config_cflags[] =
125 {
126 { "HOLD", MC_HOLD },
127 { "NEVEROP", MC_NEVEROP },
128 { "SECURE", MC_SECURE },
129 { "VERBOSE", MC_VERBOSE },
130 { NULL, 0 }
131 };*/
132
133 /* *INDENT-ON* */
134
135 /* configInit()
136 * Initialises the configuration settings.
137 *
138 * inputs - none
139 * outputs - none
140 */
141 void
142 configInit(void)
143 {
144 /* Initialise serverinfo{} stuff. */
145 me.name[0] = '\0';
146
147 if (me.admin_name != NULL)
148 free(me.admin_name);
149 if (me.admin_email != NULL)
150 free(me.admin_email);
151
152 me.desc[0] = me.sid[0] = '\0';
153
154 me.admin_name = me.admin_email = NULL;
155
156 settings.vhost[0] = '\0';
157
158 if (settings.network_name != NULL)
159 free(settings.network_name);
160 if (settings.mta_path != NULL)
161 free(settings.mta_path);
162
163 settings.network_name = settings.mta_path = NULL;
164 settings.reconnect_time = settings.ping_time = settings.expire_time = 0;
165 settings.auth_type = 0;
166
167 globals.start = globals.max_fd = 0;
168 globals.uplink_failed = globals.connected = globals.bursting = 0;
169
170 globals.currtime = time(NULL);
171
172 if (dlinkLength(&uplink_list) > 0)
173 uplinkFlush();
174
175 memset(&uplink_list, '\0', sizeof(uplink_list));
176
177 /* Initialise userserv{} stuff. */
178 userserv.nick[0] = userserv.user[0] = '\0';
179 userserv.host[0] = userserv.real[0] = '\0';
180
181 userserv.enabled = userserv.max_users = userserv.default_flags = 0;
182
183 /* Initialise chanserv{} stuff. */
184 chanserv.nick[0] = chanserv.user[0] = '\0';
185 chanserv.host[0] = chanserv.real[0] = '\0';
186
187 chanserv.max_chans = chanserv.default_flags = 0;
188 chanserv.enabled = chanserv.join_chans = chanserv.part_chans = 0;
189 }
190
191 /* configParse()
192 * Parses the configuration file.
193 *
194 * inputs - none
195 * outputs - none
196 */
197 void
198 configParse(void)
199 {
200 ConfigFile *cfptr, *cfp;
201 ConfigEntry *ce;
202 ConfigTable *ct = NULL;
203
204 cfptr = cfp = config_load(globals.config_file);
205
206 if (cfp == NULL)
207 {
208 ilog(L_INFO, "configParse(): Error: %s", strerror(errno));
209 exit(EXIT_FAILURE);
210 }
211
212 for (; cfptr; cfptr = cfptr->cf_next)
213 {
214 for (ce = cfptr->cf_entries; ce; ce = ce->ce_next)
215 {
216 for (ct = config_root_table; ct->name; ct++)
217 {
218 if (!strcasecmp(ct->name, ce->ce_varname))
219 {
220 if ((globals.run_flags & RF_REHASHING) &&
221 (ct->rehashable == 0))
222 continue;
223
224 ct->func(ce);
225 break;
226 }
227 }
228
229 if (ct->name == NULL)
230 {
231 ilog(L_ERROR, "%s:%d: Invalid configuration option: %s",
232 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
233 ce->ce_varname);
234 }
235 }
236 }
237
238 config_free(cfp);
239 }
240
241 /* configCheck()
242 * Performs sanity checking on configuration settings.
243 *
244 * inputs - none
245 * outputs - 1 on verified or 0 on failure
246 */
247 uchar
248 configCheck(void)
249 {
250 if (me.name[0] == '\0')
251 {
252 ilog(L_INFO, "Config error: no serverinfo::name set.");
253 return 0;
254 }
255
256 if (me.desc[0] == '\0')
257 {
258 ilog(L_INFO, "Config error: no serverinfo::description set.");
259 return 0;
260 }
261
262 if (me.sid == '\0')
263 {
264 ilog(L_INFO, "Config error: no serverinfo::sid set.");
265 return 0;
266 }
267
268 if (settings.reconnect_time < 5)
269 {
270 ilog(L_INFO, "Config warning: value too low for "
271 "serverinfo::reconnect_time; defaulting to 5.");
272 }
273
274 if (settings.ping_time == 0)
275 {
276 ilog(L_INFO, "Config warning: value too low for "
277 "serverinfo::ping_time; defaulting to 5.");
278 }
279
280 if (me.admin_name == NULL)
281 {
282 ilog(L_INFO, "Config error: no serverinfo::admin_name set.");
283 return 0;
284 }
285
286 if (me.admin_email == NULL)
287 {
288 ilog(L_INFO, "Config error: no serverinfo::admin_email set.");
289 return 0;
290 }
291
292 /* This spits out a warning and not an error because other services
293 * later on might want to use MyUsers. Making it error out is probably
294 * a bad idea, while spitting out a warning could serve as a reminder for
295 * someone that didn't mean to do this.
296 */
297 if ((userserv.enabled == 1) && (chanserv.enabled == 0))
298 {
299 ilog(L_INFO, "Config warning: userserv is enabled without chanserv.");
300 }
301
302 if ((userserv.enabled == 0) && (chanserv.enabled == 1))
303 {
304 ilog(L_INFO, "Config error: chanserv is enabled without userserv.");
305 return 0;
306 }
307
308 if (userserv.enabled == 1)
309 {
310 if (userserv.nick[0] == '\0')
311 {
312 ilog(L_INFO, "Config error: no userserv::nick set.");
313 return 0;
314 }
315
316 if (userserv.user[0] == '\0')
317 {
318 ilog(L_INFO, "Config error: no userserv::user set.");
319 return 0;
320 }
321
322 if (userserv.host[0] == '\0')
323 {
324 ilog(L_INFO, "Config error: no userserv::host set.");
325 return 0;
326 }
327
328 if (userserv.real[0] == '\0')
329 {
330 ilog(L_INFO, "Config error: no userserv::real set.");
331 return 0;
332 }
333
334 if (userserv.max_users < 1)
335 {
336 ilog(L_INFO, "Config warning: value too low for "
337 "userserv::max_users; defaulting to 5.");
338 }
339 }
340
341 if (chanserv.enabled == 1)
342 {
343 if (chanserv.nick[0] == '\0')
344 {
345 ilog(L_INFO, "Config error: no chanserv::nick set.");
346 return 0;
347 }
348
349 if (chanserv.user[0] == '\0')
350 {
351 ilog(L_INFO, "Config error: no chanserv::user set.");
352 return 0;
353 }
354
355 if (chanserv.host[0] == '\0')
356 {
357 ilog(L_INFO, "Config error: no chanserv::host set.");
358 return 0;
359 }
360
361 if (chanserv.real[0] == '\0')
362 {
363 ilog(L_INFO, "Config error: no chanserv::real set.");
364 return 0;
365 }
366
367 if (chanserv.max_chans < 1)
368 {
369 ilog(L_INFO, "Config warning: value too low for "
370 "chanserv::max_users; defaulting to 5.");
371 }
372 }
373
374 return 1;
375 }
376
377 static uchar
378 c_subblock(ConfigEntry *ce, const char *subblock, ConfigTable *table)
379 {
380 ConfigTable *ct = NULL;
381
382 for (ce = ce->ce_entries; ce; ce = ce->ce_next)
383 {
384 for (ct = table; ct->name; ct++)
385 {
386 if (!strcasecmp(ct->name, ce->ce_varname))
387 {
388 if ((globals.run_flags & RF_REHASHING) && (ct->rehashable == 0))
389 continue;
390
391 ct->func(ce);
392 break;
393 }
394 }
395
396 if (ct->name == NULL)
397 {
398 ilog(L_ERROR, "%s:%d: Invalid configuration option: %s::%s",
399 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
400 subblock, ce->ce_varname);
401 }
402 }
403
404 return 0;
405 }
406
407 static uchar
408 c_serverinfo(ConfigEntry *ce)
409 {
410 c_subblock(ce, "serverinfo", config_si_table);
411 return 0;
412 }
413
414 static uchar
415 c_si_name(ConfigEntry *ce)
416 {
417 if (ce->ce_vardata == NULL)
418 PARAM_ERROR(ce);
419
420 strlcpy(me.name, ce->ce_vardata, HOSTLEN);
421
422 return 0;
423 }
424
425 static uchar
426 c_si_description(ConfigEntry *ce)
427 {
428 if (ce->ce_vardata == NULL)
429 PARAM_ERROR(ce);
430
431 strlcpy(me.desc, ce->ce_vardata, REALLEN);
432
433 return 0;
434 }
435
436 static uchar
437 c_si_sid(ConfigEntry *ce)
438 {
439 if (ce->ce_vardata == NULL)
440 PARAM_ERROR(ce);
441
442 strlcpy(me.sid, ce->ce_vardata, 4);
443
444 return 0;
445 }
446
447 static uchar
448 c_si_vhost(ConfigEntry *ce)
449 {
450 if (ce->ce_vardata == NULL)
451 PARAM_ERROR(ce);
452
453 strlcpy(settings.vhost, ce->ce_vardata, HOSTLEN);
454
455 return 0;
456 }
457
458 static uchar
459 c_si_reconnect_time(ConfigEntry *ce)
460 {
461 if (ce->ce_vardata == NULL)
462 PARAM_ERROR(ce);
463
464 settings.reconnect_time = ce->ce_vardatanum;
465
466 return 0;
467 }
468
469 static uchar
470 c_si_ping_time(ConfigEntry *ce)
471 {
472 if (ce->ce_vardata == NULL)
473 PARAM_ERROR(ce);
474
475 settings.ping_time = (ce->ce_vardatanum * 60);
476
477 return 0;
478 }
479
480 static uchar
481 c_si_admin_name(ConfigEntry *ce)
482 {
483 if (ce->ce_vardata == NULL)
484 PARAM_ERROR(ce);
485
486 me.admin_name = istrdup(ce->ce_vardata);
487
488 return 0;
489 }
490
491 static uchar
492 c_si_admin_email(ConfigEntry *ce)
493 {
494 if (ce->ce_vardata == NULL)
495 PARAM_ERROR(ce);
496
497 me.admin_email = istrdup(ce->ce_vardata);
498
499 return 0;
500 }
501
502 static uchar
503 c_uplink(ConfigEntry *ce)
504 {
505 Uplink *uplink_p;
506 char name[HOSTLEN + 1], host[HOSTLEN + 1];
507 char pass[PASSLEN + 1], vhost[HOSTLEN + 1];
508 uint port = 0;
509
510 name[0] = host[0] = pass[0] = vhost[0] = '\0';
511
512 if (ce->ce_vardata == NULL)
513 PARAM_ERROR(ce);
514
515 strlcpy(name, ce->ce_vardata, HOSTLEN);
516
517 for (ce = ce->ce_entries; ce; ce = ce->ce_next)
518 {
519 if (!strcasecmp(ce->ce_varname, "HOST"))
520 {
521 if (ce->ce_vardata == NULL)
522 PARAM_ERROR(ce);
523
524 strlcpy(host, ce->ce_vardata, HOSTLEN);
525
526 continue;
527 }
528
529 else if (!strcasecmp(ce->ce_varname, "VHOST"))
530 {
531 if (ce->ce_vardata == NULL)
532 PARAM_ERROR(ce);
533
534 strlcpy(vhost, ce->ce_vardata, HOSTLEN);
535
536 continue;
537 }
538
539 else if (!strcasecmp(ce->ce_varname, "PASSWORD"))
540 {
541 if (ce->ce_vardata == NULL)
542 PARAM_ERROR(ce);
543
544 strlcpy(pass, ce->ce_vardata, PASSLEN);
545
546 continue;
547 }
548
549 else if (!strcasecmp(ce->ce_varname, "PORT"))
550 {
551 if (ce->ce_vardata == NULL)
552 PARAM_ERROR(ce);
553
554 port = ce->ce_vardatanum;
555
556 continue;
557 }
558 else
559 {
560 ilog(L_ERROR, "%s:%d: Invalid configuration option: uplink::%s",
561 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
562 ce->ce_varname);
563
564 continue;
565 }
566 }
567
568 /* Make sure it's all valid. */
569 if (host[0] == '\0')
570 {
571 ilog(L_INFO, "Invalid uplink{} block: no host specified.");
572
573 return 1;
574 }
575
576 if (pass[0] == '\0')
577 {
578 ilog(L_INFO, "Invalid uplink{} block: no pass specified.");
579
580 return 1;
581 }
582
583 if (port == 0)
584 port = 6667;
585
586 /* If we get to here then it's good to add. */
587 uplink_p = uplinkAdd(name, host, pass, port);
588
589 strlcpy(uplink_p->vhost, vhost, HOSTLEN);
590
591 return 0;
592 }
593
594 static uchar
595 c_userserv(ConfigEntry *ce)
596 {
597 c_subblock(ce, "userserv", config_us_table);
598 return 0;
599 }
600
601 static uchar
602 c_us_enable(ConfigEntry *ce)
603 {
604 userserv.enabled = 1;
605 return 0;
606 }
607
608 static uchar
609 c_us_nick(ConfigEntry *ce)
610 {
611 if (ce->ce_vardata == NULL)
612 PARAM_ERROR(ce);
613
614 if (userserv.enabled == 0)
615 return 1;
616
617 strlcpy(userserv.nick, ce->ce_vardata, NICKLEN);
618
619 return 0;
620 }
621
622 static uchar
623 c_us_user(ConfigEntry *ce)
624 {
625 if (ce->ce_vardata == NULL)
626 PARAM_ERROR(ce);
627
628 if (userserv.enabled == 0)
629 return 1;
630
631 strlcpy(userserv.user, ce->ce_vardata, USERLEN);
632
633 return 0;
634 }
635
636 static uchar
637 c_us_host(ConfigEntry *ce)
638 {
639 if (ce->ce_vardata == NULL)
640 PARAM_ERROR(ce);
641
642 if (userserv.enabled == 0)
643 return 1;
644
645 strlcpy(userserv.host, ce->ce_vardata, HOSTLEN);
646
647 return 0;
648 }
649
650 static uchar
651 c_us_real(ConfigEntry *ce)
652 {
653 if (ce->ce_vardata == NULL)
654 PARAM_ERROR(ce);
655
656 if (userserv.enabled == 0)
657 return 1;
658
659 strlcpy(userserv.real, ce->ce_vardata, REALLEN);
660
661 return 0;
662 }
663
664 static uchar
665 c_us_max_users(ConfigEntry *ce)
666 {
667 if (ce->ce_vardata == NULL)
668 PARAM_ERROR(ce);
669
670 if (userserv.enabled == 0)
671 return 1;
672
673 userserv.max_users = ce->ce_vardatanum;
674
675 return 0;
676 }
677
678 static uchar
679 c_us_default_flags(ConfigEntry *ce)
680 {
681 if (userserv.enabled == 0)
682 return 1;
683
684 /* XXX - uncomment this when i do chanserv/userserv
685 for (flce = ce->ce_entries; flce; flce = flce->ce_next)
686 {
687 int val;
688
689 val = token_to_value(config_uflags, flce->ce_varname);
690
691 if ((val != TOKEN_UNMATCHED) && (val != TOKEN_ERROR))
692 userserv.default_flags |= val;
693
694 else
695 {
696 ilog(L_INFO, "%s:%d: unknown flag: %s",
697 flce->ce_fileptr->cf_filename, flce->ce_varlinenum,
698 flce->ce_varname);
699 }
700 } */
701
702 return 0;
703 }
704
705 static uchar
706 c_chanserv(ConfigEntry *ce)
707 {
708 c_subblock(ce, "chanserv", config_cs_table);
709 return 0;
710 }
711
712 static uchar
713 c_cs_enable(ConfigEntry *ce)
714 {
715 chanserv.enabled = 1;
716 return 0;
717 }
718
719 static uchar
720 c_cs_nick(ConfigEntry *ce)
721 {
722 if (ce->ce_vardata == NULL)
723 PARAM_ERROR(ce);
724
725 if (chanserv.enabled == 0)
726 return 1;
727
728 strlcpy(chanserv.nick, ce->ce_vardata, NICKLEN);
729
730 return 0;
731 }
732
733 static uchar
734 c_cs_user(ConfigEntry *ce)
735 {
736 if (ce->ce_vardata == NULL)
737 PARAM_ERROR(ce);
738
739 if (chanserv.enabled == 0)
740 return 1;
741
742 strlcpy(chanserv.user, ce->ce_vardata, USERLEN);
743
744 return 0;
745 }
746
747 static uchar
748 c_cs_host(ConfigEntry *ce)
749 {
750 if (ce->ce_vardata == NULL)
751 PARAM_ERROR(ce);
752
753 if (chanserv.enabled == 0)
754 return 1;
755
756 strlcpy(chanserv.host, ce->ce_vardata, HOSTLEN);
757
758 return 0;
759 }
760
761 static uchar
762 c_cs_real(ConfigEntry *ce)
763 {
764 if (ce->ce_vardata == NULL)
765 PARAM_ERROR(ce);
766
767 if (chanserv.enabled == 0)
768 return 1;
769
770 strlcpy(chanserv.real, ce->ce_vardata, REALLEN);
771
772 return 0;
773 }
774
775 static uchar
776 c_cs_max_chans(ConfigEntry *ce)
777 {
778 if (ce->ce_vardata == NULL)
779 PARAM_ERROR(ce);
780
781 if (chanserv.enabled == 0)
782 return 1;
783
784 chanserv.max_chans = ce->ce_vardatanum;
785
786 return 0;
787 }
788
789 static uchar
790 c_cs_join_chans(ConfigEntry *ce)
791 {
792 if (chanserv.enabled == 0)
793 return 1;
794
795 chanserv.join_chans = 1;
796
797 return 0;
798 }
799
800 static uchar
801 c_cs_part_chans(ConfigEntry *ce)
802 {
803 if (chanserv.enabled == 0)
804 return 1;
805
806 chanserv.part_chans = 1;
807
808 return 0;
809 }
810
811 static uchar
812 c_cs_default_flags(ConfigEntry *ce)
813 {
814 if (chanserv.enabled == 0)
815 return 1;
816
817 /* XXX uncomment this when i do chanserv/userserv
818 for (flce = ce->ce_entries; flce; flce = flce->ce_next)
819 {
820 int val;
821
822 val = token_to_value(config_cflags, flce->ce_varname);
823
824 if ((val != TOKEN_UNMATCHED) && (val != TOKEN_ERROR))
825 chanserv.default_flags |= val;
826
827 else
828 {
829 ilog(L_INFO, "%s:%d: unknown flag: %s",
830 flce->ce_fileptr->cf_filename, flce->ce_varlinenum,
831 flce->ce_varname);
832 }
833 }*/
834
835 return 0;
836 }
837
838 static uchar
839 c_modules(ConfigEntry *ce)
840 {
841 c_subblock(ce, "modules", config_modules_table);
842 return 0;
843 }
844
845 static uchar
846 c_modules_path(ConfigEntry *ce)
847 {
848 if (ce->ce_vardata == NULL)
849 PARAM_ERROR(ce);
850
851 #ifndef STATIC_MODULES
852 modulePathAdd(ce->ce_vardata);
853 #endif
854
855 return 0;
856 }