4 * Internet Printing Protocol functions for CUPS.
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * Include necessary headers...
22 #include "cups-private.h"
33 static ipp_attribute_t
*ipp_add_attr(ipp_t
*ipp
, const char *name
,
34 ipp_tag_t group_tag
, ipp_tag_t value_tag
,
36 static void ipp_free_values(ipp_attribute_t
*attr
, int element
,
38 static char *ipp_get_code(const char *locale
, char *buffer
,
40 __attribute__((nonnull(1,2)));
41 static char *ipp_lang_code(const char *locale
, char *buffer
,
43 __attribute__((nonnull(1,2)));
44 static size_t ipp_length(ipp_t
*ipp
, int collection
);
45 static ssize_t
ipp_read_http(http_t
*http
, ipp_uchar_t
*buffer
,
47 static ssize_t
ipp_read_file(int *fd
, ipp_uchar_t
*buffer
,
49 static void ipp_set_error(ipp_status_t status
, const char *format
,
51 static _ipp_value_t
*ipp_set_value(ipp_t
*ipp
, ipp_attribute_t
**attr
,
53 static ssize_t
ipp_write_file(int *fd
, ipp_uchar_t
*buffer
,
58 * '_cupsBufferGet()' - Get a read/write buffer.
61 char * /* O - Buffer */
62 _cupsBufferGet(size_t size
) /* I - Size required */
64 _cups_buffer_t
*buffer
; /* Current buffer */
65 _cups_globals_t
*cg
= _cupsGlobals();
69 for (buffer
= cg
->cups_buffers
; buffer
; buffer
= buffer
->next
)
70 if (!buffer
->used
&& buffer
->size
>= size
)
75 if ((buffer
= malloc(sizeof(_cups_buffer_t
) + size
- 1)) == NULL
)
78 buffer
->next
= cg
->cups_buffers
;
80 cg
->cups_buffers
= buffer
;
90 * '_cupsBufferRelease()' - Release a read/write buffer.
94 _cupsBufferRelease(char *b
) /* I - Buffer to release */
96 _cups_buffer_t
*buffer
; /* Buffer */
100 * Mark this buffer as unused...
103 buffer
= (_cups_buffer_t
*)(b
- offsetof(_cups_buffer_t
, d
));
109 * 'ippAddBoolean()' - Add a boolean attribute to an IPP message.
111 * The @code ipp@ parameter refers to an IPP message previously created using
112 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
121 ipp_attribute_t
* /* O - New attribute */
122 ippAddBoolean(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 */
127 ipp_attribute_t
*attr
; /* New attribute */
130 DEBUG_printf(("ippAddBoolean(ipp=%p, group=%02x(%s), name=\"%s\", value=%d)",
131 ipp
, group
, ippTagString(group
), name
, value
));
134 * Range check input...
137 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
138 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
142 * Create the attribute...
145 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BOOLEAN
, 1)) == NULL
)
148 attr
->values
[0].boolean
= value
;
155 * 'ippAddBooleans()' - Add an array of boolean values.
157 * The @code ipp@ parameter refers to an IPP message previously created using
158 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
167 ipp_attribute_t
* /* O - New attribute */
168 ippAddBooleans(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 */
174 int i
; /* Looping var */
175 ipp_attribute_t
*attr
; /* New attribute */
176 _ipp_value_t
*value
; /* Current value */
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
));
184 * Range check input...
187 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
188 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
193 * Create the attribute...
196 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BOOLEAN
, num_values
)) == NULL
)
201 for (i
= num_values
, value
= attr
->values
;
204 value
->boolean
= *values
++;
212 * 'ippAddCollection()' - Add a collection value.
214 * The @code ipp@ parameter refers to an IPP message previously created using
215 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
223 * @since CUPS 1.1.19/OS X 10.3@
226 ipp_attribute_t
* /* O - New attribute */
227 ippAddCollection(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 */
232 ipp_attribute_t
*attr
; /* New attribute */
235 DEBUG_printf(("ippAddCollection(ipp=%p, group=%02x(%s), name=\"%s\", "
236 "value=%p)", ipp
, group
, ippTagString(group
), name
, value
));
239 * Range check input...
242 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
243 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
247 * Create the attribute...
250 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BEGIN_COLLECTION
, 1)) == NULL
)
253 attr
->values
[0].collection
= value
;
263 * 'ippAddCollections()' - Add an array of collection values.
265 * The @code ipp@ parameter refers to an IPP message previously created using
266 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
274 * @since CUPS 1.1.19/OS X 10.3@
277 ipp_attribute_t
* /* O - New attribute */
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 */
285 int i
; /* Looping var */
286 ipp_attribute_t
*attr
; /* New attribute */
287 _ipp_value_t
*value
; /* Current value */
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
));
295 * Range check input...
298 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
299 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
304 * Create the attribute...
307 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BEGIN_COLLECTION
,
308 num_values
)) == NULL
)
313 for (i
= num_values
, value
= attr
->values
;
317 value
->collection
= (ipp_t
*)*values
++;
318 value
->collection
->use
++;
327 * 'ippAddDate()' - Add a date attribute to an IPP message.
329 * The @code ipp@ parameter refers to an IPP message previously created using
330 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
339 ipp_attribute_t
* /* O - New attribute */
340 ippAddDate(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 */
345 ipp_attribute_t
*attr
; /* New attribute */
348 DEBUG_printf(("ippAddDate(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)",
349 ipp
, group
, ippTagString(group
), name
, value
));
352 * Range check input...
355 if (!ipp
|| !name
|| !value
|| group
< IPP_TAG_ZERO
||
356 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
360 * Create the attribute...
363 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_DATE
, 1)) == NULL
)
366 memcpy(attr
->values
[0].date
, value
, 11);
373 * 'ippAddInteger()' - Add a integer attribute to an IPP message.
375 * The @code ipp@ parameter refers to an IPP message previously created using
376 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
384 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
385 * (@code IPP_TAG_INTEGER@).
388 ipp_attribute_t
* /* O - New attribute */
389 ippAddInteger(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 */
395 ipp_attribute_t
*attr
; /* New attribute */
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
));
402 value_tag
&= IPP_TAG_CUPS_MASK
;
405 * Special-case for legacy usage: map out-of-band attributes to new ippAddOutOfBand
409 if (value_tag
>= IPP_TAG_UNSUPPORTED_VALUE
&& value_tag
<= IPP_TAG_ADMINDEFINE
)
410 return (ippAddOutOfBand(ipp
, group
, value_tag
, name
));
413 * Range check input...
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
))
422 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
423 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
428 * Create the attribute...
431 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, 1)) == NULL
)
434 attr
->values
[0].integer
= value
;
441 * 'ippAddIntegers()' - Add an array of integer values.
443 * The @code ipp@ parameter refers to an IPP message previously created using
444 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
452 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
453 * (@code IPP_TAG_INTEGER@).
456 ipp_attribute_t
* /* O - New attribute */
457 ippAddIntegers(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 */
464 int i
; /* Looping var */
465 ipp_attribute_t
*attr
; /* New attribute */
466 _ipp_value_t
*value
; /* Current value */
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
));
474 value_tag
&= IPP_TAG_CUPS_MASK
;
477 * Range check input...
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
) ||
487 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
488 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
494 * Create the attribute...
497 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, num_values
)) == NULL
)
502 for (i
= num_values
, value
= attr
->values
;
505 value
->integer
= *values
++;
513 * 'ippAddOctetString()' - Add an octetString value to an IPP message.
515 * The @code ipp@ parameter refers to an IPP message previously created using
516 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
524 * @since CUPS 1.2/OS X 10.5@
527 ipp_attribute_t
* /* O - New attribute */
528 ippAddOctetString(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 */
534 ipp_attribute_t
*attr
; /* New attribute */
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
)
542 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_STRING
, 1)) == NULL
)
546 * Initialize the attribute data...
549 attr
->values
[0].unknown
.length
= datalen
;
553 if ((attr
->values
[0].unknown
.data
= malloc((size_t)datalen
)) == NULL
)
555 ippDeleteAttribute(ipp
, attr
);
559 memcpy(attr
->values
[0].unknown
.data
, data
, (size_t)datalen
);
563 * Return the new attribute...
571 * 'ippAddOutOfBand()' - Add an out-of-band value to an IPP message.
573 * The @code ipp@ parameter refers to an IPP message previously created using
574 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
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@).
588 * @since CUPS 1.6/OS X 10.8@
591 ipp_attribute_t
* /* O - New attribute */
592 ippAddOutOfBand(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 */
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
));
601 value_tag
&= IPP_TAG_CUPS_MASK
;
604 * Range check input...
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
))
619 * Create the attribute...
622 return (ipp_add_attr(ipp
, name
, group
, value_tag
, 1));
627 * 'ippAddRange()' - Add a range of values to an IPP message.
629 * The @code ipp@ parameter refers to an IPP message previously created using
630 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
638 * The @code lower@ parameter must be less than or equal to the @code upper@ parameter.
641 ipp_attribute_t
* /* O - New attribute */
642 ippAddRange(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 */
648 ipp_attribute_t
*attr
; /* New attribute */
651 DEBUG_printf(("ippAddRange(ipp=%p, group=%02x(%s), name=\"%s\", lower=%d, "
652 "upper=%d)", ipp
, group
, ippTagString(group
), name
, lower
,
656 * Range check input...
659 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
660 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
664 * Create the attribute...
667 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RANGE
, 1)) == NULL
)
670 attr
->values
[0].range
.lower
= lower
;
671 attr
->values
[0].range
.upper
= upper
;
678 * 'ippAddRanges()' - Add ranges of values to an IPP message.
680 * The @code ipp@ parameter refers to an IPP message previously created using
681 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
690 ipp_attribute_t
* /* O - New attribute */
691 ippAddRanges(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 */
698 int i
; /* Looping var */
699 ipp_attribute_t
*attr
; /* New attribute */
700 _ipp_value_t
*value
; /* Current value */
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
));
708 * Range check input...
711 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
712 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
717 * Create the attribute...
720 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RANGE
, num_values
)) == NULL
)
725 for (i
= num_values
, value
= attr
->values
;
729 value
->range
.lower
= *lower
++;
730 value
->range
.upper
= *upper
++;
739 * 'ippAddResolution()' - Add a resolution value to an IPP message.
741 * The @code ipp@ parameter refers to an IPP message previously created using
742 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
751 ipp_attribute_t
* /* O - New attribute */
752 ippAddResolution(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 */
759 ipp_attribute_t
*attr
; /* New attribute */
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
));
767 * Range check input...
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)
777 * Create the attribute...
780 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RESOLUTION
, 1)) == NULL
)
783 attr
->values
[0].resolution
.xres
= xres
;
784 attr
->values
[0].resolution
.yres
= yres
;
785 attr
->values
[0].resolution
.units
= units
;
792 * 'ippAddResolutions()' - Add resolution values to an IPP message.
794 * The @code ipp@ parameter refers to an IPP message previously created using
795 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
804 ipp_attribute_t
* /* O - New attribute */
805 ippAddResolutions(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 */
813 int i
; /* Looping var */
814 ipp_attribute_t
*attr
; /* New attribute */
815 _ipp_value_t
*value
; /* Current value */
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
));
823 * Range check input...
826 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
827 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
829 units
< IPP_RES_PER_INCH
|| units
> IPP_RES_PER_CM
)
833 * Create the attribute...
836 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RESOLUTION
, num_values
)) == NULL
)
841 for (i
= num_values
, value
= attr
->values
;
845 value
->resolution
.xres
= *xres
++;
846 value
->resolution
.yres
= *yres
++;
847 value
->resolution
.units
= units
;
856 * 'ippAddSeparator()' - Add a group separator to an IPP message.
858 * The @code ipp@ parameter refers to an IPP message previously created using
859 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
862 ipp_attribute_t
* /* O - New attribute */
863 ippAddSeparator(ipp_t
*ipp
) /* I - IPP message */
865 DEBUG_printf(("ippAddSeparator(ipp=%p)", ipp
));
868 * Range check input...
875 * Create the attribute...
878 return (ipp_add_attr(ipp
, NULL
, IPP_TAG_ZERO
, IPP_TAG_ZERO
, 0));
883 * 'ippAddString()' - Add a language-encoded string to an IPP message.
885 * The @code ipp@ parameter refers to an IPP message previously created using
886 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
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@).
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.
905 ipp_attribute_t
* /* O - New attribute */
906 ippAddString(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 */
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 */
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
,
925 * Range check input...
928 temp_tag
= (ipp_tag_t
)((int)value_tag
& IPP_TAG_CUPS_MASK
);
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
)
937 if ((temp_tag
== IPP_TAG_TEXTLANG
|| temp_tag
== IPP_TAG_NAMELANG
)
938 != (language
!= NULL
))
941 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
942 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
947 * See if we need to map charset, language, or locale values...
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 */
961 * Create the attribute...
964 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, 1)) == NULL
)
968 * Initialize the attribute data...
971 if ((int)value_tag
& IPP_TAG_CUPS_CONST
)
973 attr
->values
[0].string
.language
= (char *)language
;
974 attr
->values
[0].string
.text
= (char *)value
;
979 attr
->values
[0].string
.language
= _cupsStrAlloc(ipp_lang_code(language
, code
,
984 if (value_tag
== IPP_TAG_CHARSET
)
985 attr
->values
[0].string
.text
= _cupsStrAlloc(ipp_get_code(value
, code
,
987 else if (value_tag
== IPP_TAG_LANGUAGE
)
988 attr
->values
[0].string
.text
= _cupsStrAlloc(ipp_lang_code(value
, code
,
991 attr
->values
[0].string
.text
= _cupsStrAlloc(value
);
1000 * 'ippAddStringf()' - Add a formatted string to an IPP message.
1002 * The @code ipp@ parameter refers to an IPP message previously created using
1003 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
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@).
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
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.
1028 * @since CUPS 1.7/OS X 10.9@
1031 ipp_attribute_t
* /* O - New attribute */
1032 ippAddStringf(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 */
1040 ipp_attribute_t
*attr
; /* New attribute */
1041 va_list ap
; /* Argument pointer */
1044 va_start(ap
, format
);
1045 attr
= ippAddStringfv(ipp
, group
, value_tag
, name
, language
, format
, ap
);
1053 * 'ippAddStringfv()' - Add a formatted string to an IPP message.
1055 * The @code ipp@ parameter refers to an IPP message previously created using
1056 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
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@).
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
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.
1081 * @since CUPS 1.7/OS X 10.9@
1084 ipp_attribute_t
* /* O - New attribute */
1085 ippAddStringfv(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 */
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 */
1100 * Range check input...
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
||
1110 if ((value_tag
== IPP_TAG_TEXTLANG
|| value_tag
== IPP_TAG_NAMELANG
)
1111 != (language
!= NULL
))
1115 * Format the string...
1118 if (!strcmp(format
, "%s"))
1121 * Optimize the simple case...
1124 const char *s
= va_arg(ap
, char *);
1129 bytes
= (ssize_t
)strlen(s
);
1130 strlcpy(buffer
, s
, sizeof(buffer
));
1135 * Do a full formatting of the message...
1138 if ((bytes
= vsnprintf(buffer
, sizeof(buffer
), format
, ap
)) < 0)
1143 * Limit the length of the string...
1150 case IPP_TAG_TEXTLANG
:
1151 max_bytes
= IPP_MAX_TEXT
;
1155 case IPP_TAG_NAMELANG
:
1156 max_bytes
= IPP_MAX_NAME
;
1159 case IPP_TAG_CHARSET
:
1160 max_bytes
= IPP_MAX_CHARSET
;
1163 case IPP_TAG_KEYWORD
:
1164 max_bytes
= IPP_MAX_KEYWORD
;
1167 case IPP_TAG_LANGUAGE
:
1168 max_bytes
= IPP_MAX_LANGUAGE
;
1171 case IPP_TAG_MIMETYPE
:
1172 max_bytes
= IPP_MAX_MIMETYPE
;
1176 max_bytes
= IPP_MAX_URI
;
1179 case IPP_TAG_URISCHEME
:
1180 max_bytes
= IPP_MAX_URISCHEME
;
1184 if (bytes
>= max_bytes
)
1186 char *bufmax
, /* Buffer at max_bytes */
1187 *bufptr
; /* Pointer into buffer */
1189 bufptr
= buffer
+ strlen(buffer
) - 1;
1190 bufmax
= buffer
+ max_bytes
- 1;
1192 while (bufptr
> bufmax
)
1196 while ((*bufptr
& 0xc0) == 0x80 && bufptr
> buffer
)
1207 * Add the formatted string and return...
1210 return (ippAddString(ipp
, group
, value_tag
, name
, language
, buffer
));
1215 * 'ippAddStrings()' - Add language-encoded strings to an IPP message.
1217 * The @code ipp@ parameter refers to an IPP message previously created using
1218 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
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@).
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@).
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.
1237 ipp_attribute_t
* /* O - New attribute */
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 */
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 */
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
));
1260 * Range check input...
1263 temp_tag
= (ipp_tag_t
)((int)value_tag
& IPP_TAG_CUPS_MASK
);
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
||
1273 if ((temp_tag
== IPP_TAG_TEXTLANG
|| temp_tag
== IPP_TAG_NAMELANG
)
1274 != (language
!= NULL
))
1277 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1278 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1284 * See if we need to map charset, language, or locale values...
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
))
1292 for (i
= 0; i
< num_values
; i
++)
1293 if (strcmp(values
[i
], ipp_get_code(values
[i
], code
, sizeof(code
))))
1295 value_tag
= temp_tag
; /* Don't do a fast copy */
1299 else if (values
&& value_tag
== (ipp_tag_t
)(IPP_TAG_LANGUAGE
| IPP_TAG_CUPS_CONST
))
1301 for (i
= 0; i
< num_values
; i
++)
1302 if (strcmp(values
[i
], ipp_lang_code(values
[i
], code
, sizeof(code
))))
1304 value_tag
= temp_tag
; /* Don't do a fast copy */
1310 * Create the attribute...
1313 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, num_values
)) == NULL
)
1317 * Initialize the attribute data...
1320 for (i
= num_values
, value
= attr
->values
;
1326 if (value
== attr
->values
)
1328 if ((int)value_tag
& IPP_TAG_CUPS_CONST
)
1329 value
->string
.language
= (char *)language
;
1331 value
->string
.language
= _cupsStrAlloc(ipp_lang_code(language
, code
,
1335 value
->string
.language
= attr
->values
[0].string
.language
;
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
)));
1347 value
->string
.text
= _cupsStrAlloc(*values
++);
1356 * 'ippContainsInteger()' - Determine whether an attribute contains the
1357 * specified value or is within the list of ranges.
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
1363 * @since CUPS 1.7/OS X 10.9@
1366 int /* O - 1 on a match, 0 on no match */
1368 ipp_attribute_t
*attr
, /* I - Attribute */
1369 int value
) /* I - Integer/enum value */
1371 int i
; /* Looping var */
1372 _ipp_value_t
*avalue
; /* Current attribute value */
1376 * Range check input...
1382 if (attr
->value_tag
!= IPP_TAG_INTEGER
&& attr
->value_tag
!= IPP_TAG_ENUM
&&
1383 attr
->value_tag
!= IPP_TAG_RANGE
)
1390 if (attr
->value_tag
== IPP_TAG_RANGE
)
1392 for (i
= attr
->num_values
, avalue
= attr
->values
; i
> 0; i
--, avalue
++)
1393 if (value
>= avalue
->range
.lower
&& value
<= avalue
->range
.upper
)
1398 for (i
= attr
->num_values
, avalue
= attr
->values
; i
> 0; i
--, avalue
++)
1399 if (value
== avalue
->integer
)
1408 * 'ippContainsString()' - Determine whether an attribute contains the
1409 * specified string value.
1411 * Returns non-zero when the attribute contains a matching charset, keyword,
1412 * language, mimeMediaType, name, text, URI, or URI scheme value.
1414 * @since CUPS 1.7/OS X 10.9@
1417 int /* O - 1 on a match, 0 on no match */
1419 ipp_attribute_t
*attr
, /* I - Attribute */
1420 const char *value
) /* I - String value */
1422 int i
; /* Looping var */
1423 _ipp_value_t
*avalue
; /* Current attribute value */
1426 DEBUG_printf(("ippContainsString(attr=%p, value=\"%s\")", attr
, value
));
1429 * Range check input...
1432 if (!attr
|| !value
)
1434 DEBUG_puts("1ippContainsString: Returning 0 (bad input)");
1442 DEBUG_printf(("1ippContainsString: attr %s, %s with %d values.",
1443 attr
->name
, ippTagString(attr
->value_tag
),
1446 switch (attr
->value_tag
& IPP_TAG_CUPS_MASK
)
1448 case IPP_TAG_CHARSET
:
1449 case IPP_TAG_KEYWORD
:
1450 case IPP_TAG_LANGUAGE
:
1451 case IPP_TAG_MIMETYPE
:
1453 case IPP_TAG_NAMELANG
:
1455 case IPP_TAG_TEXTLANG
:
1457 case IPP_TAG_URISCHEME
:
1458 for (i
= attr
->num_values
, avalue
= attr
->values
;
1462 DEBUG_printf(("1ippContainsString: value[%d]=\"%s\"",
1463 attr
->num_values
- i
, avalue
->string
.text
));
1465 if (!strcmp(value
, avalue
->string
.text
))
1467 DEBUG_puts("1ippContainsString: Returning 1 (match)");
1476 DEBUG_puts("1ippContainsString: Returning 0 (no match)");
1483 * 'ippCopyAttribute()' - Copy an attribute.
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.
1490 * @since CUPS 1.6/OS X 10.8@
1494 ipp_attribute_t
* /* O - New attribute */
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 */
1500 int i
; /* Looping var */
1501 ipp_attribute_t
*dstattr
; /* Destination attribute */
1502 _ipp_value_t
*srcval
, /* Source value */
1503 *dstval
; /* Destination value */
1506 DEBUG_printf(("ippCopyAttribute(dst=%p, srcattr=%p, quickcopy=%d)", dst
, srcattr
,
1510 * Range check input...
1513 if (!dst
|| !srcattr
)
1520 quickcopy
= quickcopy
? IPP_TAG_CUPS_CONST
: 0;
1522 switch (srcattr
->value_tag
& ~IPP_TAG_CUPS_CONST
)
1525 dstattr
= ippAddSeparator(dst
);
1528 case IPP_TAG_INTEGER
:
1530 dstattr
= ippAddIntegers(dst
, srcattr
->group_tag
, srcattr
->value_tag
,
1531 srcattr
->name
, srcattr
->num_values
, NULL
);
1535 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1537 i
--, srcval
++, dstval
++)
1538 dstval
->integer
= srcval
->integer
;
1541 case IPP_TAG_BOOLEAN
:
1542 dstattr
= ippAddBooleans(dst
, srcattr
->group_tag
, srcattr
->name
,
1543 srcattr
->num_values
, NULL
);
1547 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1549 i
--, srcval
++, dstval
++)
1550 dstval
->boolean
= srcval
->boolean
;
1555 case IPP_TAG_KEYWORD
:
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
);
1569 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1570 dstval
= dstattr
->values
;
1572 i
--, srcval
++, dstval
++)
1573 dstval
->string
.text
= srcval
->string
.text
;
1575 else if (srcattr
->value_tag
& IPP_TAG_CUPS_CONST
)
1577 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1578 dstval
= dstattr
->values
;
1580 i
--, srcval
++, dstval
++)
1581 dstval
->string
.text
= _cupsStrAlloc(srcval
->string
.text
);
1585 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1586 dstval
= dstattr
->values
;
1588 i
--, srcval
++, dstval
++)
1589 dstval
->string
.text
= _cupsStrRetain(srcval
->string
.text
);
1594 if (srcattr
->num_values
!= 1)
1597 dstattr
= ippAddDate(dst
, srcattr
->group_tag
, srcattr
->name
,
1598 srcattr
->values
[0].date
);
1601 case IPP_TAG_RESOLUTION
:
1602 dstattr
= ippAddResolutions(dst
, srcattr
->group_tag
, srcattr
->name
,
1603 srcattr
->num_values
, IPP_RES_PER_INCH
,
1608 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1610 i
--, srcval
++, dstval
++)
1612 dstval
->resolution
.xres
= srcval
->resolution
.xres
;
1613 dstval
->resolution
.yres
= srcval
->resolution
.yres
;
1614 dstval
->resolution
.units
= srcval
->resolution
.units
;
1618 case IPP_TAG_RANGE
:
1619 dstattr
= ippAddRanges(dst
, srcattr
->group_tag
, srcattr
->name
,
1620 srcattr
->num_values
, NULL
, NULL
);
1624 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1626 i
--, srcval
++, dstval
++)
1628 dstval
->range
.lower
= srcval
->range
.lower
;
1629 dstval
->range
.upper
= srcval
->range
.upper
;
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
);
1643 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1644 dstval
= dstattr
->values
;
1646 i
--, srcval
++, dstval
++)
1648 dstval
->string
.language
= srcval
->string
.language
;
1649 dstval
->string
.text
= srcval
->string
.text
;
1652 else if (srcattr
->value_tag
& IPP_TAG_CUPS_CONST
)
1654 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1655 dstval
= dstattr
->values
;
1657 i
--, srcval
++, dstval
++)
1659 if (srcval
== srcattr
->values
)
1660 dstval
->string
.language
= _cupsStrAlloc(srcval
->string
.language
);
1662 dstval
->string
.language
= dstattr
->values
[0].string
.language
;
1664 dstval
->string
.text
= _cupsStrAlloc(srcval
->string
.text
);
1669 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1670 dstval
= dstattr
->values
;
1672 i
--, srcval
++, dstval
++)
1674 if (srcval
== srcattr
->values
)
1675 dstval
->string
.language
= _cupsStrRetain(srcval
->string
.language
);
1677 dstval
->string
.language
= dstattr
->values
[0].string
.language
;
1679 dstval
->string
.text
= _cupsStrRetain(srcval
->string
.text
);
1684 case IPP_TAG_BEGIN_COLLECTION
:
1685 dstattr
= ippAddCollections(dst
, srcattr
->group_tag
, srcattr
->name
,
1686 srcattr
->num_values
, NULL
);
1690 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1692 i
--, srcval
++, dstval
++)
1694 dstval
->collection
= srcval
->collection
;
1695 srcval
->collection
->use
++;
1699 case IPP_TAG_STRING
:
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
);
1707 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1709 i
--, srcval
++, dstval
++)
1711 dstval
->unknown
.length
= srcval
->unknown
.length
;
1713 if (dstval
->unknown
.length
> 0)
1715 if ((dstval
->unknown
.data
= malloc((size_t)dstval
->unknown
.length
)) == NULL
)
1716 dstval
->unknown
.length
= 0;
1718 memcpy(dstval
->unknown
.data
, srcval
->unknown
.data
, (size_t)dstval
->unknown
.length
);
1721 break; /* anti-compiler-warning-code */
1729 * 'ippCopyAttributes()' - Copy attributes from one IPP message to another.
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.
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
1741 * @since CUPS 1.6/OS X 10.8@
1744 int /* O - 1 on success, 0 on error */
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 */
1752 ipp_attribute_t
*srcattr
; /* Source attribute */
1755 DEBUG_printf(("ippCopyAttributes(dst=%p, src=%p, quickcopy=%d, cb=%p, context=%p)",
1756 dst
, src
, quickcopy
, cb
, context
));
1759 * Range check input...
1766 * Loop through source attributes and copy as needed...
1769 for (srcattr
= src
->attrs
; srcattr
; srcattr
= srcattr
->next
)
1770 if (!cb
|| (*cb
)(context
, dst
, srcattr
))
1771 if (!ippCopyAttribute(dst
, srcattr
, quickcopy
))
1779 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
1783 time_t /* O - UNIX time value */
1784 ippDateToTime(const ipp_uchar_t
*date
) /* I - RFC 1903 date info */
1786 struct tm unixdate
; /* UNIX date/time info */
1787 time_t t
; /* Computed time */
1793 memset(&unixdate
, 0, sizeof(unixdate
));
1796 * RFC-1903 date/time format is:
1798 * Byte(s) Description
1799 * ------- -----------
1800 * 0-1 Year (0 to 65535)
1804 * 5 Minutes (0 to 59)
1805 * 6 Seconds (0 to 60, 60 = "leap second")
1806 * 7 Deciseconds (0 to 9)
1808 * 9 UTC hours (0 to 11)
1809 * 10 UTC minutes (0 to 59)
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];
1819 t
= mktime(&unixdate
);
1822 t
+= date
[9] * 3600 + date
[10] * 60;
1824 t
-= date
[9] * 3600 + date
[10] * 60;
1831 * 'ippDelete()' - Delete an IPP message.
1835 ippDelete(ipp_t
*ipp
) /* I - IPP message */
1837 ipp_attribute_t
*attr
, /* Current attribute */
1838 *next
; /* Next attribute */
1841 DEBUG_printf(("ippDelete(ipp=%p)", ipp
));
1850 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= next
)
1854 ipp_free_values(attr
, 0, attr
->num_values
);
1857 _cupsStrFree(attr
->name
);
1867 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
1869 * @since CUPS 1.1.19/OS X 10.3@
1874 ipp_t
*ipp
, /* I - IPP message */
1875 ipp_attribute_t
*attr
) /* I - Attribute to delete */
1877 ipp_attribute_t
*current
, /* Current attribute */
1878 *prev
; /* Previous attribute */
1881 DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p(%s))", ipp
, attr
,
1882 attr
? attr
->name
: "(null)"));
1885 * Range check input...
1892 * Find the attribute in the list...
1897 for (current
= ipp
->attrs
, prev
= NULL
;
1899 prev
= current
, current
= current
->next
)
1900 if (current
== attr
)
1903 * Found it, remove the attribute from the list...
1907 prev
->next
= current
->next
;
1909 ipp
->attrs
= current
->next
;
1911 if (current
== ipp
->last
)
1922 * Free memory used by the attribute...
1925 ipp_free_values(attr
, 0, attr
->num_values
);
1928 _cupsStrFree(attr
->name
);
1935 * 'ippDeleteValues()' - Delete values in an attribute.
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@.
1940 * The @code attr@ parameter may be modified as a result of setting the value.
1942 * Deleting all values in an attribute deletes the attribute.
1944 * @since CUPS 1.6/OS X 10.8@
1947 int /* O - 1 on success, 0 on failure */
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 */
1955 * Range check input...
1958 if (!ipp
|| !attr
|| !*attr
||
1959 element
< 0 || element
>= (*attr
)->num_values
|| count
<= 0 ||
1960 (element
+ count
) >= (*attr
)->num_values
)
1964 * If we are deleting all values, just delete the attribute entirely.
1967 if (count
== (*attr
)->num_values
)
1969 ippDeleteAttribute(ipp
, *attr
);
1975 * Otherwise free the values in question and return.
1978 ipp_free_values(*attr
, element
, count
);
1985 * 'ippFindAttribute()' - Find a named attribute in a request.
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".
1992 ipp_attribute_t
* /* O - Matching attribute */
1993 ippFindAttribute(ipp_t
*ipp
, /* I - IPP message */
1994 const char *name
, /* I - Name of attribute */
1995 ipp_tag_t type
) /* I - Type of attribute */
1997 DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", ipp
,
1998 name
, type
, ippTagString(type
)));
2004 * Reset the current pointer...
2007 ipp
->current
= NULL
;
2011 * Search for the attribute...
2014 return (ippFindNextAttribute(ipp
, name
, type
));
2019 * 'ippFindNextAttribute()' - Find the next named attribute in a request.
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".
2026 ipp_attribute_t
* /* O - Matching attribute */
2027 ippFindNextAttribute(ipp_t
*ipp
, /* I - IPP message */
2028 const char *name
, /* I - Name of attribute */
2029 ipp_tag_t type
) /* I - Type of attribute */
2031 ipp_attribute_t
*attr
, /* Current atttribute */
2032 *childattr
; /* Child attribute */
2033 ipp_tag_t value_tag
; /* Value tag */
2034 char parent
[1024], /* Parent attribute name */
2035 *child
= NULL
; /* Child attribute name */
2038 DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))",
2039 ipp
, name
, type
, ippTagString(type
)));
2044 DEBUG_printf(("3ippFindNextAttribute: atend=%d", ipp
->atend
));
2049 if (strchr(name
, '/'))
2052 * Search for child attribute...
2055 strlcpy(parent
, name
, sizeof(parent
));
2056 if ((child
= strchr(parent
, '/')) == NULL
)
2058 DEBUG_puts("3ippFindNextAttribute: Attribute name too long.");
2064 if (ipp
->current
&& ipp
->current
->name
&& ipp
->current
->value_tag
== IPP_TAG_BEGIN_COLLECTION
&& !strcmp(parent
, ipp
->current
->name
))
2066 while (ipp
->curindex
< ipp
->current
->num_values
)
2068 if ((childattr
= ippFindNextAttribute(ipp
->current
->values
[ipp
->curindex
].collection
, child
, type
)) != NULL
)
2072 if (ipp
->curindex
< ipp
->current
->num_values
&& ipp
->current
->values
[ipp
->curindex
].collection
)
2073 ipp
->current
->values
[ipp
->curindex
].collection
->current
= NULL
;
2076 ipp
->prev
= ipp
->current
;
2077 ipp
->current
= ipp
->current
->next
;
2090 ipp
->current
= ipp
->attrs
;
2095 attr
= ipp
->current
;
2097 else if (ipp
->current
)
2099 ipp
->prev
= ipp
->current
;
2100 attr
= ipp
->current
->next
;
2108 for (; attr
!= NULL
; ipp
->prev
= attr
, attr
= attr
->next
)
2110 DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", attr
,
2113 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_CUPS_MASK
);
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
)))
2120 ipp
->current
= attr
;
2122 if (name
== parent
&& attr
->value_tag
== IPP_TAG_BEGIN_COLLECTION
)
2124 int i
; /* Looping var */
2126 for (i
= 0; i
< attr
->num_values
; i
++)
2128 if ((childattr
= ippFindAttribute(attr
->values
[i
].collection
, child
, type
)) != NULL
)
2130 attr
->values
[0].collection
->curindex
= i
;
2140 ipp
->current
= NULL
;
2149 * 'ippFirstAttribute()' - Return the first attribute in the message.
2151 * @since CUPS 1.6/OS X 10.8@
2154 ipp_attribute_t
* /* O - First attribute or @code NULL@ if none */
2155 ippFirstAttribute(ipp_t
*ipp
) /* I - IPP message */
2158 * Range check input...
2165 * Return the first attribute...
2168 return (ipp
->current
= ipp
->attrs
);
2173 * 'ippGetBoolean()' - Get a boolean value for an attribute.
2175 * The @code element@ parameter specifies which value to get from 0 to
2176 * @link ippGetCount(attr)@ - 1.
2178 * @since CUPS 1.6/OS X 10.8@
2181 int /* O - Boolean value or 0 on error */
2182 ippGetBoolean(ipp_attribute_t
*attr
, /* I - IPP attribute */
2183 int element
) /* I - Value number (0-based) */
2186 * Range check input...
2189 if (!attr
|| attr
->value_tag
!= IPP_TAG_BOOLEAN
||
2190 element
< 0 || element
>= attr
->num_values
)
2194 * Return the value...
2197 return (attr
->values
[element
].boolean
);
2202 * 'ippGetCollection()' - Get a collection value for an attribute.
2204 * The @code element@ parameter specifies which value to get from 0 to
2205 * @link ippGetCount(attr)@ - 1.
2207 * @since CUPS 1.6/OS X 10.8@
2210 ipp_t
* /* O - Collection value or @code NULL@ on error */
2212 ipp_attribute_t
*attr
, /* I - IPP attribute */
2213 int element
) /* I - Value number (0-based) */
2216 * Range check input...
2219 if (!attr
|| attr
->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
2220 element
< 0 || element
>= attr
->num_values
)
2224 * Return the value...
2227 return (attr
->values
[element
].collection
);
2232 * 'ippGetCount()' - Get the number of values in an attribute.
2234 * @since CUPS 1.6/OS X 10.8@
2237 int /* O - Number of values or 0 on error */
2238 ippGetCount(ipp_attribute_t
*attr
) /* I - IPP attribute */
2241 * Range check input...
2248 * Return the number of values...
2251 return (attr
->num_values
);
2256 * 'ippGetDate()' - Get a date value for an attribute.
2258 * The @code element@ parameter specifies which value to get from 0 to
2259 * @link ippGetCount(attr)@ - 1.
2261 * @since CUPS 1.6/OS X 10.8@
2264 const ipp_uchar_t
* /* O - Date value or @code NULL@ */
2265 ippGetDate(ipp_attribute_t
*attr
, /* I - IPP attribute */
2266 int element
) /* I - Value number (0-based) */
2269 * Range check input...
2272 if (!attr
|| attr
->value_tag
!= IPP_TAG_DATE
||
2273 element
< 0 || element
>= attr
->num_values
)
2277 * Return the value...
2280 return (attr
->values
[element
].date
);
2285 * 'ippGetGroupTag()' - Get the group associated with an attribute.
2287 * @since CUPS 1.6/OS X 10.8@
2290 ipp_tag_t
/* O - Group tag or @code IPP_TAG_ZERO@ on error */
2291 ippGetGroupTag(ipp_attribute_t
*attr
) /* I - IPP attribute */
2294 * Range check input...
2298 return (IPP_TAG_ZERO
);
2301 * Return the group...
2304 return (attr
->group_tag
);
2309 * 'ippGetInteger()' - Get the integer/enum value for an attribute.
2311 * The @code element@ parameter specifies which value to get from 0 to
2312 * @link ippGetCount(attr)@ - 1.
2314 * @since CUPS 1.6/OS X 10.8@
2317 int /* O - Value or 0 on error */
2318 ippGetInteger(ipp_attribute_t
*attr
, /* I - IPP attribute */
2319 int element
) /* I - Value number (0-based) */
2322 * Range check input...
2325 if (!attr
|| (attr
->value_tag
!= IPP_TAG_INTEGER
&& attr
->value_tag
!= IPP_TAG_ENUM
) ||
2326 element
< 0 || element
>= attr
->num_values
)
2330 * Return the value...
2333 return (attr
->values
[element
].integer
);
2338 * 'ippGetName()' - Get the attribute name.
2340 * @since CUPS 1.6/OS X 10.8@
2343 const char * /* O - Attribute name or @code NULL@ for separators */
2344 ippGetName(ipp_attribute_t
*attr
) /* I - IPP attribute */
2347 * Range check input...
2354 * Return the name...
2357 return (attr
->name
);
2362 * 'ippGetOctetString()' - Get an octetString value from an IPP attribute.
2364 * The @code element@ parameter specifies which value to get from 0 to
2365 * @link ippGetCount(attr)@ - 1.
2367 * @since CUPS 1.7/OS X 10.9@
2370 void * /* O - Pointer to octetString data */
2372 ipp_attribute_t
*attr
, /* I - IPP attribute */
2373 int element
, /* I - Value number (0-based) */
2374 int *datalen
) /* O - Length of octetString data */
2377 * Range check input...
2380 if (!attr
|| attr
->value_tag
!= IPP_TAG_STRING
||
2381 element
< 0 || element
>= attr
->num_values
)
2390 * Return the values...
2394 *datalen
= attr
->values
[element
].unknown
.length
;
2396 return (attr
->values
[element
].unknown
.data
);
2401 * 'ippGetOperation()' - Get the operation ID in an IPP message.
2403 * @since CUPS 1.6/OS X 10.8@
2406 ipp_op_t
/* O - Operation ID or 0 on error */
2407 ippGetOperation(ipp_t
*ipp
) /* I - IPP request message */
2410 * Range check input...
2414 return ((ipp_op_t
)0);
2417 * Return the value...
2420 return (ipp
->request
.op
.operation_id
);
2425 * 'ippGetRange()' - Get a rangeOfInteger value from an attribute.
2427 * The @code element@ parameter specifies which value to get from 0 to
2428 * @link ippGetCount(attr)@ - 1.
2430 * @since CUPS 1.6/OS X 10.8@
2433 int /* O - Lower value of range or 0 */
2434 ippGetRange(ipp_attribute_t
*attr
, /* I - IPP attribute */
2435 int element
, /* I - Value number (0-based) */
2436 int *uppervalue
)/* O - Upper value of range */
2439 * Range check input...
2442 if (!attr
|| attr
->value_tag
!= IPP_TAG_RANGE
||
2443 element
< 0 || element
>= attr
->num_values
)
2452 * Return the values...
2456 *uppervalue
= attr
->values
[element
].range
.upper
;
2458 return (attr
->values
[element
].range
.lower
);
2463 * 'ippGetRequestId()' - Get the request ID from an IPP message.
2465 * @since CUPS 1.6/OS X 10.8@
2468 int /* O - Request ID or 0 on error */
2469 ippGetRequestId(ipp_t
*ipp
) /* I - IPP message */
2472 * Range check input...
2479 * Return the request ID...
2482 return (ipp
->request
.any
.request_id
);
2487 * 'ippGetResolution()' - Get a resolution value for an attribute.
2489 * The @code element@ parameter specifies which value to get from 0 to
2490 * @link ippGetCount(attr)@ - 1.
2492 * @since CUPS 1.6/OS X 10.8@
2495 int /* O - Horizontal/cross feed resolution or 0 */
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 */
2503 * Range check input...
2506 if (!attr
|| attr
->value_tag
!= IPP_TAG_RESOLUTION
||
2507 element
< 0 || element
>= attr
->num_values
)
2513 *units
= (ipp_res_t
)0;
2519 * Return the value...
2523 *yres
= attr
->values
[element
].resolution
.yres
;
2526 *units
= attr
->values
[element
].resolution
.units
;
2528 return (attr
->values
[element
].resolution
.xres
);
2533 * 'ippGetState()' - Get the IPP message state.
2535 * @since CUPS 1.6/OS X 10.8@
2538 ipp_state_t
/* O - IPP message state value */
2539 ippGetState(ipp_t
*ipp
) /* I - IPP message */
2542 * Range check input...
2546 return (IPP_STATE_IDLE
);
2549 * Return the value...
2552 return (ipp
->state
);
2557 * 'ippGetStatusCode()' - Get the status code from an IPP response or event message.
2559 * @since CUPS 1.6/OS X 10.8@
2562 ipp_status_t
/* O - Status code in IPP message */
2563 ippGetStatusCode(ipp_t
*ipp
) /* I - IPP response or event message */
2566 * Range check input...
2570 return (IPP_STATUS_ERROR_INTERNAL
);
2573 * Return the value...
2576 return (ipp
->request
.status
.status_code
);
2581 * 'ippGetString()' - Get the string and optionally the language code for an attribute.
2583 * The @code element@ parameter specifies which value to get from 0 to
2584 * @link ippGetCount(attr)@ - 1.
2586 * @since CUPS 1.6/OS X 10.8@
2590 ippGetString(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) */
2595 * Range check input...
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
)))
2604 * Return the value...
2608 *language
= attr
->values
[element
].string
.language
;
2610 return (attr
->values
[element
].string
.text
);
2615 * 'ippGetValueTag()' - Get the value tag for an attribute.
2617 * @since CUPS 1.6/OS X 10.8@
2620 ipp_tag_t
/* O - Value tag or @code IPP_TAG_ZERO@ on error */
2621 ippGetValueTag(ipp_attribute_t
*attr
) /* I - IPP attribute */
2624 * Range check input...
2628 return (IPP_TAG_ZERO
);
2631 * Return the value...
2634 return (attr
->value_tag
& IPP_TAG_CUPS_MASK
);
2639 * 'ippGetVersion()' - Get the major and minor version number from an IPP message.
2641 * @since CUPS 1.6/OS X 10.8@
2644 int /* O - Major version number or 0 on error */
2645 ippGetVersion(ipp_t
*ipp
, /* I - IPP message */
2646 int *minor
) /* O - Minor version number or @code NULL@ */
2649 * Range check input...
2661 * Return the value...
2665 *minor
= ipp
->request
.any
.version
[1];
2667 return (ipp
->request
.any
.version
[0]);
2672 * 'ippLength()' - Compute the length of an IPP message.
2675 size_t /* O - Size of IPP message */
2676 ippLength(ipp_t
*ipp
) /* I - IPP message */
2678 return (ipp_length(ipp
, 0));
2683 * 'ippNextAttribute()' - Return the next attribute in the message.
2685 * @since CUPS 1.6/OS X 10.8@
2688 ipp_attribute_t
* /* O - Next attribute or @code NULL@ if none */
2689 ippNextAttribute(ipp_t
*ipp
) /* I - IPP message */
2692 * Range check input...
2695 if (!ipp
|| !ipp
->current
)
2699 * Return the next attribute...
2702 return (ipp
->current
= ipp
->current
->next
);
2707 * 'ippNew()' - Allocate a new IPP message.
2710 ipp_t
* /* O - New IPP message */
2713 ipp_t
*temp
; /* New IPP message */
2714 _cups_globals_t
*cg
= _cupsGlobals();
2718 DEBUG_puts("ippNew()");
2720 if ((temp
= (ipp_t
*)calloc(1, sizeof(ipp_t
))) != NULL
)
2723 * Set default version - usually 2.0...
2726 if (cg
->server_version
== 0)
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);
2734 DEBUG_printf(("1ippNew: Returning %p", temp
));
2741 * 'ippNewRequest()' - Allocate a new IPP request message.
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.
2747 * @since CUPS 1.2/OS X 10.5@
2750 ipp_t
* /* O - IPP request message */
2751 ippNewRequest(ipp_op_t op
) /* I - Operation code */
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 */
2760 DEBUG_printf(("ippNewRequest(op=%02x(%s))", op
, ippOpString(op
)));
2763 * Create a new IPP message...
2766 if ((request
= ippNew()) == NULL
)
2770 * Set the operation and request ID...
2773 _cupsMutexLock(&request_mutex
);
2775 request
->request
.op
.operation_id
= op
;
2776 request
->request
.op
.request_id
= ++request_id
;
2778 _cupsMutexUnlock(&request_mutex
);
2781 * Use UTF-8 as the character set...
2784 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2785 "attributes-charset", NULL
, "utf-8");
2788 * Get the language from the current locale...
2791 language
= cupsLangDefault();
2793 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2794 "attributes-natural-language", NULL
, language
->language
);
2797 * Return the new request...
2805 * 'ippNewResponse()' - Allocate a new IPP response message.
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,
2814 * @since CUPS 1.7/OS X 10.9@
2817 ipp_t
* /* O - IPP response message */
2818 ippNewResponse(ipp_t
*request
) /* I - IPP request message */
2820 ipp_t
*response
; /* IPP response message */
2821 ipp_attribute_t
*attr
; /* Current attribute */
2825 * Range check input...
2832 * Create a new IPP message...
2835 if ((response
= ippNew()) == NULL
)
2839 * Copy the request values over to the response...
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
;
2847 * The first attribute MUST be attributes-charset...
2850 attr
= request
->attrs
;
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)
2858 * Copy charset from request...
2861 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2862 "attributes-charset", NULL
, attr
->values
[0].string
.text
);
2867 * Use "utf-8" as the default...
2870 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2871 "attributes-charset", NULL
, "utf-8");
2875 * Then attributes-natural-language...
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)
2888 * Copy language from request...
2891 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2892 "attributes-natural-language", NULL
,
2893 attr
->values
[0].string
.text
);
2898 * Use the language from the current locale...
2901 cups_lang_t
*language
= cupsLangDefault();
2902 /* Current locale */
2904 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2905 "attributes-natural-language", NULL
, language
->language
);
2913 * 'ippRead()' - Read data for an IPP message from a HTTP connection.
2916 ipp_state_t
/* O - Current state */
2917 ippRead(http_t
*http
, /* I - HTTP connection */
2918 ipp_t
*ipp
) /* I - IPP data */
2920 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT
,
2921 http
, ipp
, CUPS_LLCAST (http
? http
->data_remaining
: -1)));
2924 return (IPP_STATE_ERROR
);
2926 DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http
->state
,
2929 return (ippReadIO(http
, (ipp_iocb_t
)ipp_read_http
, http
->blocking
, NULL
,
2935 * 'ippReadFile()' - Read data for an IPP message from a file.
2937 * @since CUPS 1.1.19/OS X 10.3@
2940 ipp_state_t
/* O - Current state */
2941 ippReadFile(int fd
, /* I - HTTP data */
2942 ipp_t
*ipp
) /* I - IPP data */
2944 DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd
, ipp
));
2946 return (ippReadIO(&fd
, (ipp_iocb_t
)ipp_read_file
, 1, NULL
, ipp
));
2951 * 'ippReadIO()' - Read data for an IPP message.
2953 * @since CUPS 1.2/OS X 10.5@
2956 ipp_state_t
/* O - Current state */
2957 ippReadIO(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 */
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 */
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
));
2979 return (IPP_STATE_ERROR
);
2981 if ((buffer
= (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE
)) == NULL
)
2983 DEBUG_puts("1ippReadIO: Unable to get read buffer.");
2984 return (IPP_STATE_ERROR
);
2989 case IPP_STATE_IDLE
:
2990 ipp
->state
++; /* Avoid common problem... */
2992 case IPP_STATE_HEADER
:
2996 * Get the request header...
2999 if ((*cb
)(src
, buffer
, 8) < 8)
3001 DEBUG_puts("1ippReadIO: Unable to read header.");
3002 _cupsBufferRelease((char *)buffer
);
3003 return (IPP_STATE_ERROR
);
3007 * Then copy the request header over...
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];
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
));
3023 ipp
->state
= IPP_STATE_ATTRIBUTE
;
3024 ipp
->current
= NULL
;
3025 ipp
->curtag
= IPP_TAG_ZERO
;
3026 ipp
->prev
= ipp
->last
;
3029 * If blocking is disabled, stop here...
3035 case IPP_STATE_ATTRIBUTE
:
3038 if ((*cb
)(src
, buffer
, 1) < 1)
3040 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
3041 _cupsBufferRelease((char *)buffer
);
3042 return (IPP_STATE_ERROR
);
3045 DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p",
3046 ipp
->current
, ipp
->prev
));
3049 * Read this attribute...
3052 tag
= (ipp_tag_t
)buffer
[0];
3053 if (tag
== IPP_TAG_EXTENSION
)
3056 * Read 32-bit "extension" tag...
3059 if ((*cb
)(src
, buffer
, 4) < 1)
3061 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
3062 _cupsBufferRelease((char *)buffer
);
3063 return (IPP_STATE_ERROR
);
3066 tag
= (ipp_tag_t
)((((((buffer
[0] << 8) | buffer
[1]) << 8) |
3067 buffer
[2]) << 8) | buffer
[3]);
3069 if (tag
& IPP_TAG_CUPS_CONST
)
3072 * Fail if the high bit is set in the tag...
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
);
3082 if (tag
== IPP_TAG_END
)
3085 * No more attributes left...
3088 DEBUG_puts("2ippReadIO: IPP_TAG_END.");
3090 ipp
->state
= IPP_STATE_DATA
;
3093 else if (tag
< IPP_TAG_UNSUPPORTED_VALUE
)
3096 * Group tag... Set the current group and continue...
3099 if (ipp
->curtag
== tag
)
3100 ipp
->prev
= ippAddSeparator(ipp
);
3101 else if (ipp
->current
)
3102 ipp
->prev
= ipp
->current
;
3105 ipp
->current
= NULL
;
3106 DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag
,
3107 ippTagString(tag
), ipp
->prev
));
3111 DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag
,
3112 ippTagString(tag
)));
3118 if ((*cb
)(src
, buffer
, 2) < 2)
3120 DEBUG_puts("1ippReadIO: unable to read name length.");
3121 _cupsBufferRelease((char *)buffer
);
3122 return (IPP_STATE_ERROR
);
3125 n
= (buffer
[0] << 8) | buffer
[1];
3127 if (n
>= IPP_BUF_SIZE
)
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
);
3135 DEBUG_printf(("2ippReadIO: name length=%d", n
));
3137 if (n
== 0 && tag
!= IPP_TAG_MEMBERNAME
&&
3138 tag
!= IPP_TAG_END_COLLECTION
)
3141 * More values for current attribute...
3144 if (ipp
->current
== NULL
)
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
);
3152 attr
= ipp
->current
;
3153 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_CUPS_MASK
);
3156 * Make sure we aren't adding a new value of a different
3160 if (value_tag
== IPP_TAG_ZERO
)
3163 * Setting the value of a collection member...
3166 attr
->value_tag
= tag
;
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
))
3174 * String values can sometimes come across in different
3175 * forms; accept sets of differing values...
3178 if (tag
!= IPP_TAG_TEXTLANG
&& tag
!= IPP_TAG_NAMELANG
&&
3179 (tag
< IPP_TAG_TEXT
|| tag
> IPP_TAG_MIMETYPE
) &&
3180 tag
!= IPP_TAG_NOVALUE
)
3182 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3183 _("IPP 1setOf attribute with incompatible value "
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
);
3192 if (value_tag
!= tag
)
3194 DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.",
3195 attr
->name
, ippTagString(value_tag
), ippTagString(tag
)));
3196 ippSetValueTag(ipp
, &attr
, tag
);
3199 else if (value_tag
== IPP_TAG_INTEGER
||
3200 value_tag
== IPP_TAG_RANGE
)
3203 * Integer and rangeOfInteger values can sometimes be mixed; accept
3204 * sets of differing values...
3207 if (tag
!= IPP_TAG_INTEGER
&& tag
!= IPP_TAG_RANGE
)
3209 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3210 _("IPP 1setOf attribute with incompatible value "
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
);
3219 if (value_tag
== IPP_TAG_INTEGER
&& tag
== IPP_TAG_RANGE
)
3222 * Convert integer values to rangeOfInteger values...
3225 DEBUG_printf(("1ippReadIO: Converting %s attribute to "
3226 "rangeOfInteger.", attr
->name
));
3227 ippSetValueTag(ipp
, &attr
, IPP_TAG_RANGE
);
3230 else if (value_tag
!= tag
)
3232 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3233 _("IPP 1setOf attribute with incompatible value "
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
);
3243 * Finally, reallocate the attribute array as needed...
3246 if ((value
= ipp_set_value(ipp
, &attr
, attr
->num_values
)) == NULL
)
3248 _cupsBufferRelease((char *)buffer
);
3249 return (IPP_STATE_ERROR
);
3252 else if (tag
== IPP_TAG_MEMBERNAME
)
3255 * Name must be length 0!
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
);
3267 ipp
->prev
= ipp
->current
;
3269 attr
= ipp
->current
= ipp_add_attr(ipp
, NULL
, ipp
->curtag
, IPP_TAG_ZERO
, 1);
3272 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
3273 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3274 _cupsBufferRelease((char *)buffer
);
3275 return (IPP_STATE_ERROR
);
3278 DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p",
3279 ipp
->current
, ipp
->prev
));
3281 value
= attr
->values
;
3283 else if (tag
!= IPP_TAG_END_COLLECTION
)
3286 * New attribute; read the name and add it...
3289 if ((*cb
)(src
, buffer
, (size_t)n
) < n
)
3291 DEBUG_puts("1ippReadIO: unable to read name.");
3292 _cupsBufferRelease((char *)buffer
);
3293 return (IPP_STATE_ERROR
);
3299 ipp
->prev
= ipp
->current
;
3301 if ((attr
= ipp
->current
= ipp_add_attr(ipp
, (char *)buffer
, ipp
->curtag
, tag
,
3304 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
3305 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3306 _cupsBufferRelease((char *)buffer
);
3307 return (IPP_STATE_ERROR
);
3310 DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, "
3311 "ipp->prev=%p", buffer
, ipp
->current
, ipp
->prev
));
3313 value
= attr
->values
;
3321 if ((*cb
)(src
, buffer
, 2) < 2)
3323 DEBUG_puts("1ippReadIO: unable to read value length.");
3324 _cupsBufferRelease((char *)buffer
);
3325 return (IPP_STATE_ERROR
);
3328 n
= (buffer
[0] << 8) | buffer
[1];
3329 DEBUG_printf(("2ippReadIO: value length=%d", n
));
3331 if (n
>= IPP_BUF_SIZE
)
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
);
3342 case IPP_TAG_INTEGER
:
3346 if (tag
== IPP_TAG_INTEGER
)
3347 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3348 _("IPP integer value not 4 bytes."), 1);
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
);
3357 if ((*cb
)(src
, buffer
, 4) < 4)
3359 DEBUG_puts("1ippReadIO: Unable to read integer value.");
3360 _cupsBufferRelease((char *)buffer
);
3361 return (IPP_STATE_ERROR
);
3364 n
= (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
3367 if (attr
->value_tag
== IPP_TAG_RANGE
)
3368 value
->range
.lower
= value
->range
.upper
= n
;
3373 case IPP_TAG_BOOLEAN
:
3376 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP boolean value not 1 byte."),
3378 DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n
));
3379 _cupsBufferRelease((char *)buffer
);
3380 return (IPP_STATE_ERROR
);
3383 if ((*cb
)(src
, buffer
, 1) < 1)
3385 DEBUG_puts("1ippReadIO: Unable to read boolean value.");
3386 _cupsBufferRelease((char *)buffer
);
3387 return (IPP_STATE_ERROR
);
3390 value
->boolean
= (char)buffer
[0];
3393 case IPP_TAG_NOVALUE
:
3394 case IPP_TAG_NOTSETTABLE
:
3395 case IPP_TAG_DELETEATTR
:
3396 case IPP_TAG_ADMINDEFINE
:
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...
3403 if (attr
->value_tag
== tag
)
3408 attr
->value_tag
= IPP_TAG_TEXT
;
3413 case IPP_TAG_KEYWORD
:
3415 case IPP_TAG_URISCHEME
:
3416 case IPP_TAG_CHARSET
:
3417 case IPP_TAG_LANGUAGE
:
3418 case IPP_TAG_MIMETYPE
:
3421 if ((*cb
)(src
, buffer
, (size_t)n
) < n
)
3423 DEBUG_puts("1ippReadIO: unable to read string value.");
3424 _cupsBufferRelease((char *)buffer
);
3425 return (IPP_STATE_ERROR
);
3430 value
->string
.text
= _cupsStrAlloc((char *)buffer
);
3431 DEBUG_printf(("2ippReadIO: value=\"%s\"", value
->string
.text
));
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
);
3443 if ((*cb
)(src
, value
->date
, 11) < 11)
3445 DEBUG_puts("1ippReadIO: Unable to read date value.");
3446 _cupsBufferRelease((char *)buffer
);
3447 return (IPP_STATE_ERROR
);
3451 case IPP_TAG_RESOLUTION
:
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
);
3461 if ((*cb
)(src
, buffer
, 9) < 9)
3463 DEBUG_puts("1ippReadIO: Unable to read resolution value.");
3464 _cupsBufferRelease((char *)buffer
);
3465 return (IPP_STATE_ERROR
);
3468 value
->resolution
.xres
=
3469 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
3471 value
->resolution
.yres
=
3472 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
3474 value
->resolution
.units
=
3475 (ipp_res_t
)buffer
[8];
3478 case IPP_TAG_RANGE
:
3481 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3482 _("IPP rangeOfInteger value not 8 bytes."), 1);
3483 DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length "
3485 _cupsBufferRelease((char *)buffer
);
3486 return (IPP_STATE_ERROR
);
3489 if ((*cb
)(src
, buffer
, 8) < 8)
3491 DEBUG_puts("1ippReadIO: Unable to read range value.");
3492 _cupsBufferRelease((char *)buffer
);
3493 return (IPP_STATE_ERROR
);
3496 value
->range
.lower
=
3497 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
3499 value
->range
.upper
=
3500 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
3504 case IPP_TAG_TEXTLANG
:
3505 case IPP_TAG_NAMELANG
:
3508 if (tag
== IPP_TAG_TEXTLANG
)
3509 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3510 _("IPP textWithLanguage value less than "
3511 "minimum 4 bytes."), 1);
3513 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3514 _("IPP nameWithLanguage value less than "
3515 "minimum 4 bytes."), 1);
3516 DEBUG_printf(("1ippReadIO: bad stringWithLanguage value "
3518 _cupsBufferRelease((char *)buffer
);
3519 return (IPP_STATE_ERROR
);
3522 if ((*cb
)(src
, buffer
, (size_t)n
) < n
)
3524 DEBUG_puts("1ippReadIO: Unable to read string w/language "
3526 _cupsBufferRelease((char *)buffer
);
3527 return (IPP_STATE_ERROR
);
3533 * text-with-language and name-with-language are composite
3542 n
= (bufptr
[0] << 8) | bufptr
[1];
3544 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
) || n
>= (int)sizeof(string
))
3546 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3547 _("IPP language length overflows value."), 1);
3548 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3550 _cupsBufferRelease((char *)buffer
);
3551 return (IPP_STATE_ERROR
);
3553 else if (n
>= IPP_MAX_LANGUAGE
)
3555 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3556 _("IPP language length too large."), 1);
3557 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3559 _cupsBufferRelease((char *)buffer
);
3560 return (IPP_STATE_ERROR
);
3563 memcpy(string
, bufptr
+ 2, (size_t)n
);
3566 value
->string
.language
= _cupsStrAlloc((char *)string
);
3569 n
= (bufptr
[0] << 8) | bufptr
[1];
3571 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
))
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
);
3580 bufptr
[2 + n
] = '\0';
3581 value
->string
.text
= _cupsStrAlloc((char *)bufptr
+ 2);
3584 case IPP_TAG_BEGIN_COLLECTION
:
3586 * Oh, boy, here comes a collection value, so read it...
3589 value
->collection
= ippNew();
3593 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3594 _("IPP begCollection value not 0 bytes."), 1);
3595 DEBUG_puts("1ippReadIO: begCollection tag with value length "
3597 _cupsBufferRelease((char *)buffer
);
3598 return (IPP_STATE_ERROR
);
3601 if (ippReadIO(src
, cb
, 1, ipp
, value
->collection
) == IPP_STATE_ERROR
)
3603 DEBUG_puts("1ippReadIO: Unable to read collection value.");
3604 _cupsBufferRelease((char *)buffer
);
3605 return (IPP_STATE_ERROR
);
3609 case IPP_TAG_END_COLLECTION
:
3610 _cupsBufferRelease((char *)buffer
);
3614 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3615 _("IPP endCollection value not 0 bytes."), 1);
3616 DEBUG_puts("1ippReadIO: endCollection tag with value length "
3618 return (IPP_STATE_ERROR
);
3621 DEBUG_puts("1ippReadIO: endCollection tag...");
3622 return (ipp
->state
= IPP_STATE_DATA
);
3624 case IPP_TAG_MEMBERNAME
:
3626 * The value the name of the member in the collection, which
3627 * we need to carry over...
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
);
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
);
3646 else if ((*cb
)(src
, buffer
, (size_t)n
) < n
)
3648 DEBUG_puts("1ippReadIO: Unable to read member name value.");
3649 _cupsBufferRelease((char *)buffer
);
3650 return (IPP_STATE_ERROR
);
3654 attr
->name
= _cupsStrAlloc((char *)buffer
);
3657 * Since collection members are encoded differently than
3658 * regular attributes, make sure we don't start with an
3662 attr
->num_values
--;
3664 DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr
->name
));
3667 default : /* Other unsupported values */
3668 if (tag
== IPP_TAG_STRING
&& n
> IPP_MAX_LENGTH
)
3670 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3671 _("IPP octetString length too large."), 1);
3672 DEBUG_printf(("1ippReadIO: bad octetString value length %d.",
3674 _cupsBufferRelease((char *)buffer
);
3675 return (IPP_STATE_ERROR
);
3678 value
->unknown
.length
= n
;
3682 if ((value
->unknown
.data
= malloc((size_t)n
)) == NULL
)
3684 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
3685 DEBUG_puts("1ippReadIO: Unable to allocate value");
3686 _cupsBufferRelease((char *)buffer
);
3687 return (IPP_STATE_ERROR
);
3690 if ((*cb
)(src
, value
->unknown
.data
, (size_t)n
) < n
)
3692 DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
3693 _cupsBufferRelease((char *)buffer
);
3694 return (IPP_STATE_ERROR
);
3698 value
->unknown
.data
= NULL
;
3703 * If blocking is disabled, stop here...
3711 case IPP_STATE_DATA
:
3715 break; /* anti-compiler-warning-code */
3718 DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp
->state
));
3719 _cupsBufferRelease((char *)buffer
);
3721 return (ipp
->state
);
3726 * 'ippSetBoolean()' - Set a boolean value in an attribute.
3728 * The @code ipp@ parameter refers to an IPP message previously created using
3729 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3731 * The @code attr@ parameter may be modified as a result of setting the value.
3733 * The @code element@ parameter specifies which value to set from 0 to
3734 * @link ippGetCount(attr)@.
3736 * @since CUPS 1.6/OS X 10.8@
3739 int /* O - 1 on success, 0 on failure */
3740 ippSetBoolean(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 */
3745 _ipp_value_t
*value
; /* Current value */
3749 * Range check input...
3752 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BOOLEAN
||
3753 element
< 0 || element
> (*attr
)->num_values
)
3757 * Set the value and return...
3760 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3761 value
->boolean
= (char)boolvalue
;
3763 return (value
!= NULL
);
3768 * 'ippSetCollection()' - Set a collection value in an attribute.
3770 * The @code ipp@ parameter refers to an IPP message previously created using
3771 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3773 * The @code attr@ parameter may be modified as a result of setting the value.
3775 * The @code element@ parameter specifies which value to set from 0 to
3776 * @link ippGetCount(attr)@.
3778 * @since CUPS 1.6/OS X 10.8@
3781 int /* O - 1 on success, 0 on failure */
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 */
3788 _ipp_value_t
*value
; /* Current value */
3792 * Range check input...
3795 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
3796 element
< 0 || element
> (*attr
)->num_values
|| !colvalue
)
3800 * Set the value and return...
3803 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3805 if (value
->collection
)
3806 ippDelete(value
->collection
);
3808 value
->collection
= colvalue
;
3812 return (value
!= NULL
);
3817 * 'ippSetDate()' - Set a date value in an attribute.
3819 * The @code ipp@ parameter refers to an IPP message previously created using
3820 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3822 * The @code attr@ parameter may be modified as a result of setting the value.
3824 * The @code element@ parameter specifies which value to set from 0 to
3825 * @link ippGetCount(attr)@.
3827 * @since CUPS 1.6/OS X 10.8@
3830 int /* O - 1 on success, 0 on failure */
3831 ippSetDate(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 */
3836 _ipp_value_t
*value
; /* Current value */
3840 * Range check input...
3843 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_DATE
||
3844 element
< 0 || element
> (*attr
)->num_values
|| !datevalue
)
3848 * Set the value and return...
3851 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3852 memcpy(value
->date
, datevalue
, sizeof(value
->date
));
3854 return (value
!= NULL
);
3859 * 'ippSetGroupTag()' - Set the group tag of an attribute.
3861 * The @code ipp@ parameter refers to an IPP message previously created using
3862 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3864 * The @code attr@ parameter may be modified as a result of setting the value.
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@).
3872 * @since CUPS 1.6/OS X 10.8@
3875 int /* O - 1 on success, 0 on failure */
3877 ipp_t
*ipp
, /* I - IPP message */
3878 ipp_attribute_t
**attr
, /* IO - Attribute */
3879 ipp_tag_t group_tag
) /* I - Group tag */
3882 * Range check input - group tag must be 0x01 to 0x0F, per RFC 2911...
3885 if (!ipp
|| !attr
|| !*attr
||
3886 group_tag
< IPP_TAG_ZERO
|| group_tag
== IPP_TAG_END
||
3887 group_tag
>= IPP_TAG_UNSUPPORTED_VALUE
)
3891 * Set the group tag and return...
3894 (*attr
)->group_tag
= group_tag
;
3901 * 'ippSetInteger()' - Set an integer or enum value in an attribute.
3903 * The @code ipp@ parameter refers to an IPP message previously created using
3904 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3906 * The @code attr@ parameter may be modified as a result of setting the value.
3908 * The @code element@ parameter specifies which value to set from 0 to
3909 * @link ippGetCount(attr)@.
3911 * @since CUPS 1.6/OS X 10.8@
3914 int /* O - 1 on success, 0 on failure */
3915 ippSetInteger(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 */
3920 _ipp_value_t
*value
; /* Current value */
3924 * Range check input...
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
)
3933 * Set the value and return...
3936 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3937 value
->integer
= intvalue
;
3939 return (value
!= NULL
);
3944 * 'ippSetName()' - Set the name of an attribute.
3946 * The @code ipp@ parameter refers to an IPP message previously created using
3947 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3949 * The @code attr@ parameter may be modified as a result of setting the value.
3951 * @since CUPS 1.6/OS X 10.8@
3954 int /* O - 1 on success, 0 on failure */
3955 ippSetName(ipp_t
*ipp
, /* I - IPP message */
3956 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3957 const char *name
) /* I - Attribute name */
3959 char *temp
; /* Temporary name value */
3963 * Range check input...
3966 if (!ipp
|| !attr
|| !*attr
)
3970 * Set the value and return...
3973 if ((temp
= _cupsStrAlloc(name
)) != NULL
)
3976 _cupsStrFree((*attr
)->name
);
3978 (*attr
)->name
= temp
;
3981 return (temp
!= NULL
);
3986 * 'ippSetOctetString()' - Set an octetString value in an IPP attribute.
3988 * The @code ipp@ parameter refers to an IPP message previously created using
3989 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3991 * The @code attr@ parameter may be modified as a result of setting the value.
3993 * The @code element@ parameter specifies which value to set from 0 to
3994 * @link ippGetCount(attr)@.
3996 * @since CUPS 1.7/OS X 10.9@
3999 int /* O - 1 on success, 0 on failure */
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 */
4007 _ipp_value_t
*value
; /* Current value */
4011 * Range check input...
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
)
4020 * Set the value and return...
4023 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4025 if ((int)((*attr
)->value_tag
) & IPP_TAG_CUPS_CONST
)
4028 * Just copy the pointer...
4031 value
->unknown
.data
= (void *)data
;
4032 value
->unknown
.length
= datalen
;
4040 if (value
->unknown
.data
)
4043 * Free previous data...
4046 free(value
->unknown
.data
);
4048 value
->unknown
.data
= NULL
;
4049 value
->unknown
.length
= 0;
4054 void *temp
; /* Temporary data pointer */
4056 if ((temp
= malloc((size_t)datalen
)) != NULL
)
4058 memcpy(temp
, data
, (size_t)datalen
);
4060 value
->unknown
.data
= temp
;
4061 value
->unknown
.length
= datalen
;
4069 return (value
!= NULL
);
4074 * 'ippSetOperation()' - Set the operation ID in an IPP request message.
4076 * The @code ipp@ parameter refers to an IPP message previously created using
4077 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4079 * @since CUPS 1.6/OS X 10.8@
4082 int /* O - 1 on success, 0 on failure */
4083 ippSetOperation(ipp_t
*ipp
, /* I - IPP request message */
4084 ipp_op_t op
) /* I - Operation ID */
4087 * Range check input...
4094 * Set the operation and return...
4097 ipp
->request
.op
.operation_id
= op
;
4104 * 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
4106 * The @code ipp@ parameter refers to an IPP message previously created using
4107 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4109 * The @code attr@ parameter may be modified as a result of setting the value.
4111 * The @code element@ parameter specifies which value to set from 0 to
4112 * @link ippGetCount(attr)@.
4114 * @since CUPS 1.6/OS X 10.8@
4117 int /* O - 1 on success, 0 on failure */
4118 ippSetRange(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 */
4124 _ipp_value_t
*value
; /* Current value */
4128 * Range check input...
4131 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RANGE
||
4132 element
< 0 || element
> (*attr
)->num_values
|| lowervalue
> uppervalue
)
4136 * Set the value and return...
4139 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4141 value
->range
.lower
= lowervalue
;
4142 value
->range
.upper
= uppervalue
;
4145 return (value
!= NULL
);
4150 * 'ippSetRequestId()' - Set the request ID in an IPP message.
4152 * The @code ipp@ parameter refers to an IPP message previously created using
4153 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4155 * The @code request_id@ parameter must be greater than 0.
4157 * @since CUPS 1.6/OS X 10.8@
4160 int /* O - 1 on success, 0 on failure */
4161 ippSetRequestId(ipp_t
*ipp
, /* I - IPP message */
4162 int request_id
) /* I - Request ID */
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...
4174 * Set the request ID and return...
4177 ipp
->request
.any
.request_id
= request_id
;
4184 * 'ippSetResolution()' - Set a resolution value in an attribute.
4186 * The @code ipp@ parameter refers to an IPP message previously created using
4187 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4189 * The @code attr@ parameter may be modified as a result of setting the value.
4191 * The @code element@ parameter specifies which value to set from 0 to
4192 * @link ippGetCount(attr)@.
4194 * @since CUPS 1.6/OS X 10.8@
4197 int /* O - 1 on success, 0 on failure */
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 */
4206 _ipp_value_t
*value
; /* Current value */
4210 * Range check input...
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
)
4219 * Set the value and return...
4222 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4224 value
->resolution
.units
= unitsvalue
;
4225 value
->resolution
.xres
= xresvalue
;
4226 value
->resolution
.yres
= yresvalue
;
4229 return (value
!= NULL
);
4234 * 'ippSetState()' - Set the current state of the IPP message.
4236 * @since CUPS 1.6/OS X 10.8@
4239 int /* O - 1 on success, 0 on failure */
4240 ippSetState(ipp_t
*ipp
, /* I - IPP message */
4241 ipp_state_t state
) /* I - IPP state value */
4244 * Range check input...
4251 * Set the state and return...
4255 ipp
->current
= NULL
;
4262 * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
4264 * The @code ipp@ parameter refers to an IPP message previously created using
4265 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4267 * @since CUPS 1.6/OS X 10.8@
4270 int /* O - 1 on success, 0 on failure */
4271 ippSetStatusCode(ipp_t
*ipp
, /* I - IPP response or event message */
4272 ipp_status_t status
) /* I - Status code */
4275 * Range check input...
4282 * Set the status code and return...
4285 ipp
->request
.status
.status_code
= status
;
4292 * 'ippSetString()' - Set a string value in an attribute.
4294 * The @code ipp@ parameter refers to an IPP message previously created using
4295 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4297 * The @code attr@ parameter may be modified as a result of setting the value.
4299 * The @code element@ parameter specifies which value to set from 0 to
4300 * @link ippGetCount(attr)@.
4302 * @since CUPS 1.6/OS X 10.8@
4305 int /* O - 1 on success, 0 on failure */
4306 ippSetString(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 */
4311 char *temp
; /* Temporary string */
4312 _ipp_value_t
*value
; /* Current value */
4316 * Range check input...
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
)
4328 * Set the value and return...
4331 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4334 value
->string
.language
= (*attr
)->values
[0].string
.language
;
4336 if ((int)((*attr
)->value_tag
) & IPP_TAG_CUPS_CONST
)
4337 value
->string
.text
= (char *)strvalue
;
4338 else if ((temp
= _cupsStrAlloc(strvalue
)) != NULL
)
4340 if (value
->string
.text
)
4341 _cupsStrFree(value
->string
.text
);
4343 value
->string
.text
= temp
;
4349 return (value
!= NULL
);
4354 * 'ippSetStringf()' - Set a formatted string value of an attribute.
4356 * The @code ipp@ parameter refers to an IPP message previously created using
4357 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4359 * The @code attr@ parameter may be modified as a result of setting the value.
4361 * The @code element@ parameter specifies which value to set from 0 to
4362 * @link ippGetCount(attr)@.
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.
4369 * @since CUPS 1.7/OS X 10.9@
4372 int /* O - 1 on success, 0 on failure */
4373 ippSetStringf(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 */
4379 int ret
; /* Return value */
4380 va_list ap
; /* Pointer to additional arguments */
4383 va_start(ap
, format
);
4384 ret
= ippSetStringfv(ipp
, attr
, element
, format
, ap
);
4392 * 'ippSetStringf()' - Set a formatted string value of an attribute.
4394 * The @code ipp@ parameter refers to an IPP message previously created using
4395 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4397 * The @code attr@ parameter may be modified as a result of setting the value.
4399 * The @code element@ parameter specifies which value to set from 0 to
4400 * @link ippGetCount(attr)@.
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.
4407 * @since CUPS 1.7/OS X 10.9@
4410 int /* O - 1 on success, 0 on failure */
4411 ippSetStringfv(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 */
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 */
4425 * Range check input...
4429 value_tag
= (*attr
)->value_tag
& IPP_TAG_CUPS_MASK
;
4431 value_tag
= IPP_TAG_ZERO
;
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
||
4440 * Format the string...
4443 if (!strcmp(format
, "%s"))
4446 * Optimize the simple case...
4449 const char *s
= va_arg(ap
, char *);
4454 bytes
= (ssize_t
)strlen(s
);
4455 strlcpy(buffer
, s
, sizeof(buffer
));
4460 * Do a full formatting of the message...
4463 if ((bytes
= vsnprintf(buffer
, sizeof(buffer
), format
, ap
)) < 0)
4468 * Limit the length of the string...
4475 case IPP_TAG_TEXTLANG
:
4476 max_bytes
= IPP_MAX_TEXT
;
4480 case IPP_TAG_NAMELANG
:
4481 max_bytes
= IPP_MAX_NAME
;
4484 case IPP_TAG_CHARSET
:
4485 max_bytes
= IPP_MAX_CHARSET
;
4488 case IPP_TAG_KEYWORD
:
4489 max_bytes
= IPP_MAX_KEYWORD
;
4492 case IPP_TAG_LANGUAGE
:
4493 max_bytes
= IPP_MAX_LANGUAGE
;
4496 case IPP_TAG_MIMETYPE
:
4497 max_bytes
= IPP_MAX_MIMETYPE
;
4501 max_bytes
= IPP_MAX_URI
;
4504 case IPP_TAG_URISCHEME
:
4505 max_bytes
= IPP_MAX_URISCHEME
;
4509 if (bytes
>= max_bytes
)
4511 char *bufmax
, /* Buffer at max_bytes */
4512 *bufptr
; /* Pointer into buffer */
4514 bufptr
= buffer
+ strlen(buffer
) - 1;
4515 bufmax
= buffer
+ max_bytes
- 1;
4517 while (bufptr
> bufmax
)
4521 while ((*bufptr
& 0xc0) == 0x80 && bufptr
> buffer
)
4532 * Set the formatted string and return...
4535 return (ippSetString(ipp
, attr
, element
, buffer
));
4540 * 'ippSetValueTag()' - Set the value tag of an attribute.
4542 * The @code ipp@ parameter refers to an IPP message previously created using
4543 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4545 * The @code attr@ parameter may be modified as a result of setting the value.
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
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.
4559 * @since CUPS 1.6/OS X 10.8@
4562 int /* O - 1 on success, 0 on failure */
4564 ipp_t
*ipp
, /* I - IPP message */
4565 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4566 ipp_tag_t value_tag
) /* I - Value tag */
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 */
4577 * Range check input...
4580 if (!ipp
|| !attr
|| !*attr
)
4584 * If there is no change, return immediately...
4587 if (value_tag
== (*attr
)->value_tag
)
4591 * Otherwise implement changes as needed...
4594 temp_tag
= (ipp_tag_t
)((int)((*attr
)->value_tag
) & IPP_TAG_CUPS_MASK
);
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
:
4606 * Free any existing values...
4609 if ((*attr
)->num_values
> 0)
4610 ipp_free_values(*attr
, 0, (*attr
)->num_values
);
4613 * Set out-of-band value...
4616 (*attr
)->value_tag
= value_tag
;
4619 case IPP_TAG_RANGE
:
4620 if (temp_tag
!= IPP_TAG_INTEGER
)
4623 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
4627 integer
= value
->integer
;
4628 value
->range
.lower
= value
->range
.upper
= integer
;
4631 (*attr
)->value_tag
= IPP_TAG_RANGE
;
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
)
4640 (*attr
)->value_tag
= (ipp_tag_t
)(IPP_TAG_NAME
| ((*attr
)->value_tag
& IPP_TAG_CUPS_CONST
));
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
))
4651 if (value_tag
== IPP_TAG_TEXTLANG
&& temp_tag
!= IPP_TAG_TEXT
)
4654 if (ipp
->attrs
&& ipp
->attrs
->next
&& ipp
->attrs
->next
->name
&&
4655 !strcmp(ipp
->attrs
->next
->name
, "attributes-natural-language"))
4658 * Use the language code from the IPP message...
4661 (*attr
)->values
[0].string
.language
=
4662 _cupsStrAlloc(ipp
->attrs
->next
->values
[0].string
.text
);
4667 * Otherwise, use the language code corresponding to the locale...
4670 language
= cupsLangDefault();
4671 (*attr
)->values
[0].string
.language
= _cupsStrAlloc(ipp_lang_code(language
->language
,
4676 for (i
= (*attr
)->num_values
- 1, value
= (*attr
)->values
+ 1;
4679 value
->string
.language
= (*attr
)->values
[0].string
.language
;
4681 if ((int)(*attr
)->value_tag
& IPP_TAG_CUPS_CONST
)
4684 * Make copies of all values...
4687 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
4690 value
->string
.text
= _cupsStrAlloc(value
->string
.text
);
4693 (*attr
)->value_tag
= IPP_TAG_NAMELANG
;
4696 case IPP_TAG_KEYWORD
:
4697 if (temp_tag
== IPP_TAG_NAME
|| temp_tag
== IPP_TAG_NAMELANG
)
4698 break; /* Silently "allow" name -> keyword */
4709 * 'ippSetVersion()' - Set the version number in an IPP message.
4711 * The @code ipp@ parameter refers to an IPP message previously created using
4712 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4714 * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
4716 * @since CUPS 1.6/OS X 10.8@
4719 int /* O - 1 on success, 0 on failure */
4720 ippSetVersion(ipp_t
*ipp
, /* I - IPP message */
4721 int major
, /* I - Major version number (major.minor) */
4722 int minor
) /* I - Minor version number (major.minor) */
4725 * Range check input...
4728 if (!ipp
|| major
< 0 || minor
< 0)
4732 * Set the version number...
4735 ipp
->request
.any
.version
[0] = (ipp_uchar_t
)major
;
4736 ipp
->request
.any
.version
[1] = (ipp_uchar_t
)minor
;
4743 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
4746 const ipp_uchar_t
* /* O - RFC-1903 date/time data */
4747 ippTimeToDate(time_t t
) /* I - UNIX time value */
4749 struct tm
*unixdate
; /* UNIX unixdate/time info */
4750 ipp_uchar_t
*date
= _cupsGlobals()->ipp_date
;
4751 /* RFC-1903 date/time data */
4755 * RFC-1903 date/time format is:
4757 * Byte(s) Description
4758 * ------- -----------
4759 * 0-1 Year (0 to 65535)
4763 * 5 Minutes (0 to 59)
4764 * 6 Seconds (0 to 60, 60 = "leap second")
4765 * 7 Deciseconds (0 to 9)
4767 * 9 UTC hours (0 to 11)
4768 * 10 UTC minutes (0 to 59)
4771 unixdate
= gmtime(&t
);
4772 unixdate
->tm_year
+= 1900;
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
;
4791 * 'ippValidateAttribute()' - Validate the contents of an attribute.
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.
4797 * @since CUPS 1.7/OS X 10.9@
4800 int /* O - 1 if valid, 0 otherwise */
4801 ippValidateAttribute(
4802 ipp_attribute_t
*attr
) /* I - Attribute */
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 */
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",
4826 "Missing scheme in URI",
4827 "Unknown scheme in URI",
4828 "Missing resource in URI"
4840 * Validate the attribute name.
4843 for (ptr
= attr
->name
; *ptr
; ptr
++)
4844 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' && *ptr
!= '_')
4847 if (*ptr
|| ptr
== attr
->name
)
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
);
4855 if ((ptr
- attr
->name
) > 255)
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
));
4864 switch (attr
->value_tag
)
4866 case IPP_TAG_INTEGER
:
4869 case IPP_TAG_BOOLEAN
:
4870 for (i
= 0; i
< attr
->num_values
; i
++)
4872 if (attr
->values
[i
].boolean
!= 0 &&
4873 attr
->values
[i
].boolean
!= 1)
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
);
4885 for (i
= 0; i
< attr
->num_values
; i
++)
4887 if (attr
->values
[i
].integer
< 1)
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
);
4898 case IPP_TAG_STRING
:
4899 for (i
= 0; i
< attr
->num_values
; i
++)
4901 if (attr
->values
[i
].unknown
.length
> IPP_MAX_OCTETSTRING
)
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
);
4913 for (i
= 0; i
< attr
->num_values
; i
++)
4915 date
= attr
->values
[i
].date
;
4917 if (date
[2] < 1 || date
[2] > 12)
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]);
4925 if (date
[3] < 1 || date
[3] > 31)
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]);
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]);
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]);
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]);
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]);
4965 if (date
[8] != '-' && date
[8] != '+')
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]);
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]);
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]);
4991 case IPP_TAG_RESOLUTION
:
4992 for (i
= 0; i
< attr
->num_values
; i
++)
4994 if (attr
->values
[i
].resolution
.xres
<= 0)
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");
5009 if (attr
->values
[i
].resolution
.yres
<= 0)
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");
5024 if (attr
->values
[i
].resolution
.units
!= IPP_RES_PER_INCH
&&
5025 attr
->values
[i
].resolution
.units
!= IPP_RES_PER_CM
)
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");
5041 case IPP_TAG_RANGE
:
5042 for (i
= 0; i
< attr
->num_values
; i
++)
5044 if (attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
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
);
5056 case IPP_TAG_BEGIN_COLLECTION
:
5057 for (i
= 0; i
< attr
->num_values
; i
++)
5059 for (colattr
= attr
->values
[i
].collection
->attrs
;
5061 colattr
= colattr
->next
)
5063 if (!ippValidateAttribute(colattr
))
5070 case IPP_TAG_TEXTLANG
:
5071 for (i
= 0; i
< attr
->num_values
; i
++)
5073 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5075 if ((*ptr
& 0xe0) == 0xc0)
5078 if ((*ptr
& 0xc0) != 0x80)
5081 else if ((*ptr
& 0xf0) == 0xe0)
5084 if ((*ptr
& 0xc0) != 0x80)
5087 if ((*ptr
& 0xc0) != 0x80)
5090 else if ((*ptr
& 0xf8) == 0xf0)
5093 if ((*ptr
& 0xc0) != 0x80)
5096 if ((*ptr
& 0xc0) != 0x80)
5099 if ((*ptr
& 0xc0) != 0x80)
5102 else if (*ptr
& 0x80)
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
);
5115 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_TEXT
- 1))
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
));
5128 case IPP_TAG_NAMELANG
:
5129 for (i
= 0; i
< attr
->num_values
; i
++)
5131 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5133 if ((*ptr
& 0xe0) == 0xc0)
5136 if ((*ptr
& 0xc0) != 0x80)
5139 else if ((*ptr
& 0xf0) == 0xe0)
5142 if ((*ptr
& 0xc0) != 0x80)
5145 if ((*ptr
& 0xc0) != 0x80)
5148 else if ((*ptr
& 0xf8) == 0xf0)
5151 if ((*ptr
& 0xc0) != 0x80)
5154 if ((*ptr
& 0xc0) != 0x80)
5157 if ((*ptr
& 0xc0) != 0x80)
5160 else if (*ptr
& 0x80)
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
);
5173 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_NAME
- 1))
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
));
5185 case IPP_TAG_KEYWORD
:
5186 for (i
= 0; i
< attr
->num_values
; i
++)
5188 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5189 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' &&
5193 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
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
);
5202 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_KEYWORD
- 1))
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
));
5215 for (i
= 0; i
< attr
->num_values
; i
++)
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
));
5224 if (uri_status
< HTTP_URI_STATUS_OK
)
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
]);
5235 if (strlen(attr
->values
[i
].string
.text
) > (IPP_MAX_URI
- 1))
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
));
5246 case IPP_TAG_URISCHEME
:
5247 for (i
= 0; i
< attr
->num_values
; i
++)
5249 ptr
= attr
->values
[i
].string
.text
;
5250 if (islower(*ptr
& 255))
5252 for (ptr
++; *ptr
; ptr
++)
5253 if (!islower(*ptr
& 255) && !isdigit(*ptr
& 255) &&
5254 *ptr
!= '+' && *ptr
!= '-' && *ptr
!= '.')
5258 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
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
);
5267 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_URISCHEME
- 1))
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
));
5279 case IPP_TAG_CHARSET
:
5280 for (i
= 0; i
< attr
->num_values
; i
++)
5282 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5283 if (!isprint(*ptr
& 255) || isupper(*ptr
& 255) ||
5284 isspace(*ptr
& 255))
5287 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
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
);
5296 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_CHARSET
- 1))
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
));
5308 case IPP_TAG_LANGUAGE
:
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...
5315 if ((i
= regcomp(&re
,
5317 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
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 */
5325 "x(-[a-z0-9]{1,8})+" /* privateuse */
5327 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
5329 REG_NOSUB
| REG_EXTENDED
)) != 0)
5331 char temp
[256]; /* Temporary error string */
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
);
5340 for (i
= 0; i
< attr
->num_values
; i
++)
5342 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
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
);
5352 if (strlen(attr
->values
[i
].string
.text
) > (IPP_MAX_LANGUAGE
- 1))
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
));
5367 case IPP_TAG_MIMETYPE
:
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...
5374 if ((i
= regcomp(&re
,
5376 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
5378 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
5379 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
5380 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
5383 REG_NOSUB
| REG_EXTENDED
)) != 0)
5385 char temp
[256]; /* Temporary error string */
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
);
5394 for (i
= 0; i
< attr
->num_values
; i
++)
5396 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
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
);
5406 if (strlen(attr
->values
[i
].string
.text
) > (IPP_MAX_MIMETYPE
- 1))
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
));
5430 * 'ippValidateAttributes()' - Validate all attributes in an IPP message.
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.
5436 * @since CUPS 1.7/OS X 10.9@
5439 int /* O - 1 if valid, 0 otherwise */
5440 ippValidateAttributes(ipp_t
*ipp
) /* I - IPP message */
5442 ipp_attribute_t
*attr
; /* Current attribute */
5448 for (attr
= ipp
->attrs
; attr
; attr
= attr
->next
)
5449 if (!ippValidateAttribute(attr
))
5457 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
5460 ipp_state_t
/* O - Current state */
5461 ippWrite(http_t
*http
, /* I - HTTP connection */
5462 ipp_t
*ipp
) /* I - IPP data */
5464 DEBUG_printf(("ippWrite(http=%p, ipp=%p)", http
, ipp
));
5467 return (IPP_STATE_ERROR
);
5469 return (ippWriteIO(http
, (ipp_iocb_t
)httpWrite2
, http
->blocking
, NULL
, ipp
));
5474 * 'ippWriteFile()' - Write data for an IPP message to a file.
5476 * @since CUPS 1.1.19/OS X 10.3@
5479 ipp_state_t
/* O - Current state */
5480 ippWriteFile(int fd
, /* I - HTTP data */
5481 ipp_t
*ipp
) /* I - IPP data */
5483 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd
, ipp
));
5485 ipp
->state
= IPP_STATE_IDLE
;
5487 return (ippWriteIO(&fd
, (ipp_iocb_t
)ipp_write_file
, 1, NULL
, ipp
));
5492 * 'ippWriteIO()' - Write data for an IPP message.
5494 * @since CUPS 1.2/OS X 10.5@
5497 ipp_state_t
/* O - Current state */
5498 ippWriteIO(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 */
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 */
5512 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
5513 dst
, cb
, blocking
, parent
, ipp
));
5516 return (IPP_STATE_ERROR
);
5518 if ((buffer
= (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE
)) == NULL
)
5520 DEBUG_puts("1ippWriteIO: Unable to get write buffer");
5521 return (IPP_STATE_ERROR
);
5526 case IPP_STATE_IDLE
:
5527 ipp
->state
++; /* Avoid common problem... */
5529 case IPP_STATE_HEADER
:
5533 * Send the request header:
5536 * Operation/Status Code = 2 bytes
5537 * Request ID = 4 bytes
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
;
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
));
5558 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5560 DEBUG_puts("1ippWriteIO: Could not write IPP header...");
5561 _cupsBufferRelease((char *)buffer
);
5562 return (IPP_STATE_ERROR
);
5567 * Reset the state engine to point to the first attribute
5568 * in the request/response, with no current group.
5571 ipp
->state
= IPP_STATE_ATTRIBUTE
;
5572 ipp
->current
= ipp
->attrs
;
5573 ipp
->curtag
= IPP_TAG_ZERO
;
5575 DEBUG_printf(("1ippWriteIO: ipp->current=%p", ipp
->current
));
5578 * If blocking is disabled, stop here...
5584 case IPP_STATE_ATTRIBUTE
:
5585 while (ipp
->current
!= NULL
)
5588 * Write this attribute...
5592 attr
= ipp
->current
;
5594 ipp
->current
= ipp
->current
->next
;
5598 if (ipp
->curtag
!= attr
->group_tag
)
5601 * Send a group tag byte...
5604 ipp
->curtag
= attr
->group_tag
;
5606 if (attr
->group_tag
== IPP_TAG_ZERO
)
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
;
5613 else if (attr
->group_tag
== IPP_TAG_ZERO
)
5617 DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr
->name
,
5618 attr
->num_values
> 1 ? "1setOf " : "",
5619 ippTagString(attr
->value_tag
)));
5622 * Write the attribute tag and name.
5624 * The attribute name length does not include the trailing nul
5625 * character in the source string.
5627 * Collection values (parent != NULL) are written differently...
5633 * Get the length of the attribute name, and make sure it won't
5634 * overflow the buffer...
5637 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 8))
5639 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
5640 _cupsBufferRelease((char *)buffer
);
5641 return (IPP_STATE_ERROR
);
5645 * Write the value tag, name length, and name string...
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
,
5653 if (attr
->value_tag
> 0xff)
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
;
5662 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5664 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
5665 *bufptr
++ = (ipp_uchar_t
)n
;
5666 memcpy(bufptr
, attr
->name
, (size_t)n
);
5672 * Get the length of the attribute name, and make sure it won't
5673 * overflow the buffer...
5676 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 12))
5678 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
5679 _cupsBufferRelease((char *)buffer
);
5680 return (IPP_STATE_ERROR
);
5684 * Write the member name tag, name length, name string, value tag,
5685 * and empty name for the collection member attribute...
5688 DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
5689 IPP_TAG_MEMBERNAME
));
5690 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
5692 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5693 attr
->value_tag
, ippTagString(attr
->value_tag
)));
5694 DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
5696 *bufptr
++ = IPP_TAG_MEMBERNAME
;
5699 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
5700 *bufptr
++ = (ipp_uchar_t
)n
;
5701 memcpy(bufptr
, attr
->name
, (size_t)n
);
5704 if (attr
->value_tag
> 0xff)
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
;
5713 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5720 * Now write the attribute value(s)...
5723 switch (attr
->value_tag
& ~IPP_TAG_CUPS_CONST
)
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
:
5736 case IPP_TAG_INTEGER
:
5738 for (i
= 0, value
= attr
->values
;
5739 i
< attr
->num_values
;
5742 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 9)
5744 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5746 DEBUG_puts("1ippWriteIO: Could not write IPP "
5748 _cupsBufferRelease((char *)buffer
);
5749 return (IPP_STATE_ERROR
);
5758 * Arrays and sets are done by sending additional
5759 * values with a zero-length name...
5762 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5768 * Integers and enumerations are both 4-byte signed
5769 * (twos-complement) values.
5771 * Put the 2-byte length and 4-byte value into the buffer...
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
;
5783 case IPP_TAG_BOOLEAN
:
5784 for (i
= 0, value
= attr
->values
;
5785 i
< attr
->num_values
;
5788 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 6)
5790 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5792 DEBUG_puts("1ippWriteIO: Could not write IPP "
5794 _cupsBufferRelease((char *)buffer
);
5795 return (IPP_STATE_ERROR
);
5804 * Arrays and sets are done by sending additional
5805 * values with a zero-length name...
5808 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5814 * Boolean values are 1-byte; 0 = false, 1 = true.
5816 * Put the 2-byte length and 1-byte value into the buffer...
5821 *bufptr
++ = (ipp_uchar_t
)value
->boolean
;
5827 case IPP_TAG_KEYWORD
:
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
;
5840 * Arrays and sets are done by sending additional
5841 * values with a zero-length name...
5844 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5846 ippTagString(attr
->value_tag
)));
5847 DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
5849 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
5851 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5853 DEBUG_puts("1ippWriteIO: Could not write IPP "
5855 _cupsBufferRelease((char *)buffer
);
5856 return (IPP_STATE_ERROR
);
5862 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5867 if (value
->string
.text
!= NULL
)
5868 n
= (int)strlen(value
->string
.text
);
5872 if (n
> (IPP_BUF_SIZE
- 2))
5874 DEBUG_printf(("1ippWriteIO: String too long (%d)", n
));
5875 _cupsBufferRelease((char *)buffer
);
5876 return (IPP_STATE_ERROR
);
5879 DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n
,
5880 value
->string
.text
));
5882 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
5884 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5886 DEBUG_puts("1ippWriteIO: Could not write IPP "
5888 _cupsBufferRelease((char *)buffer
);
5889 return (IPP_STATE_ERROR
);
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)
5902 * Put the 2-byte length and string characters in the buffer.
5905 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
5906 *bufptr
++ = (ipp_uchar_t
)n
;
5910 memcpy(bufptr
, value
->string
.text
, (size_t)n
);
5917 for (i
= 0, value
= attr
->values
;
5918 i
< attr
->num_values
;
5921 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 16)
5923 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5925 DEBUG_puts("1ippWriteIO: Could not write IPP "
5927 _cupsBufferRelease((char *)buffer
);
5928 return (IPP_STATE_ERROR
);
5937 * Arrays and sets are done by sending additional
5938 * values with a zero-length name...
5941 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5947 * Date values consist of a 2-byte length and an
5948 * 11-byte date/time structure defined by RFC 1903.
5950 * Put the 2-byte length and 11-byte date/time
5951 * structure in the buffer.
5956 memcpy(bufptr
, value
->date
, 11);
5961 case IPP_TAG_RESOLUTION
:
5962 for (i
= 0, value
= attr
->values
;
5963 i
< attr
->num_values
;
5966 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 14)
5968 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5970 DEBUG_puts("1ippWriteIO: Could not write IPP "
5972 _cupsBufferRelease((char *)buffer
);
5973 return (IPP_STATE_ERROR
);
5982 * Arrays and sets are done by sending additional
5983 * values with a zero-length name...
5986 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
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.
5996 * Put the 2-byte length and resolution value data
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
;
6014 case IPP_TAG_RANGE
:
6015 for (i
= 0, value
= attr
->values
;
6016 i
< attr
->num_values
;
6019 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 13)
6021 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6023 DEBUG_puts("1ippWriteIO: Could not write IPP "
6025 _cupsBufferRelease((char *)buffer
);
6026 return (IPP_STATE_ERROR
);
6035 * Arrays and sets are done by sending additional
6036 * values with a zero-length name...
6039 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
6045 * Range values consist of a 2-byte length,
6046 * 4-byte lower value, and 4-byte upper value.
6048 * Put the 2-byte length and range value data
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
;
6065 case IPP_TAG_TEXTLANG
:
6066 case IPP_TAG_NAMELANG
:
6067 for (i
= 0, value
= attr
->values
;
6068 i
< attr
->num_values
;
6074 * Arrays and sets are done by sending additional
6075 * values with a zero-length name...
6078 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
6080 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6082 DEBUG_puts("1ippWriteIO: Could not write IPP "
6084 _cupsBufferRelease((char *)buffer
);
6085 return (IPP_STATE_ERROR
);
6091 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
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
6108 if (value
->string
.language
!= NULL
)
6109 n
+= (int)strlen(value
->string
.language
);
6111 if (value
->string
.text
!= NULL
)
6112 n
+= (int)strlen(value
->string
.text
);
6114 if (n
> (IPP_BUF_SIZE
- 2))
6116 DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
6117 "too long (%d)", n
));
6118 _cupsBufferRelease((char *)buffer
);
6119 return (IPP_STATE_ERROR
);
6122 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
6124 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6126 DEBUG_puts("1ippWriteIO: Could not write IPP "
6128 _cupsBufferRelease((char *)buffer
);
6129 return (IPP_STATE_ERROR
);
6135 /* Length of entire value */
6136 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
6137 *bufptr
++ = (ipp_uchar_t
)n
;
6139 /* Length of language */
6140 if (value
->string
.language
!= NULL
)
6141 n
= (int)strlen(value
->string
.language
);
6145 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
6146 *bufptr
++ = (ipp_uchar_t
)n
;
6151 memcpy(bufptr
, value
->string
.language
, (size_t)n
);
6155 /* Length of text */
6156 if (value
->string
.text
!= NULL
)
6157 n
= (int)strlen(value
->string
.text
);
6161 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
6162 *bufptr
++ = (ipp_uchar_t
)n
;
6167 memcpy(bufptr
, value
->string
.text
, (size_t)n
);
6173 case IPP_TAG_BEGIN_COLLECTION
:
6174 for (i
= 0, value
= attr
->values
;
6175 i
< attr
->num_values
;
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
6185 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 5)
6187 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6189 DEBUG_puts("1ippWriteIO: Could not write IPP "
6191 _cupsBufferRelease((char *)buffer
);
6192 return (IPP_STATE_ERROR
);
6201 * Arrays and sets are done by sending additional
6202 * values with a zero-length name...
6205 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
6211 * Write a data length of 0 and flush the buffer...
6217 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6219 DEBUG_puts("1ippWriteIO: Could not write IPP "
6221 _cupsBufferRelease((char *)buffer
);
6222 return (IPP_STATE_ERROR
);
6228 * Then write the collection attribute...
6231 value
->collection
->state
= IPP_STATE_IDLE
;
6233 if (ippWriteIO(dst
, cb
, 1, ipp
,
6234 value
->collection
) == IPP_STATE_ERROR
)
6236 DEBUG_puts("1ippWriteIO: Unable to write collection value");
6237 _cupsBufferRelease((char *)buffer
);
6238 return (IPP_STATE_ERROR
);
6244 for (i
= 0, value
= attr
->values
;
6245 i
< attr
->num_values
;
6251 * Arrays and sets are done by sending additional
6252 * values with a zero-length name...
6255 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
6257 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6259 DEBUG_puts("1ippWriteIO: Could not write IPP "
6261 _cupsBufferRelease((char *)buffer
);
6262 return (IPP_STATE_ERROR
);
6268 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
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
6280 n
= value
->unknown
.length
;
6282 if (n
> (IPP_BUF_SIZE
- 2))
6284 DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
6286 _cupsBufferRelease((char *)buffer
);
6287 return (IPP_STATE_ERROR
);
6290 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
6292 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6294 DEBUG_puts("1ippWriteIO: Could not write IPP "
6296 _cupsBufferRelease((char *)buffer
);
6297 return (IPP_STATE_ERROR
);
6303 /* Length of unknown value */
6304 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
6305 *bufptr
++ = (ipp_uchar_t
)n
;
6310 memcpy(bufptr
, value
->unknown
.data
, (size_t)n
);
6318 * Write the data out...
6321 if (bufptr
> buffer
)
6323 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6325 DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
6326 _cupsBufferRelease((char *)buffer
);
6327 return (IPP_STATE_ERROR
);
6330 DEBUG_printf(("2ippWriteIO: wrote %d bytes",
6331 (int)(bufptr
- buffer
)));
6335 * If blocking is disabled and we aren't at the end of the attribute
6336 * list, stop here...
6339 if (!blocking
&& ipp
->current
)
6343 if (ipp
->current
== NULL
)
6346 * Done with all of the attributes; add the end-of-attributes
6347 * tag or end-collection attribute...
6352 buffer
[0] = IPP_TAG_END
;
6357 buffer
[0] = IPP_TAG_END_COLLECTION
;
6358 buffer
[1] = 0; /* empty name */
6360 buffer
[3] = 0; /* empty value */
6365 if ((*cb
)(dst
, buffer
, (size_t)n
) < 0)
6367 DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
6368 _cupsBufferRelease((char *)buffer
);
6369 return (IPP_STATE_ERROR
);
6372 ipp
->state
= IPP_STATE_DATA
;
6376 case IPP_STATE_DATA
:
6380 break; /* anti-compiler-warning-code */
6383 _cupsBufferRelease((char *)buffer
);
6385 return (ipp
->state
);
6390 * 'ipp_add_attr()' - Add a new attribute to the message.
6393 static ipp_attribute_t
* /* O - New attribute */
6394 ipp_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 */
6400 int alloc_values
; /* Number of values to allocate */
6401 ipp_attribute_t
*attr
; /* New attribute */
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
));
6408 * Range check input...
6411 if (!ipp
|| num_values
< 0)
6415 * Allocate memory, rounding the allocation up as needed...
6418 if (num_values
<= 1)
6421 alloc_values
= (num_values
+ IPP_MAX_VALUES
- 1) & ~(IPP_MAX_VALUES
- 1);
6423 attr
= calloc(sizeof(ipp_attribute_t
) +
6424 (size_t)(alloc_values
- 1) * sizeof(_ipp_value_t
), 1);
6429 * Initialize attribute...
6433 attr
->name
= _cupsStrAlloc(name
);
6435 attr
->group_tag
= group_tag
;
6436 attr
->value_tag
= value_tag
;
6437 attr
->num_values
= num_values
;
6440 * Add it to the end of the linked list...
6444 ipp
->last
->next
= attr
;
6448 ipp
->prev
= ipp
->last
;
6449 ipp
->last
= ipp
->current
= attr
;
6452 DEBUG_printf(("5ipp_add_attr: Returning %p", attr
));
6459 * 'ipp_free_values()' - Free attribute values.
6463 ipp_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 */
6467 int i
; /* Looping var */
6468 _ipp_value_t
*value
; /* Current value */
6471 DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", attr
,
6474 if (!(attr
->value_tag
& IPP_TAG_CUPS_CONST
))
6477 * Free values as needed...
6480 switch (attr
->value_tag
)
6482 case IPP_TAG_TEXTLANG
:
6483 case IPP_TAG_NAMELANG
:
6484 if (element
== 0 && count
== attr
->num_values
&&
6485 attr
->values
[0].string
.language
)
6487 _cupsStrFree(attr
->values
[0].string
.language
);
6488 attr
->values
[0].string
.language
= NULL
;
6490 /* Fall through to other string values */
6494 case IPP_TAG_RESERVED_STRING
:
6495 case IPP_TAG_KEYWORD
:
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
;
6505 _cupsStrFree(value
->string
.text
);
6506 value
->string
.text
= NULL
;
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
:
6518 case IPP_TAG_BOOLEAN
:
6520 case IPP_TAG_RESOLUTION
:
6521 case IPP_TAG_RANGE
:
6524 case IPP_TAG_BEGIN_COLLECTION
:
6525 for (i
= count
, value
= attr
->values
+ element
;
6529 ippDelete(value
->collection
);
6530 value
->collection
= NULL
;
6534 case IPP_TAG_STRING
:
6536 for (i
= count
, value
= attr
->values
+ element
;
6540 if (value
->unknown
.data
)
6542 free(value
->unknown
.data
);
6543 value
->unknown
.data
= NULL
;
6551 * If we are not freeing values from the end, move the remaining values up...
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
));
6558 attr
->num_values
-= count
;
6563 * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
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.
6569 static char * /* O - Language code string */
6570 ipp_get_code(const char *value
, /* I - Locale/charset string */
6571 char *buffer
, /* I - String buffer */
6572 size_t bufsize
) /* I - Size of string buffer */
6574 char *bufptr
, /* Pointer into buffer */
6575 *bufend
; /* End of buffer */
6579 * Convert values to lowercase and change _ to - as needed...
6582 for (bufptr
= buffer
, bufend
= buffer
+ bufsize
- 1;
6583 *value
&& bufptr
< bufend
;
6588 *bufptr
++ = (char)_cups_tolower(*value
);
6593 * Return the converted string...
6601 * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
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".
6607 static char * /* O - Language code string */
6608 ipp_lang_code(const char *locale
, /* I - Locale string */
6609 char *buffer
, /* I - String buffer */
6610 size_t bufsize
) /* I - Size of string buffer */
6613 * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
6616 if (!_cups_strcasecmp(locale
, "c"))
6618 strlcpy(buffer
, "en", bufsize
);
6622 return (ipp_get_code(locale
, buffer
, bufsize
));
6627 * 'ipp_length()' - Compute the length of an IPP message or collection value.
6630 static size_t /* O - Size of IPP message */
6631 ipp_length(ipp_t
*ipp
, /* I - IPP message or collection */
6632 int collection
) /* I - 1 if a collection, 0 otherwise */
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 */
6641 DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", ipp
, collection
));
6645 DEBUG_puts("4ipp_length: Returning 0 bytes");
6650 * Start with 8 bytes for the IPP message header...
6653 bytes
= collection
? 0 : 8;
6656 * Then add the lengths of each attribute...
6659 group
= IPP_TAG_ZERO
;
6661 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= attr
->next
)
6663 if (attr
->group_tag
!= group
&& !collection
)
6665 group
= attr
->group_tag
;
6666 if (group
== IPP_TAG_ZERO
)
6669 bytes
++; /* Group tag */
6675 DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
6676 "bytes=" CUPS_LLFMT
, attr
->name
, attr
->num_values
, CUPS_LLCAST bytes
));
6678 if ((attr
->value_tag
& ~IPP_TAG_CUPS_CONST
) < IPP_TAG_EXTENSION
)
6679 bytes
+= (size_t)attr
->num_values
;/* Value tag for each value */
6681 bytes
+= (size_t)(5 * attr
->num_values
);
6682 /* Value tag for each value */
6683 bytes
+= (size_t)(2 * attr
->num_values
);
6685 bytes
+= strlen(attr
->name
); /* Name */
6686 bytes
+= (size_t)(2 * attr
->num_values
);
6690 bytes
+= 5; /* Add membername overhead */
6692 switch (attr
->value_tag
& ~IPP_TAG_CUPS_CONST
)
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
:
6703 case IPP_TAG_INTEGER
:
6705 bytes
+= (size_t)(4 * attr
->num_values
);
6708 case IPP_TAG_BOOLEAN
:
6709 bytes
+= (size_t)attr
->num_values
;
6714 case IPP_TAG_KEYWORD
:
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
;
6723 if (value
->string
.text
)
6724 bytes
+= strlen(value
->string
.text
);
6728 bytes
+= (size_t)(11 * attr
->num_values
);
6731 case IPP_TAG_RESOLUTION
:
6732 bytes
+= (size_t)(9 * attr
->num_values
);
6735 case IPP_TAG_RANGE
:
6736 bytes
+= (size_t)(8 * attr
->num_values
);
6739 case IPP_TAG_TEXTLANG
:
6740 case IPP_TAG_NAMELANG
:
6741 bytes
+= (size_t)(4 * attr
->num_values
);
6742 /* Charset + text length */
6744 for (i
= 0, value
= attr
->values
;
6745 i
< attr
->num_values
;
6748 if (value
->string
.language
)
6749 bytes
+= strlen(value
->string
.language
);
6751 if (value
->string
.text
)
6752 bytes
+= strlen(value
->string
.text
);
6756 case IPP_TAG_BEGIN_COLLECTION
:
6757 for (i
= 0, value
= attr
->values
;
6758 i
< attr
->num_values
;
6760 bytes
+= ipp_length(value
->collection
, 1);
6764 for (i
= 0, value
= attr
->values
;
6765 i
< attr
->num_values
;
6767 bytes
+= (size_t)value
->unknown
.length
;
6773 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
6774 * for the "end of collection" tag and return...
6782 DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT
" bytes", CUPS_LLCAST bytes
));
6789 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
6792 static ssize_t
/* O - Number of bytes read */
6793 ipp_read_http(http_t
*http
, /* I - Client connection */
6794 ipp_uchar_t
*buffer
, /* O - Buffer for data */
6795 size_t length
) /* I - Total length */
6797 ssize_t tbytes
, /* Total bytes read */
6798 bytes
; /* Bytes read this pass */
6801 DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)",
6802 http
, buffer
, (int)length
));
6805 * Loop until all bytes are read...
6808 for (tbytes
= 0, bytes
= 0;
6809 tbytes
< (int)length
;
6810 tbytes
+= bytes
, buffer
+= bytes
)
6812 DEBUG_printf(("9ipp_read_http: tbytes=" CUPS_LLFMT
", http->state=%d", CUPS_LLCAST tbytes
, http
->state
));
6814 if (http
->state
== HTTP_STATE_WAITING
)
6817 if (http
->used
== 0 && !http
->blocking
)
6820 * Wait up to 10 seconds for more data on non-blocking sockets...
6823 if (!httpWait(http
, 10000))
6834 if ((bytes
= httpRead2(http
, (char *)buffer
, length
- (size_t)tbytes
)) < 0)
6839 if (errno
!= EAGAIN
&& errno
!= EINTR
)
6845 else if (bytes
== 0)
6850 * Return the number of bytes read...
6853 if (tbytes
== 0 && bytes
< 0)
6856 DEBUG_printf(("8ipp_read_http: Returning " CUPS_LLFMT
" bytes", CUPS_LLCAST tbytes
));
6863 * 'ipp_read_file()' - Read IPP data from a file.
6866 static ssize_t
/* O - Number of bytes read */
6867 ipp_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 */
6872 return ((ssize_t
)read(*fd
, buffer
, (unsigned)length
));
6874 return (read(*fd
, buffer
, length
));
6880 * 'ipp_set_error()' - Set a formatted, localized error string.
6884 ipp_set_error(ipp_status_t status
, /* I - Status code */
6885 const char *format
, /* I - Printf-style error string */
6886 ...) /* I - Additional arguments as needed */
6888 va_list ap
; /* Pointer to additional args */
6889 char buffer
[2048]; /* Message buffer */
6890 cups_lang_t
*lang
= cupsLangDefault();
6891 /* Current language */
6894 va_start(ap
, format
);
6895 vsnprintf(buffer
, sizeof(buffer
), _cupsLangString(lang
, format
), ap
);
6898 _cupsSetError(status
, buffer
, 0);
6903 * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
6907 static _ipp_value_t
* /* O - IPP value element or NULL on error */
6908 ipp_set_value(ipp_t
*ipp
, /* IO - IPP message */
6909 ipp_attribute_t
**attr
, /* IO - IPP attribute */
6910 int element
) /* I - Value number (0-based) */
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 */
6919 * If we are setting an existing value element, return it...
6924 if (temp
->num_values
<= 1)
6927 alloc_values
= (temp
->num_values
+ IPP_MAX_VALUES
- 1) &
6928 ~(IPP_MAX_VALUES
- 1);
6930 if (element
< alloc_values
)
6932 if (element
>= temp
->num_values
)
6933 temp
->num_values
= element
+ 1;
6935 return (temp
->values
+ element
);
6939 * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
6940 * values when num_values > 1.
6943 if (alloc_values
< IPP_MAX_VALUES
)
6944 alloc_values
= IPP_MAX_VALUES
;
6946 alloc_values
+= IPP_MAX_VALUES
;
6948 DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
6952 * Reallocate memory...
6955 if ((temp
= realloc(temp
, sizeof(ipp_attribute_t
) + (size_t)(alloc_values
- 1) * sizeof(_ipp_value_t
))) == NULL
)
6957 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
6958 DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
6963 * Zero the new memory...
6966 memset(temp
->values
+ temp
->num_values
, 0, (size_t)(alloc_values
- temp
->num_values
) * sizeof(_ipp_value_t
));
6971 * Reset pointers in the list...
6974 if (ipp
->current
== *attr
&& ipp
->prev
)
6977 * Use current "previous" pointer...
6985 * Find this attribute in the linked list...
6988 for (prev
= NULL
, current
= ipp
->attrs
;
6989 current
&& current
!= *attr
;
6990 prev
= current
, current
= current
->next
);
6995 * This is a serious error!
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.");
7011 ipp
->current
= temp
;
7014 if (ipp
->last
== *attr
)
7021 * Return the value element...
7024 if (element
>= temp
->num_values
)
7025 temp
->num_values
= element
+ 1;
7027 return (temp
->values
+ element
);
7032 * 'ipp_write_file()' - Write IPP data to a file.
7035 static ssize_t
/* O - Number of bytes written */
7036 ipp_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 */
7041 return ((ssize_t
)write(*fd
, buffer
, (unsigned)length
));
7043 return (write(*fd
, buffer
, length
));