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
transform_WS_to_SEP(char * cp)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
pickfilter(RSTATUS * prs,CANDIDATE * pc,FSTATUS * pfs)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