]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/ipp.c
06fdc69b364fa49a7edd03acd6f1ca96e0f91677
[thirdparty/cups.git] / cups / ipp.c
1 /*
2 * Internet Printing Protocol functions for CUPS.
3 *
4 * Copyright © 2007-2018 by Apple Inc.
5 * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
8 * information.
9 */
10
11 /*
12 * Include necessary headers...
13 */
14
15 #include "cups-private.h"
16 #include <regex.h>
17 #ifdef _WIN32
18 # include <io.h>
19 #endif /* _WIN32 */
20
21
22 /*
23 * Local functions...
24 */
25
26 static ipp_attribute_t *ipp_add_attr(ipp_t *ipp, const char *name,
27 ipp_tag_t group_tag, ipp_tag_t value_tag,
28 int num_values);
29 static void ipp_free_values(ipp_attribute_t *attr, int element,
30 int count);
31 static char *ipp_get_code(const char *locale, char *buffer, size_t bufsize) _CUPS_NONNULL(1,2);
32 static char *ipp_lang_code(const char *locale, char *buffer, size_t bufsize) _CUPS_NONNULL(1,2);
33 static size_t ipp_length(ipp_t *ipp, int collection);
34 static ssize_t ipp_read_http(http_t *http, ipp_uchar_t *buffer,
35 size_t length);
36 static ssize_t ipp_read_file(int *fd, ipp_uchar_t *buffer,
37 size_t length);
38 static void ipp_set_error(ipp_status_t status, const char *format,
39 ...);
40 static _ipp_value_t *ipp_set_value(ipp_t *ipp, ipp_attribute_t **attr,
41 int element);
42 static ssize_t ipp_write_file(int *fd, ipp_uchar_t *buffer,
43 size_t length);
44
45
46 /*
47 * '_cupsBufferGet()' - Get a read/write buffer.
48 */
49
50 char * /* O - Buffer */
51 _cupsBufferGet(size_t size) /* I - Size required */
52 {
53 _cups_buffer_t *buffer; /* Current buffer */
54 _cups_globals_t *cg = _cupsGlobals();
55 /* Global data */
56
57
58 for (buffer = cg->cups_buffers; buffer; buffer = buffer->next)
59 if (!buffer->used && buffer->size >= size)
60 break;
61
62 if (!buffer)
63 {
64 if ((buffer = malloc(sizeof(_cups_buffer_t) + size - 1)) == NULL)
65 return (NULL);
66
67 buffer->next = cg->cups_buffers;
68 buffer->size = size;
69 cg->cups_buffers = buffer;
70 }
71
72 buffer->used = 1;
73
74 return (buffer->d);
75 }
76
77
78 /*
79 * '_cupsBufferRelease()' - Release a read/write buffer.
80 */
81
82 void
83 _cupsBufferRelease(char *b) /* I - Buffer to release */
84 {
85 _cups_buffer_t *buffer; /* Buffer */
86
87
88 /*
89 * Mark this buffer as unused...
90 */
91
92 buffer = (_cups_buffer_t *)(b - offsetof(_cups_buffer_t, d));
93 buffer->used = 0;
94 }
95
96
97 /*
98 * 'ippAddBoolean()' - Add a boolean attribute to an IPP message.
99 *
100 * The @code ipp@ parameter refers to an IPP message previously created using
101 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
102 *
103 * The @code group@ parameter specifies the IPP attribute group tag: none
104 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
105 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
106 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
107 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
108 */
109
110 ipp_attribute_t * /* O - New attribute */
111 ippAddBoolean(ipp_t *ipp, /* I - IPP message */
112 ipp_tag_t group, /* I - IPP group */
113 const char *name, /* I - Name of attribute */
114 char value) /* I - Value of attribute */
115 {
116 ipp_attribute_t *attr; /* New attribute */
117
118
119 DEBUG_printf(("ippAddBoolean(ipp=%p, group=%02x(%s), name=\"%s\", value=%d)", (void *)ipp, group, ippTagString(group), name, value));
120
121 /*
122 * Range check input...
123 */
124
125 if (!ipp || !name || group < IPP_TAG_ZERO ||
126 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
127 return (NULL);
128
129 /*
130 * Create the attribute...
131 */
132
133 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BOOLEAN, 1)) == NULL)
134 return (NULL);
135
136 attr->values[0].boolean = value;
137
138 return (attr);
139 }
140
141
142 /*
143 * 'ippAddBooleans()' - Add an array of boolean values.
144 *
145 * The @code ipp@ parameter refers to an IPP message previously created using
146 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
147 *
148 * The @code group@ parameter specifies the IPP attribute group tag: none
149 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
150 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
151 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
152 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
153 */
154
155 ipp_attribute_t * /* O - New attribute */
156 ippAddBooleans(ipp_t *ipp, /* I - IPP message */
157 ipp_tag_t group, /* I - IPP group */
158 const char *name, /* I - Name of attribute */
159 int num_values, /* I - Number of values */
160 const char *values) /* I - Values */
161 {
162 int i; /* Looping var */
163 ipp_attribute_t *attr; /* New attribute */
164 _ipp_value_t *value; /* Current value */
165
166
167 DEBUG_printf(("ippAddBooleans(ipp=%p, group=%02x(%s), name=\"%s\", num_values=%d, values=%p)", (void *)ipp, group, ippTagString(group), name, num_values, (void *)values));
168
169 /*
170 * Range check input...
171 */
172
173 if (!ipp || !name || group < IPP_TAG_ZERO ||
174 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
175 num_values < 1)
176 return (NULL);
177
178 /*
179 * Create the attribute...
180 */
181
182 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BOOLEAN, num_values)) == NULL)
183 return (NULL);
184
185 if (values)
186 {
187 for (i = num_values, value = attr->values;
188 i > 0;
189 i --, value ++)
190 value->boolean = *values++;
191 }
192
193 return (attr);
194 }
195
196
197 /*
198 * 'ippAddCollection()' - Add a collection value.
199 *
200 * The @code ipp@ parameter refers to an IPP message previously created using
201 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
202 *
203 * The @code group@ parameter specifies the IPP attribute group tag: none
204 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
205 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
206 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
207 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
208 *
209 * @since CUPS 1.1.19/macOS 10.3@
210 */
211
212 ipp_attribute_t * /* O - New attribute */
213 ippAddCollection(ipp_t *ipp, /* I - IPP message */
214 ipp_tag_t group, /* I - IPP group */
215 const char *name, /* I - Name of attribute */
216 ipp_t *value) /* I - Value */
217 {
218 ipp_attribute_t *attr; /* New attribute */
219
220
221 DEBUG_printf(("ippAddCollection(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)", (void *)ipp, group, ippTagString(group), name, (void *)value));
222
223 /*
224 * Range check input...
225 */
226
227 if (!ipp || !name || group < IPP_TAG_ZERO ||
228 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
229 return (NULL);
230
231 /*
232 * Create the attribute...
233 */
234
235 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BEGIN_COLLECTION, 1)) == NULL)
236 return (NULL);
237
238 attr->values[0].collection = value;
239
240 if (value)
241 value->use ++;
242
243 return (attr);
244 }
245
246
247 /*
248 * 'ippAddCollections()' - Add an array of collection values.
249 *
250 * The @code ipp@ parameter refers to an IPP message previously created using
251 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
252 *
253 * The @code group@ parameter specifies the IPP attribute group tag: none
254 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
255 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
256 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
257 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
258 *
259 * @since CUPS 1.1.19/macOS 10.3@
260 */
261
262 ipp_attribute_t * /* O - New attribute */
263 ippAddCollections(
264 ipp_t *ipp, /* I - IPP message */
265 ipp_tag_t group, /* I - IPP group */
266 const char *name, /* I - Name of attribute */
267 int num_values, /* I - Number of values */
268 const ipp_t **values) /* I - Values */
269 {
270 int i; /* Looping var */
271 ipp_attribute_t *attr; /* New attribute */
272 _ipp_value_t *value; /* Current value */
273
274
275 DEBUG_printf(("ippAddCollections(ipp=%p, group=%02x(%s), name=\"%s\", num_values=%d, values=%p)", (void *)ipp, group, ippTagString(group), name, num_values, (void *)values));
276
277 /*
278 * Range check input...
279 */
280
281 if (!ipp || !name || group < IPP_TAG_ZERO ||
282 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
283 num_values < 1)
284 return (NULL);
285
286 /*
287 * Create the attribute...
288 */
289
290 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BEGIN_COLLECTION,
291 num_values)) == NULL)
292 return (NULL);
293
294 if (values)
295 {
296 for (i = num_values, value = attr->values;
297 i > 0;
298 i --, value ++)
299 {
300 value->collection = (ipp_t *)*values++;
301 value->collection->use ++;
302 }
303 }
304
305 return (attr);
306 }
307
308
309 /*
310 * 'ippAddDate()' - Add a dateTime attribute to an IPP message.
311 *
312 * The @code ipp@ parameter refers to an IPP message previously created using
313 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
314 *
315 * The @code group@ parameter specifies the IPP attribute group tag: none
316 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
317 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
318 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
319 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
320 */
321
322 ipp_attribute_t * /* O - New attribute */
323 ippAddDate(ipp_t *ipp, /* I - IPP message */
324 ipp_tag_t group, /* I - IPP group */
325 const char *name, /* I - Name of attribute */
326 const ipp_uchar_t *value) /* I - Value */
327 {
328 ipp_attribute_t *attr; /* New attribute */
329
330
331 DEBUG_printf(("ippAddDate(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)", (void *)ipp, group, ippTagString(group), name, (void *)value));
332
333 /*
334 * Range check input...
335 */
336
337 if (!ipp || !name || !value || group < IPP_TAG_ZERO ||
338 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
339 return (NULL);
340
341 /*
342 * Create the attribute...
343 */
344
345 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_DATE, 1)) == NULL)
346 return (NULL);
347
348 memcpy(attr->values[0].date, value, 11);
349
350 return (attr);
351 }
352
353
354 /*
355 * 'ippAddInteger()' - Add a integer attribute to an IPP message.
356 *
357 * The @code ipp@ parameter refers to an IPP message previously created using
358 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
359 *
360 * The @code group@ parameter specifies the IPP attribute group tag: none
361 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
362 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
363 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
364 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
365 *
366 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
367 * (@code IPP_TAG_INTEGER@).
368 */
369
370 ipp_attribute_t * /* O - New attribute */
371 ippAddInteger(ipp_t *ipp, /* I - IPP message */
372 ipp_tag_t group, /* I - IPP group */
373 ipp_tag_t value_tag, /* I - Type of attribute */
374 const char *name, /* I - Name of attribute */
375 int value) /* I - Value of attribute */
376 {
377 ipp_attribute_t *attr; /* New attribute */
378
379
380 DEBUG_printf(("ippAddInteger(ipp=%p, group=%02x(%s), type=%02x(%s), name=\"%s\", value=%d)", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name, value));
381
382 value_tag &= IPP_TAG_CUPS_MASK;
383
384 /*
385 * Special-case for legacy usage: map out-of-band attributes to new ippAddOutOfBand
386 * function...
387 */
388
389 if (value_tag >= IPP_TAG_UNSUPPORTED_VALUE && value_tag <= IPP_TAG_ADMINDEFINE)
390 return (ippAddOutOfBand(ipp, group, value_tag, name));
391
392 /*
393 * Range check input...
394 */
395
396 #if 0
397 if (!ipp || !name || group < IPP_TAG_ZERO ||
398 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
399 (value_tag != IPP_TAG_INTEGER && value_tag != IPP_TAG_ENUM))
400 return (NULL);
401 #else
402 if (!ipp || !name || group < IPP_TAG_ZERO ||
403 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
404 return (NULL);
405 #endif /* 0 */
406
407 /*
408 * Create the attribute...
409 */
410
411 if ((attr = ipp_add_attr(ipp, name, group, value_tag, 1)) == NULL)
412 return (NULL);
413
414 attr->values[0].integer = value;
415
416 return (attr);
417 }
418
419
420 /*
421 * 'ippAddIntegers()' - Add an array of integer values.
422 *
423 * The @code ipp@ parameter refers to an IPP message previously created using
424 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
425 *
426 * The @code group@ parameter specifies the IPP attribute group tag: none
427 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
428 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
429 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
430 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
431 *
432 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
433 * (@code IPP_TAG_INTEGER@).
434 */
435
436 ipp_attribute_t * /* O - New attribute */
437 ippAddIntegers(ipp_t *ipp, /* I - IPP message */
438 ipp_tag_t group, /* I - IPP group */
439 ipp_tag_t value_tag, /* I - Type of attribute */
440 const char *name, /* I - Name of attribute */
441 int num_values, /* I - Number of values */
442 const int *values) /* I - Values */
443 {
444 int i; /* Looping var */
445 ipp_attribute_t *attr; /* New attribute */
446 _ipp_value_t *value; /* Current value */
447
448
449 DEBUG_printf(("ippAddIntegers(ipp=%p, group=%02x(%s), type=%02x(%s), name=\"%s\", num_values=%d, values=%p)", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name, num_values, (void *)values));
450
451 value_tag &= IPP_TAG_CUPS_MASK;
452
453 /*
454 * Range check input...
455 */
456
457 #if 0
458 if (!ipp || !name || group < IPP_TAG_ZERO ||
459 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
460 (value_tag != IPP_TAG_INTEGER && value_tag != IPP_TAG_ENUM) ||
461 num_values < 1)
462 return (NULL);
463 #else
464 if (!ipp || !name || group < IPP_TAG_ZERO ||
465 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
466 num_values < 1)
467 return (NULL);
468 #endif /* 0 */
469
470 /*
471 * Create the attribute...
472 */
473
474 if ((attr = ipp_add_attr(ipp, name, group, value_tag, num_values)) == NULL)
475 return (NULL);
476
477 if (values)
478 {
479 for (i = num_values, value = attr->values;
480 i > 0;
481 i --, value ++)
482 value->integer = *values++;
483 }
484
485 return (attr);
486 }
487
488
489 /*
490 * 'ippAddOctetString()' - Add an octetString value to an IPP message.
491 *
492 * The @code ipp@ parameter refers to an IPP message previously created using
493 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
494 *
495 * The @code group@ parameter specifies the IPP attribute group tag: none
496 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
497 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
498 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
499 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
500 *
501 * @since CUPS 1.2/macOS 10.5@
502 */
503
504 ipp_attribute_t * /* O - New attribute */
505 ippAddOctetString(ipp_t *ipp, /* I - IPP message */
506 ipp_tag_t group, /* I - IPP group */
507 const char *name, /* I - Name of attribute */
508 const void *data, /* I - octetString data */
509 int datalen) /* I - Length of data in bytes */
510 {
511 ipp_attribute_t *attr; /* New attribute */
512
513
514 if (!ipp || !name || group < IPP_TAG_ZERO ||
515 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
516 datalen < 0 || datalen > IPP_MAX_LENGTH)
517 return (NULL);
518
519 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_STRING, 1)) == NULL)
520 return (NULL);
521
522 /*
523 * Initialize the attribute data...
524 */
525
526 attr->values[0].unknown.length = datalen;
527
528 if (data)
529 {
530 if ((attr->values[0].unknown.data = malloc((size_t)datalen)) == NULL)
531 {
532 ippDeleteAttribute(ipp, attr);
533 return (NULL);
534 }
535
536 memcpy(attr->values[0].unknown.data, data, (size_t)datalen);
537 }
538
539 /*
540 * Return the new attribute...
541 */
542
543 return (attr);
544 }
545
546
547 /*
548 * 'ippAddOutOfBand()' - Add an out-of-band value to an IPP message.
549 *
550 * The @code ipp@ parameter refers to an IPP message previously created using
551 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
552 *
553 * The @code group@ parameter specifies the IPP attribute group tag: none
554 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
555 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
556 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
557 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
558 *
559 * Supported out-of-band values include unsupported-value
560 * (@code IPP_TAG_UNSUPPORTED_VALUE@), default (@code IPP_TAG_DEFAULT@), unknown
561 * (@code IPP_TAG_UNKNOWN@), no-value (@code IPP_TAG_NOVALUE@), not-settable
562 * (@code IPP_TAG_NOTSETTABLE@), delete-attribute (@code IPP_TAG_DELETEATTR@), and
563 * admin-define (@code IPP_TAG_ADMINDEFINE@).
564 *
565 * @since CUPS 1.6/macOS 10.8@
566 */
567
568 ipp_attribute_t * /* O - New attribute */
569 ippAddOutOfBand(ipp_t *ipp, /* I - IPP message */
570 ipp_tag_t group, /* I - IPP group */
571 ipp_tag_t value_tag, /* I - Type of attribute */
572 const char *name) /* I - Name of attribute */
573 {
574 DEBUG_printf(("ippAddOutOfBand(ipp=%p, group=%02x(%s), value_tag=%02x(%s), name=\"%s\")", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name));
575
576 value_tag &= IPP_TAG_CUPS_MASK;
577
578 /*
579 * Range check input...
580 */
581
582 if (!ipp || !name || group < IPP_TAG_ZERO ||
583 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
584 (value_tag != IPP_TAG_UNSUPPORTED_VALUE &&
585 value_tag != IPP_TAG_DEFAULT &&
586 value_tag != IPP_TAG_UNKNOWN &&
587 value_tag != IPP_TAG_NOVALUE &&
588 value_tag != IPP_TAG_NOTSETTABLE &&
589 value_tag != IPP_TAG_DELETEATTR &&
590 value_tag != IPP_TAG_ADMINDEFINE))
591 return (NULL);
592
593 /*
594 * Create the attribute...
595 */
596
597 return (ipp_add_attr(ipp, name, group, value_tag, 1));
598 }
599
600
601 /*
602 * 'ippAddRange()' - Add a range of values to an IPP message.
603 *
604 * The @code ipp@ parameter refers to an IPP message previously created using
605 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
606 *
607 * The @code group@ parameter specifies the IPP attribute group tag: none
608 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
609 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
610 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
611 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
612 *
613 * The @code lower@ parameter must be less than or equal to the @code upper@ parameter.
614 */
615
616 ipp_attribute_t * /* O - New attribute */
617 ippAddRange(ipp_t *ipp, /* I - IPP message */
618 ipp_tag_t group, /* I - IPP group */
619 const char *name, /* I - Name of attribute */
620 int lower, /* I - Lower value */
621 int upper) /* I - Upper value */
622 {
623 ipp_attribute_t *attr; /* New attribute */
624
625
626 DEBUG_printf(("ippAddRange(ipp=%p, group=%02x(%s), name=\"%s\", lower=%d, upper=%d)", (void *)ipp, group, ippTagString(group), name, lower, upper));
627
628 /*
629 * Range check input...
630 */
631
632 if (!ipp || !name || group < IPP_TAG_ZERO ||
633 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
634 return (NULL);
635
636 /*
637 * Create the attribute...
638 */
639
640 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RANGE, 1)) == NULL)
641 return (NULL);
642
643 attr->values[0].range.lower = lower;
644 attr->values[0].range.upper = upper;
645
646 return (attr);
647 }
648
649
650 /*
651 * 'ippAddRanges()' - Add ranges of values to an IPP message.
652 *
653 * The @code ipp@ parameter refers to an IPP message previously created using
654 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
655 *
656 * The @code group@ parameter specifies the IPP attribute group tag: none
657 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
658 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
659 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
660 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
661 */
662
663 ipp_attribute_t * /* O - New attribute */
664 ippAddRanges(ipp_t *ipp, /* I - IPP message */
665 ipp_tag_t group, /* I - IPP group */
666 const char *name, /* I - Name of attribute */
667 int num_values, /* I - Number of values */
668 const int *lower, /* I - Lower values */
669 const int *upper) /* I - Upper values */
670 {
671 int i; /* Looping var */
672 ipp_attribute_t *attr; /* New attribute */
673 _ipp_value_t *value; /* Current value */
674
675
676 DEBUG_printf(("ippAddRanges(ipp=%p, group=%02x(%s), name=\"%s\", num_values=%d, lower=%p, upper=%p)", (void *)ipp, group, ippTagString(group), name, num_values, (void *)lower, (void *)upper));
677
678 /*
679 * Range check input...
680 */
681
682 if (!ipp || !name || group < IPP_TAG_ZERO ||
683 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
684 num_values < 1)
685 return (NULL);
686
687 /*
688 * Create the attribute...
689 */
690
691 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RANGE, num_values)) == NULL)
692 return (NULL);
693
694 if (lower && upper)
695 {
696 for (i = num_values, value = attr->values;
697 i > 0;
698 i --, value ++)
699 {
700 value->range.lower = *lower++;
701 value->range.upper = *upper++;
702 }
703 }
704
705 return (attr);
706 }
707
708
709 /*
710 * 'ippAddResolution()' - Add a resolution value to an IPP message.
711 *
712 * The @code ipp@ parameter refers to an IPP message previously created using
713 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
714 *
715 * The @code group@ parameter specifies the IPP attribute group tag: none
716 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
717 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
718 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
719 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
720 */
721
722 ipp_attribute_t * /* O - New attribute */
723 ippAddResolution(ipp_t *ipp, /* I - IPP message */
724 ipp_tag_t group, /* I - IPP group */
725 const char *name, /* I - Name of attribute */
726 ipp_res_t units, /* I - Units for resolution */
727 int xres, /* I - X resolution */
728 int yres) /* I - Y resolution */
729 {
730 ipp_attribute_t *attr; /* New attribute */
731
732
733 DEBUG_printf(("ippAddResolution(ipp=%p, group=%02x(%s), name=\"%s\", units=%d, xres=%d, yres=%d)", (void *)ipp, group,
734 ippTagString(group), name, units, xres, yres));
735
736 /*
737 * Range check input...
738 */
739
740 if (!ipp || !name || group < IPP_TAG_ZERO ||
741 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
742 units < IPP_RES_PER_INCH || units > IPP_RES_PER_CM ||
743 xres < 0 || yres < 0)
744 return (NULL);
745
746 /*
747 * Create the attribute...
748 */
749
750 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RESOLUTION, 1)) == NULL)
751 return (NULL);
752
753 attr->values[0].resolution.xres = xres;
754 attr->values[0].resolution.yres = yres;
755 attr->values[0].resolution.units = units;
756
757 return (attr);
758 }
759
760
761 /*
762 * 'ippAddResolutions()' - Add resolution values to an IPP message.
763 *
764 * The @code ipp@ parameter refers to an IPP message previously created using
765 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
766 *
767 * The @code group@ parameter specifies the IPP attribute group tag: none
768 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
769 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
770 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
771 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
772 */
773
774 ipp_attribute_t * /* O - New attribute */
775 ippAddResolutions(ipp_t *ipp, /* I - IPP message */
776 ipp_tag_t group, /* I - IPP group */
777 const char *name, /* I - Name of attribute */
778 int num_values,/* I - Number of values */
779 ipp_res_t units, /* I - Units for resolution */
780 const int *xres, /* I - X resolutions */
781 const int *yres) /* I - Y resolutions */
782 {
783 int i; /* Looping var */
784 ipp_attribute_t *attr; /* New attribute */
785 _ipp_value_t *value; /* Current value */
786
787
788 DEBUG_printf(("ippAddResolutions(ipp=%p, group=%02x(%s), name=\"%s\", num_value=%d, units=%d, xres=%p, yres=%p)", (void *)ipp, group, ippTagString(group), name, num_values, units, (void *)xres, (void *)yres));
789
790 /*
791 * Range check input...
792 */
793
794 if (!ipp || !name || group < IPP_TAG_ZERO ||
795 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
796 num_values < 1 ||
797 units < IPP_RES_PER_INCH || units > IPP_RES_PER_CM)
798 return (NULL);
799
800 /*
801 * Create the attribute...
802 */
803
804 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RESOLUTION, num_values)) == NULL)
805 return (NULL);
806
807 if (xres && yres)
808 {
809 for (i = num_values, value = attr->values;
810 i > 0;
811 i --, value ++)
812 {
813 value->resolution.xres = *xres++;
814 value->resolution.yres = *yres++;
815 value->resolution.units = units;
816 }
817 }
818
819 return (attr);
820 }
821
822
823 /*
824 * 'ippAddSeparator()' - Add a group separator to an IPP message.
825 *
826 * The @code ipp@ parameter refers to an IPP message previously created using
827 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
828 */
829
830 ipp_attribute_t * /* O - New attribute */
831 ippAddSeparator(ipp_t *ipp) /* I - IPP message */
832 {
833 DEBUG_printf(("ippAddSeparator(ipp=%p)", (void *)ipp));
834
835 /*
836 * Range check input...
837 */
838
839 if (!ipp)
840 return (NULL);
841
842 /*
843 * Create the attribute...
844 */
845
846 return (ipp_add_attr(ipp, NULL, IPP_TAG_ZERO, IPP_TAG_ZERO, 0));
847 }
848
849
850 /*
851 * 'ippAddString()' - Add a language-encoded string to an IPP message.
852 *
853 * The @code ipp@ parameter refers to an IPP message previously created using
854 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
855 *
856 * The @code group@ parameter specifies the IPP attribute group tag: none
857 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
858 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
859 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
860 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
861 *
862 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
863 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
864 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
865 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
866 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
867 * (@code IPP_TAG_URISCHEME@).
868 *
869 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
870 * textWithLanguage string values and must be @code NULL@ for all other string values.
871 */
872
873 ipp_attribute_t * /* O - New attribute */
874 ippAddString(ipp_t *ipp, /* I - IPP message */
875 ipp_tag_t group, /* I - IPP group */
876 ipp_tag_t value_tag, /* I - Type of attribute */
877 const char *name, /* I - Name of attribute */
878 const char *language, /* I - Language code */
879 const char *value) /* I - Value */
880 {
881 ipp_tag_t temp_tag; /* Temporary value tag (masked) */
882 ipp_attribute_t *attr; /* New attribute */
883 char code[IPP_MAX_LANGUAGE];
884 /* Charset/language code buffer */
885
886
887 DEBUG_printf(("ippAddString(ipp=%p, group=%02x(%s), value_tag=%02x(%s), name=\"%s\", language=\"%s\", value=\"%s\")", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name, language, value));
888
889 /*
890 * Range check input...
891 */
892
893 temp_tag = (ipp_tag_t)((int)value_tag & IPP_TAG_CUPS_MASK);
894
895 #if 0
896 if (!ipp || !name || group < IPP_TAG_ZERO ||
897 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
898 (temp_tag < IPP_TAG_TEXT && temp_tag != IPP_TAG_TEXTLANG &&
899 temp_tag != IPP_TAG_NAMELANG) || temp_tag > IPP_TAG_MIMETYPE)
900 return (NULL);
901
902 if ((temp_tag == IPP_TAG_TEXTLANG || temp_tag == IPP_TAG_NAMELANG)
903 != (language != NULL))
904 return (NULL);
905 #else
906 if (!ipp || !name || group < IPP_TAG_ZERO ||
907 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
908 return (NULL);
909 #endif /* 0 */
910
911 /*
912 * See if we need to map charset, language, or locale values...
913 */
914
915 if (language && ((int)value_tag & IPP_TAG_CUPS_CONST) &&
916 strcmp(language, ipp_lang_code(language, code, sizeof(code))))
917 value_tag = temp_tag; /* Don't do a fast copy */
918 else if (value && value_tag == (ipp_tag_t)(IPP_TAG_CHARSET | IPP_TAG_CUPS_CONST) &&
919 strcmp(value, ipp_get_code(value, code, sizeof(code))))
920 value_tag = temp_tag; /* Don't do a fast copy */
921 else if (value && value_tag == (ipp_tag_t)(IPP_TAG_LANGUAGE | IPP_TAG_CUPS_CONST) &&
922 strcmp(value, ipp_lang_code(value, code, sizeof(code))))
923 value_tag = temp_tag; /* Don't do a fast copy */
924
925 /*
926 * Create the attribute...
927 */
928
929 if ((attr = ipp_add_attr(ipp, name, group, value_tag, 1)) == NULL)
930 return (NULL);
931
932 /*
933 * Initialize the attribute data...
934 */
935
936 if ((int)value_tag & IPP_TAG_CUPS_CONST)
937 {
938 attr->values[0].string.language = (char *)language;
939 attr->values[0].string.text = (char *)value;
940 }
941 else
942 {
943 if (language)
944 attr->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language, code,
945 sizeof(code)));
946
947 if (value)
948 {
949 if (value_tag == IPP_TAG_CHARSET)
950 attr->values[0].string.text = _cupsStrAlloc(ipp_get_code(value, code,
951 sizeof(code)));
952 else if (value_tag == IPP_TAG_LANGUAGE)
953 attr->values[0].string.text = _cupsStrAlloc(ipp_lang_code(value, code,
954 sizeof(code)));
955 else
956 attr->values[0].string.text = _cupsStrAlloc(value);
957 }
958 }
959
960 return (attr);
961 }
962
963
964 /*
965 * 'ippAddStringf()' - Add a formatted string to an IPP message.
966 *
967 * The @code ipp@ parameter refers to an IPP message previously created using
968 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
969 *
970 * The @code group@ parameter specifies the IPP attribute group tag: none
971 * (@code IPP_TAG_ZERO@, for member attributes), document
972 * (@code IPP_TAG_DOCUMENT@), event notification
973 * (@code IPP_TAG_EVENT_NOTIFICATION@), operation (@code IPP_TAG_OPERATION@),
974 * printer (@code IPP_TAG_PRINTER@), subscription (@code IPP_TAG_SUBSCRIPTION@),
975 * or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
976 *
977 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
978 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
979 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
980 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
981 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
982 * (@code IPP_TAG_URISCHEME@).
983 *
984 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage
985 * and textWithLanguage string values and must be @code NULL@ for all other
986 * string values.
987 *
988 * The @code format@ parameter uses formatting characters compatible with the
989 * printf family of standard functions. Additional arguments follow it as
990 * needed. The formatted string is truncated as needed to the maximum length of
991 * the corresponding value type.
992 *
993 * @since CUPS 1.7/macOS 10.9@
994 */
995
996 ipp_attribute_t * /* O - New attribute */
997 ippAddStringf(ipp_t *ipp, /* I - IPP message */
998 ipp_tag_t group, /* I - IPP group */
999 ipp_tag_t value_tag, /* I - Type of attribute */
1000 const char *name, /* I - Name of attribute */
1001 const char *language, /* I - Language code (@code NULL@ for default) */
1002 const char *format, /* I - Printf-style format string */
1003 ...) /* I - Additional arguments as needed */
1004 {
1005 ipp_attribute_t *attr; /* New attribute */
1006 va_list ap; /* Argument pointer */
1007
1008
1009 va_start(ap, format);
1010 attr = ippAddStringfv(ipp, group, value_tag, name, language, format, ap);
1011 va_end(ap);
1012
1013 return (attr);
1014 }
1015
1016
1017 /*
1018 * 'ippAddStringfv()' - Add a formatted string to an IPP message.
1019 *
1020 * The @code ipp@ parameter refers to an IPP message previously created using
1021 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
1022 *
1023 * The @code group@ parameter specifies the IPP attribute group tag: none
1024 * (@code IPP_TAG_ZERO@, for member attributes), document
1025 * (@code IPP_TAG_DOCUMENT@), event notification
1026 * (@code IPP_TAG_EVENT_NOTIFICATION@), operation (@code IPP_TAG_OPERATION@),
1027 * printer (@code IPP_TAG_PRINTER@), subscription (@code IPP_TAG_SUBSCRIPTION@),
1028 * or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1029 *
1030 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1031 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1032 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1033 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1034 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1035 * (@code IPP_TAG_URISCHEME@).
1036 *
1037 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage
1038 * and textWithLanguage string values and must be @code NULL@ for all other
1039 * string values.
1040 *
1041 * The @code format@ parameter uses formatting characters compatible with the
1042 * printf family of standard functions. Additional arguments are passed in the
1043 * stdarg pointer @code ap@. The formatted string is truncated as needed to the
1044 * maximum length of the corresponding value type.
1045 *
1046 * @since CUPS 1.7/macOS 10.9@
1047 */
1048
1049 ipp_attribute_t * /* O - New attribute */
1050 ippAddStringfv(ipp_t *ipp, /* I - IPP message */
1051 ipp_tag_t group, /* I - IPP group */
1052 ipp_tag_t value_tag, /* I - Type of attribute */
1053 const char *name, /* I - Name of attribute */
1054 const char *language, /* I - Language code (@code NULL@ for default) */
1055 const char *format, /* I - Printf-style format string */
1056 va_list ap) /* I - Additional arguments */
1057 {
1058 char buffer[IPP_MAX_TEXT + 4];
1059 /* Formatted text string */
1060 ssize_t bytes, /* Length of formatted value */
1061 max_bytes; /* Maximum number of bytes for value */
1062
1063
1064 /*
1065 * Range check input...
1066 */
1067
1068 if (!ipp || !name || group < IPP_TAG_ZERO ||
1069 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
1070 (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG &&
1071 value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE ||
1072 !format)
1073 return (NULL);
1074
1075 if ((value_tag == IPP_TAG_TEXTLANG || value_tag == IPP_TAG_NAMELANG)
1076 != (language != NULL))
1077 return (NULL);
1078
1079 /*
1080 * Format the string...
1081 */
1082
1083 if (!strcmp(format, "%s"))
1084 {
1085 /*
1086 * Optimize the simple case...
1087 */
1088
1089 const char *s = va_arg(ap, char *);
1090
1091 if (!s)
1092 s = "(null)";
1093
1094 bytes = (ssize_t)strlen(s);
1095 strlcpy(buffer, s, sizeof(buffer));
1096 }
1097 else
1098 {
1099 /*
1100 * Do a full formatting of the message...
1101 */
1102
1103 if ((bytes = vsnprintf(buffer, sizeof(buffer), format, ap)) < 0)
1104 return (NULL);
1105 }
1106
1107 /*
1108 * Limit the length of the string...
1109 */
1110
1111 switch (value_tag)
1112 {
1113 default :
1114 case IPP_TAG_TEXT :
1115 case IPP_TAG_TEXTLANG :
1116 max_bytes = IPP_MAX_TEXT;
1117 break;
1118
1119 case IPP_TAG_NAME :
1120 case IPP_TAG_NAMELANG :
1121 max_bytes = IPP_MAX_NAME;
1122 break;
1123
1124 case IPP_TAG_CHARSET :
1125 max_bytes = IPP_MAX_CHARSET;
1126 break;
1127
1128 case IPP_TAG_KEYWORD :
1129 max_bytes = IPP_MAX_KEYWORD;
1130 break;
1131
1132 case IPP_TAG_LANGUAGE :
1133 max_bytes = IPP_MAX_LANGUAGE;
1134 break;
1135
1136 case IPP_TAG_MIMETYPE :
1137 max_bytes = IPP_MAX_MIMETYPE;
1138 break;
1139
1140 case IPP_TAG_URI :
1141 max_bytes = IPP_MAX_URI;
1142 break;
1143
1144 case IPP_TAG_URISCHEME :
1145 max_bytes = IPP_MAX_URISCHEME;
1146 break;
1147 }
1148
1149 if (bytes >= max_bytes)
1150 {
1151 char *bufmax, /* Buffer at max_bytes */
1152 *bufptr; /* Pointer into buffer */
1153
1154 bufptr = buffer + strlen(buffer) - 1;
1155 bufmax = buffer + max_bytes - 1;
1156
1157 while (bufptr > bufmax)
1158 {
1159 if (*bufptr & 0x80)
1160 {
1161 while ((*bufptr & 0xc0) == 0x80 && bufptr > buffer)
1162 bufptr --;
1163 }
1164
1165 bufptr --;
1166 }
1167
1168 *bufptr = '\0';
1169 }
1170
1171 /*
1172 * Add the formatted string and return...
1173 */
1174
1175 return (ippAddString(ipp, group, value_tag, name, language, buffer));
1176 }
1177
1178
1179 /*
1180 * 'ippAddStrings()' - Add language-encoded strings to an IPP message.
1181 *
1182 * The @code ipp@ parameter refers to an IPP message previously created using
1183 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
1184 *
1185 * The @code group@ parameter specifies the IPP attribute group tag: none
1186 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
1187 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
1188 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
1189 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1190 *
1191 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1192 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1193 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1194 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1195 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1196 * (@code IPP_TAG_URISCHEME@).
1197 *
1198 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
1199 * textWithLanguage string values and must be @code NULL@ for all other string values.
1200 */
1201
1202 ipp_attribute_t * /* O - New attribute */
1203 ippAddStrings(
1204 ipp_t *ipp, /* I - IPP message */
1205 ipp_tag_t group, /* I - IPP group */
1206 ipp_tag_t value_tag, /* I - Type of attribute */
1207 const char *name, /* I - Name of attribute */
1208 int num_values, /* I - Number of values */
1209 const char *language, /* I - Language code (@code NULL@ for default) */
1210 const char * const *values) /* I - Values */
1211 {
1212 int i; /* Looping var */
1213 ipp_tag_t temp_tag; /* Temporary value tag (masked) */
1214 ipp_attribute_t *attr; /* New attribute */
1215 _ipp_value_t *value; /* Current value */
1216 char code[32]; /* Language/charset value buffer */
1217
1218
1219 DEBUG_printf(("ippAddStrings(ipp=%p, group=%02x(%s), value_tag=%02x(%s), name=\"%s\", num_values=%d, language=\"%s\", values=%p)", (void *)ipp, group, ippTagString(group), value_tag, ippTagString(value_tag), name, num_values, language, (void *)values));
1220
1221 /*
1222 * Range check input...
1223 */
1224
1225 temp_tag = (ipp_tag_t)((int)value_tag & IPP_TAG_CUPS_MASK);
1226
1227 #if 0
1228 if (!ipp || !name || group < IPP_TAG_ZERO ||
1229 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
1230 (temp_tag < IPP_TAG_TEXT && temp_tag != IPP_TAG_TEXTLANG &&
1231 temp_tag != IPP_TAG_NAMELANG) || temp_tag > IPP_TAG_MIMETYPE ||
1232 num_values < 1)
1233 return (NULL);
1234
1235 if ((temp_tag == IPP_TAG_TEXTLANG || temp_tag == IPP_TAG_NAMELANG)
1236 != (language != NULL))
1237 return (NULL);
1238 #else
1239 if (!ipp || !name || group < IPP_TAG_ZERO ||
1240 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
1241 num_values < 1)
1242 return (NULL);
1243 #endif /* 0 */
1244
1245 /*
1246 * See if we need to map charset, language, or locale values...
1247 */
1248
1249 if (language && ((int)value_tag & IPP_TAG_CUPS_CONST) &&
1250 strcmp(language, ipp_lang_code(language, code, sizeof(code))))
1251 value_tag = temp_tag; /* Don't do a fast copy */
1252 else if (values && value_tag == (ipp_tag_t)(IPP_TAG_CHARSET | IPP_TAG_CUPS_CONST))
1253 {
1254 for (i = 0; i < num_values; i ++)
1255 if (strcmp(values[i], ipp_get_code(values[i], code, sizeof(code))))
1256 {
1257 value_tag = temp_tag; /* Don't do a fast copy */
1258 break;
1259 }
1260 }
1261 else if (values && value_tag == (ipp_tag_t)(IPP_TAG_LANGUAGE | IPP_TAG_CUPS_CONST))
1262 {
1263 for (i = 0; i < num_values; i ++)
1264 if (strcmp(values[i], ipp_lang_code(values[i], code, sizeof(code))))
1265 {
1266 value_tag = temp_tag; /* Don't do a fast copy */
1267 break;
1268 }
1269 }
1270
1271 /*
1272 * Create the attribute...
1273 */
1274
1275 if ((attr = ipp_add_attr(ipp, name, group, value_tag, num_values)) == NULL)
1276 return (NULL);
1277
1278 /*
1279 * Initialize the attribute data...
1280 */
1281
1282 for (i = num_values, value = attr->values;
1283 i > 0;
1284 i --, value ++)
1285 {
1286 if (language)
1287 {
1288 if (value == attr->values)
1289 {
1290 if ((int)value_tag & IPP_TAG_CUPS_CONST)
1291 value->string.language = (char *)language;
1292 else
1293 value->string.language = _cupsStrAlloc(ipp_lang_code(language, code,
1294 sizeof(code)));
1295 }
1296 else
1297 value->string.language = attr->values[0].string.language;
1298 }
1299
1300 if (values)
1301 {
1302 if ((int)value_tag & IPP_TAG_CUPS_CONST)
1303 value->string.text = (char *)*values++;
1304 else if (value_tag == IPP_TAG_CHARSET)
1305 value->string.text = _cupsStrAlloc(ipp_get_code(*values++, code, sizeof(code)));
1306 else if (value_tag == IPP_TAG_LANGUAGE)
1307 value->string.text = _cupsStrAlloc(ipp_lang_code(*values++, code, sizeof(code)));
1308 else
1309 value->string.text = _cupsStrAlloc(*values++);
1310 }
1311 }
1312
1313 return (attr);
1314 }
1315
1316
1317 /*
1318 * 'ippContainsInteger()' - Determine whether an attribute contains the
1319 * specified value or is within the list of ranges.
1320 *
1321 * Returns non-zero when the attribute contains either a matching integer or
1322 * enum value, or the value falls within one of the rangeOfInteger values for
1323 * the attribute.
1324 *
1325 * @since CUPS 1.7/macOS 10.9@
1326 */
1327
1328 int /* O - 1 on a match, 0 on no match */
1329 ippContainsInteger(
1330 ipp_attribute_t *attr, /* I - Attribute */
1331 int value) /* I - Integer/enum value */
1332 {
1333 int i; /* Looping var */
1334 _ipp_value_t *avalue; /* Current attribute value */
1335
1336
1337 /*
1338 * Range check input...
1339 */
1340
1341 if (!attr)
1342 return (0);
1343
1344 if (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM &&
1345 attr->value_tag != IPP_TAG_RANGE)
1346 return (0);
1347
1348 /*
1349 * Compare...
1350 */
1351
1352 if (attr->value_tag == IPP_TAG_RANGE)
1353 {
1354 for (i = attr->num_values, avalue = attr->values; i > 0; i --, avalue ++)
1355 if (value >= avalue->range.lower && value <= avalue->range.upper)
1356 return (1);
1357 }
1358 else
1359 {
1360 for (i = attr->num_values, avalue = attr->values; i > 0; i --, avalue ++)
1361 if (value == avalue->integer)
1362 return (1);
1363 }
1364
1365 return (0);
1366 }
1367
1368
1369 /*
1370 * 'ippContainsString()' - Determine whether an attribute contains the
1371 * specified string value.
1372 *
1373 * Returns non-zero when the attribute contains a matching charset, keyword,
1374 * naturalLanguage, mimeMediaType, name, text, uri, or uriScheme value.
1375 *
1376 * @since CUPS 1.7/macOS 10.9@
1377 */
1378
1379 int /* O - 1 on a match, 0 on no match */
1380 ippContainsString(
1381 ipp_attribute_t *attr, /* I - Attribute */
1382 const char *value) /* I - String value */
1383 {
1384 int i; /* Looping var */
1385 _ipp_value_t *avalue; /* Current attribute value */
1386
1387
1388 DEBUG_printf(("ippContainsString(attr=%p, value=\"%s\")", (void *)attr, value));
1389
1390 /*
1391 * Range check input...
1392 */
1393
1394 if (!attr || !value)
1395 {
1396 DEBUG_puts("1ippContainsString: Returning 0 (bad input)");
1397 return (0);
1398 }
1399
1400 /*
1401 * Compare...
1402 */
1403
1404 DEBUG_printf(("1ippContainsString: attr %s, %s with %d values.",
1405 attr->name, ippTagString(attr->value_tag),
1406 attr->num_values));
1407
1408 switch (attr->value_tag & IPP_TAG_CUPS_MASK)
1409 {
1410 case IPP_TAG_CHARSET :
1411 case IPP_TAG_KEYWORD :
1412 case IPP_TAG_LANGUAGE :
1413 case IPP_TAG_URI :
1414 case IPP_TAG_URISCHEME :
1415 for (i = attr->num_values, avalue = attr->values;
1416 i > 0;
1417 i --, avalue ++)
1418 {
1419 DEBUG_printf(("1ippContainsString: value[%d]=\"%s\"",
1420 attr->num_values - i, avalue->string.text));
1421
1422 if (!strcmp(value, avalue->string.text))
1423 {
1424 DEBUG_puts("1ippContainsString: Returning 1 (match)");
1425 return (1);
1426 }
1427 }
1428
1429 case IPP_TAG_MIMETYPE :
1430 case IPP_TAG_NAME :
1431 case IPP_TAG_NAMELANG :
1432 case IPP_TAG_TEXT :
1433 case IPP_TAG_TEXTLANG :
1434 for (i = attr->num_values, avalue = attr->values;
1435 i > 0;
1436 i --, avalue ++)
1437 {
1438 DEBUG_printf(("1ippContainsString: value[%d]=\"%s\"",
1439 attr->num_values - i, avalue->string.text));
1440
1441 if (!_cups_strcasecmp(value, avalue->string.text))
1442 {
1443 DEBUG_puts("1ippContainsString: Returning 1 (match)");
1444 return (1);
1445 }
1446 }
1447
1448 default :
1449 break;
1450 }
1451
1452 DEBUG_puts("1ippContainsString: Returning 0 (no match)");
1453
1454 return (0);
1455 }
1456
1457
1458 /*
1459 * 'ippCopyAttribute()' - Copy an attribute.
1460 *
1461 * The specified attribute, @code attr@, is copied to the destination IPP message.
1462 * When @code quickcopy@ is non-zero, a "shallow" reference copy of the attribute is
1463 * created - this should only be done as long as the original source IPP message will
1464 * not be freed for the life of the destination.
1465 *
1466 * @since CUPS 1.6/macOS 10.8@
1467 */
1468
1469
1470 ipp_attribute_t * /* O - New attribute */
1471 ippCopyAttribute(
1472 ipp_t *dst, /* I - Destination IPP message */
1473 ipp_attribute_t *srcattr, /* I - Attribute to copy */
1474 int quickcopy) /* I - 1 for a referenced copy, 0 for normal */
1475 {
1476 int i; /* Looping var */
1477 ipp_tag_t srctag; /* Source value tag */
1478 ipp_attribute_t *dstattr; /* Destination attribute */
1479 _ipp_value_t *srcval, /* Source value */
1480 *dstval; /* Destination value */
1481
1482
1483 DEBUG_printf(("ippCopyAttribute(dst=%p, srcattr=%p, quickcopy=%d)", (void *)dst, (void *)srcattr, quickcopy));
1484
1485 /*
1486 * Range check input...
1487 */
1488
1489 if (!dst || !srcattr)
1490 return (NULL);
1491
1492 /*
1493 * Copy it...
1494 */
1495
1496 quickcopy = (quickcopy && (srcattr->value_tag & IPP_TAG_CUPS_CONST)) ? IPP_TAG_CUPS_CONST : 0;
1497 srctag = srcattr->value_tag & IPP_TAG_CUPS_MASK;
1498
1499 switch (srctag)
1500 {
1501 case IPP_TAG_ZERO :
1502 dstattr = ippAddSeparator(dst);
1503 break;
1504
1505 case IPP_TAG_UNSUPPORTED_VALUE :
1506 case IPP_TAG_DEFAULT :
1507 case IPP_TAG_UNKNOWN :
1508 case IPP_TAG_NOVALUE :
1509 case IPP_TAG_NOTSETTABLE :
1510 case IPP_TAG_DELETEATTR :
1511 case IPP_TAG_ADMINDEFINE :
1512 dstattr = ippAddOutOfBand(dst, srcattr->group_tag, srctag, srcattr->name);
1513 break;
1514
1515 case IPP_TAG_INTEGER :
1516 case IPP_TAG_ENUM :
1517 case IPP_TAG_BOOLEAN :
1518 case IPP_TAG_DATE :
1519 case IPP_TAG_RESOLUTION :
1520 case IPP_TAG_RANGE :
1521 if ((dstattr = ipp_add_attr(dst, srcattr->name, srcattr->group_tag, srctag, srcattr->num_values)) != NULL)
1522 memcpy(dstattr->values, srcattr->values, (size_t)srcattr->num_values * sizeof(_ipp_value_t));
1523 break;
1524
1525 case IPP_TAG_TEXT :
1526 case IPP_TAG_NAME :
1527 case IPP_TAG_RESERVED_STRING :
1528 case IPP_TAG_KEYWORD :
1529 case IPP_TAG_URI :
1530 case IPP_TAG_URISCHEME :
1531 case IPP_TAG_CHARSET :
1532 case IPP_TAG_LANGUAGE :
1533 case IPP_TAG_MIMETYPE :
1534 if ((dstattr = ippAddStrings(dst, srcattr->group_tag, (ipp_tag_t)(srctag | quickcopy), srcattr->name, srcattr->num_values, NULL, NULL)) == NULL)
1535 break;
1536
1537 if (quickcopy)
1538 {
1539 /*
1540 * Can safely quick-copy these string values...
1541 */
1542
1543 memcpy(dstattr->values, srcattr->values, (size_t)srcattr->num_values * sizeof(_ipp_value_t));
1544 }
1545 else
1546 {
1547 /*
1548 * Otherwise do a normal reference counted copy...
1549 */
1550
1551 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++)
1552 dstval->string.text = _cupsStrAlloc(srcval->string.text);
1553 }
1554 break;
1555
1556 case IPP_TAG_TEXTLANG :
1557 case IPP_TAG_NAMELANG :
1558 if ((dstattr = ippAddStrings(dst, srcattr->group_tag, (ipp_tag_t)(srctag | quickcopy), srcattr->name, srcattr->num_values, NULL, NULL)) == NULL)
1559 break;
1560
1561 if (quickcopy)
1562 {
1563 /*
1564 * Can safely quick-copy these string values...
1565 */
1566
1567 memcpy(dstattr->values, srcattr->values, (size_t)srcattr->num_values * sizeof(_ipp_value_t));
1568 }
1569 else if (srcattr->value_tag & IPP_TAG_CUPS_CONST)
1570 {
1571 /*
1572 * Otherwise do a normal reference counted copy...
1573 */
1574
1575 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++)
1576 {
1577 if (srcval == srcattr->values)
1578 dstval->string.language = _cupsStrAlloc(srcval->string.language);
1579 else
1580 dstval->string.language = dstattr->values[0].string.language;
1581
1582 dstval->string.text = _cupsStrAlloc(srcval->string.text);
1583 }
1584 }
1585 break;
1586
1587 case IPP_TAG_BEGIN_COLLECTION :
1588 if ((dstattr = ippAddCollections(dst, srcattr->group_tag, srcattr->name, srcattr->num_values, NULL)) == NULL)
1589 break;
1590
1591 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++)
1592 {
1593 dstval->collection = srcval->collection;
1594 srcval->collection->use ++;
1595 }
1596 break;
1597
1598 case IPP_TAG_STRING :
1599 default :
1600 if ((dstattr = ipp_add_attr(dst, srcattr->name, srcattr->group_tag, srctag, srcattr->num_values)) == NULL)
1601 break;
1602
1603 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++)
1604 {
1605 dstval->unknown.length = srcval->unknown.length;
1606
1607 if (dstval->unknown.length > 0)
1608 {
1609 if ((dstval->unknown.data = malloc((size_t)dstval->unknown.length)) == NULL)
1610 dstval->unknown.length = 0;
1611 else
1612 memcpy(dstval->unknown.data, srcval->unknown.data, (size_t)dstval->unknown.length);
1613 }
1614 }
1615 break; /* anti-compiler-warning-code */
1616 }
1617
1618 return (dstattr);
1619 }
1620
1621
1622 /*
1623 * 'ippCopyAttributes()' - Copy attributes from one IPP message to another.
1624 *
1625 * Zero or more attributes are copied from the source IPP message, @code src@, to the
1626 * destination IPP message, @code dst@. When @code quickcopy@ is non-zero, a "shallow"
1627 * reference copy of the attribute is created - this should only be done as long as the
1628 * original source IPP message will not be freed for the life of the destination.
1629 *
1630 * The @code cb@ and @code context@ parameters provide a generic way to "filter" the
1631 * attributes that are copied - the function must return 1 to copy the attribute or
1632 * 0 to skip it. The function may also choose to do a partial copy of the source attribute
1633 * itself.
1634 *
1635 * @since CUPS 1.6/macOS 10.8@
1636 */
1637
1638 int /* O - 1 on success, 0 on error */
1639 ippCopyAttributes(
1640 ipp_t *dst, /* I - Destination IPP message */
1641 ipp_t *src, /* I - Source IPP message */
1642 int quickcopy, /* I - 1 for a referenced copy, 0 for normal */
1643 ipp_copycb_t cb, /* I - Copy callback or @code NULL@ for none */
1644 void *context) /* I - Context pointer */
1645 {
1646 ipp_attribute_t *srcattr; /* Source attribute */
1647
1648
1649 DEBUG_printf(("ippCopyAttributes(dst=%p, src=%p, quickcopy=%d, cb=%p, context=%p)", (void *)dst, (void *)src, quickcopy, (void *)cb, context));
1650
1651 /*
1652 * Range check input...
1653 */
1654
1655 if (!dst || !src)
1656 return (0);
1657
1658 /*
1659 * Loop through source attributes and copy as needed...
1660 */
1661
1662 for (srcattr = src->attrs; srcattr; srcattr = srcattr->next)
1663 if (!cb || (*cb)(context, dst, srcattr))
1664 if (!ippCopyAttribute(dst, srcattr, quickcopy))
1665 return (0);
1666
1667 return (1);
1668 }
1669
1670
1671 /*
1672 * 'ippDateToTime()' - Convert from RFC 2579 Date/Time format to time in
1673 * seconds.
1674 */
1675
1676 time_t /* O - UNIX time value */
1677 ippDateToTime(const ipp_uchar_t *date) /* I - RFC 2579 date info */
1678 {
1679 struct tm unixdate; /* UNIX date/time info */
1680 time_t t; /* Computed time */
1681
1682
1683 if (!date)
1684 return (0);
1685
1686 memset(&unixdate, 0, sizeof(unixdate));
1687
1688 /*
1689 * RFC-2579 date/time format is:
1690 *
1691 * Byte(s) Description
1692 * ------- -----------
1693 * 0-1 Year (0 to 65535)
1694 * 2 Month (1 to 12)
1695 * 3 Day (1 to 31)
1696 * 4 Hours (0 to 23)
1697 * 5 Minutes (0 to 59)
1698 * 6 Seconds (0 to 60, 60 = "leap second")
1699 * 7 Deciseconds (0 to 9)
1700 * 8 +/- UTC
1701 * 9 UTC hours (0 to 11)
1702 * 10 UTC minutes (0 to 59)
1703 */
1704
1705 unixdate.tm_year = ((date[0] << 8) | date[1]) - 1900;
1706 unixdate.tm_mon = date[2] - 1;
1707 unixdate.tm_mday = date[3];
1708 unixdate.tm_hour = date[4];
1709 unixdate.tm_min = date[5];
1710 unixdate.tm_sec = date[6];
1711
1712 t = mktime(&unixdate);
1713
1714 if (date[8] == '-')
1715 t += date[9] * 3600 + date[10] * 60;
1716 else
1717 t -= date[9] * 3600 + date[10] * 60;
1718
1719 return (t);
1720 }
1721
1722
1723 /*
1724 * 'ippDelete()' - Delete an IPP message.
1725 */
1726
1727 void
1728 ippDelete(ipp_t *ipp) /* I - IPP message */
1729 {
1730 ipp_attribute_t *attr, /* Current attribute */
1731 *next; /* Next attribute */
1732
1733
1734 DEBUG_printf(("ippDelete(ipp=%p)", (void *)ipp));
1735
1736 if (!ipp)
1737 return;
1738
1739 ipp->use --;
1740 if (ipp->use > 0)
1741 {
1742 DEBUG_printf(("4debug_retain: %p IPP message (use=%d)", (void *)ipp, ipp->use));
1743 return;
1744 }
1745
1746 DEBUG_printf(("4debug_free: %p IPP message", (void *)ipp));
1747
1748 for (attr = ipp->attrs; attr != NULL; attr = next)
1749 {
1750 next = attr->next;
1751
1752 DEBUG_printf(("4debug_free: %p %s %s%s (%d values)", (void *)attr, attr->name, attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag), attr->num_values));
1753
1754 ipp_free_values(attr, 0, attr->num_values);
1755
1756 if (attr->name)
1757 _cupsStrFree(attr->name);
1758
1759 free(attr);
1760 }
1761
1762 free(ipp);
1763 }
1764
1765
1766 /*
1767 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
1768 *
1769 * @since CUPS 1.1.19/macOS 10.3@
1770 */
1771
1772 void
1773 ippDeleteAttribute(
1774 ipp_t *ipp, /* I - IPP message */
1775 ipp_attribute_t *attr) /* I - Attribute to delete */
1776 {
1777 ipp_attribute_t *current, /* Current attribute */
1778 *prev; /* Previous attribute */
1779
1780
1781 DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p(%s))", (void *)ipp, (void *)attr, attr ? attr->name : "(null)"));
1782
1783 /*
1784 * Range check input...
1785 */
1786
1787 if (!attr)
1788 return;
1789
1790 DEBUG_printf(("4debug_free: %p %s %s%s (%d values)", (void *)attr, attr->name, attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag), attr->num_values));
1791
1792 /*
1793 * Find the attribute in the list...
1794 */
1795
1796 if (ipp)
1797 {
1798 for (current = ipp->attrs, prev = NULL;
1799 current;
1800 prev = current, current = current->next)
1801 if (current == attr)
1802 {
1803 /*
1804 * Found it, remove the attribute from the list...
1805 */
1806
1807 if (prev)
1808 prev->next = current->next;
1809 else
1810 ipp->attrs = current->next;
1811
1812 if (current == ipp->last)
1813 ipp->last = prev;
1814
1815 break;
1816 }
1817
1818 if (!current)
1819 return;
1820 }
1821
1822 /*
1823 * Free memory used by the attribute...
1824 */
1825
1826 ipp_free_values(attr, 0, attr->num_values);
1827
1828 if (attr->name)
1829 _cupsStrFree(attr->name);
1830
1831 free(attr);
1832 }
1833
1834
1835 /*
1836 * 'ippDeleteValues()' - Delete values in an attribute.
1837 *
1838 * The @code element@ parameter specifies the first value to delete, starting at
1839 * 0. It must be less than the number of values returned by @link ippGetCount@.
1840 *
1841 * The @code attr@ parameter may be modified as a result of setting the value.
1842 *
1843 * Deleting all values in an attribute deletes the attribute.
1844 *
1845 * @since CUPS 1.6/macOS 10.8@
1846 */
1847
1848 int /* O - 1 on success, 0 on failure */
1849 ippDeleteValues(
1850 ipp_t *ipp, /* I - IPP message */
1851 ipp_attribute_t **attr, /* IO - Attribute */
1852 int element, /* I - Index of first value to delete (0-based) */
1853 int count) /* I - Number of values to delete */
1854 {
1855 /*
1856 * Range check input...
1857 */
1858
1859 if (!ipp || !attr || !*attr ||
1860 element < 0 || element >= (*attr)->num_values || count <= 0 ||
1861 (element + count) >= (*attr)->num_values)
1862 return (0);
1863
1864 /*
1865 * If we are deleting all values, just delete the attribute entirely.
1866 */
1867
1868 if (count == (*attr)->num_values)
1869 {
1870 ippDeleteAttribute(ipp, *attr);
1871 *attr = NULL;
1872 return (1);
1873 }
1874
1875 /*
1876 * Otherwise free the values in question and return.
1877 */
1878
1879 ipp_free_values(*attr, element, count);
1880
1881 return (1);
1882 }
1883
1884
1885 /*
1886 * 'ippFindAttribute()' - Find a named attribute in a request.
1887 *
1888 * Starting with CUPS 2.0, the attribute name can contain a hierarchical list
1889 * of attribute and member names separated by slashes, for example
1890 * "media-col/media-size".
1891 */
1892
1893 ipp_attribute_t * /* O - Matching attribute */
1894 ippFindAttribute(ipp_t *ipp, /* I - IPP message */
1895 const char *name, /* I - Name of attribute */
1896 ipp_tag_t type) /* I - Type of attribute */
1897 {
1898 DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", (void *)ipp, name, type, ippTagString(type)));
1899
1900 if (!ipp || !name)
1901 return (NULL);
1902
1903 /*
1904 * Reset the current pointer...
1905 */
1906
1907 ipp->current = NULL;
1908 ipp->atend = 0;
1909
1910 /*
1911 * Search for the attribute...
1912 */
1913
1914 return (ippFindNextAttribute(ipp, name, type));
1915 }
1916
1917
1918 /*
1919 * 'ippFindNextAttribute()' - Find the next named attribute in a request.
1920 *
1921 * Starting with CUPS 2.0, the attribute name can contain a hierarchical list
1922 * of attribute and member names separated by slashes, for example
1923 * "media-col/media-size".
1924 */
1925
1926 ipp_attribute_t * /* O - Matching attribute */
1927 ippFindNextAttribute(ipp_t *ipp, /* I - IPP message */
1928 const char *name, /* I - Name of attribute */
1929 ipp_tag_t type) /* I - Type of attribute */
1930 {
1931 ipp_attribute_t *attr, /* Current atttribute */
1932 *childattr; /* Child attribute */
1933 ipp_tag_t value_tag; /* Value tag */
1934 char parent[1024], /* Parent attribute name */
1935 *child = NULL; /* Child attribute name */
1936
1937
1938 DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", (void *)ipp, name, type, ippTagString(type)));
1939
1940 if (!ipp || !name)
1941 return (NULL);
1942
1943 DEBUG_printf(("3ippFindNextAttribute: atend=%d", ipp->atend));
1944
1945 if (ipp->atend)
1946 return (NULL);
1947
1948 if (strchr(name, '/'))
1949 {
1950 /*
1951 * Search for child attribute...
1952 */
1953
1954 strlcpy(parent, name, sizeof(parent));
1955 if ((child = strchr(parent, '/')) == NULL)
1956 {
1957 DEBUG_puts("3ippFindNextAttribute: Attribute name too long.");
1958 return (NULL);
1959 }
1960
1961 *child++ = '\0';
1962
1963 if (ipp->current && ipp->current->name && ipp->current->value_tag == IPP_TAG_BEGIN_COLLECTION && !strcmp(parent, ipp->current->name))
1964 {
1965 while (ipp->curindex < ipp->current->num_values)
1966 {
1967 if ((childattr = ippFindNextAttribute(ipp->current->values[ipp->curindex].collection, child, type)) != NULL)
1968 return (childattr);
1969
1970 ipp->curindex ++;
1971 if (ipp->curindex < ipp->current->num_values && ipp->current->values[ipp->curindex].collection)
1972 ipp->current->values[ipp->curindex].collection->current = NULL;
1973 }
1974
1975 ipp->prev = ipp->current;
1976 ipp->current = ipp->current->next;
1977 ipp->curindex = 0;
1978
1979 if (!ipp->current)
1980 {
1981 ipp->atend = 1;
1982 return (NULL);
1983 }
1984 }
1985
1986 if (!ipp->current)
1987 {
1988 ipp->prev = NULL;
1989 ipp->current = ipp->attrs;
1990 ipp->curindex = 0;
1991 }
1992
1993 name = parent;
1994 attr = ipp->current;
1995 }
1996 else if (ipp->current)
1997 {
1998 ipp->prev = ipp->current;
1999 attr = ipp->current->next;
2000 }
2001 else
2002 {
2003 ipp->prev = NULL;
2004 attr = ipp->attrs;
2005 }
2006
2007 for (; attr != NULL; ipp->prev = attr, attr = attr->next)
2008 {
2009 DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", (void *)attr, attr->name));
2010
2011 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK);
2012
2013 if (attr->name != NULL && _cups_strcasecmp(attr->name, name) == 0 &&
2014 (value_tag == type || type == IPP_TAG_ZERO || name == parent ||
2015 (value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) ||
2016 (value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME)))
2017 {
2018 ipp->current = attr;
2019
2020 if (name == parent && attr->value_tag == IPP_TAG_BEGIN_COLLECTION)
2021 {
2022 int i; /* Looping var */
2023
2024 for (i = 0; i < attr->num_values; i ++)
2025 {
2026 if ((childattr = ippFindAttribute(attr->values[i].collection, child, type)) != NULL)
2027 {
2028 attr->values[0].collection->curindex = i;
2029 return (childattr);
2030 }
2031 }
2032 }
2033 else
2034 return (attr);
2035 }
2036 }
2037
2038 ipp->current = NULL;
2039 ipp->prev = NULL;
2040 ipp->atend = 1;
2041
2042 return (NULL);
2043 }
2044
2045
2046 /*
2047 * 'ippFirstAttribute()' - Return the first attribute in the message.
2048 *
2049 * @since CUPS 1.6/macOS 10.8@
2050 */
2051
2052 ipp_attribute_t * /* O - First attribute or @code NULL@ if none */
2053 ippFirstAttribute(ipp_t *ipp) /* I - IPP message */
2054 {
2055 /*
2056 * Range check input...
2057 */
2058
2059 if (!ipp)
2060 return (NULL);
2061
2062 /*
2063 * Return the first attribute...
2064 */
2065
2066 return (ipp->current = ipp->attrs);
2067 }
2068
2069
2070 /*
2071 * 'ippGetBoolean()' - Get a boolean value for an attribute.
2072 *
2073 * The @code element@ parameter specifies which value to get from 0 to
2074 * @code ippGetCount(attr)@ - 1.
2075 *
2076 * @since CUPS 1.6/macOS 10.8@
2077 */
2078
2079 int /* O - Boolean value or 0 on error */
2080 ippGetBoolean(ipp_attribute_t *attr, /* I - IPP attribute */
2081 int element) /* I - Value number (0-based) */
2082 {
2083 /*
2084 * Range check input...
2085 */
2086
2087 if (!attr || attr->value_tag != IPP_TAG_BOOLEAN ||
2088 element < 0 || element >= attr->num_values)
2089 return (0);
2090
2091 /*
2092 * Return the value...
2093 */
2094
2095 return (attr->values[element].boolean);
2096 }
2097
2098
2099 /*
2100 * 'ippGetCollection()' - Get a collection value for an attribute.
2101 *
2102 * The @code element@ parameter specifies which value to get from 0 to
2103 * @code ippGetCount(attr)@ - 1.
2104 *
2105 * @since CUPS 1.6/macOS 10.8@
2106 */
2107
2108 ipp_t * /* O - Collection value or @code NULL@ on error */
2109 ippGetCollection(
2110 ipp_attribute_t *attr, /* I - IPP attribute */
2111 int element) /* I - Value number (0-based) */
2112 {
2113 /*
2114 * Range check input...
2115 */
2116
2117 if (!attr || attr->value_tag != IPP_TAG_BEGIN_COLLECTION ||
2118 element < 0 || element >= attr->num_values)
2119 return (NULL);
2120
2121 /*
2122 * Return the value...
2123 */
2124
2125 return (attr->values[element].collection);
2126 }
2127
2128
2129 /*
2130 * 'ippGetCount()' - Get the number of values in an attribute.
2131 *
2132 * @since CUPS 1.6/macOS 10.8@
2133 */
2134
2135 int /* O - Number of values or 0 on error */
2136 ippGetCount(ipp_attribute_t *attr) /* I - IPP attribute */
2137 {
2138 /*
2139 * Range check input...
2140 */
2141
2142 if (!attr)
2143 return (0);
2144
2145 /*
2146 * Return the number of values...
2147 */
2148
2149 return (attr->num_values);
2150 }
2151
2152
2153 /*
2154 * 'ippGetDate()' - Get a dateTime value for an attribute.
2155 *
2156 * The @code element@ parameter specifies which value to get from 0 to
2157 * @code ippGetCount(attr)@ - 1.
2158 *
2159 * @since CUPS 1.6/macOS 10.8@
2160 */
2161
2162 const ipp_uchar_t * /* O - dateTime value or @code NULL@ */
2163 ippGetDate(ipp_attribute_t *attr, /* I - IPP attribute */
2164 int element) /* I - Value number (0-based) */
2165 {
2166 /*
2167 * Range check input...
2168 */
2169
2170 if (!attr || attr->value_tag != IPP_TAG_DATE ||
2171 element < 0 || element >= attr->num_values)
2172 return (NULL);
2173
2174 /*
2175 * Return the value...
2176 */
2177
2178 return (attr->values[element].date);
2179 }
2180
2181
2182 /*
2183 * 'ippGetGroupTag()' - Get the group associated with an attribute.
2184 *
2185 * @since CUPS 1.6/macOS 10.8@
2186 */
2187
2188 ipp_tag_t /* O - Group tag or @code IPP_TAG_ZERO@ on error */
2189 ippGetGroupTag(ipp_attribute_t *attr) /* I - IPP attribute */
2190 {
2191 /*
2192 * Range check input...
2193 */
2194
2195 if (!attr)
2196 return (IPP_TAG_ZERO);
2197
2198 /*
2199 * Return the group...
2200 */
2201
2202 return (attr->group_tag);
2203 }
2204
2205
2206 /*
2207 * 'ippGetInteger()' - Get the integer/enum value for an attribute.
2208 *
2209 * The @code element@ parameter specifies which value to get from 0 to
2210 * @code ippGetCount(attr)@ - 1.
2211 *
2212 * @since CUPS 1.6/macOS 10.8@
2213 */
2214
2215 int /* O - Value or 0 on error */
2216 ippGetInteger(ipp_attribute_t *attr, /* I - IPP attribute */
2217 int element) /* I - Value number (0-based) */
2218 {
2219 /*
2220 * Range check input...
2221 */
2222
2223 if (!attr || (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM) ||
2224 element < 0 || element >= attr->num_values)
2225 return (0);
2226
2227 /*
2228 * Return the value...
2229 */
2230
2231 return (attr->values[element].integer);
2232 }
2233
2234
2235 /*
2236 * 'ippGetName()' - Get the attribute name.
2237 *
2238 * @since CUPS 1.6/macOS 10.8@
2239 */
2240
2241 const char * /* O - Attribute name or @code NULL@ for separators */
2242 ippGetName(ipp_attribute_t *attr) /* I - IPP attribute */
2243 {
2244 /*
2245 * Range check input...
2246 */
2247
2248 if (!attr)
2249 return (NULL);
2250
2251 /*
2252 * Return the name...
2253 */
2254
2255 return (attr->name);
2256 }
2257
2258
2259 /*
2260 * 'ippGetOctetString()' - Get an octetString value from an IPP attribute.
2261 *
2262 * The @code element@ parameter specifies which value to get from 0 to
2263 * @code ippGetCount(attr)@ - 1.
2264 *
2265 * @since CUPS 1.7/macOS 10.9@
2266 */
2267
2268 void * /* O - Pointer to octetString data */
2269 ippGetOctetString(
2270 ipp_attribute_t *attr, /* I - IPP attribute */
2271 int element, /* I - Value number (0-based) */
2272 int *datalen) /* O - Length of octetString data */
2273 {
2274 /*
2275 * Range check input...
2276 */
2277
2278 if (!attr || attr->value_tag != IPP_TAG_STRING ||
2279 element < 0 || element >= attr->num_values)
2280 {
2281 if (datalen)
2282 *datalen = 0;
2283
2284 return (NULL);
2285 }
2286
2287 /*
2288 * Return the values...
2289 */
2290
2291 if (datalen)
2292 *datalen = attr->values[element].unknown.length;
2293
2294 return (attr->values[element].unknown.data);
2295 }
2296
2297
2298 /*
2299 * 'ippGetOperation()' - Get the operation ID in an IPP message.
2300 *
2301 * @since CUPS 1.6/macOS 10.8@
2302 */
2303
2304 ipp_op_t /* O - Operation ID or 0 on error */
2305 ippGetOperation(ipp_t *ipp) /* I - IPP request message */
2306 {
2307 /*
2308 * Range check input...
2309 */
2310
2311 if (!ipp)
2312 return ((ipp_op_t)0);
2313
2314 /*
2315 * Return the value...
2316 */
2317
2318 return (ipp->request.op.operation_id);
2319 }
2320
2321
2322 /*
2323 * 'ippGetRange()' - Get a rangeOfInteger value from an attribute.
2324 *
2325 * The @code element@ parameter specifies which value to get from 0 to
2326 * @code ippGetCount(attr)@ - 1.
2327 *
2328 * @since CUPS 1.6/macOS 10.8@
2329 */
2330
2331 int /* O - Lower value of range or 0 */
2332 ippGetRange(ipp_attribute_t *attr, /* I - IPP attribute */
2333 int element, /* I - Value number (0-based) */
2334 int *uppervalue)/* O - Upper value of range */
2335 {
2336 /*
2337 * Range check input...
2338 */
2339
2340 if (!attr || attr->value_tag != IPP_TAG_RANGE ||
2341 element < 0 || element >= attr->num_values)
2342 {
2343 if (uppervalue)
2344 *uppervalue = 0;
2345
2346 return (0);
2347 }
2348
2349 /*
2350 * Return the values...
2351 */
2352
2353 if (uppervalue)
2354 *uppervalue = attr->values[element].range.upper;
2355
2356 return (attr->values[element].range.lower);
2357 }
2358
2359
2360 /*
2361 * 'ippGetRequestId()' - Get the request ID from an IPP message.
2362 *
2363 * @since CUPS 1.6/macOS 10.8@
2364 */
2365
2366 int /* O - Request ID or 0 on error */
2367 ippGetRequestId(ipp_t *ipp) /* I - IPP message */
2368 {
2369 /*
2370 * Range check input...
2371 */
2372
2373 if (!ipp)
2374 return (0);
2375
2376 /*
2377 * Return the request ID...
2378 */
2379
2380 return (ipp->request.any.request_id);
2381 }
2382
2383
2384 /*
2385 * 'ippGetResolution()' - Get a resolution value for an attribute.
2386 *
2387 * The @code element@ parameter specifies which value to get from 0 to
2388 * @code ippGetCount(attr)@ - 1.
2389 *
2390 * @since CUPS 1.6/macOS 10.8@
2391 */
2392
2393 int /* O - Horizontal/cross feed resolution or 0 */
2394 ippGetResolution(
2395 ipp_attribute_t *attr, /* I - IPP attribute */
2396 int element, /* I - Value number (0-based) */
2397 int *yres, /* O - Vertical/feed resolution */
2398 ipp_res_t *units) /* O - Units for resolution */
2399 {
2400 /*
2401 * Range check input...
2402 */
2403
2404 if (!attr || attr->value_tag != IPP_TAG_RESOLUTION ||
2405 element < 0 || element >= attr->num_values)
2406 {
2407 if (yres)
2408 *yres = 0;
2409
2410 if (units)
2411 *units = (ipp_res_t)0;
2412
2413 return (0);
2414 }
2415
2416 /*
2417 * Return the value...
2418 */
2419
2420 if (yres)
2421 *yres = attr->values[element].resolution.yres;
2422
2423 if (units)
2424 *units = attr->values[element].resolution.units;
2425
2426 return (attr->values[element].resolution.xres);
2427 }
2428
2429
2430 /*
2431 * 'ippGetState()' - Get the IPP message state.
2432 *
2433 * @since CUPS 1.6/macOS 10.8@
2434 */
2435
2436 ipp_state_t /* O - IPP message state value */
2437 ippGetState(ipp_t *ipp) /* I - IPP message */
2438 {
2439 /*
2440 * Range check input...
2441 */
2442
2443 if (!ipp)
2444 return (IPP_STATE_IDLE);
2445
2446 /*
2447 * Return the value...
2448 */
2449
2450 return (ipp->state);
2451 }
2452
2453
2454 /*
2455 * 'ippGetStatusCode()' - Get the status code from an IPP response or event message.
2456 *
2457 * @since CUPS 1.6/macOS 10.8@
2458 */
2459
2460 ipp_status_t /* O - Status code in IPP message */
2461 ippGetStatusCode(ipp_t *ipp) /* I - IPP response or event message */
2462 {
2463 /*
2464 * Range check input...
2465 */
2466
2467 if (!ipp)
2468 return (IPP_STATUS_ERROR_INTERNAL);
2469
2470 /*
2471 * Return the value...
2472 */
2473
2474 return (ipp->request.status.status_code);
2475 }
2476
2477
2478 /*
2479 * 'ippGetString()' - Get the string and optionally the language code for an attribute.
2480 *
2481 * The @code element@ parameter specifies which value to get from 0 to
2482 * @code ippGetCount(attr)@ - 1.
2483 *
2484 * @since CUPS 1.6/macOS 10.8@
2485 */
2486
2487 const char *
2488 ippGetString(ipp_attribute_t *attr, /* I - IPP attribute */
2489 int element, /* I - Value number (0-based) */
2490 const char **language)/* O - Language code (@code NULL@ for don't care) */
2491 {
2492 ipp_tag_t tag; /* Value tag */
2493
2494
2495 /*
2496 * Range check input...
2497 */
2498
2499 tag = ippGetValueTag(attr);
2500
2501 if (!attr || element < 0 || element >= attr->num_values || (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG && (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE)))
2502 return (NULL);
2503
2504 /*
2505 * Return the value...
2506 */
2507
2508 if (language)
2509 *language = attr->values[element].string.language;
2510
2511 return (attr->values[element].string.text);
2512 }
2513
2514
2515 /*
2516 * 'ippGetValueTag()' - Get the value tag for an attribute.
2517 *
2518 * @since CUPS 1.6/macOS 10.8@
2519 */
2520
2521 ipp_tag_t /* O - Value tag or @code IPP_TAG_ZERO@ on error */
2522 ippGetValueTag(ipp_attribute_t *attr) /* I - IPP attribute */
2523 {
2524 /*
2525 * Range check input...
2526 */
2527
2528 if (!attr)
2529 return (IPP_TAG_ZERO);
2530
2531 /*
2532 * Return the value...
2533 */
2534
2535 return (attr->value_tag & IPP_TAG_CUPS_MASK);
2536 }
2537
2538
2539 /*
2540 * 'ippGetVersion()' - Get the major and minor version number from an IPP message.
2541 *
2542 * @since CUPS 1.6/macOS 10.8@
2543 */
2544
2545 int /* O - Major version number or 0 on error */
2546 ippGetVersion(ipp_t *ipp, /* I - IPP message */
2547 int *minor) /* O - Minor version number or @code NULL@ for don't care */
2548 {
2549 /*
2550 * Range check input...
2551 */
2552
2553 if (!ipp)
2554 {
2555 if (minor)
2556 *minor = 0;
2557
2558 return (0);
2559 }
2560
2561 /*
2562 * Return the value...
2563 */
2564
2565 if (minor)
2566 *minor = ipp->request.any.version[1];
2567
2568 return (ipp->request.any.version[0]);
2569 }
2570
2571
2572 /*
2573 * 'ippLength()' - Compute the length of an IPP message.
2574 */
2575
2576 size_t /* O - Size of IPP message */
2577 ippLength(ipp_t *ipp) /* I - IPP message */
2578 {
2579 return (ipp_length(ipp, 0));
2580 }
2581
2582
2583 /*
2584 * 'ippNextAttribute()' - Return the next attribute in the message.
2585 *
2586 * @since CUPS 1.6/macOS 10.8@
2587 */
2588
2589 ipp_attribute_t * /* O - Next attribute or @code NULL@ if none */
2590 ippNextAttribute(ipp_t *ipp) /* I - IPP message */
2591 {
2592 /*
2593 * Range check input...
2594 */
2595
2596 if (!ipp || !ipp->current)
2597 return (NULL);
2598
2599 /*
2600 * Return the next attribute...
2601 */
2602
2603 return (ipp->current = ipp->current->next);
2604 }
2605
2606
2607 /*
2608 * 'ippNew()' - Allocate a new IPP message.
2609 */
2610
2611 ipp_t * /* O - New IPP message */
2612 ippNew(void)
2613 {
2614 ipp_t *temp; /* New IPP message */
2615 _cups_globals_t *cg = _cupsGlobals();
2616 /* Global data */
2617
2618
2619 DEBUG_puts("ippNew()");
2620
2621 if ((temp = (ipp_t *)calloc(1, sizeof(ipp_t))) != NULL)
2622 {
2623 /*
2624 * Set default version - usually 2.0...
2625 */
2626
2627 DEBUG_printf(("4debug_alloc: %p IPP message", (void *)temp));
2628
2629 if (cg->server_version == 0)
2630 _cupsSetDefaults();
2631
2632 temp->request.any.version[0] = (ipp_uchar_t)(cg->server_version / 10);
2633 temp->request.any.version[1] = (ipp_uchar_t)(cg->server_version % 10);
2634 temp->use = 1;
2635 }
2636
2637 DEBUG_printf(("1ippNew: Returning %p", (void *)temp));
2638
2639 return (temp);
2640 }
2641
2642
2643 /*
2644 * 'ippNewRequest()' - Allocate a new IPP request message.
2645 *
2646 * The new request message is initialized with the "attributes-charset" and
2647 * "attributes-natural-language" attributes added. The
2648 * "attributes-natural-language" value is derived from the current locale.
2649 *
2650 * @since CUPS 1.2/macOS 10.5@
2651 */
2652
2653 ipp_t * /* O - IPP request message */
2654 ippNewRequest(ipp_op_t op) /* I - Operation code */
2655 {
2656 ipp_t *request; /* IPP request message */
2657 cups_lang_t *language; /* Current language localization */
2658 static int request_id = 0; /* Current request ID */
2659 static _cups_mutex_t request_mutex = _CUPS_MUTEX_INITIALIZER;
2660 /* Mutex for request ID */
2661
2662
2663 DEBUG_printf(("ippNewRequest(op=%02x(%s))", op, ippOpString(op)));
2664
2665 /*
2666 * Create a new IPP message...
2667 */
2668
2669 if ((request = ippNew()) == NULL)
2670 return (NULL);
2671
2672 /*
2673 * Set the operation and request ID...
2674 */
2675
2676 _cupsMutexLock(&request_mutex);
2677
2678 request->request.op.operation_id = op;
2679 request->request.op.request_id = ++request_id;
2680
2681 _cupsMutexUnlock(&request_mutex);
2682
2683 /*
2684 * Use UTF-8 as the character set...
2685 */
2686
2687 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2688 "attributes-charset", NULL, "utf-8");
2689
2690 /*
2691 * Get the language from the current locale...
2692 */
2693
2694 language = cupsLangDefault();
2695
2696 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2697 "attributes-natural-language", NULL, language->language);
2698
2699 /*
2700 * Return the new request...
2701 */
2702
2703 return (request);
2704 }
2705
2706
2707 /*
2708 * 'ippNewResponse()' - Allocate a new IPP response message.
2709 *
2710 * The new response message is initialized with the same "version-number",
2711 * "request-id", "attributes-charset", and "attributes-natural-language" as the
2712 * provided request message. If the "attributes-charset" or
2713 * "attributes-natural-language" attributes are missing from the request,
2714 * 'utf-8' and a value derived from the current locale are substituted,
2715 * respectively.
2716 *
2717 * @since CUPS 1.7/macOS 10.9@
2718 */
2719
2720 ipp_t * /* O - IPP response message */
2721 ippNewResponse(ipp_t *request) /* I - IPP request message */
2722 {
2723 ipp_t *response; /* IPP response message */
2724 ipp_attribute_t *attr; /* Current attribute */
2725
2726
2727 /*
2728 * Range check input...
2729 */
2730
2731 if (!request)
2732 return (NULL);
2733
2734 /*
2735 * Create a new IPP message...
2736 */
2737
2738 if ((response = ippNew()) == NULL)
2739 return (NULL);
2740
2741 /*
2742 * Copy the request values over to the response...
2743 */
2744
2745 response->request.status.version[0] = request->request.op.version[0];
2746 response->request.status.version[1] = request->request.op.version[1];
2747 response->request.status.request_id = request->request.op.request_id;
2748
2749 /*
2750 * The first attribute MUST be attributes-charset...
2751 */
2752
2753 attr = request->attrs;
2754
2755 if (attr && attr->name && !strcmp(attr->name, "attributes-charset") &&
2756 attr->group_tag == IPP_TAG_OPERATION &&
2757 attr->value_tag == IPP_TAG_CHARSET &&
2758 attr->num_values == 1)
2759 {
2760 /*
2761 * Copy charset from request...
2762 */
2763
2764 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2765 "attributes-charset", NULL, attr->values[0].string.text);
2766 }
2767 else
2768 {
2769 /*
2770 * Use "utf-8" as the default...
2771 */
2772
2773 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2774 "attributes-charset", NULL, "utf-8");
2775 }
2776
2777 /*
2778 * Then attributes-natural-language...
2779 */
2780
2781 if (attr)
2782 attr = attr->next;
2783
2784 if (attr && attr->name &&
2785 !strcmp(attr->name, "attributes-natural-language") &&
2786 attr->group_tag == IPP_TAG_OPERATION &&
2787 attr->value_tag == IPP_TAG_LANGUAGE &&
2788 attr->num_values == 1)
2789 {
2790 /*
2791 * Copy language from request...
2792 */
2793
2794 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2795 "attributes-natural-language", NULL,
2796 attr->values[0].string.text);
2797 }
2798 else
2799 {
2800 /*
2801 * Use the language from the current locale...
2802 */
2803
2804 cups_lang_t *language = cupsLangDefault();
2805 /* Current locale */
2806
2807 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2808 "attributes-natural-language", NULL, language->language);
2809 }
2810
2811 return (response);
2812 }
2813
2814
2815 /*
2816 * 'ippRead()' - Read data for an IPP message from a HTTP connection.
2817 */
2818
2819 ipp_state_t /* O - Current state */
2820 ippRead(http_t *http, /* I - HTTP connection */
2821 ipp_t *ipp) /* I - IPP data */
2822 {
2823 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT, (void *)http, (void *)ipp, CUPS_LLCAST (http ? http->data_remaining : -1)));
2824
2825 if (!http)
2826 return (IPP_STATE_ERROR);
2827
2828 DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http->state, http->used));
2829
2830 return (ippReadIO(http, (ipp_iocb_t)ipp_read_http, http->blocking, NULL,
2831 ipp));
2832 }
2833
2834
2835 /*
2836 * 'ippReadFile()' - Read data for an IPP message from a file.
2837 *
2838 * @since CUPS 1.1.19/macOS 10.3@
2839 */
2840
2841 ipp_state_t /* O - Current state */
2842 ippReadFile(int fd, /* I - HTTP data */
2843 ipp_t *ipp) /* I - IPP data */
2844 {
2845 DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd, (void *)ipp));
2846
2847 return (ippReadIO(&fd, (ipp_iocb_t)ipp_read_file, 1, NULL, ipp));
2848 }
2849
2850
2851 /*
2852 * 'ippReadIO()' - Read data for an IPP message.
2853 *
2854 * @since CUPS 1.2/macOS 10.5@
2855 */
2856
2857 ipp_state_t /* O - Current state */
2858 ippReadIO(void *src, /* I - Data source */
2859 ipp_iocb_t cb, /* I - Read callback function */
2860 int blocking, /* I - Use blocking IO? */
2861 ipp_t *parent, /* I - Parent request, if any */
2862 ipp_t *ipp) /* I - IPP data */
2863 {
2864 int n; /* Length of data */
2865 unsigned char *buffer, /* Data buffer */
2866 string[IPP_MAX_TEXT],
2867 /* Small string buffer */
2868 *bufptr; /* Pointer into buffer */
2869 ipp_attribute_t *attr; /* Current attribute */
2870 ipp_tag_t tag; /* Current tag */
2871 ipp_tag_t value_tag; /* Current value tag */
2872 _ipp_value_t *value; /* Current value */
2873
2874
2875 DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)src, (void *)cb, blocking, (void *)parent, (void *)ipp));
2876 DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp ? ipp->state : IPP_STATE_ERROR));
2877
2878 if (!src || !ipp)
2879 return (IPP_STATE_ERROR);
2880
2881 if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
2882 {
2883 DEBUG_puts("1ippReadIO: Unable to get read buffer.");
2884 return (IPP_STATE_ERROR);
2885 }
2886
2887 switch (ipp->state)
2888 {
2889 case IPP_STATE_IDLE :
2890 ipp->state ++; /* Avoid common problem... */
2891
2892 case IPP_STATE_HEADER :
2893 if (parent == NULL)
2894 {
2895 /*
2896 * Get the request header...
2897 */
2898
2899 if ((*cb)(src, buffer, 8) < 8)
2900 {
2901 DEBUG_puts("1ippReadIO: Unable to read header.");
2902 _cupsBufferRelease((char *)buffer);
2903 return (IPP_STATE_ERROR);
2904 }
2905
2906 /*
2907 * Then copy the request header over...
2908 */
2909
2910 ipp->request.any.version[0] = buffer[0];
2911 ipp->request.any.version[1] = buffer[1];
2912 ipp->request.any.op_status = (buffer[2] << 8) | buffer[3];
2913 ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) |
2914 buffer[6]) << 8) | buffer[7];
2915
2916 DEBUG_printf(("2ippReadIO: version=%d.%d", buffer[0], buffer[1]));
2917 DEBUG_printf(("2ippReadIO: op_status=%04x",
2918 ipp->request.any.op_status));
2919 DEBUG_printf(("2ippReadIO: request_id=%d",
2920 ipp->request.any.request_id));
2921 }
2922
2923 ipp->state = IPP_STATE_ATTRIBUTE;
2924 ipp->current = NULL;
2925 ipp->curtag = IPP_TAG_ZERO;
2926 ipp->prev = ipp->last;
2927
2928 /*
2929 * If blocking is disabled, stop here...
2930 */
2931
2932 if (!blocking)
2933 break;
2934
2935 case IPP_STATE_ATTRIBUTE :
2936 for (;;)
2937 {
2938 if ((*cb)(src, buffer, 1) < 1)
2939 {
2940 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
2941 _cupsBufferRelease((char *)buffer);
2942 return (IPP_STATE_ERROR);
2943 }
2944
2945 DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev));
2946
2947 /*
2948 * Read this attribute...
2949 */
2950
2951 tag = (ipp_tag_t)buffer[0];
2952 if (tag == IPP_TAG_EXTENSION)
2953 {
2954 /*
2955 * Read 32-bit "extension" tag...
2956 */
2957
2958 if ((*cb)(src, buffer, 4) < 1)
2959 {
2960 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
2961 _cupsBufferRelease((char *)buffer);
2962 return (IPP_STATE_ERROR);
2963 }
2964
2965 tag = (ipp_tag_t)((((((buffer[0] << 8) | buffer[1]) << 8) |
2966 buffer[2]) << 8) | buffer[3]);
2967
2968 if (tag & IPP_TAG_CUPS_CONST)
2969 {
2970 /*
2971 * Fail if the high bit is set in the tag...
2972 */
2973
2974 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
2975 DEBUG_printf(("1ippReadIO: bad tag 0x%x.", tag));
2976 _cupsBufferRelease((char *)buffer);
2977 return (IPP_STATE_ERROR);
2978 }
2979 }
2980
2981 if (tag == IPP_TAG_END)
2982 {
2983 /*
2984 * No more attributes left...
2985 */
2986
2987 DEBUG_puts("2ippReadIO: IPP_TAG_END.");
2988
2989 ipp->state = IPP_STATE_DATA;
2990 break;
2991 }
2992 else if (tag == IPP_TAG_ZERO || (tag == IPP_TAG_OPERATION && ipp->curtag != IPP_TAG_ZERO))
2993 {
2994 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid group tag."), 1);
2995 DEBUG_printf(("1ippReadIO: bad tag 0x%02x.", tag));
2996 _cupsBufferRelease((char *)buffer);
2997 return (IPP_STATE_ERROR);
2998 }
2999 else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
3000 {
3001 /*
3002 * Group tag... Set the current group and continue...
3003 */
3004
3005 if (ipp->curtag == tag)
3006 ipp->prev = ippAddSeparator(ipp);
3007 else if (ipp->current)
3008 ipp->prev = ipp->current;
3009
3010 ipp->curtag = tag;
3011 ipp->current = NULL;
3012 DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag, ippTagString(tag), (void *)ipp->prev));
3013 continue;
3014 }
3015
3016 DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag,
3017 ippTagString(tag)));
3018
3019 /*
3020 * Get the name...
3021 */
3022
3023 if ((*cb)(src, buffer, 2) < 2)
3024 {
3025 DEBUG_puts("1ippReadIO: unable to read name length.");
3026 _cupsBufferRelease((char *)buffer);
3027 return (IPP_STATE_ERROR);
3028 }
3029
3030 n = (buffer[0] << 8) | buffer[1];
3031
3032 if (n >= IPP_BUF_SIZE)
3033 {
3034 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP name larger than 32767 bytes."), 1);
3035 DEBUG_printf(("1ippReadIO: bad name length %d.", n));
3036 _cupsBufferRelease((char *)buffer);
3037 return (IPP_STATE_ERROR);
3038 }
3039
3040 DEBUG_printf(("2ippReadIO: name length=%d", n));
3041
3042 if (n == 0 && tag != IPP_TAG_MEMBERNAME &&
3043 tag != IPP_TAG_END_COLLECTION)
3044 {
3045 /*
3046 * More values for current attribute...
3047 */
3048
3049 if (ipp->current == NULL)
3050 {
3051 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP attribute has no name."), 1);
3052 DEBUG_puts("1ippReadIO: Attribute without name and no current.");
3053 _cupsBufferRelease((char *)buffer);
3054 return (IPP_STATE_ERROR);
3055 }
3056
3057 attr = ipp->current;
3058 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK);
3059
3060 /*
3061 * Make sure we aren't adding a new value of a different
3062 * type...
3063 */
3064
3065 if (value_tag == IPP_TAG_ZERO)
3066 {
3067 /*
3068 * Setting the value of a collection member...
3069 */
3070
3071 attr->value_tag = tag;
3072 }
3073 else if (value_tag == IPP_TAG_TEXTLANG ||
3074 value_tag == IPP_TAG_NAMELANG ||
3075 (value_tag >= IPP_TAG_TEXT &&
3076 value_tag <= IPP_TAG_MIMETYPE))
3077 {
3078 /*
3079 * String values can sometimes come across in different
3080 * forms; accept sets of differing values...
3081 */
3082
3083 if (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG &&
3084 (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE) &&
3085 tag != IPP_TAG_NOVALUE)
3086 {
3087 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3088 _("IPP 1setOf attribute with incompatible value "
3089 "tags."), 1);
3090 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3091 value_tag, ippTagString(value_tag), tag,
3092 ippTagString(tag)));
3093 _cupsBufferRelease((char *)buffer);
3094 return (IPP_STATE_ERROR);
3095 }
3096
3097 if (value_tag != tag)
3098 {
3099 DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.",
3100 attr->name, ippTagString(value_tag), ippTagString(tag)));
3101 ippSetValueTag(ipp, &attr, tag);
3102 }
3103 }
3104 else if (value_tag == IPP_TAG_INTEGER ||
3105 value_tag == IPP_TAG_RANGE)
3106 {
3107 /*
3108 * Integer and rangeOfInteger values can sometimes be mixed; accept
3109 * sets of differing values...
3110 */
3111
3112 if (tag != IPP_TAG_INTEGER && tag != IPP_TAG_RANGE)
3113 {
3114 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3115 _("IPP 1setOf attribute with incompatible value "
3116 "tags."), 1);
3117 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3118 value_tag, ippTagString(value_tag), tag,
3119 ippTagString(tag)));
3120 _cupsBufferRelease((char *)buffer);
3121 return (IPP_STATE_ERROR);
3122 }
3123
3124 if (value_tag == IPP_TAG_INTEGER && tag == IPP_TAG_RANGE)
3125 {
3126 /*
3127 * Convert integer values to rangeOfInteger values...
3128 */
3129
3130 DEBUG_printf(("1ippReadIO: Converting %s attribute to "
3131 "rangeOfInteger.", attr->name));
3132 ippSetValueTag(ipp, &attr, IPP_TAG_RANGE);
3133 }
3134 }
3135 else if (value_tag != tag)
3136 {
3137 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3138 _("IPP 1setOf attribute with incompatible value "
3139 "tags."), 1);
3140 DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
3141 value_tag, ippTagString(value_tag), tag,
3142 ippTagString(tag)));
3143 _cupsBufferRelease((char *)buffer);
3144 return (IPP_STATE_ERROR);
3145 }
3146
3147 /*
3148 * Finally, reallocate the attribute array as needed...
3149 */
3150
3151 if ((value = ipp_set_value(ipp, &attr, attr->num_values)) == NULL)
3152 {
3153 _cupsBufferRelease((char *)buffer);
3154 return (IPP_STATE_ERROR);
3155 }
3156 }
3157 else if (tag == IPP_TAG_MEMBERNAME)
3158 {
3159 /*
3160 * Name must be length 0!
3161 */
3162
3163 if (n)
3164 {
3165 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP member name is not empty."), 1);
3166 DEBUG_puts("1ippReadIO: member name not empty.");
3167 _cupsBufferRelease((char *)buffer);
3168 return (IPP_STATE_ERROR);
3169 }
3170
3171 if (ipp->current)
3172 ipp->prev = ipp->current;
3173
3174 attr = ipp->current = ipp_add_attr(ipp, NULL, ipp->curtag, IPP_TAG_ZERO, 1);
3175 if (!attr)
3176 {
3177 _cupsSetHTTPError(HTTP_STATUS_ERROR);
3178 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3179 _cupsBufferRelease((char *)buffer);
3180 return (IPP_STATE_ERROR);
3181 }
3182
3183 DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev));
3184
3185 value = attr->values;
3186 }
3187 else if (tag != IPP_TAG_END_COLLECTION)
3188 {
3189 /*
3190 * New attribute; read the name and add it...
3191 */
3192
3193 if ((*cb)(src, buffer, (size_t)n) < n)
3194 {
3195 DEBUG_puts("1ippReadIO: unable to read name.");
3196 _cupsBufferRelease((char *)buffer);
3197 return (IPP_STATE_ERROR);
3198 }
3199
3200 buffer[n] = '\0';
3201
3202 if (ipp->current)
3203 ipp->prev = ipp->current;
3204
3205 if ((attr = ipp->current = ipp_add_attr(ipp, (char *)buffer, ipp->curtag, tag,
3206 1)) == NULL)
3207 {
3208 _cupsSetHTTPError(HTTP_STATUS_ERROR);
3209 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3210 _cupsBufferRelease((char *)buffer);
3211 return (IPP_STATE_ERROR);
3212 }
3213
3214 DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, ipp->prev=%p", buffer, (void *)ipp->current, (void *)ipp->prev));
3215
3216 value = attr->values;
3217 }
3218 else
3219 {
3220 attr = NULL;
3221 value = NULL;
3222 }
3223
3224 if ((*cb)(src, buffer, 2) < 2)
3225 {
3226 DEBUG_puts("1ippReadIO: unable to read value length.");
3227 _cupsBufferRelease((char *)buffer);
3228 return (IPP_STATE_ERROR);
3229 }
3230
3231 n = (buffer[0] << 8) | buffer[1];
3232 DEBUG_printf(("2ippReadIO: value length=%d", n));
3233
3234 if (n >= IPP_BUF_SIZE)
3235 {
3236 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3237 _("IPP value larger than 32767 bytes."), 1);
3238 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
3239 _cupsBufferRelease((char *)buffer);
3240 return (IPP_STATE_ERROR);
3241 }
3242
3243 switch (tag)
3244 {
3245 case IPP_TAG_INTEGER :
3246 case IPP_TAG_ENUM :
3247 if (n != 4)
3248 {
3249 if (tag == IPP_TAG_INTEGER)
3250 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3251 _("IPP integer value not 4 bytes."), 1);
3252 else
3253 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3254 _("IPP enum value not 4 bytes."), 1);
3255 DEBUG_printf(("1ippReadIO: bad integer value length %d.", n));
3256 _cupsBufferRelease((char *)buffer);
3257 return (IPP_STATE_ERROR);
3258 }
3259
3260 if ((*cb)(src, buffer, 4) < 4)
3261 {
3262 DEBUG_puts("1ippReadIO: Unable to read integer value.");
3263 _cupsBufferRelease((char *)buffer);
3264 return (IPP_STATE_ERROR);
3265 }
3266
3267 n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3268 buffer[3];
3269
3270 if (attr->value_tag == IPP_TAG_RANGE)
3271 value->range.lower = value->range.upper = n;
3272 else
3273 value->integer = n;
3274 break;
3275
3276 case IPP_TAG_BOOLEAN :
3277 if (n != 1)
3278 {
3279 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP boolean value not 1 byte."),
3280 1);
3281 DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n));
3282 _cupsBufferRelease((char *)buffer);
3283 return (IPP_STATE_ERROR);
3284 }
3285
3286 if ((*cb)(src, buffer, 1) < 1)
3287 {
3288 DEBUG_puts("1ippReadIO: Unable to read boolean value.");
3289 _cupsBufferRelease((char *)buffer);
3290 return (IPP_STATE_ERROR);
3291 }
3292
3293 value->boolean = (char)buffer[0];
3294 break;
3295
3296 case IPP_TAG_UNSUPPORTED_VALUE :
3297 case IPP_TAG_DEFAULT :
3298 case IPP_TAG_UNKNOWN :
3299 case IPP_TAG_NOVALUE :
3300 case IPP_TAG_NOTSETTABLE :
3301 case IPP_TAG_DELETEATTR :
3302 case IPP_TAG_ADMINDEFINE :
3303 /*
3304 * These value types are not supposed to have values, however
3305 * some vendors (Brother) do not implement IPP correctly and so
3306 * we need to map non-empty values to text...
3307 */
3308
3309 if (attr->value_tag == tag)
3310 {
3311 if (n == 0)
3312 break;
3313
3314 attr->value_tag = IPP_TAG_TEXT;
3315 }
3316
3317 case IPP_TAG_TEXT :
3318 case IPP_TAG_NAME :
3319 case IPP_TAG_RESERVED_STRING :
3320 case IPP_TAG_KEYWORD :
3321 case IPP_TAG_URI :
3322 case IPP_TAG_URISCHEME :
3323 case IPP_TAG_CHARSET :
3324 case IPP_TAG_LANGUAGE :
3325 case IPP_TAG_MIMETYPE :
3326 if (n > 0)
3327 {
3328 if ((*cb)(src, buffer, (size_t)n) < n)
3329 {
3330 DEBUG_puts("1ippReadIO: unable to read string value.");
3331 _cupsBufferRelease((char *)buffer);
3332 return (IPP_STATE_ERROR);
3333 }
3334 }
3335
3336 buffer[n] = '\0';
3337 value->string.text = _cupsStrAlloc((char *)buffer);
3338 DEBUG_printf(("2ippReadIO: value=\"%s\"", value->string.text));
3339 break;
3340
3341 case IPP_TAG_DATE :
3342 if (n != 11)
3343 {
3344 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP date value not 11 bytes."), 1);
3345 DEBUG_printf(("1ippReadIO: bad date value length %d.", n));
3346 _cupsBufferRelease((char *)buffer);
3347 return (IPP_STATE_ERROR);
3348 }
3349
3350 if ((*cb)(src, value->date, 11) < 11)
3351 {
3352 DEBUG_puts("1ippReadIO: Unable to read date value.");
3353 _cupsBufferRelease((char *)buffer);
3354 return (IPP_STATE_ERROR);
3355 }
3356 break;
3357
3358 case IPP_TAG_RESOLUTION :
3359 if (n != 9)
3360 {
3361 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3362 _("IPP resolution value not 9 bytes."), 1);
3363 DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n));
3364 _cupsBufferRelease((char *)buffer);
3365 return (IPP_STATE_ERROR);
3366 }
3367
3368 if ((*cb)(src, buffer, 9) < 9)
3369 {
3370 DEBUG_puts("1ippReadIO: Unable to read resolution value.");
3371 _cupsBufferRelease((char *)buffer);
3372 return (IPP_STATE_ERROR);
3373 }
3374
3375 value->resolution.xres =
3376 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3377 buffer[3];
3378 value->resolution.yres =
3379 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
3380 buffer[7];
3381 value->resolution.units =
3382 (ipp_res_t)buffer[8];
3383 break;
3384
3385 case IPP_TAG_RANGE :
3386 if (n != 8)
3387 {
3388 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3389 _("IPP rangeOfInteger value not 8 bytes."), 1);
3390 DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length "
3391 "%d.", n));
3392 _cupsBufferRelease((char *)buffer);
3393 return (IPP_STATE_ERROR);
3394 }
3395
3396 if ((*cb)(src, buffer, 8) < 8)
3397 {
3398 DEBUG_puts("1ippReadIO: Unable to read range value.");
3399 _cupsBufferRelease((char *)buffer);
3400 return (IPP_STATE_ERROR);
3401 }
3402
3403 value->range.lower =
3404 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3405 buffer[3];
3406 value->range.upper =
3407 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
3408 buffer[7];
3409 break;
3410
3411 case IPP_TAG_TEXTLANG :
3412 case IPP_TAG_NAMELANG :
3413 if (n < 4)
3414 {
3415 if (tag == IPP_TAG_TEXTLANG)
3416 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3417 _("IPP textWithLanguage value less than "
3418 "minimum 4 bytes."), 1);
3419 else
3420 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3421 _("IPP nameWithLanguage value less than "
3422 "minimum 4 bytes."), 1);
3423 DEBUG_printf(("1ippReadIO: bad stringWithLanguage value "
3424 "length %d.", n));
3425 _cupsBufferRelease((char *)buffer);
3426 return (IPP_STATE_ERROR);
3427 }
3428
3429 if ((*cb)(src, buffer, (size_t)n) < n)
3430 {
3431 DEBUG_puts("1ippReadIO: Unable to read string w/language "
3432 "value.");
3433 _cupsBufferRelease((char *)buffer);
3434 return (IPP_STATE_ERROR);
3435 }
3436
3437 bufptr = buffer;
3438
3439 /*
3440 * text-with-language and name-with-language are composite
3441 * values:
3442 *
3443 * language-length
3444 * language
3445 * text-length
3446 * text
3447 */
3448
3449 n = (bufptr[0] << 8) | bufptr[1];
3450
3451 if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) || n >= (int)sizeof(string))
3452 {
3453 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3454 _("IPP language length overflows value."), 1);
3455 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3456 n));
3457 _cupsBufferRelease((char *)buffer);
3458 return (IPP_STATE_ERROR);
3459 }
3460 else if (n >= IPP_MAX_LANGUAGE)
3461 {
3462 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3463 _("IPP language length too large."), 1);
3464 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3465 n));
3466 _cupsBufferRelease((char *)buffer);
3467 return (IPP_STATE_ERROR);
3468 }
3469
3470 memcpy(string, bufptr + 2, (size_t)n);
3471 string[n] = '\0';
3472
3473 value->string.language = _cupsStrAlloc((char *)string);
3474
3475 bufptr += 2 + n;
3476 n = (bufptr[0] << 8) | bufptr[1];
3477
3478 if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE))
3479 {
3480 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3481 _("IPP string length overflows value."), 1);
3482 DEBUG_printf(("1ippReadIO: bad string value length %d.", n));
3483 _cupsBufferRelease((char *)buffer);
3484 return (IPP_STATE_ERROR);
3485 }
3486
3487 bufptr[2 + n] = '\0';
3488 value->string.text = _cupsStrAlloc((char *)bufptr + 2);
3489 break;
3490
3491 case IPP_TAG_BEGIN_COLLECTION :
3492 /*
3493 * Oh, boy, here comes a collection value, so read it...
3494 */
3495
3496 value->collection = ippNew();
3497
3498 if (n > 0)
3499 {
3500 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3501 _("IPP begCollection value not 0 bytes."), 1);
3502 DEBUG_puts("1ippReadIO: begCollection tag with value length "
3503 "> 0.");
3504 _cupsBufferRelease((char *)buffer);
3505 return (IPP_STATE_ERROR);
3506 }
3507
3508 if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_STATE_ERROR)
3509 {
3510 DEBUG_puts("1ippReadIO: Unable to read collection value.");
3511 _cupsBufferRelease((char *)buffer);
3512 return (IPP_STATE_ERROR);
3513 }
3514 break;
3515
3516 case IPP_TAG_END_COLLECTION :
3517 _cupsBufferRelease((char *)buffer);
3518
3519 if (n > 0)
3520 {
3521 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3522 _("IPP endCollection value not 0 bytes."), 1);
3523 DEBUG_puts("1ippReadIO: endCollection tag with value length "
3524 "> 0.");
3525 return (IPP_STATE_ERROR);
3526 }
3527
3528 DEBUG_puts("1ippReadIO: endCollection tag...");
3529 return (ipp->state = IPP_STATE_DATA);
3530
3531 case IPP_TAG_MEMBERNAME :
3532 /*
3533 * The value the name of the member in the collection, which
3534 * we need to carry over...
3535 */
3536
3537 if (!attr)
3538 {
3539 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3540 _("IPP memberName with no attribute."), 1);
3541 DEBUG_puts("1ippReadIO: Member name without attribute.");
3542 _cupsBufferRelease((char *)buffer);
3543 return (IPP_STATE_ERROR);
3544 }
3545 else if (n == 0)
3546 {
3547 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3548 _("IPP memberName value is empty."), 1);
3549 DEBUG_puts("1ippReadIO: Empty member name value.");
3550 _cupsBufferRelease((char *)buffer);
3551 return (IPP_STATE_ERROR);
3552 }
3553 else if ((*cb)(src, buffer, (size_t)n) < n)
3554 {
3555 DEBUG_puts("1ippReadIO: Unable to read member name value.");
3556 _cupsBufferRelease((char *)buffer);
3557 return (IPP_STATE_ERROR);
3558 }
3559
3560 buffer[n] = '\0';
3561 attr->name = _cupsStrAlloc((char *)buffer);
3562
3563 /*
3564 * Since collection members are encoded differently than
3565 * regular attributes, make sure we don't start with an
3566 * empty value...
3567 */
3568
3569 attr->num_values --;
3570
3571 DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr->name));
3572 break;
3573
3574 case IPP_TAG_STRING :
3575 default : /* Other unsupported values */
3576 if (tag == IPP_TAG_STRING && n > IPP_MAX_LENGTH)
3577 {
3578 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3579 _("IPP octetString length too large."), 1);
3580 DEBUG_printf(("1ippReadIO: bad octetString value length %d.",
3581 n));
3582 _cupsBufferRelease((char *)buffer);
3583 return (IPP_STATE_ERROR);
3584 }
3585
3586 value->unknown.length = n;
3587
3588 if (n > 0)
3589 {
3590 if ((value->unknown.data = malloc((size_t)n)) == NULL)
3591 {
3592 _cupsSetHTTPError(HTTP_STATUS_ERROR);
3593 DEBUG_puts("1ippReadIO: Unable to allocate value");
3594 _cupsBufferRelease((char *)buffer);
3595 return (IPP_STATE_ERROR);
3596 }
3597
3598 if ((*cb)(src, value->unknown.data, (size_t)n) < n)
3599 {
3600 DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
3601 _cupsBufferRelease((char *)buffer);
3602 return (IPP_STATE_ERROR);
3603 }
3604 }
3605 else
3606 value->unknown.data = NULL;
3607 break;
3608 }
3609
3610 /*
3611 * If blocking is disabled, stop here...
3612 */
3613
3614 if (!blocking)
3615 break;
3616 }
3617 break;
3618
3619 case IPP_STATE_DATA :
3620 break;
3621
3622 default :
3623 break; /* anti-compiler-warning-code */
3624 }
3625
3626 DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp->state));
3627 _cupsBufferRelease((char *)buffer);
3628
3629 return (ipp->state);
3630 }
3631
3632
3633 /*
3634 * 'ippSetBoolean()' - Set a boolean value in an attribute.
3635 *
3636 * The @code ipp@ parameter refers to an IPP message previously created using
3637 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3638 *
3639 * The @code attr@ parameter may be modified as a result of setting the value.
3640 *
3641 * The @code element@ parameter specifies which value to set from 0 to
3642 * @code ippGetCount(attr)@.
3643 *
3644 * @since CUPS 1.6/macOS 10.8@
3645 */
3646
3647 int /* O - 1 on success, 0 on failure */
3648 ippSetBoolean(ipp_t *ipp, /* I - IPP message */
3649 ipp_attribute_t **attr, /* IO - IPP attribute */
3650 int element, /* I - Value number (0-based) */
3651 int boolvalue)/* I - Boolean value */
3652 {
3653 _ipp_value_t *value; /* Current value */
3654
3655
3656 /*
3657 * Range check input...
3658 */
3659
3660 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BOOLEAN ||
3661 element < 0 || element > (*attr)->num_values)
3662 return (0);
3663
3664 /*
3665 * Set the value and return...
3666 */
3667
3668 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3669 value->boolean = (char)boolvalue;
3670
3671 return (value != NULL);
3672 }
3673
3674
3675 /*
3676 * 'ippSetCollection()' - Set a collection value in an attribute.
3677 *
3678 * The @code ipp@ parameter refers to an IPP message previously created using
3679 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3680 *
3681 * The @code attr@ parameter may be modified as a result of setting the value.
3682 *
3683 * The @code element@ parameter specifies which value to set from 0 to
3684 * @code ippGetCount(attr)@.
3685 *
3686 * @since CUPS 1.6/macOS 10.8@
3687 */
3688
3689 int /* O - 1 on success, 0 on failure */
3690 ippSetCollection(
3691 ipp_t *ipp, /* I - IPP message */
3692 ipp_attribute_t **attr, /* IO - IPP attribute */
3693 int element, /* I - Value number (0-based) */
3694 ipp_t *colvalue) /* I - Collection value */
3695 {
3696 _ipp_value_t *value; /* Current value */
3697
3698
3699 /*
3700 * Range check input...
3701 */
3702
3703 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BEGIN_COLLECTION ||
3704 element < 0 || element > (*attr)->num_values || !colvalue)
3705 return (0);
3706
3707 /*
3708 * Set the value and return...
3709 */
3710
3711 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3712 {
3713 if (value->collection)
3714 ippDelete(value->collection);
3715
3716 value->collection = colvalue;
3717 colvalue->use ++;
3718 }
3719
3720 return (value != NULL);
3721 }
3722
3723
3724 /*
3725 * 'ippSetDate()' - Set a dateTime value in an attribute.
3726 *
3727 * The @code ipp@ parameter refers to an IPP message previously created using
3728 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3729 *
3730 * The @code attr@ parameter may be modified as a result of setting the value.
3731 *
3732 * The @code element@ parameter specifies which value to set from 0 to
3733 * @code ippGetCount(attr)@.
3734 *
3735 * @since CUPS 1.6/macOS 10.8@
3736 */
3737
3738 int /* O - 1 on success, 0 on failure */
3739 ippSetDate(ipp_t *ipp, /* I - IPP message */
3740 ipp_attribute_t **attr, /* IO - IPP attribute */
3741 int element, /* I - Value number (0-based) */
3742 const ipp_uchar_t *datevalue)/* I - dateTime value */
3743 {
3744 _ipp_value_t *value; /* Current value */
3745
3746
3747 /*
3748 * Range check input...
3749 */
3750
3751 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_DATE ||
3752 element < 0 || element > (*attr)->num_values || !datevalue)
3753 return (0);
3754
3755 /*
3756 * Set the value and return...
3757 */
3758
3759 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3760 memcpy(value->date, datevalue, sizeof(value->date));
3761
3762 return (value != NULL);
3763 }
3764
3765
3766 /*
3767 * 'ippSetGroupTag()' - Set the group tag of an attribute.
3768 *
3769 * The @code ipp@ parameter refers to an IPP message previously created using
3770 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3771 *
3772 * The @code attr@ parameter may be modified as a result of setting the value.
3773 *
3774 * The @code group@ parameter specifies the IPP attribute group tag: none
3775 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
3776 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
3777 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
3778 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
3779 *
3780 * @since CUPS 1.6/macOS 10.8@
3781 */
3782
3783 int /* O - 1 on success, 0 on failure */
3784 ippSetGroupTag(
3785 ipp_t *ipp, /* I - IPP message */
3786 ipp_attribute_t **attr, /* IO - Attribute */
3787 ipp_tag_t group_tag) /* I - Group tag */
3788 {
3789 /*
3790 * Range check input - group tag must be 0x01 to 0x0F, per RFC 8011...
3791 */
3792
3793 if (!ipp || !attr || !*attr ||
3794 group_tag < IPP_TAG_ZERO || group_tag == IPP_TAG_END ||
3795 group_tag >= IPP_TAG_UNSUPPORTED_VALUE)
3796 return (0);
3797
3798 /*
3799 * Set the group tag and return...
3800 */
3801
3802 (*attr)->group_tag = group_tag;
3803
3804 return (1);
3805 }
3806
3807
3808 /*
3809 * 'ippSetInteger()' - Set an integer or enum value in an attribute.
3810 *
3811 * The @code ipp@ parameter refers to an IPP message previously created using
3812 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3813 *
3814 * The @code attr@ parameter may be modified as a result of setting the value.
3815 *
3816 * The @code element@ parameter specifies which value to set from 0 to
3817 * @code ippGetCount(attr)@.
3818 *
3819 * @since CUPS 1.6/macOS 10.8@
3820 */
3821
3822 int /* O - 1 on success, 0 on failure */
3823 ippSetInteger(ipp_t *ipp, /* I - IPP message */
3824 ipp_attribute_t **attr, /* IO - IPP attribute */
3825 int element, /* I - Value number (0-based) */
3826 int intvalue) /* I - Integer/enum value */
3827 {
3828 _ipp_value_t *value; /* Current value */
3829
3830
3831 /*
3832 * Range check input...
3833 */
3834
3835 if (!ipp || !attr || !*attr ||
3836 ((*attr)->value_tag != IPP_TAG_INTEGER && (*attr)->value_tag != IPP_TAG_ENUM) ||
3837 element < 0 || element > (*attr)->num_values)
3838 return (0);
3839
3840 /*
3841 * Set the value and return...
3842 */
3843
3844 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3845 value->integer = intvalue;
3846
3847 return (value != NULL);
3848 }
3849
3850
3851 /*
3852 * 'ippSetName()' - Set the name of an attribute.
3853 *
3854 * The @code ipp@ parameter refers to an IPP message previously created using
3855 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3856 *
3857 * The @code attr@ parameter may be modified as a result of setting the value.
3858 *
3859 * @since CUPS 1.6/macOS 10.8@
3860 */
3861
3862 int /* O - 1 on success, 0 on failure */
3863 ippSetName(ipp_t *ipp, /* I - IPP message */
3864 ipp_attribute_t **attr, /* IO - IPP attribute */
3865 const char *name) /* I - Attribute name */
3866 {
3867 char *temp; /* Temporary name value */
3868
3869
3870 /*
3871 * Range check input...
3872 */
3873
3874 if (!ipp || !attr || !*attr)
3875 return (0);
3876
3877 /*
3878 * Set the value and return...
3879 */
3880
3881 if ((temp = _cupsStrAlloc(name)) != NULL)
3882 {
3883 if ((*attr)->name)
3884 _cupsStrFree((*attr)->name);
3885
3886 (*attr)->name = temp;
3887 }
3888
3889 return (temp != NULL);
3890 }
3891
3892
3893 /*
3894 * 'ippSetOctetString()' - Set an octetString value in an IPP attribute.
3895 *
3896 * The @code ipp@ parameter refers to an IPP message previously created using
3897 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3898 *
3899 * The @code attr@ parameter may be modified as a result of setting the value.
3900 *
3901 * The @code element@ parameter specifies which value to set from 0 to
3902 * @code ippGetCount(attr)@.
3903 *
3904 * @since CUPS 1.7/macOS 10.9@
3905 */
3906
3907 int /* O - 1 on success, 0 on failure */
3908 ippSetOctetString(
3909 ipp_t *ipp, /* I - IPP message */
3910 ipp_attribute_t **attr, /* IO - IPP attribute */
3911 int element, /* I - Value number (0-based) */
3912 const void *data, /* I - Pointer to octetString data */
3913 int datalen) /* I - Length of octetString data */
3914 {
3915 _ipp_value_t *value; /* Current value */
3916
3917
3918 /*
3919 * Range check input...
3920 */
3921
3922 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_STRING ||
3923 element < 0 || element > (*attr)->num_values ||
3924 datalen < 0 || datalen > IPP_MAX_LENGTH)
3925 return (0);
3926
3927 /*
3928 * Set the value and return...
3929 */
3930
3931 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3932 {
3933 if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST)
3934 {
3935 /*
3936 * Just copy the pointer...
3937 */
3938
3939 value->unknown.data = (void *)data;
3940 value->unknown.length = datalen;
3941 }
3942 else
3943 {
3944 /*
3945 * Copy the data...
3946 */
3947
3948 if (value->unknown.data)
3949 {
3950 /*
3951 * Free previous data...
3952 */
3953
3954 free(value->unknown.data);
3955
3956 value->unknown.data = NULL;
3957 value->unknown.length = 0;
3958 }
3959
3960 if (datalen > 0)
3961 {
3962 void *temp; /* Temporary data pointer */
3963
3964 if ((temp = malloc((size_t)datalen)) != NULL)
3965 {
3966 memcpy(temp, data, (size_t)datalen);
3967
3968 value->unknown.data = temp;
3969 value->unknown.length = datalen;
3970 }
3971 else
3972 return (0);
3973 }
3974 }
3975 }
3976
3977 return (value != NULL);
3978 }
3979
3980
3981 /*
3982 * 'ippSetOperation()' - Set the operation ID in an IPP request message.
3983 *
3984 * The @code ipp@ parameter refers to an IPP message previously created using
3985 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3986 *
3987 * @since CUPS 1.6/macOS 10.8@
3988 */
3989
3990 int /* O - 1 on success, 0 on failure */
3991 ippSetOperation(ipp_t *ipp, /* I - IPP request message */
3992 ipp_op_t op) /* I - Operation ID */
3993 {
3994 /*
3995 * Range check input...
3996 */
3997
3998 if (!ipp)
3999 return (0);
4000
4001 /*
4002 * Set the operation and return...
4003 */
4004
4005 ipp->request.op.operation_id = op;
4006
4007 return (1);
4008 }
4009
4010
4011 /*
4012 * 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
4013 *
4014 * The @code ipp@ parameter refers to an IPP message previously created using
4015 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4016 *
4017 * The @code attr@ parameter may be modified as a result of setting the value.
4018 *
4019 * The @code element@ parameter specifies which value to set from 0 to
4020 * @code ippGetCount(attr)@.
4021 *
4022 * @since CUPS 1.6/macOS 10.8@
4023 */
4024
4025 int /* O - 1 on success, 0 on failure */
4026 ippSetRange(ipp_t *ipp, /* I - IPP message */
4027 ipp_attribute_t **attr, /* IO - IPP attribute */
4028 int element, /* I - Value number (0-based) */
4029 int lowervalue, /* I - Lower bound for range */
4030 int uppervalue) /* I - Upper bound for range */
4031 {
4032 _ipp_value_t *value; /* Current value */
4033
4034
4035 /*
4036 * Range check input...
4037 */
4038
4039 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_RANGE ||
4040 element < 0 || element > (*attr)->num_values || lowervalue > uppervalue)
4041 return (0);
4042
4043 /*
4044 * Set the value and return...
4045 */
4046
4047 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4048 {
4049 value->range.lower = lowervalue;
4050 value->range.upper = uppervalue;
4051 }
4052
4053 return (value != NULL);
4054 }
4055
4056
4057 /*
4058 * 'ippSetRequestId()' - Set the request ID in an IPP message.
4059 *
4060 * The @code ipp@ parameter refers to an IPP message previously created using
4061 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4062 *
4063 * The @code request_id@ parameter must be greater than 0.
4064 *
4065 * @since CUPS 1.6/macOS 10.8@
4066 */
4067
4068 int /* O - 1 on success, 0 on failure */
4069 ippSetRequestId(ipp_t *ipp, /* I - IPP message */
4070 int request_id) /* I - Request ID */
4071 {
4072 /*
4073 * Range check input; not checking request_id values since ipptool wants to send
4074 * invalid values for conformance testing and a bad request_id does not affect the
4075 * encoding of a message...
4076 */
4077
4078 if (!ipp)
4079 return (0);
4080
4081 /*
4082 * Set the request ID and return...
4083 */
4084
4085 ipp->request.any.request_id = request_id;
4086
4087 return (1);
4088 }
4089
4090
4091 /*
4092 * 'ippSetResolution()' - Set a resolution value in an attribute.
4093 *
4094 * The @code ipp@ parameter refers to an IPP message previously created using
4095 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4096 *
4097 * The @code attr@ parameter may be modified as a result of setting the value.
4098 *
4099 * The @code element@ parameter specifies which value to set from 0 to
4100 * @code ippGetCount(attr)@.
4101 *
4102 * @since CUPS 1.6/macOS 10.8@
4103 */
4104
4105 int /* O - 1 on success, 0 on failure */
4106 ippSetResolution(
4107 ipp_t *ipp, /* I - IPP message */
4108 ipp_attribute_t **attr, /* IO - IPP attribute */
4109 int element, /* I - Value number (0-based) */
4110 ipp_res_t unitsvalue, /* I - Resolution units */
4111 int xresvalue, /* I - Horizontal/cross feed resolution */
4112 int yresvalue) /* I - Vertical/feed resolution */
4113 {
4114 _ipp_value_t *value; /* Current value */
4115
4116
4117 /*
4118 * Range check input...
4119 */
4120
4121 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_RESOLUTION ||
4122 element < 0 || element > (*attr)->num_values || xresvalue <= 0 || yresvalue <= 0 ||
4123 unitsvalue < IPP_RES_PER_INCH || unitsvalue > IPP_RES_PER_CM)
4124 return (0);
4125
4126 /*
4127 * Set the value and return...
4128 */
4129
4130 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4131 {
4132 value->resolution.units = unitsvalue;
4133 value->resolution.xres = xresvalue;
4134 value->resolution.yres = yresvalue;
4135 }
4136
4137 return (value != NULL);
4138 }
4139
4140
4141 /*
4142 * 'ippSetState()' - Set the current state of the IPP message.
4143 *
4144 * @since CUPS 1.6/macOS 10.8@
4145 */
4146
4147 int /* O - 1 on success, 0 on failure */
4148 ippSetState(ipp_t *ipp, /* I - IPP message */
4149 ipp_state_t state) /* I - IPP state value */
4150 {
4151 /*
4152 * Range check input...
4153 */
4154
4155 if (!ipp)
4156 return (0);
4157
4158 /*
4159 * Set the state and return...
4160 */
4161
4162 ipp->state = state;
4163 ipp->current = NULL;
4164
4165 return (1);
4166 }
4167
4168
4169 /*
4170 * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
4171 *
4172 * The @code ipp@ parameter refers to an IPP message previously created using
4173 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4174 *
4175 * @since CUPS 1.6/macOS 10.8@
4176 */
4177
4178 int /* O - 1 on success, 0 on failure */
4179 ippSetStatusCode(ipp_t *ipp, /* I - IPP response or event message */
4180 ipp_status_t status) /* I - Status code */
4181 {
4182 /*
4183 * Range check input...
4184 */
4185
4186 if (!ipp)
4187 return (0);
4188
4189 /*
4190 * Set the status code and return...
4191 */
4192
4193 ipp->request.status.status_code = status;
4194
4195 return (1);
4196 }
4197
4198
4199 /*
4200 * 'ippSetString()' - Set a string value in an attribute.
4201 *
4202 * The @code ipp@ parameter refers to an IPP message previously created using
4203 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4204 *
4205 * The @code attr@ parameter may be modified as a result of setting the value.
4206 *
4207 * The @code element@ parameter specifies which value to set from 0 to
4208 * @code ippGetCount(attr)@.
4209 *
4210 * @since CUPS 1.6/macOS 10.8@
4211 */
4212
4213 int /* O - 1 on success, 0 on failure */
4214 ippSetString(ipp_t *ipp, /* I - IPP message */
4215 ipp_attribute_t **attr, /* IO - IPP attribute */
4216 int element, /* I - Value number (0-based) */
4217 const char *strvalue) /* I - String value */
4218 {
4219 char *temp; /* Temporary string */
4220 _ipp_value_t *value; /* Current value */
4221 ipp_tag_t value_tag; /* Value tag */
4222
4223
4224 /*
4225 * Range check input...
4226 */
4227
4228 if (attr && *attr)
4229 value_tag = (*attr)->value_tag & IPP_TAG_CUPS_MASK;
4230 else
4231 value_tag = IPP_TAG_ZERO;
4232
4233 if (!ipp || !attr || !*attr ||
4234 (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG &&
4235 value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE ||
4236 element < 0 || element > (*attr)->num_values || !strvalue)
4237 return (0);
4238
4239 /*
4240 * Set the value and return...
4241 */
4242
4243 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4244 {
4245 if (element > 0)
4246 value->string.language = (*attr)->values[0].string.language;
4247
4248 if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST)
4249 value->string.text = (char *)strvalue;
4250 else if ((temp = _cupsStrAlloc(strvalue)) != NULL)
4251 {
4252 if (value->string.text)
4253 _cupsStrFree(value->string.text);
4254
4255 value->string.text = temp;
4256 }
4257 else
4258 return (0);
4259 }
4260
4261 return (value != NULL);
4262 }
4263
4264
4265 /*
4266 * 'ippSetStringf()' - Set a formatted string value of an attribute.
4267 *
4268 * The @code ipp@ parameter refers to an IPP message previously created using
4269 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4270 *
4271 * The @code attr@ parameter may be modified as a result of setting the value.
4272 *
4273 * The @code element@ parameter specifies which value to set from 0 to
4274 * @code ippGetCount(attr)@.
4275 *
4276 * The @code format@ parameter uses formatting characters compatible with the
4277 * printf family of standard functions. Additional arguments follow it as
4278 * needed. The formatted string is truncated as needed to the maximum length of
4279 * the corresponding value type.
4280 *
4281 * @since CUPS 1.7/macOS 10.9@
4282 */
4283
4284 int /* O - 1 on success, 0 on failure */
4285 ippSetStringf(ipp_t *ipp, /* I - IPP message */
4286 ipp_attribute_t **attr, /* IO - IPP attribute */
4287 int element, /* I - Value number (0-based) */
4288 const char *format, /* I - Printf-style format string */
4289 ...) /* I - Additional arguments as needed */
4290 {
4291 int ret; /* Return value */
4292 va_list ap; /* Pointer to additional arguments */
4293
4294
4295 va_start(ap, format);
4296 ret = ippSetStringfv(ipp, attr, element, format, ap);
4297 va_end(ap);
4298
4299 return (ret);
4300 }
4301
4302
4303 /*
4304 * 'ippSetStringf()' - Set a formatted string value of an attribute.
4305 *
4306 * The @code ipp@ parameter refers to an IPP message previously created using
4307 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4308 *
4309 * The @code attr@ parameter may be modified as a result of setting the value.
4310 *
4311 * The @code element@ parameter specifies which value to set from 0 to
4312 * @code ippGetCount(attr)@.
4313 *
4314 * The @code format@ parameter uses formatting characters compatible with the
4315 * printf family of standard functions. Additional arguments follow it as
4316 * needed. The formatted string is truncated as needed to the maximum length of
4317 * the corresponding value type.
4318 *
4319 * @since CUPS 1.7/macOS 10.9@
4320 */
4321
4322 int /* O - 1 on success, 0 on failure */
4323 ippSetStringfv(ipp_t *ipp, /* I - IPP message */
4324 ipp_attribute_t **attr, /* IO - IPP attribute */
4325 int element, /* I - Value number (0-based) */
4326 const char *format, /* I - Printf-style format string */
4327 va_list ap) /* I - Pointer to additional arguments */
4328 {
4329 ipp_tag_t value_tag; /* Value tag */
4330 char buffer[IPP_MAX_TEXT + 4];
4331 /* Formatted text string */
4332 ssize_t bytes, /* Length of formatted value */
4333 max_bytes; /* Maximum number of bytes for value */
4334
4335
4336 /*
4337 * Range check input...
4338 */
4339
4340 if (attr && *attr)
4341 value_tag = (*attr)->value_tag & IPP_TAG_CUPS_MASK;
4342 else
4343 value_tag = IPP_TAG_ZERO;
4344
4345 if (!ipp || !attr || !*attr ||
4346 (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG &&
4347 value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE ||
4348 !format)
4349 return (0);
4350
4351 /*
4352 * Format the string...
4353 */
4354
4355 if (!strcmp(format, "%s"))
4356 {
4357 /*
4358 * Optimize the simple case...
4359 */
4360
4361 const char *s = va_arg(ap, char *);
4362
4363 if (!s)
4364 s = "(null)";
4365
4366 bytes = (ssize_t)strlen(s);
4367 strlcpy(buffer, s, sizeof(buffer));
4368 }
4369 else
4370 {
4371 /*
4372 * Do a full formatting of the message...
4373 */
4374
4375 if ((bytes = vsnprintf(buffer, sizeof(buffer), format, ap)) < 0)
4376 return (0);
4377 }
4378
4379 /*
4380 * Limit the length of the string...
4381 */
4382
4383 switch (value_tag)
4384 {
4385 default :
4386 case IPP_TAG_TEXT :
4387 case IPP_TAG_TEXTLANG :
4388 max_bytes = IPP_MAX_TEXT;
4389 break;
4390
4391 case IPP_TAG_NAME :
4392 case IPP_TAG_NAMELANG :
4393 max_bytes = IPP_MAX_NAME;
4394 break;
4395
4396 case IPP_TAG_CHARSET :
4397 max_bytes = IPP_MAX_CHARSET;
4398 break;
4399
4400 case IPP_TAG_KEYWORD :
4401 max_bytes = IPP_MAX_KEYWORD;
4402 break;
4403
4404 case IPP_TAG_LANGUAGE :
4405 max_bytes = IPP_MAX_LANGUAGE;
4406 break;
4407
4408 case IPP_TAG_MIMETYPE :
4409 max_bytes = IPP_MAX_MIMETYPE;
4410 break;
4411
4412 case IPP_TAG_URI :
4413 max_bytes = IPP_MAX_URI;
4414 break;
4415
4416 case IPP_TAG_URISCHEME :
4417 max_bytes = IPP_MAX_URISCHEME;
4418 break;
4419 }
4420
4421 if (bytes >= max_bytes)
4422 {
4423 char *bufmax, /* Buffer at max_bytes */
4424 *bufptr; /* Pointer into buffer */
4425
4426 bufptr = buffer + strlen(buffer) - 1;
4427 bufmax = buffer + max_bytes - 1;
4428
4429 while (bufptr > bufmax)
4430 {
4431 if (*bufptr & 0x80)
4432 {
4433 while ((*bufptr & 0xc0) == 0x80 && bufptr > buffer)
4434 bufptr --;
4435 }
4436
4437 bufptr --;
4438 }
4439
4440 *bufptr = '\0';
4441 }
4442
4443 /*
4444 * Set the formatted string and return...
4445 */
4446
4447 return (ippSetString(ipp, attr, element, buffer));
4448 }
4449
4450
4451 /*
4452 * 'ippSetValueTag()' - Set the value tag of an attribute.
4453 *
4454 * The @code ipp@ parameter refers to an IPP message previously created using
4455 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4456 *
4457 * The @code attr@ parameter may be modified as a result of setting the value.
4458 *
4459 * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger
4460 * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name
4461 * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text
4462 * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage
4463 * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various
4464 * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes
4465 * will be rejected.
4466 *
4467 * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language
4468 * code in the "attributes-natural-language" attribute or, if not present, the language
4469 * code for the current locale.
4470 *
4471 * @since CUPS 1.6/macOS 10.8@
4472 */
4473
4474 int /* O - 1 on success, 0 on failure */
4475 ippSetValueTag(
4476 ipp_t *ipp, /* I - IPP message */
4477 ipp_attribute_t **attr, /* IO - IPP attribute */
4478 ipp_tag_t value_tag) /* I - Value tag */
4479 {
4480 int i; /* Looping var */
4481 _ipp_value_t *value; /* Current value */
4482 int integer; /* Current integer value */
4483 cups_lang_t *language; /* Current language */
4484 char code[32]; /* Language code */
4485 ipp_tag_t temp_tag; /* Temporary value tag */
4486
4487
4488 /*
4489 * Range check input...
4490 */
4491
4492 if (!ipp || !attr || !*attr)
4493 return (0);
4494
4495 /*
4496 * If there is no change, return immediately...
4497 */
4498
4499 if (value_tag == (*attr)->value_tag)
4500 return (1);
4501
4502 /*
4503 * Otherwise implement changes as needed...
4504 */
4505
4506 temp_tag = (ipp_tag_t)((int)((*attr)->value_tag) & IPP_TAG_CUPS_MASK);
4507
4508 switch (value_tag)
4509 {
4510 case IPP_TAG_UNSUPPORTED_VALUE :
4511 case IPP_TAG_DEFAULT :
4512 case IPP_TAG_UNKNOWN :
4513 case IPP_TAG_NOVALUE :
4514 case IPP_TAG_NOTSETTABLE :
4515 case IPP_TAG_DELETEATTR :
4516 case IPP_TAG_ADMINDEFINE :
4517 /*
4518 * Free any existing values...
4519 */
4520
4521 if ((*attr)->num_values > 0)
4522 ipp_free_values(*attr, 0, (*attr)->num_values);
4523
4524 /*
4525 * Set out-of-band value...
4526 */
4527
4528 (*attr)->value_tag = value_tag;
4529 break;
4530
4531 case IPP_TAG_RANGE :
4532 if (temp_tag != IPP_TAG_INTEGER)
4533 return (0);
4534
4535 for (i = (*attr)->num_values, value = (*attr)->values;
4536 i > 0;
4537 i --, value ++)
4538 {
4539 integer = value->integer;
4540 value->range.lower = value->range.upper = integer;
4541 }
4542
4543 (*attr)->value_tag = IPP_TAG_RANGE;
4544 break;
4545
4546 case IPP_TAG_NAME :
4547 if (temp_tag != IPP_TAG_KEYWORD && temp_tag != IPP_TAG_URI &&
4548 temp_tag != IPP_TAG_URISCHEME && temp_tag != IPP_TAG_LANGUAGE &&
4549 temp_tag != IPP_TAG_MIMETYPE)
4550 return (0);
4551
4552 (*attr)->value_tag = (ipp_tag_t)(IPP_TAG_NAME | ((*attr)->value_tag & IPP_TAG_CUPS_CONST));
4553 break;
4554
4555 case IPP_TAG_NAMELANG :
4556 case IPP_TAG_TEXTLANG :
4557 if (value_tag == IPP_TAG_NAMELANG &&
4558 (temp_tag != IPP_TAG_NAME && temp_tag != IPP_TAG_KEYWORD &&
4559 temp_tag != IPP_TAG_URI && temp_tag != IPP_TAG_URISCHEME &&
4560 temp_tag != IPP_TAG_LANGUAGE && temp_tag != IPP_TAG_MIMETYPE))
4561 return (0);
4562
4563 if (value_tag == IPP_TAG_TEXTLANG && temp_tag != IPP_TAG_TEXT)
4564 return (0);
4565
4566 if (ipp->attrs && ipp->attrs->next && ipp->attrs->next->name &&
4567 !strcmp(ipp->attrs->next->name, "attributes-natural-language"))
4568 {
4569 /*
4570 * Use the language code from the IPP message...
4571 */
4572
4573 (*attr)->values[0].string.language =
4574 _cupsStrAlloc(ipp->attrs->next->values[0].string.text);
4575 }
4576 else
4577 {
4578 /*
4579 * Otherwise, use the language code corresponding to the locale...
4580 */
4581
4582 language = cupsLangDefault();
4583 (*attr)->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language->language,
4584 code,
4585 sizeof(code)));
4586 }
4587
4588 for (i = (*attr)->num_values - 1, value = (*attr)->values + 1;
4589 i > 0;
4590 i --, value ++)
4591 value->string.language = (*attr)->values[0].string.language;
4592
4593 if ((int)(*attr)->value_tag & IPP_TAG_CUPS_CONST)
4594 {
4595 /*
4596 * Make copies of all values...
4597 */
4598
4599 for (i = (*attr)->num_values, value = (*attr)->values;
4600 i > 0;
4601 i --, value ++)
4602 value->string.text = _cupsStrAlloc(value->string.text);
4603 }
4604
4605 (*attr)->value_tag = IPP_TAG_NAMELANG;
4606 break;
4607
4608 case IPP_TAG_KEYWORD :
4609 if (temp_tag == IPP_TAG_NAME || temp_tag == IPP_TAG_NAMELANG)
4610 break; /* Silently "allow" name -> keyword */
4611
4612 default :
4613 return (0);
4614 }
4615
4616 return (1);
4617 }
4618
4619
4620 /*
4621 * 'ippSetVersion()' - Set the version number in an IPP message.
4622 *
4623 * The @code ipp@ parameter refers to an IPP message previously created using
4624 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4625 *
4626 * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
4627 *
4628 * @since CUPS 1.6/macOS 10.8@
4629 */
4630
4631 int /* O - 1 on success, 0 on failure */
4632 ippSetVersion(ipp_t *ipp, /* I - IPP message */
4633 int major, /* I - Major version number (major.minor) */
4634 int minor) /* I - Minor version number (major.minor) */
4635 {
4636 /*
4637 * Range check input...
4638 */
4639
4640 if (!ipp || major < 0 || minor < 0)
4641 return (0);
4642
4643 /*
4644 * Set the version number...
4645 */
4646
4647 ipp->request.any.version[0] = (ipp_uchar_t)major;
4648 ipp->request.any.version[1] = (ipp_uchar_t)minor;
4649
4650 return (1);
4651 }
4652
4653
4654 /*
4655 * 'ippTimeToDate()' - Convert from time in seconds to RFC 2579 format.
4656 */
4657
4658 const ipp_uchar_t * /* O - RFC-2579 date/time data */
4659 ippTimeToDate(time_t t) /* I - Time in seconds */
4660 {
4661 struct tm *unixdate; /* UNIX unixdate/time info */
4662 ipp_uchar_t *date = _cupsGlobals()->ipp_date;
4663 /* RFC-2579 date/time data */
4664
4665
4666 /*
4667 * RFC-2579 date/time format is:
4668 *
4669 * Byte(s) Description
4670 * ------- -----------
4671 * 0-1 Year (0 to 65535)
4672 * 2 Month (1 to 12)
4673 * 3 Day (1 to 31)
4674 * 4 Hours (0 to 23)
4675 * 5 Minutes (0 to 59)
4676 * 6 Seconds (0 to 60, 60 = "leap second")
4677 * 7 Deciseconds (0 to 9)
4678 * 8 +/- UTC
4679 * 9 UTC hours (0 to 11)
4680 * 10 UTC minutes (0 to 59)
4681 */
4682
4683 unixdate = gmtime(&t);
4684 unixdate->tm_year += 1900;
4685
4686 date[0] = (ipp_uchar_t)(unixdate->tm_year >> 8);
4687 date[1] = (ipp_uchar_t)(unixdate->tm_year);
4688 date[2] = (ipp_uchar_t)(unixdate->tm_mon + 1);
4689 date[3] = (ipp_uchar_t)unixdate->tm_mday;
4690 date[4] = (ipp_uchar_t)unixdate->tm_hour;
4691 date[5] = (ipp_uchar_t)unixdate->tm_min;
4692 date[6] = (ipp_uchar_t)unixdate->tm_sec;
4693 date[7] = 0;
4694 date[8] = '+';
4695 date[9] = 0;
4696 date[10] = 0;
4697
4698 return (date);
4699 }
4700
4701
4702 /*
4703 * 'ippValidateAttribute()' - Validate the contents of an attribute.
4704 *
4705 * This function validates the contents of an attribute based on the name and
4706 * value tag. 1 is returned if the attribute is valid, 0 otherwise. On
4707 * failure, @link cupsLastErrorString@ is set to a human-readable message.
4708 *
4709 * @since CUPS 1.7/macOS 10.9@
4710 */
4711
4712 int /* O - 1 if valid, 0 otherwise */
4713 ippValidateAttribute(
4714 ipp_attribute_t *attr) /* I - Attribute */
4715 {
4716 int i; /* Looping var */
4717 char scheme[64], /* Scheme from URI */
4718 userpass[256], /* Username/password from URI */
4719 hostname[256], /* Hostname from URI */
4720 resource[1024]; /* Resource from URI */
4721 int port, /* Port number from URI */
4722 uri_status; /* URI separation status */
4723 const char *ptr; /* Pointer into string */
4724 ipp_attribute_t *colattr; /* Collection attribute */
4725 regex_t re; /* Regular expression */
4726 ipp_uchar_t *date; /* Current date value */
4727
4728
4729 /*
4730 * Skip separators.
4731 */
4732
4733 if (!attr->name)
4734 return (1);
4735
4736 /*
4737 * Validate the attribute name.
4738 */
4739
4740 for (ptr = attr->name; *ptr; ptr ++)
4741 if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' && *ptr != '_')
4742 break;
4743
4744 if (*ptr || ptr == attr->name)
4745 {
4746 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad attribute name - invalid character (RFC 8011 section 5.1.4)."), attr->name);
4747 return (0);
4748 }
4749
4750 if ((ptr - attr->name) > 255)
4751 {
4752 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad attribute name - bad length %d (RFC 8011 section 5.1.4)."), attr->name, (int)(ptr - attr->name));
4753 return (0);
4754 }
4755
4756 switch (attr->value_tag)
4757 {
4758 case IPP_TAG_INTEGER :
4759 break;
4760
4761 case IPP_TAG_BOOLEAN :
4762 for (i = 0; i < attr->num_values; i ++)
4763 {
4764 if (attr->values[i].boolean != 0 &&
4765 attr->values[i].boolean != 1)
4766 {
4767 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad boolean value %d (RFC 8011 section 5.1.21)."), attr->name, attr->values[i].boolean);
4768 return (0);
4769 }
4770 }
4771 break;
4772
4773 case IPP_TAG_ENUM :
4774 for (i = 0; i < attr->num_values; i ++)
4775 {
4776 if (attr->values[i].integer < 1)
4777 {
4778 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad enum value %d - out of range (RFC 8011 section 5.1.5)."), attr->name, attr->values[i].integer);
4779 return (0);
4780 }
4781 }
4782 break;
4783
4784 case IPP_TAG_STRING :
4785 for (i = 0; i < attr->num_values; i ++)
4786 {
4787 if (attr->values[i].unknown.length > IPP_MAX_OCTETSTRING)
4788 {
4789 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad octetString value - bad length %d (RFC 8011 section 5.1.20)."), attr->name, attr->values[i].unknown.length);
4790 return (0);
4791 }
4792 }
4793 break;
4794
4795 case IPP_TAG_DATE :
4796 for (i = 0; i < attr->num_values; i ++)
4797 {
4798 date = attr->values[i].date;
4799
4800 if (date[2] < 1 || date[2] > 12)
4801 {
4802 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime month %u (RFC 8011 section 5.1.15)."), attr->name, date[2]);
4803 return (0);
4804 }
4805
4806 if (date[3] < 1 || date[3] > 31)
4807 {
4808 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime day %u (RFC 8011 section 5.1.15)."), attr->name, date[3]);
4809 return (0);
4810 }
4811
4812 if (date[4] > 23)
4813 {
4814 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime hours %u (RFC 8011 section 5.1.15)."), attr->name, date[4]);
4815 return (0);
4816 }
4817
4818 if (date[5] > 59)
4819 {
4820 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime minutes %u (RFC 8011 section 5.1.15)."), attr->name, date[5]);
4821 return (0);
4822 }
4823
4824 if (date[6] > 60)
4825 {
4826 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime seconds %u (RFC 8011 section 5.1.15)."), attr->name, date[6]);
4827 return (0);
4828 }
4829
4830 if (date[7] > 9)
4831 {
4832 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime deciseconds %u (RFC 8011 section 5.1.15)."), attr->name, date[7]);
4833 return (0);
4834 }
4835
4836 if (date[8] != '-' && date[8] != '+')
4837 {
4838 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime UTC sign '%c' (RFC 8011 section 5.1.15)."), attr->name, date[8]);
4839 return (0);
4840 }
4841
4842 if (date[9] > 11)
4843 {
4844 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime UTC hours %u (RFC 8011 section 5.1.15)."), attr->name, date[9]);
4845 return (0);
4846 }
4847
4848 if (date[10] > 59)
4849 {
4850 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime UTC minutes %u (RFC 8011 section 5.1.15)."), attr->name, date[10]);
4851 return (0);
4852 }
4853 }
4854 break;
4855
4856 case IPP_TAG_RESOLUTION :
4857 for (i = 0; i < attr->num_values; i ++)
4858 {
4859 if (attr->values[i].resolution.xres <= 0)
4860 {
4861 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad resolution value %dx%d%s - cross feed resolution must be positive (RFC 8011 section 5.1.16)."), attr->name, attr->values[i].resolution.xres, attr->values[i].resolution.yres, attr->values[i].resolution.units == IPP_RES_PER_INCH ? "dpi" : attr->values[i].resolution.units == IPP_RES_PER_CM ? "dpcm" : "unknown");
4862 return (0);
4863 }
4864
4865 if (attr->values[i].resolution.yres <= 0)
4866 {
4867 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad resolution value %dx%d%s - feed resolution must be positive (RFC 8011 section 5.1.16)."), attr->name, attr->values[i].resolution.xres, attr->values[i].resolution.yres, attr->values[i].resolution.units == IPP_RES_PER_INCH ? "dpi" : attr->values[i].resolution.units == IPP_RES_PER_CM ? "dpcm" : "unknown");
4868 return (0);
4869 }
4870
4871 if (attr->values[i].resolution.units != IPP_RES_PER_INCH && attr->values[i].resolution.units != IPP_RES_PER_CM)
4872 {
4873 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad resolution value %dx%d%s - bad units value (RFC 8011 section 5.1.16)."), attr->name, attr->values[i].resolution.xres, attr->values[i].resolution.yres, attr->values[i].resolution.units == IPP_RES_PER_INCH ? "dpi" : attr->values[i].resolution.units == IPP_RES_PER_CM ? "dpcm" : "unknown");
4874 return (0);
4875 }
4876 }
4877 break;
4878
4879 case IPP_TAG_RANGE :
4880 for (i = 0; i < attr->num_values; i ++)
4881 {
4882 if (attr->values[i].range.lower > attr->values[i].range.upper)
4883 {
4884 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad rangeOfInteger value %d-%d - lower greater than upper (RFC 8011 section 5.1.14)."), attr->name, attr->values[i].range.lower, attr->values[i].range.upper);
4885 return (0);
4886 }
4887 }
4888 break;
4889
4890 case IPP_TAG_BEGIN_COLLECTION :
4891 for (i = 0; i < attr->num_values; i ++)
4892 {
4893 for (colattr = attr->values[i].collection->attrs;
4894 colattr;
4895 colattr = colattr->next)
4896 {
4897 if (!ippValidateAttribute(colattr))
4898 return (0);
4899 }
4900 }
4901 break;
4902
4903 case IPP_TAG_TEXT :
4904 case IPP_TAG_TEXTLANG :
4905 for (i = 0; i < attr->num_values; i ++)
4906 {
4907 for (ptr = attr->values[i].string.text; *ptr; ptr ++)
4908 {
4909 if ((*ptr & 0xe0) == 0xc0)
4910 {
4911 ptr ++;
4912 if ((*ptr & 0xc0) != 0x80)
4913 break;
4914 }
4915 else if ((*ptr & 0xf0) == 0xe0)
4916 {
4917 ptr ++;
4918 if ((*ptr & 0xc0) != 0x80)
4919 break;
4920 ptr ++;
4921 if ((*ptr & 0xc0) != 0x80)
4922 break;
4923 }
4924 else if ((*ptr & 0xf8) == 0xf0)
4925 {
4926 ptr ++;
4927 if ((*ptr & 0xc0) != 0x80)
4928 break;
4929 ptr ++;
4930 if ((*ptr & 0xc0) != 0x80)
4931 break;
4932 ptr ++;
4933 if ((*ptr & 0xc0) != 0x80)
4934 break;
4935 }
4936 else if (*ptr & 0x80)
4937 break;
4938 else if ((*ptr < ' ' && *ptr != '\n' && *ptr != '\r' && *ptr != '\t') || *ptr == 0x7f)
4939 break;
4940 }
4941
4942 if (*ptr)
4943 {
4944 if (*ptr < ' ' || *ptr == 0x7f)
4945 {
4946 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad text value \"%s\" - bad control character (PWG 5100.14 section 8.3)."), attr->name, attr->values[i].string.text);
4947 return (0);
4948 }
4949 else
4950 {
4951 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad text value \"%s\" - bad UTF-8 sequence (RFC 8011 section 5.1.2)."), attr->name, attr->values[i].string.text);
4952 return (0);
4953 }
4954 }
4955
4956 if ((ptr - attr->values[i].string.text) > (IPP_MAX_TEXT - 1))
4957 {
4958 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad text value \"%s\" - bad length %d (RFC 8011 section 5.1.2)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text));
4959 return (0);
4960 }
4961 }
4962 break;
4963
4964 case IPP_TAG_NAME :
4965 case IPP_TAG_NAMELANG :
4966 for (i = 0; i < attr->num_values; i ++)
4967 {
4968 for (ptr = attr->values[i].string.text; *ptr; ptr ++)
4969 {
4970 if ((*ptr & 0xe0) == 0xc0)
4971 {
4972 ptr ++;
4973 if ((*ptr & 0xc0) != 0x80)
4974 break;
4975 }
4976 else if ((*ptr & 0xf0) == 0xe0)
4977 {
4978 ptr ++;
4979 if ((*ptr & 0xc0) != 0x80)
4980 break;
4981 ptr ++;
4982 if ((*ptr & 0xc0) != 0x80)
4983 break;
4984 }
4985 else if ((*ptr & 0xf8) == 0xf0)
4986 {
4987 ptr ++;
4988 if ((*ptr & 0xc0) != 0x80)
4989 break;
4990 ptr ++;
4991 if ((*ptr & 0xc0) != 0x80)
4992 break;
4993 ptr ++;
4994 if ((*ptr & 0xc0) != 0x80)
4995 break;
4996 }
4997 else if (*ptr & 0x80)
4998 break;
4999 else if (*ptr < ' ' || *ptr == 0x7f)
5000 break;
5001 }
5002
5003 if (*ptr)
5004 {
5005 if (*ptr < ' ' || *ptr == 0x7f)
5006 {
5007 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad name value \"%s\" - bad control character (PWG 5100.14 section 8.1)."), attr->name, attr->values[i].string.text);
5008 return (0);
5009 }
5010 else
5011 {
5012 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad name value \"%s\" - bad UTF-8 sequence (RFC 8011 section 5.1.3)."), attr->name, attr->values[i].string.text);
5013 return (0);
5014 }
5015 }
5016
5017 if ((ptr - attr->values[i].string.text) > (IPP_MAX_NAME - 1))
5018 {
5019 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad name value \"%s\" - bad length %d (RFC 8011 section 5.1.3)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text));
5020 return (0);
5021 }
5022 }
5023 break;
5024
5025 case IPP_TAG_KEYWORD :
5026 for (i = 0; i < attr->num_values; i ++)
5027 {
5028 for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5029 {
5030 if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' &&
5031 *ptr != '_')
5032 break;
5033 }
5034
5035 if (*ptr || ptr == attr->values[i].string.text)
5036 {
5037 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad keyword value \"%s\" - invalid character (RFC 8011 section 5.1.4)."), attr->name, attr->values[i].string.text);
5038 return (0);
5039 }
5040
5041 if ((ptr - attr->values[i].string.text) > (IPP_MAX_KEYWORD - 1))
5042 {
5043 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad keyword value \"%s\" - bad length %d (RFC 8011 section 5.1.4)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text));
5044 return (0);
5045 }
5046 }
5047 break;
5048
5049 case IPP_TAG_URI :
5050 for (i = 0; i < attr->num_values; i ++)
5051 {
5052 uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource));
5053
5054 if (uri_status < HTTP_URI_STATUS_OK)
5055 {
5056 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad URI value \"%s\" - %s (RFC 8011 section 5.1.6)."), attr->name, attr->values[i].string.text, httpURIStatusString(uri_status));
5057 return (0);
5058 }
5059
5060 if (strlen(attr->values[i].string.text) > (IPP_MAX_URI - 1))
5061 {
5062 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad URI value \"%s\" - bad length %d (RFC 8011 section 5.1.6)."), attr->name, attr->values[i].string.text, (int)strlen(attr->values[i].string.text));
5063 }
5064 }
5065 break;
5066
5067 case IPP_TAG_URISCHEME :
5068 for (i = 0; i < attr->num_values; i ++)
5069 {
5070 ptr = attr->values[i].string.text;
5071 if (islower(*ptr & 255))
5072 {
5073 for (ptr ++; *ptr; ptr ++)
5074 {
5075 if (!islower(*ptr & 255) && !isdigit(*ptr & 255) &&
5076 *ptr != '+' && *ptr != '-' && *ptr != '.')
5077 break;
5078 }
5079 }
5080
5081 if (*ptr || ptr == attr->values[i].string.text)
5082 {
5083 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad uriScheme value \"%s\" - bad characters (RFC 8011 section 5.1.7)."), attr->name, attr->values[i].string.text);
5084 return (0);
5085 }
5086
5087 if ((ptr - attr->values[i].string.text) > (IPP_MAX_URISCHEME - 1))
5088 {
5089 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad uriScheme value \"%s\" - bad length %d (RFC 8011 section 5.1.7)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text));
5090 return (0);
5091 }
5092 }
5093 break;
5094
5095 case IPP_TAG_CHARSET :
5096 for (i = 0; i < attr->num_values; i ++)
5097 {
5098 for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5099 {
5100 if (!isprint(*ptr & 255) || isupper(*ptr & 255) ||
5101 isspace(*ptr & 255))
5102 break;
5103 }
5104
5105 if (*ptr || ptr == attr->values[i].string.text)
5106 {
5107 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad charset value \"%s\" - bad characters (RFC 8011 section 5.1.8)."), attr->name, attr->values[i].string.text);
5108 return (0);
5109 }
5110
5111 if ((ptr - attr->values[i].string.text) > (IPP_MAX_CHARSET - 1))
5112 {
5113 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad charset value \"%s\" - bad length %d (RFC 8011 section 5.1.8)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text));
5114 return (0);
5115 }
5116 }
5117 break;
5118
5119 case IPP_TAG_LANGUAGE :
5120 /*
5121 * The following regular expression is derived from the ABNF for
5122 * language tags in RFC 4646. All I can say is that this is the
5123 * easiest way to check the values...
5124 */
5125
5126 if ((i = regcomp(&re,
5127 "^("
5128 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
5129 /* language */
5130 "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */
5131 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */
5132 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */
5133 "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */
5134 "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */
5135 "|"
5136 "x(-[a-z0-9]{1,8})+" /* privateuse */
5137 "|"
5138 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
5139 ")$",
5140 REG_NOSUB | REG_EXTENDED)) != 0)
5141 {
5142 char temp[256]; /* Temporary error string */
5143
5144 regerror(i, &re, temp, sizeof(temp));
5145 ipp_set_error(IPP_STATUS_ERROR_INTERNAL, _("Unable to compile naturalLanguage regular expression: %s."), temp);
5146 return (0);
5147 }
5148
5149 for (i = 0; i < attr->num_values; i ++)
5150 {
5151 if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
5152 {
5153 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad naturalLanguage value \"%s\" - bad characters (RFC 8011 section 5.1.9)."), attr->name, attr->values[i].string.text);
5154 regfree(&re);
5155 return (0);
5156 }
5157
5158 if (strlen(attr->values[i].string.text) > (IPP_MAX_LANGUAGE - 1))
5159 {
5160 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad naturalLanguage value \"%s\" - bad length %d (RFC 8011 section 5.1.9)."), attr->name, attr->values[i].string.text, (int)strlen(attr->values[i].string.text));
5161 regfree(&re);
5162 return (0);
5163 }
5164 }
5165
5166 regfree(&re);
5167 break;
5168
5169 case IPP_TAG_MIMETYPE :
5170 /*
5171 * The following regular expression is derived from the ABNF for
5172 * MIME media types in RFC 2045 and 4288. All I can say is that this is
5173 * the easiest way to check the values...
5174 */
5175
5176 if ((i = regcomp(&re,
5177 "^"
5178 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
5179 "/"
5180 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
5181 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
5182 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
5183 /* value */
5184 "$",
5185 REG_NOSUB | REG_EXTENDED)) != 0)
5186 {
5187 char temp[256]; /* Temporary error string */
5188
5189 regerror(i, &re, temp, sizeof(temp));
5190 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("Unable to compile mimeMediaType regular expression: %s."), temp);
5191 return (0);
5192 }
5193
5194 for (i = 0; i < attr->num_values; i ++)
5195 {
5196 if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
5197 {
5198 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad mimeMediaType value \"%s\" - bad characters (RFC 8011 section 5.1.10)."), attr->name, attr->values[i].string.text);
5199 regfree(&re);
5200 return (0);
5201 }
5202
5203 if (strlen(attr->values[i].string.text) > (IPP_MAX_MIMETYPE - 1))
5204 {
5205 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad mimeMediaType value \"%s\" - bad length %d (RFC 8011 section 5.1.10)."), attr->name, attr->values[i].string.text, (int)strlen(attr->values[i].string.text));
5206 regfree(&re);
5207 return (0);
5208 }
5209 }
5210
5211 regfree(&re);
5212 break;
5213
5214 default :
5215 break;
5216 }
5217
5218 return (1);
5219 }
5220
5221
5222 /*
5223 * 'ippValidateAttributes()' - Validate all attributes in an IPP message.
5224 *
5225 * This function validates the contents of the IPP message, including each
5226 * attribute. Like @link ippValidateAttribute@, @link cupsLastErrorString@ is
5227 * set to a human-readable message on failure.
5228 *
5229 * @since CUPS 1.7/macOS 10.9@
5230 */
5231
5232 int /* O - 1 if valid, 0 otherwise */
5233 ippValidateAttributes(ipp_t *ipp) /* I - IPP message */
5234 {
5235 ipp_attribute_t *attr; /* Current attribute */
5236
5237
5238 if (!ipp)
5239 return (1);
5240
5241 for (attr = ipp->attrs; attr; attr = attr->next)
5242 if (!ippValidateAttribute(attr))
5243 return (0);
5244
5245 return (1);
5246 }
5247
5248
5249 /*
5250 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
5251 */
5252
5253 ipp_state_t /* O - Current state */
5254 ippWrite(http_t *http, /* I - HTTP connection */
5255 ipp_t *ipp) /* I - IPP data */
5256 {
5257 DEBUG_printf(("ippWrite(http=%p, ipp=%p)", (void *)http, (void *)ipp));
5258
5259 if (!http)
5260 return (IPP_STATE_ERROR);
5261
5262 return (ippWriteIO(http, (ipp_iocb_t)httpWrite2, http->blocking, NULL, ipp));
5263 }
5264
5265
5266 /*
5267 * 'ippWriteFile()' - Write data for an IPP message to a file.
5268 *
5269 * @since CUPS 1.1.19/macOS 10.3@
5270 */
5271
5272 ipp_state_t /* O - Current state */
5273 ippWriteFile(int fd, /* I - HTTP data */
5274 ipp_t *ipp) /* I - IPP data */
5275 {
5276 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd, (void *)ipp));
5277
5278 ipp->state = IPP_STATE_IDLE;
5279
5280 return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp));
5281 }
5282
5283
5284 /*
5285 * 'ippWriteIO()' - Write data for an IPP message.
5286 *
5287 * @since CUPS 1.2/macOS 10.5@
5288 */
5289
5290 ipp_state_t /* O - Current state */
5291 ippWriteIO(void *dst, /* I - Destination */
5292 ipp_iocb_t cb, /* I - Write callback function */
5293 int blocking, /* I - Use blocking IO? */
5294 ipp_t *parent, /* I - Parent IPP message */
5295 ipp_t *ipp) /* I - IPP data */
5296 {
5297 int i; /* Looping var */
5298 int n; /* Length of data */
5299 unsigned char *buffer, /* Data buffer */
5300 *bufptr; /* Pointer into buffer */
5301 ipp_attribute_t *attr; /* Current attribute */
5302 _ipp_value_t *value; /* Current value */
5303
5304
5305 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)dst, (void *)cb, blocking, (void *)parent, (void *)ipp));
5306
5307 if (!dst || !ipp)
5308 return (IPP_STATE_ERROR);
5309
5310 if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
5311 {
5312 DEBUG_puts("1ippWriteIO: Unable to get write buffer");
5313 return (IPP_STATE_ERROR);
5314 }
5315
5316 switch (ipp->state)
5317 {
5318 case IPP_STATE_IDLE :
5319 ipp->state ++; /* Avoid common problem... */
5320
5321 case IPP_STATE_HEADER :
5322 if (parent == NULL)
5323 {
5324 /*
5325 * Send the request header:
5326 *
5327 * Version = 2 bytes
5328 * Operation/Status Code = 2 bytes
5329 * Request ID = 4 bytes
5330 * Total = 8 bytes
5331 */
5332
5333 bufptr = buffer;
5334
5335 *bufptr++ = ipp->request.any.version[0];
5336 *bufptr++ = ipp->request.any.version[1];
5337 *bufptr++ = (ipp_uchar_t)(ipp->request.any.op_status >> 8);
5338 *bufptr++ = (ipp_uchar_t)ipp->request.any.op_status;
5339 *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 24);
5340 *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 16);
5341 *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 8);
5342 *bufptr++ = (ipp_uchar_t)ipp->request.any.request_id;
5343
5344 DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer[0], buffer[1]));
5345 DEBUG_printf(("2ippWriteIO: op_status=%04x",
5346 ipp->request.any.op_status));
5347 DEBUG_printf(("2ippWriteIO: request_id=%d",
5348 ipp->request.any.request_id));
5349
5350 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5351 {
5352 DEBUG_puts("1ippWriteIO: Could not write IPP header...");
5353 _cupsBufferRelease((char *)buffer);
5354 return (IPP_STATE_ERROR);
5355 }
5356 }
5357
5358 /*
5359 * Reset the state engine to point to the first attribute
5360 * in the request/response, with no current group.
5361 */
5362
5363 ipp->state = IPP_STATE_ATTRIBUTE;
5364 ipp->current = ipp->attrs;
5365 ipp->curtag = IPP_TAG_ZERO;
5366
5367 DEBUG_printf(("1ippWriteIO: ipp->current=%p", (void *)ipp->current));
5368
5369 /*
5370 * If blocking is disabled, stop here...
5371 */
5372
5373 if (!blocking)
5374 break;
5375
5376 case IPP_STATE_ATTRIBUTE :
5377 while (ipp->current != NULL)
5378 {
5379 /*
5380 * Write this attribute...
5381 */
5382
5383 bufptr = buffer;
5384 attr = ipp->current;
5385
5386 ipp->current = ipp->current->next;
5387
5388 if (!parent)
5389 {
5390 if (ipp->curtag != attr->group_tag)
5391 {
5392 /*
5393 * Send a group tag byte...
5394 */
5395
5396 ipp->curtag = attr->group_tag;
5397
5398 if (attr->group_tag == IPP_TAG_ZERO)
5399 continue;
5400
5401 DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
5402 attr->group_tag, ippTagString(attr->group_tag)));
5403 *bufptr++ = (ipp_uchar_t)attr->group_tag;
5404 }
5405 else if (attr->group_tag == IPP_TAG_ZERO)
5406 continue;
5407 }
5408
5409 DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr->name,
5410 attr->num_values > 1 ? "1setOf " : "",
5411 ippTagString(attr->value_tag)));
5412
5413 /*
5414 * Write the attribute tag and name.
5415 *
5416 * The attribute name length does not include the trailing nul
5417 * character in the source string.
5418 *
5419 * Collection values (parent != NULL) are written differently...
5420 */
5421
5422 if (parent == NULL)
5423 {
5424 /*
5425 * Get the length of the attribute name, and make sure it won't
5426 * overflow the buffer...
5427 */
5428
5429 if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 8))
5430 {
5431 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
5432 _cupsBufferRelease((char *)buffer);
5433 return (IPP_STATE_ERROR);
5434 }
5435
5436 /*
5437 * Write the value tag, name length, and name string...
5438 */
5439
5440 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5441 attr->value_tag, ippTagString(attr->value_tag)));
5442 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
5443 attr->name));
5444
5445 if (attr->value_tag > 0xff)
5446 {
5447 *bufptr++ = IPP_TAG_EXTENSION;
5448 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
5449 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
5450 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
5451 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5452 }
5453 else
5454 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5455
5456 *bufptr++ = (ipp_uchar_t)(n >> 8);
5457 *bufptr++ = (ipp_uchar_t)n;
5458 memcpy(bufptr, attr->name, (size_t)n);
5459 bufptr += n;
5460 }
5461 else
5462 {
5463 /*
5464 * Get the length of the attribute name, and make sure it won't
5465 * overflow the buffer...
5466 */
5467
5468 if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 12))
5469 {
5470 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
5471 _cupsBufferRelease((char *)buffer);
5472 return (IPP_STATE_ERROR);
5473 }
5474
5475 /*
5476 * Write the member name tag, name length, name string, value tag,
5477 * and empty name for the collection member attribute...
5478 */
5479
5480 DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
5481 IPP_TAG_MEMBERNAME));
5482 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
5483 attr->name));
5484 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5485 attr->value_tag, ippTagString(attr->value_tag)));
5486 DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
5487
5488 *bufptr++ = IPP_TAG_MEMBERNAME;
5489 *bufptr++ = 0;
5490 *bufptr++ = 0;
5491 *bufptr++ = (ipp_uchar_t)(n >> 8);
5492 *bufptr++ = (ipp_uchar_t)n;
5493 memcpy(bufptr, attr->name, (size_t)n);
5494 bufptr += n;
5495
5496 if (attr->value_tag > 0xff)
5497 {
5498 *bufptr++ = IPP_TAG_EXTENSION;
5499 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
5500 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
5501 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
5502 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5503 }
5504 else
5505 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5506
5507 *bufptr++ = 0;
5508 *bufptr++ = 0;
5509 }
5510
5511 /*
5512 * Now write the attribute value(s)...
5513 */
5514
5515 switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
5516 {
5517 case IPP_TAG_UNSUPPORTED_VALUE :
5518 case IPP_TAG_DEFAULT :
5519 case IPP_TAG_UNKNOWN :
5520 case IPP_TAG_NOVALUE :
5521 case IPP_TAG_NOTSETTABLE :
5522 case IPP_TAG_DELETEATTR :
5523 case IPP_TAG_ADMINDEFINE :
5524 *bufptr++ = 0;
5525 *bufptr++ = 0;
5526 break;
5527
5528 case IPP_TAG_INTEGER :
5529 case IPP_TAG_ENUM :
5530 for (i = 0, value = attr->values;
5531 i < attr->num_values;
5532 i ++, value ++)
5533 {
5534 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 9)
5535 {
5536 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5537 {
5538 DEBUG_puts("1ippWriteIO: Could not write IPP "
5539 "attribute...");
5540 _cupsBufferRelease((char *)buffer);
5541 return (IPP_STATE_ERROR);
5542 }
5543
5544 bufptr = buffer;
5545 }
5546
5547 if (i)
5548 {
5549 /*
5550 * Arrays and sets are done by sending additional
5551 * values with a zero-length name...
5552 */
5553
5554 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5555 *bufptr++ = 0;
5556 *bufptr++ = 0;
5557 }
5558
5559 /*
5560 * Integers and enumerations are both 4-byte signed
5561 * (twos-complement) values.
5562 *
5563 * Put the 2-byte length and 4-byte value into the buffer...
5564 */
5565
5566 *bufptr++ = 0;
5567 *bufptr++ = 4;
5568 *bufptr++ = (ipp_uchar_t)(value->integer >> 24);
5569 *bufptr++ = (ipp_uchar_t)(value->integer >> 16);
5570 *bufptr++ = (ipp_uchar_t)(value->integer >> 8);
5571 *bufptr++ = (ipp_uchar_t)value->integer;
5572 }
5573 break;
5574
5575 case IPP_TAG_BOOLEAN :
5576 for (i = 0, value = attr->values;
5577 i < attr->num_values;
5578 i ++, value ++)
5579 {
5580 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 6)
5581 {
5582 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5583 {
5584 DEBUG_puts("1ippWriteIO: Could not write IPP "
5585 "attribute...");
5586 _cupsBufferRelease((char *)buffer);
5587 return (IPP_STATE_ERROR);
5588 }
5589
5590 bufptr = buffer;
5591 }
5592
5593 if (i)
5594 {
5595 /*
5596 * Arrays and sets are done by sending additional
5597 * values with a zero-length name...
5598 */
5599
5600 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5601 *bufptr++ = 0;
5602 *bufptr++ = 0;
5603 }
5604
5605 /*
5606 * Boolean values are 1-byte; 0 = false, 1 = true.
5607 *
5608 * Put the 2-byte length and 1-byte value into the buffer...
5609 */
5610
5611 *bufptr++ = 0;
5612 *bufptr++ = 1;
5613 *bufptr++ = (ipp_uchar_t)value->boolean;
5614 }
5615 break;
5616
5617 case IPP_TAG_TEXT :
5618 case IPP_TAG_NAME :
5619 case IPP_TAG_KEYWORD :
5620 case IPP_TAG_URI :
5621 case IPP_TAG_URISCHEME :
5622 case IPP_TAG_CHARSET :
5623 case IPP_TAG_LANGUAGE :
5624 case IPP_TAG_MIMETYPE :
5625 for (i = 0, value = attr->values;
5626 i < attr->num_values;
5627 i ++, value ++)
5628 {
5629 if (i)
5630 {
5631 /*
5632 * Arrays and sets are done by sending additional
5633 * values with a zero-length name...
5634 */
5635
5636 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5637 attr->value_tag,
5638 ippTagString(attr->value_tag)));
5639 DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
5640
5641 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
5642 {
5643 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5644 {
5645 DEBUG_puts("1ippWriteIO: Could not write IPP "
5646 "attribute...");
5647 _cupsBufferRelease((char *)buffer);
5648 return (IPP_STATE_ERROR);
5649 }
5650
5651 bufptr = buffer;
5652 }
5653
5654 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5655 *bufptr++ = 0;
5656 *bufptr++ = 0;
5657 }
5658
5659 if (value->string.text != NULL)
5660 n = (int)strlen(value->string.text);
5661 else
5662 n = 0;
5663
5664 if (n > (IPP_BUF_SIZE - 2))
5665 {
5666 DEBUG_printf(("1ippWriteIO: String too long (%d)", n));
5667 _cupsBufferRelease((char *)buffer);
5668 return (IPP_STATE_ERROR);
5669 }
5670
5671 DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n,
5672 value->string.text));
5673
5674 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
5675 {
5676 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5677 {
5678 DEBUG_puts("1ippWriteIO: Could not write IPP "
5679 "attribute...");
5680 _cupsBufferRelease((char *)buffer);
5681 return (IPP_STATE_ERROR);
5682 }
5683
5684 bufptr = buffer;
5685 }
5686
5687 /*
5688 * All simple strings consist of the 2-byte length and
5689 * character data without the trailing nul normally found
5690 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
5691 * bytes since the 2-byte length is a signed (twos-complement)
5692 * value.
5693 *
5694 * Put the 2-byte length and string characters in the buffer.
5695 */
5696
5697 *bufptr++ = (ipp_uchar_t)(n >> 8);
5698 *bufptr++ = (ipp_uchar_t)n;
5699
5700 if (n > 0)
5701 {
5702 memcpy(bufptr, value->string.text, (size_t)n);
5703 bufptr += n;
5704 }
5705 }
5706 break;
5707
5708 case IPP_TAG_DATE :
5709 for (i = 0, value = attr->values;
5710 i < attr->num_values;
5711 i ++, value ++)
5712 {
5713 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 16)
5714 {
5715 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5716 {
5717 DEBUG_puts("1ippWriteIO: Could not write IPP "
5718 "attribute...");
5719 _cupsBufferRelease((char *)buffer);
5720 return (IPP_STATE_ERROR);
5721 }
5722
5723 bufptr = buffer;
5724 }
5725
5726 if (i)
5727 {
5728 /*
5729 * Arrays and sets are done by sending additional
5730 * values with a zero-length name...
5731 */
5732
5733 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5734 *bufptr++ = 0;
5735 *bufptr++ = 0;
5736 }
5737
5738 /*
5739 * Date values consist of a 2-byte length and an
5740 * 11-byte date/time structure defined by RFC 1903.
5741 *
5742 * Put the 2-byte length and 11-byte date/time
5743 * structure in the buffer.
5744 */
5745
5746 *bufptr++ = 0;
5747 *bufptr++ = 11;
5748 memcpy(bufptr, value->date, 11);
5749 bufptr += 11;
5750 }
5751 break;
5752
5753 case IPP_TAG_RESOLUTION :
5754 for (i = 0, value = attr->values;
5755 i < attr->num_values;
5756 i ++, value ++)
5757 {
5758 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 14)
5759 {
5760 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5761 {
5762 DEBUG_puts("1ippWriteIO: Could not write IPP "
5763 "attribute...");
5764 _cupsBufferRelease((char *)buffer);
5765 return (IPP_STATE_ERROR);
5766 }
5767
5768 bufptr = buffer;
5769 }
5770
5771 if (i)
5772 {
5773 /*
5774 * Arrays and sets are done by sending additional
5775 * values with a zero-length name...
5776 */
5777
5778 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5779 *bufptr++ = 0;
5780 *bufptr++ = 0;
5781 }
5782
5783 /*
5784 * Resolution values consist of a 2-byte length,
5785 * 4-byte horizontal resolution value, 4-byte vertical
5786 * resolution value, and a 1-byte units value.
5787 *
5788 * Put the 2-byte length and resolution value data
5789 * into the buffer.
5790 */
5791
5792 *bufptr++ = 0;
5793 *bufptr++ = 9;
5794 *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 24);
5795 *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 16);
5796 *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 8);
5797 *bufptr++ = (ipp_uchar_t)value->resolution.xres;
5798 *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 24);
5799 *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 16);
5800 *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 8);
5801 *bufptr++ = (ipp_uchar_t)value->resolution.yres;
5802 *bufptr++ = (ipp_uchar_t)value->resolution.units;
5803 }
5804 break;
5805
5806 case IPP_TAG_RANGE :
5807 for (i = 0, value = attr->values;
5808 i < attr->num_values;
5809 i ++, value ++)
5810 {
5811 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 13)
5812 {
5813 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5814 {
5815 DEBUG_puts("1ippWriteIO: Could not write IPP "
5816 "attribute...");
5817 _cupsBufferRelease((char *)buffer);
5818 return (IPP_STATE_ERROR);
5819 }
5820
5821 bufptr = buffer;
5822 }
5823
5824 if (i)
5825 {
5826 /*
5827 * Arrays and sets are done by sending additional
5828 * values with a zero-length name...
5829 */
5830
5831 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5832 *bufptr++ = 0;
5833 *bufptr++ = 0;
5834 }
5835
5836 /*
5837 * Range values consist of a 2-byte length,
5838 * 4-byte lower value, and 4-byte upper value.
5839 *
5840 * Put the 2-byte length and range value data
5841 * into the buffer.
5842 */
5843
5844 *bufptr++ = 0;
5845 *bufptr++ = 8;
5846 *bufptr++ = (ipp_uchar_t)(value->range.lower >> 24);
5847 *bufptr++ = (ipp_uchar_t)(value->range.lower >> 16);
5848 *bufptr++ = (ipp_uchar_t)(value->range.lower >> 8);
5849 *bufptr++ = (ipp_uchar_t)value->range.lower;
5850 *bufptr++ = (ipp_uchar_t)(value->range.upper >> 24);
5851 *bufptr++ = (ipp_uchar_t)(value->range.upper >> 16);
5852 *bufptr++ = (ipp_uchar_t)(value->range.upper >> 8);
5853 *bufptr++ = (ipp_uchar_t)value->range.upper;
5854 }
5855 break;
5856
5857 case IPP_TAG_TEXTLANG :
5858 case IPP_TAG_NAMELANG :
5859 for (i = 0, value = attr->values;
5860 i < attr->num_values;
5861 i ++, value ++)
5862 {
5863 if (i)
5864 {
5865 /*
5866 * Arrays and sets are done by sending additional
5867 * values with a zero-length name...
5868 */
5869
5870 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
5871 {
5872 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5873 {
5874 DEBUG_puts("1ippWriteIO: Could not write IPP "
5875 "attribute...");
5876 _cupsBufferRelease((char *)buffer);
5877 return (IPP_STATE_ERROR);
5878 }
5879
5880 bufptr = buffer;
5881 }
5882
5883 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5884 *bufptr++ = 0;
5885 *bufptr++ = 0;
5886 }
5887
5888 /*
5889 * textWithLanguage and nameWithLanguage values consist
5890 * of a 2-byte length for both strings and their
5891 * individual lengths, a 2-byte length for the
5892 * character string, the character string without the
5893 * trailing nul, a 2-byte length for the character
5894 * set string, and the character set string without
5895 * the trailing nul.
5896 */
5897
5898 n = 4;
5899
5900 if (value->string.language != NULL)
5901 n += (int)strlen(value->string.language);
5902
5903 if (value->string.text != NULL)
5904 n += (int)strlen(value->string.text);
5905
5906 if (n > (IPP_BUF_SIZE - 2))
5907 {
5908 DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
5909 "too long (%d)", n));
5910 _cupsBufferRelease((char *)buffer);
5911 return (IPP_STATE_ERROR);
5912 }
5913
5914 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
5915 {
5916 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5917 {
5918 DEBUG_puts("1ippWriteIO: Could not write IPP "
5919 "attribute...");
5920 _cupsBufferRelease((char *)buffer);
5921 return (IPP_STATE_ERROR);
5922 }
5923
5924 bufptr = buffer;
5925 }
5926
5927 /* Length of entire value */
5928 *bufptr++ = (ipp_uchar_t)(n >> 8);
5929 *bufptr++ = (ipp_uchar_t)n;
5930
5931 /* Length of language */
5932 if (value->string.language != NULL)
5933 n = (int)strlen(value->string.language);
5934 else
5935 n = 0;
5936
5937 *bufptr++ = (ipp_uchar_t)(n >> 8);
5938 *bufptr++ = (ipp_uchar_t)n;
5939
5940 /* Language */
5941 if (n > 0)
5942 {
5943 memcpy(bufptr, value->string.language, (size_t)n);
5944 bufptr += n;
5945 }
5946
5947 /* Length of text */
5948 if (value->string.text != NULL)
5949 n = (int)strlen(value->string.text);
5950 else
5951 n = 0;
5952
5953 *bufptr++ = (ipp_uchar_t)(n >> 8);
5954 *bufptr++ = (ipp_uchar_t)n;
5955
5956 /* Text */
5957 if (n > 0)
5958 {
5959 memcpy(bufptr, value->string.text, (size_t)n);
5960 bufptr += n;
5961 }
5962 }
5963 break;
5964
5965 case IPP_TAG_BEGIN_COLLECTION :
5966 for (i = 0, value = attr->values;
5967 i < attr->num_values;
5968 i ++, value ++)
5969 {
5970 /*
5971 * Collections are written with the begin-collection
5972 * tag first with a value of 0 length, followed by the
5973 * attributes in the collection, then the end-collection
5974 * value...
5975 */
5976
5977 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 5)
5978 {
5979 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5980 {
5981 DEBUG_puts("1ippWriteIO: Could not write IPP "
5982 "attribute...");
5983 _cupsBufferRelease((char *)buffer);
5984 return (IPP_STATE_ERROR);
5985 }
5986
5987 bufptr = buffer;
5988 }
5989
5990 if (i)
5991 {
5992 /*
5993 * Arrays and sets are done by sending additional
5994 * values with a zero-length name...
5995 */
5996
5997 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5998 *bufptr++ = 0;
5999 *bufptr++ = 0;
6000 }
6001
6002 /*
6003 * Write a data length of 0 and flush the buffer...
6004 */
6005
6006 *bufptr++ = 0;
6007 *bufptr++ = 0;
6008
6009 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6010 {
6011 DEBUG_puts("1ippWriteIO: Could not write IPP "
6012 "attribute...");
6013 _cupsBufferRelease((char *)buffer);
6014 return (IPP_STATE_ERROR);
6015 }
6016
6017 bufptr = buffer;
6018
6019 /*
6020 * Then write the collection attribute...
6021 */
6022
6023 value->collection->state = IPP_STATE_IDLE;
6024
6025 if (ippWriteIO(dst, cb, 1, ipp,
6026 value->collection) == IPP_STATE_ERROR)
6027 {
6028 DEBUG_puts("1ippWriteIO: Unable to write collection value");
6029 _cupsBufferRelease((char *)buffer);
6030 return (IPP_STATE_ERROR);
6031 }
6032 }
6033 break;
6034
6035 default :
6036 for (i = 0, value = attr->values;
6037 i < attr->num_values;
6038 i ++, value ++)
6039 {
6040 if (i)
6041 {
6042 /*
6043 * Arrays and sets are done by sending additional
6044 * values with a zero-length name...
6045 */
6046
6047 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
6048 {
6049 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6050 {
6051 DEBUG_puts("1ippWriteIO: Could not write IPP "
6052 "attribute...");
6053 _cupsBufferRelease((char *)buffer);
6054 return (IPP_STATE_ERROR);
6055 }
6056
6057 bufptr = buffer;
6058 }
6059
6060 *bufptr++ = (ipp_uchar_t)attr->value_tag;
6061 *bufptr++ = 0;
6062 *bufptr++ = 0;
6063 }
6064
6065 /*
6066 * An unknown value might some new value that a
6067 * vendor has come up with. It consists of a
6068 * 2-byte length and the bytes in the unknown
6069 * value buffer.
6070 */
6071
6072 n = value->unknown.length;
6073
6074 if (n > (IPP_BUF_SIZE - 2))
6075 {
6076 DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
6077 n));
6078 _cupsBufferRelease((char *)buffer);
6079 return (IPP_STATE_ERROR);
6080 }
6081
6082 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
6083 {
6084 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6085 {
6086 DEBUG_puts("1ippWriteIO: Could not write IPP "
6087 "attribute...");
6088 _cupsBufferRelease((char *)buffer);
6089 return (IPP_STATE_ERROR);
6090 }
6091
6092 bufptr = buffer;
6093 }
6094
6095 /* Length of unknown value */
6096 *bufptr++ = (ipp_uchar_t)(n >> 8);
6097 *bufptr++ = (ipp_uchar_t)n;
6098
6099 /* Value */
6100 if (n > 0)
6101 {
6102 memcpy(bufptr, value->unknown.data, (size_t)n);
6103 bufptr += n;
6104 }
6105 }
6106 break;
6107 }
6108
6109 /*
6110 * Write the data out...
6111 */
6112
6113 if (bufptr > buffer)
6114 {
6115 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6116 {
6117 DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
6118 _cupsBufferRelease((char *)buffer);
6119 return (IPP_STATE_ERROR);
6120 }
6121
6122 DEBUG_printf(("2ippWriteIO: wrote %d bytes",
6123 (int)(bufptr - buffer)));
6124 }
6125
6126 /*
6127 * If blocking is disabled and we aren't at the end of the attribute
6128 * list, stop here...
6129 */
6130
6131 if (!blocking && ipp->current)
6132 break;
6133 }
6134
6135 if (ipp->current == NULL)
6136 {
6137 /*
6138 * Done with all of the attributes; add the end-of-attributes
6139 * tag or end-collection attribute...
6140 */
6141
6142 if (parent == NULL)
6143 {
6144 buffer[0] = IPP_TAG_END;
6145 n = 1;
6146 }
6147 else
6148 {
6149 buffer[0] = IPP_TAG_END_COLLECTION;
6150 buffer[1] = 0; /* empty name */
6151 buffer[2] = 0;
6152 buffer[3] = 0; /* empty value */
6153 buffer[4] = 0;
6154 n = 5;
6155 }
6156
6157 if ((*cb)(dst, buffer, (size_t)n) < 0)
6158 {
6159 DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
6160 _cupsBufferRelease((char *)buffer);
6161 return (IPP_STATE_ERROR);
6162 }
6163
6164 ipp->state = IPP_STATE_DATA;
6165 }
6166 break;
6167
6168 case IPP_STATE_DATA :
6169 break;
6170
6171 default :
6172 break; /* anti-compiler-warning-code */
6173 }
6174
6175 _cupsBufferRelease((char *)buffer);
6176
6177 return (ipp->state);
6178 }
6179
6180
6181 /*
6182 * 'ipp_add_attr()' - Add a new attribute to the message.
6183 */
6184
6185 static ipp_attribute_t * /* O - New attribute */
6186 ipp_add_attr(ipp_t *ipp, /* I - IPP message */
6187 const char *name, /* I - Attribute name or NULL */
6188 ipp_tag_t group_tag, /* I - Group tag or IPP_TAG_ZERO */
6189 ipp_tag_t value_tag, /* I - Value tag or IPP_TAG_ZERO */
6190 int num_values) /* I - Number of values */
6191 {
6192 int alloc_values; /* Number of values to allocate */
6193 ipp_attribute_t *attr; /* New attribute */
6194
6195
6196 DEBUG_printf(("4ipp_add_attr(ipp=%p, name=\"%s\", group_tag=0x%x, value_tag=0x%x, num_values=%d)", (void *)ipp, name, group_tag, value_tag, num_values));
6197
6198 /*
6199 * Range check input...
6200 */
6201
6202 if (!ipp || num_values < 0)
6203 return (NULL);
6204
6205 /*
6206 * Allocate memory, rounding the allocation up as needed...
6207 */
6208
6209 if (num_values <= 1)
6210 alloc_values = 1;
6211 else
6212 alloc_values = (num_values + IPP_MAX_VALUES - 1) & ~(IPP_MAX_VALUES - 1);
6213
6214 attr = calloc(sizeof(ipp_attribute_t) +
6215 (size_t)(alloc_values - 1) * sizeof(_ipp_value_t), 1);
6216
6217 if (attr)
6218 {
6219 /*
6220 * Initialize attribute...
6221 */
6222
6223 DEBUG_printf(("4debug_alloc: %p %s %s%s (%d values)", (void *)attr, name, num_values > 1 ? "1setOf " : "", ippTagString(value_tag), num_values));
6224
6225 if (name)
6226 attr->name = _cupsStrAlloc(name);
6227
6228 attr->group_tag = group_tag;
6229 attr->value_tag = value_tag;
6230 attr->num_values = num_values;
6231
6232 /*
6233 * Add it to the end of the linked list...
6234 */
6235
6236 if (ipp->last)
6237 ipp->last->next = attr;
6238 else
6239 ipp->attrs = attr;
6240
6241 ipp->prev = ipp->last;
6242 ipp->last = ipp->current = attr;
6243 }
6244
6245 DEBUG_printf(("5ipp_add_attr: Returning %p", (void *)attr));
6246
6247 return (attr);
6248 }
6249
6250
6251 /*
6252 * 'ipp_free_values()' - Free attribute values.
6253 */
6254
6255 static void
6256 ipp_free_values(ipp_attribute_t *attr, /* I - Attribute to free values from */
6257 int element,/* I - First value to free */
6258 int count) /* I - Number of values to free */
6259 {
6260 int i; /* Looping var */
6261 _ipp_value_t *value; /* Current value */
6262
6263
6264 DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", (void *)attr, element, count));
6265
6266 if (!(attr->value_tag & IPP_TAG_CUPS_CONST))
6267 {
6268 /*
6269 * Free values as needed...
6270 */
6271
6272 switch (attr->value_tag)
6273 {
6274 case IPP_TAG_TEXTLANG :
6275 case IPP_TAG_NAMELANG :
6276 if (element == 0 && count == attr->num_values &&
6277 attr->values[0].string.language)
6278 {
6279 _cupsStrFree(attr->values[0].string.language);
6280 attr->values[0].string.language = NULL;
6281 }
6282 /* Fall through to other string values */
6283
6284 case IPP_TAG_TEXT :
6285 case IPP_TAG_NAME :
6286 case IPP_TAG_RESERVED_STRING :
6287 case IPP_TAG_KEYWORD :
6288 case IPP_TAG_URI :
6289 case IPP_TAG_URISCHEME :
6290 case IPP_TAG_CHARSET :
6291 case IPP_TAG_LANGUAGE :
6292 case IPP_TAG_MIMETYPE :
6293 for (i = count, value = attr->values + element;
6294 i > 0;
6295 i --, value ++)
6296 {
6297 _cupsStrFree(value->string.text);
6298 value->string.text = NULL;
6299 }
6300 break;
6301
6302 case IPP_TAG_UNSUPPORTED_VALUE :
6303 case IPP_TAG_DEFAULT :
6304 case IPP_TAG_UNKNOWN :
6305 case IPP_TAG_NOVALUE :
6306 case IPP_TAG_NOTSETTABLE :
6307 case IPP_TAG_DELETEATTR :
6308 case IPP_TAG_ADMINDEFINE :
6309 case IPP_TAG_INTEGER :
6310 case IPP_TAG_ENUM :
6311 case IPP_TAG_BOOLEAN :
6312 case IPP_TAG_DATE :
6313 case IPP_TAG_RESOLUTION :
6314 case IPP_TAG_RANGE :
6315 break;
6316
6317 case IPP_TAG_BEGIN_COLLECTION :
6318 for (i = count, value = attr->values + element;
6319 i > 0;
6320 i --, value ++)
6321 {
6322 ippDelete(value->collection);
6323 value->collection = NULL;
6324 }
6325 break;
6326
6327 case IPP_TAG_STRING :
6328 default :
6329 for (i = count, value = attr->values + element;
6330 i > 0;
6331 i --, value ++)
6332 {
6333 if (value->unknown.data)
6334 {
6335 free(value->unknown.data);
6336 value->unknown.data = NULL;
6337 }
6338 }
6339 break;
6340 }
6341 }
6342
6343 /*
6344 * If we are not freeing values from the end, move the remaining values up...
6345 */
6346
6347 if ((element + count) < attr->num_values)
6348 memmove(attr->values + element, attr->values + element + count,
6349 (size_t)(attr->num_values - count - element) * sizeof(_ipp_value_t));
6350
6351 attr->num_values -= count;
6352 }
6353
6354
6355 /*
6356 * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
6357 *
6358 * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
6359 * to "ll-cc", "ll-region", and "charset-number", respectively.
6360 */
6361
6362 static char * /* O - Language code string */
6363 ipp_get_code(const char *value, /* I - Locale/charset string */
6364 char *buffer, /* I - String buffer */
6365 size_t bufsize) /* I - Size of string buffer */
6366 {
6367 char *bufptr, /* Pointer into buffer */
6368 *bufend; /* End of buffer */
6369
6370
6371 /*
6372 * Convert values to lowercase and change _ to - as needed...
6373 */
6374
6375 for (bufptr = buffer, bufend = buffer + bufsize - 1;
6376 *value && bufptr < bufend;
6377 value ++)
6378 if (*value == '_')
6379 *bufptr++ = '-';
6380 else
6381 *bufptr++ = (char)_cups_tolower(*value);
6382
6383 *bufptr = '\0';
6384
6385 /*
6386 * Return the converted string...
6387 */
6388
6389 return (buffer);
6390 }
6391
6392
6393 /*
6394 * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
6395 *
6396 * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
6397 * "ll-region", respectively. It also converts the "C" (POSIX) locale to "en".
6398 */
6399
6400 static char * /* O - Language code string */
6401 ipp_lang_code(const char *locale, /* I - Locale string */
6402 char *buffer, /* I - String buffer */
6403 size_t bufsize) /* I - Size of string buffer */
6404 {
6405 /*
6406 * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
6407 */
6408
6409 if (!_cups_strcasecmp(locale, "c"))
6410 {
6411 strlcpy(buffer, "en", bufsize);
6412 return (buffer);
6413 }
6414 else
6415 return (ipp_get_code(locale, buffer, bufsize));
6416 }
6417
6418
6419 /*
6420 * 'ipp_length()' - Compute the length of an IPP message or collection value.
6421 */
6422
6423 static size_t /* O - Size of IPP message */
6424 ipp_length(ipp_t *ipp, /* I - IPP message or collection */
6425 int collection) /* I - 1 if a collection, 0 otherwise */
6426 {
6427 int i; /* Looping var */
6428 size_t bytes; /* Number of bytes */
6429 ipp_attribute_t *attr; /* Current attribute */
6430 ipp_tag_t group; /* Current group */
6431 _ipp_value_t *value; /* Current value */
6432
6433
6434 DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", (void *)ipp, collection));
6435
6436 if (!ipp)
6437 {
6438 DEBUG_puts("4ipp_length: Returning 0 bytes");
6439 return (0);
6440 }
6441
6442 /*
6443 * Start with 8 bytes for the IPP message header...
6444 */
6445
6446 bytes = collection ? 0 : 8;
6447
6448 /*
6449 * Then add the lengths of each attribute...
6450 */
6451
6452 group = IPP_TAG_ZERO;
6453
6454 for (attr = ipp->attrs; attr != NULL; attr = attr->next)
6455 {
6456 if (attr->group_tag != group && !collection)
6457 {
6458 group = attr->group_tag;
6459 if (group == IPP_TAG_ZERO)
6460 continue;
6461
6462 bytes ++; /* Group tag */
6463 }
6464
6465 if (!attr->name)
6466 continue;
6467
6468 DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
6469 "bytes=" CUPS_LLFMT, attr->name, attr->num_values, CUPS_LLCAST bytes));
6470
6471 if ((attr->value_tag & ~IPP_TAG_CUPS_CONST) < IPP_TAG_EXTENSION)
6472 bytes += (size_t)attr->num_values;/* Value tag for each value */
6473 else
6474 bytes += (size_t)(5 * attr->num_values);
6475 /* Value tag for each value */
6476 bytes += (size_t)(2 * attr->num_values);
6477 /* Name lengths */
6478 bytes += strlen(attr->name); /* Name */
6479 bytes += (size_t)(2 * attr->num_values);
6480 /* Value lengths */
6481
6482 if (collection)
6483 bytes += 5; /* Add membername overhead */
6484
6485 switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
6486 {
6487 case IPP_TAG_UNSUPPORTED_VALUE :
6488 case IPP_TAG_DEFAULT :
6489 case IPP_TAG_UNKNOWN :
6490 case IPP_TAG_NOVALUE :
6491 case IPP_TAG_NOTSETTABLE :
6492 case IPP_TAG_DELETEATTR :
6493 case IPP_TAG_ADMINDEFINE :
6494 break;
6495
6496 case IPP_TAG_INTEGER :
6497 case IPP_TAG_ENUM :
6498 bytes += (size_t)(4 * attr->num_values);
6499 break;
6500
6501 case IPP_TAG_BOOLEAN :
6502 bytes += (size_t)attr->num_values;
6503 break;
6504
6505 case IPP_TAG_TEXT :
6506 case IPP_TAG_NAME :
6507 case IPP_TAG_KEYWORD :
6508 case IPP_TAG_URI :
6509 case IPP_TAG_URISCHEME :
6510 case IPP_TAG_CHARSET :
6511 case IPP_TAG_LANGUAGE :
6512 case IPP_TAG_MIMETYPE :
6513 for (i = 0, value = attr->values;
6514 i < attr->num_values;
6515 i ++, value ++)
6516 if (value->string.text)
6517 bytes += strlen(value->string.text);
6518 break;
6519
6520 case IPP_TAG_DATE :
6521 bytes += (size_t)(11 * attr->num_values);
6522 break;
6523
6524 case IPP_TAG_RESOLUTION :
6525 bytes += (size_t)(9 * attr->num_values);
6526 break;
6527
6528 case IPP_TAG_RANGE :
6529 bytes += (size_t)(8 * attr->num_values);
6530 break;
6531
6532 case IPP_TAG_TEXTLANG :
6533 case IPP_TAG_NAMELANG :
6534 bytes += (size_t)(4 * attr->num_values);
6535 /* Charset + text length */
6536
6537 for (i = 0, value = attr->values;
6538 i < attr->num_values;
6539 i ++, value ++)
6540 {
6541 if (value->string.language)
6542 bytes += strlen(value->string.language);
6543
6544 if (value->string.text)
6545 bytes += strlen(value->string.text);
6546 }
6547 break;
6548
6549 case IPP_TAG_BEGIN_COLLECTION :
6550 for (i = 0, value = attr->values;
6551 i < attr->num_values;
6552 i ++, value ++)
6553 bytes += ipp_length(value->collection, 1);
6554 break;
6555
6556 default :
6557 for (i = 0, value = attr->values;
6558 i < attr->num_values;
6559 i ++, value ++)
6560 bytes += (size_t)value->unknown.length;
6561 break;
6562 }
6563 }
6564
6565 /*
6566 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
6567 * for the "end of collection" tag and return...
6568 */
6569
6570 if (collection)
6571 bytes += 5;
6572 else
6573 bytes ++;
6574
6575 DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST bytes));
6576
6577 return (bytes);
6578 }
6579
6580
6581 /*
6582 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
6583 */
6584
6585 static ssize_t /* O - Number of bytes read */
6586 ipp_read_http(http_t *http, /* I - Client connection */
6587 ipp_uchar_t *buffer, /* O - Buffer for data */
6588 size_t length) /* I - Total length */
6589 {
6590 ssize_t tbytes, /* Total bytes read */
6591 bytes; /* Bytes read this pass */
6592
6593
6594 DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)", (void *)http, (void *)buffer, (int)length));
6595
6596 /*
6597 * Loop until all bytes are read...
6598 */
6599
6600 for (tbytes = 0, bytes = 0;
6601 tbytes < (int)length;
6602 tbytes += bytes, buffer += bytes)
6603 {
6604 DEBUG_printf(("9ipp_read_http: tbytes=" CUPS_LLFMT ", http->state=%d", CUPS_LLCAST tbytes, http->state));
6605
6606 if (http->state == HTTP_STATE_WAITING)
6607 break;
6608
6609 if (http->used == 0 && !http->blocking)
6610 {
6611 /*
6612 * Wait up to 10 seconds for more data on non-blocking sockets...
6613 */
6614
6615 if (!httpWait(http, 10000))
6616 {
6617 /*
6618 * Signal no data...
6619 */
6620
6621 bytes = -1;
6622 break;
6623 }
6624 }
6625 else if (http->used == 0 && http->timeout_value > 0)
6626 {
6627 /*
6628 * Wait up to timeout seconds for more data on blocking sockets...
6629 */
6630
6631 if (!httpWait(http, (int)(1000 * http->timeout_value)))
6632 {
6633 /*
6634 * Signal no data...
6635 */
6636
6637 bytes = -1;
6638 break;
6639 }
6640 }
6641
6642 if ((bytes = httpRead2(http, (char *)buffer, length - (size_t)tbytes)) < 0)
6643 {
6644 #ifdef _WIN32
6645 break;
6646 #else
6647 if (errno != EAGAIN && errno != EINTR)
6648 break;
6649
6650 bytes = 0;
6651 #endif /* _WIN32 */
6652 }
6653 else if (bytes == 0)
6654 break;
6655 }
6656
6657 /*
6658 * Return the number of bytes read...
6659 */
6660
6661 if (tbytes == 0 && bytes < 0)
6662 tbytes = -1;
6663
6664 DEBUG_printf(("8ipp_read_http: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST tbytes));
6665
6666 return (tbytes);
6667 }
6668
6669
6670 /*
6671 * 'ipp_read_file()' - Read IPP data from a file.
6672 */
6673
6674 static ssize_t /* O - Number of bytes read */
6675 ipp_read_file(int *fd, /* I - File descriptor */
6676 ipp_uchar_t *buffer, /* O - Read buffer */
6677 size_t length) /* I - Number of bytes to read */
6678 {
6679 #ifdef _WIN32
6680 return ((ssize_t)read(*fd, buffer, (unsigned)length));
6681 #else
6682 return (read(*fd, buffer, length));
6683 #endif /* _WIN32 */
6684 }
6685
6686
6687 /*
6688 * 'ipp_set_error()' - Set a formatted, localized error string.
6689 */
6690
6691 static void
6692 ipp_set_error(ipp_status_t status, /* I - Status code */
6693 const char *format, /* I - Printf-style error string */
6694 ...) /* I - Additional arguments as needed */
6695 {
6696 va_list ap; /* Pointer to additional args */
6697 char buffer[2048]; /* Message buffer */
6698 cups_lang_t *lang = cupsLangDefault();
6699 /* Current language */
6700
6701
6702 va_start(ap, format);
6703 vsnprintf(buffer, sizeof(buffer), _cupsLangString(lang, format), ap);
6704 va_end(ap);
6705
6706 _cupsSetError(status, buffer, 0);
6707 }
6708
6709
6710 /*
6711 * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
6712 * needed.
6713 */
6714
6715 static _ipp_value_t * /* O - IPP value element or NULL on error */
6716 ipp_set_value(ipp_t *ipp, /* IO - IPP message */
6717 ipp_attribute_t **attr, /* IO - IPP attribute */
6718 int element) /* I - Value number (0-based) */
6719 {
6720 ipp_attribute_t *temp, /* New attribute pointer */
6721 *current, /* Current attribute in list */
6722 *prev; /* Previous attribute in list */
6723 int alloc_values; /* Allocated values */
6724
6725
6726 /*
6727 * If we are setting an existing value element, return it...
6728 */
6729
6730 temp = *attr;
6731
6732 if (temp->num_values <= 1)
6733 alloc_values = 1;
6734 else
6735 alloc_values = (temp->num_values + IPP_MAX_VALUES - 1) &
6736 ~(IPP_MAX_VALUES - 1);
6737
6738 if (element < alloc_values)
6739 {
6740 if (element >= temp->num_values)
6741 temp->num_values = element + 1;
6742
6743 return (temp->values + element);
6744 }
6745
6746 /*
6747 * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
6748 * values when num_values > 1.
6749 */
6750
6751 if (alloc_values < IPP_MAX_VALUES)
6752 alloc_values = IPP_MAX_VALUES;
6753 else
6754 alloc_values += IPP_MAX_VALUES;
6755
6756 DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
6757 alloc_values));
6758
6759 /*
6760 * Reallocate memory...
6761 */
6762
6763 if ((temp = realloc(temp, sizeof(ipp_attribute_t) + (size_t)(alloc_values - 1) * sizeof(_ipp_value_t))) == NULL)
6764 {
6765 _cupsSetHTTPError(HTTP_STATUS_ERROR);
6766 DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
6767 return (NULL);
6768 }
6769
6770 /*
6771 * Zero the new memory...
6772 */
6773
6774 memset(temp->values + temp->num_values, 0, (size_t)(alloc_values - temp->num_values) * sizeof(_ipp_value_t));
6775
6776 if (temp != *attr)
6777 {
6778 /*
6779 * Reset pointers in the list...
6780 */
6781
6782 #ifndef __clang_analyzer__
6783 DEBUG_printf(("4debug_free: %p %s", (void *)*attr, temp->name));
6784 #endif /* !__clang_analyzer__ */
6785 DEBUG_printf(("4debug_alloc: %p %s %s%s (%d)", (void *)temp, temp->name, temp->num_values > 1 ? "1setOf " : "", ippTagString(temp->value_tag), temp->num_values));
6786
6787 if (ipp->current == *attr && ipp->prev)
6788 {
6789 /*
6790 * Use current "previous" pointer...
6791 */
6792
6793 prev = ipp->prev;
6794 }
6795 else
6796 {
6797 /*
6798 * Find this attribute in the linked list...
6799 */
6800
6801 for (prev = NULL, current = ipp->attrs;
6802 current && current != *attr;
6803 prev = current, current = current->next);
6804
6805 if (!current)
6806 {
6807 /*
6808 * This is a serious error!
6809 */
6810
6811 *attr = temp;
6812 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
6813 _("IPP attribute is not a member of the message."), 1);
6814 DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
6815 return (NULL);
6816 }
6817 }
6818
6819 if (prev)
6820 prev->next = temp;
6821 else
6822 ipp->attrs = temp;
6823
6824 ipp->current = temp;
6825 ipp->prev = prev;
6826
6827 if (ipp->last == *attr)
6828 ipp->last = temp;
6829
6830 *attr = temp;
6831 }
6832
6833 /*
6834 * Return the value element...
6835 */
6836
6837 if (element >= temp->num_values)
6838 temp->num_values = element + 1;
6839
6840 return (temp->values + element);
6841 }
6842
6843
6844 /*
6845 * 'ipp_write_file()' - Write IPP data to a file.
6846 */
6847
6848 static ssize_t /* O - Number of bytes written */
6849 ipp_write_file(int *fd, /* I - File descriptor */
6850 ipp_uchar_t *buffer, /* I - Data to write */
6851 size_t length) /* I - Number of bytes to write */
6852 {
6853 #ifdef _WIN32
6854 return ((ssize_t)write(*fd, buffer, (unsigned)length));
6855 #else
6856 return (write(*fd, buffer, length));
6857 #endif /* _WIN32 */
6858 }