]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/dest-options.c
Add code signing for macOS Mojave.
[thirdparty/cups.git] / cups / dest-options.c
CommitLineData
dcb445bc 1/*
7e86f2f6 2 * Destination option/media support for CUPS.
dcb445bc 3 *
22974c5f 4 * Copyright © 2012-2018 by Apple Inc.
dcb445bc 5 *
22974c5f
MS
6 * Licensed under Apache License v2.0. See the file "LICENSE" for more
7 * information.
dcb445bc
MS
8 */
9
10/*
11 * Include necessary headers...
12 */
13
14#include "cups-private.h"
15
16
6961465f
MS
17/*
18 * Local constants...
19 */
20
21#define _CUPS_MEDIA_READY_TTL 30 /* Life of xxx-ready values */
22
23
dcb445bc
MS
24/*
25 * Local functions...
26 */
27
a29fd7dd 28static void cups_add_dconstres(cups_array_t *a, ipp_t *collection);
336b669e
MS
29static int cups_collection_contains(ipp_t *test, ipp_t *match);
30static size_t cups_collection_string(ipp_attribute_t *attr, char *buffer, size_t bufsize);
a29fd7dd
MS
31static int cups_compare_dconstres(_cups_dconstres_t *a,
32 _cups_dconstres_t *b);
dcb445bc
MS
33static int cups_compare_media_db(_cups_media_db_t *a,
34 _cups_media_db_t *b);
35static _cups_media_db_t *cups_copy_media_db(_cups_media_db_t *mdb);
6961465f
MS
36static void cups_create_cached(http_t *http, cups_dinfo_t *dinfo,
37 unsigned flags);
a29fd7dd
MS
38static void cups_create_constraints(cups_dinfo_t *dinfo);
39static void cups_create_defaults(cups_dinfo_t *dinfo);
6961465f
MS
40static void cups_create_media_db(cups_dinfo_t *dinfo,
41 unsigned flags);
dcb445bc 42static void cups_free_media_db(_cups_media_db_t *mdb);
6961465f
MS
43static int cups_get_media_db(http_t *http, cups_dinfo_t *dinfo,
44 pwg_media_t *pwg, unsigned flags,
dcb445bc
MS
45 cups_size_t *size);
46static int cups_is_close_media_db(_cups_media_db_t *a,
47 _cups_media_db_t *b);
a29fd7dd
MS
48static cups_array_t *cups_test_constraints(cups_dinfo_t *dinfo,
49 const char *new_option,
50 const char *new_value,
51 int num_options,
52 cups_option_t *options,
53 int *num_conflicts,
54 cups_option_t **conflicts);
6961465f 55static void cups_update_ready(http_t *http, cups_dinfo_t *dinfo);
a29fd7dd 56
dcb445bc 57
71dc43af
MS
58/*
59 * 'cupsAddDestMediaOptions()' - Add the option corresponding to the specified media size.
60 *
61 * @since CUPS 2.3@
62 */
63
64int /* O - New number of options */
65cupsAddDestMediaOptions(
66 http_t *http, /* I - Connection to destination */
67 cups_dest_t *dest, /* I - Destination */
68 cups_dinfo_t *dinfo, /* I - Destination information */
69 unsigned flags, /* I - Media matching flags */
70 cups_size_t *size, /* I - Media size */
71 int num_options, /* I - Current number of options */
72 cups_option_t **options) /* IO - Options */
73{
74 cups_array_t *db; /* Media database */
75 _cups_media_db_t *mdb; /* Media database entry */
76 char value[2048]; /* Option value */
77
78
79 /*
80 * Range check input...
81 */
82
83 if (!http || !dest || !dinfo || !size || !options)
84 {
85 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
86 return (num_options);
87 }
88
89 /*
90 * Find the matching media size...
91 */
92
93 if (flags & CUPS_MEDIA_FLAGS_READY)
94 db = dinfo->ready_db;
95 else
96 db = dinfo->media_db;
97
98 DEBUG_printf(("1cupsAddDestMediaOptions: size->media=\"%s\"", size->media));
99
100 for (mdb = (_cups_media_db_t *)cupsArrayFirst(db); mdb; mdb = (_cups_media_db_t *)cupsArrayNext(db))
101 {
102 if (mdb->key && !strcmp(mdb->key, size->media))
103 break;
104 else if (mdb->size_name && !strcmp(mdb->size_name, size->media))
105 break;
106 }
107
108 if (!mdb)
109 {
110 for (mdb = (_cups_media_db_t *)cupsArrayFirst(db); mdb; mdb = (_cups_media_db_t *)cupsArrayNext(db))
111 {
112 if (mdb->width == size->width && mdb->length == size->length && mdb->bottom == size->bottom && mdb->left == size->left && mdb->right == size->right && mdb->top == size->top)
113 break;
114 }
115 }
116
117 if (!mdb)
118 {
119 for (mdb = (_cups_media_db_t *)cupsArrayFirst(db); mdb; mdb = (_cups_media_db_t *)cupsArrayNext(db))
120 {
121 if (mdb->width == size->width && mdb->length == size->length)
122 break;
123 }
124 }
125
126 if (!mdb)
127 {
128 DEBUG_puts("1cupsAddDestMediaOptions: Unable to find matching size.");
129 return (num_options);
130 }
131
132 DEBUG_printf(("1cupsAddDestMediaOptions: MATCH mdb%p [key=\"%s\" size_name=\"%s\" source=\"%s\" type=\"%s\" width=%d length=%d B%d L%d R%d T%d]", (void *)mdb, mdb->key, mdb->size_name, mdb->source, mdb->type, mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top));
133
134 if (mdb->source)
135 {
136 if (mdb->type)
137 snprintf(value, sizeof(value), "{media-size={x-dimension=%d y-dimension=%d} media-bottom-margin=%d media-left-margin=%d media-right-margin=%d media-top-margin=%d media-source=\"%s\" media-type=\"%s\"}", mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top, mdb->source, mdb->type);
138 else
139 snprintf(value, sizeof(value), "{media-size={x-dimension=%d y-dimension=%d} media-bottom-margin=%d media-left-margin=%d media-right-margin=%d media-top-margin=%d media-source=\"%s\"}", mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top, mdb->source);
140 }
141 else if (mdb->type)
142 {
143 snprintf(value, sizeof(value), "{media-size={x-dimension=%d y-dimension=%d} media-bottom-margin=%d media-left-margin=%d media-right-margin=%d media-top-margin=%d media-type=\"%s\"}", mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top, mdb->type);
144 }
145 else
146 {
147 snprintf(value, sizeof(value), "{media-size={x-dimension=%d y-dimension=%d} media-bottom-margin=%d media-left-margin=%d media-right-margin=%d media-top-margin=%d}", mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top);
148 }
149
150 num_options = cupsAddOption("media-col", value, num_options, options);
151
152 return (num_options);
153}
154
155
dcb445bc
MS
156/*
157 * 'cupsCheckDestSupported()' - Check that the option and value are supported
158 * by the destination.
159 *
160 * Returns 1 if supported, 0 otherwise.
161 *
8072030b 162 * @since CUPS 1.6/macOS 10.8@
dcb445bc
MS
163 */
164
165int /* O - 1 if supported, 0 otherwise */
166cupsCheckDestSupported(
167 http_t *http, /* I - Connection to destination */
168 cups_dest_t *dest, /* I - Destination */
169 cups_dinfo_t *dinfo, /* I - Destination information */
170 const char *option, /* I - Option */
49b6c6af 171 const char *value) /* I - Value or @code NULL@ */
dcb445bc
MS
172{
173 int i; /* Looping var */
174 char temp[1024]; /* Temporary string */
175 int int_value; /* Integer value */
176 int xres_value, /* Horizontal resolution */
177 yres_value; /* Vertical resolution */
178 ipp_res_t units_value; /* Resolution units */
179 ipp_attribute_t *attr; /* Attribute */
180 _ipp_value_t *attrval; /* Current attribute value */
181
182
7536de1a
MS
183 /*
184 * Get the default connection as needed...
185 */
186
187 if (!http)
188 http = _cupsConnect();
189
dcb445bc
MS
190 /*
191 * Range check input...
192 */
193
49b6c6af 194 if (!http || !dest || !dinfo || !option)
dcb445bc
MS
195 return (0);
196
197 /*
198 * Lookup the attribute...
199 */
200
201 if (strstr(option, "-supported"))
202 attr = ippFindAttribute(dinfo->attrs, option, IPP_TAG_ZERO);
203 else
204 {
205 snprintf(temp, sizeof(temp), "%s-supported", option);
206 attr = ippFindAttribute(dinfo->attrs, temp, IPP_TAG_ZERO);
207 }
208
209 if (!attr)
210 return (0);
211
49b6c6af
MS
212 if (!value)
213 return (1);
214
215/*
dcb445bc
MS
216 * Compare values...
217 */
218
219 if (!strcmp(option, "media") && !strncmp(value, "custom_", 7))
220 {
221 /*
222 * Check range of custom media sizes...
223 */
224
6961465f 225 pwg_media_t *pwg; /* Current PWG media size info */
982be458
MS
226 int min_width, /* Minimum width */
227 min_length, /* Minimum length */
228 max_width, /* Maximum width */
229 max_length; /* Maximum length */
dcb445bc
MS
230
231 /*
232 * Get the minimum and maximum size...
233 */
234
235 min_width = min_length = INT_MAX;
236 max_width = max_length = 0;
237
238 for (i = attr->num_values, attrval = attr->values;
239 i > 0;
240 i --, attrval ++)
241 {
242 if (!strncmp(attrval->string.text, "custom_min_", 11) &&
6961465f 243 (pwg = pwgMediaForPWG(attrval->string.text)) != NULL)
dcb445bc
MS
244 {
245 min_width = pwg->width;
246 min_length = pwg->length;
247 }
248 else if (!strncmp(attrval->string.text, "custom_max_", 11) &&
6961465f 249 (pwg = pwgMediaForPWG(attrval->string.text)) != NULL)
dcb445bc
MS
250 {
251 max_width = pwg->width;
252 max_length = pwg->length;
253 }
254 }
255
256 /*
257 * Check the range...
258 */
259
260 if (min_width < INT_MAX && max_width > 0 &&
6961465f 261 (pwg = pwgMediaForPWG(value)) != NULL &&
dcb445bc
MS
262 pwg->width >= min_width && pwg->width <= max_width &&
263 pwg->length >= min_length && pwg->length <= max_length)
264 return (1);
265 }
266 else
267 {
268 /*
269 * Check literal values...
270 */
271
272 switch (attr->value_tag)
273 {
274 case IPP_TAG_INTEGER :
275 case IPP_TAG_ENUM :
276 int_value = atoi(value);
277
278 for (i = 0; i < attr->num_values; i ++)
279 if (attr->values[i].integer == int_value)
280 return (1);
281 break;
282
283 case IPP_TAG_BOOLEAN :
284 return (attr->values[0].boolean);
285
a29fd7dd
MS
286 case IPP_TAG_RANGE :
287 int_value = atoi(value);
288
289 for (i = 0; i < attr->num_values; i ++)
290 if (int_value >= attr->values[i].range.lower &&
291 int_value <= attr->values[i].range.upper)
292 return (1);
293 break;
294
dcb445bc
MS
295 case IPP_TAG_RESOLUTION :
296 if (sscanf(value, "%dx%d%15s", &xres_value, &yres_value, temp) != 3)
297 {
298 if (sscanf(value, "%d%15s", &xres_value, temp) != 2)
299 return (0);
300
301 yres_value = xres_value;
302 }
303
304 if (!strcmp(temp, "dpi"))
305 units_value = IPP_RES_PER_INCH;
3e7fe0ca 306 else if (!strcmp(temp, "dpc") || !strcmp(temp, "dpcm"))
dcb445bc
MS
307 units_value = IPP_RES_PER_CM;
308 else
309 return (0);
310
311 for (i = attr->num_values, attrval = attr->values;
312 i > 0;
313 i --, attrval ++)
314 {
315 if (attrval->resolution.xres == xres_value &&
316 attrval->resolution.yres == yres_value &&
317 attrval->resolution.units == units_value)
318 return (1);
319 }
320 break;
321
322 case IPP_TAG_TEXT :
323 case IPP_TAG_NAME :
324 case IPP_TAG_KEYWORD :
325 case IPP_TAG_CHARSET :
326 case IPP_TAG_URI :
327 case IPP_TAG_URISCHEME :
328 case IPP_TAG_MIMETYPE :
329 case IPP_TAG_LANGUAGE :
330 case IPP_TAG_TEXTLANG :
331 case IPP_TAG_NAMELANG :
332 for (i = 0; i < attr->num_values; i ++)
333 if (!strcmp(attr->values[i].string.text, value))
334 return (1);
335 break;
336
337 default :
338 break;
339 }
340 }
341
342 /*
343 * If we get there the option+value is not supported...
344 */
345
346 return (0);
347}
348
349
350/*
351 * 'cupsCopyDestConflicts()' - Get conflicts and resolutions for a new
352 * option/value pair.
353 *
354 * "num_options" and "options" represent the currently selected options by the
355 * user. "new_option" and "new_value" are the setting the user has just
356 * changed.
357 *
a29fd7dd
MS
358 * Returns 1 if there is a conflict, 0 if there are no conflicts, and -1 if
359 * there was an unrecoverable error such as a resolver loop.
dcb445bc 360 *
5a9febac
MS
361 * If "num_conflicts" and "conflicts" are not @code NULL@, they are set to
362 * contain the list of conflicting option/value pairs. Similarly, if
363 * "num_resolved" and "resolved" are not @code NULL@ they will be set to the
364 * list of changes needed to resolve the conflict.
dcb445bc
MS
365 *
366 * If cupsCopyDestConflicts returns 1 but "num_resolved" and "resolved" are set
5a9febac 367 * to 0 and @code NULL@, respectively, then the conflict cannot be resolved.
dcb445bc 368 *
8072030b 369 * @since CUPS 1.6/macOS 10.8@
dcb445bc
MS
370 */
371
a29fd7dd 372int /* O - 1 if there is a conflict, 0 if none, -1 on error */
dcb445bc
MS
373cupsCopyDestConflicts(
374 http_t *http, /* I - Connection to destination */
375 cups_dest_t *dest, /* I - Destination */
376 cups_dinfo_t *dinfo, /* I - Destination information */
377 int num_options, /* I - Number of current options */
378 cups_option_t *options, /* I - Current options */
379 const char *new_option, /* I - New option */
380 const char *new_value, /* I - New value */
381 int *num_conflicts, /* O - Number of conflicting options */
382 cups_option_t **conflicts, /* O - Conflicting options */
383 int *num_resolved, /* O - Number of options to resolve */
384 cups_option_t **resolved) /* O - Resolved options */
385{
a29fd7dd
MS
386 int i, /* Looping var */
387 have_conflicts = 0, /* Do we have conflicts? */
388 changed, /* Did we change something? */
389 tries, /* Number of tries for resolution */
390 num_myconf = 0, /* My number of conflicting options */
391 num_myres = 0; /* My number of resolved options */
392 cups_option_t *myconf = NULL, /* My conflicting options */
393 *myres = NULL, /* My resolved options */
394 *myoption, /* My current option */
395 *option; /* Current option */
7e86f2f6 396 cups_array_t *active = NULL, /* Active conflicts */
a29fd7dd
MS
397 *pass = NULL, /* Resolvers for this pass */
398 *resolvers = NULL, /* Resolvers we have used */
399 *test; /* Test array for conflicts */
400 _cups_dconstres_t *c, /* Current constraint */
401 *r; /* Current resolver */
402 ipp_attribute_t *attr; /* Current attribute */
403 char value[2048]; /* Current attribute value as string */
404 const char *myvalue; /* Current value of an option */
405
406
dcb445bc
MS
407 /*
408 * Clear returned values...
409 */
410
411 if (num_conflicts)
412 *num_conflicts = 0;
413
414 if (conflicts)
415 *conflicts = NULL;
416
417 if (num_resolved)
418 *num_resolved = 0;
419
420 if (resolved)
421 *resolved = NULL;
422
7536de1a
MS
423 /*
424 * Get the default connection as needed...
425 */
426
427 if (!http)
428 http = _cupsConnect();
429
dcb445bc
MS
430 /*
431 * Range check input...
432 */
433
a29fd7dd 434 if (!http || !dest || !dinfo ||
dcb445bc
MS
435 (num_conflicts != NULL) != (conflicts != NULL) ||
436 (num_resolved != NULL) != (resolved != NULL))
437 return (0);
438
439 /*
a29fd7dd 440 * Load constraints as needed...
dcb445bc
MS
441 */
442
a29fd7dd
MS
443 if (!dinfo->constraints)
444 cups_create_constraints(dinfo);
dcb445bc 445
a29fd7dd
MS
446 if (cupsArrayCount(dinfo->constraints) == 0)
447 return (0);
448
449 if (!dinfo->num_defaults)
450 cups_create_defaults(dinfo);
451
452 /*
453 * If we are resolving, create a shadow array...
454 */
455
456 if (num_resolved)
457 {
458 for (i = num_options, option = options; i > 0; i --, option ++)
459 num_myres = cupsAddOption(option->name, option->value, num_myres, &myres);
460
461 if (new_option && new_value)
462 num_myres = cupsAddOption(new_option, new_value, num_myres, &myres);
463 }
464 else
465 {
466 num_myres = num_options;
467 myres = options;
468 }
469
470 /*
471 * Check for any conflicts...
472 */
473
474 if (num_resolved)
475 pass = cupsArrayNew((cups_array_func_t)cups_compare_dconstres, NULL);
476
477 for (tries = 0; tries < 100; tries ++)
478 {
479 /*
480 * Check for any conflicts...
481 */
482
483 if (num_conflicts || num_resolved)
484 {
485 cupsFreeOptions(num_myconf, myconf);
486
487 num_myconf = 0;
488 myconf = NULL;
489 active = cups_test_constraints(dinfo, new_option, new_value,
490 num_myres, myres, &num_myconf,
491 &myconf);
492 }
493 else
494 active = cups_test_constraints(dinfo, new_option, new_value, num_myres,
495 myres, NULL, NULL);
496
497 have_conflicts = (active != NULL);
498
499 if (!active || !num_resolved)
500 break; /* All done */
501
502 /*
503 * Scan the constraints that were triggered to apply resolvers...
504 */
505
506 if (!resolvers)
507 resolvers = cupsArrayNew((cups_array_func_t)cups_compare_dconstres, NULL);
508
509 for (c = (_cups_dconstres_t *)cupsArrayFirst(active), changed = 0;
510 c;
511 c = (_cups_dconstres_t *)cupsArrayNext(active))
512 {
513 if (cupsArrayFind(pass, c))
514 continue; /* Already applied this resolver... */
515
516 if (cupsArrayFind(resolvers, c))
517 {
518 DEBUG_printf(("1cupsCopyDestConflicts: Resolver loop with %s.",
519 c->name));
520 have_conflicts = -1;
521 goto cleanup;
522 }
523
524 if ((r = cupsArrayFind(dinfo->resolvers, c)) == NULL)
525 {
526 DEBUG_printf(("1cupsCopyDestConflicts: Resolver %s not found.",
527 c->name));
528 have_conflicts = -1;
529 goto cleanup;
530 }
531
532 /*
533 * Add the options from the resolver...
534 */
535
536 cupsArrayAdd(pass, r);
537 cupsArrayAdd(resolvers, r);
538
539 for (attr = ippFirstAttribute(r->collection);
540 attr;
541 attr = ippNextAttribute(r->collection))
542 {
543 if (new_option && !strcmp(attr->name, new_option))
544 continue; /* Ignore this if we just changed it */
545
546 if (ippAttributeString(attr, value, sizeof(value)) >= sizeof(value))
547 continue; /* Ignore if the value is too long */
548
549 if ((test = cups_test_constraints(dinfo, attr->name, value, num_myres,
550 myres, NULL, NULL)) == NULL)
551 {
552 /*
553 * That worked, flag it...
554 */
555
556 changed = 1;
557 }
558 else
559 cupsArrayDelete(test);
560
561 /*
562 * Add the option/value from the resolver regardless of whether it
563 * worked; this makes sure that we can cascade several changes to
564 * make things resolve...
565 */
566
567 num_myres = cupsAddOption(attr->name, value, num_myres, &myres);
568 }
569 }
570
571 if (!changed)
572 {
573 DEBUG_puts("1cupsCopyDestConflicts: Unable to resolve constraints.");
574 have_conflicts = -1;
575 goto cleanup;
576 }
577
578 cupsArrayClear(pass);
579
580 cupsArrayDelete(active);
581 active = NULL;
582 }
583
0fa6c7fa 584 if (tries >= 100)
a29fd7dd
MS
585 {
586 DEBUG_puts("1cupsCopyDestConflicts: Unable to resolve after 100 tries.");
587 have_conflicts = -1;
588 goto cleanup;
589 }
590
591 /*
592 * Copy resolved options as needed...
593 */
594
595 if (num_resolved)
596 {
597 for (i = num_myres, myoption = myres; i > 0; i --, myoption ++)
598 {
599 if ((myvalue = cupsGetOption(myoption->name, num_options,
600 options)) == NULL ||
601 strcmp(myvalue, myoption->value))
602 {
603 if (new_option && !strcmp(new_option, myoption->name) &&
604 new_value && !strcmp(new_value, myoption->value))
605 continue;
606
607 *num_resolved = cupsAddOption(myoption->name, myoption->value,
608 *num_resolved, resolved);
609 }
610 }
611 }
612
613 /*
614 * Clean up...
615 */
616
617 cleanup:
618
619 cupsArrayDelete(active);
620 cupsArrayDelete(pass);
621 cupsArrayDelete(resolvers);
622
623 if (num_resolved)
624 {
625 /*
626 * Free shadow copy of options...
627 */
628
629 cupsFreeOptions(num_myres, myres);
630 }
631
632 if (num_conflicts)
633 {
634 /*
635 * Return conflicting options to caller...
636 */
637
638 *num_conflicts = num_myconf;
639 *conflicts = myconf;
640 }
641 else
642 {
643 /*
644 * Free conflicting options...
645 */
646
647 cupsFreeOptions(num_myconf, myconf);
648 }
649
650 return (have_conflicts);
dcb445bc
MS
651}
652
653
654/*
655 * 'cupsCopyDestInfo()' - Get the supported values/capabilities for the
656 * destination.
657 *
658 * The caller is responsible for calling @link cupsFreeDestInfo@ on the return
659 * value. @code NULL@ is returned on error.
660 *
8072030b 661 * @since CUPS 1.6/macOS 10.8@
dcb445bc
MS
662 */
663
664cups_dinfo_t * /* O - Destination information */
665cupsCopyDestInfo(
666 http_t *http, /* I - Connection to destination */
667 cups_dest_t *dest) /* I - Destination */
668{
669 cups_dinfo_t *dinfo; /* Destination information */
b969d5af 670 unsigned dflags; /* Destination flags */
dcb445bc
MS
671 ipp_t *request, /* Get-Printer-Attributes request */
672 *response; /* Supported attributes */
a29fd7dd
MS
673 int tries, /* Number of tries so far */
674 delay, /* Current retry delay */
675 prev_delay; /* Next retry delay */
dcb445bc
MS
676 const char *uri; /* Printer URI */
677 char resource[1024]; /* Resource path */
678 int version; /* IPP version */
679 ipp_status_t status; /* Status of request */
b969d5af 680 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */
dcb445bc
MS
681 static const char * const requested_attrs[] =
682 { /* Requested attributes */
683 "job-template",
684 "media-col-database",
685 "printer-description"
686 };
687
688
b969d5af 689 DEBUG_printf(("cupsCopyDestInfo(http=%p, dest=%p(%s))", (void *)http, (void *)dest, dest ? dest->name : ""));
dcb445bc 690
7536de1a
MS
691 /*
692 * Get the default connection as needed...
693 */
694
695 if (!http)
b969d5af 696 {
22974c5f 697 DEBUG_puts("1cupsCopyDestInfo: Default server connection.");
b969d5af
MS
698 http = _cupsConnect();
699 dflags = CUPS_DEST_FLAGS_NONE;
700 }
701#ifdef AF_LOCAL
22974c5f
MS
702 else if (httpAddrFamily(http->hostaddr) == AF_LOCAL)
703 {
704 DEBUG_puts("1cupsCopyDestInfo: Connection to server (domain socket).");
705 dflags = CUPS_DEST_FLAGS_NONE;
706 }
b969d5af 707#endif /* AF_LOCAL */
22974c5f
MS
708 else if ((strcmp(http->hostname, cg->server) && cg->server[0] != '/') || cg->ipp_port != httpAddrPort(http->hostaddr))
709 {
710 DEBUG_printf(("1cupsCopyDestInfo: Connection to device (%s).", http->hostname));
b969d5af 711 dflags = CUPS_DEST_FLAGS_DEVICE;
22974c5f 712 }
b969d5af 713 else
22974c5f
MS
714 {
715 DEBUG_printf(("1cupsCopyDestInfo: Connection to server (%s).", http->hostname));
b969d5af 716 dflags = CUPS_DEST_FLAGS_NONE;
22974c5f 717 }
7536de1a 718
dcb445bc
MS
719 /*
720 * Range check input...
721 */
722
723 if (!http || !dest)
724 return (NULL);
725
726 /*
727 * Get the printer URI and resource path...
728 */
729
b969d5af
MS
730 if ((uri = _cupsGetDestResource(dest, dflags, resource, sizeof(resource))) == NULL)
731 {
732 DEBUG_puts("1cupsCopyDestInfo: Unable to get resource.");
dcb445bc 733 return (NULL);
b969d5af 734 }
dcb445bc
MS
735
736 /*
737 * Get the supported attributes...
738 */
739
a29fd7dd
MS
740 delay = 1;
741 prev_delay = 1;
742 tries = 0;
743 version = 20;
dcb445bc
MS
744
745 do
746 {
747 /*
748 * Send a Get-Printer-Attributes request...
749 */
750
cb7f98ee 751 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
6a3d63e6
MS
752
753 ippSetVersion(request, version / 10, version % 10);
b969d5af
MS
754 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
755 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser());
756 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(requested_attrs) / sizeof(requested_attrs[0])), NULL, requested_attrs);
dcb445bc
MS
757 response = cupsDoRequest(http, request, resource);
758 status = cupsLastError();
759
cb7f98ee 760 if (status > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED)
dcb445bc 761 {
b969d5af 762 DEBUG_printf(("1cupsCopyDestInfo: Get-Printer-Attributes for '%s' returned %s (%s)", dest->name, ippErrorString(status), cupsLastErrorString()));
dcb445bc
MS
763
764 ippDelete(response);
765 response = NULL;
766
b969d5af
MS
767 if ((status == IPP_STATUS_ERROR_BAD_REQUEST || status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED) && version > 11)
768 {
dcb445bc 769 version = 11;
b969d5af 770 }
cb7f98ee 771 else if (status == IPP_STATUS_ERROR_BUSY)
a29fd7dd 772 {
7e86f2f6 773 sleep((unsigned)delay);
a29fd7dd
MS
774
775 delay = _cupsNextDelay(delay, &prev_delay);
776 }
dcb445bc
MS
777 else
778 return (NULL);
779 }
a29fd7dd
MS
780
781 tries ++;
dcb445bc 782 }
a29fd7dd
MS
783 while (!response && tries < 10);
784
785 if (!response)
b969d5af
MS
786 {
787 DEBUG_puts("1cupsCopyDestInfo: Unable to get printer attributes.");
a29fd7dd 788 return (NULL);
b969d5af 789 }
dcb445bc
MS
790
791 /*
792 * Allocate a cups_dinfo_t structure and return it...
793 */
794
795 if ((dinfo = calloc(1, sizeof(cups_dinfo_t))) == NULL)
796 {
cb7f98ee 797 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
dcb445bc
MS
798 ippDelete(response);
799 return (NULL);
800 }
801
b969d5af
MS
802 DEBUG_printf(("1cupsCopyDestInfo: version=%d, uri=\"%s\", resource=\"%s\".", version, uri, resource));
803
6961465f 804 dinfo->version = version;
dcb445bc
MS
805 dinfo->uri = uri;
806 dinfo->resource = _cupsStrAlloc(resource);
807 dinfo->attrs = response;
808
809 return (dinfo);
810}
811
812
6961465f
MS
813/*
814 * 'cupsFindDestDefault()' - Find the default value(s) for the given option.
815 *
816 * The returned value is an IPP attribute. Use the @code ippGetBoolean@,
817 * @code ippGetCollection@, @code ippGetCount@, @code ippGetDate@,
818 * @code ippGetInteger@, @code ippGetOctetString@, @code ippGetRange@,
819 * @code ippGetResolution@, @code ippGetString@, and @code ippGetValueTag@
820 * functions to inspect the default value(s) as needed.
821 *
8072030b 822 * @since CUPS 1.7/macOS 10.9@
6961465f
MS
823 */
824
825ipp_attribute_t * /* O - Default attribute or @code NULL@ for none */
826cupsFindDestDefault(
827 http_t *http, /* I - Connection to destination */
828 cups_dest_t *dest, /* I - Destination */
829 cups_dinfo_t *dinfo, /* I - Destination information */
830 const char *option) /* I - Option/attribute name */
831{
832 char name[IPP_MAX_NAME]; /* Attribute name */
833
834
7536de1a
MS
835 /*
836 * Get the default connection as needed...
837 */
838
839 if (!http)
840 http = _cupsConnect();
841
6961465f
MS
842 /*
843 * Range check input...
844 */
845
846 if (!http || !dest || !dinfo || !option)
847 {
848 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
849 return (NULL);
850 }
851
852 /*
853 * Find and return the attribute...
854 */
855
856 snprintf(name, sizeof(name), "%s-default", option);
857 return (ippFindAttribute(dinfo->attrs, name, IPP_TAG_ZERO));
858}
859
46385a1a 860
6961465f
MS
861/*
862 * 'cupsFindDestReady()' - Find the default value(s) for the given option.
863 *
864 * The returned value is an IPP attribute. Use the @code ippGetBoolean@,
865 * @code ippGetCollection@, @code ippGetCount@, @code ippGetDate@,
866 * @code ippGetInteger@, @code ippGetOctetString@, @code ippGetRange@,
867 * @code ippGetResolution@, @code ippGetString@, and @code ippGetValueTag@
868 * functions to inspect the default value(s) as needed.
869 *
8072030b 870 * @since CUPS 1.7/macOS 10.9@
6961465f
MS
871 */
872
873ipp_attribute_t * /* O - Default attribute or @code NULL@ for none */
874cupsFindDestReady(
875 http_t *http, /* I - Connection to destination */
876 cups_dest_t *dest, /* I - Destination */
877 cups_dinfo_t *dinfo, /* I - Destination information */
878 const char *option) /* I - Option/attribute name */
879{
880 char name[IPP_MAX_NAME]; /* Attribute name */
881
882
7536de1a
MS
883 /*
884 * Get the default connection as needed...
885 */
886
887 if (!http)
888 http = _cupsConnect();
889
6961465f
MS
890 /*
891 * Range check input...
892 */
893
894 if (!http || !dest || !dinfo || !option)
895 {
896 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
897 return (NULL);
898 }
899
900 /*
901 * Find and return the attribute...
902 */
903
904 cups_update_ready(http, dinfo);
905
906 snprintf(name, sizeof(name), "%s-ready", option);
907 return (ippFindAttribute(dinfo->ready_attrs, name, IPP_TAG_ZERO));
908}
909
46385a1a 910
6961465f
MS
911/*
912 * 'cupsFindDestSupported()' - Find the default value(s) for the given option.
913 *
914 * The returned value is an IPP attribute. Use the @code ippGetBoolean@,
915 * @code ippGetCollection@, @code ippGetCount@, @code ippGetDate@,
916 * @code ippGetInteger@, @code ippGetOctetString@, @code ippGetRange@,
917 * @code ippGetResolution@, @code ippGetString@, and @code ippGetValueTag@
918 * functions to inspect the default value(s) as needed.
919 *
8072030b 920 * @since CUPS 1.7/macOS 10.9@
6961465f
MS
921 */
922
923ipp_attribute_t * /* O - Default attribute or @code NULL@ for none */
924cupsFindDestSupported(
925 http_t *http, /* I - Connection to destination */
926 cups_dest_t *dest, /* I - Destination */
927 cups_dinfo_t *dinfo, /* I - Destination information */
928 const char *option) /* I - Option/attribute name */
929{
930 char name[IPP_MAX_NAME]; /* Attribute name */
931
932
7536de1a
MS
933 /*
934 * Get the default connection as needed...
935 */
936
937 if (!http)
938 http = _cupsConnect();
939
6961465f
MS
940 /*
941 * Range check input...
942 */
943
944 if (!http || !dest || !dinfo || !option)
945 {
946 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
947 return (NULL);
948 }
949
950 /*
951 * Find and return the attribute...
952 */
953
954 snprintf(name, sizeof(name), "%s-supported", option);
955 return (ippFindAttribute(dinfo->attrs, name, IPP_TAG_ZERO));
956}
957
958
dcb445bc
MS
959/*
960 * 'cupsFreeDestInfo()' - Free destination information obtained using
961 * @link cupsCopyDestInfo@.
98d88c8d
MS
962 *
963 * @since CUPS 1.6/macOS 10.8@
dcb445bc
MS
964 */
965
966void
967cupsFreeDestInfo(cups_dinfo_t *dinfo) /* I - Destination information */
968{
969 /*
970 * Range check input...
971 */
972
973 if (!dinfo)
974 return;
975
976 /*
977 * Free memory and return...
978 */
979
980 _cupsStrFree(dinfo->resource);
981
dcb445bc 982 cupsArrayDelete(dinfo->constraints);
a29fd7dd 983 cupsArrayDelete(dinfo->resolvers);
dcb445bc
MS
984
985 cupsArrayDelete(dinfo->localizations);
986
987 cupsArrayDelete(dinfo->media_db);
988
6961465f
MS
989 cupsArrayDelete(dinfo->cached_db);
990
991 ippDelete(dinfo->ready_attrs);
992 cupsArrayDelete(dinfo->ready_db);
993
a29fd7dd
MS
994 ippDelete(dinfo->attrs);
995
dcb445bc
MS
996 free(dinfo);
997}
998
999
6961465f
MS
1000/*
1001 * 'cupsGetDestMediaByIndex()' - Get a media name, dimension, and margins for a
1002 * specific size.
1003 *
1004 * The @code flags@ parameter determines which set of media are indexed. For
1005 * example, passing @code CUPS_MEDIA_FLAGS_BORDERLESS@ will get the Nth
1006 * borderless size supported by the printer.
1007 *
8072030b 1008 * @since CUPS 1.7/macOS 10.9@
6961465f
MS
1009 */
1010
1011int /* O - 1 on success, 0 on failure */
1012cupsGetDestMediaByIndex(
1013 http_t *http, /* I - Connection to destination */
1014 cups_dest_t *dest, /* I - Destination */
1015 cups_dinfo_t *dinfo, /* I - Destination information */
1016 int n, /* I - Media size number (0-based) */
1017 unsigned flags, /* I - Media flags */
1018 cups_size_t *size) /* O - Media size information */
1019{
ae26bf70
MS
1020 _cups_media_db_t *nsize; /* Size for N */
1021 pwg_media_t *pwg; /* PWG media name for size */
6961465f
MS
1022
1023
7536de1a
MS
1024 /*
1025 * Get the default connection as needed...
1026 */
1027
1028 if (!http)
1029 http = _cupsConnect();
1030
6961465f
MS
1031 /*
1032 * Range check input...
1033 */
1034
1035 if (size)
1036 memset(size, 0, sizeof(cups_size_t));
1037
1038 if (!http || !dest || !dinfo || n < 0 || !size)
1039 {
1040 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
1041 return (0);
1042 }
1043
1044 /*
1045 * Load media list as needed...
1046 */
1047
1048 if (flags & CUPS_MEDIA_FLAGS_READY)
1049 cups_update_ready(http, dinfo);
1050
1051 if (!dinfo->cached_db || dinfo->cached_flags != flags)
1052 cups_create_cached(http, dinfo, flags);
1053
1054 /*
1055 * Copy the size over and return...
1056 */
1057
ae26bf70
MS
1058 if ((nsize = (_cups_media_db_t *)cupsArrayIndex(dinfo->cached_db, n)) == NULL)
1059 {
1060 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
1061 return (0);
1062 }
503b54c9 1063
84de5e92 1064 if (nsize->key)
ae26bf70 1065 strlcpy(size->media, nsize->key, sizeof(size->media));
84de5e92
MS
1066 else if (nsize->size_name)
1067 strlcpy(size->media, nsize->size_name, sizeof(size->media));
ae26bf70
MS
1068 else if ((pwg = pwgMediaForSize(nsize->width, nsize->length)) != NULL)
1069 strlcpy(size->media, pwg->pwg, sizeof(size->media));
1070 else
6961465f
MS
1071 {
1072 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
1073 return (0);
1074 }
1075
ae26bf70
MS
1076 size->width = nsize->width;
1077 size->length = nsize->length;
1078 size->bottom = nsize->bottom;
1079 size->left = nsize->left;
1080 size->right = nsize->right;
1081 size->top = nsize->top;
6961465f
MS
1082
1083 return (1);
1084}
1085
1086
dcb445bc
MS
1087/*
1088 * 'cupsGetDestMediaByName()' - Get media names, dimensions, and margins.
1089 *
5a9febac 1090 * The "media" string is a PWG media name. "Flags" provides some matching
dcb445bc
MS
1091 * guidance (multiple flags can be combined):
1092 *
5a9febac
MS
1093 * CUPS_MEDIA_FLAGS_DEFAULT = find the closest size supported by the printer,
1094 * CUPS_MEDIA_FLAGS_BORDERLESS = find a borderless size,
1095 * CUPS_MEDIA_FLAGS_DUPLEX = find a size compatible with 2-sided printing,
1096 * CUPS_MEDIA_FLAGS_EXACT = find an exact match for the size, and
dcb445bc
MS
1097 * CUPS_MEDIA_FLAGS_READY = if the printer supports media sensing, find the
1098 * size amongst the "ready" media.
1099 *
1100 * The matching result (if any) is returned in the "cups_size_t" structure.
1101 *
1102 * Returns 1 when there is a match and 0 if there is not a match.
1103 *
8072030b 1104 * @since CUPS 1.6/macOS 10.8@
dcb445bc
MS
1105 */
1106
1107int /* O - 1 on match, 0 on failure */
1108cupsGetDestMediaByName(
1109 http_t *http, /* I - Connection to destination */
1110 cups_dest_t *dest, /* I - Destination */
1111 cups_dinfo_t *dinfo, /* I - Destination information */
1112 const char *media, /* I - Media name */
1113 unsigned flags, /* I - Media matching flags */
1114 cups_size_t *size) /* O - Media size information */
1115{
6961465f 1116 pwg_media_t *pwg; /* PWG media info */
dcb445bc
MS
1117
1118
7536de1a
MS
1119 /*
1120 * Get the default connection as needed...
1121 */
1122
1123 if (!http)
1124 http = _cupsConnect();
1125
dcb445bc
MS
1126 /*
1127 * Range check input...
1128 */
1129
1130 if (size)
1131 memset(size, 0, sizeof(cups_size_t));
1132
1133 if (!http || !dest || !dinfo || !media || !size)
1134 {
cb7f98ee 1135 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
dcb445bc
MS
1136 return (0);
1137 }
1138
1139 /*
1140 * Lookup the media size name...
1141 */
1142
6961465f
MS
1143 if ((pwg = pwgMediaForPWG(media)) == NULL)
1144 if ((pwg = pwgMediaForLegacy(media)) == NULL)
dcb445bc
MS
1145 {
1146 DEBUG_printf(("1cupsGetDestMediaByName: Unknown size '%s'.", media));
cb7f98ee 1147 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown media size name."), 1);
dcb445bc
MS
1148 return (0);
1149 }
1150
1151 /*
1152 * Lookup the size...
1153 */
1154
6961465f 1155 return (cups_get_media_db(http, dinfo, pwg, flags, size));
dcb445bc
MS
1156}
1157
1158
1159/*
1160 * 'cupsGetDestMediaBySize()' - Get media names, dimensions, and margins.
1161 *
5a9febac
MS
1162 * "Width" and "length" are the dimensions in hundredths of millimeters.
1163 * "Flags" provides some matching guidance (multiple flags can be combined):
dcb445bc 1164 *
5a9febac
MS
1165 * CUPS_MEDIA_FLAGS_DEFAULT = find the closest size supported by the printer,
1166 * CUPS_MEDIA_FLAGS_BORDERLESS = find a borderless size,
1167 * CUPS_MEDIA_FLAGS_DUPLEX = find a size compatible with 2-sided printing,
1168 * CUPS_MEDIA_FLAGS_EXACT = find an exact match for the size, and
dcb445bc
MS
1169 * CUPS_MEDIA_FLAGS_READY = if the printer supports media sensing, find the
1170 * size amongst the "ready" media.
1171 *
1172 * The matching result (if any) is returned in the "cups_size_t" structure.
1173 *
1174 * Returns 1 when there is a match and 0 if there is not a match.
1175 *
8072030b 1176 * @since CUPS 1.6/macOS 10.8@
dcb445bc
MS
1177 */
1178
1179int /* O - 1 on match, 0 on failure */
1180cupsGetDestMediaBySize(
1181 http_t *http, /* I - Connection to destination */
1182 cups_dest_t *dest, /* I - Destination */
1183 cups_dinfo_t *dinfo, /* I - Destination information */
1184 int width, /* I - Media width in hundredths of
1185 * of millimeters */
1186 int length, /* I - Media length in hundredths of
1187 * of millimeters */
1188 unsigned flags, /* I - Media matching flags */
1189 cups_size_t *size) /* O - Media size information */
1190{
6961465f 1191 pwg_media_t *pwg; /* PWG media info */
dcb445bc
MS
1192
1193
7536de1a
MS
1194 /*
1195 * Get the default connection as needed...
1196 */
1197
1198 if (!http)
1199 http = _cupsConnect();
1200
dcb445bc
MS
1201 /*
1202 * Range check input...
1203 */
1204
1205 if (size)
1206 memset(size, 0, sizeof(cups_size_t));
1207
1208 if (!http || !dest || !dinfo || width <= 0 || length <= 0 || !size)
1209 {
cb7f98ee 1210 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
dcb445bc
MS
1211 return (0);
1212 }
1213
1214 /*
1215 * Lookup the media size name...
1216 */
1217
6961465f 1218 if ((pwg = pwgMediaForSize(width, length)) == NULL)
dcb445bc
MS
1219 {
1220 DEBUG_printf(("1cupsGetDestMediaBySize: Invalid size %dx%d.", width,
1221 length));
cb7f98ee 1222 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid media size."), 1);
dcb445bc
MS
1223 return (0);
1224 }
1225
1226 /*
1227 * Lookup the size...
1228 */
1229
6961465f
MS
1230 return (cups_get_media_db(http, dinfo, pwg, flags, size));
1231}
1232
1233
1234/*
1235 * 'cupsGetDestMediaCount()' - Get the number of sizes supported by a
1236 * destination.
1237 *
1238 * The @code flags@ parameter determines the set of media sizes that are
1239 * counted. For example, passing @code CUPS_MEDIA_FLAGS_BORDERLESS@ will return
1240 * the number of borderless sizes.
1241 *
8072030b 1242 * @since CUPS 1.7/macOS 10.9@
6961465f
MS
1243 */
1244
1245int /* O - Number of sizes */
1246cupsGetDestMediaCount(
1247 http_t *http, /* I - Connection to destination */
1248 cups_dest_t *dest, /* I - Destination */
1249 cups_dinfo_t *dinfo, /* I - Destination information */
1250 unsigned flags) /* I - Media flags */
1251{
7536de1a
MS
1252 /*
1253 * Get the default connection as needed...
1254 */
1255
1256 if (!http)
1257 http = _cupsConnect();
1258
6961465f
MS
1259 /*
1260 * Range check input...
1261 */
1262
1263 if (!http || !dest || !dinfo)
1264 {
1265 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
1266 return (0);
1267 }
1268
1269 /*
1270 * Load media list as needed...
1271 */
1272
1273 if (flags & CUPS_MEDIA_FLAGS_READY)
1274 cups_update_ready(http, dinfo);
1275
1276 if (!dinfo->cached_db || dinfo->cached_flags != flags)
1277 cups_create_cached(http, dinfo, flags);
1278
1279 return (cupsArrayCount(dinfo->cached_db));
1280}
1281
1282
1283/*
1284 * 'cupsGetDestMediaDefault()' - Get the default size for a destination.
1285 *
1286 * The @code flags@ parameter determines which default size is returned. For
1287 * example, passing @code CUPS_MEDIA_FLAGS_BORDERLESS@ will return the default
1288 * borderless size, typically US Letter or A4, but sometimes 4x6 photo media.
1289 *
8072030b 1290 * @since CUPS 1.7/macOS 10.9@
6961465f
MS
1291 */
1292
1293int /* O - 1 on success, 0 on failure */
1294cupsGetDestMediaDefault(
1295 http_t *http, /* I - Connection to destination */
1296 cups_dest_t *dest, /* I - Destination */
1297 cups_dinfo_t *dinfo, /* I - Destination information */
1298 unsigned flags, /* I - Media flags */
1299 cups_size_t *size) /* O - Media size information */
1300{
1301 const char *media; /* Default media size */
1302
1303
7536de1a
MS
1304 /*
1305 * Get the default connection as needed...
1306 */
1307
1308 if (!http)
1309 http = _cupsConnect();
1310
6961465f
MS
1311 /*
1312 * Range check input...
1313 */
1314
1315 if (size)
1316 memset(size, 0, sizeof(cups_size_t));
1317
1318 if (!http || !dest || !dinfo || !size)
1319 {
1320 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
1321 return (0);
1322 }
1323
1324 /*
1325 * Get the default media size, if any...
1326 */
1327
336b669e 1328 if ((media = cupsGetOption("media", dest->num_options, dest->options)) == NULL)
6961465f
MS
1329 media = "na_letter_8.5x11in";
1330
1331 if (cupsGetDestMediaByName(http, dest, dinfo, media, flags, size))
1332 return (1);
1333
336b669e 1334 if (strcmp(media, "na_letter_8.5x11in") && cupsGetDestMediaByName(http, dest, dinfo, "iso_a4_210x297mm", flags, size))
6961465f
MS
1335 return (1);
1336
336b669e 1337 if (strcmp(media, "iso_a4_210x297mm") && cupsGetDestMediaByName(http, dest, dinfo, "na_letter_8.5x11in", flags, size))
6961465f
MS
1338 return (1);
1339
336b669e 1340 if ((flags & CUPS_MEDIA_FLAGS_BORDERLESS) && cupsGetDestMediaByName(http, dest, dinfo, "na_index_4x6in", flags, size))
6961465f
MS
1341 return (1);
1342
1343 /*
1344 * Fall back to the first matching media size...
1345 */
1346
7e86f2f6 1347 return (cupsGetDestMediaByIndex(http, dest, dinfo, 0, flags, size));
dcb445bc
MS
1348}
1349
1350
a29fd7dd
MS
1351/*
1352 * 'cups_add_dconstres()' - Add a constraint or resolver to an array.
1353 */
1354
1355static void
1356cups_add_dconstres(
1357 cups_array_t *a, /* I - Array */
1358 ipp_t *collection) /* I - Collection value */
1359{
1360 ipp_attribute_t *attr; /* Attribute */
1361 _cups_dconstres_t *temp; /* Current constraint/resolver */
1362
1363
1364 if ((attr = ippFindAttribute(collection, "resolver-name",
1365 IPP_TAG_NAME)) == NULL)
1366 return;
1367
1368 if ((temp = calloc(1, sizeof(_cups_dconstres_t))) == NULL)
1369 return;
1370
1371 temp->name = attr->values[0].string.text;
1372 temp->collection = collection;
1373
1374 cupsArrayAdd(a, temp);
1375}
1376
1377
336b669e
MS
1378/*
1379 * 'cups_collection_contains()' - Check whether test collection is contained in the matching collection.
1380 */
1381
1382static int /* O - 1 on a match, 0 on a non-match */
1383cups_collection_contains(ipp_t *test, /* I - Collection to test */
1384 ipp_t *match) /* I - Matching values */
1385{
89f3668e
MS
1386 int i, j, /* Looping vars */
1387 mcount, /* Number of match values */
1388 tcount; /* Number of test values */
336b669e
MS
1389 ipp_attribute_t *tattr, /* Testing attribute */
1390 *mattr; /* Matching attribute */
1391 const char *tval; /* Testing string value */
1392
1393
1394 for (mattr = ippFirstAttribute(match); mattr; mattr = ippNextAttribute(match))
1395 {
1396 if ((tattr = ippFindAttribute(test, ippGetName(mattr), IPP_TAG_ZERO)) == NULL)
1397 return (0);
1398
89f3668e 1399 tcount = ippGetCount(tattr);
336b669e
MS
1400
1401 switch (ippGetValueTag(mattr))
1402 {
1403 case IPP_TAG_INTEGER :
1404 case IPP_TAG_ENUM :
1405 if (ippGetValueTag(tattr) != ippGetValueTag(mattr))
1406 return (0);
1407
89f3668e 1408 for (i = 0; i < tcount; i ++)
336b669e
MS
1409 {
1410 if (!ippContainsInteger(mattr, ippGetInteger(tattr, i)))
1411 return (0);
1412 }
1413 break;
1414
1415 case IPP_TAG_RANGE :
1416 if (ippGetValueTag(tattr) != IPP_TAG_INTEGER)
1417 return (0);
1418
89f3668e 1419 for (i = 0; i < tcount; i ++)
336b669e
MS
1420 {
1421 if (!ippContainsInteger(mattr, ippGetInteger(tattr, i)))
1422 return (0);
1423 }
1424 break;
1425
1426 case IPP_TAG_BOOLEAN :
1427 if (ippGetValueTag(tattr) != IPP_TAG_BOOLEAN || ippGetBoolean(tattr, 0) != ippGetBoolean(mattr, 0))
1428 return (0);
1429 break;
1430
1431 case IPP_TAG_TEXTLANG :
1432 case IPP_TAG_NAMELANG :
1433 case IPP_TAG_TEXT :
1434 case IPP_TAG_NAME :
1435 case IPP_TAG_KEYWORD :
1436 case IPP_TAG_URI :
1437 case IPP_TAG_URISCHEME :
1438 case IPP_TAG_CHARSET :
1439 case IPP_TAG_LANGUAGE :
1440 case IPP_TAG_MIMETYPE :
89f3668e 1441 for (i = 0; i < tcount; i ++)
336b669e
MS
1442 {
1443 if ((tval = ippGetString(tattr, i, NULL)) == NULL || !ippContainsString(mattr, tval))
1444 return (0);
1445 }
1446 break;
1447
89f3668e
MS
1448 case IPP_TAG_BEGIN_COLLECTION :
1449 for (i = 0; i < tcount; i ++)
1450 {
1451 ipp_t *tcol = ippGetCollection(tattr, i);
1452 /* Testing collection */
1453
1454 for (j = 0, mcount = ippGetCount(mattr); j < mcount; j ++)
1455 if (!cups_collection_contains(tcol, ippGetCollection(mattr, j)))
1456 return (0);
1457 }
1458 break;
1459
336b669e
MS
1460 default :
1461 return (0);
1462 }
1463 }
1464
1465 return (1);
1466}
1467
1468
1469/*
1470 * 'cups_collection_string()' - Convert an IPP collection to an option string.
1471 */
1472
1473static size_t /* O - Number of bytes needed */
1474cups_collection_string(
1475 ipp_attribute_t *attr, /* I - Collection attribute */
1476 char *buffer, /* I - String buffer */
1477 size_t bufsize) /* I - Size of buffer */
1478{
1479 int i, j, /* Looping vars */
1480 count, /* Number of collection values */
1481 mcount; /* Number of member values */
1482 ipp_t *col; /* Collection */
1483 ipp_attribute_t *first, /* First member attribute */
1484 *member; /* Member attribute */
1485 char *bufptr, /* Pointer into buffer */
1486 *bufend, /* End of buffer */
1487 temp[100]; /* Temporary string */
1488 const char *mptr; /* Pointer into member value */
1489 int mlen; /* Length of octetString */
1490
1491
1492 bufptr = buffer;
1493 bufend = buffer + bufsize - 1;
1494
1495 for (i = 0, count = ippGetCount(attr); i < count; i ++)
1496 {
1497 col = ippGetCollection(attr, i);
1498
1499 if (i)
1500 {
1501 if (bufptr < bufend)
1502 *bufptr++ = ',';
1503 else
1504 bufptr ++;
1505 }
1506
1507 if (bufptr < bufend)
1508 *bufptr++ = '{';
1509 else
1510 bufptr ++;
1511
1512 for (member = first = ippFirstAttribute(col); member; member = ippNextAttribute(col))
1513 {
1514 const char *mname = ippGetName(member);
1515
1516 if (member != first)
1517 {
1518 if (bufptr < bufend)
1519 *bufptr++ = ' ';
1520 else
1521 bufptr ++;
1522 }
1523
1524 if (ippGetValueTag(member) == IPP_TAG_BOOLEAN)
1525 {
1526 if (!ippGetBoolean(member, 0))
1527 {
1528 if (bufptr < bufend)
e22f464e 1529 strlcpy(bufptr, "no", (size_t)(bufend - bufptr + 1));
336b669e
MS
1530 bufptr += 2;
1531 }
1532
1533 if (bufptr < bufend)
e22f464e 1534 strlcpy(bufptr, mname, (size_t)(bufend - bufptr + 1));
336b669e
MS
1535 bufptr += strlen(mname);
1536 continue;
1537 }
1538
1539 if (bufptr < bufend)
e22f464e 1540 strlcpy(bufptr, mname, (size_t)(bufend - bufptr + 1));
336b669e
MS
1541 bufptr += strlen(mname);
1542
1543 if (bufptr < bufend)
1544 *bufptr++ = '=';
1545 else
1546 bufptr ++;
1547
1548 if (ippGetValueTag(member) == IPP_TAG_BEGIN_COLLECTION)
1549 {
1550 /*
1551 * Convert sub-collection...
1552 */
1553
1554 bufptr += cups_collection_string(member, bufptr, bufptr < bufend ? (size_t)(bufend - bufptr + 1) : 0);
1555 }
1556 else
1557 {
1558 /*
1559 * Convert simple type...
1560 */
1561
1562 for (j = 0, mcount = ippGetCount(member); j < mcount; j ++)
1563 {
1564 if (j)
1565 {
1566 if (bufptr < bufend)
1567 *bufptr++ = ',';
1568 else
1569 bufptr ++;
1570 }
1571
1572 switch (ippGetValueTag(member))
1573 {
1574 case IPP_TAG_INTEGER :
1575 case IPP_TAG_ENUM :
e22f464e 1576 bufptr += snprintf(bufptr, bufptr < bufend ? (size_t)(bufend - bufptr + 1) : 0, "%d", ippGetInteger(member, j));
336b669e
MS
1577 break;
1578
1579 case IPP_TAG_STRING :
1580 if (bufptr < bufend)
1581 *bufptr++ = '\"';
1582 else
1583 bufptr ++;
1584
1585 for (mptr = (const char *)ippGetOctetString(member, j, &mlen); mlen > 0; mlen --, mptr ++)
1586 {
1587 if (*mptr == '\"' || *mptr == '\\')
1588 {
1589 if (bufptr < bufend)
1590 *bufptr++ = '\\';
1591 else
1592 bufptr ++;
1593 }
1594
1595 if (bufptr < bufend)
1596 *bufptr++ = *mptr;
1597 else
1598 bufptr ++;
1599 }
1600
1601 if (bufptr < bufend)
1602 *bufptr++ = '\"';
1603 else
1604 bufptr ++;
1605 break;
1606
1607 case IPP_TAG_DATE :
1608 {
1609 unsigned year; /* Year */
1610 const ipp_uchar_t *date = ippGetDate(member, j);
1611 /* Date value */
1612
1613 year = ((unsigned)date[0] << 8) + (unsigned)date[1];
1614
1615 if (date[9] == 0 && date[10] == 0)
1616 snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02uZ", year, date[2], date[3], date[4], date[5], date[6]);
1617 else
1618 snprintf(temp, sizeof(temp), "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u", year, date[2], date[3], date[4], date[5], date[6], date[8], date[9], date[10]);
1619
1620 if (buffer && bufptr < bufend)
1621 strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1));
1622
1623 bufptr += strlen(temp);
1624 }
1625 break;
1626
1627 case IPP_TAG_RESOLUTION :
1628 {
1629 int xres, /* Horizontal resolution */
1630 yres; /* Vertical resolution */
1631 ipp_res_t units; /* Resolution units */
1632
1633 xres = ippGetResolution(member, j, &yres, &units);
1634
1635 if (xres == yres)
1636 snprintf(temp, sizeof(temp), "%d%s", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
1637 else
1638 snprintf(temp, sizeof(temp), "%dx%d%s", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
1639
1640 if (buffer && bufptr < bufend)
1641 strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1));
1642
1643 bufptr += strlen(temp);
1644 }
1645 break;
1646
1647 case IPP_TAG_RANGE :
1648 {
1649 int lower, /* Lower bound */
1650 upper; /* Upper bound */
1651
1652 lower = ippGetRange(member, j, &upper);
1653
1654 snprintf(temp, sizeof(temp), "%d-%d", lower, upper);
1655
1656 if (buffer && bufptr < bufend)
1657 strlcpy(bufptr, temp, (size_t)(bufend - bufptr + 1));
1658
1659 bufptr += strlen(temp);
1660 }
1661 break;
1662
1663 case IPP_TAG_TEXTLANG :
1664 case IPP_TAG_NAMELANG :
1665 case IPP_TAG_TEXT :
1666 case IPP_TAG_NAME :
1667 case IPP_TAG_KEYWORD :
1668 case IPP_TAG_URI :
1669 case IPP_TAG_URISCHEME :
1670 case IPP_TAG_CHARSET :
1671 case IPP_TAG_LANGUAGE :
1672 case IPP_TAG_MIMETYPE :
1673 if (bufptr < bufend)
1674 *bufptr++ = '\"';
1675 else
1676 bufptr ++;
1677
1678 for (mptr = ippGetString(member, j, NULL); *mptr; mptr ++)
1679 {
1680 if (*mptr == '\"' || *mptr == '\\')
1681 {
1682 if (bufptr < bufend)
1683 *bufptr++ = '\\';
1684 else
1685 bufptr ++;
1686 }
1687
1688 if (bufptr < bufend)
1689 *bufptr++ = *mptr;
1690 else
1691 bufptr ++;
1692 }
1693
1694 if (bufptr < bufend)
1695 *bufptr++ = '\"';
1696 else
1697 bufptr ++;
1698 break;
1699
1700 default :
1701 break;
1702 }
1703 }
1704 }
1705 }
1706
1707 if (bufptr < bufend)
1708 *bufptr++ = '}';
1709 else
1710 bufptr ++;
1711 }
1712
1713 *bufptr = '\0';
1714 return ((size_t)(bufptr - buffer + 1));
1715}
1716
1717
a29fd7dd
MS
1718/*
1719 * 'cups_compare_dconstres()' - Compare to resolver entries.
1720 */
1721
1722static int /* O - Result of comparison */
1723cups_compare_dconstres(
1724 _cups_dconstres_t *a, /* I - First resolver */
1725 _cups_dconstres_t *b) /* I - Second resolver */
1726{
1727 return (strcmp(a->name, b->name));
1728}
1729
1730
dcb445bc
MS
1731/*
1732 * 'cups_compare_media_db()' - Compare two media entries.
1733 */
1734
1735static int /* O - Result of comparison */
1736cups_compare_media_db(
1737 _cups_media_db_t *a, /* I - First media entries */
1738 _cups_media_db_t *b) /* I - Second media entries */
1739{
1740 int result; /* Result of comparison */
1741
1742
1743 if ((result = a->width - b->width) == 0)
1744 result = a->length - b->length;
1745
1746 return (result);
1747}
1748
1749
1750/*
1751 * 'cups_copy_media_db()' - Copy a media entry.
1752 */
1753
1754static _cups_media_db_t * /* O - New media entry */
1755cups_copy_media_db(
1756 _cups_media_db_t *mdb) /* I - Media entry to copy */
1757{
1758 _cups_media_db_t *temp; /* New media entry */
1759
1760
1761 if ((temp = calloc(1, sizeof(_cups_media_db_t))) == NULL)
1762 return (NULL);
1763
1764 if (mdb->color)
1765 temp->color = _cupsStrAlloc(mdb->color);
1766 if (mdb->key)
1767 temp->key = _cupsStrAlloc(mdb->key);
1768 if (mdb->info)
1769 temp->info = _cupsStrAlloc(mdb->info);
1770 if (mdb->size_name)
1771 temp->size_name = _cupsStrAlloc(mdb->size_name);
1772 if (mdb->source)
1773 temp->source = _cupsStrAlloc(mdb->source);
1774 if (mdb->type)
1775 temp->type = _cupsStrAlloc(mdb->type);
1776
1777 temp->width = mdb->width;
1778 temp->length = mdb->length;
1779 temp->bottom = mdb->bottom;
1780 temp->left = mdb->left;
1781 temp->right = mdb->right;
1782 temp->top = mdb->top;
1783
1784 return (temp);
1785}
1786
1787
6961465f
MS
1788/*
1789 * 'cups_create_cached()' - Create the media selection cache.
1790 */
1791
1792static void
1793cups_create_cached(http_t *http, /* I - Connection to destination */
1794 cups_dinfo_t *dinfo, /* I - Destination information */
1795 unsigned flags) /* I - Media selection flags */
1796{
1797 cups_array_t *db; /* Media database array to use */
1798 _cups_media_db_t *mdb, /* Media database entry */
1799 *first; /* First entry this size */
1800
1801
807315e6 1802 DEBUG_printf(("3cups_create_cached(http=%p, dinfo=%p, flags=%u)", (void *)http, (void *)dinfo, flags));
ae26bf70 1803
6961465f
MS
1804 if (dinfo->cached_db)
1805 cupsArrayDelete(dinfo->cached_db);
1806
1807 dinfo->cached_db = cupsArrayNew(NULL, NULL);
1808 dinfo->cached_flags = flags;
1809
1810 if (flags & CUPS_MEDIA_FLAGS_READY)
1811 {
ae26bf70
MS
1812 DEBUG_puts("4cups_create_cached: ready media");
1813
6961465f
MS
1814 cups_update_ready(http, dinfo);
1815 db = dinfo->ready_db;
1816 }
1817 else
1818 {
ae26bf70
MS
1819 DEBUG_puts("4cups_create_cached: supported media");
1820
6961465f
MS
1821 if (!dinfo->media_db)
1822 cups_create_media_db(dinfo, CUPS_MEDIA_FLAGS_DEFAULT);
1823
1824 db = dinfo->media_db;
1825 }
1826
1827 for (mdb = (_cups_media_db_t *)cupsArrayFirst(db), first = mdb;
1828 mdb;
1829 mdb = (_cups_media_db_t *)cupsArrayNext(db))
1830 {
807315e6 1831 DEBUG_printf(("4cups_create_cached: %p key=\"%s\", type=\"%s\", %dx%d, B%d L%d R%d T%d", (void *)mdb, mdb->key, mdb->type, mdb->width, mdb->length, mdb->bottom, mdb->left, mdb->right, mdb->top));
ae26bf70 1832
6961465f
MS
1833 if (flags & CUPS_MEDIA_FLAGS_BORDERLESS)
1834 {
1835 if (!mdb->left && !mdb->right && !mdb->top && !mdb->bottom)
ae26bf70 1836 {
807315e6 1837 DEBUG_printf(("4cups_create_cached: add %p", (void *)mdb));
6961465f 1838 cupsArrayAdd(dinfo->cached_db, mdb);
ae26bf70 1839 }
6961465f
MS
1840 }
1841 else if (flags & CUPS_MEDIA_FLAGS_DUPLEX)
1842 {
1843 if (first->width != mdb->width || first->length != mdb->length)
1844 {
807315e6 1845 DEBUG_printf(("4cups_create_cached: add %p", (void *)first));
6961465f
MS
1846 cupsArrayAdd(dinfo->cached_db, first);
1847 first = mdb;
1848 }
ae26bf70
MS
1849 else if (mdb->left >= first->left && mdb->right >= first->right && mdb->top >= first->top && mdb->bottom >= first->bottom &&
1850 (mdb->left != first->left || mdb->right != first->right || mdb->top != first->top || mdb->bottom != first->bottom))
6961465f
MS
1851 first = mdb;
1852 }
5b69e934 1853 else
ae26bf70 1854 {
807315e6 1855 DEBUG_printf(("4cups_create_cached: add %p", (void *)mdb));
5b69e934 1856 cupsArrayAdd(dinfo->cached_db, mdb);
ae26bf70 1857 }
6961465f
MS
1858 }
1859
1860 if (flags & CUPS_MEDIA_FLAGS_DUPLEX)
ae26bf70 1861 {
807315e6 1862 DEBUG_printf(("4cups_create_cached: add %p", (void *)first));
6961465f 1863 cupsArrayAdd(dinfo->cached_db, first);
ae26bf70 1864 }
6961465f
MS
1865}
1866
1867
a29fd7dd
MS
1868/*
1869 * 'cups_create_constraints()' - Create the constraints and resolvers arrays.
1870 */
1871
1872static void
1873cups_create_constraints(
1874 cups_dinfo_t *dinfo) /* I - Destination information */
1875{
1876 int i; /* Looping var */
1877 ipp_attribute_t *attr; /* Attribute */
1878 _ipp_value_t *val; /* Current value */
1879
1880
1881 dinfo->constraints = cupsArrayNew3(NULL, NULL, NULL, 0, NULL,
1882 (cups_afree_func_t)free);
1883 dinfo->resolvers = cupsArrayNew3((cups_array_func_t)cups_compare_dconstres,
1884 NULL, NULL, 0, NULL,
1885 (cups_afree_func_t)free);
1886
1887 if ((attr = ippFindAttribute(dinfo->attrs, "job-constraints-supported",
1888 IPP_TAG_BEGIN_COLLECTION)) != NULL)
1889 {
1890 for (i = attr->num_values, val = attr->values; i > 0; i --, val ++)
1891 cups_add_dconstres(dinfo->constraints, val->collection);
1892 }
1893
1894 if ((attr = ippFindAttribute(dinfo->attrs, "job-resolvers-supported",
1895 IPP_TAG_BEGIN_COLLECTION)) != NULL)
1896 {
1897 for (i = attr->num_values, val = attr->values; i > 0; i --, val ++)
1898 cups_add_dconstres(dinfo->resolvers, val->collection);
1899 }
1900}
1901
1902
1903/*
1904 * 'cups_create_defaults()' - Create the -default option array.
a29fd7dd
MS
1905 */
1906
1907static void
1908cups_create_defaults(
1909 cups_dinfo_t *dinfo) /* I - Destination information */
1910{
1911 ipp_attribute_t *attr; /* Current attribute */
1912 char name[IPP_MAX_NAME + 1],
1913 /* Current name */
1914 *nameptr, /* Pointer into current name */
1915 value[2048]; /* Current value */
1916
1917
1918 /*
1919 * Iterate through the printer attributes looking for xxx-default and adding
1920 * xxx=value to the defaults option array.
1921 */
1922
336b669e 1923 for (attr = ippFirstAttribute(dinfo->attrs); attr; attr = ippNextAttribute(dinfo->attrs))
a29fd7dd 1924 {
336b669e 1925 if (!ippGetName(attr) || ippGetGroupTag(attr) != IPP_TAG_PRINTER)
a29fd7dd
MS
1926 continue;
1927
336b669e
MS
1928 strlcpy(name, ippGetName(attr), sizeof(name));
1929 if ((nameptr = name + strlen(name) - 8) <= name || strcmp(nameptr, "-default"))
a29fd7dd
MS
1930 continue;
1931
1932 *nameptr = '\0';
1933
336b669e
MS
1934 if (ippGetValueTag(attr) == IPP_TAG_BEGIN_COLLECTION)
1935 {
1936 if (cups_collection_string(attr, value, sizeof(value)) >= sizeof(value))
1937 continue;
1938 }
1939 else if (ippAttributeString(attr, value, sizeof(value)) >= sizeof(value))
a29fd7dd
MS
1940 continue;
1941
336b669e 1942 dinfo->num_defaults = cupsAddOption(name, value, dinfo->num_defaults, &dinfo->defaults);
a29fd7dd
MS
1943 }
1944}
1945
1946
dcb445bc
MS
1947/*
1948 * 'cups_create_media_db()' - Create the media database.
1949 */
1950
1951static void
1952cups_create_media_db(
6961465f
MS
1953 cups_dinfo_t *dinfo, /* I - Destination information */
1954 unsigned flags) /* I - Media flags */
dcb445bc
MS
1955{
1956 int i; /* Looping var */
1957 _ipp_value_t *val; /* Current value */
1958 ipp_attribute_t *media_col_db, /* media-col-database */
1959 *media_attr, /* media-xxx */
1960 *x_dimension, /* x-dimension */
1961 *y_dimension; /* y-dimension */
6961465f
MS
1962 pwg_media_t *pwg; /* PWG media info */
1963 cups_array_t *db; /* New media database array */
dcb445bc 1964 _cups_media_db_t mdb; /* Media entry */
84de5e92 1965 char media_key[256]; /* Synthesized media-key value */
dcb445bc
MS
1966
1967
6961465f
MS
1968 db = cupsArrayNew3((cups_array_func_t)cups_compare_media_db,
1969 NULL, NULL, 0,
1970 (cups_acopy_func_t)cups_copy_media_db,
1971 (cups_afree_func_t)cups_free_media_db);
dcb445bc 1972
6961465f
MS
1973 if (flags == CUPS_MEDIA_FLAGS_READY)
1974 {
1975 dinfo->ready_db = db;
1976
1977 media_col_db = ippFindAttribute(dinfo->ready_attrs, "media-col-ready",
1978 IPP_TAG_BEGIN_COLLECTION);
1979 media_attr = ippFindAttribute(dinfo->ready_attrs, "media-ready",
1980 IPP_TAG_ZERO);
1981 }
1982 else
1983 {
1984 dinfo->media_db = db;
1985 dinfo->min_size.width = INT_MAX;
1986 dinfo->min_size.length = INT_MAX;
1987 dinfo->max_size.width = 0;
1988 dinfo->max_size.length = 0;
1989
1990 media_col_db = ippFindAttribute(dinfo->attrs, "media-col-database",
1991 IPP_TAG_BEGIN_COLLECTION);
1992 media_attr = ippFindAttribute(dinfo->attrs, "media-supported",
1993 IPP_TAG_ZERO);
1994 }
1995
1996 if (media_col_db)
dcb445bc
MS
1997 {
1998 _ipp_value_t *custom = NULL; /* Custom size range value */
1999
2000 for (i = media_col_db->num_values, val = media_col_db->values;
2001 i > 0;
2002 i --, val ++)
2003 {
2004 memset(&mdb, 0, sizeof(mdb));
2005
2006 if ((media_attr = ippFindAttribute(val->collection, "media-size",
2007 IPP_TAG_BEGIN_COLLECTION)) != NULL)
2008 {
2009 ipp_t *media_size = media_attr->values[0].collection;
2010 /* media-size collection value */
2011
2012 if ((x_dimension = ippFindAttribute(media_size, "x-dimension",
6961465f 2013 IPP_TAG_INTEGER)) != NULL &&
dcb445bc
MS
2014 (y_dimension = ippFindAttribute(media_size, "y-dimension",
2015 IPP_TAG_INTEGER)) != NULL)
2016 {
6961465f
MS
2017 /*
2018 * Fixed size...
2019 */
2020
dcb445bc
MS
2021 mdb.width = x_dimension->values[0].integer;
2022 mdb.length = y_dimension->values[0].integer;
2023 }
6961465f
MS
2024 else if ((x_dimension = ippFindAttribute(media_size, "x-dimension",
2025 IPP_TAG_INTEGER)) != NULL &&
2026 (y_dimension = ippFindAttribute(media_size, "y-dimension",
2027 IPP_TAG_RANGE)) != NULL)
2028 {
2029 /*
2030 * Roll limits...
2031 */
2032
2033 mdb.width = x_dimension->values[0].integer;
2034 mdb.length = y_dimension->values[0].range.upper;
2035 }
2036 else if (flags != CUPS_MEDIA_FLAGS_READY &&
2037 (x_dimension = ippFindAttribute(media_size, "x-dimension",
2038 IPP_TAG_RANGE)) != NULL &&
dcb445bc
MS
2039 (y_dimension = ippFindAttribute(media_size, "y-dimension",
2040 IPP_TAG_RANGE)) != NULL)
2041 {
2042 /*
2043 * Custom size range; save this as the custom size value with default
2044 * margins, then continue; we'll capture the real margins below...
2045 */
2046
2047 custom = val;
2048
2049 dinfo->min_size.width = x_dimension->values[0].range.lower;
2050 dinfo->min_size.length = y_dimension->values[0].range.lower;
2051 dinfo->min_size.left =
2052 dinfo->min_size.right = 635; /* Default 1/4" side margins */
2053 dinfo->min_size.top =
2054 dinfo->min_size.bottom = 1270; /* Default 1/2" top/bottom margins */
2055
2056 dinfo->max_size.width = x_dimension->values[0].range.upper;
2057 dinfo->max_size.length = y_dimension->values[0].range.upper;
2058 dinfo->max_size.left =
2059 dinfo->max_size.right = 635; /* Default 1/4" side margins */
2060 dinfo->max_size.top =
2061 dinfo->max_size.bottom = 1270; /* Default 1/2" top/bottom margins */
dcb445bc
MS
2062 continue;
2063 }
2064 }
2065
84de5e92 2066 if ((media_attr = ippFindAttribute(val->collection, "media-color", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD))
dcb445bc
MS
2067 mdb.color = media_attr->values[0].string.text;
2068
84de5e92 2069 if ((media_attr = ippFindAttribute(val->collection, "media-info", IPP_TAG_TEXT)) != NULL)
dcb445bc
MS
2070 mdb.info = media_attr->values[0].string.text;
2071
84de5e92 2072 if ((media_attr = ippFindAttribute(val->collection, "media-key", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD))
dcb445bc
MS
2073 mdb.key = media_attr->values[0].string.text;
2074
84de5e92 2075 if ((media_attr = ippFindAttribute(val->collection, "media-size-name", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD))
dcb445bc
MS
2076 mdb.size_name = media_attr->values[0].string.text;
2077
84de5e92 2078 if ((media_attr = ippFindAttribute(val->collection, "media-source", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD))
dcb445bc
MS
2079 mdb.source = media_attr->values[0].string.text;
2080
84de5e92 2081 if ((media_attr = ippFindAttribute(val->collection, "media-type", IPP_TAG_ZERO)) != NULL && (media_attr->value_tag == IPP_TAG_NAME || media_attr->value_tag == IPP_TAG_NAMELANG || media_attr->value_tag == IPP_TAG_KEYWORD))
dcb445bc
MS
2082 mdb.type = media_attr->values[0].string.text;
2083
84de5e92 2084 if ((media_attr = ippFindAttribute(val->collection, "media-bottom-margin", IPP_TAG_INTEGER)) != NULL)
dcb445bc
MS
2085 mdb.bottom = media_attr->values[0].integer;
2086
84de5e92 2087 if ((media_attr = ippFindAttribute(val->collection, "media-left-margin", IPP_TAG_INTEGER)) != NULL)
dcb445bc
MS
2088 mdb.left = media_attr->values[0].integer;
2089
84de5e92 2090 if ((media_attr = ippFindAttribute(val->collection, "media-right-margin", IPP_TAG_INTEGER)) != NULL)
dcb445bc
MS
2091 mdb.right = media_attr->values[0].integer;
2092
84de5e92 2093 if ((media_attr = ippFindAttribute(val->collection, "media-top-margin", IPP_TAG_INTEGER)) != NULL)
dcb445bc
MS
2094 mdb.top = media_attr->values[0].integer;
2095
71dc43af
MS
2096 if (!mdb.key)
2097 {
84de5e92
MS
2098 if (!mdb.size_name && (pwg = pwgMediaForSize(mdb.width, mdb.length)) != NULL)
2099 mdb.size_name = (char *)pwg->pwg;
2100
2101 if (!mdb.size_name)
2102 {
2103 /*
2104 * Use a CUPS-specific identifier if we don't have a size name...
2105 */
2106
2107 if (flags & CUPS_MEDIA_FLAGS_READY)
2108 snprintf(media_key, sizeof(media_key), "cups-media-ready-%d", i + 1);
2109 else
2110 snprintf(media_key, sizeof(media_key), "cups-media-%d", i + 1);
2111 }
2112 else if (mdb.source)
2113 {
2114 /*
2115 * Generate key using size name, source, and type (if set)...
2116 */
2117
2118 if (mdb.type)
2119 snprintf(media_key, sizeof(media_key), "%s_%s_%s", mdb.size_name, mdb.source, mdb.type);
2120 else
2121 snprintf(media_key, sizeof(media_key), "%s_%s", mdb.size_name, mdb.source);
2122 }
2123 else if (mdb.type)
2124 {
2125 /*
2126 * Generate key using size name and type...
2127 */
2128
2129 snprintf(media_key, sizeof(media_key), "%s_%s", mdb.size_name, mdb.type);
2130 }
2131 else
2132 {
2133 /*
2134 * Key is just the size name...
2135 */
2136
2137 strlcpy(media_key, mdb.size_name, sizeof(media_key));
2138 }
2139
2140 /*
2141 * Append "_borderless" for borderless media...
2142 */
2143
2144 if (!mdb.bottom && !mdb.left && !mdb.right && !mdb.top)
2145 strlcat(media_key, "_borderless", sizeof(media_key));
71dc43af
MS
2146
2147 mdb.key = media_key;
2148 }
2149
84de5e92
MS
2150 DEBUG_printf(("1cups_create_media_db: Adding media: key=\"%s\", width=%d, length=%d, source=\"%s\", type=\"%s\".", mdb.key, mdb.width, mdb.length, mdb.source, mdb.type));
2151
6961465f 2152 cupsArrayAdd(db, &mdb);
dcb445bc
MS
2153 }
2154
2155 if (custom)
2156 {
2157 if ((media_attr = ippFindAttribute(custom->collection,
2158 "media-bottom-margin",
2159 IPP_TAG_INTEGER)) != NULL)
2160 {
2161 dinfo->min_size.top =
2162 dinfo->max_size.top = media_attr->values[0].integer;
2163 }
2164
2165 if ((media_attr = ippFindAttribute(custom->collection,
2166 "media-left-margin",
2167 IPP_TAG_INTEGER)) != NULL)
2168 {
2169 dinfo->min_size.left =
2170 dinfo->max_size.left = media_attr->values[0].integer;
2171 }
2172
2173 if ((media_attr = ippFindAttribute(custom->collection,
2174 "media-right-margin",
2175 IPP_TAG_INTEGER)) != NULL)
2176 {
2177 dinfo->min_size.right =
2178 dinfo->max_size.right = media_attr->values[0].integer;
2179 }
2180
2181 if ((media_attr = ippFindAttribute(custom->collection,
2182 "media-top-margin",
2183 IPP_TAG_INTEGER)) != NULL)
2184 {
2185 dinfo->min_size.top =
2186 dinfo->max_size.top = media_attr->values[0].integer;
2187 }
2188 }
2189 }
6961465f 2190 else if (media_attr &&
dcb445bc
MS
2191 (media_attr->value_tag == IPP_TAG_NAME ||
2192 media_attr->value_tag == IPP_TAG_NAMELANG ||
2193 media_attr->value_tag == IPP_TAG_KEYWORD))
2194 {
2195 memset(&mdb, 0, sizeof(mdb));
2196
2197 mdb.left =
2198 mdb.right = 635; /* Default 1/4" side margins */
2199 mdb.top =
2200 mdb.bottom = 1270; /* Default 1/2" top/bottom margins */
2201
82cc1f9a 2202 for (i = media_attr->num_values, val = media_attr->values;
dcb445bc
MS
2203 i > 0;
2204 i --, val ++)
2205 {
6961465f
MS
2206 if ((pwg = pwgMediaForPWG(val->string.text)) == NULL)
2207 if ((pwg = pwgMediaForLegacy(val->string.text)) == NULL)
dcb445bc
MS
2208 {
2209 DEBUG_printf(("3cups_create_media_db: Ignoring unknown size '%s'.",
2210 val->string.text));
2211 continue;
2212 }
2213
2214 mdb.width = pwg->width;
2215 mdb.length = pwg->length;
2216
6961465f
MS
2217 if (flags != CUPS_MEDIA_FLAGS_READY &&
2218 !strncmp(val->string.text, "custom_min_", 11))
dcb445bc
MS
2219 {
2220 mdb.size_name = NULL;
2221 dinfo->min_size = mdb;
2222 }
6961465f
MS
2223 else if (flags != CUPS_MEDIA_FLAGS_READY &&
2224 !strncmp(val->string.text, "custom_max_", 11))
dcb445bc
MS
2225 {
2226 mdb.size_name = NULL;
2227 dinfo->max_size = mdb;
2228 }
2229 else
2230 {
2231 mdb.size_name = val->string.text;
2232
6961465f 2233 cupsArrayAdd(db, &mdb);
dcb445bc
MS
2234 }
2235 }
2236 }
2237}
2238
2239
2240/*
2241 * 'cups_free_media_cb()' - Free a media entry.
2242 */
2243
2244static void
2245cups_free_media_db(
2246 _cups_media_db_t *mdb) /* I - Media entry to free */
2247{
2248 if (mdb->color)
2249 _cupsStrFree(mdb->color);
2250 if (mdb->key)
2251 _cupsStrFree(mdb->key);
2252 if (mdb->info)
2253 _cupsStrFree(mdb->info);
2254 if (mdb->size_name)
2255 _cupsStrFree(mdb->size_name);
2256 if (mdb->source)
2257 _cupsStrFree(mdb->source);
2258 if (mdb->type)
2259 _cupsStrFree(mdb->type);
2260
2261 free(mdb);
2262}
2263
2264
2265/*
2266 * 'cups_get_media_db()' - Lookup the media entry for a given size.
2267 */
2268
2269static int /* O - 1 on match, 0 on failure */
6961465f
MS
2270cups_get_media_db(http_t *http, /* I - Connection to destination */
2271 cups_dinfo_t *dinfo, /* I - Destination information */
2272 pwg_media_t *pwg, /* I - PWG media info */
dcb445bc 2273 unsigned flags, /* I - Media matching flags */
6961465f 2274 cups_size_t *size) /* O - Media size/margin/name info */
dcb445bc 2275{
6961465f 2276 cups_array_t *db; /* Which media database to query */
dcb445bc
MS
2277 _cups_media_db_t *mdb, /* Current media database entry */
2278 *best = NULL, /* Best matching entry */
2279 key; /* Search key */
2280
2281
2282 /*
2283 * Create the media database as needed...
2284 */
2285
6961465f
MS
2286 if (flags & CUPS_MEDIA_FLAGS_READY)
2287 {
2288 cups_update_ready(http, dinfo);
2289 db = dinfo->ready_db;
2290 }
2291 else
2292 {
2293 if (!dinfo->media_db)
2294 cups_create_media_db(dinfo, CUPS_MEDIA_FLAGS_DEFAULT);
2295
2296 db = dinfo->media_db;
2297 }
dcb445bc
MS
2298
2299 /*
2300 * Find a match...
2301 */
2302
2303 memset(&key, 0, sizeof(key));
2304 key.width = pwg->width;
2305 key.length = pwg->length;
2306
6961465f 2307 if ((mdb = cupsArrayFind(db, &key)) != NULL)
dcb445bc
MS
2308 {
2309 /*
2310 * Found an exact match, let's figure out the best margins for the flags
2311 * supplied...
2312 */
2313
2314 best = mdb;
2315
2316 if (flags & CUPS_MEDIA_FLAGS_BORDERLESS)
2317 {
2318 /*
2319 * Look for the smallest margins...
2320 */
2321
ae26bf70 2322 if (best->left != 0 || best->right != 0 || best->top != 0 || best->bottom != 0)
dcb445bc 2323 {
6961465f 2324 for (mdb = (_cups_media_db_t *)cupsArrayNext(db);
dcb445bc 2325 mdb && !cups_compare_media_db(mdb, &key);
6961465f 2326 mdb = (_cups_media_db_t *)cupsArrayNext(db))
dcb445bc
MS
2327 {
2328 if (mdb->left <= best->left && mdb->right <= best->right &&
2329 mdb->top <= best->top && mdb->bottom <= best->bottom)
2330 {
2331 best = mdb;
2332 if (mdb->left == 0 && mdb->right == 0 && mdb->bottom == 0 &&
2333 mdb->top == 0)
2334 break;
2335 }
2336 }
2337 }
2338
2339 /*
2340 * If we need an exact match, return no-match if the size is not
2341 * borderless.
2342 */
2343
2344 if ((flags & CUPS_MEDIA_FLAGS_EXACT) &&
2345 (best->left || best->right || best->top || best->bottom))
2346 return (0);
2347 }
2348 else if (flags & CUPS_MEDIA_FLAGS_DUPLEX)
2349 {
2350 /*
2351 * Look for the largest margins...
2352 */
2353
6961465f 2354 for (mdb = (_cups_media_db_t *)cupsArrayNext(db);
dcb445bc 2355 mdb && !cups_compare_media_db(mdb, &key);
6961465f 2356 mdb = (_cups_media_db_t *)cupsArrayNext(db))
dcb445bc
MS
2357 {
2358 if (mdb->left >= best->left && mdb->right >= best->right &&
ae26bf70
MS
2359 mdb->top >= best->top && mdb->bottom >= best->bottom &&
2360 (mdb->bottom != best->bottom || mdb->left != best->left || mdb->right != best->right || mdb->top != best->top))
dcb445bc
MS
2361 best = mdb;
2362 }
2363 }
2364 else
2365 {
2366 /*
2367 * Look for the smallest non-zero margins...
2368 */
2369
6961465f 2370 for (mdb = (_cups_media_db_t *)cupsArrayNext(db);
dcb445bc 2371 mdb && !cups_compare_media_db(mdb, &key);
6961465f 2372 mdb = (_cups_media_db_t *)cupsArrayNext(db))
dcb445bc
MS
2373 {
2374 if (((mdb->left > 0 && mdb->left <= best->left) || best->left == 0) &&
ae26bf70 2375 ((mdb->right > 0 && mdb->right <= best->right) || best->right == 0) &&
dcb445bc 2376 ((mdb->top > 0 && mdb->top <= best->top) || best->top == 0) &&
ae26bf70
MS
2377 ((mdb->bottom > 0 && mdb->bottom <= best->bottom) || best->bottom == 0) &&
2378 (mdb->bottom != best->bottom || mdb->left != best->left || mdb->right != best->right || mdb->top != best->top))
dcb445bc
MS
2379 best = mdb;
2380 }
2381 }
2382 }
2383 else if (flags & CUPS_MEDIA_FLAGS_EXACT)
2384 {
2385 /*
2386 * See if we can do this as a custom size...
2387 */
2388
2389 if (pwg->width < dinfo->min_size.width ||
2390 pwg->width > dinfo->max_size.width ||
2391 pwg->length < dinfo->min_size.length ||
2392 pwg->length > dinfo->max_size.length)
2393 return (0); /* Out of range */
2394
2395 if ((flags & CUPS_MEDIA_FLAGS_BORDERLESS) &&
2396 (dinfo->min_size.left > 0 || dinfo->min_size.right > 0 ||
2397 dinfo->min_size.top > 0 || dinfo->min_size.bottom > 0))
2398 return (0); /* Not borderless */
2399
2400 key.size_name = (char *)pwg->pwg;
2401 key.bottom = dinfo->min_size.bottom;
2402 key.left = dinfo->min_size.left;
2403 key.right = dinfo->min_size.right;
2404 key.top = dinfo->min_size.top;
2405
2406 best = &key;
2407 }
2408 else if (pwg->width >= dinfo->min_size.width &&
2409 pwg->width <= dinfo->max_size.width &&
2410 pwg->length >= dinfo->min_size.length &&
2411 pwg->length <= dinfo->max_size.length)
2412 {
2413 /*
2414 * Map to custom size...
2415 */
2416
2417 key.size_name = (char *)pwg->pwg;
2418 key.bottom = dinfo->min_size.bottom;
2419 key.left = dinfo->min_size.left;
2420 key.right = dinfo->min_size.right;
2421 key.top = dinfo->min_size.top;
2422
2423 best = &key;
2424 }
2425 else
2426 {
2427 /*
2428 * Find a close size...
2429 */
2430
6961465f 2431 for (mdb = (_cups_media_db_t *)cupsArrayFirst(db);
dcb445bc 2432 mdb;
6961465f 2433 mdb = (_cups_media_db_t *)cupsArrayNext(db))
dcb445bc
MS
2434 if (cups_is_close_media_db(mdb, &key))
2435 break;
2436
2437 if (!mdb)
2438 return (0);
2439
2440 best = mdb;
2441
2442 if (flags & CUPS_MEDIA_FLAGS_BORDERLESS)
2443 {
2444 /*
2445 * Look for the smallest margins...
2446 */
2447
2448 if (best->left != 0 || best->right != 0 || best->top != 0 ||
2449 best->bottom != 0)
2450 {
6961465f 2451 for (mdb = (_cups_media_db_t *)cupsArrayNext(db);
dcb445bc 2452 mdb && cups_is_close_media_db(mdb, &key);
6961465f 2453 mdb = (_cups_media_db_t *)cupsArrayNext(db))
dcb445bc
MS
2454 {
2455 if (mdb->left <= best->left && mdb->right <= best->right &&
ae26bf70
MS
2456 mdb->top <= best->top && mdb->bottom <= best->bottom &&
2457 (mdb->bottom != best->bottom || mdb->left != best->left || mdb->right != best->right || mdb->top != best->top))
dcb445bc
MS
2458 {
2459 best = mdb;
2460 if (mdb->left == 0 && mdb->right == 0 && mdb->bottom == 0 &&
2461 mdb->top == 0)
2462 break;
2463 }
2464 }
2465 }
2466 }
2467 else if (flags & CUPS_MEDIA_FLAGS_DUPLEX)
2468 {
2469 /*
2470 * Look for the largest margins...
2471 */
2472
6961465f 2473 for (mdb = (_cups_media_db_t *)cupsArrayNext(db);
dcb445bc 2474 mdb && cups_is_close_media_db(mdb, &key);
6961465f 2475 mdb = (_cups_media_db_t *)cupsArrayNext(db))
dcb445bc
MS
2476 {
2477 if (mdb->left >= best->left && mdb->right >= best->right &&
ae26bf70
MS
2478 mdb->top >= best->top && mdb->bottom >= best->bottom &&
2479 (mdb->bottom != best->bottom || mdb->left != best->left || mdb->right != best->right || mdb->top != best->top))
dcb445bc
MS
2480 best = mdb;
2481 }
2482 }
2483 else
2484 {
2485 /*
2486 * Look for the smallest non-zero margins...
2487 */
2488
6961465f 2489 for (mdb = (_cups_media_db_t *)cupsArrayNext(db);
dcb445bc 2490 mdb && cups_is_close_media_db(mdb, &key);
6961465f 2491 mdb = (_cups_media_db_t *)cupsArrayNext(db))
dcb445bc
MS
2492 {
2493 if (((mdb->left > 0 && mdb->left <= best->left) || best->left == 0) &&
2494 ((mdb->right > 0 && mdb->right <= best->right) ||
2495 best->right == 0) &&
2496 ((mdb->top > 0 && mdb->top <= best->top) || best->top == 0) &&
2497 ((mdb->bottom > 0 && mdb->bottom <= best->bottom) ||
ae26bf70
MS
2498 best->bottom == 0) &&
2499 (mdb->bottom != best->bottom || mdb->left != best->left || mdb->right != best->right || mdb->top != best->top))
dcb445bc
MS
2500 best = mdb;
2501 }
2502 }
2503 }
2504
2505 if (best)
2506 {
2507 /*
2508 * Return the matching size...
2509 */
2510
71dc43af
MS
2511 if (best->key)
2512 strlcpy(size->media, best->key, sizeof(size->media));
982be458 2513 else if (best->size_name)
dcb445bc 2514 strlcpy(size->media, best->size_name, sizeof(size->media));
dcb445bc
MS
2515 else
2516 strlcpy(size->media, pwg->pwg, sizeof(size->media));
2517
2518 size->width = best->width;
2519 size->length = best->length;
2520 size->bottom = best->bottom;
2521 size->left = best->left;
2522 size->right = best->right;
2523 size->top = best->top;
2524
2525 return (1);
2526 }
2527
2528 return (0);
2529}
2530
2531
2532/*
2533 * 'cups_is_close_media_db()' - Compare two media entries to see if they are
2534 * close to the same size.
2535 *
2536 * Currently we use 5 points (from PostScript) as the matching range...
2537 */
2538
2539static int /* O - 1 if the sizes are close */
2540cups_is_close_media_db(
2541 _cups_media_db_t *a, /* I - First media entries */
2542 _cups_media_db_t *b) /* I - Second media entries */
2543{
2544 int dwidth, /* Difference in width */
2545 dlength; /* Difference in length */
2546
2547
2548 dwidth = a->width - b->width;
2549 dlength = a->length - b->length;
2550
2551 return (dwidth >= -176 && dwidth <= 176 &&
2552 dlength >= -176 && dlength <= 176);
2553}
2554
2555
a29fd7dd
MS
2556/*
2557 * 'cups_test_constraints()' - Test constraints.
a29fd7dd
MS
2558 */
2559
2560static cups_array_t * /* O - Active constraints */
2561cups_test_constraints(
2562 cups_dinfo_t *dinfo, /* I - Destination information */
2563 const char *new_option, /* I - Newly selected option */
2564 const char *new_value, /* I - Newly selected value */
2565 int num_options, /* I - Number of options */
2566 cups_option_t *options, /* I - Options */
2567 int *num_conflicts, /* O - Number of conflicting options */
2568 cups_option_t **conflicts) /* O - Conflicting options */
2569{
2570 int i, /* Looping var */
336b669e 2571 count, /* Number of values */
a29fd7dd
MS
2572 match; /* Value matches? */
2573 int num_matching; /* Number of matching options */
2574 cups_option_t *matching; /* Matching options */
2575 _cups_dconstres_t *c; /* Current constraint */
2576 cups_array_t *active = NULL; /* Active constraints */
336b669e 2577 ipp_t *col; /* Collection value */
a29fd7dd
MS
2578 ipp_attribute_t *attr; /* Current attribute */
2579 _ipp_value_t *attrval; /* Current attribute value */
2580 const char *value; /* Current value */
2581 char temp[1024]; /* Temporary string */
2582 int int_value; /* Integer value */
2583 int xres_value, /* Horizontal resolution */
2584 yres_value; /* Vertical resolution */
2585 ipp_res_t units_value; /* Resolution units */
2586
2587
2588 for (c = (_cups_dconstres_t *)cupsArrayFirst(dinfo->constraints);
2589 c;
2590 c = (_cups_dconstres_t *)cupsArrayNext(dinfo->constraints))
2591 {
2592 num_matching = 0;
2593 matching = NULL;
2594
2595 for (attr = ippFirstAttribute(c->collection);
2596 attr;
2597 attr = ippNextAttribute(c->collection))
2598 {
a29fd7dd
MS
2599 /*
2600 * Get the value for the current attribute in the constraint...
2601 */
2602
2603 if (new_option && new_value && !strcmp(attr->name, new_option))
2604 value = new_value;
336b669e 2605 else if ((value = cupsGetOption(attr->name, num_options, options)) == NULL)
a29fd7dd
MS
2606 value = cupsGetOption(attr->name, dinfo->num_defaults, dinfo->defaults);
2607
2608 if (!value)
2609 {
2610 /*
2611 * Not set so this constraint does not apply...
2612 */
2613
2614 break;
2615 }
2616
2617 match = 0;
2618
2619 switch (attr->value_tag)
2620 {
2621 case IPP_TAG_INTEGER :
2622 case IPP_TAG_ENUM :
2623 int_value = atoi(value);
2624
2625 for (i = attr->num_values, attrval = attr->values;
2626 i > 0;
2627 i --, attrval ++)
2628 {
2629 if (attrval->integer == int_value)
2630 {
2631 match = 1;
2632 break;
2633 }
2634 }
2635 break;
2636
2637 case IPP_TAG_BOOLEAN :
2638 int_value = !strcmp(value, "true");
2639
2640 for (i = attr->num_values, attrval = attr->values;
2641 i > 0;
2642 i --, attrval ++)
2643 {
2644 if (attrval->boolean == int_value)
2645 {
2646 match = 1;
2647 break;
2648 }
2649 }
2650 break;
2651
2652 case IPP_TAG_RANGE :
2653 int_value = atoi(value);
2654
2655 for (i = attr->num_values, attrval = attr->values;
2656 i > 0;
2657 i --, attrval ++)
2658 {
2659 if (int_value >= attrval->range.lower &&
2660 int_value <= attrval->range.upper)
2661 {
2662 match = 1;
2663 break;
2664 }
2665 }
2666 break;
2667
2668 case IPP_TAG_RESOLUTION :
2669 if (sscanf(value, "%dx%d%15s", &xres_value, &yres_value, temp) != 3)
2670 {
2671 if (sscanf(value, "%d%15s", &xres_value, temp) != 2)
2672 break;
2673
2674 yres_value = xres_value;
2675 }
2676
2677 if (!strcmp(temp, "dpi"))
2678 units_value = IPP_RES_PER_INCH;
2679 else if (!strcmp(temp, "dpc") || !strcmp(temp, "dpcm"))
2680 units_value = IPP_RES_PER_CM;
2681 else
2682 break;
2683
2684 for (i = attr->num_values, attrval = attr->values;
2685 i > 0;
2686 i --, attrval ++)
2687 {
2688 if (attrval->resolution.xres == xres_value &&
2689 attrval->resolution.yres == yres_value &&
2690 attrval->resolution.units == units_value)
2691 {
2692 match = 1;
2693 break;
2694 }
2695 }
2696 break;
2697
2698 case IPP_TAG_TEXT :
2699 case IPP_TAG_NAME :
2700 case IPP_TAG_KEYWORD :
2701 case IPP_TAG_CHARSET :
2702 case IPP_TAG_URI :
2703 case IPP_TAG_URISCHEME :
2704 case IPP_TAG_MIMETYPE :
2705 case IPP_TAG_LANGUAGE :
2706 case IPP_TAG_TEXTLANG :
2707 case IPP_TAG_NAMELANG :
2708 for (i = attr->num_values, attrval = attr->values;
2709 i > 0;
2710 i --, attrval ++)
2711 {
2712 if (!strcmp(attrval->string.text, value))
2713 {
2714 match = 1;
2715 break;
2716 }
2717 }
2718 break;
2719
336b669e
MS
2720 case IPP_TAG_BEGIN_COLLECTION :
2721 col = ippNew();
2722 _cupsEncodeOption(col, IPP_TAG_ZERO, NULL, ippGetName(attr), value);
2723
2724 for (i = 0, count = ippGetCount(attr); i < count; i ++)
2725 {
2726 if (cups_collection_contains(col, ippGetCollection(attr, i)))
2727 {
2728 match = 1;
2729 break;
2730 }
2731 }
2732
2733 ippDelete(col);
2734 break;
2735
a29fd7dd
MS
2736 default :
2737 break;
2738 }
2739
2740 if (!match)
2741 break;
2742
2743 num_matching = cupsAddOption(attr->name, value, num_matching, &matching);
2744 }
2745
2746 if (!attr)
2747 {
2748 if (!active)
2749 active = cupsArrayNew(NULL, NULL);
2750
2751 cupsArrayAdd(active, c);
2752
2753 if (num_conflicts && conflicts)
2754 {
2755 cups_option_t *moption; /* Matching option */
2756
2757 for (i = num_matching, moption = matching; i > 0; i --, moption ++)
336b669e 2758 *num_conflicts = cupsAddOption(moption->name, moption->value, *num_conflicts, conflicts);
a29fd7dd
MS
2759 }
2760 }
2761
2762 cupsFreeOptions(num_matching, matching);
2763 }
2764
2765 return (active);
2766}
2767
2768
6961465f
MS
2769/*
2770 * 'cups_update_ready()' - Update xxx-ready attributes for the printer.
2771 */
2772
2773static void
2774cups_update_ready(http_t *http, /* I - Connection to destination */
2775 cups_dinfo_t *dinfo) /* I - Destination information */
2776{
2777 ipp_t *request; /* Get-Printer-Attributes request */
2778 static const char * const pattrs[] = /* Printer attributes we want */
2779 {
2780 "finishings-col-ready",
2781 "finishings-ready",
2782 "job-finishings-col-ready",
2783 "job-finishings-ready",
2784 "media-col-ready",
2785 "media-ready"
2786 };
2787
2788
2789 /*
2790 * Don't update more than once every 30 seconds...
2791 */
2792
2793 if ((time(NULL) - dinfo->ready_time) < _CUPS_MEDIA_READY_TTL)
2794 return;
2795
2796 /*
2797 * Free any previous results...
2798 */
2799
2800 if (dinfo->cached_flags & CUPS_MEDIA_FLAGS_READY)
2801 {
2802 cupsArrayDelete(dinfo->cached_db);
2803 dinfo->cached_db = NULL;
2804 dinfo->cached_flags = CUPS_MEDIA_FLAGS_DEFAULT;
2805 }
2806
2807 ippDelete(dinfo->ready_attrs);
2808 dinfo->ready_attrs = NULL;
2809
2810 cupsArrayDelete(dinfo->ready_db);
2811 dinfo->ready_db = NULL;
2812
2813 /*
2814 * Query the xxx-ready values...
2815 */
2816
2817 request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
2818 ippSetVersion(request, dinfo->version / 10, dinfo->version % 10);
2819
2820 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
2821 dinfo->uri);
2822 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
2823 NULL, cupsUser());
7e86f2f6 2824 ippAddStrings(request, IPP_TAG_OPERATION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs);
6961465f
MS
2825
2826 dinfo->ready_attrs = cupsDoRequest(http, request, dinfo->resource);
2827
2828 /*
2829 * Update the ready media database...
2830 */
2831
2832 cups_create_media_db(dinfo, CUPS_MEDIA_FLAGS_READY);
2833
2834 /*
2835 * Update last lookup time and return...
2836 */
2837
2838 dinfo->ready_time = time(NULL);
2839}