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