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