Home | History | Annotate | Download | only in lpsched
      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 1996 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.2.1.5	*/
     32 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
     33 
     34 #include "string.h"
     35 #include "limits.h"
     36 
     37 #include "lpsched.h"
     38 
     39 #include "validate.h"
     40 
     41 /*
     42  * Transform consecutive "LP_SEP" characters to a single comma and n-1 LP_SEP;
     43  *
     44  * BUT we'll leave LP_SEP inside single quotes alone!
     45  *
     46  * This is to allow the following case (and the like) to work correctly:
     47  *	prtitle='standard input'
     48  */
     49 
     50 void
     51 transform_WS_to_SEP(char *cp)
     52 {	char *p;
     53 	int inside_quote = 0;
     54 	int done_one_already = 0;
     55 
     56 	for (p = cp; *p != '\0'; p++) {
     57 		if (*p == '\'') {
     58 			inside_quote = (inside_quote + 1) % 2;
     59 			continue;
     60 		}
     61 		if (inside_quote)
     62 			continue;
     63 		if (*p == ' ') {
     64 			if (!done_one_already) {
     65 				*p = ',';
     66 				done_one_already = 1;
     67 			} else {
     68 				/* multiple LP_WS into one LP_SEP */
     69 			}
     70 		} else {
     71 			done_one_already = 0;
     72 		}
     73 	}
     74 }
     75 
     76 /**
     77  ** pickfilter() - SEE IF WE CAN FIND A FILTER FOR THIS REQUEST
     78  **/
     79 
     80 int
     81 pickfilter(RSTATUS *prs, CANDIDATE *pc, FSTATUS *pfs)
     82 {
     83 	register char **	pp;
     84 	register char **	pl;
     85 
     86 	register PSTATUS *	pps		= pc->pps;
     87 
     88 	char *			pipes[2]	= { 0 , 0 };
     89 	char *			cp;
     90 	char *			output_type;
     91 
     92 	char **			modes		= 0;
     93 	char **			parms		= 0;
     94 	char **			valid_printer_types;
     95 	char **			p_cpi		= 0;
     96 	char **			p_lpi		= 0;
     97 	char **			p_pwid		= 0;
     98 	char **			p_plen		= 0;
     99 
    100 	FILTERTYPE		ret		= fl_none;
    101 
    102 	int			got_cpi		= 0;
    103 	int			got_lpi		= 0;
    104 	int			got_plen	= 0;
    105 	int			got_pwid	= 0;
    106 	int			must_have_filter= 0;
    107 
    108 	unsigned long		chk;
    109 
    110 
    111 	/* fix for bugid 1097387	*/
    112 	output_type = (char *) NULL;
    113 
    114 	/*
    115 	 * The bulk of the code below is building a parameter list "parms"
    116 	 * to send to "insfilter()".
    117 	 */
    118 
    119 	if (prs->request->modes) {
    120 		cp = Strdup(prs->request->modes);
    121 		transform_WS_to_SEP(cp);
    122 		modes = getlist(cp, "", LP_SEP);
    123 		Free (cp);
    124 	}
    125 
    126 	pp = parms = (char **)Malloc(
    127 		2 * (NPARM_SPEC + lenlist(modes) + 1) * sizeof(char *)
    128 	);
    129 
    130 	/*
    131 	 * Add to the parameter list the appropriate cpi/lpi/etc.
    132 	 * characteristics (aka ``stuff'') that will be used for
    133 	 * this job. The printer defaults are questionable.
    134 	 * Take this opportunity to also save the ``stuff'' in
    135 	 * the request structure.
    136 	 */
    137 
    138 	unload_str (&(prs->cpi));
    139 	unload_str (&(prs->lpi));
    140 	unload_str (&(prs->plen));
    141 	unload_str (&(prs->pwid));
    142 
    143 	/*
    144 	 * If a form is involved, pick up its page size and print
    145 	 * spacing requirements.
    146 	 */
    147 	if (pfs) {
    148 		if (pfs->cpi) {
    149 			*pp++ = PARM_CPI;
    150 			*pp++ = prs->cpi = pfs->cpi;
    151 			got_cpi = 1;
    152 		}
    153 		if (pfs->lpi) {
    154 			*pp++ = PARM_LPI;
    155 			*pp++ = prs->lpi = pfs->lpi;
    156 			got_lpi = 1;
    157 		}
    158 		if (pfs->plen) {
    159 			*pp++ = PARM_LENGTH;
    160 			*pp++ = prs->plen = pfs->plen;
    161 			got_plen = 1;
    162 		}
    163 		if (pfs->pwid) {
    164 			*pp++ = PARM_WIDTH;
    165 			*pp++ = prs->pwid = pfs->pwid;
    166 			got_pwid = 1;
    167 		}
    168 
    169 	/*
    170 	 * If no form is involved, pick up whatever page size and print
    171 	 * spacing requirements were given by the user.
    172 	 */
    173 	} else {
    174 		if (o_cpi) {
    175 			*pp++ = PARM_CPI;
    176 			*pp++ = prs->cpi = o_cpi;
    177 			got_cpi = 1;
    178 		}
    179 		if (o_lpi) {
    180 			*pp++ = PARM_LPI;
    181 			*pp++ = prs->lpi = o_lpi;
    182 			got_lpi = 1;
    183 		}
    184 		if (o_length) {
    185 			*pp++ = PARM_LENGTH;
    186 			*pp++ = prs->plen = o_length;
    187 			got_plen = 1;
    188 		}
    189 		if (o_width) {
    190 			*pp++ = PARM_WIDTH;
    191 			*pp++ = prs->pwid = o_width;
    192 			got_pwid = 1;
    193 		}
    194 	}
    195 
    196 	/*
    197 	 * Pick up whatever page size and print spacing requirements
    198 	 * haven't been specified yet from the printer defaults.
    199 	 *
    200 	 * Note: The following cpi/lpi/etc are guaranteed to work
    201 	 * for at least one type of the printer at hand, but not
    202 	 * necessarily all types. Once we pick a type that works
    203 	 * we'll verify that the cpi/lpi/etc stuff works, too.
    204 	 * The code that does that assumes that we do the following last,
    205 	 * after picking up the form and/or user stuff. If this changes,
    206 	 * then the later code will have to be changed, too.
    207 	 */
    208 	if (!got_cpi && pps->cpi) {
    209 		*pp++ = PARM_CPI;
    210 		*(p_cpi = pp++) = prs->cpi = pps->cpi;
    211 	}
    212 	if (!got_lpi && pps->lpi) {
    213 		*pp++ = PARM_LPI;
    214 		*(p_lpi = pp++) = prs->lpi = pps->lpi;
    215 	}
    216 	if (!got_plen && pps->plen) {
    217 		*pp++ = PARM_LENGTH;
    218 		*(p_plen = pp++) = prs->plen = pps->plen;
    219 	}
    220 	if (!got_pwid && pps->pwid) {
    221 		*pp++ = PARM_WIDTH;
    222 		*(p_pwid = pp++) = prs->pwid = pps->pwid;
    223 	}
    224 
    225 	/*
    226 	 * Pick up the number of pages, character set (the form's
    227 	 * or the user's), the form name, the number of copies,
    228 	 * and the modes.
    229 	 */
    230 
    231 	if (prs->request->pages) {
    232 		*pp++ = PARM_PAGES;
    233 		*pp++ = prs->request->pages;
    234 		must_have_filter = 1;
    235 	}
    236 
    237 	if (prs->request->charset) {
    238 		*pp++ = PARM_CHARSET;
    239 		*pp++ = prs->request->charset;
    240 
    241 	} else if (pfs && pfs->form->chset) {
    242 		*pp++ = PARM_CHARSET;
    243 		*pp++ = pfs->form->chset;
    244 	}
    245 
    246 	if (prs->request->form) {
    247 		*pp++ = PARM_FORM;
    248 		*pp++ = prs->request->form;
    249 	}
    250 
    251 	if (prs->request->copies > 1) {
    252 		*pp++ = PARM_COPIES;
    253 		sprintf ((*pp++ = BIGGEST_NUMBER_S), "%d", prs->request->copies);
    254 	}
    255 
    256 	if (modes) {
    257 		for (pl = modes; *pl; pl++) {
    258 			*pp++ = PARM_MODES;
    259 			*pp++ = *pl;
    260 		}
    261 		must_have_filter = 1;
    262 	}
    263 
    264 	*pp = 0;	/* null terminated list! */
    265 
    266 
    267 	/*
    268 	 * If the printer type(s) are not ``unknown'', then include
    269 	 * them as possible ``output'' type(s) to match
    270 	 * with the user's input type (directly, or through a filter).
    271 	 */
    272 	if (!STREQU(*(pps->printer->printer_types), NAME_UNKNOWN))
    273 		valid_printer_types = pc->printer_types;
    274 	else {
    275 		valid_printer_types = 0;
    276 		must_have_filter = 0;
    277 	}
    278 
    279 	pc->fast = 0;
    280 	pc->slow = 0;
    281 	pc->output_type = 0;
    282 	pc->flags = 0;
    283 	ret = fl_none;
    284 
    285 	/*
    286 	 * If we don't really need a filter and the types match,
    287 	 * then that's good enough. Some ``broadly defined''
    288 	 * filters might match our needs, but if the printer
    289 	 * can do what we need, then why pull in a filter?
    290 
    291 
    292 
    293 	 * Besides, Section 3.40 in the requirements imply
    294 	 * that we don't use a filter if the printer can handle
    295 	 * the file.
    296 	 */
    297 	if (!must_have_filter ) {
    298 
    299 		if (
    300 			valid_printer_types
    301 		     && searchlist_with_terminfo(
    302 				prs->request->input_type,
    303 				valid_printer_types
    304 			)
    305 		) {
    306 			ret = fl_both;	/* not really, but ok */
    307 			pc->printer_type = Strdup(prs->request->input_type);
    308 
    309 		} else if (
    310 			pps->printer->input_types
    311 		     && searchlist_with_terminfo(
    312 				prs->request->input_type,
    313 				pps->printer->input_types
    314 			)
    315 		) {
    316 			ret = fl_both;	/* not really, but ok */
    317 
    318 			/*
    319 			 * (1) There is one printer type, might even
    320 			 *     be ``unknown'';
    321 			 * (2) There are several printer types, but that
    322 			 *     means only one input type, ``simple'',
    323 			 *     which any of the printer types can handle.
    324 			 */
    325 			pc->printer_type = Strdup(*(pc->printer_types));
    326 
    327 		}
    328 	}
    329 
    330 	/*
    331 	 * Don't try using a filter if the user doesn't want
    332 	 * a filter to be used! He or she would rather see an
    333 	 * error message than (heaven forbid!) a filter being
    334 	 * used.
    335 	 */
    336 	if (ret == fl_none && !(prs->request->actions & ACT_RAW)) {
    337 
    338 		/*
    339 		 * For each printer type, and each input type the printer
    340 		 * accepts, see if we have a filter that matches the
    341 		 * request to the printer. Each time we try, save the
    342 		 * output type we use in case of success; we just might
    343 		 * need that value later....
    344 		 */
    345 
    346 		for (
    347 			pl = valid_printer_types;
    348 			pl && *pl && ret == fl_none;
    349 			pl++
    350 		)
    351 			ret = insfilter(
    352 				pipes,
    353 				prs->request->input_type,
    354 				(output_type = *pl),
    355 				*pl,
    356 				pps->printer->name,
    357 				parms,
    358 				&(pc->flags)
    359 			);
    360 		if (ret != fl_none)
    361 			pc->printer_type = Strdup(*pl);
    362 
    363 		for (
    364 			pl = pps->printer->input_types;
    365 			pl && *pl && ret == fl_none;
    366 			pl++
    367 		)
    368 			/*
    369 			 * Don't waste time with check we've already made.
    370 			 */
    371 			if ((must_have_filter == 1) ||
    372 				!valid_printer_types
    373 			     || !searchlist(*pl, valid_printer_types)
    374 			)
    375 				/*
    376 				 * Either we have one (or less) printer
    377 				 * types and many input types, or we have
    378 				 * one input type, ``simple''; regardless,
    379 				 * using the first printer type is OK.
    380 				 */
    381 				ret = insfilter(
    382 					pipes,
    383 					prs->request->input_type,
    384 					(output_type = *pl),
    385 					*(pc->printer_types),
    386 					pps->printer->name,
    387 					parms,
    388 					&(pc->flags)
    389 				);
    390 		if (ret != fl_none)
    391 			pc->printer_type = Strdup(*(pc->printer_types));
    392 
    393 	}
    394 
    395 	/*
    396 	 * If we were successful, check that the printer type
    397 	 * we picked can handle the PRINTER'S cpi/lpi/etc. defaults.
    398 	 * (We know that ALL the printer's types can handle the stuff
    399 	 * the user gave or the stuff in the form.)
    400 	 * Each printer's default that doesn't pass muster gets dropped.
    401 	 * This may mean re-instantiating the filter(s) (if any).
    402 	 */
    403 	if (ret != fl_none && (p_cpi || p_lpi || p_pwid || p_plen)) {
    404 
    405 #define	NZ(X)	((X)? *(X) : (char *)0)
    406 		chk = chkprinter(
    407 			pc->printer_type,
    408 			NZ(p_cpi),
    409 			NZ(p_lpi),
    410 			NZ(p_plen),
    411 			NZ(p_pwid),
    412 			(char *)0
    413 		);
    414 
    415 		if (chk) {
    416 			register char **	_pp;
    417 
    418 			char *			hole	= "";
    419 
    420 
    421 			/*
    422 			 * Remove the offending printer defaults from the
    423 			 * request list of cpi/lpi/etc. stuff, and punch
    424 			 * (non-null!) holes in the parameter list.
    425 			 */
    426 #define DROP(P,R)	if (P) {P[-1] = P[0] = hole; R = 0;} else/*EMPTY*/
    427 			if (chk & PCK_CPI)	DROP (p_cpi, prs->cpi);
    428 			if (chk & PCK_LPI)	DROP (p_lpi, prs->lpi);
    429 			if (chk & PCK_WIDTH)	DROP (p_pwid, prs->pwid);
    430 			if (chk & PCK_LENGTH)	DROP (p_plen, prs->plen);
    431 
    432 			/*
    433 			 * If there are filters, we have to re-instantiate
    434 			 * them. (Can't check "ret" here, because it may
    435 			 * be misleading.)
    436 			 */
    437 			if (pipes[0] || pipes[1]) {
    438 
    439 				/*
    440 				 * First, close up the gaps we punched in
    441 				 * the parameter list.
    442 				 */
    443 				for (pp = _pp = parms; *pp; pp++)
    444 					if (*pp != hole)
    445 						*_pp++ = *pp;
    446 				*_pp = 0;
    447 
    448 				/*
    449 				 * Re-instantiate the filter(s). This
    450 				 * CAN'T fail, because it is not mandatory
    451 				 * that filters handle cpi/lpi/etc. stuff.
    452 				 */
    453 				ret = insfilter(
    454 					pipes,
    455 					prs->request->input_type,
    456 					output_type,
    457 					pc->printer_type,
    458 					pps->printer->name,
    459 					parms,
    460 					&(pc->flags)
    461 				);
    462 			}
    463 		}
    464 	}
    465 
    466 	/*
    467 	 * Save the filters, if any. Note: although "ret" can be
    468 	 * misleading, i.e. set to "fl_both" when there really aren't
    469 	 * any filters, the declaration of "pipes" ensured they'd be
    470 	 * zero if not set.
    471 	 */
    472 	if (ret == fl_both || ret == fl_slow)
    473 		pc->slow = pipes[0];
    474 	if (ret == fl_both || ret == fl_fast)
    475 		pc->fast = pipes[1];
    476 
    477 	if (ret != fl_none)
    478 		pc->output_type = Strdup (output_type);
    479 
    480 	/*
    481 	 * Wait until now to allocate storage for the cpi/etc.
    482 	 * stuff, to make life easier above.
    483 	 */
    484 	if (prs->cpi)	prs->cpi = Strdup(prs->cpi);
    485 	if (prs->lpi)	prs->lpi = Strdup(prs->lpi);
    486 	if (prs->plen)	prs->plen = Strdup(prs->plen);
    487 	if (prs->pwid)	prs->pwid = Strdup(prs->pwid);
    488 
    489 
    490 	if (parms)
    491 		Free ((char *)parms);
    492 	if (modes)
    493 		freelist (modes);
    494 
    495 	return ((ret != fl_none));
    496 }
    497