1 #include "qpage.h"
2
3
4 /*
5 ** global variables
6 */
7 #ifndef lint
8 static char sccsid[] = "@(#)config.c 1.29 01/01/99 tomiii@qpage.org";
9 #endif
10 service_t *Services = NULL;
11 service_t *DefaultService = NULL;
12 pager_t *Pagers = NULL;
13 pgroup_t *Groups = NULL;
14 modem_t *Modems = NULL;
15 char *PIDfile = NULL;
16 char *Administrator = NULL;
17 char *ForceHostname = NULL;
18 char *SigFile = NULL;
19 char *QueueDir = NULL;
20 char *LockDir = NULL;
21 int IdentTimeout = DEFAULT_IDENTTIMEOUT;
22 int SNPPTimeout = DEFAULT_SNPPTIMEOUT;
23 int Synchronous = TRUE;
24
25
26 /*
27 **
28 ** init_service_defaults()
29 **
30 ** This function initializes a paging service to the default values
31 ** from the default paging service.
32 **
33 ** Input:
34 ** service - the service to set the defaults for
35 **
36 ** Returns:
37 ** nothing
38 */
39 void
init_service_defaults(service_t * service)40 init_service_defaults(service_t *service)
41 {
42 if (DefaultService->device)
43 service->device = strdup(DefaultService->device);
44
45 if (DefaultService->dialcmd)
46 service->dialcmd = strdup(DefaultService->dialcmd);
47
48 if (DefaultService->phone)
49 service->phone = strdup(DefaultService->phone);
50
51 if (DefaultService->password)
52 service->password = strdup(DefaultService->password);
53
54 service->baudrate = DefaultService->baudrate;
55 service->parity = DefaultService->parity;
56 service->maxmsgsize = DefaultService->maxmsgsize;
57 service->maxpages = DefaultService->maxpages;
58 service->maxtries = DefaultService->maxtries;
59 service->identfrom = DefaultService->identfrom;
60 service->allowpid = DefaultService->allowpid;
61 service->msgprefix = DefaultService->msgprefix;
62 }
63
64
65 /*
66 ** check_device()
67 **
68 ** This function verifies whether a service's device specification is
69 ** valid or not.
70 **
71 ** Input:
72 ** filename - the name of the configuration file being read
73 ** lineno - the current line number being read
74 ** value - the value of the "device" keyword
75 **
76 ** Returns:
77 ** The number of errors found (i.e. 0=success, >0=failure)
78 */
79 int
check_device(char * filename,int lineno,char * value)80 check_device(char *filename, int lineno, char *value)
81 {
82 char *ptr;
83 char *last;
84 char *res;
85 int ok;
86
87
88 ok = FALSE;
89
90 res = (void *)malloc(strlen(value)+1);
91 ptr = safe_strtok(value, ",", &last, res);
92 do {
93 if (lookup(Modems, ptr) != NULL) {
94 ok = TRUE;
95 continue;
96 }
97
98 if (ptr[0] != '/') {
99 qpage_log(LOG_WARNING, "%s(%d): undefined modem %s",
100 filename, lineno, ptr);
101
102 continue;
103 }
104
105 if (access(ptr, R_OK|W_OK) < 0) {
106 qpage_log(LOG_WARNING, "%s(%d): cannot access %s: %s",
107 filename, lineno, ptr, strerror(errno));
108
109 continue;
110 }
111
112 ok = TRUE;
113 }
114 while ((ptr = safe_strtok(NULL, ",", &last, res)) != NULL);
115 free(res);
116
117 return(ok);
118 }
119
120
121 /*
122 ** check_modem()
123 **
124 ** This function verifies that a modem specification has all the
125 ** required information.
126 **
127 ** Input:
128 ** filename - the name of the configuration file being read
129 ** lineno - the current line number being read
130 ** modem - the modem specification to be checked
131 **
132 ** Returns:
133 ** The number of errors found (i.e. 0=success, >0=failure)
134 */
135 int
check_modem(char * filename,int lineno,modem_t * modem)136 check_modem(char *filename, int lineno, modem_t *modem)
137 {
138 if (modem == NULL)
139 return(0);
140
141 if (modem->device != NULL)
142 return(0);
143
144 if (modem->name[0] == '/') {
145 if (access(modem->name, R_OK|W_OK) == 0) {
146 modem->device = strdup(modem->name);
147 return(0);
148 }
149
150 qpage_log(LOG_ERR, "%s(%d): cannot access %s: %s",
151 filename, lineno, modem->name, strerror(errno));
152 }
153 else {
154 qpage_log(LOG_ERR, "%s(%d): no device for modem=%s",
155 filename, lineno, modem->name);
156 }
157
158 return(1);
159 }
160
161
162 /*
163 ** check_service()
164 **
165 ** This function verifies that a service specification has all the
166 ** required information. If a required field is missing, a bogus
167 ** string is substituted and an error is returned. We still keep
168 ** the service entry around because otherwise it would cause errors
169 ** for pager entries that reference them (it's misleading to users).
170 **
171 ** Input:
172 ** filename - the current filename
173 ** lineno - the current line number
174 ** service - the service specification to be checked
175 **
176 ** Returns:
177 ** The number of errors found (i.e. 0=success, >0=failure)
178 */
179 int
check_service(char * filename,int lineno,service_t * service)180 check_service(char *filename, int lineno, service_t *service)
181 {
182 char *ptr;
183 char *last;
184 char *res;
185 int errors;
186
187
188 if (service == NULL)
189 return(0);
190
191 if (service->device == NULL) {
192 qpage_log(LOG_ERR, "%s(%d): no modem device for service=%s",
193 filename, lineno, service->name);
194
195 service->device = strdup("FATAL_CONFIGURATION_ERROR");
196 return(1);
197 }
198
199 errors = 0;
200
201 /*
202 ** make sure we have enough information to dial the modem
203 */
204 if (service->dialcmd == NULL) {
205 if (service->phone == NULL) {
206 qpage_log(LOG_ERR, "%s(%d): no phone number for "
207 "service=%s", filename, lineno, service->name);
208
209 errors++;
210 }
211
212 res = (void *)malloc(strlen(service->device)+1);
213 ptr = safe_strtok(service->device, ",", &last, res);
214 do {
215 if (lookup(Modems, ptr) != NULL)
216 continue;
217
218 qpage_log(LOG_ERR, "%s(%d): no dial command for "
219 "service=%s, device=%s", filename, lineno,
220 service->name, ptr);
221
222 errors++;
223 }
224 while ((ptr = safe_strtok(NULL, ",", &last, res)) != NULL);
225 free(res);
226 }
227
228 return(errors);
229 }
230
231
232 /*
233 ** check_pager()
234 **
235 ** This function verifies that a pager specification has all the
236 ** required information. If a required field is missing, the entry
237 ** for this pager is freed. Note that we are aways passed the head
238 ** of a linked list so we don't need to worry about changing a pointer
239 ** pointing at this pager.
240 **
241 ** Input:
242 ** filename - the current filename
243 ** lineno - the current line number
244 ** pager - a pointer to the pager structure
245 **
246 ** Returns:
247 ** The number of errors found (i.e. 0=success, >0=failure)
248 */
249 int
check_pager(char * filename,int lineno,pager_t ** pager)250 check_pager(char *filename, int lineno, pager_t **pager)
251 {
252 pager_t *tmp;
253
254
255 tmp = *pager;
256
257 if (tmp && tmp->pagerid == NULL) {
258 qpage_log(LOG_ERR, "%s(%d): no pagerid for pager=%s",
259 filename, lineno, tmp->name);
260 *pager = tmp->next;
261 free(tmp->name);
262 my_free(tmp->text);
263 free(tmp);
264 return(1);
265 }
266
267 return(0);
268 }
269
270
271 /*
272 ** check_group()
273 **
274 ** This function verifies that a group specification has all the
275 ** required information.
276 **
277 ** Input:
278 ** filename - the current filename
279 ** lineno - the current line number
280 ** group - the group specification to be checked
281 **
282 ** Returns:
283 ** The number of errors found (i.e. 0=success, >0=failure)
284 */
285 int
check_group(char * filename,int lineno,pgroup_t * group)286 check_group(char *filename, int lineno, pgroup_t *group)
287 {
288 if (group && group->members == NULL) {
289 qpage_log(LOG_ERR, "%s(%d): group %s has no members",
290 filename, lineno, group->name);
291
292 return(1);
293 }
294
295 return(0);
296 }
297
298
299 /*
300 ** read_config_file()
301 **
302 ** This function reads the configuration file.
303 **
304 ** Input:
305 ** the name of a configuration file
306 **
307 ** Returns:
308 ** an integer status code
309 **
310 ** Side effects:
311 ** This function changes the current working directory to
312 ** that of the page queue as specified in the configuration
313 ** file. It is an error if no such specification is present.
314 **
315 ** The following global variables are modified:
316 **
317 ** Pagers
318 ** Services
319 ** Groups
320 ** Modems
321 ** IdentTimeout
322 ** SNPPTimeout
323 ** Administrator
324 ** ForceHostname
325 */
326 int
read_config_file(char * filename)327 read_config_file(char *filename)
328 {
329 FILE *fp;
330 modem_t *modem;
331 service_t *service;
332 pager_t *pager;
333 pgroup_t *group;
334 member_t *tmp;
335 char buff[1024];
336 char value[1024];
337 char *ptr;
338 int errors;
339 int lineno;
340 int pos;
341
342
343 modem = NULL;
344 service = NULL;
345 errors = 0;
346 pager = NULL;
347 group = NULL;
348 lineno = 0;
349 pos = 0;
350
351 if (Services == NULL) {
352 Services = (void *)malloc(sizeof(service_t));
353 (void)memset((char *)Services, 0, sizeof(*Services));
354 Services->name = strdup("default");
355 Services->dialcmd = NULL;
356 Services->baudrate = DEFAULT_BAUDRATE;
357 Services->parity = DEFAULT_PARITY;
358 Services->maxmsgsize = DEFAULT_MAXMSGSIZE;
359 Services->maxpages = DEFAULT_MAXPAGES;
360 Services->maxtries = DEFAULT_MAXTRIES;
361 Services->identfrom = DEFAULT_IDENTFROM;
362 Services->allowpid = DEFAULT_ALLOWPID;
363 Services->msgprefix = DEFAULT_PREFIX;
364
365 DefaultService = Services;
366 }
367
368 if (QueueDir == NULL)
369 QueueDir = strdup(DEFAULT_QUEUEDIR);
370
371 if ((fp = fopen(filename, "r")) == NULL) {
372 qpage_log(LOG_ERR, "cannot open %s: %s", filename,
373 strerror(errno));
374 return(-1);
375 }
376
377 for (;;) {
378 if (pos && buff[pos]) {
379 #ifdef CONFDEBUG
380 printf("Leftover characters: <%s>\n", &buff[pos]);
381 #endif
382 (void)strcpy(buff, &buff[pos]);
383 }
384 else {
385 if (fgets(buff, sizeof(buff), fp) == NULL)
386 break;
387
388 lineno++;
389 }
390
391 #ifndef STRICT_COMMENTS
392 /*
393 ** let comments start anywhere in the line
394 */
395 if ((ptr = strchr(buff, '#')) != NULL)
396 *ptr = '\0';
397 #endif
398
399 /*
400 ** Skip comments and blank lines
401 */
402 if ((buff[0] == '#') || (buff[0] == '\n')) {
403 pos = 0;
404 continue;
405 }
406
407 /*
408 ** strip trailing newlines
409 */
410 if ((ptr = strchr(buff, '\n')) != NULL)
411 *ptr = '\0';
412
413 /*
414 ** This is the name of another configuration file we
415 ** need to process.
416 */
417 if (sscanf(buff, "include=%s%n", value, &pos) == 1) {
418 #ifdef CONFDEBUG
419 printf("include=<%s>\n", value);
420 #endif
421 errors += check_modem(filename, lineno, modem);
422 errors += check_service(filename, lineno, service);
423 errors += check_pager(filename, lineno, &Pagers);
424 errors += check_group(filename, lineno, group);
425 modem = NULL;
426 service = NULL;
427 pager = NULL;
428 group = NULL;
429
430 errors += read_config_file(value);
431 continue;
432 }
433
434 /*
435 ** This specifies whether a child process handling an
436 ** SNPP connection should notify its parent that there's
437 ** work to do. If false, the parent will wait for the
438 ** normal sleep timer to expire before processing the
439 ** page queue.
440 */
441 if (sscanf(buff, "synchronous=%s%n", value, &pos) == 1) {
442 #ifdef CONFDEBUG
443 printf("synchronous=<%s>\n", value);
444 #endif
445 errors += check_modem(filename, lineno, modem);
446 errors += check_service(filename, lineno, service);
447 errors += check_pager(filename, lineno, &Pagers);
448 errors += check_group(filename, lineno, group);
449 modem = NULL;
450 service = NULL;
451 pager = NULL;
452 group = NULL;
453
454 if (!strcasecmp(value, "no"))
455 Synchronous = FALSE;
456
457 if (!strcasecmp(value, "off"))
458 Synchronous = FALSE;
459
460 if (!strcasecmp(value, "false"))
461 Synchronous = FALSE;
462
463 continue;
464 }
465
466 /*
467 ** This is the location of the queue directory. This
468 ** keyword causes the termination of any current service,
469 ** pager, or group specification.
470 */
471 if (sscanf(buff, "queuedir=%s%n", value, &pos) == 1) {
472 #ifdef CONFDEBUG
473 printf("queuedir=<%s>\n", value);
474 #endif
475 errors += check_modem(filename, lineno, modem);
476 errors += check_service(filename, lineno, service);
477 errors += check_pager(filename, lineno, &Pagers);
478 errors += check_group(filename, lineno, group);
479 modem = NULL;
480 service = NULL;
481 pager = NULL;
482 group = NULL;
483
484 if (access(value, R_OK|W_OK|X_OK) < 0) {
485 qpage_log(LOG_ERR,
486 "%s(%d): cannot access %s: %s",
487 filename, lineno, value,
488 strerror(errno));
489
490 errors++;
491 continue;
492 }
493
494 my_free(QueueDir);
495 QueueDir = strdup(value);
496
497 continue;
498 }
499
500 /*
501 ** This is the location of the lock directory. This
502 ** keyword causes the termination of any current service,
503 ** pager, or group specification.
504 */
505 if (sscanf(buff, "lockdir=%s%n", value, &pos) == 1) {
506 #ifdef CONFDEBUG
507 printf("lockdir=<%s>\n", value);
508 #endif
509 errors += check_modem(filename, lineno, modem);
510 errors += check_service(filename, lineno, service);
511 errors += check_pager(filename, lineno, &Pagers);
512 errors += check_group(filename, lineno, group);
513 modem = NULL;
514 service = NULL;
515 pager = NULL;
516 group = NULL;
517
518 if (access(value, R_OK|W_OK|X_OK) < 0) {
519 qpage_log(LOG_ERR,
520 "%s(%d): cannot access %s: %s",
521 filename, lineno, value,
522 strerror(errno));
523
524 errors++;
525 continue;
526 }
527
528 my_free(LockDir);
529 LockDir = strdup(value);
530
531 continue;
532 }
533
534 /*
535 ** This is the ident timeout in seconds. This keyword
536 ** causes the termination of any current service, pager,
537 ** or group specification.
538 */
539 if (sscanf(buff, "identtimeout=%s%n", value, &pos) == 1) {
540 #ifdef CONFDEBUG
541 printf("identtimeout=<%s>\n", value);
542 #endif
543 errors += check_modem(filename, lineno, modem);
544 errors += check_service(filename, lineno, service);
545 errors += check_pager(filename, lineno, &Pagers);
546 errors += check_group(filename, lineno, group);
547 modem = NULL;
548 service = NULL;
549 pager = NULL;
550 group = NULL;
551
552 IdentTimeout = atoi(value);
553
554 if (IdentTimeout < 0)
555 IdentTimeout = 0;
556
557 continue;
558 }
559
560 /*
561 ** This is the SNPP command timeout in seconds. This keyword
562 ** causes the termination of any current service, pager, or
563 ** group specification.
564 */
565 if (sscanf(buff, "snpptimeout=%s%n", value, &pos) == 1) {
566 #ifdef CONFDEBUG
567 printf("snpptimeout=<%s>\n", value);
568 #endif
569 errors += check_modem(filename, lineno, modem);
570 errors += check_service(filename, lineno, service);
571 errors += check_pager(filename, lineno, &Pagers);
572 errors += check_group(filename, lineno, group);
573 modem = NULL;
574 service = NULL;
575 pager = NULL;
576 group = NULL;
577
578 SNPPTimeout = atoi(value);
579
580 /*
581 ** make sure they didn't define something stupid
582 */
583 if (SNPPTimeout < 2)
584 SNPPTimeout = 2;
585
586 continue;
587 }
588
589 /*
590 ** This specifies the filename in which the qpage server
591 ** should write it's process ID. This file is not used
592 ** by qpage for any other purpose; it is provided as a
593 ** convenience for the administrator.
594 */
595 if (sscanf(buff, "pidfile=%s%n", value, &pos) == 1) {
596 #ifdef CONFDEBUG
597 printf("pidfile=<%s>\n", value);
598 #endif
599 errors += check_modem(filename, lineno, modem);
600 errors += check_service(filename, lineno, service);
601 errors += check_pager(filename, lineno, &Pagers);
602 errors += check_group(filename, lineno, group);
603 modem = NULL;
604 service = NULL;
605 pager = NULL;
606 group = NULL;
607
608 my_free(PIDfile);
609 PIDfile = strdup(value);
610
611 continue;
612 }
613
614 /*
615 ** This specifies the e-mail addresses of the qpage
616 ** administrator. If defined, status notification is
617 ** sent to this address (regardless of the service level)
618 ** for all failed pages. This keyword causes the termination
619 ** of any current service, pager, or group specification.
620 */
621 if (sscanf(buff, "administrator=%s%n", value, &pos) == 1) {
622 #ifdef CONFDEBUG
623 printf("administrator=<%s>\n", value);
624 #endif
625 errors += check_modem(filename, lineno, modem);
626 errors += check_service(filename, lineno, service);
627 errors += check_pager(filename, lineno, &Pagers);
628 errors += check_group(filename, lineno, group);
629 modem = NULL;
630 service = NULL;
631 pager = NULL;
632 group = NULL;
633
634 my_free(Administrator);
635 Administrator = strdup(value);
636
637 continue;
638 }
639
640 /*
641 ** This specifies whether qpage should qualify the
642 ** addresses used to send e-mail notification to
643 ** page submitters. If true (and the CALLerid info
644 ** does not contain "@host.name") then the submitter's
645 ** hostname will be appended to the notification e-mail
646 ** address. If the vaue of this keyword starts with
647 ** '@' then it is appended as-is to unqualified addresses.
648 ** This keyword causes the termination of any current
649 ** service, pager, or group specification.
650 **
651 ** Disclaimer: Using "true" for this keyword should
652 ** be a last resort. I strongly believe that all e-mail
653 ** addresses for a given domain should use the domain
654 ** name ONLY (with no leading hostname). Administrators
655 ** who implement public user@host e-mail addresses (where
656 ** "host" is the name of the user's workstation) should
657 ** be forced to scrub toilets for a living.
658 */
659 if (sscanf(buff, "forcehostname=%s%n", value, &pos) == 1) {
660 #ifdef CONFDEBUG
661 printf("forcehostname=<%s>\n", value);
662 #endif
663 errors += check_modem(filename, lineno, modem);
664 errors += check_service(filename, lineno, service);
665 errors += check_pager(filename, lineno, &Pagers);
666 errors += check_group(filename, lineno, group);
667 modem = NULL;
668 service = NULL;
669 pager = NULL;
670 group = NULL;
671
672 if (value[0] == '@') {
673 ForceHostname = strdup(value);
674 continue;
675 }
676
677 if (!strcasecmp(value, "on"))
678 ForceHostname = strdup("true");
679
680 if (!strcasecmp(value, "yes"))
681 ForceHostname = strdup("true");
682
683 if (!strcasecmp(value, "true"))
684 ForceHostname = strdup("true");
685
686 continue;
687 }
688
689 /*
690 ** This specifies the signature file to be used when
691 ** sending e-mail notifications to the page submitter.
692 ** This keyword causes the termination of any current
693 ** modem, service, pager, or group specification.
694 */
695 if (sscanf(buff, "sigfile=%s%n", value, &pos) == 1) {
696 #ifdef CONFDEBUG
697 printf("sigfile=<%s>\n", value);
698 #endif
699 errors += check_modem(filename, lineno, modem);
700 errors += check_service(filename, lineno, service);
701 errors += check_pager(filename, lineno, &Pagers);
702 errors += check_group(filename, lineno, group);
703 modem = NULL;
704 service = NULL;
705 pager = NULL;
706 group = NULL;
707
708 if (access(value, R_OK) < 0) {
709 qpage_log(LOG_ERR,
710 "%s(%d): cannot access %s: %s",
711 filename, lineno, value,
712 strerror(errno));
713
714 errors++;
715 continue;
716 }
717
718 my_free(SigFile);
719 SigFile = strdup(value);
720
721 continue;
722 }
723
724 /*
725 ** This is a modem specification. Add another node to
726 ** the modems linked-list. This keyword causes the
727 ** causes the termination of any current service, pager,
728 ** or group specification.
729 */
730 if (sscanf(buff, "modem=%s%n", value, &pos) == 1) {
731 #ifdef CONFDEBUG
732 printf("modem=<%s>\n", value);
733 #endif
734 errors += check_modem(filename, lineno, modem);
735 errors += check_service(filename, lineno, service);
736 errors += check_pager(filename, lineno, &Pagers);
737 errors += check_group(filename, lineno, group);
738 modem = NULL;
739 service = NULL;
740 pager = NULL;
741 group = NULL;
742
743 if ((modem = lookup(Modems, value)) == NULL) {
744 modem = (void *)malloc(sizeof(*modem));
745 (void)memset((char *)modem, 0, sizeof(*modem));
746 modem->next = Modems;
747 Modems = modem;
748 modem->name = strdup(value);
749 modem->initcmd = strdup(DEFAULT_INITCMD);
750 modem->dialcmd = strdup(DEFAULT_DIALCMD);
751 }
752 else {
753 qpage_log(LOG_ERR,
754 "%s(%d): duplicate modem %s",
755 filename, lineno, value);
756
757 modem = NULL;
758 }
759
760 continue;
761 }
762
763 /*
764 ** This is a paging service specification. Add another
765 ** node to the services linked-list. Note that we are
766 ** building the linked-list in reverse order. This keyword
767 ** causes the termination of any current modem, pager,
768 ** or group specification.
769 */
770 if (sscanf(buff, "service=%s%n", value, &pos) == 1) {
771 #ifdef CONFDEBUG
772 printf("service=<%s>\n", value);
773 #endif
774 errors += check_modem(filename, lineno, modem);
775 errors += check_service(filename, lineno, service);
776 errors += check_pager(filename, lineno, &Pagers);
777 errors += check_group(filename, lineno, group);
778 modem = NULL;
779 service = NULL;
780 pager = NULL;
781 group = NULL;
782
783 if ((service = lookup(Services, value)) == NULL) {
784 service = (void *)malloc(sizeof(*service));
785 (void)memset((char *)service, 0,
786 sizeof(*service));
787 service->next = Services;
788 Services = service;
789 service->name = strdup(value);
790
791 init_service_defaults(service);
792
793 if (!strcmp(value, "default"))
794 DefaultService = service;
795 }
796
797 continue;
798 }
799
800 /*
801 ** This is a pager specification. Add another node to the
802 ** pagers linked-list. Note that we are building the list
803 ** in reverse order. This keyword causes the termination
804 ** of any current modem, service or group specification.
805 */
806 if (sscanf(buff, "pager=%s%n", value, &pos) == 1) {
807 #ifdef CONFDEBUG
808 printf("pager=<%s>\n", value);
809 #endif
810 errors += check_modem(filename, lineno, modem);
811 errors += check_service(filename, lineno, service);
812 errors += check_pager(filename, lineno, &Pagers);
813 errors += check_group(filename, lineno, group);
814 modem = NULL;
815 service = NULL;
816 pager = NULL;
817 group = NULL;
818
819 if (lookup(Groups, value) != NULL) {
820 qpage_log(LOG_ERR,
821 "%s(%d): pager %s not allowed, "
822 "group %s already defined",
823 value, value);
824
825 continue;
826 }
827
828 if ((pager = lookup(Pagers, value)) == NULL) {
829 pager = (void *)malloc(sizeof(*pager));
830 (void)memset((char *)pager, 0, sizeof(*pager));
831 pager->next = Pagers;
832 Pagers = pager;
833 pager->name = strdup(value);
834 pager->service = DefaultService;
835 }
836 else {
837 qpage_log(LOG_ERR,
838 "%s(%d): duplicate pager %s",
839 filename, lineno, value);
840
841 pager = NULL;
842 }
843
844 continue;
845 }
846
847 /*
848 ** This is a group specification. Add another node to the
849 ** groups linked-list. Note that we are building the list
850 ** in reverse order. This keyword causes the termination
851 ** of any current modem, service or pager specification.
852 */
853 if (sscanf(buff, "group=%s%n", value, &pos) == 1) {
854 #ifdef CONFDEBUG
855 printf("group=<%s>\n", value);
856 #endif
857 errors += check_modem(filename, lineno, modem);
858 errors += check_service(filename, lineno, service);
859 errors += check_pager(filename, lineno, &Pagers);
860 errors += check_group(filename, lineno, group);
861 modem = NULL;
862 service = NULL;
863 pager = NULL;
864 group = NULL;
865
866 if (lookup(Pagers, value) != NULL) {
867 qpage_log(LOG_ERR,
868 "%s(%d): group %s not allowed, "
869 "pager %s already defined",
870 value, value);
871
872 continue;
873 }
874
875 if ((group = lookup(Groups, value)) == NULL) {
876 group = (void *)malloc(sizeof(*group));
877 (void)memset((char *)group, 0, sizeof(*group));
878 group->next = Groups;
879 Groups = group;
880 group->name = strdup(value);
881 }
882 else {
883 qpage_log(LOG_ERR,
884 "%s(%d): duplicate group %s",
885 filename, lineno, value);
886
887 group = NULL;
888 }
889
890 continue;
891 }
892
893 /*
894 ** This section processes modem specific keywords
895 */
896 if (modem && isspace(buff[0])) {
897 if (sscanf(buff, " text=%s%n", value, &pos) == 1) {
898 #ifdef CONFDEBUG
899 printf("%s:text=<%s>\n", modem->name,
900 value);
901 #endif
902 /*
903 ** translate underscores to spaces
904 */
905 for (ptr=value; *ptr; ptr++)
906 if (*ptr == '_')
907 *ptr = ' ';
908
909 modem->text = strdup(value);
910 continue;
911 }
912
913 if (sscanf(buff, " device=%s%n", value, &pos) == 1) {
914 #ifdef CONFDEBUG
915 printf("%s:device=<%s>\n", modem->name,
916 value);
917 #endif
918 if (access(value, R_OK|W_OK) < 0) {
919 qpage_log(LOG_ERR,
920 "%s(%d): cannot access %s: %s",
921 filename, lineno, value,
922 strerror(errno));
923
924 errors++;
925 continue;
926 }
927
928 my_free(modem->device);
929 modem->device = strdup(value);
930 continue;
931 }
932
933 if (sscanf(buff, " initcmd=%s%n", value, &pos) == 1) {
934 #ifdef CONFDEBUG
935 printf("%s:initcmd=<%s>\n", modem->name,
936 value);
937 #endif
938 my_free(modem->initcmd);
939 modem->initcmd = strdup(value);
940 continue;
941 }
942
943 if (sscanf(buff, " dialcmd=%s%n", value, &pos) == 1) {
944 #ifdef CONFDEBUG
945 printf("%s:dialcmd=<%s>\n", modem->name,
946 value);
947 #endif
948 my_free(modem->dialcmd);
949 modem->dialcmd = strdup(value);
950 continue;
951 }
952 }
953
954 /*
955 ** This section processes service specific keywords
956 */
957 if (service && isspace(buff[0])) {
958 if (sscanf(buff, " text=%s%n", value, &pos) == 1) {
959 #ifdef CONFDEBUG
960 printf("%s:text=<%s>\n", service->name,
961 value);
962 #endif
963 /*
964 ** translate underscores to spaces
965 */
966 for (ptr=value; *ptr; ptr++)
967 if (*ptr == '_')
968 *ptr = ' ';
969
970 service->text = strdup(value);
971 continue;
972 }
973
974 if (sscanf(buff, " device=%s%n", value, &pos) == 1) {
975 #ifdef CONFDEBUG
976 printf("%s:device=<%s>\n", service->name,
977 value);
978 #endif
979 if (check_device(filename, lineno, value) < 0) {
980 errors++;
981 continue;
982 }
983
984 my_free(service->device);
985 service->device = strdup(value);
986 continue;
987 }
988
989 if (sscanf(buff, " dialcmd=%s%n", value, &pos) == 1) {
990 #ifdef CONFDEBUG
991 printf("%s:dialcmd=<%s>\n", service->name,
992 value);
993 #endif
994 my_free(service->dialcmd);
995 service->dialcmd = strdup(value);
996 qpage_log(LOG_WARNING,
997 "%s(%d): warning: obsolete keyword "
998 "\"dialcmd\"", filename, lineno);
999 continue;
1000 }
1001
1002 if (sscanf(buff, " phone=%s%n", value, &pos) == 1) {
1003 #ifdef CONFDEBUG
1004 printf("%s:phone=<%s>\n", service->name,
1005 value);
1006 #endif
1007 my_free(service->phone);
1008 service->phone = strdup(value);
1009 continue;
1010 }
1011
1012 if (sscanf(buff, " password=%s%n", value, &pos) == 1) {
1013 #ifdef CONFDEBUG
1014 printf("%s:password=<%s>\n", service->name,
1015 value);
1016 #endif
1017 service->password = strdup(value);
1018 continue;
1019 }
1020
1021 if (sscanf(buff, " baudrate=%s%n", value, &pos) == 1) {
1022 #ifdef CONFDEBUG
1023 printf("%s:baudrate=<%s>\n", service->name,
1024 value);
1025 #endif
1026 switch (atoi(value)) {
1027 case 300:
1028 service->baudrate = B300;
1029 break;
1030
1031 case 1200:
1032 service->baudrate = B1200;
1033 break;
1034
1035 case 2400:
1036 service->baudrate = B2400;
1037 break;
1038
1039 case 9600:
1040 service->baudrate = B9600;
1041 break;
1042
1043 case 19200:
1044 service->baudrate = B19200;
1045 break;
1046
1047 case 38400:
1048 service->baudrate = B38400;
1049 break;
1050 #ifdef B57600
1051 case 57600:
1052 service->baudrate = B57600;
1053 break;
1054 #endif
1055 #ifdef B115200
1056 case 115200:
1057 service->baudrate = B115200;
1058 break;
1059 #endif
1060 default:
1061 qpage_log(LOG_WARNING,
1062 "unrecognized baud "
1063 "rate %s", value);
1064 service->baudrate = B300;
1065 break;
1066 }
1067 continue;
1068 }
1069
1070 if (sscanf(buff, " parity=%s%n", value, &pos) == 1) {
1071 #ifdef CONFDEBUG
1072 printf("%s:parity=<%s>\n", service->name,
1073 value);
1074 #endif
1075 if (!strcasecmp(value, "even"))
1076 service->parity = EVEN;
1077 else
1078 if (!strcasecmp(value, "odd"))
1079 service->parity = ODD;
1080 else
1081 if (!strcasecmp(value, "none"))
1082 service->parity = NONE;
1083 else
1084 qpage_log(LOG_WARNING,
1085 "unrecognized parity %s", value);
1086
1087 continue;
1088 }
1089
1090 if (sscanf(buff, " maxmsgsize=%s%n", value, &pos) == 1) {
1091 #ifdef CONFDEBUG
1092 printf("%s:maxmsgsize=<%s>\n", service->name,
1093 value);
1094 #endif
1095 service->maxmsgsize = atoi(value);
1096
1097 if (service->maxmsgsize > MAXMSGSIZE)
1098 service->maxmsgsize = MAXMSGSIZE;
1099
1100 continue;
1101 }
1102
1103 if (sscanf(buff, " maxpages=%s%n", value, &pos) == 1) {
1104 #ifdef CONFDEBUG
1105 printf("%s:maxpages=<%s>\n", service->name,
1106 value);
1107 #endif
1108 service->maxpages = atoi(value);
1109
1110 if (service->maxpages < 1)
1111 service->maxpages = 1;
1112
1113 if (service->maxpages > 9)
1114 service->maxpages = 9;
1115
1116 continue;
1117 }
1118
1119 if (sscanf(buff, " maxtries=%s%n", value, &pos) == 1) {
1120 #ifdef CONFDEBUG
1121 printf("%s:maxtries=<%s>\n", service->name,
1122 value);
1123 #endif
1124 service->maxtries = atoi(value);
1125 continue;
1126 }
1127
1128 if (sscanf(buff, " identfrom=%s%n", value, &pos) == 1) {
1129 #ifdef CONFDEBUG
1130 printf("%s:identfrom=<%s>\n", service->name,
1131 value);
1132 #endif
1133 if (!strcasecmp(value, "no"))
1134 service->identfrom = FALSE;
1135
1136 if (!strcasecmp(value, "off"))
1137 service->identfrom = FALSE;
1138
1139 if (!strcasecmp(value, "false"))
1140 service->identfrom = FALSE;
1141
1142 continue;
1143 }
1144
1145 if (sscanf(buff, " allowpid=%s%n", value, &pos) == 1) {
1146 #ifdef CONFDEBUG
1147 printf("%s:allowpid=<%s>\n", service->name,
1148 value);
1149 #endif
1150 if (!strcasecmp(value, "on"))
1151 service->allowpid = TRUE;
1152
1153 if (!strcasecmp(value, "yes"))
1154 service->allowpid = TRUE;
1155
1156 if (!strcasecmp(value, "true"))
1157 service->allowpid = TRUE;
1158
1159 continue;
1160 }
1161
1162 if (sscanf(buff, " msgprefix=%s%n", value, &pos) == 1) {
1163 #ifdef CONFDEBUG
1164 printf("%s:msgprefix=<%s>\n", service->name,
1165 value);
1166 #endif
1167 if (!strcasecmp(value, "no"))
1168 service->msgprefix = FALSE;
1169
1170 if (!strcasecmp(value, "off"))
1171 service->msgprefix = FALSE;
1172
1173 if (!strcasecmp(value, "false"))
1174 service->msgprefix = FALSE;
1175
1176 continue;
1177 }
1178 }
1179
1180 /*
1181 ** This section processes pager specific keywords
1182 */
1183 if (pager && isspace(buff[0])) {
1184 if (sscanf(buff, " text=%s%n", value, &pos) == 1) {
1185 #ifdef CONFDEBUG
1186 printf("%s:text=<%s>\n", pager->name,
1187 value);
1188 #endif
1189 /*
1190 ** translate underscores to spaces
1191 */
1192 for (ptr=value; *ptr; ptr++)
1193 if (*ptr == '_')
1194 *ptr = ' ';
1195
1196 pager->text = strdup(value);
1197 continue;
1198 }
1199
1200 if (sscanf(buff, " pagerid=%s%n", value, &pos) == 1) {
1201 #ifdef CONFDEBUG
1202 printf("%s:pagerid=<%s>\n", pager->name,
1203 value);
1204 #endif
1205 pager->pagerid = strdup(value);
1206 continue;
1207 }
1208
1209 if (sscanf(buff, " service=%s%n", value, &pos) == 1) {
1210 #ifdef CONFDEBUG
1211 printf("%s:service=<%s>\n", pager->name,
1212 value);
1213 #endif
1214 pager->service = lookup(Services, value);
1215
1216 if (pager->service == NULL) {
1217 errors++;
1218
1219 qpage_log(LOG_ERR,
1220 "no service %s for pager=%s",
1221 value, pager->name);
1222
1223 Pagers = pager->next;
1224
1225 my_free(pager->pagerid);
1226 free(pager->name);
1227 free(pager);
1228 pager = NULL;
1229 }
1230
1231 continue;
1232 }
1233 }
1234
1235 /*
1236 ** This section processes group specific keywords
1237 */
1238 if (group && isspace(buff[0])) {
1239 if (sscanf(buff, " text=%s%n", value, &pos) == 1) {
1240 #ifdef CONFDEBUG
1241 printf("%s:text=<%s>\n", group->name,
1242 value);
1243 #endif
1244 /*
1245 ** translate underscores to spaces
1246 */
1247 for (ptr=value; *ptr; ptr++)
1248 if (*ptr == '_')
1249 *ptr = ' ';
1250
1251 group->text = strdup(value);
1252 continue;
1253 }
1254
1255 if (sscanf(buff, " member=%s%n", value, &pos) == 1) {
1256 #ifdef CONFDEBUG
1257 printf("%s:member=<%s>\n", group->name,
1258 value);
1259 #endif
1260 /*
1261 ** check for a duty schedule
1262 */
1263 if ((ptr = strchr(value, '/')) != NULL) {
1264 *ptr++ = '\0';
1265
1266 if (on_duty(ptr, 0) < 0)
1267 continue;
1268 }
1269
1270 if ((pager = lookup(Pagers, value)) != NULL) {
1271 /*
1272 ** The pager is valid. Add to group.
1273 */
1274 tmp = (void *)malloc(sizeof(*tmp));
1275 (void)memset((char *)tmp, 0, sizeof(*tmp));
1276 tmp->pager = pager;
1277
1278 if (ptr)
1279 tmp->schedule = strdup(ptr);
1280
1281 tmp->next = group->members;
1282 group->members = tmp;
1283
1284 pager = NULL;
1285 }
1286 else
1287 qpage_log(LOG_ERR,
1288 "no such pager %s for group=%s",
1289 value, group->name);
1290
1291 continue;
1292 }
1293 }
1294
1295 /*
1296 ** check for a line consisting of nothing but whitespace
1297 */
1298 for (ptr=buff; *ptr; ptr++) {
1299 if (!isspace(*ptr))
1300 break;
1301 }
1302
1303 if (*ptr == (char)NULL) {
1304 #ifdef CONFDEBUG
1305 printf("<just whitespace>\n");
1306 #endif
1307 pos = 0;
1308 continue;
1309 }
1310
1311 qpage_log(LOG_WARNING, "%s(%d): unexpected: <%s>",
1312 filename, lineno, safe_string(ptr));
1313
1314 errors++;
1315 pos = 0;
1316 }
1317
1318 (void)fclose(fp);
1319
1320 /*
1321 ** make sure the last entry we read is complete
1322 */
1323 errors += check_modem(filename, lineno, modem);
1324 errors += check_service(filename, lineno, service);
1325 errors += check_pager(filename, lineno, &Pagers);
1326 errors += check_group(filename, lineno, group);
1327
1328 return(errors);
1329 }
1330
1331
1332 /*
1333 ** free_modems()
1334 **
1335 ** This function frees all the memory associated with the
1336 ** global Modems linked list.
1337 **
1338 ** Input:
1339 ** list - a pointer to the head node of the list
1340 **
1341 ** Returns:
1342 ** nothing
1343 */
1344 void
free_modems(modem_t * list)1345 free_modems(modem_t *list)
1346 {
1347 if (list) {
1348 free_modems(list->next);
1349
1350 my_free(list->name);
1351 my_free(list->text);
1352 my_free(list->device);
1353 my_free(list->initcmd);
1354 my_free(list->dialcmd);
1355 free(list);
1356 }
1357 }
1358
1359
1360 /*
1361 ** free_services()
1362 **
1363 ** This function frees all the memory associated with the
1364 ** global Services linked list.
1365 **
1366 ** Input:
1367 ** list - a pointer to the head node of the list
1368 **
1369 ** Returns:
1370 ** nothing
1371 */
1372 void
free_services(service_t * list)1373 free_services(service_t *list)
1374 {
1375 if (list) {
1376 free_services(list->next);
1377
1378 my_free(list->name);
1379 my_free(list->text);
1380 my_free(list->device);
1381 my_free(list->dialcmd);
1382 my_free(list->phone);
1383 my_free(list->password);
1384 free(list);
1385 }
1386 }
1387
1388
1389 /*
1390 ** free_pagers()
1391 **
1392 ** This function frees all the memory associated with the
1393 ** global Pagers linked list.
1394 **
1395 ** Input:
1396 ** list - a pointer to the head node of the list
1397 **
1398 ** Returns:
1399 ** nothing
1400 */
1401 void
free_pagers(pager_t * list)1402 free_pagers(pager_t *list)
1403 {
1404 if (list) {
1405 free_pagers(list->next);
1406
1407 my_free(list->name);
1408 my_free(list->text);
1409 my_free(list->pagerid);
1410 free(list);
1411 }
1412 }
1413
1414
1415 /*
1416 ** free_groups()
1417 **
1418 ** This function frees all the memory associated with the
1419 ** global Groups linked list.
1420 **
1421 ** Input:
1422 ** list - a pointer to the head node of the list
1423 **
1424 ** Returns:
1425 ** nothing
1426 */
1427 void
free_groups(pgroup_t * list)1428 free_groups(pgroup_t *list)
1429 {
1430 member_t *tmp;
1431
1432 if (list) {
1433 free_groups(list->next);
1434
1435 my_free(list->name);
1436 my_free(list->text);
1437
1438 while (list->members) {
1439 tmp = list->members;
1440 list->members = tmp->next;
1441 my_free(tmp->schedule);
1442 free(tmp);
1443 }
1444
1445 free(list);
1446 }
1447 }
1448
1449
1450 /*
1451 ** get_qpage_config()
1452 **
1453 ** This function is the entry point to functions that read the
1454 ** configuration file. Any buffers allocated in previous calls to
1455 ** this function is first freed before allocating new buffers.
1456 **
1457 ** Input:
1458 ** filename - the name of the configuration file to read
1459 **
1460 ** Returns:
1461 ** The number of errors found while reading the configuration
1462 **
1463 ** Side effects:
1464 ** The current working directory is changed to the value
1465 ** specified by the "queuedir" keyword.
1466 */
1467 int
get_qpage_config(char * filename)1468 get_qpage_config(char *filename)
1469 {
1470 int errors;
1471
1472 free_modems(Modems);
1473 free_services(Services);
1474 free_pagers(Pagers);
1475 free_groups(Groups);
1476
1477 Modems = NULL;
1478 Services = NULL;
1479 Pagers = NULL;
1480 Groups = NULL;
1481
1482 my_free(Administrator);
1483 my_free(ForceHostname);
1484 my_free(QueueDir);
1485 my_free(LockDir);
1486
1487 Administrator = NULL;
1488 ForceHostname = NULL;
1489 QueueDir = NULL;
1490 LockDir = strdup(DEFAULT_LOCKDIR);;
1491 IdentTimeout = DEFAULT_IDENTTIMEOUT;
1492 SNPPTimeout = DEFAULT_SNPPTIMEOUT;
1493
1494 errors = read_config_file(filename);
1495
1496 if (access(LockDir, R_OK|W_OK|X_OK) < 0) {
1497 qpage_log(LOG_ERR, "cannot access LockDir(%s): %s", LockDir,
1498 strerror(errno));
1499
1500 errors++;
1501 }
1502
1503 if (QueueDir != NULL) {
1504 /*
1505 ** It is not necessary to chdir to the queue directory
1506 ** during interactive mode since the queue is not used.
1507 */
1508 if (Interactive == FALSE) {
1509 if (access(QueueDir, R_OK|W_OK|X_OK) < 0) {
1510 qpage_log(LOG_ERR,
1511 "cannot access QueueDir(%s): %s",
1512 QueueDir, strerror(errno));
1513
1514 errors++;
1515 }
1516
1517 if (chdir(QueueDir) < 0) {
1518 qpage_log(LOG_ERR,
1519 "cannot chdir to QueueDir(%s): %s",
1520 QueueDir, strerror(errno));
1521
1522 errors++;
1523 }
1524 }
1525 }
1526 else {
1527 qpage_log(LOG_ERR, "no queue directory specified!");
1528 errors++;
1529 }
1530
1531 return(errors);
1532 }
1533
1534
1535 /*
1536 ** dump_qpage_config()
1537 **
1538 ** Print the qpage configuration file(s) to stdout (for the XCONfig
1539 ** command). This is a hack. I'm not proud of it.
1540 */
1541 void
dump_qpage_config(char * filename)1542 dump_qpage_config(char *filename)
1543 {
1544 FILE *fp;
1545 char buff[1024];
1546 char value[1024];
1547
1548
1549 if ((fp = fopen(filename, "r")) == NULL) {
1550 (void)printf("[cannot open %s: %s]\n", filename,
1551 strerror(errno));
1552
1553 return;
1554 }
1555
1556 (void)printf("[---------- begin %s ----------]\n", filename);
1557
1558 while (fgets(buff, sizeof(buff), fp)) {
1559
1560 (void)printf("%s", buff);
1561
1562 if (sscanf(buff, "include=%s", value) == 1)
1563 dump_qpage_config(value);
1564 }
1565
1566 (void)printf("[---------- end %s ----------]\n", filename);
1567 }
1568