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