]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/ipp.c
Merge pull request #5350 from benlees/master
[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_attribute_t *dstattr; /* Destination attribute */
1478 _ipp_value_t *srcval, /* Source value */
1479 *dstval; /* Destination value */
1480
1481
1482 DEBUG_printf(("ippCopyAttribute(dst=%p, srcattr=%p, quickcopy=%d)", (void *)dst, (void *)srcattr, quickcopy));
1483
1484 /*
1485 * Range check input...
1486 */
1487
1488 if (!dst || !srcattr)
1489 return (NULL);
1490
1491 /*
1492 * Copy it...
1493 */
1494
1495 quickcopy = quickcopy ? IPP_TAG_CUPS_CONST : 0;
1496
1497 switch (srcattr->value_tag & ~IPP_TAG_CUPS_CONST)
1498 {
1499 case IPP_TAG_ZERO :
1500 dstattr = ippAddSeparator(dst);
1501 break;
1502
1503 case IPP_TAG_UNSUPPORTED_VALUE :
1504 case IPP_TAG_DEFAULT :
1505 case IPP_TAG_UNKNOWN :
1506 case IPP_TAG_NOVALUE :
1507 case IPP_TAG_NOTSETTABLE :
1508 case IPP_TAG_DELETEATTR :
1509 case IPP_TAG_ADMINDEFINE :
1510 dstattr = ippAddOutOfBand(dst, srcattr->group_tag, srcattr->value_tag & ~IPP_TAG_CUPS_CONST, srcattr->name);
1511 break;
1512
1513 case IPP_TAG_INTEGER :
1514 case IPP_TAG_ENUM :
1515 dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag,
1516 srcattr->name, srcattr->num_values, NULL);
1517 if (!dstattr)
1518 break;
1519
1520 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1521 i > 0;
1522 i --, srcval ++, dstval ++)
1523 dstval->integer = srcval->integer;
1524 break;
1525
1526 case IPP_TAG_BOOLEAN :
1527 dstattr = ippAddBooleans(dst, srcattr->group_tag, srcattr->name,
1528 srcattr->num_values, NULL);
1529 if (!dstattr)
1530 break;
1531
1532 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1533 i > 0;
1534 i --, srcval ++, dstval ++)
1535 dstval->boolean = srcval->boolean;
1536 break;
1537
1538 case IPP_TAG_TEXT :
1539 case IPP_TAG_NAME :
1540 case IPP_TAG_KEYWORD :
1541 case IPP_TAG_URI :
1542 case IPP_TAG_URISCHEME :
1543 case IPP_TAG_CHARSET :
1544 case IPP_TAG_LANGUAGE :
1545 case IPP_TAG_MIMETYPE :
1546 dstattr = ippAddStrings(dst, srcattr->group_tag,
1547 (ipp_tag_t)(srcattr->value_tag | quickcopy),
1548 srcattr->name, srcattr->num_values, NULL, NULL);
1549 if (!dstattr)
1550 break;
1551
1552 if (quickcopy)
1553 {
1554 for (i = srcattr->num_values, srcval = srcattr->values,
1555 dstval = dstattr->values;
1556 i > 0;
1557 i --, srcval ++, dstval ++)
1558 dstval->string.text = srcval->string.text;
1559 }
1560 else if (srcattr->value_tag & IPP_TAG_CUPS_CONST)
1561 {
1562 for (i = srcattr->num_values, srcval = srcattr->values,
1563 dstval = dstattr->values;
1564 i > 0;
1565 i --, srcval ++, dstval ++)
1566 dstval->string.text = _cupsStrAlloc(srcval->string.text);
1567 }
1568 else
1569 {
1570 for (i = srcattr->num_values, srcval = srcattr->values,
1571 dstval = dstattr->values;
1572 i > 0;
1573 i --, srcval ++, dstval ++)
1574 dstval->string.text = _cupsStrRetain(srcval->string.text);
1575 }
1576 break;
1577
1578 case IPP_TAG_DATE :
1579 if (srcattr->num_values != 1)
1580 return (NULL);
1581
1582 dstattr = ippAddDate(dst, srcattr->group_tag, srcattr->name,
1583 srcattr->values[0].date);
1584 break;
1585
1586 case IPP_TAG_RESOLUTION :
1587 dstattr = ippAddResolutions(dst, srcattr->group_tag, srcattr->name,
1588 srcattr->num_values, IPP_RES_PER_INCH,
1589 NULL, NULL);
1590 if (!dstattr)
1591 break;
1592
1593 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1594 i > 0;
1595 i --, srcval ++, dstval ++)
1596 {
1597 dstval->resolution.xres = srcval->resolution.xres;
1598 dstval->resolution.yres = srcval->resolution.yres;
1599 dstval->resolution.units = srcval->resolution.units;
1600 }
1601 break;
1602
1603 case IPP_TAG_RANGE :
1604 dstattr = ippAddRanges(dst, srcattr->group_tag, srcattr->name,
1605 srcattr->num_values, NULL, NULL);
1606 if (!dstattr)
1607 break;
1608
1609 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1610 i > 0;
1611 i --, srcval ++, dstval ++)
1612 {
1613 dstval->range.lower = srcval->range.lower;
1614 dstval->range.upper = srcval->range.upper;
1615 }
1616 break;
1617
1618 case IPP_TAG_TEXTLANG :
1619 case IPP_TAG_NAMELANG :
1620 dstattr = ippAddStrings(dst, srcattr->group_tag,
1621 (ipp_tag_t)(srcattr->value_tag | quickcopy),
1622 srcattr->name, srcattr->num_values, NULL, NULL);
1623 if (!dstattr)
1624 break;
1625
1626 if (quickcopy)
1627 {
1628 for (i = srcattr->num_values, srcval = srcattr->values,
1629 dstval = dstattr->values;
1630 i > 0;
1631 i --, srcval ++, dstval ++)
1632 {
1633 dstval->string.language = srcval->string.language;
1634 dstval->string.text = srcval->string.text;
1635 }
1636 }
1637 else if (srcattr->value_tag & IPP_TAG_CUPS_CONST)
1638 {
1639 for (i = srcattr->num_values, srcval = srcattr->values,
1640 dstval = dstattr->values;
1641 i > 0;
1642 i --, srcval ++, dstval ++)
1643 {
1644 if (srcval == srcattr->values)
1645 dstval->string.language = _cupsStrAlloc(srcval->string.language);
1646 else
1647 dstval->string.language = dstattr->values[0].string.language;
1648
1649 dstval->string.text = _cupsStrAlloc(srcval->string.text);
1650 }
1651 }
1652 else
1653 {
1654 for (i = srcattr->num_values, srcval = srcattr->values,
1655 dstval = dstattr->values;
1656 i > 0;
1657 i --, srcval ++, dstval ++)
1658 {
1659 if (srcval == srcattr->values)
1660 dstval->string.language = _cupsStrRetain(srcval->string.language);
1661 else
1662 dstval->string.language = dstattr->values[0].string.language;
1663
1664 dstval->string.text = _cupsStrRetain(srcval->string.text);
1665 }
1666 }
1667 break;
1668
1669 case IPP_TAG_BEGIN_COLLECTION :
1670 dstattr = ippAddCollections(dst, srcattr->group_tag, srcattr->name,
1671 srcattr->num_values, NULL);
1672 if (!dstattr)
1673 break;
1674
1675 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1676 i > 0;
1677 i --, srcval ++, dstval ++)
1678 {
1679 dstval->collection = srcval->collection;
1680 srcval->collection->use ++;
1681 }
1682 break;
1683
1684 case IPP_TAG_STRING :
1685 default :
1686 /* TODO: Implement quick copy for unknown/octetString values */
1687 dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag,
1688 srcattr->name, srcattr->num_values, NULL);
1689 if (!dstattr)
1690 break;
1691
1692 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1693 i > 0;
1694 i --, srcval ++, dstval ++)
1695 {
1696 dstval->unknown.length = srcval->unknown.length;
1697
1698 if (dstval->unknown.length > 0)
1699 {
1700 if ((dstval->unknown.data = malloc((size_t)dstval->unknown.length)) == NULL)
1701 dstval->unknown.length = 0;
1702 else
1703 memcpy(dstval->unknown.data, srcval->unknown.data, (size_t)dstval->unknown.length);
1704 }
1705 }
1706 break; /* anti-compiler-warning-code */
1707 }
1708
1709 return (dstattr);
1710 }
1711
1712
1713 /*
1714 * 'ippCopyAttributes()' - Copy attributes from one IPP message to another.
1715 *
1716 * Zero or more attributes are copied from the source IPP message, @code src@, to the
1717 * destination IPP message, @code dst@. When @code quickcopy@ is non-zero, a "shallow"
1718 * reference copy of the attribute is created - this should only be done as long as the
1719 * original source IPP message will not be freed for the life of the destination.
1720 *
1721 * The @code cb@ and @code context@ parameters provide a generic way to "filter" the
1722 * attributes that are copied - the function must return 1 to copy the attribute or
1723 * 0 to skip it. The function may also choose to do a partial copy of the source attribute
1724 * itself.
1725 *
1726 * @since CUPS 1.6/macOS 10.8@
1727 */
1728
1729 int /* O - 1 on success, 0 on error */
1730 ippCopyAttributes(
1731 ipp_t *dst, /* I - Destination IPP message */
1732 ipp_t *src, /* I - Source IPP message */
1733 int quickcopy, /* I - 1 for a referenced copy, 0 for normal */
1734 ipp_copycb_t cb, /* I - Copy callback or @code NULL@ for none */
1735 void *context) /* I - Context pointer */
1736 {
1737 ipp_attribute_t *srcattr; /* Source attribute */
1738
1739
1740 DEBUG_printf(("ippCopyAttributes(dst=%p, src=%p, quickcopy=%d, cb=%p, context=%p)", (void *)dst, (void *)src, quickcopy, (void *)cb, context));
1741
1742 /*
1743 * Range check input...
1744 */
1745
1746 if (!dst || !src)
1747 return (0);
1748
1749 /*
1750 * Loop through source attributes and copy as needed...
1751 */
1752
1753 for (srcattr = src->attrs; srcattr; srcattr = srcattr->next)
1754 if (!cb || (*cb)(context, dst, srcattr))
1755 if (!ippCopyAttribute(dst, srcattr, quickcopy))
1756 return (0);
1757
1758 return (1);
1759 }
1760
1761
1762 /*
1763 * 'ippDateToTime()' - Convert from RFC 2579 Date/Time format to time in
1764 * seconds.
1765 */
1766
1767 time_t /* O - UNIX time value */
1768 ippDateToTime(const ipp_uchar_t *date) /* I - RFC 2579 date info */
1769 {
1770 struct tm unixdate; /* UNIX date/time info */
1771 time_t t; /* Computed time */
1772
1773
1774 if (!date)
1775 return (0);
1776
1777 memset(&unixdate, 0, sizeof(unixdate));
1778
1779 /*
1780 * RFC-2579 date/time format is:
1781 *
1782 * Byte(s) Description
1783 * ------- -----------
1784 * 0-1 Year (0 to 65535)
1785 * 2 Month (1 to 12)
1786 * 3 Day (1 to 31)
1787 * 4 Hours (0 to 23)
1788 * 5 Minutes (0 to 59)
1789 * 6 Seconds (0 to 60, 60 = "leap second")
1790 * 7 Deciseconds (0 to 9)
1791 * 8 +/- UTC
1792 * 9 UTC hours (0 to 11)
1793 * 10 UTC minutes (0 to 59)
1794 */
1795
1796 unixdate.tm_year = ((date[0] << 8) | date[1]) - 1900;
1797 unixdate.tm_mon = date[2] - 1;
1798 unixdate.tm_mday = date[3];
1799 unixdate.tm_hour = date[4];
1800 unixdate.tm_min = date[5];
1801 unixdate.tm_sec = date[6];
1802
1803 t = mktime(&unixdate);
1804
1805 if (date[8] == '-')
1806 t += date[9] * 3600 + date[10] * 60;
1807 else
1808 t -= date[9] * 3600 + date[10] * 60;
1809
1810 return (t);
1811 }
1812
1813
1814 /*
1815 * 'ippDelete()' - Delete an IPP message.
1816 */
1817
1818 void
1819 ippDelete(ipp_t *ipp) /* I - IPP message */
1820 {
1821 ipp_attribute_t *attr, /* Current attribute */
1822 *next; /* Next attribute */
1823
1824
1825 DEBUG_printf(("ippDelete(ipp=%p)", (void *)ipp));
1826
1827 if (!ipp)
1828 return;
1829
1830 ipp->use --;
1831 if (ipp->use > 0)
1832 {
1833 DEBUG_printf(("4debug_retain: %p IPP message (use=%d)", (void *)ipp, ipp->use));
1834 return;
1835 }
1836
1837 DEBUG_printf(("4debug_free: %p IPP message", (void *)ipp));
1838
1839 for (attr = ipp->attrs; attr != NULL; attr = next)
1840 {
1841 next = attr->next;
1842
1843 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));
1844
1845 ipp_free_values(attr, 0, attr->num_values);
1846
1847 if (attr->name)
1848 _cupsStrFree(attr->name);
1849
1850 free(attr);
1851 }
1852
1853 free(ipp);
1854 }
1855
1856
1857 /*
1858 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
1859 *
1860 * @since CUPS 1.1.19/macOS 10.3@
1861 */
1862
1863 void
1864 ippDeleteAttribute(
1865 ipp_t *ipp, /* I - IPP message */
1866 ipp_attribute_t *attr) /* I - Attribute to delete */
1867 {
1868 ipp_attribute_t *current, /* Current attribute */
1869 *prev; /* Previous attribute */
1870
1871
1872 DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p(%s))", (void *)ipp, (void *)attr, attr ? attr->name : "(null)"));
1873
1874 /*
1875 * Range check input...
1876 */
1877
1878 if (!attr)
1879 return;
1880
1881 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));
1882
1883 /*
1884 * Find the attribute in the list...
1885 */
1886
1887 if (ipp)
1888 {
1889 for (current = ipp->attrs, prev = NULL;
1890 current;
1891 prev = current, current = current->next)
1892 if (current == attr)
1893 {
1894 /*
1895 * Found it, remove the attribute from the list...
1896 */
1897
1898 if (prev)
1899 prev->next = current->next;
1900 else
1901 ipp->attrs = current->next;
1902
1903 if (current == ipp->last)
1904 ipp->last = prev;
1905
1906 break;
1907 }
1908
1909 if (!current)
1910 return;
1911 }
1912
1913 /*
1914 * Free memory used by the attribute...
1915 */
1916
1917 ipp_free_values(attr, 0, attr->num_values);
1918
1919 if (attr->name)
1920 _cupsStrFree(attr->name);
1921
1922 free(attr);
1923 }
1924
1925
1926 /*
1927 * 'ippDeleteValues()' - Delete values in an attribute.
1928 *
1929 * The @code element@ parameter specifies the first value to delete, starting at
1930 * 0. It must be less than the number of values returned by @link ippGetCount@.
1931 *
1932 * The @code attr@ parameter may be modified as a result of setting the value.
1933 *
1934 * Deleting all values in an attribute deletes the attribute.
1935 *
1936 * @since CUPS 1.6/macOS 10.8@
1937 */
1938
1939 int /* O - 1 on success, 0 on failure */
1940 ippDeleteValues(
1941 ipp_t *ipp, /* I - IPP message */
1942 ipp_attribute_t **attr, /* IO - Attribute */
1943 int element, /* I - Index of first value to delete (0-based) */
1944 int count) /* I - Number of values to delete */
1945 {
1946 /*
1947 * Range check input...
1948 */
1949
1950 if (!ipp || !attr || !*attr ||
1951 element < 0 || element >= (*attr)->num_values || count <= 0 ||
1952 (element + count) >= (*attr)->num_values)
1953 return (0);
1954
1955 /*
1956 * If we are deleting all values, just delete the attribute entirely.
1957 */
1958
1959 if (count == (*attr)->num_values)
1960 {
1961 ippDeleteAttribute(ipp, *attr);
1962 *attr = NULL;
1963 return (1);
1964 }
1965
1966 /*
1967 * Otherwise free the values in question and return.
1968 */
1969
1970 ipp_free_values(*attr, element, count);
1971
1972 return (1);
1973 }
1974
1975
1976 /*
1977 * 'ippFindAttribute()' - Find a named attribute in a request.
1978 *
1979 * Starting with CUPS 2.0, the attribute name can contain a hierarchical list
1980 * of attribute and member names separated by slashes, for example
1981 * "media-col/media-size".
1982 */
1983
1984 ipp_attribute_t * /* O - Matching attribute */
1985 ippFindAttribute(ipp_t *ipp, /* I - IPP message */
1986 const char *name, /* I - Name of attribute */
1987 ipp_tag_t type) /* I - Type of attribute */
1988 {
1989 DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", (void *)ipp, name, type, ippTagString(type)));
1990
1991 if (!ipp || !name)
1992 return (NULL);
1993
1994 /*
1995 * Reset the current pointer...
1996 */
1997
1998 ipp->current = NULL;
1999 ipp->atend = 0;
2000
2001 /*
2002 * Search for the attribute...
2003 */
2004
2005 return (ippFindNextAttribute(ipp, name, type));
2006 }
2007
2008
2009 /*
2010 * 'ippFindNextAttribute()' - Find the next named attribute in a request.
2011 *
2012 * Starting with CUPS 2.0, the attribute name can contain a hierarchical list
2013 * of attribute and member names separated by slashes, for example
2014 * "media-col/media-size".
2015 */
2016
2017 ipp_attribute_t * /* O - Matching attribute */
2018 ippFindNextAttribute(ipp_t *ipp, /* I - IPP message */
2019 const char *name, /* I - Name of attribute */
2020 ipp_tag_t type) /* I - Type of attribute */
2021 {
2022 ipp_attribute_t *attr, /* Current atttribute */
2023 *childattr; /* Child attribute */
2024 ipp_tag_t value_tag; /* Value tag */
2025 char parent[1024], /* Parent attribute name */
2026 *child = NULL; /* Child attribute name */
2027
2028
2029 DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", (void *)ipp, name, type, ippTagString(type)));
2030
2031 if (!ipp || !name)
2032 return (NULL);
2033
2034 DEBUG_printf(("3ippFindNextAttribute: atend=%d", ipp->atend));
2035
2036 if (ipp->atend)
2037 return (NULL);
2038
2039 if (strchr(name, '/'))
2040 {
2041 /*
2042 * Search for child attribute...
2043 */
2044
2045 strlcpy(parent, name, sizeof(parent));
2046 if ((child = strchr(parent, '/')) == NULL)
2047 {
2048 DEBUG_puts("3ippFindNextAttribute: Attribute name too long.");
2049 return (NULL);
2050 }
2051
2052 *child++ = '\0';
2053
2054 if (ipp->current && ipp->current->name && ipp->current->value_tag == IPP_TAG_BEGIN_COLLECTION && !strcmp(parent, ipp->current->name))
2055 {
2056 while (ipp->curindex < ipp->current->num_values)
2057 {
2058 if ((childattr = ippFindNextAttribute(ipp->current->values[ipp->curindex].collection, child, type)) != NULL)
2059 return (childattr);
2060
2061 ipp->curindex ++;
2062 if (ipp->curindex < ipp->current->num_values && ipp->current->values[ipp->curindex].collection)
2063 ipp->current->values[ipp->curindex].collection->current = NULL;
2064 }
2065
2066 ipp->prev = ipp->current;
2067 ipp->current = ipp->current->next;
2068 ipp->curindex = 0;
2069
2070 if (!ipp->current)
2071 {
2072 ipp->atend = 1;
2073 return (NULL);
2074 }
2075 }
2076
2077 if (!ipp->current)
2078 {
2079 ipp->prev = NULL;
2080 ipp->current = ipp->attrs;
2081 ipp->curindex = 0;
2082 }
2083
2084 name = parent;
2085 attr = ipp->current;
2086 }
2087 else if (ipp->current)
2088 {
2089 ipp->prev = ipp->current;
2090 attr = ipp->current->next;
2091 }
2092 else
2093 {
2094 ipp->prev = NULL;
2095 attr = ipp->attrs;
2096 }
2097
2098 for (; attr != NULL; ipp->prev = attr, attr = attr->next)
2099 {
2100 DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", (void *)attr, attr->name));
2101
2102 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK);
2103
2104 if (attr->name != NULL && _cups_strcasecmp(attr->name, name) == 0 &&
2105 (value_tag == type || type == IPP_TAG_ZERO || name == parent ||
2106 (value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) ||
2107 (value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME)))
2108 {
2109 ipp->current = attr;
2110
2111 if (name == parent && attr->value_tag == IPP_TAG_BEGIN_COLLECTION)
2112 {
2113 int i; /* Looping var */
2114
2115 for (i = 0; i < attr->num_values; i ++)
2116 {
2117 if ((childattr = ippFindAttribute(attr->values[i].collection, child, type)) != NULL)
2118 {
2119 attr->values[0].collection->curindex = i;
2120 return (childattr);
2121 }
2122 }
2123 }
2124 else
2125 return (attr);
2126 }
2127 }
2128
2129 ipp->current = NULL;
2130 ipp->prev = NULL;
2131 ipp->atend = 1;
2132
2133 return (NULL);
2134 }
2135
2136
2137 /*
2138 * 'ippFirstAttribute()' - Return the first attribute in the message.
2139 *
2140 * @since CUPS 1.6/macOS 10.8@
2141 */
2142
2143 ipp_attribute_t * /* O - First attribute or @code NULL@ if none */
2144 ippFirstAttribute(ipp_t *ipp) /* I - IPP message */
2145 {
2146 /*
2147 * Range check input...
2148 */
2149
2150 if (!ipp)
2151 return (NULL);
2152
2153 /*
2154 * Return the first attribute...
2155 */
2156
2157 return (ipp->current = ipp->attrs);
2158 }
2159
2160
2161 /*
2162 * 'ippGetBoolean()' - Get a boolean value for an attribute.
2163 *
2164 * The @code element@ parameter specifies which value to get from 0 to
2165 * @code ippGetCount(attr)@ - 1.
2166 *
2167 * @since CUPS 1.6/macOS 10.8@
2168 */
2169
2170 int /* O - Boolean value or 0 on error */
2171 ippGetBoolean(ipp_attribute_t *attr, /* I - IPP attribute */
2172 int element) /* I - Value number (0-based) */
2173 {
2174 /*
2175 * Range check input...
2176 */
2177
2178 if (!attr || attr->value_tag != IPP_TAG_BOOLEAN ||
2179 element < 0 || element >= attr->num_values)
2180 return (0);
2181
2182 /*
2183 * Return the value...
2184 */
2185
2186 return (attr->values[element].boolean);
2187 }
2188
2189
2190 /*
2191 * 'ippGetCollection()' - Get a collection value for an attribute.
2192 *
2193 * The @code element@ parameter specifies which value to get from 0 to
2194 * @code ippGetCount(attr)@ - 1.
2195 *
2196 * @since CUPS 1.6/macOS 10.8@
2197 */
2198
2199 ipp_t * /* O - Collection value or @code NULL@ on error */
2200 ippGetCollection(
2201 ipp_attribute_t *attr, /* I - IPP attribute */
2202 int element) /* I - Value number (0-based) */
2203 {
2204 /*
2205 * Range check input...
2206 */
2207
2208 if (!attr || attr->value_tag != IPP_TAG_BEGIN_COLLECTION ||
2209 element < 0 || element >= attr->num_values)
2210 return (NULL);
2211
2212 /*
2213 * Return the value...
2214 */
2215
2216 return (attr->values[element].collection);
2217 }
2218
2219
2220 /*
2221 * 'ippGetCount()' - Get the number of values in an attribute.
2222 *
2223 * @since CUPS 1.6/macOS 10.8@
2224 */
2225
2226 int /* O - Number of values or 0 on error */
2227 ippGetCount(ipp_attribute_t *attr) /* I - IPP attribute */
2228 {
2229 /*
2230 * Range check input...
2231 */
2232
2233 if (!attr)
2234 return (0);
2235
2236 /*
2237 * Return the number of values...
2238 */
2239
2240 return (attr->num_values);
2241 }
2242
2243
2244 /*
2245 * 'ippGetDate()' - Get a dateTime value for an attribute.
2246 *
2247 * The @code element@ parameter specifies which value to get from 0 to
2248 * @code ippGetCount(attr)@ - 1.
2249 *
2250 * @since CUPS 1.6/macOS 10.8@
2251 */
2252
2253 const ipp_uchar_t * /* O - dateTime value or @code NULL@ */
2254 ippGetDate(ipp_attribute_t *attr, /* I - IPP attribute */
2255 int element) /* I - Value number (0-based) */
2256 {
2257 /*
2258 * Range check input...
2259 */
2260
2261 if (!attr || attr->value_tag != IPP_TAG_DATE ||
2262 element < 0 || element >= attr->num_values)
2263 return (NULL);
2264
2265 /*
2266 * Return the value...
2267 */
2268
2269 return (attr->values[element].date);
2270 }
2271
2272
2273 /*
2274 * 'ippGetGroupTag()' - Get the group associated with an attribute.
2275 *
2276 * @since CUPS 1.6/macOS 10.8@
2277 */
2278
2279 ipp_tag_t /* O - Group tag or @code IPP_TAG_ZERO@ on error */
2280 ippGetGroupTag(ipp_attribute_t *attr) /* I - IPP attribute */
2281 {
2282 /*
2283 * Range check input...
2284 */
2285
2286 if (!attr)
2287 return (IPP_TAG_ZERO);
2288
2289 /*
2290 * Return the group...
2291 */
2292
2293 return (attr->group_tag);
2294 }
2295
2296
2297 /*
2298 * 'ippGetInteger()' - Get the integer/enum value for an attribute.
2299 *
2300 * The @code element@ parameter specifies which value to get from 0 to
2301 * @code ippGetCount(attr)@ - 1.
2302 *
2303 * @since CUPS 1.6/macOS 10.8@
2304 */
2305
2306 int /* O - Value or 0 on error */
2307 ippGetInteger(ipp_attribute_t *attr, /* I - IPP attribute */
2308 int element) /* I - Value number (0-based) */
2309 {
2310 /*
2311 * Range check input...
2312 */
2313
2314 if (!attr || (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM) ||
2315 element < 0 || element >= attr->num_values)
2316 return (0);
2317
2318 /*
2319 * Return the value...
2320 */
2321
2322 return (attr->values[element].integer);
2323 }
2324
2325
2326 /*
2327 * 'ippGetName()' - Get the attribute name.
2328 *
2329 * @since CUPS 1.6/macOS 10.8@
2330 */
2331
2332 const char * /* O - Attribute name or @code NULL@ for separators */
2333 ippGetName(ipp_attribute_t *attr) /* I - IPP attribute */
2334 {
2335 /*
2336 * Range check input...
2337 */
2338
2339 if (!attr)
2340 return (NULL);
2341
2342 /*
2343 * Return the name...
2344 */
2345
2346 return (attr->name);
2347 }
2348
2349
2350 /*
2351 * 'ippGetOctetString()' - Get an octetString value from an IPP attribute.
2352 *
2353 * The @code element@ parameter specifies which value to get from 0 to
2354 * @code ippGetCount(attr)@ - 1.
2355 *
2356 * @since CUPS 1.7/macOS 10.9@
2357 */
2358
2359 void * /* O - Pointer to octetString data */
2360 ippGetOctetString(
2361 ipp_attribute_t *attr, /* I - IPP attribute */
2362 int element, /* I - Value number (0-based) */
2363 int *datalen) /* O - Length of octetString data */
2364 {
2365 /*
2366 * Range check input...
2367 */
2368
2369 if (!attr || attr->value_tag != IPP_TAG_STRING ||
2370 element < 0 || element >= attr->num_values)
2371 {
2372 if (datalen)
2373 *datalen = 0;
2374
2375 return (NULL);
2376 }
2377
2378 /*
2379 * Return the values...
2380 */
2381
2382 if (datalen)
2383 *datalen = attr->values[element].unknown.length;
2384
2385 return (attr->values[element].unknown.data);
2386 }
2387
2388
2389 /*
2390 * 'ippGetOperation()' - Get the operation ID in an IPP message.
2391 *
2392 * @since CUPS 1.6/macOS 10.8@
2393 */
2394
2395 ipp_op_t /* O - Operation ID or 0 on error */
2396 ippGetOperation(ipp_t *ipp) /* I - IPP request message */
2397 {
2398 /*
2399 * Range check input...
2400 */
2401
2402 if (!ipp)
2403 return ((ipp_op_t)0);
2404
2405 /*
2406 * Return the value...
2407 */
2408
2409 return (ipp->request.op.operation_id);
2410 }
2411
2412
2413 /*
2414 * 'ippGetRange()' - Get a rangeOfInteger value from an attribute.
2415 *
2416 * The @code element@ parameter specifies which value to get from 0 to
2417 * @code ippGetCount(attr)@ - 1.
2418 *
2419 * @since CUPS 1.6/macOS 10.8@
2420 */
2421
2422 int /* O - Lower value of range or 0 */
2423 ippGetRange(ipp_attribute_t *attr, /* I - IPP attribute */
2424 int element, /* I - Value number (0-based) */
2425 int *uppervalue)/* O - Upper value of range */
2426 {
2427 /*
2428 * Range check input...
2429 */
2430
2431 if (!attr || attr->value_tag != IPP_TAG_RANGE ||
2432 element < 0 || element >= attr->num_values)
2433 {
2434 if (uppervalue)
2435 *uppervalue = 0;
2436
2437 return (0);
2438 }
2439
2440 /*
2441 * Return the values...
2442 */
2443
2444 if (uppervalue)
2445 *uppervalue = attr->values[element].range.upper;
2446
2447 return (attr->values[element].range.lower);
2448 }
2449
2450
2451 /*
2452 * 'ippGetRequestId()' - Get the request ID from an IPP message.
2453 *
2454 * @since CUPS 1.6/macOS 10.8@
2455 */
2456
2457 int /* O - Request ID or 0 on error */
2458 ippGetRequestId(ipp_t *ipp) /* I - IPP message */
2459 {
2460 /*
2461 * Range check input...
2462 */
2463
2464 if (!ipp)
2465 return (0);
2466
2467 /*
2468 * Return the request ID...
2469 */
2470
2471 return (ipp->request.any.request_id);
2472 }
2473
2474
2475 /*
2476 * 'ippGetResolution()' - Get a resolution value for an attribute.
2477 *
2478 * The @code element@ parameter specifies which value to get from 0 to
2479 * @code ippGetCount(attr)@ - 1.
2480 *
2481 * @since CUPS 1.6/macOS 10.8@
2482 */
2483
2484 int /* O - Horizontal/cross feed resolution or 0 */
2485 ippGetResolution(
2486 ipp_attribute_t *attr, /* I - IPP attribute */
2487 int element, /* I - Value number (0-based) */
2488 int *yres, /* O - Vertical/feed resolution */
2489 ipp_res_t *units) /* O - Units for resolution */
2490 {
2491 /*
2492 * Range check input...
2493 */
2494
2495 if (!attr || attr->value_tag != IPP_TAG_RESOLUTION ||
2496 element < 0 || element >= attr->num_values)
2497 {
2498 if (yres)
2499 *yres = 0;
2500
2501 if (units)
2502 *units = (ipp_res_t)0;
2503
2504 return (0);
2505 }
2506
2507 /*
2508 * Return the value...
2509 */
2510
2511 if (yres)
2512 *yres = attr->values[element].resolution.yres;
2513
2514 if (units)
2515 *units = attr->values[element].resolution.units;
2516
2517 return (attr->values[element].resolution.xres);
2518 }
2519
2520
2521 /*
2522 * 'ippGetState()' - Get the IPP message state.
2523 *
2524 * @since CUPS 1.6/macOS 10.8@
2525 */
2526
2527 ipp_state_t /* O - IPP message state value */
2528 ippGetState(ipp_t *ipp) /* I - IPP message */
2529 {
2530 /*
2531 * Range check input...
2532 */
2533
2534 if (!ipp)
2535 return (IPP_STATE_IDLE);
2536
2537 /*
2538 * Return the value...
2539 */
2540
2541 return (ipp->state);
2542 }
2543
2544
2545 /*
2546 * 'ippGetStatusCode()' - Get the status code from an IPP response or event message.
2547 *
2548 * @since CUPS 1.6/macOS 10.8@
2549 */
2550
2551 ipp_status_t /* O - Status code in IPP message */
2552 ippGetStatusCode(ipp_t *ipp) /* I - IPP response or event message */
2553 {
2554 /*
2555 * Range check input...
2556 */
2557
2558 if (!ipp)
2559 return (IPP_STATUS_ERROR_INTERNAL);
2560
2561 /*
2562 * Return the value...
2563 */
2564
2565 return (ipp->request.status.status_code);
2566 }
2567
2568
2569 /*
2570 * 'ippGetString()' - Get the string and optionally the language code for an attribute.
2571 *
2572 * The @code element@ parameter specifies which value to get from 0 to
2573 * @code ippGetCount(attr)@ - 1.
2574 *
2575 * @since CUPS 1.6/macOS 10.8@
2576 */
2577
2578 const char *
2579 ippGetString(ipp_attribute_t *attr, /* I - IPP attribute */
2580 int element, /* I - Value number (0-based) */
2581 const char **language)/* O - Language code (@code NULL@ for don't care) */
2582 {
2583 ipp_tag_t tag; /* Value tag */
2584
2585
2586 /*
2587 * Range check input...
2588 */
2589
2590 tag = ippGetValueTag(attr);
2591
2592 if (!attr || element < 0 || element >= attr->num_values || (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG && (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE)))
2593 return (NULL);
2594
2595 /*
2596 * Return the value...
2597 */
2598
2599 if (language)
2600 *language = attr->values[element].string.language;
2601
2602 return (attr->values[element].string.text);
2603 }
2604
2605
2606 /*
2607 * 'ippGetValueTag()' - Get the value tag for an attribute.
2608 *
2609 * @since CUPS 1.6/macOS 10.8@
2610 */
2611
2612 ipp_tag_t /* O - Value tag or @code IPP_TAG_ZERO@ on error */
2613 ippGetValueTag(ipp_attribute_t *attr) /* I - IPP attribute */
2614 {
2615 /*
2616 * Range check input...
2617 */
2618
2619 if (!attr)
2620 return (IPP_TAG_ZERO);
2621
2622 /*
2623 * Return the value...
2624 */
2625
2626 return (attr->value_tag & IPP_TAG_CUPS_MASK);
2627 }
2628
2629
2630 /*
2631 * 'ippGetVersion()' - Get the major and minor version number from an IPP message.
2632 *
2633 * @since CUPS 1.6/macOS 10.8@
2634 */
2635
2636 int /* O - Major version number or 0 on error */
2637 ippGetVersion(ipp_t *ipp, /* I - IPP message */
2638 int *minor) /* O - Minor version number or @code NULL@ for don't care */
2639 {
2640 /*
2641 * Range check input...
2642 */
2643
2644 if (!ipp)
2645 {
2646 if (minor)
2647 *minor = 0;
2648
2649 return (0);
2650 }
2651
2652 /*
2653 * Return the value...
2654 */
2655
2656 if (minor)
2657 *minor = ipp->request.any.version[1];
2658
2659 return (ipp->request.any.version[0]);
2660 }
2661
2662
2663 /*
2664 * 'ippLength()' - Compute the length of an IPP message.
2665 */
2666
2667 size_t /* O - Size of IPP message */
2668 ippLength(ipp_t *ipp) /* I - IPP message */
2669 {
2670 return (ipp_length(ipp, 0));
2671 }
2672
2673
2674 /*
2675 * 'ippNextAttribute()' - Return the next attribute in the message.
2676 *
2677 * @since CUPS 1.6/macOS 10.8@
2678 */
2679
2680 ipp_attribute_t * /* O - Next attribute or @code NULL@ if none */
2681 ippNextAttribute(ipp_t *ipp) /* I - IPP message */
2682 {
2683 /*
2684 * Range check input...
2685 */
2686
2687 if (!ipp || !ipp->current)
2688 return (NULL);
2689
2690 /*
2691 * Return the next attribute...
2692 */
2693
2694 return (ipp->current = ipp->current->next);
2695 }
2696
2697
2698 /*
2699 * 'ippNew()' - Allocate a new IPP message.
2700 */
2701
2702 ipp_t * /* O - New IPP message */
2703 ippNew(void)
2704 {
2705 ipp_t *temp; /* New IPP message */
2706 _cups_globals_t *cg = _cupsGlobals();
2707 /* Global data */
2708
2709
2710 DEBUG_puts("ippNew()");
2711
2712 if ((temp = (ipp_t *)calloc(1, sizeof(ipp_t))) != NULL)
2713 {
2714 /*
2715 * Set default version - usually 2.0...
2716 */
2717
2718 DEBUG_printf(("4debug_alloc: %p IPP message", (void *)temp));
2719
2720 if (cg->server_version == 0)
2721 _cupsSetDefaults();
2722
2723 temp->request.any.version[0] = (ipp_uchar_t)(cg->server_version / 10);
2724 temp->request.any.version[1] = (ipp_uchar_t)(cg->server_version % 10);
2725 temp->use = 1;
2726 }
2727
2728 DEBUG_printf(("1ippNew: Returning %p", (void *)temp));
2729
2730 return (temp);
2731 }
2732
2733
2734 /*
2735 * 'ippNewRequest()' - Allocate a new IPP request message.
2736 *
2737 * The new request message is initialized with the "attributes-charset" and
2738 * "attributes-natural-language" attributes added. The
2739 * "attributes-natural-language" value is derived from the current locale.
2740 *
2741 * @since CUPS 1.2/macOS 10.5@
2742 */
2743
2744 ipp_t * /* O - IPP request message */
2745 ippNewRequest(ipp_op_t op) /* I - Operation code */
2746 {
2747 ipp_t *request; /* IPP request message */
2748 cups_lang_t *language; /* Current language localization */
2749 static int request_id = 0; /* Current request ID */
2750 static _cups_mutex_t request_mutex = _CUPS_MUTEX_INITIALIZER;
2751 /* Mutex for request ID */
2752
2753
2754 DEBUG_printf(("ippNewRequest(op=%02x(%s))", op, ippOpString(op)));
2755
2756 /*
2757 * Create a new IPP message...
2758 */
2759
2760 if ((request = ippNew()) == NULL)
2761 return (NULL);
2762
2763 /*
2764 * Set the operation and request ID...
2765 */
2766
2767 _cupsMutexLock(&request_mutex);
2768
2769 request->request.op.operation_id = op;
2770 request->request.op.request_id = ++request_id;
2771
2772 _cupsMutexUnlock(&request_mutex);
2773
2774 /*
2775 * Use UTF-8 as the character set...
2776 */
2777
2778 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2779 "attributes-charset", NULL, "utf-8");
2780
2781 /*
2782 * Get the language from the current locale...
2783 */
2784
2785 language = cupsLangDefault();
2786
2787 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2788 "attributes-natural-language", NULL, language->language);
2789
2790 /*
2791 * Return the new request...
2792 */
2793
2794 return (request);
2795 }
2796
2797
2798 /*
2799 * 'ippNewResponse()' - Allocate a new IPP response message.
2800 *
2801 * The new response message is initialized with the same "version-number",
2802 * "request-id", "attributes-charset", and "attributes-natural-language" as the
2803 * provided request message. If the "attributes-charset" or
2804 * "attributes-natural-language" attributes are missing from the request,
2805 * 'utf-8' and a value derived from the current locale are substituted,
2806 * respectively.
2807 *
2808 * @since CUPS 1.7/macOS 10.9@
2809 */
2810
2811 ipp_t * /* O - IPP response message */
2812 ippNewResponse(ipp_t *request) /* I - IPP request message */
2813 {
2814 ipp_t *response; /* IPP response message */
2815 ipp_attribute_t *attr; /* Current attribute */
2816
2817
2818 /*
2819 * Range check input...
2820 */
2821
2822 if (!request)
2823 return (NULL);
2824
2825 /*
2826 * Create a new IPP message...
2827 */
2828
2829 if ((response = ippNew()) == NULL)
2830 return (NULL);
2831
2832 /*
2833 * Copy the request values over to the response...
2834 */
2835
2836 response->request.status.version[0] = request->request.op.version[0];
2837 response->request.status.version[1] = request->request.op.version[1];
2838 response->request.status.request_id = request->request.op.request_id;
2839
2840 /*
2841 * The first attribute MUST be attributes-charset...
2842 */
2843
2844 attr = request->attrs;
2845
2846 if (attr && attr->name && !strcmp(attr->name, "attributes-charset") &&
2847 attr->group_tag == IPP_TAG_OPERATION &&
2848 attr->value_tag == IPP_TAG_CHARSET &&
2849 attr->num_values == 1)
2850 {
2851 /*
2852 * Copy charset from request...
2853 */
2854
2855 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2856 "attributes-charset", NULL, attr->values[0].string.text);
2857 }
2858 else
2859 {
2860 /*
2861 * Use "utf-8" as the default...
2862 */
2863
2864 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2865 "attributes-charset", NULL, "utf-8");
2866 }
2867
2868 /*
2869 * Then attributes-natural-language...
2870 */
2871
2872 if (attr)
2873 attr = attr->next;
2874
2875 if (attr && attr->name &&
2876 !strcmp(attr->name, "attributes-natural-language") &&
2877 attr->group_tag == IPP_TAG_OPERATION &&
2878 attr->value_tag == IPP_TAG_LANGUAGE &&
2879 attr->num_values == 1)
2880 {
2881 /*
2882 * Copy language from request...
2883 */
2884
2885 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2886 "attributes-natural-language", NULL,
2887 attr->values[0].string.text);
2888 }
2889 else
2890 {
2891 /*
2892 * Use the language from the current locale...
2893 */
2894
2895 cups_lang_t *language = cupsLangDefault();
2896 /* Current locale */
2897
2898 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2899 "attributes-natural-language", NULL, language->language);
2900 }
2901
2902 return (response);
2903 }
2904
2905
2906 /*
2907 * 'ippRead()' - Read data for an IPP message from a HTTP connection.
2908 */
2909
2910 ipp_state_t /* O - Current state */
2911 ippRead(http_t *http, /* I - HTTP connection */
2912 ipp_t *ipp) /* I - IPP data */
2913 {
2914 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT, (void *)http, (void *)ipp, CUPS_LLCAST (http ? http->data_remaining : -1)));
2915
2916 if (!http)
2917 return (IPP_STATE_ERROR);
2918
2919 DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http->state, http->used));
2920
2921 return (ippReadIO(http, (ipp_iocb_t)ipp_read_http, http->blocking, NULL,
2922 ipp));
2923 }
2924
2925
2926 /*
2927 * 'ippReadFile()' - Read data for an IPP message from a file.
2928 *
2929 * @since CUPS 1.1.19/macOS 10.3@
2930 */
2931
2932 ipp_state_t /* O - Current state */
2933 ippReadFile(int fd, /* I - HTTP data */
2934 ipp_t *ipp) /* I - IPP data */
2935 {
2936 DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd, (void *)ipp));
2937
2938 return (ippReadIO(&fd, (ipp_iocb_t)ipp_read_file, 1, NULL, ipp));
2939 }
2940
2941
2942 /*
2943 * 'ippReadIO()' - Read data for an IPP message.
2944 *
2945 * @since CUPS 1.2/macOS 10.5@
2946 */
2947
2948 ipp_state_t /* O - Current state */
2949 ippReadIO(void *src, /* I - Data source */
2950 ipp_iocb_t cb, /* I - Read callback function */
2951 int blocking, /* I - Use blocking IO? */
2952 ipp_t *parent, /* I - Parent request, if any */
2953 ipp_t *ipp) /* I - IPP data */
2954 {
2955 int n; /* Length of data */
2956 unsigned char *buffer, /* Data buffer */
2957 string[IPP_MAX_TEXT],
2958 /* Small string buffer */
2959 *bufptr; /* Pointer into buffer */
2960 ipp_attribute_t *attr; /* Current attribute */
2961 ipp_tag_t tag; /* Current tag */
2962 ipp_tag_t value_tag; /* Current value tag */
2963 _ipp_value_t *value; /* Current value */
2964
2965
2966 DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)src, (void *)cb, blocking, (void *)parent, (void *)ipp));
2967 DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp ? ipp->state : IPP_STATE_ERROR));
2968
2969 if (!src || !ipp)
2970 return (IPP_STATE_ERROR);
2971
2972 if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
2973 {
2974 DEBUG_puts("1ippReadIO: Unable to get read buffer.");
2975 return (IPP_STATE_ERROR);
2976 }
2977
2978 switch (ipp->state)
2979 {
2980 case IPP_STATE_IDLE :
2981 ipp->state ++; /* Avoid common problem... */
2982
2983 case IPP_STATE_HEADER :
2984 if (parent == NULL)
2985 {
2986 /*
2987 * Get the request header...
2988 */
2989
2990 if ((*cb)(src, buffer, 8) < 8)
2991 {
2992 DEBUG_puts("1ippReadIO: Unable to read header.");
2993 _cupsBufferRelease((char *)buffer);
2994 return (IPP_STATE_ERROR);
2995 }
2996
2997 /*
2998 * Then copy the request header over...
2999 */
3000
3001 ipp->request.any.version[0] = buffer[0];
3002 ipp->request.any.version[1] = buffer[1];
3003 ipp->request.any.op_status = (buffer[2] << 8) | buffer[3];
3004 ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) |
3005 buffer[6]) << 8) | buffer[7];
3006
3007 DEBUG_printf(("2ippReadIO: version=%d.%d", buffer[0], buffer[1]));
3008 DEBUG_printf(("2ippReadIO: op_status=%04x",
3009 ipp->request.any.op_status));
3010 DEBUG_printf(("2ippReadIO: request_id=%d",
3011 ipp->request.any.request_id));
3012 }
3013
3014 ipp->state = IPP_STATE_ATTRIBUTE;
3015 ipp->current = NULL;
3016 ipp->curtag = IPP_TAG_ZERO;
3017 ipp->prev = ipp->last;
3018
3019 /*
3020 * If blocking is disabled, stop here...
3021 */
3022
3023 if (!blocking)
3024 break;
3025
3026 case IPP_STATE_ATTRIBUTE :
3027 for (;;)
3028 {
3029 if ((*cb)(src, buffer, 1) < 1)
3030 {
3031 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
3032 _cupsBufferRelease((char *)buffer);
3033 return (IPP_STATE_ERROR);
3034 }
3035
3036 DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev));
3037
3038 /*
3039 * Read this attribute...
3040 */
3041
3042 tag = (ipp_tag_t)buffer[0];
3043 if (tag == IPP_TAG_EXTENSION)
3044 {
3045 /*
3046 * Read 32-bit "extension" tag...
3047 */
3048
3049 if ((*cb)(src, buffer, 4) < 1)
3050 {
3051 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
3052 _cupsBufferRelease((char *)buffer);
3053 return (IPP_STATE_ERROR);
3054 }
3055
3056 tag = (ipp_tag_t)((((((buffer[0] << 8) | buffer[1]) << 8) |
3057 buffer[2]) << 8) | buffer[3]);
3058
3059 if (tag & IPP_TAG_CUPS_CONST)
3060 {
3061 /*
3062 * Fail if the high bit is set in the tag...
3063 */
3064
3065 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
3066 DEBUG_printf(("1ippReadIO: bad tag 0x%x.", tag));
3067 _cupsBufferRelease((char *)buffer);
3068 return (IPP_STATE_ERROR);
3069 }
3070 }
3071
3072 if (tag == IPP_TAG_END)
3073 {
3074 /*
3075 * No more attributes left...
3076 */
3077
3078 DEBUG_puts("2ippReadIO: IPP_TAG_END.");
3079
3080 ipp->state = IPP_STATE_DATA;
3081 break;
3082 }
3083 else if (tag == IPP_TAG_ZERO || (tag == IPP_TAG_OPERATION && ipp->curtag != IPP_TAG_ZERO))
3084 {
3085 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid group tag."), 1);
3086 DEBUG_printf(("1ippReadIO: bad tag 0x%02x.", tag));
3087 _cupsBufferRelease((char *)buffer);
3088 return (IPP_STATE_ERROR);
3089 }
3090 else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
3091 {
3092 /*
3093 * Group tag... Set the current group and continue...
3094 */
3095
3096 if (ipp->curtag == tag)
3097 ipp->prev = ippAddSeparator(ipp);
3098 else if (ipp->current)
3099 ipp->prev = ipp->current;
3100
3101 ipp->curtag = tag;
3102 ipp->current = NULL;
3103 DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag, ippTagString(tag), (void *)ipp->prev));
3104 continue;
3105 }
3106
3107 DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag,
3108 ippTagString(tag)));
3109
3110 /*
3111 * Get the name...
3112 */
3113
3114 if ((*cb)(src, buffer, 2) < 2)
3115 {
3116 DEBUG_puts("1ippReadIO: unable to read name length.");
3117 _cupsBufferRelease((char *)buffer);
3118 return (IPP_STATE_ERROR);
3119 }
3120
3121 n = (buffer[0] << 8) | buffer[1];
3122
3123 if (n >= IPP_BUF_SIZE)
3124 {
3125 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP name larger than 32767 bytes."), 1);
3126 DEBUG_printf(("1ippReadIO: bad name length %d.", n));
3127 _cupsBufferRelease((char *)buffer);
3128 return (IPP_STATE_ERROR);
3129 }
3130
3131 DEBUG_printf(("2ippReadIO: name length=%d", n));
3132
3133 if (n == 0 && tag != IPP_TAG_MEMBERNAME &&
3134 tag != IPP_TAG_END_COLLECTION)
3135 {
3136 /*
3137 * More values for current attribute...
3138 */
3139
3140 if (ipp->current == NULL)
3141 {
3142 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP attribute has no name."), 1);
3143 DEBUG_puts("1ippReadIO: Attribute without name and no current.");
3144 _cupsBufferRelease((char *)buffer);
3145 return (IPP_STATE_ERROR);
3146 }
3147
3148 attr = ipp->current;
3149 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK);
3150
3151 /*
3152 * Make sure we aren't adding a new value of a different
3153 * type...
3154 */
3155
3156 if (value_tag == IPP_TAG_ZERO)
3157 {
3158 /*
3159 * Setting the value of a collection member...
3160 */
3161
3162 attr->value_tag = tag;
3163 }
3164 else if (value_tag == IPP_TAG_TEXTLANG ||
3165 value_tag == IPP_TAG_NAMELANG ||
3166 (value_tag >= IPP_TAG_TEXT &&
3167 value_tag <= IPP_TAG_MIMETYPE))
3168 {
3169 /*
3170 * String values can sometimes come across in different
3171 * forms; accept sets of differing values...
3172 */
3173
3174 if (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG &&
3175 (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE) &&
3176 tag != IPP_TAG_NOVALUE)
3177 {
3178 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3179 _("IPP 1setOf attribute with incompatible value "
3180 "tags."), 1);
3181 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3182 value_tag, ippTagString(value_tag), tag,
3183 ippTagString(tag)));
3184 _cupsBufferRelease((char *)buffer);
3185 return (IPP_STATE_ERROR);
3186 }
3187
3188 if (value_tag != tag)
3189 {
3190 DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.",
3191 attr->name, ippTagString(value_tag), ippTagString(tag)));
3192 ippSetValueTag(ipp, &attr, tag);
3193 }
3194 }
3195 else if (value_tag == IPP_TAG_INTEGER ||
3196 value_tag == IPP_TAG_RANGE)
3197 {
3198 /*
3199 * Integer and rangeOfInteger values can sometimes be mixed; accept
3200 * sets of differing values...
3201 */
3202
3203 if (tag != IPP_TAG_INTEGER && tag != IPP_TAG_RANGE)
3204 {
3205 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3206 _("IPP 1setOf attribute with incompatible value "
3207 "tags."), 1);
3208 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3209 value_tag, ippTagString(value_tag), tag,
3210 ippTagString(tag)));
3211 _cupsBufferRelease((char *)buffer);
3212 return (IPP_STATE_ERROR);
3213 }
3214
3215 if (value_tag == IPP_TAG_INTEGER && tag == IPP_TAG_RANGE)
3216 {
3217 /*
3218 * Convert integer values to rangeOfInteger values...
3219 */
3220
3221 DEBUG_printf(("1ippReadIO: Converting %s attribute to "
3222 "rangeOfInteger.", attr->name));
3223 ippSetValueTag(ipp, &attr, IPP_TAG_RANGE);
3224 }
3225 }
3226 else if (value_tag != tag)
3227 {
3228 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3229 _("IPP 1setOf attribute with incompatible value "
3230 "tags."), 1);
3231 DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
3232 value_tag, ippTagString(value_tag), tag,
3233 ippTagString(tag)));
3234 _cupsBufferRelease((char *)buffer);
3235 return (IPP_STATE_ERROR);
3236 }
3237
3238 /*
3239 * Finally, reallocate the attribute array as needed...
3240 */
3241
3242 if ((value = ipp_set_value(ipp, &attr, attr->num_values)) == NULL)
3243 {
3244 _cupsBufferRelease((char *)buffer);
3245 return (IPP_STATE_ERROR);
3246 }
3247 }
3248 else if (tag == IPP_TAG_MEMBERNAME)
3249 {
3250 /*
3251 * Name must be length 0!
3252 */
3253
3254 if (n)
3255 {
3256 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP member name is not empty."), 1);
3257 DEBUG_puts("1ippReadIO: member name not empty.");
3258 _cupsBufferRelease((char *)buffer);
3259 return (IPP_STATE_ERROR);
3260 }
3261
3262 if (ipp->current)
3263 ipp->prev = ipp->current;
3264
3265 attr = ipp->current = ipp_add_attr(ipp, NULL, ipp->curtag, IPP_TAG_ZERO, 1);
3266 if (!attr)
3267 {
3268 _cupsSetHTTPError(HTTP_STATUS_ERROR);
3269 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3270 _cupsBufferRelease((char *)buffer);
3271 return (IPP_STATE_ERROR);
3272 }
3273
3274 DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev));
3275
3276 value = attr->values;
3277 }
3278 else if (tag != IPP_TAG_END_COLLECTION)
3279 {
3280 /*
3281 * New attribute; read the name and add it...
3282 */
3283
3284 if ((*cb)(src, buffer, (size_t)n) < n)
3285 {
3286 DEBUG_puts("1ippReadIO: unable to read name.");
3287 _cupsBufferRelease((char *)buffer);
3288 return (IPP_STATE_ERROR);
3289 }
3290
3291 buffer[n] = '\0';
3292
3293 if (ipp->current)
3294 ipp->prev = ipp->current;
3295
3296 if ((attr = ipp->current = ipp_add_attr(ipp, (char *)buffer, ipp->curtag, tag,
3297 1)) == NULL)
3298 {
3299 _cupsSetHTTPError(HTTP_STATUS_ERROR);
3300 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3301 _cupsBufferRelease((char *)buffer);
3302 return (IPP_STATE_ERROR);
3303 }
3304
3305 DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, ipp->prev=%p", buffer, (void *)ipp->current, (void *)ipp->prev));
3306
3307 value = attr->values;
3308 }
3309 else
3310 {
3311 attr = NULL;
3312 value = NULL;
3313 }
3314
3315 if ((*cb)(src, buffer, 2) < 2)
3316 {
3317 DEBUG_puts("1ippReadIO: unable to read value length.");
3318 _cupsBufferRelease((char *)buffer);
3319 return (IPP_STATE_ERROR);
3320 }
3321
3322 n = (buffer[0] << 8) | buffer[1];
3323 DEBUG_printf(("2ippReadIO: value length=%d", n));
3324
3325 if (n >= IPP_BUF_SIZE)
3326 {
3327 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3328 _("IPP value larger than 32767 bytes."), 1);
3329 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
3330 _cupsBufferRelease((char *)buffer);
3331 return (IPP_STATE_ERROR);
3332 }
3333
3334 switch (tag)
3335 {
3336 case IPP_TAG_INTEGER :
3337 case IPP_TAG_ENUM :
3338 if (n != 4)
3339 {
3340 if (tag == IPP_TAG_INTEGER)
3341 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3342 _("IPP integer value not 4 bytes."), 1);
3343 else
3344 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3345 _("IPP enum value not 4 bytes."), 1);
3346 DEBUG_printf(("1ippReadIO: bad integer value length %d.", n));
3347 _cupsBufferRelease((char *)buffer);
3348 return (IPP_STATE_ERROR);
3349 }
3350
3351 if ((*cb)(src, buffer, 4) < 4)
3352 {
3353 DEBUG_puts("1ippReadIO: Unable to read integer value.");
3354 _cupsBufferRelease((char *)buffer);
3355 return (IPP_STATE_ERROR);
3356 }
3357
3358 n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3359 buffer[3];
3360
3361 if (attr->value_tag == IPP_TAG_RANGE)
3362 value->range.lower = value->range.upper = n;
3363 else
3364 value->integer = n;
3365 break;
3366
3367 case IPP_TAG_BOOLEAN :
3368 if (n != 1)
3369 {
3370 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP boolean value not 1 byte."),
3371 1);
3372 DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n));
3373 _cupsBufferRelease((char *)buffer);
3374 return (IPP_STATE_ERROR);
3375 }
3376
3377 if ((*cb)(src, buffer, 1) < 1)
3378 {
3379 DEBUG_puts("1ippReadIO: Unable to read boolean value.");
3380 _cupsBufferRelease((char *)buffer);
3381 return (IPP_STATE_ERROR);
3382 }
3383
3384 value->boolean = (char)buffer[0];
3385 break;
3386
3387 case IPP_TAG_UNSUPPORTED_VALUE :
3388 case IPP_TAG_DEFAULT :
3389 case IPP_TAG_UNKNOWN :
3390 case IPP_TAG_NOVALUE :
3391 case IPP_TAG_NOTSETTABLE :
3392 case IPP_TAG_DELETEATTR :
3393 case IPP_TAG_ADMINDEFINE :
3394 /*
3395 * These value types are not supposed to have values, however
3396 * some vendors (Brother) do not implement IPP correctly and so
3397 * we need to map non-empty values to text...
3398 */
3399
3400 if (attr->value_tag == tag)
3401 {
3402 if (n == 0)
3403 break;
3404
3405 attr->value_tag = IPP_TAG_TEXT;
3406 }
3407
3408 case IPP_TAG_TEXT :
3409 case IPP_TAG_NAME :
3410 case IPP_TAG_RESERVED_STRING :
3411 case IPP_TAG_KEYWORD :
3412 case IPP_TAG_URI :
3413 case IPP_TAG_URISCHEME :
3414 case IPP_TAG_CHARSET :
3415 case IPP_TAG_LANGUAGE :
3416 case IPP_TAG_MIMETYPE :
3417 if (n > 0)
3418 {
3419 if ((*cb)(src, buffer, (size_t)n) < n)
3420 {
3421 DEBUG_puts("1ippReadIO: unable to read string value.");
3422 _cupsBufferRelease((char *)buffer);
3423 return (IPP_STATE_ERROR);
3424 }
3425 }
3426
3427 buffer[n] = '\0';
3428 value->string.text = _cupsStrAlloc((char *)buffer);
3429 DEBUG_printf(("2ippReadIO: value=\"%s\"", value->string.text));
3430 break;
3431
3432 case IPP_TAG_DATE :
3433 if (n != 11)
3434 {
3435 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP date value not 11 bytes."), 1);
3436 DEBUG_printf(("1ippReadIO: bad date value length %d.", n));
3437 _cupsBufferRelease((char *)buffer);
3438 return (IPP_STATE_ERROR);
3439 }
3440
3441 if ((*cb)(src, value->date, 11) < 11)
3442 {
3443 DEBUG_puts("1ippReadIO: Unable to read date value.");
3444 _cupsBufferRelease((char *)buffer);
3445 return (IPP_STATE_ERROR);
3446 }
3447 break;
3448
3449 case IPP_TAG_RESOLUTION :
3450 if (n != 9)
3451 {
3452 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3453 _("IPP resolution value not 9 bytes."), 1);
3454 DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n));
3455 _cupsBufferRelease((char *)buffer);
3456 return (IPP_STATE_ERROR);
3457 }
3458
3459 if ((*cb)(src, buffer, 9) < 9)
3460 {
3461 DEBUG_puts("1ippReadIO: Unable to read resolution value.");
3462 _cupsBufferRelease((char *)buffer);
3463 return (IPP_STATE_ERROR);
3464 }
3465
3466 value->resolution.xres =
3467 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3468 buffer[3];
3469 value->resolution.yres =
3470 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
3471 buffer[7];
3472 value->resolution.units =
3473 (ipp_res_t)buffer[8];
3474 break;
3475
3476 case IPP_TAG_RANGE :
3477 if (n != 8)
3478 {
3479 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3480 _("IPP rangeOfInteger value not 8 bytes."), 1);
3481 DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length "
3482 "%d.", n));
3483 _cupsBufferRelease((char *)buffer);
3484 return (IPP_STATE_ERROR);
3485 }
3486
3487 if ((*cb)(src, buffer, 8) < 8)
3488 {
3489 DEBUG_puts("1ippReadIO: Unable to read range value.");
3490 _cupsBufferRelease((char *)buffer);
3491 return (IPP_STATE_ERROR);
3492 }
3493
3494 value->range.lower =
3495 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3496 buffer[3];
3497 value->range.upper =
3498 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
3499 buffer[7];
3500 break;
3501
3502 case IPP_TAG_TEXTLANG :
3503 case IPP_TAG_NAMELANG :
3504 if (n < 4)
3505 {
3506 if (tag == IPP_TAG_TEXTLANG)
3507 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3508 _("IPP textWithLanguage value less than "
3509 "minimum 4 bytes."), 1);
3510 else
3511 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3512 _("IPP nameWithLanguage value less than "
3513 "minimum 4 bytes."), 1);
3514 DEBUG_printf(("1ippReadIO: bad stringWithLanguage value "
3515 "length %d.", n));
3516 _cupsBufferRelease((char *)buffer);
3517 return (IPP_STATE_ERROR);
3518 }
3519
3520 if ((*cb)(src, buffer, (size_t)n) < n)
3521 {
3522 DEBUG_puts("1ippReadIO: Unable to read string w/language "
3523 "value.");
3524 _cupsBufferRelease((char *)buffer);
3525 return (IPP_STATE_ERROR);
3526 }
3527
3528 bufptr = buffer;
3529
3530 /*
3531 * text-with-language and name-with-language are composite
3532 * values:
3533 *
3534 * language-length
3535 * language
3536 * text-length
3537 * text
3538 */
3539
3540 n = (bufptr[0] << 8) | bufptr[1];
3541
3542 if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) || n >= (int)sizeof(string))
3543 {
3544 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3545 _("IPP language length overflows value."), 1);
3546 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3547 n));
3548 _cupsBufferRelease((char *)buffer);
3549 return (IPP_STATE_ERROR);
3550 }
3551 else if (n >= IPP_MAX_LANGUAGE)
3552 {
3553 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3554 _("IPP language length too large."), 1);
3555 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3556 n));
3557 _cupsBufferRelease((char *)buffer);
3558 return (IPP_STATE_ERROR);
3559 }
3560
3561 memcpy(string, bufptr + 2, (size_t)n);
3562 string[n] = '\0';
3563
3564 value->string.language = _cupsStrAlloc((char *)string);
3565
3566 bufptr += 2 + n;
3567 n = (bufptr[0] << 8) | bufptr[1];
3568
3569 if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE))
3570 {
3571 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3572 _("IPP string length overflows value."), 1);
3573 DEBUG_printf(("1ippReadIO: bad string value length %d.", n));
3574 _cupsBufferRelease((char *)buffer);
3575 return (IPP_STATE_ERROR);
3576 }
3577
3578 bufptr[2 + n] = '\0';
3579 value->string.text = _cupsStrAlloc((char *)bufptr + 2);
3580 break;
3581
3582 case IPP_TAG_BEGIN_COLLECTION :
3583 /*
3584 * Oh, boy, here comes a collection value, so read it...
3585 */
3586
3587 value->collection = ippNew();
3588
3589 if (n > 0)
3590 {
3591 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3592 _("IPP begCollection value not 0 bytes."), 1);
3593 DEBUG_puts("1ippReadIO: begCollection tag with value length "
3594 "> 0.");
3595 _cupsBufferRelease((char *)buffer);
3596 return (IPP_STATE_ERROR);
3597 }
3598
3599 if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_STATE_ERROR)
3600 {
3601 DEBUG_puts("1ippReadIO: Unable to read collection value.");
3602 _cupsBufferRelease((char *)buffer);
3603 return (IPP_STATE_ERROR);
3604 }
3605 break;
3606
3607 case IPP_TAG_END_COLLECTION :
3608 _cupsBufferRelease((char *)buffer);
3609
3610 if (n > 0)
3611 {
3612 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3613 _("IPP endCollection value not 0 bytes."), 1);
3614 DEBUG_puts("1ippReadIO: endCollection tag with value length "
3615 "> 0.");
3616 return (IPP_STATE_ERROR);
3617 }
3618
3619 DEBUG_puts("1ippReadIO: endCollection tag...");
3620 return (ipp->state = IPP_STATE_DATA);
3621
3622 case IPP_TAG_MEMBERNAME :
3623 /*
3624 * The value the name of the member in the collection, which
3625 * we need to carry over...
3626 */
3627
3628 if (!attr)
3629 {
3630 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3631 _("IPP memberName with no attribute."), 1);
3632 DEBUG_puts("1ippReadIO: Member name without attribute.");
3633 _cupsBufferRelease((char *)buffer);
3634 return (IPP_STATE_ERROR);
3635 }
3636 else if (n == 0)
3637 {
3638 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3639 _("IPP memberName value is empty."), 1);
3640 DEBUG_puts("1ippReadIO: Empty member name value.");
3641 _cupsBufferRelease((char *)buffer);
3642 return (IPP_STATE_ERROR);
3643 }
3644 else if ((*cb)(src, buffer, (size_t)n) < n)
3645 {
3646 DEBUG_puts("1ippReadIO: Unable to read member name value.");
3647 _cupsBufferRelease((char *)buffer);
3648 return (IPP_STATE_ERROR);
3649 }
3650
3651 buffer[n] = '\0';
3652 attr->name = _cupsStrAlloc((char *)buffer);
3653
3654 /*
3655 * Since collection members are encoded differently than
3656 * regular attributes, make sure we don't start with an
3657 * empty value...
3658 */
3659
3660 attr->num_values --;
3661
3662 DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr->name));
3663 break;
3664
3665 case IPP_TAG_STRING :
3666 default : /* Other unsupported values */
3667 if (tag == IPP_TAG_STRING && n > IPP_MAX_LENGTH)
3668 {
3669 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3670 _("IPP octetString length too large."), 1);
3671 DEBUG_printf(("1ippReadIO: bad octetString value length %d.",
3672 n));
3673 _cupsBufferRelease((char *)buffer);
3674 return (IPP_STATE_ERROR);
3675 }
3676
3677 value->unknown.length = n;
3678
3679 if (n > 0)
3680 {
3681 if ((value->unknown.data = malloc((size_t)n)) == NULL)
3682 {
3683 _cupsSetHTTPError(HTTP_STATUS_ERROR);
3684 DEBUG_puts("1ippReadIO: Unable to allocate value");
3685 _cupsBufferRelease((char *)buffer);
3686 return (IPP_STATE_ERROR);
3687 }
3688
3689 if ((*cb)(src, value->unknown.data, (size_t)n) < n)
3690 {
3691 DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
3692 _cupsBufferRelease((char *)buffer);
3693 return (IPP_STATE_ERROR);
3694 }
3695 }
3696 else
3697 value->unknown.data = NULL;
3698 break;
3699 }
3700
3701 /*
3702 * If blocking is disabled, stop here...
3703 */
3704
3705 if (!blocking)
3706 break;
3707 }
3708 break;
3709
3710 case IPP_STATE_DATA :
3711 break;
3712
3713 default :
3714 break; /* anti-compiler-warning-code */
3715 }
3716
3717 DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp->state));
3718 _cupsBufferRelease((char *)buffer);
3719
3720 return (ipp->state);
3721 }
3722
3723
3724 /*
3725 * 'ippSetBoolean()' - Set a boolean 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 ippSetBoolean(ipp_t *ipp, /* I - IPP message */
3740 ipp_attribute_t **attr, /* IO - IPP attribute */
3741 int element, /* I - Value number (0-based) */
3742 int boolvalue)/* I - Boolean 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_BOOLEAN ||
3752 element < 0 || element > (*attr)->num_values)
3753 return (0);
3754
3755 /*
3756 * Set the value and return...
3757 */
3758
3759 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3760 value->boolean = (char)boolvalue;
3761
3762 return (value != NULL);
3763 }
3764
3765
3766 /*
3767 * 'ippSetCollection()' - Set a collection value in 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 element@ parameter specifies which value to set from 0 to
3775 * @code ippGetCount(attr)@.
3776 *
3777 * @since CUPS 1.6/macOS 10.8@
3778 */
3779
3780 int /* O - 1 on success, 0 on failure */
3781 ippSetCollection(
3782 ipp_t *ipp, /* I - IPP message */
3783 ipp_attribute_t **attr, /* IO - IPP attribute */
3784 int element, /* I - Value number (0-based) */
3785 ipp_t *colvalue) /* I - Collection value */
3786 {
3787 _ipp_value_t *value; /* Current value */
3788
3789
3790 /*
3791 * Range check input...
3792 */
3793
3794 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BEGIN_COLLECTION ||
3795 element < 0 || element > (*attr)->num_values || !colvalue)
3796 return (0);
3797
3798 /*
3799 * Set the value and return...
3800 */
3801
3802 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3803 {
3804 if (value->collection)
3805 ippDelete(value->collection);
3806
3807 value->collection = colvalue;
3808 colvalue->use ++;
3809 }
3810
3811 return (value != NULL);
3812 }
3813
3814
3815 /*
3816 * 'ippSetDate()' - Set a dateTime value in an attribute.
3817 *
3818 * The @code ipp@ parameter refers to an IPP message previously created using
3819 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3820 *
3821 * The @code attr@ parameter may be modified as a result of setting the value.
3822 *
3823 * The @code element@ parameter specifies which value to set from 0 to
3824 * @code ippGetCount(attr)@.
3825 *
3826 * @since CUPS 1.6/macOS 10.8@
3827 */
3828
3829 int /* O - 1 on success, 0 on failure */
3830 ippSetDate(ipp_t *ipp, /* I - IPP message */
3831 ipp_attribute_t **attr, /* IO - IPP attribute */
3832 int element, /* I - Value number (0-based) */
3833 const ipp_uchar_t *datevalue)/* I - dateTime value */
3834 {
3835 _ipp_value_t *value; /* Current value */
3836
3837
3838 /*
3839 * Range check input...
3840 */
3841
3842 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_DATE ||
3843 element < 0 || element > (*attr)->num_values || !datevalue)
3844 return (0);
3845
3846 /*
3847 * Set the value and return...
3848 */
3849
3850 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3851 memcpy(value->date, datevalue, sizeof(value->date));
3852
3853 return (value != NULL);
3854 }
3855
3856
3857 /*
3858 * 'ippSetGroupTag()' - Set the group tag of an attribute.
3859 *
3860 * The @code ipp@ parameter refers to an IPP message previously created using
3861 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3862 *
3863 * The @code attr@ parameter may be modified as a result of setting the value.
3864 *
3865 * The @code group@ parameter specifies the IPP attribute group tag: none
3866 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
3867 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
3868 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
3869 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
3870 *
3871 * @since CUPS 1.6/macOS 10.8@
3872 */
3873
3874 int /* O - 1 on success, 0 on failure */
3875 ippSetGroupTag(
3876 ipp_t *ipp, /* I - IPP message */
3877 ipp_attribute_t **attr, /* IO - Attribute */
3878 ipp_tag_t group_tag) /* I - Group tag */
3879 {
3880 /*
3881 * Range check input - group tag must be 0x01 to 0x0F, per RFC 8011...
3882 */
3883
3884 if (!ipp || !attr || !*attr ||
3885 group_tag < IPP_TAG_ZERO || group_tag == IPP_TAG_END ||
3886 group_tag >= IPP_TAG_UNSUPPORTED_VALUE)
3887 return (0);
3888
3889 /*
3890 * Set the group tag and return...
3891 */
3892
3893 (*attr)->group_tag = group_tag;
3894
3895 return (1);
3896 }
3897
3898
3899 /*
3900 * 'ippSetInteger()' - Set an integer or enum value in an attribute.
3901 *
3902 * The @code ipp@ parameter refers to an IPP message previously created using
3903 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3904 *
3905 * The @code attr@ parameter may be modified as a result of setting the value.
3906 *
3907 * The @code element@ parameter specifies which value to set from 0 to
3908 * @code ippGetCount(attr)@.
3909 *
3910 * @since CUPS 1.6/macOS 10.8@
3911 */
3912
3913 int /* O - 1 on success, 0 on failure */
3914 ippSetInteger(ipp_t *ipp, /* I - IPP message */
3915 ipp_attribute_t **attr, /* IO - IPP attribute */
3916 int element, /* I - Value number (0-based) */
3917 int intvalue) /* I - Integer/enum value */
3918 {
3919 _ipp_value_t *value; /* Current value */
3920
3921
3922 /*
3923 * Range check input...
3924 */
3925
3926 if (!ipp || !attr || !*attr ||
3927 ((*attr)->value_tag != IPP_TAG_INTEGER && (*attr)->value_tag != IPP_TAG_ENUM) ||
3928 element < 0 || element > (*attr)->num_values)
3929 return (0);
3930
3931 /*
3932 * Set the value and return...
3933 */
3934
3935 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3936 value->integer = intvalue;
3937
3938 return (value != NULL);
3939 }
3940
3941
3942 /*
3943 * 'ippSetName()' - Set the name of an attribute.
3944 *
3945 * The @code ipp@ parameter refers to an IPP message previously created using
3946 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3947 *
3948 * The @code attr@ parameter may be modified as a result of setting the value.
3949 *
3950 * @since CUPS 1.6/macOS 10.8@
3951 */
3952
3953 int /* O - 1 on success, 0 on failure */
3954 ippSetName(ipp_t *ipp, /* I - IPP message */
3955 ipp_attribute_t **attr, /* IO - IPP attribute */
3956 const char *name) /* I - Attribute name */
3957 {
3958 char *temp; /* Temporary name value */
3959
3960
3961 /*
3962 * Range check input...
3963 */
3964
3965 if (!ipp || !attr || !*attr)
3966 return (0);
3967
3968 /*
3969 * Set the value and return...
3970 */
3971
3972 if ((temp = _cupsStrAlloc(name)) != NULL)
3973 {
3974 if ((*attr)->name)
3975 _cupsStrFree((*attr)->name);
3976
3977 (*attr)->name = temp;
3978 }
3979
3980 return (temp != NULL);
3981 }
3982
3983
3984 /*
3985 * 'ippSetOctetString()' - Set an octetString value in an IPP attribute.
3986 *
3987 * The @code ipp@ parameter refers to an IPP message previously created using
3988 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3989 *
3990 * The @code attr@ parameter may be modified as a result of setting the value.
3991 *
3992 * The @code element@ parameter specifies which value to set from 0 to
3993 * @code ippGetCount(attr)@.
3994 *
3995 * @since CUPS 1.7/macOS 10.9@
3996 */
3997
3998 int /* O - 1 on success, 0 on failure */
3999 ippSetOctetString(
4000 ipp_t *ipp, /* I - IPP message */
4001 ipp_attribute_t **attr, /* IO - IPP attribute */
4002 int element, /* I - Value number (0-based) */
4003 const void *data, /* I - Pointer to octetString data */
4004 int datalen) /* I - Length of octetString data */
4005 {
4006 _ipp_value_t *value; /* Current value */
4007
4008
4009 /*
4010 * Range check input...
4011 */
4012
4013 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_STRING ||
4014 element < 0 || element > (*attr)->num_values ||
4015 datalen < 0 || datalen > IPP_MAX_LENGTH)
4016 return (0);
4017
4018 /*
4019 * Set the value and return...
4020 */
4021
4022 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4023 {
4024 if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST)
4025 {
4026 /*
4027 * Just copy the pointer...
4028 */
4029
4030 value->unknown.data = (void *)data;
4031 value->unknown.length = datalen;
4032 }
4033 else
4034 {
4035 /*
4036 * Copy the data...
4037 */
4038
4039 if (value->unknown.data)
4040 {
4041 /*
4042 * Free previous data...
4043 */
4044
4045 free(value->unknown.data);
4046
4047 value->unknown.data = NULL;
4048 value->unknown.length = 0;
4049 }
4050
4051 if (datalen > 0)
4052 {
4053 void *temp; /* Temporary data pointer */
4054
4055 if ((temp = malloc((size_t)datalen)) != NULL)
4056 {
4057 memcpy(temp, data, (size_t)datalen);
4058
4059 value->unknown.data = temp;
4060 value->unknown.length = datalen;
4061 }
4062 else
4063 return (0);
4064 }
4065 }
4066 }
4067
4068 return (value != NULL);
4069 }
4070
4071
4072 /*
4073 * 'ippSetOperation()' - Set the operation ID in an IPP request message.
4074 *
4075 * The @code ipp@ parameter refers to an IPP message previously created using
4076 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4077 *
4078 * @since CUPS 1.6/macOS 10.8@
4079 */
4080
4081 int /* O - 1 on success, 0 on failure */
4082 ippSetOperation(ipp_t *ipp, /* I - IPP request message */
4083 ipp_op_t op) /* I - Operation ID */
4084 {
4085 /*
4086 * Range check input...
4087 */
4088
4089 if (!ipp)
4090 return (0);
4091
4092 /*
4093 * Set the operation and return...
4094 */
4095
4096 ipp->request.op.operation_id = op;
4097
4098 return (1);
4099 }
4100
4101
4102 /*
4103 * 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
4104 *
4105 * The @code ipp@ parameter refers to an IPP message previously created using
4106 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4107 *
4108 * The @code attr@ parameter may be modified as a result of setting the value.
4109 *
4110 * The @code element@ parameter specifies which value to set from 0 to
4111 * @code ippGetCount(attr)@.
4112 *
4113 * @since CUPS 1.6/macOS 10.8@
4114 */
4115
4116 int /* O - 1 on success, 0 on failure */
4117 ippSetRange(ipp_t *ipp, /* I - IPP message */
4118 ipp_attribute_t **attr, /* IO - IPP attribute */
4119 int element, /* I - Value number (0-based) */
4120 int lowervalue, /* I - Lower bound for range */
4121 int uppervalue) /* I - Upper bound for range */
4122 {
4123 _ipp_value_t *value; /* Current value */
4124
4125
4126 /*
4127 * Range check input...
4128 */
4129
4130 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_RANGE ||
4131 element < 0 || element > (*attr)->num_values || lowervalue > uppervalue)
4132 return (0);
4133
4134 /*
4135 * Set the value and return...
4136 */
4137
4138 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4139 {
4140 value->range.lower = lowervalue;
4141 value->range.upper = uppervalue;
4142 }
4143
4144 return (value != NULL);
4145 }
4146
4147
4148 /*
4149 * 'ippSetRequestId()' - Set the request ID in an IPP message.
4150 *
4151 * The @code ipp@ parameter refers to an IPP message previously created using
4152 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4153 *
4154 * The @code request_id@ parameter must be greater than 0.
4155 *
4156 * @since CUPS 1.6/macOS 10.8@
4157 */
4158
4159 int /* O - 1 on success, 0 on failure */
4160 ippSetRequestId(ipp_t *ipp, /* I - IPP message */
4161 int request_id) /* I - Request ID */
4162 {
4163 /*
4164 * Range check input; not checking request_id values since ipptool wants to send
4165 * invalid values for conformance testing and a bad request_id does not affect the
4166 * encoding of a message...
4167 */
4168
4169 if (!ipp)
4170 return (0);
4171
4172 /*
4173 * Set the request ID and return...
4174 */
4175
4176 ipp->request.any.request_id = request_id;
4177
4178 return (1);
4179 }
4180
4181
4182 /*
4183 * 'ippSetResolution()' - Set a resolution value in an attribute.
4184 *
4185 * The @code ipp@ parameter refers to an IPP message previously created using
4186 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4187 *
4188 * The @code attr@ parameter may be modified as a result of setting the value.
4189 *
4190 * The @code element@ parameter specifies which value to set from 0 to
4191 * @code ippGetCount(attr)@.
4192 *
4193 * @since CUPS 1.6/macOS 10.8@
4194 */
4195
4196 int /* O - 1 on success, 0 on failure */
4197 ippSetResolution(
4198 ipp_t *ipp, /* I - IPP message */
4199 ipp_attribute_t **attr, /* IO - IPP attribute */
4200 int element, /* I - Value number (0-based) */
4201 ipp_res_t unitsvalue, /* I - Resolution units */
4202 int xresvalue, /* I - Horizontal/cross feed resolution */
4203 int yresvalue) /* I - Vertical/feed resolution */
4204 {
4205 _ipp_value_t *value; /* Current value */
4206
4207
4208 /*
4209 * Range check input...
4210 */
4211
4212 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_RESOLUTION ||
4213 element < 0 || element > (*attr)->num_values || xresvalue <= 0 || yresvalue <= 0 ||
4214 unitsvalue < IPP_RES_PER_INCH || unitsvalue > IPP_RES_PER_CM)
4215 return (0);
4216
4217 /*
4218 * Set the value and return...
4219 */
4220
4221 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4222 {
4223 value->resolution.units = unitsvalue;
4224 value->resolution.xres = xresvalue;
4225 value->resolution.yres = yresvalue;
4226 }
4227
4228 return (value != NULL);
4229 }
4230
4231
4232 /*
4233 * 'ippSetState()' - Set the current state of the IPP message.
4234 *
4235 * @since CUPS 1.6/macOS 10.8@
4236 */
4237
4238 int /* O - 1 on success, 0 on failure */
4239 ippSetState(ipp_t *ipp, /* I - IPP message */
4240 ipp_state_t state) /* I - IPP state value */
4241 {
4242 /*
4243 * Range check input...
4244 */
4245
4246 if (!ipp)
4247 return (0);
4248
4249 /*
4250 * Set the state and return...
4251 */
4252
4253 ipp->state = state;
4254 ipp->current = NULL;
4255
4256 return (1);
4257 }
4258
4259
4260 /*
4261 * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
4262 *
4263 * The @code ipp@ parameter refers to an IPP message previously created using
4264 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4265 *
4266 * @since CUPS 1.6/macOS 10.8@
4267 */
4268
4269 int /* O - 1 on success, 0 on failure */
4270 ippSetStatusCode(ipp_t *ipp, /* I - IPP response or event message */
4271 ipp_status_t status) /* I - Status code */
4272 {
4273 /*
4274 * Range check input...
4275 */
4276
4277 if (!ipp)
4278 return (0);
4279
4280 /*
4281 * Set the status code and return...
4282 */
4283
4284 ipp->request.status.status_code = status;
4285
4286 return (1);
4287 }
4288
4289
4290 /*
4291 * 'ippSetString()' - Set a string value in an attribute.
4292 *
4293 * The @code ipp@ parameter refers to an IPP message previously created using
4294 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4295 *
4296 * The @code attr@ parameter may be modified as a result of setting the value.
4297 *
4298 * The @code element@ parameter specifies which value to set from 0 to
4299 * @code ippGetCount(attr)@.
4300 *
4301 * @since CUPS 1.6/macOS 10.8@
4302 */
4303
4304 int /* O - 1 on success, 0 on failure */
4305 ippSetString(ipp_t *ipp, /* I - IPP message */
4306 ipp_attribute_t **attr, /* IO - IPP attribute */
4307 int element, /* I - Value number (0-based) */
4308 const char *strvalue) /* I - String value */
4309 {
4310 char *temp; /* Temporary string */
4311 _ipp_value_t *value; /* Current value */
4312 ipp_tag_t value_tag; /* Value tag */
4313
4314
4315 /*
4316 * Range check input...
4317 */
4318
4319 if (attr && *attr)
4320 value_tag = (*attr)->value_tag & IPP_TAG_CUPS_MASK;
4321 else
4322 value_tag = IPP_TAG_ZERO;
4323
4324 if (!ipp || !attr || !*attr ||
4325 (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG &&
4326 value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE ||
4327 !strvalue)
4328 return (0);
4329
4330 /*
4331 * Set the value and return...
4332 */
4333
4334 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4335 {
4336 if (element > 0)
4337 value->string.language = (*attr)->values[0].string.language;
4338
4339 if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST)
4340 value->string.text = (char *)strvalue;
4341 else if ((temp = _cupsStrAlloc(strvalue)) != NULL)
4342 {
4343 if (value->string.text)
4344 _cupsStrFree(value->string.text);
4345
4346 value->string.text = temp;
4347 }
4348 else
4349 return (0);
4350 }
4351
4352 return (value != NULL);
4353 }
4354
4355
4356 /*
4357 * 'ippSetStringf()' - Set a formatted string value of an attribute.
4358 *
4359 * The @code ipp@ parameter refers to an IPP message previously created using
4360 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4361 *
4362 * The @code attr@ parameter may be modified as a result of setting the value.
4363 *
4364 * The @code element@ parameter specifies which value to set from 0 to
4365 * @code ippGetCount(attr)@.
4366 *
4367 * The @code format@ parameter uses formatting characters compatible with the
4368 * printf family of standard functions. Additional arguments follow it as
4369 * needed. The formatted string is truncated as needed to the maximum length of
4370 * the corresponding value type.
4371 *
4372 * @since CUPS 1.7/macOS 10.9@
4373 */
4374
4375 int /* O - 1 on success, 0 on failure */
4376 ippSetStringf(ipp_t *ipp, /* I - IPP message */
4377 ipp_attribute_t **attr, /* IO - IPP attribute */
4378 int element, /* I - Value number (0-based) */
4379 const char *format, /* I - Printf-style format string */
4380 ...) /* I - Additional arguments as needed */
4381 {
4382 int ret; /* Return value */
4383 va_list ap; /* Pointer to additional arguments */
4384
4385
4386 va_start(ap, format);
4387 ret = ippSetStringfv(ipp, attr, element, format, ap);
4388 va_end(ap);
4389
4390 return (ret);
4391 }
4392
4393
4394 /*
4395 * 'ippSetStringf()' - Set a formatted string value of an attribute.
4396 *
4397 * The @code ipp@ parameter refers to an IPP message previously created using
4398 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4399 *
4400 * The @code attr@ parameter may be modified as a result of setting the value.
4401 *
4402 * The @code element@ parameter specifies which value to set from 0 to
4403 * @code ippGetCount(attr)@.
4404 *
4405 * The @code format@ parameter uses formatting characters compatible with the
4406 * printf family of standard functions. Additional arguments follow it as
4407 * needed. The formatted string is truncated as needed to the maximum length of
4408 * the corresponding value type.
4409 *
4410 * @since CUPS 1.7/macOS 10.9@
4411 */
4412
4413 int /* O - 1 on success, 0 on failure */
4414 ippSetStringfv(ipp_t *ipp, /* I - IPP message */
4415 ipp_attribute_t **attr, /* IO - IPP attribute */
4416 int element, /* I - Value number (0-based) */
4417 const char *format, /* I - Printf-style format string */
4418 va_list ap) /* I - Pointer to additional arguments */
4419 {
4420 ipp_tag_t value_tag; /* Value tag */
4421 char buffer[IPP_MAX_TEXT + 4];
4422 /* Formatted text string */
4423 ssize_t bytes, /* Length of formatted value */
4424 max_bytes; /* Maximum number of bytes for value */
4425
4426
4427 /*
4428 * Range check input...
4429 */
4430
4431 if (attr && *attr)
4432 value_tag = (*attr)->value_tag & IPP_TAG_CUPS_MASK;
4433 else
4434 value_tag = IPP_TAG_ZERO;
4435
4436 if (!ipp || !attr || !*attr ||
4437 (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG &&
4438 value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE ||
4439 !format)
4440 return (0);
4441
4442 /*
4443 * Format the string...
4444 */
4445
4446 if (!strcmp(format, "%s"))
4447 {
4448 /*
4449 * Optimize the simple case...
4450 */
4451
4452 const char *s = va_arg(ap, char *);
4453
4454 if (!s)
4455 s = "(null)";
4456
4457 bytes = (ssize_t)strlen(s);
4458 strlcpy(buffer, s, sizeof(buffer));
4459 }
4460 else
4461 {
4462 /*
4463 * Do a full formatting of the message...
4464 */
4465
4466 if ((bytes = vsnprintf(buffer, sizeof(buffer), format, ap)) < 0)
4467 return (0);
4468 }
4469
4470 /*
4471 * Limit the length of the string...
4472 */
4473
4474 switch (value_tag)
4475 {
4476 default :
4477 case IPP_TAG_TEXT :
4478 case IPP_TAG_TEXTLANG :
4479 max_bytes = IPP_MAX_TEXT;
4480 break;
4481
4482 case IPP_TAG_NAME :
4483 case IPP_TAG_NAMELANG :
4484 max_bytes = IPP_MAX_NAME;
4485 break;
4486
4487 case IPP_TAG_CHARSET :
4488 max_bytes = IPP_MAX_CHARSET;
4489 break;
4490
4491 case IPP_TAG_KEYWORD :
4492 max_bytes = IPP_MAX_KEYWORD;
4493 break;
4494
4495 case IPP_TAG_LANGUAGE :
4496 max_bytes = IPP_MAX_LANGUAGE;
4497 break;
4498
4499 case IPP_TAG_MIMETYPE :
4500 max_bytes = IPP_MAX_MIMETYPE;
4501 break;
4502
4503 case IPP_TAG_URI :
4504 max_bytes = IPP_MAX_URI;
4505 break;
4506
4507 case IPP_TAG_URISCHEME :
4508 max_bytes = IPP_MAX_URISCHEME;
4509 break;
4510 }
4511
4512 if (bytes >= max_bytes)
4513 {
4514 char *bufmax, /* Buffer at max_bytes */
4515 *bufptr; /* Pointer into buffer */
4516
4517 bufptr = buffer + strlen(buffer) - 1;
4518 bufmax = buffer + max_bytes - 1;
4519
4520 while (bufptr > bufmax)
4521 {
4522 if (*bufptr & 0x80)
4523 {
4524 while ((*bufptr & 0xc0) == 0x80 && bufptr > buffer)
4525 bufptr --;
4526 }
4527
4528 bufptr --;
4529 }
4530
4531 *bufptr = '\0';
4532 }
4533
4534 /*
4535 * Set the formatted string and return...
4536 */
4537
4538 return (ippSetString(ipp, attr, element, buffer));
4539 }
4540
4541
4542 /*
4543 * 'ippSetValueTag()' - Set the value tag of an attribute.
4544 *
4545 * The @code ipp@ parameter refers to an IPP message previously created using
4546 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4547 *
4548 * The @code attr@ parameter may be modified as a result of setting the value.
4549 *
4550 * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger
4551 * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name
4552 * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text
4553 * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage
4554 * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various
4555 * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes
4556 * will be rejected.
4557 *
4558 * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language
4559 * code in the "attributes-natural-language" attribute or, if not present, the language
4560 * code for the current locale.
4561 *
4562 * @since CUPS 1.6/macOS 10.8@
4563 */
4564
4565 int /* O - 1 on success, 0 on failure */
4566 ippSetValueTag(
4567 ipp_t *ipp, /* I - IPP message */
4568 ipp_attribute_t **attr, /* IO - IPP attribute */
4569 ipp_tag_t value_tag) /* I - Value tag */
4570 {
4571 int i; /* Looping var */
4572 _ipp_value_t *value; /* Current value */
4573 int integer; /* Current integer value */
4574 cups_lang_t *language; /* Current language */
4575 char code[32]; /* Language code */
4576 ipp_tag_t temp_tag; /* Temporary value tag */
4577
4578
4579 /*
4580 * Range check input...
4581 */
4582
4583 if (!ipp || !attr || !*attr)
4584 return (0);
4585
4586 /*
4587 * If there is no change, return immediately...
4588 */
4589
4590 if (value_tag == (*attr)->value_tag)
4591 return (1);
4592
4593 /*
4594 * Otherwise implement changes as needed...
4595 */
4596
4597 temp_tag = (ipp_tag_t)((int)((*attr)->value_tag) & IPP_TAG_CUPS_MASK);
4598
4599 switch (value_tag)
4600 {
4601 case IPP_TAG_UNSUPPORTED_VALUE :
4602 case IPP_TAG_DEFAULT :
4603 case IPP_TAG_UNKNOWN :
4604 case IPP_TAG_NOVALUE :
4605 case IPP_TAG_NOTSETTABLE :
4606 case IPP_TAG_DELETEATTR :
4607 case IPP_TAG_ADMINDEFINE :
4608 /*
4609 * Free any existing values...
4610 */
4611
4612 if ((*attr)->num_values > 0)
4613 ipp_free_values(*attr, 0, (*attr)->num_values);
4614
4615 /*
4616 * Set out-of-band value...
4617 */
4618
4619 (*attr)->value_tag = value_tag;
4620 break;
4621
4622 case IPP_TAG_RANGE :
4623 if (temp_tag != IPP_TAG_INTEGER)
4624 return (0);
4625
4626 for (i = (*attr)->num_values, value = (*attr)->values;
4627 i > 0;
4628 i --, value ++)
4629 {
4630 integer = value->integer;
4631 value->range.lower = value->range.upper = integer;
4632 }
4633
4634 (*attr)->value_tag = IPP_TAG_RANGE;
4635 break;
4636
4637 case IPP_TAG_NAME :
4638 if (temp_tag != IPP_TAG_KEYWORD && temp_tag != IPP_TAG_URI &&
4639 temp_tag != IPP_TAG_URISCHEME && temp_tag != IPP_TAG_LANGUAGE &&
4640 temp_tag != IPP_TAG_MIMETYPE)
4641 return (0);
4642
4643 (*attr)->value_tag = (ipp_tag_t)(IPP_TAG_NAME | ((*attr)->value_tag & IPP_TAG_CUPS_CONST));
4644 break;
4645
4646 case IPP_TAG_NAMELANG :
4647 case IPP_TAG_TEXTLANG :
4648 if (value_tag == IPP_TAG_NAMELANG &&
4649 (temp_tag != IPP_TAG_NAME && temp_tag != IPP_TAG_KEYWORD &&
4650 temp_tag != IPP_TAG_URI && temp_tag != IPP_TAG_URISCHEME &&
4651 temp_tag != IPP_TAG_LANGUAGE && temp_tag != IPP_TAG_MIMETYPE))
4652 return (0);
4653
4654 if (value_tag == IPP_TAG_TEXTLANG && temp_tag != IPP_TAG_TEXT)
4655 return (0);
4656
4657 if (ipp->attrs && ipp->attrs->next && ipp->attrs->next->name &&
4658 !strcmp(ipp->attrs->next->name, "attributes-natural-language"))
4659 {
4660 /*
4661 * Use the language code from the IPP message...
4662 */
4663
4664 (*attr)->values[0].string.language =
4665 _cupsStrAlloc(ipp->attrs->next->values[0].string.text);
4666 }
4667 else
4668 {
4669 /*
4670 * Otherwise, use the language code corresponding to the locale...
4671 */
4672
4673 language = cupsLangDefault();
4674 (*attr)->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language->language,
4675 code,
4676 sizeof(code)));
4677 }
4678
4679 for (i = (*attr)->num_values - 1, value = (*attr)->values + 1;
4680 i > 0;
4681 i --, value ++)
4682 value->string.language = (*attr)->values[0].string.language;
4683
4684 if ((int)(*attr)->value_tag & IPP_TAG_CUPS_CONST)
4685 {
4686 /*
4687 * Make copies of all values...
4688 */
4689
4690 for (i = (*attr)->num_values, value = (*attr)->values;
4691 i > 0;
4692 i --, value ++)
4693 value->string.text = _cupsStrAlloc(value->string.text);
4694 }
4695
4696 (*attr)->value_tag = IPP_TAG_NAMELANG;
4697 break;
4698
4699 case IPP_TAG_KEYWORD :
4700 if (temp_tag == IPP_TAG_NAME || temp_tag == IPP_TAG_NAMELANG)
4701 break; /* Silently "allow" name -> keyword */
4702
4703 default :
4704 return (0);
4705 }
4706
4707 return (1);
4708 }
4709
4710
4711 /*
4712 * 'ippSetVersion()' - Set the version number in an IPP message.
4713 *
4714 * The @code ipp@ parameter refers to an IPP message previously created using
4715 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4716 *
4717 * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
4718 *
4719 * @since CUPS 1.6/macOS 10.8@
4720 */
4721
4722 int /* O - 1 on success, 0 on failure */
4723 ippSetVersion(ipp_t *ipp, /* I - IPP message */
4724 int major, /* I - Major version number (major.minor) */
4725 int minor) /* I - Minor version number (major.minor) */
4726 {
4727 /*
4728 * Range check input...
4729 */
4730
4731 if (!ipp || major < 0 || minor < 0)
4732 return (0);
4733
4734 /*
4735 * Set the version number...
4736 */
4737
4738 ipp->request.any.version[0] = (ipp_uchar_t)major;
4739 ipp->request.any.version[1] = (ipp_uchar_t)minor;
4740
4741 return (1);
4742 }
4743
4744
4745 /*
4746 * 'ippTimeToDate()' - Convert from time in seconds to RFC 2579 format.
4747 */
4748
4749 const ipp_uchar_t * /* O - RFC-2579 date/time data */
4750 ippTimeToDate(time_t t) /* I - Time in seconds */
4751 {
4752 struct tm *unixdate; /* UNIX unixdate/time info */
4753 ipp_uchar_t *date = _cupsGlobals()->ipp_date;
4754 /* RFC-2579 date/time data */
4755
4756
4757 /*
4758 * RFC-2579 date/time format is:
4759 *
4760 * Byte(s) Description
4761 * ------- -----------
4762 * 0-1 Year (0 to 65535)
4763 * 2 Month (1 to 12)
4764 * 3 Day (1 to 31)
4765 * 4 Hours (0 to 23)
4766 * 5 Minutes (0 to 59)
4767 * 6 Seconds (0 to 60, 60 = "leap second")
4768 * 7 Deciseconds (0 to 9)
4769 * 8 +/- UTC
4770 * 9 UTC hours (0 to 11)
4771 * 10 UTC minutes (0 to 59)
4772 */
4773
4774 unixdate = gmtime(&t);
4775 unixdate->tm_year += 1900;
4776
4777 date[0] = (ipp_uchar_t)(unixdate->tm_year >> 8);
4778 date[1] = (ipp_uchar_t)(unixdate->tm_year);
4779 date[2] = (ipp_uchar_t)(unixdate->tm_mon + 1);
4780 date[3] = (ipp_uchar_t)unixdate->tm_mday;
4781 date[4] = (ipp_uchar_t)unixdate->tm_hour;
4782 date[5] = (ipp_uchar_t)unixdate->tm_min;
4783 date[6] = (ipp_uchar_t)unixdate->tm_sec;
4784 date[7] = 0;
4785 date[8] = '+';
4786 date[9] = 0;
4787 date[10] = 0;
4788
4789 return (date);
4790 }
4791
4792
4793 /*
4794 * 'ippValidateAttribute()' - Validate the contents of an attribute.
4795 *
4796 * This function validates the contents of an attribute based on the name and
4797 * value tag. 1 is returned if the attribute is valid, 0 otherwise. On
4798 * failure, @link cupsLastErrorString@ is set to a human-readable message.
4799 *
4800 * @since CUPS 1.7/macOS 10.9@
4801 */
4802
4803 int /* O - 1 if valid, 0 otherwise */
4804 ippValidateAttribute(
4805 ipp_attribute_t *attr) /* I - Attribute */
4806 {
4807 int i; /* Looping var */
4808 char scheme[64], /* Scheme from URI */
4809 userpass[256], /* Username/password from URI */
4810 hostname[256], /* Hostname from URI */
4811 resource[1024]; /* Resource from URI */
4812 int port, /* Port number from URI */
4813 uri_status; /* URI separation status */
4814 const char *ptr; /* Pointer into string */
4815 ipp_attribute_t *colattr; /* Collection attribute */
4816 regex_t re; /* Regular expression */
4817 ipp_uchar_t *date; /* Current date value */
4818
4819
4820 /*
4821 * Skip separators.
4822 */
4823
4824 if (!attr->name)
4825 return (1);
4826
4827 /*
4828 * Validate the attribute name.
4829 */
4830
4831 for (ptr = attr->name; *ptr; ptr ++)
4832 if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' && *ptr != '_')
4833 break;
4834
4835 if (*ptr || ptr == attr->name)
4836 {
4837 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad attribute name - invalid character (RFC 8011 section 5.1.4)."), attr->name);
4838 return (0);
4839 }
4840
4841 if ((ptr - attr->name) > 255)
4842 {
4843 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));
4844 return (0);
4845 }
4846
4847 switch (attr->value_tag)
4848 {
4849 case IPP_TAG_INTEGER :
4850 break;
4851
4852 case IPP_TAG_BOOLEAN :
4853 for (i = 0; i < attr->num_values; i ++)
4854 {
4855 if (attr->values[i].boolean != 0 &&
4856 attr->values[i].boolean != 1)
4857 {
4858 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);
4859 return (0);
4860 }
4861 }
4862 break;
4863
4864 case IPP_TAG_ENUM :
4865 for (i = 0; i < attr->num_values; i ++)
4866 {
4867 if (attr->values[i].integer < 1)
4868 {
4869 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);
4870 return (0);
4871 }
4872 }
4873 break;
4874
4875 case IPP_TAG_STRING :
4876 for (i = 0; i < attr->num_values; i ++)
4877 {
4878 if (attr->values[i].unknown.length > IPP_MAX_OCTETSTRING)
4879 {
4880 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);
4881 return (0);
4882 }
4883 }
4884 break;
4885
4886 case IPP_TAG_DATE :
4887 for (i = 0; i < attr->num_values; i ++)
4888 {
4889 date = attr->values[i].date;
4890
4891 if (date[2] < 1 || date[2] > 12)
4892 {
4893 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime month %u (RFC 8011 section 5.1.15)."), attr->name, date[2]);
4894 return (0);
4895 }
4896
4897 if (date[3] < 1 || date[3] > 31)
4898 {
4899 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime day %u (RFC 8011 section 5.1.15)."), attr->name, date[3]);
4900 return (0);
4901 }
4902
4903 if (date[4] > 23)
4904 {
4905 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime hours %u (RFC 8011 section 5.1.15)."), attr->name, date[4]);
4906 return (0);
4907 }
4908
4909 if (date[5] > 59)
4910 {
4911 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime minutes %u (RFC 8011 section 5.1.15)."), attr->name, date[5]);
4912 return (0);
4913 }
4914
4915 if (date[6] > 60)
4916 {
4917 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime seconds %u (RFC 8011 section 5.1.15)."), attr->name, date[6]);
4918 return (0);
4919 }
4920
4921 if (date[7] > 9)
4922 {
4923 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime deciseconds %u (RFC 8011 section 5.1.15)."), attr->name, date[7]);
4924 return (0);
4925 }
4926
4927 if (date[8] != '-' && date[8] != '+')
4928 {
4929 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime UTC sign '%c' (RFC 8011 section 5.1.15)."), attr->name, date[8]);
4930 return (0);
4931 }
4932
4933 if (date[9] > 11)
4934 {
4935 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime UTC hours %u (RFC 8011 section 5.1.15)."), attr->name, date[9]);
4936 return (0);
4937 }
4938
4939 if (date[10] > 59)
4940 {
4941 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime UTC minutes %u (RFC 8011 section 5.1.15)."), attr->name, date[10]);
4942 return (0);
4943 }
4944 }
4945 break;
4946
4947 case IPP_TAG_RESOLUTION :
4948 for (i = 0; i < attr->num_values; i ++)
4949 {
4950 if (attr->values[i].resolution.xres <= 0)
4951 {
4952 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");
4953 return (0);
4954 }
4955
4956 if (attr->values[i].resolution.yres <= 0)
4957 {
4958 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");
4959 return (0);
4960 }
4961
4962 if (attr->values[i].resolution.units != IPP_RES_PER_INCH && attr->values[i].resolution.units != IPP_RES_PER_CM)
4963 {
4964 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");
4965 return (0);
4966 }
4967 }
4968 break;
4969
4970 case IPP_TAG_RANGE :
4971 for (i = 0; i < attr->num_values; i ++)
4972 {
4973 if (attr->values[i].range.lower > attr->values[i].range.upper)
4974 {
4975 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);
4976 return (0);
4977 }
4978 }
4979 break;
4980
4981 case IPP_TAG_BEGIN_COLLECTION :
4982 for (i = 0; i < attr->num_values; i ++)
4983 {
4984 for (colattr = attr->values[i].collection->attrs;
4985 colattr;
4986 colattr = colattr->next)
4987 {
4988 if (!ippValidateAttribute(colattr))
4989 return (0);
4990 }
4991 }
4992 break;
4993
4994 case IPP_TAG_TEXT :
4995 case IPP_TAG_TEXTLANG :
4996 for (i = 0; i < attr->num_values; i ++)
4997 {
4998 for (ptr = attr->values[i].string.text; *ptr; ptr ++)
4999 {
5000 if ((*ptr & 0xe0) == 0xc0)
5001 {
5002 ptr ++;
5003 if ((*ptr & 0xc0) != 0x80)
5004 break;
5005 }
5006 else if ((*ptr & 0xf0) == 0xe0)
5007 {
5008 ptr ++;
5009 if ((*ptr & 0xc0) != 0x80)
5010 break;
5011 ptr ++;
5012 if ((*ptr & 0xc0) != 0x80)
5013 break;
5014 }
5015 else if ((*ptr & 0xf8) == 0xf0)
5016 {
5017 ptr ++;
5018 if ((*ptr & 0xc0) != 0x80)
5019 break;
5020 ptr ++;
5021 if ((*ptr & 0xc0) != 0x80)
5022 break;
5023 ptr ++;
5024 if ((*ptr & 0xc0) != 0x80)
5025 break;
5026 }
5027 else if (*ptr & 0x80)
5028 break;
5029 else if ((*ptr < ' ' && *ptr != '\n' && *ptr != '\r' && *ptr != '\t') || *ptr == 0x7f)
5030 break;
5031 }
5032
5033 if (*ptr)
5034 {
5035 if (*ptr < ' ' || *ptr == 0x7f)
5036 {
5037 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);
5038 return (0);
5039 }
5040 else
5041 {
5042 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);
5043 return (0);
5044 }
5045 }
5046
5047 if ((ptr - attr->values[i].string.text) > (IPP_MAX_TEXT - 1))
5048 {
5049 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));
5050 return (0);
5051 }
5052 }
5053 break;
5054
5055 case IPP_TAG_NAME :
5056 case IPP_TAG_NAMELANG :
5057 for (i = 0; i < attr->num_values; i ++)
5058 {
5059 for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5060 {
5061 if ((*ptr & 0xe0) == 0xc0)
5062 {
5063 ptr ++;
5064 if ((*ptr & 0xc0) != 0x80)
5065 break;
5066 }
5067 else if ((*ptr & 0xf0) == 0xe0)
5068 {
5069 ptr ++;
5070 if ((*ptr & 0xc0) != 0x80)
5071 break;
5072 ptr ++;
5073 if ((*ptr & 0xc0) != 0x80)
5074 break;
5075 }
5076 else if ((*ptr & 0xf8) == 0xf0)
5077 {
5078 ptr ++;
5079 if ((*ptr & 0xc0) != 0x80)
5080 break;
5081 ptr ++;
5082 if ((*ptr & 0xc0) != 0x80)
5083 break;
5084 ptr ++;
5085 if ((*ptr & 0xc0) != 0x80)
5086 break;
5087 }
5088 else if (*ptr & 0x80)
5089 break;
5090 else if (*ptr < ' ' || *ptr == 0x7f)
5091 break;
5092 }
5093
5094 if (*ptr)
5095 {
5096 if (*ptr < ' ' || *ptr == 0x7f)
5097 {
5098 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);
5099 return (0);
5100 }
5101 else
5102 {
5103 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);
5104 return (0);
5105 }
5106 }
5107
5108 if ((ptr - attr->values[i].string.text) > (IPP_MAX_NAME - 1))
5109 {
5110 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));
5111 return (0);
5112 }
5113 }
5114 break;
5115
5116 case IPP_TAG_KEYWORD :
5117 for (i = 0; i < attr->num_values; i ++)
5118 {
5119 for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5120 {
5121 if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' &&
5122 *ptr != '_')
5123 break;
5124 }
5125
5126 if (*ptr || ptr == attr->values[i].string.text)
5127 {
5128 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);
5129 return (0);
5130 }
5131
5132 if ((ptr - attr->values[i].string.text) > (IPP_MAX_KEYWORD - 1))
5133 {
5134 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));
5135 return (0);
5136 }
5137 }
5138 break;
5139
5140 case IPP_TAG_URI :
5141 for (i = 0; i < attr->num_values; i ++)
5142 {
5143 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));
5144
5145 if (uri_status < HTTP_URI_STATUS_OK)
5146 {
5147 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));
5148 return (0);
5149 }
5150
5151 if (strlen(attr->values[i].string.text) > (IPP_MAX_URI - 1))
5152 {
5153 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));
5154 }
5155 }
5156 break;
5157
5158 case IPP_TAG_URISCHEME :
5159 for (i = 0; i < attr->num_values; i ++)
5160 {
5161 ptr = attr->values[i].string.text;
5162 if (islower(*ptr & 255))
5163 {
5164 for (ptr ++; *ptr; ptr ++)
5165 {
5166 if (!islower(*ptr & 255) && !isdigit(*ptr & 255) &&
5167 *ptr != '+' && *ptr != '-' && *ptr != '.')
5168 break;
5169 }
5170 }
5171
5172 if (*ptr || ptr == attr->values[i].string.text)
5173 {
5174 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);
5175 return (0);
5176 }
5177
5178 if ((ptr - attr->values[i].string.text) > (IPP_MAX_URISCHEME - 1))
5179 {
5180 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));
5181 return (0);
5182 }
5183 }
5184 break;
5185
5186 case IPP_TAG_CHARSET :
5187 for (i = 0; i < attr->num_values; i ++)
5188 {
5189 for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5190 {
5191 if (!isprint(*ptr & 255) || isupper(*ptr & 255) ||
5192 isspace(*ptr & 255))
5193 break;
5194 }
5195
5196 if (*ptr || ptr == attr->values[i].string.text)
5197 {
5198 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);
5199 return (0);
5200 }
5201
5202 if ((ptr - attr->values[i].string.text) > (IPP_MAX_CHARSET - 1))
5203 {
5204 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));
5205 return (0);
5206 }
5207 }
5208 break;
5209
5210 case IPP_TAG_LANGUAGE :
5211 /*
5212 * The following regular expression is derived from the ABNF for
5213 * language tags in RFC 4646. All I can say is that this is the
5214 * easiest way to check the values...
5215 */
5216
5217 if ((i = regcomp(&re,
5218 "^("
5219 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
5220 /* language */
5221 "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */
5222 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */
5223 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */
5224 "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */
5225 "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */
5226 "|"
5227 "x(-[a-z0-9]{1,8})+" /* privateuse */
5228 "|"
5229 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
5230 ")$",
5231 REG_NOSUB | REG_EXTENDED)) != 0)
5232 {
5233 char temp[256]; /* Temporary error string */
5234
5235 regerror(i, &re, temp, sizeof(temp));
5236 ipp_set_error(IPP_STATUS_ERROR_INTERNAL, _("Unable to compile naturalLanguage regular expression: %s."), temp);
5237 return (0);
5238 }
5239
5240 for (i = 0; i < attr->num_values; i ++)
5241 {
5242 if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
5243 {
5244 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);
5245 regfree(&re);
5246 return (0);
5247 }
5248
5249 if (strlen(attr->values[i].string.text) > (IPP_MAX_LANGUAGE - 1))
5250 {
5251 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));
5252 regfree(&re);
5253 return (0);
5254 }
5255 }
5256
5257 regfree(&re);
5258 break;
5259
5260 case IPP_TAG_MIMETYPE :
5261 /*
5262 * The following regular expression is derived from the ABNF for
5263 * MIME media types in RFC 2045 and 4288. All I can say is that this is
5264 * the easiest way to check the values...
5265 */
5266
5267 if ((i = regcomp(&re,
5268 "^"
5269 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
5270 "/"
5271 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
5272 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
5273 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
5274 /* value */
5275 "$",
5276 REG_NOSUB | REG_EXTENDED)) != 0)
5277 {
5278 char temp[256]; /* Temporary error string */
5279
5280 regerror(i, &re, temp, sizeof(temp));
5281 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("Unable to compile mimeMediaType regular expression: %s."), temp);
5282 return (0);
5283 }
5284
5285 for (i = 0; i < attr->num_values; i ++)
5286 {
5287 if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
5288 {
5289 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);
5290 regfree(&re);
5291 return (0);
5292 }
5293
5294 if (strlen(attr->values[i].string.text) > (IPP_MAX_MIMETYPE - 1))
5295 {
5296 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));
5297 regfree(&re);
5298 return (0);
5299 }
5300 }
5301
5302 regfree(&re);
5303 break;
5304
5305 default :
5306 break;
5307 }
5308
5309 return (1);
5310 }
5311
5312
5313 /*
5314 * 'ippValidateAttributes()' - Validate all attributes in an IPP message.
5315 *
5316 * This function validates the contents of the IPP message, including each
5317 * attribute. Like @link ippValidateAttribute@, @link cupsLastErrorString@ is
5318 * set to a human-readable message on failure.
5319 *
5320 * @since CUPS 1.7/macOS 10.9@
5321 */
5322
5323 int /* O - 1 if valid, 0 otherwise */
5324 ippValidateAttributes(ipp_t *ipp) /* I - IPP message */
5325 {
5326 ipp_attribute_t *attr; /* Current attribute */
5327
5328
5329 if (!ipp)
5330 return (1);
5331
5332 for (attr = ipp->attrs; attr; attr = attr->next)
5333 if (!ippValidateAttribute(attr))
5334 return (0);
5335
5336 return (1);
5337 }
5338
5339
5340 /*
5341 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
5342 */
5343
5344 ipp_state_t /* O - Current state */
5345 ippWrite(http_t *http, /* I - HTTP connection */
5346 ipp_t *ipp) /* I - IPP data */
5347 {
5348 DEBUG_printf(("ippWrite(http=%p, ipp=%p)", (void *)http, (void *)ipp));
5349
5350 if (!http)
5351 return (IPP_STATE_ERROR);
5352
5353 return (ippWriteIO(http, (ipp_iocb_t)httpWrite2, http->blocking, NULL, ipp));
5354 }
5355
5356
5357 /*
5358 * 'ippWriteFile()' - Write data for an IPP message to a file.
5359 *
5360 * @since CUPS 1.1.19/macOS 10.3@
5361 */
5362
5363 ipp_state_t /* O - Current state */
5364 ippWriteFile(int fd, /* I - HTTP data */
5365 ipp_t *ipp) /* I - IPP data */
5366 {
5367 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd, (void *)ipp));
5368
5369 ipp->state = IPP_STATE_IDLE;
5370
5371 return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp));
5372 }
5373
5374
5375 /*
5376 * 'ippWriteIO()' - Write data for an IPP message.
5377 *
5378 * @since CUPS 1.2/macOS 10.5@
5379 */
5380
5381 ipp_state_t /* O - Current state */
5382 ippWriteIO(void *dst, /* I - Destination */
5383 ipp_iocb_t cb, /* I - Write callback function */
5384 int blocking, /* I - Use blocking IO? */
5385 ipp_t *parent, /* I - Parent IPP message */
5386 ipp_t *ipp) /* I - IPP data */
5387 {
5388 int i; /* Looping var */
5389 int n; /* Length of data */
5390 unsigned char *buffer, /* Data buffer */
5391 *bufptr; /* Pointer into buffer */
5392 ipp_attribute_t *attr; /* Current attribute */
5393 _ipp_value_t *value; /* Current value */
5394
5395
5396 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)dst, (void *)cb, blocking, (void *)parent, (void *)ipp));
5397
5398 if (!dst || !ipp)
5399 return (IPP_STATE_ERROR);
5400
5401 if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
5402 {
5403 DEBUG_puts("1ippWriteIO: Unable to get write buffer");
5404 return (IPP_STATE_ERROR);
5405 }
5406
5407 switch (ipp->state)
5408 {
5409 case IPP_STATE_IDLE :
5410 ipp->state ++; /* Avoid common problem... */
5411
5412 case IPP_STATE_HEADER :
5413 if (parent == NULL)
5414 {
5415 /*
5416 * Send the request header:
5417 *
5418 * Version = 2 bytes
5419 * Operation/Status Code = 2 bytes
5420 * Request ID = 4 bytes
5421 * Total = 8 bytes
5422 */
5423
5424 bufptr = buffer;
5425
5426 *bufptr++ = ipp->request.any.version[0];
5427 *bufptr++ = ipp->request.any.version[1];
5428 *bufptr++ = (ipp_uchar_t)(ipp->request.any.op_status >> 8);
5429 *bufptr++ = (ipp_uchar_t)ipp->request.any.op_status;
5430 *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 24);
5431 *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 16);
5432 *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 8);
5433 *bufptr++ = (ipp_uchar_t)ipp->request.any.request_id;
5434
5435 DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer[0], buffer[1]));
5436 DEBUG_printf(("2ippWriteIO: op_status=%04x",
5437 ipp->request.any.op_status));
5438 DEBUG_printf(("2ippWriteIO: request_id=%d",
5439 ipp->request.any.request_id));
5440
5441 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5442 {
5443 DEBUG_puts("1ippWriteIO: Could not write IPP header...");
5444 _cupsBufferRelease((char *)buffer);
5445 return (IPP_STATE_ERROR);
5446 }
5447 }
5448
5449 /*
5450 * Reset the state engine to point to the first attribute
5451 * in the request/response, with no current group.
5452 */
5453
5454 ipp->state = IPP_STATE_ATTRIBUTE;
5455 ipp->current = ipp->attrs;
5456 ipp->curtag = IPP_TAG_ZERO;
5457
5458 DEBUG_printf(("1ippWriteIO: ipp->current=%p", (void *)ipp->current));
5459
5460 /*
5461 * If blocking is disabled, stop here...
5462 */
5463
5464 if (!blocking)
5465 break;
5466
5467 case IPP_STATE_ATTRIBUTE :
5468 while (ipp->current != NULL)
5469 {
5470 /*
5471 * Write this attribute...
5472 */
5473
5474 bufptr = buffer;
5475 attr = ipp->current;
5476
5477 ipp->current = ipp->current->next;
5478
5479 if (!parent)
5480 {
5481 if (ipp->curtag != attr->group_tag)
5482 {
5483 /*
5484 * Send a group tag byte...
5485 */
5486
5487 ipp->curtag = attr->group_tag;
5488
5489 if (attr->group_tag == IPP_TAG_ZERO)
5490 continue;
5491
5492 DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
5493 attr->group_tag, ippTagString(attr->group_tag)));
5494 *bufptr++ = (ipp_uchar_t)attr->group_tag;
5495 }
5496 else if (attr->group_tag == IPP_TAG_ZERO)
5497 continue;
5498 }
5499
5500 DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr->name,
5501 attr->num_values > 1 ? "1setOf " : "",
5502 ippTagString(attr->value_tag)));
5503
5504 /*
5505 * Write the attribute tag and name.
5506 *
5507 * The attribute name length does not include the trailing nul
5508 * character in the source string.
5509 *
5510 * Collection values (parent != NULL) are written differently...
5511 */
5512
5513 if (parent == NULL)
5514 {
5515 /*
5516 * Get the length of the attribute name, and make sure it won't
5517 * overflow the buffer...
5518 */
5519
5520 if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 8))
5521 {
5522 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
5523 _cupsBufferRelease((char *)buffer);
5524 return (IPP_STATE_ERROR);
5525 }
5526
5527 /*
5528 * Write the value tag, name length, and name string...
5529 */
5530
5531 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5532 attr->value_tag, ippTagString(attr->value_tag)));
5533 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
5534 attr->name));
5535
5536 if (attr->value_tag > 0xff)
5537 {
5538 *bufptr++ = IPP_TAG_EXTENSION;
5539 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
5540 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
5541 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
5542 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5543 }
5544 else
5545 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5546
5547 *bufptr++ = (ipp_uchar_t)(n >> 8);
5548 *bufptr++ = (ipp_uchar_t)n;
5549 memcpy(bufptr, attr->name, (size_t)n);
5550 bufptr += n;
5551 }
5552 else
5553 {
5554 /*
5555 * Get the length of the attribute name, and make sure it won't
5556 * overflow the buffer...
5557 */
5558
5559 if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 12))
5560 {
5561 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
5562 _cupsBufferRelease((char *)buffer);
5563 return (IPP_STATE_ERROR);
5564 }
5565
5566 /*
5567 * Write the member name tag, name length, name string, value tag,
5568 * and empty name for the collection member attribute...
5569 */
5570
5571 DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
5572 IPP_TAG_MEMBERNAME));
5573 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
5574 attr->name));
5575 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5576 attr->value_tag, ippTagString(attr->value_tag)));
5577 DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
5578
5579 *bufptr++ = IPP_TAG_MEMBERNAME;
5580 *bufptr++ = 0;
5581 *bufptr++ = 0;
5582 *bufptr++ = (ipp_uchar_t)(n >> 8);
5583 *bufptr++ = (ipp_uchar_t)n;
5584 memcpy(bufptr, attr->name, (size_t)n);
5585 bufptr += n;
5586
5587 if (attr->value_tag > 0xff)
5588 {
5589 *bufptr++ = IPP_TAG_EXTENSION;
5590 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
5591 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
5592 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
5593 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5594 }
5595 else
5596 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5597
5598 *bufptr++ = 0;
5599 *bufptr++ = 0;
5600 }
5601
5602 /*
5603 * Now write the attribute value(s)...
5604 */
5605
5606 switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
5607 {
5608 case IPP_TAG_UNSUPPORTED_VALUE :
5609 case IPP_TAG_DEFAULT :
5610 case IPP_TAG_UNKNOWN :
5611 case IPP_TAG_NOVALUE :
5612 case IPP_TAG_NOTSETTABLE :
5613 case IPP_TAG_DELETEATTR :
5614 case IPP_TAG_ADMINDEFINE :
5615 *bufptr++ = 0;
5616 *bufptr++ = 0;
5617 break;
5618
5619 case IPP_TAG_INTEGER :
5620 case IPP_TAG_ENUM :
5621 for (i = 0, value = attr->values;
5622 i < attr->num_values;
5623 i ++, value ++)
5624 {
5625 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 9)
5626 {
5627 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5628 {
5629 DEBUG_puts("1ippWriteIO: Could not write IPP "
5630 "attribute...");
5631 _cupsBufferRelease((char *)buffer);
5632 return (IPP_STATE_ERROR);
5633 }
5634
5635 bufptr = buffer;
5636 }
5637
5638 if (i)
5639 {
5640 /*
5641 * Arrays and sets are done by sending additional
5642 * values with a zero-length name...
5643 */
5644
5645 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5646 *bufptr++ = 0;
5647 *bufptr++ = 0;
5648 }
5649
5650 /*
5651 * Integers and enumerations are both 4-byte signed
5652 * (twos-complement) values.
5653 *
5654 * Put the 2-byte length and 4-byte value into the buffer...
5655 */
5656
5657 *bufptr++ = 0;
5658 *bufptr++ = 4;
5659 *bufptr++ = (ipp_uchar_t)(value->integer >> 24);
5660 *bufptr++ = (ipp_uchar_t)(value->integer >> 16);
5661 *bufptr++ = (ipp_uchar_t)(value->integer >> 8);
5662 *bufptr++ = (ipp_uchar_t)value->integer;
5663 }
5664 break;
5665
5666 case IPP_TAG_BOOLEAN :
5667 for (i = 0, value = attr->values;
5668 i < attr->num_values;
5669 i ++, value ++)
5670 {
5671 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 6)
5672 {
5673 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5674 {
5675 DEBUG_puts("1ippWriteIO: Could not write IPP "
5676 "attribute...");
5677 _cupsBufferRelease((char *)buffer);
5678 return (IPP_STATE_ERROR);
5679 }
5680
5681 bufptr = buffer;
5682 }
5683
5684 if (i)
5685 {
5686 /*
5687 * Arrays and sets are done by sending additional
5688 * values with a zero-length name...
5689 */
5690
5691 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5692 *bufptr++ = 0;
5693 *bufptr++ = 0;
5694 }
5695
5696 /*
5697 * Boolean values are 1-byte; 0 = false, 1 = true.
5698 *
5699 * Put the 2-byte length and 1-byte value into the buffer...
5700 */
5701
5702 *bufptr++ = 0;
5703 *bufptr++ = 1;
5704 *bufptr++ = (ipp_uchar_t)value->boolean;
5705 }
5706 break;
5707
5708 case IPP_TAG_TEXT :
5709 case IPP_TAG_NAME :
5710 case IPP_TAG_KEYWORD :
5711 case IPP_TAG_URI :
5712 case IPP_TAG_URISCHEME :
5713 case IPP_TAG_CHARSET :
5714 case IPP_TAG_LANGUAGE :
5715 case IPP_TAG_MIMETYPE :
5716 for (i = 0, value = attr->values;
5717 i < attr->num_values;
5718 i ++, value ++)
5719 {
5720 if (i)
5721 {
5722 /*
5723 * Arrays and sets are done by sending additional
5724 * values with a zero-length name...
5725 */
5726
5727 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5728 attr->value_tag,
5729 ippTagString(attr->value_tag)));
5730 DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
5731
5732 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
5733 {
5734 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5735 {
5736 DEBUG_puts("1ippWriteIO: Could not write IPP "
5737 "attribute...");
5738 _cupsBufferRelease((char *)buffer);
5739 return (IPP_STATE_ERROR);
5740 }
5741
5742 bufptr = buffer;
5743 }
5744
5745 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5746 *bufptr++ = 0;
5747 *bufptr++ = 0;
5748 }
5749
5750 if (value->string.text != NULL)
5751 n = (int)strlen(value->string.text);
5752 else
5753 n = 0;
5754
5755 if (n > (IPP_BUF_SIZE - 2))
5756 {
5757 DEBUG_printf(("1ippWriteIO: String too long (%d)", n));
5758 _cupsBufferRelease((char *)buffer);
5759 return (IPP_STATE_ERROR);
5760 }
5761
5762 DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n,
5763 value->string.text));
5764
5765 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
5766 {
5767 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5768 {
5769 DEBUG_puts("1ippWriteIO: Could not write IPP "
5770 "attribute...");
5771 _cupsBufferRelease((char *)buffer);
5772 return (IPP_STATE_ERROR);
5773 }
5774
5775 bufptr = buffer;
5776 }
5777
5778 /*
5779 * All simple strings consist of the 2-byte length and
5780 * character data without the trailing nul normally found
5781 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
5782 * bytes since the 2-byte length is a signed (twos-complement)
5783 * value.
5784 *
5785 * Put the 2-byte length and string characters in the buffer.
5786 */
5787
5788 *bufptr++ = (ipp_uchar_t)(n >> 8);
5789 *bufptr++ = (ipp_uchar_t)n;
5790
5791 if (n > 0)
5792 {
5793 memcpy(bufptr, value->string.text, (size_t)n);
5794 bufptr += n;
5795 }
5796 }
5797 break;
5798
5799 case IPP_TAG_DATE :
5800 for (i = 0, value = attr->values;
5801 i < attr->num_values;
5802 i ++, value ++)
5803 {
5804 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 16)
5805 {
5806 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5807 {
5808 DEBUG_puts("1ippWriteIO: Could not write IPP "
5809 "attribute...");
5810 _cupsBufferRelease((char *)buffer);
5811 return (IPP_STATE_ERROR);
5812 }
5813
5814 bufptr = buffer;
5815 }
5816
5817 if (i)
5818 {
5819 /*
5820 * Arrays and sets are done by sending additional
5821 * values with a zero-length name...
5822 */
5823
5824 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5825 *bufptr++ = 0;
5826 *bufptr++ = 0;
5827 }
5828
5829 /*
5830 * Date values consist of a 2-byte length and an
5831 * 11-byte date/time structure defined by RFC 1903.
5832 *
5833 * Put the 2-byte length and 11-byte date/time
5834 * structure in the buffer.
5835 */
5836
5837 *bufptr++ = 0;
5838 *bufptr++ = 11;
5839 memcpy(bufptr, value->date, 11);
5840 bufptr += 11;
5841 }
5842 break;
5843
5844 case IPP_TAG_RESOLUTION :
5845 for (i = 0, value = attr->values;
5846 i < attr->num_values;
5847 i ++, value ++)
5848 {
5849 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 14)
5850 {
5851 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5852 {
5853 DEBUG_puts("1ippWriteIO: Could not write IPP "
5854 "attribute...");
5855 _cupsBufferRelease((char *)buffer);
5856 return (IPP_STATE_ERROR);
5857 }
5858
5859 bufptr = buffer;
5860 }
5861
5862 if (i)
5863 {
5864 /*
5865 * Arrays and sets are done by sending additional
5866 * values with a zero-length name...
5867 */
5868
5869 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5870 *bufptr++ = 0;
5871 *bufptr++ = 0;
5872 }
5873
5874 /*
5875 * Resolution values consist of a 2-byte length,
5876 * 4-byte horizontal resolution value, 4-byte vertical
5877 * resolution value, and a 1-byte units value.
5878 *
5879 * Put the 2-byte length and resolution value data
5880 * into the buffer.
5881 */
5882
5883 *bufptr++ = 0;
5884 *bufptr++ = 9;
5885 *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 24);
5886 *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 16);
5887 *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 8);
5888 *bufptr++ = (ipp_uchar_t)value->resolution.xres;
5889 *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 24);
5890 *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 16);
5891 *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 8);
5892 *bufptr++ = (ipp_uchar_t)value->resolution.yres;
5893 *bufptr++ = (ipp_uchar_t)value->resolution.units;
5894 }
5895 break;
5896
5897 case IPP_TAG_RANGE :
5898 for (i = 0, value = attr->values;
5899 i < attr->num_values;
5900 i ++, value ++)
5901 {
5902 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 13)
5903 {
5904 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5905 {
5906 DEBUG_puts("1ippWriteIO: Could not write IPP "
5907 "attribute...");
5908 _cupsBufferRelease((char *)buffer);
5909 return (IPP_STATE_ERROR);
5910 }
5911
5912 bufptr = buffer;
5913 }
5914
5915 if (i)
5916 {
5917 /*
5918 * Arrays and sets are done by sending additional
5919 * values with a zero-length name...
5920 */
5921
5922 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5923 *bufptr++ = 0;
5924 *bufptr++ = 0;
5925 }
5926
5927 /*
5928 * Range values consist of a 2-byte length,
5929 * 4-byte lower value, and 4-byte upper value.
5930 *
5931 * Put the 2-byte length and range value data
5932 * into the buffer.
5933 */
5934
5935 *bufptr++ = 0;
5936 *bufptr++ = 8;
5937 *bufptr++ = (ipp_uchar_t)(value->range.lower >> 24);
5938 *bufptr++ = (ipp_uchar_t)(value->range.lower >> 16);
5939 *bufptr++ = (ipp_uchar_t)(value->range.lower >> 8);
5940 *bufptr++ = (ipp_uchar_t)value->range.lower;
5941 *bufptr++ = (ipp_uchar_t)(value->range.upper >> 24);
5942 *bufptr++ = (ipp_uchar_t)(value->range.upper >> 16);
5943 *bufptr++ = (ipp_uchar_t)(value->range.upper >> 8);
5944 *bufptr++ = (ipp_uchar_t)value->range.upper;
5945 }
5946 break;
5947
5948 case IPP_TAG_TEXTLANG :
5949 case IPP_TAG_NAMELANG :
5950 for (i = 0, value = attr->values;
5951 i < attr->num_values;
5952 i ++, value ++)
5953 {
5954 if (i)
5955 {
5956 /*
5957 * Arrays and sets are done by sending additional
5958 * values with a zero-length name...
5959 */
5960
5961 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
5962 {
5963 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5964 {
5965 DEBUG_puts("1ippWriteIO: Could not write IPP "
5966 "attribute...");
5967 _cupsBufferRelease((char *)buffer);
5968 return (IPP_STATE_ERROR);
5969 }
5970
5971 bufptr = buffer;
5972 }
5973
5974 *bufptr++ = (ipp_uchar_t)attr->value_tag;
5975 *bufptr++ = 0;
5976 *bufptr++ = 0;
5977 }
5978
5979 /*
5980 * textWithLanguage and nameWithLanguage values consist
5981 * of a 2-byte length for both strings and their
5982 * individual lengths, a 2-byte length for the
5983 * character string, the character string without the
5984 * trailing nul, a 2-byte length for the character
5985 * set string, and the character set string without
5986 * the trailing nul.
5987 */
5988
5989 n = 4;
5990
5991 if (value->string.language != NULL)
5992 n += (int)strlen(value->string.language);
5993
5994 if (value->string.text != NULL)
5995 n += (int)strlen(value->string.text);
5996
5997 if (n > (IPP_BUF_SIZE - 2))
5998 {
5999 DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
6000 "too long (%d)", n));
6001 _cupsBufferRelease((char *)buffer);
6002 return (IPP_STATE_ERROR);
6003 }
6004
6005 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
6006 {
6007 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6008 {
6009 DEBUG_puts("1ippWriteIO: Could not write IPP "
6010 "attribute...");
6011 _cupsBufferRelease((char *)buffer);
6012 return (IPP_STATE_ERROR);
6013 }
6014
6015 bufptr = buffer;
6016 }
6017
6018 /* Length of entire value */
6019 *bufptr++ = (ipp_uchar_t)(n >> 8);
6020 *bufptr++ = (ipp_uchar_t)n;
6021
6022 /* Length of language */
6023 if (value->string.language != NULL)
6024 n = (int)strlen(value->string.language);
6025 else
6026 n = 0;
6027
6028 *bufptr++ = (ipp_uchar_t)(n >> 8);
6029 *bufptr++ = (ipp_uchar_t)n;
6030
6031 /* Language */
6032 if (n > 0)
6033 {
6034 memcpy(bufptr, value->string.language, (size_t)n);
6035 bufptr += n;
6036 }
6037
6038 /* Length of text */
6039 if (value->string.text != NULL)
6040 n = (int)strlen(value->string.text);
6041 else
6042 n = 0;
6043
6044 *bufptr++ = (ipp_uchar_t)(n >> 8);
6045 *bufptr++ = (ipp_uchar_t)n;
6046
6047 /* Text */
6048 if (n > 0)
6049 {
6050 memcpy(bufptr, value->string.text, (size_t)n);
6051 bufptr += n;
6052 }
6053 }
6054 break;
6055
6056 case IPP_TAG_BEGIN_COLLECTION :
6057 for (i = 0, value = attr->values;
6058 i < attr->num_values;
6059 i ++, value ++)
6060 {
6061 /*
6062 * Collections are written with the begin-collection
6063 * tag first with a value of 0 length, followed by the
6064 * attributes in the collection, then the end-collection
6065 * value...
6066 */
6067
6068 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 5)
6069 {
6070 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6071 {
6072 DEBUG_puts("1ippWriteIO: Could not write IPP "
6073 "attribute...");
6074 _cupsBufferRelease((char *)buffer);
6075 return (IPP_STATE_ERROR);
6076 }
6077
6078 bufptr = buffer;
6079 }
6080
6081 if (i)
6082 {
6083 /*
6084 * Arrays and sets are done by sending additional
6085 * values with a zero-length name...
6086 */
6087
6088 *bufptr++ = (ipp_uchar_t)attr->value_tag;
6089 *bufptr++ = 0;
6090 *bufptr++ = 0;
6091 }
6092
6093 /*
6094 * Write a data length of 0 and flush the buffer...
6095 */
6096
6097 *bufptr++ = 0;
6098 *bufptr++ = 0;
6099
6100 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6101 {
6102 DEBUG_puts("1ippWriteIO: Could not write IPP "
6103 "attribute...");
6104 _cupsBufferRelease((char *)buffer);
6105 return (IPP_STATE_ERROR);
6106 }
6107
6108 bufptr = buffer;
6109
6110 /*
6111 * Then write the collection attribute...
6112 */
6113
6114 value->collection->state = IPP_STATE_IDLE;
6115
6116 if (ippWriteIO(dst, cb, 1, ipp,
6117 value->collection) == IPP_STATE_ERROR)
6118 {
6119 DEBUG_puts("1ippWriteIO: Unable to write collection value");
6120 _cupsBufferRelease((char *)buffer);
6121 return (IPP_STATE_ERROR);
6122 }
6123 }
6124 break;
6125
6126 default :
6127 for (i = 0, value = attr->values;
6128 i < attr->num_values;
6129 i ++, value ++)
6130 {
6131 if (i)
6132 {
6133 /*
6134 * Arrays and sets are done by sending additional
6135 * values with a zero-length name...
6136 */
6137
6138 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
6139 {
6140 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6141 {
6142 DEBUG_puts("1ippWriteIO: Could not write IPP "
6143 "attribute...");
6144 _cupsBufferRelease((char *)buffer);
6145 return (IPP_STATE_ERROR);
6146 }
6147
6148 bufptr = buffer;
6149 }
6150
6151 *bufptr++ = (ipp_uchar_t)attr->value_tag;
6152 *bufptr++ = 0;
6153 *bufptr++ = 0;
6154 }
6155
6156 /*
6157 * An unknown value might some new value that a
6158 * vendor has come up with. It consists of a
6159 * 2-byte length and the bytes in the unknown
6160 * value buffer.
6161 */
6162
6163 n = value->unknown.length;
6164
6165 if (n > (IPP_BUF_SIZE - 2))
6166 {
6167 DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
6168 n));
6169 _cupsBufferRelease((char *)buffer);
6170 return (IPP_STATE_ERROR);
6171 }
6172
6173 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
6174 {
6175 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6176 {
6177 DEBUG_puts("1ippWriteIO: Could not write IPP "
6178 "attribute...");
6179 _cupsBufferRelease((char *)buffer);
6180 return (IPP_STATE_ERROR);
6181 }
6182
6183 bufptr = buffer;
6184 }
6185
6186 /* Length of unknown value */
6187 *bufptr++ = (ipp_uchar_t)(n >> 8);
6188 *bufptr++ = (ipp_uchar_t)n;
6189
6190 /* Value */
6191 if (n > 0)
6192 {
6193 memcpy(bufptr, value->unknown.data, (size_t)n);
6194 bufptr += n;
6195 }
6196 }
6197 break;
6198 }
6199
6200 /*
6201 * Write the data out...
6202 */
6203
6204 if (bufptr > buffer)
6205 {
6206 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6207 {
6208 DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
6209 _cupsBufferRelease((char *)buffer);
6210 return (IPP_STATE_ERROR);
6211 }
6212
6213 DEBUG_printf(("2ippWriteIO: wrote %d bytes",
6214 (int)(bufptr - buffer)));
6215 }
6216
6217 /*
6218 * If blocking is disabled and we aren't at the end of the attribute
6219 * list, stop here...
6220 */
6221
6222 if (!blocking && ipp->current)
6223 break;
6224 }
6225
6226 if (ipp->current == NULL)
6227 {
6228 /*
6229 * Done with all of the attributes; add the end-of-attributes
6230 * tag or end-collection attribute...
6231 */
6232
6233 if (parent == NULL)
6234 {
6235 buffer[0] = IPP_TAG_END;
6236 n = 1;
6237 }
6238 else
6239 {
6240 buffer[0] = IPP_TAG_END_COLLECTION;
6241 buffer[1] = 0; /* empty name */
6242 buffer[2] = 0;
6243 buffer[3] = 0; /* empty value */
6244 buffer[4] = 0;
6245 n = 5;
6246 }
6247
6248 if ((*cb)(dst, buffer, (size_t)n) < 0)
6249 {
6250 DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
6251 _cupsBufferRelease((char *)buffer);
6252 return (IPP_STATE_ERROR);
6253 }
6254
6255 ipp->state = IPP_STATE_DATA;
6256 }
6257 break;
6258
6259 case IPP_STATE_DATA :
6260 break;
6261
6262 default :
6263 break; /* anti-compiler-warning-code */
6264 }
6265
6266 _cupsBufferRelease((char *)buffer);
6267
6268 return (ipp->state);
6269 }
6270
6271
6272 /*
6273 * 'ipp_add_attr()' - Add a new attribute to the message.
6274 */
6275
6276 static ipp_attribute_t * /* O - New attribute */
6277 ipp_add_attr(ipp_t *ipp, /* I - IPP message */
6278 const char *name, /* I - Attribute name or NULL */
6279 ipp_tag_t group_tag, /* I - Group tag or IPP_TAG_ZERO */
6280 ipp_tag_t value_tag, /* I - Value tag or IPP_TAG_ZERO */
6281 int num_values) /* I - Number of values */
6282 {
6283 int alloc_values; /* Number of values to allocate */
6284 ipp_attribute_t *attr; /* New attribute */
6285
6286
6287 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));
6288
6289 /*
6290 * Range check input...
6291 */
6292
6293 if (!ipp || num_values < 0)
6294 return (NULL);
6295
6296 /*
6297 * Allocate memory, rounding the allocation up as needed...
6298 */
6299
6300 if (num_values <= 1)
6301 alloc_values = 1;
6302 else
6303 alloc_values = (num_values + IPP_MAX_VALUES - 1) & ~(IPP_MAX_VALUES - 1);
6304
6305 attr = calloc(sizeof(ipp_attribute_t) +
6306 (size_t)(alloc_values - 1) * sizeof(_ipp_value_t), 1);
6307
6308 if (attr)
6309 {
6310 /*
6311 * Initialize attribute...
6312 */
6313
6314 DEBUG_printf(("4debug_alloc: %p %s %s%s (%d values)", (void *)attr, name, num_values > 1 ? "1setOf " : "", ippTagString(value_tag), num_values));
6315
6316 if (name)
6317 attr->name = _cupsStrAlloc(name);
6318
6319 attr->group_tag = group_tag;
6320 attr->value_tag = value_tag;
6321 attr->num_values = num_values;
6322
6323 /*
6324 * Add it to the end of the linked list...
6325 */
6326
6327 if (ipp->last)
6328 ipp->last->next = attr;
6329 else
6330 ipp->attrs = attr;
6331
6332 ipp->prev = ipp->last;
6333 ipp->last = ipp->current = attr;
6334 }
6335
6336 DEBUG_printf(("5ipp_add_attr: Returning %p", (void *)attr));
6337
6338 return (attr);
6339 }
6340
6341
6342 /*
6343 * 'ipp_free_values()' - Free attribute values.
6344 */
6345
6346 static void
6347 ipp_free_values(ipp_attribute_t *attr, /* I - Attribute to free values from */
6348 int element,/* I - First value to free */
6349 int count) /* I - Number of values to free */
6350 {
6351 int i; /* Looping var */
6352 _ipp_value_t *value; /* Current value */
6353
6354
6355 DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", (void *)attr, element, count));
6356
6357 if (!(attr->value_tag & IPP_TAG_CUPS_CONST))
6358 {
6359 /*
6360 * Free values as needed...
6361 */
6362
6363 switch (attr->value_tag)
6364 {
6365 case IPP_TAG_TEXTLANG :
6366 case IPP_TAG_NAMELANG :
6367 if (element == 0 && count == attr->num_values &&
6368 attr->values[0].string.language)
6369 {
6370 _cupsStrFree(attr->values[0].string.language);
6371 attr->values[0].string.language = NULL;
6372 }
6373 /* Fall through to other string values */
6374
6375 case IPP_TAG_TEXT :
6376 case IPP_TAG_NAME :
6377 case IPP_TAG_RESERVED_STRING :
6378 case IPP_TAG_KEYWORD :
6379 case IPP_TAG_URI :
6380 case IPP_TAG_URISCHEME :
6381 case IPP_TAG_CHARSET :
6382 case IPP_TAG_LANGUAGE :
6383 case IPP_TAG_MIMETYPE :
6384 for (i = count, value = attr->values + element;
6385 i > 0;
6386 i --, value ++)
6387 {
6388 _cupsStrFree(value->string.text);
6389 value->string.text = NULL;
6390 }
6391 break;
6392
6393 case IPP_TAG_UNSUPPORTED_VALUE :
6394 case IPP_TAG_DEFAULT :
6395 case IPP_TAG_UNKNOWN :
6396 case IPP_TAG_NOVALUE :
6397 case IPP_TAG_NOTSETTABLE :
6398 case IPP_TAG_DELETEATTR :
6399 case IPP_TAG_ADMINDEFINE :
6400 case IPP_TAG_INTEGER :
6401 case IPP_TAG_ENUM :
6402 case IPP_TAG_BOOLEAN :
6403 case IPP_TAG_DATE :
6404 case IPP_TAG_RESOLUTION :
6405 case IPP_TAG_RANGE :
6406 break;
6407
6408 case IPP_TAG_BEGIN_COLLECTION :
6409 for (i = count, value = attr->values + element;
6410 i > 0;
6411 i --, value ++)
6412 {
6413 ippDelete(value->collection);
6414 value->collection = NULL;
6415 }
6416 break;
6417
6418 case IPP_TAG_STRING :
6419 default :
6420 for (i = count, value = attr->values + element;
6421 i > 0;
6422 i --, value ++)
6423 {
6424 if (value->unknown.data)
6425 {
6426 free(value->unknown.data);
6427 value->unknown.data = NULL;
6428 }
6429 }
6430 break;
6431 }
6432 }
6433
6434 /*
6435 * If we are not freeing values from the end, move the remaining values up...
6436 */
6437
6438 if ((element + count) < attr->num_values)
6439 memmove(attr->values + element, attr->values + element + count,
6440 (size_t)(attr->num_values - count - element) * sizeof(_ipp_value_t));
6441
6442 attr->num_values -= count;
6443 }
6444
6445
6446 /*
6447 * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
6448 *
6449 * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
6450 * to "ll-cc", "ll-region", and "charset-number", respectively.
6451 */
6452
6453 static char * /* O - Language code string */
6454 ipp_get_code(const char *value, /* I - Locale/charset string */
6455 char *buffer, /* I - String buffer */
6456 size_t bufsize) /* I - Size of string buffer */
6457 {
6458 char *bufptr, /* Pointer into buffer */
6459 *bufend; /* End of buffer */
6460
6461
6462 /*
6463 * Convert values to lowercase and change _ to - as needed...
6464 */
6465
6466 for (bufptr = buffer, bufend = buffer + bufsize - 1;
6467 *value && bufptr < bufend;
6468 value ++)
6469 if (*value == '_')
6470 *bufptr++ = '-';
6471 else
6472 *bufptr++ = (char)_cups_tolower(*value);
6473
6474 *bufptr = '\0';
6475
6476 /*
6477 * Return the converted string...
6478 */
6479
6480 return (buffer);
6481 }
6482
6483
6484 /*
6485 * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
6486 *
6487 * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
6488 * "ll-region", respectively. It also converts the "C" (POSIX) locale to "en".
6489 */
6490
6491 static char * /* O - Language code string */
6492 ipp_lang_code(const char *locale, /* I - Locale string */
6493 char *buffer, /* I - String buffer */
6494 size_t bufsize) /* I - Size of string buffer */
6495 {
6496 /*
6497 * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
6498 */
6499
6500 if (!_cups_strcasecmp(locale, "c"))
6501 {
6502 strlcpy(buffer, "en", bufsize);
6503 return (buffer);
6504 }
6505 else
6506 return (ipp_get_code(locale, buffer, bufsize));
6507 }
6508
6509
6510 /*
6511 * 'ipp_length()' - Compute the length of an IPP message or collection value.
6512 */
6513
6514 static size_t /* O - Size of IPP message */
6515 ipp_length(ipp_t *ipp, /* I - IPP message or collection */
6516 int collection) /* I - 1 if a collection, 0 otherwise */
6517 {
6518 int i; /* Looping var */
6519 size_t bytes; /* Number of bytes */
6520 ipp_attribute_t *attr; /* Current attribute */
6521 ipp_tag_t group; /* Current group */
6522 _ipp_value_t *value; /* Current value */
6523
6524
6525 DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", (void *)ipp, collection));
6526
6527 if (!ipp)
6528 {
6529 DEBUG_puts("4ipp_length: Returning 0 bytes");
6530 return (0);
6531 }
6532
6533 /*
6534 * Start with 8 bytes for the IPP message header...
6535 */
6536
6537 bytes = collection ? 0 : 8;
6538
6539 /*
6540 * Then add the lengths of each attribute...
6541 */
6542
6543 group = IPP_TAG_ZERO;
6544
6545 for (attr = ipp->attrs; attr != NULL; attr = attr->next)
6546 {
6547 if (attr->group_tag != group && !collection)
6548 {
6549 group = attr->group_tag;
6550 if (group == IPP_TAG_ZERO)
6551 continue;
6552
6553 bytes ++; /* Group tag */
6554 }
6555
6556 if (!attr->name)
6557 continue;
6558
6559 DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
6560 "bytes=" CUPS_LLFMT, attr->name, attr->num_values, CUPS_LLCAST bytes));
6561
6562 if ((attr->value_tag & ~IPP_TAG_CUPS_CONST) < IPP_TAG_EXTENSION)
6563 bytes += (size_t)attr->num_values;/* Value tag for each value */
6564 else
6565 bytes += (size_t)(5 * attr->num_values);
6566 /* Value tag for each value */
6567 bytes += (size_t)(2 * attr->num_values);
6568 /* Name lengths */
6569 bytes += strlen(attr->name); /* Name */
6570 bytes += (size_t)(2 * attr->num_values);
6571 /* Value lengths */
6572
6573 if (collection)
6574 bytes += 5; /* Add membername overhead */
6575
6576 switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
6577 {
6578 case IPP_TAG_UNSUPPORTED_VALUE :
6579 case IPP_TAG_DEFAULT :
6580 case IPP_TAG_UNKNOWN :
6581 case IPP_TAG_NOVALUE :
6582 case IPP_TAG_NOTSETTABLE :
6583 case IPP_TAG_DELETEATTR :
6584 case IPP_TAG_ADMINDEFINE :
6585 break;
6586
6587 case IPP_TAG_INTEGER :
6588 case IPP_TAG_ENUM :
6589 bytes += (size_t)(4 * attr->num_values);
6590 break;
6591
6592 case IPP_TAG_BOOLEAN :
6593 bytes += (size_t)attr->num_values;
6594 break;
6595
6596 case IPP_TAG_TEXT :
6597 case IPP_TAG_NAME :
6598 case IPP_TAG_KEYWORD :
6599 case IPP_TAG_URI :
6600 case IPP_TAG_URISCHEME :
6601 case IPP_TAG_CHARSET :
6602 case IPP_TAG_LANGUAGE :
6603 case IPP_TAG_MIMETYPE :
6604 for (i = 0, value = attr->values;
6605 i < attr->num_values;
6606 i ++, value ++)
6607 if (value->string.text)
6608 bytes += strlen(value->string.text);
6609 break;
6610
6611 case IPP_TAG_DATE :
6612 bytes += (size_t)(11 * attr->num_values);
6613 break;
6614
6615 case IPP_TAG_RESOLUTION :
6616 bytes += (size_t)(9 * attr->num_values);
6617 break;
6618
6619 case IPP_TAG_RANGE :
6620 bytes += (size_t)(8 * attr->num_values);
6621 break;
6622
6623 case IPP_TAG_TEXTLANG :
6624 case IPP_TAG_NAMELANG :
6625 bytes += (size_t)(4 * attr->num_values);
6626 /* Charset + text length */
6627
6628 for (i = 0, value = attr->values;
6629 i < attr->num_values;
6630 i ++, value ++)
6631 {
6632 if (value->string.language)
6633 bytes += strlen(value->string.language);
6634
6635 if (value->string.text)
6636 bytes += strlen(value->string.text);
6637 }
6638 break;
6639
6640 case IPP_TAG_BEGIN_COLLECTION :
6641 for (i = 0, value = attr->values;
6642 i < attr->num_values;
6643 i ++, value ++)
6644 bytes += ipp_length(value->collection, 1);
6645 break;
6646
6647 default :
6648 for (i = 0, value = attr->values;
6649 i < attr->num_values;
6650 i ++, value ++)
6651 bytes += (size_t)value->unknown.length;
6652 break;
6653 }
6654 }
6655
6656 /*
6657 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
6658 * for the "end of collection" tag and return...
6659 */
6660
6661 if (collection)
6662 bytes += 5;
6663 else
6664 bytes ++;
6665
6666 DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST bytes));
6667
6668 return (bytes);
6669 }
6670
6671
6672 /*
6673 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
6674 */
6675
6676 static ssize_t /* O - Number of bytes read */
6677 ipp_read_http(http_t *http, /* I - Client connection */
6678 ipp_uchar_t *buffer, /* O - Buffer for data */
6679 size_t length) /* I - Total length */
6680 {
6681 ssize_t tbytes, /* Total bytes read */
6682 bytes; /* Bytes read this pass */
6683
6684
6685 DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)", (void *)http, (void *)buffer, (int)length));
6686
6687 /*
6688 * Loop until all bytes are read...
6689 */
6690
6691 for (tbytes = 0, bytes = 0;
6692 tbytes < (int)length;
6693 tbytes += bytes, buffer += bytes)
6694 {
6695 DEBUG_printf(("9ipp_read_http: tbytes=" CUPS_LLFMT ", http->state=%d", CUPS_LLCAST tbytes, http->state));
6696
6697 if (http->state == HTTP_STATE_WAITING)
6698 break;
6699
6700 if (http->used == 0 && !http->blocking)
6701 {
6702 /*
6703 * Wait up to 10 seconds for more data on non-blocking sockets...
6704 */
6705
6706 if (!httpWait(http, 10000))
6707 {
6708 /*
6709 * Signal no data...
6710 */
6711
6712 bytes = -1;
6713 break;
6714 }
6715 }
6716 else if (http->used == 0 && http->timeout_value > 0)
6717 {
6718 /*
6719 * Wait up to timeout seconds for more data on blocking sockets...
6720 */
6721
6722 if (!httpWait(http, (int)(1000 * http->timeout_value)))
6723 {
6724 /*
6725 * Signal no data...
6726 */
6727
6728 bytes = -1;
6729 break;
6730 }
6731 }
6732
6733 if ((bytes = httpRead2(http, (char *)buffer, length - (size_t)tbytes)) < 0)
6734 {
6735 #ifdef WIN32
6736 break;
6737 #else
6738 if (errno != EAGAIN && errno != EINTR)
6739 break;
6740
6741 bytes = 0;
6742 #endif /* WIN32 */
6743 }
6744 else if (bytes == 0)
6745 break;
6746 }
6747
6748 /*
6749 * Return the number of bytes read...
6750 */
6751
6752 if (tbytes == 0 && bytes < 0)
6753 tbytes = -1;
6754
6755 DEBUG_printf(("8ipp_read_http: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST tbytes));
6756
6757 return (tbytes);
6758 }
6759
6760
6761 /*
6762 * 'ipp_read_file()' - Read IPP data from a file.
6763 */
6764
6765 static ssize_t /* O - Number of bytes read */
6766 ipp_read_file(int *fd, /* I - File descriptor */
6767 ipp_uchar_t *buffer, /* O - Read buffer */
6768 size_t length) /* I - Number of bytes to read */
6769 {
6770 #ifdef WIN32
6771 return ((ssize_t)read(*fd, buffer, (unsigned)length));
6772 #else
6773 return (read(*fd, buffer, length));
6774 #endif /* WIN32 */
6775 }
6776
6777
6778 /*
6779 * 'ipp_set_error()' - Set a formatted, localized error string.
6780 */
6781
6782 static void
6783 ipp_set_error(ipp_status_t status, /* I - Status code */
6784 const char *format, /* I - Printf-style error string */
6785 ...) /* I - Additional arguments as needed */
6786 {
6787 va_list ap; /* Pointer to additional args */
6788 char buffer[2048]; /* Message buffer */
6789 cups_lang_t *lang = cupsLangDefault();
6790 /* Current language */
6791
6792
6793 va_start(ap, format);
6794 vsnprintf(buffer, sizeof(buffer), _cupsLangString(lang, format), ap);
6795 va_end(ap);
6796
6797 _cupsSetError(status, buffer, 0);
6798 }
6799
6800
6801 /*
6802 * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
6803 * needed.
6804 */
6805
6806 static _ipp_value_t * /* O - IPP value element or NULL on error */
6807 ipp_set_value(ipp_t *ipp, /* IO - IPP message */
6808 ipp_attribute_t **attr, /* IO - IPP attribute */
6809 int element) /* I - Value number (0-based) */
6810 {
6811 ipp_attribute_t *temp, /* New attribute pointer */
6812 *current, /* Current attribute in list */
6813 *prev; /* Previous attribute in list */
6814 int alloc_values; /* Allocated values */
6815
6816
6817 /*
6818 * If we are setting an existing value element, return it...
6819 */
6820
6821 temp = *attr;
6822
6823 if (temp->num_values <= 1)
6824 alloc_values = 1;
6825 else
6826 alloc_values = (temp->num_values + IPP_MAX_VALUES - 1) &
6827 ~(IPP_MAX_VALUES - 1);
6828
6829 if (element < alloc_values)
6830 {
6831 if (element >= temp->num_values)
6832 temp->num_values = element + 1;
6833
6834 return (temp->values + element);
6835 }
6836
6837 /*
6838 * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
6839 * values when num_values > 1.
6840 */
6841
6842 if (alloc_values < IPP_MAX_VALUES)
6843 alloc_values = IPP_MAX_VALUES;
6844 else
6845 alloc_values += IPP_MAX_VALUES;
6846
6847 DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
6848 alloc_values));
6849
6850 /*
6851 * Reallocate memory...
6852 */
6853
6854 if ((temp = realloc(temp, sizeof(ipp_attribute_t) + (size_t)(alloc_values - 1) * sizeof(_ipp_value_t))) == NULL)
6855 {
6856 _cupsSetHTTPError(HTTP_STATUS_ERROR);
6857 DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
6858 return (NULL);
6859 }
6860
6861 /*
6862 * Zero the new memory...
6863 */
6864
6865 memset(temp->values + temp->num_values, 0, (size_t)(alloc_values - temp->num_values) * sizeof(_ipp_value_t));
6866
6867 if (temp != *attr)
6868 {
6869 /*
6870 * Reset pointers in the list...
6871 */
6872
6873 DEBUG_printf(("4debug_free: %p %s", (void *)*attr, temp->name));
6874 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));
6875
6876 if (ipp->current == *attr && ipp->prev)
6877 {
6878 /*
6879 * Use current "previous" pointer...
6880 */
6881
6882 prev = ipp->prev;
6883 }
6884 else
6885 {
6886 /*
6887 * Find this attribute in the linked list...
6888 */
6889
6890 for (prev = NULL, current = ipp->attrs;
6891 current && current != *attr;
6892 prev = current, current = current->next);
6893
6894 if (!current)
6895 {
6896 /*
6897 * This is a serious error!
6898 */
6899
6900 *attr = temp;
6901 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
6902 _("IPP attribute is not a member of the message."), 1);
6903 DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
6904 return (NULL);
6905 }
6906 }
6907
6908 if (prev)
6909 prev->next = temp;
6910 else
6911 ipp->attrs = temp;
6912
6913 ipp->current = temp;
6914 ipp->prev = prev;
6915
6916 if (ipp->last == *attr)
6917 ipp->last = temp;
6918
6919 *attr = temp;
6920 }
6921
6922 /*
6923 * Return the value element...
6924 */
6925
6926 if (element >= temp->num_values)
6927 temp->num_values = element + 1;
6928
6929 return (temp->values + element);
6930 }
6931
6932
6933 /*
6934 * 'ipp_write_file()' - Write IPP data to a file.
6935 */
6936
6937 static ssize_t /* O - Number of bytes written */
6938 ipp_write_file(int *fd, /* I - File descriptor */
6939 ipp_uchar_t *buffer, /* I - Data to write */
6940 size_t length) /* I - Number of bytes to write */
6941 {
6942 #ifdef WIN32
6943 return ((ssize_t)write(*fd, buffer, (unsigned)length));
6944 #else
6945 return (write(*fd, buffer, length));
6946 #endif /* WIN32 */
6947 }