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