Home | History | Annotate | Download | only in cmd
      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 ==