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.
1988 ipp_attribute_t
* /* O - Matching attribute */
1989 ippFindAttribute(ipp_t
*ipp
, /* I - IPP message */
1990 const char *name
, /* I - Name of attribute */
1991 ipp_tag_t type
) /* I - Type of attribute */
1993 DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", ipp
,
1994 name
, type
, ippTagString(type
)));
2000 * Reset the current pointer...
2003 ipp
->current
= NULL
;
2006 * Search for the attribute...
2009 return (ippFindNextAttribute(ipp
, name
, type
));
2014 * 'ippFindNextAttribute()' - Find the next named attribute in a request.
2017 ipp_attribute_t
* /* O - Matching attribute */
2018 ippFindNextAttribute(ipp_t
*ipp
, /* I - IPP message */
2019 const char *name
, /* I - Name of attribute */
2020 ipp_tag_t type
) /* I - Type of attribute */
2022 ipp_attribute_t
*attr
; /* Current atttribute */
2023 ipp_tag_t value_tag
; /* Value tag */
2026 DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))",
2027 ipp
, name
, type
, ippTagString(type
)));
2034 ipp
->prev
= ipp
->current
;
2035 attr
= ipp
->current
->next
;
2043 for (; attr
!= NULL
; ipp
->prev
= attr
, attr
= attr
->next
)
2045 DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", attr
,
2048 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_CUPS_MASK
);
2050 if (attr
->name
!= NULL
&& _cups_strcasecmp(attr
->name
, name
) == 0 &&
2051 (value_tag
== type
|| type
== IPP_TAG_ZERO
||
2052 (value_tag
== IPP_TAG_TEXTLANG
&& type
== IPP_TAG_TEXT
) ||
2053 (value_tag
== IPP_TAG_NAMELANG
&& type
== IPP_TAG_NAME
)))
2055 ipp
->current
= attr
;
2061 ipp
->current
= NULL
;
2069 * 'ippFirstAttribute()' - Return the first attribute in the message.
2071 * @since CUPS 1.6/OS X 10.8@
2074 ipp_attribute_t
* /* O - First attribute or @code NULL@ if none */
2075 ippFirstAttribute(ipp_t
*ipp
) /* I - IPP message */
2078 * Range check input...
2085 * Return the first attribute...
2088 return (ipp
->current
= ipp
->attrs
);
2093 * 'ippGetBoolean()' - Get a boolean value for an attribute.
2095 * The @code element@ parameter specifies which value to get from 0 to
2096 * @link ippGetCount(attr)@ - 1.
2098 * @since CUPS 1.6/OS X 10.8@
2101 int /* O - Boolean value or -1 on error */
2102 ippGetBoolean(ipp_attribute_t
*attr
, /* I - IPP attribute */
2103 int element
) /* I - Value number (0-based) */
2106 * Range check input...
2109 if (!attr
|| attr
->value_tag
!= IPP_TAG_BOOLEAN
||
2110 element
< 0 || element
>= attr
->num_values
)
2114 * Return the value...
2117 return (attr
->values
[element
].boolean
);
2122 * 'ippGetCollection()' - Get a collection value for an attribute.
2124 * The @code element@ parameter specifies which value to get from 0 to
2125 * @link ippGetCount(attr)@ - 1.
2127 * @since CUPS 1.6/OS X 10.8@
2130 ipp_t
* /* O - Collection value or @code NULL@ on error */
2132 ipp_attribute_t
*attr
, /* I - IPP attribute */
2133 int element
) /* I - Value number (0-based) */
2136 * Range check input...
2139 if (!attr
|| attr
->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
2140 element
< 0 || element
>= attr
->num_values
)
2144 * Return the value...
2147 return (attr
->values
[element
].collection
);
2152 * 'ippGetCount()' - Get the number of values in an attribute.
2154 * @since CUPS 1.6/OS X 10.8@
2157 int /* O - Number of values or -1 on error */
2158 ippGetCount(ipp_attribute_t
*attr
) /* I - IPP attribute */
2161 * Range check input...
2168 * Return the number of values...
2171 return (attr
->num_values
);
2176 * 'ippGetDate()' - Get a date value for an attribute.
2178 * The @code element@ parameter specifies which value to get from 0 to
2179 * @link ippGetCount(attr)@ - 1.
2181 * @since CUPS 1.6/OS X 10.8@
2184 const ipp_uchar_t
* /* O - Date value or @code NULL@ */
2185 ippGetDate(ipp_attribute_t
*attr
, /* I - IPP attribute */
2186 int element
) /* I - Value number (0-based) */
2189 * Range check input...
2192 if (!attr
|| attr
->value_tag
!= IPP_TAG_DATE
||
2193 element
< 0 || element
>= attr
->num_values
)
2197 * Return the value...
2200 return (attr
->values
[element
].date
);
2205 * 'ippGetGroupTag()' - Get the group associated with an attribute.
2207 * @since CUPS 1.6/OS X 10.8@
2210 ipp_tag_t
/* O - Group tag or @code IPP_TAG_ZERO@ on error */
2211 ippGetGroupTag(ipp_attribute_t
*attr
) /* I - IPP attribute */
2214 * Range check input...
2218 return (IPP_TAG_ZERO
);
2221 * Return the group...
2224 return (attr
->group_tag
);
2229 * 'ippGetInteger()' - Get the integer/enum value for an attribute.
2231 * The @code element@ parameter specifies which value to get from 0 to
2232 * @link ippGetCount(attr)@ - 1.
2234 * @since CUPS 1.6/OS X 10.8@
2237 int /* O - Value or -1 on error */
2238 ippGetInteger(ipp_attribute_t
*attr
, /* I - IPP attribute */
2239 int element
) /* I - Value number (0-based) */
2242 * Range check input...
2245 if (!attr
|| (attr
->value_tag
!= IPP_TAG_INTEGER
&& attr
->value_tag
!= IPP_TAG_ENUM
) ||
2246 element
< 0 || element
>= attr
->num_values
)
2250 * Return the value...
2253 return (attr
->values
[element
].integer
);
2258 * 'ippGetName()' - Get the attribute name.
2260 * @since CUPS 1.6/OS X 10.8@
2263 const char * /* O - Attribute name or @code NULL@ for separators */
2264 ippGetName(ipp_attribute_t
*attr
) /* I - IPP attribute */
2267 * Range check input...
2274 * Return the name...
2277 return (attr
->name
);
2282 * 'ippGetOctetString()' - Get an octetString value from an IPP attribute.
2284 * The @code element@ parameter specifies which value to get from 0 to
2285 * @link ippGetCount(attr)@ - 1.
2287 * @since CUPS 1.7/OS X 10.9@
2290 void * /* O - Pointer to octetString data */
2292 ipp_attribute_t
*attr
, /* I - IPP attribute */
2293 int element
, /* I - Value number (0-based) */
2294 int *datalen
) /* O - Length of octetString data */
2297 * Range check input...
2300 if (!attr
|| attr
->value_tag
!= IPP_TAG_STRING
||
2301 element
< 0 || element
>= attr
->num_values
)
2310 * Return the values...
2314 *datalen
= attr
->values
[element
].unknown
.length
;
2316 return (attr
->values
[element
].unknown
.data
);
2321 * 'ippGetOperation()' - Get the operation ID in an IPP message.
2323 * @since CUPS 1.6/OS X 10.8@
2326 ipp_op_t
/* O - Operation ID or -1 on error */
2327 ippGetOperation(ipp_t
*ipp
) /* I - IPP request message */
2330 * Range check input...
2334 return ((ipp_op_t
)-1);
2337 * Return the value...
2340 return (ipp
->request
.op
.operation_id
);
2345 * 'ippGetRange()' - Get a rangeOfInteger value from an attribute.
2347 * The @code element@ parameter specifies which value to get from 0 to
2348 * @link ippGetCount(attr)@ - 1.
2350 * @since CUPS 1.6/OS X 10.8@
2353 int /* O - Lower value of range or -1 */
2354 ippGetRange(ipp_attribute_t
*attr
, /* I - IPP attribute */
2355 int element
, /* I - Value number (0-based) */
2356 int *uppervalue
)/* O - Upper value of range */
2359 * Range check input...
2362 if (!attr
|| attr
->value_tag
!= IPP_TAG_RANGE
||
2363 element
< 0 || element
>= attr
->num_values
)
2372 * Return the values...
2376 *uppervalue
= attr
->values
[element
].range
.upper
;
2378 return (attr
->values
[element
].range
.lower
);
2383 * 'ippGetRequestId()' - Get the request ID from an IPP message.
2385 * @since CUPS 1.6/OS X 10.8@
2388 int /* O - Request ID or -1 on error */
2389 ippGetRequestId(ipp_t
*ipp
) /* I - IPP message */
2392 * Range check input...
2399 * Return the request ID...
2402 return (ipp
->request
.any
.request_id
);
2407 * 'ippGetResolution()' - Get a resolution value for an attribute.
2409 * The @code element@ parameter specifies which value to get from 0 to
2410 * @link ippGetCount(attr)@ - 1.
2412 * @since CUPS 1.6/OS X 10.8@
2415 int /* O - Horizontal/cross feed resolution or -1 */
2417 ipp_attribute_t
*attr
, /* I - IPP attribute */
2418 int element
, /* I - Value number (0-based) */
2419 int *yres
, /* O - Vertical/feed resolution */
2420 ipp_res_t
*units
) /* O - Units for resolution */
2423 * Range check input...
2426 if (!attr
|| attr
->value_tag
!= IPP_TAG_RESOLUTION
||
2427 element
< 0 || element
>= attr
->num_values
)
2431 * Return the value...
2435 *yres
= attr
->values
[element
].resolution
.yres
;
2438 *units
= attr
->values
[element
].resolution
.units
;
2440 return (attr
->values
[element
].resolution
.xres
);
2445 * 'ippGetState()' - Get the IPP message state.
2447 * @since CUPS 1.6/OS X 10.8@
2450 ipp_state_t
/* O - IPP message state value */
2451 ippGetState(ipp_t
*ipp
) /* I - IPP message */
2454 * Range check input...
2458 return (IPP_STATE_IDLE
);
2461 * Return the value...
2464 return (ipp
->state
);
2469 * 'ippGetStatusCode()' - Get the status code from an IPP response or event message.
2471 * @since CUPS 1.6/OS X 10.8@
2474 ipp_status_t
/* O - Status code in IPP message */
2475 ippGetStatusCode(ipp_t
*ipp
) /* I - IPP response or event message */
2478 * Range check input...
2482 return (IPP_STATUS_ERROR_INTERNAL
);
2485 * Return the value...
2488 return (ipp
->request
.status
.status_code
);
2493 * 'ippGetString()' - Get the string and optionally the language code for an attribute.
2495 * The @code element@ parameter specifies which value to get from 0 to
2496 * @link ippGetCount(attr)@ - 1.
2498 * @since CUPS 1.6/OS X 10.8@
2502 ippGetString(ipp_attribute_t
*attr
, /* I - IPP attribute */
2503 int element
, /* I - Value number (0-based) */
2504 const char **language
)/* O - Language code (@code NULL@ for don't care) */
2507 * Range check input...
2510 if (!attr
|| element
< 0 || element
>= attr
->num_values
||
2511 (attr
->value_tag
!= IPP_TAG_TEXTLANG
&& attr
->value_tag
!= IPP_TAG_NAMELANG
&&
2512 (attr
->value_tag
< IPP_TAG_TEXT
|| attr
->value_tag
> IPP_TAG_MIMETYPE
)))
2516 * Return the value...
2520 *language
= attr
->values
[element
].string
.language
;
2522 return (attr
->values
[element
].string
.text
);
2527 * 'ippGetValueTag()' - Get the value tag for an attribute.
2529 * @since CUPS 1.6/OS X 10.8@
2532 ipp_tag_t
/* O - Value tag or @code IPP_TAG_ZERO@ on error */
2533 ippGetValueTag(ipp_attribute_t
*attr
) /* I - IPP attribute */
2536 * Range check input...
2540 return (IPP_TAG_ZERO
);
2543 * Return the value...
2546 return (attr
->value_tag
& IPP_TAG_CUPS_MASK
);
2551 * 'ippGetVersion()' - Get the major and minor version number from an IPP message.
2553 * @since CUPS 1.6/OS X 10.8@
2556 int /* O - Major version number or -1 on error */
2557 ippGetVersion(ipp_t
*ipp
, /* I - IPP message */
2558 int *minor
) /* O - Minor version number or @code NULL@ */
2561 * Range check input...
2573 * Return the value...
2577 *minor
= ipp
->request
.any
.version
[1];
2579 return (ipp
->request
.any
.version
[0]);
2584 * 'ippLength()' - Compute the length of an IPP message.
2587 size_t /* O - Size of IPP message */
2588 ippLength(ipp_t
*ipp
) /* I - IPP message */
2590 return (ipp_length(ipp
, 0));
2595 * 'ippNextAttribute()' - Return the next attribute in the message.
2597 * @since CUPS 1.6/OS X 10.8@
2600 ipp_attribute_t
* /* O - Next attribute or @code NULL@ if none */
2601 ippNextAttribute(ipp_t
*ipp
) /* I - IPP message */
2604 * Range check input...
2607 if (!ipp
|| !ipp
->current
)
2611 * Return the next attribute...
2614 return (ipp
->current
= ipp
->current
->next
);
2619 * 'ippNew()' - Allocate a new IPP message.
2622 ipp_t
* /* O - New IPP message */
2625 ipp_t
*temp
; /* New IPP message */
2626 _cups_globals_t
*cg
= _cupsGlobals();
2630 DEBUG_puts("ippNew()");
2632 if ((temp
= (ipp_t
*)calloc(1, sizeof(ipp_t
))) != NULL
)
2635 * Set default version - usually 2.0...
2638 if (cg
->server_version
== 0)
2641 temp
->request
.any
.version
[0] = (ipp_uchar_t
)(cg
->server_version
/ 10);
2642 temp
->request
.any
.version
[1] = (ipp_uchar_t
)(cg
->server_version
% 10);
2646 DEBUG_printf(("1ippNew: Returning %p", temp
));
2653 * 'ippNewRequest()' - Allocate a new IPP request message.
2655 * The new request message is initialized with the attributes-charset and
2656 * attributes-natural-language attributes added. The
2657 * attributes-natural-language value is derived from the current locale.
2659 * @since CUPS 1.2/OS X 10.5@
2662 ipp_t
* /* O - IPP request message */
2663 ippNewRequest(ipp_op_t op
) /* I - Operation code */
2665 ipp_t
*request
; /* IPP request message */
2666 cups_lang_t
*language
; /* Current language localization */
2667 static int request_id
= 0; /* Current request ID */
2668 static _cups_mutex_t request_mutex
= _CUPS_MUTEX_INITIALIZER
;
2669 /* Mutex for request ID */
2672 DEBUG_printf(("ippNewRequest(op=%02x(%s))", op
, ippOpString(op
)));
2675 * Create a new IPP message...
2678 if ((request
= ippNew()) == NULL
)
2682 * Set the operation and request ID...
2685 _cupsMutexLock(&request_mutex
);
2687 request
->request
.op
.operation_id
= op
;
2688 request
->request
.op
.request_id
= ++request_id
;
2690 _cupsMutexUnlock(&request_mutex
);
2693 * Use UTF-8 as the character set...
2696 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2697 "attributes-charset", NULL
, "utf-8");
2700 * Get the language from the current locale...
2703 language
= cupsLangDefault();
2705 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2706 "attributes-natural-language", NULL
, language
->language
);
2709 * Return the new request...
2717 * 'ippNewResponse()' - Allocate a new IPP response message.
2719 * The new response message is initialized with the same version-number,
2720 * request-id, attributes-charset, and attributes-natural-language as the
2721 * provided request message. If the attributes-charset or
2722 * attributes-natural-language attributes are missing from the request,
2723 * "utf-8" and a value derived from the current locale are substituted,
2726 * @since CUPS 1.7/OS X 10.9@
2729 ipp_t
* /* O - IPP response message */
2730 ippNewResponse(ipp_t
*request
) /* I - IPP request message */
2732 ipp_t
*response
; /* IPP response message */
2733 ipp_attribute_t
*attr
; /* Current attribute */
2737 * Range check input...
2744 * Create a new IPP message...
2747 if ((response
= ippNew()) == NULL
)
2751 * Copy the request values over to the response...
2754 response
->request
.status
.version
[0] = request
->request
.op
.version
[0];
2755 response
->request
.status
.version
[1] = request
->request
.op
.version
[1];
2756 response
->request
.status
.request_id
= request
->request
.op
.request_id
;
2759 * The first attribute MUST be attributes-charset...
2762 attr
= request
->attrs
;
2764 if (attr
&& attr
->name
&& !strcmp(attr
->name
, "attributes-charset") &&
2765 attr
->group_tag
== IPP_TAG_OPERATION
&&
2766 attr
->value_tag
== IPP_TAG_CHARSET
&&
2767 attr
->num_values
== 1)
2770 * Copy charset from request...
2773 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2774 "attributes-charset", NULL
, attr
->values
[0].string
.text
);
2779 * Use "utf-8" as the default...
2782 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2783 "attributes-charset", NULL
, "utf-8");
2787 * Then attributes-natural-language...
2793 if (attr
&& attr
->name
&&
2794 !strcmp(attr
->name
, "attributes-natural-language") &&
2795 attr
->group_tag
== IPP_TAG_OPERATION
&&
2796 attr
->value_tag
== IPP_TAG_LANGUAGE
&&
2797 attr
->num_values
== 1)
2800 * Copy language from request...
2803 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2804 "attributes-natural-language", NULL
,
2805 attr
->values
[0].string
.text
);
2810 * Use the language from the current locale...
2813 cups_lang_t
*language
= cupsLangDefault();
2814 /* Current locale */
2816 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2817 "attributes-natural-language", NULL
, language
->language
);
2825 * 'ippRead()' - Read data for an IPP message from a HTTP connection.
2828 ipp_state_t
/* O - Current state */
2829 ippRead(http_t
*http
, /* I - HTTP connection */
2830 ipp_t
*ipp
) /* I - IPP data */
2832 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT
,
2833 http
, ipp
, CUPS_LLCAST (http
? http
->data_remaining
: -1)));
2836 return (IPP_STATE_ERROR
);
2838 DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http
->state
,
2841 return (ippReadIO(http
, (ipp_iocb_t
)ipp_read_http
, http
->blocking
, NULL
,
2847 * 'ippReadFile()' - Read data for an IPP message from a file.
2849 * @since CUPS 1.1.19/OS X 10.3@
2852 ipp_state_t
/* O - Current state */
2853 ippReadFile(int fd
, /* I - HTTP data */
2854 ipp_t
*ipp
) /* I - IPP data */
2856 DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd
, ipp
));
2858 return (ippReadIO(&fd
, (ipp_iocb_t
)ipp_read_file
, 1, NULL
, ipp
));
2863 * 'ippReadIO()' - Read data for an IPP message.
2865 * @since CUPS 1.2/OS X 10.5@
2868 ipp_state_t
/* O - Current state */
2869 ippReadIO(void *src
, /* I - Data source */
2870 ipp_iocb_t cb
, /* I - Read callback function */
2871 int blocking
, /* I - Use blocking IO? */
2872 ipp_t
*parent
, /* I - Parent request, if any */
2873 ipp_t
*ipp
) /* I - IPP data */
2875 int n
; /* Length of data */
2876 unsigned char *buffer
, /* Data buffer */
2877 string
[IPP_MAX_TEXT
],
2878 /* Small string buffer */
2879 *bufptr
; /* Pointer into buffer */
2880 ipp_attribute_t
*attr
; /* Current attribute */
2881 ipp_tag_t tag
; /* Current tag */
2882 ipp_tag_t value_tag
; /* Current value tag */
2883 _ipp_value_t
*value
; /* Current value */
2886 DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
2887 src
, cb
, blocking
, parent
, ipp
));
2888 DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp
? ipp
->state
: IPP_STATE_ERROR
));
2891 return (IPP_STATE_ERROR
);
2893 if ((buffer
= (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE
)) == NULL
)
2895 DEBUG_puts("1ippReadIO: Unable to get read buffer.");
2896 return (IPP_STATE_ERROR
);
2901 case IPP_STATE_IDLE
:
2902 ipp
->state
++; /* Avoid common problem... */
2904 case IPP_STATE_HEADER
:
2908 * Get the request header...
2911 if ((*cb
)(src
, buffer
, 8) < 8)
2913 DEBUG_puts("1ippReadIO: Unable to read header.");
2914 _cupsBufferRelease((char *)buffer
);
2915 return (IPP_STATE_ERROR
);
2919 * Then copy the request header over...
2922 ipp
->request
.any
.version
[0] = buffer
[0];
2923 ipp
->request
.any
.version
[1] = buffer
[1];
2924 ipp
->request
.any
.op_status
= (buffer
[2] << 8) | buffer
[3];
2925 ipp
->request
.any
.request_id
= (((((buffer
[4] << 8) | buffer
[5]) << 8) |
2926 buffer
[6]) << 8) | buffer
[7];
2928 DEBUG_printf(("2ippReadIO: version=%d.%d", buffer
[0], buffer
[1]));
2929 DEBUG_printf(("2ippReadIO: op_status=%04x",
2930 ipp
->request
.any
.op_status
));
2931 DEBUG_printf(("2ippReadIO: request_id=%d",
2932 ipp
->request
.any
.request_id
));
2935 ipp
->state
= IPP_STATE_ATTRIBUTE
;
2936 ipp
->current
= NULL
;
2937 ipp
->curtag
= IPP_TAG_ZERO
;
2938 ipp
->prev
= ipp
->last
;
2941 * If blocking is disabled, stop here...
2947 case IPP_STATE_ATTRIBUTE
:
2950 if ((*cb
)(src
, buffer
, 1) < 1)
2952 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
2953 _cupsBufferRelease((char *)buffer
);
2954 return (IPP_STATE_ERROR
);
2957 DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p",
2958 ipp
->current
, ipp
->prev
));
2961 * Read this attribute...
2964 tag
= (ipp_tag_t
)buffer
[0];
2965 if (tag
== IPP_TAG_EXTENSION
)
2968 * Read 32-bit "extension" tag...
2971 if ((*cb
)(src
, buffer
, 4) < 1)
2973 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
2974 _cupsBufferRelease((char *)buffer
);
2975 return (IPP_STATE_ERROR
);
2978 tag
= (ipp_tag_t
)((((((buffer
[0] << 8) | buffer
[1]) << 8) |
2979 buffer
[2]) << 8) | buffer
[3]);
2981 if (tag
& IPP_TAG_CUPS_CONST
)
2984 * Fail if the high bit is set in the tag...
2987 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
2988 DEBUG_printf(("1ippReadIO: bad tag 0x%x.", tag
));
2989 _cupsBufferRelease((char *)buffer
);
2990 return (IPP_STATE_ERROR
);
2994 if (tag
== IPP_TAG_END
)
2997 * No more attributes left...
3000 DEBUG_puts("2ippReadIO: IPP_TAG_END.");
3002 ipp
->state
= IPP_STATE_DATA
;
3005 else if (tag
< IPP_TAG_UNSUPPORTED_VALUE
)
3008 * Group tag... Set the current group and continue...
3011 if (ipp
->curtag
== tag
)
3012 ipp
->prev
= ippAddSeparator(ipp
);
3013 else if (ipp
->current
)
3014 ipp
->prev
= ipp
->current
;
3017 ipp
->current
= NULL
;
3018 DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag
,
3019 ippTagString(tag
), ipp
->prev
));
3023 DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag
,
3024 ippTagString(tag
)));
3030 if ((*cb
)(src
, buffer
, 2) < 2)
3032 DEBUG_puts("1ippReadIO: unable to read name length.");
3033 _cupsBufferRelease((char *)buffer
);
3034 return (IPP_STATE_ERROR
);
3037 n
= (buffer
[0] << 8) | buffer
[1];
3039 if (n
>= IPP_BUF_SIZE
)
3041 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP name larger than 32767 bytes."), 1);
3042 DEBUG_printf(("1ippReadIO: bad name length %d.", n
));
3043 _cupsBufferRelease((char *)buffer
);
3044 return (IPP_STATE_ERROR
);
3047 DEBUG_printf(("2ippReadIO: name length=%d", n
));
3049 if (n
== 0 && tag
!= IPP_TAG_MEMBERNAME
&&
3050 tag
!= IPP_TAG_END_COLLECTION
)
3053 * More values for current attribute...
3056 if (ipp
->current
== NULL
)
3058 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP attribute has no name."), 1);
3059 DEBUG_puts("1ippReadIO: Attribute without name and no current.");
3060 _cupsBufferRelease((char *)buffer
);
3061 return (IPP_STATE_ERROR
);
3064 attr
= ipp
->current
;
3065 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_CUPS_MASK
);
3068 * Make sure we aren't adding a new value of a different
3072 if (value_tag
== IPP_TAG_ZERO
)
3075 * Setting the value of a collection member...
3078 attr
->value_tag
= tag
;
3080 else if (value_tag
== IPP_TAG_TEXTLANG
||
3081 value_tag
== IPP_TAG_NAMELANG
||
3082 (value_tag
>= IPP_TAG_TEXT
&&
3083 value_tag
<= IPP_TAG_MIMETYPE
))
3086 * String values can sometimes come across in different
3087 * forms; accept sets of differing values...
3090 if (tag
!= IPP_TAG_TEXTLANG
&& tag
!= IPP_TAG_NAMELANG
&&
3091 (tag
< IPP_TAG_TEXT
|| tag
> IPP_TAG_MIMETYPE
) &&
3092 tag
!= IPP_TAG_NOVALUE
)
3094 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3095 _("IPP 1setOf attribute with incompatible value "
3097 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3098 value_tag
, ippTagString(value_tag
), tag
,
3099 ippTagString(tag
)));
3100 _cupsBufferRelease((char *)buffer
);
3101 return (IPP_STATE_ERROR
);
3104 if (value_tag
!= tag
)
3106 DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.",
3107 attr
->name
, ippTagString(value_tag
), ippTagString(tag
)));
3108 ippSetValueTag(ipp
, &attr
, tag
);
3111 else if (value_tag
== IPP_TAG_INTEGER
||
3112 value_tag
== IPP_TAG_RANGE
)
3115 * Integer and rangeOfInteger values can sometimes be mixed; accept
3116 * sets of differing values...
3119 if (tag
!= IPP_TAG_INTEGER
&& tag
!= IPP_TAG_RANGE
)
3121 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3122 _("IPP 1setOf attribute with incompatible value "
3124 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3125 value_tag
, ippTagString(value_tag
), tag
,
3126 ippTagString(tag
)));
3127 _cupsBufferRelease((char *)buffer
);
3128 return (IPP_STATE_ERROR
);
3131 if (value_tag
== IPP_TAG_INTEGER
&& tag
== IPP_TAG_RANGE
)
3134 * Convert integer values to rangeOfInteger values...
3137 DEBUG_printf(("1ippReadIO: Converting %s attribute to "
3138 "rangeOfInteger.", attr
->name
));
3139 ippSetValueTag(ipp
, &attr
, IPP_TAG_RANGE
);
3142 else if (value_tag
!= tag
)
3144 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3145 _("IPP 1setOf attribute with incompatible value "
3147 DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
3148 value_tag
, ippTagString(value_tag
), tag
,
3149 ippTagString(tag
)));
3150 _cupsBufferRelease((char *)buffer
);
3151 return (IPP_STATE_ERROR
);
3155 * Finally, reallocate the attribute array as needed...
3158 if ((value
= ipp_set_value(ipp
, &attr
, attr
->num_values
)) == NULL
)
3160 _cupsBufferRelease((char *)buffer
);
3161 return (IPP_STATE_ERROR
);
3164 else if (tag
== IPP_TAG_MEMBERNAME
)
3167 * Name must be length 0!
3172 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP member name is not empty."), 1);
3173 DEBUG_puts("1ippReadIO: member name not empty.");
3174 _cupsBufferRelease((char *)buffer
);
3175 return (IPP_STATE_ERROR
);
3179 ipp
->prev
= ipp
->current
;
3181 attr
= ipp
->current
= ipp_add_attr(ipp
, NULL
, ipp
->curtag
, IPP_TAG_ZERO
, 1);
3184 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
3185 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3186 _cupsBufferRelease((char *)buffer
);
3187 return (IPP_STATE_ERROR
);
3190 DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p",
3191 ipp
->current
, ipp
->prev
));
3193 value
= attr
->values
;
3195 else if (tag
!= IPP_TAG_END_COLLECTION
)
3198 * New attribute; read the name and add it...
3201 if ((*cb
)(src
, buffer
, (size_t)n
) < n
)
3203 DEBUG_puts("1ippReadIO: unable to read name.");
3204 _cupsBufferRelease((char *)buffer
);
3205 return (IPP_STATE_ERROR
);
3211 ipp
->prev
= ipp
->current
;
3213 if ((attr
= ipp
->current
= ipp_add_attr(ipp
, (char *)buffer
, ipp
->curtag
, tag
,
3216 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
3217 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3218 _cupsBufferRelease((char *)buffer
);
3219 return (IPP_STATE_ERROR
);
3222 DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, "
3223 "ipp->prev=%p", buffer
, ipp
->current
, ipp
->prev
));
3225 value
= attr
->values
;
3233 if ((*cb
)(src
, buffer
, 2) < 2)
3235 DEBUG_puts("1ippReadIO: unable to read value length.");
3236 _cupsBufferRelease((char *)buffer
);
3237 return (IPP_STATE_ERROR
);
3240 n
= (buffer
[0] << 8) | buffer
[1];
3241 DEBUG_printf(("2ippReadIO: value length=%d", n
));
3243 if (n
>= IPP_BUF_SIZE
)
3245 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3246 _("IPP value larger than 32767 bytes."), 1);
3247 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
3248 _cupsBufferRelease((char *)buffer
);
3249 return (IPP_STATE_ERROR
);
3254 case IPP_TAG_INTEGER
:
3258 if (tag
== IPP_TAG_INTEGER
)
3259 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3260 _("IPP integer value not 4 bytes."), 1);
3262 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3263 _("IPP enum value not 4 bytes."), 1);
3264 DEBUG_printf(("1ippReadIO: bad integer value length %d.", n
));
3265 _cupsBufferRelease((char *)buffer
);
3266 return (IPP_STATE_ERROR
);
3269 if ((*cb
)(src
, buffer
, 4) < 4)
3271 DEBUG_puts("1ippReadIO: Unable to read integer value.");
3272 _cupsBufferRelease((char *)buffer
);
3273 return (IPP_STATE_ERROR
);
3276 n
= (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
3279 if (attr
->value_tag
== IPP_TAG_RANGE
)
3280 value
->range
.lower
= value
->range
.upper
= n
;
3285 case IPP_TAG_BOOLEAN
:
3288 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP boolean value not 1 byte."),
3290 DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n
));
3291 _cupsBufferRelease((char *)buffer
);
3292 return (IPP_STATE_ERROR
);
3295 if ((*cb
)(src
, buffer
, 1) < 1)
3297 DEBUG_puts("1ippReadIO: Unable to read boolean value.");
3298 _cupsBufferRelease((char *)buffer
);
3299 return (IPP_STATE_ERROR
);
3302 value
->boolean
= (char)buffer
[0];
3305 case IPP_TAG_NOVALUE
:
3306 case IPP_TAG_NOTSETTABLE
:
3307 case IPP_TAG_DELETEATTR
:
3308 case IPP_TAG_ADMINDEFINE
:
3310 * These value types are not supposed to have values, however
3311 * some vendors (Brother) do not implement IPP correctly and so
3312 * we need to map non-empty values to text...
3315 if (attr
->value_tag
== tag
)
3320 attr
->value_tag
= IPP_TAG_TEXT
;
3325 case IPP_TAG_KEYWORD
:
3327 case IPP_TAG_URISCHEME
:
3328 case IPP_TAG_CHARSET
:
3329 case IPP_TAG_LANGUAGE
:
3330 case IPP_TAG_MIMETYPE
:
3333 if ((*cb
)(src
, buffer
, (size_t)n
) < n
)
3335 DEBUG_puts("1ippReadIO: unable to read string value.");
3336 _cupsBufferRelease((char *)buffer
);
3337 return (IPP_STATE_ERROR
);
3342 value
->string
.text
= _cupsStrAlloc((char *)buffer
);
3343 DEBUG_printf(("2ippReadIO: value=\"%s\"", value
->string
.text
));
3349 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP date value not 11 bytes."), 1);
3350 DEBUG_printf(("1ippReadIO: bad date value length %d.", n
));
3351 _cupsBufferRelease((char *)buffer
);
3352 return (IPP_STATE_ERROR
);
3355 if ((*cb
)(src
, value
->date
, 11) < 11)
3357 DEBUG_puts("1ippReadIO: Unable to read date value.");
3358 _cupsBufferRelease((char *)buffer
);
3359 return (IPP_STATE_ERROR
);
3363 case IPP_TAG_RESOLUTION
:
3366 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3367 _("IPP resolution value not 9 bytes."), 1);
3368 DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n
));
3369 _cupsBufferRelease((char *)buffer
);
3370 return (IPP_STATE_ERROR
);
3373 if ((*cb
)(src
, buffer
, 9) < 9)
3375 DEBUG_puts("1ippReadIO: Unable to read resolution value.");
3376 _cupsBufferRelease((char *)buffer
);
3377 return (IPP_STATE_ERROR
);
3380 value
->resolution
.xres
=
3381 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
3383 value
->resolution
.yres
=
3384 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
3386 value
->resolution
.units
=
3387 (ipp_res_t
)buffer
[8];
3390 case IPP_TAG_RANGE
:
3393 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3394 _("IPP rangeOfInteger value not 8 bytes."), 1);
3395 DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length "
3397 _cupsBufferRelease((char *)buffer
);
3398 return (IPP_STATE_ERROR
);
3401 if ((*cb
)(src
, buffer
, 8) < 8)
3403 DEBUG_puts("1ippReadIO: Unable to read range value.");
3404 _cupsBufferRelease((char *)buffer
);
3405 return (IPP_STATE_ERROR
);
3408 value
->range
.lower
=
3409 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
3411 value
->range
.upper
=
3412 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
3416 case IPP_TAG_TEXTLANG
:
3417 case IPP_TAG_NAMELANG
:
3420 if (tag
== IPP_TAG_TEXTLANG
)
3421 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3422 _("IPP textWithLanguage value less than "
3423 "minimum 4 bytes."), 1);
3425 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3426 _("IPP nameWithLanguage value less than "
3427 "minimum 4 bytes."), 1);
3428 DEBUG_printf(("1ippReadIO: bad stringWithLanguage value "
3430 _cupsBufferRelease((char *)buffer
);
3431 return (IPP_STATE_ERROR
);
3434 if ((*cb
)(src
, buffer
, (size_t)n
) < n
)
3436 DEBUG_puts("1ippReadIO: Unable to read string w/language "
3438 _cupsBufferRelease((char *)buffer
);
3439 return (IPP_STATE_ERROR
);
3445 * text-with-language and name-with-language are composite
3454 n
= (bufptr
[0] << 8) | bufptr
[1];
3456 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
) || n
>= (int)sizeof(string
))
3458 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3459 _("IPP language length overflows value."), 1);
3460 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3462 _cupsBufferRelease((char *)buffer
);
3463 return (IPP_STATE_ERROR
);
3465 else if (n
>= IPP_MAX_LANGUAGE
)
3467 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3468 _("IPP language length too large."), 1);
3469 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3471 _cupsBufferRelease((char *)buffer
);
3472 return (IPP_STATE_ERROR
);
3475 memcpy(string
, bufptr
+ 2, (size_t)n
);
3478 value
->string
.language
= _cupsStrAlloc((char *)string
);
3481 n
= (bufptr
[0] << 8) | bufptr
[1];
3483 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
))
3485 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3486 _("IPP string length overflows value."), 1);
3487 DEBUG_printf(("1ippReadIO: bad string value length %d.", n
));
3488 _cupsBufferRelease((char *)buffer
);
3489 return (IPP_STATE_ERROR
);
3492 bufptr
[2 + n
] = '\0';
3493 value
->string
.text
= _cupsStrAlloc((char *)bufptr
+ 2);
3496 case IPP_TAG_BEGIN_COLLECTION
:
3498 * Oh, boy, here comes a collection value, so read it...
3501 value
->collection
= ippNew();
3505 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3506 _("IPP begCollection value not 0 bytes."), 1);
3507 DEBUG_puts("1ippReadIO: begCollection tag with value length "
3509 _cupsBufferRelease((char *)buffer
);
3510 return (IPP_STATE_ERROR
);
3513 if (ippReadIO(src
, cb
, 1, ipp
, value
->collection
) == IPP_STATE_ERROR
)
3515 DEBUG_puts("1ippReadIO: Unable to read collection value.");
3516 _cupsBufferRelease((char *)buffer
);
3517 return (IPP_STATE_ERROR
);
3521 case IPP_TAG_END_COLLECTION
:
3522 _cupsBufferRelease((char *)buffer
);
3526 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3527 _("IPP endCollection value not 0 bytes."), 1);
3528 DEBUG_puts("1ippReadIO: endCollection tag with value length "
3530 return (IPP_STATE_ERROR
);
3533 DEBUG_puts("1ippReadIO: endCollection tag...");
3534 return (ipp
->state
= IPP_STATE_DATA
);
3536 case IPP_TAG_MEMBERNAME
:
3538 * The value the name of the member in the collection, which
3539 * we need to carry over...
3544 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3545 _("IPP memberName with no attribute."), 1);
3546 DEBUG_puts("1ippReadIO: Member name without attribute.");
3547 _cupsBufferRelease((char *)buffer
);
3548 return (IPP_STATE_ERROR
);
3552 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3553 _("IPP memberName value is empty."), 1);
3554 DEBUG_puts("1ippReadIO: Empty member name value.");
3555 _cupsBufferRelease((char *)buffer
);
3556 return (IPP_STATE_ERROR
);
3558 else if ((*cb
)(src
, buffer
, (size_t)n
) < n
)
3560 DEBUG_puts("1ippReadIO: Unable to read member name value.");
3561 _cupsBufferRelease((char *)buffer
);
3562 return (IPP_STATE_ERROR
);
3566 attr
->name
= _cupsStrAlloc((char *)buffer
);
3569 * Since collection members are encoded differently than
3570 * regular attributes, make sure we don't start with an
3574 attr
->num_values
--;
3576 DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr
->name
));
3579 default : /* Other unsupported values */
3580 if (tag
== IPP_TAG_STRING
&& n
> IPP_MAX_LENGTH
)
3582 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3583 _("IPP octetString length too large."), 1);
3584 DEBUG_printf(("1ippReadIO: bad octetString value length %d.",
3586 _cupsBufferRelease((char *)buffer
);
3587 return (IPP_STATE_ERROR
);
3590 value
->unknown
.length
= n
;
3594 if ((value
->unknown
.data
= malloc((size_t)n
)) == NULL
)
3596 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
3597 DEBUG_puts("1ippReadIO: Unable to allocate value");
3598 _cupsBufferRelease((char *)buffer
);
3599 return (IPP_STATE_ERROR
);
3602 if ((*cb
)(src
, value
->unknown
.data
, (size_t)n
) < n
)
3604 DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
3605 _cupsBufferRelease((char *)buffer
);
3606 return (IPP_STATE_ERROR
);
3610 value
->unknown
.data
= NULL
;
3615 * If blocking is disabled, stop here...
3623 case IPP_STATE_DATA
:
3627 break; /* anti-compiler-warning-code */
3630 DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp
->state
));
3631 _cupsBufferRelease((char *)buffer
);
3633 return (ipp
->state
);
3638 * 'ippSetBoolean()' - Set a boolean value in an attribute.
3640 * The @code ipp@ parameter refers to an IPP message previously created using
3641 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3643 * The @code attr@ parameter may be modified as a result of setting the value.
3645 * The @code element@ parameter specifies which value to set from 0 to
3646 * @link ippGetCount(attr)@.
3648 * @since CUPS 1.6/OS X 10.8@
3651 int /* O - 1 on success, 0 on failure */
3652 ippSetBoolean(ipp_t
*ipp
, /* I - IPP message */
3653 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3654 int element
, /* I - Value number (0-based) */
3655 int boolvalue
)/* I - Boolean value */
3657 _ipp_value_t
*value
; /* Current value */
3661 * Range check input...
3664 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BOOLEAN
||
3665 element
< 0 || element
> (*attr
)->num_values
)
3669 * Set the value and return...
3672 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3673 value
->boolean
= (char)boolvalue
;
3675 return (value
!= NULL
);
3680 * 'ippSetCollection()' - Set a collection value in an attribute.
3682 * The @code ipp@ parameter refers to an IPP message previously created using
3683 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3685 * The @code attr@ parameter may be modified as a result of setting the value.
3687 * The @code element@ parameter specifies which value to set from 0 to
3688 * @link ippGetCount(attr)@.
3690 * @since CUPS 1.6/OS X 10.8@
3693 int /* O - 1 on success, 0 on failure */
3695 ipp_t
*ipp
, /* I - IPP message */
3696 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3697 int element
, /* I - Value number (0-based) */
3698 ipp_t
*colvalue
) /* I - Collection value */
3700 _ipp_value_t
*value
; /* Current value */
3704 * Range check input...
3707 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
3708 element
< 0 || element
> (*attr
)->num_values
|| !colvalue
)
3712 * Set the value and return...
3715 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3717 if (value
->collection
)
3718 ippDelete(value
->collection
);
3720 value
->collection
= colvalue
;
3724 return (value
!= NULL
);
3729 * 'ippSetDate()' - Set a date value in an attribute.
3731 * The @code ipp@ parameter refers to an IPP message previously created using
3732 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3734 * The @code attr@ parameter may be modified as a result of setting the value.
3736 * The @code element@ parameter specifies which value to set from 0 to
3737 * @link ippGetCount(attr)@.
3739 * @since CUPS 1.6/OS X 10.8@
3742 int /* O - 1 on success, 0 on failure */
3743 ippSetDate(ipp_t
*ipp
, /* I - IPP message */
3744 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3745 int element
, /* I - Value number (0-based) */
3746 const ipp_uchar_t
*datevalue
)/* I - Date value */
3748 _ipp_value_t
*value
; /* Current value */
3752 * Range check input...
3755 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_DATE
||
3756 element
< 0 || element
> (*attr
)->num_values
|| !datevalue
)
3760 * Set the value and return...
3763 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3764 memcpy(value
->date
, datevalue
, sizeof(value
->date
));
3766 return (value
!= NULL
);
3771 * 'ippSetGroupTag()' - Set the group tag of an attribute.
3773 * The @code ipp@ parameter refers to an IPP message previously created using
3774 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3776 * The @code attr@ parameter may be modified as a result of setting the value.
3778 * The @code group@ parameter specifies the IPP attribute group tag: none
3779 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
3780 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
3781 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
3782 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
3784 * @since CUPS 1.6/OS X 10.8@
3787 int /* O - 1 on success, 0 on failure */
3789 ipp_t
*ipp
, /* I - IPP message */
3790 ipp_attribute_t
**attr
, /* IO - Attribute */
3791 ipp_tag_t group_tag
) /* I - Group tag */
3794 * Range check input - group tag must be 0x01 to 0x0F, per RFC 2911...
3797 if (!ipp
|| !attr
|| !*attr
||
3798 group_tag
< IPP_TAG_ZERO
|| group_tag
== IPP_TAG_END
||
3799 group_tag
>= IPP_TAG_UNSUPPORTED_VALUE
)
3803 * Set the group tag and return...
3806 (*attr
)->group_tag
= group_tag
;
3813 * 'ippSetInteger()' - Set an integer or enum value in an attribute.
3815 * The @code ipp@ parameter refers to an IPP message previously created using
3816 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3818 * The @code attr@ parameter may be modified as a result of setting the value.
3820 * The @code element@ parameter specifies which value to set from 0 to
3821 * @link ippGetCount(attr)@.
3823 * @since CUPS 1.6/OS X 10.8@
3826 int /* O - 1 on success, 0 on failure */
3827 ippSetInteger(ipp_t
*ipp
, /* I - IPP message */
3828 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3829 int element
, /* I - Value number (0-based) */
3830 int intvalue
) /* I - Integer/enum value */
3832 _ipp_value_t
*value
; /* Current value */
3836 * Range check input...
3839 if (!ipp
|| !attr
|| !*attr
||
3840 ((*attr
)->value_tag
!= IPP_TAG_INTEGER
&& (*attr
)->value_tag
!= IPP_TAG_ENUM
) ||
3841 element
< 0 || element
> (*attr
)->num_values
)
3845 * Set the value and return...
3848 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3849 value
->integer
= intvalue
;
3851 return (value
!= NULL
);
3856 * 'ippSetName()' - Set the name of an attribute.
3858 * The @code ipp@ parameter refers to an IPP message previously created using
3859 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3861 * The @code attr@ parameter may be modified as a result of setting the value.
3863 * @since CUPS 1.6/OS X 10.8@
3866 int /* O - 1 on success, 0 on failure */
3867 ippSetName(ipp_t
*ipp
, /* I - IPP message */
3868 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3869 const char *name
) /* I - Attribute name */
3871 char *temp
; /* Temporary name value */
3875 * Range check input...
3878 if (!ipp
|| !attr
|| !*attr
)
3882 * Set the value and return...
3885 if ((temp
= _cupsStrAlloc(name
)) != NULL
)
3888 _cupsStrFree((*attr
)->name
);
3890 (*attr
)->name
= temp
;
3893 return (temp
!= NULL
);
3898 * 'ippSetOctetString()' - Set an octetString value in an IPP attribute.
3900 * The @code ipp@ parameter refers to an IPP message previously created using
3901 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3903 * The @code attr@ parameter may be modified as a result of setting the value.
3905 * The @code element@ parameter specifies which value to set from 0 to
3906 * @link ippGetCount(attr)@.
3908 * @since CUPS 1.7/OS X 10.9@
3911 int /* O - 1 on success, 0 on failure */
3913 ipp_t
*ipp
, /* I - IPP message */
3914 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3915 int element
, /* I - Value number (0-based) */
3916 const void *data
, /* I - Pointer to octetString data */
3917 int datalen
) /* I - Length of octetString data */
3919 _ipp_value_t
*value
; /* Current value */
3923 * Range check input...
3926 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_STRING
||
3927 element
< 0 || element
> (*attr
)->num_values
||
3928 datalen
< 0 || datalen
> IPP_MAX_LENGTH
)
3932 * Set the value and return...
3935 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3937 if ((int)((*attr
)->value_tag
) & IPP_TAG_CUPS_CONST
)
3940 * Just copy the pointer...
3943 value
->unknown
.data
= (void *)data
;
3944 value
->unknown
.length
= datalen
;
3952 if (value
->unknown
.data
)
3955 * Free previous data...
3958 free(value
->unknown
.data
);
3960 value
->unknown
.data
= NULL
;
3961 value
->unknown
.length
= 0;
3966 void *temp
; /* Temporary data pointer */
3968 if ((temp
= malloc((size_t)datalen
)) != NULL
)
3970 memcpy(temp
, data
, (size_t)datalen
);
3972 value
->unknown
.data
= temp
;
3973 value
->unknown
.length
= datalen
;
3981 return (value
!= NULL
);
3986 * 'ippSetOperation()' - Set the operation ID in an IPP request message.
3988 * The @code ipp@ parameter refers to an IPP message previously created using
3989 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3991 * @since CUPS 1.6/OS X 10.8@
3994 int /* O - 1 on success, 0 on failure */
3995 ippSetOperation(ipp_t
*ipp
, /* I - IPP request message */
3996 ipp_op_t op
) /* I - Operation ID */
3999 * Range check input...
4006 * Set the operation and return...
4009 ipp
->request
.op
.operation_id
= op
;
4016 * 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
4018 * The @code ipp@ parameter refers to an IPP message previously created using
4019 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4021 * The @code attr@ parameter may be modified as a result of setting the value.
4023 * The @code element@ parameter specifies which value to set from 0 to
4024 * @link ippGetCount(attr)@.
4026 * @since CUPS 1.6/OS X 10.8@
4029 int /* O - 1 on success, 0 on failure */
4030 ippSetRange(ipp_t
*ipp
, /* I - IPP message */
4031 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4032 int element
, /* I - Value number (0-based) */
4033 int lowervalue
, /* I - Lower bound for range */
4034 int uppervalue
) /* I - Upper bound for range */
4036 _ipp_value_t
*value
; /* Current value */
4040 * Range check input...
4043 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RANGE
||
4044 element
< 0 || element
> (*attr
)->num_values
|| lowervalue
> uppervalue
)
4048 * Set the value and return...
4051 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4053 value
->range
.lower
= lowervalue
;
4054 value
->range
.upper
= uppervalue
;
4057 return (value
!= NULL
);
4062 * 'ippSetRequestId()' - Set the request ID in an IPP message.
4064 * The @code ipp@ parameter refers to an IPP message previously created using
4065 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4067 * The @code request_id@ parameter must be greater than 0.
4069 * @since CUPS 1.6/OS X 10.8@
4072 int /* O - 1 on success, 0 on failure */
4073 ippSetRequestId(ipp_t
*ipp
, /* I - IPP message */
4074 int request_id
) /* I - Request ID */
4077 * Range check input; not checking request_id values since ipptool wants to send
4078 * invalid values for conformance testing and a bad request_id does not affect the
4079 * encoding of a message...
4086 * Set the request ID and return...
4089 ipp
->request
.any
.request_id
= request_id
;
4096 * 'ippSetResolution()' - Set a resolution value in an attribute.
4098 * The @code ipp@ parameter refers to an IPP message previously created using
4099 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4101 * The @code attr@ parameter may be modified as a result of setting the value.
4103 * The @code element@ parameter specifies which value to set from 0 to
4104 * @link ippGetCount(attr)@.
4106 * @since CUPS 1.6/OS X 10.8@
4109 int /* O - 1 on success, 0 on failure */
4111 ipp_t
*ipp
, /* I - IPP message */
4112 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4113 int element
, /* I - Value number (0-based) */
4114 ipp_res_t unitsvalue
, /* I - Resolution units */
4115 int xresvalue
, /* I - Horizontal/cross feed resolution */
4116 int yresvalue
) /* I - Vertical/feed resolution */
4118 _ipp_value_t
*value
; /* Current value */
4122 * Range check input...
4125 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RESOLUTION
||
4126 element
< 0 || element
> (*attr
)->num_values
|| xresvalue
<= 0 || yresvalue
<= 0 ||
4127 unitsvalue
< IPP_RES_PER_INCH
|| unitsvalue
> IPP_RES_PER_CM
)
4131 * Set the value and return...
4134 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4136 value
->resolution
.units
= unitsvalue
;
4137 value
->resolution
.xres
= xresvalue
;
4138 value
->resolution
.yres
= yresvalue
;
4141 return (value
!= NULL
);
4146 * 'ippSetState()' - Set the current state of the IPP message.
4148 * @since CUPS 1.6/OS X 10.8@
4151 int /* O - 1 on success, 0 on failure */
4152 ippSetState(ipp_t
*ipp
, /* I - IPP message */
4153 ipp_state_t state
) /* I - IPP state value */
4156 * Range check input...
4163 * Set the state and return...
4167 ipp
->current
= NULL
;
4174 * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
4176 * The @code ipp@ parameter refers to an IPP message previously created using
4177 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4179 * @since CUPS 1.6/OS X 10.8@
4182 int /* O - 1 on success, 0 on failure */
4183 ippSetStatusCode(ipp_t
*ipp
, /* I - IPP response or event message */
4184 ipp_status_t status
) /* I - Status code */
4187 * Range check input...
4194 * Set the status code and return...
4197 ipp
->request
.status
.status_code
= status
;
4204 * 'ippSetString()' - Set a string value in an attribute.
4206 * The @code ipp@ parameter refers to an IPP message previously created using
4207 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4209 * The @code attr@ parameter may be modified as a result of setting the value.
4211 * The @code element@ parameter specifies which value to set from 0 to
4212 * @link ippGetCount(attr)@.
4214 * @since CUPS 1.6/OS X 10.8@
4217 int /* O - 1 on success, 0 on failure */
4218 ippSetString(ipp_t
*ipp
, /* I - IPP message */
4219 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4220 int element
, /* I - Value number (0-based) */
4221 const char *strvalue
) /* I - String value */
4223 char *temp
; /* Temporary string */
4224 _ipp_value_t
*value
; /* Current value */
4228 * Range check input...
4231 if (!ipp
|| !attr
|| !*attr
||
4232 ((*attr
)->value_tag
!= IPP_TAG_TEXTLANG
&&
4233 (*attr
)->value_tag
!= IPP_TAG_NAMELANG
&&
4234 ((*attr
)->value_tag
< IPP_TAG_TEXT
||
4235 (*attr
)->value_tag
> IPP_TAG_MIMETYPE
)) ||
4236 element
< 0 || element
> (*attr
)->num_values
|| !strvalue
)
4240 * Set the value and return...
4243 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4246 value
->string
.language
= (*attr
)->values
[0].string
.language
;
4248 if ((int)((*attr
)->value_tag
) & IPP_TAG_CUPS_CONST
)
4249 value
->string
.text
= (char *)strvalue
;
4250 else if ((temp
= _cupsStrAlloc(strvalue
)) != NULL
)
4252 if (value
->string
.text
)
4253 _cupsStrFree(value
->string
.text
);
4255 value
->string
.text
= temp
;
4261 return (value
!= NULL
);
4266 * 'ippSetStringf()' - Set a formatted string value of an attribute.
4268 * The @code ipp@ parameter refers to an IPP message previously created using
4269 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4271 * The @code attr@ parameter may be modified as a result of setting the value.
4273 * The @code element@ parameter specifies which value to set from 0 to
4274 * @link ippGetCount(attr)@.
4276 * The @code format@ parameter uses formatting characters compatible with the
4277 * printf family of standard functions. Additional arguments follow it as
4278 * needed. The formatted string is truncated as needed to the maximum length of
4279 * the corresponding value type.
4281 * @since CUPS 1.7/OS X 10.9@
4284 int /* O - 1 on success, 0 on failure */
4285 ippSetStringf(ipp_t
*ipp
, /* I - IPP message */
4286 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4287 int element
, /* I - Value number (0-based) */
4288 const char *format
, /* I - Printf-style format string */
4289 ...) /* I - Additional arguments as needed */
4291 int ret
; /* Return value */
4292 va_list ap
; /* Pointer to additional arguments */
4295 va_start(ap
, format
);
4296 ret
= ippSetStringfv(ipp
, attr
, element
, format
, ap
);
4304 * 'ippSetStringf()' - Set a formatted string value of an attribute.
4306 * The @code ipp@ parameter refers to an IPP message previously created using
4307 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4309 * The @code attr@ parameter may be modified as a result of setting the value.
4311 * The @code element@ parameter specifies which value to set from 0 to
4312 * @link ippGetCount(attr)@.
4314 * The @code format@ parameter uses formatting characters compatible with the
4315 * printf family of standard functions. Additional arguments follow it as
4316 * needed. The formatted string is truncated as needed to the maximum length of
4317 * the corresponding value type.
4319 * @since CUPS 1.7/OS X 10.9@
4322 int /* O - 1 on success, 0 on failure */
4323 ippSetStringfv(ipp_t
*ipp
, /* I - IPP message */
4324 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4325 int element
, /* I - Value number (0-based) */
4326 const char *format
, /* I - Printf-style format string */
4327 va_list ap
) /* I - Pointer to additional arguments */
4329 ipp_tag_t value_tag
; /* Value tag */
4330 char buffer
[IPP_MAX_TEXT
+ 4];
4331 /* Formatted text string */
4332 ssize_t bytes
, /* Length of formatted value */
4333 max_bytes
; /* Maximum number of bytes for value */
4337 * Range check input...
4341 value_tag
= (*attr
)->value_tag
& IPP_TAG_CUPS_MASK
;
4343 value_tag
= IPP_TAG_ZERO
;
4345 if (!ipp
|| !attr
|| !*attr
||
4346 (value_tag
< IPP_TAG_TEXT
&& value_tag
!= IPP_TAG_TEXTLANG
&&
4347 value_tag
!= IPP_TAG_NAMELANG
) || value_tag
> IPP_TAG_MIMETYPE
||
4352 * Format the string...
4355 if (!strcmp(format
, "%s"))
4358 * Optimize the simple case...
4361 const char *s
= va_arg(ap
, char *);
4366 bytes
= (ssize_t
)strlen(s
);
4367 strlcpy(buffer
, s
, sizeof(buffer
));
4372 * Do a full formatting of the message...
4375 if ((bytes
= vsnprintf(buffer
, sizeof(buffer
), format
, ap
)) < 0)
4380 * Limit the length of the string...
4387 case IPP_TAG_TEXTLANG
:
4388 max_bytes
= IPP_MAX_TEXT
;
4392 case IPP_TAG_NAMELANG
:
4393 max_bytes
= IPP_MAX_NAME
;
4396 case IPP_TAG_CHARSET
:
4397 max_bytes
= IPP_MAX_CHARSET
;
4400 case IPP_TAG_KEYWORD
:
4401 max_bytes
= IPP_MAX_KEYWORD
;
4404 case IPP_TAG_LANGUAGE
:
4405 max_bytes
= IPP_MAX_LANGUAGE
;
4408 case IPP_TAG_MIMETYPE
:
4409 max_bytes
= IPP_MAX_MIMETYPE
;
4413 max_bytes
= IPP_MAX_URI
;
4416 case IPP_TAG_URISCHEME
:
4417 max_bytes
= IPP_MAX_URISCHEME
;
4421 if (bytes
>= max_bytes
)
4423 char *bufmax
, /* Buffer at max_bytes */
4424 *bufptr
; /* Pointer into buffer */
4426 bufptr
= buffer
+ strlen(buffer
) - 1;
4427 bufmax
= buffer
+ max_bytes
- 1;
4429 while (bufptr
> bufmax
)
4433 while ((*bufptr
& 0xc0) == 0x80 && bufptr
> buffer
)
4444 * Set the formatted string and return...
4447 return (ippSetString(ipp
, attr
, element
, buffer
));
4452 * 'ippSetValueTag()' - Set the value tag of an attribute.
4454 * The @code ipp@ parameter refers to an IPP message previously created using
4455 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4457 * The @code attr@ parameter may be modified as a result of setting the value.
4459 * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger
4460 * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name
4461 * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text
4462 * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage
4463 * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various
4464 * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes
4467 * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language
4468 * code in the "attributes-natural-language" attribute or, if not present, the language
4469 * code for the current locale.
4471 * @since CUPS 1.6/OS X 10.8@
4474 int /* O - 1 on success, 0 on failure */
4476 ipp_t
*ipp
, /* I - IPP message */
4477 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4478 ipp_tag_t value_tag
) /* I - Value tag */
4480 int i
; /* Looping var */
4481 _ipp_value_t
*value
; /* Current value */
4482 int integer
; /* Current integer value */
4483 cups_lang_t
*language
; /* Current language */
4484 char code
[32]; /* Language code */
4485 ipp_tag_t temp_tag
; /* Temporary value tag */
4489 * Range check input...
4492 if (!ipp
|| !attr
|| !*attr
)
4496 * If there is no change, return immediately...
4499 if (value_tag
== (*attr
)->value_tag
)
4503 * Otherwise implement changes as needed...
4506 temp_tag
= (ipp_tag_t
)((int)((*attr
)->value_tag
) & IPP_TAG_CUPS_MASK
);
4510 case IPP_TAG_UNSUPPORTED_VALUE
:
4511 case IPP_TAG_DEFAULT
:
4512 case IPP_TAG_UNKNOWN
:
4513 case IPP_TAG_NOVALUE
:
4514 case IPP_TAG_NOTSETTABLE
:
4515 case IPP_TAG_DELETEATTR
:
4516 case IPP_TAG_ADMINDEFINE
:
4518 * Free any existing values...
4521 if ((*attr
)->num_values
> 0)
4522 ipp_free_values(*attr
, 0, (*attr
)->num_values
);
4525 * Set out-of-band value...
4528 (*attr
)->value_tag
= value_tag
;
4531 case IPP_TAG_RANGE
:
4532 if (temp_tag
!= IPP_TAG_INTEGER
)
4535 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
4539 integer
= value
->integer
;
4540 value
->range
.lower
= value
->range
.upper
= integer
;
4543 (*attr
)->value_tag
= IPP_TAG_RANGE
;
4547 if (temp_tag
!= IPP_TAG_KEYWORD
&& temp_tag
!= IPP_TAG_URI
&&
4548 temp_tag
!= IPP_TAG_URISCHEME
&& temp_tag
!= IPP_TAG_LANGUAGE
&&
4549 temp_tag
!= IPP_TAG_MIMETYPE
)
4552 (*attr
)->value_tag
= (ipp_tag_t
)(IPP_TAG_NAME
| ((*attr
)->value_tag
& IPP_TAG_CUPS_CONST
));
4555 case IPP_TAG_NAMELANG
:
4556 case IPP_TAG_TEXTLANG
:
4557 if (value_tag
== IPP_TAG_NAMELANG
&&
4558 (temp_tag
!= IPP_TAG_NAME
&& temp_tag
!= IPP_TAG_KEYWORD
&&
4559 temp_tag
!= IPP_TAG_URI
&& temp_tag
!= IPP_TAG_URISCHEME
&&
4560 temp_tag
!= IPP_TAG_LANGUAGE
&& temp_tag
!= IPP_TAG_MIMETYPE
))
4563 if (value_tag
== IPP_TAG_TEXTLANG
&& temp_tag
!= IPP_TAG_TEXT
)
4566 if (ipp
->attrs
&& ipp
->attrs
->next
&& ipp
->attrs
->next
->name
&&
4567 !strcmp(ipp
->attrs
->next
->name
, "attributes-natural-language"))
4570 * Use the language code from the IPP message...
4573 (*attr
)->values
[0].string
.language
=
4574 _cupsStrAlloc(ipp
->attrs
->next
->values
[0].string
.text
);
4579 * Otherwise, use the language code corresponding to the locale...
4582 language
= cupsLangDefault();
4583 (*attr
)->values
[0].string
.language
= _cupsStrAlloc(ipp_lang_code(language
->language
,
4588 for (i
= (*attr
)->num_values
- 1, value
= (*attr
)->values
+ 1;
4591 value
->string
.language
= (*attr
)->values
[0].string
.language
;
4593 if ((int)(*attr
)->value_tag
& IPP_TAG_CUPS_CONST
)
4596 * Make copies of all values...
4599 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
4602 value
->string
.text
= _cupsStrAlloc(value
->string
.text
);
4605 (*attr
)->value_tag
= IPP_TAG_NAMELANG
;
4608 case IPP_TAG_KEYWORD
:
4609 if (temp_tag
== IPP_TAG_NAME
|| temp_tag
== IPP_TAG_NAMELANG
)
4610 break; /* Silently "allow" name -> keyword */
4621 * 'ippSetVersion()' - Set the version number in an IPP message.
4623 * The @code ipp@ parameter refers to an IPP message previously created using
4624 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4626 * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
4628 * @since CUPS 1.6/OS X 10.8@
4631 int /* O - 1 on success, 0 on failure */
4632 ippSetVersion(ipp_t
*ipp
, /* I - IPP message */
4633 int major
, /* I - Major version number (major.minor) */
4634 int minor
) /* I - Minor version number (major.minor) */
4637 * Range check input...
4640 if (!ipp
|| major
< 0 || minor
< 0)
4644 * Set the version number...
4647 ipp
->request
.any
.version
[0] = (ipp_uchar_t
)major
;
4648 ipp
->request
.any
.version
[1] = (ipp_uchar_t
)minor
;
4655 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
4658 const ipp_uchar_t
* /* O - RFC-1903 date/time data */
4659 ippTimeToDate(time_t t
) /* I - UNIX time value */
4661 struct tm
*unixdate
; /* UNIX unixdate/time info */
4662 ipp_uchar_t
*date
= _cupsGlobals()->ipp_date
;
4663 /* RFC-1903 date/time data */
4667 * RFC-1903 date/time format is:
4669 * Byte(s) Description
4670 * ------- -----------
4671 * 0-1 Year (0 to 65535)
4675 * 5 Minutes (0 to 59)
4676 * 6 Seconds (0 to 60, 60 = "leap second")
4677 * 7 Deciseconds (0 to 9)
4679 * 9 UTC hours (0 to 11)
4680 * 10 UTC minutes (0 to 59)
4683 unixdate
= gmtime(&t
);
4684 unixdate
->tm_year
+= 1900;
4686 date
[0] = (ipp_uchar_t
)(unixdate
->tm_year
>> 8);
4687 date
[1] = (ipp_uchar_t
)(unixdate
->tm_year
);
4688 date
[2] = (ipp_uchar_t
)(unixdate
->tm_mon
+ 1);
4689 date
[3] = (ipp_uchar_t
)unixdate
->tm_mday
;
4690 date
[4] = (ipp_uchar_t
)unixdate
->tm_hour
;
4691 date
[5] = (ipp_uchar_t
)unixdate
->tm_min
;
4692 date
[6] = (ipp_uchar_t
)unixdate
->tm_sec
;
4703 * 'ippValidateAttribute()' - Validate the contents of an attribute.
4705 * This function validates the contents of an attribute based on the name and
4706 * value tag. 1 is returned if the attribute is valid, 0 otherwise. On
4707 * failure, cupsLastErrorString() is set to a human-readable message.
4709 * @since CUPS 1.7/OS X 10.9@
4712 int /* O - 1 if valid, 0 otherwise */
4713 ippValidateAttribute(
4714 ipp_attribute_t
*attr
) /* I - Attribute */
4716 int i
; /* Looping var */
4717 char scheme
[64], /* Scheme from URI */
4718 userpass
[256], /* Username/password from URI */
4719 hostname
[256], /* Hostname from URI */
4720 resource
[1024]; /* Resource from URI */
4721 int port
, /* Port number from URI */
4722 uri_status
; /* URI separation status */
4723 const char *ptr
; /* Pointer into string */
4724 ipp_attribute_t
*colattr
; /* Collection attribute */
4725 regex_t re
; /* Regular expression */
4726 ipp_uchar_t
*date
; /* Current date value */
4727 static const char * const uri_status_strings
[] =
4728 { /* URI status strings */
4730 "Bad arguments to function",
4731 "Bad resource in URI",
4732 "Bad port number in URI",
4733 "Bad hostname/address in URI",
4734 "Bad username in URI",
4735 "Bad scheme in URI",
4738 "Missing scheme in URI",
4739 "Unknown scheme in URI",
4740 "Missing resource in URI"
4752 * Validate the attribute name.
4755 for (ptr
= attr
->name
; *ptr
; ptr
++)
4756 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' && *ptr
!= '_')
4759 if (*ptr
|| ptr
== attr
->name
)
4761 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4762 _("\"%s\": Bad attribute name - invalid character "
4763 "(RFC 2911 section 4.1.3)."), attr
->name
);
4767 if ((ptr
- attr
->name
) > 255)
4769 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4770 _("\"%s\": Bad attribute name - bad length %d "
4771 "(RFC 2911 section 4.1.3)."), attr
->name
,
4772 (int)(ptr
- attr
->name
));
4776 switch (attr
->value_tag
)
4778 case IPP_TAG_INTEGER
:
4781 case IPP_TAG_BOOLEAN
:
4782 for (i
= 0; i
< attr
->num_values
; i
++)
4784 if (attr
->values
[i
].boolean
!= 0 &&
4785 attr
->values
[i
].boolean
!= 1)
4787 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4788 _("\"%s\": Bad boolen value %d "
4789 "(RFC 2911 section 4.1.11)."), attr
->name
,
4790 attr
->values
[i
].boolean
);
4797 for (i
= 0; i
< attr
->num_values
; i
++)
4799 if (attr
->values
[i
].integer
< 1)
4801 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4802 _("\"%s\": Bad enum value %d - out of range "
4803 "(RFC 2911 section 4.1.4)."), attr
->name
,
4804 attr
->values
[i
].integer
);
4810 case IPP_TAG_STRING
:
4811 for (i
= 0; i
< attr
->num_values
; i
++)
4813 if (attr
->values
[i
].unknown
.length
> IPP_MAX_OCTETSTRING
)
4815 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4816 _("\"%s\": Bad octetString value - bad length %d "
4817 "(RFC 2911 section 4.1.10)."), attr
->name
,
4818 attr
->values
[i
].unknown
.length
);
4825 for (i
= 0; i
< attr
->num_values
; i
++)
4827 date
= attr
->values
[i
].date
;
4829 if (date
[2] < 1 || date
[2] > 12)
4831 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4832 _("\"%s\": Bad dateTime month %u "
4833 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[2]);
4837 if (date
[3] < 1 || date
[3] > 31)
4839 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4840 _("\"%s\": Bad dateTime day %u "
4841 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[3]);
4847 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4848 _("\"%s\": Bad dateTime hours %u "
4849 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[4]);
4855 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4856 _("\"%s\": Bad dateTime minutes %u "
4857 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[5]);
4863 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4864 _("\"%s\": Bad dateTime seconds %u "
4865 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[6]);
4871 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4872 _("\"%s\": Bad dateTime deciseconds %u "
4873 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[7]);
4877 if (date
[8] != '-' && date
[8] != '+')
4879 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4880 _("\"%s\": Bad dateTime UTC sign '%c' "
4881 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[8]);
4887 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4888 _("\"%s\": Bad dateTime UTC hours %u "
4889 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[9]);
4895 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4896 _("\"%s\": Bad dateTime UTC minutes %u "
4897 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[10]);
4903 case IPP_TAG_RESOLUTION
:
4904 for (i
= 0; i
< attr
->num_values
; i
++)
4906 if (attr
->values
[i
].resolution
.xres
<= 0)
4908 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4909 _("\"%s\": Bad resolution value %dx%d%s - cross "
4910 "feed resolution must be positive "
4911 "(RFC 2911 section 4.1.15)."), attr
->name
,
4912 attr
->values
[i
].resolution
.xres
,
4913 attr
->values
[i
].resolution
.yres
,
4914 attr
->values
[i
].resolution
.units
==
4915 IPP_RES_PER_INCH
? "dpi" :
4916 attr
->values
[i
].resolution
.units
==
4917 IPP_RES_PER_CM
? "dpcm" : "unknown");
4921 if (attr
->values
[i
].resolution
.yres
<= 0)
4923 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4924 _("\"%s\": Bad resolution value %dx%d%s - feed "
4925 "resolution must be positive "
4926 "(RFC 2911 section 4.1.15)."), attr
->name
,
4927 attr
->values
[i
].resolution
.xres
,
4928 attr
->values
[i
].resolution
.yres
,
4929 attr
->values
[i
].resolution
.units
==
4930 IPP_RES_PER_INCH
? "dpi" :
4931 attr
->values
[i
].resolution
.units
==
4932 IPP_RES_PER_CM
? "dpcm" : "unknown");
4936 if (attr
->values
[i
].resolution
.units
!= IPP_RES_PER_INCH
&&
4937 attr
->values
[i
].resolution
.units
!= IPP_RES_PER_CM
)
4939 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4940 _("\"%s\": Bad resolution value %dx%d%s - bad "
4941 "units value (RFC 2911 section 4.1.15)."),
4942 attr
->name
, attr
->values
[i
].resolution
.xres
,
4943 attr
->values
[i
].resolution
.yres
,
4944 attr
->values
[i
].resolution
.units
==
4945 IPP_RES_PER_INCH
? "dpi" :
4946 attr
->values
[i
].resolution
.units
==
4947 IPP_RES_PER_CM
? "dpcm" : "unknown");
4953 case IPP_TAG_RANGE
:
4954 for (i
= 0; i
< attr
->num_values
; i
++)
4956 if (attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
4958 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4959 _("\"%s\": Bad rangeOfInteger value %d-%d - lower "
4960 "greater than upper (RFC 2911 section 4.1.13)."),
4961 attr
->name
, attr
->values
[i
].range
.lower
,
4962 attr
->values
[i
].range
.upper
);
4968 case IPP_TAG_BEGIN_COLLECTION
:
4969 for (i
= 0; i
< attr
->num_values
; i
++)
4971 for (colattr
= attr
->values
[i
].collection
->attrs
;
4973 colattr
= colattr
->next
)
4975 if (!ippValidateAttribute(colattr
))
4982 case IPP_TAG_TEXTLANG
:
4983 for (i
= 0; i
< attr
->num_values
; i
++)
4985 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4987 if ((*ptr
& 0xe0) == 0xc0)
4990 if ((*ptr
& 0xc0) != 0x80)
4993 else if ((*ptr
& 0xf0) == 0xe0)
4996 if ((*ptr
& 0xc0) != 0x80)
4999 if ((*ptr
& 0xc0) != 0x80)
5002 else if ((*ptr
& 0xf8) == 0xf0)
5005 if ((*ptr
& 0xc0) != 0x80)
5008 if ((*ptr
& 0xc0) != 0x80)
5011 if ((*ptr
& 0xc0) != 0x80)
5014 else if (*ptr
& 0x80)
5020 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5021 _("\"%s\": Bad text value \"%s\" - bad UTF-8 "
5022 "sequence (RFC 2911 section 4.1.1)."), attr
->name
,
5023 attr
->values
[i
].string
.text
);
5027 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_TEXT
- 1))
5029 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5030 _("\"%s\": Bad text value \"%s\" - bad length %d "
5031 "(RFC 2911 section 4.1.1)."), attr
->name
,
5032 attr
->values
[i
].string
.text
,
5033 (int)(ptr
- attr
->values
[i
].string
.text
));
5040 case IPP_TAG_NAMELANG
:
5041 for (i
= 0; i
< attr
->num_values
; i
++)
5043 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5045 if ((*ptr
& 0xe0) == 0xc0)
5048 if ((*ptr
& 0xc0) != 0x80)
5051 else if ((*ptr
& 0xf0) == 0xe0)
5054 if ((*ptr
& 0xc0) != 0x80)
5057 if ((*ptr
& 0xc0) != 0x80)
5060 else if ((*ptr
& 0xf8) == 0xf0)
5063 if ((*ptr
& 0xc0) != 0x80)
5066 if ((*ptr
& 0xc0) != 0x80)
5069 if ((*ptr
& 0xc0) != 0x80)
5072 else if (*ptr
& 0x80)
5078 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5079 _("\"%s\": Bad name value \"%s\" - bad UTF-8 "
5080 "sequence (RFC 2911 section 4.1.2)."), attr
->name
,
5081 attr
->values
[i
].string
.text
);
5085 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_NAME
- 1))
5087 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5088 _("\"%s\": Bad name value \"%s\" - bad length %d "
5089 "(RFC 2911 section 4.1.2)."), attr
->name
,
5090 attr
->values
[i
].string
.text
,
5091 (int)(ptr
- attr
->values
[i
].string
.text
));
5097 case IPP_TAG_KEYWORD
:
5098 for (i
= 0; i
< attr
->num_values
; i
++)
5100 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5101 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' &&
5105 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
5107 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5108 _("\"%s\": Bad keyword value \"%s\" - invalid "
5109 "character (RFC 2911 section 4.1.3)."),
5110 attr
->name
, attr
->values
[i
].string
.text
);
5114 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_KEYWORD
- 1))
5116 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5117 _("\"%s\": Bad keyword value \"%s\" - bad "
5118 "length %d (RFC 2911 section 4.1.3)."),
5119 attr
->name
, attr
->values
[i
].string
.text
,
5120 (int)(ptr
- attr
->values
[i
].string
.text
));
5127 for (i
= 0; i
< attr
->num_values
; i
++)
5129 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
,
5130 attr
->values
[i
].string
.text
,
5131 scheme
, sizeof(scheme
),
5132 userpass
, sizeof(userpass
),
5133 hostname
, sizeof(hostname
),
5134 &port
, resource
, sizeof(resource
));
5136 if (uri_status
< HTTP_URI_STATUS_OK
)
5138 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5139 _("\"%s\": Bad URI value \"%s\" - %s "
5140 "(RFC 2911 section 4.1.5)."), attr
->name
,
5141 attr
->values
[i
].string
.text
,
5142 uri_status_strings
[uri_status
-
5143 HTTP_URI_STATUS_OVERFLOW
]);
5147 if (strlen(attr
->values
[i
].string
.text
) > (IPP_MAX_URI
- 1))
5149 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5150 _("\"%s\": Bad URI value \"%s\" - bad length %d "
5151 "(RFC 2911 section 4.1.5)."), attr
->name
,
5152 attr
->values
[i
].string
.text
,
5153 (int)strlen(attr
->values
[i
].string
.text
));
5158 case IPP_TAG_URISCHEME
:
5159 for (i
= 0; i
< attr
->num_values
; i
++)
5161 ptr
= attr
->values
[i
].string
.text
;
5162 if (islower(*ptr
& 255))
5164 for (ptr
++; *ptr
; ptr
++)
5165 if (!islower(*ptr
& 255) && !isdigit(*ptr
& 255) &&
5166 *ptr
!= '+' && *ptr
!= '-' && *ptr
!= '.')
5170 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
5172 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5173 _("\"%s\": Bad uriScheme value \"%s\" - bad "
5174 "characters (RFC 2911 section 4.1.6)."),
5175 attr
->name
, attr
->values
[i
].string
.text
);
5179 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_URISCHEME
- 1))
5181 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5182 _("\"%s\": Bad uriScheme value \"%s\" - bad "
5183 "length %d (RFC 2911 section 4.1.6)."),
5184 attr
->name
, attr
->values
[i
].string
.text
,
5185 (int)(ptr
- attr
->values
[i
].string
.text
));
5191 case IPP_TAG_CHARSET
:
5192 for (i
= 0; i
< attr
->num_values
; i
++)
5194 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5195 if (!isprint(*ptr
& 255) || isupper(*ptr
& 255) ||
5196 isspace(*ptr
& 255))
5199 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
5201 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5202 _("\"%s\": Bad charset value \"%s\" - bad "
5203 "characters (RFC 2911 section 4.1.7)."),
5204 attr
->name
, attr
->values
[i
].string
.text
);
5208 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_CHARSET
- 1))
5210 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5211 _("\"%s\": Bad charset value \"%s\" - bad "
5212 "length %d (RFC 2911 section 4.1.7)."),
5213 attr
->name
, attr
->values
[i
].string
.text
,
5214 (int)(ptr
- attr
->values
[i
].string
.text
));
5220 case IPP_TAG_LANGUAGE
:
5222 * The following regular expression is derived from the ABNF for
5223 * language tags in RFC 4646. All I can say is that this is the
5224 * easiest way to check the values...
5227 if ((i
= regcomp(&re
,
5229 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
5231 "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */
5232 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */
5233 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */
5234 "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */
5235 "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */
5237 "x(-[a-z0-9]{1,8})+" /* privateuse */
5239 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
5241 REG_NOSUB
| REG_EXTENDED
)) != 0)
5243 char temp
[256]; /* Temporary error string */
5245 regerror(i
, &re
, temp
, sizeof(temp
));
5246 ipp_set_error(IPP_STATUS_ERROR_INTERNAL
,
5247 _("Unable to compile naturalLanguage regular "
5248 "expression: %s."), temp
);
5252 for (i
= 0; i
< attr
->num_values
; i
++)
5254 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
5256 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5257 _("\"%s\": Bad naturalLanguage value \"%s\" - bad "
5258 "characters (RFC 2911 section 4.1.8)."),
5259 attr
->name
, attr
->values
[i
].string
.text
);
5264 if (strlen(attr
->values
[i
].string
.text
) > (IPP_MAX_LANGUAGE
- 1))
5266 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5267 _("\"%s\": Bad naturalLanguage value \"%s\" - bad "
5268 "length %d (RFC 2911 section 4.1.8)."),
5269 attr
->name
, attr
->values
[i
].string
.text
,
5270 (int)strlen(attr
->values
[i
].string
.text
));
5279 case IPP_TAG_MIMETYPE
:
5281 * The following regular expression is derived from the ABNF for
5282 * MIME media types in RFC 2045 and 4288. All I can say is that this is
5283 * the easiest way to check the values...
5286 if ((i
= regcomp(&re
,
5288 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
5290 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
5291 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
5292 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
5295 REG_NOSUB
| REG_EXTENDED
)) != 0)
5297 char temp
[256]; /* Temporary error string */
5299 regerror(i
, &re
, temp
, sizeof(temp
));
5300 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5301 _("Unable to compile mimeMediaType regular "
5302 "expression: %s."), temp
);
5306 for (i
= 0; i
< attr
->num_values
; i
++)
5308 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
5310 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5311 _("\"%s\": Bad mimeMediaType value \"%s\" - bad "
5312 "characters (RFC 2911 section 4.1.9)."),
5313 attr
->name
, attr
->values
[i
].string
.text
);
5318 if (strlen(attr
->values
[i
].string
.text
) > (IPP_MAX_MIMETYPE
- 1))
5320 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5321 _("\"%s\": Bad mimeMediaType value \"%s\" - bad "
5322 "length %d (RFC 2911 section 4.1.9)."),
5323 attr
->name
, attr
->values
[i
].string
.text
,
5324 (int)strlen(attr
->values
[i
].string
.text
));
5342 * 'ippValidateAttributes()' - Validate all attributes in an IPP message.
5344 * This function validates the contents of the IPP message, including each
5345 * attribute. Like @link ippValidateAttribute@, cupsLastErrorString() is set
5346 * to a human-readable message on failure.
5348 * @since CUPS 1.7/OS X 10.9@
5351 int /* O - 1 if valid, 0 otherwise */
5352 ippValidateAttributes(ipp_t
*ipp
) /* I - IPP message */
5354 ipp_attribute_t
*attr
; /* Current attribute */
5360 for (attr
= ipp
->attrs
; attr
; attr
= attr
->next
)
5361 if (!ippValidateAttribute(attr
))
5369 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
5372 ipp_state_t
/* O - Current state */
5373 ippWrite(http_t
*http
, /* I - HTTP connection */
5374 ipp_t
*ipp
) /* I - IPP data */
5376 DEBUG_printf(("ippWrite(http=%p, ipp=%p)", http
, ipp
));
5379 return (IPP_STATE_ERROR
);
5381 return (ippWriteIO(http
, (ipp_iocb_t
)httpWrite2
, http
->blocking
, NULL
, ipp
));
5386 * 'ippWriteFile()' - Write data for an IPP message to a file.
5388 * @since CUPS 1.1.19/OS X 10.3@
5391 ipp_state_t
/* O - Current state */
5392 ippWriteFile(int fd
, /* I - HTTP data */
5393 ipp_t
*ipp
) /* I - IPP data */
5395 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd
, ipp
));
5397 ipp
->state
= IPP_STATE_IDLE
;
5399 return (ippWriteIO(&fd
, (ipp_iocb_t
)ipp_write_file
, 1, NULL
, ipp
));
5404 * 'ippWriteIO()' - Write data for an IPP message.
5406 * @since CUPS 1.2/OS X 10.5@
5409 ipp_state_t
/* O - Current state */
5410 ippWriteIO(void *dst
, /* I - Destination */
5411 ipp_iocb_t cb
, /* I - Write callback function */
5412 int blocking
, /* I - Use blocking IO? */
5413 ipp_t
*parent
, /* I - Parent IPP message */
5414 ipp_t
*ipp
) /* I - IPP data */
5416 int i
; /* Looping var */
5417 int n
; /* Length of data */
5418 unsigned char *buffer
, /* Data buffer */
5419 *bufptr
; /* Pointer into buffer */
5420 ipp_attribute_t
*attr
; /* Current attribute */
5421 _ipp_value_t
*value
; /* Current value */
5424 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
5425 dst
, cb
, blocking
, parent
, ipp
));
5428 return (IPP_STATE_ERROR
);
5430 if ((buffer
= (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE
)) == NULL
)
5432 DEBUG_puts("1ippWriteIO: Unable to get write buffer");
5433 return (IPP_STATE_ERROR
);
5438 case IPP_STATE_IDLE
:
5439 ipp
->state
++; /* Avoid common problem... */
5441 case IPP_STATE_HEADER
:
5445 * Send the request header:
5448 * Operation/Status Code = 2 bytes
5449 * Request ID = 4 bytes
5455 *bufptr
++ = ipp
->request
.any
.version
[0];
5456 *bufptr
++ = ipp
->request
.any
.version
[1];
5457 *bufptr
++ = (ipp_uchar_t
)(ipp
->request
.any
.op_status
>> 8);
5458 *bufptr
++ = (ipp_uchar_t
)ipp
->request
.any
.op_status
;
5459 *bufptr
++ = (ipp_uchar_t
)(ipp
->request
.any
.request_id
>> 24);
5460 *bufptr
++ = (ipp_uchar_t
)(ipp
->request
.any
.request_id
>> 16);
5461 *bufptr
++ = (ipp_uchar_t
)(ipp
->request
.any
.request_id
>> 8);
5462 *bufptr
++ = (ipp_uchar_t
)ipp
->request
.any
.request_id
;
5464 DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer
[0], buffer
[1]));
5465 DEBUG_printf(("2ippWriteIO: op_status=%04x",
5466 ipp
->request
.any
.op_status
));
5467 DEBUG_printf(("2ippWriteIO: request_id=%d",
5468 ipp
->request
.any
.request_id
));
5470 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5472 DEBUG_puts("1ippWriteIO: Could not write IPP header...");
5473 _cupsBufferRelease((char *)buffer
);
5474 return (IPP_STATE_ERROR
);
5479 * Reset the state engine to point to the first attribute
5480 * in the request/response, with no current group.
5483 ipp
->state
= IPP_STATE_ATTRIBUTE
;
5484 ipp
->current
= ipp
->attrs
;
5485 ipp
->curtag
= IPP_TAG_ZERO
;
5487 DEBUG_printf(("1ippWriteIO: ipp->current=%p", ipp
->current
));
5490 * If blocking is disabled, stop here...
5496 case IPP_STATE_ATTRIBUTE
:
5497 while (ipp
->current
!= NULL
)
5500 * Write this attribute...
5504 attr
= ipp
->current
;
5506 ipp
->current
= ipp
->current
->next
;
5510 if (ipp
->curtag
!= attr
->group_tag
)
5513 * Send a group tag byte...
5516 ipp
->curtag
= attr
->group_tag
;
5518 if (attr
->group_tag
== IPP_TAG_ZERO
)
5521 DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
5522 attr
->group_tag
, ippTagString(attr
->group_tag
)));
5523 *bufptr
++ = (ipp_uchar_t
)attr
->group_tag
;
5525 else if (attr
->group_tag
== IPP_TAG_ZERO
)
5529 DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr
->name
,
5530 attr
->num_values
> 1 ? "1setOf " : "",
5531 ippTagString(attr
->value_tag
)));
5534 * Write the attribute tag and name.
5536 * The attribute name length does not include the trailing nul
5537 * character in the source string.
5539 * Collection values (parent != NULL) are written differently...
5545 * Get the length of the attribute name, and make sure it won't
5546 * overflow the buffer...
5549 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 8))
5551 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
5552 _cupsBufferRelease((char *)buffer
);
5553 return (IPP_STATE_ERROR
);
5557 * Write the value tag, name length, and name string...
5560 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5561 attr
->value_tag
, ippTagString(attr
->value_tag
)));
5562 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
5565 if (attr
->value_tag
> 0xff)
5567 *bufptr
++ = IPP_TAG_EXTENSION
;
5568 *bufptr
++ = (ipp_uchar_t
)(attr
->value_tag
>> 24);
5569 *bufptr
++ = (ipp_uchar_t
)(attr
->value_tag
>> 16);
5570 *bufptr
++ = (ipp_uchar_t
)(attr
->value_tag
>> 8);
5571 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5574 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5576 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
5577 *bufptr
++ = (ipp_uchar_t
)n
;
5578 memcpy(bufptr
, attr
->name
, (size_t)n
);
5584 * Get the length of the attribute name, and make sure it won't
5585 * overflow the buffer...
5588 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 12))
5590 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
5591 _cupsBufferRelease((char *)buffer
);
5592 return (IPP_STATE_ERROR
);
5596 * Write the member name tag, name length, name string, value tag,
5597 * and empty name for the collection member attribute...
5600 DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
5601 IPP_TAG_MEMBERNAME
));
5602 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
5604 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5605 attr
->value_tag
, ippTagString(attr
->value_tag
)));
5606 DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
5608 *bufptr
++ = IPP_TAG_MEMBERNAME
;
5611 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
5612 *bufptr
++ = (ipp_uchar_t
)n
;
5613 memcpy(bufptr
, attr
->name
, (size_t)n
);
5616 if (attr
->value_tag
> 0xff)
5618 *bufptr
++ = IPP_TAG_EXTENSION
;
5619 *bufptr
++ = (ipp_uchar_t
)(attr
->value_tag
>> 24);
5620 *bufptr
++ = (ipp_uchar_t
)(attr
->value_tag
>> 16);
5621 *bufptr
++ = (ipp_uchar_t
)(attr
->value_tag
>> 8);
5622 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5625 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5632 * Now write the attribute value(s)...
5635 switch (attr
->value_tag
& ~IPP_TAG_CUPS_CONST
)
5637 case IPP_TAG_UNSUPPORTED_VALUE
:
5638 case IPP_TAG_DEFAULT
:
5639 case IPP_TAG_UNKNOWN
:
5640 case IPP_TAG_NOVALUE
:
5641 case IPP_TAG_NOTSETTABLE
:
5642 case IPP_TAG_DELETEATTR
:
5643 case IPP_TAG_ADMINDEFINE
:
5648 case IPP_TAG_INTEGER
:
5650 for (i
= 0, value
= attr
->values
;
5651 i
< attr
->num_values
;
5654 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 9)
5656 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5658 DEBUG_puts("1ippWriteIO: Could not write IPP "
5660 _cupsBufferRelease((char *)buffer
);
5661 return (IPP_STATE_ERROR
);
5670 * Arrays and sets are done by sending additional
5671 * values with a zero-length name...
5674 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5680 * Integers and enumerations are both 4-byte signed
5681 * (twos-complement) values.
5683 * Put the 2-byte length and 4-byte value into the buffer...
5688 *bufptr
++ = (ipp_uchar_t
)(value
->integer
>> 24);
5689 *bufptr
++ = (ipp_uchar_t
)(value
->integer
>> 16);
5690 *bufptr
++ = (ipp_uchar_t
)(value
->integer
>> 8);
5691 *bufptr
++ = (ipp_uchar_t
)value
->integer
;
5695 case IPP_TAG_BOOLEAN
:
5696 for (i
= 0, value
= attr
->values
;
5697 i
< attr
->num_values
;
5700 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 6)
5702 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5704 DEBUG_puts("1ippWriteIO: Could not write IPP "
5706 _cupsBufferRelease((char *)buffer
);
5707 return (IPP_STATE_ERROR
);
5716 * Arrays and sets are done by sending additional
5717 * values with a zero-length name...
5720 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5726 * Boolean values are 1-byte; 0 = false, 1 = true.
5728 * Put the 2-byte length and 1-byte value into the buffer...
5733 *bufptr
++ = (ipp_uchar_t
)value
->boolean
;
5739 case IPP_TAG_KEYWORD
:
5741 case IPP_TAG_URISCHEME
:
5742 case IPP_TAG_CHARSET
:
5743 case IPP_TAG_LANGUAGE
:
5744 case IPP_TAG_MIMETYPE
:
5745 for (i
= 0, value
= attr
->values
;
5746 i
< attr
->num_values
;
5752 * Arrays and sets are done by sending additional
5753 * values with a zero-length name...
5756 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5758 ippTagString(attr
->value_tag
)));
5759 DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
5761 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
5763 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5765 DEBUG_puts("1ippWriteIO: Could not write IPP "
5767 _cupsBufferRelease((char *)buffer
);
5768 return (IPP_STATE_ERROR
);
5774 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5779 if (value
->string
.text
!= NULL
)
5780 n
= (int)strlen(value
->string
.text
);
5784 if (n
> (IPP_BUF_SIZE
- 2))
5786 DEBUG_printf(("1ippWriteIO: String too long (%d)", n
));
5787 _cupsBufferRelease((char *)buffer
);
5788 return (IPP_STATE_ERROR
);
5791 DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n
,
5792 value
->string
.text
));
5794 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
5796 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5798 DEBUG_puts("1ippWriteIO: Could not write IPP "
5800 _cupsBufferRelease((char *)buffer
);
5801 return (IPP_STATE_ERROR
);
5808 * All simple strings consist of the 2-byte length and
5809 * character data without the trailing nul normally found
5810 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
5811 * bytes since the 2-byte length is a signed (twos-complement)
5814 * Put the 2-byte length and string characters in the buffer.
5817 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
5818 *bufptr
++ = (ipp_uchar_t
)n
;
5822 memcpy(bufptr
, value
->string
.text
, (size_t)n
);
5829 for (i
= 0, value
= attr
->values
;
5830 i
< attr
->num_values
;
5833 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 16)
5835 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5837 DEBUG_puts("1ippWriteIO: Could not write IPP "
5839 _cupsBufferRelease((char *)buffer
);
5840 return (IPP_STATE_ERROR
);
5849 * Arrays and sets are done by sending additional
5850 * values with a zero-length name...
5853 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5859 * Date values consist of a 2-byte length and an
5860 * 11-byte date/time structure defined by RFC 1903.
5862 * Put the 2-byte length and 11-byte date/time
5863 * structure in the buffer.
5868 memcpy(bufptr
, value
->date
, 11);
5873 case IPP_TAG_RESOLUTION
:
5874 for (i
= 0, value
= attr
->values
;
5875 i
< attr
->num_values
;
5878 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 14)
5880 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5882 DEBUG_puts("1ippWriteIO: Could not write IPP "
5884 _cupsBufferRelease((char *)buffer
);
5885 return (IPP_STATE_ERROR
);
5894 * Arrays and sets are done by sending additional
5895 * values with a zero-length name...
5898 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5904 * Resolution values consist of a 2-byte length,
5905 * 4-byte horizontal resolution value, 4-byte vertical
5906 * resolution value, and a 1-byte units value.
5908 * Put the 2-byte length and resolution value data
5914 *bufptr
++ = (ipp_uchar_t
)(value
->resolution
.xres
>> 24);
5915 *bufptr
++ = (ipp_uchar_t
)(value
->resolution
.xres
>> 16);
5916 *bufptr
++ = (ipp_uchar_t
)(value
->resolution
.xres
>> 8);
5917 *bufptr
++ = (ipp_uchar_t
)value
->resolution
.xres
;
5918 *bufptr
++ = (ipp_uchar_t
)(value
->resolution
.yres
>> 24);
5919 *bufptr
++ = (ipp_uchar_t
)(value
->resolution
.yres
>> 16);
5920 *bufptr
++ = (ipp_uchar_t
)(value
->resolution
.yres
>> 8);
5921 *bufptr
++ = (ipp_uchar_t
)value
->resolution
.yres
;
5922 *bufptr
++ = (ipp_uchar_t
)value
->resolution
.units
;
5926 case IPP_TAG_RANGE
:
5927 for (i
= 0, value
= attr
->values
;
5928 i
< attr
->num_values
;
5931 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 13)
5933 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5935 DEBUG_puts("1ippWriteIO: Could not write IPP "
5937 _cupsBufferRelease((char *)buffer
);
5938 return (IPP_STATE_ERROR
);
5947 * Arrays and sets are done by sending additional
5948 * values with a zero-length name...
5951 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5957 * Range values consist of a 2-byte length,
5958 * 4-byte lower value, and 4-byte upper value.
5960 * Put the 2-byte length and range value data
5966 *bufptr
++ = (ipp_uchar_t
)(value
->range
.lower
>> 24);
5967 *bufptr
++ = (ipp_uchar_t
)(value
->range
.lower
>> 16);
5968 *bufptr
++ = (ipp_uchar_t
)(value
->range
.lower
>> 8);
5969 *bufptr
++ = (ipp_uchar_t
)value
->range
.lower
;
5970 *bufptr
++ = (ipp_uchar_t
)(value
->range
.upper
>> 24);
5971 *bufptr
++ = (ipp_uchar_t
)(value
->range
.upper
>> 16);
5972 *bufptr
++ = (ipp_uchar_t
)(value
->range
.upper
>> 8);
5973 *bufptr
++ = (ipp_uchar_t
)value
->range
.upper
;
5977 case IPP_TAG_TEXTLANG
:
5978 case IPP_TAG_NAMELANG
:
5979 for (i
= 0, value
= attr
->values
;
5980 i
< attr
->num_values
;
5986 * Arrays and sets are done by sending additional
5987 * values with a zero-length name...
5990 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
5992 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5994 DEBUG_puts("1ippWriteIO: Could not write IPP "
5996 _cupsBufferRelease((char *)buffer
);
5997 return (IPP_STATE_ERROR
);
6003 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
6009 * textWithLanguage and nameWithLanguage values consist
6010 * of a 2-byte length for both strings and their
6011 * individual lengths, a 2-byte length for the
6012 * character string, the character string without the
6013 * trailing nul, a 2-byte length for the character
6014 * set string, and the character set string without
6020 if (value
->string
.language
!= NULL
)
6021 n
+= (int)strlen(value
->string
.language
);
6023 if (value
->string
.text
!= NULL
)
6024 n
+= (int)strlen(value
->string
.text
);
6026 if (n
> (IPP_BUF_SIZE
- 2))
6028 DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
6029 "too long (%d)", n
));
6030 _cupsBufferRelease((char *)buffer
);
6031 return (IPP_STATE_ERROR
);
6034 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
6036 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6038 DEBUG_puts("1ippWriteIO: Could not write IPP "
6040 _cupsBufferRelease((char *)buffer
);
6041 return (IPP_STATE_ERROR
);
6047 /* Length of entire value */
6048 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
6049 *bufptr
++ = (ipp_uchar_t
)n
;
6051 /* Length of language */
6052 if (value
->string
.language
!= NULL
)
6053 n
= (int)strlen(value
->string
.language
);
6057 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
6058 *bufptr
++ = (ipp_uchar_t
)n
;
6063 memcpy(bufptr
, value
->string
.language
, (size_t)n
);
6067 /* Length of text */
6068 if (value
->string
.text
!= NULL
)
6069 n
= (int)strlen(value
->string
.text
);
6073 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
6074 *bufptr
++ = (ipp_uchar_t
)n
;
6079 memcpy(bufptr
, value
->string
.text
, (size_t)n
);
6085 case IPP_TAG_BEGIN_COLLECTION
:
6086 for (i
= 0, value
= attr
->values
;
6087 i
< attr
->num_values
;
6091 * Collections are written with the begin-collection
6092 * tag first with a value of 0 length, followed by the
6093 * attributes in the collection, then the end-collection
6097 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 5)
6099 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6101 DEBUG_puts("1ippWriteIO: Could not write IPP "
6103 _cupsBufferRelease((char *)buffer
);
6104 return (IPP_STATE_ERROR
);
6113 * Arrays and sets are done by sending additional
6114 * values with a zero-length name...
6117 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
6123 * Write a data length of 0 and flush the buffer...
6129 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6131 DEBUG_puts("1ippWriteIO: Could not write IPP "
6133 _cupsBufferRelease((char *)buffer
);
6134 return (IPP_STATE_ERROR
);
6140 * Then write the collection attribute...
6143 value
->collection
->state
= IPP_STATE_IDLE
;
6145 if (ippWriteIO(dst
, cb
, 1, ipp
,
6146 value
->collection
) == IPP_STATE_ERROR
)
6148 DEBUG_puts("1ippWriteIO: Unable to write collection value");
6149 _cupsBufferRelease((char *)buffer
);
6150 return (IPP_STATE_ERROR
);
6156 for (i
= 0, value
= attr
->values
;
6157 i
< attr
->num_values
;
6163 * Arrays and sets are done by sending additional
6164 * values with a zero-length name...
6167 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
6169 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6171 DEBUG_puts("1ippWriteIO: Could not write IPP "
6173 _cupsBufferRelease((char *)buffer
);
6174 return (IPP_STATE_ERROR
);
6180 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
6186 * An unknown value might some new value that a
6187 * vendor has come up with. It consists of a
6188 * 2-byte length and the bytes in the unknown
6192 n
= value
->unknown
.length
;
6194 if (n
> (IPP_BUF_SIZE
- 2))
6196 DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
6198 _cupsBufferRelease((char *)buffer
);
6199 return (IPP_STATE_ERROR
);
6202 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
6204 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6206 DEBUG_puts("1ippWriteIO: Could not write IPP "
6208 _cupsBufferRelease((char *)buffer
);
6209 return (IPP_STATE_ERROR
);
6215 /* Length of unknown value */
6216 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
6217 *bufptr
++ = (ipp_uchar_t
)n
;
6222 memcpy(bufptr
, value
->unknown
.data
, (size_t)n
);
6230 * Write the data out...
6233 if (bufptr
> buffer
)
6235 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6237 DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
6238 _cupsBufferRelease((char *)buffer
);
6239 return (IPP_STATE_ERROR
);
6242 DEBUG_printf(("2ippWriteIO: wrote %d bytes",
6243 (int)(bufptr
- buffer
)));
6247 * If blocking is disabled and we aren't at the end of the attribute
6248 * list, stop here...
6251 if (!blocking
&& ipp
->current
)
6255 if (ipp
->current
== NULL
)
6258 * Done with all of the attributes; add the end-of-attributes
6259 * tag or end-collection attribute...
6264 buffer
[0] = IPP_TAG_END
;
6269 buffer
[0] = IPP_TAG_END_COLLECTION
;
6270 buffer
[1] = 0; /* empty name */
6272 buffer
[3] = 0; /* empty value */
6277 if ((*cb
)(dst
, buffer
, (size_t)n
) < 0)
6279 DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
6280 _cupsBufferRelease((char *)buffer
);
6281 return (IPP_STATE_ERROR
);
6284 ipp
->state
= IPP_STATE_DATA
;
6288 case IPP_STATE_DATA
:
6292 break; /* anti-compiler-warning-code */
6295 _cupsBufferRelease((char *)buffer
);
6297 return (ipp
->state
);
6302 * 'ipp_add_attr()' - Add a new attribute to the message.
6305 static ipp_attribute_t
* /* O - New attribute */
6306 ipp_add_attr(ipp_t
*ipp
, /* I - IPP message */
6307 const char *name
, /* I - Attribute name or NULL */
6308 ipp_tag_t group_tag
, /* I - Group tag or IPP_TAG_ZERO */
6309 ipp_tag_t value_tag
, /* I - Value tag or IPP_TAG_ZERO */
6310 int num_values
) /* I - Number of values */
6312 int alloc_values
; /* Number of values to allocate */
6313 ipp_attribute_t
*attr
; /* New attribute */
6316 DEBUG_printf(("4ipp_add_attr(ipp=%p, name=\"%s\", group_tag=0x%x, value_tag=0x%x, "
6317 "num_values=%d)", ipp
, name
, group_tag
, value_tag
, num_values
));
6320 * Range check input...
6323 if (!ipp
|| num_values
< 0)
6327 * Allocate memory, rounding the allocation up as needed...
6330 if (num_values
<= 1)
6333 alloc_values
= (num_values
+ IPP_MAX_VALUES
- 1) & ~(IPP_MAX_VALUES
- 1);
6335 attr
= calloc(sizeof(ipp_attribute_t
) +
6336 (size_t)(alloc_values
- 1) * sizeof(_ipp_value_t
), 1);
6341 * Initialize attribute...
6345 attr
->name
= _cupsStrAlloc(name
);
6347 attr
->group_tag
= group_tag
;
6348 attr
->value_tag
= value_tag
;
6349 attr
->num_values
= num_values
;
6352 * Add it to the end of the linked list...
6356 ipp
->last
->next
= attr
;
6360 ipp
->prev
= ipp
->last
;
6361 ipp
->last
= ipp
->current
= attr
;
6364 DEBUG_printf(("5ipp_add_attr: Returning %p", attr
));
6371 * 'ipp_free_values()' - Free attribute values.
6375 ipp_free_values(ipp_attribute_t
*attr
, /* I - Attribute to free values from */
6376 int element
,/* I - First value to free */
6377 int count
) /* I - Number of values to free */
6379 int i
; /* Looping var */
6380 _ipp_value_t
*value
; /* Current value */
6383 DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", attr
,
6386 if (!(attr
->value_tag
& IPP_TAG_CUPS_CONST
))
6389 * Free values as needed...
6392 switch (attr
->value_tag
)
6394 case IPP_TAG_TEXTLANG
:
6395 case IPP_TAG_NAMELANG
:
6396 if (element
== 0 && count
== attr
->num_values
&&
6397 attr
->values
[0].string
.language
)
6399 _cupsStrFree(attr
->values
[0].string
.language
);
6400 attr
->values
[0].string
.language
= NULL
;
6402 /* Fall through to other string values */
6406 case IPP_TAG_RESERVED_STRING
:
6407 case IPP_TAG_KEYWORD
:
6409 case IPP_TAG_URISCHEME
:
6410 case IPP_TAG_CHARSET
:
6411 case IPP_TAG_LANGUAGE
:
6412 case IPP_TAG_MIMETYPE
:
6413 for (i
= count
, value
= attr
->values
+ element
;
6417 _cupsStrFree(value
->string
.text
);
6418 value
->string
.text
= NULL
;
6422 case IPP_TAG_DEFAULT
:
6423 case IPP_TAG_UNKNOWN
:
6424 case IPP_TAG_NOVALUE
:
6425 case IPP_TAG_NOTSETTABLE
:
6426 case IPP_TAG_DELETEATTR
:
6427 case IPP_TAG_ADMINDEFINE
:
6428 case IPP_TAG_INTEGER
:
6430 case IPP_TAG_BOOLEAN
:
6432 case IPP_TAG_RESOLUTION
:
6433 case IPP_TAG_RANGE
:
6436 case IPP_TAG_BEGIN_COLLECTION
:
6437 for (i
= count
, value
= attr
->values
+ element
;
6441 ippDelete(value
->collection
);
6442 value
->collection
= NULL
;
6446 case IPP_TAG_STRING
:
6448 for (i
= count
, value
= attr
->values
+ element
;
6452 if (value
->unknown
.data
)
6454 free(value
->unknown
.data
);
6455 value
->unknown
.data
= NULL
;
6463 * If we are not freeing values from the end, move the remaining values up...
6466 if ((element
+ count
) < attr
->num_values
)
6467 memmove(attr
->values
+ element
, attr
->values
+ element
+ count
,
6468 (size_t)(attr
->num_values
- count
- element
) * sizeof(_ipp_value_t
));
6470 attr
->num_values
-= count
;
6475 * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
6477 * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
6478 * to "ll-cc", "ll-region", and "charset-number", respectively.
6481 static char * /* O - Language code string */
6482 ipp_get_code(const char *value
, /* I - Locale/charset string */
6483 char *buffer
, /* I - String buffer */
6484 size_t bufsize
) /* I - Size of string buffer */
6486 char *bufptr
, /* Pointer into buffer */
6487 *bufend
; /* End of buffer */
6491 * Convert values to lowercase and change _ to - as needed...
6494 for (bufptr
= buffer
, bufend
= buffer
+ bufsize
- 1;
6495 *value
&& bufptr
< bufend
;
6500 *bufptr
++ = (char)_cups_tolower(*value
);
6505 * Return the converted string...
6513 * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
6515 * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
6516 * "ll-region", respectively. It also converts the "C" (POSIX) locale to "en".
6519 static char * /* O - Language code string */
6520 ipp_lang_code(const char *locale
, /* I - Locale string */
6521 char *buffer
, /* I - String buffer */
6522 size_t bufsize
) /* I - Size of string buffer */
6525 * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
6528 if (!_cups_strcasecmp(locale
, "c"))
6530 strlcpy(buffer
, "en", bufsize
);
6534 return (ipp_get_code(locale
, buffer
, bufsize
));
6539 * 'ipp_length()' - Compute the length of an IPP message or collection value.
6542 static size_t /* O - Size of IPP message */
6543 ipp_length(ipp_t
*ipp
, /* I - IPP message or collection */
6544 int collection
) /* I - 1 if a collection, 0 otherwise */
6546 int i
; /* Looping var */
6547 size_t bytes
; /* Number of bytes */
6548 ipp_attribute_t
*attr
; /* Current attribute */
6549 ipp_tag_t group
; /* Current group */
6550 _ipp_value_t
*value
; /* Current value */
6553 DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", ipp
, collection
));
6557 DEBUG_puts("4ipp_length: Returning 0 bytes");
6562 * Start with 8 bytes for the IPP message header...
6565 bytes
= collection
? 0 : 8;
6568 * Then add the lengths of each attribute...
6571 group
= IPP_TAG_ZERO
;
6573 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= attr
->next
)
6575 if (attr
->group_tag
!= group
&& !collection
)
6577 group
= attr
->group_tag
;
6578 if (group
== IPP_TAG_ZERO
)
6581 bytes
++; /* Group tag */
6587 DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
6588 "bytes=" CUPS_LLFMT
, attr
->name
, attr
->num_values
, CUPS_LLCAST bytes
));
6590 if (attr
->value_tag
< IPP_TAG_EXTENSION
)
6591 bytes
+= (size_t)attr
->num_values
;/* Value tag for each value */
6593 bytes
+= (size_t)(5 * attr
->num_values
);
6594 /* Value tag for each value */
6595 bytes
+= (size_t)(2 * attr
->num_values
);
6597 bytes
+= strlen(attr
->name
); /* Name */
6598 bytes
+= (size_t)(2 * attr
->num_values
);
6602 bytes
+= 5; /* Add membername overhead */
6604 switch (attr
->value_tag
& ~IPP_TAG_CUPS_CONST
)
6606 case IPP_TAG_UNSUPPORTED_VALUE
:
6607 case IPP_TAG_DEFAULT
:
6608 case IPP_TAG_UNKNOWN
:
6609 case IPP_TAG_NOVALUE
:
6610 case IPP_TAG_NOTSETTABLE
:
6611 case IPP_TAG_DELETEATTR
:
6612 case IPP_TAG_ADMINDEFINE
:
6615 case IPP_TAG_INTEGER
:
6617 bytes
+= (size_t)(4 * attr
->num_values
);
6620 case IPP_TAG_BOOLEAN
:
6621 bytes
+= (size_t)attr
->num_values
;
6626 case IPP_TAG_KEYWORD
:
6628 case IPP_TAG_URISCHEME
:
6629 case IPP_TAG_CHARSET
:
6630 case IPP_TAG_LANGUAGE
:
6631 case IPP_TAG_MIMETYPE
:
6632 for (i
= 0, value
= attr
->values
;
6633 i
< attr
->num_values
;
6635 if (value
->string
.text
)
6636 bytes
+= strlen(value
->string
.text
);
6640 bytes
+= (size_t)(11 * attr
->num_values
);
6643 case IPP_TAG_RESOLUTION
:
6644 bytes
+= (size_t)(9 * attr
->num_values
);
6647 case IPP_TAG_RANGE
:
6648 bytes
+= (size_t)(8 * attr
->num_values
);
6651 case IPP_TAG_TEXTLANG
:
6652 case IPP_TAG_NAMELANG
:
6653 bytes
+= (size_t)(4 * attr
->num_values
);
6654 /* Charset + text length */
6656 for (i
= 0, value
= attr
->values
;
6657 i
< attr
->num_values
;
6660 if (value
->string
.language
)
6661 bytes
+= strlen(value
->string
.language
);
6663 if (value
->string
.text
)
6664 bytes
+= strlen(value
->string
.text
);
6668 case IPP_TAG_BEGIN_COLLECTION
:
6669 for (i
= 0, value
= attr
->values
;
6670 i
< attr
->num_values
;
6672 bytes
+= ipp_length(value
->collection
, 1);
6676 for (i
= 0, value
= attr
->values
;
6677 i
< attr
->num_values
;
6679 bytes
+= (size_t)value
->unknown
.length
;
6685 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
6686 * for the "end of collection" tag and return...
6694 DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT
" bytes", CUPS_LLCAST bytes
));
6701 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
6704 static ssize_t
/* O - Number of bytes read */
6705 ipp_read_http(http_t
*http
, /* I - Client connection */
6706 ipp_uchar_t
*buffer
, /* O - Buffer for data */
6707 size_t length
) /* I - Total length */
6709 ssize_t tbytes
, /* Total bytes read */
6710 bytes
; /* Bytes read this pass */
6713 DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)",
6714 http
, buffer
, (int)length
));
6717 * Loop until all bytes are read...
6720 for (tbytes
= 0, bytes
= 0;
6721 tbytes
< (int)length
;
6722 tbytes
+= bytes
, buffer
+= bytes
)
6724 DEBUG_printf(("9ipp_read_http: tbytes=" CUPS_LLFMT
", http->state=%d", CUPS_LLCAST tbytes
, http
->state
));
6726 if (http
->state
== HTTP_STATE_WAITING
)
6729 if (http
->used
== 0 && !http
->blocking
)
6732 * Wait up to 10 seconds for more data on non-blocking sockets...
6735 if (!httpWait(http
, 10000))
6746 if ((bytes
= httpRead2(http
, (char *)buffer
, length
- (size_t)tbytes
)) < 0)
6751 if (errno
!= EAGAIN
&& errno
!= EINTR
)
6757 else if (bytes
== 0)
6762 * Return the number of bytes read...
6765 if (tbytes
== 0 && bytes
< 0)
6768 DEBUG_printf(("8ipp_read_http: Returning " CUPS_LLFMT
" bytes", CUPS_LLCAST tbytes
));
6775 * 'ipp_read_file()' - Read IPP data from a file.
6778 static ssize_t
/* O - Number of bytes read */
6779 ipp_read_file(int *fd
, /* I - File descriptor */
6780 ipp_uchar_t
*buffer
, /* O - Read buffer */
6781 size_t length
) /* I - Number of bytes to read */
6784 return ((ssize_t
)read(*fd
, buffer
, (unsigned)length
));
6786 return (read(*fd
, buffer
, length
));
6792 * 'ipp_set_error()' - Set a formatted, localized error string.
6796 ipp_set_error(ipp_status_t status
, /* I - Status code */
6797 const char *format
, /* I - Printf-style error string */
6798 ...) /* I - Additional arguments as needed */
6800 va_list ap
; /* Pointer to additional args */
6801 char buffer
[2048]; /* Message buffer */
6802 cups_lang_t
*lang
= cupsLangDefault();
6803 /* Current language */
6806 va_start(ap
, format
);
6807 vsnprintf(buffer
, sizeof(buffer
), _cupsLangString(lang
, format
), ap
);
6810 _cupsSetError(status
, buffer
, 0);
6815 * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
6819 static _ipp_value_t
* /* O - IPP value element or NULL on error */
6820 ipp_set_value(ipp_t
*ipp
, /* IO - IPP message */
6821 ipp_attribute_t
**attr
, /* IO - IPP attribute */
6822 int element
) /* I - Value number (0-based) */
6824 ipp_attribute_t
*temp
, /* New attribute pointer */
6825 *current
, /* Current attribute in list */
6826 *prev
; /* Previous attribute in list */
6827 int alloc_values
; /* Allocated values */
6831 * If we are setting an existing value element, return it...
6836 if (temp
->num_values
<= 1)
6839 alloc_values
= (temp
->num_values
+ IPP_MAX_VALUES
- 1) &
6840 ~(IPP_MAX_VALUES
- 1);
6842 if (element
< alloc_values
)
6844 if (element
>= temp
->num_values
)
6845 temp
->num_values
= element
+ 1;
6847 return (temp
->values
+ element
);
6851 * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
6852 * values when num_values > 1.
6855 if (alloc_values
< IPP_MAX_VALUES
)
6856 alloc_values
= IPP_MAX_VALUES
;
6858 alloc_values
+= IPP_MAX_VALUES
;
6860 DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
6864 * Reallocate memory...
6867 if ((temp
= realloc(temp
, sizeof(ipp_attribute_t
) + (size_t)(alloc_values
- 1) * sizeof(_ipp_value_t
))) == NULL
)
6869 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
6870 DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
6875 * Zero the new memory...
6878 memset(temp
->values
+ temp
->num_values
, 0, (size_t)(alloc_values
- temp
->num_values
) * sizeof(_ipp_value_t
));
6883 * Reset pointers in the list...
6886 if (ipp
->current
== *attr
&& ipp
->prev
)
6889 * Use current "previous" pointer...
6897 * Find this attribute in the linked list...
6900 for (prev
= NULL
, current
= ipp
->attrs
;
6901 current
&& current
!= *attr
;
6902 prev
= current
, current
= current
->next
);
6907 * This is a serious error!
6911 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
6912 _("IPP attribute is not a member of the message."), 1);
6913 DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
6923 ipp
->current
= temp
;
6926 if (ipp
->last
== *attr
)
6933 * Return the value element...
6936 if (element
>= temp
->num_values
)
6937 temp
->num_values
= element
+ 1;
6939 return (temp
->values
+ element
);
6944 * 'ipp_write_file()' - Write IPP data to a file.
6947 static ssize_t
/* O - Number of bytes written */
6948 ipp_write_file(int *fd
, /* I - File descriptor */
6949 ipp_uchar_t
*buffer
, /* I - Data to write */
6950 size_t length
) /* I - Number of bytes to write */
6953 return ((ssize_t
)write(*fd
, buffer
, (unsigned)length
));
6955 return (write(*fd
, buffer
, length
));