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