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