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