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