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)
4632           return (0);
4633 
4634         (*attr)->value_tag = (ipp_tag_t)(IPP_TAG_NAME | ((*attr)->value_tag & IPP_TAG_CUPS_CONST));
4635         break;
4636 
4637     case IPP_TAG_NAMELANG :
4638     case IPP_TAG_TEXTLANG :
4639         if (value_tag == IPP_TAG_NAMELANG && (temp_tag != IPP_TAG_NAME && temp_tag != IPP_TAG_KEYWORD))
4640           return (0);
4641 
4642         if (value_tag == IPP_TAG_TEXTLANG && temp_tag != IPP_TAG_TEXT)
4643           return (0);
4644 
4645         if (ipp->attrs && ipp->attrs->next && ipp->attrs->next->name &&
4646             !strcmp(ipp->attrs->next->name, "attributes-natural-language"))
4647         {
4648          /*
4649           * Use the language code from the IPP message...
4650           */
4651 
4652 	  (*attr)->values[0].string.language =
4653 	      _cupsStrAlloc(ipp->attrs->next->values[0].string.text);
4654         }
4655         else
4656         {
4657          /*
4658           * Otherwise, use the language code corresponding to the locale...
4659           */
4660 
4661 	  language = cupsLangDefault();
4662 	  (*attr)->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language->language,
4663 									code,
4664 									sizeof(code)));
4665         }
4666 
4667         for (i = (*attr)->num_values - 1, value = (*attr)->values + 1;
4668              i > 0;
4669              i --, value ++)
4670           value->string.language = (*attr)->values[0].string.language;
4671 
4672         if ((int)(*attr)->value_tag & IPP_TAG_CUPS_CONST)
4673         {
4674          /*
4675           * Make copies of all values...
4676           */
4677 
4678 	  for (i = (*attr)->num_values, value = (*attr)->values;
4679 	       i > 0;
4680 	       i --, value ++)
4681 	    value->string.text = _cupsStrAlloc(value->string.text);
4682         }
4683 
4684         (*attr)->value_tag = IPP_TAG_NAMELANG;
4685         break;
4686 
4687     case IPP_TAG_KEYWORD :
4688         if (temp_tag == IPP_TAG_NAME || temp_tag == IPP_TAG_NAMELANG)
4689           break;			/* Silently "allow" name -> keyword */
4690 
4691     default :
4692         return (0);
4693   }
4694 
4695   return (1);
4696 }
4697 
4698 
4699 /*
4700  * 'ippSetVersion()' - Set the version number in an IPP message.
4701  *
4702  * The @code ipp@ parameter refers to an IPP message previously created using
4703  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4704  *
4705  * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
4706  *
4707  * @since CUPS 1.6/macOS 10.8@
4708  */
4709 
4710 int					/* O - 1 on success, 0 on failure */
ippSetVersion(ipp_t * ipp,int major,int minor)4711 ippSetVersion(ipp_t *ipp,		/* I - IPP message */
4712               int   major,		/* I - Major version number (major.minor) */
4713               int   minor)		/* I - Minor version number (major.minor) */
4714 {
4715  /*
4716   * Range check input...
4717   */
4718 
4719   if (!ipp || major < 0 || minor < 0)
4720     return (0);
4721 
4722  /*
4723   * Set the version number...
4724   */
4725 
4726   ipp->request.any.version[0] = (ipp_uchar_t)major;
4727   ipp->request.any.version[1] = (ipp_uchar_t)minor;
4728 
4729   return (1);
4730 }
4731 
4732 
4733 /*
4734  * 'ippTimeToDate()' - Convert from time in seconds to RFC 2579 format.
4735  */
4736 
4737 const ipp_uchar_t *			/* O - RFC-2579 date/time data */
ippTimeToDate(time_t t)4738 ippTimeToDate(time_t t)			/* I - Time in seconds */
4739 {
4740   struct tm	*unixdate;		/* UNIX unixdate/time info */
4741   ipp_uchar_t	*date = _cupsGlobals()->ipp_date;
4742 					/* RFC-2579 date/time data */
4743 
4744 
4745  /*
4746   * RFC-2579 date/time format is:
4747   *
4748   *    Byte(s)  Description
4749   *    -------  -----------
4750   *    0-1      Year (0 to 65535)
4751   *    2        Month (1 to 12)
4752   *    3        Day (1 to 31)
4753   *    4        Hours (0 to 23)
4754   *    5        Minutes (0 to 59)
4755   *    6        Seconds (0 to 60, 60 = "leap second")
4756   *    7        Deciseconds (0 to 9)
4757   *    8        +/- UTC
4758   *    9        UTC hours (0 to 11)
4759   *    10       UTC minutes (0 to 59)
4760   */
4761 
4762   unixdate = gmtime(&t);
4763   unixdate->tm_year += 1900;
4764 
4765   date[0]  = (ipp_uchar_t)(unixdate->tm_year >> 8);
4766   date[1]  = (ipp_uchar_t)(unixdate->tm_year);
4767   date[2]  = (ipp_uchar_t)(unixdate->tm_mon + 1);
4768   date[3]  = (ipp_uchar_t)unixdate->tm_mday;
4769   date[4]  = (ipp_uchar_t)unixdate->tm_hour;
4770   date[5]  = (ipp_uchar_t)unixdate->tm_min;
4771   date[6]  = (ipp_uchar_t)unixdate->tm_sec;
4772   date[7]  = 0;
4773   date[8]  = '+';
4774   date[9]  = 0;
4775   date[10] = 0;
4776 
4777   return (date);
4778 }
4779 
4780 
4781 /*
4782  * 'ippValidateAttribute()' - Validate the contents of an attribute.
4783  *
4784  * This function validates the contents of an attribute based on the name and
4785  * value tag.  1 is returned if the attribute is valid, 0 otherwise.  On
4786  * failure, @link cupsLastErrorString@ is set to a human-readable message.
4787  *
4788  * @since CUPS 1.7/macOS 10.9@
4789  */
4790 
4791 int					/* O - 1 if valid, 0 otherwise */
ippValidateAttribute(ipp_attribute_t * attr)4792 ippValidateAttribute(
4793     ipp_attribute_t *attr)		/* I - Attribute */
4794 {
4795   int		i;			/* Looping var */
4796   char		scheme[64],		/* Scheme from URI */
4797 		userpass[256],		/* Username/password from URI */
4798 		hostname[256],		/* Hostname from URI */
4799 		resource[1024];		/* Resource from URI */
4800   int		port,			/* Port number from URI */
4801 		uri_status;		/* URI separation status */
4802   const char	*ptr;			/* Pointer into string */
4803   ipp_attribute_t *colattr;		/* Collection attribute */
4804   regex_t	re;			/* Regular expression */
4805   ipp_uchar_t	*date;			/* Current date value */
4806   static const char * const uri_status_strings[] =
4807   {					/* URI status strings */
4808     "URI too large",
4809     "Bad arguments to function",
4810     "Bad resource in URI",
4811     "Bad port number in URI",
4812     "Bad hostname/address in URI",
4813     "Bad username in URI",
4814     "Bad scheme in URI",
4815     "Bad/empty URI",
4816     "OK",
4817     "Missing scheme in URI",
4818     "Unknown scheme in URI",
4819     "Missing resource in URI"
4820   };
4821 
4822 
4823  /*
4824   * Skip separators.
4825   */
4826 
4827   if (!attr->name)
4828     return (1);
4829 
4830  /*
4831   * Validate the attribute name.
4832   */
4833 
4834   for (ptr = attr->name; *ptr; ptr ++)
4835     if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' && *ptr != '_')
4836       break;
4837 
4838   if (*ptr || ptr == attr->name)
4839   {
4840     ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4841                   _("\"%s\": Bad attribute name - invalid character "
4842 		    "(RFC 8011 section 5.1.4)."), attr->name);
4843     return (0);
4844   }
4845 
4846   if ((ptr - attr->name) > 255)
4847   {
4848     ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4849                   _("\"%s\": Bad attribute name - bad length %d "
4850 		    "(RFC 8011 section 5.1.4)."), attr->name,
4851 		  (int)(ptr - attr->name));
4852     return (0);
4853   }
4854 
4855   switch (attr->value_tag)
4856   {
4857     case IPP_TAG_INTEGER :
4858         break;
4859 
4860     case IPP_TAG_BOOLEAN :
4861         for (i = 0; i < attr->num_values; i ++)
4862 	{
4863 	  if (attr->values[i].boolean != 0 &&
4864 	      attr->values[i].boolean != 1)
4865 	  {
4866 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4867                           _("\"%s\": Bad boolen value %d "
4868 			    "(RFC 8011 section 5.1.21)."), attr->name,
4869 			  attr->values[i].boolean);
4870 	    return (0);
4871 	  }
4872 	}
4873         break;
4874 
4875     case IPP_TAG_ENUM :
4876         for (i = 0; i < attr->num_values; i ++)
4877 	{
4878 	  if (attr->values[i].integer < 1)
4879 	  {
4880 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4881 			  _("\"%s\": Bad enum value %d - out of range "
4882 			    "(RFC 8011 section 5.1.5)."), attr->name,
4883 			    attr->values[i].integer);
4884             return (0);
4885 	  }
4886 	}
4887         break;
4888 
4889     case IPP_TAG_STRING :
4890         for (i = 0; i < attr->num_values; i ++)
4891 	{
4892 	  if (attr->values[i].unknown.length > IPP_MAX_OCTETSTRING)
4893 	  {
4894 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4895 			  _("\"%s\": Bad octetString value - bad length %d "
4896 			    "(RFC 8011 section 5.1.20)."), attr->name,
4897 			    attr->values[i].unknown.length);
4898 	    return (0);
4899 	  }
4900 	}
4901         break;
4902 
4903     case IPP_TAG_DATE :
4904         for (i = 0; i < attr->num_values; i ++)
4905 	{
4906 	  date = attr->values[i].date;
4907 
4908           if (date[2] < 1 || date[2] > 12)
4909 	  {
4910 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4911 			  _("\"%s\": Bad dateTime month %u "
4912 			    "(RFC 8011 section 5.1.15)."), attr->name, date[2]);
4913 	    return (0);
4914 	  }
4915 
4916           if (date[3] < 1 || date[3] > 31)
4917 	  {
4918 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4919 			  _("\"%s\": Bad dateTime day %u "
4920 			    "(RFC 8011 section 5.1.15)."), attr->name, date[3]);
4921 	    return (0);
4922 	  }
4923 
4924           if (date[4] > 23)
4925 	  {
4926 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4927 			  _("\"%s\": Bad dateTime hours %u "
4928 			    "(RFC 8011 section 5.1.15)."), attr->name, date[4]);
4929 	    return (0);
4930 	  }
4931 
4932           if (date[5] > 59)
4933 	  {
4934 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4935 			  _("\"%s\": Bad dateTime minutes %u "
4936 			    "(RFC 8011 section 5.1.15)."), attr->name, date[5]);
4937 	    return (0);
4938 	  }
4939 
4940           if (date[6] > 60)
4941 	  {
4942 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4943 			  _("\"%s\": Bad dateTime seconds %u "
4944 			    "(RFC 8011 section 5.1.15)."), attr->name, date[6]);
4945 	    return (0);
4946 	  }
4947 
4948           if (date[7] > 9)
4949 	  {
4950 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4951 			  _("\"%s\": Bad dateTime deciseconds %u "
4952 			    "(RFC 8011 section 5.1.15)."), attr->name, date[7]);
4953 	    return (0);
4954 	  }
4955 
4956           if (date[8] != '-' && date[8] != '+')
4957 	  {
4958 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4959 			  _("\"%s\": Bad dateTime UTC sign '%c' "
4960 			    "(RFC 8011 section 5.1.15)."), attr->name, date[8]);
4961 	    return (0);
4962 	  }
4963 
4964           if (date[9] > 11)
4965 	  {
4966 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4967 			  _("\"%s\": Bad dateTime UTC hours %u "
4968 			    "(RFC 8011 section 5.1.15)."), attr->name, date[9]);
4969 	    return (0);
4970 	  }
4971 
4972           if (date[10] > 59)
4973 	  {
4974 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4975 			  _("\"%s\": Bad dateTime UTC minutes %u "
4976 			    "(RFC 8011 section 5.1.15)."), attr->name, date[10]);
4977 	    return (0);
4978 	  }
4979 	}
4980         break;
4981 
4982     case IPP_TAG_RESOLUTION :
4983         for (i = 0; i < attr->num_values; i ++)
4984 	{
4985 	  if (attr->values[i].resolution.xres <= 0)
4986 	  {
4987 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4988 			  _("\"%s\": Bad resolution value %dx%d%s - cross "
4989 			    "feed resolution must be positive "
4990 			    "(RFC 8011 section 5.1.16)."), attr->name,
4991 			  attr->values[i].resolution.xres,
4992 			  attr->values[i].resolution.yres,
4993 			  attr->values[i].resolution.units ==
4994 			      IPP_RES_PER_INCH ? "dpi" :
4995 			      attr->values[i].resolution.units ==
4996 				  IPP_RES_PER_CM ? "dpcm" : "unknown");
4997 	    return (0);
4998 	  }
4999 
5000 	  if (attr->values[i].resolution.yres <= 0)
5001 	  {
5002 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5003 			  _("\"%s\": Bad resolution value %dx%d%s - feed "
5004 			    "resolution must be positive "
5005 			    "(RFC 8011 section 5.1.16)."), attr->name,
5006 			  attr->values[i].resolution.xres,
5007 			  attr->values[i].resolution.yres,
5008 			  attr->values[i].resolution.units ==
5009 			      IPP_RES_PER_INCH ? "dpi" :
5010 			      attr->values[i].resolution.units ==
5011 				  IPP_RES_PER_CM ? "dpcm" : "unknown");
5012             return (0);
5013 	  }
5014 
5015 	  if (attr->values[i].resolution.units != IPP_RES_PER_INCH &&
5016 	      attr->values[i].resolution.units != IPP_RES_PER_CM)
5017 	  {
5018 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5019 			  _("\"%s\": Bad resolution value %dx%d%s - bad "
5020 			    "units value (RFC 8011 section 5.1.16)."),
5021 			  attr->name, attr->values[i].resolution.xres,
5022 			  attr->values[i].resolution.yres,
5023 			  attr->values[i].resolution.units ==
5024 			      IPP_RES_PER_INCH ? "dpi" :
5025 			      attr->values[i].resolution.units ==
5026 				  IPP_RES_PER_CM ? "dpcm" : "unknown");
5027 	    return (0);
5028 	  }
5029 	}
5030         break;
5031 
5032     case IPP_TAG_RANGE :
5033         for (i = 0; i < attr->num_values; i ++)
5034 	{
5035 	  if (attr->values[i].range.lower > attr->values[i].range.upper)
5036 	  {
5037 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5038 			  _("\"%s\": Bad rangeOfInteger value %d-%d - lower "
5039 			    "greater than upper (RFC 8011 section 5.1.14)."),
5040 			  attr->name, attr->values[i].range.lower,
5041 			  attr->values[i].range.upper);
5042 	    return (0);
5043 	  }
5044 	}
5045         break;
5046 
5047     case IPP_TAG_BEGIN_COLLECTION :
5048         for (i = 0; i < attr->num_values; i ++)
5049 	{
5050 	  for (colattr = attr->values[i].collection->attrs;
5051 	       colattr;
5052 	       colattr = colattr->next)
5053 	  {
5054 	    if (!ippValidateAttribute(colattr))
5055 	      return (0);
5056 	  }
5057 	}
5058         break;
5059 
5060     case IPP_TAG_TEXT :
5061     case IPP_TAG_TEXTLANG :
5062         for (i = 0; i < attr->num_values; i ++)
5063 	{
5064 	  for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5065 	  {
5066 	    if ((*ptr & 0xe0) == 0xc0)
5067 	    {
5068 	      ptr ++;
5069 	      if ((*ptr & 0xc0) != 0x80)
5070 	        break;
5071 	    }
5072 	    else if ((*ptr & 0xf0) == 0xe0)
5073 	    {
5074 	      ptr ++;
5075 	      if ((*ptr & 0xc0) != 0x80)
5076 	        break;
5077 	      ptr ++;
5078 	      if ((*ptr & 0xc0) != 0x80)
5079 	        break;
5080 	    }
5081 	    else if ((*ptr & 0xf8) == 0xf0)
5082 	    {
5083 	      ptr ++;
5084 	      if ((*ptr & 0xc0) != 0x80)
5085 	        break;
5086 	      ptr ++;
5087 	      if ((*ptr & 0xc0) != 0x80)
5088 	        break;
5089 	      ptr ++;
5090 	      if ((*ptr & 0xc0) != 0x80)
5091 	        break;
5092 	    }
5093 	    else if (*ptr & 0x80)
5094 	      break;
5095 	  }
5096 
5097 	  if (*ptr)
5098 	  {
5099 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5100 			  _("\"%s\": Bad text value \"%s\" - bad UTF-8 "
5101 			    "sequence (RFC 8011 section 5.1.2)."), attr->name,
5102 			  attr->values[i].string.text);
5103 	    return (0);
5104 	  }
5105 
5106 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_TEXT - 1))
5107 	  {
5108 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5109 			  _("\"%s\": Bad text value \"%s\" - bad length %d "
5110 			    "(RFC 8011 section 5.1.2)."), attr->name,
5111 			  attr->values[i].string.text,
5112 			  (int)(ptr - attr->values[i].string.text));
5113 	    return (0);
5114 	  }
5115 	}
5116         break;
5117 
5118     case IPP_TAG_NAME :
5119     case IPP_TAG_NAMELANG :
5120         for (i = 0; i < attr->num_values; i ++)
5121 	{
5122 	  for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5123 	  {
5124 	    if ((*ptr & 0xe0) == 0xc0)
5125 	    {
5126 	      ptr ++;
5127 	      if ((*ptr & 0xc0) != 0x80)
5128 	        break;
5129 	    }
5130 	    else if ((*ptr & 0xf0) == 0xe0)
5131 	    {
5132 	      ptr ++;
5133 	      if ((*ptr & 0xc0) != 0x80)
5134 	        break;
5135 	      ptr ++;
5136 	      if ((*ptr & 0xc0) != 0x80)
5137 	        break;
5138 	    }
5139 	    else if ((*ptr & 0xf8) == 0xf0)
5140 	    {
5141 	      ptr ++;
5142 	      if ((*ptr & 0xc0) != 0x80)
5143 	        break;
5144 	      ptr ++;
5145 	      if ((*ptr & 0xc0) != 0x80)
5146 	        break;
5147 	      ptr ++;
5148 	      if ((*ptr & 0xc0) != 0x80)
5149 	        break;
5150 	    }
5151 	    else if (*ptr & 0x80)
5152 	      break;
5153 	  }
5154 
5155 	  if (*ptr)
5156 	  {
5157 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5158 			  _("\"%s\": Bad name value \"%s\" - bad UTF-8 "
5159 			    "sequence (RFC 8011 section 5.1.3)."), attr->name,
5160 			  attr->values[i].string.text);
5161 	    return (0);
5162 	  }
5163 
5164 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_NAME - 1))
5165 	  {
5166 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5167 			  _("\"%s\": Bad name value \"%s\" - bad length %d "
5168 			    "(RFC 8011 section 5.1.3)."), attr->name,
5169 			  attr->values[i].string.text,
5170 			  (int)(ptr - attr->values[i].string.text));
5171 	    return (0);
5172 	  }
5173 	}
5174         break;
5175 
5176     case IPP_TAG_KEYWORD :
5177         for (i = 0; i < attr->num_values; i ++)
5178 	{
5179 	  for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5180 	    if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' &&
5181 	        *ptr != '_')
5182 	      break;
5183 
5184 	  if (*ptr || ptr == attr->values[i].string.text)
5185 	  {
5186 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5187 			  _("\"%s\": Bad keyword value \"%s\" - invalid "
5188 			    "character (RFC 8011 section 5.1.4)."),
5189 			  attr->name, attr->values[i].string.text);
5190 	    return (0);
5191 	  }
5192 
5193 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_KEYWORD - 1))
5194 	  {
5195 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5196 			  _("\"%s\": Bad keyword value \"%s\" - bad "
5197 			    "length %d (RFC 8011 section 5.1.4)."),
5198 			  attr->name, attr->values[i].string.text,
5199 			  (int)(ptr - attr->values[i].string.text));
5200 	    return (0);
5201 	  }
5202 	}
5203         break;
5204 
5205     case IPP_TAG_URI :
5206         for (i = 0; i < attr->num_values; i ++)
5207 	{
5208 	  uri_status = httpSeparateURI(HTTP_URI_CODING_ALL,
5209 	                               attr->values[i].string.text,
5210 				       scheme, sizeof(scheme),
5211 				       userpass, sizeof(userpass),
5212 				       hostname, sizeof(hostname),
5213 				       &port, resource, sizeof(resource));
5214 
5215 	  if (uri_status < HTTP_URI_STATUS_OK)
5216 	  {
5217 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5218 			  _("\"%s\": Bad URI value \"%s\" - %s "
5219 			    "(RFC 8011 section 5.1.6)."), attr->name,
5220 			  attr->values[i].string.text,
5221 			  uri_status_strings[uri_status -
5222 					     HTTP_URI_STATUS_OVERFLOW]);
5223 	    return (0);
5224 	  }
5225 
5226 	  if (strlen(attr->values[i].string.text) > (IPP_MAX_URI - 1))
5227 	  {
5228 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5229 			  _("\"%s\": Bad URI value \"%s\" - bad length %d "
5230 			    "(RFC 8011 section 5.1.6)."), attr->name,
5231 			  attr->values[i].string.text,
5232 			  (int)strlen(attr->values[i].string.text));
5233 	  }
5234 	}
5235         break;
5236 
5237     case IPP_TAG_URISCHEME :
5238         for (i = 0; i < attr->num_values; i ++)
5239 	{
5240 	  ptr = attr->values[i].string.text;
5241 	  if (islower(*ptr & 255))
5242 	  {
5243 	    for (ptr ++; *ptr; ptr ++)
5244 	      if (!islower(*ptr & 255) && !isdigit(*ptr & 255) &&
5245 	          *ptr != '+' && *ptr != '-' && *ptr != '.')
5246                 break;
5247 	  }
5248 
5249 	  if (*ptr || ptr == attr->values[i].string.text)
5250 	  {
5251 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5252 			  _("\"%s\": Bad uriScheme value \"%s\" - bad "
5253 			    "characters (RFC 8011 section 5.1.7)."),
5254 			  attr->name, attr->values[i].string.text);
5255 	    return (0);
5256 	  }
5257 
5258 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_URISCHEME - 1))
5259 	  {
5260 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5261 			  _("\"%s\": Bad uriScheme value \"%s\" - bad "
5262 			    "length %d (RFC 8011 section 5.1.7)."),
5263 			  attr->name, attr->values[i].string.text,
5264 			  (int)(ptr - attr->values[i].string.text));
5265 	    return (0);
5266 	  }
5267 	}
5268         break;
5269 
5270     case IPP_TAG_CHARSET :
5271         for (i = 0; i < attr->num_values; i ++)
5272 	{
5273 	  for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5274 	    if (!isprint(*ptr & 255) || isupper(*ptr & 255) ||
5275 	        isspace(*ptr & 255))
5276 	      break;
5277 
5278 	  if (*ptr || ptr == attr->values[i].string.text)
5279 	  {
5280 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5281 			  _("\"%s\": Bad charset value \"%s\" - bad "
5282 			    "characters (RFC 8011 section 5.1.8)."),
5283 			  attr->name, attr->values[i].string.text);
5284 	    return (0);
5285 	  }
5286 
5287 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_CHARSET - 1))
5288 	  {
5289 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5290 			  _("\"%s\": Bad charset value \"%s\" - bad "
5291 			    "length %d (RFC 8011 section 5.1.8)."),
5292 			  attr->name, attr->values[i].string.text,
5293 			  (int)(ptr - attr->values[i].string.text));
5294 	    return (0);
5295 	  }
5296 	}
5297         break;
5298 
5299     case IPP_TAG_LANGUAGE :
5300        /*
5301         * The following regular expression is derived from the ABNF for
5302 	* language tags in RFC 4646.  All I can say is that this is the
5303 	* easiest way to check the values...
5304 	*/
5305 
5306         if ((i = regcomp(&re,
5307 			 "^("
5308 			 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
5309 								/* language */
5310 			 "(-[a-z][a-z][a-z][a-z]){0,1}"		/* script */
5311 			 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}"	/* region */
5312 			 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*"	/* variant */
5313 			 "(-[a-wy-z](-[a-z0-9]{2,8})+)*"	/* extension */
5314 			 "(-x(-[a-z0-9]{1,8})+)*"		/* privateuse */
5315 			 "|"
5316 			 "x(-[a-z0-9]{1,8})+"			/* privateuse */
5317 			 "|"
5318 			 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}"	/* grandfathered */
5319 			 ")$",
5320 			 REG_NOSUB | REG_EXTENDED)) != 0)
5321         {
5322           char	temp[256];		/* Temporary error string */
5323 
5324           regerror(i, &re, temp, sizeof(temp));
5325 	  ipp_set_error(IPP_STATUS_ERROR_INTERNAL,
5326 			_("Unable to compile naturalLanguage regular "
5327 			  "expression: %s."), temp);
5328 	  return (0);
5329         }
5330 
5331         for (i = 0; i < attr->num_values; i ++)
5332 	{
5333 	  if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
5334 	  {
5335 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5336 			  _("\"%s\": Bad naturalLanguage value \"%s\" - bad "
5337 			    "characters (RFC 8011 section 5.1.9)."),
5338 			  attr->name, attr->values[i].string.text);
5339 	    regfree(&re);
5340 	    return (0);
5341 	  }
5342 
5343 	  if (strlen(attr->values[i].string.text) > (IPP_MAX_LANGUAGE - 1))
5344 	  {
5345 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5346 			  _("\"%s\": Bad naturalLanguage value \"%s\" - bad "
5347 			    "length %d (RFC 8011 section 5.1.9)."),
5348 			  attr->name, attr->values[i].string.text,
5349 			  (int)strlen(attr->values[i].string.text));
5350 	    regfree(&re);
5351 	    return (0);
5352 	  }
5353 	}
5354 
5355 	regfree(&re);
5356         break;
5357 
5358     case IPP_TAG_MIMETYPE :
5359        /*
5360         * The following regular expression is derived from the ABNF for
5361 	* MIME media types in RFC 2045 and 4288.  All I can say is that this is
5362 	* the easiest way to check the values...
5363 	*/
5364 
5365         if ((i = regcomp(&re,
5366 			 "^"
5367 			 "[-a-zA-Z0-9!#$&.+^_]{1,127}"		/* type-name */
5368 			 "/"
5369 			 "[-a-zA-Z0-9!#$&.+^_]{1,127}"		/* subtype-name */
5370 			 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}="	/* parameter= */
5371 			 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
5372 			 					/* value */
5373 			 "$",
5374 			 REG_NOSUB | REG_EXTENDED)) != 0)
5375         {
5376           char	temp[256];		/* Temporary error string */
5377 
5378           regerror(i, &re, temp, sizeof(temp));
5379 	  ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5380 			_("Unable to compile mimeMediaType regular "
5381 			  "expression: %s."), temp);
5382 	  return (0);
5383         }
5384 
5385         for (i = 0; i < attr->num_values; i ++)
5386 	{
5387 	  if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
5388 	  {
5389 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5390 			  _("\"%s\": Bad mimeMediaType value \"%s\" - bad "
5391 			    "characters (RFC 8011 section 5.1.10)."),
5392 			  attr->name, attr->values[i].string.text);
5393 	    regfree(&re);
5394 	    return (0);
5395 	  }
5396 
5397 	  if (strlen(attr->values[i].string.text) > (IPP_MAX_MIMETYPE - 1))
5398 	  {
5399 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5400 			  _("\"%s\": Bad mimeMediaType value \"%s\" - bad "
5401 			    "length %d (RFC 8011 section 5.1.10)."),
5402 			  attr->name, attr->values[i].string.text,
5403 			  (int)strlen(attr->values[i].string.text));
5404 	    regfree(&re);
5405 	    return (0);
5406 	  }
5407 	}
5408 
5409 	regfree(&re);
5410         break;
5411 
5412     default :
5413         break;
5414   }
5415 
5416   return (1);
5417 }
5418 
5419 
5420 /*
5421  * 'ippValidateAttributes()' - Validate all attributes in an IPP message.
5422  *
5423  * This function validates the contents of the IPP message, including each
5424  * attribute.  Like @link ippValidateAttribute@, @link cupsLastErrorString@ is
5425  * set to a human-readable message on failure.
5426  *
5427  * @since CUPS 1.7/macOS 10.9@
5428  */
5429 
5430 int					/* O - 1 if valid, 0 otherwise */
ippValidateAttributes(ipp_t * ipp)5431 ippValidateAttributes(ipp_t *ipp)	/* I - IPP message */
5432 {
5433   ipp_attribute_t	*attr;		/* Current attribute */
5434 
5435 
5436   if (!ipp)
5437     return (1);
5438 
5439   for (attr = ipp->attrs; attr; attr = attr->next)
5440     if (!ippValidateAttribute(attr))
5441       return (0);
5442 
5443   return (1);
5444 }
5445 
5446 
5447 /*
5448  * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
5449  */
5450 
5451 ipp_state_t				/* O - Current state */
ippWrite(http_t * http,ipp_t * ipp)5452 ippWrite(http_t *http,			/* I - HTTP connection */
5453          ipp_t  *ipp)			/* I - IPP data */
5454 {
5455   DEBUG_printf(("ippWrite(http=%p, ipp=%p)", (void *)http, (void *)ipp));
5456 
5457   if (!http)
5458     return (IPP_STATE_ERROR);
5459 
5460   return (ippWriteIO(http, (ipp_iocb_t)httpWrite2, http->blocking, NULL, ipp));
5461 }
5462 
5463 
5464 /*
5465  * 'ippWriteFile()' - Write data for an IPP message to a file.
5466  *
5467  * @since CUPS 1.1.19/macOS 10.3@
5468  */
5469 
5470 ipp_state_t				/* O - Current state */
ippWriteFile(int fd,ipp_t * ipp)5471 ippWriteFile(int   fd,			/* I - HTTP data */
5472              ipp_t *ipp)		/* I - IPP data */
5473 {
5474   DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd, (void *)ipp));
5475 
5476   ipp->state = IPP_STATE_IDLE;
5477 
5478   return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp));
5479 }
5480 
5481 
5482 /*
5483  * 'ippWriteIO()' - Write data for an IPP message.
5484  *
5485  * @since CUPS 1.2/macOS 10.5@
5486  */
5487 
5488 ipp_state_t				/* O - Current state */
ippWriteIO(void * dst,ipp_iocb_t cb,int blocking,ipp_t * parent,ipp_t * ipp)5489 ippWriteIO(void       *dst,		/* I - Destination */
5490            ipp_iocb_t cb,		/* I - Write callback function */
5491 	   int        blocking,		/* I - Use blocking IO? */
5492 	   ipp_t      *parent,		/* I - Parent IPP message */
5493            ipp_t      *ipp)		/* I - IPP data */
5494 {
5495   int			i;		/* Looping var */
5496   int			n;		/* Length of data */
5497   unsigned char		*buffer,	/* Data buffer */
5498 			*bufptr;	/* Pointer into buffer */
5499   ipp_attribute_t	*attr;		/* Current attribute */
5500   _ipp_value_t		*value;		/* Current value */
5501 
5502 
5503   DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)dst, (void *)cb, blocking, (void *)parent, (void *)ipp));
5504 
5505   if (!dst || !ipp)
5506     return (IPP_STATE_ERROR);
5507 
5508   if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
5509   {
5510     DEBUG_puts("1ippWriteIO: Unable to get write buffer");
5511     return (IPP_STATE_ERROR);
5512   }
5513 
5514   switch (ipp->state)
5515   {
5516     case IPP_STATE_IDLE :
5517         ipp->state ++; /* Avoid common problem... */
5518 
5519     case IPP_STATE_HEADER :
5520         if (parent == NULL)
5521 	{
5522 	 /*
5523 	  * Send the request header:
5524 	  *
5525 	  *                 Version = 2 bytes
5526 	  *   Operation/Status Code = 2 bytes
5527 	  *              Request ID = 4 bytes
5528 	  *                   Total = 8 bytes
5529 	  */
5530 
5531           bufptr = buffer;
5532 
5533 	  *bufptr++ = ipp->request.any.version[0];
5534 	  *bufptr++ = ipp->request.any.version[1];
5535 	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.op_status >> 8);
5536 	  *bufptr++ = (ipp_uchar_t)ipp->request.any.op_status;
5537 	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 24);
5538 	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 16);
5539 	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 8);
5540 	  *bufptr++ = (ipp_uchar_t)ipp->request.any.request_id;
5541 
5542 	  DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer[0], buffer[1]));
5543 	  DEBUG_printf(("2ippWriteIO: op_status=%04x",
5544 			ipp->request.any.op_status));
5545 	  DEBUG_printf(("2ippWriteIO: request_id=%d",
5546 			ipp->request.any.request_id));
5547 
5548           if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5549 	  {
5550 	    DEBUG_puts("1ippWriteIO: Could not write IPP header...");
5551 	    _cupsBufferRelease((char *)buffer);
5552 	    return (IPP_STATE_ERROR);
5553 	  }
5554 	}
5555 
5556        /*
5557 	* Reset the state engine to point to the first attribute
5558 	* in the request/response, with no current group.
5559 	*/
5560 
5561         ipp->state   = IPP_STATE_ATTRIBUTE;
5562 	ipp->current = ipp->attrs;
5563 	ipp->curtag  = IPP_TAG_ZERO;
5564 
5565 	DEBUG_printf(("1ippWriteIO: ipp->current=%p", (void *)ipp->current));
5566 
5567        /*
5568         * If blocking is disabled, stop here...
5569 	*/
5570 
5571         if (!blocking)
5572 	  break;
5573 
5574     case IPP_STATE_ATTRIBUTE :
5575         while (ipp->current != NULL)
5576 	{
5577 	 /*
5578 	  * Write this attribute...
5579 	  */
5580 
5581 	  bufptr = buffer;
5582 	  attr   = ipp->current;
5583 
5584 	  ipp->current = ipp->current->next;
5585 
5586           if (!parent)
5587 	  {
5588 	    if (ipp->curtag != attr->group_tag)
5589 	    {
5590 	     /*
5591 	      * Send a group tag byte...
5592 	      */
5593 
5594 	      ipp->curtag = attr->group_tag;
5595 
5596 	      if (attr->group_tag == IPP_TAG_ZERO)
5597 		continue;
5598 
5599 	      DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
5600 			    attr->group_tag, ippTagString(attr->group_tag)));
5601 	      *bufptr++ = (ipp_uchar_t)attr->group_tag;
5602 	    }
5603 	    else if (attr->group_tag == IPP_TAG_ZERO)
5604 	      continue;
5605 	  }
5606 
5607 	  DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr->name,
5608 	                attr->num_values > 1 ? "1setOf " : "",
5609 			ippTagString(attr->value_tag)));
5610 
5611          /*
5612 	  * Write the attribute tag and name.
5613 	  *
5614 	  * The attribute name length does not include the trailing nul
5615 	  * character in the source string.
5616 	  *
5617 	  * Collection values (parent != NULL) are written differently...
5618 	  */
5619 
5620           if (parent == NULL)
5621 	  {
5622            /*
5623 	    * Get the length of the attribute name, and make sure it won't
5624 	    * overflow the buffer...
5625 	    */
5626 
5627             if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 8))
5628 	    {
5629 	      DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
5630 	      _cupsBufferRelease((char *)buffer);
5631 	      return (IPP_STATE_ERROR);
5632 	    }
5633 
5634            /*
5635 	    * Write the value tag, name length, and name string...
5636 	    */
5637 
5638             DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5639 	                  attr->value_tag, ippTagString(attr->value_tag)));
5640             DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
5641 	                  attr->name));
5642 
5643             if (attr->value_tag > 0xff)
5644             {
5645               *bufptr++ = IPP_TAG_EXTENSION;
5646 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
5647 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
5648 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
5649 	      *bufptr++ = (ipp_uchar_t)attr->value_tag;
5650             }
5651             else
5652 	      *bufptr++ = (ipp_uchar_t)attr->value_tag;
5653 
5654 	    *bufptr++ = (ipp_uchar_t)(n >> 8);
5655 	    *bufptr++ = (ipp_uchar_t)n;
5656 	    memcpy(bufptr, attr->name, (size_t)n);
5657 	    bufptr += n;
5658           }
5659 	  else
5660 	  {
5661            /*
5662 	    * Get the length of the attribute name, and make sure it won't
5663 	    * overflow the buffer...
5664 	    */
5665 
5666             if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 12))
5667 	    {
5668 	      DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
5669 	      _cupsBufferRelease((char *)buffer);
5670 	      return (IPP_STATE_ERROR);
5671 	    }
5672 
5673            /*
5674 	    * Write the member name tag, name length, name string, value tag,
5675 	    * and empty name for the collection member attribute...
5676 	    */
5677 
5678             DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
5679 	                  IPP_TAG_MEMBERNAME));
5680             DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
5681 	                  attr->name));
5682             DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5683 	                  attr->value_tag, ippTagString(attr->value_tag)));
5684             DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
5685 
5686             *bufptr++ = IPP_TAG_MEMBERNAME;
5687 	    *bufptr++ = 0;
5688 	    *bufptr++ = 0;
5689 	    *bufptr++ = (ipp_uchar_t)(n >> 8);
5690 	    *bufptr++ = (ipp_uchar_t)n;
5691 	    memcpy(bufptr, attr->name, (size_t)n);
5692 	    bufptr += n;
5693 
5694             if (attr->value_tag > 0xff)
5695             {
5696               *bufptr++ = IPP_TAG_EXTENSION;
5697 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
5698 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
5699 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
5700 	      *bufptr++ = (ipp_uchar_t)attr->value_tag;
5701             }
5702             else
5703 	      *bufptr++ = (ipp_uchar_t)attr->value_tag;
5704 
5705             *bufptr++ = 0;
5706             *bufptr++ = 0;
5707 	  }
5708 
5709          /*
5710 	  * Now write the attribute value(s)...
5711 	  */
5712 
5713 	  switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
5714 	  {
5715 	    case IPP_TAG_UNSUPPORTED_VALUE :
5716 	    case IPP_TAG_DEFAULT :
5717 	    case IPP_TAG_UNKNOWN :
5718 	    case IPP_TAG_NOVALUE :
5719 	    case IPP_TAG_NOTSETTABLE :
5720 	    case IPP_TAG_DELETEATTR :
5721 	    case IPP_TAG_ADMINDEFINE :
5722 		*bufptr++ = 0;
5723 		*bufptr++ = 0;
5724 	        break;
5725 
5726 	    case IPP_TAG_INTEGER :
5727 	    case IPP_TAG_ENUM :
5728 	        for (i = 0, value = attr->values;
5729 		     i < attr->num_values;
5730 		     i ++, value ++)
5731 		{
5732                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 9)
5733 		  {
5734                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5735 	            {
5736 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5737 		                 "attribute...");
5738 		      _cupsBufferRelease((char *)buffer);
5739 	              return (IPP_STATE_ERROR);
5740 	            }
5741 
5742 		    bufptr = buffer;
5743 		  }
5744 
5745 		  if (i)
5746 		  {
5747 		   /*
5748 		    * Arrays and sets are done by sending additional
5749 		    * values with a zero-length name...
5750 		    */
5751 
5752                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5753 		    *bufptr++ = 0;
5754 		    *bufptr++ = 0;
5755 		  }
5756 
5757 		 /*
5758 	          * Integers and enumerations are both 4-byte signed
5759 		  * (twos-complement) values.
5760 		  *
5761 		  * Put the 2-byte length and 4-byte value into the buffer...
5762 		  */
5763 
5764 	          *bufptr++ = 0;
5765 		  *bufptr++ = 4;
5766 		  *bufptr++ = (ipp_uchar_t)(value->integer >> 24);
5767 		  *bufptr++ = (ipp_uchar_t)(value->integer >> 16);
5768 		  *bufptr++ = (ipp_uchar_t)(value->integer >> 8);
5769 		  *bufptr++ = (ipp_uchar_t)value->integer;
5770 		}
5771 		break;
5772 
5773 	    case IPP_TAG_BOOLEAN :
5774 	        for (i = 0, value = attr->values;
5775 		     i < attr->num_values;
5776 		     i ++, value ++)
5777 		{
5778                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 6)
5779 		  {
5780                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5781 	            {
5782 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5783 		                 "attribute...");
5784 		      _cupsBufferRelease((char *)buffer);
5785 	              return (IPP_STATE_ERROR);
5786 	            }
5787 
5788 		    bufptr = buffer;
5789 		  }
5790 
5791 		  if (i)
5792 		  {
5793 		   /*
5794 		    * Arrays and sets are done by sending additional
5795 		    * values with a zero-length name...
5796 		    */
5797 
5798                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5799 		    *bufptr++ = 0;
5800 		    *bufptr++ = 0;
5801 		  }
5802 
5803                  /*
5804 		  * Boolean values are 1-byte; 0 = false, 1 = true.
5805 		  *
5806 		  * Put the 2-byte length and 1-byte value into the buffer...
5807 		  */
5808 
5809 	          *bufptr++ = 0;
5810 		  *bufptr++ = 1;
5811 		  *bufptr++ = (ipp_uchar_t)value->boolean;
5812 		}
5813 		break;
5814 
5815 	    case IPP_TAG_TEXT :
5816 	    case IPP_TAG_NAME :
5817 	    case IPP_TAG_KEYWORD :
5818 	    case IPP_TAG_URI :
5819 	    case IPP_TAG_URISCHEME :
5820 	    case IPP_TAG_CHARSET :
5821 	    case IPP_TAG_LANGUAGE :
5822 	    case IPP_TAG_MIMETYPE :
5823 	        for (i = 0, value = attr->values;
5824 		     i < attr->num_values;
5825 		     i ++, value ++)
5826 		{
5827 		  if (i)
5828 		  {
5829 		   /*
5830 		    * Arrays and sets are done by sending additional
5831 		    * values with a zero-length name...
5832 		    */
5833 
5834         	    DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5835 		                  attr->value_tag,
5836 				  ippTagString(attr->value_tag)));
5837         	    DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
5838 
5839                     if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
5840 		    {
5841                       if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5842 	              {
5843 	        	DEBUG_puts("1ippWriteIO: Could not write IPP "
5844 			           "attribute...");
5845 			_cupsBufferRelease((char *)buffer);
5846 	        	return (IPP_STATE_ERROR);
5847 	              }
5848 
5849 		      bufptr = buffer;
5850 		    }
5851 
5852                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5853 		    *bufptr++ = 0;
5854 		    *bufptr++ = 0;
5855 		  }
5856 
5857                   if (value->string.text != NULL)
5858                     n = (int)strlen(value->string.text);
5859 		  else
5860 		    n = 0;
5861 
5862                   if (n > (IPP_BUF_SIZE - 2))
5863 		  {
5864 		    DEBUG_printf(("1ippWriteIO: String too long (%d)", n));
5865 		    _cupsBufferRelease((char *)buffer);
5866 		    return (IPP_STATE_ERROR);
5867 		  }
5868 
5869                   DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n,
5870 		                value->string.text));
5871 
5872                   if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
5873 		  {
5874                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5875 	            {
5876 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5877 		                 "attribute...");
5878 		      _cupsBufferRelease((char *)buffer);
5879 	              return (IPP_STATE_ERROR);
5880 	            }
5881 
5882 		    bufptr = buffer;
5883 		  }
5884 
5885 		 /*
5886 		  * All simple strings consist of the 2-byte length and
5887 		  * character data without the trailing nul normally found
5888 		  * in C strings.  Also, strings cannot be longer than IPP_MAX_LENGTH
5889 		  * bytes since the 2-byte length is a signed (twos-complement)
5890 		  * value.
5891 		  *
5892 		  * Put the 2-byte length and string characters in the buffer.
5893 		  */
5894 
5895 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
5896 		  *bufptr++ = (ipp_uchar_t)n;
5897 
5898 		  if (n > 0)
5899 		  {
5900 		    memcpy(bufptr, value->string.text, (size_t)n);
5901 		    bufptr += n;
5902 		  }
5903 		}
5904 		break;
5905 
5906 	    case IPP_TAG_DATE :
5907 	        for (i = 0, value = attr->values;
5908 		     i < attr->num_values;
5909 		     i ++, value ++)
5910 		{
5911                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 16)
5912 		  {
5913                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5914 	            {
5915 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5916 		                 "attribute...");
5917 		      _cupsBufferRelease((char *)buffer);
5918 	              return (IPP_STATE_ERROR);
5919 	            }
5920 
5921 		    bufptr = buffer;
5922 		  }
5923 
5924 		  if (i)
5925 		  {
5926 		   /*
5927 		    * Arrays and sets are done by sending additional
5928 		    * values with a zero-length name...
5929 		    */
5930 
5931                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5932 		    *bufptr++ = 0;
5933 		    *bufptr++ = 0;
5934 		  }
5935 
5936                  /*
5937 		  * Date values consist of a 2-byte length and an
5938 		  * 11-byte date/time structure defined by RFC 1903.
5939 		  *
5940 		  * Put the 2-byte length and 11-byte date/time
5941 		  * structure in the buffer.
5942 		  */
5943 
5944 	          *bufptr++ = 0;
5945 		  *bufptr++ = 11;
5946 		  memcpy(bufptr, value->date, 11);
5947 		  bufptr += 11;
5948 		}
5949 		break;
5950 
5951 	    case IPP_TAG_RESOLUTION :
5952 	        for (i = 0, value = attr->values;
5953 		     i < attr->num_values;
5954 		     i ++, value ++)
5955 		{
5956                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 14)
5957 		  {
5958                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5959 	            {
5960 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5961 		                 "attribute...");
5962 		      _cupsBufferRelease((char *)buffer);
5963 		      return (IPP_STATE_ERROR);
5964 	            }
5965 
5966 		    bufptr = buffer;
5967 		  }
5968 
5969 		  if (i)
5970 		  {
5971 		   /*
5972 		    * Arrays and sets are done by sending additional
5973 		    * values with a zero-length name...
5974 		    */
5975 
5976                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5977 		    *bufptr++ = 0;
5978 		    *bufptr++ = 0;
5979 		  }
5980 
5981                  /*
5982 		  * Resolution values consist of a 2-byte length,
5983 		  * 4-byte horizontal resolution value, 4-byte vertical
5984 		  * resolution value, and a 1-byte units value.
5985 		  *
5986 		  * Put the 2-byte length and resolution value data
5987 		  * into the buffer.
5988 		  */
5989 
5990 	          *bufptr++ = 0;
5991 		  *bufptr++ = 9;
5992 		  *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 24);
5993 		  *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 16);
5994 		  *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 8);
5995 		  *bufptr++ = (ipp_uchar_t)value->resolution.xres;
5996 		  *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 24);
5997 		  *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 16);
5998 		  *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 8);
5999 		  *bufptr++ = (ipp_uchar_t)value->resolution.yres;
6000 		  *bufptr++ = (ipp_uchar_t)value->resolution.units;
6001 		}
6002 		break;
6003 
6004 	    case IPP_TAG_RANGE :
6005 	        for (i = 0, value = attr->values;
6006 		     i < attr->num_values;
6007 		     i ++, value ++)
6008 		{
6009                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 13)
6010 		  {
6011                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6012 	            {
6013 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
6014 		                 "attribute...");
6015 		      _cupsBufferRelease((char *)buffer);
6016 	              return (IPP_STATE_ERROR);
6017 	            }
6018 
6019 		    bufptr = buffer;
6020 		  }
6021 
6022 		  if (i)
6023 		  {
6024 		   /*
6025 		    * Arrays and sets are done by sending additional
6026 		    * values with a zero-length name...
6027 		    */
6028 
6029                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
6030 		    *bufptr++ = 0;
6031 		    *bufptr++ = 0;
6032 		  }
6033 
6034                  /*
6035 		  * Range values consist of a 2-byte length,
6036 		  * 4-byte lower value, and 4-byte upper value.
6037 		  *
6038 		  * Put the 2-byte length and range value data
6039 		  * into the buffer.
6040 		  */
6041 
6042 	          *bufptr++ = 0;
6043 		  *bufptr++ = 8;
6044 		  *bufptr++ = (ipp_uchar_t)(value->range.lower >> 24);
6045 		  *bufptr++ = (ipp_uchar_t)(value->range.lower >> 16);
6046 		  *bufptr++ = (ipp_uchar_t)(value->range.lower >> 8);
6047 		  *bufptr++ = (ipp_uchar_t)value->range.lower;
6048 		  *bufptr++ = (ipp_uchar_t)(value->range.upper >> 24);
6049 		  *bufptr++ = (ipp_uchar_t)(value->range.upper >> 16);
6050 		  *bufptr++ = (ipp_uchar_t)(value->range.upper >> 8);
6051 		  *bufptr++ = (ipp_uchar_t)value->range.upper;
6052 		}
6053 		break;
6054 
6055 	    case IPP_TAG_TEXTLANG :
6056 	    case IPP_TAG_NAMELANG :
6057 	        for (i = 0, value = attr->values;
6058 		     i < attr->num_values;
6059 		     i ++, value ++)
6060 		{
6061 		  if (i)
6062 		  {
6063 		   /*
6064 		    * Arrays and sets are done by sending additional
6065 		    * values with a zero-length name...
6066 		    */
6067 
6068                     if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
6069 		    {
6070                       if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6071 	              {
6072 	        	DEBUG_puts("1ippWriteIO: Could not write IPP "
6073 		                   "attribute...");
6074 			_cupsBufferRelease((char *)buffer);
6075 	        	return (IPP_STATE_ERROR);
6076 	              }
6077 
6078 		      bufptr = buffer;
6079 		    }
6080 
6081                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
6082 		    *bufptr++ = 0;
6083 		    *bufptr++ = 0;
6084 		  }
6085 
6086                  /*
6087 		  * textWithLanguage and nameWithLanguage values consist
6088 		  * of a 2-byte length for both strings and their
6089 		  * individual lengths, a 2-byte length for the
6090 		  * character string, the character string without the
6091 		  * trailing nul, a 2-byte length for the character
6092 		  * set string, and the character set string without
6093 		  * the trailing nul.
6094 		  */
6095 
6096                   n = 4;
6097 
6098 		  if (value->string.language != NULL)
6099                     n += (int)strlen(value->string.language);
6100 
6101 		  if (value->string.text != NULL)
6102                     n += (int)strlen(value->string.text);
6103 
6104                   if (n > (IPP_BUF_SIZE - 2))
6105 		  {
6106 		    DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
6107 		                  "too long (%d)", n));
6108 		    _cupsBufferRelease((char *)buffer);
6109 		    return (IPP_STATE_ERROR);
6110                   }
6111 
6112                   if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
6113 		  {
6114                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6115 	            {
6116 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
6117 		                 "attribute...");
6118 		      _cupsBufferRelease((char *)buffer);
6119 	              return (IPP_STATE_ERROR);
6120 	            }
6121 
6122 		    bufptr = buffer;
6123 		  }
6124 
6125                  /* Length of entire value */
6126 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
6127 		  *bufptr++ = (ipp_uchar_t)n;
6128 
6129                  /* Length of language */
6130 		  if (value->string.language != NULL)
6131 		    n = (int)strlen(value->string.language);
6132 		  else
6133 		    n = 0;
6134 
6135 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
6136 		  *bufptr++ = (ipp_uchar_t)n;
6137 
6138                  /* Language */
6139 		  if (n > 0)
6140 		  {
6141 		    memcpy(bufptr, value->string.language, (size_t)n);
6142 		    bufptr += n;
6143 		  }
6144 
6145                  /* Length of text */
6146                   if (value->string.text != NULL)
6147 		    n = (int)strlen(value->string.text);
6148 		  else
6149 		    n = 0;
6150 
6151 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
6152 		  *bufptr++ = (ipp_uchar_t)n;
6153 
6154                  /* Text */
6155 		  if (n > 0)
6156 		  {
6157 		    memcpy(bufptr, value->string.text, (size_t)n);
6158 		    bufptr += n;
6159 		  }
6160 		}
6161 		break;
6162 
6163             case IPP_TAG_BEGIN_COLLECTION :
6164 	        for (i = 0, value = attr->values;
6165 		     i < attr->num_values;
6166 		     i ++, value ++)
6167 		{
6168 		 /*
6169 		  * Collections are written with the begin-collection
6170 		  * tag first with a value of 0 length, followed by the
6171 		  * attributes in the collection, then the end-collection
6172 		  * value...
6173 		  */
6174 
6175                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 5)
6176 		  {
6177                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6178 	            {
6179 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
6180 		                 "attribute...");
6181 		      _cupsBufferRelease((char *)buffer);
6182 	              return (IPP_STATE_ERROR);
6183 	            }
6184 
6185 		    bufptr = buffer;
6186 		  }
6187 
6188 		  if (i)
6189 		  {
6190 		   /*
6191 		    * Arrays and sets are done by sending additional
6192 		    * values with a zero-length name...
6193 		    */
6194 
6195                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
6196 		    *bufptr++ = 0;
6197 		    *bufptr++ = 0;
6198 		  }
6199 
6200                  /*
6201 		  * Write a data length of 0 and flush the buffer...
6202 		  */
6203 
6204 	          *bufptr++ = 0;
6205 		  *bufptr++ = 0;
6206 
6207                   if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6208 	          {
6209 	            DEBUG_puts("1ippWriteIO: Could not write IPP "
6210 		               "attribute...");
6211 		    _cupsBufferRelease((char *)buffer);
6212 	            return (IPP_STATE_ERROR);
6213 	          }
6214 
6215 		  bufptr = buffer;
6216 
6217                  /*
6218 		  * Then write the collection attribute...
6219 		  */
6220 
6221                   value->collection->state = IPP_STATE_IDLE;
6222 
6223 		  if (ippWriteIO(dst, cb, 1, ipp,
6224 		                 value->collection) == IPP_STATE_ERROR)
6225 		  {
6226 		    DEBUG_puts("1ippWriteIO: Unable to write collection value");
6227 		    _cupsBufferRelease((char *)buffer);
6228 		    return (IPP_STATE_ERROR);
6229 		  }
6230 		}
6231 		break;
6232 
6233             default :
6234 	        for (i = 0, value = attr->values;
6235 		     i < attr->num_values;
6236 		     i ++, value ++)
6237 		{
6238 		  if (i)
6239 		  {
6240 		   /*
6241 		    * Arrays and sets are done by sending additional
6242 		    * values with a zero-length name...
6243 		    */
6244 
6245                     if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
6246 		    {
6247                       if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6248 	              {
6249 	        	DEBUG_puts("1ippWriteIO: Could not write IPP "
6250 		                   "attribute...");
6251 			_cupsBufferRelease((char *)buffer);
6252 	        	return (IPP_STATE_ERROR);
6253 	              }
6254 
6255 		      bufptr = buffer;
6256 		    }
6257 
6258                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
6259 		    *bufptr++ = 0;
6260 		    *bufptr++ = 0;
6261 		  }
6262 
6263                  /*
6264 		  * An unknown value might some new value that a
6265 		  * vendor has come up with. It consists of a
6266 		  * 2-byte length and the bytes in the unknown
6267 		  * value buffer.
6268 		  */
6269 
6270                   n = value->unknown.length;
6271 
6272                   if (n > (IPP_BUF_SIZE - 2))
6273 		  {
6274 		    DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
6275 		                  n));
6276 		    _cupsBufferRelease((char *)buffer);
6277 		    return (IPP_STATE_ERROR);
6278 		  }
6279 
6280                   if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
6281 		  {
6282                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6283 	            {
6284 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
6285 		                 "attribute...");
6286 		      _cupsBufferRelease((char *)buffer);
6287 	              return (IPP_STATE_ERROR);
6288 	            }
6289 
6290 		    bufptr = buffer;
6291 		  }
6292 
6293                  /* Length of unknown value */
6294 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
6295 		  *bufptr++ = (ipp_uchar_t)n;
6296 
6297                  /* Value */
6298 		  if (n > 0)
6299 		  {
6300 		    memcpy(bufptr, value->unknown.data, (size_t)n);
6301 		    bufptr += n;
6302 		  }
6303 		}
6304 		break;
6305 	  }
6306 
6307          /*
6308 	  * Write the data out...
6309 	  */
6310 
6311 	  if (bufptr > buffer)
6312 	  {
6313 	    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6314 	    {
6315 	      DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
6316 	      _cupsBufferRelease((char *)buffer);
6317 	      return (IPP_STATE_ERROR);
6318 	    }
6319 
6320 	    DEBUG_printf(("2ippWriteIO: wrote %d bytes",
6321 			  (int)(bufptr - buffer)));
6322 	  }
6323 
6324 	 /*
6325           * If blocking is disabled and we aren't at the end of the attribute
6326           * list, stop here...
6327 	  */
6328 
6329           if (!blocking && ipp->current)
6330 	    break;
6331 	}
6332 
6333 	if (ipp->current == NULL)
6334 	{
6335          /*
6336 	  * Done with all of the attributes; add the end-of-attributes
6337 	  * tag or end-collection attribute...
6338 	  */
6339 
6340           if (parent == NULL)
6341 	  {
6342             buffer[0] = IPP_TAG_END;
6343 	    n         = 1;
6344 	  }
6345 	  else
6346 	  {
6347             buffer[0] = IPP_TAG_END_COLLECTION;
6348 	    buffer[1] = 0; /* empty name */
6349 	    buffer[2] = 0;
6350 	    buffer[3] = 0; /* empty value */
6351 	    buffer[4] = 0;
6352 	    n         = 5;
6353 	  }
6354 
6355 	  if ((*cb)(dst, buffer, (size_t)n) < 0)
6356 	  {
6357 	    DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
6358 	    _cupsBufferRelease((char *)buffer);
6359 	    return (IPP_STATE_ERROR);
6360 	  }
6361 
6362 	  ipp->state = IPP_STATE_DATA;
6363 	}
6364         break;
6365 
6366     case IPP_STATE_DATA :
6367         break;
6368 
6369     default :
6370         break; /* anti-compiler-warning-code */
6371   }
6372 
6373   _cupsBufferRelease((char *)buffer);
6374 
6375   return (ipp->state);
6376 }
6377 
6378 
6379 /*
6380  * 'ipp_add_attr()' - Add a new attribute to the message.
6381  */
6382 
6383 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)6384 ipp_add_attr(ipp_t      *ipp,		/* I - IPP message */
6385              const char *name,		/* I - Attribute name or NULL */
6386              ipp_tag_t  group_tag,	/* I - Group tag or IPP_TAG_ZERO */
6387              ipp_tag_t  value_tag,	/* I - Value tag or IPP_TAG_ZERO */
6388              int        num_values)	/* I - Number of values */
6389 {
6390   int			alloc_values;	/* Number of values to allocate */
6391   ipp_attribute_t	*attr;		/* New attribute */
6392 
6393 
6394   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));
6395 
6396  /*
6397   * Range check input...
6398   */
6399 
6400   if (!ipp || num_values < 0)
6401     return (NULL);
6402 
6403  /*
6404   * Allocate memory, rounding the allocation up as needed...
6405   */
6406 
6407   if (num_values <= 1)
6408     alloc_values = 1;
6409   else
6410     alloc_values = (num_values + IPP_MAX_VALUES - 1) & ~(IPP_MAX_VALUES - 1);
6411 
6412   attr = calloc(sizeof(ipp_attribute_t) +
6413                 (size_t)(alloc_values - 1) * sizeof(_ipp_value_t), 1);
6414 
6415   if (attr)
6416   {
6417    /*
6418     * Initialize attribute...
6419     */
6420 
6421     DEBUG_printf(("4debug_alloc: %p %s %s%s (%d values)", (void *)attr, name, num_values > 1 ? "1setOf " : "", ippTagString(value_tag), num_values));
6422 
6423     if (name)
6424       attr->name = _cupsStrAlloc(name);
6425 
6426     attr->group_tag  = group_tag;
6427     attr->value_tag  = value_tag;
6428     attr->num_values = num_values;
6429 
6430    /*
6431     * Add it to the end of the linked list...
6432     */
6433 
6434     if (ipp->last)
6435       ipp->last->next = attr;
6436     else
6437       ipp->attrs = attr;
6438 
6439     ipp->prev = ipp->last;
6440     ipp->last = ipp->current = attr;
6441   }
6442 
6443   DEBUG_printf(("5ipp_add_attr: Returning %p", (void *)attr));
6444 
6445   return (attr);
6446 }
6447 
6448 
6449 /*
6450  * 'ipp_free_values()' - Free attribute values.
6451  */
6452 
6453 static void
ipp_free_values(ipp_attribute_t * attr,int element,int count)6454 ipp_free_values(ipp_attribute_t *attr,	/* I - Attribute to free values from */
6455                 int             element,/* I - First value to free */
6456                 int             count)	/* I - Number of values to free */
6457 {
6458   int		i;			/* Looping var */
6459   _ipp_value_t	*value;			/* Current value */
6460 
6461 
6462   DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", (void *)attr, element, count));
6463 
6464   if (!(attr->value_tag & IPP_TAG_CUPS_CONST))
6465   {
6466    /*
6467     * Free values as needed...
6468     */
6469 
6470     switch (attr->value_tag)
6471     {
6472       case IPP_TAG_TEXTLANG :
6473       case IPP_TAG_NAMELANG :
6474 	  if (element == 0 && count == attr->num_values &&
6475 	      attr->values[0].string.language)
6476 	  {
6477 	    _cupsStrFree(attr->values[0].string.language);
6478 	    attr->values[0].string.language = NULL;
6479 	  }
6480 	  /* Fall through to other string values */
6481 
6482       case IPP_TAG_TEXT :
6483       case IPP_TAG_NAME :
6484       case IPP_TAG_RESERVED_STRING :
6485       case IPP_TAG_KEYWORD :
6486       case IPP_TAG_URI :
6487       case IPP_TAG_URISCHEME :
6488       case IPP_TAG_CHARSET :
6489       case IPP_TAG_LANGUAGE :
6490       case IPP_TAG_MIMETYPE :
6491 	  for (i = count, value = attr->values + element;
6492 	       i > 0;
6493 	       i --, value ++)
6494 	  {
6495 	    _cupsStrFree(value->string.text);
6496 	    value->string.text = NULL;
6497 	  }
6498 	  break;
6499 
6500       case IPP_TAG_DEFAULT :
6501       case IPP_TAG_UNKNOWN :
6502       case IPP_TAG_NOVALUE :
6503       case IPP_TAG_NOTSETTABLE :
6504       case IPP_TAG_DELETEATTR :
6505       case IPP_TAG_ADMINDEFINE :
6506       case IPP_TAG_INTEGER :
6507       case IPP_TAG_ENUM :
6508       case IPP_TAG_BOOLEAN :
6509       case IPP_TAG_DATE :
6510       case IPP_TAG_RESOLUTION :
6511       case IPP_TAG_RANGE :
6512 	  break;
6513 
6514       case IPP_TAG_BEGIN_COLLECTION :
6515 	  for (i = count, value = attr->values + element;
6516 	       i > 0;
6517 	       i --, value ++)
6518 	  {
6519 	    ippDelete(value->collection);
6520 	    value->collection = NULL;
6521 	  }
6522 	  break;
6523 
6524       case IPP_TAG_STRING :
6525       default :
6526 	  for (i = count, value = attr->values + element;
6527 	       i > 0;
6528 	       i --, value ++)
6529 	  {
6530 	    if (value->unknown.data)
6531 	    {
6532 	      free(value->unknown.data);
6533 	      value->unknown.data = NULL;
6534 	    }
6535 	  }
6536 	  break;
6537     }
6538   }
6539 
6540  /*
6541   * If we are not freeing values from the end, move the remaining values up...
6542   */
6543 
6544   if ((element + count) < attr->num_values)
6545     memmove(attr->values + element, attr->values + element + count,
6546             (size_t)(attr->num_values - count - element) * sizeof(_ipp_value_t));
6547 
6548   attr->num_values -= count;
6549 }
6550 
6551 
6552 /*
6553  * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
6554  *
6555  * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
6556  * to "ll-cc", "ll-region", and "charset-number", respectively.
6557  */
6558 
6559 static char *				/* O - Language code string */
ipp_get_code(const char * value,char * buffer,size_t bufsize)6560 ipp_get_code(const char *value,		/* I - Locale/charset string */
6561              char       *buffer,	/* I - String buffer */
6562              size_t     bufsize)	/* I - Size of string buffer */
6563 {
6564   char	*bufptr,			/* Pointer into buffer */
6565 	*bufend;			/* End of buffer */
6566 
6567 
6568  /*
6569   * Convert values to lowercase and change _ to - as needed...
6570   */
6571 
6572   for (bufptr = buffer, bufend = buffer + bufsize - 1;
6573        *value && bufptr < bufend;
6574        value ++)
6575     if (*value == '_')
6576       *bufptr++ = '-';
6577     else
6578       *bufptr++ = (char)_cups_tolower(*value);
6579 
6580   *bufptr = '\0';
6581 
6582  /*
6583   * Return the converted string...
6584   */
6585 
6586   return (buffer);
6587 }
6588 
6589 
6590 /*
6591  * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
6592  *
6593  * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
6594  * "ll-region", respectively.  It also converts the "C" (POSIX) locale to "en".
6595  */
6596 
6597 static char *				/* O - Language code string */
ipp_lang_code(const char * locale,char * buffer,size_t bufsize)6598 ipp_lang_code(const char *locale,	/* I - Locale string */
6599               char       *buffer,	/* I - String buffer */
6600               size_t     bufsize)	/* I - Size of string buffer */
6601 {
6602  /*
6603   * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
6604   */
6605 
6606   if (!_cups_strcasecmp(locale, "c"))
6607   {
6608     strlcpy(buffer, "en", bufsize);
6609     return (buffer);
6610   }
6611   else
6612     return (ipp_get_code(locale, buffer, bufsize));
6613 }
6614 
6615 
6616 /*
6617  * 'ipp_length()' - Compute the length of an IPP message or collection value.
6618  */
6619 
6620 static size_t				/* O - Size of IPP message */
ipp_length(ipp_t * ipp,int collection)6621 ipp_length(ipp_t *ipp,			/* I - IPP message or collection */
6622            int   collection)		/* I - 1 if a collection, 0 otherwise */
6623 {
6624   int			i;		/* Looping var */
6625   size_t		bytes;		/* Number of bytes */
6626   ipp_attribute_t	*attr;		/* Current attribute */
6627   ipp_tag_t		group;		/* Current group */
6628   _ipp_value_t		*value;		/* Current value */
6629 
6630 
6631   DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", (void *)ipp, collection));
6632 
6633   if (!ipp)
6634   {
6635     DEBUG_puts("4ipp_length: Returning 0 bytes");
6636     return (0);
6637   }
6638 
6639  /*
6640   * Start with 8 bytes for the IPP message header...
6641   */
6642 
6643   bytes = collection ? 0 : 8;
6644 
6645  /*
6646   * Then add the lengths of each attribute...
6647   */
6648 
6649   group = IPP_TAG_ZERO;
6650 
6651   for (attr = ipp->attrs; attr != NULL; attr = attr->next)
6652   {
6653     if (attr->group_tag != group && !collection)
6654     {
6655       group = attr->group_tag;
6656       if (group == IPP_TAG_ZERO)
6657 	continue;
6658 
6659       bytes ++;	/* Group tag */
6660     }
6661 
6662     if (!attr->name)
6663       continue;
6664 
6665     DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
6666                   "bytes=" CUPS_LLFMT, attr->name, attr->num_values, CUPS_LLCAST bytes));
6667 
6668     if ((attr->value_tag & ~IPP_TAG_CUPS_CONST) < IPP_TAG_EXTENSION)
6669       bytes += (size_t)attr->num_values;/* Value tag for each value */
6670     else
6671       bytes += (size_t)(5 * attr->num_values);
6672 					/* Value tag for each value */
6673     bytes += (size_t)(2 * attr->num_values);
6674 					/* Name lengths */
6675     bytes += strlen(attr->name);	/* Name */
6676     bytes += (size_t)(2 * attr->num_values);
6677 					/* Value lengths */
6678 
6679     if (collection)
6680       bytes += 5;			/* Add membername overhead */
6681 
6682     switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
6683     {
6684       case IPP_TAG_UNSUPPORTED_VALUE :
6685       case IPP_TAG_DEFAULT :
6686       case IPP_TAG_UNKNOWN :
6687       case IPP_TAG_NOVALUE :
6688       case IPP_TAG_NOTSETTABLE :
6689       case IPP_TAG_DELETEATTR :
6690       case IPP_TAG_ADMINDEFINE :
6691           break;
6692 
6693       case IPP_TAG_INTEGER :
6694       case IPP_TAG_ENUM :
6695           bytes += (size_t)(4 * attr->num_values);
6696 	  break;
6697 
6698       case IPP_TAG_BOOLEAN :
6699           bytes += (size_t)attr->num_values;
6700 	  break;
6701 
6702       case IPP_TAG_TEXT :
6703       case IPP_TAG_NAME :
6704       case IPP_TAG_KEYWORD :
6705       case IPP_TAG_URI :
6706       case IPP_TAG_URISCHEME :
6707       case IPP_TAG_CHARSET :
6708       case IPP_TAG_LANGUAGE :
6709       case IPP_TAG_MIMETYPE :
6710 	  for (i = 0, value = attr->values;
6711 	       i < attr->num_values;
6712 	       i ++, value ++)
6713 	    if (value->string.text)
6714 	      bytes += strlen(value->string.text);
6715 	  break;
6716 
6717       case IPP_TAG_DATE :
6718           bytes += (size_t)(11 * attr->num_values);
6719 	  break;
6720 
6721       case IPP_TAG_RESOLUTION :
6722           bytes += (size_t)(9 * attr->num_values);
6723 	  break;
6724 
6725       case IPP_TAG_RANGE :
6726           bytes += (size_t)(8 * attr->num_values);
6727 	  break;
6728 
6729       case IPP_TAG_TEXTLANG :
6730       case IPP_TAG_NAMELANG :
6731           bytes += (size_t)(4 * attr->num_values);
6732 					/* Charset + text length */
6733 
6734 	  for (i = 0, value = attr->values;
6735 	       i < attr->num_values;
6736 	       i ++, value ++)
6737 	  {
6738 	    if (value->string.language)
6739 	      bytes += strlen(value->string.language);
6740 
6741 	    if (value->string.text)
6742 	      bytes += strlen(value->string.text);
6743 	  }
6744 	  break;
6745 
6746       case IPP_TAG_BEGIN_COLLECTION :
6747 	  for (i = 0, value = attr->values;
6748 	       i < attr->num_values;
6749 	       i ++, value ++)
6750             bytes += ipp_length(value->collection, 1);
6751 	  break;
6752 
6753       default :
6754 	  for (i = 0, value = attr->values;
6755 	       i < attr->num_values;
6756 	       i ++, value ++)
6757             bytes += (size_t)value->unknown.length;
6758 	  break;
6759     }
6760   }
6761 
6762  /*
6763   * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
6764   * for the "end of collection" tag and return...
6765   */
6766 
6767   if (collection)
6768     bytes += 5;
6769   else
6770     bytes ++;
6771 
6772   DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST bytes));
6773 
6774   return (bytes);
6775 }
6776 
6777 
6778 /*
6779  * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
6780  */
6781 
6782 static ssize_t				/* O - Number of bytes read */
ipp_read_http(http_t * http,ipp_uchar_t * buffer,size_t length)6783 ipp_read_http(http_t      *http,	/* I - Client connection */
6784               ipp_uchar_t *buffer,	/* O - Buffer for data */
6785 	      size_t      length)	/* I - Total length */
6786 {
6787   ssize_t	tbytes,			/* Total bytes read */
6788 		bytes;			/* Bytes read this pass */
6789 
6790 
6791   DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)", (void *)http, (void *)buffer, (int)length));
6792 
6793  /*
6794   * Loop until all bytes are read...
6795   */
6796 
6797   for (tbytes = 0, bytes = 0;
6798        tbytes < (int)length;
6799        tbytes += bytes, buffer += bytes)
6800   {
6801     DEBUG_printf(("9ipp_read_http: tbytes=" CUPS_LLFMT ", http->state=%d", CUPS_LLCAST tbytes, http->state));
6802 
6803     if (http->state == HTTP_STATE_WAITING)
6804       break;
6805 
6806     if (http->used == 0 && !http->blocking)
6807     {
6808      /*
6809       * Wait up to 10 seconds for more data on non-blocking sockets...
6810       */
6811 
6812       if (!httpWait(http, 10000))
6813       {
6814        /*
6815 	* Signal no data...
6816 	*/
6817 
6818 	bytes = -1;
6819 	break;
6820       }
6821     }
6822     else if (http->used == 0 && http->timeout_value > 0)
6823     {
6824      /*
6825       * Wait up to timeout seconds for more data on blocking sockets...
6826       */
6827 
6828       if (!httpWait(http, (int)(1000 * http->timeout_value)))
6829       {
6830        /*
6831 	* Signal no data...
6832 	*/
6833 
6834 	bytes = -1;
6835 	break;
6836       }
6837     }
6838 
6839     if ((bytes = httpRead2(http, (char *)buffer, length - (size_t)tbytes)) < 0)
6840     {
6841 #ifdef WIN32
6842       break;
6843 #else
6844       if (errno != EAGAIN && errno != EINTR)
6845 	break;
6846 
6847       bytes = 0;
6848 #endif /* WIN32 */
6849     }
6850     else if (bytes == 0)
6851       break;
6852   }
6853 
6854  /*
6855   * Return the number of bytes read...
6856   */
6857 
6858   if (tbytes == 0 && bytes < 0)
6859     tbytes = -1;
6860 
6861   DEBUG_printf(("8ipp_read_http: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST tbytes));
6862 
6863   return (tbytes);
6864 }
6865 
6866 
6867 /*
6868  * 'ipp_read_file()' - Read IPP data from a file.
6869  */
6870 
6871 static ssize_t				/* O - Number of bytes read */
ipp_read_file(int * fd,ipp_uchar_t * buffer,size_t length)6872 ipp_read_file(int         *fd,		/* I - File descriptor */
6873               ipp_uchar_t *buffer,	/* O - Read buffer */
6874 	      size_t      length)	/* I - Number of bytes to read */
6875 {
6876 #ifdef WIN32
6877   return ((ssize_t)read(*fd, buffer, (unsigned)length));
6878 #else
6879   return (read(*fd, buffer, length));
6880 #endif /* WIN32 */
6881 }
6882 
6883 
6884 /*
6885  * 'ipp_set_error()' - Set a formatted, localized error string.
6886  */
6887 
6888 static void
ipp_set_error(ipp_status_t status,const char * format,...)6889 ipp_set_error(ipp_status_t status,	/* I - Status code */
6890               const char   *format,	/* I - Printf-style error string */
6891 	      ...)			/* I - Additional arguments as needed */
6892 {
6893   va_list	ap;			/* Pointer to additional args */
6894   char		buffer[2048];		/* Message buffer */
6895   cups_lang_t	*lang = cupsLangDefault();
6896 					/* Current language */
6897 
6898 
6899   va_start(ap, format);
6900   vsnprintf(buffer, sizeof(buffer), _cupsLangString(lang, format), ap);
6901   va_end(ap);
6902 
6903   _cupsSetError(status, buffer, 0);
6904 }
6905 
6906 
6907 /*
6908  * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
6909  *                     needed.
6910  */
6911 
6912 static _ipp_value_t *			/* O  - IPP value element or NULL on error */
ipp_set_value(ipp_t * ipp,ipp_attribute_t ** attr,int element)6913 ipp_set_value(ipp_t           *ipp,	/* IO - IPP message */
6914               ipp_attribute_t **attr,	/* IO - IPP attribute */
6915               int             element)	/* I  - Value number (0-based) */
6916 {
6917   ipp_attribute_t	*temp,		/* New attribute pointer */
6918 			*current,	/* Current attribute in list */
6919 			*prev;		/* Previous attribute in list */
6920   int			alloc_values;	/* Allocated values */
6921 
6922 
6923  /*
6924   * If we are setting an existing value element, return it...
6925   */
6926 
6927   temp = *attr;
6928 
6929   if (temp->num_values <= 1)
6930     alloc_values = 1;
6931   else
6932     alloc_values = (temp->num_values + IPP_MAX_VALUES - 1) &
6933                    ~(IPP_MAX_VALUES - 1);
6934 
6935   if (element < alloc_values)
6936   {
6937     if (element >= temp->num_values)
6938       temp->num_values = element + 1;
6939 
6940     return (temp->values + element);
6941   }
6942 
6943  /*
6944   * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
6945   * values when num_values > 1.
6946   */
6947 
6948   if (alloc_values < IPP_MAX_VALUES)
6949     alloc_values = IPP_MAX_VALUES;
6950   else
6951     alloc_values += IPP_MAX_VALUES;
6952 
6953   DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
6954                 alloc_values));
6955 
6956  /*
6957   * Reallocate memory...
6958   */
6959 
6960   if ((temp = realloc(temp, sizeof(ipp_attribute_t) + (size_t)(alloc_values - 1) * sizeof(_ipp_value_t))) == NULL)
6961   {
6962     _cupsSetHTTPError(HTTP_STATUS_ERROR);
6963     DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
6964     return (NULL);
6965   }
6966 
6967  /*
6968   * Zero the new memory...
6969   */
6970 
6971   memset(temp->values + temp->num_values, 0, (size_t)(alloc_values - temp->num_values) * sizeof(_ipp_value_t));
6972 
6973   if (temp != *attr)
6974   {
6975    /*
6976     * Reset pointers in the list...
6977     */
6978 
6979     DEBUG_printf(("4debug_free: %p %s", (void *)*attr, temp->name));
6980     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));
6981 
6982     if (ipp->current == *attr && ipp->prev)
6983     {
6984      /*
6985       * Use current "previous" pointer...
6986       */
6987 
6988       prev = ipp->prev;
6989     }
6990     else
6991     {
6992      /*
6993       * Find this attribute in the linked list...
6994       */
6995 
6996       for (prev = NULL, current = ipp->attrs;
6997 	   current && current != *attr;
6998 	   prev = current, current = current->next);
6999 
7000       if (!current)
7001       {
7002        /*
7003 	* This is a serious error!
7004 	*/
7005 
7006 	*attr = temp;
7007 	_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
7008 	              _("IPP attribute is not a member of the message."), 1);
7009 	DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
7010 	return (NULL);
7011       }
7012     }
7013 
7014     if (prev)
7015       prev->next = temp;
7016     else
7017       ipp->attrs = temp;
7018 
7019     ipp->current = temp;
7020     ipp->prev    = prev;
7021 
7022     if (ipp->last == *attr)
7023       ipp->last = temp;
7024 
7025     *attr = temp;
7026   }
7027 
7028  /*
7029   * Return the value element...
7030   */
7031 
7032   if (element >= temp->num_values)
7033     temp->num_values = element + 1;
7034 
7035   return (temp->values + element);
7036 }
7037 
7038 
7039 /*
7040  * 'ipp_write_file()' - Write IPP data to a file.
7041  */
7042 
7043 static ssize_t				/* O - Number of bytes written */
ipp_write_file(int * fd,ipp_uchar_t * buffer,size_t length)7044 ipp_write_file(int         *fd,		/* I - File descriptor */
7045                ipp_uchar_t *buffer,	/* I - Data to write */
7046                size_t      length)	/* I - Number of bytes to write */
7047 {
7048 #ifdef WIN32
7049   return ((ssize_t)write(*fd, buffer, (unsigned)length));
7050 #else
7051   return (write(*fd, buffer, length));
7052 #endif /* WIN32 */
7053 }
7054