• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Internet Printing Protocol functions for CUPS.
3  *
4  * Copyright © 2007-2019 by Apple Inc.
5  * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
6  *
7  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
8  * information.
9  */
10 
11 /*
12  * Include necessary headers...
13  */
14 
15 #include "cups-private.h"
16 #include "debug-internal.h"
17 #include <regex.h>
18 #ifdef _WIN32
19 #  include <io.h>
20 #endif /* _WIN32 */
21 
22 
23 /*
24  * Local functions...
25  */
26 
27 static ipp_attribute_t	*ipp_add_attr(ipp_t *ipp, const char *name,
28 			              ipp_tag_t  group_tag, ipp_tag_t value_tag,
29 			              int num_values);
30 static void		ipp_free_values(ipp_attribute_t *attr, int element,
31 			                int count);
32 static char		*ipp_get_code(const char *locale, char *buffer, size_t bufsize) _CUPS_NONNULL(1,2);
33 static char		*ipp_lang_code(const char *locale, char *buffer, size_t bufsize) _CUPS_NONNULL(1,2);
34 static size_t		ipp_length(ipp_t *ipp, int collection);
35 static ssize_t		ipp_read_http(http_t *http, ipp_uchar_t *buffer,
36 			              size_t length);
37 static ssize_t		ipp_read_file(int *fd, ipp_uchar_t *buffer,
38 			              size_t length);
39 static void		ipp_set_error(ipp_status_t status, const char *format,
40 			              ...);
41 static _ipp_value_t	*ipp_set_value(ipp_t *ipp, ipp_attribute_t **attr,
42 			               int element);
43 static ssize_t		ipp_write_file(int *fd, ipp_uchar_t *buffer,
44 			               size_t length);
45 
46 
47 /*
48  * '_cupsBufferGet()' - Get a read/write buffer.
49  */
50 
51 char *					/* O - Buffer */
_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   ipp_attribute_t	*attr;		/* Current attribute */
2871   ipp_tag_t		tag;		/* Current tag */
2872   ipp_tag_t		value_tag;	/* Current value tag */
2873   _ipp_value_t		*value;		/* Current value */
2874 
2875 
2876   DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)src, (void *)cb, blocking, (void *)parent, (void *)ipp));
2877   DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp ? ipp->state : IPP_STATE_ERROR));
2878 
2879   if (!src || !ipp)
2880     return (IPP_STATE_ERROR);
2881 
2882   if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
2883   {
2884     DEBUG_puts("1ippReadIO: Unable to get read buffer.");
2885     return (IPP_STATE_ERROR);
2886   }
2887 
2888   switch (ipp->state)
2889   {
2890     case IPP_STATE_IDLE :
2891         ipp->state ++; /* Avoid common problem... */
2892 
2893     case IPP_STATE_HEADER :
2894         if (parent == NULL)
2895 	{
2896 	 /*
2897           * Get the request header...
2898 	  */
2899 
2900           if ((*cb)(src, buffer, 8) < 8)
2901 	  {
2902 	    DEBUG_puts("1ippReadIO: Unable to read header.");
2903 	    _cupsBufferRelease((char *)buffer);
2904 	    return (IPP_STATE_ERROR);
2905 	  }
2906 
2907 	 /*
2908           * Then copy the request header over...
2909 	  */
2910 
2911           ipp->request.any.version[0]  = buffer[0];
2912           ipp->request.any.version[1]  = buffer[1];
2913           ipp->request.any.op_status   = (buffer[2] << 8) | buffer[3];
2914           ipp->request.any.request_id  = (((((buffer[4] << 8) | buffer[5]) << 8) |
2915 	                        	 buffer[6]) << 8) | buffer[7];
2916 
2917           DEBUG_printf(("2ippReadIO: version=%d.%d", buffer[0], buffer[1]));
2918 	  DEBUG_printf(("2ippReadIO: op_status=%04x",
2919 	                ipp->request.any.op_status));
2920 	  DEBUG_printf(("2ippReadIO: request_id=%d",
2921 	                ipp->request.any.request_id));
2922         }
2923 
2924         ipp->state   = IPP_STATE_ATTRIBUTE;
2925 	ipp->current = NULL;
2926 	ipp->curtag  = IPP_TAG_ZERO;
2927 	ipp->prev    = ipp->last;
2928 
2929        /*
2930         * If blocking is disabled, stop here...
2931 	*/
2932 
2933         if (!blocking)
2934 	  break;
2935 
2936     case IPP_STATE_ATTRIBUTE :
2937         for (;;)
2938 	{
2939 	  if ((*cb)(src, buffer, 1) < 1)
2940 	  {
2941 	    DEBUG_puts("1ippReadIO: Callback returned EOF/error");
2942 	    _cupsBufferRelease((char *)buffer);
2943 	    return (IPP_STATE_ERROR);
2944 	  }
2945 
2946 	  DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev));
2947 
2948 	 /*
2949 	  * Read this attribute...
2950 	  */
2951 
2952           tag = (ipp_tag_t)buffer[0];
2953           if (tag == IPP_TAG_EXTENSION)
2954           {
2955            /*
2956             * Read 32-bit "extension" tag...
2957             */
2958 
2959 	    if ((*cb)(src, buffer, 4) < 4)
2960 	    {
2961 	      DEBUG_puts("1ippReadIO: Callback returned EOF/error");
2962 	      _cupsBufferRelease((char *)buffer);
2963 	      return (IPP_STATE_ERROR);
2964 	    }
2965 
2966 	    tag = (ipp_tag_t)((((((buffer[0] << 8) | buffer[1]) << 8) |
2967 	                        buffer[2]) << 8) | buffer[3]);
2968 
2969             if (tag & IPP_TAG_CUPS_CONST)
2970             {
2971              /*
2972               * Fail if the high bit is set in the tag...
2973               */
2974 
2975 	      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
2976 	      DEBUG_printf(("1ippReadIO: bad tag 0x%x.", tag));
2977 	      _cupsBufferRelease((char *)buffer);
2978 	      return (IPP_STATE_ERROR);
2979             }
2980           }
2981 
2982 	  if (tag == IPP_TAG_END)
2983 	  {
2984 	   /*
2985 	    * No more attributes left...
2986 	    */
2987 
2988             DEBUG_puts("2ippReadIO: IPP_TAG_END.");
2989 
2990 	    ipp->state = IPP_STATE_DATA;
2991 	    break;
2992 	  }
2993 	  else if (tag == IPP_TAG_ZERO || (tag == IPP_TAG_OPERATION && ipp->curtag != IPP_TAG_ZERO))
2994 	  {
2995 	    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid group tag."), 1);
2996 	    DEBUG_printf(("1ippReadIO: bad tag 0x%02x.", tag));
2997 	    _cupsBufferRelease((char *)buffer);
2998 	    return (IPP_STATE_ERROR);
2999 	  }
3000           else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
3001 	  {
3002 	   /*
3003 	    * Group tag...  Set the current group and continue...
3004 	    */
3005 
3006             if (ipp->curtag == tag)
3007 	      ipp->prev = ippAddSeparator(ipp);
3008             else if (ipp->current)
3009 	      ipp->prev = ipp->current;
3010 
3011 	    ipp->curtag  = tag;
3012 	    ipp->current = NULL;
3013 	    DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag, ippTagString(tag), (void *)ipp->prev));
3014 	    continue;
3015 	  }
3016 
3017           DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag,
3018 	                ippTagString(tag)));
3019 
3020          /*
3021 	  * Get the name...
3022 	  */
3023 
3024           if ((*cb)(src, buffer, 2) < 2)
3025 	  {
3026 	    DEBUG_puts("1ippReadIO: unable to read name length.");
3027 	    _cupsBufferRelease((char *)buffer);
3028 	    return (IPP_STATE_ERROR);
3029 	  }
3030 
3031           n = (buffer[0] << 8) | buffer[1];
3032 
3033           if (n >= IPP_BUF_SIZE)
3034 	  {
3035 	    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP name larger than 32767 bytes."), 1);
3036 	    DEBUG_printf(("1ippReadIO: bad name length %d.", n));
3037 	    _cupsBufferRelease((char *)buffer);
3038 	    return (IPP_STATE_ERROR);
3039 	  }
3040 
3041           DEBUG_printf(("2ippReadIO: name length=%d", n));
3042 
3043           if (n && parent)
3044           {
3045             _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid named IPP attribute in collection."), 1);
3046             DEBUG_puts("1ippReadIO: bad attribute name in collection.");
3047             return (IPP_STATE_ERROR);
3048           }
3049           else if (n == 0 && tag != IPP_TAG_MEMBERNAME && tag != IPP_TAG_END_COLLECTION)
3050 	  {
3051 	   /*
3052 	    * More values for current attribute...
3053 	    */
3054 
3055             if (ipp->current == NULL)
3056 	    {
3057 	      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP attribute has no name."), 1);
3058 	      DEBUG_puts("1ippReadIO: Attribute without name and no current.");
3059 	      _cupsBufferRelease((char *)buffer);
3060 	      return (IPP_STATE_ERROR);
3061 	    }
3062 
3063             attr      = ipp->current;
3064 	    value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK);
3065 
3066 	   /*
3067 	    * Make sure we aren't adding a new value of a different
3068 	    * type...
3069 	    */
3070 
3071 	    if (value_tag == IPP_TAG_ZERO)
3072 	    {
3073 	     /*
3074 	      * Setting the value of a collection member...
3075 	      */
3076 
3077 	      attr->value_tag = tag;
3078 	    }
3079 	    else if (value_tag == IPP_TAG_TEXTLANG ||
3080 	             value_tag == IPP_TAG_NAMELANG ||
3081 		     (value_tag >= IPP_TAG_TEXT &&
3082 		      value_tag <= IPP_TAG_MIMETYPE))
3083             {
3084 	     /*
3085 	      * String values can sometimes come across in different
3086 	      * forms; accept sets of differing values...
3087 	      */
3088 
3089 	      if (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG &&
3090 	          (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE) &&
3091 		  tag != IPP_TAG_NOVALUE)
3092 	      {
3093 		_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3094 		              _("IPP 1setOf attribute with incompatible value "
3095 		                "tags."), 1);
3096 		DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3097 			      value_tag, ippTagString(value_tag), tag,
3098 			      ippTagString(tag)));
3099 		_cupsBufferRelease((char *)buffer);
3100 	        return (IPP_STATE_ERROR);
3101 	      }
3102 
3103               if (value_tag != tag)
3104               {
3105                 DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.",
3106                               attr->name, ippTagString(value_tag), ippTagString(tag)));
3107 		ippSetValueTag(ipp, &attr, tag);
3108 	      }
3109             }
3110 	    else if (value_tag == IPP_TAG_INTEGER ||
3111 	             value_tag == IPP_TAG_RANGE)
3112             {
3113 	     /*
3114 	      * Integer and rangeOfInteger values can sometimes be mixed; accept
3115 	      * sets of differing values...
3116 	      */
3117 
3118 	      if (tag != IPP_TAG_INTEGER && tag != IPP_TAG_RANGE)
3119 	      {
3120 		_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3121 		              _("IPP 1setOf attribute with incompatible value "
3122 		                "tags."), 1);
3123 		DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3124 			      value_tag, ippTagString(value_tag), tag,
3125 			      ippTagString(tag)));
3126 		_cupsBufferRelease((char *)buffer);
3127 	        return (IPP_STATE_ERROR);
3128 	      }
3129 
3130               if (value_tag == IPP_TAG_INTEGER && tag == IPP_TAG_RANGE)
3131               {
3132                /*
3133                 * Convert integer values to rangeOfInteger values...
3134                 */
3135 
3136 		DEBUG_printf(("1ippReadIO: Converting %s attribute to "
3137 		              "rangeOfInteger.", attr->name));
3138                 ippSetValueTag(ipp, &attr, IPP_TAG_RANGE);
3139               }
3140             }
3141 	    else if (value_tag != tag)
3142 	    {
3143 	      _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3144 			    _("IPP 1setOf attribute with incompatible value "
3145 			      "tags."), 1);
3146 	      DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
3147 	                    value_tag, ippTagString(value_tag), tag,
3148 			    ippTagString(tag)));
3149 	      _cupsBufferRelease((char *)buffer);
3150 	      return (IPP_STATE_ERROR);
3151             }
3152 
3153            /*
3154 	    * Finally, reallocate the attribute array as needed...
3155 	    */
3156 
3157 	    if ((value = ipp_set_value(ipp, &attr, attr->num_values)) == NULL)
3158 	    {
3159 	      _cupsBufferRelease((char *)buffer);
3160 	      return (IPP_STATE_ERROR);
3161 	    }
3162 	  }
3163 	  else if (tag == IPP_TAG_MEMBERNAME)
3164 	  {
3165 	   /*
3166 	    * Name must be length 0!
3167 	    */
3168 
3169 	    if (n)
3170 	    {
3171 	      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP member name is not empty."), 1);
3172 	      DEBUG_puts("1ippReadIO: member name not empty.");
3173 	      _cupsBufferRelease((char *)buffer);
3174 	      return (IPP_STATE_ERROR);
3175 	    }
3176 
3177             if (ipp->current)
3178 	      ipp->prev = ipp->current;
3179 
3180 	    attr = ipp->current = ipp_add_attr(ipp, NULL, ipp->curtag, IPP_TAG_ZERO, 1);
3181 	    if (!attr)
3182 	    {
3183 	      _cupsSetHTTPError(HTTP_STATUS_ERROR);
3184 	      DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3185 	      _cupsBufferRelease((char *)buffer);
3186 	      return (IPP_STATE_ERROR);
3187 	    }
3188 
3189 	    DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev));
3190 
3191 	    value = attr->values;
3192 	  }
3193 	  else if (tag != IPP_TAG_END_COLLECTION)
3194 	  {
3195 	   /*
3196 	    * New attribute; read the name and add it...
3197 	    */
3198 
3199 	    if ((*cb)(src, buffer, (size_t)n) < n)
3200 	    {
3201 	      DEBUG_puts("1ippReadIO: unable to read name.");
3202 	      _cupsBufferRelease((char *)buffer);
3203 	      return (IPP_STATE_ERROR);
3204 	    }
3205 
3206 	    buffer[n] = '\0';
3207 
3208             if (ipp->current)
3209 	      ipp->prev = ipp->current;
3210 
3211 	    if ((attr = ipp->current = ipp_add_attr(ipp, (char *)buffer, ipp->curtag, tag,
3212 	                                            1)) == NULL)
3213 	    {
3214 	      _cupsSetHTTPError(HTTP_STATUS_ERROR);
3215 	      DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3216 	      _cupsBufferRelease((char *)buffer);
3217 	      return (IPP_STATE_ERROR);
3218 	    }
3219 
3220 	    DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, ipp->prev=%p", buffer, (void *)ipp->current, (void *)ipp->prev));
3221 
3222 	    value = attr->values;
3223 	  }
3224 	  else
3225 	  {
3226 	    attr  = NULL;
3227 	    value = NULL;
3228 	  }
3229 
3230 	  if ((*cb)(src, buffer, 2) < 2)
3231 	  {
3232 	    DEBUG_puts("1ippReadIO: unable to read value length.");
3233 	    _cupsBufferRelease((char *)buffer);
3234 	    return (IPP_STATE_ERROR);
3235 	  }
3236 
3237 	  n = (buffer[0] << 8) | buffer[1];
3238           DEBUG_printf(("2ippReadIO: value length=%d", n));
3239 
3240 	  if (n >= IPP_BUF_SIZE)
3241 	  {
3242 	    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3243 			  _("IPP value larger than 32767 bytes."), 1);
3244 	    DEBUG_printf(("1ippReadIO: bad value length %d.", n));
3245 	    _cupsBufferRelease((char *)buffer);
3246 	    return (IPP_STATE_ERROR);
3247 	  }
3248 
3249 	  switch (tag)
3250 	  {
3251 	    case IPP_TAG_INTEGER :
3252 	    case IPP_TAG_ENUM :
3253 		if (n != 4)
3254 		{
3255 		  if (tag == IPP_TAG_INTEGER)
3256 		    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3257 				  _("IPP integer value not 4 bytes."), 1);
3258 		  else
3259 		    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3260 				  _("IPP enum value not 4 bytes."), 1);
3261 		  DEBUG_printf(("1ippReadIO: bad integer value length %d.", n));
3262 		  _cupsBufferRelease((char *)buffer);
3263 		  return (IPP_STATE_ERROR);
3264 		}
3265 
3266 	        if ((*cb)(src, buffer, 4) < 4)
3267 		{
3268 	          DEBUG_puts("1ippReadIO: Unable to read integer value.");
3269 		  _cupsBufferRelease((char *)buffer);
3270 		  return (IPP_STATE_ERROR);
3271 		}
3272 
3273 		n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3274 		    buffer[3];
3275 
3276                 if (attr->value_tag == IPP_TAG_RANGE)
3277                   value->range.lower = value->range.upper = n;
3278                 else
3279 		  value->integer = n;
3280 	        break;
3281 
3282 	    case IPP_TAG_BOOLEAN :
3283 		if (n != 1)
3284 		{
3285 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP boolean value not 1 byte."),
3286 		                1);
3287 		  DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n));
3288 		  _cupsBufferRelease((char *)buffer);
3289 		  return (IPP_STATE_ERROR);
3290 		}
3291 
3292 	        if ((*cb)(src, buffer, 1) < 1)
3293 		{
3294 	          DEBUG_puts("1ippReadIO: Unable to read boolean value.");
3295 		  _cupsBufferRelease((char *)buffer);
3296 		  return (IPP_STATE_ERROR);
3297 		}
3298 
3299                 value->boolean = (char)buffer[0];
3300 	        break;
3301 
3302 	    case IPP_TAG_UNSUPPORTED_VALUE :
3303 	    case IPP_TAG_DEFAULT :
3304 	    case IPP_TAG_UNKNOWN :
3305 	    case IPP_TAG_NOVALUE :
3306 	    case IPP_TAG_NOTSETTABLE :
3307 	    case IPP_TAG_DELETEATTR :
3308 	    case IPP_TAG_ADMINDEFINE :
3309 	       /*
3310 	        * These value types are not supposed to have values, however
3311 		* some vendors (Brother) do not implement IPP correctly and so
3312 		* we need to map non-empty values to text...
3313 		*/
3314 
3315 	        if (attr->value_tag == tag)
3316 		{
3317 		  if (n == 0)
3318 		    break;
3319 
3320 		  attr->value_tag = IPP_TAG_TEXT;
3321 		}
3322 
3323 	    case IPP_TAG_TEXT :
3324 	    case IPP_TAG_NAME :
3325 	    case IPP_TAG_RESERVED_STRING :
3326 	    case IPP_TAG_KEYWORD :
3327 	    case IPP_TAG_URI :
3328 	    case IPP_TAG_URISCHEME :
3329 	    case IPP_TAG_CHARSET :
3330 	    case IPP_TAG_LANGUAGE :
3331 	    case IPP_TAG_MIMETYPE :
3332 	        if (n > 0)
3333 	        {
3334 		  if ((*cb)(src, buffer, (size_t)n) < n)
3335 		  {
3336 		    DEBUG_puts("1ippReadIO: unable to read string value.");
3337 		    _cupsBufferRelease((char *)buffer);
3338 		    return (IPP_STATE_ERROR);
3339 		  }
3340 		}
3341 
3342 		buffer[n] = '\0';
3343 		value->string.text = _cupsStrAlloc((char *)buffer);
3344 		DEBUG_printf(("2ippReadIO: value=\"%s\"", value->string.text));
3345 	        break;
3346 
3347 	    case IPP_TAG_DATE :
3348 		if (n != 11)
3349 		{
3350 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP date value not 11 bytes."), 1);
3351 		  DEBUG_printf(("1ippReadIO: bad date value length %d.", n));
3352 		  _cupsBufferRelease((char *)buffer);
3353 		  return (IPP_STATE_ERROR);
3354 		}
3355 
3356 	        if ((*cb)(src, value->date, 11) < 11)
3357 		{
3358 	          DEBUG_puts("1ippReadIO: Unable to read date value.");
3359 		  _cupsBufferRelease((char *)buffer);
3360 		  return (IPP_STATE_ERROR);
3361 		}
3362 	        break;
3363 
3364 	    case IPP_TAG_RESOLUTION :
3365 		if (n != 9)
3366 		{
3367 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3368 		                _("IPP resolution value not 9 bytes."), 1);
3369 		  DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n));
3370 		  _cupsBufferRelease((char *)buffer);
3371 		  return (IPP_STATE_ERROR);
3372 		}
3373 
3374 	        if ((*cb)(src, buffer, 9) < 9)
3375 		{
3376 	          DEBUG_puts("1ippReadIO: Unable to read resolution value.");
3377 		  _cupsBufferRelease((char *)buffer);
3378 		  return (IPP_STATE_ERROR);
3379 		}
3380 
3381                 value->resolution.xres =
3382 		    (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3383 		    buffer[3];
3384                 value->resolution.yres =
3385 		    (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
3386 		    buffer[7];
3387                 value->resolution.units =
3388 		    (ipp_res_t)buffer[8];
3389 	        break;
3390 
3391 	    case IPP_TAG_RANGE :
3392 		if (n != 8)
3393 		{
3394 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3395 		                _("IPP rangeOfInteger value not 8 bytes."), 1);
3396 		  DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length "
3397 		                "%d.", n));
3398 		  _cupsBufferRelease((char *)buffer);
3399 		  return (IPP_STATE_ERROR);
3400 		}
3401 
3402 	        if ((*cb)(src, buffer, 8) < 8)
3403 		{
3404 	          DEBUG_puts("1ippReadIO: Unable to read range value.");
3405 		  _cupsBufferRelease((char *)buffer);
3406 		  return (IPP_STATE_ERROR);
3407 		}
3408 
3409                 value->range.lower =
3410 		    (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3411 		    buffer[3];
3412                 value->range.upper =
3413 		    (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
3414 		    buffer[7];
3415 	        break;
3416 
3417 	    case IPP_TAG_TEXTLANG :
3418 	    case IPP_TAG_NAMELANG :
3419 	        if (n < 4)
3420 		{
3421 		  if (tag == IPP_TAG_TEXTLANG)
3422 		    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3423 		                  _("IPP textWithLanguage value less than "
3424 		                    "minimum 4 bytes."), 1);
3425 		  else
3426 		    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3427 		                  _("IPP nameWithLanguage value less than "
3428 		                    "minimum 4 bytes."), 1);
3429 		  DEBUG_printf(("1ippReadIO: bad stringWithLanguage value "
3430 		                "length %d.", n));
3431 		  _cupsBufferRelease((char *)buffer);
3432 		  return (IPP_STATE_ERROR);
3433 		}
3434 
3435 	        if ((*cb)(src, buffer, (size_t)n) < n)
3436 		{
3437 	          DEBUG_puts("1ippReadIO: Unable to read string w/language "
3438 		             "value.");
3439 		  _cupsBufferRelease((char *)buffer);
3440 		  return (IPP_STATE_ERROR);
3441 		}
3442 
3443                 bufptr = buffer;
3444 
3445 	       /*
3446 	        * text-with-language and name-with-language are composite
3447 		* values:
3448 		*
3449 		*    language-length
3450 		*    language
3451 		*    text-length
3452 		*    text
3453 		*/
3454 
3455 		n = (bufptr[0] << 8) | bufptr[1];
3456 
3457 		if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) || n >= (int)sizeof(string))
3458 		{
3459 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3460 		                _("IPP language length overflows value."), 1);
3461 		  DEBUG_printf(("1ippReadIO: bad language value length %d.",
3462 		                n));
3463 		  _cupsBufferRelease((char *)buffer);
3464 		  return (IPP_STATE_ERROR);
3465 		}
3466 		else if (n >= IPP_MAX_LANGUAGE)
3467 		{
3468 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3469 		                _("IPP language length too large."), 1);
3470 		  DEBUG_printf(("1ippReadIO: bad language value length %d.",
3471 		                n));
3472 		  _cupsBufferRelease((char *)buffer);
3473 		  return (IPP_STATE_ERROR);
3474 		}
3475 
3476 		memcpy(string, bufptr + 2, (size_t)n);
3477 		string[n] = '\0';
3478 
3479 		value->string.language = _cupsStrAlloc((char *)string);
3480 
3481                 bufptr += 2 + n;
3482 		n = (bufptr[0] << 8) | bufptr[1];
3483 
3484 		if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE))
3485 		{
3486 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3487 		                _("IPP string length overflows value."), 1);
3488 		  DEBUG_printf(("1ippReadIO: bad string value length %d.", n));
3489 		  _cupsBufferRelease((char *)buffer);
3490 		  return (IPP_STATE_ERROR);
3491 		}
3492 
3493 		bufptr[2 + n] = '\0';
3494                 value->string.text = _cupsStrAlloc((char *)bufptr + 2);
3495 	        break;
3496 
3497             case IPP_TAG_BEGIN_COLLECTION :
3498 	       /*
3499 	        * Oh, boy, here comes a collection value, so read it...
3500 		*/
3501 
3502                 value->collection = ippNew();
3503 
3504                 if (n > 0)
3505 		{
3506 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3507 		                _("IPP begCollection value not 0 bytes."), 1);
3508 	          DEBUG_puts("1ippReadIO: begCollection tag with value length "
3509 		             "> 0.");
3510 		  _cupsBufferRelease((char *)buffer);
3511 		  return (IPP_STATE_ERROR);
3512 		}
3513 
3514 		if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_STATE_ERROR)
3515 		{
3516 	          DEBUG_puts("1ippReadIO: Unable to read collection value.");
3517 		  _cupsBufferRelease((char *)buffer);
3518 		  return (IPP_STATE_ERROR);
3519 		}
3520                 break;
3521 
3522             case IPP_TAG_END_COLLECTION :
3523 		_cupsBufferRelease((char *)buffer);
3524 
3525                 if (n > 0)
3526 		{
3527 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3528 		                _("IPP endCollection value not 0 bytes."), 1);
3529 	          DEBUG_puts("1ippReadIO: endCollection tag with value length "
3530 		             "> 0.");
3531 		  return (IPP_STATE_ERROR);
3532 		}
3533 
3534 	        DEBUG_puts("1ippReadIO: endCollection tag...");
3535 		return (ipp->state = IPP_STATE_DATA);
3536 
3537             case IPP_TAG_MEMBERNAME :
3538 	       /*
3539 	        * The value the name of the member in the collection, which
3540 		* we need to carry over...
3541 		*/
3542 
3543                 if (!attr)
3544                 {
3545 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3546 		                _("IPP memberName with no attribute."), 1);
3547 	          DEBUG_puts("1ippReadIO: Member name without attribute.");
3548 		  _cupsBufferRelease((char *)buffer);
3549 		  return (IPP_STATE_ERROR);
3550                 }
3551 		else if (n == 0)
3552 		{
3553 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3554 		                _("IPP memberName value is empty."), 1);
3555 	          DEBUG_puts("1ippReadIO: Empty member name value.");
3556 		  _cupsBufferRelease((char *)buffer);
3557 		  return (IPP_STATE_ERROR);
3558 		}
3559 		else if ((*cb)(src, buffer, (size_t)n) < n)
3560 		{
3561 	          DEBUG_puts("1ippReadIO: Unable to read member name value.");
3562 		  _cupsBufferRelease((char *)buffer);
3563 		  return (IPP_STATE_ERROR);
3564 		}
3565 
3566 		buffer[n] = '\0';
3567 		attr->name = _cupsStrAlloc((char *)buffer);
3568 
3569                /*
3570 	        * Since collection members are encoded differently than
3571 		* regular attributes, make sure we don't start with an
3572 		* empty value...
3573 		*/
3574 
3575                 attr->num_values --;
3576 
3577 		DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr->name));
3578 		break;
3579 
3580             case IPP_TAG_STRING :
3581             default : /* Other unsupported values */
3582                 if (tag == IPP_TAG_STRING && n > IPP_MAX_LENGTH)
3583 		{
3584 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3585 		                _("IPP octetString length too large."), 1);
3586 		  DEBUG_printf(("1ippReadIO: bad octetString value length %d.",
3587 		                n));
3588 		  _cupsBufferRelease((char *)buffer);
3589 		  return (IPP_STATE_ERROR);
3590 		}
3591 
3592                 value->unknown.length = n;
3593 
3594 	        if (n > 0)
3595 		{
3596 		  if ((value->unknown.data = malloc((size_t)n)) == NULL)
3597 		  {
3598 		    _cupsSetHTTPError(HTTP_STATUS_ERROR);
3599 		    DEBUG_puts("1ippReadIO: Unable to allocate value");
3600 		    _cupsBufferRelease((char *)buffer);
3601 		    return (IPP_STATE_ERROR);
3602 		  }
3603 
3604 	          if ((*cb)(src, value->unknown.data, (size_t)n) < n)
3605 		  {
3606 	            DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
3607 		    _cupsBufferRelease((char *)buffer);
3608 		    return (IPP_STATE_ERROR);
3609 		  }
3610 		}
3611 		else
3612 		  value->unknown.data = NULL;
3613 	        break;
3614 	  }
3615 
3616 	 /*
3617           * If blocking is disabled, stop here...
3618 	  */
3619 
3620           if (!blocking)
3621 	    break;
3622 	}
3623         break;
3624 
3625     case IPP_STATE_DATA :
3626         break;
3627 
3628     default :
3629         break; /* anti-compiler-warning-code */
3630   }
3631 
3632   DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp->state));
3633   _cupsBufferRelease((char *)buffer);
3634 
3635   return (ipp->state);
3636 }
3637 
3638 
3639 /*
3640  * 'ippSetBoolean()' - Set a boolean value in an attribute.
3641  *
3642  * The @code ipp@ parameter refers to an IPP message previously created using
3643  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3644  *
3645  * The @code attr@ parameter may be modified as a result of setting the value.
3646  *
3647  * The @code element@ parameter specifies which value to set from 0 to
3648  * @code ippGetCount(attr)@.
3649  *
3650  * @since CUPS 1.6/macOS 10.8@
3651  */
3652 
3653 int					/* O  - 1 on success, 0 on failure */
ippSetBoolean(ipp_t * ipp,ipp_attribute_t ** attr,int element,int boolvalue)3654 ippSetBoolean(ipp_t           *ipp,	/* I  - IPP message */
3655               ipp_attribute_t **attr,	/* IO - IPP attribute */
3656               int             element,	/* I  - Value number (0-based) */
3657               int             boolvalue)/* I  - Boolean value */
3658 {
3659   _ipp_value_t	*value;			/* Current value */
3660 
3661 
3662  /*
3663   * Range check input...
3664   */
3665 
3666   if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BOOLEAN ||
3667       element < 0 || element > (*attr)->num_values)
3668     return (0);
3669 
3670  /*
3671   * Set the value and return...
3672   */
3673 
3674   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3675     value->boolean = (char)boolvalue;
3676 
3677   return (value != NULL);
3678 }
3679 
3680 
3681 /*
3682  * 'ippSetCollection()' - Set a collection value in an attribute.
3683  *
3684  * The @code ipp@ parameter refers to an IPP message previously created using
3685  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3686  *
3687  * The @code attr@ parameter may be modified as a result of setting the value.
3688  *
3689  * The @code element@ parameter specifies which value to set from 0 to
3690  * @code ippGetCount(attr)@.
3691  *
3692  * @since CUPS 1.6/macOS 10.8@
3693  */
3694 
3695 int					/* O  - 1 on success, 0 on failure */
ippSetCollection(ipp_t * ipp,ipp_attribute_t ** attr,int element,ipp_t * colvalue)3696 ippSetCollection(
3697     ipp_t           *ipp,		/* I  - IPP message */
3698     ipp_attribute_t **attr,		/* IO - IPP attribute */
3699     int             element,		/* I  - Value number (0-based) */
3700     ipp_t           *colvalue)		/* I  - Collection value */
3701 {
3702   _ipp_value_t	*value;			/* Current value */
3703 
3704 
3705  /*
3706   * Range check input...
3707   */
3708 
3709   if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BEGIN_COLLECTION ||
3710       element < 0 || element > (*attr)->num_values || !colvalue)
3711     return (0);
3712 
3713  /*
3714   * Set the value and return...
3715   */
3716 
3717   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3718   {
3719     if (value->collection)
3720       ippDelete(value->collection);
3721 
3722     value->collection = colvalue;
3723     colvalue->use ++;
3724   }
3725 
3726   return (value != NULL);
3727 }
3728 
3729 
3730 /*
3731  * 'ippSetDate()' - Set a dateTime value in an attribute.
3732  *
3733  * The @code ipp@ parameter refers to an IPP message previously created using
3734  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3735  *
3736  * The @code attr@ parameter may be modified as a result of setting the value.
3737  *
3738  * The @code element@ parameter specifies which value to set from 0 to
3739  * @code ippGetCount(attr)@.
3740  *
3741  * @since CUPS 1.6/macOS 10.8@
3742  */
3743 
3744 int					/* O  - 1 on success, 0 on failure */
ippSetDate(ipp_t * ipp,ipp_attribute_t ** attr,int element,const ipp_uchar_t * datevalue)3745 ippSetDate(ipp_t             *ipp,	/* I  - IPP message */
3746            ipp_attribute_t   **attr,	/* IO - IPP attribute */
3747            int               element,	/* I  - Value number (0-based) */
3748            const ipp_uchar_t *datevalue)/* I  - dateTime value */
3749 {
3750   _ipp_value_t	*value;			/* Current value */
3751 
3752 
3753  /*
3754   * Range check input...
3755   */
3756 
3757   if (!ipp || !attr || !*attr || ((*attr)->value_tag != IPP_TAG_DATE && (*attr)->value_tag != IPP_TAG_NOVALUE && (*attr)->value_tag != IPP_TAG_UNKNOWN) || element < 0 || element > (*attr)->num_values || !datevalue)
3758     return (0);
3759 
3760  /*
3761   * Set the value and return...
3762   */
3763 
3764   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3765     memcpy(value->date, datevalue, sizeof(value->date));
3766 
3767   return (value != NULL);
3768 }
3769 
3770 
3771 /*
3772  * 'ippSetGroupTag()' - Set the group tag of an attribute.
3773  *
3774  * The @code ipp@ parameter refers to an IPP message previously created using
3775  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3776  *
3777  * The @code attr@ parameter may be modified as a result of setting the value.
3778  *
3779  * The @code group@ parameter specifies the IPP attribute group tag: none
3780  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
3781  * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
3782  * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
3783  * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
3784  *
3785  * @since CUPS 1.6/macOS 10.8@
3786  */
3787 
3788 int					/* O  - 1 on success, 0 on failure */
ippSetGroupTag(ipp_t * ipp,ipp_attribute_t ** attr,ipp_tag_t group_tag)3789 ippSetGroupTag(
3790     ipp_t           *ipp,		/* I  - IPP message */
3791     ipp_attribute_t **attr,		/* IO - Attribute */
3792     ipp_tag_t       group_tag)		/* I  - Group tag */
3793 {
3794  /*
3795   * Range check input - group tag must be 0x01 to 0x0F, per RFC 8011...
3796   */
3797 
3798   if (!ipp || !attr || !*attr ||
3799       group_tag < IPP_TAG_ZERO || group_tag == IPP_TAG_END ||
3800       group_tag >= IPP_TAG_UNSUPPORTED_VALUE)
3801     return (0);
3802 
3803  /*
3804   * Set the group tag and return...
3805   */
3806 
3807   (*attr)->group_tag = group_tag;
3808 
3809   return (1);
3810 }
3811 
3812 
3813 /*
3814  * 'ippSetInteger()' - Set an integer or enum value in an attribute.
3815  *
3816  * The @code ipp@ parameter refers to an IPP message previously created using
3817  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3818  *
3819  * The @code attr@ parameter may be modified as a result of setting the value.
3820  *
3821  * The @code element@ parameter specifies which value to set from 0 to
3822  * @code ippGetCount(attr)@.
3823  *
3824  * @since CUPS 1.6/macOS 10.8@
3825  */
3826 
3827 int					/* O  - 1 on success, 0 on failure */
ippSetInteger(ipp_t * ipp,ipp_attribute_t ** attr,int element,int intvalue)3828 ippSetInteger(ipp_t           *ipp,	/* I  - IPP message */
3829               ipp_attribute_t **attr,	/* IO - IPP attribute */
3830               int             element,	/* I  - Value number (0-based) */
3831               int             intvalue)	/* I  - Integer/enum value */
3832 {
3833   _ipp_value_t	*value;			/* Current value */
3834 
3835 
3836  /*
3837   * Range check input...
3838   */
3839 
3840   if (!ipp || !attr || !*attr || ((*attr)->value_tag != IPP_TAG_INTEGER && (*attr)->value_tag != IPP_TAG_ENUM && (*attr)->value_tag != IPP_TAG_NOVALUE && (*attr)->value_tag != IPP_TAG_UNKNOWN) || element < 0 || element > (*attr)->num_values)
3841     return (0);
3842 
3843  /*
3844   * Set the value and return...
3845   */
3846 
3847   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3848   {
3849     if ((*attr)->value_tag != IPP_TAG_ENUM)
3850       (*attr)->value_tag = IPP_TAG_INTEGER;
3851 
3852     value->integer = intvalue;
3853   }
3854 
3855   return (value != NULL);
3856 }
3857 
3858 
3859 /*
3860  * 'ippSetName()' - Set the name of an attribute.
3861  *
3862  * The @code ipp@ parameter refers to an IPP message previously created using
3863  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3864  *
3865  * The @code attr@ parameter may be modified as a result of setting the value.
3866  *
3867  * @since CUPS 1.6/macOS 10.8@
3868  */
3869 
3870 int					/* O  - 1 on success, 0 on failure */
ippSetName(ipp_t * ipp,ipp_attribute_t ** attr,const char * name)3871 ippSetName(ipp_t           *ipp,	/* I  - IPP message */
3872 	   ipp_attribute_t **attr,	/* IO - IPP attribute */
3873 	   const char      *name)	/* I  - Attribute name */
3874 {
3875   char	*temp;				/* Temporary name value */
3876 
3877 
3878  /*
3879   * Range check input...
3880   */
3881 
3882   if (!ipp || !attr || !*attr)
3883     return (0);
3884 
3885  /*
3886   * Set the value and return...
3887   */
3888 
3889   if ((temp = _cupsStrAlloc(name)) != NULL)
3890   {
3891     if ((*attr)->name)
3892       _cupsStrFree((*attr)->name);
3893 
3894     (*attr)->name = temp;
3895   }
3896 
3897   return (temp != NULL);
3898 }
3899 
3900 
3901 /*
3902  * 'ippSetOctetString()' - Set an octetString value in an IPP attribute.
3903  *
3904  * The @code ipp@ parameter refers to an IPP message previously created using
3905  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3906  *
3907  * The @code attr@ parameter may be modified as a result of setting the value.
3908  *
3909  * The @code element@ parameter specifies which value to set from 0 to
3910  * @code ippGetCount(attr)@.
3911  *
3912  * @since CUPS 1.7/macOS 10.9@
3913  */
3914 
3915 int					/* O  - 1 on success, 0 on failure */
ippSetOctetString(ipp_t * ipp,ipp_attribute_t ** attr,int element,const void * data,int datalen)3916 ippSetOctetString(
3917     ipp_t           *ipp,		/* I  - IPP message */
3918     ipp_attribute_t **attr,		/* IO - IPP attribute */
3919     int             element,		/* I  - Value number (0-based) */
3920     const void      *data,		/* I  - Pointer to octetString data */
3921     int             datalen)		/* I  - Length of octetString data */
3922 {
3923   _ipp_value_t	*value;			/* Current value */
3924 
3925 
3926  /*
3927   * Range check input...
3928   */
3929 
3930   if (!ipp || !attr || !*attr || ((*attr)->value_tag != IPP_TAG_STRING && (*attr)->value_tag != IPP_TAG_NOVALUE && (*attr)->value_tag != IPP_TAG_UNKNOWN) || element < 0 || element > (*attr)->num_values || datalen < 0 || datalen > IPP_MAX_LENGTH)
3931     return (0);
3932 
3933  /*
3934   * Set the value and return...
3935   */
3936 
3937   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3938   {
3939     if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST)
3940     {
3941      /*
3942       * Just copy the pointer...
3943       */
3944 
3945       value->unknown.data   = (void *)data;
3946       value->unknown.length = datalen;
3947     }
3948     else
3949     {
3950      /*
3951       * Copy the data...
3952       */
3953 
3954       (*attr)->value_tag = IPP_TAG_STRING;
3955 
3956       if (value->unknown.data)
3957       {
3958        /*
3959 	* Free previous data...
3960 	*/
3961 
3962 	free(value->unknown.data);
3963 
3964 	value->unknown.data   = NULL;
3965         value->unknown.length = 0;
3966       }
3967 
3968       if (datalen > 0)
3969       {
3970 	void	*temp;			/* Temporary data pointer */
3971 
3972 	if ((temp = malloc((size_t)datalen)) != NULL)
3973 	{
3974 	  memcpy(temp, data, (size_t)datalen);
3975 
3976 	  value->unknown.data   = temp;
3977 	  value->unknown.length = datalen;
3978 	}
3979 	else
3980 	  return (0);
3981       }
3982     }
3983   }
3984 
3985   return (value != NULL);
3986 }
3987 
3988 
3989 /*
3990  * 'ippSetOperation()' - Set the operation ID in an IPP request message.
3991  *
3992  * The @code ipp@ parameter refers to an IPP message previously created using
3993  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3994  *
3995  * @since CUPS 1.6/macOS 10.8@
3996  */
3997 
3998 int					/* O - 1 on success, 0 on failure */
ippSetOperation(ipp_t * ipp,ipp_op_t op)3999 ippSetOperation(ipp_t    *ipp,		/* I - IPP request message */
4000                 ipp_op_t op)		/* I - Operation ID */
4001 {
4002  /*
4003   * Range check input...
4004   */
4005 
4006   if (!ipp)
4007     return (0);
4008 
4009  /*
4010   * Set the operation and return...
4011   */
4012 
4013   ipp->request.op.operation_id = op;
4014 
4015   return (1);
4016 }
4017 
4018 
4019 /*
4020  * 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
4021  *
4022  * The @code ipp@ parameter refers to an IPP message previously created using
4023  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4024  *
4025  * The @code attr@ parameter may be modified as a result of setting the value.
4026  *
4027  * The @code element@ parameter specifies which value to set from 0 to
4028  * @code ippGetCount(attr)@.
4029  *
4030  * @since CUPS 1.6/macOS 10.8@
4031  */
4032 
4033 int					/* O  - 1 on success, 0 on failure */
ippSetRange(ipp_t * ipp,ipp_attribute_t ** attr,int element,int lowervalue,int uppervalue)4034 ippSetRange(ipp_t           *ipp,	/* I  - IPP message */
4035             ipp_attribute_t **attr,	/* IO - IPP attribute */
4036             int             element,	/* I  - Value number (0-based) */
4037 	    int             lowervalue,	/* I  - Lower bound for range */
4038 	    int             uppervalue)	/* I  - Upper bound for range */
4039 {
4040   _ipp_value_t	*value;			/* Current value */
4041 
4042 
4043  /*
4044   * Range check input...
4045   */
4046 
4047   if (!ipp || !attr || !*attr || ((*attr)->value_tag != IPP_TAG_RANGE && (*attr)->value_tag != IPP_TAG_NOVALUE && (*attr)->value_tag != IPP_TAG_UNKNOWN) || element < 0 || element > (*attr)->num_values || lowervalue > uppervalue)
4048     return (0);
4049 
4050  /*
4051   * Set the value and return...
4052   */
4053 
4054   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4055   {
4056     (*attr)->value_tag = IPP_TAG_RANGE;
4057     value->range.lower = lowervalue;
4058     value->range.upper = uppervalue;
4059   }
4060 
4061   return (value != NULL);
4062 }
4063 
4064 
4065 /*
4066  * 'ippSetRequestId()' - Set the request ID in an IPP message.
4067  *
4068  * The @code ipp@ parameter refers to an IPP message previously created using
4069  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4070  *
4071  * The @code request_id@ parameter must be greater than 0.
4072  *
4073  * @since CUPS 1.6/macOS 10.8@
4074  */
4075 
4076 int					/* O - 1 on success, 0 on failure */
ippSetRequestId(ipp_t * ipp,int request_id)4077 ippSetRequestId(ipp_t *ipp,		/* I - IPP message */
4078                 int   request_id)	/* I - Request ID */
4079 {
4080  /*
4081   * Range check input; not checking request_id values since ipptool wants to send
4082   * invalid values for conformance testing and a bad request_id does not affect the
4083   * encoding of a message...
4084   */
4085 
4086   if (!ipp)
4087     return (0);
4088 
4089  /*
4090   * Set the request ID and return...
4091   */
4092 
4093   ipp->request.any.request_id = request_id;
4094 
4095   return (1);
4096 }
4097 
4098 
4099 /*
4100  * 'ippSetResolution()' - Set a resolution value in an attribute.
4101  *
4102  * The @code ipp@ parameter refers to an IPP message previously created using
4103  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4104  *
4105  * The @code attr@ parameter may be modified as a result of setting the value.
4106  *
4107  * The @code element@ parameter specifies which value to set from 0 to
4108  * @code ippGetCount(attr)@.
4109  *
4110  * @since CUPS 1.6/macOS 10.8@
4111  */
4112 
4113 int					/* O  - 1 on success, 0 on failure */
ippSetResolution(ipp_t * ipp,ipp_attribute_t ** attr,int element,ipp_res_t unitsvalue,int xresvalue,int yresvalue)4114 ippSetResolution(
4115     ipp_t           *ipp,		/* I  - IPP message */
4116     ipp_attribute_t **attr,		/* IO - IPP attribute */
4117     int             element,		/* I  - Value number (0-based) */
4118     ipp_res_t       unitsvalue,		/* I  - Resolution units */
4119     int             xresvalue,		/* I  - Horizontal/cross feed resolution */
4120     int             yresvalue)		/* I  - Vertical/feed resolution */
4121 {
4122   _ipp_value_t	*value;			/* Current value */
4123 
4124 
4125  /*
4126   * Range check input...
4127   */
4128 
4129   if (!ipp || !attr || !*attr || ((*attr)->value_tag != IPP_TAG_RESOLUTION && (*attr)->value_tag != IPP_TAG_NOVALUE && (*attr)->value_tag != IPP_TAG_UNKNOWN) || element < 0 || element > (*attr)->num_values || xresvalue <= 0 || yresvalue <= 0 || unitsvalue < IPP_RES_PER_INCH || unitsvalue > IPP_RES_PER_CM)
4130     return (0);
4131 
4132  /*
4133   * Set the value and return...
4134   */
4135 
4136   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4137   {
4138     (*attr)->value_tag      = IPP_TAG_RESOLUTION;
4139     value->resolution.units = unitsvalue;
4140     value->resolution.xres  = xresvalue;
4141     value->resolution.yres  = yresvalue;
4142   }
4143 
4144   return (value != NULL);
4145 }
4146 
4147 
4148 /*
4149  * 'ippSetState()' - Set the current state of the IPP message.
4150  *
4151  * @since CUPS 1.6/macOS 10.8@
4152  */
4153 
4154 int					/* O - 1 on success, 0 on failure */
ippSetState(ipp_t * ipp,ipp_state_t state)4155 ippSetState(ipp_t       *ipp,		/* I - IPP message */
4156             ipp_state_t state)		/* I - IPP state value */
4157 {
4158  /*
4159   * Range check input...
4160   */
4161 
4162   if (!ipp)
4163     return (0);
4164 
4165  /*
4166   * Set the state and return...
4167   */
4168 
4169   ipp->state   = state;
4170   ipp->current = NULL;
4171 
4172   return (1);
4173 }
4174 
4175 
4176 /*
4177  * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
4178  *
4179  * The @code ipp@ parameter refers to an IPP message previously created using
4180  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4181  *
4182  * @since CUPS 1.6/macOS 10.8@
4183  */
4184 
4185 int					/* O - 1 on success, 0 on failure */
ippSetStatusCode(ipp_t * ipp,ipp_status_t status)4186 ippSetStatusCode(ipp_t        *ipp,	/* I - IPP response or event message */
4187                  ipp_status_t status)	/* I - Status code */
4188 {
4189  /*
4190   * Range check input...
4191   */
4192 
4193   if (!ipp)
4194     return (0);
4195 
4196  /*
4197   * Set the status code and return...
4198   */
4199 
4200   ipp->request.status.status_code = status;
4201 
4202   return (1);
4203 }
4204 
4205 
4206 /*
4207  * 'ippSetString()' - Set a string value in an attribute.
4208  *
4209  * The @code ipp@ parameter refers to an IPP message previously created using
4210  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4211  *
4212  * The @code attr@ parameter may be modified as a result of setting the value.
4213  *
4214  * The @code element@ parameter specifies which value to set from 0 to
4215  * @code ippGetCount(attr)@.
4216  *
4217  * @since CUPS 1.6/macOS 10.8@
4218  */
4219 
4220 int					/* O  - 1 on success, 0 on failure */
ippSetString(ipp_t * ipp,ipp_attribute_t ** attr,int element,const char * strvalue)4221 ippSetString(ipp_t           *ipp,	/* I  - IPP message */
4222              ipp_attribute_t **attr,	/* IO - IPP attribute */
4223              int             element,	/* I  - Value number (0-based) */
4224 	     const char      *strvalue)	/* I  - String value */
4225 {
4226   char		*temp;			/* Temporary string */
4227   _ipp_value_t	*value;			/* Current value */
4228   ipp_tag_t	value_tag;		/* Value tag */
4229 
4230 
4231  /*
4232   * Range check input...
4233   */
4234 
4235   if (attr && *attr)
4236     value_tag = (*attr)->value_tag & IPP_TAG_CUPS_MASK;
4237   else
4238     value_tag = IPP_TAG_ZERO;
4239 
4240   if (!ipp || !attr || !*attr || (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG && value_tag != IPP_TAG_NAMELANG && value_tag != IPP_TAG_NOVALUE && value_tag != IPP_TAG_UNKNOWN) || value_tag > IPP_TAG_MIMETYPE || element < 0 || element > (*attr)->num_values || !strvalue)
4241     return (0);
4242 
4243  /*
4244   * Set the value and return...
4245   */
4246 
4247   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4248   {
4249     if (value_tag == IPP_TAG_NOVALUE || value_tag == IPP_TAG_UNKNOWN)
4250       (*attr)->value_tag = IPP_TAG_KEYWORD;
4251 
4252     if (element > 0)
4253       value->string.language = (*attr)->values[0].string.language;
4254 
4255     if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST)
4256       value->string.text = (char *)strvalue;
4257     else if ((temp = _cupsStrAlloc(strvalue)) != NULL)
4258     {
4259       if (value->string.text)
4260         _cupsStrFree(value->string.text);
4261 
4262       value->string.text = temp;
4263     }
4264     else
4265       return (0);
4266   }
4267 
4268   return (value != NULL);
4269 }
4270 
4271 
4272 /*
4273  * 'ippSetStringf()' - Set a formatted string value of an attribute.
4274  *
4275  * The @code ipp@ parameter refers to an IPP message previously created using
4276  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4277  *
4278  * The @code attr@ parameter may be modified as a result of setting the value.
4279  *
4280  * The @code element@ parameter specifies which value to set from 0 to
4281  * @code ippGetCount(attr)@.
4282  *
4283  * The @code format@ parameter uses formatting characters compatible with the
4284  * printf family of standard functions.  Additional arguments follow it as
4285  * needed.  The formatted string is truncated as needed to the maximum length of
4286  * the corresponding value type.
4287  *
4288  * @since CUPS 1.7/macOS 10.9@
4289  */
4290 
4291 int					/* O  - 1 on success, 0 on failure */
ippSetStringf(ipp_t * ipp,ipp_attribute_t ** attr,int element,const char * format,...)4292 ippSetStringf(ipp_t           *ipp,	/* I  - IPP message */
4293               ipp_attribute_t **attr,	/* IO - IPP attribute */
4294               int             element,	/* I  - Value number (0-based) */
4295 	      const char      *format,	/* I  - Printf-style format string */
4296 	      ...)			/* I  - Additional arguments as needed */
4297 {
4298   int		ret;			/* Return value */
4299   va_list	ap;			/* Pointer to additional arguments */
4300 
4301 
4302   va_start(ap, format);
4303   ret = ippSetStringfv(ipp, attr, element, format, ap);
4304   va_end(ap);
4305 
4306   return (ret);
4307 }
4308 
4309 
4310 /*
4311  * 'ippSetStringf()' - Set a formatted string value of an attribute.
4312  *
4313  * The @code ipp@ parameter refers to an IPP message previously created using
4314  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4315  *
4316  * The @code attr@ parameter may be modified as a result of setting the value.
4317  *
4318  * The @code element@ parameter specifies which value to set from 0 to
4319  * @code ippGetCount(attr)@.
4320  *
4321  * The @code format@ parameter uses formatting characters compatible with the
4322  * printf family of standard functions.  Additional arguments follow it as
4323  * needed.  The formatted string is truncated as needed to the maximum length of
4324  * the corresponding value type.
4325  *
4326  * @since CUPS 1.7/macOS 10.9@
4327  */
4328 
4329 int					/* O  - 1 on success, 0 on failure */
ippSetStringfv(ipp_t * ipp,ipp_attribute_t ** attr,int element,const char * format,va_list ap)4330 ippSetStringfv(ipp_t           *ipp,	/* I  - IPP message */
4331                ipp_attribute_t **attr,	/* IO - IPP attribute */
4332                int             element,	/* I  - Value number (0-based) */
4333 	       const char      *format,	/* I  - Printf-style format string */
4334 	       va_list         ap)	/* I  - Pointer to additional arguments */
4335 {
4336   ipp_tag_t	value_tag;		/* Value tag */
4337   char		buffer[IPP_MAX_TEXT + 4];
4338 					/* Formatted text string */
4339   ssize_t	bytes,			/* Length of formatted value */
4340 		max_bytes;		/* Maximum number of bytes for value */
4341 
4342 
4343  /*
4344   * Range check input...
4345   */
4346 
4347   if (attr && *attr)
4348     value_tag = (*attr)->value_tag & IPP_TAG_CUPS_MASK;
4349   else
4350     value_tag = IPP_TAG_ZERO;
4351 
4352   if (!ipp || !attr || !*attr || (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG && value_tag != IPP_TAG_NAMELANG && value_tag != IPP_TAG_NOVALUE && value_tag != IPP_TAG_UNKNOWN) || value_tag > IPP_TAG_MIMETYPE || !format)
4353     return (0);
4354 
4355  /*
4356   * Format the string...
4357   */
4358 
4359   if (!strcmp(format, "%s"))
4360   {
4361    /*
4362     * Optimize the simple case...
4363     */
4364 
4365     const char *s = va_arg(ap, char *);
4366 
4367     if (!s)
4368       s = "(null)";
4369 
4370     bytes = (ssize_t)strlen(s);
4371     strlcpy(buffer, s, sizeof(buffer));
4372   }
4373   else
4374   {
4375    /*
4376     * Do a full formatting of the message...
4377     */
4378 
4379     if ((bytes = vsnprintf(buffer, sizeof(buffer), format, ap)) < 0)
4380       return (0);
4381   }
4382 
4383  /*
4384   * Limit the length of the string...
4385   */
4386 
4387   switch (value_tag)
4388   {
4389     default :
4390     case IPP_TAG_TEXT :
4391     case IPP_TAG_TEXTLANG :
4392         max_bytes = IPP_MAX_TEXT;
4393         break;
4394 
4395     case IPP_TAG_NAME :
4396     case IPP_TAG_NAMELANG :
4397         max_bytes = IPP_MAX_NAME;
4398         break;
4399 
4400     case IPP_TAG_CHARSET :
4401         max_bytes = IPP_MAX_CHARSET;
4402         break;
4403 
4404     case IPP_TAG_NOVALUE :
4405     case IPP_TAG_UNKNOWN :
4406     case IPP_TAG_KEYWORD :
4407         max_bytes = IPP_MAX_KEYWORD;
4408         break;
4409 
4410     case IPP_TAG_LANGUAGE :
4411         max_bytes = IPP_MAX_LANGUAGE;
4412         break;
4413 
4414     case IPP_TAG_MIMETYPE :
4415         max_bytes = IPP_MAX_MIMETYPE;
4416         break;
4417 
4418     case IPP_TAG_URI :
4419         max_bytes = IPP_MAX_URI;
4420         break;
4421 
4422     case IPP_TAG_URISCHEME :
4423         max_bytes = IPP_MAX_URISCHEME;
4424         break;
4425   }
4426 
4427   if (bytes >= max_bytes)
4428   {
4429     char	*bufmax,		/* Buffer at max_bytes */
4430 		*bufptr;		/* Pointer into buffer */
4431 
4432     bufptr = buffer + strlen(buffer) - 1;
4433     bufmax = buffer + max_bytes - 1;
4434 
4435     while (bufptr > bufmax)
4436     {
4437       if (*bufptr & 0x80)
4438       {
4439         while ((*bufptr & 0xc0) == 0x80 && bufptr > buffer)
4440           bufptr --;
4441       }
4442 
4443       bufptr --;
4444     }
4445 
4446     *bufptr = '\0';
4447   }
4448 
4449  /*
4450   * Set the formatted string and return...
4451   */
4452 
4453   return (ippSetString(ipp, attr, element, buffer));
4454 }
4455 
4456 
4457 /*
4458  * 'ippSetValueTag()' - Set the value tag of an attribute.
4459  *
4460  * The @code ipp@ parameter refers to an IPP message previously created using
4461  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4462  *
4463  * The @code attr@ parameter may be modified as a result of setting the value.
4464  *
4465  * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger
4466  * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name
4467  * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text
4468  * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage
4469  * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various
4470  * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes
4471  * will be rejected.
4472  *
4473  * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language
4474  * code in the "attributes-natural-language" attribute or, if not present, the language
4475  * code for the current locale.
4476  *
4477  * @since CUPS 1.6/macOS 10.8@
4478  */
4479 
4480 int					/* O  - 1 on success, 0 on failure */
ippSetValueTag(ipp_t * ipp,ipp_attribute_t ** attr,ipp_tag_t value_tag)4481 ippSetValueTag(
4482     ipp_t          *ipp,		/* I  - IPP message */
4483     ipp_attribute_t **attr,		/* IO - IPP attribute */
4484     ipp_tag_t       value_tag)		/* I  - Value tag */
4485 {
4486   int		i;			/* Looping var */
4487   _ipp_value_t	*value;			/* Current value */
4488   int		integer;		/* Current integer value */
4489   cups_lang_t	*language;		/* Current language */
4490   char		code[32];		/* Language code */
4491   ipp_tag_t	temp_tag;		/* Temporary value tag */
4492 
4493 
4494  /*
4495   * Range check input...
4496   */
4497 
4498   if (!ipp || !attr || !*attr)
4499     return (0);
4500 
4501  /*
4502   * If there is no change, return immediately...
4503   */
4504 
4505   if (value_tag == (*attr)->value_tag)
4506     return (1);
4507 
4508  /*
4509   * Otherwise implement changes as needed...
4510   */
4511 
4512   temp_tag = (ipp_tag_t)((int)((*attr)->value_tag) & IPP_TAG_CUPS_MASK);
4513 
4514   switch (value_tag)
4515   {
4516     case IPP_TAG_UNSUPPORTED_VALUE :
4517     case IPP_TAG_DEFAULT :
4518     case IPP_TAG_UNKNOWN :
4519     case IPP_TAG_NOVALUE :
4520     case IPP_TAG_NOTSETTABLE :
4521     case IPP_TAG_DELETEATTR :
4522     case IPP_TAG_ADMINDEFINE :
4523        /*
4524         * Free any existing values...
4525         */
4526 
4527         if ((*attr)->num_values > 0)
4528           ipp_free_values(*attr, 0, (*attr)->num_values);
4529 
4530        /*
4531         * Set out-of-band value...
4532         */
4533 
4534         (*attr)->value_tag = value_tag;
4535         break;
4536 
4537     case IPP_TAG_RANGE :
4538         if (temp_tag != IPP_TAG_INTEGER)
4539           return (0);
4540 
4541         for (i = (*attr)->num_values, value = (*attr)->values;
4542              i > 0;
4543              i --, value ++)
4544         {
4545           integer            = value->integer;
4546           value->range.lower = value->range.upper = integer;
4547         }
4548 
4549         (*attr)->value_tag = IPP_TAG_RANGE;
4550         break;
4551 
4552     case IPP_TAG_NAME :
4553         if (temp_tag != IPP_TAG_KEYWORD)
4554           return (0);
4555 
4556         (*attr)->value_tag = (ipp_tag_t)(IPP_TAG_NAME | ((*attr)->value_tag & IPP_TAG_CUPS_CONST));
4557         break;
4558 
4559     case IPP_TAG_NAMELANG :
4560     case IPP_TAG_TEXTLANG :
4561         if (value_tag == IPP_TAG_NAMELANG && (temp_tag != IPP_TAG_NAME && temp_tag != IPP_TAG_KEYWORD))
4562           return (0);
4563 
4564         if (value_tag == IPP_TAG_TEXTLANG && temp_tag != IPP_TAG_TEXT)
4565           return (0);
4566 
4567         if (ipp->attrs && ipp->attrs->next && ipp->attrs->next->name &&
4568             !strcmp(ipp->attrs->next->name, "attributes-natural-language") && (ipp->attrs->next->value_tag & IPP_TAG_CUPS_MASK) == IPP_TAG_LANGUAGE)
4569         {
4570          /*
4571           * Use the language code from the IPP message...
4572           */
4573 
4574 	  (*attr)->values[0].string.language =
4575 	      _cupsStrAlloc(ipp->attrs->next->values[0].string.text);
4576         }
4577         else
4578         {
4579          /*
4580           * Otherwise, use the language code corresponding to the locale...
4581           */
4582 
4583 	  language = cupsLangDefault();
4584 	  (*attr)->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language->language,
4585 									code,
4586 									sizeof(code)));
4587         }
4588 
4589         for (i = (*attr)->num_values - 1, value = (*attr)->values + 1;
4590              i > 0;
4591              i --, value ++)
4592           value->string.language = (*attr)->values[0].string.language;
4593 
4594         if ((int)(*attr)->value_tag & IPP_TAG_CUPS_CONST)
4595         {
4596          /*
4597           * Make copies of all values...
4598           */
4599 
4600 	  for (i = (*attr)->num_values, value = (*attr)->values;
4601 	       i > 0;
4602 	       i --, value ++)
4603 	    value->string.text = _cupsStrAlloc(value->string.text);
4604         }
4605 
4606         (*attr)->value_tag = IPP_TAG_NAMELANG;
4607         break;
4608 
4609     case IPP_TAG_KEYWORD :
4610         if (temp_tag == IPP_TAG_NAME || temp_tag == IPP_TAG_NAMELANG)
4611           break;			/* Silently "allow" name -> keyword */
4612 
4613     default :
4614         return (0);
4615   }
4616 
4617   return (1);
4618 }
4619 
4620 
4621 /*
4622  * 'ippSetVersion()' - Set the version number in an IPP message.
4623  *
4624  * The @code ipp@ parameter refers to an IPP message previously created using
4625  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4626  *
4627  * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
4628  *
4629  * @since CUPS 1.6/macOS 10.8@
4630  */
4631 
4632 int					/* O - 1 on success, 0 on failure */
ippSetVersion(ipp_t * ipp,int major,int minor)4633 ippSetVersion(ipp_t *ipp,		/* I - IPP message */
4634               int   major,		/* I - Major version number (major.minor) */
4635               int   minor)		/* I - Minor version number (major.minor) */
4636 {
4637  /*
4638   * Range check input...
4639   */
4640 
4641   if (!ipp || major < 0 || minor < 0)
4642     return (0);
4643 
4644  /*
4645   * Set the version number...
4646   */
4647 
4648   ipp->request.any.version[0] = (ipp_uchar_t)major;
4649   ipp->request.any.version[1] = (ipp_uchar_t)minor;
4650 
4651   return (1);
4652 }
4653 
4654 
4655 /*
4656  * 'ippTimeToDate()' - Convert from time in seconds to RFC 2579 format.
4657  */
4658 
4659 const ipp_uchar_t *			/* O - RFC-2579 date/time data */
ippTimeToDate(time_t t)4660 ippTimeToDate(time_t t)			/* I - Time in seconds */
4661 {
4662   struct tm	unixdate;		/* UNIX unixdate/time info */
4663   ipp_uchar_t	*date = _cupsGlobals()->ipp_date;
4664 					/* RFC-2579 date/time data */
4665 
4666 
4667  /*
4668   * RFC-2579 date/time format is:
4669   *
4670   *    Byte(s)  Description
4671   *    -------  -----------
4672   *    0-1      Year (0 to 65535)
4673   *    2        Month (1 to 12)
4674   *    3        Day (1 to 31)
4675   *    4        Hours (0 to 23)
4676   *    5        Minutes (0 to 59)
4677   *    6        Seconds (0 to 60, 60 = "leap second")
4678   *    7        Deciseconds (0 to 9)
4679   *    8        +/- UTC
4680   *    9        UTC hours (0 to 11)
4681   *    10       UTC minutes (0 to 59)
4682   */
4683 
4684   gmtime_r(&t, &unixdate);
4685   unixdate.tm_year += 1900;
4686 
4687   date[0]  = (ipp_uchar_t)(unixdate.tm_year >> 8);
4688   date[1]  = (ipp_uchar_t)(unixdate.tm_year);
4689   date[2]  = (ipp_uchar_t)(unixdate.tm_mon + 1);
4690   date[3]  = (ipp_uchar_t)unixdate.tm_mday;
4691   date[4]  = (ipp_uchar_t)unixdate.tm_hour;
4692   date[5]  = (ipp_uchar_t)unixdate.tm_min;
4693   date[6]  = (ipp_uchar_t)unixdate.tm_sec;
4694   date[7]  = 0;
4695   date[8]  = '+';
4696   date[9]  = 0;
4697   date[10] = 0;
4698 
4699   return (date);
4700 }
4701 
4702 
4703 /*
4704  * 'ippValidateAttribute()' - Validate the contents of an attribute.
4705  *
4706  * This function validates the contents of an attribute based on the name and
4707  * value tag.  1 is returned if the attribute is valid, 0 otherwise.  On
4708  * failure, @link cupsLastErrorString@ is set to a human-readable message.
4709  *
4710  * @since CUPS 1.7/macOS 10.9@
4711  */
4712 
4713 int					/* O - 1 if valid, 0 otherwise */
ippValidateAttribute(ipp_attribute_t * attr)4714 ippValidateAttribute(
4715     ipp_attribute_t *attr)		/* I - Attribute */
4716 {
4717   int		i;			/* Looping var */
4718   char		scheme[64],		/* Scheme from URI */
4719 		userpass[256],		/* Username/password from URI */
4720 		hostname[256],		/* Hostname from URI */
4721 		resource[1024];		/* Resource from URI */
4722   int		port,			/* Port number from URI */
4723 		uri_status;		/* URI separation status */
4724   const char	*ptr;			/* Pointer into string */
4725   ipp_attribute_t *colattr;		/* Collection attribute */
4726   regex_t	re;			/* Regular expression */
4727   ipp_uchar_t	*date;			/* Current date value */
4728 
4729 
4730  /*
4731   * Skip separators.
4732   */
4733 
4734   if (!attr->name)
4735     return (1);
4736 
4737  /*
4738   * Validate the attribute name.
4739   */
4740 
4741   for (ptr = attr->name; *ptr; ptr ++)
4742     if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' && *ptr != '_')
4743       break;
4744 
4745   if (*ptr || ptr == attr->name)
4746   {
4747     ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad attribute name - invalid character (RFC 8011 section 5.1.4)."), attr->name);
4748     return (0);
4749   }
4750 
4751   if ((ptr - attr->name) > 255)
4752   {
4753     ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad attribute name - bad length %d (RFC 8011 section 5.1.4)."), attr->name, (int)(ptr - attr->name));
4754     return (0);
4755   }
4756 
4757   switch (attr->value_tag)
4758   {
4759     case IPP_TAG_INTEGER :
4760         break;
4761 
4762     case IPP_TAG_BOOLEAN :
4763         for (i = 0; i < attr->num_values; i ++)
4764 	{
4765 	  if (attr->values[i].boolean != 0 &&
4766 	      attr->values[i].boolean != 1)
4767 	  {
4768 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad boolean value %d (RFC 8011 section 5.1.21)."), attr->name, attr->values[i].boolean);
4769 	    return (0);
4770 	  }
4771 	}
4772         break;
4773 
4774     case IPP_TAG_ENUM :
4775         for (i = 0; i < attr->num_values; i ++)
4776 	{
4777 	  if (attr->values[i].integer < 1)
4778 	  {
4779 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad enum value %d - out of range (RFC 8011 section 5.1.5)."), attr->name, attr->values[i].integer);
4780             return (0);
4781 	  }
4782 	}
4783         break;
4784 
4785     case IPP_TAG_STRING :
4786         for (i = 0; i < attr->num_values; i ++)
4787 	{
4788 	  if (attr->values[i].unknown.length > IPP_MAX_OCTETSTRING)
4789 	  {
4790 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad octetString value - bad length %d (RFC 8011 section 5.1.20)."), attr->name, attr->values[i].unknown.length);
4791 	    return (0);
4792 	  }
4793 	}
4794         break;
4795 
4796     case IPP_TAG_DATE :
4797         for (i = 0; i < attr->num_values; i ++)
4798 	{
4799 	  date = attr->values[i].date;
4800 
4801           if (date[2] < 1 || date[2] > 12)
4802 	  {
4803 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime month %u (RFC 8011 section 5.1.15)."), attr->name, date[2]);
4804 	    return (0);
4805 	  }
4806 
4807           if (date[3] < 1 || date[3] > 31)
4808 	  {
4809 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime day %u (RFC 8011 section 5.1.15)."), attr->name, date[3]);
4810 	    return (0);
4811 	  }
4812 
4813           if (date[4] > 23)
4814 	  {
4815 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime hours %u (RFC 8011 section 5.1.15)."), attr->name, date[4]);
4816 	    return (0);
4817 	  }
4818 
4819           if (date[5] > 59)
4820 	  {
4821 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime minutes %u (RFC 8011 section 5.1.15)."), attr->name, date[5]);
4822 	    return (0);
4823 	  }
4824 
4825           if (date[6] > 60)
4826 	  {
4827 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime seconds %u (RFC 8011 section 5.1.15)."), attr->name, date[6]);
4828 	    return (0);
4829 	  }
4830 
4831           if (date[7] > 9)
4832 	  {
4833 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime deciseconds %u (RFC 8011 section 5.1.15)."), attr->name, date[7]);
4834 	    return (0);
4835 	  }
4836 
4837           if (date[8] != '-' && date[8] != '+')
4838 	  {
4839 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime UTC sign '%c' (RFC 8011 section 5.1.15)."), attr->name, date[8]);
4840 	    return (0);
4841 	  }
4842 
4843           if (date[9] > 11)
4844 	  {
4845 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime UTC hours %u (RFC 8011 section 5.1.15)."), attr->name, date[9]);
4846 	    return (0);
4847 	  }
4848 
4849           if (date[10] > 59)
4850 	  {
4851 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime UTC minutes %u (RFC 8011 section 5.1.15)."), attr->name, date[10]);
4852 	    return (0);
4853 	  }
4854 	}
4855         break;
4856 
4857     case IPP_TAG_RESOLUTION :
4858         for (i = 0; i < attr->num_values; i ++)
4859 	{
4860 	  if (attr->values[i].resolution.xres <= 0)
4861 	  {
4862 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad resolution value %dx%d%s - cross feed resolution must be positive (RFC 8011 section 5.1.16)."), attr->name, attr->values[i].resolution.xres, attr->values[i].resolution.yres, attr->values[i].resolution.units == IPP_RES_PER_INCH ? "dpi" : attr->values[i].resolution.units == IPP_RES_PER_CM ? "dpcm" : "unknown");
4863 	    return (0);
4864 	  }
4865 
4866 	  if (attr->values[i].resolution.yres <= 0)
4867 	  {
4868 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad resolution value %dx%d%s - feed resolution must be positive (RFC 8011 section 5.1.16)."), attr->name, attr->values[i].resolution.xres, attr->values[i].resolution.yres, attr->values[i].resolution.units == IPP_RES_PER_INCH ? "dpi" : attr->values[i].resolution.units == IPP_RES_PER_CM ? "dpcm" : "unknown");
4869             return (0);
4870 	  }
4871 
4872 	  if (attr->values[i].resolution.units != IPP_RES_PER_INCH && attr->values[i].resolution.units != IPP_RES_PER_CM)
4873 	  {
4874 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad resolution value %dx%d%s - bad units value (RFC 8011 section 5.1.16)."), attr->name, attr->values[i].resolution.xres, attr->values[i].resolution.yres, attr->values[i].resolution.units == IPP_RES_PER_INCH ? "dpi" : attr->values[i].resolution.units == IPP_RES_PER_CM ? "dpcm" : "unknown");
4875 	    return (0);
4876 	  }
4877 	}
4878         break;
4879 
4880     case IPP_TAG_RANGE :
4881         for (i = 0; i < attr->num_values; i ++)
4882 	{
4883 	  if (attr->values[i].range.lower > attr->values[i].range.upper)
4884 	  {
4885 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad rangeOfInteger value %d-%d - lower greater than upper (RFC 8011 section 5.1.14)."), attr->name, attr->values[i].range.lower, attr->values[i].range.upper);
4886 	    return (0);
4887 	  }
4888 	}
4889         break;
4890 
4891     case IPP_TAG_BEGIN_COLLECTION :
4892         for (i = 0; i < attr->num_values; i ++)
4893 	{
4894 	  for (colattr = attr->values[i].collection->attrs;
4895 	       colattr;
4896 	       colattr = colattr->next)
4897 	  {
4898 	    if (!ippValidateAttribute(colattr))
4899 	      return (0);
4900 	  }
4901 	}
4902         break;
4903 
4904     case IPP_TAG_TEXT :
4905     case IPP_TAG_TEXTLANG :
4906         for (i = 0; i < attr->num_values; i ++)
4907 	{
4908 	  for (ptr = attr->values[i].string.text; *ptr; ptr ++)
4909 	  {
4910 	    if ((*ptr & 0xe0) == 0xc0)
4911 	    {
4912 	      if ((ptr[1] & 0xc0) != 0x80)
4913 	        break;
4914 
4915 	      ptr ++;
4916 	    }
4917 	    else if ((*ptr & 0xf0) == 0xe0)
4918 	    {
4919 	      if ((ptr[1] & 0xc0) != 0x80 || (ptr[2] & 0xc0) != 0x80)
4920 	        break;
4921 
4922 	      ptr += 2;
4923 	    }
4924 	    else if ((*ptr & 0xf8) == 0xf0)
4925 	    {
4926 	      if ((ptr[1] & 0xc0) != 0x80 || (ptr[2] & 0xc0) != 0x80 || (ptr[3] & 0xc0) != 0x80)
4927 	        break;
4928 
4929 	      ptr += 3;
4930 	    }
4931 	    else if (*ptr & 0x80)
4932 	      break;
4933 	    else if ((*ptr < ' ' && *ptr != '\n' && *ptr != '\r' && *ptr != '\t') || *ptr == 0x7f)
4934 	      break;
4935 	  }
4936 
4937           if (*ptr)
4938           {
4939 	    if (*ptr < ' ' || *ptr == 0x7f)
4940 	    {
4941 	      ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad text value \"%s\" - bad control character (PWG 5100.14 section 8.3)."), attr->name, attr->values[i].string.text);
4942 	      return (0);
4943 	    }
4944 	    else
4945 	    {
4946 	      ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad text value \"%s\" - bad UTF-8 sequence (RFC 8011 section 5.1.2)."), attr->name, attr->values[i].string.text);
4947 	      return (0);
4948 	    }
4949           }
4950 
4951 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_TEXT - 1))
4952 	  {
4953 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad text value \"%s\" - bad length %d (RFC 8011 section 5.1.2)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text));
4954 	    return (0);
4955 	  }
4956 	}
4957         break;
4958 
4959     case IPP_TAG_NAME :
4960     case IPP_TAG_NAMELANG :
4961         for (i = 0; i < attr->num_values; i ++)
4962 	{
4963 	  for (ptr = attr->values[i].string.text; *ptr; ptr ++)
4964 	  {
4965 	    if ((*ptr & 0xe0) == 0xc0)
4966 	    {
4967 	      if ((ptr[1] & 0xc0) != 0x80)
4968 	        break;
4969 
4970 	      ptr ++;
4971 	    }
4972 	    else if ((*ptr & 0xf0) == 0xe0)
4973 	    {
4974 	      if ((ptr[1] & 0xc0) != 0x80 || (ptr[2] & 0xc0) != 0x80)
4975 	        break;
4976 
4977 	      ptr += 2;
4978 	    }
4979 	    else if ((*ptr & 0xf8) == 0xf0)
4980 	    {
4981 	      if ((ptr[1] & 0xc0) != 0x80 || (ptr[2] & 0xc0) != 0x80 || (ptr[3] & 0xc0) != 0x80)
4982 	        break;
4983 
4984 	      ptr += 3;
4985 	    }
4986 	    else if (*ptr & 0x80)
4987 	      break;
4988 	    else if (*ptr < ' ' || *ptr == 0x7f)
4989 	      break;
4990 	  }
4991 
4992 	  if (*ptr)
4993 	  {
4994 	    if (*ptr < ' ' || *ptr == 0x7f)
4995 	    {
4996 	      ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad name value \"%s\" - bad control character (PWG 5100.14 section 8.1)."), attr->name, attr->values[i].string.text);
4997 	      return (0);
4998 	    }
4999 	    else
5000 	    {
5001 	      ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad name value \"%s\" - bad UTF-8 sequence (RFC 8011 section 5.1.3)."), attr->name, attr->values[i].string.text);
5002 	      return (0);
5003 	    }
5004           }
5005 
5006 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_NAME - 1))
5007 	  {
5008 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad name value \"%s\" - bad length %d (RFC 8011 section 5.1.3)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text));
5009 	    return (0);
5010 	  }
5011 	}
5012         break;
5013 
5014     case IPP_TAG_KEYWORD :
5015         for (i = 0; i < attr->num_values; i ++)
5016 	{
5017 	  for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5018 	  {
5019 	    if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' &&
5020 	        *ptr != '_')
5021 	      break;
5022 	  }
5023 
5024 	  if (*ptr || ptr == attr->values[i].string.text)
5025 	  {
5026 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad keyword value \"%s\" - invalid character (RFC 8011 section 5.1.4)."), attr->name, attr->values[i].string.text);
5027 	    return (0);
5028 	  }
5029 
5030 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_KEYWORD - 1))
5031 	  {
5032 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad keyword value \"%s\" - bad length %d (RFC 8011 section 5.1.4)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text));
5033 	    return (0);
5034 	  }
5035 	}
5036         break;
5037 
5038     case IPP_TAG_URI :
5039         for (i = 0; i < attr->num_values; i ++)
5040 	{
5041 	  uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource));
5042 
5043 	  if (uri_status < HTTP_URI_STATUS_OK)
5044 	  {
5045 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad URI value \"%s\" - %s (RFC 8011 section 5.1.6)."), attr->name, attr->values[i].string.text, httpURIStatusString(uri_status));
5046 	    return (0);
5047 	  }
5048 
5049 	  if (strlen(attr->values[i].string.text) > (IPP_MAX_URI - 1))
5050 	  {
5051 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad URI value \"%s\" - bad length %d (RFC 8011 section 5.1.6)."), attr->name, attr->values[i].string.text, (int)strlen(attr->values[i].string.text));
5052 	  }
5053 	}
5054         break;
5055 
5056     case IPP_TAG_URISCHEME :
5057         for (i = 0; i < attr->num_values; i ++)
5058 	{
5059 	  ptr = attr->values[i].string.text;
5060 	  if (islower(*ptr & 255))
5061 	  {
5062 	    for (ptr ++; *ptr; ptr ++)
5063 	    {
5064 	      if (!islower(*ptr & 255) && !isdigit(*ptr & 255) &&
5065 	          *ptr != '+' && *ptr != '-' && *ptr != '.')
5066                 break;
5067 	    }
5068 	  }
5069 
5070 	  if (*ptr || ptr == attr->values[i].string.text)
5071 	  {
5072 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad uriScheme value \"%s\" - bad characters (RFC 8011 section 5.1.7)."), attr->name, attr->values[i].string.text);
5073 	    return (0);
5074 	  }
5075 
5076 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_URISCHEME - 1))
5077 	  {
5078 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad uriScheme value \"%s\" - bad length %d (RFC 8011 section 5.1.7)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text));
5079 	    return (0);
5080 	  }
5081 	}
5082         break;
5083 
5084     case IPP_TAG_CHARSET :
5085         for (i = 0; i < attr->num_values; i ++)
5086 	{
5087 	  for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5088 	  {
5089 	    if (!isprint(*ptr & 255) || isupper(*ptr & 255) ||
5090 	        isspace(*ptr & 255))
5091 	      break;
5092 	  }
5093 
5094 	  if (*ptr || ptr == attr->values[i].string.text)
5095 	  {
5096 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad charset value \"%s\" - bad characters (RFC 8011 section 5.1.8)."), attr->name, attr->values[i].string.text);
5097 	    return (0);
5098 	  }
5099 
5100 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_CHARSET - 1))
5101 	  {
5102 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad charset value \"%s\" - bad length %d (RFC 8011 section 5.1.8)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text));
5103 	    return (0);
5104 	  }
5105 	}
5106         break;
5107 
5108     case IPP_TAG_LANGUAGE :
5109        /*
5110         * The following regular expression is derived from the ABNF for
5111 	* language tags in RFC 4646.  All I can say is that this is the
5112 	* easiest way to check the values...
5113 	*/
5114 
5115         if ((i = regcomp(&re,
5116 			 "^("
5117 			 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
5118 								/* language */
5119 			 "(-[a-z][a-z][a-z][a-z]){0,1}"		/* script */
5120 			 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}"	/* region */
5121 			 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*"	/* variant */
5122 			 "(-[a-wy-z](-[a-z0-9]{2,8})+)*"	/* extension */
5123 			 "(-x(-[a-z0-9]{1,8})+)*"		/* privateuse */
5124 			 "|"
5125 			 "x(-[a-z0-9]{1,8})+"			/* privateuse */
5126 			 "|"
5127 			 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}"	/* grandfathered */
5128 			 ")$",
5129 			 REG_NOSUB | REG_EXTENDED)) != 0)
5130         {
5131           char	temp[256];		/* Temporary error string */
5132 
5133           regerror(i, &re, temp, sizeof(temp));
5134 	  ipp_set_error(IPP_STATUS_ERROR_INTERNAL, _("Unable to compile naturalLanguage regular expression: %s."), temp);
5135 	  return (0);
5136         }
5137 
5138         for (i = 0; i < attr->num_values; i ++)
5139 	{
5140 	  if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
5141 	  {
5142 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad naturalLanguage value \"%s\" - bad characters (RFC 8011 section 5.1.9)."), attr->name, attr->values[i].string.text);
5143 	    regfree(&re);
5144 	    return (0);
5145 	  }
5146 
5147 	  if (strlen(attr->values[i].string.text) > (IPP_MAX_LANGUAGE - 1))
5148 	  {
5149 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad naturalLanguage value \"%s\" - bad length %d (RFC 8011 section 5.1.9)."), attr->name, attr->values[i].string.text, (int)strlen(attr->values[i].string.text));
5150 	    regfree(&re);
5151 	    return (0);
5152 	  }
5153 	}
5154 
5155 	regfree(&re);
5156         break;
5157 
5158     case IPP_TAG_MIMETYPE :
5159        /*
5160         * The following regular expression is derived from the ABNF for
5161 	* MIME media types in RFC 2045 and 4288.  All I can say is that this is
5162 	* the easiest way to check the values...
5163 	*/
5164 
5165         if ((i = regcomp(&re,
5166 			 "^"
5167 			 "[-a-zA-Z0-9!#$&.+^_]{1,127}"		/* type-name */
5168 			 "/"
5169 			 "[-a-zA-Z0-9!#$&.+^_]{1,127}"		/* subtype-name */
5170 			 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}="	/* parameter= */
5171 			 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
5172 			 					/* value */
5173 			 "$",
5174 			 REG_NOSUB | REG_EXTENDED)) != 0)
5175         {
5176           char	temp[256];		/* Temporary error string */
5177 
5178           regerror(i, &re, temp, sizeof(temp));
5179 	  ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("Unable to compile mimeMediaType regular expression: %s."), temp);
5180 	  return (0);
5181         }
5182 
5183         for (i = 0; i < attr->num_values; i ++)
5184 	{
5185 	  if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
5186 	  {
5187 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad mimeMediaType value \"%s\" - bad characters (RFC 8011 section 5.1.10)."), attr->name, attr->values[i].string.text);
5188 	    regfree(&re);
5189 	    return (0);
5190 	  }
5191 
5192 	  if (strlen(attr->values[i].string.text) > (IPP_MAX_MIMETYPE - 1))
5193 	  {
5194 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad mimeMediaType value \"%s\" - bad length %d (RFC 8011 section 5.1.10)."), attr->name, attr->values[i].string.text, (int)strlen(attr->values[i].string.text));
5195 	    regfree(&re);
5196 	    return (0);
5197 	  }
5198 	}
5199 
5200 	regfree(&re);
5201         break;
5202 
5203     default :
5204         break;
5205   }
5206 
5207   return (1);
5208 }
5209 
5210 
5211 /*
5212  * 'ippValidateAttributes()' - Validate all attributes in an IPP message.
5213  *
5214  * This function validates the contents of the IPP message, including each
5215  * attribute.  Like @link ippValidateAttribute@, @link cupsLastErrorString@ is
5216  * set to a human-readable message on failure.
5217  *
5218  * @since CUPS 1.7/macOS 10.9@
5219  */
5220 
5221 int					/* O - 1 if valid, 0 otherwise */
ippValidateAttributes(ipp_t * ipp)5222 ippValidateAttributes(ipp_t *ipp)	/* I - IPP message */
5223 {
5224   ipp_attribute_t	*attr;		/* Current attribute */
5225 
5226 
5227   if (!ipp)
5228     return (1);
5229 
5230   for (attr = ipp->attrs; attr; attr = attr->next)
5231     if (!ippValidateAttribute(attr))
5232       return (0);
5233 
5234   return (1);
5235 }
5236 
5237 
5238 /*
5239  * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
5240  */
5241 
5242 ipp_state_t				/* O - Current state */
ippWrite(http_t * http,ipp_t * ipp)5243 ippWrite(http_t *http,			/* I - HTTP connection */
5244          ipp_t  *ipp)			/* I - IPP data */
5245 {
5246   DEBUG_printf(("ippWrite(http=%p, ipp=%p)", (void *)http, (void *)ipp));
5247 
5248   if (!http)
5249     return (IPP_STATE_ERROR);
5250 
5251   return (ippWriteIO(http, (ipp_iocb_t)httpWrite2, http->blocking, NULL, ipp));
5252 }
5253 
5254 
5255 /*
5256  * 'ippWriteFile()' - Write data for an IPP message to a file.
5257  *
5258  * @since CUPS 1.1.19/macOS 10.3@
5259  */
5260 
5261 ipp_state_t				/* O - Current state */
ippWriteFile(int fd,ipp_t * ipp)5262 ippWriteFile(int   fd,			/* I - HTTP data */
5263              ipp_t *ipp)		/* I - IPP data */
5264 {
5265   DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd, (void *)ipp));
5266 
5267   ipp->state = IPP_STATE_IDLE;
5268 
5269   return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp));
5270 }
5271 
5272 
5273 /*
5274  * 'ippWriteIO()' - Write data for an IPP message.
5275  *
5276  * @since CUPS 1.2/macOS 10.5@
5277  */
5278 
5279 ipp_state_t				/* O - Current state */
ippWriteIO(void * dst,ipp_iocb_t cb,int blocking,ipp_t * parent,ipp_t * ipp)5280 ippWriteIO(void       *dst,		/* I - Destination */
5281            ipp_iocb_t cb,		/* I - Write callback function */
5282 	   int        blocking,		/* I - Use blocking IO? */
5283 	   ipp_t      *parent,		/* I - Parent IPP message */
5284            ipp_t      *ipp)		/* I - IPP data */
5285 {
5286   int			i;		/* Looping var */
5287   int			n;		/* Length of data */
5288   unsigned char		*buffer,	/* Data buffer */
5289 			*bufptr;	/* Pointer into buffer */
5290   ipp_attribute_t	*attr;		/* Current attribute */
5291   _ipp_value_t		*value;		/* Current value */
5292 
5293 
5294   DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)dst, (void *)cb, blocking, (void *)parent, (void *)ipp));
5295 
5296   if (!dst || !ipp)
5297     return (IPP_STATE_ERROR);
5298 
5299   if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
5300   {
5301     DEBUG_puts("1ippWriteIO: Unable to get write buffer");
5302     return (IPP_STATE_ERROR);
5303   }
5304 
5305   switch (ipp->state)
5306   {
5307     case IPP_STATE_IDLE :
5308         ipp->state ++; /* Avoid common problem... */
5309 
5310     case IPP_STATE_HEADER :
5311         if (parent == NULL)
5312 	{
5313 	 /*
5314 	  * Send the request header:
5315 	  *
5316 	  *                 Version = 2 bytes
5317 	  *   Operation/Status Code = 2 bytes
5318 	  *              Request ID = 4 bytes
5319 	  *                   Total = 8 bytes
5320 	  */
5321 
5322           bufptr = buffer;
5323 
5324 	  *bufptr++ = ipp->request.any.version[0];
5325 	  *bufptr++ = ipp->request.any.version[1];
5326 	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.op_status >> 8);
5327 	  *bufptr++ = (ipp_uchar_t)ipp->request.any.op_status;
5328 	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 24);
5329 	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 16);
5330 	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 8);
5331 	  *bufptr++ = (ipp_uchar_t)ipp->request.any.request_id;
5332 
5333 	  DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer[0], buffer[1]));
5334 	  DEBUG_printf(("2ippWriteIO: op_status=%04x",
5335 			ipp->request.any.op_status));
5336 	  DEBUG_printf(("2ippWriteIO: request_id=%d",
5337 			ipp->request.any.request_id));
5338 
5339           if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5340 	  {
5341 	    DEBUG_puts("1ippWriteIO: Could not write IPP header...");
5342 	    _cupsBufferRelease((char *)buffer);
5343 	    return (IPP_STATE_ERROR);
5344 	  }
5345 	}
5346 
5347        /*
5348 	* Reset the state engine to point to the first attribute
5349 	* in the request/response, with no current group.
5350 	*/
5351 
5352         ipp->state   = IPP_STATE_ATTRIBUTE;
5353 	ipp->current = ipp->attrs;
5354 	ipp->curtag  = IPP_TAG_ZERO;
5355 
5356 	DEBUG_printf(("1ippWriteIO: ipp->current=%p", (void *)ipp->current));
5357 
5358        /*
5359         * If blocking is disabled, stop here...
5360 	*/
5361 
5362         if (!blocking)
5363 	  break;
5364 
5365     case IPP_STATE_ATTRIBUTE :
5366         while (ipp->current != NULL)
5367 	{
5368 	 /*
5369 	  * Write this attribute...
5370 	  */
5371 
5372 	  bufptr = buffer;
5373 	  attr   = ipp->current;
5374 
5375 	  ipp->current = ipp->current->next;
5376 
5377           if (!parent)
5378 	  {
5379 	    if (ipp->curtag != attr->group_tag)
5380 	    {
5381 	     /*
5382 	      * Send a group tag byte...
5383 	      */
5384 
5385 	      ipp->curtag = attr->group_tag;
5386 
5387 	      if (attr->group_tag == IPP_TAG_ZERO)
5388 		continue;
5389 
5390 	      DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
5391 			    attr->group_tag, ippTagString(attr->group_tag)));
5392 	      *bufptr++ = (ipp_uchar_t)attr->group_tag;
5393 	    }
5394 	    else if (attr->group_tag == IPP_TAG_ZERO)
5395 	      continue;
5396 	  }
5397 
5398 	  DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr->name,
5399 	                attr->num_values > 1 ? "1setOf " : "",
5400 			ippTagString(attr->value_tag)));
5401 
5402          /*
5403 	  * Write the attribute tag and name.
5404 	  *
5405 	  * The attribute name length does not include the trailing nul
5406 	  * character in the source string.
5407 	  *
5408 	  * Collection values (parent != NULL) are written differently...
5409 	  */
5410 
5411           if (parent == NULL)
5412 	  {
5413            /*
5414 	    * Get the length of the attribute name, and make sure it won't
5415 	    * overflow the buffer...
5416 	    */
5417 
5418             if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 8))
5419 	    {
5420 	      DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
5421 	      _cupsBufferRelease((char *)buffer);
5422 	      return (IPP_STATE_ERROR);
5423 	    }
5424 
5425            /*
5426 	    * Write the value tag, name length, and name string...
5427 	    */
5428 
5429             DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5430 	                  attr->value_tag, ippTagString(attr->value_tag)));
5431             DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
5432 	                  attr->name));
5433 
5434             if (attr->value_tag > 0xff)
5435             {
5436               *bufptr++ = IPP_TAG_EXTENSION;
5437 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
5438 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
5439 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
5440 	      *bufptr++ = (ipp_uchar_t)attr->value_tag;
5441             }
5442             else
5443 	      *bufptr++ = (ipp_uchar_t)attr->value_tag;
5444 
5445 	    *bufptr++ = (ipp_uchar_t)(n >> 8);
5446 	    *bufptr++ = (ipp_uchar_t)n;
5447 	    memcpy(bufptr, attr->name, (size_t)n);
5448 	    bufptr += n;
5449           }
5450 	  else
5451 	  {
5452            /*
5453 	    * Get the length of the attribute name, and make sure it won't
5454 	    * overflow the buffer...
5455 	    */
5456 
5457             if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 12))
5458 	    {
5459 	      DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
5460 	      _cupsBufferRelease((char *)buffer);
5461 	      return (IPP_STATE_ERROR);
5462 	    }
5463 
5464            /*
5465 	    * Write the member name tag, name length, name string, value tag,
5466 	    * and empty name for the collection member attribute...
5467 	    */
5468 
5469             DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
5470 	                  IPP_TAG_MEMBERNAME));
5471             DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
5472 	                  attr->name));
5473             DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5474 	                  attr->value_tag, ippTagString(attr->value_tag)));
5475             DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
5476 
5477             *bufptr++ = IPP_TAG_MEMBERNAME;
5478 	    *bufptr++ = 0;
5479 	    *bufptr++ = 0;
5480 	    *bufptr++ = (ipp_uchar_t)(n >> 8);
5481 	    *bufptr++ = (ipp_uchar_t)n;
5482 	    memcpy(bufptr, attr->name, (size_t)n);
5483 	    bufptr += n;
5484 
5485             if (attr->value_tag > 0xff)
5486             {
5487               *bufptr++ = IPP_TAG_EXTENSION;
5488 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
5489 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
5490 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
5491 	      *bufptr++ = (ipp_uchar_t)attr->value_tag;
5492             }
5493             else
5494 	      *bufptr++ = (ipp_uchar_t)attr->value_tag;
5495 
5496             *bufptr++ = 0;
5497             *bufptr++ = 0;
5498 	  }
5499 
5500          /*
5501 	  * Now write the attribute value(s)...
5502 	  */
5503 
5504 	  switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
5505 	  {
5506 	    case IPP_TAG_UNSUPPORTED_VALUE :
5507 	    case IPP_TAG_DEFAULT :
5508 	    case IPP_TAG_UNKNOWN :
5509 	    case IPP_TAG_NOVALUE :
5510 	    case IPP_TAG_NOTSETTABLE :
5511 	    case IPP_TAG_DELETEATTR :
5512 	    case IPP_TAG_ADMINDEFINE :
5513 		*bufptr++ = 0;
5514 		*bufptr++ = 0;
5515 	        break;
5516 
5517 	    case IPP_TAG_INTEGER :
5518 	    case IPP_TAG_ENUM :
5519 	        for (i = 0, value = attr->values;
5520 		     i < attr->num_values;
5521 		     i ++, value ++)
5522 		{
5523                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 9)
5524 		  {
5525                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5526 	            {
5527 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5528 		                 "attribute...");
5529 		      _cupsBufferRelease((char *)buffer);
5530 	              return (IPP_STATE_ERROR);
5531 	            }
5532 
5533 		    bufptr = buffer;
5534 		  }
5535 
5536 		  if (i)
5537 		  {
5538 		   /*
5539 		    * Arrays and sets are done by sending additional
5540 		    * values with a zero-length name...
5541 		    */
5542 
5543                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5544 		    *bufptr++ = 0;
5545 		    *bufptr++ = 0;
5546 		  }
5547 
5548 		 /*
5549 	          * Integers and enumerations are both 4-byte signed
5550 		  * (twos-complement) values.
5551 		  *
5552 		  * Put the 2-byte length and 4-byte value into the buffer...
5553 		  */
5554 
5555 	          *bufptr++ = 0;
5556 		  *bufptr++ = 4;
5557 		  *bufptr++ = (ipp_uchar_t)(value->integer >> 24);
5558 		  *bufptr++ = (ipp_uchar_t)(value->integer >> 16);
5559 		  *bufptr++ = (ipp_uchar_t)(value->integer >> 8);
5560 		  *bufptr++ = (ipp_uchar_t)value->integer;
5561 		}
5562 		break;
5563 
5564 	    case IPP_TAG_BOOLEAN :
5565 	        for (i = 0, value = attr->values;
5566 		     i < attr->num_values;
5567 		     i ++, value ++)
5568 		{
5569                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 6)
5570 		  {
5571                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5572 	            {
5573 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5574 		                 "attribute...");
5575 		      _cupsBufferRelease((char *)buffer);
5576 	              return (IPP_STATE_ERROR);
5577 	            }
5578 
5579 		    bufptr = buffer;
5580 		  }
5581 
5582 		  if (i)
5583 		  {
5584 		   /*
5585 		    * Arrays and sets are done by sending additional
5586 		    * values with a zero-length name...
5587 		    */
5588 
5589                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5590 		    *bufptr++ = 0;
5591 		    *bufptr++ = 0;
5592 		  }
5593 
5594                  /*
5595 		  * Boolean values are 1-byte; 0 = false, 1 = true.
5596 		  *
5597 		  * Put the 2-byte length and 1-byte value into the buffer...
5598 		  */
5599 
5600 	          *bufptr++ = 0;
5601 		  *bufptr++ = 1;
5602 		  *bufptr++ = (ipp_uchar_t)value->boolean;
5603 		}
5604 		break;
5605 
5606 	    case IPP_TAG_TEXT :
5607 	    case IPP_TAG_NAME :
5608 	    case IPP_TAG_KEYWORD :
5609 	    case IPP_TAG_URI :
5610 	    case IPP_TAG_URISCHEME :
5611 	    case IPP_TAG_CHARSET :
5612 	    case IPP_TAG_LANGUAGE :
5613 	    case IPP_TAG_MIMETYPE :
5614 	        for (i = 0, value = attr->values;
5615 		     i < attr->num_values;
5616 		     i ++, value ++)
5617 		{
5618 		  if (i)
5619 		  {
5620 		   /*
5621 		    * Arrays and sets are done by sending additional
5622 		    * values with a zero-length name...
5623 		    */
5624 
5625         	    DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5626 		                  attr->value_tag,
5627 				  ippTagString(attr->value_tag)));
5628         	    DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
5629 
5630                     if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
5631 		    {
5632                       if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5633 	              {
5634 	        	DEBUG_puts("1ippWriteIO: Could not write IPP "
5635 			           "attribute...");
5636 			_cupsBufferRelease((char *)buffer);
5637 	        	return (IPP_STATE_ERROR);
5638 	              }
5639 
5640 		      bufptr = buffer;
5641 		    }
5642 
5643                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5644 		    *bufptr++ = 0;
5645 		    *bufptr++ = 0;
5646 		  }
5647 
5648                   if (value->string.text != NULL)
5649                     n = (int)strlen(value->string.text);
5650 		  else
5651 		    n = 0;
5652 
5653                   if (n > (IPP_BUF_SIZE - 2))
5654 		  {
5655 		    DEBUG_printf(("1ippWriteIO: String too long (%d)", n));
5656 		    _cupsBufferRelease((char *)buffer);
5657 		    return (IPP_STATE_ERROR);
5658 		  }
5659 
5660                   DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n,
5661 		                value->string.text));
5662 
5663                   if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
5664 		  {
5665                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5666 	            {
5667 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5668 		                 "attribute...");
5669 		      _cupsBufferRelease((char *)buffer);
5670 	              return (IPP_STATE_ERROR);
5671 	            }
5672 
5673 		    bufptr = buffer;
5674 		  }
5675 
5676 		 /*
5677 		  * All simple strings consist of the 2-byte length and
5678 		  * character data without the trailing nul normally found
5679 		  * in C strings.  Also, strings cannot be longer than IPP_MAX_LENGTH
5680 		  * bytes since the 2-byte length is a signed (twos-complement)
5681 		  * value.
5682 		  *
5683 		  * Put the 2-byte length and string characters in the buffer.
5684 		  */
5685 
5686 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
5687 		  *bufptr++ = (ipp_uchar_t)n;
5688 
5689 		  if (n > 0)
5690 		  {
5691 		    memcpy(bufptr, value->string.text, (size_t)n);
5692 		    bufptr += n;
5693 		  }
5694 		}
5695 		break;
5696 
5697 	    case IPP_TAG_DATE :
5698 	        for (i = 0, value = attr->values;
5699 		     i < attr->num_values;
5700 		     i ++, value ++)
5701 		{
5702                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 16)
5703 		  {
5704                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5705 	            {
5706 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5707 		                 "attribute...");
5708 		      _cupsBufferRelease((char *)buffer);
5709 	              return (IPP_STATE_ERROR);
5710 	            }
5711 
5712 		    bufptr = buffer;
5713 		  }
5714 
5715 		  if (i)
5716 		  {
5717 		   /*
5718 		    * Arrays and sets are done by sending additional
5719 		    * values with a zero-length name...
5720 		    */
5721 
5722                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5723 		    *bufptr++ = 0;
5724 		    *bufptr++ = 0;
5725 		  }
5726 
5727                  /*
5728 		  * Date values consist of a 2-byte length and an
5729 		  * 11-byte date/time structure defined by RFC 1903.
5730 		  *
5731 		  * Put the 2-byte length and 11-byte date/time
5732 		  * structure in the buffer.
5733 		  */
5734 
5735 	          *bufptr++ = 0;
5736 		  *bufptr++ = 11;
5737 		  memcpy(bufptr, value->date, 11);
5738 		  bufptr += 11;
5739 		}
5740 		break;
5741 
5742 	    case IPP_TAG_RESOLUTION :
5743 	        for (i = 0, value = attr->values;
5744 		     i < attr->num_values;
5745 		     i ++, value ++)
5746 		{
5747                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 14)
5748 		  {
5749                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5750 	            {
5751 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5752 		                 "attribute...");
5753 		      _cupsBufferRelease((char *)buffer);
5754 		      return (IPP_STATE_ERROR);
5755 	            }
5756 
5757 		    bufptr = buffer;
5758 		  }
5759 
5760 		  if (i)
5761 		  {
5762 		   /*
5763 		    * Arrays and sets are done by sending additional
5764 		    * values with a zero-length name...
5765 		    */
5766 
5767                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5768 		    *bufptr++ = 0;
5769 		    *bufptr++ = 0;
5770 		  }
5771 
5772                  /*
5773 		  * Resolution values consist of a 2-byte length,
5774 		  * 4-byte horizontal resolution value, 4-byte vertical
5775 		  * resolution value, and a 1-byte units value.
5776 		  *
5777 		  * Put the 2-byte length and resolution value data
5778 		  * into the buffer.
5779 		  */
5780 
5781 	          *bufptr++ = 0;
5782 		  *bufptr++ = 9;
5783 		  *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 24);
5784 		  *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 16);
5785 		  *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 8);
5786 		  *bufptr++ = (ipp_uchar_t)value->resolution.xres;
5787 		  *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 24);
5788 		  *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 16);
5789 		  *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 8);
5790 		  *bufptr++ = (ipp_uchar_t)value->resolution.yres;
5791 		  *bufptr++ = (ipp_uchar_t)value->resolution.units;
5792 		}
5793 		break;
5794 
5795 	    case IPP_TAG_RANGE :
5796 	        for (i = 0, value = attr->values;
5797 		     i < attr->num_values;
5798 		     i ++, value ++)
5799 		{
5800                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 13)
5801 		  {
5802                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5803 	            {
5804 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5805 		                 "attribute...");
5806 		      _cupsBufferRelease((char *)buffer);
5807 	              return (IPP_STATE_ERROR);
5808 	            }
5809 
5810 		    bufptr = buffer;
5811 		  }
5812 
5813 		  if (i)
5814 		  {
5815 		   /*
5816 		    * Arrays and sets are done by sending additional
5817 		    * values with a zero-length name...
5818 		    */
5819 
5820                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5821 		    *bufptr++ = 0;
5822 		    *bufptr++ = 0;
5823 		  }
5824 
5825                  /*
5826 		  * Range values consist of a 2-byte length,
5827 		  * 4-byte lower value, and 4-byte upper value.
5828 		  *
5829 		  * Put the 2-byte length and range value data
5830 		  * into the buffer.
5831 		  */
5832 
5833 	          *bufptr++ = 0;
5834 		  *bufptr++ = 8;
5835 		  *bufptr++ = (ipp_uchar_t)(value->range.lower >> 24);
5836 		  *bufptr++ = (ipp_uchar_t)(value->range.lower >> 16);
5837 		  *bufptr++ = (ipp_uchar_t)(value->range.lower >> 8);
5838 		  *bufptr++ = (ipp_uchar_t)value->range.lower;
5839 		  *bufptr++ = (ipp_uchar_t)(value->range.upper >> 24);
5840 		  *bufptr++ = (ipp_uchar_t)(value->range.upper >> 16);
5841 		  *bufptr++ = (ipp_uchar_t)(value->range.upper >> 8);
5842 		  *bufptr++ = (ipp_uchar_t)value->range.upper;
5843 		}
5844 		break;
5845 
5846 	    case IPP_TAG_TEXTLANG :
5847 	    case IPP_TAG_NAMELANG :
5848 	        for (i = 0, value = attr->values;
5849 		     i < attr->num_values;
5850 		     i ++, value ++)
5851 		{
5852 		  if (i)
5853 		  {
5854 		   /*
5855 		    * Arrays and sets are done by sending additional
5856 		    * values with a zero-length name...
5857 		    */
5858 
5859                     if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
5860 		    {
5861                       if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5862 	              {
5863 	        	DEBUG_puts("1ippWriteIO: Could not write IPP "
5864 		                   "attribute...");
5865 			_cupsBufferRelease((char *)buffer);
5866 	        	return (IPP_STATE_ERROR);
5867 	              }
5868 
5869 		      bufptr = buffer;
5870 		    }
5871 
5872                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5873 		    *bufptr++ = 0;
5874 		    *bufptr++ = 0;
5875 		  }
5876 
5877                  /*
5878 		  * textWithLanguage and nameWithLanguage values consist
5879 		  * of a 2-byte length for both strings and their
5880 		  * individual lengths, a 2-byte length for the
5881 		  * character string, the character string without the
5882 		  * trailing nul, a 2-byte length for the character
5883 		  * set string, and the character set string without
5884 		  * the trailing nul.
5885 		  */
5886 
5887                   n = 4;
5888 
5889 		  if (value->string.language != NULL)
5890                     n += (int)strlen(value->string.language);
5891 
5892 		  if (value->string.text != NULL)
5893                     n += (int)strlen(value->string.text);
5894 
5895                   if (n > (IPP_BUF_SIZE - 2))
5896 		  {
5897 		    DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
5898 		                  "too long (%d)", n));
5899 		    _cupsBufferRelease((char *)buffer);
5900 		    return (IPP_STATE_ERROR);
5901                   }
5902 
5903                   if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
5904 		  {
5905                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5906 	            {
5907 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5908 		                 "attribute...");
5909 		      _cupsBufferRelease((char *)buffer);
5910 	              return (IPP_STATE_ERROR);
5911 	            }
5912 
5913 		    bufptr = buffer;
5914 		  }
5915 
5916                  /* Length of entire value */
5917 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
5918 		  *bufptr++ = (ipp_uchar_t)n;
5919 
5920                  /* Length of language */
5921 		  if (value->string.language != NULL)
5922 		    n = (int)strlen(value->string.language);
5923 		  else
5924 		    n = 0;
5925 
5926 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
5927 		  *bufptr++ = (ipp_uchar_t)n;
5928 
5929                  /* Language */
5930 		  if (n > 0)
5931 		  {
5932 		    memcpy(bufptr, value->string.language, (size_t)n);
5933 		    bufptr += n;
5934 		  }
5935 
5936                  /* Length of text */
5937                   if (value->string.text != NULL)
5938 		    n = (int)strlen(value->string.text);
5939 		  else
5940 		    n = 0;
5941 
5942 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
5943 		  *bufptr++ = (ipp_uchar_t)n;
5944 
5945                  /* Text */
5946 		  if (n > 0)
5947 		  {
5948 		    memcpy(bufptr, value->string.text, (size_t)n);
5949 		    bufptr += n;
5950 		  }
5951 		}
5952 		break;
5953 
5954             case IPP_TAG_BEGIN_COLLECTION :
5955 	        for (i = 0, value = attr->values;
5956 		     i < attr->num_values;
5957 		     i ++, value ++)
5958 		{
5959 		 /*
5960 		  * Collections are written with the begin-collection
5961 		  * tag first with a value of 0 length, followed by the
5962 		  * attributes in the collection, then the end-collection
5963 		  * value...
5964 		  */
5965 
5966                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 5)
5967 		  {
5968                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5969 	            {
5970 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5971 		                 "attribute...");
5972 		      _cupsBufferRelease((char *)buffer);
5973 	              return (IPP_STATE_ERROR);
5974 	            }
5975 
5976 		    bufptr = buffer;
5977 		  }
5978 
5979 		  if (i)
5980 		  {
5981 		   /*
5982 		    * Arrays and sets are done by sending additional
5983 		    * values with a zero-length name...
5984 		    */
5985 
5986                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5987 		    *bufptr++ = 0;
5988 		    *bufptr++ = 0;
5989 		  }
5990 
5991                  /*
5992 		  * Write a data length of 0 and flush the buffer...
5993 		  */
5994 
5995 	          *bufptr++ = 0;
5996 		  *bufptr++ = 0;
5997 
5998                   if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5999 	          {
6000 	            DEBUG_puts("1ippWriteIO: Could not write IPP "
6001 		               "attribute...");
6002 		    _cupsBufferRelease((char *)buffer);
6003 	            return (IPP_STATE_ERROR);
6004 	          }
6005 
6006 		  bufptr = buffer;
6007 
6008                  /*
6009 		  * Then write the collection attribute...
6010 		  */
6011 
6012                   value->collection->state = IPP_STATE_IDLE;
6013 
6014 		  if (ippWriteIO(dst, cb, 1, ipp,
6015 		                 value->collection) == IPP_STATE_ERROR)
6016 		  {
6017 		    DEBUG_puts("1ippWriteIO: Unable to write collection value");
6018 		    _cupsBufferRelease((char *)buffer);
6019 		    return (IPP_STATE_ERROR);
6020 		  }
6021 		}
6022 		break;
6023 
6024             default :
6025 	        for (i = 0, value = attr->values;
6026 		     i < attr->num_values;
6027 		     i ++, value ++)
6028 		{
6029 		  if (i)
6030 		  {
6031 		   /*
6032 		    * Arrays and sets are done by sending additional
6033 		    * values with a zero-length name...
6034 		    */
6035 
6036                     if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
6037 		    {
6038                       if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6039 	              {
6040 	        	DEBUG_puts("1ippWriteIO: Could not write IPP "
6041 		                   "attribute...");
6042 			_cupsBufferRelease((char *)buffer);
6043 	        	return (IPP_STATE_ERROR);
6044 	              }
6045 
6046 		      bufptr = buffer;
6047 		    }
6048 
6049                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
6050 		    *bufptr++ = 0;
6051 		    *bufptr++ = 0;
6052 		  }
6053 
6054                  /*
6055 		  * An unknown value might some new value that a
6056 		  * vendor has come up with. It consists of a
6057 		  * 2-byte length and the bytes in the unknown
6058 		  * value buffer.
6059 		  */
6060 
6061                   n = value->unknown.length;
6062 
6063                   if (n > (IPP_BUF_SIZE - 2))
6064 		  {
6065 		    DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
6066 		                  n));
6067 		    _cupsBufferRelease((char *)buffer);
6068 		    return (IPP_STATE_ERROR);
6069 		  }
6070 
6071                   if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
6072 		  {
6073                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6074 	            {
6075 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
6076 		                 "attribute...");
6077 		      _cupsBufferRelease((char *)buffer);
6078 	              return (IPP_STATE_ERROR);
6079 	            }
6080 
6081 		    bufptr = buffer;
6082 		  }
6083 
6084                  /* Length of unknown value */
6085 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
6086 		  *bufptr++ = (ipp_uchar_t)n;
6087 
6088                  /* Value */
6089 		  if (n > 0)
6090 		  {
6091 		    memcpy(bufptr, value->unknown.data, (size_t)n);
6092 		    bufptr += n;
6093 		  }
6094 		}
6095 		break;
6096 	  }
6097 
6098          /*
6099 	  * Write the data out...
6100 	  */
6101 
6102 	  if (bufptr > buffer)
6103 	  {
6104 	    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6105 	    {
6106 	      DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
6107 	      _cupsBufferRelease((char *)buffer);
6108 	      return (IPP_STATE_ERROR);
6109 	    }
6110 
6111 	    DEBUG_printf(("2ippWriteIO: wrote %d bytes",
6112 			  (int)(bufptr - buffer)));
6113 	  }
6114 
6115 	 /*
6116           * If blocking is disabled and we aren't at the end of the attribute
6117           * list, stop here...
6118 	  */
6119 
6120           if (!blocking && ipp->current)
6121 	    break;
6122 	}
6123 
6124 	if (ipp->current == NULL)
6125 	{
6126          /*
6127 	  * Done with all of the attributes; add the end-of-attributes
6128 	  * tag or end-collection attribute...
6129 	  */
6130 
6131           if (parent == NULL)
6132 	  {
6133             buffer[0] = IPP_TAG_END;
6134 	    n         = 1;
6135 	  }
6136 	  else
6137 	  {
6138             buffer[0] = IPP_TAG_END_COLLECTION;
6139 	    buffer[1] = 0; /* empty name */
6140 	    buffer[2] = 0;
6141 	    buffer[3] = 0; /* empty value */
6142 	    buffer[4] = 0;
6143 	    n         = 5;
6144 	  }
6145 
6146 	  if ((*cb)(dst, buffer, (size_t)n) < 0)
6147 	  {
6148 	    DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
6149 	    _cupsBufferRelease((char *)buffer);
6150 	    return (IPP_STATE_ERROR);
6151 	  }
6152 
6153 	  ipp->state = IPP_STATE_DATA;
6154 	}
6155         break;
6156 
6157     case IPP_STATE_DATA :
6158         break;
6159 
6160     default :
6161         break; /* anti-compiler-warning-code */
6162   }
6163 
6164   _cupsBufferRelease((char *)buffer);
6165 
6166   return (ipp->state);
6167 }
6168 
6169 
6170 /*
6171  * 'ipp_add_attr()' - Add a new attribute to the message.
6172  */
6173 
6174 static ipp_attribute_t *		/* O - New attribute */
ipp_add_attr(ipp_t * ipp,const char * name,ipp_tag_t group_tag,ipp_tag_t value_tag,int num_values)6175 ipp_add_attr(ipp_t      *ipp,		/* I - IPP message */
6176              const char *name,		/* I - Attribute name or NULL */
6177              ipp_tag_t  group_tag,	/* I - Group tag or IPP_TAG_ZERO */
6178              ipp_tag_t  value_tag,	/* I - Value tag or IPP_TAG_ZERO */
6179              int        num_values)	/* I - Number of values */
6180 {
6181   int			alloc_values;	/* Number of values to allocate */
6182   ipp_attribute_t	*attr;		/* New attribute */
6183 
6184 
6185   DEBUG_printf(("4ipp_add_attr(ipp=%p, name=\"%s\", group_tag=0x%x, value_tag=0x%x, num_values=%d)", (void *)ipp, name, group_tag, value_tag, num_values));
6186 
6187  /*
6188   * Range check input...
6189   */
6190 
6191   if (!ipp || num_values < 0)
6192     return (NULL);
6193 
6194  /*
6195   * Allocate memory, rounding the allocation up as needed...
6196   */
6197 
6198   if (num_values <= 1)
6199     alloc_values = 1;
6200   else
6201     alloc_values = (num_values + IPP_MAX_VALUES - 1) & ~(IPP_MAX_VALUES - 1);
6202 
6203   attr = calloc(sizeof(ipp_attribute_t) +
6204                 (size_t)(alloc_values - 1) * sizeof(_ipp_value_t), 1);
6205 
6206   if (attr)
6207   {
6208    /*
6209     * Initialize attribute...
6210     */
6211 
6212     DEBUG_printf(("4debug_alloc: %p %s %s%s (%d values)", (void *)attr, name, num_values > 1 ? "1setOf " : "", ippTagString(value_tag), num_values));
6213 
6214     if (name)
6215       attr->name = _cupsStrAlloc(name);
6216 
6217     attr->group_tag  = group_tag;
6218     attr->value_tag  = value_tag;
6219     attr->num_values = num_values;
6220 
6221    /*
6222     * Add it to the end of the linked list...
6223     */
6224 
6225     if (ipp->last)
6226       ipp->last->next = attr;
6227     else
6228       ipp->attrs = attr;
6229 
6230     ipp->prev = ipp->last;
6231     ipp->last = ipp->current = attr;
6232   }
6233 
6234   DEBUG_printf(("5ipp_add_attr: Returning %p", (void *)attr));
6235 
6236   return (attr);
6237 }
6238 
6239 
6240 /*
6241  * 'ipp_free_values()' - Free attribute values.
6242  */
6243 
6244 static void
ipp_free_values(ipp_attribute_t * attr,int element,int count)6245 ipp_free_values(ipp_attribute_t *attr,	/* I - Attribute to free values from */
6246                 int             element,/* I - First value to free */
6247                 int             count)	/* I - Number of values to free */
6248 {
6249   int		i;			/* Looping var */
6250   _ipp_value_t	*value;			/* Current value */
6251 
6252 
6253   DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", (void *)attr, element, count));
6254 
6255   if (!(attr->value_tag & IPP_TAG_CUPS_CONST))
6256   {
6257    /*
6258     * Free values as needed...
6259     */
6260 
6261     switch (attr->value_tag)
6262     {
6263       case IPP_TAG_TEXTLANG :
6264       case IPP_TAG_NAMELANG :
6265 	  if (element == 0 && count == attr->num_values &&
6266 	      attr->values[0].string.language)
6267 	  {
6268 	    _cupsStrFree(attr->values[0].string.language);
6269 	    attr->values[0].string.language = NULL;
6270 	  }
6271 	  /* Fall through to other string values */
6272 
6273       case IPP_TAG_TEXT :
6274       case IPP_TAG_NAME :
6275       case IPP_TAG_RESERVED_STRING :
6276       case IPP_TAG_KEYWORD :
6277       case IPP_TAG_URI :
6278       case IPP_TAG_URISCHEME :
6279       case IPP_TAG_CHARSET :
6280       case IPP_TAG_LANGUAGE :
6281       case IPP_TAG_MIMETYPE :
6282 	  for (i = count, value = attr->values + element;
6283 	       i > 0;
6284 	       i --, value ++)
6285 	  {
6286 	    _cupsStrFree(value->string.text);
6287 	    value->string.text = NULL;
6288 	  }
6289 	  break;
6290 
6291       case IPP_TAG_UNSUPPORTED_VALUE :
6292       case IPP_TAG_DEFAULT :
6293       case IPP_TAG_UNKNOWN :
6294       case IPP_TAG_NOVALUE :
6295       case IPP_TAG_NOTSETTABLE :
6296       case IPP_TAG_DELETEATTR :
6297       case IPP_TAG_ADMINDEFINE :
6298       case IPP_TAG_INTEGER :
6299       case IPP_TAG_ENUM :
6300       case IPP_TAG_BOOLEAN :
6301       case IPP_TAG_DATE :
6302       case IPP_TAG_RESOLUTION :
6303       case IPP_TAG_RANGE :
6304 	  break;
6305 
6306       case IPP_TAG_BEGIN_COLLECTION :
6307 	  for (i = count, value = attr->values + element;
6308 	       i > 0;
6309 	       i --, value ++)
6310 	  {
6311 	    ippDelete(value->collection);
6312 	    value->collection = NULL;
6313 	  }
6314 	  break;
6315 
6316       case IPP_TAG_STRING :
6317       default :
6318 	  for (i = count, value = attr->values + element;
6319 	       i > 0;
6320 	       i --, value ++)
6321 	  {
6322 	    if (value->unknown.data)
6323 	    {
6324 	      free(value->unknown.data);
6325 	      value->unknown.data = NULL;
6326 	    }
6327 	  }
6328 	  break;
6329     }
6330   }
6331 
6332  /*
6333   * If we are not freeing values from the end, move the remaining values up...
6334   */
6335 
6336   if ((element + count) < attr->num_values)
6337     memmove(attr->values + element, attr->values + element + count,
6338             (size_t)(attr->num_values - count - element) * sizeof(_ipp_value_t));
6339 
6340   attr->num_values -= count;
6341 }
6342 
6343 
6344 /*
6345  * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
6346  *
6347  * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
6348  * to "ll-cc", "ll-region", and "charset-number", respectively.
6349  */
6350 
6351 static char *				/* O - Language code string */
ipp_get_code(const char * value,char * buffer,size_t bufsize)6352 ipp_get_code(const char *value,		/* I - Locale/charset string */
6353              char       *buffer,	/* I - String buffer */
6354              size_t     bufsize)	/* I - Size of string buffer */
6355 {
6356   char	*bufptr,			/* Pointer into buffer */
6357 	*bufend;			/* End of buffer */
6358 
6359 
6360  /*
6361   * Convert values to lowercase and change _ to - as needed...
6362   */
6363 
6364   for (bufptr = buffer, bufend = buffer + bufsize - 1;
6365        *value && bufptr < bufend;
6366        value ++)
6367     if (*value == '_')
6368       *bufptr++ = '-';
6369     else
6370       *bufptr++ = (char)_cups_tolower(*value);
6371 
6372   *bufptr = '\0';
6373 
6374  /*
6375   * Return the converted string...
6376   */
6377 
6378   return (buffer);
6379 }
6380 
6381 
6382 /*
6383  * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
6384  *
6385  * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
6386  * "ll-region", respectively.  It also converts the "C" (POSIX) locale to "en".
6387  */
6388 
6389 static char *				/* O - Language code string */
ipp_lang_code(const char * locale,char * buffer,size_t bufsize)6390 ipp_lang_code(const char *locale,	/* I - Locale string */
6391               char       *buffer,	/* I - String buffer */
6392               size_t     bufsize)	/* I - Size of string buffer */
6393 {
6394  /*
6395   * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
6396   */
6397 
6398   if (!_cups_strcasecmp(locale, "c"))
6399   {
6400     strlcpy(buffer, "en", bufsize);
6401     return (buffer);
6402   }
6403   else
6404     return (ipp_get_code(locale, buffer, bufsize));
6405 }
6406 
6407 
6408 /*
6409  * 'ipp_length()' - Compute the length of an IPP message or collection value.
6410  */
6411 
6412 static size_t				/* O - Size of IPP message */
ipp_length(ipp_t * ipp,int collection)6413 ipp_length(ipp_t *ipp,			/* I - IPP message or collection */
6414            int   collection)		/* I - 1 if a collection, 0 otherwise */
6415 {
6416   int			i;		/* Looping var */
6417   size_t		bytes;		/* Number of bytes */
6418   ipp_attribute_t	*attr;		/* Current attribute */
6419   ipp_tag_t		group;		/* Current group */
6420   _ipp_value_t		*value;		/* Current value */
6421 
6422 
6423   DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", (void *)ipp, collection));
6424 
6425   if (!ipp)
6426   {
6427     DEBUG_puts("4ipp_length: Returning 0 bytes");
6428     return (0);
6429   }
6430 
6431  /*
6432   * Start with 8 bytes for the IPP message header...
6433   */
6434 
6435   bytes = collection ? 0 : 8;
6436 
6437  /*
6438   * Then add the lengths of each attribute...
6439   */
6440 
6441   group = IPP_TAG_ZERO;
6442 
6443   for (attr = ipp->attrs; attr != NULL; attr = attr->next)
6444   {
6445     if (attr->group_tag != group && !collection)
6446     {
6447       group = attr->group_tag;
6448       if (group == IPP_TAG_ZERO)
6449 	continue;
6450 
6451       bytes ++;	/* Group tag */
6452     }
6453 
6454     if (!attr->name)
6455       continue;
6456 
6457     DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
6458                   "bytes=" CUPS_LLFMT, attr->name, attr->num_values, CUPS_LLCAST bytes));
6459 
6460     if ((attr->value_tag & ~IPP_TAG_CUPS_CONST) < IPP_TAG_EXTENSION)
6461       bytes += (size_t)attr->num_values;/* Value tag for each value */
6462     else
6463       bytes += (size_t)(5 * attr->num_values);
6464 					/* Value tag for each value */
6465     bytes += (size_t)(2 * attr->num_values);
6466 					/* Name lengths */
6467     bytes += strlen(attr->name);	/* Name */
6468     bytes += (size_t)(2 * attr->num_values);
6469 					/* Value lengths */
6470 
6471     if (collection)
6472       bytes += 5;			/* Add membername overhead */
6473 
6474     switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
6475     {
6476       case IPP_TAG_UNSUPPORTED_VALUE :
6477       case IPP_TAG_DEFAULT :
6478       case IPP_TAG_UNKNOWN :
6479       case IPP_TAG_NOVALUE :
6480       case IPP_TAG_NOTSETTABLE :
6481       case IPP_TAG_DELETEATTR :
6482       case IPP_TAG_ADMINDEFINE :
6483           break;
6484 
6485       case IPP_TAG_INTEGER :
6486       case IPP_TAG_ENUM :
6487           bytes += (size_t)(4 * attr->num_values);
6488 	  break;
6489 
6490       case IPP_TAG_BOOLEAN :
6491           bytes += (size_t)attr->num_values;
6492 	  break;
6493 
6494       case IPP_TAG_TEXT :
6495       case IPP_TAG_NAME :
6496       case IPP_TAG_KEYWORD :
6497       case IPP_TAG_URI :
6498       case IPP_TAG_URISCHEME :
6499       case IPP_TAG_CHARSET :
6500       case IPP_TAG_LANGUAGE :
6501       case IPP_TAG_MIMETYPE :
6502 	  for (i = 0, value = attr->values;
6503 	       i < attr->num_values;
6504 	       i ++, value ++)
6505 	    if (value->string.text)
6506 	      bytes += strlen(value->string.text);
6507 	  break;
6508 
6509       case IPP_TAG_DATE :
6510           bytes += (size_t)(11 * attr->num_values);
6511 	  break;
6512 
6513       case IPP_TAG_RESOLUTION :
6514           bytes += (size_t)(9 * attr->num_values);
6515 	  break;
6516 
6517       case IPP_TAG_RANGE :
6518           bytes += (size_t)(8 * attr->num_values);
6519 	  break;
6520 
6521       case IPP_TAG_TEXTLANG :
6522       case IPP_TAG_NAMELANG :
6523           bytes += (size_t)(4 * attr->num_values);
6524 					/* Charset + text length */
6525 
6526 	  for (i = 0, value = attr->values;
6527 	       i < attr->num_values;
6528 	       i ++, value ++)
6529 	  {
6530 	    if (value->string.language)
6531 	      bytes += strlen(value->string.language);
6532 
6533 	    if (value->string.text)
6534 	      bytes += strlen(value->string.text);
6535 	  }
6536 	  break;
6537 
6538       case IPP_TAG_BEGIN_COLLECTION :
6539 	  for (i = 0, value = attr->values;
6540 	       i < attr->num_values;
6541 	       i ++, value ++)
6542             bytes += ipp_length(value->collection, 1);
6543 	  break;
6544 
6545       default :
6546 	  for (i = 0, value = attr->values;
6547 	       i < attr->num_values;
6548 	       i ++, value ++)
6549             bytes += (size_t)value->unknown.length;
6550 	  break;
6551     }
6552   }
6553 
6554  /*
6555   * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
6556   * for the "end of collection" tag and return...
6557   */
6558 
6559   if (collection)
6560     bytes += 5;
6561   else
6562     bytes ++;
6563 
6564   DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST bytes));
6565 
6566   return (bytes);
6567 }
6568 
6569 
6570 /*
6571  * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
6572  */
6573 
6574 static ssize_t				/* O - Number of bytes read */
ipp_read_http(http_t * http,ipp_uchar_t * buffer,size_t length)6575 ipp_read_http(http_t      *http,	/* I - Client connection */
6576               ipp_uchar_t *buffer,	/* O - Buffer for data */
6577 	      size_t      length)	/* I - Total length */
6578 {
6579   ssize_t	tbytes,			/* Total bytes read */
6580 		bytes;			/* Bytes read this pass */
6581 
6582 
6583   DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)", (void *)http, (void *)buffer, (int)length));
6584 
6585  /*
6586   * Loop until all bytes are read...
6587   */
6588 
6589   for (tbytes = 0, bytes = 0;
6590        tbytes < (int)length;
6591        tbytes += bytes, buffer += bytes)
6592   {
6593     DEBUG_printf(("9ipp_read_http: tbytes=" CUPS_LLFMT ", http->state=%d", CUPS_LLCAST tbytes, http->state));
6594 
6595     if (http->state == HTTP_STATE_WAITING)
6596       break;
6597 
6598     if (http->used == 0 && !http->blocking)
6599     {
6600      /*
6601       * Wait up to 10 seconds for more data on non-blocking sockets...
6602       */
6603 
6604       if (!httpWait(http, 10000))
6605       {
6606        /*
6607 	* Signal no data...
6608 	*/
6609 
6610 	bytes = -1;
6611 	break;
6612       }
6613     }
6614     else if (http->used == 0 && http->timeout_value > 0)
6615     {
6616      /*
6617       * Wait up to timeout seconds for more data on blocking sockets...
6618       */
6619 
6620       if (!httpWait(http, (int)(1000 * http->timeout_value)))
6621       {
6622        /*
6623 	* Signal no data...
6624 	*/
6625 
6626 	bytes = -1;
6627 	break;
6628       }
6629     }
6630 
6631     if ((bytes = httpRead2(http, (char *)buffer, length - (size_t)tbytes)) < 0)
6632     {
6633 #ifdef _WIN32
6634       break;
6635 #else
6636       if (errno != EAGAIN && errno != EINTR)
6637 	break;
6638 
6639       bytes = 0;
6640 #endif /* _WIN32 */
6641     }
6642     else if (bytes == 0)
6643       break;
6644   }
6645 
6646  /*
6647   * Return the number of bytes read...
6648   */
6649 
6650   if (tbytes == 0 && bytes < 0)
6651     tbytes = -1;
6652 
6653   DEBUG_printf(("8ipp_read_http: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST tbytes));
6654 
6655   return (tbytes);
6656 }
6657 
6658 
6659 /*
6660  * 'ipp_read_file()' - Read IPP data from a file.
6661  */
6662 
6663 static ssize_t				/* O - Number of bytes read */
ipp_read_file(int * fd,ipp_uchar_t * buffer,size_t length)6664 ipp_read_file(int         *fd,		/* I - File descriptor */
6665               ipp_uchar_t *buffer,	/* O - Read buffer */
6666 	      size_t      length)	/* I - Number of bytes to read */
6667 {
6668 #ifdef _WIN32
6669   return ((ssize_t)read(*fd, buffer, (unsigned)length));
6670 #else
6671   return (read(*fd, buffer, length));
6672 #endif /* _WIN32 */
6673 }
6674 
6675 
6676 /*
6677  * 'ipp_set_error()' - Set a formatted, localized error string.
6678  */
6679 
6680 static void
ipp_set_error(ipp_status_t status,const char * format,...)6681 ipp_set_error(ipp_status_t status,	/* I - Status code */
6682               const char   *format,	/* I - Printf-style error string */
6683 	      ...)			/* I - Additional arguments as needed */
6684 {
6685   va_list	ap;			/* Pointer to additional args */
6686   char		buffer[2048];		/* Message buffer */
6687   cups_lang_t	*lang = cupsLangDefault();
6688 					/* Current language */
6689 
6690 
6691   va_start(ap, format);
6692   vsnprintf(buffer, sizeof(buffer), _cupsLangString(lang, format), ap);
6693   va_end(ap);
6694 
6695   _cupsSetError(status, buffer, 0);
6696 }
6697 
6698 
6699 /*
6700  * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
6701  *                     needed.
6702  */
6703 
6704 static _ipp_value_t *			/* O  - IPP value element or NULL on error */
ipp_set_value(ipp_t * ipp,ipp_attribute_t ** attr,int element)6705 ipp_set_value(ipp_t           *ipp,	/* IO - IPP message */
6706               ipp_attribute_t **attr,	/* IO - IPP attribute */
6707               int             element)	/* I  - Value number (0-based) */
6708 {
6709   ipp_attribute_t	*temp,		/* New attribute pointer */
6710 			*current,	/* Current attribute in list */
6711 			*prev;		/* Previous attribute in list */
6712   int			alloc_values;	/* Allocated values */
6713 
6714 
6715  /*
6716   * If we are setting an existing value element, return it...
6717   */
6718 
6719   temp = *attr;
6720 
6721   if (temp->num_values <= 1)
6722     alloc_values = 1;
6723   else
6724     alloc_values = (temp->num_values + IPP_MAX_VALUES - 1) &
6725                    ~(IPP_MAX_VALUES - 1);
6726 
6727   if (element < alloc_values)
6728   {
6729     if (element >= temp->num_values)
6730       temp->num_values = element + 1;
6731 
6732     return (temp->values + element);
6733   }
6734 
6735  /*
6736   * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
6737   * values when num_values > 1.
6738   */
6739 
6740   if (alloc_values < IPP_MAX_VALUES)
6741     alloc_values = IPP_MAX_VALUES;
6742   else
6743     alloc_values += IPP_MAX_VALUES;
6744 
6745   DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
6746                 alloc_values));
6747 
6748  /*
6749   * Reallocate memory...
6750   */
6751 
6752   if ((temp = realloc(temp, sizeof(ipp_attribute_t) + (size_t)(alloc_values - 1) * sizeof(_ipp_value_t))) == NULL)
6753   {
6754     _cupsSetHTTPError(HTTP_STATUS_ERROR);
6755     DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
6756     return (NULL);
6757   }
6758 
6759  /*
6760   * Zero the new memory...
6761   */
6762 
6763   memset(temp->values + temp->num_values, 0, (size_t)(alloc_values - temp->num_values) * sizeof(_ipp_value_t));
6764 
6765   if (temp != *attr)
6766   {
6767    /*
6768     * Reset pointers in the list...
6769     */
6770 
6771 #ifndef __clang_analyzer__
6772     DEBUG_printf(("4debug_free: %p %s", (void *)*attr, temp->name));
6773 #endif /* !__clang_analyzer__ */
6774     DEBUG_printf(("4debug_alloc: %p %s %s%s (%d)", (void *)temp, temp->name, temp->num_values > 1 ? "1setOf " : "", ippTagString(temp->value_tag), temp->num_values));
6775 
6776     if (ipp->current == *attr && ipp->prev)
6777     {
6778      /*
6779       * Use current "previous" pointer...
6780       */
6781 
6782       prev = ipp->prev;
6783     }
6784     else
6785     {
6786      /*
6787       * Find this attribute in the linked list...
6788       */
6789 
6790       for (prev = NULL, current = ipp->attrs;
6791 	   current && current != *attr;
6792 	   prev = current, current = current->next);
6793 
6794       if (!current)
6795       {
6796        /*
6797 	* This is a serious error!
6798 	*/
6799 
6800 	*attr = temp;
6801 	_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
6802 	              _("IPP attribute is not a member of the message."), 1);
6803 	DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
6804 	return (NULL);
6805       }
6806     }
6807 
6808     if (prev)
6809       prev->next = temp;
6810     else
6811       ipp->attrs = temp;
6812 
6813     ipp->current = temp;
6814     ipp->prev    = prev;
6815 
6816     if (ipp->last == *attr)
6817       ipp->last = temp;
6818 
6819     *attr = temp;
6820   }
6821 
6822  /*
6823   * Return the value element...
6824   */
6825 
6826   if (element >= temp->num_values)
6827     temp->num_values = element + 1;
6828 
6829   return (temp->values + element);
6830 }
6831 
6832 
6833 /*
6834  * 'ipp_write_file()' - Write IPP data to a file.
6835  */
6836 
6837 static ssize_t				/* O - Number of bytes written */
ipp_write_file(int * fd,ipp_uchar_t * buffer,size_t length)6838 ipp_write_file(int         *fd,		/* I - File descriptor */
6839                ipp_uchar_t *buffer,	/* I - Data to write */
6840                size_t      length)	/* I - Number of bytes to write */
6841 {
6842 #ifdef _WIN32
6843   return ((ssize_t)write(*fd, buffer, (unsigned)length));
6844 #else
6845   return (write(*fd, buffer, length));
6846 #endif /* _WIN32 */
6847 }
6848