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