2 * "$Id: ipp.c 10102 2011-11-02 23:52:39Z mike $"
4 * Internet Printing Protocol functions for CUPS.
6 * Copyright 2007-2012 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 * _cupsBufferGet() - Get a read/write buffer.
20 * _cupsBufferRelease() - Release a read/write buffer.
21 * ippAddBoolean() - Add a boolean attribute to an IPP message.
22 * ippAddBooleans() - Add an array of boolean values.
23 * ippAddCollection() - Add a collection value.
24 * ippAddCollections() - Add an array of collection values.
25 * ippAddDate() - Add a date attribute to an IPP message.
26 * ippAddInteger() - Add a integer attribute to an IPP message.
27 * ippAddIntegers() - Add an array of integer values.
28 * ippAddOctetString() - Add an octetString value to an IPP message.
29 * ippAddOutOfBand() - Add an out-of-band value to an IPP message.
30 * ippAddRange() - Add a range of values to an IPP message.
31 * ippAddRanges() - Add ranges of values to an IPP message.
32 * ippAddResolution() - Add a resolution value to an IPP message.
33 * ippAddResolutions() - Add resolution values to an IPP message.
34 * ippAddSeparator() - Add a group separator to an IPP message.
35 * ippAddString() - Add a language-encoded string to an IPP message.
36 * ippAddStrings() - Add language-encoded strings to an IPP message.
37 * ippCopyAttribute() - Copy an attribute.
38 * ippCopyAttributes() - Copy attributes from one IPP message to another.
39 * ippDateToTime() - Convert from RFC 1903 Date/Time format to UNIX
41 * ippDelete() - Delete an IPP message.
42 * ippDeleteAttribute() - Delete a single attribute in an IPP message.
43 * ippDeleteValues() - Delete values in an attribute.
44 * ippFindAttribute() - Find a named attribute in a request.
45 * ippFindNextAttribute() - Find the next named attribute in a request.
46 * ippFirstAttribute() - Return the first attribute in the message.
47 * ippGetBoolean() - Get a boolean value for an attribute.
48 * ippGetCollection() - Get a collection value for an attribute.
49 * ippGetCount() - Get the number of values in an attribute.
50 * ippGetDate() - Get a date value for an attribute.
51 * ippGetGroupTag() - Get the group associated with an attribute.
52 * ippGetInteger() - Get the integer/enum value for an attribute.
53 * ippGetName() - Get the attribute name.
54 * ippGetOperation() - Get the operation ID in an IPP message.
55 * ippGetRange() - Get a rangeOfInteger value from an attribute.
56 * ippGetRequestId() - Get the request ID from an IPP message.
57 * ippGetResolution() - Get a resolution value for an attribute.
58 * ippGetStatusCode() - Get the status code from an IPP response or event
60 * ippGetString() - Get the string and optionally the language code
62 * ippGetValueTag() - Get the value tag for an attribute.
63 * ippGetVersion() - Get the major and minor version number from an
65 * ippLength() - Compute the length of an IPP message.
66 * ippNextAttribute() - Return the next attribute in the message.
67 * ippNew() - Allocate a new IPP message.
68 * ippNewRequest() - Allocate a new IPP request message.
69 * ippRead() - Read data for an IPP message from a HTTP
71 * ippReadFile() - Read data for an IPP message from a file.
72 * ippReadIO() - Read data for an IPP message.
73 * ippSetBoolean() - Set a boolean value in an attribute.
74 * ippSetCollection() - Set a collection value in an attribute.
75 * ippSetDate() - Set a date value in an attribute.
76 * ippSetGroupTag() - Set the group tag of an attribute.
77 * ippSetInteger() - Set an integer or enum value in an attribute.
78 * ippSetName() - Set the name of an attribute.
79 * ippSetOperation() - Set the operation ID in an IPP request message.
80 * ippSetRange() - Set a rangeOfInteger value in an attribute.
81 * ippSetRequestId() - Set the request ID in an IPP message.
82 * ippSetResolution() - Set a resolution value in an attribute.
83 * ippSetState() - Set the current state of the IPP message.
84 * ippSetStatusCode() - Set the status code in an IPP response or event
86 * ippSetString() - Set a string value in an attribute.
87 * ippSetValueTag() - Set the value tag of an attribute.
88 * ippSetVersion() - Set the version number in an IPP message.
89 * ippTimeToDate() - Convert from UNIX time to RFC 1903 format.
90 * ippWrite() - Write data for an IPP message to a HTTP
92 * ippWriteFile() - Write data for an IPP message to a file.
93 * ippWriteIO() - Write data for an IPP message.
94 * ipp_add_attr() - Add a new attribute to the message.
95 * ipp_free_values() - Free attribute values.
96 * ipp_get_code() - Convert a C locale/charset name into an IPP
97 * language/charset code.
98 * ipp_lang_code() - Convert a C locale name into an IPP language
100 * ipp_length() - Compute the length of an IPP message or
102 * ipp_read_http() - Semi-blocking read on a HTTP connection...
103 * ipp_read_file() - Read IPP data from a file.
104 * ipp_set_value() - Get the value element from an attribute,
105 * expanding it as needed.
106 * ipp_write_file() - Write IPP data to a file.
110 * Include necessary headers...
113 #include "cups-private.h"
123 static ipp_attribute_t
*ipp_add_attr(ipp_t
*ipp
, const char *name
,
124 ipp_tag_t group_tag
, ipp_tag_t value_tag
,
126 static void ipp_free_values(ipp_attribute_t
*attr
, int element
,
128 static char *ipp_get_code(const char *locale
, char *buffer
,
130 __attribute__((nonnull(1,2)));
131 static char *ipp_lang_code(const char *locale
, char *buffer
,
133 __attribute__((nonnull(1,2)));
134 static size_t ipp_length(ipp_t
*ipp
, int collection
);
135 static ssize_t
ipp_read_http(http_t
*http
, ipp_uchar_t
*buffer
,
137 static ssize_t
ipp_read_file(int *fd
, ipp_uchar_t
*buffer
,
139 static _ipp_value_t
*ipp_set_value(ipp_t
*ipp
, ipp_attribute_t
**attr
,
141 static ssize_t
ipp_write_file(int *fd
, ipp_uchar_t
*buffer
,
146 * '_cupsBufferGet()' - Get a read/write buffer.
149 char * /* O - Buffer */
150 _cupsBufferGet(size_t size
) /* I - Size required */
152 _cups_buffer_t
*buffer
; /* Current buffer */
153 _cups_globals_t
*cg
= _cupsGlobals();
157 for (buffer
= cg
->cups_buffers
; buffer
; buffer
= buffer
->next
)
158 if (!buffer
->used
&& buffer
->size
>= size
)
163 if ((buffer
= malloc(sizeof(_cups_buffer_t
) + size
- 1)) == NULL
)
166 buffer
->next
= cg
->cups_buffers
;
168 cg
->cups_buffers
= buffer
;
178 * '_cupsBufferRelease()' - Release a read/write buffer.
182 _cupsBufferRelease(char *b
) /* I - Buffer to release */
184 _cups_buffer_t
*buffer
; /* Buffer */
188 * Mark this buffer as unused...
191 buffer
= (_cups_buffer_t
*)(b
- offsetof(_cups_buffer_t
, d
));
197 * 'ippAddBoolean()' - Add a boolean attribute to an IPP message.
199 * The @code ipp@ parameter refers to an IPP message previously created using the
200 * @link ippNew@ or @link ippNewRequest@ functions.
202 * The @code group@ parameter specifies the IPP attribute group tag: none
203 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
204 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
205 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
206 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
209 ipp_attribute_t
* /* O - New attribute */
210 ippAddBoolean(ipp_t
*ipp
, /* I - IPP message */
211 ipp_tag_t group
, /* I - IPP group */
212 const char *name
, /* I - Name of attribute */
213 char value
) /* I - Value of attribute */
215 ipp_attribute_t
*attr
; /* New attribute */
218 DEBUG_printf(("ippAddBoolean(ipp=%p, group=%02x(%s), name=\"%s\", value=%d)",
219 ipp
, group
, ippTagString(group
), name
, value
));
222 * Range check input...
225 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
226 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
230 * Create the attribute...
233 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BOOLEAN
, 1)) == NULL
)
236 attr
->values
[0].boolean
= value
;
243 * 'ippAddBooleans()' - Add an array of boolean values.
245 * The @code ipp@ parameter refers to an IPP message previously created using the
246 * @link ippNew@ or @link ippNewRequest@ functions.
248 * The @code group@ parameter specifies the IPP attribute group tag: none
249 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
250 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
251 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
252 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
255 ipp_attribute_t
* /* O - New attribute */
256 ippAddBooleans(ipp_t
*ipp
, /* I - IPP message */
257 ipp_tag_t group
, /* I - IPP group */
258 const char *name
, /* I - Name of attribute */
259 int num_values
, /* I - Number of values */
260 const char *values
) /* I - Values */
262 int i
; /* Looping var */
263 ipp_attribute_t
*attr
; /* New attribute */
264 _ipp_value_t
*value
; /* Current value */
267 DEBUG_printf(("ippAddBooleans(ipp=%p, group=%02x(%s), name=\"%s\", "
268 "num_values=%d, values=%p)", ipp
, group
, ippTagString(group
),
269 name
, num_values
, values
));
272 * Range check input...
275 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
276 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
281 * Create the attribute...
284 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BOOLEAN
, num_values
)) == NULL
)
289 for (i
= num_values
, value
= attr
->values
;
292 value
->boolean
= *values
++;
300 * 'ippAddCollection()' - Add a collection value.
302 * The @code ipp@ parameter refers to an IPP message previously created using the
303 * @link ippNew@ or @link ippNewRequest@ functions.
305 * The @code group@ parameter specifies the IPP attribute group tag: none
306 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
307 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
308 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
309 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
311 * @since CUPS 1.1.19/OS X 10.3@
314 ipp_attribute_t
* /* O - New attribute */
315 ippAddCollection(ipp_t
*ipp
, /* I - IPP message */
316 ipp_tag_t group
, /* I - IPP group */
317 const char *name
, /* I - Name of attribute */
318 ipp_t
*value
) /* I - Value */
320 ipp_attribute_t
*attr
; /* New attribute */
323 DEBUG_printf(("ippAddCollection(ipp=%p, group=%02x(%s), name=\"%s\", "
324 "value=%p)", ipp
, group
, ippTagString(group
), name
, value
));
327 * Range check input...
330 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
331 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
335 * Create the attribute...
338 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BEGIN_COLLECTION
, 1)) == NULL
)
341 attr
->values
[0].collection
= value
;
351 * 'ippAddCollections()' - Add an array of collection values.
353 * The @code ipp@ parameter refers to an IPP message previously created using the
354 * @link ippNew@ or @link ippNewRequest@ functions.
356 * The @code group@ parameter specifies the IPP attribute group tag: none
357 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
358 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
359 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
360 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
362 * @since CUPS 1.1.19/OS X 10.3@
365 ipp_attribute_t
* /* O - New attribute */
367 ipp_t
*ipp
, /* I - IPP message */
368 ipp_tag_t group
, /* I - IPP group */
369 const char *name
, /* I - Name of attribute */
370 int num_values
, /* I - Number of values */
371 const ipp_t
**values
) /* I - Values */
373 int i
; /* Looping var */
374 ipp_attribute_t
*attr
; /* New attribute */
375 _ipp_value_t
*value
; /* Current value */
378 DEBUG_printf(("ippAddCollections(ipp=%p, group=%02x(%s), name=\"%s\", "
379 "num_values=%d, values=%p)", ipp
, group
, ippTagString(group
),
380 name
, num_values
, values
));
383 * Range check input...
386 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
387 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
392 * Create the attribute...
395 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BEGIN_COLLECTION
,
396 num_values
)) == NULL
)
401 for (i
= num_values
, value
= attr
->values
;
405 value
->collection
= (ipp_t
*)*values
++;
406 value
->collection
->use
++;
415 * 'ippAddDate()' - Add a date attribute to an IPP message.
417 * The @code ipp@ parameter refers to an IPP message previously created using the
418 * @link ippNew@ or @link ippNewRequest@ functions.
420 * The @code group@ parameter specifies the IPP attribute group tag: none
421 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
422 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
423 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
424 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
427 ipp_attribute_t
* /* O - New attribute */
428 ippAddDate(ipp_t
*ipp
, /* I - IPP message */
429 ipp_tag_t group
, /* I - IPP group */
430 const char *name
, /* I - Name of attribute */
431 const ipp_uchar_t
*value
) /* I - Value */
433 ipp_attribute_t
*attr
; /* New attribute */
436 DEBUG_printf(("ippAddDate(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)",
437 ipp
, group
, ippTagString(group
), name
, value
));
440 * Range check input...
443 if (!ipp
|| !name
|| !value
|| group
< IPP_TAG_ZERO
||
444 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
448 * Create the attribute...
451 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_DATE
, 1)) == NULL
)
454 memcpy(attr
->values
[0].date
, value
, 11);
461 * 'ippAddInteger()' - Add a integer attribute to an IPP message.
463 * The @code ipp@ parameter refers to an IPP message previously created using the
464 * @link ippNew@ or @link ippNewRequest@ functions.
466 * The @code group@ parameter specifies the IPP attribute group tag: none
467 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
468 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
469 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
470 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
472 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
473 * (@code IPP_TAG_INTEGER@).
476 ipp_attribute_t
* /* O - New attribute */
477 ippAddInteger(ipp_t
*ipp
, /* I - IPP message */
478 ipp_tag_t group
, /* I - IPP group */
479 ipp_tag_t value_tag
, /* I - Type of attribute */
480 const char *name
, /* I - Name of attribute */
481 int value
) /* I - Value of attribute */
483 ipp_attribute_t
*attr
; /* New attribute */
486 DEBUG_printf(("ippAddInteger(ipp=%p, group=%02x(%s), type=%02x(%s), "
487 "name=\"%s\", value=%d)", ipp
, group
, ippTagString(group
),
488 value_tag
, ippTagString(value_tag
), name
, value
));
490 value_tag
&= IPP_TAG_MASK
;
493 * Special-case for legacy usage: map out-of-band attributes to new ippAddOutOfBand
497 if (value_tag
>= IPP_TAG_UNSUPPORTED_VALUE
&& value_tag
<= IPP_TAG_ADMINDEFINE
)
498 return (ippAddOutOfBand(ipp
, group
, value_tag
, name
));
501 * Range check input...
505 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
506 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
507 (value_tag
!= IPP_TAG_INTEGER
&& value_tag
!= IPP_TAG_ENUM
))
510 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
511 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
516 * Create the attribute...
519 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, 1)) == NULL
)
522 attr
->values
[0].integer
= value
;
529 * 'ippAddIntegers()' - Add an array of integer values.
531 * The @code ipp@ parameter refers to an IPP message previously created using the
532 * @link ippNew@ or @link ippNewRequest@ functions.
534 * The @code group@ parameter specifies the IPP attribute group tag: none
535 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
536 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
537 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
538 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
540 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
541 * (@code IPP_TAG_INTEGER@).
544 ipp_attribute_t
* /* O - New attribute */
545 ippAddIntegers(ipp_t
*ipp
, /* I - IPP message */
546 ipp_tag_t group
, /* I - IPP group */
547 ipp_tag_t value_tag
, /* I - Type of attribute */
548 const char *name
, /* I - Name of attribute */
549 int num_values
, /* I - Number of values */
550 const int *values
) /* I - Values */
552 int i
; /* Looping var */
553 ipp_attribute_t
*attr
; /* New attribute */
554 _ipp_value_t
*value
; /* Current value */
557 DEBUG_printf(("ippAddIntegers(ipp=%p, group=%02x(%s), type=%02x(%s), "
558 "name=\"%s\", num_values=%d, values=%p)", ipp
,
559 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
560 num_values
, values
));
562 value_tag
&= IPP_TAG_MASK
;
565 * Range check input...
569 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
570 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
571 (value_tag
!= IPP_TAG_INTEGER
&& value_tag
!= IPP_TAG_ENUM
) ||
575 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
576 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
582 * Create the attribute...
585 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, num_values
)) == NULL
)
590 for (i
= num_values
, value
= attr
->values
;
593 value
->integer
= *values
++;
601 * 'ippAddOctetString()' - Add an octetString value to an IPP message.
603 * The @code ipp@ parameter refers to an IPP message previously created using the
604 * @link ippNew@ or @link ippNewRequest@ functions.
606 * The @code group@ parameter specifies the IPP attribute group tag: none
607 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
608 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
609 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
610 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
612 * @since CUPS 1.2/OS X 10.5@
615 ipp_attribute_t
* /* O - New attribute */
616 ippAddOctetString(ipp_t
*ipp
, /* I - IPP message */
617 ipp_tag_t group
, /* I - IPP group */
618 const char *name
, /* I - Name of attribute */
619 const void *data
, /* I - octetString data */
620 int datalen
) /* I - Length of data in bytes */
622 ipp_attribute_t
*attr
; /* New attribute */
625 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
626 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
629 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_STRING
, 1)) == NULL
)
633 * Initialize the attribute data...
636 attr
->values
[0].unknown
.length
= datalen
;
640 if ((attr
->values
[0].unknown
.data
= malloc(datalen
)) == NULL
)
642 ippDeleteAttribute(ipp
, attr
);
646 memcpy(attr
->values
[0].unknown
.data
, data
, datalen
);
650 * Return the new attribute...
658 * 'ippAddOutOfBand()' - Add an out-of-band value to an IPP message.
660 * The @code ipp@ parameter refers to an IPP message previously created using the
661 * @link ippNew@ or @link ippNewRequest@ functions.
663 * The @code group@ parameter specifies the IPP attribute group tag: none
664 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
665 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
666 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
667 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
669 * Supported out-of-band values include unsupported-value
670 * (@code IPP_TAG_UNSUPPORTED_VALUE@), default (@code IPP_TAG_DEFAULT@), unknown
671 * (@code IPP_TAG_UNKNOWN@), no-value (@code IPP_TAG_NOVALUE@), not-settable
672 * (@code IPP_TAG_NOTSETTABLE@), delete-attribute (@code IPP_TAG_DELETEATTR@), and
673 * admin-define (@code IPP_TAG_ADMINDEFINE@).
675 * @since CUPS 1.6/OS X 10.8@
678 ipp_attribute_t
* /* O - New attribute */
679 ippAddOutOfBand(ipp_t
*ipp
, /* I - IPP message */
680 ipp_tag_t group
, /* I - IPP group */
681 ipp_tag_t value_tag
, /* I - Type of attribute */
682 const char *name
) /* I - Name of attribute */
684 DEBUG_printf(("ippAddOutOfBand(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
685 "name=\"%s\")", ipp
, group
, ippTagString(group
), value_tag
,
686 ippTagString(value_tag
), name
));
688 value_tag
&= IPP_TAG_MASK
;
691 * Range check input...
694 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
695 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
696 (value_tag
!= IPP_TAG_UNSUPPORTED_VALUE
&&
697 value_tag
!= IPP_TAG_DEFAULT
&&
698 value_tag
!= IPP_TAG_UNKNOWN
&&
699 value_tag
!= IPP_TAG_NOVALUE
&&
700 value_tag
!= IPP_TAG_NOTSETTABLE
&&
701 value_tag
!= IPP_TAG_DELETEATTR
&&
702 value_tag
!= IPP_TAG_ADMINDEFINE
))
706 * Create the attribute...
709 return (ipp_add_attr(ipp
, name
, group
, value_tag
, 1));
714 * 'ippAddRange()' - Add a range of values to an IPP message.
716 * The @code ipp@ parameter refers to an IPP message previously created using the
717 * @link ippNew@ or @link ippNewRequest@ functions.
719 * The @code group@ parameter specifies the IPP attribute group tag: none
720 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
721 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
722 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
723 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
725 * The @code lower@ parameter must be less than or equal to the @code upper@ parameter.
728 ipp_attribute_t
* /* O - New attribute */
729 ippAddRange(ipp_t
*ipp
, /* I - IPP message */
730 ipp_tag_t group
, /* I - IPP group */
731 const char *name
, /* I - Name of attribute */
732 int lower
, /* I - Lower value */
733 int upper
) /* I - Upper value */
735 ipp_attribute_t
*attr
; /* New attribute */
738 DEBUG_printf(("ippAddRange(ipp=%p, group=%02x(%s), name=\"%s\", lower=%d, "
739 "upper=%d)", ipp
, group
, ippTagString(group
), name
, lower
,
743 * Range check input...
746 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
747 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
751 * Create the attribute...
754 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RANGE
, 1)) == NULL
)
757 attr
->values
[0].range
.lower
= lower
;
758 attr
->values
[0].range
.upper
= upper
;
765 * 'ippAddRanges()' - Add ranges of values to an IPP message.
767 * The @code ipp@ parameter refers to an IPP message previously created using the
768 * @link ippNew@ or @link ippNewRequest@ functions.
770 * The @code group@ parameter specifies the IPP attribute group tag: none
771 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
772 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
773 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
774 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
777 ipp_attribute_t
* /* O - New attribute */
778 ippAddRanges(ipp_t
*ipp
, /* I - IPP message */
779 ipp_tag_t group
, /* I - IPP group */
780 const char *name
, /* I - Name of attribute */
781 int num_values
, /* I - Number of values */
782 const int *lower
, /* I - Lower values */
783 const int *upper
) /* I - Upper values */
785 int i
; /* Looping var */
786 ipp_attribute_t
*attr
; /* New attribute */
787 _ipp_value_t
*value
; /* Current value */
790 DEBUG_printf(("ippAddRanges(ipp=%p, group=%02x(%s), name=\"%s\", "
791 "num_values=%d, lower=%p, upper=%p)", ipp
, group
,
792 ippTagString(group
), name
, num_values
, lower
, upper
));
795 * Range check input...
798 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
799 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
804 * Create the attribute...
807 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RANGE
, num_values
)) == NULL
)
812 for (i
= num_values
, value
= attr
->values
;
816 value
->range
.lower
= *lower
++;
817 value
->range
.upper
= *upper
++;
826 * 'ippAddResolution()' - Add a resolution value to an IPP message.
828 * The @code ipp@ parameter refers to an IPP message previously created using the
829 * @link ippNew@ or @link ippNewRequest@ functions.
831 * The @code group@ parameter specifies the IPP attribute group tag: none
832 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
833 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
834 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
835 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
838 ipp_attribute_t
* /* O - New attribute */
839 ippAddResolution(ipp_t
*ipp
, /* I - IPP message */
840 ipp_tag_t group
, /* I - IPP group */
841 const char *name
, /* I - Name of attribute */
842 ipp_res_t units
, /* I - Units for resolution */
843 int xres
, /* I - X resolution */
844 int yres
) /* I - Y resolution */
846 ipp_attribute_t
*attr
; /* New attribute */
849 DEBUG_printf(("ippAddResolution(ipp=%p, group=%02x(%s), name=\"%s\", "
850 "units=%d, xres=%d, yres=%d)", ipp
, group
,
851 ippTagString(group
), name
, units
, xres
, yres
));
854 * Range check input...
857 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
858 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
859 units
< IPP_RES_PER_INCH
|| units
> IPP_RES_PER_CM
||
860 xres
< 0 || yres
< 0)
864 * Create the attribute...
867 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RESOLUTION
, 1)) == NULL
)
870 attr
->values
[0].resolution
.xres
= xres
;
871 attr
->values
[0].resolution
.yres
= yres
;
872 attr
->values
[0].resolution
.units
= units
;
879 * 'ippAddResolutions()' - Add resolution values to an IPP message.
881 * The @code ipp@ parameter refers to an IPP message previously created using the
882 * @link ippNew@ or @link ippNewRequest@ functions.
884 * The @code group@ parameter specifies the IPP attribute group tag: none
885 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
886 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
887 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
888 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
891 ipp_attribute_t
* /* O - New attribute */
892 ippAddResolutions(ipp_t
*ipp
, /* I - IPP message */
893 ipp_tag_t group
, /* I - IPP group */
894 const char *name
, /* I - Name of attribute */
895 int num_values
,/* I - Number of values */
896 ipp_res_t units
, /* I - Units for resolution */
897 const int *xres
, /* I - X resolutions */
898 const int *yres
) /* I - Y resolutions */
900 int i
; /* Looping var */
901 ipp_attribute_t
*attr
; /* New attribute */
902 _ipp_value_t
*value
; /* Current value */
905 DEBUG_printf(("ippAddResolutions(ipp=%p, group=%02x(%s), name=\"%s\", "
906 "num_value=%d, units=%d, xres=%p, yres=%p)", ipp
, group
,
907 ippTagString(group
), name
, num_values
, units
, xres
, yres
));
910 * Range check input...
913 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
914 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
916 units
< IPP_RES_PER_INCH
|| units
> IPP_RES_PER_CM
)
920 * Create the attribute...
923 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RESOLUTION
, num_values
)) == NULL
)
928 for (i
= num_values
, value
= attr
->values
;
932 value
->resolution
.xres
= *xres
++;
933 value
->resolution
.yres
= *yres
++;
934 value
->resolution
.units
= units
;
943 * 'ippAddSeparator()' - Add a group separator to an IPP message.
945 * The @code ipp@ parameter refers to an IPP message previously created using the
946 * @link ippNew@ or @link ippNewRequest@ functions.
949 ipp_attribute_t
* /* O - New attribute */
950 ippAddSeparator(ipp_t
*ipp
) /* I - IPP message */
952 DEBUG_printf(("ippAddSeparator(ipp=%p)", ipp
));
955 * Range check input...
962 * Create the attribute...
965 return (ipp_add_attr(ipp
, NULL
, IPP_TAG_ZERO
, IPP_TAG_ZERO
, 0));
970 * 'ippAddString()' - Add a language-encoded string to an IPP message.
972 * The @code ipp@ parameter refers to an IPP message previously created using the
973 * @link ippNew@ or @link ippNewRequest@ functions.
975 * The @code group@ parameter specifies the IPP attribute group tag: none
976 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
977 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
978 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
979 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
981 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
982 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
983 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
984 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
985 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
986 * (@code IPP_TAG_URISCHEME@).
988 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
989 * textWithLanguage string values and must be @code NULL@ for all other string values.
992 ipp_attribute_t
* /* O - New attribute */
993 ippAddString(ipp_t
*ipp
, /* I - IPP message */
994 ipp_tag_t group
, /* I - IPP group */
995 ipp_tag_t value_tag
, /* I - Type of attribute */
996 const char *name
, /* I - Name of attribute */
997 const char *language
, /* I - Language code */
998 const char *value
) /* I - Value */
1000 ipp_tag_t temp_tag
; /* Temporary value tag (masked) */
1001 ipp_attribute_t
*attr
; /* New attribute */
1002 char code
[32]; /* Charset/language code buffer */
1005 DEBUG_printf(("ippAddString(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
1006 "name=\"%s\", language=\"%s\", value=\"%s\")", ipp
,
1007 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
1011 * Range check input...
1014 temp_tag
= (ipp_tag_t
)((int)value_tag
& IPP_TAG_MASK
);
1017 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1018 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1019 (temp_tag
< IPP_TAG_TEXT
&& temp_tag
!= IPP_TAG_TEXTLANG
&&
1020 temp_tag
!= IPP_TAG_NAMELANG
) || temp_tag
> IPP_TAG_MIMETYPE
)
1023 if ((temp_tag
== IPP_TAG_TEXTLANG
|| temp_tag
== IPP_TAG_NAMELANG
)
1024 != (language
!= NULL
))
1027 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1028 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
1033 * See if we need to map charset, language, or locale values...
1036 if (language
&& ((int)value_tag
& IPP_TAG_COPY
) &&
1037 strcmp(language
, ipp_lang_code(language
, code
, sizeof(code
))))
1038 value_tag
= temp_tag
; /* Don't do a fast copy */
1039 else if (value
&& value_tag
== (ipp_tag_t
)(IPP_TAG_CHARSET
| IPP_TAG_COPY
) &&
1040 strcmp(value
, ipp_get_code(value
, code
, sizeof(code
))))
1041 value_tag
= temp_tag
; /* Don't do a fast copy */
1042 else if (value
&& value_tag
== (ipp_tag_t
)(IPP_TAG_LANGUAGE
| IPP_TAG_COPY
) &&
1043 strcmp(value
, ipp_lang_code(value
, code
, sizeof(code
))))
1044 value_tag
= temp_tag
; /* Don't do a fast copy */
1047 * Create the attribute...
1050 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, 1)) == NULL
)
1054 * Initialize the attribute data...
1057 if ((int)value_tag
& IPP_TAG_COPY
)
1059 attr
->values
[0].string
.language
= (char *)language
;
1060 attr
->values
[0].string
.text
= (char *)value
;
1065 attr
->values
[0].string
.language
= _cupsStrAlloc(ipp_lang_code(language
, code
,
1070 if (value_tag
== IPP_TAG_CHARSET
)
1071 attr
->values
[0].string
.text
= _cupsStrAlloc(ipp_get_code(value
, code
,
1073 else if (value_tag
== IPP_TAG_LANGUAGE
)
1074 attr
->values
[0].string
.text
= _cupsStrAlloc(ipp_lang_code(value
, code
,
1077 attr
->values
[0].string
.text
= _cupsStrAlloc(value
);
1086 * 'ippAddStrings()' - Add language-encoded strings to an IPP message.
1088 * The @code ipp@ parameter refers to an IPP message previously created using the
1089 * @link ippNew@ or @link ippNewRequest@ functions.
1091 * The @code group@ parameter specifies the IPP attribute group tag: none
1092 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
1093 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
1094 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
1095 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1097 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1098 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1099 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1100 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1101 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1102 * (@code IPP_TAG_URISCHEME@).
1104 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
1105 * textWithLanguage string values and must be @code NULL@ for all other string values.
1108 ipp_attribute_t
* /* O - New attribute */
1110 ipp_t
*ipp
, /* I - IPP message */
1111 ipp_tag_t group
, /* I - IPP group */
1112 ipp_tag_t value_tag
, /* I - Type of attribute */
1113 const char *name
, /* I - Name of attribute */
1114 int num_values
, /* I - Number of values */
1115 const char *language
, /* I - Language code (@code NULL@ for default) */
1116 const char * const *values
) /* I - Values */
1118 int i
; /* Looping var */
1119 ipp_tag_t temp_tag
; /* Temporary value tag (masked) */
1120 ipp_attribute_t
*attr
; /* New attribute */
1121 _ipp_value_t
*value
; /* Current value */
1122 char code
[32]; /* Language/charset value buffer */
1125 DEBUG_printf(("ippAddStrings(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
1126 "name=\"%s\", num_values=%d, language=\"%s\", values=%p)", ipp
,
1127 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
1128 num_values
, language
, values
));
1131 * Range check input...
1134 temp_tag
= (ipp_tag_t
)((int)value_tag
& IPP_TAG_MASK
);
1137 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1138 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1139 (temp_tag
< IPP_TAG_TEXT
&& temp_tag
!= IPP_TAG_TEXTLANG
&&
1140 temp_tag
!= IPP_TAG_NAMELANG
) || temp_tag
> IPP_TAG_MIMETYPE
||
1144 if ((temp_tag
== IPP_TAG_TEXTLANG
|| temp_tag
== IPP_TAG_NAMELANG
)
1145 != (language
!= NULL
))
1148 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1149 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1155 * See if we need to map charset, language, or locale values...
1158 if (language
&& ((int)value_tag
& IPP_TAG_COPY
) &&
1159 strcmp(language
, ipp_lang_code(language
, code
, sizeof(code
))))
1160 value_tag
= temp_tag
; /* Don't do a fast copy */
1161 else if (values
&& value_tag
== (ipp_tag_t
)(IPP_TAG_CHARSET
| IPP_TAG_COPY
))
1163 for (i
= 0; i
< num_values
; i
++)
1164 if (strcmp(values
[i
], ipp_get_code(values
[i
], code
, sizeof(code
))))
1166 value_tag
= temp_tag
; /* Don't do a fast copy */
1170 else if (values
&& value_tag
== (ipp_tag_t
)(IPP_TAG_LANGUAGE
| IPP_TAG_COPY
))
1172 for (i
= 0; i
< num_values
; i
++)
1173 if (strcmp(values
[i
], ipp_lang_code(values
[i
], code
, sizeof(code
))))
1175 value_tag
= temp_tag
; /* Don't do a fast copy */
1181 * Create the attribute...
1184 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, num_values
)) == NULL
)
1188 * Initialize the attribute data...
1191 for (i
= num_values
, value
= attr
->values
;
1197 if (value
== attr
->values
)
1199 if ((int)value_tag
& IPP_TAG_COPY
)
1200 value
->string
.language
= (char *)language
;
1202 value
->string
.language
= _cupsStrAlloc(ipp_lang_code(language
, code
,
1206 value
->string
.language
= attr
->values
[0].string
.language
;
1211 if ((int)value_tag
& IPP_TAG_COPY
)
1212 value
->string
.text
= (char *)*values
++;
1213 else if (value_tag
== IPP_TAG_CHARSET
)
1214 value
->string
.text
= _cupsStrAlloc(ipp_get_code(*values
++, code
, sizeof(code
)));
1215 else if (value_tag
== IPP_TAG_LANGUAGE
)
1216 value
->string
.text
= _cupsStrAlloc(ipp_lang_code(*values
++, code
, sizeof(code
)));
1218 value
->string
.text
= _cupsStrAlloc(*values
++);
1227 * 'ippCopyAttribute()' - Copy an attribute.
1229 * The specified attribute, @code attr@, is copied to the destination IPP message.
1230 * When @code quickcopy@ is non-zero, a "shallow" reference copy of the attribute is
1231 * created - this should only be done as long as the original source IPP message will
1232 * not be freed for the life of the destination.
1234 * @since CUPS 1.6/OS X 10.8@
1238 ipp_attribute_t
* /* O - New attribute */
1240 ipp_t
*dst
, /* I - Destination IPP message */
1241 ipp_attribute_t
*srcattr
, /* I - Attribute to copy */
1242 int quickcopy
) /* I - 1 for a referenced copy, 0 for normal */
1244 int i
; /* Looping var */
1245 ipp_attribute_t
*dstattr
; /* Destination attribute */
1246 _ipp_value_t
*srcval
, /* Source value */
1247 *dstval
; /* Destination value */
1250 DEBUG_printf(("ippCopyAttribute(dst=%p, srcattr=%p, quickcopy=%d)", dst
, srcattr
,
1254 * Range check input...
1257 if (!dst
|| !srcattr
)
1264 quickcopy
= quickcopy
? IPP_TAG_COPY
: 0;
1266 switch (srcattr
->value_tag
& ~IPP_TAG_COPY
)
1269 dstattr
= ippAddSeparator(dst
);
1272 case IPP_TAG_INTEGER
:
1274 dstattr
= ippAddIntegers(dst
, srcattr
->group_tag
, srcattr
->value_tag
,
1275 srcattr
->name
, srcattr
->num_values
, NULL
);
1279 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1281 i
--, srcval
++, dstval
++)
1282 dstval
->integer
= srcval
->integer
;
1285 case IPP_TAG_BOOLEAN
:
1286 dstattr
= ippAddBooleans(dst
, srcattr
->group_tag
, srcattr
->name
,
1287 srcattr
->num_values
, NULL
);
1291 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1293 i
--, srcval
++, dstval
++)
1294 dstval
->boolean
= srcval
->boolean
;
1299 case IPP_TAG_KEYWORD
:
1301 case IPP_TAG_URISCHEME
:
1302 case IPP_TAG_CHARSET
:
1303 case IPP_TAG_LANGUAGE
:
1304 case IPP_TAG_MIMETYPE
:
1305 dstattr
= ippAddStrings(dst
, srcattr
->group_tag
,
1306 (ipp_tag_t
)(srcattr
->value_tag
| quickcopy
),
1307 srcattr
->name
, srcattr
->num_values
, NULL
, NULL
);
1313 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1314 dstval
= dstattr
->values
;
1316 i
--, srcval
++, dstval
++)
1317 dstval
->string
.text
= srcval
->string
.text
;
1319 else if (srcattr
->value_tag
& IPP_TAG_COPY
)
1321 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1322 dstval
= dstattr
->values
;
1324 i
--, srcval
++, dstval
++)
1325 dstval
->string
.text
= _cupsStrAlloc(srcval
->string
.text
);
1329 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1330 dstval
= dstattr
->values
;
1332 i
--, srcval
++, dstval
++)
1333 dstval
->string
.text
= _cupsStrRetain(srcval
->string
.text
);
1338 if (srcattr
->num_values
!= 1)
1341 dstattr
= ippAddDate(dst
, srcattr
->group_tag
, srcattr
->name
,
1342 srcattr
->values
[0].date
);
1345 case IPP_TAG_RESOLUTION
:
1346 dstattr
= ippAddResolutions(dst
, srcattr
->group_tag
, srcattr
->name
,
1347 srcattr
->num_values
, IPP_RES_PER_INCH
,
1352 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1354 i
--, srcval
++, dstval
++)
1356 dstval
->resolution
.xres
= srcval
->resolution
.xres
;
1357 dstval
->resolution
.yres
= srcval
->resolution
.yres
;
1358 dstval
->resolution
.units
= srcval
->resolution
.units
;
1362 case IPP_TAG_RANGE
:
1363 dstattr
= ippAddRanges(dst
, srcattr
->group_tag
, srcattr
->name
,
1364 srcattr
->num_values
, NULL
, NULL
);
1368 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1370 i
--, srcval
++, dstval
++)
1372 dstval
->range
.lower
= srcval
->range
.lower
;
1373 dstval
->range
.upper
= srcval
->range
.upper
;
1377 case IPP_TAG_TEXTLANG
:
1378 case IPP_TAG_NAMELANG
:
1379 dstattr
= ippAddStrings(dst
, srcattr
->group_tag
,
1380 (ipp_tag_t
)(srcattr
->value_tag
| quickcopy
),
1381 srcattr
->name
, srcattr
->num_values
, NULL
, NULL
);
1387 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1388 dstval
= dstattr
->values
;
1390 i
--, srcval
++, dstval
++)
1392 dstval
->string
.language
= srcval
->string
.language
;
1393 dstval
->string
.text
= srcval
->string
.text
;
1396 else if (srcattr
->value_tag
& IPP_TAG_COPY
)
1398 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1399 dstval
= dstattr
->values
;
1401 i
--, srcval
++, dstval
++)
1403 if (srcval
== srcattr
->values
)
1404 dstval
->string
.language
= _cupsStrAlloc(srcval
->string
.language
);
1406 dstval
->string
.language
= dstattr
->values
[0].string
.language
;
1408 dstval
->string
.text
= _cupsStrAlloc(srcval
->string
.text
);
1413 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1414 dstval
= dstattr
->values
;
1416 i
--, srcval
++, dstval
++)
1418 if (srcval
== srcattr
->values
)
1419 dstval
->string
.language
= _cupsStrRetain(srcval
->string
.language
);
1421 dstval
->string
.language
= dstattr
->values
[0].string
.language
;
1423 dstval
->string
.text
= _cupsStrRetain(srcval
->string
.text
);
1428 case IPP_TAG_BEGIN_COLLECTION
:
1429 dstattr
= ippAddCollections(dst
, srcattr
->group_tag
, srcattr
->name
,
1430 srcattr
->num_values
, NULL
);
1434 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1436 i
--, srcval
++, dstval
++)
1438 dstval
->collection
= srcval
->collection
;
1439 srcval
->collection
->use
++;
1443 case IPP_TAG_STRING
:
1445 /* TODO: Implement quick copy for unknown/octetString values */
1446 dstattr
= ippAddIntegers(dst
, srcattr
->group_tag
, srcattr
->value_tag
,
1447 srcattr
->name
, srcattr
->num_values
, NULL
);
1451 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1453 i
--, srcval
++, dstval
++)
1455 dstval
->unknown
.length
= srcval
->unknown
.length
;
1457 if (dstval
->unknown
.length
> 0)
1459 if ((dstval
->unknown
.data
= malloc(dstval
->unknown
.length
)) == NULL
)
1460 dstval
->unknown
.length
= 0;
1462 memcpy(dstval
->unknown
.data
, srcval
->unknown
.data
, dstval
->unknown
.length
);
1465 break; /* anti-compiler-warning-code */
1473 * 'ippCopyAttributes()' - Copy attributes from one IPP message to another.
1475 * Zero or more attributes are copied from the source IPP message, @code@ src, to the
1476 * destination IPP message, @code dst@. When @code quickcopy@ is non-zero, a "shallow"
1477 * reference copy of the attribute is created - this should only be done as long as the
1478 * original source IPP message will not be freed for the life of the destination.
1480 * The @code cb@ and @code context@ parameters provide a generic way to "filter" the
1481 * attributes that are copied - the function must return 1 to copy the attribute or
1482 * 0 to skip it. The function may also choose to do a partial copy of the source attribute
1485 * @since CUPS 1.6/OS X 10.8@
1488 int /* O - 1 on success, 0 on error */
1490 ipp_t
*dst
, /* I - Destination IPP message */
1491 ipp_t
*src
, /* I - Source IPP message */
1492 int quickcopy
, /* I - 1 for a referenced copy, 0 for normal */
1493 ipp_copycb_t cb
, /* I - Copy callback or @code NULL@ for none */
1494 void *context
) /* I - Context pointer */
1496 ipp_attribute_t
*srcattr
; /* Source attribute */
1499 DEBUG_printf(("ippCopyAttributes(dst=%p, src=%p, quickcopy=%d, cb=%p, context=%p)",
1500 dst
, src
, quickcopy
, cb
, context
));
1503 * Range check input...
1510 * Loop through source attributes and copy as needed...
1513 for (srcattr
= src
->attrs
; srcattr
; srcattr
= srcattr
->next
)
1514 if (!cb
|| (*cb
)(context
, dst
, srcattr
))
1515 if (!ippCopyAttribute(dst
, srcattr
, quickcopy
))
1523 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
1527 time_t /* O - UNIX time value */
1528 ippDateToTime(const ipp_uchar_t
*date
) /* I - RFC 1903 date info */
1530 struct tm unixdate
; /* UNIX date/time info */
1531 time_t t
; /* Computed time */
1537 memset(&unixdate
, 0, sizeof(unixdate
));
1540 * RFC-1903 date/time format is:
1542 * Byte(s) Description
1543 * ------- -----------
1544 * 0-1 Year (0 to 65535)
1548 * 5 Minutes (0 to 59)
1549 * 6 Seconds (0 to 60, 60 = "leap second")
1550 * 7 Deciseconds (0 to 9)
1552 * 9 UTC hours (0 to 11)
1553 * 10 UTC minutes (0 to 59)
1556 unixdate
.tm_year
= ((date
[0] << 8) | date
[1]) - 1900;
1557 unixdate
.tm_mon
= date
[2] - 1;
1558 unixdate
.tm_mday
= date
[3];
1559 unixdate
.tm_hour
= date
[4];
1560 unixdate
.tm_min
= date
[5];
1561 unixdate
.tm_sec
= date
[6];
1563 t
= mktime(&unixdate
);
1566 t
+= date
[9] * 3600 + date
[10] * 60;
1568 t
-= date
[9] * 3600 + date
[10] * 60;
1575 * 'ippDelete()' - Delete an IPP message.
1579 ippDelete(ipp_t
*ipp
) /* I - IPP message */
1581 ipp_attribute_t
*attr
, /* Current attribute */
1582 *next
; /* Next attribute */
1585 DEBUG_printf(("ippDelete(ipp=%p)", ipp
));
1594 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= next
)
1598 ipp_free_values(attr
, 0, attr
->num_values
);
1601 _cupsStrFree(attr
->name
);
1611 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
1613 * @since CUPS 1.1.19/OS X 10.3@
1618 ipp_t
*ipp
, /* I - IPP message */
1619 ipp_attribute_t
*attr
) /* I - Attribute to delete */
1621 ipp_attribute_t
*current
, /* Current attribute */
1622 *prev
; /* Previous attribute */
1625 DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p(%s))", ipp
, attr
,
1626 attr
? attr
->name
: "(null)"));
1629 * Range check input...
1636 * Find the attribute in the list...
1641 for (current
= ipp
->attrs
, prev
= NULL
;
1643 prev
= current
, current
= current
->next
)
1644 if (current
== attr
)
1647 * Found it, remove the attribute from the list...
1651 prev
->next
= current
->next
;
1653 ipp
->attrs
= current
->next
;
1655 if (current
== ipp
->last
)
1666 * Free memory used by the attribute...
1669 ipp_free_values(attr
, 0, attr
->num_values
);
1672 _cupsStrFree(attr
->name
);
1679 * 'ippDeleteValues()' - Delete values in an attribute.
1681 * The @code element@ parameter specifies the first value to delete, starting at
1682 * 0. It must be less than the number of values returned by @link ippGetCount@.
1684 * The @code attr@ parameter may be modified as a result of setting the value.
1686 * Deleting all values in an attribute deletes the attribute.
1688 * @since CUPS 1.6/OS X 10.8@
1691 int /* O - 1 on success, 0 on failure */
1693 ipp_t
*ipp
, /* I - IPP message */
1694 ipp_attribute_t
**attr
, /* IO - Attribute */
1695 int element
, /* I - Index of first value to delete (0-based) */
1696 int count
) /* I - Number of values to delete */
1699 * Range check input...
1702 if (!ipp
|| !attr
|| !*attr
||
1703 element
< 0 || element
>= (*attr
)->num_values
|| count
<= 0 ||
1704 (element
+ count
) >= (*attr
)->num_values
)
1708 * If we are deleting all values, just delete the attribute entirely.
1711 if (count
== (*attr
)->num_values
)
1713 ippDeleteAttribute(ipp
, *attr
);
1719 * Otherwise free the values in question and return.
1722 ipp_free_values(*attr
, element
, count
);
1729 * 'ippFindAttribute()' - Find a named attribute in a request.
1732 ipp_attribute_t
* /* O - Matching attribute */
1733 ippFindAttribute(ipp_t
*ipp
, /* I - IPP message */
1734 const char *name
, /* I - Name of attribute */
1735 ipp_tag_t type
) /* I - Type of attribute */
1737 DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", ipp
,
1738 name
, type
, ippTagString(type
)));
1744 * Reset the current pointer...
1747 ipp
->current
= NULL
;
1750 * Search for the attribute...
1753 return (ippFindNextAttribute(ipp
, name
, type
));
1758 * 'ippFindNextAttribute()' - Find the next named attribute in a request.
1761 ipp_attribute_t
* /* O - Matching attribute */
1762 ippFindNextAttribute(ipp_t
*ipp
, /* I - IPP message */
1763 const char *name
, /* I - Name of attribute */
1764 ipp_tag_t type
) /* I - Type of attribute */
1766 ipp_attribute_t
*attr
; /* Current atttribute */
1767 ipp_tag_t value_tag
; /* Value tag */
1770 DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))",
1771 ipp
, name
, type
, ippTagString(type
)));
1778 ipp
->prev
= ipp
->current
;
1779 attr
= ipp
->current
->next
;
1787 for (; attr
!= NULL
; ipp
->prev
= attr
, attr
= attr
->next
)
1789 DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", attr
,
1792 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_MASK
);
1794 if (attr
->name
!= NULL
&& _cups_strcasecmp(attr
->name
, name
) == 0 &&
1795 (value_tag
== type
|| type
== IPP_TAG_ZERO
||
1796 (value_tag
== IPP_TAG_TEXTLANG
&& type
== IPP_TAG_TEXT
) ||
1797 (value_tag
== IPP_TAG_NAMELANG
&& type
== IPP_TAG_NAME
)))
1799 ipp
->current
= attr
;
1805 ipp
->current
= NULL
;
1813 * 'ippFirstAttribute()' - Return the first attribute in the message.
1815 * @since CUPS 1.6/OS X 10.8@
1818 ipp_attribute_t
* /* O - First attribute or @code NULL@ if none */
1819 ippFirstAttribute(ipp_t
*ipp
) /* I - IPP message */
1822 * Range check input...
1829 * Return the first attribute...
1832 return (ipp
->current
= ipp
->attrs
);
1837 * 'ippGetBoolean()' - Get a boolean value for an attribute.
1839 * The @code element@ parameter specifies which value to get from 0 to
1840 * @link ippGetCount(attr)@ - 1.
1842 * @since CUPS 1.6/OS X 10.8@
1845 int /* O - Boolean value or -1 on error */
1846 ippGetBoolean(ipp_attribute_t
*attr
, /* I - IPP attribute */
1847 int element
) /* I - Value number (0-based) */
1850 * Range check input...
1853 if (!attr
|| attr
->value_tag
!= IPP_TAG_BOOLEAN
||
1854 element
< 0 || element
>= attr
->num_values
)
1858 * Return the value...
1861 return (attr
->values
[element
].boolean
);
1866 * 'ippGetCollection()' - Get a collection value for an attribute.
1868 * The @code element@ parameter specifies which value to get from 0 to
1869 * @link ippGetCount(attr)@ - 1.
1871 * @since CUPS 1.6/OS X 10.8@
1874 ipp_t
* /* O - Collection value or @code NULL@ on error */
1876 ipp_attribute_t
*attr
, /* I - IPP attribute */
1877 int element
) /* I - Value number (0-based) */
1880 * Range check input...
1883 if (!attr
|| attr
->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
1884 element
< 0 || element
>= attr
->num_values
)
1888 * Return the value...
1891 return (attr
->values
[element
].collection
);
1896 * 'ippGetCount()' - Get the number of values in an attribute.
1898 * @since CUPS 1.6/OS X 10.8@
1901 int /* O - Number of values or -1 on error */
1902 ippGetCount(ipp_attribute_t
*attr
) /* I - IPP attribute */
1905 * Range check input...
1912 * Return the number of values...
1915 return (attr
->num_values
);
1920 * 'ippGetDate()' - Get a date value for an attribute.
1922 * The @code element@ parameter specifies which value to get from 0 to
1923 * @link ippGetCount(attr)@ - 1.
1925 * @since CUPS 1.6/OS X 10.8@
1928 const ipp_uchar_t
* /* O - Date value or @code NULL@ */
1929 ippGetDate(ipp_attribute_t
*attr
, /* I - IPP attribute */
1930 int element
) /* I - Value number (0-based) */
1933 * Range check input...
1936 if (!attr
|| attr
->value_tag
!= IPP_TAG_DATE
||
1937 element
< 0 || element
>= attr
->num_values
)
1941 * Return the value...
1944 return (attr
->values
[element
].date
);
1949 * 'ippGetGroupTag()' - Get the group associated with an attribute.
1951 * @since CUPS 1.6/OS X 10.8@
1954 ipp_tag_t
/* O - Group tag or @code IPP_TAG_ZERO@ on error */
1955 ippGetGroupTag(ipp_attribute_t
*attr
) /* I - IPP attribute */
1958 * Range check input...
1962 return (IPP_TAG_ZERO
);
1965 * Return the group...
1968 return (attr
->group_tag
);
1973 * 'ippGetInteger()' - Get the integer/enum value for an attribute.
1975 * The @code element@ parameter specifies which value to get from 0 to
1976 * @link ippGetCount(attr)@ - 1.
1978 * @since CUPS 1.6/OS X 10.8@
1981 int /* O - Value or -1 on error */
1982 ippGetInteger(ipp_attribute_t
*attr
, /* I - IPP attribute */
1983 int element
) /* I - Value number (0-based) */
1986 * Range check input...
1989 if (!attr
|| (attr
->value_tag
!= IPP_TAG_INTEGER
&& attr
->value_tag
!= IPP_TAG_ENUM
) ||
1990 element
< 0 || element
>= attr
->num_values
)
1994 * Return the value...
1997 return (attr
->values
[element
].integer
);
2002 * 'ippGetName()' - Get the attribute name.
2004 * @since CUPS 1.6/OS X 10.8@
2007 const char * /* O - Attribute name or @code NULL@ for separators */
2008 ippGetName(ipp_attribute_t
*attr
) /* I - IPP attribute */
2011 * Range check input...
2018 * Return the name...
2021 return (attr
->name
);
2026 * 'ippGetOperation()' - Get the operation ID in an IPP message.
2028 * @since CUPS 1.6/OS X 10.8@
2031 ipp_op_t
/* O - Operation ID or -1 on error */
2032 ippGetOperation(ipp_t
*ipp
) /* I - IPP request message */
2035 * Range check input...
2039 return ((ipp_op_t
)-1);
2042 * Return the value...
2045 return (ipp
->request
.op
.operation_id
);
2050 * 'ippGetRange()' - Get a rangeOfInteger value from an attribute.
2052 * The @code element@ parameter specifies which value to get from 0 to
2053 * @link ippGetCount(attr)@ - 1.
2055 * @since CUPS 1.6/OS X 10.8@
2058 int /* O - Lower value of range or -1 */
2059 ippGetRange(ipp_attribute_t
*attr
, /* I - IPP attribute */
2060 int element
, /* I - Value number (0-based) */
2061 int *uppervalue
)/* O - Upper value of range */
2064 * Range check input...
2067 if (!attr
|| attr
->value_tag
!= IPP_TAG_RANGE
||
2068 element
< 0 || element
>= attr
->num_values
)
2077 * Return the values...
2081 *uppervalue
= attr
->values
[element
].range
.upper
;
2083 return (attr
->values
[element
].range
.lower
);
2088 * 'ippGetRequestId()' - Get the request ID from an IPP message.
2090 * @since CUPS 1.6/OS X 10.8@
2093 int /* O - Request ID or -1 on error */
2094 ippGetRequestId(ipp_t
*ipp
) /* I - IPP message */
2097 * Range check input...
2104 * Return the request ID...
2107 return (ipp
->request
.any
.request_id
);
2112 * 'ippGetResolution()' - Get a resolution value for an attribute.
2114 * The @code element@ parameter specifies which value to get from 0 to
2115 * @link ippGetCount(attr)@ - 1.
2117 * @since CUPS 1.6/OS X 10.8@
2120 int /* O - Horizontal/cross feed resolution or -1 */
2122 ipp_attribute_t
*attr
, /* I - IPP attribute */
2123 int element
, /* I - Value number (0-based) */
2124 int *yres
, /* O - Vertical/feed resolution */
2125 ipp_res_t
*units
) /* O - Units for resolution */
2128 * Range check input...
2131 if (!attr
|| attr
->value_tag
!= IPP_TAG_RESOLUTION
||
2132 element
< 0 || element
>= attr
->num_values
)
2136 * Return the value...
2140 *yres
= attr
->values
[element
].resolution
.yres
;
2143 *units
= attr
->values
[element
].resolution
.units
;
2145 return (attr
->values
[element
].resolution
.xres
);
2150 * 'ippGetState()' - Get the IPP message state.
2152 * @since CUPS 1.6/OS X 10.8@
2155 ipp_state_t
/* O - IPP message state value */
2156 ippGetState(ipp_t
*ipp
) /* I - IPP message */
2159 * Range check input...
2166 * Return the value...
2169 return (ipp
->state
);
2174 * 'ippGetStatusCode()' - Get the status code from an IPP response or event message.
2176 * @since CUPS 1.6/OS X 10.8@
2179 ipp_status_t
/* O - Status code in IPP message */
2180 ippGetStatusCode(ipp_t
*ipp
) /* I - IPP response or event message */
2183 * Range check input...
2187 return (IPP_INTERNAL_ERROR
);
2190 * Return the value...
2193 return (ipp
->request
.status
.status_code
);
2198 * 'ippGetString()' - Get the string and optionally the language code for an attribute.
2200 * The @code element@ parameter specifies which value to get from 0 to
2201 * @link ippGetCount(attr)@ - 1.
2203 * @since CUPS 1.6/OS X 10.8@
2207 ippGetString(ipp_attribute_t
*attr
, /* I - IPP attribute */
2208 int element
, /* I - Value number (0-based) */
2209 const char **language
)/* O - Language code (@code NULL@ for don't care) */
2212 * Range check input...
2215 if (!attr
|| element
< 0 || element
>= attr
->num_values
||
2216 (attr
->value_tag
!= IPP_TAG_TEXTLANG
&& attr
->value_tag
!= IPP_TAG_NAMELANG
&&
2217 (attr
->value_tag
< IPP_TAG_TEXT
|| attr
->value_tag
> IPP_TAG_MIMETYPE
)))
2221 * Return the value...
2225 *language
= attr
->values
[element
].string
.language
;
2227 return (attr
->values
[element
].string
.text
);
2232 * 'ippGetValueTag()' - Get the value tag for an attribute.
2234 * @since CUPS 1.6/OS X 10.8@
2237 ipp_tag_t
/* O - Value tag or @code IPP_TAG_ZERO@ on error */
2238 ippGetValueTag(ipp_attribute_t
*attr
) /* I - IPP attribute */
2241 * Range check input...
2245 return (IPP_TAG_ZERO
);
2248 * Return the value...
2251 return (attr
->value_tag
);
2256 * 'ippGetVersion()' - Get the major and minor version number from an IPP message.
2258 * @since CUPS 1.6/OS X 10.8@
2261 int /* O - Major version number or -1 on error */
2262 ippGetVersion(ipp_t
*ipp
, /* I - IPP message */
2263 int *minor
) /* O - Minor version number or @code NULL@ */
2266 * Range check input...
2278 * Return the value...
2282 *minor
= ipp
->request
.any
.version
[1];
2284 return (ipp
->request
.any
.version
[0]);
2289 * 'ippLength()' - Compute the length of an IPP message.
2292 size_t /* O - Size of IPP message */
2293 ippLength(ipp_t
*ipp
) /* I - IPP message */
2295 return (ipp_length(ipp
, 0));
2300 * 'ippNextAttribute()' - Return the next attribute in the message.
2302 * @since CUPS 1.6/OS X 10.8@
2305 ipp_attribute_t
* /* O - Next attribute or @code NULL@ if none */
2306 ippNextAttribute(ipp_t
*ipp
) /* I - IPP message */
2309 * Range check input...
2312 if (!ipp
|| !ipp
->current
)
2316 * Return the next attribute...
2319 return (ipp
->current
= ipp
->current
->next
);
2324 * 'ippNew()' - Allocate a new IPP message.
2327 ipp_t
* /* O - New IPP message */
2330 ipp_t
*temp
; /* New IPP message */
2333 DEBUG_puts("ippNew()");
2335 if ((temp
= (ipp_t
*)calloc(1, sizeof(ipp_t
))) != NULL
)
2338 * Default to IPP 2.0...
2341 temp
->request
.any
.version
[0] = 2;
2342 temp
->request
.any
.version
[1] = 0;
2346 DEBUG_printf(("1ippNew: Returning %p", temp
));
2353 * 'ippNewRequest()' - Allocate a new IPP request message.
2355 * The new request message is initialized with the attributes-charset and
2356 * attributes-natural-language attributes added. The
2357 * attributes-natural-language value is derived from the current locale.
2359 * @since CUPS 1.2/OS X 10.5@
2362 ipp_t
* /* O - IPP request message */
2363 ippNewRequest(ipp_op_t op
) /* I - Operation code */
2365 ipp_t
*request
; /* IPP request message */
2366 cups_lang_t
*language
; /* Current language localization */
2367 static int request_id
= 0; /* Current request ID */
2368 static _cups_mutex_t request_mutex
= _CUPS_MUTEX_INITIALIZER
;
2369 /* Mutex for request ID */
2372 DEBUG_printf(("ippNewRequest(op=%02x(%s))", op
, ippOpString(op
)));
2375 * Create a new IPP message...
2378 if ((request
= ippNew()) == NULL
)
2382 * Set the operation and request ID...
2385 _cupsMutexLock(&request_mutex
);
2387 request
->request
.op
.operation_id
= op
;
2388 request
->request
.op
.request_id
= ++request_id
;
2390 _cupsMutexUnlock(&request_mutex
);
2393 * Use UTF-8 as the character set...
2396 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2397 "attributes-charset", NULL
, "utf-8");
2400 * Get the language from the current locale...
2403 language
= cupsLangDefault();
2405 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2406 "attributes-natural-language", NULL
, language
->language
);
2409 * Return the new request...
2417 * 'ippRead()' - Read data for an IPP message from a HTTP connection.
2420 ipp_state_t
/* O - Current state */
2421 ippRead(http_t
*http
, /* I - HTTP connection */
2422 ipp_t
*ipp
) /* I - IPP data */
2424 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT
,
2425 http
, ipp
, CUPS_LLCAST (http
? http
->data_remaining
: -1)));
2430 DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http
->state
,
2433 return (ippReadIO(http
, (ipp_iocb_t
)ipp_read_http
, http
->blocking
, NULL
,
2439 * 'ippReadFile()' - Read data for an IPP message from a file.
2441 * @since CUPS 1.1.19/OS X 10.3@
2444 ipp_state_t
/* O - Current state */
2445 ippReadFile(int fd
, /* I - HTTP data */
2446 ipp_t
*ipp
) /* I - IPP data */
2448 DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd
, ipp
));
2450 return (ippReadIO(&fd
, (ipp_iocb_t
)ipp_read_file
, 1, NULL
, ipp
));
2455 * 'ippReadIO()' - Read data for an IPP message.
2457 * @since CUPS 1.2/OS X 10.5@
2460 ipp_state_t
/* O - Current state */
2461 ippReadIO(void *src
, /* I - Data source */
2462 ipp_iocb_t cb
, /* I - Read callback function */
2463 int blocking
, /* I - Use blocking IO? */
2464 ipp_t
*parent
, /* I - Parent request, if any */
2465 ipp_t
*ipp
) /* I - IPP data */
2467 int n
; /* Length of data */
2468 unsigned char *buffer
, /* Data buffer */
2469 string
[IPP_MAX_NAME
],
2470 /* Small string buffer */
2471 *bufptr
; /* Pointer into buffer */
2472 ipp_attribute_t
*attr
; /* Current attribute */
2473 ipp_tag_t tag
; /* Current tag */
2474 ipp_tag_t value_tag
; /* Current value tag */
2475 _ipp_value_t
*value
; /* Current value */
2478 DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
2479 src
, cb
, blocking
, parent
, ipp
));
2480 DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp
? ipp
->state
: IPP_ERROR
));
2485 if ((buffer
= (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE
)) == NULL
)
2487 DEBUG_puts("1ippReadIO: Unable to get read buffer.");
2494 ipp
->state
++; /* Avoid common problem... */
2500 * Get the request header...
2503 if ((*cb
)(src
, buffer
, 8) < 8)
2505 DEBUG_puts("1ippReadIO: Unable to read header.");
2506 _cupsBufferRelease((char *)buffer
);
2511 * Then copy the request header over...
2514 ipp
->request
.any
.version
[0] = buffer
[0];
2515 ipp
->request
.any
.version
[1] = buffer
[1];
2516 ipp
->request
.any
.op_status
= (buffer
[2] << 8) | buffer
[3];
2517 ipp
->request
.any
.request_id
= (((((buffer
[4] << 8) | buffer
[5]) << 8) |
2518 buffer
[6]) << 8) | buffer
[7];
2520 DEBUG_printf(("2ippReadIO: version=%d.%d", buffer
[0], buffer
[1]));
2521 DEBUG_printf(("2ippReadIO: op_status=%04x",
2522 ipp
->request
.any
.op_status
));
2523 DEBUG_printf(("2ippReadIO: request_id=%d",
2524 ipp
->request
.any
.request_id
));
2527 ipp
->state
= IPP_ATTRIBUTE
;
2528 ipp
->current
= NULL
;
2529 ipp
->curtag
= IPP_TAG_ZERO
;
2530 ipp
->prev
= ipp
->last
;
2533 * If blocking is disabled, stop here...
2539 case IPP_ATTRIBUTE
:
2542 if ((*cb
)(src
, buffer
, 1) < 1)
2544 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
2545 _cupsBufferRelease((char *)buffer
);
2549 DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p",
2550 ipp
->current
, ipp
->prev
));
2553 * Read this attribute...
2556 tag
= (ipp_tag_t
)buffer
[0];
2557 if (tag
== IPP_TAG_EXTENSION
)
2560 * Read 32-bit "extension" tag...
2563 if ((*cb
)(src
, buffer
, 4) < 1)
2565 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
2566 _cupsBufferRelease((char *)buffer
);
2570 tag
= (ipp_tag_t
)((((((buffer
[0] << 8) | buffer
[1]) << 8) |
2571 buffer
[2]) << 8) | buffer
[3]);
2573 if (tag
& IPP_TAG_COPY
)
2576 * Fail if the high bit is set in the tag...
2579 _cupsSetError(IPP_INTERNAL_ERROR
, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
2580 DEBUG_printf(("1ippReadIO: bad name length %d.", n
));
2581 _cupsBufferRelease((char *)buffer
);
2586 if (tag
== IPP_TAG_END
)
2589 * No more attributes left...
2592 DEBUG_puts("2ippReadIO: IPP_TAG_END.");
2594 ipp
->state
= IPP_DATA
;
2597 else if (tag
< IPP_TAG_UNSUPPORTED_VALUE
)
2600 * Group tag... Set the current group and continue...
2603 if (ipp
->curtag
== tag
)
2604 ipp
->prev
= ippAddSeparator(ipp
);
2605 else if (ipp
->current
)
2606 ipp
->prev
= ipp
->current
;
2609 ipp
->current
= NULL
;
2610 DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag
,
2611 ippTagString(tag
), ipp
->prev
));
2615 DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag
,
2616 ippTagString(tag
)));
2622 if ((*cb
)(src
, buffer
, 2) < 2)
2624 DEBUG_puts("1ippReadIO: unable to read name length.");
2625 _cupsBufferRelease((char *)buffer
);
2629 n
= (buffer
[0] << 8) | buffer
[1];
2631 if (n
>= IPP_BUF_SIZE
)
2633 _cupsSetError(IPP_INTERNAL_ERROR
, _("IPP name larger than 32767 bytes."), 1);
2634 DEBUG_printf(("1ippReadIO: bad name length %d.", n
));
2635 _cupsBufferRelease((char *)buffer
);
2639 DEBUG_printf(("2ippReadIO: name length=%d", n
));
2641 if (n
== 0 && tag
!= IPP_TAG_MEMBERNAME
&&
2642 tag
!= IPP_TAG_END_COLLECTION
)
2645 * More values for current attribute...
2648 if (ipp
->current
== NULL
)
2650 _cupsSetError(IPP_INTERNAL_ERROR
, _("IPP attribute has no name."), 1);
2651 DEBUG_puts("1ippReadIO: Attribute without name and no current.");
2652 _cupsBufferRelease((char *)buffer
);
2656 attr
= ipp
->current
;
2657 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_MASK
);
2660 * Make sure we aren't adding a new value of a different
2664 if (value_tag
== IPP_TAG_ZERO
)
2667 * Setting the value of a collection member...
2670 attr
->value_tag
= tag
;
2672 else if (value_tag
== IPP_TAG_TEXTLANG
||
2673 value_tag
== IPP_TAG_NAMELANG
||
2674 (value_tag
>= IPP_TAG_TEXT
&&
2675 value_tag
<= IPP_TAG_MIMETYPE
))
2678 * String values can sometimes come across in different
2679 * forms; accept sets of differing values...
2682 if (tag
!= IPP_TAG_TEXTLANG
&& tag
!= IPP_TAG_NAMELANG
&&
2683 (tag
< IPP_TAG_TEXT
|| tag
> IPP_TAG_MIMETYPE
) &&
2684 tag
!= IPP_TAG_NOVALUE
)
2686 _cupsSetError(IPP_INTERNAL_ERROR
,
2687 _("IPP 1setOf attribute with incompatible value "
2689 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
2690 value_tag
, ippTagString(value_tag
), tag
,
2691 ippTagString(tag
)));
2692 _cupsBufferRelease((char *)buffer
);
2696 if (value_tag
!= tag
)
2698 DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.",
2699 attr
->name
, ippTagString(value_tag
), ippTagString(tag
)));
2700 ippSetValueTag(ipp
, &attr
, tag
);
2703 else if (value_tag
== IPP_TAG_INTEGER
||
2704 value_tag
== IPP_TAG_RANGE
)
2707 * Integer and rangeOfInteger values can sometimes be mixed; accept
2708 * sets of differing values...
2711 if (tag
!= IPP_TAG_INTEGER
&& tag
!= IPP_TAG_RANGE
)
2713 _cupsSetError(IPP_INTERNAL_ERROR
,
2714 _("IPP 1setOf attribute with incompatible value "
2716 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
2717 value_tag
, ippTagString(value_tag
), tag
,
2718 ippTagString(tag
)));
2719 _cupsBufferRelease((char *)buffer
);
2723 if (value_tag
== IPP_TAG_INTEGER
&& tag
== IPP_TAG_RANGE
)
2726 * Convert integer values to rangeOfInteger values...
2729 DEBUG_printf(("1ippReadIO: Converting %s attribute to "
2730 "rangeOfInteger.", attr
->name
));
2731 ippSetValueTag(ipp
, &attr
, IPP_TAG_RANGE
);
2734 else if (value_tag
!= tag
)
2736 _cupsSetError(IPP_INTERNAL_ERROR
,
2737 _("IPP 1setOf attribute with incompatible value "
2739 DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
2740 value_tag
, ippTagString(value_tag
), tag
,
2741 ippTagString(tag
)));
2742 _cupsBufferRelease((char *)buffer
);
2747 * Finally, reallocate the attribute array as needed...
2750 if ((value
= ipp_set_value(ipp
, &attr
, attr
->num_values
)) == NULL
)
2752 _cupsBufferRelease((char *)buffer
);
2756 else if (tag
== IPP_TAG_MEMBERNAME
)
2759 * Name must be length 0!
2764 _cupsSetError(IPP_INTERNAL_ERROR
, _("IPP member name is not empty."), 1);
2765 DEBUG_puts("1ippReadIO: member name not empty.");
2766 _cupsBufferRelease((char *)buffer
);
2771 ipp
->prev
= ipp
->current
;
2773 attr
= ipp
->current
= ipp_add_attr(ipp
, NULL
, ipp
->curtag
, IPP_TAG_ZERO
, 1);
2775 DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p",
2776 ipp
->current
, ipp
->prev
));
2778 value
= attr
->values
;
2780 else if (tag
!= IPP_TAG_END_COLLECTION
)
2783 * New attribute; read the name and add it...
2786 if ((*cb
)(src
, buffer
, n
) < n
)
2788 DEBUG_puts("1ippReadIO: unable to read name.");
2789 _cupsBufferRelease((char *)buffer
);
2796 ipp
->prev
= ipp
->current
;
2798 if ((attr
= ipp
->current
= ipp_add_attr(ipp
, (char *)buffer
, ipp
->curtag
, tag
,
2801 _cupsSetHTTPError(HTTP_ERROR
);
2802 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
2803 _cupsBufferRelease((char *)buffer
);
2807 DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, "
2808 "ipp->prev=%p", buffer
, ipp
->current
, ipp
->prev
));
2810 value
= attr
->values
;
2818 if ((*cb
)(src
, buffer
, 2) < 2)
2820 DEBUG_puts("1ippReadIO: unable to read value length.");
2821 _cupsBufferRelease((char *)buffer
);
2825 n
= (buffer
[0] << 8) | buffer
[1];
2826 DEBUG_printf(("2ippReadIO: value length=%d", n
));
2828 if (n
>= IPP_BUF_SIZE
)
2830 _cupsSetError(IPP_INTERNAL_ERROR
,
2831 _("IPP value larger than 32767 bytes."), 1);
2832 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2833 _cupsBufferRelease((char *)buffer
);
2839 case IPP_TAG_INTEGER
:
2843 if (tag
== IPP_TAG_INTEGER
)
2844 _cupsSetError(IPP_INTERNAL_ERROR
,
2845 _("IPP integer value not 4 bytes."), 1);
2847 _cupsSetError(IPP_INTERNAL_ERROR
,
2848 _("IPP enum value not 4 bytes."), 1);
2849 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2850 _cupsBufferRelease((char *)buffer
);
2854 if ((*cb
)(src
, buffer
, 4) < 4)
2856 DEBUG_puts("1ippReadIO: Unable to read integer value.");
2857 _cupsBufferRelease((char *)buffer
);
2861 n
= (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
2864 if (attr
->value_tag
== IPP_TAG_RANGE
)
2865 value
->range
.lower
= value
->range
.upper
= n
;
2870 case IPP_TAG_BOOLEAN
:
2873 _cupsSetError(IPP_INTERNAL_ERROR
, _("IPP boolean value not 1 byte."),
2875 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2876 _cupsBufferRelease((char *)buffer
);
2880 if ((*cb
)(src
, buffer
, 1) < 1)
2882 DEBUG_puts("1ippReadIO: Unable to read boolean value.");
2883 _cupsBufferRelease((char *)buffer
);
2887 value
->boolean
= buffer
[0];
2890 case IPP_TAG_NOVALUE
:
2891 case IPP_TAG_NOTSETTABLE
:
2892 case IPP_TAG_DELETEATTR
:
2893 case IPP_TAG_ADMINDEFINE
:
2895 * These value types are not supposed to have values, however
2896 * some vendors (Brother) do not implement IPP correctly and so
2897 * we need to map non-empty values to text...
2900 if (attr
->value_tag
== tag
)
2905 attr
->value_tag
= IPP_TAG_TEXT
;
2910 case IPP_TAG_KEYWORD
:
2912 case IPP_TAG_URISCHEME
:
2913 case IPP_TAG_CHARSET
:
2914 case IPP_TAG_LANGUAGE
:
2915 case IPP_TAG_MIMETYPE
:
2916 if ((*cb
)(src
, buffer
, n
) < n
)
2918 DEBUG_puts("1ippReadIO: unable to read string value.");
2919 _cupsBufferRelease((char *)buffer
);
2924 value
->string
.text
= _cupsStrAlloc((char *)buffer
);
2925 DEBUG_printf(("2ippReadIO: value=\"%s\"", value
->string
.text
));
2931 _cupsSetError(IPP_INTERNAL_ERROR
, _("IPP date value not 11 bytes."), 1);
2932 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2933 _cupsBufferRelease((char *)buffer
);
2937 if ((*cb
)(src
, value
->date
, 11) < 11)
2939 DEBUG_puts("1ippReadIO: Unable to read date value.");
2940 _cupsBufferRelease((char *)buffer
);
2945 case IPP_TAG_RESOLUTION
:
2948 _cupsSetError(IPP_INTERNAL_ERROR
,
2949 _("IPP resolution value not 9 bytes."), 1);
2950 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2951 _cupsBufferRelease((char *)buffer
);
2955 if ((*cb
)(src
, buffer
, 9) < 9)
2957 DEBUG_puts("1ippReadIO: Unable to read resolution value.");
2958 _cupsBufferRelease((char *)buffer
);
2962 value
->resolution
.xres
=
2963 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
2965 value
->resolution
.yres
=
2966 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
2968 value
->resolution
.units
=
2969 (ipp_res_t
)buffer
[8];
2972 case IPP_TAG_RANGE
:
2975 _cupsSetError(IPP_INTERNAL_ERROR
,
2976 _("IPP rangeOfInteger value not 8 bytes."), 1);
2977 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2978 _cupsBufferRelease((char *)buffer
);
2982 if ((*cb
)(src
, buffer
, 8) < 8)
2984 DEBUG_puts("1ippReadIO: Unable to read range value.");
2985 _cupsBufferRelease((char *)buffer
);
2989 value
->range
.lower
=
2990 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
2992 value
->range
.upper
=
2993 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
2997 case IPP_TAG_TEXTLANG
:
2998 case IPP_TAG_NAMELANG
:
3001 if (tag
== IPP_TAG_TEXTLANG
)
3002 _cupsSetError(IPP_INTERNAL_ERROR
,
3003 _("IPP textWithLanguage value less than "
3004 "minimum 4 bytes."), 1);
3006 _cupsSetError(IPP_INTERNAL_ERROR
,
3007 _("IPP nameWithLanguage value less than "
3008 "minimum 4 bytes."), 1);
3009 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
3010 _cupsBufferRelease((char *)buffer
);
3014 if ((*cb
)(src
, buffer
, n
) < n
)
3016 DEBUG_puts("1ippReadIO: Unable to read string w/language "
3018 _cupsBufferRelease((char *)buffer
);
3025 * text-with-language and name-with-language are composite
3034 n
= (bufptr
[0] << 8) | bufptr
[1];
3036 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
) ||
3037 n
>= sizeof(string
))
3039 _cupsSetError(IPP_INTERNAL_ERROR
,
3040 _("IPP language length overflows value."), 1);
3041 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
3042 _cupsBufferRelease((char *)buffer
);
3046 memcpy(string
, bufptr
+ 2, n
);
3049 value
->string
.language
= _cupsStrAlloc((char *)string
);
3052 n
= (bufptr
[0] << 8) | bufptr
[1];
3054 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
))
3056 _cupsSetError(IPP_INTERNAL_ERROR
,
3057 _("IPP string length overflows value."), 1);
3058 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
3059 _cupsBufferRelease((char *)buffer
);
3063 bufptr
[2 + n
] = '\0';
3064 value
->string
.text
= _cupsStrAlloc((char *)bufptr
+ 2);
3067 case IPP_TAG_BEGIN_COLLECTION
:
3069 * Oh, boy, here comes a collection value, so read it...
3072 value
->collection
= ippNew();
3076 _cupsSetError(IPP_INTERNAL_ERROR
,
3077 _("IPP begCollection value not 0 bytes."), 1);
3078 DEBUG_puts("1ippReadIO: begCollection tag with value length "
3080 _cupsBufferRelease((char *)buffer
);
3084 if (ippReadIO(src
, cb
, 1, ipp
, value
->collection
) == IPP_ERROR
)
3086 DEBUG_puts("1ippReadIO: Unable to read collection value.");
3087 _cupsBufferRelease((char *)buffer
);
3092 case IPP_TAG_END_COLLECTION
:
3093 _cupsBufferRelease((char *)buffer
);
3097 _cupsSetError(IPP_INTERNAL_ERROR
,
3098 _("IPP endCollection value not 0 bytes."), 1);
3099 DEBUG_puts("1ippReadIO: endCollection tag with value length "
3104 DEBUG_puts("1ippReadIO: endCollection tag...");
3105 return (ipp
->state
= IPP_DATA
);
3107 case IPP_TAG_MEMBERNAME
:
3109 * The value the name of the member in the collection, which
3110 * we need to carry over...
3113 if ((*cb
)(src
, buffer
, n
) < n
)
3115 DEBUG_puts("1ippReadIO: Unable to read member name value.");
3116 _cupsBufferRelease((char *)buffer
);
3121 attr
->name
= _cupsStrAlloc((char *)buffer
);
3124 * Since collection members are encoded differently than
3125 * regular attributes, make sure we don't start with an
3129 attr
->num_values
--;
3131 DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr
->name
));
3134 default : /* Other unsupported values */
3135 value
->unknown
.length
= n
;
3138 if ((value
->unknown
.data
= malloc(n
)) == NULL
)
3140 _cupsSetHTTPError(HTTP_ERROR
);
3141 DEBUG_puts("1ippReadIO: Unable to allocate value");
3142 _cupsBufferRelease((char *)buffer
);
3146 if ((*cb
)(src
, value
->unknown
.data
, n
) < n
)
3148 DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
3149 _cupsBufferRelease((char *)buffer
);
3154 value
->unknown
.data
= NULL
;
3159 * If blocking is disabled, stop here...
3171 break; /* anti-compiler-warning-code */
3174 DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp
->state
));
3175 _cupsBufferRelease((char *)buffer
);
3177 return (ipp
->state
);
3182 * 'ippSetBoolean()' - Set a boolean value in an attribute.
3184 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3185 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3187 * The @code attr@ parameter may be modified as a result of setting the value.
3189 * The @code element@ parameter specifies which value to set from 0 to
3190 * @link ippGetCount(attr)@.
3192 * @since CUPS 1.6/OS X 10.8@
3195 int /* O - 1 on success, 0 on failure */
3196 ippSetBoolean(ipp_t
*ipp
, /* IO - IPP message */
3197 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3198 int element
, /* I - Value number (0-based) */
3199 int boolvalue
)/* I - Boolean value */
3201 _ipp_value_t
*value
; /* Current value */
3205 * Range check input...
3208 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BOOLEAN
||
3209 element
< 0 || element
> (*attr
)->num_values
)
3213 * Set the value and return...
3216 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3217 value
->boolean
= boolvalue
;
3219 return (value
!= NULL
);
3224 * 'ippSetCollection()' - Set a collection value in an attribute.
3226 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3227 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3229 * The @code attr@ parameter may be modified as a result of setting the value.
3231 * The @code element@ parameter specifies which value to set from 0 to
3232 * @link ippGetCount(attr)@.
3234 * @since CUPS 1.6/OS X 10.8@
3237 int /* O - 1 on success, 0 on failure */
3239 ipp_t
*ipp
, /* IO - IPP message */
3240 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3241 int element
, /* I - Value number (0-based) */
3242 ipp_t
*colvalue
) /* I - Collection value */
3244 _ipp_value_t
*value
; /* Current value */
3248 * Range check input...
3251 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
3252 element
< 0 || element
> (*attr
)->num_values
|| !colvalue
)
3256 * Set the value and return...
3259 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3261 if (value
->collection
)
3262 ippDelete(value
->collection
);
3264 value
->collection
= colvalue
;
3268 return (value
!= NULL
);
3273 * 'ippSetDate()' - Set a date value in an attribute.
3275 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3276 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3278 * The @code attr@ parameter may be modified as a result of setting the value.
3280 * The @code element@ parameter specifies which value to set from 0 to
3281 * @link ippGetCount(attr)@.
3283 * @since CUPS 1.6/OS X 10.8@
3286 int /* O - 1 on success, 0 on failure */
3287 ippSetDate(ipp_t
*ipp
, /* IO - IPP message */
3288 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3289 int element
, /* I - Value number (0-based) */
3290 const ipp_uchar_t
*datevalue
)/* I - Date value */
3292 _ipp_value_t
*value
; /* Current value */
3296 * Range check input...
3299 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_DATE
||
3300 element
< 0 || element
> (*attr
)->num_values
|| !datevalue
)
3304 * Set the value and return...
3307 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3308 memcpy(value
->date
, datevalue
, sizeof(value
->date
));
3310 return (value
!= NULL
);
3315 * 'ippSetGroupTag()' - Set the group tag of an attribute.
3317 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3318 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3320 * The @code attr@ parameter may be modified as a result of setting the value.
3322 * The @code group@ parameter specifies the IPP attribute group tag: none
3323 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
3324 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
3325 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
3326 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
3328 * @since CUPS 1.6/OS X 10.8@
3331 int /* O - 1 on success, 0 on failure */
3333 ipp_t
*ipp
, /* IO - IPP message */
3334 ipp_attribute_t
**attr
, /* IO - Attribute */
3335 ipp_tag_t group_tag
) /* I - Group tag */
3338 * Range check input - group tag must be 0x01 to 0x0F, per RFC 2911...
3341 if (!ipp
|| !attr
|| group_tag
< IPP_TAG_ZERO
|| group_tag
== IPP_TAG_END
||
3342 group_tag
>= IPP_TAG_UNSUPPORTED_VALUE
)
3346 * Set the group tag and return...
3349 (*attr
)->group_tag
= group_tag
;
3356 * 'ippSetInteger()' - Set an integer or enum value in an attribute.
3358 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3359 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3361 * The @code attr@ parameter may be modified as a result of setting the value.
3363 * The @code element@ parameter specifies which value to set from 0 to
3364 * @link ippGetCount(attr)@.
3366 * @since CUPS 1.6/OS X 10.8@
3369 int /* O - 1 on success, 0 on failure */
3370 ippSetInteger(ipp_t
*ipp
, /* IO - IPP message */
3371 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3372 int element
, /* I - Value number (0-based) */
3373 int intvalue
) /* I - Integer/enum value */
3375 _ipp_value_t
*value
; /* Current value */
3379 * Range check input...
3382 if (!ipp
|| !attr
|| !*attr
||
3383 ((*attr
)->value_tag
!= IPP_TAG_INTEGER
&& (*attr
)->value_tag
!= IPP_TAG_ENUM
) ||
3384 element
< 0 || element
> (*attr
)->num_values
)
3388 * Set the value and return...
3391 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3392 value
->integer
= intvalue
;
3394 return (value
!= NULL
);
3399 * 'ippSetName()' - Set the name of an attribute.
3401 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3402 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3404 * The @code attr@ parameter may be modified as a result of setting the value.
3406 * @since CUPS 1.6/OS X 10.8@
3409 int /* O - 1 on success, 0 on failure */
3410 ippSetName(ipp_t
*ipp
, /* IO - IPP message */
3411 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3412 const char *name
) /* I - Attribute name */
3414 char *temp
; /* Temporary name value */
3418 * Range check input...
3421 if (!ipp
|| !attr
|| !*attr
)
3425 * Set the value and return...
3428 if ((temp
= _cupsStrAlloc(name
)) != NULL
)
3431 _cupsStrFree((*attr
)->name
);
3433 (*attr
)->name
= temp
;
3436 return (temp
!= NULL
);
3441 * 'ippSetOperation()' - Set the operation ID in an IPP request message.
3443 * The @code ipp@ parameter refers to an IPP message previously created using the
3444 * @link ippNew@ or @link ippNewRequest@ functions.
3446 * @since CUPS 1.6/OS X 10.8@
3449 int /* O - 1 on success, 0 on failure */
3450 ippSetOperation(ipp_t
*ipp
, /* I - IPP request message */
3451 ipp_op_t op
) /* I - Operation ID */
3454 * Range check input...
3461 * Set the operation and return...
3464 ipp
->request
.op
.operation_id
= op
;
3471 * 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
3473 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3474 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3476 * The @code attr@ parameter may be modified as a result of setting the value.
3478 * The @code element@ parameter specifies which value to set from 0 to
3479 * @link ippGetCount(attr)@.
3481 * @since CUPS 1.6/OS X 10.8@
3484 int /* O - 1 on success, 0 on failure */
3485 ippSetRange(ipp_t
*ipp
, /* IO - IPP message */
3486 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3487 int element
, /* I - Value number (0-based) */
3488 int lowervalue
, /* I - Lower bound for range */
3489 int uppervalue
) /* I - Upper bound for range */
3491 _ipp_value_t
*value
; /* Current value */
3495 * Range check input...
3498 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RANGE
||
3499 element
< 0 || element
> (*attr
)->num_values
|| lowervalue
> uppervalue
)
3503 * Set the value and return...
3506 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3508 value
->range
.lower
= lowervalue
;
3509 value
->range
.upper
= uppervalue
;
3512 return (value
!= NULL
);
3517 * 'ippSetRequestId()' - Set the request ID in an IPP message.
3519 * The @code ipp@ parameter refers to an IPP message previously created using the
3520 * @link ippNew@ or @link ippNewRequest@ functions.
3522 * The @code request_id@ parameter must be greater than 0.
3524 * @since CUPS 1.6/OS X 10.8@
3527 int /* O - 1 on success, 0 on failure */
3528 ippSetRequestId(ipp_t
*ipp
, /* I - IPP message */
3529 int request_id
) /* I - Request ID */
3532 * Range check input; not checking request_id values since ipptool wants to send
3533 * invalid values for conformance testing and a bad request_id does not affect the
3534 * encoding of a message...
3541 * Set the request ID and return...
3544 ipp
->request
.any
.request_id
= request_id
;
3551 * 'ippSetResolution()' - Set a resolution value in an attribute.
3553 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3554 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3556 * The @code attr@ parameter may be modified as a result of setting the value.
3558 * The @code element@ parameter specifies which value to set from 0 to
3559 * @link ippGetCount(attr)@.
3561 * @since CUPS 1.6/OS X 10.8@
3564 int /* O - 1 on success, 0 on failure */
3566 ipp_t
*ipp
, /* IO - IPP message */
3567 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3568 int element
, /* I - Value number (0-based) */
3569 ipp_res_t unitsvalue
, /* I - Resolution units */
3570 int xresvalue
, /* I - Horizontal/cross feed resolution */
3571 int yresvalue
) /* I - Vertical/feed resolution */
3573 _ipp_value_t
*value
; /* Current value */
3577 * Range check input...
3580 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RESOLUTION
||
3581 element
< 0 || element
> (*attr
)->num_values
|| xresvalue
<= 0 || yresvalue
<= 0 ||
3582 unitsvalue
< IPP_RES_PER_INCH
|| unitsvalue
> IPP_RES_PER_CM
)
3586 * Set the value and return...
3589 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3591 value
->resolution
.units
= unitsvalue
;
3592 value
->resolution
.xres
= xresvalue
;
3593 value
->resolution
.yres
= yresvalue
;
3596 return (value
!= NULL
);
3601 * 'ippSetState()' - Set the current state of the IPP message.
3603 * @since CUPS 1.6/OS X 10.8@
3606 int /* O - 1 on success, 0 on failure */
3607 ippSetState(ipp_t
*ipp
, /* I - IPP message */
3608 ipp_state_t state
) /* I - IPP state value */
3611 * Range check input...
3618 * Set the state and return...
3622 ipp
->current
= NULL
;
3629 * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
3631 * The @code ipp@ parameter refers to an IPP message previously created using the
3632 * @link ippNew@ or @link ippNewRequest@ functions.
3634 * @since CUPS 1.6/OS X 10.8@
3637 int /* O - 1 on success, 0 on failure */
3638 ippSetStatusCode(ipp_t
*ipp
, /* I - IPP response or event message */
3639 ipp_status_t status
) /* I - Status code */
3642 * Range check input...
3649 * Set the status code and return...
3652 ipp
->request
.status
.status_code
= status
;
3659 * 'ippSetString()' - Set a string value in an attribute.
3661 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3662 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3664 * The @code attr@ parameter may be modified as a result of setting the value.
3666 * The @code element@ parameter specifies which value to set from 0 to
3667 * @link ippGetCount(attr)@.
3669 * @since CUPS 1.6/OS X 10.8@
3672 int /* O - 1 on success, 0 on failure */
3673 ippSetString(ipp_t
*ipp
, /* IO - IPP message */
3674 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3675 int element
, /* I - Value number (0-based) */
3676 const char *strvalue
) /* I - String value */
3678 char *temp
; /* Temporary string */
3679 _ipp_value_t
*value
; /* Current value */
3683 * Range check input...
3686 if (!ipp
|| !attr
|| !*attr
||
3687 ((*attr
)->value_tag
!= IPP_TAG_TEXTLANG
&&
3688 (*attr
)->value_tag
!= IPP_TAG_NAMELANG
&&
3689 ((*attr
)->value_tag
< IPP_TAG_TEXT
||
3690 (*attr
)->value_tag
> IPP_TAG_MIMETYPE
)) ||
3691 element
< 0 || element
> (*attr
)->num_values
|| !strvalue
)
3695 * Set the value and return...
3698 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3701 value
->string
.language
= (*attr
)->values
[0].string
.language
;
3703 if ((int)((*attr
)->value_tag
) & IPP_TAG_COPY
)
3704 value
->string
.text
= (char *)strvalue
;
3705 else if ((temp
= _cupsStrAlloc(strvalue
)) != NULL
)
3707 if (value
->string
.text
)
3708 _cupsStrFree(value
->string
.text
);
3710 value
->string
.text
= temp
;
3716 return (value
!= NULL
);
3721 * 'ippSetValueTag()' - Set the value tag of an attribute.
3723 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3724 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3726 * The @code attr@ parameter may be modified as a result of setting the value.
3728 * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger
3729 * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name
3730 * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text
3731 * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage
3732 * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various
3733 * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes
3736 * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language
3737 * code in the "attributes-natural-language" attribute or, if not present, the language
3738 * code for the current locale.
3740 * @since CUPS 1.6/OS X 10.8@
3743 int /* O - 1 on success, 0 on failure */
3745 ipp_t
*ipp
, /* IO - IPP message */
3746 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3747 ipp_tag_t value_tag
) /* I - Value tag */
3749 int i
; /* Looping var */
3750 _ipp_value_t
*value
; /* Current value */
3751 int integer
; /* Current integer value */
3752 cups_lang_t
*language
; /* Current language */
3753 char code
[32]; /* Language code */
3754 ipp_tag_t temp_tag
; /* Temporary value tag */
3758 * Range check input...
3765 * If there is no change, return immediately...
3768 if (value_tag
== (*attr
)->value_tag
)
3772 * Otherwise implement changes as needed...
3775 temp_tag
= (ipp_tag_t
)((int)((*attr
)->value_tag
) & IPP_TAG_MASK
);
3779 case IPP_TAG_UNSUPPORTED_VALUE
:
3780 case IPP_TAG_DEFAULT
:
3781 case IPP_TAG_UNKNOWN
:
3782 case IPP_TAG_NOVALUE
:
3783 case IPP_TAG_NOTSETTABLE
:
3784 case IPP_TAG_DELETEATTR
:
3785 case IPP_TAG_ADMINDEFINE
:
3787 * Free any existing values...
3790 if ((*attr
)->num_values
> 0)
3791 ipp_free_values(*attr
, 0, (*attr
)->num_values
);
3794 * Set out-of-band value...
3797 (*attr
)->value_tag
= value_tag
;
3800 case IPP_TAG_RANGE
:
3801 if (temp_tag
!= IPP_TAG_INTEGER
)
3804 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
3808 integer
= value
->integer
;
3809 value
->range
.lower
= value
->range
.upper
= integer
;
3812 (*attr
)->value_tag
= IPP_TAG_RANGE
;
3816 if (temp_tag
!= IPP_TAG_KEYWORD
&& temp_tag
!= IPP_TAG_URI
&&
3817 temp_tag
!= IPP_TAG_URISCHEME
&& temp_tag
!= IPP_TAG_LANGUAGE
&&
3818 temp_tag
!= IPP_TAG_MIMETYPE
)
3821 (*attr
)->value_tag
= (ipp_tag_t
)(IPP_TAG_NAME
| ((*attr
)->value_tag
& IPP_TAG_COPY
));
3824 case IPP_TAG_NAMELANG
:
3825 case IPP_TAG_TEXTLANG
:
3826 if (value_tag
== IPP_TAG_NAMELANG
&&
3827 (temp_tag
!= IPP_TAG_NAME
&& temp_tag
!= IPP_TAG_KEYWORD
&&
3828 temp_tag
!= IPP_TAG_URI
&& temp_tag
!= IPP_TAG_URISCHEME
&&
3829 temp_tag
!= IPP_TAG_LANGUAGE
&& temp_tag
!= IPP_TAG_MIMETYPE
))
3832 if (value_tag
== IPP_TAG_TEXTLANG
&& temp_tag
!= IPP_TAG_TEXT
)
3835 if (ipp
->attrs
&& ipp
->attrs
->next
&& ipp
->attrs
->next
->name
&&
3836 !strcmp(ipp
->attrs
->next
->name
, "attributes-natural-language"))
3839 * Use the language code from the IPP message...
3842 (*attr
)->values
[0].string
.language
=
3843 _cupsStrAlloc(ipp
->attrs
->next
->values
[0].string
.text
);
3848 * Otherwise, use the language code corresponding to the locale...
3851 language
= cupsLangDefault();
3852 (*attr
)->values
[0].string
.language
= _cupsStrAlloc(ipp_lang_code(language
->language
,
3857 for (i
= (*attr
)->num_values
- 1, value
= (*attr
)->values
+ 1;
3860 value
->string
.language
= (*attr
)->values
[0].string
.language
;
3862 if ((int)(*attr
)->value_tag
& IPP_TAG_COPY
)
3865 * Make copies of all values...
3868 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
3871 value
->string
.text
= _cupsStrAlloc(value
->string
.text
);
3874 (*attr
)->value_tag
= IPP_TAG_NAMELANG
;
3877 case IPP_TAG_KEYWORD
:
3878 if (temp_tag
== IPP_TAG_NAME
|| temp_tag
== IPP_TAG_NAMELANG
)
3879 break; /* Silently "allow" name -> keyword */
3890 * 'ippSetVersion()' - Set the version number in an IPP message.
3892 * The @code ipp@ parameter refers to an IPP message previously created using the
3893 * @link ippNew@ or @link ippNewRequest@ functions.
3895 * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
3897 * @since CUPS 1.6/OS X 10.8@
3900 int /* O - 1 on success, 0 on failure */
3901 ippSetVersion(ipp_t
*ipp
, /* I - IPP message */
3902 int major
, /* I - Major version number (major.minor) */
3903 int minor
) /* I - Minor version number (major.minor) */
3906 * Range check input...
3909 if (!ipp
|| major
< 0 || minor
< 0)
3913 * Set the version number...
3916 ipp
->request
.any
.version
[0] = major
;
3917 ipp
->request
.any
.version
[1] = minor
;
3924 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
3927 const ipp_uchar_t
* /* O - RFC-1903 date/time data */
3928 ippTimeToDate(time_t t
) /* I - UNIX time value */
3930 struct tm
*unixdate
; /* UNIX unixdate/time info */
3931 ipp_uchar_t
*date
= _cupsGlobals()->ipp_date
;
3932 /* RFC-1903 date/time data */
3936 * RFC-1903 date/time format is:
3938 * Byte(s) Description
3939 * ------- -----------
3940 * 0-1 Year (0 to 65535)
3944 * 5 Minutes (0 to 59)
3945 * 6 Seconds (0 to 60, 60 = "leap second")
3946 * 7 Deciseconds (0 to 9)
3948 * 9 UTC hours (0 to 11)
3949 * 10 UTC minutes (0 to 59)
3952 unixdate
= gmtime(&t
);
3953 unixdate
->tm_year
+= 1900;
3955 date
[0] = unixdate
->tm_year
>> 8;
3956 date
[1] = unixdate
->tm_year
;
3957 date
[2] = unixdate
->tm_mon
+ 1;
3958 date
[3] = unixdate
->tm_mday
;
3959 date
[4] = unixdate
->tm_hour
;
3960 date
[5] = unixdate
->tm_min
;
3961 date
[6] = unixdate
->tm_sec
;
3972 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
3975 ipp_state_t
/* O - Current state */
3976 ippWrite(http_t
*http
, /* I - HTTP connection */
3977 ipp_t
*ipp
) /* I - IPP data */
3979 DEBUG_printf(("ippWrite(http=%p, ipp=%p)", http
, ipp
));
3984 return (ippWriteIO(http
, (ipp_iocb_t
)httpWrite2
, http
->blocking
, NULL
, ipp
));
3989 * 'ippWriteFile()' - Write data for an IPP message to a file.
3991 * @since CUPS 1.1.19/OS X 10.3@
3994 ipp_state_t
/* O - Current state */
3995 ippWriteFile(int fd
, /* I - HTTP data */
3996 ipp_t
*ipp
) /* I - IPP data */
3998 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd
, ipp
));
4000 ipp
->state
= IPP_IDLE
;
4002 return (ippWriteIO(&fd
, (ipp_iocb_t
)ipp_write_file
, 1, NULL
, ipp
));
4007 * 'ippWriteIO()' - Write data for an IPP message.
4009 * @since CUPS 1.2/OS X 10.5@
4012 ipp_state_t
/* O - Current state */
4013 ippWriteIO(void *dst
, /* I - Destination */
4014 ipp_iocb_t cb
, /* I - Write callback function */
4015 int blocking
, /* I - Use blocking IO? */
4016 ipp_t
*parent
, /* I - Parent IPP message */
4017 ipp_t
*ipp
) /* I - IPP data */
4019 int i
; /* Looping var */
4020 int n
; /* Length of data */
4021 unsigned char *buffer
, /* Data buffer */
4022 *bufptr
; /* Pointer into buffer */
4023 ipp_attribute_t
*attr
; /* Current attribute */
4024 _ipp_value_t
*value
; /* Current value */
4027 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
4028 dst
, cb
, blocking
, parent
, ipp
));
4033 if ((buffer
= (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE
)) == NULL
)
4035 DEBUG_puts("1ippWriteIO: Unable to get write buffer");
4042 ipp
->state
++; /* Avoid common problem... */
4048 * Send the request header:
4051 * Operation/Status Code = 2 bytes
4052 * Request ID = 4 bytes
4058 *bufptr
++ = ipp
->request
.any
.version
[0];
4059 *bufptr
++ = ipp
->request
.any
.version
[1];
4060 *bufptr
++ = ipp
->request
.any
.op_status
>> 8;
4061 *bufptr
++ = ipp
->request
.any
.op_status
;
4062 *bufptr
++ = ipp
->request
.any
.request_id
>> 24;
4063 *bufptr
++ = ipp
->request
.any
.request_id
>> 16;
4064 *bufptr
++ = ipp
->request
.any
.request_id
>> 8;
4065 *bufptr
++ = ipp
->request
.any
.request_id
;
4067 DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer
[0], buffer
[1]));
4068 DEBUG_printf(("2ippWriteIO: op_status=%04x",
4069 ipp
->request
.any
.op_status
));
4070 DEBUG_printf(("2ippWriteIO: request_id=%d",
4071 ipp
->request
.any
.request_id
));
4073 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4075 DEBUG_puts("1ippWriteIO: Could not write IPP header...");
4076 _cupsBufferRelease((char *)buffer
);
4082 * Reset the state engine to point to the first attribute
4083 * in the request/response, with no current group.
4086 ipp
->state
= IPP_ATTRIBUTE
;
4087 ipp
->current
= ipp
->attrs
;
4088 ipp
->curtag
= IPP_TAG_ZERO
;
4090 DEBUG_printf(("1ippWriteIO: ipp->current=%p", ipp
->current
));
4093 * If blocking is disabled, stop here...
4099 case IPP_ATTRIBUTE
:
4100 while (ipp
->current
!= NULL
)
4103 * Write this attribute...
4107 attr
= ipp
->current
;
4109 ipp
->current
= ipp
->current
->next
;
4113 if (ipp
->curtag
!= attr
->group_tag
)
4116 * Send a group tag byte...
4119 ipp
->curtag
= attr
->group_tag
;
4121 if (attr
->group_tag
== IPP_TAG_ZERO
)
4124 DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
4125 attr
->group_tag
, ippTagString(attr
->group_tag
)));
4126 *bufptr
++ = attr
->group_tag
;
4128 else if (attr
->group_tag
== IPP_TAG_ZERO
)
4132 DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr
->name
,
4133 attr
->num_values
> 1 ? "1setOf " : "",
4134 ippTagString(attr
->value_tag
)));
4137 * Write the attribute tag and name.
4139 * The attribute name length does not include the trailing nul
4140 * character in the source string.
4142 * Collection values (parent != NULL) are written differently...
4148 * Get the length of the attribute name, and make sure it won't
4149 * overflow the buffer...
4152 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 8))
4154 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
4155 _cupsBufferRelease((char *)buffer
);
4160 * Write the value tag, name length, and name string...
4163 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4164 attr
->value_tag
, ippTagString(attr
->value_tag
)));
4165 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
4168 if (attr
->value_tag
> 0xff)
4170 *bufptr
++ = IPP_TAG_EXTENSION
;
4171 *bufptr
++ = attr
->value_tag
>> 24;
4172 *bufptr
++ = attr
->value_tag
>> 16;
4173 *bufptr
++ = attr
->value_tag
>> 8;
4174 *bufptr
++ = attr
->value_tag
;
4177 *bufptr
++ = attr
->value_tag
;
4181 memcpy(bufptr
, attr
->name
, n
);
4187 * Get the length of the attribute name, and make sure it won't
4188 * overflow the buffer...
4191 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 12))
4193 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
4194 _cupsBufferRelease((char *)buffer
);
4199 * Write the member name tag, name length, name string, value tag,
4200 * and empty name for the collection member attribute...
4203 DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
4204 IPP_TAG_MEMBERNAME
));
4205 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
4207 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4208 attr
->value_tag
, ippTagString(attr
->value_tag
)));
4209 DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
4211 *bufptr
++ = IPP_TAG_MEMBERNAME
;
4216 memcpy(bufptr
, attr
->name
, n
);
4219 if (attr
->value_tag
> 0xff)
4221 *bufptr
++ = IPP_TAG_EXTENSION
;
4222 *bufptr
++ = attr
->value_tag
>> 24;
4223 *bufptr
++ = attr
->value_tag
>> 16;
4224 *bufptr
++ = attr
->value_tag
>> 8;
4225 *bufptr
++ = attr
->value_tag
;
4228 *bufptr
++ = attr
->value_tag
;
4235 * Now write the attribute value(s)...
4238 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
4240 case IPP_TAG_UNSUPPORTED_VALUE
:
4241 case IPP_TAG_DEFAULT
:
4242 case IPP_TAG_UNKNOWN
:
4243 case IPP_TAG_NOVALUE
:
4244 case IPP_TAG_NOTSETTABLE
:
4245 case IPP_TAG_DELETEATTR
:
4246 case IPP_TAG_ADMINDEFINE
:
4251 case IPP_TAG_INTEGER
:
4253 for (i
= 0, value
= attr
->values
;
4254 i
< attr
->num_values
;
4257 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 9)
4259 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4261 DEBUG_puts("1ippWriteIO: Could not write IPP "
4263 _cupsBufferRelease((char *)buffer
);
4273 * Arrays and sets are done by sending additional
4274 * values with a zero-length name...
4277 *bufptr
++ = attr
->value_tag
;
4283 * Integers and enumerations are both 4-byte signed
4284 * (twos-complement) values.
4286 * Put the 2-byte length and 4-byte value into the buffer...
4291 *bufptr
++ = value
->integer
>> 24;
4292 *bufptr
++ = value
->integer
>> 16;
4293 *bufptr
++ = value
->integer
>> 8;
4294 *bufptr
++ = value
->integer
;
4298 case IPP_TAG_BOOLEAN
:
4299 for (i
= 0, value
= attr
->values
;
4300 i
< attr
->num_values
;
4303 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 6)
4305 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4307 DEBUG_puts("1ippWriteIO: Could not write IPP "
4309 _cupsBufferRelease((char *)buffer
);
4319 * Arrays and sets are done by sending additional
4320 * values with a zero-length name...
4323 *bufptr
++ = attr
->value_tag
;
4329 * Boolean values are 1-byte; 0 = false, 1 = true.
4331 * Put the 2-byte length and 1-byte value into the buffer...
4336 *bufptr
++ = value
->boolean
;
4342 case IPP_TAG_KEYWORD
:
4344 case IPP_TAG_URISCHEME
:
4345 case IPP_TAG_CHARSET
:
4346 case IPP_TAG_LANGUAGE
:
4347 case IPP_TAG_MIMETYPE
:
4348 for (i
= 0, value
= attr
->values
;
4349 i
< attr
->num_values
;
4355 * Arrays and sets are done by sending additional
4356 * values with a zero-length name...
4359 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4361 ippTagString(attr
->value_tag
)));
4362 DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
4364 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
4366 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4368 DEBUG_puts("1ippWriteIO: Could not write IPP "
4370 _cupsBufferRelease((char *)buffer
);
4377 *bufptr
++ = attr
->value_tag
;
4382 if (value
->string
.text
!= NULL
)
4383 n
= (int)strlen(value
->string
.text
);
4387 if (n
> (IPP_BUF_SIZE
- 2))
4389 DEBUG_printf(("1ippWriteIO: String too long (%d)", n
));
4390 _cupsBufferRelease((char *)buffer
);
4394 DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n
,
4395 value
->string
.text
));
4397 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
4399 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4401 DEBUG_puts("1ippWriteIO: Could not write IPP "
4403 _cupsBufferRelease((char *)buffer
);
4411 * All simple strings consist of the 2-byte length and
4412 * character data without the trailing nul normally found
4413 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
4414 * bytes since the 2-byte length is a signed (twos-complement)
4417 * Put the 2-byte length and string characters in the buffer.
4425 memcpy(bufptr
, value
->string
.text
, n
);
4432 for (i
= 0, value
= attr
->values
;
4433 i
< attr
->num_values
;
4436 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 16)
4438 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4440 DEBUG_puts("1ippWriteIO: Could not write IPP "
4442 _cupsBufferRelease((char *)buffer
);
4452 * Arrays and sets are done by sending additional
4453 * values with a zero-length name...
4456 *bufptr
++ = attr
->value_tag
;
4462 * Date values consist of a 2-byte length and an
4463 * 11-byte date/time structure defined by RFC 1903.
4465 * Put the 2-byte length and 11-byte date/time
4466 * structure in the buffer.
4471 memcpy(bufptr
, value
->date
, 11);
4476 case IPP_TAG_RESOLUTION
:
4477 for (i
= 0, value
= attr
->values
;
4478 i
< attr
->num_values
;
4481 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 14)
4483 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4485 DEBUG_puts("1ippWriteIO: Could not write IPP "
4487 _cupsBufferRelease((char *)buffer
);
4497 * Arrays and sets are done by sending additional
4498 * values with a zero-length name...
4501 *bufptr
++ = attr
->value_tag
;
4507 * Resolution values consist of a 2-byte length,
4508 * 4-byte horizontal resolution value, 4-byte vertical
4509 * resolution value, and a 1-byte units value.
4511 * Put the 2-byte length and resolution value data
4517 *bufptr
++ = value
->resolution
.xres
>> 24;
4518 *bufptr
++ = value
->resolution
.xres
>> 16;
4519 *bufptr
++ = value
->resolution
.xres
>> 8;
4520 *bufptr
++ = value
->resolution
.xres
;
4521 *bufptr
++ = value
->resolution
.yres
>> 24;
4522 *bufptr
++ = value
->resolution
.yres
>> 16;
4523 *bufptr
++ = value
->resolution
.yres
>> 8;
4524 *bufptr
++ = value
->resolution
.yres
;
4525 *bufptr
++ = value
->resolution
.units
;
4529 case IPP_TAG_RANGE
:
4530 for (i
= 0, value
= attr
->values
;
4531 i
< attr
->num_values
;
4534 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 13)
4536 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4538 DEBUG_puts("1ippWriteIO: Could not write IPP "
4540 _cupsBufferRelease((char *)buffer
);
4550 * Arrays and sets are done by sending additional
4551 * values with a zero-length name...
4554 *bufptr
++ = attr
->value_tag
;
4560 * Range values consist of a 2-byte length,
4561 * 4-byte lower value, and 4-byte upper value.
4563 * Put the 2-byte length and range value data
4569 *bufptr
++ = value
->range
.lower
>> 24;
4570 *bufptr
++ = value
->range
.lower
>> 16;
4571 *bufptr
++ = value
->range
.lower
>> 8;
4572 *bufptr
++ = value
->range
.lower
;
4573 *bufptr
++ = value
->range
.upper
>> 24;
4574 *bufptr
++ = value
->range
.upper
>> 16;
4575 *bufptr
++ = value
->range
.upper
>> 8;
4576 *bufptr
++ = value
->range
.upper
;
4580 case IPP_TAG_TEXTLANG
:
4581 case IPP_TAG_NAMELANG
:
4582 for (i
= 0, value
= attr
->values
;
4583 i
< attr
->num_values
;
4589 * Arrays and sets are done by sending additional
4590 * values with a zero-length name...
4593 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
4595 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4597 DEBUG_puts("1ippWriteIO: Could not write IPP "
4599 _cupsBufferRelease((char *)buffer
);
4606 *bufptr
++ = attr
->value_tag
;
4612 * textWithLanguage and nameWithLanguage values consist
4613 * of a 2-byte length for both strings and their
4614 * individual lengths, a 2-byte length for the
4615 * character string, the character string without the
4616 * trailing nul, a 2-byte length for the character
4617 * set string, and the character set string without
4623 if (value
->string
.language
!= NULL
)
4624 n
+= (int)strlen(value
->string
.language
);
4626 if (value
->string
.text
!= NULL
)
4627 n
+= (int)strlen(value
->string
.text
);
4629 if (n
> (IPP_BUF_SIZE
- 2))
4631 DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
4632 "too long (%d)", n
));
4633 _cupsBufferRelease((char *)buffer
);
4637 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
4639 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4641 DEBUG_puts("1ippWriteIO: Could not write IPP "
4643 _cupsBufferRelease((char *)buffer
);
4650 /* Length of entire value */
4654 /* Length of language */
4655 if (value
->string
.language
!= NULL
)
4656 n
= (int)strlen(value
->string
.language
);
4666 memcpy(bufptr
, value
->string
.language
, n
);
4670 /* Length of text */
4671 if (value
->string
.text
!= NULL
)
4672 n
= (int)strlen(value
->string
.text
);
4682 memcpy(bufptr
, value
->string
.text
, n
);
4688 case IPP_TAG_BEGIN_COLLECTION
:
4689 for (i
= 0, value
= attr
->values
;
4690 i
< attr
->num_values
;
4694 * Collections are written with the begin-collection
4695 * tag first with a value of 0 length, followed by the
4696 * attributes in the collection, then the end-collection
4700 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 5)
4702 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4704 DEBUG_puts("1ippWriteIO: Could not write IPP "
4706 _cupsBufferRelease((char *)buffer
);
4716 * Arrays and sets are done by sending additional
4717 * values with a zero-length name...
4720 *bufptr
++ = attr
->value_tag
;
4726 * Write a data length of 0 and flush the buffer...
4732 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4734 DEBUG_puts("1ippWriteIO: Could not write IPP "
4736 _cupsBufferRelease((char *)buffer
);
4743 * Then write the collection attribute...
4746 value
->collection
->state
= IPP_IDLE
;
4748 if (ippWriteIO(dst
, cb
, 1, ipp
,
4749 value
->collection
) == IPP_ERROR
)
4751 DEBUG_puts("1ippWriteIO: Unable to write collection value");
4752 _cupsBufferRelease((char *)buffer
);
4759 for (i
= 0, value
= attr
->values
;
4760 i
< attr
->num_values
;
4766 * Arrays and sets are done by sending additional
4767 * values with a zero-length name...
4770 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
4772 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4774 DEBUG_puts("1ippWriteIO: Could not write IPP "
4776 _cupsBufferRelease((char *)buffer
);
4783 *bufptr
++ = attr
->value_tag
;
4789 * An unknown value might some new value that a
4790 * vendor has come up with. It consists of a
4791 * 2-byte length and the bytes in the unknown
4795 n
= value
->unknown
.length
;
4797 if (n
> (IPP_BUF_SIZE
- 2))
4799 DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
4801 _cupsBufferRelease((char *)buffer
);
4805 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
4807 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4809 DEBUG_puts("1ippWriteIO: Could not write IPP "
4811 _cupsBufferRelease((char *)buffer
);
4818 /* Length of unknown value */
4825 memcpy(bufptr
, value
->unknown
.data
, n
);
4833 * Write the data out...
4836 if (bufptr
> buffer
)
4838 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4840 DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4841 _cupsBufferRelease((char *)buffer
);
4845 DEBUG_printf(("2ippWriteIO: wrote %d bytes",
4846 (int)(bufptr
- buffer
)));
4850 * If blocking is disabled, stop here...
4857 if (ipp
->current
== NULL
)
4860 * Done with all of the attributes; add the end-of-attributes
4861 * tag or end-collection attribute...
4866 buffer
[0] = IPP_TAG_END
;
4871 buffer
[0] = IPP_TAG_END_COLLECTION
;
4872 buffer
[1] = 0; /* empty name */
4874 buffer
[3] = 0; /* empty value */
4879 if ((*cb
)(dst
, buffer
, n
) < 0)
4881 DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
4882 _cupsBufferRelease((char *)buffer
);
4886 ipp
->state
= IPP_DATA
;
4894 break; /* anti-compiler-warning-code */
4897 _cupsBufferRelease((char *)buffer
);
4899 return (ipp
->state
);
4904 * 'ipp_add_attr()' - Add a new attribute to the message.
4907 static ipp_attribute_t
* /* O - New attribute */
4908 ipp_add_attr(ipp_t
*ipp
, /* I - IPP message */
4909 const char *name
, /* I - Attribute name or NULL */
4910 ipp_tag_t group_tag
, /* I - Group tag or IPP_TAG_ZERO */
4911 ipp_tag_t value_tag
, /* I - Value tag or IPP_TAG_ZERO */
4912 int num_values
) /* I - Number of values */
4914 int alloc_values
; /* Number of values to allocate */
4915 ipp_attribute_t
*attr
; /* New attribute */
4918 DEBUG_printf(("4ipp_add_attr(ipp=%p, name=\"%s\", group_tag=0x%x, value_tag=0x%x, "
4919 "num_values=%d)", ipp
, name
, group_tag
, value_tag
, num_values
));
4922 * Range check input...
4925 if (!ipp
|| num_values
< 0)
4929 * Allocate memory, rounding the allocation up as needed...
4932 if (num_values
<= 1)
4935 alloc_values
= (num_values
+ IPP_MAX_VALUES
- 1) & ~(IPP_MAX_VALUES
- 1);
4937 attr
= calloc(sizeof(ipp_attribute_t
) +
4938 (alloc_values
- 1) * sizeof(_ipp_value_t
), 1);
4943 * Initialize attribute...
4947 attr
->name
= _cupsStrAlloc(name
);
4949 attr
->group_tag
= group_tag
;
4950 attr
->value_tag
= value_tag
;
4951 attr
->num_values
= num_values
;
4954 * Add it to the end of the linked list...
4958 ipp
->last
->next
= attr
;
4962 ipp
->prev
= ipp
->last
;
4963 ipp
->last
= ipp
->current
= attr
;
4966 DEBUG_printf(("5ipp_add_attr: Returning %p", attr
));
4973 * 'ipp_free_values()' - Free attribute values.
4977 ipp_free_values(ipp_attribute_t
*attr
, /* I - Attribute to free values from */
4978 int element
,/* I - First value to free */
4979 int count
) /* I - Number of values to free */
4981 int i
; /* Looping var */
4982 _ipp_value_t
*value
; /* Current value */
4985 DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", attr
, element
, count
));
4987 if (!(attr
->value_tag
& IPP_TAG_COPY
))
4990 * Free values as needed...
4993 switch (attr
->value_tag
)
4995 case IPP_TAG_TEXTLANG
:
4996 case IPP_TAG_NAMELANG
:
4997 if (element
== 0 && count
== attr
->num_values
&& attr
->values
[0].string
.language
)
4998 _cupsStrFree(attr
->values
[0].string
.language
);
5002 case IPP_TAG_RESERVED_STRING
:
5003 case IPP_TAG_KEYWORD
:
5005 case IPP_TAG_URISCHEME
:
5006 case IPP_TAG_CHARSET
:
5007 case IPP_TAG_LANGUAGE
:
5008 case IPP_TAG_MIMETYPE
:
5009 for (i
= count
, value
= attr
->values
+ element
;
5012 _cupsStrFree(value
->string
.text
);
5015 case IPP_TAG_DEFAULT
:
5016 case IPP_TAG_UNKNOWN
:
5017 case IPP_TAG_NOVALUE
:
5018 case IPP_TAG_NOTSETTABLE
:
5019 case IPP_TAG_DELETEATTR
:
5020 case IPP_TAG_ADMINDEFINE
:
5021 case IPP_TAG_INTEGER
:
5023 case IPP_TAG_BOOLEAN
:
5025 case IPP_TAG_RESOLUTION
:
5026 case IPP_TAG_RANGE
:
5029 case IPP_TAG_BEGIN_COLLECTION
:
5030 for (i
= count
, value
= attr
->values
+ element
;
5033 ippDelete(value
->collection
);
5036 case IPP_TAG_STRING
:
5038 for (i
= count
, value
= attr
->values
+ element
;
5041 if (value
->unknown
.data
)
5042 free(value
->unknown
.data
);
5048 * If we are not freeing values from the end, move the remaining values up...
5051 if ((element
+ count
) < attr
->num_values
)
5052 memmove(attr
->values
+ element
, attr
->values
+ element
+ count
,
5053 (attr
->num_values
- count
- element
) * sizeof(_ipp_value_t
));
5055 attr
->num_values
-= count
;
5060 * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
5062 * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
5063 * to "ll-cc", "ll-region", and "charset-number", respectively.
5066 static char * /* O - Language code string */
5067 ipp_get_code(const char *value
, /* I - Locale/charset string */
5068 char *buffer
, /* I - String buffer */
5069 size_t bufsize
) /* I - Size of string buffer */
5071 char *bufptr
, /* Pointer into buffer */
5072 *bufend
; /* End of buffer */
5076 * Convert values to lowercase and change _ to - as needed...
5079 for (bufptr
= buffer
, bufend
= buffer
+ bufsize
- 1;
5080 *value
&& bufptr
< bufend
;
5085 *bufptr
++ = _cups_tolower(*value
);
5090 * Return the converted string...
5098 * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
5100 * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
5101 * "ll-region", respectively. It also converts the "C" (POSIX) locale to "en".
5104 static char * /* O - Language code string */
5105 ipp_lang_code(const char *locale
, /* I - Locale string */
5106 char *buffer
, /* I - String buffer */
5107 size_t bufsize
) /* I - Size of string buffer */
5110 * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
5113 if (!_cups_strcasecmp(locale
, "c"))
5115 strlcpy(buffer
, "en", bufsize
);
5119 return (ipp_get_code(locale
, buffer
, bufsize
));
5124 * 'ipp_length()' - Compute the length of an IPP message or collection value.
5127 static size_t /* O - Size of IPP message */
5128 ipp_length(ipp_t
*ipp
, /* I - IPP message or collection */
5129 int collection
) /* I - 1 if a collection, 0 otherwise */
5131 int i
; /* Looping var */
5132 size_t bytes
; /* Number of bytes */
5133 ipp_attribute_t
*attr
; /* Current attribute */
5134 ipp_tag_t group
; /* Current group */
5135 _ipp_value_t
*value
; /* Current value */
5138 DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", ipp
, collection
));
5142 DEBUG_puts("4ipp_length: Returning 0 bytes");
5147 * Start with 8 bytes for the IPP message header...
5150 bytes
= collection
? 0 : 8;
5153 * Then add the lengths of each attribute...
5156 group
= IPP_TAG_ZERO
;
5158 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= attr
->next
)
5160 if (attr
->group_tag
!= group
&& !collection
)
5162 group
= attr
->group_tag
;
5163 if (group
== IPP_TAG_ZERO
)
5166 bytes
++; /* Group tag */
5172 DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
5173 "bytes=" CUPS_LLFMT
, attr
->name
, attr
->num_values
, CUPS_LLCAST bytes
));
5175 if (attr
->value_tag
< IPP_TAG_EXTENSION
)
5176 bytes
+= attr
->num_values
; /* Value tag for each value */
5178 bytes
+= 5 * attr
->num_values
; /* Value tag for each value */
5179 bytes
+= 2 * attr
->num_values
; /* Name lengths */
5180 bytes
+= (int)strlen(attr
->name
); /* Name */
5181 bytes
+= 2 * attr
->num_values
; /* Value lengths */
5184 bytes
+= 5; /* Add membername overhead */
5186 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
5188 case IPP_TAG_UNSUPPORTED_VALUE
:
5189 case IPP_TAG_DEFAULT
:
5190 case IPP_TAG_UNKNOWN
:
5191 case IPP_TAG_NOVALUE
:
5192 case IPP_TAG_NOTSETTABLE
:
5193 case IPP_TAG_DELETEATTR
:
5194 case IPP_TAG_ADMINDEFINE
:
5197 case IPP_TAG_INTEGER
:
5199 bytes
+= 4 * attr
->num_values
;
5202 case IPP_TAG_BOOLEAN
:
5203 bytes
+= attr
->num_values
;
5208 case IPP_TAG_KEYWORD
:
5210 case IPP_TAG_URISCHEME
:
5211 case IPP_TAG_CHARSET
:
5212 case IPP_TAG_LANGUAGE
:
5213 case IPP_TAG_MIMETYPE
:
5214 for (i
= 0, value
= attr
->values
;
5215 i
< attr
->num_values
;
5217 if (value
->string
.text
)
5218 bytes
+= strlen(value
->string
.text
);
5222 bytes
+= 11 * attr
->num_values
;
5225 case IPP_TAG_RESOLUTION
:
5226 bytes
+= 9 * attr
->num_values
;
5229 case IPP_TAG_RANGE
:
5230 bytes
+= 8 * attr
->num_values
;
5233 case IPP_TAG_TEXTLANG
:
5234 case IPP_TAG_NAMELANG
:
5235 bytes
+= 4 * attr
->num_values
;/* Charset + text length */
5237 for (i
= 0, value
= attr
->values
;
5238 i
< attr
->num_values
;
5241 if (value
->string
.language
)
5242 bytes
+= strlen(value
->string
.language
);
5244 if (value
->string
.text
)
5245 bytes
+= strlen(value
->string
.text
);
5249 case IPP_TAG_BEGIN_COLLECTION
:
5250 for (i
= 0, value
= attr
->values
;
5251 i
< attr
->num_values
;
5253 bytes
+= ipp_length(value
->collection
, 1);
5257 for (i
= 0, value
= attr
->values
;
5258 i
< attr
->num_values
;
5260 bytes
+= value
->unknown
.length
;
5266 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
5267 * for the "end of collection" tag and return...
5275 DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT
" bytes", CUPS_LLCAST bytes
));
5282 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
5285 static ssize_t
/* O - Number of bytes read */
5286 ipp_read_http(http_t
*http
, /* I - Client connection */
5287 ipp_uchar_t
*buffer
, /* O - Buffer for data */
5288 size_t length
) /* I - Total length */
5290 int tbytes
, /* Total bytes read */
5291 bytes
; /* Bytes read this pass */
5292 char len
[32]; /* Length string */
5295 DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)",
5296 http
, buffer
, (int)length
));
5299 * Loop until all bytes are read...
5302 for (tbytes
= 0, bytes
= 0;
5303 tbytes
< (int)length
;
5304 tbytes
+= bytes
, buffer
+= bytes
)
5306 DEBUG_printf(("9ipp_read_http: tbytes=%d, http->state=%d", tbytes
,
5309 if (http
->state
== HTTP_WAITING
)
5312 if (http
->used
> 0 && http
->data_encoding
== HTTP_ENCODE_LENGTH
)
5315 * Do "fast read" from HTTP buffer directly...
5318 if (http
->used
> (int)(length
- tbytes
))
5319 bytes
= (int)(length
- tbytes
);
5324 buffer
[0] = http
->buffer
[0];
5326 memcpy(buffer
, http
->buffer
, bytes
);
5328 http
->used
-= bytes
;
5329 http
->data_remaining
-= bytes
;
5331 if (http
->data_remaining
<= INT_MAX
)
5332 http
->_data_remaining
= (int)http
->data_remaining
;
5334 http
->_data_remaining
= INT_MAX
;
5337 memmove(http
->buffer
, http
->buffer
+ bytes
, http
->used
);
5339 if (http
->data_remaining
== 0)
5341 if (http
->data_encoding
== HTTP_ENCODE_CHUNKED
)
5344 * Get the trailing CR LF after the chunk...
5347 if (!httpGets(len
, sizeof(len
), http
))
5351 if (http
->data_encoding
!= HTTP_ENCODE_CHUNKED
)
5353 if (http
->state
== HTTP_POST_RECV
)
5356 http
->state
= HTTP_WAITING
;
5362 if (!http
->blocking
)
5365 * Wait up to 10 seconds for more data on non-blocking sockets...
5368 if (!httpWait(http
, 10000))
5379 if ((bytes
= httpRead2(http
, (char *)buffer
, length
- tbytes
)) < 0)
5384 if (errno
!= EAGAIN
&& errno
!= EINTR
)
5390 else if (bytes
== 0)
5396 * Return the number of bytes read...
5399 if (tbytes
== 0 && bytes
< 0)
5402 DEBUG_printf(("8ipp_read_http: Returning %d bytes", tbytes
));
5409 * 'ipp_read_file()' - Read IPP data from a file.
5412 static ssize_t
/* O - Number of bytes read */
5413 ipp_read_file(int *fd
, /* I - File descriptor */
5414 ipp_uchar_t
*buffer
, /* O - Read buffer */
5415 size_t length
) /* I - Number of bytes to read */
5418 return ((ssize_t
)read(*fd
, buffer
, (unsigned)length
));
5420 return (read(*fd
, buffer
, length
));
5426 * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
5430 static _ipp_value_t
* /* O - IPP value element or NULL on error */
5431 ipp_set_value(ipp_t
*ipp
, /* IO - IPP message */
5432 ipp_attribute_t
**attr
, /* IO - IPP attribute */
5433 int element
) /* I - Value number (0-based) */
5435 ipp_attribute_t
*temp
, /* New attribute pointer */
5436 *current
, /* Current attribute in list */
5437 *prev
; /* Previous attribute in list */
5438 int alloc_values
; /* Allocated values */
5442 * If we are setting an existing value element, return it...
5447 if (temp
->num_values
<= 1)
5450 alloc_values
= (temp
->num_values
+ IPP_MAX_VALUES
- 1) &
5451 ~(IPP_MAX_VALUES
- 1);
5453 if (element
< alloc_values
)
5455 if (element
>= temp
->num_values
)
5456 temp
->num_values
= element
+ 1;
5458 return (temp
->values
+ element
);
5462 * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
5463 * values when num_values > 1.
5466 if (alloc_values
< IPP_MAX_VALUES
)
5467 alloc_values
= IPP_MAX_VALUES
;
5469 alloc_values
+= IPP_MAX_VALUES
;
5471 DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
5475 * Reallocate memory...
5478 if ((temp
= realloc(temp
, sizeof(ipp_attribute_t
) +
5479 (alloc_values
- 1) * sizeof(_ipp_value_t
))) == NULL
)
5481 _cupsSetHTTPError(HTTP_ERROR
);
5482 DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
5487 * Zero the new memory...
5490 memset(temp
->values
+ temp
->num_values
, 0,
5491 (alloc_values
- temp
->num_values
) * sizeof(_ipp_value_t
));
5496 * Reset pointers in the list...
5499 if (ipp
->current
== *attr
&& ipp
->prev
)
5502 * Use current "previous" pointer...
5510 * Find this attribute in the linked list...
5513 for (prev
= NULL
, current
= ipp
->attrs
;
5514 current
&& current
!= *attr
;
5515 prev
= current
, current
= current
->next
);
5520 * This is a serious error!
5524 _cupsSetError(IPP_INTERNAL_ERROR
,
5525 _("IPP attribute is not a member of the message."), 1);
5526 DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
5536 ipp
->current
= temp
;
5539 if (ipp
->last
== *attr
)
5546 * Return the value element...
5549 if (element
>= temp
->num_values
)
5550 temp
->num_values
= element
+ 1;
5552 return (temp
->values
+ element
);
5557 * 'ipp_write_file()' - Write IPP data to a file.
5560 static ssize_t
/* O - Number of bytes written */
5561 ipp_write_file(int *fd
, /* I - File descriptor */
5562 ipp_uchar_t
*buffer
, /* I - Data to write */
5563 size_t length
) /* I - Number of bytes to write */
5566 return ((ssize_t
)write(*fd
, buffer
, (unsigned)length
));
5568 return (write(*fd
, buffer
, length
));
5574 * End of "$Id: ipp.c 10102 2011-11-02 23:52:39Z mike $".