xref: /titanic_52/usr/src/cmd/lp/cmd/lpsched/validate.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 2001 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 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.11.1.10	*/
32 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
33 
34 #include "lpsched.h"
35 
36 #include "validate.h"
37 
38 #define register auto
39 
40 int		pickfilter ( RSTATUS * , CANDIDATE * , FSTATUS * );
41 
42 unsigned long		chkprinter_result	= 0;
43 char *			o_cpi		= 0;
44 char *			o_lpi		= 0;
45 char *			o_width		= 0;
46 char *			o_length	= 0;
47 
48 static int		wants_nobanner	= 0;
49 static int		lp_or_root	= 0;
50 
51 static int		_chkopts ( RSTATUS *, CANDIDATE * , FSTATUS * );
52 static void		free_candidate ( CANDIDATE * );
53 
54 /**
55  ** _validate() - FIND A PRINTER TO HANDLE A REQUEST
56  **/
57 
58 short
59 _validate(RSTATUS *prs, PSTATUS *pps, PSTATUS *stop_pps, char **prefixp,
60 	 int moving)
61 {
62 	register CANDIDATE	*pc		= 0,
63 				*pcend,
64 				*best_pc	= 0;
65 
66 	register FSTATUS	*pfs		= 0;
67 
68 	register CSTATUS	*pcs		= 0;
69 
70 	CANDIDATE		*arena		= 0,
71 				single;
72 
73 	size_t			n;
74 
75 	short			ret;
76 
77 	chkprinter_result = 0;
78 	o_cpi = o_lpi = o_width = o_length = 0;
79 	wants_nobanner = 0;
80 	memset (&single, 0, sizeof(single));
81 
82 	lp_or_root = 0;
83 
84 	if (STREQU(prs->secure->system, Local_System))
85 		if (bangequ(prs->secure->user, "root") ||
86 					bangequ(prs->secure->user, "lp"))
87 			lp_or_root = 1;
88 
89 
90 	if (prefixp)
91 		*prefixp = prs->request->destination;
92 
93 	/*
94 	 * If a destination other than "any" was given,
95 	 * see if it exists in our internal tables.
96 	 */
97 	if (!pps && prs->request->destination &&
98 	    !STREQU(prs->request->destination, NAME_ANY))
99 		if (((pps = search_ptable(prs->request->destination)) != NULL) ||
100 		    ((pcs = search_ctable(prs->request->destination)) != NULL) &&
101 		    pcs->class->members)
102 			/*EMPTY*/;
103 		else {
104 			ret = MNODEST;
105 			goto Return;
106 		}
107 
108 	/*
109 	 * If we are trying to avoid a printer, but the request
110 	 * was destined for just that printer, we're out.
111 	 */
112 	if (pps && pps == stop_pps) {
113 		ret = MERRDEST;
114 		goto Return;
115 	}
116 
117 	/*
118 	 * If a form was given, see if it exists; if so,
119 	 * see if the user is allowed to use it.
120 	 * If a remote printer was specified, then don't use any local
121 	 * form knowledge.
122 	 */
123 	if (prs && prs->request && prs->request->form && (pps || pcs)) {
124 		if ((pfs = search_ftable(prs->request->form))) {
125 			if (lp_or_root || allowed(prs->secure->user,
126 				pfs->users_allowed, pfs->users_denied))
127 				/*EMPTY*/;
128 			else {
129 				ret = MDENYMEDIA;
130 				goto Return;
131 			}
132 		} else {
133 			ret = MNOMEDIA;
134 			goto Return;
135 		}
136 	}
137 
138 	/*
139 	 * If the request includes -o options there may be pitch and
140 	 * size and no-banner requests that have to be checked. One
141 	 * could argue that this shouldn't be in the Spooler, because
142 	 * the Spooler's job is SPOOLING, not PRINTING. That's right,
143 	 * except that the Spooler will be making a choice of printers
144 	 * so it has to evaluate carefully: E.g. user wants ANY printer,
145 	 * so we should pick one that can handle what he/she wants.
146 	 *
147 	 * Parse out the important stuff here so we have it when we
148 	 * need it.
149 	 */
150 	{
151 		register char		**list,
152 					**pl;
153 
154 		if (
155 			prs->request->options
156 		     && (list = dashos(prs->request->options))
157 		) {
158 			for (pl = list ; *pl; pl++)
159 				if (STRNEQU(*pl, "cpi=", 4))
160 					o_cpi = Strdup(*pl + 4);
161 				else if (STRNEQU(*pl, "lpi=", 4))
162 					o_lpi = Strdup(*pl + 4);
163 				else if (STRNEQU(*pl, "width=", 6))
164 					o_width = Strdup(*pl + 6);
165 				else if (STRNEQU(*pl, "length=", 7))
166 					o_length = Strdup(*pl + 7);
167 				else if (STREQU(*pl, "nobanner"))
168 					wants_nobanner = 1;
169 			freelist (list);
170 		}
171 	}
172 
173 	/*
174 	 * This macro checks that a form has a mandatory print wheel
175 	 * (or character set).
176 	 */
177 #define	CHKMAND(PFS) \
178 	( \
179 		(PFS) \
180 	     && (PFS)->form->chset \
181 	     && !STREQU((PFS)->form->chset, NAME_ANY) \
182 	     && (PFS)->form->mandatory \
183 	)
184 
185 	/*
186 	 * This macro checks that the user is allowed to use the
187 	 * printer.
188 	 */
189 #define CHKU(PRS,PPS) \
190 	( \
191 		lp_or_root \
192 	     || allowed( \
193 			(PRS)->secure->user, \
194 			(PPS)->users_allowed, \
195 			(PPS)->users_denied \
196 		) \
197 	)
198 
199 	/*
200 	 * This macro checks that the form is allowed on the printer,
201 	 * or is already mounted there.
202 	 * Note: By doing this check we don't have to check that the
203 	 * characteristics of the form, such as pitch, size, or
204 	 * character set, against the printer's capabilities, ASSUMING,
205 	 * of course, that the allow list is correct. That is, the
206 	 * allow list lists forms that have already been checked against
207 	 * the printer!
208 	 */
209 #define CHKF(PFS,PPS) \
210 	( \
211 		isFormMountedOnPrinter(PPS,PFS) \
212 	     || allowed( \
213 			(PFS)->form->name, \
214 			(PPS)->forms_allowed, \
215 			(PPS)->forms_denied \
216 		) \
217 	)
218 
219 	/*
220 	 * This macro checks that the print wheel is acceptable
221 	 * for the printer or is mounted. Note: If the printer doesn't
222 	 * take print wheels, the check passes. The check for printers
223 	 * that don't take print wheels is below.
224 	 */
225 #define CHKPW(PW,PPS) \
226 	( \
227 		!(PPS)->printer->daisy \
228 	     || ( \
229 			(PPS)->pwheel_name \
230 		     && STREQU((PPS)->pwheel_name, (PW)) \
231 		) \
232 	     || searchlist((PW), (PPS)->printer->char_sets) \
233 	)
234 
235 	/*
236 	 * This macro checks the pitch, page size, and (if need be)
237 	 * the character set. The character set isn't checked if the
238 	 * printer takes print wheels, or if the character set is
239 	 * listed in the printer's alias list.
240 	 * The form has to be checked as well; while we're sure that
241 	 * at least one type for each printer can handle the form's
242 	 * cpi/lpi/etc. characteristics (lpadmin made sure), we aren't
243 	 * sure that ALL the types work.
244 	 */
245 #define CHKOPTS(PRS,PC,PFS) _chkopts((PRS),(PC),(PFS)) /* was a macro */
246 
247 	/*
248 	 * This macro checks the acceptance status of a printer.
249 	 * If the request is already assigned to that printer,
250 	 * then it's okay. It's ambiguous what should happen if
251 	 * originally a "-d any" request was accepted, temporarily
252 	 * assigned one printer, then the administrator (1) rejected
253 	 * further requests for the printers and (2) made the
254 	 * temporarily assigned printer unusable for the request.
255 	 * What will happen, of course, is that the request will
256 	 * be canceled, even though the other printers would be okay
257 	 * if not rejecting....but if we were to say, gee it's okay,
258 	 * the request has already been accepted, we may be allowing
259 	 * it on printers that were NEVER accepting. Thus we can
260 	 * continue to accept it only for the printer already assigned.
261 	 */
262 #define CHKACCEPT(PRS,PPS) \
263 	( \
264 		!((PPS)->status & PS_REJECTED) \
265 	     || (PRS)->printer == (PPS) \
266 	     || moving \
267 	)
268 
269 	/*
270 	 * If a print wheel or character set is given, see if it
271 	 * is allowed on the form.
272 	 */
273 	if (prs->request->charset)
274 		if (
275 			!CHKMAND(pfs)
276 		     || STREQU(prs->request->charset, pfs->form->chset)
277 		)
278 			/*EMPTY*/;
279 		else {
280 			ret = MDENYMEDIA;
281 			chkprinter_result |= PCK_CHARSET;
282 			goto Return;
283 		}
284 
285 	/*
286 	 * If a single printer was named, check the request against it.
287 	 * Do the accept/reject check late so that we give the most
288 	 * useful information to the user.
289 	 */
290 	if (pps) {
291 		(pc = &single)->pps = pps;
292 
293 		/* Does the printer allow the user? */
294 		if (!CHKU(prs, pps)) {
295 			ret = MDENYDEST;
296 			goto Return;
297 		}
298 
299 		/* Does the printer allow the form? */
300 		if (pfs && !CHKF(pfs, pps)) {
301 			ret = MNOMOUNT;
302 			goto Return;
303 		}
304 
305 		/* Does the printer allow the pwheel? */
306 		if (
307 			prs->request->charset
308 		     && !CHKPW(prs->request->charset, pps)
309 		) {
310 			ret = MNOMOUNT;
311 			goto Return;
312 		}
313 
314 		/* Can printer handle the pitch/size/charset/nobanner? */
315 		if (!CHKOPTS(prs, pc, pfs)) {
316 			ret = MDENYDEST;
317 			goto Return;
318 		}
319 
320 		/* Is the printer allowing requests? */
321 		if (!CHKACCEPT(prs, pps)) {
322 			ret = MERRDEST;
323 			goto Return;
324 		}
325 
326 		/* Is there a filter which will convert the input? */
327 		if (!pickfilter(prs, pc, pfs)) {
328 			ret = MNOFILTER;
329 			goto Return;
330 		}
331 
332 		best_pc = pc;
333 		ret = MOK;
334 		goto Return;
335 	}
336 
337 	/*
338 	 * Do the acceptance check on the class (if we have one)
339 	 * now so we can proceed with checks on individual printers
340 	 * in the class. Don't toss out the request if it is already
341 	 * assigned a printer just because the class is NOW rejecting.
342 	 */
343 	if (
344 		pcs
345 	     && (pcs->status & CS_REJECTED)
346 	     && !moving
347 	     && !prs->printer
348 	) {
349 		ret = MERRDEST;
350 		goto Return;
351 	}
352 
353 	/*
354 	 * Construct a list of printers based on the destination
355 	 * given. Cross off those that aren't accepting requests,
356 	 * that can't take the form, or which the user can't use.
357 	 * See if the list becomes empty.
358 	 */
359 
360 	if (pcs)
361 		n = lenlist(pcs->class->members);
362 	else {
363 		n = 0;
364 		for (pps = walk_ptable(1); pps; pps = walk_ptable(0))
365 			n++;
366 	}
367 	pcend = arena = (CANDIDATE *)Calloc(n, sizeof(CANDIDATE));
368 
369 	/*
370 	 * Start with a list of printers that are accepting requests.
371 	 * Don't skip a printer if it's rejecting but the request
372 	 * has already been accepted for it.
373 	 */
374 	if (pcs) {
375 		register char		 **pn;
376 
377 		for (pn = pcs->class->members; *pn; pn++)
378 			if (
379 				((pps = search_ptable(*pn)) != NULL)
380 			     && pps != stop_pps
381 			)
382 				(pcend++)->pps = pps;
383 
384 
385 	} else
386 		for (pps = walk_ptable(1); pps; pps = walk_ptable(0))
387 			if (CHKACCEPT(prs, pps) && pps != stop_pps)
388 				(pcend++)->pps = pps;
389 
390 	if (pcend == arena) {
391 		ret = MERRDEST;
392 		goto Return;
393 	}
394 
395 	/*
396 	 * Clean out printers that the user can't use. We piggy-back
397 	 * the pitch/size/banner checks here because the same error return
398 	 * is given (strange, eh?).
399 	 */
400 	{
401 		register CANDIDATE	*pcend2;
402 
403 		for (pcend2 = pc = arena; pc < pcend; pc++) {
404 			if (CHKU(prs, pc->pps) && CHKOPTS(prs, pc, pfs))
405 				*pcend2++ = *pc;
406 			else
407 				free_candidate (pc);
408 		}
409 
410 		if (pcend2 == arena) {
411 			ret = MDENYDEST;
412 			goto Return;
413 		}
414 		pcend = pcend2;
415 
416 	}
417 
418 	/*
419 	 * Clean out printers that can't mount the form,
420 	 * EXCEPT for printers that already have it mounted:
421 	 */
422 	if (pfs) {
423 		register CANDIDATE	*pcend2;
424 
425 		for (pcend2 = pc = arena; pc < pcend; pc++)
426 			if (CHKF(pfs, pc->pps))
427 				*pcend2++ = *pc;
428 			else
429 				free_candidate (pc);
430 
431 		if (pcend2 == arena) {
432 			ret = MNOMOUNT;
433 			goto Return;
434 		}
435 		pcend = pcend2;
436 
437 	}
438 
439 	/*
440 	 * Clean out printers that can't take the print wheel
441 	 * EXCEPT for printers that already have it mounted
442 	 * or printers for which it is a selectable character set:
443 	 */
444 	if (prs->request->charset) {
445 		register CANDIDATE	*pcend2;
446 
447 		for (pcend2 = pc = arena; pc < pcend; pc++)
448 			if (CHKPW(prs->request->charset, pc->pps))
449 				*pcend2++ = *pc;
450 			else
451 				free_candidate (pc);
452 
453 		if (pcend2 == arena) {
454 			ret = MNOMOUNT;
455 			goto Return;
456 		}
457 		pcend = pcend2;
458 
459 	}
460 
461 	/*
462 	 * Clean out printers that can't handle the printing
463 	 * and for which there's no filter to convert the input.
464 	 *
465 	 */
466 
467 	/*
468 	 * Is the form mounted, or is none needed?
469 	 */
470 #define CHKFMNT(PFS,PPS) (isFormUsableOnPrinter(PPS,PFS))
471 
472 	/*
473 	 * Is the print-wheel mounted, or is none needed?
474 	 */
475 #define CHKPWMNT(PRS,PPS) SAME((PPS)->pwheel_name, (PRS)->request->charset)
476 
477 	/*
478 	 * Do we NOT need a special character set, or can we select
479 	 * it on the printer? Note: Getting this far means that IF
480 	 * the printer has selectable character sets (!daisy) then
481 	 * it can select the one we want.
482 	 */
483 #define CHKCHSET(PRS,PPS) \
484 	( \
485 		!(PRS)->request->charset \
486 	     || !(PPS)->printer->daisy \
487 	)
488 
489 	/*
490 	 * Is the printer able to print now?
491 	 */
492 #define CHKENB(PPS)	 (!((PPS)->status & (PS_DISABLED|PS_FAULTED)))
493 
494 	/*
495 	 * Is the printer not busy printing another request, or
496 	 * not awaiting an auto-retry after a fault?
497 	 */
498 #define CHKFREE(PPS)	 (!((PPS)->status & (PS_BUSY|PS_LATER)))
499 
500 	/*
501 	 * Is the printer local?
502 	 */
503 #define CHKLOCAL(PPS)	 (!((PPS)->status & (PS_REMOTE)))
504 
505 	{
506 		register CANDIDATE	*pcend2;
507 
508 		for (pcend2 = pc = arena; pc < pcend; pc++)
509 			if (pickfilter(prs, pc, pfs)) {
510 
511 				/*
512 				 * Compute a ``weight'' for this printer,
513 				 * based on its status. We'll later pick
514 				 * the printer with the highest weight.
515 				 */
516 				pc->weight = 0;
517 				if (!pc->fast && !pc->slow)
518 					pc->weight += WEIGHT_NOFILTER;
519 				if (CHKFREE(pc->pps))
520 					pc->weight += WEIGHT_FREE;
521 				if (CHKENB(pc->pps))
522 					pc->weight += WEIGHT_ENABLED;
523 				if (CHKFMNT(pfs, pc->pps))
524 					pc->weight += WEIGHT_MOUNTED;
525 				if (CHKPWMNT(prs, pc->pps))
526 					pc->weight += WEIGHT_MOUNTED;
527 				if (CHKCHSET(prs, pc->pps))
528 					pc->weight += WEIGHT_SELECTS;
529 				if (CHKLOCAL(pc->pps))
530 					pc->weight += WEIGHT_LOCAL;
531 
532 #if	defined(FILTER_EARLY_OUT)
533 				if (pc->weight == WEIGHT_MAX) {
534 					/*
535 					 * This is the one!
536 					 */
537 					best_pc = pc;
538 					ret = MOK;
539 					goto Return;
540 				}
541 #endif
542 				/*
543 				 * This is a candidate!
544 				 */
545 				*pcend2++ = *pc;
546 
547 			} else
548 				/*
549 				 * No filter for this one!
550 				 */
551 				free_candidate (pc);
552 
553 		if (pcend2 == arena) {
554 			ret = MNOFILTER;
555 			goto Return;
556 		}
557 		pcend = pcend2;
558 
559 	}
560 
561 	if (pcend - arena == 1) {
562 		best_pc = arena;
563 		ret = MOK;
564 		goto Return;
565 	}
566 
567 #if	defined(OTHER_FACTORS)
568 	/*
569 	 * Here you might want to add code that considers
570 	 * other factors: the size of the file(s) to be
571 	 * printed ("prs->secure->size") in relation to the
572 	 * printer (e.g. printer A gets mostly large
573 	 * files, printer B gets mostly small files); the
574 	 * number/total-size of requests currently queued
575 	 * for the printer; etc.
576 	 *
577 	 * If your code includes eliminating printers drop them
578 	 * from the list (as done in several places above).
579 	 * Otherwise, your code should add weights to the weight
580 	 * already computed. Change the WEIGHT_MAX, increase the
581 	 * other WEIGHT_X values to compensate, etc., as appropriate.
582 	 */
583 	;
584 #endif
585 
586 	/*
587 	 * Pick the best printer from a list of eligible candidates.
588 	 */
589 	best_pc = arena;
590 	for (pc = arena + 1; pc < pcend; pc++)
591 		if (pc->weight > best_pc->weight)
592 			best_pc = pc;
593 	ret = MOK;
594 
595 	/*
596 	 * Branch to here if MOK and/or if things have been allocated.
597 	 */
598 Return:	if (ret == MOK) {
599 		register USER		*pu = Getuser(prs->secure->user);
600 
601 		register char		*pwheel_name;
602 
603 		PSTATUS			*oldpps = prs->printer;
604 
605 
606 		/*
607 		 * We are going to accept this print request, having
608 		 * found a printer for it. This printer will be assigned
609 		 * to the request, although this assignment may be
610 		 * temporary if other printers qualify and this printer
611 		 * is changed to no longer qualify. Qualification in
612 		 * this context includes being ready to print!
613 		 */
614 		prs->printer = best_pc->pps;
615 		load_str (&(prs->printer_type), best_pc->printer_type);
616 
617 		/*
618 		 * Assign the form (if any) to the request. Adjust
619 		 * the number of requests queued for old and new form
620 		 * accordingly.
621 		 */
622 		if (prs->form != pfs) {
623 			unqueue_form (prs);
624 			queue_form (prs, pfs);
625 		}
626 
627 		/*
628 		 * Ditto for the print wheel, except include here the
629 		 * print wheel needed by the form.
630 		 * CAUTION: When checking this request later, don't
631 		 * refuse to service it if the print wheel for the
632 		 * form isn't mounted but the form is; a mounted form
633 		 * overrides its other needs. Don't be confused by the
634 		 * name of the bit, RSS_PWMAND; a printer that prints
635 		 * this request MUST have the print wheel mounted
636 		 * (if it takes print wheels) if the user asked for
637 		 * a particular print wheel.
638 		 */
639 		prs->status &= ~RSS_PWMAND;
640 		if (CHKMAND(pfs))
641 			pwheel_name = pfs->form->chset;
642 		else
643 			if ((pwheel_name = prs->request->charset) != NULL)
644 				prs->status |= RSS_PWMAND;
645 
646 		if (!SAME(pwheel_name, prs->pwheel_name)) {
647 			unqueue_pwheel (prs);
648 			queue_pwheel (prs, pwheel_name);
649 		}
650 
651 		/*
652 		 * Adjust the priority to lie within the limits allowed
653 		 * for the user (this is a silent adjustment as required).
654 		 * CURRENTLY, ONLY NEW REQUESTS WILL GET QUEUED ACCORDING
655 		 * TO THIS PRIORITY. EXISTING REQUESTS BEING (RE)EVALUATED
656 		 * WILL NOT BE REQUEUED.
657 		 * A wild priority is changed to the default, or the
658 		 * limit, whichever is the lower priority (higher value).
659 		 */
660 		if (prs->request->priority < 0 || 39 < prs->request->priority)
661 			prs->request->priority = getdfltpri();
662 		if (pu && prs->request->priority < pu->priority_limit)
663 			prs->request->priority = pu->priority_limit;
664 
665 		/*
666 		 * If a filter is involved, change the number of
667 		 * copies to 1 (if the filter handles it).
668 		 */
669 		if (
670 			(best_pc->fast || best_pc->slow)
671 		     && (best_pc->flags & FPARM_COPIES)
672 		     && prs->request->copies > 1
673 		)
674 			prs->copies = 1;
675 		else
676 			/*
677 			 * We use two ".copies" because we don't
678 			 * want to lose track of the number requested,
679 			 * but do want to mark the number the interface
680 			 * program is to handle. Here is the best
681 			 * place to know this.
682 			 */
683 			prs->copies = prs->request->copies;
684 
685 		if (best_pc->slow) {
686 			/*
687 			 * If the filter has changed, the request will
688 			 * have to be refiltered. This may mean stopping
689 			 * a currently running filter or interface.
690 			 */
691 			if (!SAME(best_pc->slow, prs->slow)) {
692 
693 			    if (prs->request->outcome & RS_FILTERED)
694 				prs->request->outcome &= ~RS_FILTERED;
695 
696 			    if (
697 				prs->request->outcome & RS_FILTERING
698 			     && !(prs->request->outcome & RS_STOPPED)
699 			    ) {
700 				prs->request->outcome |= RS_REFILTER;
701 				prs->request->outcome |= RS_STOPPED;
702 				terminate (prs->exec);
703 
704 			    } else if (
705 				prs->request->outcome & RS_PRINTING
706 			     && !(prs->request->outcome & RS_STOPPED)
707 			    ) {
708 				prs->request->outcome |= RS_STOPPED;
709 				terminate (oldpps->exec);
710 			    }
711 
712 			}
713 
714 			load_str (&(prs->slow), best_pc->slow);
715 			/* Assumption: if there is a slow filter,
716 			 * there is an output_type
717 			 */
718 
719 			load_str (&(prs->output_type), best_pc->output_type);
720 		} else
721 			unload_str (&(prs->slow));
722 
723 		load_str (&(prs->fast), best_pc->fast);
724 
725 		if (prs->request->actions & ACT_FAST && prs->slow) {
726 			if (prs->fast) {
727 				prs->fast = makestr(
728 					prs->slow,
729 					"|",
730 					prs->fast,
731 					(char *)0
732 				);
733 				Free (prs->slow);
734 			} else
735 				prs->fast = prs->slow;
736 			prs->slow = 0;
737 		}
738 
739 	}
740 
741 
742 	/*
743 	 * Free the space allocated for the candidates, INCLUDING
744 	 * the one chosen. Any allocated space in the chosen candidate
745 	 * that has to be saved should have been COPIED already.
746 	 */
747 	if (arena) {
748 		for (pc = arena; pc < pcend; pc++)
749 			free_candidate (pc);
750 		Free ((char *)arena);
751 	} else if (best_pc)
752 		free_candidate (best_pc);
753 
754 	if (o_length)
755 		Free (o_length);
756 	if (o_width)
757 		Free (o_width);
758 	if (o_lpi)
759 		Free (o_lpi);
760 	if (o_cpi)
761 		Free (o_cpi);
762 
763 
764 	/*
765 	 * The following value is valid ONLY IF the request
766 	 * is canceled or rejected. Not all requests that
767 	 * we fail in this routine are tossed out!
768 	 */
769 	prs->reason = ret;
770 
771 
772 	return (ret);
773 }
774 
775 /**
776  ** _chkopts() - CHECK -o OPTIONS
777  **/
778 
779 static int
780 _chkopts(RSTATUS *prs, CANDIDATE *pc, FSTATUS *pfs)
781 {
782 	unsigned long		ret	= 0;
783 	unsigned long		chk	= 0;
784 
785 	char *			charset;
786 	char *			cpi	= 0;
787 	char *			lpi	= 0;
788 	char *			width	= 0;
789 	char *			length	= 0;
790 	char *			paper = NULL;
791 
792 	char **			pt;
793 
794 
795 	/*
796 	 * If we have a form, it overrides whatever print characteristics
797 	 * the user gave.
798 	 */
799 	if (pfs) {
800 		cpi = pfs->cpi;
801 		lpi = pfs->lpi;
802 		width = pfs->pwid;
803 		length = pfs->plen;
804 		paper = pfs->form->paper;
805 	} else {
806 		cpi = o_cpi;
807 		lpi = o_lpi;
808 		width = o_width;
809 		length = o_length;
810 	}
811 
812 	/*
813 	 * If the printer takes print wheels, or the character set
814 	 * the user wants is listed in the character set map for this
815 	 * printer, we needn't check if the printer can handle the
816 	 * character set. (Note: The check for the print wheel case
817 	 * is done elsewhere.)
818 	 */
819 
820 	if (pc->pps->printer->daisy ||
821 	    search_cslist(prs->request->charset, pc->pps->printer->char_sets))
822 		charset = 0;
823 	else
824 		charset = prs->request->charset;
825 
826 	pc->printer_types = 0;
827 	for (pt = pc->pps->printer->printer_types; *pt; pt++) {
828 		unsigned long		this;
829 
830 		if (paper) {
831 			if (allowed(paper,pc->pps->paper_allowed,NULL)) {
832 				addlist (&(pc->printer_types), *pt);
833 			} else {
834 				ret |= PCK_PAPER;
835 			}
836 		} else {
837 			this = chkprinter(*pt, cpi, lpi, length, width,
838 				charset);
839 			if (this == 0)
840 				addlist(&(pc->printer_types), *pt);
841 			chk |= this;
842 		}
843 	}
844 	if (!pc->printer_types)
845 		ret |= chk;
846 
847 	if (pc->pps->printer->banner == BAN_ALWAYS) {
848 		if ((wants_nobanner == 1) && (lp_or_root != 1)) {
849 			/* delete "nobanner" */
850 			char **list;
851 
852 			if (prs->request->options &&
853 			    (list = dashos(prs->request->options))) {
854 				dellist(&list, "nobanner");
855 				free(prs->request->options);
856 				prs->request->options = sprintlist(list);
857 			}
858 		}
859 	} else if (pc->pps->printer->banner == BAN_NEVER) {
860 		if (wants_nobanner == 0) {
861 			/* add "nobanner" */
862 			char **list = NULL;
863 
864 			if (prs->request->options) {
865 				list = dashos(prs->request->options);
866 				free(prs->request->options);
867 			}
868 			appendlist(&list, "nobanner");
869 			prs->request->options = sprintlist(list);
870 		}
871 	} else /* if (pc->pps->printer->banner == BAN_OPTIONAL) */ {
872 		/* it is optional, leave it alone */
873 	}
874 
875 	chkprinter_result |= ret;
876 	return (ret == 0);
877 }
878 
879 /**
880  ** free_candidate()
881  **/
882 
883 static void
884 free_candidate(CANDIDATE *pc)
885 {
886 	if (pc->slow)
887 		unload_str (&(pc->slow));
888 	if (pc->fast)
889 		unload_str (&(pc->fast));
890 	if (pc->printer_types) {
891 		freelist (pc->printer_types);
892 		pc->printer_types = 0;
893 	}
894 	if (pc->printer_type)
895 		unload_str (&(pc->printer_type));
896 	if (pc->output_type)
897 		unload_str (&(pc->output_type));
898 	return;
899 }
900