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