xref: /illumos-gate/usr/src/cmd/lp/cmd/lpforms.c (revision f928ce67)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include <locale.h>
33 #include "stdio.h"
34 #include "errno.h"
35 #include "string.h"
36 #include "sys/types.h"
37 #include "sys/stat.h"
38 #include "stdlib.h"
39 
40 #include "lp.h"
41 #include "access.h"
42 #include "form.h"
43 #include "msgs.h"
44 
45 #define	WHO_AM_I	I_AM_LPFORMS
46 #include "oam.h"
47 
48 #define	OPT_LIST	"f:F:xlLA:u:W:Q:P:d"
49 
50 #define TMPDIR		"/usr/tmp"
51 
52 typedef int		(*Action)();
53 
54 #if	defined(__STDC__)
55 
56 static int	add_form ( char * , FILE * , FALERT * , char * );
57 static int	add_alert ( char * , FILE * , FALERT * , char * );
58 static int	delete_form ( char * );
59 static int	list_form ( char * );
60 static int	list_alert ( char * );
61 static int	list_both ( char * );
62 static int	any_alert ( char * , FILE * , FALERT * );
63 static int	quiet_alert ( char * );
64 static int	notify_spooler ( int , int , char * );
65 static int	onerror ( int , int , int );
66 
67 static Action	set_action ( int (*)() , char * );
68 
69 #else
70 
71 static int	add_form();
72 static int	add_alert();
73 static int	delete_form();
74 static int	list_form();
75 static int	list_alert();
76 static int	list_both();
77 static int	any_alert();
78 static int	quiet_alert();
79 static int	notify_spooler();
80 static int	onerror();
81 
82 static Action	set_action();
83 
84 #endif
85 
86 /**
87  ** usage()
88  **/
89 
90 void			usage ()
91 {
92 	(void) printf (gettext(
93 "usage:\n"
94 "\n"
95 "  (add or change form)\n"
96 "    lpforms -f form-name [options]\n"
97 "	[-F path-name | - | -P paper [-d] | -d ]	(form definition)\n"
98 "	   -F path-name			(initialize from file)\n"
99 "	   -				(initialize from stdin)\n"
100 "	   -P paper [-d]		(initialize with paper (as default))\n"
101 "	   -d				(create form with paper of same name)\n"
102 "	[-u allow:user-list | deny:user-list]	(who's allowed to use)\n"
103 "	[-A mail | write | shell-command]  (alert definition)\n"
104 "	[-Q threshold]			(# needed for alert)\n"
105 "	[-W interval]			(minutes between alerts)\n"
106 "\n"
107 "  (list form)\n"
108 "    lpforms -f form-name -l\n"
109 "    lpforms -f form-name -L (verbose for -P forms)\n"
110 "\n"
111 "  (delete form)\n"
112 "    lpforms -f form-name -x\n"
113 "\n"
114 "  (define alert for forms with no alert yet)\n"
115 "    lpforms -f any -A {mail | write | shell-command}\n"
116 "\n"
117 "  (define alert for all forms)\n"
118 "    lpforms -f all -A {mail | write | shell-command}\n"
119 "\n"
120 "  (examine alerting)\n"
121 "    lpforms -f form-name -A list\n"
122 "\n"
123 "  (stop alerting)\n"
124 "    lpforms -f form-name -A quiet		(temporarily)\n"
125 "    lpforms -f form-name -A none		(for good)"
126 "\n"
127 ));
128 
129 	return;
130 }
131 
132 static char *P = NULL;
133 static int d = 0;
134 static int L = 0;
135 /**
136  ** main()
137  **/
138 
139 int
140 main(int argc, char *argv[])
141 {
142 	extern int		optind;
143 	extern int		opterr;
144 	extern int		optopt;
145 
146 	extern char *		optarg;
147 
148 	int			c;
149 	int			cnt = 0;
150 
151 	char *			form		= 0;
152 	char *			u		= 0;
153 	char *			cp;
154 	char *			rest;
155 
156 	Action			action		= 0;
157 
158 	FILE			*input		= 0;
159 
160 	FORM			fbuf;
161 
162 	FALERT			alert		= { (char *)0, -1, -1 };
163 
164 	struct stat		statbuf;
165 
166 
167 	(void) setlocale (LC_ALL, "");
168 
169 #if !defined(TEXT_DOMAIN)
170 #define TEXT_DOMAIN "SYS_TEST"
171 #endif
172 	(void) textdomain(TEXT_DOMAIN);
173 
174 	if (!is_user_admin()) {
175 		LP_ERRMSG (ERROR, E_LP_NOTADM);
176 		exit (1);
177 	}
178 
179 	opterr = 0;
180 
181 	while ((c = getopt(argc, argv, OPT_LIST)) != -1) {
182 
183 		/*
184 		 * These options take values; "getopt()" passes values
185 		 * that begin with a dash without checking if they're
186 		 * options. If a value is missing, we want to complain
187 		 * about it.
188 		 */
189 		switch (c) {
190 		case 'W':
191 		case 'Q':
192 			/*
193 			 * These options take numeric values, which might
194 			 * be negative. Negative values are handled later,
195 			 * but here we just screen them.
196 			 */
197 			(void)strtol (optarg, &rest, 10);
198 			if (!rest || (!*rest && rest != optarg))
199 				break;
200 			/*FALLTHROUGH*/
201 		case 'f':
202 		case 'F':
203 		case 'A':
204 		case 'u':
205 			if (!*optarg) {
206 				(cp = "-X")[1] = c;
207 				LP_ERRMSG1 (ERROR, E_LP_NULLARG, cp);
208 				exit (1);
209 			}
210 			if (*optarg == '-') {
211 				(cp = "-X")[1] = c;
212 				LP_ERRMSG1 (ERROR, E_LP_OPTARG, cp);
213 				exit (1);
214 			}
215 			break;
216 		}
217 
218 		switch (c) {
219 
220 		case 'f':
221 			if (form)
222 				LP_ERRMSG1 (WARNING, E_LP_2MANY, 'f');
223 			form = optarg;
224 			if (!syn_name(form)) {
225 				LP_ERRMSG1 (ERROR, E_LP_NOTNAME, form);
226 				exit (1);
227 			} else if (!*form)
228 				form = NAME_ALL;
229 			break;
230 
231 		case 'F':
232 			if (input)
233 				LP_ERRMSG1 (WARNING, E_LP_2MANY, 'F');
234 			if (!(input = fopen(optarg, "r"))) {
235 				LP_ERRMSG1 (ERROR, E_FOR_OPEN, optarg);
236 				exit (1);
237 			}
238 			action = set_action(add_form, "-F");
239 			break;
240 
241 		case 'A':
242 			if (STREQU(NAME_LIST, optarg))
243 				action = set_action(list_alert, "\"-A list\"");
244 
245 			else if (STREQU(NAME_QUIET, optarg))
246 				action = set_action(quiet_alert, "\"-A quiet\"");
247 
248 			else {
249 				if (STREQU(MAIL, optarg) || STREQU(WRITE, optarg))
250 					alert.shcmd = makestr(optarg, " ", getname(), (char *)0);
251 				else
252 					alert.shcmd = strdup(optarg);
253 				action = set_action(add_alert, "-A");
254 			}
255 			break;
256 
257 		case 'Q':
258 			if (alert.Q != -1)
259 				LP_ERRMSG1 (WARNING, E_LP_2MANY, 'Q');
260 			if (STREQU(NAME_ANY, optarg))
261 				alert.Q = 1;
262 			else {
263 				alert.Q = strtol(optarg, &rest, 10);
264 				if (alert.Q < 0) {
265 					LP_ERRMSG1 (ERROR, E_LP_NEGARG, 'Q');
266 					exit (1);
267 				}
268 				if (rest && *rest) {
269 					LP_ERRMSG1 (ERROR, E_LP_GARBNMB, 'Q');
270 					exit (1);
271 				}
272 				if (alert.Q == 0) {
273 					LP_ERRMSG1 (ERROR, E_LP_ZEROARG, 'Q');
274 					exit (1);
275 				}
276 			}
277 			action = set_action(add_alert, "-Q");
278 			break;
279 
280 		case 'W':
281 			if (alert.W != -1)
282 				LP_ERRMSG1 (WARNING, E_LP_2MANY, 'W');
283 			if (STREQU(NAME_ONCE, optarg))
284 				alert.W = 0;
285 			else {
286 				alert.W = strtol(optarg, &rest, 10);
287 				if (alert.W < 0) {
288 					LP_ERRMSG1 (ERROR, E_LP_NEGARG, 'W');
289 					exit (1);
290 				}
291 				if (rest && *rest) {
292 					LP_ERRMSG1 (ERROR, E_LP_GARBNMB, 'W');
293 					exit (1);
294 				}
295 			}
296 			action = set_action(add_alert, "-W");
297 			break;
298 
299 		case 'u':
300 			if (u)
301 				LP_ERRMSG1 (WARNING, E_LP_2MANY, 'u');
302 			u = strdup(optarg);
303 			action = set_action(add_form, "-u");
304 			break;
305 
306 		case 'x':
307 			action = set_action(delete_form, "-x");
308 			break;
309 
310 		case 'L':
311 			L = 1;
312 			action = set_action(list_form, "-L");
313 			break;
314 		case 'l':
315 			action = set_action(list_form, "-l");
316 			break;
317 
318 		case 'd':
319 			d = 1;
320 			action = set_action(add_form, "-d");
321 			break;
322 
323 		case 'P':
324 			if (P)
325 				LP_ERRMSG1 (WARNING, E_LP_2MANY, 'P');
326 			action = set_action(add_form, "-P");
327 			P = strdup(optarg);
328 			break;
329 
330 		default:
331 			if (optopt == '?') {
332 				usage ();
333 				exit (0);
334 			}
335 			(cp = "-X")[1] = optopt;
336 			if (strchr(OPT_LIST, optopt))
337 				LP_ERRMSG1 (ERROR, E_LP_OPTARG, cp);
338 			else
339 				LP_ERRMSG1 (ERROR, E_LP_OPTION, cp);
340 			exit (1);
341 
342 		}
343 	}
344 
345 	if (!form) {
346 		LP_ERRMSG (ERROR, E_FOR_FORMNAME);
347 		exit (1);
348 	}
349 
350 	if (STREQU(NAME_ANY, form))
351 		action = set_action(any_alert, "\"-f any\"");
352 
353 	if (optind < argc && STREQU(argv[optind], "-")) {
354 		action = set_action(add_form, "-");
355 		input = stdin;
356 		optind++;
357 	}
358 	if (optind < argc)
359 		LP_ERRMSG1 (WARNING, E_FOR_EXTRAARG, argv[optind]);
360 
361 	if (!action) {
362 		LP_ERRMSG (ERROR, E_FOR_NOACT);
363 		exit (1);
364 	}
365 
366 	if (action == any_alert && STREQU(alert.shcmd, NAME_NONE)) {
367 		LP_ERRMSG (WARNING, E_FOR_ANYDEL);
368 		exit (0);
369 	}
370 
371 	/*
372 	 * We must have a shell command for the alert if:
373 	 *
374 	 *	(1) we're adding a new form and the -W or -Q options
375 	 *	    have been given, or
376 	 *
377 	 *	(2) the -f any option was given.
378 	 */
379 	if (
380 		(
381 			action == add_form
382 		     && !alert.shcmd
383 		     && (alert.Q != -1 || alert.W != -1)
384 		     && !STREQU(NAME_ALL, form)
385 		     && getform(form, &fbuf, (FALERT *)0, (FILE **)0) != 0
386 		)
387 	     || action == any_alert && !alert.shcmd
388 	) {
389 		LP_ERRMSG (ERROR, E_FOR_NOSHCMDERR);
390 		return (1);
391 	}
392 
393 	if (P && (! STREQU(P,form))) {
394 		while (P && (cnt++ < 2)) {
395 			/*
396 			 * two times should do it unless user has edited
397 			 * files directly
398 			 */
399 			if (getform(P, &fbuf, (FALERT *)0, (FILE **)0) != -1) {
400 				if (!fbuf.paper) {
401 					LP_ERRMSG3(ERROR, E_FOR_ALSO_SEP_FORM,
402 						form, P, P);
403 					return (1);
404 				} else if (!STREQU(fbuf.paper, P))
405 					P = Strdup(fbuf.paper);
406 				else
407 					break;	 /* we found a good paper */
408 			} else {
409 				int result;
410 				int saveD;
411 
412 				saveD = d;
413 				d = 1;
414 				result = ((*action)(P, NULL, &alert, u));
415 				d = saveD;
416 				return (result ? result :
417 					((*action)(form, input, &alert, u)));
418 			}
419 		}
420 	}
421 
422 	if (d && !P)
423 		P = Strdup(form);
424 
425 	return ((*action)(form, input, &alert, u));
426 }
427 
428 /**
429  ** add_alert()
430  ** add_form()
431  **/
432 
433 /*
434  * "add_alert()" exists just to simplify the checking of mixed
435  * options in "set_action()".
436  */
437 
438 static int
439 #if	defined(__STDC__)
440 add_alert (
441 	char *			form,
442 	FILE *			input,
443 	FALERT *		p_new_alert,
444 	char *			u
445 )
446 #else
447 add_alert (form, input, new_alert, u)
448 	char *			form;
449 	FILE *			input;
450 	FALERT *		p_new_alert;
451 	char *			u;
452 #endif
453 {
454 	return (add_form(form, input, p_new_alert, u));
455 }
456 
457 static int
458 #if	defined(__STDC__)
459 add_form (
460 	char *			form,
461 	FILE *			input,
462 	FALERT *		p_new_alert,
463 	char *			u
464 )
465 #else
466 add_form (form, input, new_alert, u)
467 	char *			form;
468 	FILE *			input;
469 	FALERT *		p_new_alert;
470 	char *			u;
471 #endif
472 {
473 	int			fld;
474 	int			which_set[FO_MAX];
475 	int			new_form	= 0;
476 	int			nform;
477 	int			return_code;
478 
479 	char *			all_list[]	= { NAME_ALL, 0 };
480 	char **			u_allow		= 0;
481 	char **			u_deny		= 0;
482 
483 	FILE *			align_fp	= 0;
484 
485 	FORM			fbuf;
486 	FORM			new_fbuf;
487 
488 	FALERT			alert;
489 
490 
491 	/*
492 	 * Read the input configuration (if any) and parse it into a form,
493 	 * storing it in the form buffer "fbuf". Keep track of
494 	 * which fields have been given, to avoid overwriting unchanged
495 	 * fields later.
496 	 */
497 	if (input) {
498 		for (fld = 0; fld < FO_MAX; fld++)
499 			which_set[fld] = 0;
500 
501 		if (rdform(form, &new_fbuf, fileno(input), onerror,
502 				which_set) == -1) {
503 			LP_ERRMSG2 (ERROR, E_FOR_UNKNOWN, "(input)", PERROR);
504 			return (1);
505 		}
506 		for (fld = 0; fld < FO_MAX; fld++)
507 			if (which_set[fld])
508 				break;
509 		if (fld >= FO_MAX)
510 			LP_ERRMSG (WARNING, E_FOR_EMPTYFILE);
511 
512 		/*
513 		 * Read the alignment pattern (if any) into a temporary
514 		 * file so that it can be used for (potentially) many
515 		 * forms.
516 		 */
517 		if (which_set[FO_ALIGN]) {
518 
519 			size_t			n;
520 
521 			char			buf[BUFSIZ];
522 
523 
524 
525 			if ((align_fp = tmpfile()) == NULL) {
526 				LP_ERRMSG (ERROR, E_FOR_CTMPFILE);
527 				exit (1);
528 			}
529 
530 			while ((n = fread(buf, 1, BUFSIZ, input)))
531 				fwrite (buf, 1, n, align_fp);
532 		}
533 	}
534 
535 	/*
536 	 * Parse the user allow/deny list (if any).
537 	 */
538 	if (u) {
539 
540 		char *			cp;
541 		char *			type;
542 
543 
544 		type = strtok(u, ":");
545 		cp = strtok((char *)0, ":");
546 
547 		if (STREQU(type, NAME_ALLOW) && cp) {
548 			if (!(u_allow = getlist(cp, LP_WS, LP_SEP)))
549 				LP_ERRMSG1 (
550 					WARNING,
551 					E_LP_MISSING,
552 					NAME_ALLOW
553 				);
554 
555 		} else if (STREQU(type, NAME_DENY) && cp) {
556 			if (!(u_deny = getlist(cp, LP_WS, LP_SEP)))
557 				LP_ERRMSG1 (
558 					WARNING,
559 					E_LP_MISSING,
560 					NAME_DENY
561 				);
562 
563 		} else {
564 			LP_ERRMSG (ERROR, E_LP_UALLOWDENY);
565 			exit (1);
566 		}
567 	}
568 
569 	/*
570 	 * The following loop gets either a particular form or
571 	 * all forms (one at a time). The value of "return_code"
572 	 * controls the loop and is also the value to use in the
573 	 * "return()" at the end.
574 	 */
575 	nform = 0;
576 	return_code = -1;
577 	while (return_code == -1) {
578 
579 		/*
580 		 * If we are adding/changing a single form, set
581 		 * the loop control to get us out.
582 		 */
583 		if (!STREQU(NAME_ALL, form))
584 			return_code = 0;
585 
586 		nform++;
587 
588 		if (P) {
589 			memset ((char *)&fbuf, 0, sizeof(FORM));
590 			fbuf.name = strdup(form);
591 			fbuf.plen.val = DPLEN;
592 			fbuf.plen.sc = 0;
593 			fbuf.pwid.val = DPWIDTH;
594 			fbuf.pwid.sc = 0;
595 			fbuf.lpi.val = DLPITCH;
596 			fbuf.lpi.sc = 0;
597 			fbuf.cpi.val = DCPITCH;
598 			fbuf.cpi.sc = 0;
599 			fbuf.np = DNP;
600 			fbuf.chset = strdup(DCHSET);
601 			fbuf.mandatory = 0;
602 			fbuf.rcolor = strdup(DRCOLOR);
603 			fbuf.conttype = strdup(DCONTYP);
604 			fbuf.paper = P;
605 			fbuf.isDefault = d;
606 			alert.shcmd = 0;
607 			alert.W = alert.Q = -1;
608 			new_form = 1;
609 
610 		} else if (getform(form, &fbuf, &alert, (FILE **)0) == -1)
611 			switch (errno) {
612 
613 			case ENOENT:
614 				/*
615 				 * This is a problem only if it occurs
616 				 * immediately on trying to get ``all''.
617 				 */
618 				if (STREQU(NAME_ALL, form)) {
619 					if (nform > 1)
620 						return_code = 0;
621 					else {
622 						LP_ERRMSG (ERROR, E_FOR_NOFORMS);
623 						return_code = 1;
624 					}
625 					continue;
626 				}
627 
628 				/*
629 				 * We're adding a new form,
630 				 * so set up default values.
631 				 */
632 				memset ((char *)&fbuf, 0, sizeof(FORM));
633 				fbuf.name = strdup(form);
634 				fbuf.plen.val = DPLEN;
635 				fbuf.plen.sc = 0;
636 				fbuf.pwid.val = DPWIDTH;
637 				fbuf.pwid.sc = 0;
638 				fbuf.lpi.val = DLPITCH;
639 				fbuf.lpi.sc = 0;
640 				fbuf.cpi.val = DCPITCH;
641 				fbuf.cpi.sc = 0;
642 				fbuf.np = DNP;
643 				fbuf.chset = strdup(DCHSET);
644 				fbuf.mandatory = 0;
645 				fbuf.rcolor = strdup(DRCOLOR);
646 				fbuf.conttype = strdup(DCONTYP);
647 				alert.shcmd = 0;
648 				alert.W = alert.Q = -1;
649 
650 				new_form = 1;
651 				break;
652 
653 			default:
654 				/*
655 				 * Don't know if we'll have a good name
656 				 * in the "all" case on getting here, so
657 				 * punt on naming the form in the error
658 				 * message.
659 				 */
660 				LP_ERRMSG2 (ERROR, E_LP_GETFORM, form, PERROR);
661 				return_code = 1;
662 				continue;
663 			}
664 
665 		/*
666 		 * Copy just those items that were given in the input.
667 		 */
668 		if (!input && new_form && !P) {
669 			LP_ERRMSG1 (ERROR, E_LP_NOFORM, form);
670 			return (1);
671 		}
672 		if (input)
673 			for (fld = 0; fld < FO_MAX; fld++)
674 				if (which_set[fld]) switch(fld) {
675 
676 				case FO_PLEN:
677 					fbuf.plen = new_fbuf.plen;
678 					break;
679 
680 				case FO_PWID:
681 					fbuf.pwid = new_fbuf.pwid;
682 					break;
683 
684 				case FO_CPI:
685 					fbuf.cpi = new_fbuf.cpi;
686 					break;
687 
688 				case FO_LPI:
689 					fbuf.lpi = new_fbuf.lpi;
690 					break;
691 
692 				case FO_NP:
693 					fbuf.np = new_fbuf.np;
694 					break;
695 
696 				case FO_CHSET:
697 					fbuf.chset = new_fbuf.chset;
698 					fbuf.mandatory = new_fbuf.mandatory;
699 					break;
700 
701 				case FO_RCOLOR:
702 					fbuf.rcolor = new_fbuf.rcolor;
703 					break;
704 
705 				case FO_CMT:
706 					fbuf.comment = new_fbuf.comment;
707 					break;
708 
709 				case FO_ALIGN:
710 					fbuf.conttype = new_fbuf.conttype;
711 					rewind (align_fp);
712 					break;
713 
714 				case FO_PAPER:
715 					fbuf.paper = new_fbuf.paper;
716 					fbuf.isDefault = new_fbuf.isDefault;
717 					break;
718 
719 				}
720 
721 		/*
722 		 * Set just those alert elements that were given.
723 		 * However, complain about those form(s) that don't have
724 		 * a shell command yet, and none was given, yet -W or -Q
725 		 * were given.
726 		 */
727 		if (
728 			!alert.shcmd && !p_new_alert->shcmd
729 		     && (p_new_alert->W != -1 || p_new_alert->Q != -1)
730 		)
731 			LP_ERRMSG1 (WARNING, E_FOR_NOSHCMDWARN, fbuf.name);
732 		else {
733 			if (p_new_alert->shcmd)
734 				alert.shcmd = p_new_alert->shcmd;
735 			if (p_new_alert->Q != -1)
736 				alert.Q = p_new_alert->Q;
737 			if (p_new_alert->W != -1)
738 				alert.W = p_new_alert->W;
739 		}
740 
741 		/*
742 		 * Create/update the form.
743 		 */
744 #define P_FBUF	(new_form || input? &fbuf : (FORM *)0)
745 		if (putform(fbuf.name, P_FBUF, &alert, &align_fp) == -1) {
746 			LP_ERRMSG2 (ERROR, E_LP_PUTFORM, fbuf.name, PERROR);
747 			return_code = 1;
748 			continue;
749 		}
750 
751 		/*
752 		 * Allow/deny users.
753 		 */
754 		if (new_form && allow_user_form(all_list, fbuf.name) == -1) {
755 			LP_ERRMSG1 (ERROR, E_LP_ACCESSINFO, PERROR);
756 			return_code = 1;
757 			continue;
758 		}
759 		if (u_allow && allow_user_form(u_allow, fbuf.name) == -1) {
760 			LP_ERRMSG1 (ERROR, E_LP_ACCESSINFO, PERROR);
761 			return_code = 1;
762 			continue;
763 		}
764 		if (u_deny && deny_user_form(u_deny, fbuf.name) == -1) {
765 			LP_ERRMSG1 (ERROR, E_LP_ACCESSINFO, PERROR);
766 			return_code = 1;
767 			continue;
768 		}
769 
770 		notify_spooler (S_LOAD_FORM, R_LOAD_FORM, fbuf.name);
771 
772 	}
773 
774 	if (align_fp)
775 		close_lpfile (align_fp);
776 
777 	return (return_code);
778 }
779 
780 /**
781  ** list_form()
782  ** list_alert()
783  ** list_both()
784  **/
785 
786 #if	defined(__STDC__)
787 
788 static int	list ( char * , void (*)() );
789 static void	_list_form ( FORM * , FALERT * , FILE * );
790 static void	_list_alert ( FORM * , FALERT * );
791 static void	_list_both ( FORM * , FALERT * , FILE * );
792 
793 #else
794 
795 static int	list();
796 static void	_list_form();
797 static void	_list_alert();
798 static void	_list_both();
799 
800 #endif
801 
802 static int
803 #if	defined(__STDC__)
804 list_form (
805 	char			*form
806 )
807 #else
808 list_form (form)
809 	char			*form;
810 #endif
811 {
812 	return (list(form, _list_form));
813 }
814 
815 static int
816 #if	defined(__STDC__)
817 list_alert (
818 	char			*form
819 )
820 #else
821 list_alert (form)
822 	char			*form;
823 #endif
824 {
825 	return (list(form, _list_alert));
826 }
827 
828 static int
829 #if	defined(__STDC__)
830 list_both (
831 	char			*form
832 )
833 #else
834 list_both (form)
835 	char			*form;
836 #endif
837 {
838 	return (list(form, _list_both));
839 }
840 
841 static int
842 #if	defined(__STDC__)
843 list (
844 	char			*form,
845 	void			(*subaction)()
846 )
847 #else
848 list (form, subaction)
849 	char			*form;
850 	void			(*subaction)();
851 #endif
852 {
853 	FORM			fbuf;
854 
855 	FALERT			alert;
856 
857 	FILE * 			align_fp;
858 
859 	char			*nl;
860 
861 
862 	if (STREQU(NAME_ALL, form)) {
863 
864 		nl = "";
865 		while (getform(form, &fbuf, &alert, &align_fp) == 0) {
866 			printf (gettext("%sForm name: %s\n"), nl, fbuf.name);
867 			(*subaction) (&fbuf, &alert, align_fp);
868 			nl = "\n";
869 		}
870 
871 		switch (errno) {
872 		case ENOENT:
873 			return (0);
874 		default:
875 			/*
876 			 * Don't know if we'll have a good name
877 			 * in the "all" case on getting here, so
878 			 * punt on naming the form in the error
879 			 * message.
880 			 */
881 			LP_ERRMSG2 (ERROR, E_LP_GETFORM, form, PERROR);
882 			return (1);
883 		}
884 
885 	} else {
886 
887 		if (getform(form, &fbuf, &alert, &align_fp) == 0) {
888 			(*subaction) (&fbuf, &alert, align_fp);
889 			return (0);
890 		}
891 
892 		switch (errno) {
893 		case ENOENT:
894 			LP_ERRMSG1 (ERROR, E_LP_NOFORM, form);
895 			return (1);
896 		default:
897 			LP_ERRMSG2 (ERROR, E_LP_GETFORM, form, PERROR);
898 			return (1);
899 		}
900 
901 	}
902 }
903 
904 /**
905  ** _list_form()
906  **/
907 
908 static void
909 #if	defined(__STDC__)
910 _list_form (
911 	FORM *			pf,
912 	FALERT *		palert,
913 	FILE *			align_fp
914 )
915 #else
916 _list_form (pf, palert, align_fp)
917 	FORM *			pf;
918 	FALERT *		palert;
919 	FILE *			align_fp;
920 #endif
921 {
922 	size_t			n;
923 
924 	char			buf[BUFSIZ];
925 
926 	int			which_set[FO_MAX];
927 	int			fld,whichVal;
928 
929 
930 	whichVal = (pf->paper && (L == 0) ? 0 : 1);
931 	for (fld = 0; fld < FO_MAX; fld++)
932 		which_set[fld] = whichVal;
933 	if (!align_fp)
934 		which_set[FO_ALIGN] = 0;
935 	if (pf->paper)
936 		which_set[FO_PAPER] = 1;
937 	wrform (pf->name, pf, 1, onerror, which_set);
938 	if (align_fp)
939 		while ((n = fread(buf, 1, BUFSIZ, align_fp)))
940 			write (1, buf, n);
941 }
942 
943 /**
944  ** _list_alert()
945  **/
946 
947 static void
948 #if	defined(__STDC__)
949 _list_alert (
950 	FORM *			ignore,
951 	FALERT *		palert
952 )
953 #else
954 _list_alert (ignore, palert)
955 	FORM *			ignore;
956 	FALERT *		palert;
957 #endif
958 {
959 	printalert (stdout, palert, 0);
960 }
961 
962 /**
963  ** _list_both()
964  **/
965 
966 static void
967 #if	defined(__STDC__)
968 _list_both (
969 	FORM *			pf,
970 	FALERT *		palert,
971 	FILE *			align_fp
972 )
973 #else
974 _list_both (pf, palert, align_fp)
975 	FORM *			pf;
976 	FALERT *		palert;
977 	FILE *			align_fp;
978 #endif
979 {
980 	_list_alert (pf, palert);
981 	_list_form (pf, palert, align_fp);
982 }
983 
984 /**
985  ** any_alert()
986  **/
987 
988 static int
989 #if	defined(__STDC__)
990 any_alert (
991 	char *			form,
992 	FILE *			ignore,
993 	FALERT *		p_new_alert
994 )
995 #else
996 any_alert (form, ignore, p_new_alert)
997 	char *			form;
998 	FILE *			ignore;
999 	FALERT *		p_new_alert;
1000 #endif
1001 {
1002 	FORM			fbuf;
1003 
1004 	FALERT			alert;
1005 
1006 
1007 	while (getform(NAME_ALL, &fbuf, &alert, (FILE **)0) == 0)
1008 		if (!alert.shcmd)
1009 			if (putform(fbuf.name, (FORM *)0, p_new_alert, (FILE **)0) == -1) {
1010 				LP_ERRMSG2 (ERROR, E_LP_PUTFORM, fbuf.name, PERROR);
1011 				return (1);
1012 			}
1013 
1014 	return (0);
1015 }
1016 
1017 /**
1018  ** delete_form()
1019  ** quiet_alert()
1020  **/
1021 
1022 #if	defined(__STDC__)
1023 
1024 static int	dq ( char * , int (*)() );
1025 static int	_delete_form ( char * );
1026 static int	_quiet_alert ( char * );
1027 
1028 #else
1029 
1030 static int	dq();
1031 static int	_delete_form();
1032 static int	_quiet_alert();
1033 
1034 #endif
1035 
1036 static int
1037 #if	defined(__STDC__)
1038 delete_form (
1039 	char			*form
1040 )
1041 #else
1042 delete_form (form)
1043 	char			*form;
1044 #endif
1045 {
1046 	return (dq(form, _delete_form));
1047 }
1048 
1049 static int
1050 #if	defined(__STDC__)
1051 quiet_alert (
1052 	char *			form
1053 )
1054 #else
1055 quiet_alert (form)
1056 	char *			form;
1057 #endif
1058 {
1059 	return (dq(form, _quiet_alert));
1060 }
1061 
1062 static int
1063 #if	defined(__STDC__)
1064 dq (
1065 	char			*form,
1066 	int			(*subaction)()
1067 )
1068 #else
1069 dq (form, subaction)
1070 	char			*form;
1071 	int			(*subaction)();
1072 #endif
1073 {
1074 	FORM			fbuf;
1075 
1076 
1077 	if (STREQU(NAME_ANY, form) || STREQU(NAME_NONE, form)) {
1078 		LP_ERRMSG (ERROR, E_FOR_ANYNONE);
1079 		exit (1);
1080 	}
1081 
1082 	if (STREQU(NAME_ALL, form)) {
1083 
1084 		while (getform(form, &fbuf, (FALERT *)0, (FILE **)0) == 0)
1085 			if ((*subaction)(fbuf.name) == 1)
1086 				return (1);
1087 
1088 		switch (errno) {
1089 		case ENOENT:
1090 			return (0);
1091 		default:
1092 			/*
1093 			 * Don't know if we'll have a good name
1094 			 * in the "all" case on getting here, so
1095 			 * punt on naming the form in the error
1096 			 * message.
1097 			 */
1098 			LP_ERRMSG2 (ERROR, E_LP_GETFORM, form, PERROR);
1099 			return (1);
1100 		}
1101 
1102 	} else {
1103 
1104 		if (getform(form, &fbuf, (FALERT *)0, (FILE **)0) == 0)
1105 			return ((*subaction)(fbuf.name));
1106 
1107 		switch (errno) {
1108 		case ENOENT:
1109 			LP_ERRMSG1 (ERROR, E_LP_NOFORM, form);
1110 			return (1);
1111 		default:
1112 			LP_ERRMSG2 (ERROR, E_LP_GETFORM, form, PERROR);
1113 			return (1);
1114 		}
1115 	}
1116 }
1117 
1118 static int
1119 #if	defined(__STDC__)
1120 _delete_form (
1121 	char			*form
1122 )
1123 #else
1124 _delete_form (form)
1125 	char			*form;
1126 #endif
1127 {
1128 	switch (notify_spooler(S_UNLOAD_FORM, R_UNLOAD_FORM, form)) {
1129 
1130 	case -1:
1131 		if (anyrequests()) {
1132 			LP_ERRMSG (ERROR, E_FOR_MOPENREQX);
1133 			return (1);
1134 		}
1135 		/*FALLTHROUGH*/
1136 
1137 	case MNODEST:
1138 		if (delform(form) == -1) {
1139 			if (errno == ENOENT) {
1140 				LP_ERRMSG1 (ERROR, E_LP_NOFORM, form);
1141 				return (1);
1142 			} else {
1143 				LP_ERRMSG2 (
1144 					ERROR,
1145 		     			E_FOR_UNKNOWN,
1146 					form,
1147 					PERROR
1148 				);
1149 				return (1);
1150 			}
1151 		}
1152 		break;
1153 
1154 	case MOK:
1155 		if (delform(form) == -1) {
1156     			LP_ERRMSG (ERROR, E_FOR_DELSTRANGE);
1157 			return (1);
1158 		}
1159 		break;
1160 	}
1161 	return (0);
1162 }
1163 
1164 static int
1165 #if	defined(__STDC__)
1166 _quiet_alert (
1167 	char *			form
1168 )
1169 #else
1170 _quiet_alert (form)
1171 	char *			form;
1172 #endif
1173 {
1174 	char			*msgbuf;
1175 
1176 	int			mtype;
1177 
1178 	int			size;
1179 
1180 	short			status;
1181 
1182 	/*
1183 	 * If the attempt to open a message queue to the
1184 	 * Spooler fails, assume it isn't running and just
1185 	 * return--don't say anything, `cause the user may
1186 	 * know. Any other failure deserves an error message.
1187 	 */
1188 
1189 	if (mopen() == -1)
1190 		return (0);
1191 
1192 	size = putmessage (NULL, S_QUIET_ALERT, form, QA_FORM);
1193 	msgbuf = malloc(size);
1194 	putmessage (msgbuf, S_QUIET_ALERT, form, QA_FORM);
1195 
1196 	if (msend(msgbuf) == -1) {
1197 		LP_ERRMSG (ERROR, E_LP_MSEND);
1198 		mclose ();
1199 		return (1);
1200 	}
1201 
1202 	if (mrecv(msgbuf, size) == -1) {
1203 		LP_ERRMSG (ERROR, E_LP_MRECV);
1204 		mclose ();
1205 		return (1);
1206 	}
1207 
1208 	mtype = getmessage(msgbuf, R_QUIET_ALERT, &status);
1209 	free (msgbuf);
1210 	mclose ();
1211 	if (mtype != R_QUIET_ALERT) {
1212 		LP_ERRMSG (ERROR, E_LP_BADREPLY);
1213 		return (1);
1214 	}
1215 
1216 	switch (status) {
1217 
1218 	case MOK:
1219 		break;
1220 
1221 	case MNODEST:	/* not quite, but not a lie either */
1222 	case MERRDEST:
1223 		LP_ERRMSG1 (WARNING, E_LP_NOQUIET, form);
1224 		break;
1225 
1226 	case MNOPERM:	/* taken care of up front */
1227 	default:
1228 		LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, status);
1229 		return (1);
1230 		/*NOTREACHED*/
1231 	}
1232 
1233 	return (0);
1234 }
1235 
1236 /**
1237  ** set_action() - CHECK FOR AMBIGUOUS ACTIONS
1238  **/
1239 
1240 static Action
1241 #if	defined(__STDC__)
1242 set_action (
1243 	Action			action,
1244 	char *			option
1245 )
1246 #else
1247 set_action (action, option)
1248 	Action			action;
1249 	char *			option;
1250 #endif
1251 {
1252 	static Action		prev_action	= 0;
1253 
1254 	static char *		prev_option;
1255 
1256 
1257 	if (
1258 		action == list_form && prev_action == list_alert
1259 	     || action == list_alert && prev_action == list_form
1260 	)
1261 		action = list_both;
1262 
1263 	else if (
1264 		action == add_form && prev_action == add_alert
1265 	     || action == add_alert && prev_action == add_form
1266 	)
1267 		action = add_form;
1268 
1269 	else if (
1270 		action == any_alert && prev_action == add_alert
1271 	     || action == add_alert && prev_action == any_alert
1272 	)
1273 		action = any_alert;
1274 
1275 	else if (prev_action && prev_action != action) {
1276  		LP_ERRMSG2 (ERROR, E_LP_AMBIG, option, prev_option);
1277 		exit (1);
1278 	}
1279 
1280 OK:	prev_action = action;
1281 	prev_option = option;
1282 	return (action);
1283 }
1284 
1285 /**
1286  ** notify_spooler() - NOTIFY SPOOLER OF ACTION ON FORMS DB
1287  **/
1288 
1289 static int
1290 #if	defined(__STDC__)
1291 notify_spooler (
1292 	int			sendmsg,
1293 	int			replymsg,
1294 	char *			form
1295 )
1296 #else
1297 notify_spooler (sendmsg, replymsg, form)
1298 	int			sendmsg;
1299 	int			replymsg;
1300 	char *			form;
1301 #endif
1302 {
1303 	char *			msgbuf;
1304 
1305 	int			mtype;
1306 	int			size;
1307 
1308 	short			status;
1309 
1310 	/*
1311 	 * If the attempt to open a message queue to the
1312 	 * Spooler fails, assume it isn't running and just
1313 	 * return--don't say anything, `cause the user may
1314 	 * know. Any other failure deserves an error message.
1315 	 */
1316 
1317 	if (mopen() == -1)
1318 		return (-1);
1319 
1320 	size = putmessage((char *)0, sendmsg, form);
1321 	msgbuf = malloc(size);
1322 	putmessage (msgbuf, sendmsg, form);
1323 
1324 	if (msend(msgbuf) == -1) {
1325 		LP_ERRMSG (ERROR, E_LP_MSEND);
1326 		mclose ();
1327 		exit (1);
1328 	}
1329 	if (mrecv(msgbuf, size) == -1) {
1330 		LP_ERRMSG (ERROR, E_LP_MRECV);
1331 		mclose ();
1332 		exit (1);
1333 	}
1334 	mclose ();
1335 
1336 	mtype = getmessage(msgbuf, replymsg, &status);
1337 	free (msgbuf);
1338 	if (mtype != replymsg) {
1339 		LP_ERRMSG (ERROR, E_LP_BADREPLY);
1340 		exit (1);
1341 	}
1342 
1343 	if (status == MOK)
1344 		return (MOK);
1345 
1346 	if (sendmsg == S_LOAD_FORM)
1347 		switch (status) {
1348 		case MNOSPACE:
1349 			LP_ERRMSG (ERROR, E_FOR_NOSPACE);
1350 			break;
1351 		case MNOPERM:
1352 			LP_ERRMSG (ERROR, E_LP_NOTADM);
1353 			break;
1354 
1355 		/*
1356 		 * The following two error conditions should have
1357 		 * already been trapped, so treat them as bad status
1358 		 * should they occur.
1359 		 */
1360 		case MNODEST:
1361 		case MERRDEST:
1362 		default:
1363 			LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, status);
1364 			break;
1365 		}
1366 
1367 	if (sendmsg == S_UNLOAD_FORM)
1368 		switch (status) {
1369 		case MBUSY:
1370 			LP_ERRMSG1 (ERROR, E_FOR_FORMBUSY, form);
1371 			break;
1372 		case MNODEST:
1373 			return (MNODEST);
1374 		case MNOPERM:
1375 			LP_ERRMSG (ERROR, E_LP_NOTADM);
1376 			break;
1377 		default:
1378 			LP_ERRMSG (ERROR, E_LP_BADSTATUS);
1379 			break;
1380 		}
1381 
1382 	exit (1);
1383 }
1384 
1385 /**
1386  ** onerror()
1387  **/
1388 
1389 static int
1390 #if	defined(__STDC__)
1391 onerror (
1392 	int			Errno,
1393 	int			lp_errno,
1394 	int			linenum
1395 )
1396 #else
1397 onerror (Errno, lp_errno, linenum)
1398 	int			Errno;
1399 	int			lp_errno;
1400 	int			linenum;
1401 #endif
1402 {
1403 	static int		nerrors	= 0;
1404 
1405 
1406 	if (Errno == EBADF) {
1407 		switch (lp_errno) {
1408 		case LP_EBADSDN:
1409 			LP_ERRMSG1 (WARNING, E_FOR_BADSCALE, linenum);
1410 			break;
1411 		case LP_EBADINT:
1412 			LP_ERRMSG1 (WARNING, E_FOR_BADINT, linenum);
1413 			break;
1414 		case LP_EBADNAME:
1415 			LP_ERRMSG1 (WARNING, E_FOR_NOTNAME, linenum);
1416 			break;
1417 		case LP_EBADARG:
1418 			LP_ERRMSG1 (WARNING, E_FOR_BADCHSETQUALIFIER, linenum);
1419 			break;
1420 		case LP_ETRAILIN:
1421 			LP_ERRMSG1 (WARNING, E_FOR_TRAILIN, linenum);
1422 			break;
1423 		case LP_EBADCTYPE:
1424 			LP_ERRMSG1 (WARNING, E_FOR_NOTCTYPE, linenum);
1425 			break;
1426 		case LP_EBADHDR:
1427 			LP_ERRMSG1 (WARNING, E_FOR_BADHDR, linenum);
1428 			break;
1429 		}
1430 		if (nerrors++ >= 5) {
1431 			LP_ERRMSG (ERROR, E_LP_GARBAGE);
1432 			return (-1);
1433 		}
1434 		return (0);
1435 	} else {
1436 		LP_ERRMSG2 (ERROR, E_FOR_UNKNOWN, "(stdin)", PERROR);
1437 		return (-1);
1438 	}
1439 }
1440