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 tag 0x%x.", tag
));
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 integer 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 boolean 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
:
2918 if ((*cb
)(src
, buffer
, n
) < n
)
2920 DEBUG_puts("1ippReadIO: unable to read string value.");
2921 _cupsBufferRelease((char *)buffer
);
2927 value
->string
.text
= _cupsStrAlloc((char *)buffer
);
2928 DEBUG_printf(("2ippReadIO: value=\"%s\"", value
->string
.text
));
2934 _cupsSetError(IPP_INTERNAL_ERROR
, _("IPP date value not 11 bytes."), 1);
2935 DEBUG_printf(("1ippReadIO: bad date value length %d.", n
));
2936 _cupsBufferRelease((char *)buffer
);
2940 if ((*cb
)(src
, value
->date
, 11) < 11)
2942 DEBUG_puts("1ippReadIO: Unable to read date value.");
2943 _cupsBufferRelease((char *)buffer
);
2948 case IPP_TAG_RESOLUTION
:
2951 _cupsSetError(IPP_INTERNAL_ERROR
,
2952 _("IPP resolution value not 9 bytes."), 1);
2953 DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n
));
2954 _cupsBufferRelease((char *)buffer
);
2958 if ((*cb
)(src
, buffer
, 9) < 9)
2960 DEBUG_puts("1ippReadIO: Unable to read resolution value.");
2961 _cupsBufferRelease((char *)buffer
);
2965 value
->resolution
.xres
=
2966 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
2968 value
->resolution
.yres
=
2969 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
2971 value
->resolution
.units
=
2972 (ipp_res_t
)buffer
[8];
2975 case IPP_TAG_RANGE
:
2978 _cupsSetError(IPP_INTERNAL_ERROR
,
2979 _("IPP rangeOfInteger value not 8 bytes."), 1);
2980 DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length "
2982 _cupsBufferRelease((char *)buffer
);
2986 if ((*cb
)(src
, buffer
, 8) < 8)
2988 DEBUG_puts("1ippReadIO: Unable to read range value.");
2989 _cupsBufferRelease((char *)buffer
);
2993 value
->range
.lower
=
2994 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
2996 value
->range
.upper
=
2997 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
3001 case IPP_TAG_TEXTLANG
:
3002 case IPP_TAG_NAMELANG
:
3005 if (tag
== IPP_TAG_TEXTLANG
)
3006 _cupsSetError(IPP_INTERNAL_ERROR
,
3007 _("IPP textWithLanguage value less than "
3008 "minimum 4 bytes."), 1);
3010 _cupsSetError(IPP_INTERNAL_ERROR
,
3011 _("IPP nameWithLanguage value less than "
3012 "minimum 4 bytes."), 1);
3013 DEBUG_printf(("1ippReadIO: bad stringWithLanguage value "
3015 _cupsBufferRelease((char *)buffer
);
3019 if ((*cb
)(src
, buffer
, n
) < n
)
3021 DEBUG_puts("1ippReadIO: Unable to read string w/language "
3023 _cupsBufferRelease((char *)buffer
);
3030 * text-with-language and name-with-language are composite
3039 n
= (bufptr
[0] << 8) | bufptr
[1];
3041 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
) ||
3042 n
>= sizeof(string
))
3044 _cupsSetError(IPP_INTERNAL_ERROR
,
3045 _("IPP language length overflows value."), 1);
3046 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3048 _cupsBufferRelease((char *)buffer
);
3052 memcpy(string
, bufptr
+ 2, n
);
3055 value
->string
.language
= _cupsStrAlloc((char *)string
);
3058 n
= (bufptr
[0] << 8) | bufptr
[1];
3060 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
))
3062 _cupsSetError(IPP_INTERNAL_ERROR
,
3063 _("IPP string length overflows value."), 1);
3064 DEBUG_printf(("1ippReadIO: bad string value length %d.", n
));
3065 _cupsBufferRelease((char *)buffer
);
3069 bufptr
[2 + n
] = '\0';
3070 value
->string
.text
= _cupsStrAlloc((char *)bufptr
+ 2);
3073 case IPP_TAG_BEGIN_COLLECTION
:
3075 * Oh, boy, here comes a collection value, so read it...
3078 value
->collection
= ippNew();
3082 _cupsSetError(IPP_INTERNAL_ERROR
,
3083 _("IPP begCollection value not 0 bytes."), 1);
3084 DEBUG_puts("1ippReadIO: begCollection tag with value length "
3086 _cupsBufferRelease((char *)buffer
);
3090 if (ippReadIO(src
, cb
, 1, ipp
, value
->collection
) == IPP_ERROR
)
3092 DEBUG_puts("1ippReadIO: Unable to read collection value.");
3093 _cupsBufferRelease((char *)buffer
);
3098 case IPP_TAG_END_COLLECTION
:
3099 _cupsBufferRelease((char *)buffer
);
3103 _cupsSetError(IPP_INTERNAL_ERROR
,
3104 _("IPP endCollection value not 0 bytes."), 1);
3105 DEBUG_puts("1ippReadIO: endCollection tag with value length "
3110 DEBUG_puts("1ippReadIO: endCollection tag...");
3111 return (ipp
->state
= IPP_DATA
);
3113 case IPP_TAG_MEMBERNAME
:
3115 * The value the name of the member in the collection, which
3116 * we need to carry over...
3121 _cupsSetError(IPP_INTERNAL_ERROR
,
3122 _("IPP memberName value is empty."), 1);
3123 DEBUG_puts("1ippReadIO: Empty member name value.");
3124 _cupsBufferRelease((char *)buffer
);
3127 else if ((*cb
)(src
, buffer
, n
) < n
)
3129 DEBUG_puts("1ippReadIO: Unable to read member name value.");
3130 _cupsBufferRelease((char *)buffer
);
3135 attr
->name
= _cupsStrAlloc((char *)buffer
);
3138 * Since collection members are encoded differently than
3139 * regular attributes, make sure we don't start with an
3143 attr
->num_values
--;
3145 DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr
->name
));
3148 default : /* Other unsupported values */
3149 value
->unknown
.length
= n
;
3152 if ((value
->unknown
.data
= malloc(n
)) == NULL
)
3154 _cupsSetHTTPError(HTTP_ERROR
);
3155 DEBUG_puts("1ippReadIO: Unable to allocate value");
3156 _cupsBufferRelease((char *)buffer
);
3160 if ((*cb
)(src
, value
->unknown
.data
, n
) < n
)
3162 DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
3163 _cupsBufferRelease((char *)buffer
);
3168 value
->unknown
.data
= NULL
;
3173 * If blocking is disabled, stop here...
3185 break; /* anti-compiler-warning-code */
3188 DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp
->state
));
3189 _cupsBufferRelease((char *)buffer
);
3191 return (ipp
->state
);
3196 * 'ippSetBoolean()' - Set a boolean value in an attribute.
3198 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3199 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3201 * The @code attr@ parameter may be modified as a result of setting the value.
3203 * The @code element@ parameter specifies which value to set from 0 to
3204 * @link ippGetCount(attr)@.
3206 * @since CUPS 1.6/OS X 10.8@
3209 int /* O - 1 on success, 0 on failure */
3210 ippSetBoolean(ipp_t
*ipp
, /* IO - IPP message */
3211 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3212 int element
, /* I - Value number (0-based) */
3213 int boolvalue
)/* I - Boolean value */
3215 _ipp_value_t
*value
; /* Current value */
3219 * Range check input...
3222 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BOOLEAN
||
3223 element
< 0 || element
> (*attr
)->num_values
)
3227 * Set the value and return...
3230 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3231 value
->boolean
= boolvalue
;
3233 return (value
!= NULL
);
3238 * 'ippSetCollection()' - Set a collection value in an attribute.
3240 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3241 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3243 * The @code attr@ parameter may be modified as a result of setting the value.
3245 * The @code element@ parameter specifies which value to set from 0 to
3246 * @link ippGetCount(attr)@.
3248 * @since CUPS 1.6/OS X 10.8@
3251 int /* O - 1 on success, 0 on failure */
3253 ipp_t
*ipp
, /* IO - IPP message */
3254 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3255 int element
, /* I - Value number (0-based) */
3256 ipp_t
*colvalue
) /* I - Collection value */
3258 _ipp_value_t
*value
; /* Current value */
3262 * Range check input...
3265 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
3266 element
< 0 || element
> (*attr
)->num_values
|| !colvalue
)
3270 * Set the value and return...
3273 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3275 if (value
->collection
)
3276 ippDelete(value
->collection
);
3278 value
->collection
= colvalue
;
3282 return (value
!= NULL
);
3287 * 'ippSetDate()' - Set a date value in an attribute.
3289 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3290 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3292 * The @code attr@ parameter may be modified as a result of setting the value.
3294 * The @code element@ parameter specifies which value to set from 0 to
3295 * @link ippGetCount(attr)@.
3297 * @since CUPS 1.6/OS X 10.8@
3300 int /* O - 1 on success, 0 on failure */
3301 ippSetDate(ipp_t
*ipp
, /* IO - IPP message */
3302 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3303 int element
, /* I - Value number (0-based) */
3304 const ipp_uchar_t
*datevalue
)/* I - Date value */
3306 _ipp_value_t
*value
; /* Current value */
3310 * Range check input...
3313 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_DATE
||
3314 element
< 0 || element
> (*attr
)->num_values
|| !datevalue
)
3318 * Set the value and return...
3321 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3322 memcpy(value
->date
, datevalue
, sizeof(value
->date
));
3324 return (value
!= NULL
);
3329 * 'ippSetGroupTag()' - Set the group tag of an attribute.
3331 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3332 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3334 * The @code attr@ parameter may be modified as a result of setting the value.
3336 * The @code group@ parameter specifies the IPP attribute group tag: none
3337 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
3338 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
3339 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
3340 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
3342 * @since CUPS 1.6/OS X 10.8@
3345 int /* O - 1 on success, 0 on failure */
3347 ipp_t
*ipp
, /* IO - IPP message */
3348 ipp_attribute_t
**attr
, /* IO - Attribute */
3349 ipp_tag_t group_tag
) /* I - Group tag */
3352 * Range check input - group tag must be 0x01 to 0x0F, per RFC 2911...
3355 if (!ipp
|| !attr
|| group_tag
< IPP_TAG_ZERO
|| group_tag
== IPP_TAG_END
||
3356 group_tag
>= IPP_TAG_UNSUPPORTED_VALUE
)
3360 * Set the group tag and return...
3363 (*attr
)->group_tag
= group_tag
;
3370 * 'ippSetInteger()' - Set an integer or enum value in an attribute.
3372 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3373 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3375 * The @code attr@ parameter may be modified as a result of setting the value.
3377 * The @code element@ parameter specifies which value to set from 0 to
3378 * @link ippGetCount(attr)@.
3380 * @since CUPS 1.6/OS X 10.8@
3383 int /* O - 1 on success, 0 on failure */
3384 ippSetInteger(ipp_t
*ipp
, /* IO - IPP message */
3385 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3386 int element
, /* I - Value number (0-based) */
3387 int intvalue
) /* I - Integer/enum value */
3389 _ipp_value_t
*value
; /* Current value */
3393 * Range check input...
3396 if (!ipp
|| !attr
|| !*attr
||
3397 ((*attr
)->value_tag
!= IPP_TAG_INTEGER
&& (*attr
)->value_tag
!= IPP_TAG_ENUM
) ||
3398 element
< 0 || element
> (*attr
)->num_values
)
3402 * Set the value and return...
3405 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3406 value
->integer
= intvalue
;
3408 return (value
!= NULL
);
3413 * 'ippSetName()' - Set the name of an attribute.
3415 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3416 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3418 * The @code attr@ parameter may be modified as a result of setting the value.
3420 * @since CUPS 1.6/OS X 10.8@
3423 int /* O - 1 on success, 0 on failure */
3424 ippSetName(ipp_t
*ipp
, /* IO - IPP message */
3425 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3426 const char *name
) /* I - Attribute name */
3428 char *temp
; /* Temporary name value */
3432 * Range check input...
3435 if (!ipp
|| !attr
|| !*attr
)
3439 * Set the value and return...
3442 if ((temp
= _cupsStrAlloc(name
)) != NULL
)
3445 _cupsStrFree((*attr
)->name
);
3447 (*attr
)->name
= temp
;
3450 return (temp
!= NULL
);
3455 * 'ippSetOperation()' - Set the operation ID in an IPP request message.
3457 * The @code ipp@ parameter refers to an IPP message previously created using the
3458 * @link ippNew@ or @link ippNewRequest@ functions.
3460 * @since CUPS 1.6/OS X 10.8@
3463 int /* O - 1 on success, 0 on failure */
3464 ippSetOperation(ipp_t
*ipp
, /* I - IPP request message */
3465 ipp_op_t op
) /* I - Operation ID */
3468 * Range check input...
3475 * Set the operation and return...
3478 ipp
->request
.op
.operation_id
= op
;
3485 * 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
3487 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3488 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3490 * The @code attr@ parameter may be modified as a result of setting the value.
3492 * The @code element@ parameter specifies which value to set from 0 to
3493 * @link ippGetCount(attr)@.
3495 * @since CUPS 1.6/OS X 10.8@
3498 int /* O - 1 on success, 0 on failure */
3499 ippSetRange(ipp_t
*ipp
, /* IO - IPP message */
3500 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3501 int element
, /* I - Value number (0-based) */
3502 int lowervalue
, /* I - Lower bound for range */
3503 int uppervalue
) /* I - Upper bound for range */
3505 _ipp_value_t
*value
; /* Current value */
3509 * Range check input...
3512 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RANGE
||
3513 element
< 0 || element
> (*attr
)->num_values
|| lowervalue
> uppervalue
)
3517 * Set the value and return...
3520 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3522 value
->range
.lower
= lowervalue
;
3523 value
->range
.upper
= uppervalue
;
3526 return (value
!= NULL
);
3531 * 'ippSetRequestId()' - Set the request ID in an IPP message.
3533 * The @code ipp@ parameter refers to an IPP message previously created using the
3534 * @link ippNew@ or @link ippNewRequest@ functions.
3536 * The @code request_id@ parameter must be greater than 0.
3538 * @since CUPS 1.6/OS X 10.8@
3541 int /* O - 1 on success, 0 on failure */
3542 ippSetRequestId(ipp_t
*ipp
, /* I - IPP message */
3543 int request_id
) /* I - Request ID */
3546 * Range check input; not checking request_id values since ipptool wants to send
3547 * invalid values for conformance testing and a bad request_id does not affect the
3548 * encoding of a message...
3555 * Set the request ID and return...
3558 ipp
->request
.any
.request_id
= request_id
;
3565 * 'ippSetResolution()' - Set a resolution value in an attribute.
3567 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3568 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3570 * The @code attr@ parameter may be modified as a result of setting the value.
3572 * The @code element@ parameter specifies which value to set from 0 to
3573 * @link ippGetCount(attr)@.
3575 * @since CUPS 1.6/OS X 10.8@
3578 int /* O - 1 on success, 0 on failure */
3580 ipp_t
*ipp
, /* IO - IPP message */
3581 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3582 int element
, /* I - Value number (0-based) */
3583 ipp_res_t unitsvalue
, /* I - Resolution units */
3584 int xresvalue
, /* I - Horizontal/cross feed resolution */
3585 int yresvalue
) /* I - Vertical/feed resolution */
3587 _ipp_value_t
*value
; /* Current value */
3591 * Range check input...
3594 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RESOLUTION
||
3595 element
< 0 || element
> (*attr
)->num_values
|| xresvalue
<= 0 || yresvalue
<= 0 ||
3596 unitsvalue
< IPP_RES_PER_INCH
|| unitsvalue
> IPP_RES_PER_CM
)
3600 * Set the value and return...
3603 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3605 value
->resolution
.units
= unitsvalue
;
3606 value
->resolution
.xres
= xresvalue
;
3607 value
->resolution
.yres
= yresvalue
;
3610 return (value
!= NULL
);
3615 * 'ippSetState()' - Set the current state of the IPP message.
3617 * @since CUPS 1.6/OS X 10.8@
3620 int /* O - 1 on success, 0 on failure */
3621 ippSetState(ipp_t
*ipp
, /* I - IPP message */
3622 ipp_state_t state
) /* I - IPP state value */
3625 * Range check input...
3632 * Set the state and return...
3636 ipp
->current
= NULL
;
3643 * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
3645 * The @code ipp@ parameter refers to an IPP message previously created using the
3646 * @link ippNew@ or @link ippNewRequest@ functions.
3648 * @since CUPS 1.6/OS X 10.8@
3651 int /* O - 1 on success, 0 on failure */
3652 ippSetStatusCode(ipp_t
*ipp
, /* I - IPP response or event message */
3653 ipp_status_t status
) /* I - Status code */
3656 * Range check input...
3663 * Set the status code and return...
3666 ipp
->request
.status
.status_code
= status
;
3673 * 'ippSetString()' - Set a string value in an attribute.
3675 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3676 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3678 * The @code attr@ parameter may be modified as a result of setting the value.
3680 * The @code element@ parameter specifies which value to set from 0 to
3681 * @link ippGetCount(attr)@.
3683 * @since CUPS 1.6/OS X 10.8@
3686 int /* O - 1 on success, 0 on failure */
3687 ippSetString(ipp_t
*ipp
, /* IO - IPP message */
3688 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3689 int element
, /* I - Value number (0-based) */
3690 const char *strvalue
) /* I - String value */
3692 char *temp
; /* Temporary string */
3693 _ipp_value_t
*value
; /* Current value */
3697 * Range check input...
3700 if (!ipp
|| !attr
|| !*attr
||
3701 ((*attr
)->value_tag
!= IPP_TAG_TEXTLANG
&&
3702 (*attr
)->value_tag
!= IPP_TAG_NAMELANG
&&
3703 ((*attr
)->value_tag
< IPP_TAG_TEXT
||
3704 (*attr
)->value_tag
> IPP_TAG_MIMETYPE
)) ||
3705 element
< 0 || element
> (*attr
)->num_values
|| !strvalue
)
3709 * Set the value and return...
3712 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3715 value
->string
.language
= (*attr
)->values
[0].string
.language
;
3717 if ((int)((*attr
)->value_tag
) & IPP_TAG_COPY
)
3718 value
->string
.text
= (char *)strvalue
;
3719 else if ((temp
= _cupsStrAlloc(strvalue
)) != NULL
)
3721 if (value
->string
.text
)
3722 _cupsStrFree(value
->string
.text
);
3724 value
->string
.text
= temp
;
3730 return (value
!= NULL
);
3735 * 'ippSetValueTag()' - Set the value tag of an attribute.
3737 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3738 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3740 * The @code attr@ parameter may be modified as a result of setting the value.
3742 * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger
3743 * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name
3744 * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text
3745 * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage
3746 * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various
3747 * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes
3750 * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language
3751 * code in the "attributes-natural-language" attribute or, if not present, the language
3752 * code for the current locale.
3754 * @since CUPS 1.6/OS X 10.8@
3757 int /* O - 1 on success, 0 on failure */
3759 ipp_t
*ipp
, /* IO - IPP message */
3760 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3761 ipp_tag_t value_tag
) /* I - Value tag */
3763 int i
; /* Looping var */
3764 _ipp_value_t
*value
; /* Current value */
3765 int integer
; /* Current integer value */
3766 cups_lang_t
*language
; /* Current language */
3767 char code
[32]; /* Language code */
3768 ipp_tag_t temp_tag
; /* Temporary value tag */
3772 * Range check input...
3779 * If there is no change, return immediately...
3782 if (value_tag
== (*attr
)->value_tag
)
3786 * Otherwise implement changes as needed...
3789 temp_tag
= (ipp_tag_t
)((int)((*attr
)->value_tag
) & IPP_TAG_MASK
);
3793 case IPP_TAG_UNSUPPORTED_VALUE
:
3794 case IPP_TAG_DEFAULT
:
3795 case IPP_TAG_UNKNOWN
:
3796 case IPP_TAG_NOVALUE
:
3797 case IPP_TAG_NOTSETTABLE
:
3798 case IPP_TAG_DELETEATTR
:
3799 case IPP_TAG_ADMINDEFINE
:
3801 * Free any existing values...
3804 if ((*attr
)->num_values
> 0)
3805 ipp_free_values(*attr
, 0, (*attr
)->num_values
);
3808 * Set out-of-band value...
3811 (*attr
)->value_tag
= value_tag
;
3814 case IPP_TAG_RANGE
:
3815 if (temp_tag
!= IPP_TAG_INTEGER
)
3818 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
3822 integer
= value
->integer
;
3823 value
->range
.lower
= value
->range
.upper
= integer
;
3826 (*attr
)->value_tag
= IPP_TAG_RANGE
;
3830 if (temp_tag
!= IPP_TAG_KEYWORD
&& temp_tag
!= IPP_TAG_URI
&&
3831 temp_tag
!= IPP_TAG_URISCHEME
&& temp_tag
!= IPP_TAG_LANGUAGE
&&
3832 temp_tag
!= IPP_TAG_MIMETYPE
)
3835 (*attr
)->value_tag
= (ipp_tag_t
)(IPP_TAG_NAME
| ((*attr
)->value_tag
& IPP_TAG_COPY
));
3838 case IPP_TAG_NAMELANG
:
3839 case IPP_TAG_TEXTLANG
:
3840 if (value_tag
== IPP_TAG_NAMELANG
&&
3841 (temp_tag
!= IPP_TAG_NAME
&& temp_tag
!= IPP_TAG_KEYWORD
&&
3842 temp_tag
!= IPP_TAG_URI
&& temp_tag
!= IPP_TAG_URISCHEME
&&
3843 temp_tag
!= IPP_TAG_LANGUAGE
&& temp_tag
!= IPP_TAG_MIMETYPE
))
3846 if (value_tag
== IPP_TAG_TEXTLANG
&& temp_tag
!= IPP_TAG_TEXT
)
3849 if (ipp
->attrs
&& ipp
->attrs
->next
&& ipp
->attrs
->next
->name
&&
3850 !strcmp(ipp
->attrs
->next
->name
, "attributes-natural-language"))
3853 * Use the language code from the IPP message...
3856 (*attr
)->values
[0].string
.language
=
3857 _cupsStrAlloc(ipp
->attrs
->next
->values
[0].string
.text
);
3862 * Otherwise, use the language code corresponding to the locale...
3865 language
= cupsLangDefault();
3866 (*attr
)->values
[0].string
.language
= _cupsStrAlloc(ipp_lang_code(language
->language
,
3871 for (i
= (*attr
)->num_values
- 1, value
= (*attr
)->values
+ 1;
3874 value
->string
.language
= (*attr
)->values
[0].string
.language
;
3876 if ((int)(*attr
)->value_tag
& IPP_TAG_COPY
)
3879 * Make copies of all values...
3882 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
3885 value
->string
.text
= _cupsStrAlloc(value
->string
.text
);
3888 (*attr
)->value_tag
= IPP_TAG_NAMELANG
;
3891 case IPP_TAG_KEYWORD
:
3892 if (temp_tag
== IPP_TAG_NAME
|| temp_tag
== IPP_TAG_NAMELANG
)
3893 break; /* Silently "allow" name -> keyword */
3904 * 'ippSetVersion()' - Set the version number in an IPP message.
3906 * The @code ipp@ parameter refers to an IPP message previously created using the
3907 * @link ippNew@ or @link ippNewRequest@ functions.
3909 * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
3911 * @since CUPS 1.6/OS X 10.8@
3914 int /* O - 1 on success, 0 on failure */
3915 ippSetVersion(ipp_t
*ipp
, /* I - IPP message */
3916 int major
, /* I - Major version number (major.minor) */
3917 int minor
) /* I - Minor version number (major.minor) */
3920 * Range check input...
3923 if (!ipp
|| major
< 0 || minor
< 0)
3927 * Set the version number...
3930 ipp
->request
.any
.version
[0] = major
;
3931 ipp
->request
.any
.version
[1] = minor
;
3938 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
3941 const ipp_uchar_t
* /* O - RFC-1903 date/time data */
3942 ippTimeToDate(time_t t
) /* I - UNIX time value */
3944 struct tm
*unixdate
; /* UNIX unixdate/time info */
3945 ipp_uchar_t
*date
= _cupsGlobals()->ipp_date
;
3946 /* RFC-1903 date/time data */
3950 * RFC-1903 date/time format is:
3952 * Byte(s) Description
3953 * ------- -----------
3954 * 0-1 Year (0 to 65535)
3958 * 5 Minutes (0 to 59)
3959 * 6 Seconds (0 to 60, 60 = "leap second")
3960 * 7 Deciseconds (0 to 9)
3962 * 9 UTC hours (0 to 11)
3963 * 10 UTC minutes (0 to 59)
3966 unixdate
= gmtime(&t
);
3967 unixdate
->tm_year
+= 1900;
3969 date
[0] = unixdate
->tm_year
>> 8;
3970 date
[1] = unixdate
->tm_year
;
3971 date
[2] = unixdate
->tm_mon
+ 1;
3972 date
[3] = unixdate
->tm_mday
;
3973 date
[4] = unixdate
->tm_hour
;
3974 date
[5] = unixdate
->tm_min
;
3975 date
[6] = unixdate
->tm_sec
;
3986 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
3989 ipp_state_t
/* O - Current state */
3990 ippWrite(http_t
*http
, /* I - HTTP connection */
3991 ipp_t
*ipp
) /* I - IPP data */
3993 DEBUG_printf(("ippWrite(http=%p, ipp=%p)", http
, ipp
));
3998 return (ippWriteIO(http
, (ipp_iocb_t
)httpWrite2
, http
->blocking
, NULL
, ipp
));
4003 * 'ippWriteFile()' - Write data for an IPP message to a file.
4005 * @since CUPS 1.1.19/OS X 10.3@
4008 ipp_state_t
/* O - Current state */
4009 ippWriteFile(int fd
, /* I - HTTP data */
4010 ipp_t
*ipp
) /* I - IPP data */
4012 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd
, ipp
));
4014 ipp
->state
= IPP_IDLE
;
4016 return (ippWriteIO(&fd
, (ipp_iocb_t
)ipp_write_file
, 1, NULL
, ipp
));
4021 * 'ippWriteIO()' - Write data for an IPP message.
4023 * @since CUPS 1.2/OS X 10.5@
4026 ipp_state_t
/* O - Current state */
4027 ippWriteIO(void *dst
, /* I - Destination */
4028 ipp_iocb_t cb
, /* I - Write callback function */
4029 int blocking
, /* I - Use blocking IO? */
4030 ipp_t
*parent
, /* I - Parent IPP message */
4031 ipp_t
*ipp
) /* I - IPP data */
4033 int i
; /* Looping var */
4034 int n
; /* Length of data */
4035 unsigned char *buffer
, /* Data buffer */
4036 *bufptr
; /* Pointer into buffer */
4037 ipp_attribute_t
*attr
; /* Current attribute */
4038 _ipp_value_t
*value
; /* Current value */
4041 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
4042 dst
, cb
, blocking
, parent
, ipp
));
4047 if ((buffer
= (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE
)) == NULL
)
4049 DEBUG_puts("1ippWriteIO: Unable to get write buffer");
4056 ipp
->state
++; /* Avoid common problem... */
4062 * Send the request header:
4065 * Operation/Status Code = 2 bytes
4066 * Request ID = 4 bytes
4072 *bufptr
++ = ipp
->request
.any
.version
[0];
4073 *bufptr
++ = ipp
->request
.any
.version
[1];
4074 *bufptr
++ = ipp
->request
.any
.op_status
>> 8;
4075 *bufptr
++ = ipp
->request
.any
.op_status
;
4076 *bufptr
++ = ipp
->request
.any
.request_id
>> 24;
4077 *bufptr
++ = ipp
->request
.any
.request_id
>> 16;
4078 *bufptr
++ = ipp
->request
.any
.request_id
>> 8;
4079 *bufptr
++ = ipp
->request
.any
.request_id
;
4081 DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer
[0], buffer
[1]));
4082 DEBUG_printf(("2ippWriteIO: op_status=%04x",
4083 ipp
->request
.any
.op_status
));
4084 DEBUG_printf(("2ippWriteIO: request_id=%d",
4085 ipp
->request
.any
.request_id
));
4087 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4089 DEBUG_puts("1ippWriteIO: Could not write IPP header...");
4090 _cupsBufferRelease((char *)buffer
);
4096 * Reset the state engine to point to the first attribute
4097 * in the request/response, with no current group.
4100 ipp
->state
= IPP_ATTRIBUTE
;
4101 ipp
->current
= ipp
->attrs
;
4102 ipp
->curtag
= IPP_TAG_ZERO
;
4104 DEBUG_printf(("1ippWriteIO: ipp->current=%p", ipp
->current
));
4107 * If blocking is disabled, stop here...
4113 case IPP_ATTRIBUTE
:
4114 while (ipp
->current
!= NULL
)
4117 * Write this attribute...
4121 attr
= ipp
->current
;
4123 ipp
->current
= ipp
->current
->next
;
4127 if (ipp
->curtag
!= attr
->group_tag
)
4130 * Send a group tag byte...
4133 ipp
->curtag
= attr
->group_tag
;
4135 if (attr
->group_tag
== IPP_TAG_ZERO
)
4138 DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
4139 attr
->group_tag
, ippTagString(attr
->group_tag
)));
4140 *bufptr
++ = attr
->group_tag
;
4142 else if (attr
->group_tag
== IPP_TAG_ZERO
)
4146 DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr
->name
,
4147 attr
->num_values
> 1 ? "1setOf " : "",
4148 ippTagString(attr
->value_tag
)));
4151 * Write the attribute tag and name.
4153 * The attribute name length does not include the trailing nul
4154 * character in the source string.
4156 * Collection values (parent != NULL) are written differently...
4162 * Get the length of the attribute name, and make sure it won't
4163 * overflow the buffer...
4166 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 8))
4168 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
4169 _cupsBufferRelease((char *)buffer
);
4174 * Write the value tag, name length, and name string...
4177 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4178 attr
->value_tag
, ippTagString(attr
->value_tag
)));
4179 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
4182 if (attr
->value_tag
> 0xff)
4184 *bufptr
++ = IPP_TAG_EXTENSION
;
4185 *bufptr
++ = attr
->value_tag
>> 24;
4186 *bufptr
++ = attr
->value_tag
>> 16;
4187 *bufptr
++ = attr
->value_tag
>> 8;
4188 *bufptr
++ = attr
->value_tag
;
4191 *bufptr
++ = attr
->value_tag
;
4195 memcpy(bufptr
, attr
->name
, n
);
4201 * Get the length of the attribute name, and make sure it won't
4202 * overflow the buffer...
4205 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 12))
4207 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
4208 _cupsBufferRelease((char *)buffer
);
4213 * Write the member name tag, name length, name string, value tag,
4214 * and empty name for the collection member attribute...
4217 DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
4218 IPP_TAG_MEMBERNAME
));
4219 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
4221 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4222 attr
->value_tag
, ippTagString(attr
->value_tag
)));
4223 DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
4225 *bufptr
++ = IPP_TAG_MEMBERNAME
;
4230 memcpy(bufptr
, attr
->name
, n
);
4233 if (attr
->value_tag
> 0xff)
4235 *bufptr
++ = IPP_TAG_EXTENSION
;
4236 *bufptr
++ = attr
->value_tag
>> 24;
4237 *bufptr
++ = attr
->value_tag
>> 16;
4238 *bufptr
++ = attr
->value_tag
>> 8;
4239 *bufptr
++ = attr
->value_tag
;
4242 *bufptr
++ = attr
->value_tag
;
4249 * Now write the attribute value(s)...
4252 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
4254 case IPP_TAG_UNSUPPORTED_VALUE
:
4255 case IPP_TAG_DEFAULT
:
4256 case IPP_TAG_UNKNOWN
:
4257 case IPP_TAG_NOVALUE
:
4258 case IPP_TAG_NOTSETTABLE
:
4259 case IPP_TAG_DELETEATTR
:
4260 case IPP_TAG_ADMINDEFINE
:
4265 case IPP_TAG_INTEGER
:
4267 for (i
= 0, value
= attr
->values
;
4268 i
< attr
->num_values
;
4271 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 9)
4273 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4275 DEBUG_puts("1ippWriteIO: Could not write IPP "
4277 _cupsBufferRelease((char *)buffer
);
4287 * Arrays and sets are done by sending additional
4288 * values with a zero-length name...
4291 *bufptr
++ = attr
->value_tag
;
4297 * Integers and enumerations are both 4-byte signed
4298 * (twos-complement) values.
4300 * Put the 2-byte length and 4-byte value into the buffer...
4305 *bufptr
++ = value
->integer
>> 24;
4306 *bufptr
++ = value
->integer
>> 16;
4307 *bufptr
++ = value
->integer
>> 8;
4308 *bufptr
++ = value
->integer
;
4312 case IPP_TAG_BOOLEAN
:
4313 for (i
= 0, value
= attr
->values
;
4314 i
< attr
->num_values
;
4317 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 6)
4319 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4321 DEBUG_puts("1ippWriteIO: Could not write IPP "
4323 _cupsBufferRelease((char *)buffer
);
4333 * Arrays and sets are done by sending additional
4334 * values with a zero-length name...
4337 *bufptr
++ = attr
->value_tag
;
4343 * Boolean values are 1-byte; 0 = false, 1 = true.
4345 * Put the 2-byte length and 1-byte value into the buffer...
4350 *bufptr
++ = value
->boolean
;
4356 case IPP_TAG_KEYWORD
:
4358 case IPP_TAG_URISCHEME
:
4359 case IPP_TAG_CHARSET
:
4360 case IPP_TAG_LANGUAGE
:
4361 case IPP_TAG_MIMETYPE
:
4362 for (i
= 0, value
= attr
->values
;
4363 i
< attr
->num_values
;
4369 * Arrays and sets are done by sending additional
4370 * values with a zero-length name...
4373 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4375 ippTagString(attr
->value_tag
)));
4376 DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
4378 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
4380 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4382 DEBUG_puts("1ippWriteIO: Could not write IPP "
4384 _cupsBufferRelease((char *)buffer
);
4391 *bufptr
++ = attr
->value_tag
;
4396 if (value
->string
.text
!= NULL
)
4397 n
= (int)strlen(value
->string
.text
);
4401 if (n
> (IPP_BUF_SIZE
- 2))
4403 DEBUG_printf(("1ippWriteIO: String too long (%d)", n
));
4404 _cupsBufferRelease((char *)buffer
);
4408 DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n
,
4409 value
->string
.text
));
4411 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
4413 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4415 DEBUG_puts("1ippWriteIO: Could not write IPP "
4417 _cupsBufferRelease((char *)buffer
);
4425 * All simple strings consist of the 2-byte length and
4426 * character data without the trailing nul normally found
4427 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
4428 * bytes since the 2-byte length is a signed (twos-complement)
4431 * Put the 2-byte length and string characters in the buffer.
4439 memcpy(bufptr
, value
->string
.text
, n
);
4446 for (i
= 0, value
= attr
->values
;
4447 i
< attr
->num_values
;
4450 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 16)
4452 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4454 DEBUG_puts("1ippWriteIO: Could not write IPP "
4456 _cupsBufferRelease((char *)buffer
);
4466 * Arrays and sets are done by sending additional
4467 * values with a zero-length name...
4470 *bufptr
++ = attr
->value_tag
;
4476 * Date values consist of a 2-byte length and an
4477 * 11-byte date/time structure defined by RFC 1903.
4479 * Put the 2-byte length and 11-byte date/time
4480 * structure in the buffer.
4485 memcpy(bufptr
, value
->date
, 11);
4490 case IPP_TAG_RESOLUTION
:
4491 for (i
= 0, value
= attr
->values
;
4492 i
< attr
->num_values
;
4495 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 14)
4497 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4499 DEBUG_puts("1ippWriteIO: Could not write IPP "
4501 _cupsBufferRelease((char *)buffer
);
4511 * Arrays and sets are done by sending additional
4512 * values with a zero-length name...
4515 *bufptr
++ = attr
->value_tag
;
4521 * Resolution values consist of a 2-byte length,
4522 * 4-byte horizontal resolution value, 4-byte vertical
4523 * resolution value, and a 1-byte units value.
4525 * Put the 2-byte length and resolution value data
4531 *bufptr
++ = value
->resolution
.xres
>> 24;
4532 *bufptr
++ = value
->resolution
.xres
>> 16;
4533 *bufptr
++ = value
->resolution
.xres
>> 8;
4534 *bufptr
++ = value
->resolution
.xres
;
4535 *bufptr
++ = value
->resolution
.yres
>> 24;
4536 *bufptr
++ = value
->resolution
.yres
>> 16;
4537 *bufptr
++ = value
->resolution
.yres
>> 8;
4538 *bufptr
++ = value
->resolution
.yres
;
4539 *bufptr
++ = value
->resolution
.units
;
4543 case IPP_TAG_RANGE
:
4544 for (i
= 0, value
= attr
->values
;
4545 i
< attr
->num_values
;
4548 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 13)
4550 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4552 DEBUG_puts("1ippWriteIO: Could not write IPP "
4554 _cupsBufferRelease((char *)buffer
);
4564 * Arrays and sets are done by sending additional
4565 * values with a zero-length name...
4568 *bufptr
++ = attr
->value_tag
;
4574 * Range values consist of a 2-byte length,
4575 * 4-byte lower value, and 4-byte upper value.
4577 * Put the 2-byte length and range value data
4583 *bufptr
++ = value
->range
.lower
>> 24;
4584 *bufptr
++ = value
->range
.lower
>> 16;
4585 *bufptr
++ = value
->range
.lower
>> 8;
4586 *bufptr
++ = value
->range
.lower
;
4587 *bufptr
++ = value
->range
.upper
>> 24;
4588 *bufptr
++ = value
->range
.upper
>> 16;
4589 *bufptr
++ = value
->range
.upper
>> 8;
4590 *bufptr
++ = value
->range
.upper
;
4594 case IPP_TAG_TEXTLANG
:
4595 case IPP_TAG_NAMELANG
:
4596 for (i
= 0, value
= attr
->values
;
4597 i
< attr
->num_values
;
4603 * Arrays and sets are done by sending additional
4604 * values with a zero-length name...
4607 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
4609 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4611 DEBUG_puts("1ippWriteIO: Could not write IPP "
4613 _cupsBufferRelease((char *)buffer
);
4620 *bufptr
++ = attr
->value_tag
;
4626 * textWithLanguage and nameWithLanguage values consist
4627 * of a 2-byte length for both strings and their
4628 * individual lengths, a 2-byte length for the
4629 * character string, the character string without the
4630 * trailing nul, a 2-byte length for the character
4631 * set string, and the character set string without
4637 if (value
->string
.language
!= NULL
)
4638 n
+= (int)strlen(value
->string
.language
);
4640 if (value
->string
.text
!= NULL
)
4641 n
+= (int)strlen(value
->string
.text
);
4643 if (n
> (IPP_BUF_SIZE
- 2))
4645 DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
4646 "too long (%d)", n
));
4647 _cupsBufferRelease((char *)buffer
);
4651 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
4653 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4655 DEBUG_puts("1ippWriteIO: Could not write IPP "
4657 _cupsBufferRelease((char *)buffer
);
4664 /* Length of entire value */
4668 /* Length of language */
4669 if (value
->string
.language
!= NULL
)
4670 n
= (int)strlen(value
->string
.language
);
4680 memcpy(bufptr
, value
->string
.language
, n
);
4684 /* Length of text */
4685 if (value
->string
.text
!= NULL
)
4686 n
= (int)strlen(value
->string
.text
);
4696 memcpy(bufptr
, value
->string
.text
, n
);
4702 case IPP_TAG_BEGIN_COLLECTION
:
4703 for (i
= 0, value
= attr
->values
;
4704 i
< attr
->num_values
;
4708 * Collections are written with the begin-collection
4709 * tag first with a value of 0 length, followed by the
4710 * attributes in the collection, then the end-collection
4714 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 5)
4716 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4718 DEBUG_puts("1ippWriteIO: Could not write IPP "
4720 _cupsBufferRelease((char *)buffer
);
4730 * Arrays and sets are done by sending additional
4731 * values with a zero-length name...
4734 *bufptr
++ = attr
->value_tag
;
4740 * Write a data length of 0 and flush the buffer...
4746 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4748 DEBUG_puts("1ippWriteIO: Could not write IPP "
4750 _cupsBufferRelease((char *)buffer
);
4757 * Then write the collection attribute...
4760 value
->collection
->state
= IPP_IDLE
;
4762 if (ippWriteIO(dst
, cb
, 1, ipp
,
4763 value
->collection
) == IPP_ERROR
)
4765 DEBUG_puts("1ippWriteIO: Unable to write collection value");
4766 _cupsBufferRelease((char *)buffer
);
4773 for (i
= 0, value
= attr
->values
;
4774 i
< attr
->num_values
;
4780 * Arrays and sets are done by sending additional
4781 * values with a zero-length name...
4784 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
4786 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4788 DEBUG_puts("1ippWriteIO: Could not write IPP "
4790 _cupsBufferRelease((char *)buffer
);
4797 *bufptr
++ = attr
->value_tag
;
4803 * An unknown value might some new value that a
4804 * vendor has come up with. It consists of a
4805 * 2-byte length and the bytes in the unknown
4809 n
= value
->unknown
.length
;
4811 if (n
> (IPP_BUF_SIZE
- 2))
4813 DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
4815 _cupsBufferRelease((char *)buffer
);
4819 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
4821 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4823 DEBUG_puts("1ippWriteIO: Could not write IPP "
4825 _cupsBufferRelease((char *)buffer
);
4832 /* Length of unknown value */
4839 memcpy(bufptr
, value
->unknown
.data
, n
);
4847 * Write the data out...
4850 if (bufptr
> buffer
)
4852 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4854 DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4855 _cupsBufferRelease((char *)buffer
);
4859 DEBUG_printf(("2ippWriteIO: wrote %d bytes",
4860 (int)(bufptr
- buffer
)));
4864 * If blocking is disabled, stop here...
4871 if (ipp
->current
== NULL
)
4874 * Done with all of the attributes; add the end-of-attributes
4875 * tag or end-collection attribute...
4880 buffer
[0] = IPP_TAG_END
;
4885 buffer
[0] = IPP_TAG_END_COLLECTION
;
4886 buffer
[1] = 0; /* empty name */
4888 buffer
[3] = 0; /* empty value */
4893 if ((*cb
)(dst
, buffer
, n
) < 0)
4895 DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
4896 _cupsBufferRelease((char *)buffer
);
4900 ipp
->state
= IPP_DATA
;
4908 break; /* anti-compiler-warning-code */
4911 _cupsBufferRelease((char *)buffer
);
4913 return (ipp
->state
);
4918 * 'ipp_add_attr()' - Add a new attribute to the message.
4921 static ipp_attribute_t
* /* O - New attribute */
4922 ipp_add_attr(ipp_t
*ipp
, /* I - IPP message */
4923 const char *name
, /* I - Attribute name or NULL */
4924 ipp_tag_t group_tag
, /* I - Group tag or IPP_TAG_ZERO */
4925 ipp_tag_t value_tag
, /* I - Value tag or IPP_TAG_ZERO */
4926 int num_values
) /* I - Number of values */
4928 int alloc_values
; /* Number of values to allocate */
4929 ipp_attribute_t
*attr
; /* New attribute */
4932 DEBUG_printf(("4ipp_add_attr(ipp=%p, name=\"%s\", group_tag=0x%x, value_tag=0x%x, "
4933 "num_values=%d)", ipp
, name
, group_tag
, value_tag
, num_values
));
4936 * Range check input...
4939 if (!ipp
|| num_values
< 0)
4943 * Allocate memory, rounding the allocation up as needed...
4946 if (num_values
<= 1)
4949 alloc_values
= (num_values
+ IPP_MAX_VALUES
- 1) & ~(IPP_MAX_VALUES
- 1);
4951 attr
= calloc(sizeof(ipp_attribute_t
) +
4952 (alloc_values
- 1) * sizeof(_ipp_value_t
), 1);
4957 * Initialize attribute...
4961 attr
->name
= _cupsStrAlloc(name
);
4963 attr
->group_tag
= group_tag
;
4964 attr
->value_tag
= value_tag
;
4965 attr
->num_values
= num_values
;
4968 * Add it to the end of the linked list...
4972 ipp
->last
->next
= attr
;
4976 ipp
->prev
= ipp
->last
;
4977 ipp
->last
= ipp
->current
= attr
;
4980 DEBUG_printf(("5ipp_add_attr: Returning %p", attr
));
4987 * 'ipp_free_values()' - Free attribute values.
4991 ipp_free_values(ipp_attribute_t
*attr
, /* I - Attribute to free values from */
4992 int element
,/* I - First value to free */
4993 int count
) /* I - Number of values to free */
4995 int i
; /* Looping var */
4996 _ipp_value_t
*value
; /* Current value */
4999 DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", attr
, element
, count
));
5001 if (!(attr
->value_tag
& IPP_TAG_COPY
))
5004 * Free values as needed...
5007 switch (attr
->value_tag
)
5009 case IPP_TAG_TEXTLANG
:
5010 case IPP_TAG_NAMELANG
:
5011 if (element
== 0 && count
== attr
->num_values
&& attr
->values
[0].string
.language
)
5012 _cupsStrFree(attr
->values
[0].string
.language
);
5016 case IPP_TAG_RESERVED_STRING
:
5017 case IPP_TAG_KEYWORD
:
5019 case IPP_TAG_URISCHEME
:
5020 case IPP_TAG_CHARSET
:
5021 case IPP_TAG_LANGUAGE
:
5022 case IPP_TAG_MIMETYPE
:
5023 for (i
= count
, value
= attr
->values
+ element
;
5026 _cupsStrFree(value
->string
.text
);
5029 case IPP_TAG_DEFAULT
:
5030 case IPP_TAG_UNKNOWN
:
5031 case IPP_TAG_NOVALUE
:
5032 case IPP_TAG_NOTSETTABLE
:
5033 case IPP_TAG_DELETEATTR
:
5034 case IPP_TAG_ADMINDEFINE
:
5035 case IPP_TAG_INTEGER
:
5037 case IPP_TAG_BOOLEAN
:
5039 case IPP_TAG_RESOLUTION
:
5040 case IPP_TAG_RANGE
:
5043 case IPP_TAG_BEGIN_COLLECTION
:
5044 for (i
= count
, value
= attr
->values
+ element
;
5047 ippDelete(value
->collection
);
5050 case IPP_TAG_STRING
:
5052 for (i
= count
, value
= attr
->values
+ element
;
5055 if (value
->unknown
.data
)
5056 free(value
->unknown
.data
);
5062 * If we are not freeing values from the end, move the remaining values up...
5065 if ((element
+ count
) < attr
->num_values
)
5066 memmove(attr
->values
+ element
, attr
->values
+ element
+ count
,
5067 (attr
->num_values
- count
- element
) * sizeof(_ipp_value_t
));
5069 attr
->num_values
-= count
;
5074 * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
5076 * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
5077 * to "ll-cc", "ll-region", and "charset-number", respectively.
5080 static char * /* O - Language code string */
5081 ipp_get_code(const char *value
, /* I - Locale/charset string */
5082 char *buffer
, /* I - String buffer */
5083 size_t bufsize
) /* I - Size of string buffer */
5085 char *bufptr
, /* Pointer into buffer */
5086 *bufend
; /* End of buffer */
5090 * Convert values to lowercase and change _ to - as needed...
5093 for (bufptr
= buffer
, bufend
= buffer
+ bufsize
- 1;
5094 *value
&& bufptr
< bufend
;
5099 *bufptr
++ = _cups_tolower(*value
);
5104 * Return the converted string...
5112 * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
5114 * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
5115 * "ll-region", respectively. It also converts the "C" (POSIX) locale to "en".
5118 static char * /* O - Language code string */
5119 ipp_lang_code(const char *locale
, /* I - Locale string */
5120 char *buffer
, /* I - String buffer */
5121 size_t bufsize
) /* I - Size of string buffer */
5124 * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
5127 if (!_cups_strcasecmp(locale
, "c"))
5129 strlcpy(buffer
, "en", bufsize
);
5133 return (ipp_get_code(locale
, buffer
, bufsize
));
5138 * 'ipp_length()' - Compute the length of an IPP message or collection value.
5141 static size_t /* O - Size of IPP message */
5142 ipp_length(ipp_t
*ipp
, /* I - IPP message or collection */
5143 int collection
) /* I - 1 if a collection, 0 otherwise */
5145 int i
; /* Looping var */
5146 size_t bytes
; /* Number of bytes */
5147 ipp_attribute_t
*attr
; /* Current attribute */
5148 ipp_tag_t group
; /* Current group */
5149 _ipp_value_t
*value
; /* Current value */
5152 DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", ipp
, collection
));
5156 DEBUG_puts("4ipp_length: Returning 0 bytes");
5161 * Start with 8 bytes for the IPP message header...
5164 bytes
= collection
? 0 : 8;
5167 * Then add the lengths of each attribute...
5170 group
= IPP_TAG_ZERO
;
5172 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= attr
->next
)
5174 if (attr
->group_tag
!= group
&& !collection
)
5176 group
= attr
->group_tag
;
5177 if (group
== IPP_TAG_ZERO
)
5180 bytes
++; /* Group tag */
5186 DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
5187 "bytes=" CUPS_LLFMT
, attr
->name
, attr
->num_values
, CUPS_LLCAST bytes
));
5189 if (attr
->value_tag
< IPP_TAG_EXTENSION
)
5190 bytes
+= attr
->num_values
; /* Value tag for each value */
5192 bytes
+= 5 * attr
->num_values
; /* Value tag for each value */
5193 bytes
+= 2 * attr
->num_values
; /* Name lengths */
5194 bytes
+= (int)strlen(attr
->name
); /* Name */
5195 bytes
+= 2 * attr
->num_values
; /* Value lengths */
5198 bytes
+= 5; /* Add membername overhead */
5200 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
5202 case IPP_TAG_UNSUPPORTED_VALUE
:
5203 case IPP_TAG_DEFAULT
:
5204 case IPP_TAG_UNKNOWN
:
5205 case IPP_TAG_NOVALUE
:
5206 case IPP_TAG_NOTSETTABLE
:
5207 case IPP_TAG_DELETEATTR
:
5208 case IPP_TAG_ADMINDEFINE
:
5211 case IPP_TAG_INTEGER
:
5213 bytes
+= 4 * attr
->num_values
;
5216 case IPP_TAG_BOOLEAN
:
5217 bytes
+= attr
->num_values
;
5222 case IPP_TAG_KEYWORD
:
5224 case IPP_TAG_URISCHEME
:
5225 case IPP_TAG_CHARSET
:
5226 case IPP_TAG_LANGUAGE
:
5227 case IPP_TAG_MIMETYPE
:
5228 for (i
= 0, value
= attr
->values
;
5229 i
< attr
->num_values
;
5231 if (value
->string
.text
)
5232 bytes
+= strlen(value
->string
.text
);
5236 bytes
+= 11 * attr
->num_values
;
5239 case IPP_TAG_RESOLUTION
:
5240 bytes
+= 9 * attr
->num_values
;
5243 case IPP_TAG_RANGE
:
5244 bytes
+= 8 * attr
->num_values
;
5247 case IPP_TAG_TEXTLANG
:
5248 case IPP_TAG_NAMELANG
:
5249 bytes
+= 4 * attr
->num_values
;/* Charset + text length */
5251 for (i
= 0, value
= attr
->values
;
5252 i
< attr
->num_values
;
5255 if (value
->string
.language
)
5256 bytes
+= strlen(value
->string
.language
);
5258 if (value
->string
.text
)
5259 bytes
+= strlen(value
->string
.text
);
5263 case IPP_TAG_BEGIN_COLLECTION
:
5264 for (i
= 0, value
= attr
->values
;
5265 i
< attr
->num_values
;
5267 bytes
+= ipp_length(value
->collection
, 1);
5271 for (i
= 0, value
= attr
->values
;
5272 i
< attr
->num_values
;
5274 bytes
+= value
->unknown
.length
;
5280 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
5281 * for the "end of collection" tag and return...
5289 DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT
" bytes", CUPS_LLCAST bytes
));
5296 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
5299 static ssize_t
/* O - Number of bytes read */
5300 ipp_read_http(http_t
*http
, /* I - Client connection */
5301 ipp_uchar_t
*buffer
, /* O - Buffer for data */
5302 size_t length
) /* I - Total length */
5304 int tbytes
, /* Total bytes read */
5305 bytes
; /* Bytes read this pass */
5308 DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)",
5309 http
, buffer
, (int)length
));
5312 * Loop until all bytes are read...
5315 for (tbytes
= 0, bytes
= 0;
5316 tbytes
< (int)length
;
5317 tbytes
+= bytes
, buffer
+= bytes
)
5319 DEBUG_printf(("9ipp_read_http: tbytes=%d, http->state=%d", tbytes
,
5322 if (http
->state
== HTTP_WAITING
)
5325 if (http
->used
== 0 && !http
->blocking
)
5328 * Wait up to 10 seconds for more data on non-blocking sockets...
5331 if (!httpWait(http
, 10000))
5342 if ((bytes
= httpRead2(http
, (char *)buffer
, length
- tbytes
)) < 0)
5347 if (errno
!= EAGAIN
&& errno
!= EINTR
)
5353 else if (bytes
== 0)
5358 * Return the number of bytes read...
5361 if (tbytes
== 0 && bytes
< 0)
5364 DEBUG_printf(("8ipp_read_http: Returning %d bytes", tbytes
));
5371 * 'ipp_read_file()' - Read IPP data from a file.
5374 static ssize_t
/* O - Number of bytes read */
5375 ipp_read_file(int *fd
, /* I - File descriptor */
5376 ipp_uchar_t
*buffer
, /* O - Read buffer */
5377 size_t length
) /* I - Number of bytes to read */
5380 return ((ssize_t
)read(*fd
, buffer
, (unsigned)length
));
5382 return (read(*fd
, buffer
, length
));
5388 * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
5392 static _ipp_value_t
* /* O - IPP value element or NULL on error */
5393 ipp_set_value(ipp_t
*ipp
, /* IO - IPP message */
5394 ipp_attribute_t
**attr
, /* IO - IPP attribute */
5395 int element
) /* I - Value number (0-based) */
5397 ipp_attribute_t
*temp
, /* New attribute pointer */
5398 *current
, /* Current attribute in list */
5399 *prev
; /* Previous attribute in list */
5400 int alloc_values
; /* Allocated values */
5404 * If we are setting an existing value element, return it...
5409 if (temp
->num_values
<= 1)
5412 alloc_values
= (temp
->num_values
+ IPP_MAX_VALUES
- 1) &
5413 ~(IPP_MAX_VALUES
- 1);
5415 if (element
< alloc_values
)
5417 if (element
>= temp
->num_values
)
5418 temp
->num_values
= element
+ 1;
5420 return (temp
->values
+ element
);
5424 * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
5425 * values when num_values > 1.
5428 if (alloc_values
< IPP_MAX_VALUES
)
5429 alloc_values
= IPP_MAX_VALUES
;
5431 alloc_values
+= IPP_MAX_VALUES
;
5433 DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
5437 * Reallocate memory...
5440 if ((temp
= realloc(temp
, sizeof(ipp_attribute_t
) +
5441 (alloc_values
- 1) * sizeof(_ipp_value_t
))) == NULL
)
5443 _cupsSetHTTPError(HTTP_ERROR
);
5444 DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
5449 * Zero the new memory...
5452 memset(temp
->values
+ temp
->num_values
, 0,
5453 (alloc_values
- temp
->num_values
) * sizeof(_ipp_value_t
));
5458 * Reset pointers in the list...
5461 if (ipp
->current
== *attr
&& ipp
->prev
)
5464 * Use current "previous" pointer...
5472 * Find this attribute in the linked list...
5475 for (prev
= NULL
, current
= ipp
->attrs
;
5476 current
&& current
!= *attr
;
5477 prev
= current
, current
= current
->next
);
5482 * This is a serious error!
5486 _cupsSetError(IPP_INTERNAL_ERROR
,
5487 _("IPP attribute is not a member of the message."), 1);
5488 DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
5498 ipp
->current
= temp
;
5501 if (ipp
->last
== *attr
)
5508 * Return the value element...
5511 if (element
>= temp
->num_values
)
5512 temp
->num_values
= element
+ 1;
5514 return (temp
->values
+ element
);
5519 * 'ipp_write_file()' - Write IPP data to a file.
5522 static ssize_t
/* O - Number of bytes written */
5523 ipp_write_file(int *fd
, /* I - File descriptor */
5524 ipp_uchar_t
*buffer
, /* I - Data to write */
5525 size_t length
) /* I - Number of bytes to write */
5528 return ((ssize_t
)write(*fd
, buffer
, (unsigned)length
));
5530 return (write(*fd
, buffer
, length
));
5536 * End of "$Id: ipp.c 10102 2011-11-02 23:52:39Z mike $".