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 date 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  * language, mimeMediaType, name, text, URI, or URI scheme 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_INTEGER :
1513     case IPP_TAG_ENUM :
1514         dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag,
1515 	                         srcattr->name, srcattr->num_values, NULL);
1516         if (!dstattr)
1517           break;
1518 
1519         for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1520              i > 0;
1521              i --, srcval ++, dstval ++)
1522 	  dstval->integer = srcval->integer;
1523         break;
1524 
1525     case IPP_TAG_BOOLEAN :
1526         dstattr = ippAddBooleans(dst, srcattr->group_tag, srcattr->name,
1527 	                        srcattr->num_values, NULL);
1528         if (!dstattr)
1529           break;
1530 
1531         for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1532              i > 0;
1533              i --, srcval ++, dstval ++)
1534 	  dstval->boolean = srcval->boolean;
1535         break;
1536 
1537     case IPP_TAG_TEXT :
1538     case IPP_TAG_NAME :
1539     case IPP_TAG_KEYWORD :
1540     case IPP_TAG_URI :
1541     case IPP_TAG_URISCHEME :
1542     case IPP_TAG_CHARSET :
1543     case IPP_TAG_LANGUAGE :
1544     case IPP_TAG_MIMETYPE :
1545         dstattr = ippAddStrings(dst, srcattr->group_tag,
1546 	                        (ipp_tag_t)(srcattr->value_tag | quickcopy),
1547 	                        srcattr->name, srcattr->num_values, NULL, NULL);
1548         if (!dstattr)
1549           break;
1550 
1551         if (quickcopy)
1552 	{
1553 	  for (i = srcattr->num_values, srcval = srcattr->values,
1554 	           dstval = dstattr->values;
1555 	       i > 0;
1556 	       i --, srcval ++, dstval ++)
1557 	    dstval->string.text = srcval->string.text;
1558         }
1559 	else if (srcattr->value_tag & IPP_TAG_CUPS_CONST)
1560 	{
1561 	  for (i = srcattr->num_values, srcval = srcattr->values,
1562 	           dstval = dstattr->values;
1563 	       i > 0;
1564 	       i --, srcval ++, dstval ++)
1565 	    dstval->string.text = _cupsStrAlloc(srcval->string.text);
1566 	}
1567 	else
1568 	{
1569 	  for (i = srcattr->num_values, srcval = srcattr->values,
1570 	           dstval = dstattr->values;
1571 	       i > 0;
1572 	       i --, srcval ++, dstval ++)
1573 	    dstval->string.text = _cupsStrRetain(srcval->string.text);
1574 	}
1575         break;
1576 
1577     case IPP_TAG_DATE :
1578         if (srcattr->num_values != 1)
1579           return (NULL);
1580 
1581         dstattr = ippAddDate(dst, srcattr->group_tag, srcattr->name,
1582 	                     srcattr->values[0].date);
1583         break;
1584 
1585     case IPP_TAG_RESOLUTION :
1586         dstattr = ippAddResolutions(dst, srcattr->group_tag, srcattr->name,
1587 	                            srcattr->num_values, IPP_RES_PER_INCH,
1588 				    NULL, NULL);
1589         if (!dstattr)
1590           break;
1591 
1592         for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1593              i > 0;
1594              i --, srcval ++, dstval ++)
1595 	{
1596 	  dstval->resolution.xres  = srcval->resolution.xres;
1597 	  dstval->resolution.yres  = srcval->resolution.yres;
1598 	  dstval->resolution.units = srcval->resolution.units;
1599 	}
1600         break;
1601 
1602     case IPP_TAG_RANGE :
1603         dstattr = ippAddRanges(dst, srcattr->group_tag, srcattr->name,
1604 	                       srcattr->num_values, NULL, NULL);
1605         if (!dstattr)
1606           break;
1607 
1608         for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1609              i > 0;
1610              i --, srcval ++, dstval ++)
1611 	{
1612 	  dstval->range.lower = srcval->range.lower;
1613 	  dstval->range.upper = srcval->range.upper;
1614 	}
1615         break;
1616 
1617     case IPP_TAG_TEXTLANG :
1618     case IPP_TAG_NAMELANG :
1619         dstattr = ippAddStrings(dst, srcattr->group_tag,
1620 	                        (ipp_tag_t)(srcattr->value_tag | quickcopy),
1621 	                        srcattr->name, srcattr->num_values, NULL, NULL);
1622         if (!dstattr)
1623           break;
1624 
1625         if (quickcopy)
1626 	{
1627 	  for (i = srcattr->num_values, srcval = srcattr->values,
1628 	           dstval = dstattr->values;
1629 	       i > 0;
1630 	       i --, srcval ++, dstval ++)
1631 	  {
1632             dstval->string.language = srcval->string.language;
1633 	    dstval->string.text     = srcval->string.text;
1634           }
1635         }
1636 	else if (srcattr->value_tag & IPP_TAG_CUPS_CONST)
1637 	{
1638 	  for (i = srcattr->num_values, srcval = srcattr->values,
1639 	           dstval = dstattr->values;
1640 	       i > 0;
1641 	       i --, srcval ++, dstval ++)
1642 	  {
1643 	    if (srcval == srcattr->values)
1644               dstval->string.language = _cupsStrAlloc(srcval->string.language);
1645 	    else
1646               dstval->string.language = dstattr->values[0].string.language;
1647 
1648 	    dstval->string.text = _cupsStrAlloc(srcval->string.text);
1649           }
1650         }
1651 	else
1652 	{
1653 	  for (i = srcattr->num_values, srcval = srcattr->values,
1654 	           dstval = dstattr->values;
1655 	       i > 0;
1656 	       i --, srcval ++, dstval ++)
1657 	  {
1658 	    if (srcval == srcattr->values)
1659               dstval->string.language = _cupsStrRetain(srcval->string.language);
1660 	    else
1661               dstval->string.language = dstattr->values[0].string.language;
1662 
1663 	    dstval->string.text = _cupsStrRetain(srcval->string.text);
1664           }
1665         }
1666         break;
1667 
1668     case IPP_TAG_BEGIN_COLLECTION :
1669         dstattr = ippAddCollections(dst, srcattr->group_tag, srcattr->name,
1670 	                            srcattr->num_values, NULL);
1671         if (!dstattr)
1672           break;
1673 
1674         for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1675              i > 0;
1676              i --, srcval ++, dstval ++)
1677 	{
1678 	  dstval->collection = srcval->collection;
1679 	  srcval->collection->use ++;
1680 	}
1681         break;
1682 
1683     case IPP_TAG_STRING :
1684     default :
1685         /* TODO: Implement quick copy for unknown/octetString values */
1686         dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag,
1687 	                         srcattr->name, srcattr->num_values, NULL);
1688         if (!dstattr)
1689           break;
1690 
1691         for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1692              i > 0;
1693              i --, srcval ++, dstval ++)
1694 	{
1695 	  dstval->unknown.length = srcval->unknown.length;
1696 
1697 	  if (dstval->unknown.length > 0)
1698 	  {
1699 	    if ((dstval->unknown.data = malloc((size_t)dstval->unknown.length)) == NULL)
1700 	      dstval->unknown.length = 0;
1701 	    else
1702 	      memcpy(dstval->unknown.data, srcval->unknown.data, (size_t)dstval->unknown.length);
1703 	  }
1704 	}
1705         break; /* anti-compiler-warning-code */
1706   }
1707 
1708   return (dstattr);
1709 }
1710 
1711 
1712 /*
1713  * 'ippCopyAttributes()' - Copy attributes from one IPP message to another.
1714  *
1715  * Zero or more attributes are copied from the source IPP message, @code src@, to the
1716  * destination IPP message, @code dst@. When @code quickcopy@ is non-zero, a "shallow"
1717  * reference copy of the attribute is created - this should only be done as long as the
1718  * original source IPP message will not be freed for the life of the destination.
1719  *
1720  * The @code cb@ and @code context@ parameters provide a generic way to "filter" the
1721  * attributes that are copied - the function must return 1 to copy the attribute or
1722  * 0 to skip it. The function may also choose to do a partial copy of the source attribute
1723  * itself.
1724  *
1725  * @since CUPS 1.6/macOS 10.8@
1726  */
1727 
1728 int					/* O - 1 on success, 0 on error */
ippCopyAttributes(ipp_t * dst,ipp_t * src,int quickcopy,ipp_copycb_t cb,void * context)1729 ippCopyAttributes(
1730     ipp_t        *dst,			/* I - Destination IPP message */
1731     ipp_t        *src,			/* I - Source IPP message */
1732     int          quickcopy,		/* I - 1 for a referenced copy, 0 for normal */
1733     ipp_copycb_t cb,			/* I - Copy callback or @code NULL@ for none */
1734     void         *context)		/* I - Context pointer */
1735 {
1736   ipp_attribute_t	*srcattr;	/* Source attribute */
1737 
1738 
1739   DEBUG_printf(("ippCopyAttributes(dst=%p, src=%p, quickcopy=%d, cb=%p, context=%p)", (void *)dst, (void *)src, quickcopy, (void *)cb, context));
1740 
1741  /*
1742   * Range check input...
1743   */
1744 
1745   if (!dst || !src)
1746     return (0);
1747 
1748  /*
1749   * Loop through source attributes and copy as needed...
1750   */
1751 
1752   for (srcattr = src->attrs; srcattr; srcattr = srcattr->next)
1753     if (!cb || (*cb)(context, dst, srcattr))
1754       if (!ippCopyAttribute(dst, srcattr, quickcopy))
1755         return (0);
1756 
1757   return (1);
1758 }
1759 
1760 
1761 /*
1762  * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
1763  *                     in seconds.
1764  */
1765 
1766 time_t					/* O - UNIX time value */
ippDateToTime(const ipp_uchar_t * date)1767 ippDateToTime(const ipp_uchar_t *date)	/* I - RFC 1903 date info */
1768 {
1769   struct tm	unixdate;		/* UNIX date/time info */
1770   time_t	t;			/* Computed time */
1771 
1772 
1773   if (!date)
1774     return (0);
1775 
1776   memset(&unixdate, 0, sizeof(unixdate));
1777 
1778  /*
1779   * RFC-1903 date/time format is:
1780   *
1781   *    Byte(s)  Description
1782   *    -------  -----------
1783   *    0-1      Year (0 to 65535)
1784   *    2        Month (1 to 12)
1785   *    3        Day (1 to 31)
1786   *    4        Hours (0 to 23)
1787   *    5        Minutes (0 to 59)
1788   *    6        Seconds (0 to 60, 60 = "leap second")
1789   *    7        Deciseconds (0 to 9)
1790   *    8        +/- UTC
1791   *    9        UTC hours (0 to 11)
1792   *    10       UTC minutes (0 to 59)
1793   */
1794 
1795   unixdate.tm_year = ((date[0] << 8) | date[1]) - 1900;
1796   unixdate.tm_mon  = date[2] - 1;
1797   unixdate.tm_mday = date[3];
1798   unixdate.tm_hour = date[4];
1799   unixdate.tm_min  = date[5];
1800   unixdate.tm_sec  = date[6];
1801 
1802   t = mktime(&unixdate);
1803 
1804   if (date[8] == '-')
1805     t += date[9] * 3600 + date[10] * 60;
1806   else
1807     t -= date[9] * 3600 + date[10] * 60;
1808 
1809   return (t);
1810 }
1811 
1812 
1813 /*
1814  * 'ippDelete()' - Delete an IPP message.
1815  */
1816 
1817 void
ippDelete(ipp_t * ipp)1818 ippDelete(ipp_t *ipp)			/* I - IPP message */
1819 {
1820   ipp_attribute_t	*attr,		/* Current attribute */
1821 			*next;		/* Next attribute */
1822 
1823 
1824   DEBUG_printf(("ippDelete(ipp=%p)", (void *)ipp));
1825 
1826   if (!ipp)
1827     return;
1828 
1829   ipp->use --;
1830   if (ipp->use > 0)
1831     return;
1832 
1833   for (attr = ipp->attrs; attr != NULL; attr = next)
1834   {
1835     next = attr->next;
1836 
1837     ipp_free_values(attr, 0, attr->num_values);
1838 
1839     if (attr->name)
1840       _cupsStrFree(attr->name);
1841 
1842     free(attr);
1843   }
1844 
1845   free(ipp);
1846 }
1847 
1848 
1849 /*
1850  * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
1851  *
1852  * @since CUPS 1.1.19/macOS 10.3@
1853  */
1854 
1855 void
ippDeleteAttribute(ipp_t * ipp,ipp_attribute_t * attr)1856 ippDeleteAttribute(
1857     ipp_t           *ipp,		/* I - IPP message */
1858     ipp_attribute_t *attr)		/* I - Attribute to delete */
1859 {
1860   ipp_attribute_t	*current,	/* Current attribute */
1861 			*prev;		/* Previous attribute */
1862 
1863 
1864   DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p(%s))", (void *)ipp, (void *)attr, attr ? attr->name : "(null)"));
1865 
1866  /*
1867   * Range check input...
1868   */
1869 
1870   if (!attr)
1871     return;
1872 
1873  /*
1874   * Find the attribute in the list...
1875   */
1876 
1877   if (ipp)
1878   {
1879     for (current = ipp->attrs, prev = NULL;
1880 	 current;
1881 	 prev = current, current = current->next)
1882       if (current == attr)
1883       {
1884        /*
1885 	* Found it, remove the attribute from the list...
1886 	*/
1887 
1888 	if (prev)
1889 	  prev->next = current->next;
1890 	else
1891 	  ipp->attrs = current->next;
1892 
1893 	if (current == ipp->last)
1894 	  ipp->last = prev;
1895 
1896         break;
1897       }
1898 
1899     if (!current)
1900       return;
1901   }
1902 
1903  /*
1904   * Free memory used by the attribute...
1905   */
1906 
1907   ipp_free_values(attr, 0, attr->num_values);
1908 
1909   if (attr->name)
1910     _cupsStrFree(attr->name);
1911 
1912   free(attr);
1913 }
1914 
1915 
1916 /*
1917  * 'ippDeleteValues()' - Delete values in an attribute.
1918  *
1919  * The @code element@ parameter specifies the first value to delete, starting at
1920  * 0. It must be less than the number of values returned by @link ippGetCount@.
1921  *
1922  * The @code attr@ parameter may be modified as a result of setting the value.
1923  *
1924  * Deleting all values in an attribute deletes the attribute.
1925  *
1926  * @since CUPS 1.6/macOS 10.8@
1927  */
1928 
1929 int					/* O  - 1 on success, 0 on failure */
ippDeleteValues(ipp_t * ipp,ipp_attribute_t ** attr,int element,int count)1930 ippDeleteValues(
1931     ipp_t           *ipp,		/* I  - IPP message */
1932     ipp_attribute_t **attr,		/* IO - Attribute */
1933     int             element,		/* I  - Index of first value to delete (0-based) */
1934     int             count)		/* I  - Number of values to delete */
1935 {
1936  /*
1937   * Range check input...
1938   */
1939 
1940   if (!ipp || !attr || !*attr ||
1941       element < 0 || element >= (*attr)->num_values || count <= 0 ||
1942       (element + count) >= (*attr)->num_values)
1943     return (0);
1944 
1945  /*
1946   * If we are deleting all values, just delete the attribute entirely.
1947   */
1948 
1949   if (count == (*attr)->num_values)
1950   {
1951     ippDeleteAttribute(ipp, *attr);
1952     *attr = NULL;
1953     return (1);
1954   }
1955 
1956  /*
1957   * Otherwise free the values in question and return.
1958   */
1959 
1960   ipp_free_values(*attr, element, count);
1961 
1962   return (1);
1963 }
1964 
1965 
1966 /*
1967  * 'ippFindAttribute()' - Find a named attribute in a request.
1968  *
1969  * Starting with CUPS 2.0, the attribute name can contain a hierarchical list
1970  * of attribute and member names separated by slashes, for example
1971  * "media-col/media-size".
1972  */
1973 
1974 ipp_attribute_t	*			/* O - Matching attribute */
ippFindAttribute(ipp_t * ipp,const char * name,ipp_tag_t type)1975 ippFindAttribute(ipp_t      *ipp,	/* I - IPP message */
1976                  const char *name,	/* I - Name of attribute */
1977 		 ipp_tag_t  type)	/* I - Type of attribute */
1978 {
1979   DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", (void *)ipp, name, type, ippTagString(type)));
1980 
1981   if (!ipp || !name)
1982     return (NULL);
1983 
1984  /*
1985   * Reset the current pointer...
1986   */
1987 
1988   ipp->current = NULL;
1989   ipp->atend   = 0;
1990 
1991  /*
1992   * Search for the attribute...
1993   */
1994 
1995   return (ippFindNextAttribute(ipp, name, type));
1996 }
1997 
1998 
1999 /*
2000  * 'ippFindNextAttribute()' - Find the next named attribute in a request.
2001  *
2002  * Starting with CUPS 2.0, the attribute name can contain a hierarchical list
2003  * of attribute and member names separated by slashes, for example
2004  * "media-col/media-size".
2005  */
2006 
2007 ipp_attribute_t	*			/* O - Matching attribute */
ippFindNextAttribute(ipp_t * ipp,const char * name,ipp_tag_t type)2008 ippFindNextAttribute(ipp_t      *ipp,	/* I - IPP message */
2009                      const char *name,	/* I - Name of attribute */
2010 		     ipp_tag_t  type)	/* I - Type of attribute */
2011 {
2012   ipp_attribute_t	*attr,		/* Current atttribute */
2013 			*childattr;	/* Child attribute */
2014   ipp_tag_t		value_tag;	/* Value tag */
2015   char			parent[1024],	/* Parent attribute name */
2016 			*child = NULL;	/* Child attribute name */
2017 
2018 
2019   DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", (void *)ipp, name, type, ippTagString(type)));
2020 
2021   if (!ipp || !name)
2022     return (NULL);
2023 
2024   DEBUG_printf(("3ippFindNextAttribute: atend=%d", ipp->atend));
2025 
2026   if (ipp->atend)
2027     return (NULL);
2028 
2029   if (strchr(name, '/'))
2030   {
2031    /*
2032     * Search for child attribute...
2033     */
2034 
2035     strlcpy(parent, name, sizeof(parent));
2036     if ((child = strchr(parent, '/')) == NULL)
2037     {
2038       DEBUG_puts("3ippFindNextAttribute: Attribute name too long.");
2039       return (NULL);
2040     }
2041 
2042     *child++ = '\0';
2043 
2044     if (ipp->current && ipp->current->name && ipp->current->value_tag == IPP_TAG_BEGIN_COLLECTION && !strcmp(parent, ipp->current->name))
2045     {
2046       while (ipp->curindex < ipp->current->num_values)
2047       {
2048         if ((childattr = ippFindNextAttribute(ipp->current->values[ipp->curindex].collection, child, type)) != NULL)
2049           return (childattr);
2050 
2051         ipp->curindex ++;
2052         if (ipp->curindex < ipp->current->num_values && ipp->current->values[ipp->curindex].collection)
2053           ipp->current->values[ipp->curindex].collection->current = NULL;
2054       }
2055 
2056       ipp->prev     = ipp->current;
2057       ipp->current  = ipp->current->next;
2058       ipp->curindex = 0;
2059 
2060       if (!ipp->current)
2061       {
2062         ipp->atend = 1;
2063         return (NULL);
2064       }
2065     }
2066 
2067     if (!ipp->current)
2068     {
2069       ipp->prev     = NULL;
2070       ipp->current  = ipp->attrs;
2071       ipp->curindex = 0;
2072     }
2073 
2074     name = parent;
2075     attr = ipp->current;
2076   }
2077   else if (ipp->current)
2078   {
2079     ipp->prev = ipp->current;
2080     attr      = ipp->current->next;
2081   }
2082   else
2083   {
2084     ipp->prev = NULL;
2085     attr      = ipp->attrs;
2086   }
2087 
2088   for (; attr != NULL; ipp->prev = attr, attr = attr->next)
2089   {
2090     DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", (void *)attr, attr->name));
2091 
2092     value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK);
2093 
2094     if (attr->name != NULL && _cups_strcasecmp(attr->name, name) == 0 &&
2095         (value_tag == type || type == IPP_TAG_ZERO || name == parent ||
2096 	 (value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) ||
2097 	 (value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME)))
2098     {
2099       ipp->current = attr;
2100 
2101       if (name == parent && attr->value_tag == IPP_TAG_BEGIN_COLLECTION)
2102       {
2103         int i;				/* Looping var */
2104 
2105         for (i = 0; i < attr->num_values; i ++)
2106         {
2107 	  if ((childattr = ippFindAttribute(attr->values[i].collection, child, type)) != NULL)
2108 	  {
2109 	    attr->values[0].collection->curindex = i;
2110 	    return (childattr);
2111 	  }
2112         }
2113       }
2114       else
2115         return (attr);
2116     }
2117   }
2118 
2119   ipp->current = NULL;
2120   ipp->prev    = NULL;
2121   ipp->atend   = 1;
2122 
2123   return (NULL);
2124 }
2125 
2126 
2127 /*
2128  * 'ippFirstAttribute()' - Return the first attribute in the message.
2129  *
2130  * @since CUPS 1.6/macOS 10.8@
2131  */
2132 
2133 ipp_attribute_t	*			/* O - First attribute or @code NULL@ if none */
ippFirstAttribute(ipp_t * ipp)2134 ippFirstAttribute(ipp_t *ipp)		/* I - IPP message */
2135 {
2136  /*
2137   * Range check input...
2138   */
2139 
2140   if (!ipp)
2141     return (NULL);
2142 
2143  /*
2144   * Return the first attribute...
2145   */
2146 
2147   return (ipp->current = ipp->attrs);
2148 }
2149 
2150 
2151 /*
2152  * 'ippGetBoolean()' - Get a boolean value for an attribute.
2153  *
2154  * The @code element@ parameter specifies which value to get from 0 to
2155  * @link ippGetCount(attr)@ - 1.
2156  *
2157  * @since CUPS 1.6/macOS 10.8@
2158  */
2159 
2160 int					/* O - Boolean value or 0 on error */
ippGetBoolean(ipp_attribute_t * attr,int element)2161 ippGetBoolean(ipp_attribute_t *attr,	/* I - IPP attribute */
2162               int             element)	/* I - Value number (0-based) */
2163 {
2164  /*
2165   * Range check input...
2166   */
2167 
2168   if (!attr || attr->value_tag != IPP_TAG_BOOLEAN ||
2169       element < 0 || element >= attr->num_values)
2170     return (0);
2171 
2172  /*
2173   * Return the value...
2174   */
2175 
2176   return (attr->values[element].boolean);
2177 }
2178 
2179 
2180 /*
2181  * 'ippGetCollection()' - Get a collection value for an attribute.
2182  *
2183  * The @code element@ parameter specifies which value to get from 0 to
2184  * @link ippGetCount(attr)@ - 1.
2185  *
2186  * @since CUPS 1.6/macOS 10.8@
2187  */
2188 
2189 ipp_t *					/* O - Collection value or @code NULL@ on error */
ippGetCollection(ipp_attribute_t * attr,int element)2190 ippGetCollection(
2191     ipp_attribute_t *attr,		/* I - IPP attribute */
2192     int             element)		/* I - Value number (0-based) */
2193 {
2194  /*
2195   * Range check input...
2196   */
2197 
2198   if (!attr || attr->value_tag != IPP_TAG_BEGIN_COLLECTION ||
2199       element < 0 || element >= attr->num_values)
2200     return (NULL);
2201 
2202  /*
2203   * Return the value...
2204   */
2205 
2206   return (attr->values[element].collection);
2207 }
2208 
2209 
2210 /*
2211  * 'ippGetCount()' - Get the number of values in an attribute.
2212  *
2213  * @since CUPS 1.6/macOS 10.8@
2214  */
2215 
2216 int					/* O - Number of values or 0 on error */
ippGetCount(ipp_attribute_t * attr)2217 ippGetCount(ipp_attribute_t *attr)	/* I - IPP attribute */
2218 {
2219  /*
2220   * Range check input...
2221   */
2222 
2223   if (!attr)
2224     return (0);
2225 
2226  /*
2227   * Return the number of values...
2228   */
2229 
2230   return (attr->num_values);
2231 }
2232 
2233 
2234 /*
2235  * 'ippGetDate()' - Get a date value for an attribute.
2236  *
2237  * The @code element@ parameter specifies which value to get from 0 to
2238  * @link ippGetCount(attr)@ - 1.
2239  *
2240  * @since CUPS 1.6/macOS 10.8@
2241  */
2242 
2243 const ipp_uchar_t *			/* O - Date value or @code NULL@ */
ippGetDate(ipp_attribute_t * attr,int element)2244 ippGetDate(ipp_attribute_t *attr,	/* I - IPP attribute */
2245            int             element)	/* I - Value number (0-based) */
2246 {
2247  /*
2248   * Range check input...
2249   */
2250 
2251   if (!attr || attr->value_tag != IPP_TAG_DATE ||
2252       element < 0 || element >= attr->num_values)
2253     return (NULL);
2254 
2255  /*
2256   * Return the value...
2257   */
2258 
2259   return (attr->values[element].date);
2260 }
2261 
2262 
2263 /*
2264  * 'ippGetGroupTag()' - Get the group associated with an attribute.
2265  *
2266  * @since CUPS 1.6/macOS 10.8@
2267  */
2268 
2269 ipp_tag_t				/* O - Group tag or @code IPP_TAG_ZERO@ on error */
ippGetGroupTag(ipp_attribute_t * attr)2270 ippGetGroupTag(ipp_attribute_t *attr)	/* I - IPP attribute */
2271 {
2272  /*
2273   * Range check input...
2274   */
2275 
2276   if (!attr)
2277     return (IPP_TAG_ZERO);
2278 
2279  /*
2280   * Return the group...
2281   */
2282 
2283   return (attr->group_tag);
2284 }
2285 
2286 
2287 /*
2288  * 'ippGetInteger()' - Get the integer/enum value for an attribute.
2289  *
2290  * The @code element@ parameter specifies which value to get from 0 to
2291  * @link ippGetCount(attr)@ - 1.
2292  *
2293  * @since CUPS 1.6/macOS 10.8@
2294  */
2295 
2296 int					/* O - Value or 0 on error */
ippGetInteger(ipp_attribute_t * attr,int element)2297 ippGetInteger(ipp_attribute_t *attr,	/* I - IPP attribute */
2298               int             element)	/* I - Value number (0-based) */
2299 {
2300  /*
2301   * Range check input...
2302   */
2303 
2304   if (!attr || (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM) ||
2305       element < 0 || element >= attr->num_values)
2306     return (0);
2307 
2308  /*
2309   * Return the value...
2310   */
2311 
2312   return (attr->values[element].integer);
2313 }
2314 
2315 
2316 /*
2317  * 'ippGetName()' - Get the attribute name.
2318  *
2319  * @since CUPS 1.6/macOS 10.8@
2320  */
2321 
2322 const char *				/* O - Attribute name or @code NULL@ for separators */
ippGetName(ipp_attribute_t * attr)2323 ippGetName(ipp_attribute_t *attr)	/* I - IPP attribute */
2324 {
2325  /*
2326   * Range check input...
2327   */
2328 
2329   if (!attr)
2330     return (NULL);
2331 
2332  /*
2333   * Return the name...
2334   */
2335 
2336   return (attr->name);
2337 }
2338 
2339 
2340 /*
2341  * 'ippGetOctetString()' - Get an octetString value from an IPP attribute.
2342  *
2343  * The @code element@ parameter specifies which value to get from 0 to
2344  * @link ippGetCount(attr)@ - 1.
2345  *
2346  * @since CUPS 1.7/macOS 10.9@
2347  */
2348 
2349 void *					/* O - Pointer to octetString data */
ippGetOctetString(ipp_attribute_t * attr,int element,int * datalen)2350 ippGetOctetString(
2351     ipp_attribute_t *attr,		/* I - IPP attribute */
2352     int             element,		/* I - Value number (0-based) */
2353     int             *datalen)		/* O - Length of octetString data */
2354 {
2355  /*
2356   * Range check input...
2357   */
2358 
2359   if (!attr || attr->value_tag != IPP_TAG_STRING ||
2360       element < 0 || element >= attr->num_values)
2361   {
2362     if (datalen)
2363       *datalen = 0;
2364 
2365     return (NULL);
2366   }
2367 
2368  /*
2369   * Return the values...
2370   */
2371 
2372   if (datalen)
2373     *datalen = attr->values[element].unknown.length;
2374 
2375   return (attr->values[element].unknown.data);
2376 }
2377 
2378 
2379 /*
2380  * 'ippGetOperation()' - Get the operation ID in an IPP message.
2381  *
2382  * @since CUPS 1.6/macOS 10.8@
2383  */
2384 
2385 ipp_op_t				/* O - Operation ID or 0 on error */
ippGetOperation(ipp_t * ipp)2386 ippGetOperation(ipp_t *ipp)		/* I - IPP request message */
2387 {
2388  /*
2389   * Range check input...
2390   */
2391 
2392   if (!ipp)
2393     return ((ipp_op_t)0);
2394 
2395  /*
2396   * Return the value...
2397   */
2398 
2399   return (ipp->request.op.operation_id);
2400 }
2401 
2402 
2403 /*
2404  * 'ippGetRange()' - Get a rangeOfInteger value from an attribute.
2405  *
2406  * The @code element@ parameter specifies which value to get from 0 to
2407  * @link ippGetCount(attr)@ - 1.
2408  *
2409  * @since CUPS 1.6/macOS 10.8@
2410  */
2411 
2412 int					/* O - Lower value of range or 0 */
ippGetRange(ipp_attribute_t * attr,int element,int * uppervalue)2413 ippGetRange(ipp_attribute_t *attr,	/* I - IPP attribute */
2414 	    int             element,	/* I - Value number (0-based) */
2415 	    int             *uppervalue)/* O - Upper value of range */
2416 {
2417  /*
2418   * Range check input...
2419   */
2420 
2421   if (!attr || attr->value_tag != IPP_TAG_RANGE ||
2422       element < 0 || element >= attr->num_values)
2423   {
2424     if (uppervalue)
2425       *uppervalue = 0;
2426 
2427     return (0);
2428   }
2429 
2430  /*
2431   * Return the values...
2432   */
2433 
2434   if (uppervalue)
2435     *uppervalue = attr->values[element].range.upper;
2436 
2437   return (attr->values[element].range.lower);
2438 }
2439 
2440 
2441 /*
2442  * 'ippGetRequestId()' - Get the request ID from an IPP message.
2443  *
2444  * @since CUPS 1.6/macOS 10.8@
2445  */
2446 
2447 int					/* O - Request ID or 0 on error */
ippGetRequestId(ipp_t * ipp)2448 ippGetRequestId(ipp_t *ipp)		/* I - IPP message */
2449 {
2450  /*
2451   * Range check input...
2452   */
2453 
2454   if (!ipp)
2455     return (0);
2456 
2457  /*
2458   * Return the request ID...
2459   */
2460 
2461   return (ipp->request.any.request_id);
2462 }
2463 
2464 
2465 /*
2466  * 'ippGetResolution()' - Get a resolution value for an attribute.
2467  *
2468  * The @code element@ parameter specifies which value to get from 0 to
2469  * @link ippGetCount(attr)@ - 1.
2470  *
2471  * @since CUPS 1.6/macOS 10.8@
2472  */
2473 
2474 int					/* O - Horizontal/cross feed resolution or 0 */
ippGetResolution(ipp_attribute_t * attr,int element,int * yres,ipp_res_t * units)2475 ippGetResolution(
2476     ipp_attribute_t *attr,		/* I - IPP attribute */
2477     int             element,		/* I - Value number (0-based) */
2478     int             *yres,		/* O - Vertical/feed resolution */
2479     ipp_res_t       *units)		/* O - Units for resolution */
2480 {
2481  /*
2482   * Range check input...
2483   */
2484 
2485   if (!attr || attr->value_tag != IPP_TAG_RESOLUTION ||
2486       element < 0 || element >= attr->num_values)
2487   {
2488     if (yres)
2489       *yres = 0;
2490 
2491     if (units)
2492       *units = (ipp_res_t)0;
2493 
2494     return (0);
2495   }
2496 
2497  /*
2498   * Return the value...
2499   */
2500 
2501   if (yres)
2502     *yres = attr->values[element].resolution.yres;
2503 
2504   if (units)
2505     *units = attr->values[element].resolution.units;
2506 
2507   return (attr->values[element].resolution.xres);
2508 }
2509 
2510 
2511 /*
2512  * 'ippGetState()' - Get the IPP message state.
2513  *
2514  * @since CUPS 1.6/macOS 10.8@
2515  */
2516 
2517 ipp_state_t				/* O - IPP message state value */
ippGetState(ipp_t * ipp)2518 ippGetState(ipp_t *ipp)			/* I - IPP message */
2519 {
2520  /*
2521   * Range check input...
2522   */
2523 
2524   if (!ipp)
2525     return (IPP_STATE_IDLE);
2526 
2527  /*
2528   * Return the value...
2529   */
2530 
2531   return (ipp->state);
2532 }
2533 
2534 
2535 /*
2536  * 'ippGetStatusCode()' - Get the status code from an IPP response or event message.
2537  *
2538  * @since CUPS 1.6/macOS 10.8@
2539  */
2540 
2541 ipp_status_t				/* O - Status code in IPP message */
ippGetStatusCode(ipp_t * ipp)2542 ippGetStatusCode(ipp_t *ipp)		/* I - IPP response or event message */
2543 {
2544  /*
2545   * Range check input...
2546   */
2547 
2548   if (!ipp)
2549     return (IPP_STATUS_ERROR_INTERNAL);
2550 
2551  /*
2552   * Return the value...
2553   */
2554 
2555   return (ipp->request.status.status_code);
2556 }
2557 
2558 
2559 /*
2560  * 'ippGetString()' - Get the string and optionally the language code for an attribute.
2561  *
2562  * The @code element@ parameter specifies which value to get from 0 to
2563  * @link ippGetCount(attr)@ - 1.
2564  *
2565  * @since CUPS 1.6/macOS 10.8@
2566  */
2567 
2568 const char *
ippGetString(ipp_attribute_t * attr,int element,const char ** language)2569 ippGetString(ipp_attribute_t *attr,	/* I - IPP attribute */
2570              int             element,	/* I - Value number (0-based) */
2571 	     const char      **language)/* O - Language code (@code NULL@ for don't care) */
2572 {
2573   ipp_tag_t	tag;			/* Value tag */
2574 
2575 
2576  /*
2577   * Range check input...
2578   */
2579 
2580   tag = ippGetValueTag(attr);
2581 
2582   if (!attr || element < 0 || element >= attr->num_values || (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG && (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE)))
2583     return (NULL);
2584 
2585  /*
2586   * Return the value...
2587   */
2588 
2589   if (language)
2590     *language = attr->values[element].string.language;
2591 
2592   return (attr->values[element].string.text);
2593 }
2594 
2595 
2596 /*
2597  * 'ippGetValueTag()' - Get the value tag for an attribute.
2598  *
2599  * @since CUPS 1.6/macOS 10.8@
2600  */
2601 
2602 ipp_tag_t				/* O - Value tag or @code IPP_TAG_ZERO@ on error */
ippGetValueTag(ipp_attribute_t * attr)2603 ippGetValueTag(ipp_attribute_t *attr)	/* I - IPP attribute */
2604 {
2605  /*
2606   * Range check input...
2607   */
2608 
2609   if (!attr)
2610     return (IPP_TAG_ZERO);
2611 
2612  /*
2613   * Return the value...
2614   */
2615 
2616   return (attr->value_tag & IPP_TAG_CUPS_MASK);
2617 }
2618 
2619 
2620 /*
2621  * 'ippGetVersion()' - Get the major and minor version number from an IPP message.
2622  *
2623  * @since CUPS 1.6/macOS 10.8@
2624  */
2625 
2626 int					/* O - Major version number or 0 on error */
ippGetVersion(ipp_t * ipp,int * minor)2627 ippGetVersion(ipp_t *ipp,		/* I - IPP message */
2628               int   *minor)		/* O - Minor version number or @code NULL@ */
2629 {
2630  /*
2631   * Range check input...
2632   */
2633 
2634   if (!ipp)
2635   {
2636     if (minor)
2637       *minor = 0;
2638 
2639     return (0);
2640   }
2641 
2642  /*
2643   * Return the value...
2644   */
2645 
2646   if (minor)
2647     *minor = ipp->request.any.version[1];
2648 
2649   return (ipp->request.any.version[0]);
2650 }
2651 
2652 
2653 /*
2654  * 'ippLength()' - Compute the length of an IPP message.
2655  */
2656 
2657 size_t					/* O - Size of IPP message */
ippLength(ipp_t * ipp)2658 ippLength(ipp_t *ipp)			/* I - IPP message */
2659 {
2660   return (ipp_length(ipp, 0));
2661 }
2662 
2663 
2664 /*
2665  * 'ippNextAttribute()' - Return the next attribute in the message.
2666  *
2667  * @since CUPS 1.6/macOS 10.8@
2668  */
2669 
2670 ipp_attribute_t *			/* O - Next attribute or @code NULL@ if none */
ippNextAttribute(ipp_t * ipp)2671 ippNextAttribute(ipp_t *ipp)		/* I - IPP message */
2672 {
2673  /*
2674   * Range check input...
2675   */
2676 
2677   if (!ipp || !ipp->current)
2678     return (NULL);
2679 
2680  /*
2681   * Return the next attribute...
2682   */
2683 
2684   return (ipp->current = ipp->current->next);
2685 }
2686 
2687 
2688 /*
2689  * 'ippNew()' - Allocate a new IPP message.
2690  */
2691 
2692 ipp_t *					/* O - New IPP message */
ippNew(void)2693 ippNew(void)
2694 {
2695   ipp_t			*temp;		/* New IPP message */
2696   _cups_globals_t	*cg = _cupsGlobals();
2697 					/* Global data */
2698 
2699 
2700   DEBUG_puts("ippNew()");
2701 
2702   if ((temp = (ipp_t *)calloc(1, sizeof(ipp_t))) != NULL)
2703   {
2704    /*
2705     * Set default version - usually 2.0...
2706     */
2707 
2708     if (cg->server_version == 0)
2709       _cupsSetDefaults();
2710 
2711     temp->request.any.version[0] = (ipp_uchar_t)(cg->server_version / 10);
2712     temp->request.any.version[1] = (ipp_uchar_t)(cg->server_version % 10);
2713     temp->use                    = 1;
2714   }
2715 
2716   DEBUG_printf(("1ippNew: Returning %p", (void *)temp));
2717 
2718   return (temp);
2719 }
2720 
2721 
2722 /*
2723  *  'ippNewRequest()' - Allocate a new IPP request message.
2724  *
2725  * The new request message is initialized with the attributes-charset and
2726  * attributes-natural-language attributes added. The
2727  * attributes-natural-language value is derived from the current locale.
2728  *
2729  * @since CUPS 1.2/macOS 10.5@
2730  */
2731 
2732 ipp_t *					/* O - IPP request message */
ippNewRequest(ipp_op_t op)2733 ippNewRequest(ipp_op_t op)		/* I - Operation code */
2734 {
2735   ipp_t		*request;		/* IPP request message */
2736   cups_lang_t	*language;		/* Current language localization */
2737   static int	request_id = 0;		/* Current request ID */
2738   static _cups_mutex_t request_mutex = _CUPS_MUTEX_INITIALIZER;
2739 					/* Mutex for request ID */
2740 
2741 
2742   DEBUG_printf(("ippNewRequest(op=%02x(%s))", op, ippOpString(op)));
2743 
2744  /*
2745   * Create a new IPP message...
2746   */
2747 
2748   if ((request = ippNew()) == NULL)
2749     return (NULL);
2750 
2751  /*
2752   * Set the operation and request ID...
2753   */
2754 
2755   _cupsMutexLock(&request_mutex);
2756 
2757   request->request.op.operation_id = op;
2758   request->request.op.request_id   = ++request_id;
2759 
2760   _cupsMutexUnlock(&request_mutex);
2761 
2762  /*
2763   * Use UTF-8 as the character set...
2764   */
2765 
2766   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2767                "attributes-charset", NULL, "utf-8");
2768 
2769  /*
2770   * Get the language from the current locale...
2771   */
2772 
2773   language = cupsLangDefault();
2774 
2775   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2776                "attributes-natural-language", NULL, language->language);
2777 
2778  /*
2779   * Return the new request...
2780   */
2781 
2782   return (request);
2783 }
2784 
2785 
2786 /*
2787  * 'ippNewResponse()' - Allocate a new IPP response message.
2788  *
2789  * The new response message is initialized with the same version-number,
2790  * request-id, attributes-charset, and attributes-natural-language as the
2791  * provided request message.  If the attributes-charset or
2792  * attributes-natural-language attributes are missing from the request,
2793  * "utf-8" and a value derived from the current locale are substituted,
2794  * respectively.
2795  *
2796  * @since CUPS 1.7/macOS 10.9@
2797  */
2798 
2799 ipp_t *					/* O - IPP response message */
ippNewResponse(ipp_t * request)2800 ippNewResponse(ipp_t *request)		/* I - IPP request message */
2801 {
2802   ipp_t			*response;	/* IPP response message */
2803   ipp_attribute_t	*attr;		/* Current attribute */
2804 
2805 
2806  /*
2807   * Range check input...
2808   */
2809 
2810   if (!request)
2811     return (NULL);
2812 
2813  /*
2814   * Create a new IPP message...
2815   */
2816 
2817   if ((response = ippNew()) == NULL)
2818     return (NULL);
2819 
2820  /*
2821   * Copy the request values over to the response...
2822   */
2823 
2824   response->request.status.version[0] = request->request.op.version[0];
2825   response->request.status.version[1] = request->request.op.version[1];
2826   response->request.status.request_id = request->request.op.request_id;
2827 
2828  /*
2829   * The first attribute MUST be attributes-charset...
2830   */
2831 
2832   attr = request->attrs;
2833 
2834   if (attr && attr->name && !strcmp(attr->name, "attributes-charset") &&
2835       attr->group_tag == IPP_TAG_OPERATION &&
2836       attr->value_tag == IPP_TAG_CHARSET &&
2837       attr->num_values == 1)
2838   {
2839    /*
2840     * Copy charset from request...
2841     */
2842 
2843     ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2844 		 "attributes-charset", NULL, attr->values[0].string.text);
2845   }
2846   else
2847   {
2848    /*
2849     * Use "utf-8" as the default...
2850     */
2851 
2852     ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2853 		 "attributes-charset", NULL, "utf-8");
2854   }
2855 
2856  /*
2857   * Then attributes-natural-language...
2858   */
2859 
2860   if (attr)
2861     attr = attr->next;
2862 
2863   if (attr && attr->name &&
2864       !strcmp(attr->name, "attributes-natural-language") &&
2865       attr->group_tag == IPP_TAG_OPERATION &&
2866       attr->value_tag == IPP_TAG_LANGUAGE &&
2867       attr->num_values == 1)
2868   {
2869    /*
2870     * Copy language from request...
2871     */
2872 
2873     ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2874 		 "attributes-natural-language", NULL,
2875 		 attr->values[0].string.text);
2876   }
2877   else
2878   {
2879    /*
2880     * Use the language from the current locale...
2881     */
2882 
2883     cups_lang_t *language = cupsLangDefault();
2884 					/* Current locale */
2885 
2886     ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2887 		 "attributes-natural-language", NULL, language->language);
2888   }
2889 
2890   return (response);
2891 }
2892 
2893 
2894 /*
2895  * 'ippRead()' - Read data for an IPP message from a HTTP connection.
2896  */
2897 
2898 ipp_state_t				/* O - Current state */
ippRead(http_t * http,ipp_t * ipp)2899 ippRead(http_t *http,			/* I - HTTP connection */
2900         ipp_t  *ipp)			/* I - IPP data */
2901 {
2902   DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT, (void *)http, (void *)ipp, CUPS_LLCAST (http ? http->data_remaining : -1)));
2903 
2904   if (!http)
2905     return (IPP_STATE_ERROR);
2906 
2907   DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http->state, http->used));
2908 
2909   return (ippReadIO(http, (ipp_iocb_t)ipp_read_http, http->blocking, NULL,
2910                     ipp));
2911 }
2912 
2913 
2914 /*
2915  * 'ippReadFile()' - Read data for an IPP message from a file.
2916  *
2917  * @since CUPS 1.1.19/macOS 10.3@
2918  */
2919 
2920 ipp_state_t				/* O - Current state */
ippReadFile(int fd,ipp_t * ipp)2921 ippReadFile(int   fd,			/* I - HTTP data */
2922             ipp_t *ipp)			/* I - IPP data */
2923 {
2924   DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd, (void *)ipp));
2925 
2926   return (ippReadIO(&fd, (ipp_iocb_t)ipp_read_file, 1, NULL, ipp));
2927 }
2928 
2929 
2930 /*
2931  * 'ippReadIO()' - Read data for an IPP message.
2932  *
2933  * @since CUPS 1.2/macOS 10.5@
2934  */
2935 
2936 ipp_state_t				/* O - Current state */
ippReadIO(void * src,ipp_iocb_t cb,int blocking,ipp_t * parent,ipp_t * ipp)2937 ippReadIO(void       *src,		/* I - Data source */
2938           ipp_iocb_t cb,		/* I - Read callback function */
2939 	  int        blocking,		/* I - Use blocking IO? */
2940 	  ipp_t      *parent,		/* I - Parent request, if any */
2941           ipp_t      *ipp)		/* I - IPP data */
2942 {
2943   int			n;		/* Length of data */
2944   unsigned char		*buffer,	/* Data buffer */
2945 			string[IPP_MAX_TEXT],
2946 					/* Small string buffer */
2947 			*bufptr;	/* Pointer into buffer */
2948   ipp_attribute_t	*attr;		/* Current attribute */
2949   ipp_tag_t		tag;		/* Current tag */
2950   ipp_tag_t		value_tag;	/* Current value tag */
2951   _ipp_value_t		*value;		/* Current value */
2952 
2953 
2954   DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)src, (void *)cb, blocking, (void *)parent, (void *)ipp));
2955   DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp ? ipp->state : IPP_STATE_ERROR));
2956 
2957   if (!src || !ipp)
2958     return (IPP_STATE_ERROR);
2959 
2960   if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
2961   {
2962     DEBUG_puts("1ippReadIO: Unable to get read buffer.");
2963     return (IPP_STATE_ERROR);
2964   }
2965 
2966   switch (ipp->state)
2967   {
2968     case IPP_STATE_IDLE :
2969         ipp->state ++; /* Avoid common problem... */
2970 
2971     case IPP_STATE_HEADER :
2972         if (parent == NULL)
2973 	{
2974 	 /*
2975           * Get the request header...
2976 	  */
2977 
2978           if ((*cb)(src, buffer, 8) < 8)
2979 	  {
2980 	    DEBUG_puts("1ippReadIO: Unable to read header.");
2981 	    _cupsBufferRelease((char *)buffer);
2982 	    return (IPP_STATE_ERROR);
2983 	  }
2984 
2985 	 /*
2986           * Then copy the request header over...
2987 	  */
2988 
2989           ipp->request.any.version[0]  = buffer[0];
2990           ipp->request.any.version[1]  = buffer[1];
2991           ipp->request.any.op_status   = (buffer[2] << 8) | buffer[3];
2992           ipp->request.any.request_id  = (((((buffer[4] << 8) | buffer[5]) << 8) |
2993 	                        	 buffer[6]) << 8) | buffer[7];
2994 
2995           DEBUG_printf(("2ippReadIO: version=%d.%d", buffer[0], buffer[1]));
2996 	  DEBUG_printf(("2ippReadIO: op_status=%04x",
2997 	                ipp->request.any.op_status));
2998 	  DEBUG_printf(("2ippReadIO: request_id=%d",
2999 	                ipp->request.any.request_id));
3000         }
3001 
3002         ipp->state   = IPP_STATE_ATTRIBUTE;
3003 	ipp->current = NULL;
3004 	ipp->curtag  = IPP_TAG_ZERO;
3005 	ipp->prev    = ipp->last;
3006 
3007        /*
3008         * If blocking is disabled, stop here...
3009 	*/
3010 
3011         if (!blocking)
3012 	  break;
3013 
3014     case IPP_STATE_ATTRIBUTE :
3015         for (;;)
3016 	{
3017 	  if ((*cb)(src, buffer, 1) < 1)
3018 	  {
3019 	    DEBUG_puts("1ippReadIO: Callback returned EOF/error");
3020 	    _cupsBufferRelease((char *)buffer);
3021 	    return (IPP_STATE_ERROR);
3022 	  }
3023 
3024 	  DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev));
3025 
3026 	 /*
3027 	  * Read this attribute...
3028 	  */
3029 
3030           tag = (ipp_tag_t)buffer[0];
3031           if (tag == IPP_TAG_EXTENSION)
3032           {
3033            /*
3034             * Read 32-bit "extension" tag...
3035             */
3036 
3037 	    if ((*cb)(src, buffer, 4) < 1)
3038 	    {
3039 	      DEBUG_puts("1ippReadIO: Callback returned EOF/error");
3040 	      _cupsBufferRelease((char *)buffer);
3041 	      return (IPP_STATE_ERROR);
3042 	    }
3043 
3044 	    tag = (ipp_tag_t)((((((buffer[0] << 8) | buffer[1]) << 8) |
3045 	                        buffer[2]) << 8) | buffer[3]);
3046 
3047             if (tag & IPP_TAG_CUPS_CONST)
3048             {
3049              /*
3050               * Fail if the high bit is set in the tag...
3051               */
3052 
3053 	      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
3054 	      DEBUG_printf(("1ippReadIO: bad tag 0x%x.", tag));
3055 	      _cupsBufferRelease((char *)buffer);
3056 	      return (IPP_STATE_ERROR);
3057             }
3058           }
3059 
3060 	  if (tag == IPP_TAG_END)
3061 	  {
3062 	   /*
3063 	    * No more attributes left...
3064 	    */
3065 
3066             DEBUG_puts("2ippReadIO: IPP_TAG_END.");
3067 
3068 	    ipp->state = IPP_STATE_DATA;
3069 	    break;
3070 	  }
3071           else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
3072 	  {
3073 	   /*
3074 	    * Group tag...  Set the current group and continue...
3075 	    */
3076 
3077             if (ipp->curtag == tag)
3078 	      ipp->prev = ippAddSeparator(ipp);
3079             else if (ipp->current)
3080 	      ipp->prev = ipp->current;
3081 
3082 	    ipp->curtag  = tag;
3083 	    ipp->current = NULL;
3084 	    DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag, ippTagString(tag), (void *)ipp->prev));
3085 	    continue;
3086 	  }
3087 
3088           DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag,
3089 	                ippTagString(tag)));
3090 
3091          /*
3092 	  * Get the name...
3093 	  */
3094 
3095           if ((*cb)(src, buffer, 2) < 2)
3096 	  {
3097 	    DEBUG_puts("1ippReadIO: unable to read name length.");
3098 	    _cupsBufferRelease((char *)buffer);
3099 	    return (IPP_STATE_ERROR);
3100 	  }
3101 
3102           n = (buffer[0] << 8) | buffer[1];
3103 
3104           if (n >= IPP_BUF_SIZE)
3105 	  {
3106 	    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP name larger than 32767 bytes."), 1);
3107 	    DEBUG_printf(("1ippReadIO: bad name length %d.", n));
3108 	    _cupsBufferRelease((char *)buffer);
3109 	    return (IPP_STATE_ERROR);
3110 	  }
3111 
3112           DEBUG_printf(("2ippReadIO: name length=%d", n));
3113 
3114           if (n == 0 && tag != IPP_TAG_MEMBERNAME &&
3115 	      tag != IPP_TAG_END_COLLECTION)
3116 	  {
3117 	   /*
3118 	    * More values for current attribute...
3119 	    */
3120 
3121             if (ipp->current == NULL)
3122 	    {
3123 	      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP attribute has no name."), 1);
3124 	      DEBUG_puts("1ippReadIO: Attribute without name and no current.");
3125 	      _cupsBufferRelease((char *)buffer);
3126 	      return (IPP_STATE_ERROR);
3127 	    }
3128 
3129             attr      = ipp->current;
3130 	    value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK);
3131 
3132 	   /*
3133 	    * Make sure we aren't adding a new value of a different
3134 	    * type...
3135 	    */
3136 
3137 	    if (value_tag == IPP_TAG_ZERO)
3138 	    {
3139 	     /*
3140 	      * Setting the value of a collection member...
3141 	      */
3142 
3143 	      attr->value_tag = tag;
3144 	    }
3145 	    else if (value_tag == IPP_TAG_TEXTLANG ||
3146 	             value_tag == IPP_TAG_NAMELANG ||
3147 		     (value_tag >= IPP_TAG_TEXT &&
3148 		      value_tag <= IPP_TAG_MIMETYPE))
3149             {
3150 	     /*
3151 	      * String values can sometimes come across in different
3152 	      * forms; accept sets of differing values...
3153 	      */
3154 
3155 	      if (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG &&
3156 	          (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE) &&
3157 		  tag != IPP_TAG_NOVALUE)
3158 	      {
3159 		_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3160 		              _("IPP 1setOf attribute with incompatible value "
3161 		                "tags."), 1);
3162 		DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3163 			      value_tag, ippTagString(value_tag), tag,
3164 			      ippTagString(tag)));
3165 		_cupsBufferRelease((char *)buffer);
3166 	        return (IPP_STATE_ERROR);
3167 	      }
3168 
3169               if (value_tag != tag)
3170               {
3171                 DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.",
3172                               attr->name, ippTagString(value_tag), ippTagString(tag)));
3173 		ippSetValueTag(ipp, &attr, tag);
3174 	      }
3175             }
3176 	    else if (value_tag == IPP_TAG_INTEGER ||
3177 	             value_tag == IPP_TAG_RANGE)
3178             {
3179 	     /*
3180 	      * Integer and rangeOfInteger values can sometimes be mixed; accept
3181 	      * sets of differing values...
3182 	      */
3183 
3184 	      if (tag != IPP_TAG_INTEGER && tag != IPP_TAG_RANGE)
3185 	      {
3186 		_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3187 		              _("IPP 1setOf attribute with incompatible value "
3188 		                "tags."), 1);
3189 		DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3190 			      value_tag, ippTagString(value_tag), tag,
3191 			      ippTagString(tag)));
3192 		_cupsBufferRelease((char *)buffer);
3193 	        return (IPP_STATE_ERROR);
3194 	      }
3195 
3196               if (value_tag == IPP_TAG_INTEGER && tag == IPP_TAG_RANGE)
3197               {
3198                /*
3199                 * Convert integer values to rangeOfInteger values...
3200                 */
3201 
3202 		DEBUG_printf(("1ippReadIO: Converting %s attribute to "
3203 		              "rangeOfInteger.", attr->name));
3204                 ippSetValueTag(ipp, &attr, IPP_TAG_RANGE);
3205               }
3206             }
3207 	    else if (value_tag != tag)
3208 	    {
3209 	      _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3210 			    _("IPP 1setOf attribute with incompatible value "
3211 			      "tags."), 1);
3212 	      DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
3213 	                    value_tag, ippTagString(value_tag), tag,
3214 			    ippTagString(tag)));
3215 	      _cupsBufferRelease((char *)buffer);
3216 	      return (IPP_STATE_ERROR);
3217             }
3218 
3219            /*
3220 	    * Finally, reallocate the attribute array as needed...
3221 	    */
3222 
3223 	    if ((value = ipp_set_value(ipp, &attr, attr->num_values)) == NULL)
3224 	    {
3225 	      _cupsBufferRelease((char *)buffer);
3226 	      return (IPP_STATE_ERROR);
3227 	    }
3228 	  }
3229 	  else if (tag == IPP_TAG_MEMBERNAME)
3230 	  {
3231 	   /*
3232 	    * Name must be length 0!
3233 	    */
3234 
3235 	    if (n)
3236 	    {
3237 	      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP member name is not empty."), 1);
3238 	      DEBUG_puts("1ippReadIO: member name not empty.");
3239 	      _cupsBufferRelease((char *)buffer);
3240 	      return (IPP_STATE_ERROR);
3241 	    }
3242 
3243             if (ipp->current)
3244 	      ipp->prev = ipp->current;
3245 
3246 	    attr = ipp->current = ipp_add_attr(ipp, NULL, ipp->curtag, IPP_TAG_ZERO, 1);
3247 	    if (!attr)
3248 	    {
3249 	      _cupsSetHTTPError(HTTP_STATUS_ERROR);
3250 	      DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3251 	      _cupsBufferRelease((char *)buffer);
3252 	      return (IPP_STATE_ERROR);
3253 	    }
3254 
3255 	    DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev));
3256 
3257 	    value = attr->values;
3258 	  }
3259 	  else if (tag != IPP_TAG_END_COLLECTION)
3260 	  {
3261 	   /*
3262 	    * New attribute; read the name and add it...
3263 	    */
3264 
3265 	    if ((*cb)(src, buffer, (size_t)n) < n)
3266 	    {
3267 	      DEBUG_puts("1ippReadIO: unable to read name.");
3268 	      _cupsBufferRelease((char *)buffer);
3269 	      return (IPP_STATE_ERROR);
3270 	    }
3271 
3272 	    buffer[n] = '\0';
3273 
3274             if (ipp->current)
3275 	      ipp->prev = ipp->current;
3276 
3277 	    if ((attr = ipp->current = ipp_add_attr(ipp, (char *)buffer, ipp->curtag, tag,
3278 	                                            1)) == NULL)
3279 	    {
3280 	      _cupsSetHTTPError(HTTP_STATUS_ERROR);
3281 	      DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3282 	      _cupsBufferRelease((char *)buffer);
3283 	      return (IPP_STATE_ERROR);
3284 	    }
3285 
3286 	    DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, ipp->prev=%p", buffer, (void *)ipp->current, (void *)ipp->prev));
3287 
3288 	    value = attr->values;
3289 	  }
3290 	  else
3291 	  {
3292 	    attr  = NULL;
3293 	    value = NULL;
3294 	  }
3295 
3296 	  if ((*cb)(src, buffer, 2) < 2)
3297 	  {
3298 	    DEBUG_puts("1ippReadIO: unable to read value length.");
3299 	    _cupsBufferRelease((char *)buffer);
3300 	    return (IPP_STATE_ERROR);
3301 	  }
3302 
3303 	  n = (buffer[0] << 8) | buffer[1];
3304           DEBUG_printf(("2ippReadIO: value length=%d", n));
3305 
3306 	  if (n >= IPP_BUF_SIZE)
3307 	  {
3308 	    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3309 			  _("IPP value larger than 32767 bytes."), 1);
3310 	    DEBUG_printf(("1ippReadIO: bad value length %d.", n));
3311 	    _cupsBufferRelease((char *)buffer);
3312 	    return (IPP_STATE_ERROR);
3313 	  }
3314 
3315 	  switch (tag)
3316 	  {
3317 	    case IPP_TAG_INTEGER :
3318 	    case IPP_TAG_ENUM :
3319 		if (n != 4)
3320 		{
3321 		  if (tag == IPP_TAG_INTEGER)
3322 		    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3323 				  _("IPP integer value not 4 bytes."), 1);
3324 		  else
3325 		    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3326 				  _("IPP enum value not 4 bytes."), 1);
3327 		  DEBUG_printf(("1ippReadIO: bad integer value length %d.", n));
3328 		  _cupsBufferRelease((char *)buffer);
3329 		  return (IPP_STATE_ERROR);
3330 		}
3331 
3332 	        if ((*cb)(src, buffer, 4) < 4)
3333 		{
3334 	          DEBUG_puts("1ippReadIO: Unable to read integer value.");
3335 		  _cupsBufferRelease((char *)buffer);
3336 		  return (IPP_STATE_ERROR);
3337 		}
3338 
3339 		n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3340 		    buffer[3];
3341 
3342                 if (attr->value_tag == IPP_TAG_RANGE)
3343                   value->range.lower = value->range.upper = n;
3344                 else
3345 		  value->integer = n;
3346 	        break;
3347 
3348 	    case IPP_TAG_BOOLEAN :
3349 		if (n != 1)
3350 		{
3351 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP boolean value not 1 byte."),
3352 		                1);
3353 		  DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n));
3354 		  _cupsBufferRelease((char *)buffer);
3355 		  return (IPP_STATE_ERROR);
3356 		}
3357 
3358 	        if ((*cb)(src, buffer, 1) < 1)
3359 		{
3360 	          DEBUG_puts("1ippReadIO: Unable to read boolean value.");
3361 		  _cupsBufferRelease((char *)buffer);
3362 		  return (IPP_STATE_ERROR);
3363 		}
3364 
3365                 value->boolean = (char)buffer[0];
3366 	        break;
3367 
3368             case IPP_TAG_NOVALUE :
3369 	    case IPP_TAG_NOTSETTABLE :
3370 	    case IPP_TAG_DELETEATTR :
3371 	    case IPP_TAG_ADMINDEFINE :
3372 	       /*
3373 	        * These value types are not supposed to have values, however
3374 		* some vendors (Brother) do not implement IPP correctly and so
3375 		* we need to map non-empty values to text...
3376 		*/
3377 
3378 	        if (attr->value_tag == tag)
3379 		{
3380 		  if (n == 0)
3381 		    break;
3382 
3383 		  attr->value_tag = IPP_TAG_TEXT;
3384 		}
3385 
3386 	    case IPP_TAG_TEXT :
3387 	    case IPP_TAG_NAME :
3388 	    case IPP_TAG_KEYWORD :
3389 	    case IPP_TAG_URI :
3390 	    case IPP_TAG_URISCHEME :
3391 	    case IPP_TAG_CHARSET :
3392 	    case IPP_TAG_LANGUAGE :
3393 	    case IPP_TAG_MIMETYPE :
3394 	        if (n > 0)
3395 	        {
3396 		  if ((*cb)(src, buffer, (size_t)n) < n)
3397 		  {
3398 		    DEBUG_puts("1ippReadIO: unable to read string value.");
3399 		    _cupsBufferRelease((char *)buffer);
3400 		    return (IPP_STATE_ERROR);
3401 		  }
3402 		}
3403 
3404 		buffer[n] = '\0';
3405 		value->string.text = _cupsStrAlloc((char *)buffer);
3406 		DEBUG_printf(("2ippReadIO: value=\"%s\"", value->string.text));
3407 	        break;
3408 
3409 	    case IPP_TAG_DATE :
3410 		if (n != 11)
3411 		{
3412 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP date value not 11 bytes."), 1);
3413 		  DEBUG_printf(("1ippReadIO: bad date value length %d.", n));
3414 		  _cupsBufferRelease((char *)buffer);
3415 		  return (IPP_STATE_ERROR);
3416 		}
3417 
3418 	        if ((*cb)(src, value->date, 11) < 11)
3419 		{
3420 	          DEBUG_puts("1ippReadIO: Unable to read date value.");
3421 		  _cupsBufferRelease((char *)buffer);
3422 		  return (IPP_STATE_ERROR);
3423 		}
3424 	        break;
3425 
3426 	    case IPP_TAG_RESOLUTION :
3427 		if (n != 9)
3428 		{
3429 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3430 		                _("IPP resolution value not 9 bytes."), 1);
3431 		  DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n));
3432 		  _cupsBufferRelease((char *)buffer);
3433 		  return (IPP_STATE_ERROR);
3434 		}
3435 
3436 	        if ((*cb)(src, buffer, 9) < 9)
3437 		{
3438 	          DEBUG_puts("1ippReadIO: Unable to read resolution value.");
3439 		  _cupsBufferRelease((char *)buffer);
3440 		  return (IPP_STATE_ERROR);
3441 		}
3442 
3443                 value->resolution.xres =
3444 		    (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3445 		    buffer[3];
3446                 value->resolution.yres =
3447 		    (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
3448 		    buffer[7];
3449                 value->resolution.units =
3450 		    (ipp_res_t)buffer[8];
3451 	        break;
3452 
3453 	    case IPP_TAG_RANGE :
3454 		if (n != 8)
3455 		{
3456 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3457 		                _("IPP rangeOfInteger value not 8 bytes."), 1);
3458 		  DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length "
3459 		                "%d.", n));
3460 		  _cupsBufferRelease((char *)buffer);
3461 		  return (IPP_STATE_ERROR);
3462 		}
3463 
3464 	        if ((*cb)(src, buffer, 8) < 8)
3465 		{
3466 	          DEBUG_puts("1ippReadIO: Unable to read range value.");
3467 		  _cupsBufferRelease((char *)buffer);
3468 		  return (IPP_STATE_ERROR);
3469 		}
3470 
3471                 value->range.lower =
3472 		    (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3473 		    buffer[3];
3474                 value->range.upper =
3475 		    (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
3476 		    buffer[7];
3477 	        break;
3478 
3479 	    case IPP_TAG_TEXTLANG :
3480 	    case IPP_TAG_NAMELANG :
3481 	        if (n < 4)
3482 		{
3483 		  if (tag == IPP_TAG_TEXTLANG)
3484 		    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3485 		                  _("IPP textWithLanguage value less than "
3486 		                    "minimum 4 bytes."), 1);
3487 		  else
3488 		    _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3489 		                  _("IPP nameWithLanguage value less than "
3490 		                    "minimum 4 bytes."), 1);
3491 		  DEBUG_printf(("1ippReadIO: bad stringWithLanguage value "
3492 		                "length %d.", n));
3493 		  _cupsBufferRelease((char *)buffer);
3494 		  return (IPP_STATE_ERROR);
3495 		}
3496 
3497 	        if ((*cb)(src, buffer, (size_t)n) < n)
3498 		{
3499 	          DEBUG_puts("1ippReadIO: Unable to read string w/language "
3500 		             "value.");
3501 		  _cupsBufferRelease((char *)buffer);
3502 		  return (IPP_STATE_ERROR);
3503 		}
3504 
3505                 bufptr = buffer;
3506 
3507 	       /*
3508 	        * text-with-language and name-with-language are composite
3509 		* values:
3510 		*
3511 		*    language-length
3512 		*    language
3513 		*    text-length
3514 		*    text
3515 		*/
3516 
3517 		n = (bufptr[0] << 8) | bufptr[1];
3518 
3519 		if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) || n >= (int)sizeof(string))
3520 		{
3521 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3522 		                _("IPP language length overflows value."), 1);
3523 		  DEBUG_printf(("1ippReadIO: bad language value length %d.",
3524 		                n));
3525 		  _cupsBufferRelease((char *)buffer);
3526 		  return (IPP_STATE_ERROR);
3527 		}
3528 		else if (n >= IPP_MAX_LANGUAGE)
3529 		{
3530 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3531 		                _("IPP language length too large."), 1);
3532 		  DEBUG_printf(("1ippReadIO: bad language value length %d.",
3533 		                n));
3534 		  _cupsBufferRelease((char *)buffer);
3535 		  return (IPP_STATE_ERROR);
3536 		}
3537 
3538 		memcpy(string, bufptr + 2, (size_t)n);
3539 		string[n] = '\0';
3540 
3541 		value->string.language = _cupsStrAlloc((char *)string);
3542 
3543                 bufptr += 2 + n;
3544 		n = (bufptr[0] << 8) | bufptr[1];
3545 
3546 		if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE))
3547 		{
3548 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3549 		                _("IPP string length overflows value."), 1);
3550 		  DEBUG_printf(("1ippReadIO: bad string value length %d.", n));
3551 		  _cupsBufferRelease((char *)buffer);
3552 		  return (IPP_STATE_ERROR);
3553 		}
3554 
3555 		bufptr[2 + n] = '\0';
3556                 value->string.text = _cupsStrAlloc((char *)bufptr + 2);
3557 	        break;
3558 
3559             case IPP_TAG_BEGIN_COLLECTION :
3560 	       /*
3561 	        * Oh, boy, here comes a collection value, so read it...
3562 		*/
3563 
3564                 value->collection = ippNew();
3565 
3566                 if (n > 0)
3567 		{
3568 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3569 		                _("IPP begCollection value not 0 bytes."), 1);
3570 	          DEBUG_puts("1ippReadIO: begCollection tag with value length "
3571 		             "> 0.");
3572 		  _cupsBufferRelease((char *)buffer);
3573 		  return (IPP_STATE_ERROR);
3574 		}
3575 
3576 		if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_STATE_ERROR)
3577 		{
3578 	          DEBUG_puts("1ippReadIO: Unable to read collection value.");
3579 		  _cupsBufferRelease((char *)buffer);
3580 		  return (IPP_STATE_ERROR);
3581 		}
3582                 break;
3583 
3584             case IPP_TAG_END_COLLECTION :
3585 		_cupsBufferRelease((char *)buffer);
3586 
3587                 if (n > 0)
3588 		{
3589 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3590 		                _("IPP endCollection value not 0 bytes."), 1);
3591 	          DEBUG_puts("1ippReadIO: endCollection tag with value length "
3592 		             "> 0.");
3593 		  return (IPP_STATE_ERROR);
3594 		}
3595 
3596 	        DEBUG_puts("1ippReadIO: endCollection tag...");
3597 		return (ipp->state = IPP_STATE_DATA);
3598 
3599             case IPP_TAG_MEMBERNAME :
3600 	       /*
3601 	        * The value the name of the member in the collection, which
3602 		* we need to carry over...
3603 		*/
3604 
3605                 if (!attr)
3606                 {
3607 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3608 		                _("IPP memberName with no attribute."), 1);
3609 	          DEBUG_puts("1ippReadIO: Member name without attribute.");
3610 		  _cupsBufferRelease((char *)buffer);
3611 		  return (IPP_STATE_ERROR);
3612                 }
3613 		else if (n == 0)
3614 		{
3615 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3616 		                _("IPP memberName value is empty."), 1);
3617 	          DEBUG_puts("1ippReadIO: Empty member name value.");
3618 		  _cupsBufferRelease((char *)buffer);
3619 		  return (IPP_STATE_ERROR);
3620 		}
3621 		else if ((*cb)(src, buffer, (size_t)n) < n)
3622 		{
3623 	          DEBUG_puts("1ippReadIO: Unable to read member name value.");
3624 		  _cupsBufferRelease((char *)buffer);
3625 		  return (IPP_STATE_ERROR);
3626 		}
3627 
3628 		buffer[n] = '\0';
3629 		attr->name = _cupsStrAlloc((char *)buffer);
3630 
3631                /*
3632 	        * Since collection members are encoded differently than
3633 		* regular attributes, make sure we don't start with an
3634 		* empty value...
3635 		*/
3636 
3637                 attr->num_values --;
3638 
3639 		DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr->name));
3640 		break;
3641 
3642             default : /* Other unsupported values */
3643                 if (tag == IPP_TAG_STRING && n > IPP_MAX_LENGTH)
3644 		{
3645 		  _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
3646 		                _("IPP octetString length too large."), 1);
3647 		  DEBUG_printf(("1ippReadIO: bad octetString value length %d.",
3648 		                n));
3649 		  _cupsBufferRelease((char *)buffer);
3650 		  return (IPP_STATE_ERROR);
3651 		}
3652 
3653                 value->unknown.length = n;
3654 
3655 	        if (n > 0)
3656 		{
3657 		  if ((value->unknown.data = malloc((size_t)n)) == NULL)
3658 		  {
3659 		    _cupsSetHTTPError(HTTP_STATUS_ERROR);
3660 		    DEBUG_puts("1ippReadIO: Unable to allocate value");
3661 		    _cupsBufferRelease((char *)buffer);
3662 		    return (IPP_STATE_ERROR);
3663 		  }
3664 
3665 	          if ((*cb)(src, value->unknown.data, (size_t)n) < n)
3666 		  {
3667 	            DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
3668 		    _cupsBufferRelease((char *)buffer);
3669 		    return (IPP_STATE_ERROR);
3670 		  }
3671 		}
3672 		else
3673 		  value->unknown.data = NULL;
3674 	        break;
3675 	  }
3676 
3677 	 /*
3678           * If blocking is disabled, stop here...
3679 	  */
3680 
3681           if (!blocking)
3682 	    break;
3683 	}
3684         break;
3685 
3686     case IPP_STATE_DATA :
3687         break;
3688 
3689     default :
3690         break; /* anti-compiler-warning-code */
3691   }
3692 
3693   DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp->state));
3694   _cupsBufferRelease((char *)buffer);
3695 
3696   return (ipp->state);
3697 }
3698 
3699 
3700 /*
3701  * 'ippSetBoolean()' - Set a boolean value in an attribute.
3702  *
3703  * The @code ipp@ parameter refers to an IPP message previously created using
3704  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3705  *
3706  * The @code attr@ parameter may be modified as a result of setting the value.
3707  *
3708  * The @code element@ parameter specifies which value to set from 0 to
3709  * @link ippGetCount(attr)@.
3710  *
3711  * @since CUPS 1.6/macOS 10.8@
3712  */
3713 
3714 int					/* O  - 1 on success, 0 on failure */
ippSetBoolean(ipp_t * ipp,ipp_attribute_t ** attr,int element,int boolvalue)3715 ippSetBoolean(ipp_t           *ipp,	/* I  - IPP message */
3716               ipp_attribute_t **attr,	/* IO - IPP attribute */
3717               int             element,	/* I  - Value number (0-based) */
3718               int             boolvalue)/* I  - Boolean value */
3719 {
3720   _ipp_value_t	*value;			/* Current value */
3721 
3722 
3723  /*
3724   * Range check input...
3725   */
3726 
3727   if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BOOLEAN ||
3728       element < 0 || element > (*attr)->num_values)
3729     return (0);
3730 
3731  /*
3732   * Set the value and return...
3733   */
3734 
3735   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3736     value->boolean = (char)boolvalue;
3737 
3738   return (value != NULL);
3739 }
3740 
3741 
3742 /*
3743  * 'ippSetCollection()' - Set a collection value in an attribute.
3744  *
3745  * The @code ipp@ parameter refers to an IPP message previously created using
3746  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3747  *
3748  * The @code attr@ parameter may be modified as a result of setting the value.
3749  *
3750  * The @code element@ parameter specifies which value to set from 0 to
3751  * @link ippGetCount(attr)@.
3752  *
3753  * @since CUPS 1.6/macOS 10.8@
3754  */
3755 
3756 int					/* O  - 1 on success, 0 on failure */
ippSetCollection(ipp_t * ipp,ipp_attribute_t ** attr,int element,ipp_t * colvalue)3757 ippSetCollection(
3758     ipp_t           *ipp,		/* I  - IPP message */
3759     ipp_attribute_t **attr,		/* IO - IPP attribute */
3760     int             element,		/* I  - Value number (0-based) */
3761     ipp_t           *colvalue)		/* I  - Collection value */
3762 {
3763   _ipp_value_t	*value;			/* Current value */
3764 
3765 
3766  /*
3767   * Range check input...
3768   */
3769 
3770   if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BEGIN_COLLECTION ||
3771       element < 0 || element > (*attr)->num_values || !colvalue)
3772     return (0);
3773 
3774  /*
3775   * Set the value and return...
3776   */
3777 
3778   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3779   {
3780     if (value->collection)
3781       ippDelete(value->collection);
3782 
3783     value->collection = colvalue;
3784     colvalue->use ++;
3785   }
3786 
3787   return (value != NULL);
3788 }
3789 
3790 
3791 /*
3792  * 'ippSetDate()' - Set a date value in an attribute.
3793  *
3794  * The @code ipp@ parameter refers to an IPP message previously created using
3795  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3796  *
3797  * The @code attr@ parameter may be modified as a result of setting the value.
3798  *
3799  * The @code element@ parameter specifies which value to set from 0 to
3800  * @link ippGetCount(attr)@.
3801  *
3802  * @since CUPS 1.6/macOS 10.8@
3803  */
3804 
3805 int					/* O  - 1 on success, 0 on failure */
ippSetDate(ipp_t * ipp,ipp_attribute_t ** attr,int element,const ipp_uchar_t * datevalue)3806 ippSetDate(ipp_t             *ipp,	/* I  - IPP message */
3807            ipp_attribute_t   **attr,	/* IO - IPP attribute */
3808            int               element,	/* I  - Value number (0-based) */
3809            const ipp_uchar_t *datevalue)/* I  - Date value */
3810 {
3811   _ipp_value_t	*value;			/* Current value */
3812 
3813 
3814  /*
3815   * Range check input...
3816   */
3817 
3818   if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_DATE ||
3819       element < 0 || element > (*attr)->num_values || !datevalue)
3820     return (0);
3821 
3822  /*
3823   * Set the value and return...
3824   */
3825 
3826   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3827     memcpy(value->date, datevalue, sizeof(value->date));
3828 
3829   return (value != NULL);
3830 }
3831 
3832 
3833 /*
3834  * 'ippSetGroupTag()' - Set the group tag of an attribute.
3835  *
3836  * The @code ipp@ parameter refers to an IPP message previously created using
3837  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3838  *
3839  * The @code attr@ parameter may be modified as a result of setting the value.
3840  *
3841  * The @code group@ parameter specifies the IPP attribute group tag: none
3842  * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
3843  * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
3844  * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
3845  * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
3846  *
3847  * @since CUPS 1.6/macOS 10.8@
3848  */
3849 
3850 int					/* O  - 1 on success, 0 on failure */
ippSetGroupTag(ipp_t * ipp,ipp_attribute_t ** attr,ipp_tag_t group_tag)3851 ippSetGroupTag(
3852     ipp_t           *ipp,		/* I  - IPP message */
3853     ipp_attribute_t **attr,		/* IO - Attribute */
3854     ipp_tag_t       group_tag)		/* I  - Group tag */
3855 {
3856  /*
3857   * Range check input - group tag must be 0x01 to 0x0F, per RFC 2911...
3858   */
3859 
3860   if (!ipp || !attr || !*attr ||
3861       group_tag < IPP_TAG_ZERO || group_tag == IPP_TAG_END ||
3862       group_tag >= IPP_TAG_UNSUPPORTED_VALUE)
3863     return (0);
3864 
3865  /*
3866   * Set the group tag and return...
3867   */
3868 
3869   (*attr)->group_tag = group_tag;
3870 
3871   return (1);
3872 }
3873 
3874 
3875 /*
3876  * 'ippSetInteger()' - Set an integer or enum value in an attribute.
3877  *
3878  * The @code ipp@ parameter refers to an IPP message previously created using
3879  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3880  *
3881  * The @code attr@ parameter may be modified as a result of setting the value.
3882  *
3883  * The @code element@ parameter specifies which value to set from 0 to
3884  * @link ippGetCount(attr)@.
3885  *
3886  * @since CUPS 1.6/macOS 10.8@
3887  */
3888 
3889 int					/* O  - 1 on success, 0 on failure */
ippSetInteger(ipp_t * ipp,ipp_attribute_t ** attr,int element,int intvalue)3890 ippSetInteger(ipp_t           *ipp,	/* I  - IPP message */
3891               ipp_attribute_t **attr,	/* IO - IPP attribute */
3892               int             element,	/* I  - Value number (0-based) */
3893               int             intvalue)	/* I  - Integer/enum value */
3894 {
3895   _ipp_value_t	*value;			/* Current value */
3896 
3897 
3898  /*
3899   * Range check input...
3900   */
3901 
3902   if (!ipp || !attr || !*attr ||
3903       ((*attr)->value_tag != IPP_TAG_INTEGER && (*attr)->value_tag != IPP_TAG_ENUM) ||
3904       element < 0 || element > (*attr)->num_values)
3905     return (0);
3906 
3907  /*
3908   * Set the value and return...
3909   */
3910 
3911   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3912     value->integer = intvalue;
3913 
3914   return (value != NULL);
3915 }
3916 
3917 
3918 /*
3919  * 'ippSetName()' - Set the name of an attribute.
3920  *
3921  * The @code ipp@ parameter refers to an IPP message previously created using
3922  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3923  *
3924  * The @code attr@ parameter may be modified as a result of setting the value.
3925  *
3926  * @since CUPS 1.6/macOS 10.8@
3927  */
3928 
3929 int					/* O  - 1 on success, 0 on failure */
ippSetName(ipp_t * ipp,ipp_attribute_t ** attr,const char * name)3930 ippSetName(ipp_t           *ipp,	/* I  - IPP message */
3931 	   ipp_attribute_t **attr,	/* IO - IPP attribute */
3932 	   const char      *name)	/* I  - Attribute name */
3933 {
3934   char	*temp;				/* Temporary name value */
3935 
3936 
3937  /*
3938   * Range check input...
3939   */
3940 
3941   if (!ipp || !attr || !*attr)
3942     return (0);
3943 
3944  /*
3945   * Set the value and return...
3946   */
3947 
3948   if ((temp = _cupsStrAlloc(name)) != NULL)
3949   {
3950     if ((*attr)->name)
3951       _cupsStrFree((*attr)->name);
3952 
3953     (*attr)->name = temp;
3954   }
3955 
3956   return (temp != NULL);
3957 }
3958 
3959 
3960 /*
3961  * 'ippSetOctetString()' - Set an octetString value in an IPP attribute.
3962  *
3963  * The @code ipp@ parameter refers to an IPP message previously created using
3964  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3965  *
3966  * The @code attr@ parameter may be modified as a result of setting the value.
3967  *
3968  * The @code element@ parameter specifies which value to set from 0 to
3969  * @link ippGetCount(attr)@.
3970  *
3971  * @since CUPS 1.7/macOS 10.9@
3972  */
3973 
3974 int					/* O  - 1 on success, 0 on failure */
ippSetOctetString(ipp_t * ipp,ipp_attribute_t ** attr,int element,const void * data,int datalen)3975 ippSetOctetString(
3976     ipp_t           *ipp,		/* I  - IPP message */
3977     ipp_attribute_t **attr,		/* IO - IPP attribute */
3978     int             element,		/* I  - Value number (0-based) */
3979     const void      *data,		/* I  - Pointer to octetString data */
3980     int             datalen)		/* I  - Length of octetString data */
3981 {
3982   _ipp_value_t	*value;			/* Current value */
3983 
3984 
3985  /*
3986   * Range check input...
3987   */
3988 
3989   if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_STRING ||
3990       element < 0 || element > (*attr)->num_values ||
3991       datalen < 0 || datalen > IPP_MAX_LENGTH)
3992     return (0);
3993 
3994  /*
3995   * Set the value and return...
3996   */
3997 
3998   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3999   {
4000     if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST)
4001     {
4002      /*
4003       * Just copy the pointer...
4004       */
4005 
4006       value->unknown.data   = (void *)data;
4007       value->unknown.length = datalen;
4008     }
4009     else
4010     {
4011      /*
4012       * Copy the data...
4013       */
4014 
4015       if (value->unknown.data)
4016       {
4017        /*
4018 	* Free previous data...
4019 	*/
4020 
4021 	free(value->unknown.data);
4022 
4023 	value->unknown.data   = NULL;
4024         value->unknown.length = 0;
4025       }
4026 
4027       if (datalen > 0)
4028       {
4029 	void	*temp;			/* Temporary data pointer */
4030 
4031 	if ((temp = malloc((size_t)datalen)) != NULL)
4032 	{
4033 	  memcpy(temp, data, (size_t)datalen);
4034 
4035 	  value->unknown.data   = temp;
4036 	  value->unknown.length = datalen;
4037 	}
4038 	else
4039 	  return (0);
4040       }
4041     }
4042   }
4043 
4044   return (value != NULL);
4045 }
4046 
4047 
4048 /*
4049  * 'ippSetOperation()' - Set the operation ID in an IPP request message.
4050  *
4051  * The @code ipp@ parameter refers to an IPP message previously created using
4052  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4053  *
4054  * @since CUPS 1.6/macOS 10.8@
4055  */
4056 
4057 int					/* O - 1 on success, 0 on failure */
ippSetOperation(ipp_t * ipp,ipp_op_t op)4058 ippSetOperation(ipp_t    *ipp,		/* I - IPP request message */
4059                 ipp_op_t op)		/* I - Operation ID */
4060 {
4061  /*
4062   * Range check input...
4063   */
4064 
4065   if (!ipp)
4066     return (0);
4067 
4068  /*
4069   * Set the operation and return...
4070   */
4071 
4072   ipp->request.op.operation_id = op;
4073 
4074   return (1);
4075 }
4076 
4077 
4078 /*
4079  * 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
4080  *
4081  * The @code ipp@ parameter refers to an IPP message previously created using
4082  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4083  *
4084  * The @code attr@ parameter may be modified as a result of setting the value.
4085  *
4086  * The @code element@ parameter specifies which value to set from 0 to
4087  * @link ippGetCount(attr)@.
4088  *
4089  * @since CUPS 1.6/macOS 10.8@
4090  */
4091 
4092 int					/* O  - 1 on success, 0 on failure */
ippSetRange(ipp_t * ipp,ipp_attribute_t ** attr,int element,int lowervalue,int uppervalue)4093 ippSetRange(ipp_t           *ipp,	/* I  - IPP message */
4094             ipp_attribute_t **attr,	/* IO - IPP attribute */
4095             int             element,	/* I  - Value number (0-based) */
4096 	    int             lowervalue,	/* I  - Lower bound for range */
4097 	    int             uppervalue)	/* I  - Upper bound for range */
4098 {
4099   _ipp_value_t	*value;			/* Current value */
4100 
4101 
4102  /*
4103   * Range check input...
4104   */
4105 
4106   if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_RANGE ||
4107       element < 0 || element > (*attr)->num_values || lowervalue > uppervalue)
4108     return (0);
4109 
4110  /*
4111   * Set the value and return...
4112   */
4113 
4114   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4115   {
4116     value->range.lower = lowervalue;
4117     value->range.upper = uppervalue;
4118   }
4119 
4120   return (value != NULL);
4121 }
4122 
4123 
4124 /*
4125  * 'ippSetRequestId()' - Set the request ID in an IPP message.
4126  *
4127  * The @code ipp@ parameter refers to an IPP message previously created using
4128  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4129  *
4130  * The @code request_id@ parameter must be greater than 0.
4131  *
4132  * @since CUPS 1.6/macOS 10.8@
4133  */
4134 
4135 int					/* O - 1 on success, 0 on failure */
ippSetRequestId(ipp_t * ipp,int request_id)4136 ippSetRequestId(ipp_t *ipp,		/* I - IPP message */
4137                 int   request_id)	/* I - Request ID */
4138 {
4139  /*
4140   * Range check input; not checking request_id values since ipptool wants to send
4141   * invalid values for conformance testing and a bad request_id does not affect the
4142   * encoding of a message...
4143   */
4144 
4145   if (!ipp)
4146     return (0);
4147 
4148  /*
4149   * Set the request ID and return...
4150   */
4151 
4152   ipp->request.any.request_id = request_id;
4153 
4154   return (1);
4155 }
4156 
4157 
4158 /*
4159  * 'ippSetResolution()' - Set a resolution value in an attribute.
4160  *
4161  * The @code ipp@ parameter refers to an IPP message previously created using
4162  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4163  *
4164  * The @code attr@ parameter may be modified as a result of setting the value.
4165  *
4166  * The @code element@ parameter specifies which value to set from 0 to
4167  * @link ippGetCount(attr)@.
4168  *
4169  * @since CUPS 1.6/macOS 10.8@
4170  */
4171 
4172 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)4173 ippSetResolution(
4174     ipp_t           *ipp,		/* I  - IPP message */
4175     ipp_attribute_t **attr,		/* IO - IPP attribute */
4176     int             element,		/* I  - Value number (0-based) */
4177     ipp_res_t       unitsvalue,		/* I  - Resolution units */
4178     int             xresvalue,		/* I  - Horizontal/cross feed resolution */
4179     int             yresvalue)		/* I  - Vertical/feed resolution */
4180 {
4181   _ipp_value_t	*value;			/* Current value */
4182 
4183 
4184  /*
4185   * Range check input...
4186   */
4187 
4188   if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_RESOLUTION ||
4189       element < 0 || element > (*attr)->num_values || xresvalue <= 0 || yresvalue <= 0 ||
4190       unitsvalue < IPP_RES_PER_INCH || unitsvalue > IPP_RES_PER_CM)
4191     return (0);
4192 
4193  /*
4194   * Set the value and return...
4195   */
4196 
4197   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4198   {
4199     value->resolution.units = unitsvalue;
4200     value->resolution.xres  = xresvalue;
4201     value->resolution.yres  = yresvalue;
4202   }
4203 
4204   return (value != NULL);
4205 }
4206 
4207 
4208 /*
4209  * 'ippSetState()' - Set the current state of the IPP message.
4210  *
4211  * @since CUPS 1.6/macOS 10.8@
4212  */
4213 
4214 int					/* O - 1 on success, 0 on failure */
ippSetState(ipp_t * ipp,ipp_state_t state)4215 ippSetState(ipp_t       *ipp,		/* I - IPP message */
4216             ipp_state_t state)		/* I - IPP state value */
4217 {
4218  /*
4219   * Range check input...
4220   */
4221 
4222   if (!ipp)
4223     return (0);
4224 
4225  /*
4226   * Set the state and return...
4227   */
4228 
4229   ipp->state   = state;
4230   ipp->current = NULL;
4231 
4232   return (1);
4233 }
4234 
4235 
4236 /*
4237  * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
4238  *
4239  * The @code ipp@ parameter refers to an IPP message previously created using
4240  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4241  *
4242  * @since CUPS 1.6/macOS 10.8@
4243  */
4244 
4245 int					/* O - 1 on success, 0 on failure */
ippSetStatusCode(ipp_t * ipp,ipp_status_t status)4246 ippSetStatusCode(ipp_t        *ipp,	/* I - IPP response or event message */
4247                  ipp_status_t status)	/* I - Status code */
4248 {
4249  /*
4250   * Range check input...
4251   */
4252 
4253   if (!ipp)
4254     return (0);
4255 
4256  /*
4257   * Set the status code and return...
4258   */
4259 
4260   ipp->request.status.status_code = status;
4261 
4262   return (1);
4263 }
4264 
4265 
4266 /*
4267  * 'ippSetString()' - Set a string value in an attribute.
4268  *
4269  * The @code ipp@ parameter refers to an IPP message previously created using
4270  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4271  *
4272  * The @code attr@ parameter may be modified as a result of setting the value.
4273  *
4274  * The @code element@ parameter specifies which value to set from 0 to
4275  * @link ippGetCount(attr)@.
4276  *
4277  * @since CUPS 1.6/macOS 10.8@
4278  */
4279 
4280 int					/* O  - 1 on success, 0 on failure */
ippSetString(ipp_t * ipp,ipp_attribute_t ** attr,int element,const char * strvalue)4281 ippSetString(ipp_t           *ipp,	/* I  - IPP message */
4282              ipp_attribute_t **attr,	/* IO - IPP attribute */
4283              int             element,	/* I  - Value number (0-based) */
4284 	     const char      *strvalue)	/* I  - String value */
4285 {
4286   char		*temp;			/* Temporary string */
4287   _ipp_value_t	*value;			/* Current value */
4288 
4289 
4290  /*
4291   * Range check input...
4292   */
4293 
4294   if (!ipp || !attr || !*attr ||
4295       ((*attr)->value_tag != IPP_TAG_TEXTLANG &&
4296       (*attr)->value_tag != IPP_TAG_NAMELANG &&
4297        ((*attr)->value_tag < IPP_TAG_TEXT ||
4298         (*attr)->value_tag > IPP_TAG_MIMETYPE)) ||
4299       element < 0 || element > (*attr)->num_values || !strvalue)
4300     return (0);
4301 
4302  /*
4303   * Set the value and return...
4304   */
4305 
4306   if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4307   {
4308     if (element > 0)
4309       value->string.language = (*attr)->values[0].string.language;
4310 
4311     if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST)
4312       value->string.text = (char *)strvalue;
4313     else if ((temp = _cupsStrAlloc(strvalue)) != NULL)
4314     {
4315       if (value->string.text)
4316         _cupsStrFree(value->string.text);
4317 
4318       value->string.text = temp;
4319     }
4320     else
4321       return (0);
4322   }
4323 
4324   return (value != NULL);
4325 }
4326 
4327 
4328 /*
4329  * 'ippSetStringf()' - Set a formatted string value of an attribute.
4330  *
4331  * The @code ipp@ parameter refers to an IPP message previously created using
4332  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4333  *
4334  * The @code attr@ parameter may be modified as a result of setting the value.
4335  *
4336  * The @code element@ parameter specifies which value to set from 0 to
4337  * @link ippGetCount(attr)@.
4338  *
4339  * The @code format@ parameter uses formatting characters compatible with the
4340  * printf family of standard functions.  Additional arguments follow it as
4341  * needed.  The formatted string is truncated as needed to the maximum length of
4342  * the corresponding value type.
4343  *
4344  * @since CUPS 1.7/macOS 10.9@
4345  */
4346 
4347 int					/* O  - 1 on success, 0 on failure */
ippSetStringf(ipp_t * ipp,ipp_attribute_t ** attr,int element,const char * format,...)4348 ippSetStringf(ipp_t           *ipp,	/* I  - IPP message */
4349               ipp_attribute_t **attr,	/* IO - IPP attribute */
4350               int             element,	/* I  - Value number (0-based) */
4351 	      const char      *format,	/* I  - Printf-style format string */
4352 	      ...)			/* I  - Additional arguments as needed */
4353 {
4354   int		ret;			/* Return value */
4355   va_list	ap;			/* Pointer to additional arguments */
4356 
4357 
4358   va_start(ap, format);
4359   ret = ippSetStringfv(ipp, attr, element, format, ap);
4360   va_end(ap);
4361 
4362   return (ret);
4363 }
4364 
4365 
4366 /*
4367  * 'ippSetStringf()' - Set a formatted string value of an attribute.
4368  *
4369  * The @code ipp@ parameter refers to an IPP message previously created using
4370  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4371  *
4372  * The @code attr@ parameter may be modified as a result of setting the value.
4373  *
4374  * The @code element@ parameter specifies which value to set from 0 to
4375  * @link ippGetCount(attr)@.
4376  *
4377  * The @code format@ parameter uses formatting characters compatible with the
4378  * printf family of standard functions.  Additional arguments follow it as
4379  * needed.  The formatted string is truncated as needed to the maximum length of
4380  * the corresponding value type.
4381  *
4382  * @since CUPS 1.7/macOS 10.9@
4383  */
4384 
4385 int					/* O  - 1 on success, 0 on failure */
ippSetStringfv(ipp_t * ipp,ipp_attribute_t ** attr,int element,const char * format,va_list ap)4386 ippSetStringfv(ipp_t           *ipp,	/* I  - IPP message */
4387                ipp_attribute_t **attr,	/* IO - IPP attribute */
4388                int             element,	/* I  - Value number (0-based) */
4389 	       const char      *format,	/* I  - Printf-style format string */
4390 	       va_list         ap)	/* I  - Pointer to additional arguments */
4391 {
4392   ipp_tag_t	value_tag;		/* Value tag */
4393   char		buffer[IPP_MAX_TEXT + 4];
4394 					/* Formatted text string */
4395   ssize_t	bytes,			/* Length of formatted value */
4396 		max_bytes;		/* Maximum number of bytes for value */
4397 
4398 
4399  /*
4400   * Range check input...
4401   */
4402 
4403   if (attr && *attr)
4404     value_tag = (*attr)->value_tag & IPP_TAG_CUPS_MASK;
4405   else
4406     value_tag = IPP_TAG_ZERO;
4407 
4408   if (!ipp || !attr || !*attr ||
4409       (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG &&
4410        value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE ||
4411       !format)
4412     return (0);
4413 
4414  /*
4415   * Format the string...
4416   */
4417 
4418   if (!strcmp(format, "%s"))
4419   {
4420    /*
4421     * Optimize the simple case...
4422     */
4423 
4424     const char *s = va_arg(ap, char *);
4425 
4426     if (!s)
4427       s = "(null)";
4428 
4429     bytes = (ssize_t)strlen(s);
4430     strlcpy(buffer, s, sizeof(buffer));
4431   }
4432   else
4433   {
4434    /*
4435     * Do a full formatting of the message...
4436     */
4437 
4438     if ((bytes = vsnprintf(buffer, sizeof(buffer), format, ap)) < 0)
4439       return (0);
4440   }
4441 
4442  /*
4443   * Limit the length of the string...
4444   */
4445 
4446   switch (value_tag)
4447   {
4448     default :
4449     case IPP_TAG_TEXT :
4450     case IPP_TAG_TEXTLANG :
4451         max_bytes = IPP_MAX_TEXT;
4452         break;
4453 
4454     case IPP_TAG_NAME :
4455     case IPP_TAG_NAMELANG :
4456         max_bytes = IPP_MAX_NAME;
4457         break;
4458 
4459     case IPP_TAG_CHARSET :
4460         max_bytes = IPP_MAX_CHARSET;
4461         break;
4462 
4463     case IPP_TAG_KEYWORD :
4464         max_bytes = IPP_MAX_KEYWORD;
4465         break;
4466 
4467     case IPP_TAG_LANGUAGE :
4468         max_bytes = IPP_MAX_LANGUAGE;
4469         break;
4470 
4471     case IPP_TAG_MIMETYPE :
4472         max_bytes = IPP_MAX_MIMETYPE;
4473         break;
4474 
4475     case IPP_TAG_URI :
4476         max_bytes = IPP_MAX_URI;
4477         break;
4478 
4479     case IPP_TAG_URISCHEME :
4480         max_bytes = IPP_MAX_URISCHEME;
4481         break;
4482   }
4483 
4484   if (bytes >= max_bytes)
4485   {
4486     char	*bufmax,		/* Buffer at max_bytes */
4487 		*bufptr;		/* Pointer into buffer */
4488 
4489     bufptr = buffer + strlen(buffer) - 1;
4490     bufmax = buffer + max_bytes - 1;
4491 
4492     while (bufptr > bufmax)
4493     {
4494       if (*bufptr & 0x80)
4495       {
4496         while ((*bufptr & 0xc0) == 0x80 && bufptr > buffer)
4497           bufptr --;
4498       }
4499 
4500       bufptr --;
4501     }
4502 
4503     *bufptr = '\0';
4504   }
4505 
4506  /*
4507   * Set the formatted string and return...
4508   */
4509 
4510   return (ippSetString(ipp, attr, element, buffer));
4511 }
4512 
4513 
4514 /*
4515  * 'ippSetValueTag()' - Set the value tag of an attribute.
4516  *
4517  * The @code ipp@ parameter refers to an IPP message previously created using
4518  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4519  *
4520  * The @code attr@ parameter may be modified as a result of setting the value.
4521  *
4522  * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger
4523  * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name
4524  * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text
4525  * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage
4526  * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various
4527  * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes
4528  * will be rejected.
4529  *
4530  * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language
4531  * code in the "attributes-natural-language" attribute or, if not present, the language
4532  * code for the current locale.
4533  *
4534  * @since CUPS 1.6/macOS 10.8@
4535  */
4536 
4537 int					/* O  - 1 on success, 0 on failure */
ippSetValueTag(ipp_t * ipp,ipp_attribute_t ** attr,ipp_tag_t value_tag)4538 ippSetValueTag(
4539     ipp_t          *ipp,		/* I  - IPP message */
4540     ipp_attribute_t **attr,		/* IO - IPP attribute */
4541     ipp_tag_t       value_tag)		/* I  - Value tag */
4542 {
4543   int		i;			/* Looping var */
4544   _ipp_value_t	*value;			/* Current value */
4545   int		integer;		/* Current integer value */
4546   cups_lang_t	*language;		/* Current language */
4547   char		code[32];		/* Language code */
4548   ipp_tag_t	temp_tag;		/* Temporary value tag */
4549 
4550 
4551  /*
4552   * Range check input...
4553   */
4554 
4555   if (!ipp || !attr || !*attr)
4556     return (0);
4557 
4558  /*
4559   * If there is no change, return immediately...
4560   */
4561 
4562   if (value_tag == (*attr)->value_tag)
4563     return (1);
4564 
4565  /*
4566   * Otherwise implement changes as needed...
4567   */
4568 
4569   temp_tag = (ipp_tag_t)((int)((*attr)->value_tag) & IPP_TAG_CUPS_MASK);
4570 
4571   switch (value_tag)
4572   {
4573     case IPP_TAG_UNSUPPORTED_VALUE :
4574     case IPP_TAG_DEFAULT :
4575     case IPP_TAG_UNKNOWN :
4576     case IPP_TAG_NOVALUE :
4577     case IPP_TAG_NOTSETTABLE :
4578     case IPP_TAG_DELETEATTR :
4579     case IPP_TAG_ADMINDEFINE :
4580        /*
4581         * Free any existing values...
4582         */
4583 
4584         if ((*attr)->num_values > 0)
4585           ipp_free_values(*attr, 0, (*attr)->num_values);
4586 
4587        /*
4588         * Set out-of-band value...
4589         */
4590 
4591         (*attr)->value_tag = value_tag;
4592         break;
4593 
4594     case IPP_TAG_RANGE :
4595         if (temp_tag != IPP_TAG_INTEGER)
4596           return (0);
4597 
4598         for (i = (*attr)->num_values, value = (*attr)->values;
4599              i > 0;
4600              i --, value ++)
4601         {
4602           integer            = value->integer;
4603           value->range.lower = value->range.upper = integer;
4604         }
4605 
4606         (*attr)->value_tag = IPP_TAG_RANGE;
4607         break;
4608 
4609     case IPP_TAG_NAME :
4610         if (temp_tag != IPP_TAG_KEYWORD && temp_tag != IPP_TAG_URI &&
4611             temp_tag != IPP_TAG_URISCHEME && temp_tag != IPP_TAG_LANGUAGE &&
4612             temp_tag != IPP_TAG_MIMETYPE)
4613           return (0);
4614 
4615         (*attr)->value_tag = (ipp_tag_t)(IPP_TAG_NAME | ((*attr)->value_tag & IPP_TAG_CUPS_CONST));
4616         break;
4617 
4618     case IPP_TAG_NAMELANG :
4619     case IPP_TAG_TEXTLANG :
4620         if (value_tag == IPP_TAG_NAMELANG &&
4621             (temp_tag != IPP_TAG_NAME && temp_tag != IPP_TAG_KEYWORD &&
4622              temp_tag != IPP_TAG_URI && temp_tag != IPP_TAG_URISCHEME &&
4623              temp_tag != IPP_TAG_LANGUAGE && temp_tag != IPP_TAG_MIMETYPE))
4624           return (0);
4625 
4626         if (value_tag == IPP_TAG_TEXTLANG && temp_tag != IPP_TAG_TEXT)
4627           return (0);
4628 
4629         if (ipp->attrs && ipp->attrs->next && ipp->attrs->next->name &&
4630             !strcmp(ipp->attrs->next->name, "attributes-natural-language"))
4631         {
4632          /*
4633           * Use the language code from the IPP message...
4634           */
4635 
4636 	  (*attr)->values[0].string.language =
4637 	      _cupsStrAlloc(ipp->attrs->next->values[0].string.text);
4638         }
4639         else
4640         {
4641          /*
4642           * Otherwise, use the language code corresponding to the locale...
4643           */
4644 
4645 	  language = cupsLangDefault();
4646 	  (*attr)->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language->language,
4647 									code,
4648 									sizeof(code)));
4649         }
4650 
4651         for (i = (*attr)->num_values - 1, value = (*attr)->values + 1;
4652              i > 0;
4653              i --, value ++)
4654           value->string.language = (*attr)->values[0].string.language;
4655 
4656         if ((int)(*attr)->value_tag & IPP_TAG_CUPS_CONST)
4657         {
4658          /*
4659           * Make copies of all values...
4660           */
4661 
4662 	  for (i = (*attr)->num_values, value = (*attr)->values;
4663 	       i > 0;
4664 	       i --, value ++)
4665 	    value->string.text = _cupsStrAlloc(value->string.text);
4666         }
4667 
4668         (*attr)->value_tag = IPP_TAG_NAMELANG;
4669         break;
4670 
4671     case IPP_TAG_KEYWORD :
4672         if (temp_tag == IPP_TAG_NAME || temp_tag == IPP_TAG_NAMELANG)
4673           break;			/* Silently "allow" name -> keyword */
4674 
4675     default :
4676         return (0);
4677   }
4678 
4679   return (1);
4680 }
4681 
4682 
4683 /*
4684  * 'ippSetVersion()' - Set the version number in an IPP message.
4685  *
4686  * The @code ipp@ parameter refers to an IPP message previously created using
4687  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
4688  *
4689  * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
4690  *
4691  * @since CUPS 1.6/macOS 10.8@
4692  */
4693 
4694 int					/* O - 1 on success, 0 on failure */
ippSetVersion(ipp_t * ipp,int major,int minor)4695 ippSetVersion(ipp_t *ipp,		/* I - IPP message */
4696               int   major,		/* I - Major version number (major.minor) */
4697               int   minor)		/* I - Minor version number (major.minor) */
4698 {
4699  /*
4700   * Range check input...
4701   */
4702 
4703   if (!ipp || major < 0 || minor < 0)
4704     return (0);
4705 
4706  /*
4707   * Set the version number...
4708   */
4709 
4710   ipp->request.any.version[0] = (ipp_uchar_t)major;
4711   ipp->request.any.version[1] = (ipp_uchar_t)minor;
4712 
4713   return (1);
4714 }
4715 
4716 
4717 /*
4718  * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
4719  */
4720 
4721 const ipp_uchar_t *			/* O - RFC-1903 date/time data */
ippTimeToDate(time_t t)4722 ippTimeToDate(time_t t)			/* I - UNIX time value */
4723 {
4724   struct tm	*unixdate;		/* UNIX unixdate/time info */
4725   ipp_uchar_t	*date = _cupsGlobals()->ipp_date;
4726 					/* RFC-1903 date/time data */
4727 
4728 
4729  /*
4730   * RFC-1903 date/time format is:
4731   *
4732   *    Byte(s)  Description
4733   *    -------  -----------
4734   *    0-1      Year (0 to 65535)
4735   *    2        Month (1 to 12)
4736   *    3        Day (1 to 31)
4737   *    4        Hours (0 to 23)
4738   *    5        Minutes (0 to 59)
4739   *    6        Seconds (0 to 60, 60 = "leap second")
4740   *    7        Deciseconds (0 to 9)
4741   *    8        +/- UTC
4742   *    9        UTC hours (0 to 11)
4743   *    10       UTC minutes (0 to 59)
4744   */
4745 
4746   unixdate = gmtime(&t);
4747   unixdate->tm_year += 1900;
4748 
4749   date[0]  = (ipp_uchar_t)(unixdate->tm_year >> 8);
4750   date[1]  = (ipp_uchar_t)(unixdate->tm_year);
4751   date[2]  = (ipp_uchar_t)(unixdate->tm_mon + 1);
4752   date[3]  = (ipp_uchar_t)unixdate->tm_mday;
4753   date[4]  = (ipp_uchar_t)unixdate->tm_hour;
4754   date[5]  = (ipp_uchar_t)unixdate->tm_min;
4755   date[6]  = (ipp_uchar_t)unixdate->tm_sec;
4756   date[7]  = 0;
4757   date[8]  = '+';
4758   date[9]  = 0;
4759   date[10] = 0;
4760 
4761   return (date);
4762 }
4763 
4764 
4765 /*
4766  * 'ippValidateAttribute()' - Validate the contents of an attribute.
4767  *
4768  * This function validates the contents of an attribute based on the name and
4769  * value tag.  1 is returned if the attribute is valid, 0 otherwise.  On
4770  * failure, cupsLastErrorString() is set to a human-readable message.
4771  *
4772  * @since CUPS 1.7/macOS 10.9@
4773  */
4774 
4775 int					/* O - 1 if valid, 0 otherwise */
ippValidateAttribute(ipp_attribute_t * attr)4776 ippValidateAttribute(
4777     ipp_attribute_t *attr)		/* I - Attribute */
4778 {
4779   int		i;			/* Looping var */
4780   char		scheme[64],		/* Scheme from URI */
4781 		userpass[256],		/* Username/password from URI */
4782 		hostname[256],		/* Hostname from URI */
4783 		resource[1024];		/* Resource from URI */
4784   int		port,			/* Port number from URI */
4785 		uri_status;		/* URI separation status */
4786   const char	*ptr;			/* Pointer into string */
4787   ipp_attribute_t *colattr;		/* Collection attribute */
4788   regex_t	re;			/* Regular expression */
4789   ipp_uchar_t	*date;			/* Current date value */
4790   static const char * const uri_status_strings[] =
4791   {					/* URI status strings */
4792     "URI too large",
4793     "Bad arguments to function",
4794     "Bad resource in URI",
4795     "Bad port number in URI",
4796     "Bad hostname/address in URI",
4797     "Bad username in URI",
4798     "Bad scheme in URI",
4799     "Bad/empty URI",
4800     "OK",
4801     "Missing scheme in URI",
4802     "Unknown scheme in URI",
4803     "Missing resource in URI"
4804   };
4805 
4806 
4807  /*
4808   * Skip separators.
4809   */
4810 
4811   if (!attr->name)
4812     return (1);
4813 
4814  /*
4815   * Validate the attribute name.
4816   */
4817 
4818   for (ptr = attr->name; *ptr; ptr ++)
4819     if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' && *ptr != '_')
4820       break;
4821 
4822   if (*ptr || ptr == attr->name)
4823   {
4824     ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4825                   _("\"%s\": Bad attribute name - invalid character "
4826 		    "(RFC 2911 section 4.1.3)."), attr->name);
4827     return (0);
4828   }
4829 
4830   if ((ptr - attr->name) > 255)
4831   {
4832     ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4833                   _("\"%s\": Bad attribute name - bad length %d "
4834 		    "(RFC 2911 section 4.1.3)."), attr->name,
4835 		  (int)(ptr - attr->name));
4836     return (0);
4837   }
4838 
4839   switch (attr->value_tag)
4840   {
4841     case IPP_TAG_INTEGER :
4842         break;
4843 
4844     case IPP_TAG_BOOLEAN :
4845         for (i = 0; i < attr->num_values; i ++)
4846 	{
4847 	  if (attr->values[i].boolean != 0 &&
4848 	      attr->values[i].boolean != 1)
4849 	  {
4850 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4851                           _("\"%s\": Bad boolen value %d "
4852 			    "(RFC 2911 section 4.1.11)."), attr->name,
4853 			  attr->values[i].boolean);
4854 	    return (0);
4855 	  }
4856 	}
4857         break;
4858 
4859     case IPP_TAG_ENUM :
4860         for (i = 0; i < attr->num_values; i ++)
4861 	{
4862 	  if (attr->values[i].integer < 1)
4863 	  {
4864 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4865 			  _("\"%s\": Bad enum value %d - out of range "
4866 			    "(RFC 2911 section 4.1.4)."), attr->name,
4867 			    attr->values[i].integer);
4868             return (0);
4869 	  }
4870 	}
4871         break;
4872 
4873     case IPP_TAG_STRING :
4874         for (i = 0; i < attr->num_values; i ++)
4875 	{
4876 	  if (attr->values[i].unknown.length > IPP_MAX_OCTETSTRING)
4877 	  {
4878 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4879 			  _("\"%s\": Bad octetString value - bad length %d "
4880 			    "(RFC 2911 section 4.1.10)."), attr->name,
4881 			    attr->values[i].unknown.length);
4882 	    return (0);
4883 	  }
4884 	}
4885         break;
4886 
4887     case IPP_TAG_DATE :
4888         for (i = 0; i < attr->num_values; i ++)
4889 	{
4890 	  date = attr->values[i].date;
4891 
4892           if (date[2] < 1 || date[2] > 12)
4893 	  {
4894 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4895 			  _("\"%s\": Bad dateTime month %u "
4896 			    "(RFC 2911 section 4.1.14)."), attr->name, date[2]);
4897 	    return (0);
4898 	  }
4899 
4900           if (date[3] < 1 || date[3] > 31)
4901 	  {
4902 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4903 			  _("\"%s\": Bad dateTime day %u "
4904 			    "(RFC 2911 section 4.1.14)."), attr->name, date[3]);
4905 	    return (0);
4906 	  }
4907 
4908           if (date[4] > 23)
4909 	  {
4910 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4911 			  _("\"%s\": Bad dateTime hours %u "
4912 			    "(RFC 2911 section 4.1.14)."), attr->name, date[4]);
4913 	    return (0);
4914 	  }
4915 
4916           if (date[5] > 59)
4917 	  {
4918 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4919 			  _("\"%s\": Bad dateTime minutes %u "
4920 			    "(RFC 2911 section 4.1.14)."), attr->name, date[5]);
4921 	    return (0);
4922 	  }
4923 
4924           if (date[6] > 60)
4925 	  {
4926 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4927 			  _("\"%s\": Bad dateTime seconds %u "
4928 			    "(RFC 2911 section 4.1.14)."), attr->name, date[6]);
4929 	    return (0);
4930 	  }
4931 
4932           if (date[7] > 9)
4933 	  {
4934 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4935 			  _("\"%s\": Bad dateTime deciseconds %u "
4936 			    "(RFC 2911 section 4.1.14)."), attr->name, date[7]);
4937 	    return (0);
4938 	  }
4939 
4940           if (date[8] != '-' && date[8] != '+')
4941 	  {
4942 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4943 			  _("\"%s\": Bad dateTime UTC sign '%c' "
4944 			    "(RFC 2911 section 4.1.14)."), attr->name, date[8]);
4945 	    return (0);
4946 	  }
4947 
4948           if (date[9] > 11)
4949 	  {
4950 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4951 			  _("\"%s\": Bad dateTime UTC hours %u "
4952 			    "(RFC 2911 section 4.1.14)."), attr->name, date[9]);
4953 	    return (0);
4954 	  }
4955 
4956           if (date[10] > 59)
4957 	  {
4958 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4959 			  _("\"%s\": Bad dateTime UTC minutes %u "
4960 			    "(RFC 2911 section 4.1.14)."), attr->name, date[10]);
4961 	    return (0);
4962 	  }
4963 	}
4964         break;
4965 
4966     case IPP_TAG_RESOLUTION :
4967         for (i = 0; i < attr->num_values; i ++)
4968 	{
4969 	  if (attr->values[i].resolution.xres <= 0)
4970 	  {
4971 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4972 			  _("\"%s\": Bad resolution value %dx%d%s - cross "
4973 			    "feed resolution must be positive "
4974 			    "(RFC 2911 section 4.1.15)."), attr->name,
4975 			  attr->values[i].resolution.xres,
4976 			  attr->values[i].resolution.yres,
4977 			  attr->values[i].resolution.units ==
4978 			      IPP_RES_PER_INCH ? "dpi" :
4979 			      attr->values[i].resolution.units ==
4980 				  IPP_RES_PER_CM ? "dpcm" : "unknown");
4981 	    return (0);
4982 	  }
4983 
4984 	  if (attr->values[i].resolution.yres <= 0)
4985 	  {
4986 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4987 			  _("\"%s\": Bad resolution value %dx%d%s - feed "
4988 			    "resolution must be positive "
4989 			    "(RFC 2911 section 4.1.15)."), attr->name,
4990 			  attr->values[i].resolution.xres,
4991 			  attr->values[i].resolution.yres,
4992 			  attr->values[i].resolution.units ==
4993 			      IPP_RES_PER_INCH ? "dpi" :
4994 			      attr->values[i].resolution.units ==
4995 				  IPP_RES_PER_CM ? "dpcm" : "unknown");
4996             return (0);
4997 	  }
4998 
4999 	  if (attr->values[i].resolution.units != IPP_RES_PER_INCH &&
5000 	      attr->values[i].resolution.units != IPP_RES_PER_CM)
5001 	  {
5002 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5003 			  _("\"%s\": Bad resolution value %dx%d%s - bad "
5004 			    "units value (RFC 2911 section 4.1.15)."),
5005 			  attr->name, attr->values[i].resolution.xres,
5006 			  attr->values[i].resolution.yres,
5007 			  attr->values[i].resolution.units ==
5008 			      IPP_RES_PER_INCH ? "dpi" :
5009 			      attr->values[i].resolution.units ==
5010 				  IPP_RES_PER_CM ? "dpcm" : "unknown");
5011 	    return (0);
5012 	  }
5013 	}
5014         break;
5015 
5016     case IPP_TAG_RANGE :
5017         for (i = 0; i < attr->num_values; i ++)
5018 	{
5019 	  if (attr->values[i].range.lower > attr->values[i].range.upper)
5020 	  {
5021 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5022 			  _("\"%s\": Bad rangeOfInteger value %d-%d - lower "
5023 			    "greater than upper (RFC 2911 section 4.1.13)."),
5024 			  attr->name, attr->values[i].range.lower,
5025 			  attr->values[i].range.upper);
5026 	    return (0);
5027 	  }
5028 	}
5029         break;
5030 
5031     case IPP_TAG_BEGIN_COLLECTION :
5032         for (i = 0; i < attr->num_values; i ++)
5033 	{
5034 	  for (colattr = attr->values[i].collection->attrs;
5035 	       colattr;
5036 	       colattr = colattr->next)
5037 	  {
5038 	    if (!ippValidateAttribute(colattr))
5039 	      return (0);
5040 	  }
5041 	}
5042         break;
5043 
5044     case IPP_TAG_TEXT :
5045     case IPP_TAG_TEXTLANG :
5046         for (i = 0; i < attr->num_values; i ++)
5047 	{
5048 	  for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5049 	  {
5050 	    if ((*ptr & 0xe0) == 0xc0)
5051 	    {
5052 	      ptr ++;
5053 	      if ((*ptr & 0xc0) != 0x80)
5054 	        break;
5055 	    }
5056 	    else if ((*ptr & 0xf0) == 0xe0)
5057 	    {
5058 	      ptr ++;
5059 	      if ((*ptr & 0xc0) != 0x80)
5060 	        break;
5061 	      ptr ++;
5062 	      if ((*ptr & 0xc0) != 0x80)
5063 	        break;
5064 	    }
5065 	    else if ((*ptr & 0xf8) == 0xf0)
5066 	    {
5067 	      ptr ++;
5068 	      if ((*ptr & 0xc0) != 0x80)
5069 	        break;
5070 	      ptr ++;
5071 	      if ((*ptr & 0xc0) != 0x80)
5072 	        break;
5073 	      ptr ++;
5074 	      if ((*ptr & 0xc0) != 0x80)
5075 	        break;
5076 	    }
5077 	    else if (*ptr & 0x80)
5078 	      break;
5079 	  }
5080 
5081 	  if (*ptr)
5082 	  {
5083 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5084 			  _("\"%s\": Bad text value \"%s\" - bad UTF-8 "
5085 			    "sequence (RFC 2911 section 4.1.1)."), attr->name,
5086 			  attr->values[i].string.text);
5087 	    return (0);
5088 	  }
5089 
5090 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_TEXT - 1))
5091 	  {
5092 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5093 			  _("\"%s\": Bad text value \"%s\" - bad length %d "
5094 			    "(RFC 2911 section 4.1.1)."), attr->name,
5095 			  attr->values[i].string.text,
5096 			  (int)(ptr - attr->values[i].string.text));
5097 	    return (0);
5098 	  }
5099 	}
5100         break;
5101 
5102     case IPP_TAG_NAME :
5103     case IPP_TAG_NAMELANG :
5104         for (i = 0; i < attr->num_values; i ++)
5105 	{
5106 	  for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5107 	  {
5108 	    if ((*ptr & 0xe0) == 0xc0)
5109 	    {
5110 	      ptr ++;
5111 	      if ((*ptr & 0xc0) != 0x80)
5112 	        break;
5113 	    }
5114 	    else if ((*ptr & 0xf0) == 0xe0)
5115 	    {
5116 	      ptr ++;
5117 	      if ((*ptr & 0xc0) != 0x80)
5118 	        break;
5119 	      ptr ++;
5120 	      if ((*ptr & 0xc0) != 0x80)
5121 	        break;
5122 	    }
5123 	    else if ((*ptr & 0xf8) == 0xf0)
5124 	    {
5125 	      ptr ++;
5126 	      if ((*ptr & 0xc0) != 0x80)
5127 	        break;
5128 	      ptr ++;
5129 	      if ((*ptr & 0xc0) != 0x80)
5130 	        break;
5131 	      ptr ++;
5132 	      if ((*ptr & 0xc0) != 0x80)
5133 	        break;
5134 	    }
5135 	    else if (*ptr & 0x80)
5136 	      break;
5137 	  }
5138 
5139 	  if (*ptr)
5140 	  {
5141 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5142 			  _("\"%s\": Bad name value \"%s\" - bad UTF-8 "
5143 			    "sequence (RFC 2911 section 4.1.2)."), attr->name,
5144 			  attr->values[i].string.text);
5145 	    return (0);
5146 	  }
5147 
5148 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_NAME - 1))
5149 	  {
5150 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5151 			  _("\"%s\": Bad name value \"%s\" - bad length %d "
5152 			    "(RFC 2911 section 4.1.2)."), attr->name,
5153 			  attr->values[i].string.text,
5154 			  (int)(ptr - attr->values[i].string.text));
5155 	    return (0);
5156 	  }
5157 	}
5158         break;
5159 
5160     case IPP_TAG_KEYWORD :
5161         for (i = 0; i < attr->num_values; i ++)
5162 	{
5163 	  for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5164 	    if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' &&
5165 	        *ptr != '_')
5166 	      break;
5167 
5168 	  if (*ptr || ptr == attr->values[i].string.text)
5169 	  {
5170 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5171 			  _("\"%s\": Bad keyword value \"%s\" - invalid "
5172 			    "character (RFC 2911 section 4.1.3)."),
5173 			  attr->name, attr->values[i].string.text);
5174 	    return (0);
5175 	  }
5176 
5177 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_KEYWORD - 1))
5178 	  {
5179 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5180 			  _("\"%s\": Bad keyword value \"%s\" - bad "
5181 			    "length %d (RFC 2911 section 4.1.3)."),
5182 			  attr->name, attr->values[i].string.text,
5183 			  (int)(ptr - attr->values[i].string.text));
5184 	    return (0);
5185 	  }
5186 	}
5187         break;
5188 
5189     case IPP_TAG_URI :
5190         for (i = 0; i < attr->num_values; i ++)
5191 	{
5192 	  uri_status = httpSeparateURI(HTTP_URI_CODING_ALL,
5193 	                               attr->values[i].string.text,
5194 				       scheme, sizeof(scheme),
5195 				       userpass, sizeof(userpass),
5196 				       hostname, sizeof(hostname),
5197 				       &port, resource, sizeof(resource));
5198 
5199 	  if (uri_status < HTTP_URI_STATUS_OK)
5200 	  {
5201 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5202 			  _("\"%s\": Bad URI value \"%s\" - %s "
5203 			    "(RFC 2911 section 4.1.5)."), attr->name,
5204 			  attr->values[i].string.text,
5205 			  uri_status_strings[uri_status -
5206 					     HTTP_URI_STATUS_OVERFLOW]);
5207 	    return (0);
5208 	  }
5209 
5210 	  if (strlen(attr->values[i].string.text) > (IPP_MAX_URI - 1))
5211 	  {
5212 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5213 			  _("\"%s\": Bad URI value \"%s\" - bad length %d "
5214 			    "(RFC 2911 section 4.1.5)."), attr->name,
5215 			  attr->values[i].string.text,
5216 			  (int)strlen(attr->values[i].string.text));
5217 	  }
5218 	}
5219         break;
5220 
5221     case IPP_TAG_URISCHEME :
5222         for (i = 0; i < attr->num_values; i ++)
5223 	{
5224 	  ptr = attr->values[i].string.text;
5225 	  if (islower(*ptr & 255))
5226 	  {
5227 	    for (ptr ++; *ptr; ptr ++)
5228 	      if (!islower(*ptr & 255) && !isdigit(*ptr & 255) &&
5229 	          *ptr != '+' && *ptr != '-' && *ptr != '.')
5230                 break;
5231 	  }
5232 
5233 	  if (*ptr || ptr == attr->values[i].string.text)
5234 	  {
5235 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5236 			  _("\"%s\": Bad uriScheme value \"%s\" - bad "
5237 			    "characters (RFC 2911 section 4.1.6)."),
5238 			  attr->name, attr->values[i].string.text);
5239 	    return (0);
5240 	  }
5241 
5242 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_URISCHEME - 1))
5243 	  {
5244 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5245 			  _("\"%s\": Bad uriScheme value \"%s\" - bad "
5246 			    "length %d (RFC 2911 section 4.1.6)."),
5247 			  attr->name, attr->values[i].string.text,
5248 			  (int)(ptr - attr->values[i].string.text));
5249 	    return (0);
5250 	  }
5251 	}
5252         break;
5253 
5254     case IPP_TAG_CHARSET :
5255         for (i = 0; i < attr->num_values; i ++)
5256 	{
5257 	  for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5258 	    if (!isprint(*ptr & 255) || isupper(*ptr & 255) ||
5259 	        isspace(*ptr & 255))
5260 	      break;
5261 
5262 	  if (*ptr || ptr == attr->values[i].string.text)
5263 	  {
5264 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5265 			  _("\"%s\": Bad charset value \"%s\" - bad "
5266 			    "characters (RFC 2911 section 4.1.7)."),
5267 			  attr->name, attr->values[i].string.text);
5268 	    return (0);
5269 	  }
5270 
5271 	  if ((ptr - attr->values[i].string.text) > (IPP_MAX_CHARSET - 1))
5272 	  {
5273 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5274 			  _("\"%s\": Bad charset value \"%s\" - bad "
5275 			    "length %d (RFC 2911 section 4.1.7)."),
5276 			  attr->name, attr->values[i].string.text,
5277 			  (int)(ptr - attr->values[i].string.text));
5278 	    return (0);
5279 	  }
5280 	}
5281         break;
5282 
5283     case IPP_TAG_LANGUAGE :
5284        /*
5285         * The following regular expression is derived from the ABNF for
5286 	* language tags in RFC 4646.  All I can say is that this is the
5287 	* easiest way to check the values...
5288 	*/
5289 
5290         if ((i = regcomp(&re,
5291 			 "^("
5292 			 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
5293 								/* language */
5294 			 "(-[a-z][a-z][a-z][a-z]){0,1}"		/* script */
5295 			 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}"	/* region */
5296 			 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*"	/* variant */
5297 			 "(-[a-wy-z](-[a-z0-9]{2,8})+)*"	/* extension */
5298 			 "(-x(-[a-z0-9]{1,8})+)*"		/* privateuse */
5299 			 "|"
5300 			 "x(-[a-z0-9]{1,8})+"			/* privateuse */
5301 			 "|"
5302 			 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}"	/* grandfathered */
5303 			 ")$",
5304 			 REG_NOSUB | REG_EXTENDED)) != 0)
5305         {
5306           char	temp[256];		/* Temporary error string */
5307 
5308           regerror(i, &re, temp, sizeof(temp));
5309 	  ipp_set_error(IPP_STATUS_ERROR_INTERNAL,
5310 			_("Unable to compile naturalLanguage regular "
5311 			  "expression: %s."), temp);
5312 	  return (0);
5313         }
5314 
5315         for (i = 0; i < attr->num_values; i ++)
5316 	{
5317 	  if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
5318 	  {
5319 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5320 			  _("\"%s\": Bad naturalLanguage value \"%s\" - bad "
5321 			    "characters (RFC 2911 section 4.1.8)."),
5322 			  attr->name, attr->values[i].string.text);
5323 	    regfree(&re);
5324 	    return (0);
5325 	  }
5326 
5327 	  if (strlen(attr->values[i].string.text) > (IPP_MAX_LANGUAGE - 1))
5328 	  {
5329 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5330 			  _("\"%s\": Bad naturalLanguage value \"%s\" - bad "
5331 			    "length %d (RFC 2911 section 4.1.8)."),
5332 			  attr->name, attr->values[i].string.text,
5333 			  (int)strlen(attr->values[i].string.text));
5334 	    regfree(&re);
5335 	    return (0);
5336 	  }
5337 	}
5338 
5339 	regfree(&re);
5340         break;
5341 
5342     case IPP_TAG_MIMETYPE :
5343        /*
5344         * The following regular expression is derived from the ABNF for
5345 	* MIME media types in RFC 2045 and 4288.  All I can say is that this is
5346 	* the easiest way to check the values...
5347 	*/
5348 
5349         if ((i = regcomp(&re,
5350 			 "^"
5351 			 "[-a-zA-Z0-9!#$&.+^_]{1,127}"		/* type-name */
5352 			 "/"
5353 			 "[-a-zA-Z0-9!#$&.+^_]{1,127}"		/* subtype-name */
5354 			 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}="	/* parameter= */
5355 			 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
5356 			 					/* value */
5357 			 "$",
5358 			 REG_NOSUB | REG_EXTENDED)) != 0)
5359         {
5360           char	temp[256];		/* Temporary error string */
5361 
5362           regerror(i, &re, temp, sizeof(temp));
5363 	  ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5364 			_("Unable to compile mimeMediaType regular "
5365 			  "expression: %s."), temp);
5366 	  return (0);
5367         }
5368 
5369         for (i = 0; i < attr->num_values; i ++)
5370 	{
5371 	  if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
5372 	  {
5373 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5374 			  _("\"%s\": Bad mimeMediaType value \"%s\" - bad "
5375 			    "characters (RFC 2911 section 4.1.9)."),
5376 			  attr->name, attr->values[i].string.text);
5377 	    regfree(&re);
5378 	    return (0);
5379 	  }
5380 
5381 	  if (strlen(attr->values[i].string.text) > (IPP_MAX_MIMETYPE - 1))
5382 	  {
5383 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5384 			  _("\"%s\": Bad mimeMediaType value \"%s\" - bad "
5385 			    "length %d (RFC 2911 section 4.1.9)."),
5386 			  attr->name, attr->values[i].string.text,
5387 			  (int)strlen(attr->values[i].string.text));
5388 	    regfree(&re);
5389 	    return (0);
5390 	  }
5391 	}
5392 
5393 	regfree(&re);
5394         break;
5395 
5396     default :
5397         break;
5398   }
5399 
5400   return (1);
5401 }
5402 
5403 
5404 /*
5405  * 'ippValidateAttributes()' - Validate all attributes in an IPP message.
5406  *
5407  * This function validates the contents of the IPP message, including each
5408  * attribute.  Like @link ippValidateAttribute@, cupsLastErrorString() is set
5409  * to a human-readable message on failure.
5410  *
5411  * @since CUPS 1.7/macOS 10.9@
5412  */
5413 
5414 int					/* O - 1 if valid, 0 otherwise */
ippValidateAttributes(ipp_t * ipp)5415 ippValidateAttributes(ipp_t *ipp)	/* I - IPP message */
5416 {
5417   ipp_attribute_t	*attr;		/* Current attribute */
5418 
5419 
5420   if (!ipp)
5421     return (1);
5422 
5423   for (attr = ipp->attrs; attr; attr = attr->next)
5424     if (!ippValidateAttribute(attr))
5425       return (0);
5426 
5427   return (1);
5428 }
5429 
5430 
5431 /*
5432  * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
5433  */
5434 
5435 ipp_state_t				/* O - Current state */
ippWrite(http_t * http,ipp_t * ipp)5436 ippWrite(http_t *http,			/* I - HTTP connection */
5437          ipp_t  *ipp)			/* I - IPP data */
5438 {
5439   DEBUG_printf(("ippWrite(http=%p, ipp=%p)", (void *)http, (void *)ipp));
5440 
5441   if (!http)
5442     return (IPP_STATE_ERROR);
5443 
5444   return (ippWriteIO(http, (ipp_iocb_t)httpWrite2, http->blocking, NULL, ipp));
5445 }
5446 
5447 
5448 /*
5449  * 'ippWriteFile()' - Write data for an IPP message to a file.
5450  *
5451  * @since CUPS 1.1.19/macOS 10.3@
5452  */
5453 
5454 ipp_state_t				/* O - Current state */
ippWriteFile(int fd,ipp_t * ipp)5455 ippWriteFile(int   fd,			/* I - HTTP data */
5456              ipp_t *ipp)		/* I - IPP data */
5457 {
5458   DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd, (void *)ipp));
5459 
5460   ipp->state = IPP_STATE_IDLE;
5461 
5462   return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp));
5463 }
5464 
5465 
5466 /*
5467  * 'ippWriteIO()' - Write data for an IPP message.
5468  *
5469  * @since CUPS 1.2/macOS 10.5@
5470  */
5471 
5472 ipp_state_t				/* O - Current state */
ippWriteIO(void * dst,ipp_iocb_t cb,int blocking,ipp_t * parent,ipp_t * ipp)5473 ippWriteIO(void       *dst,		/* I - Destination */
5474            ipp_iocb_t cb,		/* I - Write callback function */
5475 	   int        blocking,		/* I - Use blocking IO? */
5476 	   ipp_t      *parent,		/* I - Parent IPP message */
5477            ipp_t      *ipp)		/* I - IPP data */
5478 {
5479   int			i;		/* Looping var */
5480   int			n;		/* Length of data */
5481   unsigned char		*buffer,	/* Data buffer */
5482 			*bufptr;	/* Pointer into buffer */
5483   ipp_attribute_t	*attr;		/* Current attribute */
5484   _ipp_value_t		*value;		/* Current value */
5485 
5486 
5487   DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)dst, (void *)cb, blocking, (void *)parent, (void *)ipp));
5488 
5489   if (!dst || !ipp)
5490     return (IPP_STATE_ERROR);
5491 
5492   if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
5493   {
5494     DEBUG_puts("1ippWriteIO: Unable to get write buffer");
5495     return (IPP_STATE_ERROR);
5496   }
5497 
5498   switch (ipp->state)
5499   {
5500     case IPP_STATE_IDLE :
5501         ipp->state ++; /* Avoid common problem... */
5502 
5503     case IPP_STATE_HEADER :
5504         if (parent == NULL)
5505 	{
5506 	 /*
5507 	  * Send the request header:
5508 	  *
5509 	  *                 Version = 2 bytes
5510 	  *   Operation/Status Code = 2 bytes
5511 	  *              Request ID = 4 bytes
5512 	  *                   Total = 8 bytes
5513 	  */
5514 
5515           bufptr = buffer;
5516 
5517 	  *bufptr++ = ipp->request.any.version[0];
5518 	  *bufptr++ = ipp->request.any.version[1];
5519 	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.op_status >> 8);
5520 	  *bufptr++ = (ipp_uchar_t)ipp->request.any.op_status;
5521 	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 24);
5522 	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 16);
5523 	  *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 8);
5524 	  *bufptr++ = (ipp_uchar_t)ipp->request.any.request_id;
5525 
5526 	  DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer[0], buffer[1]));
5527 	  DEBUG_printf(("2ippWriteIO: op_status=%04x",
5528 			ipp->request.any.op_status));
5529 	  DEBUG_printf(("2ippWriteIO: request_id=%d",
5530 			ipp->request.any.request_id));
5531 
5532           if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5533 	  {
5534 	    DEBUG_puts("1ippWriteIO: Could not write IPP header...");
5535 	    _cupsBufferRelease((char *)buffer);
5536 	    return (IPP_STATE_ERROR);
5537 	  }
5538 	}
5539 
5540        /*
5541 	* Reset the state engine to point to the first attribute
5542 	* in the request/response, with no current group.
5543 	*/
5544 
5545         ipp->state   = IPP_STATE_ATTRIBUTE;
5546 	ipp->current = ipp->attrs;
5547 	ipp->curtag  = IPP_TAG_ZERO;
5548 
5549 	DEBUG_printf(("1ippWriteIO: ipp->current=%p", (void *)ipp->current));
5550 
5551        /*
5552         * If blocking is disabled, stop here...
5553 	*/
5554 
5555         if (!blocking)
5556 	  break;
5557 
5558     case IPP_STATE_ATTRIBUTE :
5559         while (ipp->current != NULL)
5560 	{
5561 	 /*
5562 	  * Write this attribute...
5563 	  */
5564 
5565 	  bufptr = buffer;
5566 	  attr   = ipp->current;
5567 
5568 	  ipp->current = ipp->current->next;
5569 
5570           if (!parent)
5571 	  {
5572 	    if (ipp->curtag != attr->group_tag)
5573 	    {
5574 	     /*
5575 	      * Send a group tag byte...
5576 	      */
5577 
5578 	      ipp->curtag = attr->group_tag;
5579 
5580 	      if (attr->group_tag == IPP_TAG_ZERO)
5581 		continue;
5582 
5583 	      DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
5584 			    attr->group_tag, ippTagString(attr->group_tag)));
5585 	      *bufptr++ = (ipp_uchar_t)attr->group_tag;
5586 	    }
5587 	    else if (attr->group_tag == IPP_TAG_ZERO)
5588 	      continue;
5589 	  }
5590 
5591 	  DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr->name,
5592 	                attr->num_values > 1 ? "1setOf " : "",
5593 			ippTagString(attr->value_tag)));
5594 
5595          /*
5596 	  * Write the attribute tag and name.
5597 	  *
5598 	  * The attribute name length does not include the trailing nul
5599 	  * character in the source string.
5600 	  *
5601 	  * Collection values (parent != NULL) are written differently...
5602 	  */
5603 
5604           if (parent == NULL)
5605 	  {
5606            /*
5607 	    * Get the length of the attribute name, and make sure it won't
5608 	    * overflow the buffer...
5609 	    */
5610 
5611             if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 8))
5612 	    {
5613 	      DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
5614 	      _cupsBufferRelease((char *)buffer);
5615 	      return (IPP_STATE_ERROR);
5616 	    }
5617 
5618            /*
5619 	    * Write the value tag, name length, and name string...
5620 	    */
5621 
5622             DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5623 	                  attr->value_tag, ippTagString(attr->value_tag)));
5624             DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
5625 	                  attr->name));
5626 
5627             if (attr->value_tag > 0xff)
5628             {
5629               *bufptr++ = IPP_TAG_EXTENSION;
5630 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
5631 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
5632 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
5633 	      *bufptr++ = (ipp_uchar_t)attr->value_tag;
5634             }
5635             else
5636 	      *bufptr++ = (ipp_uchar_t)attr->value_tag;
5637 
5638 	    *bufptr++ = (ipp_uchar_t)(n >> 8);
5639 	    *bufptr++ = (ipp_uchar_t)n;
5640 	    memcpy(bufptr, attr->name, (size_t)n);
5641 	    bufptr += n;
5642           }
5643 	  else
5644 	  {
5645            /*
5646 	    * Get the length of the attribute name, and make sure it won't
5647 	    * overflow the buffer...
5648 	    */
5649 
5650             if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 12))
5651 	    {
5652 	      DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
5653 	      _cupsBufferRelease((char *)buffer);
5654 	      return (IPP_STATE_ERROR);
5655 	    }
5656 
5657            /*
5658 	    * Write the member name tag, name length, name string, value tag,
5659 	    * and empty name for the collection member attribute...
5660 	    */
5661 
5662             DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
5663 	                  IPP_TAG_MEMBERNAME));
5664             DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
5665 	                  attr->name));
5666             DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5667 	                  attr->value_tag, ippTagString(attr->value_tag)));
5668             DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
5669 
5670             *bufptr++ = IPP_TAG_MEMBERNAME;
5671 	    *bufptr++ = 0;
5672 	    *bufptr++ = 0;
5673 	    *bufptr++ = (ipp_uchar_t)(n >> 8);
5674 	    *bufptr++ = (ipp_uchar_t)n;
5675 	    memcpy(bufptr, attr->name, (size_t)n);
5676 	    bufptr += n;
5677 
5678             if (attr->value_tag > 0xff)
5679             {
5680               *bufptr++ = IPP_TAG_EXTENSION;
5681 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
5682 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
5683 	      *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
5684 	      *bufptr++ = (ipp_uchar_t)attr->value_tag;
5685             }
5686             else
5687 	      *bufptr++ = (ipp_uchar_t)attr->value_tag;
5688 
5689             *bufptr++ = 0;
5690             *bufptr++ = 0;
5691 	  }
5692 
5693          /*
5694 	  * Now write the attribute value(s)...
5695 	  */
5696 
5697 	  switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
5698 	  {
5699 	    case IPP_TAG_UNSUPPORTED_VALUE :
5700 	    case IPP_TAG_DEFAULT :
5701 	    case IPP_TAG_UNKNOWN :
5702 	    case IPP_TAG_NOVALUE :
5703 	    case IPP_TAG_NOTSETTABLE :
5704 	    case IPP_TAG_DELETEATTR :
5705 	    case IPP_TAG_ADMINDEFINE :
5706 		*bufptr++ = 0;
5707 		*bufptr++ = 0;
5708 	        break;
5709 
5710 	    case IPP_TAG_INTEGER :
5711 	    case IPP_TAG_ENUM :
5712 	        for (i = 0, value = attr->values;
5713 		     i < attr->num_values;
5714 		     i ++, value ++)
5715 		{
5716                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 9)
5717 		  {
5718                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5719 	            {
5720 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5721 		                 "attribute...");
5722 		      _cupsBufferRelease((char *)buffer);
5723 	              return (IPP_STATE_ERROR);
5724 	            }
5725 
5726 		    bufptr = buffer;
5727 		  }
5728 
5729 		  if (i)
5730 		  {
5731 		   /*
5732 		    * Arrays and sets are done by sending additional
5733 		    * values with a zero-length name...
5734 		    */
5735 
5736                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5737 		    *bufptr++ = 0;
5738 		    *bufptr++ = 0;
5739 		  }
5740 
5741 		 /*
5742 	          * Integers and enumerations are both 4-byte signed
5743 		  * (twos-complement) values.
5744 		  *
5745 		  * Put the 2-byte length and 4-byte value into the buffer...
5746 		  */
5747 
5748 	          *bufptr++ = 0;
5749 		  *bufptr++ = 4;
5750 		  *bufptr++ = (ipp_uchar_t)(value->integer >> 24);
5751 		  *bufptr++ = (ipp_uchar_t)(value->integer >> 16);
5752 		  *bufptr++ = (ipp_uchar_t)(value->integer >> 8);
5753 		  *bufptr++ = (ipp_uchar_t)value->integer;
5754 		}
5755 		break;
5756 
5757 	    case IPP_TAG_BOOLEAN :
5758 	        for (i = 0, value = attr->values;
5759 		     i < attr->num_values;
5760 		     i ++, value ++)
5761 		{
5762                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 6)
5763 		  {
5764                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5765 	            {
5766 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5767 		                 "attribute...");
5768 		      _cupsBufferRelease((char *)buffer);
5769 	              return (IPP_STATE_ERROR);
5770 	            }
5771 
5772 		    bufptr = buffer;
5773 		  }
5774 
5775 		  if (i)
5776 		  {
5777 		   /*
5778 		    * Arrays and sets are done by sending additional
5779 		    * values with a zero-length name...
5780 		    */
5781 
5782                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5783 		    *bufptr++ = 0;
5784 		    *bufptr++ = 0;
5785 		  }
5786 
5787                  /*
5788 		  * Boolean values are 1-byte; 0 = false, 1 = true.
5789 		  *
5790 		  * Put the 2-byte length and 1-byte value into the buffer...
5791 		  */
5792 
5793 	          *bufptr++ = 0;
5794 		  *bufptr++ = 1;
5795 		  *bufptr++ = (ipp_uchar_t)value->boolean;
5796 		}
5797 		break;
5798 
5799 	    case IPP_TAG_TEXT :
5800 	    case IPP_TAG_NAME :
5801 	    case IPP_TAG_KEYWORD :
5802 	    case IPP_TAG_URI :
5803 	    case IPP_TAG_URISCHEME :
5804 	    case IPP_TAG_CHARSET :
5805 	    case IPP_TAG_LANGUAGE :
5806 	    case IPP_TAG_MIMETYPE :
5807 	        for (i = 0, value = attr->values;
5808 		     i < attr->num_values;
5809 		     i ++, value ++)
5810 		{
5811 		  if (i)
5812 		  {
5813 		   /*
5814 		    * Arrays and sets are done by sending additional
5815 		    * values with a zero-length name...
5816 		    */
5817 
5818         	    DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5819 		                  attr->value_tag,
5820 				  ippTagString(attr->value_tag)));
5821         	    DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
5822 
5823                     if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
5824 		    {
5825                       if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5826 	              {
5827 	        	DEBUG_puts("1ippWriteIO: Could not write IPP "
5828 			           "attribute...");
5829 			_cupsBufferRelease((char *)buffer);
5830 	        	return (IPP_STATE_ERROR);
5831 	              }
5832 
5833 		      bufptr = buffer;
5834 		    }
5835 
5836                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5837 		    *bufptr++ = 0;
5838 		    *bufptr++ = 0;
5839 		  }
5840 
5841                   if (value->string.text != NULL)
5842                     n = (int)strlen(value->string.text);
5843 		  else
5844 		    n = 0;
5845 
5846                   if (n > (IPP_BUF_SIZE - 2))
5847 		  {
5848 		    DEBUG_printf(("1ippWriteIO: String too long (%d)", n));
5849 		    _cupsBufferRelease((char *)buffer);
5850 		    return (IPP_STATE_ERROR);
5851 		  }
5852 
5853                   DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n,
5854 		                value->string.text));
5855 
5856                   if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
5857 		  {
5858                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5859 	            {
5860 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5861 		                 "attribute...");
5862 		      _cupsBufferRelease((char *)buffer);
5863 	              return (IPP_STATE_ERROR);
5864 	            }
5865 
5866 		    bufptr = buffer;
5867 		  }
5868 
5869 		 /*
5870 		  * All simple strings consist of the 2-byte length and
5871 		  * character data without the trailing nul normally found
5872 		  * in C strings.  Also, strings cannot be longer than IPP_MAX_LENGTH
5873 		  * bytes since the 2-byte length is a signed (twos-complement)
5874 		  * value.
5875 		  *
5876 		  * Put the 2-byte length and string characters in the buffer.
5877 		  */
5878 
5879 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
5880 		  *bufptr++ = (ipp_uchar_t)n;
5881 
5882 		  if (n > 0)
5883 		  {
5884 		    memcpy(bufptr, value->string.text, (size_t)n);
5885 		    bufptr += n;
5886 		  }
5887 		}
5888 		break;
5889 
5890 	    case IPP_TAG_DATE :
5891 	        for (i = 0, value = attr->values;
5892 		     i < attr->num_values;
5893 		     i ++, value ++)
5894 		{
5895                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 16)
5896 		  {
5897                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5898 	            {
5899 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5900 		                 "attribute...");
5901 		      _cupsBufferRelease((char *)buffer);
5902 	              return (IPP_STATE_ERROR);
5903 	            }
5904 
5905 		    bufptr = buffer;
5906 		  }
5907 
5908 		  if (i)
5909 		  {
5910 		   /*
5911 		    * Arrays and sets are done by sending additional
5912 		    * values with a zero-length name...
5913 		    */
5914 
5915                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5916 		    *bufptr++ = 0;
5917 		    *bufptr++ = 0;
5918 		  }
5919 
5920                  /*
5921 		  * Date values consist of a 2-byte length and an
5922 		  * 11-byte date/time structure defined by RFC 1903.
5923 		  *
5924 		  * Put the 2-byte length and 11-byte date/time
5925 		  * structure in the buffer.
5926 		  */
5927 
5928 	          *bufptr++ = 0;
5929 		  *bufptr++ = 11;
5930 		  memcpy(bufptr, value->date, 11);
5931 		  bufptr += 11;
5932 		}
5933 		break;
5934 
5935 	    case IPP_TAG_RESOLUTION :
5936 	        for (i = 0, value = attr->values;
5937 		     i < attr->num_values;
5938 		     i ++, value ++)
5939 		{
5940                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 14)
5941 		  {
5942                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5943 	            {
5944 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5945 		                 "attribute...");
5946 		      _cupsBufferRelease((char *)buffer);
5947 		      return (IPP_STATE_ERROR);
5948 	            }
5949 
5950 		    bufptr = buffer;
5951 		  }
5952 
5953 		  if (i)
5954 		  {
5955 		   /*
5956 		    * Arrays and sets are done by sending additional
5957 		    * values with a zero-length name...
5958 		    */
5959 
5960                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
5961 		    *bufptr++ = 0;
5962 		    *bufptr++ = 0;
5963 		  }
5964 
5965                  /*
5966 		  * Resolution values consist of a 2-byte length,
5967 		  * 4-byte horizontal resolution value, 4-byte vertical
5968 		  * resolution value, and a 1-byte units value.
5969 		  *
5970 		  * Put the 2-byte length and resolution value data
5971 		  * into the buffer.
5972 		  */
5973 
5974 	          *bufptr++ = 0;
5975 		  *bufptr++ = 9;
5976 		  *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 24);
5977 		  *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 16);
5978 		  *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 8);
5979 		  *bufptr++ = (ipp_uchar_t)value->resolution.xres;
5980 		  *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 24);
5981 		  *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 16);
5982 		  *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 8);
5983 		  *bufptr++ = (ipp_uchar_t)value->resolution.yres;
5984 		  *bufptr++ = (ipp_uchar_t)value->resolution.units;
5985 		}
5986 		break;
5987 
5988 	    case IPP_TAG_RANGE :
5989 	        for (i = 0, value = attr->values;
5990 		     i < attr->num_values;
5991 		     i ++, value ++)
5992 		{
5993                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 13)
5994 		  {
5995                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
5996 	            {
5997 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
5998 		                 "attribute...");
5999 		      _cupsBufferRelease((char *)buffer);
6000 	              return (IPP_STATE_ERROR);
6001 	            }
6002 
6003 		    bufptr = buffer;
6004 		  }
6005 
6006 		  if (i)
6007 		  {
6008 		   /*
6009 		    * Arrays and sets are done by sending additional
6010 		    * values with a zero-length name...
6011 		    */
6012 
6013                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
6014 		    *bufptr++ = 0;
6015 		    *bufptr++ = 0;
6016 		  }
6017 
6018                  /*
6019 		  * Range values consist of a 2-byte length,
6020 		  * 4-byte lower value, and 4-byte upper value.
6021 		  *
6022 		  * Put the 2-byte length and range value data
6023 		  * into the buffer.
6024 		  */
6025 
6026 	          *bufptr++ = 0;
6027 		  *bufptr++ = 8;
6028 		  *bufptr++ = (ipp_uchar_t)(value->range.lower >> 24);
6029 		  *bufptr++ = (ipp_uchar_t)(value->range.lower >> 16);
6030 		  *bufptr++ = (ipp_uchar_t)(value->range.lower >> 8);
6031 		  *bufptr++ = (ipp_uchar_t)value->range.lower;
6032 		  *bufptr++ = (ipp_uchar_t)(value->range.upper >> 24);
6033 		  *bufptr++ = (ipp_uchar_t)(value->range.upper >> 16);
6034 		  *bufptr++ = (ipp_uchar_t)(value->range.upper >> 8);
6035 		  *bufptr++ = (ipp_uchar_t)value->range.upper;
6036 		}
6037 		break;
6038 
6039 	    case IPP_TAG_TEXTLANG :
6040 	    case IPP_TAG_NAMELANG :
6041 	        for (i = 0, value = attr->values;
6042 		     i < attr->num_values;
6043 		     i ++, value ++)
6044 		{
6045 		  if (i)
6046 		  {
6047 		   /*
6048 		    * Arrays and sets are done by sending additional
6049 		    * values with a zero-length name...
6050 		    */
6051 
6052                     if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
6053 		    {
6054                       if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6055 	              {
6056 	        	DEBUG_puts("1ippWriteIO: Could not write IPP "
6057 		                   "attribute...");
6058 			_cupsBufferRelease((char *)buffer);
6059 	        	return (IPP_STATE_ERROR);
6060 	              }
6061 
6062 		      bufptr = buffer;
6063 		    }
6064 
6065                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
6066 		    *bufptr++ = 0;
6067 		    *bufptr++ = 0;
6068 		  }
6069 
6070                  /*
6071 		  * textWithLanguage and nameWithLanguage values consist
6072 		  * of a 2-byte length for both strings and their
6073 		  * individual lengths, a 2-byte length for the
6074 		  * character string, the character string without the
6075 		  * trailing nul, a 2-byte length for the character
6076 		  * set string, and the character set string without
6077 		  * the trailing nul.
6078 		  */
6079 
6080                   n = 4;
6081 
6082 		  if (value->string.language != NULL)
6083                     n += (int)strlen(value->string.language);
6084 
6085 		  if (value->string.text != NULL)
6086                     n += (int)strlen(value->string.text);
6087 
6088                   if (n > (IPP_BUF_SIZE - 2))
6089 		  {
6090 		    DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
6091 		                  "too long (%d)", n));
6092 		    _cupsBufferRelease((char *)buffer);
6093 		    return (IPP_STATE_ERROR);
6094                   }
6095 
6096                   if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
6097 		  {
6098                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6099 	            {
6100 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
6101 		                 "attribute...");
6102 		      _cupsBufferRelease((char *)buffer);
6103 	              return (IPP_STATE_ERROR);
6104 	            }
6105 
6106 		    bufptr = buffer;
6107 		  }
6108 
6109                  /* Length of entire value */
6110 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
6111 		  *bufptr++ = (ipp_uchar_t)n;
6112 
6113                  /* Length of language */
6114 		  if (value->string.language != NULL)
6115 		    n = (int)strlen(value->string.language);
6116 		  else
6117 		    n = 0;
6118 
6119 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
6120 		  *bufptr++ = (ipp_uchar_t)n;
6121 
6122                  /* Language */
6123 		  if (n > 0)
6124 		  {
6125 		    memcpy(bufptr, value->string.language, (size_t)n);
6126 		    bufptr += n;
6127 		  }
6128 
6129                  /* Length of text */
6130                   if (value->string.text != NULL)
6131 		    n = (int)strlen(value->string.text);
6132 		  else
6133 		    n = 0;
6134 
6135 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
6136 		  *bufptr++ = (ipp_uchar_t)n;
6137 
6138                  /* Text */
6139 		  if (n > 0)
6140 		  {
6141 		    memcpy(bufptr, value->string.text, (size_t)n);
6142 		    bufptr += n;
6143 		  }
6144 		}
6145 		break;
6146 
6147             case IPP_TAG_BEGIN_COLLECTION :
6148 	        for (i = 0, value = attr->values;
6149 		     i < attr->num_values;
6150 		     i ++, value ++)
6151 		{
6152 		 /*
6153 		  * Collections are written with the begin-collection
6154 		  * tag first with a value of 0 length, followed by the
6155 		  * attributes in the collection, then the end-collection
6156 		  * value...
6157 		  */
6158 
6159                   if ((IPP_BUF_SIZE - (bufptr - buffer)) < 5)
6160 		  {
6161                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6162 	            {
6163 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
6164 		                 "attribute...");
6165 		      _cupsBufferRelease((char *)buffer);
6166 	              return (IPP_STATE_ERROR);
6167 	            }
6168 
6169 		    bufptr = buffer;
6170 		  }
6171 
6172 		  if (i)
6173 		  {
6174 		   /*
6175 		    * Arrays and sets are done by sending additional
6176 		    * values with a zero-length name...
6177 		    */
6178 
6179                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
6180 		    *bufptr++ = 0;
6181 		    *bufptr++ = 0;
6182 		  }
6183 
6184                  /*
6185 		  * Write a data length of 0 and flush the buffer...
6186 		  */
6187 
6188 	          *bufptr++ = 0;
6189 		  *bufptr++ = 0;
6190 
6191                   if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6192 	          {
6193 	            DEBUG_puts("1ippWriteIO: Could not write IPP "
6194 		               "attribute...");
6195 		    _cupsBufferRelease((char *)buffer);
6196 	            return (IPP_STATE_ERROR);
6197 	          }
6198 
6199 		  bufptr = buffer;
6200 
6201                  /*
6202 		  * Then write the collection attribute...
6203 		  */
6204 
6205                   value->collection->state = IPP_STATE_IDLE;
6206 
6207 		  if (ippWriteIO(dst, cb, 1, ipp,
6208 		                 value->collection) == IPP_STATE_ERROR)
6209 		  {
6210 		    DEBUG_puts("1ippWriteIO: Unable to write collection value");
6211 		    _cupsBufferRelease((char *)buffer);
6212 		    return (IPP_STATE_ERROR);
6213 		  }
6214 		}
6215 		break;
6216 
6217             default :
6218 	        for (i = 0, value = attr->values;
6219 		     i < attr->num_values;
6220 		     i ++, value ++)
6221 		{
6222 		  if (i)
6223 		  {
6224 		   /*
6225 		    * Arrays and sets are done by sending additional
6226 		    * values with a zero-length name...
6227 		    */
6228 
6229                     if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
6230 		    {
6231                       if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6232 	              {
6233 	        	DEBUG_puts("1ippWriteIO: Could not write IPP "
6234 		                   "attribute...");
6235 			_cupsBufferRelease((char *)buffer);
6236 	        	return (IPP_STATE_ERROR);
6237 	              }
6238 
6239 		      bufptr = buffer;
6240 		    }
6241 
6242                     *bufptr++ = (ipp_uchar_t)attr->value_tag;
6243 		    *bufptr++ = 0;
6244 		    *bufptr++ = 0;
6245 		  }
6246 
6247                  /*
6248 		  * An unknown value might some new value that a
6249 		  * vendor has come up with. It consists of a
6250 		  * 2-byte length and the bytes in the unknown
6251 		  * value buffer.
6252 		  */
6253 
6254                   n = value->unknown.length;
6255 
6256                   if (n > (IPP_BUF_SIZE - 2))
6257 		  {
6258 		    DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
6259 		                  n));
6260 		    _cupsBufferRelease((char *)buffer);
6261 		    return (IPP_STATE_ERROR);
6262 		  }
6263 
6264                   if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
6265 		  {
6266                     if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6267 	            {
6268 	              DEBUG_puts("1ippWriteIO: Could not write IPP "
6269 		                 "attribute...");
6270 		      _cupsBufferRelease((char *)buffer);
6271 	              return (IPP_STATE_ERROR);
6272 	            }
6273 
6274 		    bufptr = buffer;
6275 		  }
6276 
6277                  /* Length of unknown value */
6278 	          *bufptr++ = (ipp_uchar_t)(n >> 8);
6279 		  *bufptr++ = (ipp_uchar_t)n;
6280 
6281                  /* Value */
6282 		  if (n > 0)
6283 		  {
6284 		    memcpy(bufptr, value->unknown.data, (size_t)n);
6285 		    bufptr += n;
6286 		  }
6287 		}
6288 		break;
6289 	  }
6290 
6291          /*
6292 	  * Write the data out...
6293 	  */
6294 
6295 	  if (bufptr > buffer)
6296 	  {
6297 	    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
6298 	    {
6299 	      DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
6300 	      _cupsBufferRelease((char *)buffer);
6301 	      return (IPP_STATE_ERROR);
6302 	    }
6303 
6304 	    DEBUG_printf(("2ippWriteIO: wrote %d bytes",
6305 			  (int)(bufptr - buffer)));
6306 	  }
6307 
6308 	 /*
6309           * If blocking is disabled and we aren't at the end of the attribute
6310           * list, stop here...
6311 	  */
6312 
6313           if (!blocking && ipp->current)
6314 	    break;
6315 	}
6316 
6317 	if (ipp->current == NULL)
6318 	{
6319          /*
6320 	  * Done with all of the attributes; add the end-of-attributes
6321 	  * tag or end-collection attribute...
6322 	  */
6323 
6324           if (parent == NULL)
6325 	  {
6326             buffer[0] = IPP_TAG_END;
6327 	    n         = 1;
6328 	  }
6329 	  else
6330 	  {
6331             buffer[0] = IPP_TAG_END_COLLECTION;
6332 	    buffer[1] = 0; /* empty name */
6333 	    buffer[2] = 0;
6334 	    buffer[3] = 0; /* empty value */
6335 	    buffer[4] = 0;
6336 	    n         = 5;
6337 	  }
6338 
6339 	  if ((*cb)(dst, buffer, (size_t)n) < 0)
6340 	  {
6341 	    DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
6342 	    _cupsBufferRelease((char *)buffer);
6343 	    return (IPP_STATE_ERROR);
6344 	  }
6345 
6346 	  ipp->state = IPP_STATE_DATA;
6347 	}
6348         break;
6349 
6350     case IPP_STATE_DATA :
6351         break;
6352 
6353     default :
6354         break; /* anti-compiler-warning-code */
6355   }
6356 
6357   _cupsBufferRelease((char *)buffer);
6358 
6359   return (ipp->state);
6360 }
6361 
6362 
6363 /*
6364  * 'ipp_add_attr()' - Add a new attribute to the message.
6365  */
6366 
6367 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)6368 ipp_add_attr(ipp_t      *ipp,		/* I - IPP message */
6369              const char *name,		/* I - Attribute name or NULL */
6370              ipp_tag_t  group_tag,	/* I - Group tag or IPP_TAG_ZERO */
6371              ipp_tag_t  value_tag,	/* I - Value tag or IPP_TAG_ZERO */
6372              int        num_values)	/* I - Number of values */
6373 {
6374   int			alloc_values;	/* Number of values to allocate */
6375   ipp_attribute_t	*attr;		/* New attribute */
6376 
6377 
6378   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));
6379 
6380  /*
6381   * Range check input...
6382   */
6383 
6384   if (!ipp || num_values < 0)
6385     return (NULL);
6386 
6387  /*
6388   * Allocate memory, rounding the allocation up as needed...
6389   */
6390 
6391   if (num_values <= 1)
6392     alloc_values = 1;
6393   else
6394     alloc_values = (num_values + IPP_MAX_VALUES - 1) & ~(IPP_MAX_VALUES - 1);
6395 
6396   attr = calloc(sizeof(ipp_attribute_t) +
6397                 (size_t)(alloc_values - 1) * sizeof(_ipp_value_t), 1);
6398 
6399   if (attr)
6400   {
6401    /*
6402     * Initialize attribute...
6403     */
6404 
6405     if (name)
6406       attr->name = _cupsStrAlloc(name);
6407 
6408     attr->group_tag  = group_tag;
6409     attr->value_tag  = value_tag;
6410     attr->num_values = num_values;
6411 
6412    /*
6413     * Add it to the end of the linked list...
6414     */
6415 
6416     if (ipp->last)
6417       ipp->last->next = attr;
6418     else
6419       ipp->attrs = attr;
6420 
6421     ipp->prev = ipp->last;
6422     ipp->last = ipp->current = attr;
6423   }
6424 
6425   DEBUG_printf(("5ipp_add_attr: Returning %p", (void *)attr));
6426 
6427   return (attr);
6428 }
6429 
6430 
6431 /*
6432  * 'ipp_free_values()' - Free attribute values.
6433  */
6434 
6435 static void
ipp_free_values(ipp_attribute_t * attr,int element,int count)6436 ipp_free_values(ipp_attribute_t *attr,	/* I - Attribute to free values from */
6437                 int             element,/* I - First value to free */
6438                 int             count)	/* I - Number of values to free */
6439 {
6440   int		i;			/* Looping var */
6441   _ipp_value_t	*value;			/* Current value */
6442 
6443 
6444   DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", (void *)attr, element, count));
6445 
6446   if (!(attr->value_tag & IPP_TAG_CUPS_CONST))
6447   {
6448    /*
6449     * Free values as needed...
6450     */
6451 
6452     switch (attr->value_tag)
6453     {
6454       case IPP_TAG_TEXTLANG :
6455       case IPP_TAG_NAMELANG :
6456 	  if (element == 0 && count == attr->num_values &&
6457 	      attr->values[0].string.language)
6458 	  {
6459 	    _cupsStrFree(attr->values[0].string.language);
6460 	    attr->values[0].string.language = NULL;
6461 	  }
6462 	  /* Fall through to other string values */
6463 
6464       case IPP_TAG_TEXT :
6465       case IPP_TAG_NAME :
6466       case IPP_TAG_RESERVED_STRING :
6467       case IPP_TAG_KEYWORD :
6468       case IPP_TAG_URI :
6469       case IPP_TAG_URISCHEME :
6470       case IPP_TAG_CHARSET :
6471       case IPP_TAG_LANGUAGE :
6472       case IPP_TAG_MIMETYPE :
6473 	  for (i = count, value = attr->values + element;
6474 	       i > 0;
6475 	       i --, value ++)
6476 	  {
6477 	    _cupsStrFree(value->string.text);
6478 	    value->string.text = NULL;
6479 	  }
6480 	  break;
6481 
6482       case IPP_TAG_DEFAULT :
6483       case IPP_TAG_UNKNOWN :
6484       case IPP_TAG_NOVALUE :
6485       case IPP_TAG_NOTSETTABLE :
6486       case IPP_TAG_DELETEATTR :
6487       case IPP_TAG_ADMINDEFINE :
6488       case IPP_TAG_INTEGER :
6489       case IPP_TAG_ENUM :
6490       case IPP_TAG_BOOLEAN :
6491       case IPP_TAG_DATE :
6492       case IPP_TAG_RESOLUTION :
6493       case IPP_TAG_RANGE :
6494 	  break;
6495 
6496       case IPP_TAG_BEGIN_COLLECTION :
6497 	  for (i = count, value = attr->values + element;
6498 	       i > 0;
6499 	       i --, value ++)
6500 	  {
6501 	    ippDelete(value->collection);
6502 	    value->collection = NULL;
6503 	  }
6504 	  break;
6505 
6506       case IPP_TAG_STRING :
6507       default :
6508 	  for (i = count, value = attr->values + element;
6509 	       i > 0;
6510 	       i --, value ++)
6511 	  {
6512 	    if (value->unknown.data)
6513 	    {
6514 	      free(value->unknown.data);
6515 	      value->unknown.data = NULL;
6516 	    }
6517 	  }
6518 	  break;
6519     }
6520   }
6521 
6522  /*
6523   * If we are not freeing values from the end, move the remaining values up...
6524   */
6525 
6526   if ((element + count) < attr->num_values)
6527     memmove(attr->values + element, attr->values + element + count,
6528             (size_t)(attr->num_values - count - element) * sizeof(_ipp_value_t));
6529 
6530   attr->num_values -= count;
6531 }
6532 
6533 
6534 /*
6535  * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
6536  *
6537  * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
6538  * to "ll-cc", "ll-region", and "charset-number", respectively.
6539  */
6540 
6541 static char *				/* O - Language code string */
ipp_get_code(const char * value,char * buffer,size_t bufsize)6542 ipp_get_code(const char *value,		/* I - Locale/charset string */
6543              char       *buffer,	/* I - String buffer */
6544              size_t     bufsize)	/* I - Size of string buffer */
6545 {
6546   char	*bufptr,			/* Pointer into buffer */
6547 	*bufend;			/* End of buffer */
6548 
6549 
6550  /*
6551   * Convert values to lowercase and change _ to - as needed...
6552   */
6553 
6554   for (bufptr = buffer, bufend = buffer + bufsize - 1;
6555        *value && bufptr < bufend;
6556        value ++)
6557     if (*value == '_')
6558       *bufptr++ = '-';
6559     else
6560       *bufptr++ = (char)_cups_tolower(*value);
6561 
6562   *bufptr = '\0';
6563 
6564  /*
6565   * Return the converted string...
6566   */
6567 
6568   return (buffer);
6569 }
6570 
6571 
6572 /*
6573  * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
6574  *
6575  * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
6576  * "ll-region", respectively.  It also converts the "C" (POSIX) locale to "en".
6577  */
6578 
6579 static char *				/* O - Language code string */
ipp_lang_code(const char * locale,char * buffer,size_t bufsize)6580 ipp_lang_code(const char *locale,	/* I - Locale string */
6581               char       *buffer,	/* I - String buffer */
6582               size_t     bufsize)	/* I - Size of string buffer */
6583 {
6584  /*
6585   * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
6586   */
6587 
6588   if (!_cups_strcasecmp(locale, "c"))
6589   {
6590     strlcpy(buffer, "en", bufsize);
6591     return (buffer);
6592   }
6593   else
6594     return (ipp_get_code(locale, buffer, bufsize));
6595 }
6596 
6597 
6598 /*
6599  * 'ipp_length()' - Compute the length of an IPP message or collection value.
6600  */
6601 
6602 static size_t				/* O - Size of IPP message */
ipp_length(ipp_t * ipp,int collection)6603 ipp_length(ipp_t *ipp,			/* I - IPP message or collection */
6604            int   collection)		/* I - 1 if a collection, 0 otherwise */
6605 {
6606   int			i;		/* Looping var */
6607   size_t		bytes;		/* Number of bytes */
6608   ipp_attribute_t	*attr;		/* Current attribute */
6609   ipp_tag_t		group;		/* Current group */
6610   _ipp_value_t		*value;		/* Current value */
6611 
6612 
6613   DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", (void *)ipp, collection));
6614 
6615   if (!ipp)
6616   {
6617     DEBUG_puts("4ipp_length: Returning 0 bytes");
6618     return (0);
6619   }
6620 
6621  /*
6622   * Start with 8 bytes for the IPP message header...
6623   */
6624 
6625   bytes = collection ? 0 : 8;
6626 
6627  /*
6628   * Then add the lengths of each attribute...
6629   */
6630 
6631   group = IPP_TAG_ZERO;
6632 
6633   for (attr = ipp->attrs; attr != NULL; attr = attr->next)
6634   {
6635     if (attr->group_tag != group && !collection)
6636     {
6637       group = attr->group_tag;
6638       if (group == IPP_TAG_ZERO)
6639 	continue;
6640 
6641       bytes ++;	/* Group tag */
6642     }
6643 
6644     if (!attr->name)
6645       continue;
6646 
6647     DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
6648                   "bytes=" CUPS_LLFMT, attr->name, attr->num_values, CUPS_LLCAST bytes));
6649 
6650     if ((attr->value_tag & ~IPP_TAG_CUPS_CONST) < IPP_TAG_EXTENSION)
6651       bytes += (size_t)attr->num_values;/* Value tag for each value */
6652     else
6653       bytes += (size_t)(5 * attr->num_values);
6654 					/* Value tag for each value */
6655     bytes += (size_t)(2 * attr->num_values);
6656 					/* Name lengths */
6657     bytes += strlen(attr->name);	/* Name */
6658     bytes += (size_t)(2 * attr->num_values);
6659 					/* Value lengths */
6660 
6661     if (collection)
6662       bytes += 5;			/* Add membername overhead */
6663 
6664     switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
6665     {
6666       case IPP_TAG_UNSUPPORTED_VALUE :
6667       case IPP_TAG_DEFAULT :
6668       case IPP_TAG_UNKNOWN :
6669       case IPP_TAG_NOVALUE :
6670       case IPP_TAG_NOTSETTABLE :
6671       case IPP_TAG_DELETEATTR :
6672       case IPP_TAG_ADMINDEFINE :
6673           break;
6674 
6675       case IPP_TAG_INTEGER :
6676       case IPP_TAG_ENUM :
6677           bytes += (size_t)(4 * attr->num_values);
6678 	  break;
6679 
6680       case IPP_TAG_BOOLEAN :
6681           bytes += (size_t)attr->num_values;
6682 	  break;
6683 
6684       case IPP_TAG_TEXT :
6685       case IPP_TAG_NAME :
6686       case IPP_TAG_KEYWORD :
6687       case IPP_TAG_URI :
6688       case IPP_TAG_URISCHEME :
6689       case IPP_TAG_CHARSET :
6690       case IPP_TAG_LANGUAGE :
6691       case IPP_TAG_MIMETYPE :
6692 	  for (i = 0, value = attr->values;
6693 	       i < attr->num_values;
6694 	       i ++, value ++)
6695 	    if (value->string.text)
6696 	      bytes += strlen(value->string.text);
6697 	  break;
6698 
6699       case IPP_TAG_DATE :
6700           bytes += (size_t)(11 * attr->num_values);
6701 	  break;
6702 
6703       case IPP_TAG_RESOLUTION :
6704           bytes += (size_t)(9 * attr->num_values);
6705 	  break;
6706 
6707       case IPP_TAG_RANGE :
6708           bytes += (size_t)(8 * attr->num_values);
6709 	  break;
6710 
6711       case IPP_TAG_TEXTLANG :
6712       case IPP_TAG_NAMELANG :
6713           bytes += (size_t)(4 * attr->num_values);
6714 					/* Charset + text length */
6715 
6716 	  for (i = 0, value = attr->values;
6717 	       i < attr->num_values;
6718 	       i ++, value ++)
6719 	  {
6720 	    if (value->string.language)
6721 	      bytes += strlen(value->string.language);
6722 
6723 	    if (value->string.text)
6724 	      bytes += strlen(value->string.text);
6725 	  }
6726 	  break;
6727 
6728       case IPP_TAG_BEGIN_COLLECTION :
6729 	  for (i = 0, value = attr->values;
6730 	       i < attr->num_values;
6731 	       i ++, value ++)
6732             bytes += ipp_length(value->collection, 1);
6733 	  break;
6734 
6735       default :
6736 	  for (i = 0, value = attr->values;
6737 	       i < attr->num_values;
6738 	       i ++, value ++)
6739             bytes += (size_t)value->unknown.length;
6740 	  break;
6741     }
6742   }
6743 
6744  /*
6745   * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
6746   * for the "end of collection" tag and return...
6747   */
6748 
6749   if (collection)
6750     bytes += 5;
6751   else
6752     bytes ++;
6753 
6754   DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST bytes));
6755 
6756   return (bytes);
6757 }
6758 
6759 
6760 /*
6761  * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
6762  */
6763 
6764 static ssize_t				/* O - Number of bytes read */
ipp_read_http(http_t * http,ipp_uchar_t * buffer,size_t length)6765 ipp_read_http(http_t      *http,	/* I - Client connection */
6766               ipp_uchar_t *buffer,	/* O - Buffer for data */
6767 	      size_t      length)	/* I - Total length */
6768 {
6769   ssize_t	tbytes,			/* Total bytes read */
6770 		bytes;			/* Bytes read this pass */
6771 
6772 
6773   DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)", (void *)http, (void *)buffer, (int)length));
6774 
6775  /*
6776   * Loop until all bytes are read...
6777   */
6778 
6779   for (tbytes = 0, bytes = 0;
6780        tbytes < (int)length;
6781        tbytes += bytes, buffer += bytes)
6782   {
6783     DEBUG_printf(("9ipp_read_http: tbytes=" CUPS_LLFMT ", http->state=%d", CUPS_LLCAST tbytes, http->state));
6784 
6785     if (http->state == HTTP_STATE_WAITING)
6786       break;
6787 
6788     if (http->used == 0 && !http->blocking)
6789     {
6790      /*
6791       * Wait up to 10 seconds for more data on non-blocking sockets...
6792       */
6793 
6794       if (!httpWait(http, 10000))
6795       {
6796        /*
6797 	* Signal no data...
6798 	*/
6799 
6800 	bytes = -1;
6801 	break;
6802       }
6803     }
6804     else if (http->used == 0 && http->timeout_value > 0)
6805     {
6806      /*
6807       * Wait up to timeout seconds for more data on blocking sockets...
6808       */
6809 
6810       if (!httpWait(http, (int)(1000 * http->timeout_value)))
6811       {
6812        /*
6813 	* Signal no data...
6814 	*/
6815 
6816 	bytes = -1;
6817 	break;
6818       }
6819     }
6820 
6821     if ((bytes = httpRead2(http, (char *)buffer, length - (size_t)tbytes)) < 0)
6822     {
6823 #ifdef WIN32
6824       break;
6825 #else
6826       if (errno != EAGAIN && errno != EINTR)
6827 	break;
6828 
6829       bytes = 0;
6830 #endif /* WIN32 */
6831     }
6832     else if (bytes == 0)
6833       break;
6834   }
6835 
6836  /*
6837   * Return the number of bytes read...
6838   */
6839 
6840   if (tbytes == 0 && bytes < 0)
6841     tbytes = -1;
6842 
6843   DEBUG_printf(("8ipp_read_http: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST tbytes));
6844 
6845   return (tbytes);
6846 }
6847 
6848 
6849 /*
6850  * 'ipp_read_file()' - Read IPP data from a file.
6851  */
6852 
6853 static ssize_t				/* O - Number of bytes read */
ipp_read_file(int * fd,ipp_uchar_t * buffer,size_t length)6854 ipp_read_file(int         *fd,		/* I - File descriptor */
6855               ipp_uchar_t *buffer,	/* O - Read buffer */
6856 	      size_t      length)	/* I - Number of bytes to read */
6857 {
6858 #ifdef WIN32
6859   return ((ssize_t)read(*fd, buffer, (unsigned)length));
6860 #else
6861   return (read(*fd, buffer, length));
6862 #endif /* WIN32 */
6863 }
6864 
6865 
6866 /*
6867  * 'ipp_set_error()' - Set a formatted, localized error string.
6868  */
6869 
6870 static void
ipp_set_error(ipp_status_t status,const char * format,...)6871 ipp_set_error(ipp_status_t status,	/* I - Status code */
6872               const char   *format,	/* I - Printf-style error string */
6873 	      ...)			/* I - Additional arguments as needed */
6874 {
6875   va_list	ap;			/* Pointer to additional args */
6876   char		buffer[2048];		/* Message buffer */
6877   cups_lang_t	*lang = cupsLangDefault();
6878 					/* Current language */
6879 
6880 
6881   va_start(ap, format);
6882   vsnprintf(buffer, sizeof(buffer), _cupsLangString(lang, format), ap);
6883   va_end(ap);
6884 
6885   _cupsSetError(status, buffer, 0);
6886 }
6887 
6888 
6889 /*
6890  * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
6891  *                     needed.
6892  */
6893 
6894 static _ipp_value_t *			/* O  - IPP value element or NULL on error */
ipp_set_value(ipp_t * ipp,ipp_attribute_t ** attr,int element)6895 ipp_set_value(ipp_t           *ipp,	/* IO - IPP message */
6896               ipp_attribute_t **attr,	/* IO - IPP attribute */
6897               int             element)	/* I  - Value number (0-based) */
6898 {
6899   ipp_attribute_t	*temp,		/* New attribute pointer */
6900 			*current,	/* Current attribute in list */
6901 			*prev;		/* Previous attribute in list */
6902   int			alloc_values;	/* Allocated values */
6903 
6904 
6905  /*
6906   * If we are setting an existing value element, return it...
6907   */
6908 
6909   temp = *attr;
6910 
6911   if (temp->num_values <= 1)
6912     alloc_values = 1;
6913   else
6914     alloc_values = (temp->num_values + IPP_MAX_VALUES - 1) &
6915                    ~(IPP_MAX_VALUES - 1);
6916 
6917   if (element < alloc_values)
6918   {
6919     if (element >= temp->num_values)
6920       temp->num_values = element + 1;
6921 
6922     return (temp->values + element);
6923   }
6924 
6925  /*
6926   * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
6927   * values when num_values > 1.
6928   */
6929 
6930   if (alloc_values < IPP_MAX_VALUES)
6931     alloc_values = IPP_MAX_VALUES;
6932   else
6933     alloc_values += IPP_MAX_VALUES;
6934 
6935   DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
6936                 alloc_values));
6937 
6938  /*
6939   * Reallocate memory...
6940   */
6941 
6942   if ((temp = realloc(temp, sizeof(ipp_attribute_t) + (size_t)(alloc_values - 1) * sizeof(_ipp_value_t))) == NULL)
6943   {
6944     _cupsSetHTTPError(HTTP_STATUS_ERROR);
6945     DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
6946     return (NULL);
6947   }
6948 
6949  /*
6950   * Zero the new memory...
6951   */
6952 
6953   memset(temp->values + temp->num_values, 0, (size_t)(alloc_values - temp->num_values) * sizeof(_ipp_value_t));
6954 
6955   if (temp != *attr)
6956   {
6957    /*
6958     * Reset pointers in the list...
6959     */
6960 
6961     if (ipp->current == *attr && ipp->prev)
6962     {
6963      /*
6964       * Use current "previous" pointer...
6965       */
6966 
6967       prev = ipp->prev;
6968     }
6969     else
6970     {
6971      /*
6972       * Find this attribute in the linked list...
6973       */
6974 
6975       for (prev = NULL, current = ipp->attrs;
6976 	   current && current != *attr;
6977 	   prev = current, current = current->next);
6978 
6979       if (!current)
6980       {
6981        /*
6982 	* This is a serious error!
6983 	*/
6984 
6985 	*attr = temp;
6986 	_cupsSetError(IPP_STATUS_ERROR_INTERNAL,
6987 	              _("IPP attribute is not a member of the message."), 1);
6988 	DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
6989 	return (NULL);
6990       }
6991     }
6992 
6993     if (prev)
6994       prev->next = temp;
6995     else
6996       ipp->attrs = temp;
6997 
6998     ipp->current = temp;
6999     ipp->prev    = prev;
7000 
7001     if (ipp->last == *attr)
7002       ipp->last = temp;
7003 
7004     *attr = temp;
7005   }
7006 
7007  /*
7008   * Return the value element...
7009   */
7010 
7011   if (element >= temp->num_values)
7012     temp->num_values = element + 1;
7013 
7014   return (temp->values + element);
7015 }
7016 
7017 
7018 /*
7019  * 'ipp_write_file()' - Write IPP data to a file.
7020  */
7021 
7022 static ssize_t				/* O - Number of bytes written */
ipp_write_file(int * fd,ipp_uchar_t * buffer,size_t length)7023 ipp_write_file(int         *fd,		/* I - File descriptor */
7024                ipp_uchar_t *buffer,	/* I - Data to write */
7025                size_t      length)	/* I - Number of bytes to write */
7026 {
7027 #ifdef WIN32
7028   return ((ssize_t)write(*fd, buffer, (unsigned)length));
7029 #else
7030   return (write(*fd, buffer, length));
7031 #endif /* WIN32 */
7032 }
7033