4 * Internet Printing Protocol functions for CUPS.
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * Include necessary headers...
22 #include "cups-private.h"
33 static ipp_attribute_t
*ipp_add_attr(ipp_t
*ipp
, const char *name
,
34 ipp_tag_t group_tag
, ipp_tag_t value_tag
,
36 static void ipp_free_values(ipp_attribute_t
*attr
, int element
,
38 static char *ipp_get_code(const char *locale
, char *buffer
,
40 __attribute__((nonnull(1,2)));
41 static char *ipp_lang_code(const char *locale
, char *buffer
,
43 __attribute__((nonnull(1,2)));
44 static size_t ipp_length(ipp_t
*ipp
, int collection
);
45 static ssize_t
ipp_read_http(http_t
*http
, ipp_uchar_t
*buffer
,
47 static ssize_t
ipp_read_file(int *fd
, ipp_uchar_t
*buffer
,
49 static void ipp_set_error(ipp_status_t status
, const char *format
,
51 static _ipp_value_t
*ipp_set_value(ipp_t
*ipp
, ipp_attribute_t
**attr
,
53 static ssize_t
ipp_write_file(int *fd
, ipp_uchar_t
*buffer
,
58 * '_cupsBufferGet()' - Get a read/write buffer.
61 char * /* O - Buffer */
62 _cupsBufferGet(size_t size
) /* I - Size required */
64 _cups_buffer_t
*buffer
; /* Current buffer */
65 _cups_globals_t
*cg
= _cupsGlobals();
69 for (buffer
= cg
->cups_buffers
; buffer
; buffer
= buffer
->next
)
70 if (!buffer
->used
&& buffer
->size
>= size
)
75 if ((buffer
= malloc(sizeof(_cups_buffer_t
) + size
- 1)) == NULL
)
78 buffer
->next
= cg
->cups_buffers
;
80 cg
->cups_buffers
= buffer
;
90 * '_cupsBufferRelease()' - Release a read/write buffer.
94 _cupsBufferRelease(char *b
) /* I - Buffer to release */
96 _cups_buffer_t
*buffer
; /* Buffer */
100 * Mark this buffer as unused...
103 buffer
= (_cups_buffer_t
*)(b
- offsetof(_cups_buffer_t
, d
));
109 * 'ippAddBoolean()' - Add a boolean attribute to an IPP message.
111 * The @code ipp@ parameter refers to an IPP message previously created using
112 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
114 * The @code group@ parameter specifies the IPP attribute group tag: none
115 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
116 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
117 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
118 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
121 ipp_attribute_t
* /* O - New attribute */
122 ippAddBoolean(ipp_t
*ipp
, /* I - IPP message */
123 ipp_tag_t group
, /* I - IPP group */
124 const char *name
, /* I - Name of attribute */
125 char value
) /* I - Value of attribute */
127 ipp_attribute_t
*attr
; /* New attribute */
130 DEBUG_printf(("ippAddBoolean(ipp=%p, group=%02x(%s), name=\"%s\", value=%d)",
131 ipp
, group
, ippTagString(group
), name
, value
));
134 * Range check input...
137 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
138 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
142 * Create the attribute...
145 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BOOLEAN
, 1)) == NULL
)
148 attr
->values
[0].boolean
= value
;
155 * 'ippAddBooleans()' - Add an array of boolean values.
157 * The @code ipp@ parameter refers to an IPP message previously created using
158 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
160 * The @code group@ parameter specifies the IPP attribute group tag: none
161 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
162 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
163 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
164 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
167 ipp_attribute_t
* /* O - New attribute */
168 ippAddBooleans(ipp_t
*ipp
, /* I - IPP message */
169 ipp_tag_t group
, /* I - IPP group */
170 const char *name
, /* I - Name of attribute */
171 int num_values
, /* I - Number of values */
172 const char *values
) /* I - Values */
174 int i
; /* Looping var */
175 ipp_attribute_t
*attr
; /* New attribute */
176 _ipp_value_t
*value
; /* Current value */
179 DEBUG_printf(("ippAddBooleans(ipp=%p, group=%02x(%s), name=\"%s\", "
180 "num_values=%d, values=%p)", ipp
, group
, ippTagString(group
),
181 name
, num_values
, values
));
184 * Range check input...
187 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
188 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
193 * Create the attribute...
196 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BOOLEAN
, num_values
)) == NULL
)
201 for (i
= num_values
, value
= attr
->values
;
204 value
->boolean
= *values
++;
212 * 'ippAddCollection()' - Add a collection value.
214 * The @code ipp@ parameter refers to an IPP message previously created using
215 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
217 * The @code group@ parameter specifies the IPP attribute group tag: none
218 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
219 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
220 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
221 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
223 * @since CUPS 1.1.19/OS X 10.3@
226 ipp_attribute_t
* /* O - New attribute */
227 ippAddCollection(ipp_t
*ipp
, /* I - IPP message */
228 ipp_tag_t group
, /* I - IPP group */
229 const char *name
, /* I - Name of attribute */
230 ipp_t
*value
) /* I - Value */
232 ipp_attribute_t
*attr
; /* New attribute */
235 DEBUG_printf(("ippAddCollection(ipp=%p, group=%02x(%s), name=\"%s\", "
236 "value=%p)", ipp
, group
, ippTagString(group
), name
, value
));
239 * Range check input...
242 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
243 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
247 * Create the attribute...
250 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BEGIN_COLLECTION
, 1)) == NULL
)
253 attr
->values
[0].collection
= value
;
263 * 'ippAddCollections()' - Add an array of collection values.
265 * The @code ipp@ parameter refers to an IPP message previously created using
266 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
268 * The @code group@ parameter specifies the IPP attribute group tag: none
269 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
270 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
271 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
272 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
274 * @since CUPS 1.1.19/OS X 10.3@
277 ipp_attribute_t
* /* O - New attribute */
279 ipp_t
*ipp
, /* I - IPP message */
280 ipp_tag_t group
, /* I - IPP group */
281 const char *name
, /* I - Name of attribute */
282 int num_values
, /* I - Number of values */
283 const ipp_t
**values
) /* I - Values */
285 int i
; /* Looping var */
286 ipp_attribute_t
*attr
; /* New attribute */
287 _ipp_value_t
*value
; /* Current value */
290 DEBUG_printf(("ippAddCollections(ipp=%p, group=%02x(%s), name=\"%s\", "
291 "num_values=%d, values=%p)", ipp
, group
, ippTagString(group
),
292 name
, num_values
, values
));
295 * Range check input...
298 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
299 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
304 * Create the attribute...
307 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BEGIN_COLLECTION
,
308 num_values
)) == NULL
)
313 for (i
= num_values
, value
= attr
->values
;
317 value
->collection
= (ipp_t
*)*values
++;
318 value
->collection
->use
++;
327 * 'ippAddDate()' - Add a date attribute to an IPP message.
329 * The @code ipp@ parameter refers to an IPP message previously created using
330 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
332 * The @code group@ parameter specifies the IPP attribute group tag: none
333 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
334 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
335 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
336 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
339 ipp_attribute_t
* /* O - New attribute */
340 ippAddDate(ipp_t
*ipp
, /* I - IPP message */
341 ipp_tag_t group
, /* I - IPP group */
342 const char *name
, /* I - Name of attribute */
343 const ipp_uchar_t
*value
) /* I - Value */
345 ipp_attribute_t
*attr
; /* New attribute */
348 DEBUG_printf(("ippAddDate(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)",
349 ipp
, group
, ippTagString(group
), name
, value
));
352 * Range check input...
355 if (!ipp
|| !name
|| !value
|| group
< IPP_TAG_ZERO
||
356 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
360 * Create the attribute...
363 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_DATE
, 1)) == NULL
)
366 memcpy(attr
->values
[0].date
, value
, 11);
373 * 'ippAddInteger()' - Add a integer attribute to an IPP message.
375 * The @code ipp@ parameter refers to an IPP message previously created using
376 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
378 * The @code group@ parameter specifies the IPP attribute group tag: none
379 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
380 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
381 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
382 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
384 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
385 * (@code IPP_TAG_INTEGER@).
388 ipp_attribute_t
* /* O - New attribute */
389 ippAddInteger(ipp_t
*ipp
, /* I - IPP message */
390 ipp_tag_t group
, /* I - IPP group */
391 ipp_tag_t value_tag
, /* I - Type of attribute */
392 const char *name
, /* I - Name of attribute */
393 int value
) /* I - Value of attribute */
395 ipp_attribute_t
*attr
; /* New attribute */
398 DEBUG_printf(("ippAddInteger(ipp=%p, group=%02x(%s), type=%02x(%s), "
399 "name=\"%s\", value=%d)", ipp
, group
, ippTagString(group
),
400 value_tag
, ippTagString(value_tag
), name
, value
));
402 value_tag
&= IPP_TAG_CUPS_MASK
;
405 * Special-case for legacy usage: map out-of-band attributes to new ippAddOutOfBand
409 if (value_tag
>= IPP_TAG_UNSUPPORTED_VALUE
&& value_tag
<= IPP_TAG_ADMINDEFINE
)
410 return (ippAddOutOfBand(ipp
, group
, value_tag
, name
));
413 * Range check input...
417 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
418 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
419 (value_tag
!= IPP_TAG_INTEGER
&& value_tag
!= IPP_TAG_ENUM
))
422 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
423 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
428 * Create the attribute...
431 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, 1)) == NULL
)
434 attr
->values
[0].integer
= value
;
441 * 'ippAddIntegers()' - Add an array of integer values.
443 * The @code ipp@ parameter refers to an IPP message previously created using
444 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
446 * The @code group@ parameter specifies the IPP attribute group tag: none
447 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
448 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
449 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
450 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
452 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
453 * (@code IPP_TAG_INTEGER@).
456 ipp_attribute_t
* /* O - New attribute */
457 ippAddIntegers(ipp_t
*ipp
, /* I - IPP message */
458 ipp_tag_t group
, /* I - IPP group */
459 ipp_tag_t value_tag
, /* I - Type of attribute */
460 const char *name
, /* I - Name of attribute */
461 int num_values
, /* I - Number of values */
462 const int *values
) /* I - Values */
464 int i
; /* Looping var */
465 ipp_attribute_t
*attr
; /* New attribute */
466 _ipp_value_t
*value
; /* Current value */
469 DEBUG_printf(("ippAddIntegers(ipp=%p, group=%02x(%s), type=%02x(%s), "
470 "name=\"%s\", num_values=%d, values=%p)", ipp
,
471 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
472 num_values
, values
));
474 value_tag
&= IPP_TAG_CUPS_MASK
;
477 * Range check input...
481 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
482 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
483 (value_tag
!= IPP_TAG_INTEGER
&& value_tag
!= IPP_TAG_ENUM
) ||
487 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
488 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
494 * Create the attribute...
497 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, num_values
)) == NULL
)
502 for (i
= num_values
, value
= attr
->values
;
505 value
->integer
= *values
++;
513 * 'ippAddOctetString()' - Add an octetString value to an IPP message.
515 * The @code ipp@ parameter refers to an IPP message previously created using
516 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
518 * The @code group@ parameter specifies the IPP attribute group tag: none
519 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
520 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
521 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
522 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
524 * @since CUPS 1.2/OS X 10.5@
527 ipp_attribute_t
* /* O - New attribute */
528 ippAddOctetString(ipp_t
*ipp
, /* I - IPP message */
529 ipp_tag_t group
, /* I - IPP group */
530 const char *name
, /* I - Name of attribute */
531 const void *data
, /* I - octetString data */
532 int datalen
) /* I - Length of data in bytes */
534 ipp_attribute_t
*attr
; /* New attribute */
537 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
538 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
539 datalen
< 0 || datalen
> IPP_MAX_LENGTH
)
542 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_STRING
, 1)) == NULL
)
546 * Initialize the attribute data...
549 attr
->values
[0].unknown
.length
= datalen
;
553 if ((attr
->values
[0].unknown
.data
= malloc((size_t)datalen
)) == NULL
)
555 ippDeleteAttribute(ipp
, attr
);
559 memcpy(attr
->values
[0].unknown
.data
, data
, (size_t)datalen
);
563 * Return the new attribute...
571 * 'ippAddOutOfBand()' - Add an out-of-band value to an IPP message.
573 * The @code ipp@ parameter refers to an IPP message previously created using
574 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
576 * The @code group@ parameter specifies the IPP attribute group tag: none
577 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
578 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
579 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
580 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
582 * Supported out-of-band values include unsupported-value
583 * (@code IPP_TAG_UNSUPPORTED_VALUE@), default (@code IPP_TAG_DEFAULT@), unknown
584 * (@code IPP_TAG_UNKNOWN@), no-value (@code IPP_TAG_NOVALUE@), not-settable
585 * (@code IPP_TAG_NOTSETTABLE@), delete-attribute (@code IPP_TAG_DELETEATTR@), and
586 * admin-define (@code IPP_TAG_ADMINDEFINE@).
588 * @since CUPS 1.6/OS X 10.8@
591 ipp_attribute_t
* /* O - New attribute */
592 ippAddOutOfBand(ipp_t
*ipp
, /* I - IPP message */
593 ipp_tag_t group
, /* I - IPP group */
594 ipp_tag_t value_tag
, /* I - Type of attribute */
595 const char *name
) /* I - Name of attribute */
597 DEBUG_printf(("ippAddOutOfBand(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
598 "name=\"%s\")", ipp
, group
, ippTagString(group
), value_tag
,
599 ippTagString(value_tag
), name
));
601 value_tag
&= IPP_TAG_CUPS_MASK
;
604 * Range check input...
607 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
608 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
609 (value_tag
!= IPP_TAG_UNSUPPORTED_VALUE
&&
610 value_tag
!= IPP_TAG_DEFAULT
&&
611 value_tag
!= IPP_TAG_UNKNOWN
&&
612 value_tag
!= IPP_TAG_NOVALUE
&&
613 value_tag
!= IPP_TAG_NOTSETTABLE
&&
614 value_tag
!= IPP_TAG_DELETEATTR
&&
615 value_tag
!= IPP_TAG_ADMINDEFINE
))
619 * Create the attribute...
622 return (ipp_add_attr(ipp
, name
, group
, value_tag
, 1));
627 * 'ippAddRange()' - Add a range of values to an IPP message.
629 * The @code ipp@ parameter refers to an IPP message previously created using
630 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
632 * The @code group@ parameter specifies the IPP attribute group tag: none
633 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
634 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
635 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
636 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
638 * The @code lower@ parameter must be less than or equal to the @code upper@ parameter.
641 ipp_attribute_t
* /* O - New attribute */
642 ippAddRange(ipp_t
*ipp
, /* I - IPP message */
643 ipp_tag_t group
, /* I - IPP group */
644 const char *name
, /* I - Name of attribute */
645 int lower
, /* I - Lower value */
646 int upper
) /* I - Upper value */
648 ipp_attribute_t
*attr
; /* New attribute */
651 DEBUG_printf(("ippAddRange(ipp=%p, group=%02x(%s), name=\"%s\", lower=%d, "
652 "upper=%d)", ipp
, group
, ippTagString(group
), name
, lower
,
656 * Range check input...
659 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
660 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
664 * Create the attribute...
667 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RANGE
, 1)) == NULL
)
670 attr
->values
[0].range
.lower
= lower
;
671 attr
->values
[0].range
.upper
= upper
;
678 * 'ippAddRanges()' - Add ranges of values to an IPP message.
680 * The @code ipp@ parameter refers to an IPP message previously created using
681 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
683 * The @code group@ parameter specifies the IPP attribute group tag: none
684 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
685 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
686 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
687 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
690 ipp_attribute_t
* /* O - New attribute */
691 ippAddRanges(ipp_t
*ipp
, /* I - IPP message */
692 ipp_tag_t group
, /* I - IPP group */
693 const char *name
, /* I - Name of attribute */
694 int num_values
, /* I - Number of values */
695 const int *lower
, /* I - Lower values */
696 const int *upper
) /* I - Upper values */
698 int i
; /* Looping var */
699 ipp_attribute_t
*attr
; /* New attribute */
700 _ipp_value_t
*value
; /* Current value */
703 DEBUG_printf(("ippAddRanges(ipp=%p, group=%02x(%s), name=\"%s\", "
704 "num_values=%d, lower=%p, upper=%p)", ipp
, group
,
705 ippTagString(group
), name
, num_values
, lower
, upper
));
708 * Range check input...
711 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
712 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
717 * Create the attribute...
720 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RANGE
, num_values
)) == NULL
)
725 for (i
= num_values
, value
= attr
->values
;
729 value
->range
.lower
= *lower
++;
730 value
->range
.upper
= *upper
++;
739 * 'ippAddResolution()' - Add a resolution value to an IPP message.
741 * The @code ipp@ parameter refers to an IPP message previously created using
742 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
744 * The @code group@ parameter specifies the IPP attribute group tag: none
745 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
746 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
747 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
748 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
751 ipp_attribute_t
* /* O - New attribute */
752 ippAddResolution(ipp_t
*ipp
, /* I - IPP message */
753 ipp_tag_t group
, /* I - IPP group */
754 const char *name
, /* I - Name of attribute */
755 ipp_res_t units
, /* I - Units for resolution */
756 int xres
, /* I - X resolution */
757 int yres
) /* I - Y resolution */
759 ipp_attribute_t
*attr
; /* New attribute */
762 DEBUG_printf(("ippAddResolution(ipp=%p, group=%02x(%s), name=\"%s\", "
763 "units=%d, xres=%d, yres=%d)", ipp
, group
,
764 ippTagString(group
), name
, units
, xres
, yres
));
767 * Range check input...
770 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
771 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
772 units
< IPP_RES_PER_INCH
|| units
> IPP_RES_PER_CM
||
773 xres
< 0 || yres
< 0)
777 * Create the attribute...
780 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RESOLUTION
, 1)) == NULL
)
783 attr
->values
[0].resolution
.xres
= xres
;
784 attr
->values
[0].resolution
.yres
= yres
;
785 attr
->values
[0].resolution
.units
= units
;
792 * 'ippAddResolutions()' - Add resolution values to an IPP message.
794 * The @code ipp@ parameter refers to an IPP message previously created using
795 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
797 * The @code group@ parameter specifies the IPP attribute group tag: none
798 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
799 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
800 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
801 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
804 ipp_attribute_t
* /* O - New attribute */
805 ippAddResolutions(ipp_t
*ipp
, /* I - IPP message */
806 ipp_tag_t group
, /* I - IPP group */
807 const char *name
, /* I - Name of attribute */
808 int num_values
,/* I - Number of values */
809 ipp_res_t units
, /* I - Units for resolution */
810 const int *xres
, /* I - X resolutions */
811 const int *yres
) /* I - Y resolutions */
813 int i
; /* Looping var */
814 ipp_attribute_t
*attr
; /* New attribute */
815 _ipp_value_t
*value
; /* Current value */
818 DEBUG_printf(("ippAddResolutions(ipp=%p, group=%02x(%s), name=\"%s\", "
819 "num_value=%d, units=%d, xres=%p, yres=%p)", ipp
, group
,
820 ippTagString(group
), name
, num_values
, units
, xres
, yres
));
823 * Range check input...
826 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
827 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
829 units
< IPP_RES_PER_INCH
|| units
> IPP_RES_PER_CM
)
833 * Create the attribute...
836 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RESOLUTION
, num_values
)) == NULL
)
841 for (i
= num_values
, value
= attr
->values
;
845 value
->resolution
.xres
= *xres
++;
846 value
->resolution
.yres
= *yres
++;
847 value
->resolution
.units
= units
;
856 * 'ippAddSeparator()' - Add a group separator to an IPP message.
858 * The @code ipp@ parameter refers to an IPP message previously created using
859 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
862 ipp_attribute_t
* /* O - New attribute */
863 ippAddSeparator(ipp_t
*ipp
) /* I - IPP message */
865 DEBUG_printf(("ippAddSeparator(ipp=%p)", ipp
));
868 * Range check input...
875 * Create the attribute...
878 return (ipp_add_attr(ipp
, NULL
, IPP_TAG_ZERO
, IPP_TAG_ZERO
, 0));
883 * 'ippAddString()' - Add a language-encoded string to an IPP message.
885 * The @code ipp@ parameter refers to an IPP message previously created using
886 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
888 * The @code group@ parameter specifies the IPP attribute group tag: none
889 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
890 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
891 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
892 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
894 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
895 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
896 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
897 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
898 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
899 * (@code IPP_TAG_URISCHEME@).
901 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
902 * textWithLanguage string values and must be @code NULL@ for all other string values.
905 ipp_attribute_t
* /* O - New attribute */
906 ippAddString(ipp_t
*ipp
, /* I - IPP message */
907 ipp_tag_t group
, /* I - IPP group */
908 ipp_tag_t value_tag
, /* I - Type of attribute */
909 const char *name
, /* I - Name of attribute */
910 const char *language
, /* I - Language code */
911 const char *value
) /* I - Value */
913 ipp_tag_t temp_tag
; /* Temporary value tag (masked) */
914 ipp_attribute_t
*attr
; /* New attribute */
915 char code
[IPP_MAX_LANGUAGE
];
916 /* Charset/language code buffer */
919 DEBUG_printf(("ippAddString(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
920 "name=\"%s\", language=\"%s\", value=\"%s\")", ipp
,
921 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
925 * Range check input...
928 temp_tag
= (ipp_tag_t
)((int)value_tag
& IPP_TAG_CUPS_MASK
);
931 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
932 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
933 (temp_tag
< IPP_TAG_TEXT
&& temp_tag
!= IPP_TAG_TEXTLANG
&&
934 temp_tag
!= IPP_TAG_NAMELANG
) || temp_tag
> IPP_TAG_MIMETYPE
)
937 if ((temp_tag
== IPP_TAG_TEXTLANG
|| temp_tag
== IPP_TAG_NAMELANG
)
938 != (language
!= NULL
))
941 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
942 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
947 * See if we need to map charset, language, or locale values...
950 if (language
&& ((int)value_tag
& IPP_TAG_CUPS_CONST
) &&
951 strcmp(language
, ipp_lang_code(language
, code
, sizeof(code
))))
952 value_tag
= temp_tag
; /* Don't do a fast copy */
953 else if (value
&& value_tag
== (ipp_tag_t
)(IPP_TAG_CHARSET
| IPP_TAG_CUPS_CONST
) &&
954 strcmp(value
, ipp_get_code(value
, code
, sizeof(code
))))
955 value_tag
= temp_tag
; /* Don't do a fast copy */
956 else if (value
&& value_tag
== (ipp_tag_t
)(IPP_TAG_LANGUAGE
| IPP_TAG_CUPS_CONST
) &&
957 strcmp(value
, ipp_lang_code(value
, code
, sizeof(code
))))
958 value_tag
= temp_tag
; /* Don't do a fast copy */
961 * Create the attribute...
964 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, 1)) == NULL
)
968 * Initialize the attribute data...
971 if ((int)value_tag
& IPP_TAG_CUPS_CONST
)
973 attr
->values
[0].string
.language
= (char *)language
;
974 attr
->values
[0].string
.text
= (char *)value
;
979 attr
->values
[0].string
.language
= _cupsStrAlloc(ipp_lang_code(language
, code
,
984 if (value_tag
== IPP_TAG_CHARSET
)
985 attr
->values
[0].string
.text
= _cupsStrAlloc(ipp_get_code(value
, code
,
987 else if (value_tag
== IPP_TAG_LANGUAGE
)
988 attr
->values
[0].string
.text
= _cupsStrAlloc(ipp_lang_code(value
, code
,
991 attr
->values
[0].string
.text
= _cupsStrAlloc(value
);
1000 * 'ippAddStringf()' - Add a formatted string to an IPP message.
1002 * The @code ipp@ parameter refers to an IPP message previously created using
1003 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
1005 * The @code group@ parameter specifies the IPP attribute group tag: none
1006 * (@code IPP_TAG_ZERO@, for member attributes), document
1007 * (@code IPP_TAG_DOCUMENT@), event notification
1008 * (@code IPP_TAG_EVENT_NOTIFICATION@), operation (@code IPP_TAG_OPERATION@),
1009 * printer (@code IPP_TAG_PRINTER@), subscription (@code IPP_TAG_SUBSCRIPTION@),
1010 * or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1012 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1013 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1014 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1015 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1016 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1017 * (@code IPP_TAG_URISCHEME@).
1019 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage
1020 * and textWithLanguage string values and must be @code NULL@ for all other
1023 * The @code format@ parameter uses formatting characters compatible with the
1024 * printf family of standard functions. Additional arguments follow it as
1025 * needed. The formatted string is truncated as needed to the maximum length of
1026 * the corresponding value type.
1028 * @since CUPS 1.7/OS X 10.9@
1031 ipp_attribute_t
* /* O - New attribute */
1032 ippAddStringf(ipp_t
*ipp
, /* I - IPP message */
1033 ipp_tag_t group
, /* I - IPP group */
1034 ipp_tag_t value_tag
, /* I - Type of attribute */
1035 const char *name
, /* I - Name of attribute */
1036 const char *language
, /* I - Language code (@code NULL@ for default) */
1037 const char *format
, /* I - Printf-style format string */
1038 ...) /* I - Additional arguments as needed */
1040 ipp_attribute_t
*attr
; /* New attribute */
1041 va_list ap
; /* Argument pointer */
1044 va_start(ap
, format
);
1045 attr
= ippAddStringfv(ipp
, group
, value_tag
, name
, language
, format
, ap
);
1053 * 'ippAddStringfv()' - Add a formatted string to an IPP message.
1055 * The @code ipp@ parameter refers to an IPP message previously created using
1056 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
1058 * The @code group@ parameter specifies the IPP attribute group tag: none
1059 * (@code IPP_TAG_ZERO@, for member attributes), document
1060 * (@code IPP_TAG_DOCUMENT@), event notification
1061 * (@code IPP_TAG_EVENT_NOTIFICATION@), operation (@code IPP_TAG_OPERATION@),
1062 * printer (@code IPP_TAG_PRINTER@), subscription (@code IPP_TAG_SUBSCRIPTION@),
1063 * or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1065 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1066 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1067 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1068 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1069 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1070 * (@code IPP_TAG_URISCHEME@).
1072 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage
1073 * and textWithLanguage string values and must be @code NULL@ for all other
1076 * The @code format@ parameter uses formatting characters compatible with the
1077 * printf family of standard functions. Additional arguments are passed in the
1078 * stdarg pointer @code ap@. The formatted string is truncated as needed to the
1079 * maximum length of the corresponding value type.
1081 * @since CUPS 1.7/OS X 10.9@
1084 ipp_attribute_t
* /* O - New attribute */
1085 ippAddStringfv(ipp_t
*ipp
, /* I - IPP message */
1086 ipp_tag_t group
, /* I - IPP group */
1087 ipp_tag_t value_tag
, /* I - Type of attribute */
1088 const char *name
, /* I - Name of attribute */
1089 const char *language
, /* I - Language code (@code NULL@ for default) */
1090 const char *format
, /* I - Printf-style format string */
1091 va_list ap
) /* I - Additional arguments */
1093 char buffer
[IPP_MAX_TEXT
+ 4];
1094 /* Formatted text string */
1095 ssize_t bytes
, /* Length of formatted value */
1096 max_bytes
; /* Maximum number of bytes for value */
1100 * Range check input...
1103 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1104 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1105 (value_tag
< IPP_TAG_TEXT
&& value_tag
!= IPP_TAG_TEXTLANG
&&
1106 value_tag
!= IPP_TAG_NAMELANG
) || value_tag
> IPP_TAG_MIMETYPE
||
1110 if ((value_tag
== IPP_TAG_TEXTLANG
|| value_tag
== IPP_TAG_NAMELANG
)
1111 != (language
!= NULL
))
1115 * Format the string...
1118 if (!strcmp(format
, "%s"))
1121 * Optimize the simple case...
1124 const char *s
= va_arg(ap
, char *);
1129 bytes
= (ssize_t
)strlen(s
);
1130 strlcpy(buffer
, s
, sizeof(buffer
));
1135 * Do a full formatting of the message...
1138 if ((bytes
= vsnprintf(buffer
, sizeof(buffer
), format
, ap
)) < 0)
1143 * Limit the length of the string...
1150 case IPP_TAG_TEXTLANG
:
1151 max_bytes
= IPP_MAX_TEXT
;
1155 case IPP_TAG_NAMELANG
:
1156 max_bytes
= IPP_MAX_NAME
;
1159 case IPP_TAG_CHARSET
:
1160 max_bytes
= IPP_MAX_CHARSET
;
1163 case IPP_TAG_KEYWORD
:
1164 max_bytes
= IPP_MAX_KEYWORD
;
1167 case IPP_TAG_LANGUAGE
:
1168 max_bytes
= IPP_MAX_LANGUAGE
;
1171 case IPP_TAG_MIMETYPE
:
1172 max_bytes
= IPP_MAX_MIMETYPE
;
1176 max_bytes
= IPP_MAX_URI
;
1179 case IPP_TAG_URISCHEME
:
1180 max_bytes
= IPP_MAX_URISCHEME
;
1184 if (bytes
>= max_bytes
)
1186 char *bufmax
, /* Buffer at max_bytes */
1187 *bufptr
; /* Pointer into buffer */
1189 bufptr
= buffer
+ strlen(buffer
) - 1;
1190 bufmax
= buffer
+ max_bytes
- 1;
1192 while (bufptr
> bufmax
)
1196 while ((*bufptr
& 0xc0) == 0x80 && bufptr
> buffer
)
1207 * Add the formatted string and return...
1210 return (ippAddString(ipp
, group
, value_tag
, name
, language
, buffer
));
1215 * 'ippAddStrings()' - Add language-encoded strings to an IPP message.
1217 * The @code ipp@ parameter refers to an IPP message previously created using
1218 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
1220 * The @code group@ parameter specifies the IPP attribute group tag: none
1221 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
1222 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
1223 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
1224 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1226 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1227 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1228 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1229 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1230 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1231 * (@code IPP_TAG_URISCHEME@).
1233 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
1234 * textWithLanguage string values and must be @code NULL@ for all other string values.
1237 ipp_attribute_t
* /* O - New attribute */
1239 ipp_t
*ipp
, /* I - IPP message */
1240 ipp_tag_t group
, /* I - IPP group */
1241 ipp_tag_t value_tag
, /* I - Type of attribute */
1242 const char *name
, /* I - Name of attribute */
1243 int num_values
, /* I - Number of values */
1244 const char *language
, /* I - Language code (@code NULL@ for default) */
1245 const char * const *values
) /* I - Values */
1247 int i
; /* Looping var */
1248 ipp_tag_t temp_tag
; /* Temporary value tag (masked) */
1249 ipp_attribute_t
*attr
; /* New attribute */
1250 _ipp_value_t
*value
; /* Current value */
1251 char code
[32]; /* Language/charset value buffer */
1254 DEBUG_printf(("ippAddStrings(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
1255 "name=\"%s\", num_values=%d, language=\"%s\", values=%p)", ipp
,
1256 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
1257 num_values
, language
, values
));
1260 * Range check input...
1263 temp_tag
= (ipp_tag_t
)((int)value_tag
& IPP_TAG_CUPS_MASK
);
1266 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1267 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1268 (temp_tag
< IPP_TAG_TEXT
&& temp_tag
!= IPP_TAG_TEXTLANG
&&
1269 temp_tag
!= IPP_TAG_NAMELANG
) || temp_tag
> IPP_TAG_MIMETYPE
||
1273 if ((temp_tag
== IPP_TAG_TEXTLANG
|| temp_tag
== IPP_TAG_NAMELANG
)
1274 != (language
!= NULL
))
1277 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1278 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1284 * See if we need to map charset, language, or locale values...
1287 if (language
&& ((int)value_tag
& IPP_TAG_CUPS_CONST
) &&
1288 strcmp(language
, ipp_lang_code(language
, code
, sizeof(code
))))
1289 value_tag
= temp_tag
; /* Don't do a fast copy */
1290 else if (values
&& value_tag
== (ipp_tag_t
)(IPP_TAG_CHARSET
| IPP_TAG_CUPS_CONST
))
1292 for (i
= 0; i
< num_values
; i
++)
1293 if (strcmp(values
[i
], ipp_get_code(values
[i
], code
, sizeof(code
))))
1295 value_tag
= temp_tag
; /* Don't do a fast copy */
1299 else if (values
&& value_tag
== (ipp_tag_t
)(IPP_TAG_LANGUAGE
| IPP_TAG_CUPS_CONST
))
1301 for (i
= 0; i
< num_values
; i
++)
1302 if (strcmp(values
[i
], ipp_lang_code(values
[i
], code
, sizeof(code
))))
1304 value_tag
= temp_tag
; /* Don't do a fast copy */
1310 * Create the attribute...
1313 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, num_values
)) == NULL
)
1317 * Initialize the attribute data...
1320 for (i
= num_values
, value
= attr
->values
;
1326 if (value
== attr
->values
)
1328 if ((int)value_tag
& IPP_TAG_CUPS_CONST
)
1329 value
->string
.language
= (char *)language
;
1331 value
->string
.language
= _cupsStrAlloc(ipp_lang_code(language
, code
,
1335 value
->string
.language
= attr
->values
[0].string
.language
;
1340 if ((int)value_tag
& IPP_TAG_CUPS_CONST
)
1341 value
->string
.text
= (char *)*values
++;
1342 else if (value_tag
== IPP_TAG_CHARSET
)
1343 value
->string
.text
= _cupsStrAlloc(ipp_get_code(*values
++, code
, sizeof(code
)));
1344 else if (value_tag
== IPP_TAG_LANGUAGE
)
1345 value
->string
.text
= _cupsStrAlloc(ipp_lang_code(*values
++, code
, sizeof(code
)));
1347 value
->string
.text
= _cupsStrAlloc(*values
++);
1356 * 'ippContainsInteger()' - Determine whether an attribute contains the
1357 * specified value or is within the list of ranges.
1359 * Returns non-zero when the attribute contains either a matching integer or
1360 * enum value, or the value falls within one of the rangeOfInteger values for
1363 * @since CUPS 1.7/OS X 10.9@
1366 int /* O - 1 on a match, 0 on no match */
1368 ipp_attribute_t
*attr
, /* I - Attribute */
1369 int value
) /* I - Integer/enum value */
1371 int i
; /* Looping var */
1372 _ipp_value_t
*avalue
; /* Current attribute value */
1376 * Range check input...
1382 if (attr
->value_tag
!= IPP_TAG_INTEGER
&& attr
->value_tag
!= IPP_TAG_ENUM
&&
1383 attr
->value_tag
!= IPP_TAG_RANGE
)
1390 if (attr
->value_tag
== IPP_TAG_RANGE
)
1392 for (i
= attr
->num_values
, avalue
= attr
->values
; i
> 0; i
--, avalue
++)
1393 if (value
>= avalue
->range
.lower
&& value
<= avalue
->range
.upper
)
1398 for (i
= attr
->num_values
, avalue
= attr
->values
; i
> 0; i
--, avalue
++)
1399 if (value
== avalue
->integer
)
1408 * 'ippContainsString()' - Determine whether an attribute contains the
1409 * specified string value.
1411 * Returns non-zero when the attribute contains a matching charset, keyword,
1412 * language, mimeMediaType, name, text, URI, or URI scheme value.
1414 * @since CUPS 1.7/OS X 10.9@
1417 int /* O - 1 on a match, 0 on no match */
1419 ipp_attribute_t
*attr
, /* I - Attribute */
1420 const char *value
) /* I - String value */
1422 int i
; /* Looping var */
1423 _ipp_value_t
*avalue
; /* Current attribute value */
1426 DEBUG_printf(("ippContainsString(attr=%p, value=\"%s\")", attr
, value
));
1429 * Range check input...
1432 if (!attr
|| !value
)
1434 DEBUG_puts("1ippContainsString: Returning 0 (bad input)");
1442 DEBUG_printf(("1ippContainsString: attr %s, %s with %d values.",
1443 attr
->name
, ippTagString(attr
->value_tag
),
1446 switch (attr
->value_tag
& IPP_TAG_CUPS_MASK
)
1448 case IPP_TAG_CHARSET
:
1449 case IPP_TAG_KEYWORD
:
1450 case IPP_TAG_LANGUAGE
:
1451 case IPP_TAG_MIMETYPE
:
1453 case IPP_TAG_NAMELANG
:
1455 case IPP_TAG_TEXTLANG
:
1457 case IPP_TAG_URISCHEME
:
1458 for (i
= attr
->num_values
, avalue
= attr
->values
;
1462 DEBUG_printf(("1ippContainsString: value[%d]=\"%s\"",
1463 attr
->num_values
- i
, avalue
->string
.text
));
1465 if (!strcmp(value
, avalue
->string
.text
))
1467 DEBUG_puts("1ippContainsString: Returning 1 (match)");
1476 DEBUG_puts("1ippContainsString: Returning 0 (no match)");
1483 * 'ippCopyAttribute()' - Copy an attribute.
1485 * The specified attribute, @code attr@, is copied to the destination IPP message.
1486 * When @code quickcopy@ is non-zero, a "shallow" reference copy of the attribute is
1487 * created - this should only be done as long as the original source IPP message will
1488 * not be freed for the life of the destination.
1490 * @since CUPS 1.6/OS X 10.8@
1494 ipp_attribute_t
* /* O - New attribute */
1496 ipp_t
*dst
, /* I - Destination IPP message */
1497 ipp_attribute_t
*srcattr
, /* I - Attribute to copy */
1498 int quickcopy
) /* I - 1 for a referenced copy, 0 for normal */
1500 int i
; /* Looping var */
1501 ipp_attribute_t
*dstattr
; /* Destination attribute */
1502 _ipp_value_t
*srcval
, /* Source value */
1503 *dstval
; /* Destination value */
1506 DEBUG_printf(("ippCopyAttribute(dst=%p, srcattr=%p, quickcopy=%d)", dst
, srcattr
,
1510 * Range check input...
1513 if (!dst
|| !srcattr
)
1520 quickcopy
= quickcopy
? IPP_TAG_CUPS_CONST
: 0;
1522 switch (srcattr
->value_tag
& ~IPP_TAG_CUPS_CONST
)
1525 dstattr
= ippAddSeparator(dst
);
1528 case IPP_TAG_INTEGER
:
1530 dstattr
= ippAddIntegers(dst
, srcattr
->group_tag
, srcattr
->value_tag
,
1531 srcattr
->name
, srcattr
->num_values
, NULL
);
1535 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1537 i
--, srcval
++, dstval
++)
1538 dstval
->integer
= srcval
->integer
;
1541 case IPP_TAG_BOOLEAN
:
1542 dstattr
= ippAddBooleans(dst
, srcattr
->group_tag
, srcattr
->name
,
1543 srcattr
->num_values
, NULL
);
1547 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1549 i
--, srcval
++, dstval
++)
1550 dstval
->boolean
= srcval
->boolean
;
1555 case IPP_TAG_KEYWORD
:
1557 case IPP_TAG_URISCHEME
:
1558 case IPP_TAG_CHARSET
:
1559 case IPP_TAG_LANGUAGE
:
1560 case IPP_TAG_MIMETYPE
:
1561 dstattr
= ippAddStrings(dst
, srcattr
->group_tag
,
1562 (ipp_tag_t
)(srcattr
->value_tag
| quickcopy
),
1563 srcattr
->name
, srcattr
->num_values
, NULL
, NULL
);
1569 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1570 dstval
= dstattr
->values
;
1572 i
--, srcval
++, dstval
++)
1573 dstval
->string
.text
= srcval
->string
.text
;
1575 else if (srcattr
->value_tag
& IPP_TAG_CUPS_CONST
)
1577 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1578 dstval
= dstattr
->values
;
1580 i
--, srcval
++, dstval
++)
1581 dstval
->string
.text
= _cupsStrAlloc(srcval
->string
.text
);
1585 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1586 dstval
= dstattr
->values
;
1588 i
--, srcval
++, dstval
++)
1589 dstval
->string
.text
= _cupsStrRetain(srcval
->string
.text
);
1594 if (srcattr
->num_values
!= 1)
1597 dstattr
= ippAddDate(dst
, srcattr
->group_tag
, srcattr
->name
,
1598 srcattr
->values
[0].date
);
1601 case IPP_TAG_RESOLUTION
:
1602 dstattr
= ippAddResolutions(dst
, srcattr
->group_tag
, srcattr
->name
,
1603 srcattr
->num_values
, IPP_RES_PER_INCH
,
1608 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1610 i
--, srcval
++, dstval
++)
1612 dstval
->resolution
.xres
= srcval
->resolution
.xres
;
1613 dstval
->resolution
.yres
= srcval
->resolution
.yres
;
1614 dstval
->resolution
.units
= srcval
->resolution
.units
;
1618 case IPP_TAG_RANGE
:
1619 dstattr
= ippAddRanges(dst
, srcattr
->group_tag
, srcattr
->name
,
1620 srcattr
->num_values
, NULL
, NULL
);
1624 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1626 i
--, srcval
++, dstval
++)
1628 dstval
->range
.lower
= srcval
->range
.lower
;
1629 dstval
->range
.upper
= srcval
->range
.upper
;
1633 case IPP_TAG_TEXTLANG
:
1634 case IPP_TAG_NAMELANG
:
1635 dstattr
= ippAddStrings(dst
, srcattr
->group_tag
,
1636 (ipp_tag_t
)(srcattr
->value_tag
| quickcopy
),
1637 srcattr
->name
, srcattr
->num_values
, NULL
, NULL
);
1643 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1644 dstval
= dstattr
->values
;
1646 i
--, srcval
++, dstval
++)
1648 dstval
->string
.language
= srcval
->string
.language
;
1649 dstval
->string
.text
= srcval
->string
.text
;
1652 else if (srcattr
->value_tag
& IPP_TAG_CUPS_CONST
)
1654 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1655 dstval
= dstattr
->values
;
1657 i
--, srcval
++, dstval
++)
1659 if (srcval
== srcattr
->values
)
1660 dstval
->string
.language
= _cupsStrAlloc(srcval
->string
.language
);
1662 dstval
->string
.language
= dstattr
->values
[0].string
.language
;
1664 dstval
->string
.text
= _cupsStrAlloc(srcval
->string
.text
);
1669 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1670 dstval
= dstattr
->values
;
1672 i
--, srcval
++, dstval
++)
1674 if (srcval
== srcattr
->values
)
1675 dstval
->string
.language
= _cupsStrRetain(srcval
->string
.language
);
1677 dstval
->string
.language
= dstattr
->values
[0].string
.language
;
1679 dstval
->string
.text
= _cupsStrRetain(srcval
->string
.text
);
1684 case IPP_TAG_BEGIN_COLLECTION
:
1685 dstattr
= ippAddCollections(dst
, srcattr
->group_tag
, srcattr
->name
,
1686 srcattr
->num_values
, NULL
);
1690 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1692 i
--, srcval
++, dstval
++)
1694 dstval
->collection
= srcval
->collection
;
1695 srcval
->collection
->use
++;
1699 case IPP_TAG_STRING
:
1701 /* TODO: Implement quick copy for unknown/octetString values */
1702 dstattr
= ippAddIntegers(dst
, srcattr
->group_tag
, srcattr
->value_tag
,
1703 srcattr
->name
, srcattr
->num_values
, NULL
);
1707 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1709 i
--, srcval
++, dstval
++)
1711 dstval
->unknown
.length
= srcval
->unknown
.length
;
1713 if (dstval
->unknown
.length
> 0)
1715 if ((dstval
->unknown
.data
= malloc((size_t)dstval
->unknown
.length
)) == NULL
)
1716 dstval
->unknown
.length
= 0;
1718 memcpy(dstval
->unknown
.data
, srcval
->unknown
.data
, (size_t)dstval
->unknown
.length
);
1721 break; /* anti-compiler-warning-code */
1729 * 'ippCopyAttributes()' - Copy attributes from one IPP message to another.
1731 * Zero or more attributes are copied from the source IPP message, @code@ src, to the
1732 * destination IPP message, @code dst@. When @code quickcopy@ is non-zero, a "shallow"
1733 * reference copy of the attribute is created - this should only be done as long as the
1734 * original source IPP message will not be freed for the life of the destination.
1736 * The @code cb@ and @code context@ parameters provide a generic way to "filter" the
1737 * attributes that are copied - the function must return 1 to copy the attribute or
1738 * 0 to skip it. The function may also choose to do a partial copy of the source attribute
1741 * @since CUPS 1.6/OS X 10.8@
1744 int /* O - 1 on success, 0 on error */
1746 ipp_t
*dst
, /* I - Destination IPP message */
1747 ipp_t
*src
, /* I - Source IPP message */
1748 int quickcopy
, /* I - 1 for a referenced copy, 0 for normal */
1749 ipp_copycb_t cb
, /* I - Copy callback or @code NULL@ for none */
1750 void *context
) /* I - Context pointer */
1752 ipp_attribute_t
*srcattr
; /* Source attribute */
1755 DEBUG_printf(("ippCopyAttributes(dst=%p, src=%p, quickcopy=%d, cb=%p, context=%p)",
1756 dst
, src
, quickcopy
, cb
, context
));
1759 * Range check input...
1766 * Loop through source attributes and copy as needed...
1769 for (srcattr
= src
->attrs
; srcattr
; srcattr
= srcattr
->next
)
1770 if (!cb
|| (*cb
)(context
, dst
, srcattr
))
1771 if (!ippCopyAttribute(dst
, srcattr
, quickcopy
))
1779 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
1783 time_t /* O - UNIX time value */
1784 ippDateToTime(const ipp_uchar_t
*date
) /* I - RFC 1903 date info */
1786 struct tm unixdate
; /* UNIX date/time info */
1787 time_t t
; /* Computed time */
1793 memset(&unixdate
, 0, sizeof(unixdate
));
1796 * RFC-1903 date/time format is:
1798 * Byte(s) Description
1799 * ------- -----------
1800 * 0-1 Year (0 to 65535)
1804 * 5 Minutes (0 to 59)
1805 * 6 Seconds (0 to 60, 60 = "leap second")
1806 * 7 Deciseconds (0 to 9)
1808 * 9 UTC hours (0 to 11)
1809 * 10 UTC minutes (0 to 59)
1812 unixdate
.tm_year
= ((date
[0] << 8) | date
[1]) - 1900;
1813 unixdate
.tm_mon
= date
[2] - 1;
1814 unixdate
.tm_mday
= date
[3];
1815 unixdate
.tm_hour
= date
[4];
1816 unixdate
.tm_min
= date
[5];
1817 unixdate
.tm_sec
= date
[6];
1819 t
= mktime(&unixdate
);
1822 t
+= date
[9] * 3600 + date
[10] * 60;
1824 t
-= date
[9] * 3600 + date
[10] * 60;
1831 * 'ippDelete()' - Delete an IPP message.
1835 ippDelete(ipp_t
*ipp
) /* I - IPP message */
1837 ipp_attribute_t
*attr
, /* Current attribute */
1838 *next
; /* Next attribute */
1841 DEBUG_printf(("ippDelete(ipp=%p)", ipp
));
1850 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= next
)
1854 ipp_free_values(attr
, 0, attr
->num_values
);
1857 _cupsStrFree(attr
->name
);
1867 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
1869 * @since CUPS 1.1.19/OS X 10.3@
1874 ipp_t
*ipp
, /* I - IPP message */
1875 ipp_attribute_t
*attr
) /* I - Attribute to delete */
1877 ipp_attribute_t
*current
, /* Current attribute */
1878 *prev
; /* Previous attribute */
1881 DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p(%s))", ipp
, attr
,
1882 attr
? attr
->name
: "(null)"));
1885 * Range check input...
1892 * Find the attribute in the list...
1897 for (current
= ipp
->attrs
, prev
= NULL
;
1899 prev
= current
, current
= current
->next
)
1900 if (current
== attr
)
1903 * Found it, remove the attribute from the list...
1907 prev
->next
= current
->next
;
1909 ipp
->attrs
= current
->next
;
1911 if (current
== ipp
->last
)
1922 * Free memory used by the attribute...
1925 ipp_free_values(attr
, 0, attr
->num_values
);
1928 _cupsStrFree(attr
->name
);
1935 * 'ippDeleteValues()' - Delete values in an attribute.
1937 * The @code element@ parameter specifies the first value to delete, starting at
1938 * 0. It must be less than the number of values returned by @link ippGetCount@.
1940 * The @code attr@ parameter may be modified as a result of setting the value.
1942 * Deleting all values in an attribute deletes the attribute.
1944 * @since CUPS 1.6/OS X 10.8@
1947 int /* O - 1 on success, 0 on failure */
1949 ipp_t
*ipp
, /* I - IPP message */
1950 ipp_attribute_t
**attr
, /* IO - Attribute */
1951 int element
, /* I - Index of first value to delete (0-based) */
1952 int count
) /* I - Number of values to delete */
1955 * Range check input...
1958 if (!ipp
|| !attr
|| !*attr
||
1959 element
< 0 || element
>= (*attr
)->num_values
|| count
<= 0 ||
1960 (element
+ count
) >= (*attr
)->num_values
)
1964 * If we are deleting all values, just delete the attribute entirely.
1967 if (count
== (*attr
)->num_values
)
1969 ippDeleteAttribute(ipp
, *attr
);
1975 * Otherwise free the values in question and return.
1978 ipp_free_values(*attr
, element
, count
);
1985 * 'ippFindAttribute()' - Find a named attribute in a request.
1987 * Starting with CUPS 2.0, the attribute name can contain a hierarchical list
1988 * of attribute and member names separated by slashes, for example
1989 * "media-col/media-size".
1992 ipp_attribute_t
* /* O - Matching attribute */
1993 ippFindAttribute(ipp_t
*ipp
, /* I - IPP message */
1994 const char *name
, /* I - Name of attribute */
1995 ipp_tag_t type
) /* I - Type of attribute */
1997 DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", ipp
,
1998 name
, type
, ippTagString(type
)));
2004 * Reset the current pointer...
2007 ipp
->current
= NULL
;
2011 * Search for the attribute...
2014 return (ippFindNextAttribute(ipp
, name
, type
));
2019 * 'ippFindNextAttribute()' - Find the next named attribute in a request.
2021 * Starting with CUPS 2.0, the attribute name can contain a hierarchical list
2022 * of attribute and member names separated by slashes, for example
2023 * "media-col/media-size".
2026 ipp_attribute_t
* /* O - Matching attribute */
2027 ippFindNextAttribute(ipp_t
*ipp
, /* I - IPP message */
2028 const char *name
, /* I - Name of attribute */
2029 ipp_tag_t type
) /* I - Type of attribute */
2031 ipp_attribute_t
*attr
, /* Current atttribute */
2032 *childattr
; /* Child attribute */
2033 ipp_tag_t value_tag
; /* Value tag */
2034 char parent
[1024], /* Parent attribute name */
2035 *child
; /* Child attribute name */
2038 DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))",
2039 ipp
, name
, type
, ippTagString(type
)));
2044 DEBUG_printf(("3ippFindNextAttribute: atend=%d", ipp
->atend
));
2049 if (strchr(name
, '/'))
2052 * Search for child attribute...
2055 strlcpy(parent
, name
, sizeof(parent
));
2056 if ((child
= strchr(parent
, '/')) == NULL
)
2058 DEBUG_puts("3ippFindNextAttribute: Attribute name too long.");
2064 if (ipp
->current
&& ipp
->current
->name
&& ipp
->current
->value_tag
== IPP_TAG_BEGIN_COLLECTION
&& !strcmp(parent
, ipp
->current
->name
))
2066 while (ipp
->curindex
< ipp
->current
->num_values
)
2068 if ((childattr
= ippFindNextAttribute(ipp
->current
->values
[ipp
->curindex
].collection
, child
, type
)) != NULL
)
2072 if (ipp
->curindex
< ipp
->current
->num_values
&& ipp
->current
->values
[ipp
->curindex
].collection
)
2073 ipp
->current
->values
[ipp
->curindex
].collection
->current
= NULL
;
2076 ipp
->prev
= ipp
->current
;
2077 ipp
->current
= ipp
->current
->next
;
2090 ipp
->current
= ipp
->attrs
;
2095 attr
= ipp
->current
;
2097 else if (ipp
->current
)
2099 ipp
->prev
= ipp
->current
;
2100 attr
= ipp
->current
->next
;
2108 for (; attr
!= NULL
; ipp
->prev
= attr
, attr
= attr
->next
)
2110 DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", attr
,
2113 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_CUPS_MASK
);
2115 if (attr
->name
!= NULL
&& _cups_strcasecmp(attr
->name
, name
) == 0 &&
2116 (value_tag
== type
|| type
== IPP_TAG_ZERO
|| name
== parent
||
2117 (value_tag
== IPP_TAG_TEXTLANG
&& type
== IPP_TAG_TEXT
) ||
2118 (value_tag
== IPP_TAG_NAMELANG
&& type
== IPP_TAG_NAME
)))
2120 ipp
->current
= attr
;
2122 if (name
== parent
&& attr
->value_tag
== IPP_TAG_BEGIN_COLLECTION
)
2124 int i
; /* Looping var */
2126 for (i
= 0; i
< attr
->num_values
; i
++)
2128 if ((childattr
= ippFindAttribute(attr
->values
[i
].collection
, child
, type
)) != NULL
)
2130 attr
->values
[0].collection
->curindex
= i
;
2140 ipp
->current
= NULL
;
2149 * 'ippFirstAttribute()' - Return the first attribute in the message.
2151 * @since CUPS 1.6/OS X 10.8@
2154 ipp_attribute_t
* /* O - First attribute or @code NULL@ if none */
2155 ippFirstAttribute(ipp_t
*ipp
) /* I - IPP message */
2158 * Range check input...
2165 * Return the first attribute...
2168 return (ipp
->current
= ipp
->attrs
);
2173 * 'ippGetBoolean()' - Get a boolean value for an attribute.
2175 * The @code element@ parameter specifies which value to get from 0 to
2176 * @link ippGetCount(attr)@ - 1.
2178 * @since CUPS 1.6/OS X 10.8@
2181 int /* O - Boolean value or -1 on error */
2182 ippGetBoolean(ipp_attribute_t
*attr
, /* I - IPP attribute */
2183 int element
) /* I - Value number (0-based) */
2186 * Range check input...
2189 if (!attr
|| attr
->value_tag
!= IPP_TAG_BOOLEAN
||
2190 element
< 0 || element
>= attr
->num_values
)
2194 * Return the value...
2197 return (attr
->values
[element
].boolean
);
2202 * 'ippGetCollection()' - Get a collection value for an attribute.
2204 * The @code element@ parameter specifies which value to get from 0 to
2205 * @link ippGetCount(attr)@ - 1.
2207 * @since CUPS 1.6/OS X 10.8@
2210 ipp_t
* /* O - Collection value or @code NULL@ on error */
2212 ipp_attribute_t
*attr
, /* I - IPP attribute */
2213 int element
) /* I - Value number (0-based) */
2216 * Range check input...
2219 if (!attr
|| attr
->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
2220 element
< 0 || element
>= attr
->num_values
)
2224 * Return the value...
2227 return (attr
->values
[element
].collection
);
2232 * 'ippGetCount()' - Get the number of values in an attribute.
2234 * @since CUPS 1.6/OS X 10.8@
2237 int /* O - Number of values or -1 on error */
2238 ippGetCount(ipp_attribute_t
*attr
) /* I - IPP attribute */
2241 * Range check input...
2248 * Return the number of values...
2251 return (attr
->num_values
);
2256 * 'ippGetDate()' - Get a date value for an attribute.
2258 * The @code element@ parameter specifies which value to get from 0 to
2259 * @link ippGetCount(attr)@ - 1.
2261 * @since CUPS 1.6/OS X 10.8@
2264 const ipp_uchar_t
* /* O - Date value or @code NULL@ */
2265 ippGetDate(ipp_attribute_t
*attr
, /* I - IPP attribute */
2266 int element
) /* I - Value number (0-based) */
2269 * Range check input...
2272 if (!attr
|| attr
->value_tag
!= IPP_TAG_DATE
||
2273 element
< 0 || element
>= attr
->num_values
)
2277 * Return the value...
2280 return (attr
->values
[element
].date
);
2285 * 'ippGetGroupTag()' - Get the group associated with an attribute.
2287 * @since CUPS 1.6/OS X 10.8@
2290 ipp_tag_t
/* O - Group tag or @code IPP_TAG_ZERO@ on error */
2291 ippGetGroupTag(ipp_attribute_t
*attr
) /* I - IPP attribute */
2294 * Range check input...
2298 return (IPP_TAG_ZERO
);
2301 * Return the group...
2304 return (attr
->group_tag
);
2309 * 'ippGetInteger()' - Get the integer/enum value for an attribute.
2311 * The @code element@ parameter specifies which value to get from 0 to
2312 * @link ippGetCount(attr)@ - 1.
2314 * @since CUPS 1.6/OS X 10.8@
2317 int /* O - Value or -1 on error */
2318 ippGetInteger(ipp_attribute_t
*attr
, /* I - IPP attribute */
2319 int element
) /* I - Value number (0-based) */
2322 * Range check input...
2325 if (!attr
|| (attr
->value_tag
!= IPP_TAG_INTEGER
&& attr
->value_tag
!= IPP_TAG_ENUM
) ||
2326 element
< 0 || element
>= attr
->num_values
)
2330 * Return the value...
2333 return (attr
->values
[element
].integer
);
2338 * 'ippGetName()' - Get the attribute name.
2340 * @since CUPS 1.6/OS X 10.8@
2343 const char * /* O - Attribute name or @code NULL@ for separators */
2344 ippGetName(ipp_attribute_t
*attr
) /* I - IPP attribute */
2347 * Range check input...
2354 * Return the name...
2357 return (attr
->name
);
2362 * 'ippGetOctetString()' - Get an octetString value from an IPP attribute.
2364 * The @code element@ parameter specifies which value to get from 0 to
2365 * @link ippGetCount(attr)@ - 1.
2367 * @since CUPS 1.7/OS X 10.9@
2370 void * /* O - Pointer to octetString data */
2372 ipp_attribute_t
*attr
, /* I - IPP attribute */
2373 int element
, /* I - Value number (0-based) */
2374 int *datalen
) /* O - Length of octetString data */
2377 * Range check input...
2380 if (!attr
|| attr
->value_tag
!= IPP_TAG_STRING
||
2381 element
< 0 || element
>= attr
->num_values
)
2390 * Return the values...
2394 *datalen
= attr
->values
[element
].unknown
.length
;
2396 return (attr
->values
[element
].unknown
.data
);
2401 * 'ippGetOperation()' - Get the operation ID in an IPP message.
2403 * @since CUPS 1.6/OS X 10.8@
2406 ipp_op_t
/* O - Operation ID or -1 on error */
2407 ippGetOperation(ipp_t
*ipp
) /* I - IPP request message */
2410 * Range check input...
2414 return ((ipp_op_t
)-1);
2417 * Return the value...
2420 return (ipp
->request
.op
.operation_id
);
2425 * 'ippGetRange()' - Get a rangeOfInteger value from an attribute.
2427 * The @code element@ parameter specifies which value to get from 0 to
2428 * @link ippGetCount(attr)@ - 1.
2430 * @since CUPS 1.6/OS X 10.8@
2433 int /* O - Lower value of range or -1 */
2434 ippGetRange(ipp_attribute_t
*attr
, /* I - IPP attribute */
2435 int element
, /* I - Value number (0-based) */
2436 int *uppervalue
)/* O - Upper value of range */
2439 * Range check input...
2442 if (!attr
|| attr
->value_tag
!= IPP_TAG_RANGE
||
2443 element
< 0 || element
>= attr
->num_values
)
2452 * Return the values...
2456 *uppervalue
= attr
->values
[element
].range
.upper
;
2458 return (attr
->values
[element
].range
.lower
);
2463 * 'ippGetRequestId()' - Get the request ID from an IPP message.
2465 * @since CUPS 1.6/OS X 10.8@
2468 int /* O - Request ID or -1 on error */
2469 ippGetRequestId(ipp_t
*ipp
) /* I - IPP message */
2472 * Range check input...
2479 * Return the request ID...
2482 return (ipp
->request
.any
.request_id
);
2487 * 'ippGetResolution()' - Get a resolution value for an attribute.
2489 * The @code element@ parameter specifies which value to get from 0 to
2490 * @link ippGetCount(attr)@ - 1.
2492 * @since CUPS 1.6/OS X 10.8@
2495 int /* O - Horizontal/cross feed resolution or -1 */
2497 ipp_attribute_t
*attr
, /* I - IPP attribute */
2498 int element
, /* I - Value number (0-based) */
2499 int *yres
, /* O - Vertical/feed resolution */
2500 ipp_res_t
*units
) /* O - Units for resolution */
2503 * Range check input...
2506 if (!attr
|| attr
->value_tag
!= IPP_TAG_RESOLUTION
||
2507 element
< 0 || element
>= attr
->num_values
)
2511 * Return the value...
2515 *yres
= attr
->values
[element
].resolution
.yres
;
2518 *units
= attr
->values
[element
].resolution
.units
;
2520 return (attr
->values
[element
].resolution
.xres
);
2525 * 'ippGetState()' - Get the IPP message state.
2527 * @since CUPS 1.6/OS X 10.8@
2530 ipp_state_t
/* O - IPP message state value */
2531 ippGetState(ipp_t
*ipp
) /* I - IPP message */
2534 * Range check input...
2538 return (IPP_STATE_IDLE
);
2541 * Return the value...
2544 return (ipp
->state
);
2549 * 'ippGetStatusCode()' - Get the status code from an IPP response or event message.
2551 * @since CUPS 1.6/OS X 10.8@
2554 ipp_status_t
/* O - Status code in IPP message */
2555 ippGetStatusCode(ipp_t
*ipp
) /* I - IPP response or event message */
2558 * Range check input...
2562 return (IPP_STATUS_ERROR_INTERNAL
);
2565 * Return the value...
2568 return (ipp
->request
.status
.status_code
);
2573 * 'ippGetString()' - Get the string and optionally the language code for an attribute.
2575 * The @code element@ parameter specifies which value to get from 0 to
2576 * @link ippGetCount(attr)@ - 1.
2578 * @since CUPS 1.6/OS X 10.8@
2582 ippGetString(ipp_attribute_t
*attr
, /* I - IPP attribute */
2583 int element
, /* I - Value number (0-based) */
2584 const char **language
)/* O - Language code (@code NULL@ for don't care) */
2587 * Range check input...
2590 if (!attr
|| element
< 0 || element
>= attr
->num_values
||
2591 (attr
->value_tag
!= IPP_TAG_TEXTLANG
&& attr
->value_tag
!= IPP_TAG_NAMELANG
&&
2592 (attr
->value_tag
< IPP_TAG_TEXT
|| attr
->value_tag
> IPP_TAG_MIMETYPE
)))
2596 * Return the value...
2600 *language
= attr
->values
[element
].string
.language
;
2602 return (attr
->values
[element
].string
.text
);
2607 * 'ippGetValueTag()' - Get the value tag for an attribute.
2609 * @since CUPS 1.6/OS X 10.8@
2612 ipp_tag_t
/* O - Value tag or @code IPP_TAG_ZERO@ on error */
2613 ippGetValueTag(ipp_attribute_t
*attr
) /* I - IPP attribute */
2616 * Range check input...
2620 return (IPP_TAG_ZERO
);
2623 * Return the value...
2626 return (attr
->value_tag
& IPP_TAG_CUPS_MASK
);
2631 * 'ippGetVersion()' - Get the major and minor version number from an IPP message.
2633 * @since CUPS 1.6/OS X 10.8@
2636 int /* O - Major version number or -1 on error */
2637 ippGetVersion(ipp_t
*ipp
, /* I - IPP message */
2638 int *minor
) /* O - Minor version number or @code NULL@ */
2641 * Range check input...
2653 * Return the value...
2657 *minor
= ipp
->request
.any
.version
[1];
2659 return (ipp
->request
.any
.version
[0]);
2664 * 'ippLength()' - Compute the length of an IPP message.
2667 size_t /* O - Size of IPP message */
2668 ippLength(ipp_t
*ipp
) /* I - IPP message */
2670 return (ipp_length(ipp
, 0));
2675 * 'ippNextAttribute()' - Return the next attribute in the message.
2677 * @since CUPS 1.6/OS X 10.8@
2680 ipp_attribute_t
* /* O - Next attribute or @code NULL@ if none */
2681 ippNextAttribute(ipp_t
*ipp
) /* I - IPP message */
2684 * Range check input...
2687 if (!ipp
|| !ipp
->current
)
2691 * Return the next attribute...
2694 return (ipp
->current
= ipp
->current
->next
);
2699 * 'ippNew()' - Allocate a new IPP message.
2702 ipp_t
* /* O - New IPP message */
2705 ipp_t
*temp
; /* New IPP message */
2706 _cups_globals_t
*cg
= _cupsGlobals();
2710 DEBUG_puts("ippNew()");
2712 if ((temp
= (ipp_t
*)calloc(1, sizeof(ipp_t
))) != NULL
)
2715 * Set default version - usually 2.0...
2718 if (cg
->server_version
== 0)
2721 temp
->request
.any
.version
[0] = (ipp_uchar_t
)(cg
->server_version
/ 10);
2722 temp
->request
.any
.version
[1] = (ipp_uchar_t
)(cg
->server_version
% 10);
2726 DEBUG_printf(("1ippNew: Returning %p", temp
));
2733 * 'ippNewRequest()' - Allocate a new IPP request message.
2735 * The new request message is initialized with the attributes-charset and
2736 * attributes-natural-language attributes added. The
2737 * attributes-natural-language value is derived from the current locale.
2739 * @since CUPS 1.2/OS X 10.5@
2742 ipp_t
* /* O - IPP request message */
2743 ippNewRequest(ipp_op_t op
) /* I - Operation code */
2745 ipp_t
*request
; /* IPP request message */
2746 cups_lang_t
*language
; /* Current language localization */
2747 static int request_id
= 0; /* Current request ID */
2748 static _cups_mutex_t request_mutex
= _CUPS_MUTEX_INITIALIZER
;
2749 /* Mutex for request ID */
2752 DEBUG_printf(("ippNewRequest(op=%02x(%s))", op
, ippOpString(op
)));
2755 * Create a new IPP message...
2758 if ((request
= ippNew()) == NULL
)
2762 * Set the operation and request ID...
2765 _cupsMutexLock(&request_mutex
);
2767 request
->request
.op
.operation_id
= op
;
2768 request
->request
.op
.request_id
= ++request_id
;
2770 _cupsMutexUnlock(&request_mutex
);
2773 * Use UTF-8 as the character set...
2776 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2777 "attributes-charset", NULL
, "utf-8");
2780 * Get the language from the current locale...
2783 language
= cupsLangDefault();
2785 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2786 "attributes-natural-language", NULL
, language
->language
);
2789 * Return the new request...
2797 * 'ippNewResponse()' - Allocate a new IPP response message.
2799 * The new response message is initialized with the same version-number,
2800 * request-id, attributes-charset, and attributes-natural-language as the
2801 * provided request message. If the attributes-charset or
2802 * attributes-natural-language attributes are missing from the request,
2803 * "utf-8" and a value derived from the current locale are substituted,
2806 * @since CUPS 1.7/OS X 10.9@
2809 ipp_t
* /* O - IPP response message */
2810 ippNewResponse(ipp_t
*request
) /* I - IPP request message */
2812 ipp_t
*response
; /* IPP response message */
2813 ipp_attribute_t
*attr
; /* Current attribute */
2817 * Range check input...
2824 * Create a new IPP message...
2827 if ((response
= ippNew()) == NULL
)
2831 * Copy the request values over to the response...
2834 response
->request
.status
.version
[0] = request
->request
.op
.version
[0];
2835 response
->request
.status
.version
[1] = request
->request
.op
.version
[1];
2836 response
->request
.status
.request_id
= request
->request
.op
.request_id
;
2839 * The first attribute MUST be attributes-charset...
2842 attr
= request
->attrs
;
2844 if (attr
&& attr
->name
&& !strcmp(attr
->name
, "attributes-charset") &&
2845 attr
->group_tag
== IPP_TAG_OPERATION
&&
2846 attr
->value_tag
== IPP_TAG_CHARSET
&&
2847 attr
->num_values
== 1)
2850 * Copy charset from request...
2853 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2854 "attributes-charset", NULL
, attr
->values
[0].string
.text
);
2859 * Use "utf-8" as the default...
2862 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2863 "attributes-charset", NULL
, "utf-8");
2867 * Then attributes-natural-language...
2873 if (attr
&& attr
->name
&&
2874 !strcmp(attr
->name
, "attributes-natural-language") &&
2875 attr
->group_tag
== IPP_TAG_OPERATION
&&
2876 attr
->value_tag
== IPP_TAG_LANGUAGE
&&
2877 attr
->num_values
== 1)
2880 * Copy language from request...
2883 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2884 "attributes-natural-language", NULL
,
2885 attr
->values
[0].string
.text
);
2890 * Use the language from the current locale...
2893 cups_lang_t
*language
= cupsLangDefault();
2894 /* Current locale */
2896 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2897 "attributes-natural-language", NULL
, language
->language
);
2905 * 'ippRead()' - Read data for an IPP message from a HTTP connection.
2908 ipp_state_t
/* O - Current state */
2909 ippRead(http_t
*http
, /* I - HTTP connection */
2910 ipp_t
*ipp
) /* I - IPP data */
2912 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT
,
2913 http
, ipp
, CUPS_LLCAST (http
? http
->data_remaining
: -1)));
2916 return (IPP_STATE_ERROR
);
2918 DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http
->state
,
2921 return (ippReadIO(http
, (ipp_iocb_t
)ipp_read_http
, http
->blocking
, NULL
,
2927 * 'ippReadFile()' - Read data for an IPP message from a file.
2929 * @since CUPS 1.1.19/OS X 10.3@
2932 ipp_state_t
/* O - Current state */
2933 ippReadFile(int fd
, /* I - HTTP data */
2934 ipp_t
*ipp
) /* I - IPP data */
2936 DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd
, ipp
));
2938 return (ippReadIO(&fd
, (ipp_iocb_t
)ipp_read_file
, 1, NULL
, ipp
));
2943 * 'ippReadIO()' - Read data for an IPP message.
2945 * @since CUPS 1.2/OS X 10.5@
2948 ipp_state_t
/* O - Current state */
2949 ippReadIO(void *src
, /* I - Data source */
2950 ipp_iocb_t cb
, /* I - Read callback function */
2951 int blocking
, /* I - Use blocking IO? */
2952 ipp_t
*parent
, /* I - Parent request, if any */
2953 ipp_t
*ipp
) /* I - IPP data */
2955 int n
; /* Length of data */
2956 unsigned char *buffer
, /* Data buffer */
2957 string
[IPP_MAX_TEXT
],
2958 /* Small string buffer */
2959 *bufptr
; /* Pointer into buffer */
2960 ipp_attribute_t
*attr
; /* Current attribute */
2961 ipp_tag_t tag
; /* Current tag */
2962 ipp_tag_t value_tag
; /* Current value tag */
2963 _ipp_value_t
*value
; /* Current value */
2966 DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
2967 src
, cb
, blocking
, parent
, ipp
));
2968 DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp
? ipp
->state
: IPP_STATE_ERROR
));
2971 return (IPP_STATE_ERROR
);
2973 if ((buffer
= (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE
)) == NULL
)
2975 DEBUG_puts("1ippReadIO: Unable to get read buffer.");
2976 return (IPP_STATE_ERROR
);
2981 case IPP_STATE_IDLE
:
2982 ipp
->state
++; /* Avoid common problem... */
2984 case IPP_STATE_HEADER
:
2988 * Get the request header...
2991 if ((*cb
)(src
, buffer
, 8) < 8)
2993 DEBUG_puts("1ippReadIO: Unable to read header.");
2994 _cupsBufferRelease((char *)buffer
);
2995 return (IPP_STATE_ERROR
);
2999 * Then copy the request header over...
3002 ipp
->request
.any
.version
[0] = buffer
[0];
3003 ipp
->request
.any
.version
[1] = buffer
[1];
3004 ipp
->request
.any
.op_status
= (buffer
[2] << 8) | buffer
[3];
3005 ipp
->request
.any
.request_id
= (((((buffer
[4] << 8) | buffer
[5]) << 8) |
3006 buffer
[6]) << 8) | buffer
[7];
3008 DEBUG_printf(("2ippReadIO: version=%d.%d", buffer
[0], buffer
[1]));
3009 DEBUG_printf(("2ippReadIO: op_status=%04x",
3010 ipp
->request
.any
.op_status
));
3011 DEBUG_printf(("2ippReadIO: request_id=%d",
3012 ipp
->request
.any
.request_id
));
3015 ipp
->state
= IPP_STATE_ATTRIBUTE
;
3016 ipp
->current
= NULL
;
3017 ipp
->curtag
= IPP_TAG_ZERO
;
3018 ipp
->prev
= ipp
->last
;
3021 * If blocking is disabled, stop here...
3027 case IPP_STATE_ATTRIBUTE
:
3030 if ((*cb
)(src
, buffer
, 1) < 1)
3032 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
3033 _cupsBufferRelease((char *)buffer
);
3034 return (IPP_STATE_ERROR
);
3037 DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p",
3038 ipp
->current
, ipp
->prev
));
3041 * Read this attribute...
3044 tag
= (ipp_tag_t
)buffer
[0];
3045 if (tag
== IPP_TAG_EXTENSION
)
3048 * Read 32-bit "extension" tag...
3051 if ((*cb
)(src
, buffer
, 4) < 1)
3053 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
3054 _cupsBufferRelease((char *)buffer
);
3055 return (IPP_STATE_ERROR
);
3058 tag
= (ipp_tag_t
)((((((buffer
[0] << 8) | buffer
[1]) << 8) |
3059 buffer
[2]) << 8) | buffer
[3]);
3061 if (tag
& IPP_TAG_CUPS_CONST
)
3064 * Fail if the high bit is set in the tag...
3067 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
3068 DEBUG_printf(("1ippReadIO: bad tag 0x%x.", tag
));
3069 _cupsBufferRelease((char *)buffer
);
3070 return (IPP_STATE_ERROR
);
3074 if (tag
== IPP_TAG_END
)
3077 * No more attributes left...
3080 DEBUG_puts("2ippReadIO: IPP_TAG_END.");
3082 ipp
->state
= IPP_STATE_DATA
;
3085 else if (tag
< IPP_TAG_UNSUPPORTED_VALUE
)
3088 * Group tag... Set the current group and continue...
3091 if (ipp
->curtag
== tag
)
3092 ipp
->prev
= ippAddSeparator(ipp
);
3093 else if (ipp
->current
)
3094 ipp
->prev
= ipp
->current
;
3097 ipp
->current
= NULL
;
3098 DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag
,
3099 ippTagString(tag
), ipp
->prev
));
3103 DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag
,
3104 ippTagString(tag
)));
3110 if ((*cb
)(src
, buffer
, 2) < 2)
3112 DEBUG_puts("1ippReadIO: unable to read name length.");
3113 _cupsBufferRelease((char *)buffer
);
3114 return (IPP_STATE_ERROR
);
3117 n
= (buffer
[0] << 8) | buffer
[1];
3119 if (n
>= IPP_BUF_SIZE
)
3121 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP name larger than 32767 bytes."), 1);
3122 DEBUG_printf(("1ippReadIO: bad name length %d.", n
));
3123 _cupsBufferRelease((char *)buffer
);
3124 return (IPP_STATE_ERROR
);
3127 DEBUG_printf(("2ippReadIO: name length=%d", n
));
3129 if (n
== 0 && tag
!= IPP_TAG_MEMBERNAME
&&
3130 tag
!= IPP_TAG_END_COLLECTION
)
3133 * More values for current attribute...
3136 if (ipp
->current
== NULL
)
3138 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP attribute has no name."), 1);
3139 DEBUG_puts("1ippReadIO: Attribute without name and no current.");
3140 _cupsBufferRelease((char *)buffer
);
3141 return (IPP_STATE_ERROR
);
3144 attr
= ipp
->current
;
3145 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_CUPS_MASK
);
3148 * Make sure we aren't adding a new value of a different
3152 if (value_tag
== IPP_TAG_ZERO
)
3155 * Setting the value of a collection member...
3158 attr
->value_tag
= tag
;
3160 else if (value_tag
== IPP_TAG_TEXTLANG
||
3161 value_tag
== IPP_TAG_NAMELANG
||
3162 (value_tag
>= IPP_TAG_TEXT
&&
3163 value_tag
<= IPP_TAG_MIMETYPE
))
3166 * String values can sometimes come across in different
3167 * forms; accept sets of differing values...
3170 if (tag
!= IPP_TAG_TEXTLANG
&& tag
!= IPP_TAG_NAMELANG
&&
3171 (tag
< IPP_TAG_TEXT
|| tag
> IPP_TAG_MIMETYPE
) &&
3172 tag
!= IPP_TAG_NOVALUE
)
3174 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3175 _("IPP 1setOf attribute with incompatible value "
3177 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3178 value_tag
, ippTagString(value_tag
), tag
,
3179 ippTagString(tag
)));
3180 _cupsBufferRelease((char *)buffer
);
3181 return (IPP_STATE_ERROR
);
3184 if (value_tag
!= tag
)
3186 DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.",
3187 attr
->name
, ippTagString(value_tag
), ippTagString(tag
)));
3188 ippSetValueTag(ipp
, &attr
, tag
);
3191 else if (value_tag
== IPP_TAG_INTEGER
||
3192 value_tag
== IPP_TAG_RANGE
)
3195 * Integer and rangeOfInteger values can sometimes be mixed; accept
3196 * sets of differing values...
3199 if (tag
!= IPP_TAG_INTEGER
&& tag
!= IPP_TAG_RANGE
)
3201 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3202 _("IPP 1setOf attribute with incompatible value "
3204 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3205 value_tag
, ippTagString(value_tag
), tag
,
3206 ippTagString(tag
)));
3207 _cupsBufferRelease((char *)buffer
);
3208 return (IPP_STATE_ERROR
);
3211 if (value_tag
== IPP_TAG_INTEGER
&& tag
== IPP_TAG_RANGE
)
3214 * Convert integer values to rangeOfInteger values...
3217 DEBUG_printf(("1ippReadIO: Converting %s attribute to "
3218 "rangeOfInteger.", attr
->name
));
3219 ippSetValueTag(ipp
, &attr
, IPP_TAG_RANGE
);
3222 else if (value_tag
!= tag
)
3224 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3225 _("IPP 1setOf attribute with incompatible value "
3227 DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
3228 value_tag
, ippTagString(value_tag
), tag
,
3229 ippTagString(tag
)));
3230 _cupsBufferRelease((char *)buffer
);
3231 return (IPP_STATE_ERROR
);
3235 * Finally, reallocate the attribute array as needed...
3238 if ((value
= ipp_set_value(ipp
, &attr
, attr
->num_values
)) == NULL
)
3240 _cupsBufferRelease((char *)buffer
);
3241 return (IPP_STATE_ERROR
);
3244 else if (tag
== IPP_TAG_MEMBERNAME
)
3247 * Name must be length 0!
3252 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP member name is not empty."), 1);
3253 DEBUG_puts("1ippReadIO: member name not empty.");
3254 _cupsBufferRelease((char *)buffer
);
3255 return (IPP_STATE_ERROR
);
3259 ipp
->prev
= ipp
->current
;
3261 attr
= ipp
->current
= ipp_add_attr(ipp
, NULL
, ipp
->curtag
, IPP_TAG_ZERO
, 1);
3264 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
3265 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3266 _cupsBufferRelease((char *)buffer
);
3267 return (IPP_STATE_ERROR
);
3270 DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p",
3271 ipp
->current
, ipp
->prev
));
3273 value
= attr
->values
;
3275 else if (tag
!= IPP_TAG_END_COLLECTION
)
3278 * New attribute; read the name and add it...
3281 if ((*cb
)(src
, buffer
, (size_t)n
) < n
)
3283 DEBUG_puts("1ippReadIO: unable to read name.");
3284 _cupsBufferRelease((char *)buffer
);
3285 return (IPP_STATE_ERROR
);
3291 ipp
->prev
= ipp
->current
;
3293 if ((attr
= ipp
->current
= ipp_add_attr(ipp
, (char *)buffer
, ipp
->curtag
, tag
,
3296 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
3297 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3298 _cupsBufferRelease((char *)buffer
);
3299 return (IPP_STATE_ERROR
);
3302 DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, "
3303 "ipp->prev=%p", buffer
, ipp
->current
, ipp
->prev
));
3305 value
= attr
->values
;
3313 if ((*cb
)(src
, buffer
, 2) < 2)
3315 DEBUG_puts("1ippReadIO: unable to read value length.");
3316 _cupsBufferRelease((char *)buffer
);
3317 return (IPP_STATE_ERROR
);
3320 n
= (buffer
[0] << 8) | buffer
[1];
3321 DEBUG_printf(("2ippReadIO: value length=%d", n
));
3323 if (n
>= IPP_BUF_SIZE
)
3325 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3326 _("IPP value larger than 32767 bytes."), 1);
3327 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
3328 _cupsBufferRelease((char *)buffer
);
3329 return (IPP_STATE_ERROR
);
3334 case IPP_TAG_INTEGER
:
3338 if (tag
== IPP_TAG_INTEGER
)
3339 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3340 _("IPP integer value not 4 bytes."), 1);
3342 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3343 _("IPP enum value not 4 bytes."), 1);
3344 DEBUG_printf(("1ippReadIO: bad integer value length %d.", n
));
3345 _cupsBufferRelease((char *)buffer
);
3346 return (IPP_STATE_ERROR
);
3349 if ((*cb
)(src
, buffer
, 4) < 4)
3351 DEBUG_puts("1ippReadIO: Unable to read integer value.");
3352 _cupsBufferRelease((char *)buffer
);
3353 return (IPP_STATE_ERROR
);
3356 n
= (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
3359 if (attr
->value_tag
== IPP_TAG_RANGE
)
3360 value
->range
.lower
= value
->range
.upper
= n
;
3365 case IPP_TAG_BOOLEAN
:
3368 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP boolean value not 1 byte."),
3370 DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n
));
3371 _cupsBufferRelease((char *)buffer
);
3372 return (IPP_STATE_ERROR
);
3375 if ((*cb
)(src
, buffer
, 1) < 1)
3377 DEBUG_puts("1ippReadIO: Unable to read boolean value.");
3378 _cupsBufferRelease((char *)buffer
);
3379 return (IPP_STATE_ERROR
);
3382 value
->boolean
= (char)buffer
[0];
3385 case IPP_TAG_NOVALUE
:
3386 case IPP_TAG_NOTSETTABLE
:
3387 case IPP_TAG_DELETEATTR
:
3388 case IPP_TAG_ADMINDEFINE
:
3390 * These value types are not supposed to have values, however
3391 * some vendors (Brother) do not implement IPP correctly and so
3392 * we need to map non-empty values to text...
3395 if (attr
->value_tag
== tag
)
3400 attr
->value_tag
= IPP_TAG_TEXT
;
3405 case IPP_TAG_KEYWORD
:
3407 case IPP_TAG_URISCHEME
:
3408 case IPP_TAG_CHARSET
:
3409 case IPP_TAG_LANGUAGE
:
3410 case IPP_TAG_MIMETYPE
:
3413 if ((*cb
)(src
, buffer
, (size_t)n
) < n
)
3415 DEBUG_puts("1ippReadIO: unable to read string value.");
3416 _cupsBufferRelease((char *)buffer
);
3417 return (IPP_STATE_ERROR
);
3422 value
->string
.text
= _cupsStrAlloc((char *)buffer
);
3423 DEBUG_printf(("2ippReadIO: value=\"%s\"", value
->string
.text
));
3429 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP date value not 11 bytes."), 1);
3430 DEBUG_printf(("1ippReadIO: bad date value length %d.", n
));
3431 _cupsBufferRelease((char *)buffer
);
3432 return (IPP_STATE_ERROR
);
3435 if ((*cb
)(src
, value
->date
, 11) < 11)
3437 DEBUG_puts("1ippReadIO: Unable to read date value.");
3438 _cupsBufferRelease((char *)buffer
);
3439 return (IPP_STATE_ERROR
);
3443 case IPP_TAG_RESOLUTION
:
3446 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3447 _("IPP resolution value not 9 bytes."), 1);
3448 DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n
));
3449 _cupsBufferRelease((char *)buffer
);
3450 return (IPP_STATE_ERROR
);
3453 if ((*cb
)(src
, buffer
, 9) < 9)
3455 DEBUG_puts("1ippReadIO: Unable to read resolution value.");
3456 _cupsBufferRelease((char *)buffer
);
3457 return (IPP_STATE_ERROR
);
3460 value
->resolution
.xres
=
3461 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
3463 value
->resolution
.yres
=
3464 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
3466 value
->resolution
.units
=
3467 (ipp_res_t
)buffer
[8];
3470 case IPP_TAG_RANGE
:
3473 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3474 _("IPP rangeOfInteger value not 8 bytes."), 1);
3475 DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length "
3477 _cupsBufferRelease((char *)buffer
);
3478 return (IPP_STATE_ERROR
);
3481 if ((*cb
)(src
, buffer
, 8) < 8)
3483 DEBUG_puts("1ippReadIO: Unable to read range value.");
3484 _cupsBufferRelease((char *)buffer
);
3485 return (IPP_STATE_ERROR
);
3488 value
->range
.lower
=
3489 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
3491 value
->range
.upper
=
3492 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
3496 case IPP_TAG_TEXTLANG
:
3497 case IPP_TAG_NAMELANG
:
3500 if (tag
== IPP_TAG_TEXTLANG
)
3501 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3502 _("IPP textWithLanguage value less than "
3503 "minimum 4 bytes."), 1);
3505 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3506 _("IPP nameWithLanguage value less than "
3507 "minimum 4 bytes."), 1);
3508 DEBUG_printf(("1ippReadIO: bad stringWithLanguage value "
3510 _cupsBufferRelease((char *)buffer
);
3511 return (IPP_STATE_ERROR
);
3514 if ((*cb
)(src
, buffer
, (size_t)n
) < n
)
3516 DEBUG_puts("1ippReadIO: Unable to read string w/language "
3518 _cupsBufferRelease((char *)buffer
);
3519 return (IPP_STATE_ERROR
);
3525 * text-with-language and name-with-language are composite
3534 n
= (bufptr
[0] << 8) | bufptr
[1];
3536 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
) || n
>= (int)sizeof(string
))
3538 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3539 _("IPP language length overflows value."), 1);
3540 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3542 _cupsBufferRelease((char *)buffer
);
3543 return (IPP_STATE_ERROR
);
3545 else if (n
>= IPP_MAX_LANGUAGE
)
3547 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3548 _("IPP language length too large."), 1);
3549 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3551 _cupsBufferRelease((char *)buffer
);
3552 return (IPP_STATE_ERROR
);
3555 memcpy(string
, bufptr
+ 2, (size_t)n
);
3558 value
->string
.language
= _cupsStrAlloc((char *)string
);
3561 n
= (bufptr
[0] << 8) | bufptr
[1];
3563 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
))
3565 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3566 _("IPP string length overflows value."), 1);
3567 DEBUG_printf(("1ippReadIO: bad string value length %d.", n
));
3568 _cupsBufferRelease((char *)buffer
);
3569 return (IPP_STATE_ERROR
);
3572 bufptr
[2 + n
] = '\0';
3573 value
->string
.text
= _cupsStrAlloc((char *)bufptr
+ 2);
3576 case IPP_TAG_BEGIN_COLLECTION
:
3578 * Oh, boy, here comes a collection value, so read it...
3581 value
->collection
= ippNew();
3585 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3586 _("IPP begCollection value not 0 bytes."), 1);
3587 DEBUG_puts("1ippReadIO: begCollection tag with value length "
3589 _cupsBufferRelease((char *)buffer
);
3590 return (IPP_STATE_ERROR
);
3593 if (ippReadIO(src
, cb
, 1, ipp
, value
->collection
) == IPP_STATE_ERROR
)
3595 DEBUG_puts("1ippReadIO: Unable to read collection value.");
3596 _cupsBufferRelease((char *)buffer
);
3597 return (IPP_STATE_ERROR
);
3601 case IPP_TAG_END_COLLECTION
:
3602 _cupsBufferRelease((char *)buffer
);
3606 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3607 _("IPP endCollection value not 0 bytes."), 1);
3608 DEBUG_puts("1ippReadIO: endCollection tag with value length "
3610 return (IPP_STATE_ERROR
);
3613 DEBUG_puts("1ippReadIO: endCollection tag...");
3614 return (ipp
->state
= IPP_STATE_DATA
);
3616 case IPP_TAG_MEMBERNAME
:
3618 * The value the name of the member in the collection, which
3619 * we need to carry over...
3624 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3625 _("IPP memberName with no attribute."), 1);
3626 DEBUG_puts("1ippReadIO: Member name without attribute.");
3627 _cupsBufferRelease((char *)buffer
);
3628 return (IPP_STATE_ERROR
);
3632 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3633 _("IPP memberName value is empty."), 1);
3634 DEBUG_puts("1ippReadIO: Empty member name value.");
3635 _cupsBufferRelease((char *)buffer
);
3636 return (IPP_STATE_ERROR
);
3638 else if ((*cb
)(src
, buffer
, (size_t)n
) < n
)
3640 DEBUG_puts("1ippReadIO: Unable to read member name value.");
3641 _cupsBufferRelease((char *)buffer
);
3642 return (IPP_STATE_ERROR
);
3646 attr
->name
= _cupsStrAlloc((char *)buffer
);
3649 * Since collection members are encoded differently than
3650 * regular attributes, make sure we don't start with an
3654 attr
->num_values
--;
3656 DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr
->name
));
3659 default : /* Other unsupported values */
3660 if (tag
== IPP_TAG_STRING
&& n
> IPP_MAX_LENGTH
)
3662 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3663 _("IPP octetString length too large."), 1);
3664 DEBUG_printf(("1ippReadIO: bad octetString value length %d.",
3666 _cupsBufferRelease((char *)buffer
);
3667 return (IPP_STATE_ERROR
);
3670 value
->unknown
.length
= n
;
3674 if ((value
->unknown
.data
= malloc((size_t)n
)) == NULL
)
3676 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
3677 DEBUG_puts("1ippReadIO: Unable to allocate value");
3678 _cupsBufferRelease((char *)buffer
);
3679 return (IPP_STATE_ERROR
);
3682 if ((*cb
)(src
, value
->unknown
.data
, (size_t)n
) < n
)
3684 DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
3685 _cupsBufferRelease((char *)buffer
);
3686 return (IPP_STATE_ERROR
);
3690 value
->unknown
.data
= NULL
;
3695 * If blocking is disabled, stop here...
3703 case IPP_STATE_DATA
:
3707 break; /* anti-compiler-warning-code */
3710 DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp
->state
));
3711 _cupsBufferRelease((char *)buffer
);
3713 return (ipp
->state
);
3718 * 'ippSetBoolean()' - Set a boolean value in an attribute.
3720 * The @code ipp@ parameter refers to an IPP message previously created using
3721 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3723 * The @code attr@ parameter may be modified as a result of setting the value.
3725 * The @code element@ parameter specifies which value to set from 0 to
3726 * @link ippGetCount(attr)@.
3728 * @since CUPS 1.6/OS X 10.8@
3731 int /* O - 1 on success, 0 on failure */
3732 ippSetBoolean(ipp_t
*ipp
, /* I - IPP message */
3733 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3734 int element
, /* I - Value number (0-based) */
3735 int boolvalue
)/* I - Boolean value */
3737 _ipp_value_t
*value
; /* Current value */
3741 * Range check input...
3744 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BOOLEAN
||
3745 element
< 0 || element
> (*attr
)->num_values
)
3749 * Set the value and return...
3752 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3753 value
->boolean
= (char)boolvalue
;
3755 return (value
!= NULL
);
3760 * 'ippSetCollection()' - Set a collection value in an attribute.
3762 * The @code ipp@ parameter refers to an IPP message previously created using
3763 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3765 * The @code attr@ parameter may be modified as a result of setting the value.
3767 * The @code element@ parameter specifies which value to set from 0 to
3768 * @link ippGetCount(attr)@.
3770 * @since CUPS 1.6/OS X 10.8@
3773 int /* O - 1 on success, 0 on failure */
3775 ipp_t
*ipp
, /* I - IPP message */
3776 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3777 int element
, /* I - Value number (0-based) */
3778 ipp_t
*colvalue
) /* I - Collection value */
3780 _ipp_value_t
*value
; /* Current value */
3784 * Range check input...
3787 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
3788 element
< 0 || element
> (*attr
)->num_values
|| !colvalue
)
3792 * Set the value and return...
3795 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3797 if (value
->collection
)
3798 ippDelete(value
->collection
);
3800 value
->collection
= colvalue
;
3804 return (value
!= NULL
);
3809 * 'ippSetDate()' - Set a date value in an attribute.
3811 * The @code ipp@ parameter refers to an IPP message previously created using
3812 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3814 * The @code attr@ parameter may be modified as a result of setting the value.
3816 * The @code element@ parameter specifies which value to set from 0 to
3817 * @link ippGetCount(attr)@.
3819 * @since CUPS 1.6/OS X 10.8@
3822 int /* O - 1 on success, 0 on failure */
3823 ippSetDate(ipp_t
*ipp
, /* I - IPP message */
3824 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3825 int element
, /* I - Value number (0-based) */
3826 const ipp_uchar_t
*datevalue
)/* I - Date value */
3828 _ipp_value_t
*value
; /* Current value */
3832 * Range check input...
3835 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_DATE
||
3836 element
< 0 || element
> (*attr
)->num_values
|| !datevalue
)
3840 * Set the value and return...
3843 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3844 memcpy(value
->date
, datevalue
, sizeof(value
->date
));
3846 return (value
!= NULL
);
3851 * 'ippSetGroupTag()' - Set the group tag of an attribute.
3853 * The @code ipp@ parameter refers to an IPP message previously created using
3854 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3856 * The @code attr@ parameter may be modified as a result of setting the value.
3858 * The @code group@ parameter specifies the IPP attribute group tag: none
3859 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
3860 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
3861 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
3862 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
3864 * @since CUPS 1.6/OS X 10.8@
3867 int /* O - 1 on success, 0 on failure */
3869 ipp_t
*ipp
, /* I - IPP message */
3870 ipp_attribute_t
**attr
, /* IO - Attribute */
3871 ipp_tag_t group_tag
) /* I - Group tag */
3874 * Range check input - group tag must be 0x01 to 0x0F, per RFC 2911...
3877 if (!ipp
|| !attr
|| !*attr
||
3878 group_tag
< IPP_TAG_ZERO
|| group_tag
== IPP_TAG_END
||
3879 group_tag
>= IPP_TAG_UNSUPPORTED_VALUE
)
3883 * Set the group tag and return...
3886 (*attr
)->group_tag
= group_tag
;
3893 * 'ippSetInteger()' - Set an integer or enum value in an attribute.
3895 * The @code ipp@ parameter refers to an IPP message previously created using
3896 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3898 * The @code attr@ parameter may be modified as a result of setting the value.
3900 * The @code element@ parameter specifies which value to set from 0 to
3901 * @link ippGetCount(attr)@.
3903 * @since CUPS 1.6/OS X 10.8@
3906 int /* O - 1 on success, 0 on failure */
3907 ippSetInteger(ipp_t
*ipp
, /* I - IPP message */
3908 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3909 int element
, /* I - Value number (0-based) */
3910 int intvalue
) /* I - Integer/enum value */
3912 _ipp_value_t
*value
; /* Current value */
3916 * Range check input...
3919 if (!ipp
|| !attr
|| !*attr
||
3920 ((*attr
)->value_tag
!= IPP_TAG_INTEGER
&& (*attr
)->value_tag
!= IPP_TAG_ENUM
) ||
3921 element
< 0 || element
> (*attr
)->num_values
)
3925 * Set the value and return...
3928 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3929 value
->integer
= intvalue
;
3931 return (value
!= NULL
);
3936 * 'ippSetName()' - Set the name of an attribute.
3938 * The @code ipp@ parameter refers to an IPP message previously created using
3939 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3941 * The @code attr@ parameter may be modified as a result of setting the value.
3943 * @since CUPS 1.6/OS X 10.8@
3946 int /* O - 1 on success, 0 on failure */
3947 ippSetName(ipp_t
*ipp
, /* I - IPP message */
3948 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3949 const char *name
) /* I - Attribute name */
3951 char *temp
; /* Temporary name value */
3955 * Range check input...
3958 if (!ipp
|| !attr
|| !*attr
)
3962 * Set the value and return...
3965 if ((temp
= _cupsStrAlloc(name
)) != NULL
)
3968 _cupsStrFree((*attr
)->name
);
3970 (*attr
)->name
= temp
;
3973 return (temp
!= NULL
);
3978 * 'ippSetOctetString()' - Set an octetString value in an IPP attribute.
3980 * The @code ipp@ parameter refers to an IPP message previously created using
3981 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3983 * The @code attr@ parameter may be modified as a result of setting the value.
3985 * The @code element@ parameter specifies which value to set from 0 to
3986 * @link ippGetCount(attr)@.
3988 * @since CUPS 1.7/OS X 10.9@
3991 int /* O - 1 on success, 0 on failure */
3993 ipp_t
*ipp
, /* I - IPP message */
3994 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3995 int element
, /* I - Value number (0-based) */
3996 const void *data
, /* I - Pointer to octetString data */
3997 int datalen
) /* I - Length of octetString data */
3999 _ipp_value_t
*value
; /* Current value */
4003 * Range check input...
4006 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_STRING
||
4007 element
< 0 || element
> (*attr
)->num_values
||
4008 datalen
< 0 || datalen
> IPP_MAX_LENGTH
)
4012 * Set the value and return...
4015 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4017 if ((int)((*attr
)->value_tag
) & IPP_TAG_CUPS_CONST
)
4020 * Just copy the pointer...
4023 value
->unknown
.data
= (void *)data
;
4024 value
->unknown
.length
= datalen
;
4032 if (value
->unknown
.data
)
4035 * Free previous data...
4038 free(value
->unknown
.data
);
4040 value
->unknown
.data
= NULL
;
4041 value
->unknown
.length
= 0;
4046 void *temp
; /* Temporary data pointer */
4048 if ((temp
= malloc((size_t)datalen
)) != NULL
)
4050 memcpy(temp
, data
, (size_t)datalen
);
4052 value
->unknown
.data
= temp
;
4053 value
->unknown
.length
= datalen
;
4061 return (value
!= NULL
);
4066 * 'ippSetOperation()' - Set the operation ID in an IPP request message.
4068 * The @code ipp@ parameter refers to an IPP message previously created using
4069 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4071 * @since CUPS 1.6/OS X 10.8@
4074 int /* O - 1 on success, 0 on failure */
4075 ippSetOperation(ipp_t
*ipp
, /* I - IPP request message */
4076 ipp_op_t op
) /* I - Operation ID */
4079 * Range check input...
4086 * Set the operation and return...
4089 ipp
->request
.op
.operation_id
= op
;
4096 * 'ippSetRange()' - Set a rangeOfInteger 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 */
4110 ippSetRange(ipp_t
*ipp
, /* I - IPP message */
4111 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4112 int element
, /* I - Value number (0-based) */
4113 int lowervalue
, /* I - Lower bound for range */
4114 int uppervalue
) /* I - Upper bound for range */
4116 _ipp_value_t
*value
; /* Current value */
4120 * Range check input...
4123 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RANGE
||
4124 element
< 0 || element
> (*attr
)->num_values
|| lowervalue
> uppervalue
)
4128 * Set the value and return...
4131 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4133 value
->range
.lower
= lowervalue
;
4134 value
->range
.upper
= uppervalue
;
4137 return (value
!= NULL
);
4142 * 'ippSetRequestId()' - Set the request ID in an IPP message.
4144 * The @code ipp@ parameter refers to an IPP message previously created using
4145 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4147 * The @code request_id@ parameter must be greater than 0.
4149 * @since CUPS 1.6/OS X 10.8@
4152 int /* O - 1 on success, 0 on failure */
4153 ippSetRequestId(ipp_t
*ipp
, /* I - IPP message */
4154 int request_id
) /* I - Request ID */
4157 * Range check input; not checking request_id values since ipptool wants to send
4158 * invalid values for conformance testing and a bad request_id does not affect the
4159 * encoding of a message...
4166 * Set the request ID and return...
4169 ipp
->request
.any
.request_id
= request_id
;
4176 * 'ippSetResolution()' - Set a resolution value in an attribute.
4178 * The @code ipp@ parameter refers to an IPP message previously created using
4179 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4181 * The @code attr@ parameter may be modified as a result of setting the value.
4183 * The @code element@ parameter specifies which value to set from 0 to
4184 * @link ippGetCount(attr)@.
4186 * @since CUPS 1.6/OS X 10.8@
4189 int /* O - 1 on success, 0 on failure */
4191 ipp_t
*ipp
, /* I - IPP message */
4192 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4193 int element
, /* I - Value number (0-based) */
4194 ipp_res_t unitsvalue
, /* I - Resolution units */
4195 int xresvalue
, /* I - Horizontal/cross feed resolution */
4196 int yresvalue
) /* I - Vertical/feed resolution */
4198 _ipp_value_t
*value
; /* Current value */
4202 * Range check input...
4205 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RESOLUTION
||
4206 element
< 0 || element
> (*attr
)->num_values
|| xresvalue
<= 0 || yresvalue
<= 0 ||
4207 unitsvalue
< IPP_RES_PER_INCH
|| unitsvalue
> IPP_RES_PER_CM
)
4211 * Set the value and return...
4214 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4216 value
->resolution
.units
= unitsvalue
;
4217 value
->resolution
.xres
= xresvalue
;
4218 value
->resolution
.yres
= yresvalue
;
4221 return (value
!= NULL
);
4226 * 'ippSetState()' - Set the current state of the IPP message.
4228 * @since CUPS 1.6/OS X 10.8@
4231 int /* O - 1 on success, 0 on failure */
4232 ippSetState(ipp_t
*ipp
, /* I - IPP message */
4233 ipp_state_t state
) /* I - IPP state value */
4236 * Range check input...
4243 * Set the state and return...
4247 ipp
->current
= NULL
;
4254 * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
4256 * The @code ipp@ parameter refers to an IPP message previously created using
4257 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4259 * @since CUPS 1.6/OS X 10.8@
4262 int /* O - 1 on success, 0 on failure */
4263 ippSetStatusCode(ipp_t
*ipp
, /* I - IPP response or event message */
4264 ipp_status_t status
) /* I - Status code */
4267 * Range check input...
4274 * Set the status code and return...
4277 ipp
->request
.status
.status_code
= status
;
4284 * 'ippSetString()' - Set a string value in an attribute.
4286 * The @code ipp@ parameter refers to an IPP message previously created using
4287 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4289 * The @code attr@ parameter may be modified as a result of setting the value.
4291 * The @code element@ parameter specifies which value to set from 0 to
4292 * @link ippGetCount(attr)@.
4294 * @since CUPS 1.6/OS X 10.8@
4297 int /* O - 1 on success, 0 on failure */
4298 ippSetString(ipp_t
*ipp
, /* I - IPP message */
4299 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4300 int element
, /* I - Value number (0-based) */
4301 const char *strvalue
) /* I - String value */
4303 char *temp
; /* Temporary string */
4304 _ipp_value_t
*value
; /* Current value */
4308 * Range check input...
4311 if (!ipp
|| !attr
|| !*attr
||
4312 ((*attr
)->value_tag
!= IPP_TAG_TEXTLANG
&&
4313 (*attr
)->value_tag
!= IPP_TAG_NAMELANG
&&
4314 ((*attr
)->value_tag
< IPP_TAG_TEXT
||
4315 (*attr
)->value_tag
> IPP_TAG_MIMETYPE
)) ||
4316 element
< 0 || element
> (*attr
)->num_values
|| !strvalue
)
4320 * Set the value and return...
4323 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4326 value
->string
.language
= (*attr
)->values
[0].string
.language
;
4328 if ((int)((*attr
)->value_tag
) & IPP_TAG_CUPS_CONST
)
4329 value
->string
.text
= (char *)strvalue
;
4330 else if ((temp
= _cupsStrAlloc(strvalue
)) != NULL
)
4332 if (value
->string
.text
)
4333 _cupsStrFree(value
->string
.text
);
4335 value
->string
.text
= temp
;
4341 return (value
!= NULL
);
4346 * 'ippSetStringf()' - Set a formatted string value of an attribute.
4348 * The @code ipp@ parameter refers to an IPP message previously created using
4349 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4351 * The @code attr@ parameter may be modified as a result of setting the value.
4353 * The @code element@ parameter specifies which value to set from 0 to
4354 * @link ippGetCount(attr)@.
4356 * The @code format@ parameter uses formatting characters compatible with the
4357 * printf family of standard functions. Additional arguments follow it as
4358 * needed. The formatted string is truncated as needed to the maximum length of
4359 * the corresponding value type.
4361 * @since CUPS 1.7/OS X 10.9@
4364 int /* O - 1 on success, 0 on failure */
4365 ippSetStringf(ipp_t
*ipp
, /* I - IPP message */
4366 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4367 int element
, /* I - Value number (0-based) */
4368 const char *format
, /* I - Printf-style format string */
4369 ...) /* I - Additional arguments as needed */
4371 int ret
; /* Return value */
4372 va_list ap
; /* Pointer to additional arguments */
4375 va_start(ap
, format
);
4376 ret
= ippSetStringfv(ipp
, attr
, element
, format
, ap
);
4384 * 'ippSetStringf()' - Set a formatted string value of an attribute.
4386 * The @code ipp@ parameter refers to an IPP message previously created using
4387 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4389 * The @code attr@ parameter may be modified as a result of setting the value.
4391 * The @code element@ parameter specifies which value to set from 0 to
4392 * @link ippGetCount(attr)@.
4394 * The @code format@ parameter uses formatting characters compatible with the
4395 * printf family of standard functions. Additional arguments follow it as
4396 * needed. The formatted string is truncated as needed to the maximum length of
4397 * the corresponding value type.
4399 * @since CUPS 1.7/OS X 10.9@
4402 int /* O - 1 on success, 0 on failure */
4403 ippSetStringfv(ipp_t
*ipp
, /* I - IPP message */
4404 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4405 int element
, /* I - Value number (0-based) */
4406 const char *format
, /* I - Printf-style format string */
4407 va_list ap
) /* I - Pointer to additional arguments */
4409 ipp_tag_t value_tag
; /* Value tag */
4410 char buffer
[IPP_MAX_TEXT
+ 4];
4411 /* Formatted text string */
4412 ssize_t bytes
, /* Length of formatted value */
4413 max_bytes
; /* Maximum number of bytes for value */
4417 * Range check input...
4421 value_tag
= (*attr
)->value_tag
& IPP_TAG_CUPS_MASK
;
4423 value_tag
= IPP_TAG_ZERO
;
4425 if (!ipp
|| !attr
|| !*attr
||
4426 (value_tag
< IPP_TAG_TEXT
&& value_tag
!= IPP_TAG_TEXTLANG
&&
4427 value_tag
!= IPP_TAG_NAMELANG
) || value_tag
> IPP_TAG_MIMETYPE
||
4432 * Format the string...
4435 if (!strcmp(format
, "%s"))
4438 * Optimize the simple case...
4441 const char *s
= va_arg(ap
, char *);
4446 bytes
= (ssize_t
)strlen(s
);
4447 strlcpy(buffer
, s
, sizeof(buffer
));
4452 * Do a full formatting of the message...
4455 if ((bytes
= vsnprintf(buffer
, sizeof(buffer
), format
, ap
)) < 0)
4460 * Limit the length of the string...
4467 case IPP_TAG_TEXTLANG
:
4468 max_bytes
= IPP_MAX_TEXT
;
4472 case IPP_TAG_NAMELANG
:
4473 max_bytes
= IPP_MAX_NAME
;
4476 case IPP_TAG_CHARSET
:
4477 max_bytes
= IPP_MAX_CHARSET
;
4480 case IPP_TAG_KEYWORD
:
4481 max_bytes
= IPP_MAX_KEYWORD
;
4484 case IPP_TAG_LANGUAGE
:
4485 max_bytes
= IPP_MAX_LANGUAGE
;
4488 case IPP_TAG_MIMETYPE
:
4489 max_bytes
= IPP_MAX_MIMETYPE
;
4493 max_bytes
= IPP_MAX_URI
;
4496 case IPP_TAG_URISCHEME
:
4497 max_bytes
= IPP_MAX_URISCHEME
;
4501 if (bytes
>= max_bytes
)
4503 char *bufmax
, /* Buffer at max_bytes */
4504 *bufptr
; /* Pointer into buffer */
4506 bufptr
= buffer
+ strlen(buffer
) - 1;
4507 bufmax
= buffer
+ max_bytes
- 1;
4509 while (bufptr
> bufmax
)
4513 while ((*bufptr
& 0xc0) == 0x80 && bufptr
> buffer
)
4524 * Set the formatted string and return...
4527 return (ippSetString(ipp
, attr
, element
, buffer
));
4532 * 'ippSetValueTag()' - Set the value tag of an attribute.
4534 * The @code ipp@ parameter refers to an IPP message previously created using
4535 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4537 * The @code attr@ parameter may be modified as a result of setting the value.
4539 * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger
4540 * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name
4541 * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text
4542 * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage
4543 * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various
4544 * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes
4547 * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language
4548 * code in the "attributes-natural-language" attribute or, if not present, the language
4549 * code for the current locale.
4551 * @since CUPS 1.6/OS X 10.8@
4554 int /* O - 1 on success, 0 on failure */
4556 ipp_t
*ipp
, /* I - IPP message */
4557 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4558 ipp_tag_t value_tag
) /* I - Value tag */
4560 int i
; /* Looping var */
4561 _ipp_value_t
*value
; /* Current value */
4562 int integer
; /* Current integer value */
4563 cups_lang_t
*language
; /* Current language */
4564 char code
[32]; /* Language code */
4565 ipp_tag_t temp_tag
; /* Temporary value tag */
4569 * Range check input...
4572 if (!ipp
|| !attr
|| !*attr
)
4576 * If there is no change, return immediately...
4579 if (value_tag
== (*attr
)->value_tag
)
4583 * Otherwise implement changes as needed...
4586 temp_tag
= (ipp_tag_t
)((int)((*attr
)->value_tag
) & IPP_TAG_CUPS_MASK
);
4590 case IPP_TAG_UNSUPPORTED_VALUE
:
4591 case IPP_TAG_DEFAULT
:
4592 case IPP_TAG_UNKNOWN
:
4593 case IPP_TAG_NOVALUE
:
4594 case IPP_TAG_NOTSETTABLE
:
4595 case IPP_TAG_DELETEATTR
:
4596 case IPP_TAG_ADMINDEFINE
:
4598 * Free any existing values...
4601 if ((*attr
)->num_values
> 0)
4602 ipp_free_values(*attr
, 0, (*attr
)->num_values
);
4605 * Set out-of-band value...
4608 (*attr
)->value_tag
= value_tag
;
4611 case IPP_TAG_RANGE
:
4612 if (temp_tag
!= IPP_TAG_INTEGER
)
4615 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
4619 integer
= value
->integer
;
4620 value
->range
.lower
= value
->range
.upper
= integer
;
4623 (*attr
)->value_tag
= IPP_TAG_RANGE
;
4627 if (temp_tag
!= IPP_TAG_KEYWORD
&& temp_tag
!= IPP_TAG_URI
&&
4628 temp_tag
!= IPP_TAG_URISCHEME
&& temp_tag
!= IPP_TAG_LANGUAGE
&&
4629 temp_tag
!= IPP_TAG_MIMETYPE
)
4632 (*attr
)->value_tag
= (ipp_tag_t
)(IPP_TAG_NAME
| ((*attr
)->value_tag
& IPP_TAG_CUPS_CONST
));
4635 case IPP_TAG_NAMELANG
:
4636 case IPP_TAG_TEXTLANG
:
4637 if (value_tag
== IPP_TAG_NAMELANG
&&
4638 (temp_tag
!= IPP_TAG_NAME
&& temp_tag
!= IPP_TAG_KEYWORD
&&
4639 temp_tag
!= IPP_TAG_URI
&& temp_tag
!= IPP_TAG_URISCHEME
&&
4640 temp_tag
!= IPP_TAG_LANGUAGE
&& temp_tag
!= IPP_TAG_MIMETYPE
))
4643 if (value_tag
== IPP_TAG_TEXTLANG
&& temp_tag
!= IPP_TAG_TEXT
)
4646 if (ipp
->attrs
&& ipp
->attrs
->next
&& ipp
->attrs
->next
->name
&&
4647 !strcmp(ipp
->attrs
->next
->name
, "attributes-natural-language"))
4650 * Use the language code from the IPP message...
4653 (*attr
)->values
[0].string
.language
=
4654 _cupsStrAlloc(ipp
->attrs
->next
->values
[0].string
.text
);
4659 * Otherwise, use the language code corresponding to the locale...
4662 language
= cupsLangDefault();
4663 (*attr
)->values
[0].string
.language
= _cupsStrAlloc(ipp_lang_code(language
->language
,
4668 for (i
= (*attr
)->num_values
- 1, value
= (*attr
)->values
+ 1;
4671 value
->string
.language
= (*attr
)->values
[0].string
.language
;
4673 if ((int)(*attr
)->value_tag
& IPP_TAG_CUPS_CONST
)
4676 * Make copies of all values...
4679 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
4682 value
->string
.text
= _cupsStrAlloc(value
->string
.text
);
4685 (*attr
)->value_tag
= IPP_TAG_NAMELANG
;
4688 case IPP_TAG_KEYWORD
:
4689 if (temp_tag
== IPP_TAG_NAME
|| temp_tag
== IPP_TAG_NAMELANG
)
4690 break; /* Silently "allow" name -> keyword */
4701 * 'ippSetVersion()' - Set the version number in an IPP message.
4703 * The @code ipp@ parameter refers to an IPP message previously created using
4704 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4706 * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
4708 * @since CUPS 1.6/OS X 10.8@
4711 int /* O - 1 on success, 0 on failure */
4712 ippSetVersion(ipp_t
*ipp
, /* I - IPP message */
4713 int major
, /* I - Major version number (major.minor) */
4714 int minor
) /* I - Minor version number (major.minor) */
4717 * Range check input...
4720 if (!ipp
|| major
< 0 || minor
< 0)
4724 * Set the version number...
4727 ipp
->request
.any
.version
[0] = (ipp_uchar_t
)major
;
4728 ipp
->request
.any
.version
[1] = (ipp_uchar_t
)minor
;
4735 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
4738 const ipp_uchar_t
* /* O - RFC-1903 date/time data */
4739 ippTimeToDate(time_t t
) /* I - UNIX time value */
4741 struct tm
*unixdate
; /* UNIX unixdate/time info */
4742 ipp_uchar_t
*date
= _cupsGlobals()->ipp_date
;
4743 /* RFC-1903 date/time data */
4747 * RFC-1903 date/time format is:
4749 * Byte(s) Description
4750 * ------- -----------
4751 * 0-1 Year (0 to 65535)
4755 * 5 Minutes (0 to 59)
4756 * 6 Seconds (0 to 60, 60 = "leap second")
4757 * 7 Deciseconds (0 to 9)
4759 * 9 UTC hours (0 to 11)
4760 * 10 UTC minutes (0 to 59)
4763 unixdate
= gmtime(&t
);
4764 unixdate
->tm_year
+= 1900;
4766 date
[0] = (ipp_uchar_t
)(unixdate
->tm_year
>> 8);
4767 date
[1] = (ipp_uchar_t
)(unixdate
->tm_year
);
4768 date
[2] = (ipp_uchar_t
)(unixdate
->tm_mon
+ 1);
4769 date
[3] = (ipp_uchar_t
)unixdate
->tm_mday
;
4770 date
[4] = (ipp_uchar_t
)unixdate
->tm_hour
;
4771 date
[5] = (ipp_uchar_t
)unixdate
->tm_min
;
4772 date
[6] = (ipp_uchar_t
)unixdate
->tm_sec
;
4783 * 'ippValidateAttribute()' - Validate the contents of an attribute.
4785 * This function validates the contents of an attribute based on the name and
4786 * value tag. 1 is returned if the attribute is valid, 0 otherwise. On
4787 * failure, cupsLastErrorString() is set to a human-readable message.
4789 * @since CUPS 1.7/OS X 10.9@
4792 int /* O - 1 if valid, 0 otherwise */
4793 ippValidateAttribute(
4794 ipp_attribute_t
*attr
) /* I - Attribute */
4796 int i
; /* Looping var */
4797 char scheme
[64], /* Scheme from URI */
4798 userpass
[256], /* Username/password from URI */
4799 hostname
[256], /* Hostname from URI */
4800 resource
[1024]; /* Resource from URI */
4801 int port
, /* Port number from URI */
4802 uri_status
; /* URI separation status */
4803 const char *ptr
; /* Pointer into string */
4804 ipp_attribute_t
*colattr
; /* Collection attribute */
4805 regex_t re
; /* Regular expression */
4806 ipp_uchar_t
*date
; /* Current date value */
4807 static const char * const uri_status_strings
[] =
4808 { /* URI status strings */
4810 "Bad arguments to function",
4811 "Bad resource in URI",
4812 "Bad port number in URI",
4813 "Bad hostname/address in URI",
4814 "Bad username in URI",
4815 "Bad scheme in URI",
4818 "Missing scheme in URI",
4819 "Unknown scheme in URI",
4820 "Missing resource in URI"
4832 * Validate the attribute name.
4835 for (ptr
= attr
->name
; *ptr
; ptr
++)
4836 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' && *ptr
!= '_')
4839 if (*ptr
|| ptr
== attr
->name
)
4841 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4842 _("\"%s\": Bad attribute name - invalid character "
4843 "(RFC 2911 section 4.1.3)."), attr
->name
);
4847 if ((ptr
- attr
->name
) > 255)
4849 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4850 _("\"%s\": Bad attribute name - bad length %d "
4851 "(RFC 2911 section 4.1.3)."), attr
->name
,
4852 (int)(ptr
- attr
->name
));
4856 switch (attr
->value_tag
)
4858 case IPP_TAG_INTEGER
:
4861 case IPP_TAG_BOOLEAN
:
4862 for (i
= 0; i
< attr
->num_values
; i
++)
4864 if (attr
->values
[i
].boolean
!= 0 &&
4865 attr
->values
[i
].boolean
!= 1)
4867 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4868 _("\"%s\": Bad boolen value %d "
4869 "(RFC 2911 section 4.1.11)."), attr
->name
,
4870 attr
->values
[i
].boolean
);
4877 for (i
= 0; i
< attr
->num_values
; i
++)
4879 if (attr
->values
[i
].integer
< 1)
4881 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4882 _("\"%s\": Bad enum value %d - out of range "
4883 "(RFC 2911 section 4.1.4)."), attr
->name
,
4884 attr
->values
[i
].integer
);
4890 case IPP_TAG_STRING
:
4891 for (i
= 0; i
< attr
->num_values
; i
++)
4893 if (attr
->values
[i
].unknown
.length
> IPP_MAX_OCTETSTRING
)
4895 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4896 _("\"%s\": Bad octetString value - bad length %d "
4897 "(RFC 2911 section 4.1.10)."), attr
->name
,
4898 attr
->values
[i
].unknown
.length
);
4905 for (i
= 0; i
< attr
->num_values
; i
++)
4907 date
= attr
->values
[i
].date
;
4909 if (date
[2] < 1 || date
[2] > 12)
4911 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4912 _("\"%s\": Bad dateTime month %u "
4913 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[2]);
4917 if (date
[3] < 1 || date
[3] > 31)
4919 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4920 _("\"%s\": Bad dateTime day %u "
4921 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[3]);
4927 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4928 _("\"%s\": Bad dateTime hours %u "
4929 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[4]);
4935 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4936 _("\"%s\": Bad dateTime minutes %u "
4937 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[5]);
4943 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4944 _("\"%s\": Bad dateTime seconds %u "
4945 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[6]);
4951 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4952 _("\"%s\": Bad dateTime deciseconds %u "
4953 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[7]);
4957 if (date
[8] != '-' && date
[8] != '+')
4959 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4960 _("\"%s\": Bad dateTime UTC sign '%c' "
4961 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[8]);
4967 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4968 _("\"%s\": Bad dateTime UTC hours %u "
4969 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[9]);
4975 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4976 _("\"%s\": Bad dateTime UTC minutes %u "
4977 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[10]);
4983 case IPP_TAG_RESOLUTION
:
4984 for (i
= 0; i
< attr
->num_values
; i
++)
4986 if (attr
->values
[i
].resolution
.xres
<= 0)
4988 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4989 _("\"%s\": Bad resolution value %dx%d%s - cross "
4990 "feed resolution must be positive "
4991 "(RFC 2911 section 4.1.15)."), attr
->name
,
4992 attr
->values
[i
].resolution
.xres
,
4993 attr
->values
[i
].resolution
.yres
,
4994 attr
->values
[i
].resolution
.units
==
4995 IPP_RES_PER_INCH
? "dpi" :
4996 attr
->values
[i
].resolution
.units
==
4997 IPP_RES_PER_CM
? "dpcm" : "unknown");
5001 if (attr
->values
[i
].resolution
.yres
<= 0)
5003 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5004 _("\"%s\": Bad resolution value %dx%d%s - feed "
5005 "resolution must be positive "
5006 "(RFC 2911 section 4.1.15)."), attr
->name
,
5007 attr
->values
[i
].resolution
.xres
,
5008 attr
->values
[i
].resolution
.yres
,
5009 attr
->values
[i
].resolution
.units
==
5010 IPP_RES_PER_INCH
? "dpi" :
5011 attr
->values
[i
].resolution
.units
==
5012 IPP_RES_PER_CM
? "dpcm" : "unknown");
5016 if (attr
->values
[i
].resolution
.units
!= IPP_RES_PER_INCH
&&
5017 attr
->values
[i
].resolution
.units
!= IPP_RES_PER_CM
)
5019 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5020 _("\"%s\": Bad resolution value %dx%d%s - bad "
5021 "units value (RFC 2911 section 4.1.15)."),
5022 attr
->name
, attr
->values
[i
].resolution
.xres
,
5023 attr
->values
[i
].resolution
.yres
,
5024 attr
->values
[i
].resolution
.units
==
5025 IPP_RES_PER_INCH
? "dpi" :
5026 attr
->values
[i
].resolution
.units
==
5027 IPP_RES_PER_CM
? "dpcm" : "unknown");
5033 case IPP_TAG_RANGE
:
5034 for (i
= 0; i
< attr
->num_values
; i
++)
5036 if (attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
5038 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5039 _("\"%s\": Bad rangeOfInteger value %d-%d - lower "
5040 "greater than upper (RFC 2911 section 4.1.13)."),
5041 attr
->name
, attr
->values
[i
].range
.lower
,
5042 attr
->values
[i
].range
.upper
);
5048 case IPP_TAG_BEGIN_COLLECTION
:
5049 for (i
= 0; i
< attr
->num_values
; i
++)
5051 for (colattr
= attr
->values
[i
].collection
->attrs
;
5053 colattr
= colattr
->next
)
5055 if (!ippValidateAttribute(colattr
))
5062 case IPP_TAG_TEXTLANG
:
5063 for (i
= 0; i
< attr
->num_values
; i
++)
5065 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5067 if ((*ptr
& 0xe0) == 0xc0)
5070 if ((*ptr
& 0xc0) != 0x80)
5073 else if ((*ptr
& 0xf0) == 0xe0)
5076 if ((*ptr
& 0xc0) != 0x80)
5079 if ((*ptr
& 0xc0) != 0x80)
5082 else if ((*ptr
& 0xf8) == 0xf0)
5085 if ((*ptr
& 0xc0) != 0x80)
5088 if ((*ptr
& 0xc0) != 0x80)
5091 if ((*ptr
& 0xc0) != 0x80)
5094 else if (*ptr
& 0x80)
5100 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5101 _("\"%s\": Bad text value \"%s\" - bad UTF-8 "
5102 "sequence (RFC 2911 section 4.1.1)."), attr
->name
,
5103 attr
->values
[i
].string
.text
);
5107 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_TEXT
- 1))
5109 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5110 _("\"%s\": Bad text value \"%s\" - bad length %d "
5111 "(RFC 2911 section 4.1.1)."), attr
->name
,
5112 attr
->values
[i
].string
.text
,
5113 (int)(ptr
- attr
->values
[i
].string
.text
));
5120 case IPP_TAG_NAMELANG
:
5121 for (i
= 0; i
< attr
->num_values
; i
++)
5123 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5125 if ((*ptr
& 0xe0) == 0xc0)
5128 if ((*ptr
& 0xc0) != 0x80)
5131 else if ((*ptr
& 0xf0) == 0xe0)
5134 if ((*ptr
& 0xc0) != 0x80)
5137 if ((*ptr
& 0xc0) != 0x80)
5140 else if ((*ptr
& 0xf8) == 0xf0)
5143 if ((*ptr
& 0xc0) != 0x80)
5146 if ((*ptr
& 0xc0) != 0x80)
5149 if ((*ptr
& 0xc0) != 0x80)
5152 else if (*ptr
& 0x80)
5158 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5159 _("\"%s\": Bad name value \"%s\" - bad UTF-8 "
5160 "sequence (RFC 2911 section 4.1.2)."), attr
->name
,
5161 attr
->values
[i
].string
.text
);
5165 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_NAME
- 1))
5167 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5168 _("\"%s\": Bad name value \"%s\" - bad length %d "
5169 "(RFC 2911 section 4.1.2)."), attr
->name
,
5170 attr
->values
[i
].string
.text
,
5171 (int)(ptr
- attr
->values
[i
].string
.text
));
5177 case IPP_TAG_KEYWORD
:
5178 for (i
= 0; i
< attr
->num_values
; i
++)
5180 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5181 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' &&
5185 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
5187 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5188 _("\"%s\": Bad keyword value \"%s\" - invalid "
5189 "character (RFC 2911 section 4.1.3)."),
5190 attr
->name
, attr
->values
[i
].string
.text
);
5194 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_KEYWORD
- 1))
5196 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5197 _("\"%s\": Bad keyword value \"%s\" - bad "
5198 "length %d (RFC 2911 section 4.1.3)."),
5199 attr
->name
, attr
->values
[i
].string
.text
,
5200 (int)(ptr
- attr
->values
[i
].string
.text
));
5207 for (i
= 0; i
< attr
->num_values
; i
++)
5209 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
,
5210 attr
->values
[i
].string
.text
,
5211 scheme
, sizeof(scheme
),
5212 userpass
, sizeof(userpass
),
5213 hostname
, sizeof(hostname
),
5214 &port
, resource
, sizeof(resource
));
5216 if (uri_status
< HTTP_URI_STATUS_OK
)
5218 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5219 _("\"%s\": Bad URI value \"%s\" - %s "
5220 "(RFC 2911 section 4.1.5)."), attr
->name
,
5221 attr
->values
[i
].string
.text
,
5222 uri_status_strings
[uri_status
-
5223 HTTP_URI_STATUS_OVERFLOW
]);
5227 if (strlen(attr
->values
[i
].string
.text
) > (IPP_MAX_URI
- 1))
5229 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5230 _("\"%s\": Bad URI value \"%s\" - bad length %d "
5231 "(RFC 2911 section 4.1.5)."), attr
->name
,
5232 attr
->values
[i
].string
.text
,
5233 (int)strlen(attr
->values
[i
].string
.text
));
5238 case IPP_TAG_URISCHEME
:
5239 for (i
= 0; i
< attr
->num_values
; i
++)
5241 ptr
= attr
->values
[i
].string
.text
;
5242 if (islower(*ptr
& 255))
5244 for (ptr
++; *ptr
; ptr
++)
5245 if (!islower(*ptr
& 255) && !isdigit(*ptr
& 255) &&
5246 *ptr
!= '+' && *ptr
!= '-' && *ptr
!= '.')
5250 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
5252 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5253 _("\"%s\": Bad uriScheme value \"%s\" - bad "
5254 "characters (RFC 2911 section 4.1.6)."),
5255 attr
->name
, attr
->values
[i
].string
.text
);
5259 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_URISCHEME
- 1))
5261 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5262 _("\"%s\": Bad uriScheme value \"%s\" - bad "
5263 "length %d (RFC 2911 section 4.1.6)."),
5264 attr
->name
, attr
->values
[i
].string
.text
,
5265 (int)(ptr
- attr
->values
[i
].string
.text
));
5271 case IPP_TAG_CHARSET
:
5272 for (i
= 0; i
< attr
->num_values
; i
++)
5274 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5275 if (!isprint(*ptr
& 255) || isupper(*ptr
& 255) ||
5276 isspace(*ptr
& 255))
5279 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
5281 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5282 _("\"%s\": Bad charset value \"%s\" - bad "
5283 "characters (RFC 2911 section 4.1.7)."),
5284 attr
->name
, attr
->values
[i
].string
.text
);
5288 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_CHARSET
- 1))
5290 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5291 _("\"%s\": Bad charset value \"%s\" - bad "
5292 "length %d (RFC 2911 section 4.1.7)."),
5293 attr
->name
, attr
->values
[i
].string
.text
,
5294 (int)(ptr
- attr
->values
[i
].string
.text
));
5300 case IPP_TAG_LANGUAGE
:
5302 * The following regular expression is derived from the ABNF for
5303 * language tags in RFC 4646. All I can say is that this is the
5304 * easiest way to check the values...
5307 if ((i
= regcomp(&re
,
5309 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
5311 "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */
5312 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */
5313 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */
5314 "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */
5315 "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */
5317 "x(-[a-z0-9]{1,8})+" /* privateuse */
5319 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
5321 REG_NOSUB
| REG_EXTENDED
)) != 0)
5323 char temp
[256]; /* Temporary error string */
5325 regerror(i
, &re
, temp
, sizeof(temp
));
5326 ipp_set_error(IPP_STATUS_ERROR_INTERNAL
,
5327 _("Unable to compile naturalLanguage regular "
5328 "expression: %s."), temp
);
5332 for (i
= 0; i
< attr
->num_values
; i
++)
5334 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
5336 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5337 _("\"%s\": Bad naturalLanguage value \"%s\" - bad "
5338 "characters (RFC 2911 section 4.1.8)."),
5339 attr
->name
, attr
->values
[i
].string
.text
);
5344 if (strlen(attr
->values
[i
].string
.text
) > (IPP_MAX_LANGUAGE
- 1))
5346 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5347 _("\"%s\": Bad naturalLanguage value \"%s\" - bad "
5348 "length %d (RFC 2911 section 4.1.8)."),
5349 attr
->name
, attr
->values
[i
].string
.text
,
5350 (int)strlen(attr
->values
[i
].string
.text
));
5359 case IPP_TAG_MIMETYPE
:
5361 * The following regular expression is derived from the ABNF for
5362 * MIME media types in RFC 2045 and 4288. All I can say is that this is
5363 * the easiest way to check the values...
5366 if ((i
= regcomp(&re
,
5368 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
5370 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
5371 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
5372 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
5375 REG_NOSUB
| REG_EXTENDED
)) != 0)
5377 char temp
[256]; /* Temporary error string */
5379 regerror(i
, &re
, temp
, sizeof(temp
));
5380 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5381 _("Unable to compile mimeMediaType regular "
5382 "expression: %s."), temp
);
5386 for (i
= 0; i
< attr
->num_values
; i
++)
5388 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
5390 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5391 _("\"%s\": Bad mimeMediaType value \"%s\" - bad "
5392 "characters (RFC 2911 section 4.1.9)."),
5393 attr
->name
, attr
->values
[i
].string
.text
);
5398 if (strlen(attr
->values
[i
].string
.text
) > (IPP_MAX_MIMETYPE
- 1))
5400 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5401 _("\"%s\": Bad mimeMediaType value \"%s\" - bad "
5402 "length %d (RFC 2911 section 4.1.9)."),
5403 attr
->name
, attr
->values
[i
].string
.text
,
5404 (int)strlen(attr
->values
[i
].string
.text
));
5422 * 'ippValidateAttributes()' - Validate all attributes in an IPP message.
5424 * This function validates the contents of the IPP message, including each
5425 * attribute. Like @link ippValidateAttribute@, cupsLastErrorString() is set
5426 * to a human-readable message on failure.
5428 * @since CUPS 1.7/OS X 10.9@
5431 int /* O - 1 if valid, 0 otherwise */
5432 ippValidateAttributes(ipp_t
*ipp
) /* I - IPP message */
5434 ipp_attribute_t
*attr
; /* Current attribute */
5440 for (attr
= ipp
->attrs
; attr
; attr
= attr
->next
)
5441 if (!ippValidateAttribute(attr
))
5449 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
5452 ipp_state_t
/* O - Current state */
5453 ippWrite(http_t
*http
, /* I - HTTP connection */
5454 ipp_t
*ipp
) /* I - IPP data */
5456 DEBUG_printf(("ippWrite(http=%p, ipp=%p)", http
, ipp
));
5459 return (IPP_STATE_ERROR
);
5461 return (ippWriteIO(http
, (ipp_iocb_t
)httpWrite2
, http
->blocking
, NULL
, ipp
));
5466 * 'ippWriteFile()' - Write data for an IPP message to a file.
5468 * @since CUPS 1.1.19/OS X 10.3@
5471 ipp_state_t
/* O - Current state */
5472 ippWriteFile(int fd
, /* I - HTTP data */
5473 ipp_t
*ipp
) /* I - IPP data */
5475 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd
, ipp
));
5477 ipp
->state
= IPP_STATE_IDLE
;
5479 return (ippWriteIO(&fd
, (ipp_iocb_t
)ipp_write_file
, 1, NULL
, ipp
));
5484 * 'ippWriteIO()' - Write data for an IPP message.
5486 * @since CUPS 1.2/OS X 10.5@
5489 ipp_state_t
/* O - Current state */
5490 ippWriteIO(void *dst
, /* I - Destination */
5491 ipp_iocb_t cb
, /* I - Write callback function */
5492 int blocking
, /* I - Use blocking IO? */
5493 ipp_t
*parent
, /* I - Parent IPP message */
5494 ipp_t
*ipp
) /* I - IPP data */
5496 int i
; /* Looping var */
5497 int n
; /* Length of data */
5498 unsigned char *buffer
, /* Data buffer */
5499 *bufptr
; /* Pointer into buffer */
5500 ipp_attribute_t
*attr
; /* Current attribute */
5501 _ipp_value_t
*value
; /* Current value */
5504 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
5505 dst
, cb
, blocking
, parent
, ipp
));
5508 return (IPP_STATE_ERROR
);
5510 if ((buffer
= (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE
)) == NULL
)
5512 DEBUG_puts("1ippWriteIO: Unable to get write buffer");
5513 return (IPP_STATE_ERROR
);
5518 case IPP_STATE_IDLE
:
5519 ipp
->state
++; /* Avoid common problem... */
5521 case IPP_STATE_HEADER
:
5525 * Send the request header:
5528 * Operation/Status Code = 2 bytes
5529 * Request ID = 4 bytes
5535 *bufptr
++ = ipp
->request
.any
.version
[0];
5536 *bufptr
++ = ipp
->request
.any
.version
[1];
5537 *bufptr
++ = (ipp_uchar_t
)(ipp
->request
.any
.op_status
>> 8);
5538 *bufptr
++ = (ipp_uchar_t
)ipp
->request
.any
.op_status
;
5539 *bufptr
++ = (ipp_uchar_t
)(ipp
->request
.any
.request_id
>> 24);
5540 *bufptr
++ = (ipp_uchar_t
)(ipp
->request
.any
.request_id
>> 16);
5541 *bufptr
++ = (ipp_uchar_t
)(ipp
->request
.any
.request_id
>> 8);
5542 *bufptr
++ = (ipp_uchar_t
)ipp
->request
.any
.request_id
;
5544 DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer
[0], buffer
[1]));
5545 DEBUG_printf(("2ippWriteIO: op_status=%04x",
5546 ipp
->request
.any
.op_status
));
5547 DEBUG_printf(("2ippWriteIO: request_id=%d",
5548 ipp
->request
.any
.request_id
));
5550 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5552 DEBUG_puts("1ippWriteIO: Could not write IPP header...");
5553 _cupsBufferRelease((char *)buffer
);
5554 return (IPP_STATE_ERROR
);
5559 * Reset the state engine to point to the first attribute
5560 * in the request/response, with no current group.
5563 ipp
->state
= IPP_STATE_ATTRIBUTE
;
5564 ipp
->current
= ipp
->attrs
;
5565 ipp
->curtag
= IPP_TAG_ZERO
;
5567 DEBUG_printf(("1ippWriteIO: ipp->current=%p", ipp
->current
));
5570 * If blocking is disabled, stop here...
5576 case IPP_STATE_ATTRIBUTE
:
5577 while (ipp
->current
!= NULL
)
5580 * Write this attribute...
5584 attr
= ipp
->current
;
5586 ipp
->current
= ipp
->current
->next
;
5590 if (ipp
->curtag
!= attr
->group_tag
)
5593 * Send a group tag byte...
5596 ipp
->curtag
= attr
->group_tag
;
5598 if (attr
->group_tag
== IPP_TAG_ZERO
)
5601 DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
5602 attr
->group_tag
, ippTagString(attr
->group_tag
)));
5603 *bufptr
++ = (ipp_uchar_t
)attr
->group_tag
;
5605 else if (attr
->group_tag
== IPP_TAG_ZERO
)
5609 DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr
->name
,
5610 attr
->num_values
> 1 ? "1setOf " : "",
5611 ippTagString(attr
->value_tag
)));
5614 * Write the attribute tag and name.
5616 * The attribute name length does not include the trailing nul
5617 * character in the source string.
5619 * Collection values (parent != NULL) are written differently...
5625 * Get the length of the attribute name, and make sure it won't
5626 * overflow the buffer...
5629 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 8))
5631 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
5632 _cupsBufferRelease((char *)buffer
);
5633 return (IPP_STATE_ERROR
);
5637 * Write the value tag, name length, and name string...
5640 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5641 attr
->value_tag
, ippTagString(attr
->value_tag
)));
5642 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
5645 if (attr
->value_tag
> 0xff)
5647 *bufptr
++ = IPP_TAG_EXTENSION
;
5648 *bufptr
++ = (ipp_uchar_t
)(attr
->value_tag
>> 24);
5649 *bufptr
++ = (ipp_uchar_t
)(attr
->value_tag
>> 16);
5650 *bufptr
++ = (ipp_uchar_t
)(attr
->value_tag
>> 8);
5651 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5654 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5656 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
5657 *bufptr
++ = (ipp_uchar_t
)n
;
5658 memcpy(bufptr
, attr
->name
, (size_t)n
);
5664 * Get the length of the attribute name, and make sure it won't
5665 * overflow the buffer...
5668 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 12))
5670 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
5671 _cupsBufferRelease((char *)buffer
);
5672 return (IPP_STATE_ERROR
);
5676 * Write the member name tag, name length, name string, value tag,
5677 * and empty name for the collection member attribute...
5680 DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
5681 IPP_TAG_MEMBERNAME
));
5682 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
5684 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5685 attr
->value_tag
, ippTagString(attr
->value_tag
)));
5686 DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
5688 *bufptr
++ = IPP_TAG_MEMBERNAME
;
5691 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
5692 *bufptr
++ = (ipp_uchar_t
)n
;
5693 memcpy(bufptr
, attr
->name
, (size_t)n
);
5696 if (attr
->value_tag
> 0xff)
5698 *bufptr
++ = IPP_TAG_EXTENSION
;
5699 *bufptr
++ = (ipp_uchar_t
)(attr
->value_tag
>> 24);
5700 *bufptr
++ = (ipp_uchar_t
)(attr
->value_tag
>> 16);
5701 *bufptr
++ = (ipp_uchar_t
)(attr
->value_tag
>> 8);
5702 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5705 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5712 * Now write the attribute value(s)...
5715 switch (attr
->value_tag
& ~IPP_TAG_CUPS_CONST
)
5717 case IPP_TAG_UNSUPPORTED_VALUE
:
5718 case IPP_TAG_DEFAULT
:
5719 case IPP_TAG_UNKNOWN
:
5720 case IPP_TAG_NOVALUE
:
5721 case IPP_TAG_NOTSETTABLE
:
5722 case IPP_TAG_DELETEATTR
:
5723 case IPP_TAG_ADMINDEFINE
:
5728 case IPP_TAG_INTEGER
:
5730 for (i
= 0, value
= attr
->values
;
5731 i
< attr
->num_values
;
5734 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 9)
5736 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5738 DEBUG_puts("1ippWriteIO: Could not write IPP "
5740 _cupsBufferRelease((char *)buffer
);
5741 return (IPP_STATE_ERROR
);
5750 * Arrays and sets are done by sending additional
5751 * values with a zero-length name...
5754 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5760 * Integers and enumerations are both 4-byte signed
5761 * (twos-complement) values.
5763 * Put the 2-byte length and 4-byte value into the buffer...
5768 *bufptr
++ = (ipp_uchar_t
)(value
->integer
>> 24);
5769 *bufptr
++ = (ipp_uchar_t
)(value
->integer
>> 16);
5770 *bufptr
++ = (ipp_uchar_t
)(value
->integer
>> 8);
5771 *bufptr
++ = (ipp_uchar_t
)value
->integer
;
5775 case IPP_TAG_BOOLEAN
:
5776 for (i
= 0, value
= attr
->values
;
5777 i
< attr
->num_values
;
5780 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 6)
5782 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5784 DEBUG_puts("1ippWriteIO: Could not write IPP "
5786 _cupsBufferRelease((char *)buffer
);
5787 return (IPP_STATE_ERROR
);
5796 * Arrays and sets are done by sending additional
5797 * values with a zero-length name...
5800 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5806 * Boolean values are 1-byte; 0 = false, 1 = true.
5808 * Put the 2-byte length and 1-byte value into the buffer...
5813 *bufptr
++ = (ipp_uchar_t
)value
->boolean
;
5819 case IPP_TAG_KEYWORD
:
5821 case IPP_TAG_URISCHEME
:
5822 case IPP_TAG_CHARSET
:
5823 case IPP_TAG_LANGUAGE
:
5824 case IPP_TAG_MIMETYPE
:
5825 for (i
= 0, value
= attr
->values
;
5826 i
< attr
->num_values
;
5832 * Arrays and sets are done by sending additional
5833 * values with a zero-length name...
5836 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5838 ippTagString(attr
->value_tag
)));
5839 DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
5841 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
5843 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5845 DEBUG_puts("1ippWriteIO: Could not write IPP "
5847 _cupsBufferRelease((char *)buffer
);
5848 return (IPP_STATE_ERROR
);
5854 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5859 if (value
->string
.text
!= NULL
)
5860 n
= (int)strlen(value
->string
.text
);
5864 if (n
> (IPP_BUF_SIZE
- 2))
5866 DEBUG_printf(("1ippWriteIO: String too long (%d)", n
));
5867 _cupsBufferRelease((char *)buffer
);
5868 return (IPP_STATE_ERROR
);
5871 DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n
,
5872 value
->string
.text
));
5874 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
5876 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5878 DEBUG_puts("1ippWriteIO: Could not write IPP "
5880 _cupsBufferRelease((char *)buffer
);
5881 return (IPP_STATE_ERROR
);
5888 * All simple strings consist of the 2-byte length and
5889 * character data without the trailing nul normally found
5890 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
5891 * bytes since the 2-byte length is a signed (twos-complement)
5894 * Put the 2-byte length and string characters in the buffer.
5897 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
5898 *bufptr
++ = (ipp_uchar_t
)n
;
5902 memcpy(bufptr
, value
->string
.text
, (size_t)n
);
5909 for (i
= 0, value
= attr
->values
;
5910 i
< attr
->num_values
;
5913 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 16)
5915 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5917 DEBUG_puts("1ippWriteIO: Could not write IPP "
5919 _cupsBufferRelease((char *)buffer
);
5920 return (IPP_STATE_ERROR
);
5929 * Arrays and sets are done by sending additional
5930 * values with a zero-length name...
5933 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5939 * Date values consist of a 2-byte length and an
5940 * 11-byte date/time structure defined by RFC 1903.
5942 * Put the 2-byte length and 11-byte date/time
5943 * structure in the buffer.
5948 memcpy(bufptr
, value
->date
, 11);
5953 case IPP_TAG_RESOLUTION
:
5954 for (i
= 0, value
= attr
->values
;
5955 i
< attr
->num_values
;
5958 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 14)
5960 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
5962 DEBUG_puts("1ippWriteIO: Could not write IPP "
5964 _cupsBufferRelease((char *)buffer
);
5965 return (IPP_STATE_ERROR
);
5974 * Arrays and sets are done by sending additional
5975 * values with a zero-length name...
5978 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
5984 * Resolution values consist of a 2-byte length,
5985 * 4-byte horizontal resolution value, 4-byte vertical
5986 * resolution value, and a 1-byte units value.
5988 * Put the 2-byte length and resolution value data
5994 *bufptr
++ = (ipp_uchar_t
)(value
->resolution
.xres
>> 24);
5995 *bufptr
++ = (ipp_uchar_t
)(value
->resolution
.xres
>> 16);
5996 *bufptr
++ = (ipp_uchar_t
)(value
->resolution
.xres
>> 8);
5997 *bufptr
++ = (ipp_uchar_t
)value
->resolution
.xres
;
5998 *bufptr
++ = (ipp_uchar_t
)(value
->resolution
.yres
>> 24);
5999 *bufptr
++ = (ipp_uchar_t
)(value
->resolution
.yres
>> 16);
6000 *bufptr
++ = (ipp_uchar_t
)(value
->resolution
.yres
>> 8);
6001 *bufptr
++ = (ipp_uchar_t
)value
->resolution
.yres
;
6002 *bufptr
++ = (ipp_uchar_t
)value
->resolution
.units
;
6006 case IPP_TAG_RANGE
:
6007 for (i
= 0, value
= attr
->values
;
6008 i
< attr
->num_values
;
6011 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 13)
6013 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6015 DEBUG_puts("1ippWriteIO: Could not write IPP "
6017 _cupsBufferRelease((char *)buffer
);
6018 return (IPP_STATE_ERROR
);
6027 * Arrays and sets are done by sending additional
6028 * values with a zero-length name...
6031 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
6037 * Range values consist of a 2-byte length,
6038 * 4-byte lower value, and 4-byte upper value.
6040 * Put the 2-byte length and range value data
6046 *bufptr
++ = (ipp_uchar_t
)(value
->range
.lower
>> 24);
6047 *bufptr
++ = (ipp_uchar_t
)(value
->range
.lower
>> 16);
6048 *bufptr
++ = (ipp_uchar_t
)(value
->range
.lower
>> 8);
6049 *bufptr
++ = (ipp_uchar_t
)value
->range
.lower
;
6050 *bufptr
++ = (ipp_uchar_t
)(value
->range
.upper
>> 24);
6051 *bufptr
++ = (ipp_uchar_t
)(value
->range
.upper
>> 16);
6052 *bufptr
++ = (ipp_uchar_t
)(value
->range
.upper
>> 8);
6053 *bufptr
++ = (ipp_uchar_t
)value
->range
.upper
;
6057 case IPP_TAG_TEXTLANG
:
6058 case IPP_TAG_NAMELANG
:
6059 for (i
= 0, value
= attr
->values
;
6060 i
< attr
->num_values
;
6066 * Arrays and sets are done by sending additional
6067 * values with a zero-length name...
6070 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
6072 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6074 DEBUG_puts("1ippWriteIO: Could not write IPP "
6076 _cupsBufferRelease((char *)buffer
);
6077 return (IPP_STATE_ERROR
);
6083 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
6089 * textWithLanguage and nameWithLanguage values consist
6090 * of a 2-byte length for both strings and their
6091 * individual lengths, a 2-byte length for the
6092 * character string, the character string without the
6093 * trailing nul, a 2-byte length for the character
6094 * set string, and the character set string without
6100 if (value
->string
.language
!= NULL
)
6101 n
+= (int)strlen(value
->string
.language
);
6103 if (value
->string
.text
!= NULL
)
6104 n
+= (int)strlen(value
->string
.text
);
6106 if (n
> (IPP_BUF_SIZE
- 2))
6108 DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
6109 "too long (%d)", n
));
6110 _cupsBufferRelease((char *)buffer
);
6111 return (IPP_STATE_ERROR
);
6114 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
6116 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6118 DEBUG_puts("1ippWriteIO: Could not write IPP "
6120 _cupsBufferRelease((char *)buffer
);
6121 return (IPP_STATE_ERROR
);
6127 /* Length of entire value */
6128 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
6129 *bufptr
++ = (ipp_uchar_t
)n
;
6131 /* Length of language */
6132 if (value
->string
.language
!= NULL
)
6133 n
= (int)strlen(value
->string
.language
);
6137 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
6138 *bufptr
++ = (ipp_uchar_t
)n
;
6143 memcpy(bufptr
, value
->string
.language
, (size_t)n
);
6147 /* Length of text */
6148 if (value
->string
.text
!= NULL
)
6149 n
= (int)strlen(value
->string
.text
);
6153 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
6154 *bufptr
++ = (ipp_uchar_t
)n
;
6159 memcpy(bufptr
, value
->string
.text
, (size_t)n
);
6165 case IPP_TAG_BEGIN_COLLECTION
:
6166 for (i
= 0, value
= attr
->values
;
6167 i
< attr
->num_values
;
6171 * Collections are written with the begin-collection
6172 * tag first with a value of 0 length, followed by the
6173 * attributes in the collection, then the end-collection
6177 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 5)
6179 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6181 DEBUG_puts("1ippWriteIO: Could not write IPP "
6183 _cupsBufferRelease((char *)buffer
);
6184 return (IPP_STATE_ERROR
);
6193 * Arrays and sets are done by sending additional
6194 * values with a zero-length name...
6197 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
6203 * Write a data length of 0 and flush the buffer...
6209 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6211 DEBUG_puts("1ippWriteIO: Could not write IPP "
6213 _cupsBufferRelease((char *)buffer
);
6214 return (IPP_STATE_ERROR
);
6220 * Then write the collection attribute...
6223 value
->collection
->state
= IPP_STATE_IDLE
;
6225 if (ippWriteIO(dst
, cb
, 1, ipp
,
6226 value
->collection
) == IPP_STATE_ERROR
)
6228 DEBUG_puts("1ippWriteIO: Unable to write collection value");
6229 _cupsBufferRelease((char *)buffer
);
6230 return (IPP_STATE_ERROR
);
6236 for (i
= 0, value
= attr
->values
;
6237 i
< attr
->num_values
;
6243 * Arrays and sets are done by sending additional
6244 * values with a zero-length name...
6247 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
6249 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6251 DEBUG_puts("1ippWriteIO: Could not write IPP "
6253 _cupsBufferRelease((char *)buffer
);
6254 return (IPP_STATE_ERROR
);
6260 *bufptr
++ = (ipp_uchar_t
)attr
->value_tag
;
6266 * An unknown value might some new value that a
6267 * vendor has come up with. It consists of a
6268 * 2-byte length and the bytes in the unknown
6272 n
= value
->unknown
.length
;
6274 if (n
> (IPP_BUF_SIZE
- 2))
6276 DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
6278 _cupsBufferRelease((char *)buffer
);
6279 return (IPP_STATE_ERROR
);
6282 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
6284 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6286 DEBUG_puts("1ippWriteIO: Could not write IPP "
6288 _cupsBufferRelease((char *)buffer
);
6289 return (IPP_STATE_ERROR
);
6295 /* Length of unknown value */
6296 *bufptr
++ = (ipp_uchar_t
)(n
>> 8);
6297 *bufptr
++ = (ipp_uchar_t
)n
;
6302 memcpy(bufptr
, value
->unknown
.data
, (size_t)n
);
6310 * Write the data out...
6313 if (bufptr
> buffer
)
6315 if ((*cb
)(dst
, buffer
, (size_t)(bufptr
- buffer
)) < 0)
6317 DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
6318 _cupsBufferRelease((char *)buffer
);
6319 return (IPP_STATE_ERROR
);
6322 DEBUG_printf(("2ippWriteIO: wrote %d bytes",
6323 (int)(bufptr
- buffer
)));
6327 * If blocking is disabled and we aren't at the end of the attribute
6328 * list, stop here...
6331 if (!blocking
&& ipp
->current
)
6335 if (ipp
->current
== NULL
)
6338 * Done with all of the attributes; add the end-of-attributes
6339 * tag or end-collection attribute...
6344 buffer
[0] = IPP_TAG_END
;
6349 buffer
[0] = IPP_TAG_END_COLLECTION
;
6350 buffer
[1] = 0; /* empty name */
6352 buffer
[3] = 0; /* empty value */
6357 if ((*cb
)(dst
, buffer
, (size_t)n
) < 0)
6359 DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
6360 _cupsBufferRelease((char *)buffer
);
6361 return (IPP_STATE_ERROR
);
6364 ipp
->state
= IPP_STATE_DATA
;
6368 case IPP_STATE_DATA
:
6372 break; /* anti-compiler-warning-code */
6375 _cupsBufferRelease((char *)buffer
);
6377 return (ipp
->state
);
6382 * 'ipp_add_attr()' - Add a new attribute to the message.
6385 static ipp_attribute_t
* /* O - New attribute */
6386 ipp_add_attr(ipp_t
*ipp
, /* I - IPP message */
6387 const char *name
, /* I - Attribute name or NULL */
6388 ipp_tag_t group_tag
, /* I - Group tag or IPP_TAG_ZERO */
6389 ipp_tag_t value_tag
, /* I - Value tag or IPP_TAG_ZERO */
6390 int num_values
) /* I - Number of values */
6392 int alloc_values
; /* Number of values to allocate */
6393 ipp_attribute_t
*attr
; /* New attribute */
6396 DEBUG_printf(("4ipp_add_attr(ipp=%p, name=\"%s\", group_tag=0x%x, value_tag=0x%x, "
6397 "num_values=%d)", ipp
, name
, group_tag
, value_tag
, num_values
));
6400 * Range check input...
6403 if (!ipp
|| num_values
< 0)
6407 * Allocate memory, rounding the allocation up as needed...
6410 if (num_values
<= 1)
6413 alloc_values
= (num_values
+ IPP_MAX_VALUES
- 1) & ~(IPP_MAX_VALUES
- 1);
6415 attr
= calloc(sizeof(ipp_attribute_t
) +
6416 (size_t)(alloc_values
- 1) * sizeof(_ipp_value_t
), 1);
6421 * Initialize attribute...
6425 attr
->name
= _cupsStrAlloc(name
);
6427 attr
->group_tag
= group_tag
;
6428 attr
->value_tag
= value_tag
;
6429 attr
->num_values
= num_values
;
6432 * Add it to the end of the linked list...
6436 ipp
->last
->next
= attr
;
6440 ipp
->prev
= ipp
->last
;
6441 ipp
->last
= ipp
->current
= attr
;
6444 DEBUG_printf(("5ipp_add_attr: Returning %p", attr
));
6451 * 'ipp_free_values()' - Free attribute values.
6455 ipp_free_values(ipp_attribute_t
*attr
, /* I - Attribute to free values from */
6456 int element
,/* I - First value to free */
6457 int count
) /* I - Number of values to free */
6459 int i
; /* Looping var */
6460 _ipp_value_t
*value
; /* Current value */
6463 DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", attr
,
6466 if (!(attr
->value_tag
& IPP_TAG_CUPS_CONST
))
6469 * Free values as needed...
6472 switch (attr
->value_tag
)
6474 case IPP_TAG_TEXTLANG
:
6475 case IPP_TAG_NAMELANG
:
6476 if (element
== 0 && count
== attr
->num_values
&&
6477 attr
->values
[0].string
.language
)
6479 _cupsStrFree(attr
->values
[0].string
.language
);
6480 attr
->values
[0].string
.language
= NULL
;
6482 /* Fall through to other string values */
6486 case IPP_TAG_RESERVED_STRING
:
6487 case IPP_TAG_KEYWORD
:
6489 case IPP_TAG_URISCHEME
:
6490 case IPP_TAG_CHARSET
:
6491 case IPP_TAG_LANGUAGE
:
6492 case IPP_TAG_MIMETYPE
:
6493 for (i
= count
, value
= attr
->values
+ element
;
6497 _cupsStrFree(value
->string
.text
);
6498 value
->string
.text
= NULL
;
6502 case IPP_TAG_DEFAULT
:
6503 case IPP_TAG_UNKNOWN
:
6504 case IPP_TAG_NOVALUE
:
6505 case IPP_TAG_NOTSETTABLE
:
6506 case IPP_TAG_DELETEATTR
:
6507 case IPP_TAG_ADMINDEFINE
:
6508 case IPP_TAG_INTEGER
:
6510 case IPP_TAG_BOOLEAN
:
6512 case IPP_TAG_RESOLUTION
:
6513 case IPP_TAG_RANGE
:
6516 case IPP_TAG_BEGIN_COLLECTION
:
6517 for (i
= count
, value
= attr
->values
+ element
;
6521 ippDelete(value
->collection
);
6522 value
->collection
= NULL
;
6526 case IPP_TAG_STRING
:
6528 for (i
= count
, value
= attr
->values
+ element
;
6532 if (value
->unknown
.data
)
6534 free(value
->unknown
.data
);
6535 value
->unknown
.data
= NULL
;
6543 * If we are not freeing values from the end, move the remaining values up...
6546 if ((element
+ count
) < attr
->num_values
)
6547 memmove(attr
->values
+ element
, attr
->values
+ element
+ count
,
6548 (size_t)(attr
->num_values
- count
- element
) * sizeof(_ipp_value_t
));
6550 attr
->num_values
-= count
;
6555 * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
6557 * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
6558 * to "ll-cc", "ll-region", and "charset-number", respectively.
6561 static char * /* O - Language code string */
6562 ipp_get_code(const char *value
, /* I - Locale/charset string */
6563 char *buffer
, /* I - String buffer */
6564 size_t bufsize
) /* I - Size of string buffer */
6566 char *bufptr
, /* Pointer into buffer */
6567 *bufend
; /* End of buffer */
6571 * Convert values to lowercase and change _ to - as needed...
6574 for (bufptr
= buffer
, bufend
= buffer
+ bufsize
- 1;
6575 *value
&& bufptr
< bufend
;
6580 *bufptr
++ = (char)_cups_tolower(*value
);
6585 * Return the converted string...
6593 * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
6595 * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
6596 * "ll-region", respectively. It also converts the "C" (POSIX) locale to "en".
6599 static char * /* O - Language code string */
6600 ipp_lang_code(const char *locale
, /* I - Locale string */
6601 char *buffer
, /* I - String buffer */
6602 size_t bufsize
) /* I - Size of string buffer */
6605 * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
6608 if (!_cups_strcasecmp(locale
, "c"))
6610 strlcpy(buffer
, "en", bufsize
);
6614 return (ipp_get_code(locale
, buffer
, bufsize
));
6619 * 'ipp_length()' - Compute the length of an IPP message or collection value.
6622 static size_t /* O - Size of IPP message */
6623 ipp_length(ipp_t
*ipp
, /* I - IPP message or collection */
6624 int collection
) /* I - 1 if a collection, 0 otherwise */
6626 int i
; /* Looping var */
6627 size_t bytes
; /* Number of bytes */
6628 ipp_attribute_t
*attr
; /* Current attribute */
6629 ipp_tag_t group
; /* Current group */
6630 _ipp_value_t
*value
; /* Current value */
6633 DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", ipp
, collection
));
6637 DEBUG_puts("4ipp_length: Returning 0 bytes");
6642 * Start with 8 bytes for the IPP message header...
6645 bytes
= collection
? 0 : 8;
6648 * Then add the lengths of each attribute...
6651 group
= IPP_TAG_ZERO
;
6653 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= attr
->next
)
6655 if (attr
->group_tag
!= group
&& !collection
)
6657 group
= attr
->group_tag
;
6658 if (group
== IPP_TAG_ZERO
)
6661 bytes
++; /* Group tag */
6667 DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
6668 "bytes=" CUPS_LLFMT
, attr
->name
, attr
->num_values
, CUPS_LLCAST bytes
));
6670 if (attr
->value_tag
< IPP_TAG_EXTENSION
)
6671 bytes
+= (size_t)attr
->num_values
;/* Value tag for each value */
6673 bytes
+= (size_t)(5 * attr
->num_values
);
6674 /* Value tag for each value */
6675 bytes
+= (size_t)(2 * attr
->num_values
);
6677 bytes
+= strlen(attr
->name
); /* Name */
6678 bytes
+= (size_t)(2 * attr
->num_values
);
6682 bytes
+= 5; /* Add membername overhead */
6684 switch (attr
->value_tag
& ~IPP_TAG_CUPS_CONST
)
6686 case IPP_TAG_UNSUPPORTED_VALUE
:
6687 case IPP_TAG_DEFAULT
:
6688 case IPP_TAG_UNKNOWN
:
6689 case IPP_TAG_NOVALUE
:
6690 case IPP_TAG_NOTSETTABLE
:
6691 case IPP_TAG_DELETEATTR
:
6692 case IPP_TAG_ADMINDEFINE
:
6695 case IPP_TAG_INTEGER
:
6697 bytes
+= (size_t)(4 * attr
->num_values
);
6700 case IPP_TAG_BOOLEAN
:
6701 bytes
+= (size_t)attr
->num_values
;
6706 case IPP_TAG_KEYWORD
:
6708 case IPP_TAG_URISCHEME
:
6709 case IPP_TAG_CHARSET
:
6710 case IPP_TAG_LANGUAGE
:
6711 case IPP_TAG_MIMETYPE
:
6712 for (i
= 0, value
= attr
->values
;
6713 i
< attr
->num_values
;
6715 if (value
->string
.text
)
6716 bytes
+= strlen(value
->string
.text
);
6720 bytes
+= (size_t)(11 * attr
->num_values
);
6723 case IPP_TAG_RESOLUTION
:
6724 bytes
+= (size_t)(9 * attr
->num_values
);
6727 case IPP_TAG_RANGE
:
6728 bytes
+= (size_t)(8 * attr
->num_values
);
6731 case IPP_TAG_TEXTLANG
:
6732 case IPP_TAG_NAMELANG
:
6733 bytes
+= (size_t)(4 * attr
->num_values
);
6734 /* Charset + text length */
6736 for (i
= 0, value
= attr
->values
;
6737 i
< attr
->num_values
;
6740 if (value
->string
.language
)
6741 bytes
+= strlen(value
->string
.language
);
6743 if (value
->string
.text
)
6744 bytes
+= strlen(value
->string
.text
);
6748 case IPP_TAG_BEGIN_COLLECTION
:
6749 for (i
= 0, value
= attr
->values
;
6750 i
< attr
->num_values
;
6752 bytes
+= ipp_length(value
->collection
, 1);
6756 for (i
= 0, value
= attr
->values
;
6757 i
< attr
->num_values
;
6759 bytes
+= (size_t)value
->unknown
.length
;
6765 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
6766 * for the "end of collection" tag and return...
6774 DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT
" bytes", CUPS_LLCAST bytes
));
6781 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
6784 static ssize_t
/* O - Number of bytes read */
6785 ipp_read_http(http_t
*http
, /* I - Client connection */
6786 ipp_uchar_t
*buffer
, /* O - Buffer for data */
6787 size_t length
) /* I - Total length */
6789 ssize_t tbytes
, /* Total bytes read */
6790 bytes
; /* Bytes read this pass */
6793 DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)",
6794 http
, buffer
, (int)length
));
6797 * Loop until all bytes are read...
6800 for (tbytes
= 0, bytes
= 0;
6801 tbytes
< (int)length
;
6802 tbytes
+= bytes
, buffer
+= bytes
)
6804 DEBUG_printf(("9ipp_read_http: tbytes=" CUPS_LLFMT
", http->state=%d", CUPS_LLCAST tbytes
, http
->state
));
6806 if (http
->state
== HTTP_STATE_WAITING
)
6809 if (http
->used
== 0 && !http
->blocking
)
6812 * Wait up to 10 seconds for more data on non-blocking sockets...
6815 if (!httpWait(http
, 10000))
6826 if ((bytes
= httpRead2(http
, (char *)buffer
, length
- (size_t)tbytes
)) < 0)
6831 if (errno
!= EAGAIN
&& errno
!= EINTR
)
6837 else if (bytes
== 0)
6842 * Return the number of bytes read...
6845 if (tbytes
== 0 && bytes
< 0)
6848 DEBUG_printf(("8ipp_read_http: Returning " CUPS_LLFMT
" bytes", CUPS_LLCAST tbytes
));
6855 * 'ipp_read_file()' - Read IPP data from a file.
6858 static ssize_t
/* O - Number of bytes read */
6859 ipp_read_file(int *fd
, /* I - File descriptor */
6860 ipp_uchar_t
*buffer
, /* O - Read buffer */
6861 size_t length
) /* I - Number of bytes to read */
6864 return ((ssize_t
)read(*fd
, buffer
, (unsigned)length
));
6866 return (read(*fd
, buffer
, length
));
6872 * 'ipp_set_error()' - Set a formatted, localized error string.
6876 ipp_set_error(ipp_status_t status
, /* I - Status code */
6877 const char *format
, /* I - Printf-style error string */
6878 ...) /* I - Additional arguments as needed */
6880 va_list ap
; /* Pointer to additional args */
6881 char buffer
[2048]; /* Message buffer */
6882 cups_lang_t
*lang
= cupsLangDefault();
6883 /* Current language */
6886 va_start(ap
, format
);
6887 vsnprintf(buffer
, sizeof(buffer
), _cupsLangString(lang
, format
), ap
);
6890 _cupsSetError(status
, buffer
, 0);
6895 * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
6899 static _ipp_value_t
* /* O - IPP value element or NULL on error */
6900 ipp_set_value(ipp_t
*ipp
, /* IO - IPP message */
6901 ipp_attribute_t
**attr
, /* IO - IPP attribute */
6902 int element
) /* I - Value number (0-based) */
6904 ipp_attribute_t
*temp
, /* New attribute pointer */
6905 *current
, /* Current attribute in list */
6906 *prev
; /* Previous attribute in list */
6907 int alloc_values
; /* Allocated values */
6911 * If we are setting an existing value element, return it...
6916 if (temp
->num_values
<= 1)
6919 alloc_values
= (temp
->num_values
+ IPP_MAX_VALUES
- 1) &
6920 ~(IPP_MAX_VALUES
- 1);
6922 if (element
< alloc_values
)
6924 if (element
>= temp
->num_values
)
6925 temp
->num_values
= element
+ 1;
6927 return (temp
->values
+ element
);
6931 * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
6932 * values when num_values > 1.
6935 if (alloc_values
< IPP_MAX_VALUES
)
6936 alloc_values
= IPP_MAX_VALUES
;
6938 alloc_values
+= IPP_MAX_VALUES
;
6940 DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
6944 * Reallocate memory...
6947 if ((temp
= realloc(temp
, sizeof(ipp_attribute_t
) + (size_t)(alloc_values
- 1) * sizeof(_ipp_value_t
))) == NULL
)
6949 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
6950 DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
6955 * Zero the new memory...
6958 memset(temp
->values
+ temp
->num_values
, 0, (size_t)(alloc_values
- temp
->num_values
) * sizeof(_ipp_value_t
));
6963 * Reset pointers in the list...
6966 if (ipp
->current
== *attr
&& ipp
->prev
)
6969 * Use current "previous" pointer...
6977 * Find this attribute in the linked list...
6980 for (prev
= NULL
, current
= ipp
->attrs
;
6981 current
&& current
!= *attr
;
6982 prev
= current
, current
= current
->next
);
6987 * This is a serious error!
6991 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
6992 _("IPP attribute is not a member of the message."), 1);
6993 DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
7003 ipp
->current
= temp
;
7006 if (ipp
->last
== *attr
)
7013 * Return the value element...
7016 if (element
>= temp
->num_values
)
7017 temp
->num_values
= element
+ 1;
7019 return (temp
->values
+ element
);
7024 * 'ipp_write_file()' - Write IPP data to a file.
7027 static ssize_t
/* O - Number of bytes written */
7028 ipp_write_file(int *fd
, /* I - File descriptor */
7029 ipp_uchar_t
*buffer
, /* I - Data to write */
7030 size_t length
) /* I - Number of bytes to write */
7033 return ((ssize_t
)write(*fd
, buffer
, (unsigned)length
));
7035 return (write(*fd
, buffer
, length
));