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