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