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