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