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