2 * "$Id: ipp.c 10102 2011-11-02 23:52:39Z mike $"
4 * Internet Printing Protocol functions for CUPS.
6 * Copyright 2007-2011 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
, ipp_tag_t group_tag
,
124 ipp_tag_t value_tag
, int num_values
);
125 static void ipp_free_values(ipp_attribute_t
*attr
, int element
, int count
);
126 static char *ipp_get_code(const char *locale
, char *buffer
, size_t bufsize
);
127 static char *ipp_lang_code(const char *locale
, char *buffer
, size_t bufsize
);
128 static size_t ipp_length(ipp_t
*ipp
, int collection
);
129 static ssize_t
ipp_read_http(http_t
*http
, ipp_uchar_t
*buffer
,
131 static ssize_t
ipp_read_file(int *fd
, ipp_uchar_t
*buffer
,
133 static _ipp_value_t
*ipp_set_value(ipp_t
*ipp
, ipp_attribute_t
**attr
, int element
);
134 static ssize_t
ipp_write_file(int *fd
, ipp_uchar_t
*buffer
,
139 * '_cupsBufferGet()' - Get a read/write buffer.
142 char * /* O - Buffer */
143 _cupsBufferGet(size_t size
) /* I - Size required */
145 _cups_buffer_t
*buffer
; /* Current buffer */
146 _cups_globals_t
*cg
= _cupsGlobals();
150 for (buffer
= cg
->cups_buffers
; buffer
; buffer
= buffer
->next
)
151 if (!buffer
->used
&& buffer
->size
>= size
)
156 if ((buffer
= malloc(sizeof(_cups_buffer_t
) + size
- 1)) == NULL
)
159 buffer
->next
= cg
->cups_buffers
;
161 cg
->cups_buffers
= buffer
;
171 * '_cupsBufferRelease()' - Release a read/write buffer.
175 _cupsBufferRelease(char *b
) /* I - Buffer to release */
177 _cups_buffer_t
*buffer
; /* Buffer */
181 * Mark this buffer as unused...
184 buffer
= (_cups_buffer_t
*)(b
- offsetof(_cups_buffer_t
, d
));
190 * 'ippAddBoolean()' - Add a boolean attribute to an IPP message.
192 * The @code ipp@ parameter refers to an IPP message previously created using the
193 * @link ippNew@ or @link ippNewRequest@ functions.
195 * The @code group@ parameter specifies the IPP attribute group tag: none
196 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
197 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
198 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
199 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
202 ipp_attribute_t
* /* O - New attribute */
203 ippAddBoolean(ipp_t
*ipp
, /* I - IPP message */
204 ipp_tag_t group
, /* I - IPP group */
205 const char *name
, /* I - Name of attribute */
206 char value
) /* I - Value of attribute */
208 ipp_attribute_t
*attr
; /* New attribute */
211 DEBUG_printf(("ippAddBoolean(ipp=%p, group=%02x(%s), name=\"%s\", value=%d)",
212 ipp
, group
, ippTagString(group
), name
, value
));
215 * Range check input...
218 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
219 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
223 * Create the attribute...
226 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BOOLEAN
, 1)) == NULL
)
229 attr
->values
[0].boolean
= value
;
236 * 'ippAddBooleans()' - Add an array of boolean values.
238 * The @code ipp@ parameter refers to an IPP message previously created using the
239 * @link ippNew@ or @link ippNewRequest@ functions.
241 * The @code group@ parameter specifies the IPP attribute group tag: none
242 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
243 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
244 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
245 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
248 ipp_attribute_t
* /* O - New attribute */
249 ippAddBooleans(ipp_t
*ipp
, /* I - IPP message */
250 ipp_tag_t group
, /* I - IPP group */
251 const char *name
, /* I - Name of attribute */
252 int num_values
, /* I - Number of values */
253 const char *values
) /* I - Values */
255 int i
; /* Looping var */
256 ipp_attribute_t
*attr
; /* New attribute */
257 _ipp_value_t
*value
; /* Current value */
260 DEBUG_printf(("ippAddBooleans(ipp=%p, group=%02x(%s), name=\"%s\", "
261 "num_values=%d, values=%p)", ipp
, group
, ippTagString(group
),
262 name
, num_values
, values
));
265 * Range check input...
268 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
269 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
274 * Create the attribute...
277 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BOOLEAN
, num_values
)) == NULL
)
282 for (i
= num_values
, value
= attr
->values
;
285 value
->boolean
= *values
++;
293 * 'ippAddCollection()' - Add a collection value.
295 * The @code ipp@ parameter refers to an IPP message previously created using the
296 * @link ippNew@ or @link ippNewRequest@ functions.
298 * The @code group@ parameter specifies the IPP attribute group tag: none
299 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
300 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
301 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
302 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
304 * @since CUPS 1.1.19/Mac OS X 10.3@
307 ipp_attribute_t
* /* O - New attribute */
308 ippAddCollection(ipp_t
*ipp
, /* I - IPP message */
309 ipp_tag_t group
, /* I - IPP group */
310 const char *name
, /* I - Name of attribute */
311 ipp_t
*value
) /* I - Value */
313 ipp_attribute_t
*attr
; /* New attribute */
316 DEBUG_printf(("ippAddCollection(ipp=%p, group=%02x(%s), name=\"%s\", "
317 "value=%p)", ipp
, group
, ippTagString(group
), name
, value
));
320 * Range check input...
323 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
324 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
328 * Create the attribute...
331 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BEGIN_COLLECTION
, 1)) == NULL
)
334 attr
->values
[0].collection
= value
;
344 * 'ippAddCollections()' - Add an array of collection values.
346 * The @code ipp@ parameter refers to an IPP message previously created using the
347 * @link ippNew@ or @link ippNewRequest@ functions.
349 * The @code group@ parameter specifies the IPP attribute group tag: none
350 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
351 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
352 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
353 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
355 * @since CUPS 1.1.19/Mac OS X 10.3@
358 ipp_attribute_t
* /* O - New attribute */
360 ipp_t
*ipp
, /* I - IPP message */
361 ipp_tag_t group
, /* I - IPP group */
362 const char *name
, /* I - Name of attribute */
363 int num_values
, /* I - Number of values */
364 const ipp_t
**values
) /* I - Values */
366 int i
; /* Looping var */
367 ipp_attribute_t
*attr
; /* New attribute */
368 _ipp_value_t
*value
; /* Current value */
371 DEBUG_printf(("ippAddCollections(ipp=%p, group=%02x(%s), name=\"%s\", "
372 "num_values=%d, values=%p)", ipp
, group
, ippTagString(group
),
373 name
, num_values
, values
));
376 * Range check input...
379 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
380 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
385 * Create the attribute...
388 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BEGIN_COLLECTION
,
389 num_values
)) == NULL
)
394 for (i
= num_values
, value
= attr
->values
;
398 value
->collection
= (ipp_t
*)*values
++;
399 value
->collection
->use
++;
408 * 'ippAddDate()' - Add a date attribute to an IPP message.
410 * The @code ipp@ parameter refers to an IPP message previously created using the
411 * @link ippNew@ or @link ippNewRequest@ functions.
413 * The @code group@ parameter specifies the IPP attribute group tag: none
414 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
415 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
416 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
417 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
420 ipp_attribute_t
* /* O - New attribute */
421 ippAddDate(ipp_t
*ipp
, /* I - IPP message */
422 ipp_tag_t group
, /* I - IPP group */
423 const char *name
, /* I - Name of attribute */
424 const ipp_uchar_t
*value
) /* I - Value */
426 ipp_attribute_t
*attr
; /* New attribute */
429 DEBUG_printf(("ippAddDate(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)",
430 ipp
, group
, ippTagString(group
), name
, value
));
433 * Range check input...
436 if (!ipp
|| !name
|| !value
|| group
< IPP_TAG_ZERO
||
437 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
441 * Create the attribute...
444 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_DATE
, 1)) == NULL
)
447 memcpy(attr
->values
[0].date
, value
, 11);
454 * 'ippAddInteger()' - Add a integer attribute to an IPP message.
456 * The @code ipp@ parameter refers to an IPP message previously created using the
457 * @link ippNew@ or @link ippNewRequest@ functions.
459 * The @code group@ parameter specifies the IPP attribute group tag: none
460 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
461 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
462 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
463 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
465 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
466 * (@code IPP_TAG_INTEGER@).
469 ipp_attribute_t
* /* O - New attribute */
470 ippAddInteger(ipp_t
*ipp
, /* I - IPP message */
471 ipp_tag_t group
, /* I - IPP group */
472 ipp_tag_t value_tag
, /* I - Type of attribute */
473 const char *name
, /* I - Name of attribute */
474 int value
) /* I - Value of attribute */
476 ipp_attribute_t
*attr
; /* New attribute */
479 DEBUG_printf(("ippAddInteger(ipp=%p, group=%02x(%s), type=%02x(%s), "
480 "name=\"%s\", value=%d)", ipp
, group
, ippTagString(group
),
481 value_tag
, ippTagString(value_tag
), name
, value
));
483 value_tag
&= IPP_TAG_MASK
;
486 * Special-case for legacy usage: map out-of-band attributes to new ippAddOutOfBand
490 if (value_tag
>= IPP_TAG_UNSUPPORTED_VALUE
&& value_tag
<= IPP_TAG_ADMINDEFINE
)
491 return (ippAddOutOfBand(ipp
, group
, value_tag
, name
));
494 * Range check input...
498 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
499 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
500 (value_tag
!= IPP_TAG_INTEGER
&& value_tag
!= IPP_TAG_ENUM
))
503 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
504 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
509 * Create the attribute...
512 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, 1)) == NULL
)
515 attr
->values
[0].integer
= value
;
522 * 'ippAddIntegers()' - Add an array of integer values.
524 * The @code ipp@ parameter refers to an IPP message previously created using the
525 * @link ippNew@ or @link ippNewRequest@ functions.
527 * The @code group@ parameter specifies the IPP attribute group tag: none
528 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
529 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
530 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
531 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
533 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
534 * (@code IPP_TAG_INTEGER@).
537 ipp_attribute_t
* /* O - New attribute */
538 ippAddIntegers(ipp_t
*ipp
, /* I - IPP message */
539 ipp_tag_t group
, /* I - IPP group */
540 ipp_tag_t value_tag
, /* I - Type of attribute */
541 const char *name
, /* I - Name of attribute */
542 int num_values
, /* I - Number of values */
543 const int *values
) /* I - Values */
545 int i
; /* Looping var */
546 ipp_attribute_t
*attr
; /* New attribute */
547 _ipp_value_t
*value
; /* Current value */
550 DEBUG_printf(("ippAddIntegers(ipp=%p, group=%02x(%s), type=%02x(%s), "
551 "name=\"%s\", num_values=%d, values=%p)", ipp
,
552 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
553 num_values
, values
));
555 value_tag
&= IPP_TAG_MASK
;
558 * Range check input...
562 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
563 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
564 (value_tag
!= IPP_TAG_INTEGER
&& value_tag
!= IPP_TAG_ENUM
) ||
568 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
569 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
575 * Create the attribute...
578 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, num_values
)) == NULL
)
583 for (i
= num_values
, value
= attr
->values
;
586 value
->integer
= *values
++;
594 * 'ippAddOctetString()' - Add an octetString value to an IPP message.
596 * The @code ipp@ parameter refers to an IPP message previously created using the
597 * @link ippNew@ or @link ippNewRequest@ functions.
599 * The @code group@ parameter specifies the IPP attribute group tag: none
600 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
601 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
602 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
603 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
605 * @since CUPS 1.2/Mac OS X 10.5@
608 ipp_attribute_t
* /* O - New attribute */
609 ippAddOctetString(ipp_t
*ipp
, /* I - IPP message */
610 ipp_tag_t group
, /* I - IPP group */
611 const char *name
, /* I - Name of attribute */
612 const void *data
, /* I - octetString data */
613 int datalen
) /* I - Length of data in bytes */
615 ipp_attribute_t
*attr
; /* New attribute */
618 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
619 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
622 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_STRING
, 1)) == NULL
)
626 * Initialize the attribute data...
629 attr
->values
[0].unknown
.length
= datalen
;
633 if ((attr
->values
[0].unknown
.data
= malloc(datalen
)) == NULL
)
635 ippDeleteAttribute(ipp
, attr
);
639 memcpy(attr
->values
[0].unknown
.data
, data
, datalen
);
643 * Return the new attribute...
651 * 'ippAddOutOfBand()' - Add an out-of-band value to an IPP message.
653 * The @code ipp@ parameter refers to an IPP message previously created using the
654 * @link ippNew@ or @link ippNewRequest@ functions.
656 * The @code group@ parameter specifies the IPP attribute group tag: none
657 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
658 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
659 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
660 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
662 * Supported out-of-band values include unsupported-value
663 * (@code IPP_TAG_UNSUPPORTED_VALUE@), default (@code IPP_TAG_DEFAULT@), unknown
664 * (@code IPP_TAG_UNKNOWN@), no-value (@code IPP_TAG_NOVALUE@), not-settable
665 * (@code IPP_TAG_NOTSETTABLE@), delete-attribute (@code IPP_TAG_DELETEATTR@), and
666 * admin-define (@code IPP_TAG_ADMINDEFINE@).
671 ipp_attribute_t
* /* O - New attribute */
672 ippAddOutOfBand(ipp_t
*ipp
, /* I - IPP message */
673 ipp_tag_t group
, /* I - IPP group */
674 ipp_tag_t value_tag
, /* I - Type of attribute */
675 const char *name
) /* I - Name of attribute */
677 DEBUG_printf(("ippAddOutOfBand(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
678 "name=\"%s\")", ipp
, group
, ippTagString(group
), value_tag
,
679 ippTagString(value_tag
), name
));
681 value_tag
&= IPP_TAG_MASK
;
684 * Range check input...
687 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
688 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
689 (value_tag
!= IPP_TAG_UNSUPPORTED_VALUE
&&
690 value_tag
!= IPP_TAG_DEFAULT
&&
691 value_tag
!= IPP_TAG_UNKNOWN
&&
692 value_tag
!= IPP_TAG_NOVALUE
&&
693 value_tag
!= IPP_TAG_NOTSETTABLE
&&
694 value_tag
!= IPP_TAG_DELETEATTR
&&
695 value_tag
!= IPP_TAG_ADMINDEFINE
))
699 * Create the attribute...
702 return (ipp_add_attr(ipp
, name
, group
, value_tag
, 1));
707 * 'ippAddRange()' - Add a range of values to an IPP message.
709 * The @code ipp@ parameter refers to an IPP message previously created using the
710 * @link ippNew@ or @link ippNewRequest@ functions.
712 * The @code group@ parameter specifies the IPP attribute group tag: none
713 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
714 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
715 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
716 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
718 * The @code lower@ parameter must be less than or equal to the @code upper@ parameter.
721 ipp_attribute_t
* /* O - New attribute */
722 ippAddRange(ipp_t
*ipp
, /* I - IPP message */
723 ipp_tag_t group
, /* I - IPP group */
724 const char *name
, /* I - Name of attribute */
725 int lower
, /* I - Lower value */
726 int upper
) /* I - Upper value */
728 ipp_attribute_t
*attr
; /* New attribute */
731 DEBUG_printf(("ippAddRange(ipp=%p, group=%02x(%s), name=\"%s\", lower=%d, "
732 "upper=%d)", ipp
, group
, ippTagString(group
), name
, lower
,
736 * Range check input...
739 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
740 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
744 * Create the attribute...
747 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RANGE
, 1)) == NULL
)
750 attr
->values
[0].range
.lower
= lower
;
751 attr
->values
[0].range
.upper
= upper
;
758 * 'ippAddRanges()' - Add ranges of values to an IPP message.
760 * The @code ipp@ parameter refers to an IPP message previously created using the
761 * @link ippNew@ or @link ippNewRequest@ functions.
763 * The @code group@ parameter specifies the IPP attribute group tag: none
764 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
765 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
766 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
767 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
770 ipp_attribute_t
* /* O - New attribute */
771 ippAddRanges(ipp_t
*ipp
, /* I - IPP message */
772 ipp_tag_t group
, /* I - IPP group */
773 const char *name
, /* I - Name of attribute */
774 int num_values
, /* I - Number of values */
775 const int *lower
, /* I - Lower values */
776 const int *upper
) /* I - Upper values */
778 int i
; /* Looping var */
779 ipp_attribute_t
*attr
; /* New attribute */
780 _ipp_value_t
*value
; /* Current value */
783 DEBUG_printf(("ippAddRanges(ipp=%p, group=%02x(%s), name=\"%s\", "
784 "num_values=%d, lower=%p, upper=%p)", ipp
, group
,
785 ippTagString(group
), name
, num_values
, lower
, upper
));
788 * Range check input...
791 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
792 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
797 * Create the attribute...
800 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RANGE
, num_values
)) == NULL
)
805 for (i
= num_values
, value
= attr
->values
;
809 value
->range
.lower
= *lower
++;
810 value
->range
.upper
= *upper
++;
819 * 'ippAddResolution()' - Add a resolution value to an IPP message.
821 * The @code ipp@ parameter refers to an IPP message previously created using the
822 * @link ippNew@ or @link ippNewRequest@ functions.
824 * The @code group@ parameter specifies the IPP attribute group tag: none
825 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
826 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
827 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
828 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
831 ipp_attribute_t
* /* O - New attribute */
832 ippAddResolution(ipp_t
*ipp
, /* I - IPP message */
833 ipp_tag_t group
, /* I - IPP group */
834 const char *name
, /* I - Name of attribute */
835 ipp_res_t units
, /* I - Units for resolution */
836 int xres
, /* I - X resolution */
837 int yres
) /* I - Y resolution */
839 ipp_attribute_t
*attr
; /* New attribute */
842 DEBUG_printf(("ippAddResolution(ipp=%p, group=%02x(%s), name=\"%s\", "
843 "units=%d, xres=%d, yres=%d)", ipp
, group
,
844 ippTagString(group
), name
, units
, xres
, yres
));
847 * Range check input...
850 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
851 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
852 units
< IPP_RES_PER_INCH
|| units
> IPP_RES_PER_CM
||
853 xres
< 0 || yres
< 0)
857 * Create the attribute...
860 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RESOLUTION
, 1)) == NULL
)
863 attr
->values
[0].resolution
.xres
= xres
;
864 attr
->values
[0].resolution
.yres
= yres
;
865 attr
->values
[0].resolution
.units
= units
;
872 * 'ippAddResolutions()' - Add resolution values to an IPP message.
874 * The @code ipp@ parameter refers to an IPP message previously created using the
875 * @link ippNew@ or @link ippNewRequest@ functions.
877 * The @code group@ parameter specifies the IPP attribute group tag: none
878 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
879 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
880 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
881 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
884 ipp_attribute_t
* /* O - New attribute */
885 ippAddResolutions(ipp_t
*ipp
, /* I - IPP message */
886 ipp_tag_t group
, /* I - IPP group */
887 const char *name
, /* I - Name of attribute */
888 int num_values
,/* I - Number of values */
889 ipp_res_t units
, /* I - Units for resolution */
890 const int *xres
, /* I - X resolutions */
891 const int *yres
) /* I - Y resolutions */
893 int i
; /* Looping var */
894 ipp_attribute_t
*attr
; /* New attribute */
895 _ipp_value_t
*value
; /* Current value */
898 DEBUG_printf(("ippAddResolutions(ipp=%p, group=%02x(%s), name=\"%s\", "
899 "num_value=%d, units=%d, xres=%p, yres=%p)", ipp
, group
,
900 ippTagString(group
), name
, num_values
, units
, xres
, yres
));
903 * Range check input...
906 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
907 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
909 units
< IPP_RES_PER_INCH
|| units
> IPP_RES_PER_CM
)
913 * Create the attribute...
916 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RESOLUTION
, num_values
)) == NULL
)
921 for (i
= num_values
, value
= attr
->values
;
925 value
->resolution
.xres
= *xres
++;
926 value
->resolution
.yres
= *yres
++;
927 value
->resolution
.units
= units
;
936 * 'ippAddSeparator()' - Add a group separator to an IPP message.
938 * The @code ipp@ parameter refers to an IPP message previously created using the
939 * @link ippNew@ or @link ippNewRequest@ functions.
942 ipp_attribute_t
* /* O - New attribute */
943 ippAddSeparator(ipp_t
*ipp
) /* I - IPP message */
945 DEBUG_printf(("ippAddSeparator(ipp=%p)", ipp
));
948 * Range check input...
955 * Create the attribute...
958 return (ipp_add_attr(ipp
, NULL
, IPP_TAG_ZERO
, IPP_TAG_ZERO
, 0));
963 * 'ippAddString()' - Add a language-encoded string to an IPP message.
965 * The @code ipp@ parameter refers to an IPP message previously created using the
966 * @link ippNew@ or @link ippNewRequest@ functions.
968 * The @code group@ parameter specifies the IPP attribute group tag: none
969 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
970 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
971 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
972 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
974 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
975 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
976 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
977 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
978 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
979 * (@code IPP_TAG_URISCHEME@).
981 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
982 * textWithLanguage string values and must be @code NULL@ for all other string values.
985 ipp_attribute_t
* /* O - New attribute */
986 ippAddString(ipp_t
*ipp
, /* I - IPP message */
987 ipp_tag_t group
, /* I - IPP group */
988 ipp_tag_t value_tag
, /* I - Type of attribute */
989 const char *name
, /* I - Name of attribute */
990 const char *language
, /* I - Language code */
991 const char *value
) /* I - Value */
993 ipp_tag_t temp_tag
; /* Temporary value tag (masked) */
994 ipp_attribute_t
*attr
; /* New attribute */
995 char code
[32]; /* Charset/language code buffer */
998 DEBUG_printf(("ippAddString(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
999 "name=\"%s\", language=\"%s\", value=\"%s\")", ipp
,
1000 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
1004 * Range check input...
1007 temp_tag
= (ipp_tag_t
)((int)value_tag
& IPP_TAG_MASK
);
1010 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1011 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1012 (temp_tag
< IPP_TAG_TEXT
&& temp_tag
!= IPP_TAG_TEXTLANG
&&
1013 temp_tag
!= IPP_TAG_NAMELANG
) || temp_tag
> IPP_TAG_MIMETYPE
)
1016 if ((temp_tag
== IPP_TAG_TEXTLANG
|| temp_tag
== IPP_TAG_NAMELANG
)
1017 != (language
!= NULL
))
1020 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1021 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
1026 * See if we need to map charset, language, or locale values...
1029 if (language
&& ((int)value_tag
& IPP_TAG_COPY
) &&
1030 strcmp(language
, ipp_lang_code(language
, code
, sizeof(code
))))
1031 value_tag
= temp_tag
; /* Don't do a fast copy */
1032 else if (value
&& value_tag
== (ipp_tag_t
)(IPP_TAG_CHARSET
| IPP_TAG_COPY
) &&
1033 strcmp(value
, ipp_get_code(value
, code
, sizeof(code
))))
1034 value_tag
= temp_tag
; /* Don't do a fast copy */
1035 else if (value
&& value_tag
== (ipp_tag_t
)(IPP_TAG_LANGUAGE
| IPP_TAG_COPY
) &&
1036 strcmp(value
, ipp_lang_code(value
, code
, sizeof(code
))))
1037 value_tag
= temp_tag
; /* Don't do a fast copy */
1040 * Create the attribute...
1043 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, 1)) == NULL
)
1047 * Initialize the attribute data...
1050 if ((int)value_tag
& IPP_TAG_COPY
)
1052 attr
->values
[0].string
.language
= (char *)language
;
1053 attr
->values
[0].string
.text
= (char *)value
;
1058 attr
->values
[0].string
.language
= _cupsStrAlloc(ipp_lang_code(language
, code
,
1061 if (value_tag
== IPP_TAG_CHARSET
)
1062 attr
->values
[0].string
.text
= _cupsStrAlloc(ipp_get_code(value
, code
,
1064 else if (value_tag
== IPP_TAG_LANGUAGE
)
1065 attr
->values
[0].string
.text
= _cupsStrAlloc(ipp_lang_code(value
, code
,
1068 attr
->values
[0].string
.text
= _cupsStrAlloc(value
);
1076 * 'ippAddStrings()' - Add language-encoded strings to an IPP message.
1078 * The @code ipp@ parameter refers to an IPP message previously created using the
1079 * @link ippNew@ or @link ippNewRequest@ functions.
1081 * The @code group@ parameter specifies the IPP attribute group tag: none
1082 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
1083 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
1084 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
1085 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1087 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1088 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1089 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1090 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1091 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1092 * (@code IPP_TAG_URISCHEME@).
1094 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
1095 * textWithLanguage string values and must be @code NULL@ for all other string values.
1098 ipp_attribute_t
* /* O - New attribute */
1100 ipp_t
*ipp
, /* I - IPP message */
1101 ipp_tag_t group
, /* I - IPP group */
1102 ipp_tag_t value_tag
, /* I - Type of attribute */
1103 const char *name
, /* I - Name of attribute */
1104 int num_values
, /* I - Number of values */
1105 const char *language
, /* I - Language code (@code NULL@ for default) */
1106 const char * const *values
) /* I - Values */
1108 int i
; /* Looping var */
1109 ipp_tag_t temp_tag
; /* Temporary value tag (masked) */
1110 ipp_attribute_t
*attr
; /* New attribute */
1111 _ipp_value_t
*value
; /* Current value */
1112 char code
[32]; /* Language/charset value buffer */
1115 DEBUG_printf(("ippAddStrings(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
1116 "name=\"%s\", num_values=%d, language=\"%s\", values=%p)", ipp
,
1117 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
1118 num_values
, language
, values
));
1121 * Range check input...
1124 temp_tag
= (ipp_tag_t
)((int)value_tag
& IPP_TAG_MASK
);
1127 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1128 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1129 (temp_tag
< IPP_TAG_TEXT
&& temp_tag
!= IPP_TAG_TEXTLANG
&&
1130 temp_tag
!= IPP_TAG_NAMELANG
) || temp_tag
> IPP_TAG_MIMETYPE
||
1134 if ((temp_tag
== IPP_TAG_TEXTLANG
|| temp_tag
== IPP_TAG_NAMELANG
)
1135 != (language
!= NULL
))
1138 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1139 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1145 * See if we need to map charset, language, or locale values...
1148 if (language
&& ((int)value_tag
& IPP_TAG_COPY
) &&
1149 strcmp(language
, ipp_lang_code(language
, code
, sizeof(code
))))
1150 value_tag
= temp_tag
; /* Don't do a fast copy */
1151 else if (values
&& value_tag
== (ipp_tag_t
)(IPP_TAG_CHARSET
| IPP_TAG_COPY
))
1153 for (i
= 0; i
< num_values
; i
++)
1154 if (strcmp(values
[i
], ipp_get_code(values
[i
], code
, sizeof(code
))))
1156 value_tag
= temp_tag
; /* Don't do a fast copy */
1160 else if (values
&& value_tag
== (ipp_tag_t
)(IPP_TAG_LANGUAGE
| IPP_TAG_COPY
))
1162 for (i
= 0; i
< num_values
; i
++)
1163 if (strcmp(values
[i
], ipp_lang_code(values
[i
], code
, sizeof(code
))))
1165 value_tag
= temp_tag
; /* Don't do a fast copy */
1171 * Create the attribute...
1174 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, num_values
)) == NULL
)
1178 * Initialize the attribute data...
1181 for (i
= num_values
, value
= attr
->values
;
1187 if (value
== attr
->values
)
1189 if ((int)value_tag
& IPP_TAG_COPY
)
1190 value
->string
.language
= (char *)language
;
1192 value
->string
.language
= _cupsStrAlloc(ipp_lang_code(language
, code
,
1196 value
->string
.language
= attr
->values
[0].string
.language
;
1201 if ((int)value_tag
& IPP_TAG_COPY
)
1202 value
->string
.text
= (char *)*values
++;
1203 else if (value_tag
== IPP_TAG_CHARSET
)
1204 value
->string
.text
= _cupsStrAlloc(ipp_get_code(*values
++, code
, sizeof(code
)));
1205 else if (value_tag
== IPP_TAG_LANGUAGE
)
1206 value
->string
.text
= _cupsStrAlloc(ipp_lang_code(*values
++, code
, sizeof(code
)));
1208 value
->string
.text
= _cupsStrAlloc(*values
++);
1217 * 'ippCopyAttribute()' - Copy an attribute.
1219 * The specified attribute, @code attr@, is copied to the destination IPP message.
1220 * When @code quickcopy@ is non-zero, a "shallow" reference copy of the attribute is
1221 * created - this should only be done as long as the original source IPP message will
1222 * not be freed for the life of the destination.
1228 ipp_attribute_t
* /* O - New attribute */
1230 ipp_t
*dst
, /* I - Destination IPP message */
1231 ipp_attribute_t
*srcattr
, /* I - Attribute to copy */
1232 int quickcopy
) /* I - 1 for a referenced copy, 0 for normal */
1234 int i
; /* Looping var */
1235 ipp_attribute_t
*dstattr
; /* Destination attribute */
1236 _ipp_value_t
*srcval
, /* Source value */
1237 *dstval
; /* Destination value */
1240 DEBUG_printf(("ippCopyAttribute(dst=%p, srcattr=%p, quickcopy=%d)", dst
, srcattr
,
1244 * Range check input...
1247 if (!dst
|| !srcattr
)
1254 quickcopy
= quickcopy
? IPP_TAG_COPY
: 0;
1256 switch (srcattr
->value_tag
& ~IPP_TAG_COPY
)
1259 dstattr
= ippAddSeparator(dst
);
1262 case IPP_TAG_INTEGER
:
1264 dstattr
= ippAddIntegers(dst
, srcattr
->group_tag
, srcattr
->value_tag
,
1265 srcattr
->name
, srcattr
->num_values
, NULL
);
1269 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1271 i
--, srcval
++, dstval
++)
1272 dstval
->integer
= srcval
->integer
;
1275 case IPP_TAG_BOOLEAN
:
1276 dstattr
= ippAddBooleans(dst
, srcattr
->group_tag
, srcattr
->name
,
1277 srcattr
->num_values
, NULL
);
1281 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1283 i
--, srcval
++, dstval
++)
1284 dstval
->boolean
= srcval
->boolean
;
1289 case IPP_TAG_KEYWORD
:
1291 case IPP_TAG_URISCHEME
:
1292 case IPP_TAG_CHARSET
:
1293 case IPP_TAG_LANGUAGE
:
1294 case IPP_TAG_MIMETYPE
:
1295 dstattr
= ippAddStrings(dst
, srcattr
->group_tag
,
1296 (ipp_tag_t
)(srcattr
->value_tag
| quickcopy
),
1297 srcattr
->name
, srcattr
->num_values
, NULL
, NULL
);
1303 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1304 dstval
= dstattr
->values
;
1306 i
--, srcval
++, dstval
++)
1307 dstval
->string
.text
= srcval
->string
.text
;
1309 else if (srcattr
->value_tag
& IPP_TAG_COPY
)
1311 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1312 dstval
= dstattr
->values
;
1314 i
--, srcval
++, dstval
++)
1315 dstval
->string
.text
= _cupsStrAlloc(srcval
->string
.text
);
1319 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1320 dstval
= dstattr
->values
;
1322 i
--, srcval
++, dstval
++)
1323 dstval
->string
.text
= _cupsStrRetain(srcval
->string
.text
);
1328 if (srcattr
->num_values
!= 1)
1331 dstattr
= ippAddDate(dst
, srcattr
->group_tag
, srcattr
->name
,
1332 srcattr
->values
[0].date
);
1335 case IPP_TAG_RESOLUTION
:
1336 dstattr
= ippAddResolutions(dst
, srcattr
->group_tag
, srcattr
->name
,
1337 srcattr
->num_values
, IPP_RES_PER_INCH
,
1342 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1344 i
--, srcval
++, dstval
++)
1346 dstval
->resolution
.xres
= srcval
->resolution
.xres
;
1347 dstval
->resolution
.yres
= srcval
->resolution
.yres
;
1348 dstval
->resolution
.units
= srcval
->resolution
.units
;
1352 case IPP_TAG_RANGE
:
1353 dstattr
= ippAddRanges(dst
, srcattr
->group_tag
, srcattr
->name
,
1354 srcattr
->num_values
, NULL
, NULL
);
1358 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1360 i
--, srcval
++, dstval
++)
1362 dstval
->range
.lower
= srcval
->range
.lower
;
1363 dstval
->range
.upper
= srcval
->range
.upper
;
1367 case IPP_TAG_TEXTLANG
:
1368 case IPP_TAG_NAMELANG
:
1369 dstattr
= ippAddStrings(dst
, srcattr
->group_tag
,
1370 (ipp_tag_t
)(srcattr
->value_tag
| quickcopy
),
1371 srcattr
->name
, srcattr
->num_values
, NULL
, NULL
);
1377 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1378 dstval
= dstattr
->values
;
1380 i
--, srcval
++, dstval
++)
1382 dstval
->string
.language
= srcval
->string
.language
;
1383 dstval
->string
.text
= srcval
->string
.text
;
1386 else if (srcattr
->value_tag
& IPP_TAG_COPY
)
1388 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1389 dstval
= dstattr
->values
;
1391 i
--, srcval
++, dstval
++)
1393 if (srcval
== srcattr
->values
)
1394 dstval
->string
.language
= _cupsStrAlloc(srcval
->string
.language
);
1396 dstval
->string
.language
= dstattr
->values
[0].string
.language
;
1398 dstval
->string
.text
= _cupsStrAlloc(srcval
->string
.text
);
1403 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1404 dstval
= dstattr
->values
;
1406 i
--, srcval
++, dstval
++)
1408 if (srcval
== srcattr
->values
)
1409 dstval
->string
.language
= _cupsStrRetain(srcval
->string
.language
);
1411 dstval
->string
.language
= dstattr
->values
[0].string
.language
;
1413 dstval
->string
.text
= _cupsStrRetain(srcval
->string
.text
);
1418 case IPP_TAG_BEGIN_COLLECTION
:
1419 dstattr
= ippAddCollections(dst
, srcattr
->group_tag
, srcattr
->name
,
1420 srcattr
->num_values
, NULL
);
1424 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1426 i
--, srcval
++, dstval
++)
1428 dstval
->collection
= srcval
->collection
;
1429 srcval
->collection
->use
++;
1433 case IPP_TAG_STRING
:
1435 /* TODO: Implement quick copy for unknown/octetString values */
1436 dstattr
= ippAddIntegers(dst
, srcattr
->group_tag
, srcattr
->value_tag
,
1437 srcattr
->name
, srcattr
->num_values
, NULL
);
1441 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1443 i
--, srcval
++, dstval
++)
1445 dstval
->unknown
.length
= srcval
->unknown
.length
;
1447 if (dstval
->unknown
.length
> 0)
1449 if ((dstval
->unknown
.data
= malloc(dstval
->unknown
.length
)) == NULL
)
1450 dstval
->unknown
.length
= 0;
1452 memcpy(dstval
->unknown
.data
, srcval
->unknown
.data
, dstval
->unknown
.length
);
1455 break; /* anti-compiler-warning-code */
1463 * 'ippCopyAttributes()' - Copy attributes from one IPP message to another.
1465 * Zero or more attributes are copied from the source IPP message, @code@ src, to the
1466 * destination IPP message, @code dst@. When @code quickcopy@ is non-zero, a "shallow"
1467 * reference copy of the attribute is created - this should only be done as long as the
1468 * original source IPP message will not be freed for the life of the destination.
1470 * The @code cb@ and @code context@ parameters provide a generic way to "filter" the
1471 * attributes that are copied - the function must return 1 to copy the attribute or
1472 * 0 to skip it. The function may also choose to do a partial copy of the source attribute
1478 int /* O - 1 on success, 0 on error */
1480 ipp_t
*dst
, /* I - Destination IPP message */
1481 ipp_t
*src
, /* I - Source IPP message */
1482 int quickcopy
, /* I - 1 for a referenced copy, 0 for normal */
1483 ipp_copycb_t cb
, /* I - Copy callback or @code NULL@ for none */
1484 void *context
) /* I - Context pointer */
1486 ipp_attribute_t
*srcattr
; /* Source attribute */
1489 DEBUG_printf(("ippCopyAttributes(dst=%p, src=%p, quickcopy=%d, cb=%p, context=%p)",
1490 dst
, src
, quickcopy
, cb
, context
));
1493 * Range check input...
1500 * Loop through source attributes and copy as needed...
1503 for (srcattr
= src
->attrs
; srcattr
; srcattr
= srcattr
->next
)
1504 if (!cb
|| (*cb
)(context
, dst
, srcattr
))
1505 if (!ippCopyAttribute(dst
, srcattr
, quickcopy
))
1513 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
1517 time_t /* O - UNIX time value */
1518 ippDateToTime(const ipp_uchar_t
*date
) /* I - RFC 1903 date info */
1520 struct tm unixdate
; /* UNIX date/time info */
1521 time_t t
; /* Computed time */
1527 memset(&unixdate
, 0, sizeof(unixdate
));
1530 * RFC-1903 date/time format is:
1532 * Byte(s) Description
1533 * ------- -----------
1534 * 0-1 Year (0 to 65535)
1538 * 5 Minutes (0 to 59)
1539 * 6 Seconds (0 to 60, 60 = "leap second")
1540 * 7 Deciseconds (0 to 9)
1542 * 9 UTC hours (0 to 11)
1543 * 10 UTC minutes (0 to 59)
1546 unixdate
.tm_year
= ((date
[0] << 8) | date
[1]) - 1900;
1547 unixdate
.tm_mon
= date
[2] - 1;
1548 unixdate
.tm_mday
= date
[3];
1549 unixdate
.tm_hour
= date
[4];
1550 unixdate
.tm_min
= date
[5];
1551 unixdate
.tm_sec
= date
[6];
1553 t
= mktime(&unixdate
);
1556 t
+= date
[9] * 3600 + date
[10] * 60;
1558 t
-= date
[9] * 3600 + date
[10] * 60;
1565 * 'ippDelete()' - Delete an IPP message.
1569 ippDelete(ipp_t
*ipp
) /* I - IPP message */
1571 ipp_attribute_t
*attr
, /* Current attribute */
1572 *next
; /* Next attribute */
1575 DEBUG_printf(("ippDelete(ipp=%p)", ipp
));
1584 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= next
)
1588 ipp_free_values(attr
, 0, attr
->num_values
);
1591 _cupsStrFree(attr
->name
);
1601 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
1603 * @since CUPS 1.1.19/Mac OS X 10.3@
1608 ipp_t
*ipp
, /* I - IPP message */
1609 ipp_attribute_t
*attr
) /* I - Attribute to delete */
1611 ipp_attribute_t
*current
, /* Current attribute */
1612 *prev
; /* Previous attribute */
1615 DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p(%s))", ipp
, attr
,
1616 attr
? attr
->name
: "(null)"));
1619 * Range check input...
1626 * Find the attribute in the list...
1631 for (current
= ipp
->attrs
, prev
= NULL
;
1633 prev
= current
, current
= current
->next
)
1634 if (current
== attr
)
1637 * Found it, remove the attribute from the list...
1641 prev
->next
= current
->next
;
1643 ipp
->attrs
= current
->next
;
1645 if (current
== ipp
->last
)
1656 * Free memory used by the attribute...
1659 ipp_free_values(attr
, 0, attr
->num_values
);
1662 _cupsStrFree(attr
->name
);
1669 * 'ippDeleteValues()' - Delete values in an attribute.
1671 * The @code element@ parameter specifies the first value to delete, starting at
1672 * 0. It must be less than the number of values returned by @link ippGetCount@.
1674 * The @code attr@ parameter may be modified as a result of setting the value.
1676 * Deleting all values in an attribute deletes the attribute.
1681 int /* O - 1 on success, 0 on failure */
1683 ipp_t
*ipp
, /* I - IPP message */
1684 ipp_attribute_t
**attr
, /* IO - Attribute */
1685 int element
, /* I - Index of first value to delete (0-based) */
1686 int count
) /* I - Number of values to delete */
1689 * Range check input...
1692 if (!ipp
|| !attr
|| !*attr
||
1693 element
< 0 || element
>= (*attr
)->num_values
|| count
<= 0 ||
1694 (element
+ count
) >= (*attr
)->num_values
)
1698 * If we are deleting all values, just delete the attribute entirely.
1701 if (count
== (*attr
)->num_values
)
1703 ippDeleteAttribute(ipp
, *attr
);
1709 * Otherwise free the values in question and return.
1712 ipp_free_values(*attr
, element
, count
);
1719 * 'ippFindAttribute()' - Find a named attribute in a request.
1722 ipp_attribute_t
* /* O - Matching attribute */
1723 ippFindAttribute(ipp_t
*ipp
, /* I - IPP message */
1724 const char *name
, /* I - Name of attribute */
1725 ipp_tag_t type
) /* I - Type of attribute */
1727 DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", ipp
,
1728 name
, type
, ippTagString(type
)));
1734 * Reset the current pointer...
1737 ipp
->current
= NULL
;
1740 * Search for the attribute...
1743 return (ippFindNextAttribute(ipp
, name
, type
));
1748 * 'ippFindNextAttribute()' - Find the next named attribute in a request.
1751 ipp_attribute_t
* /* O - Matching attribute */
1752 ippFindNextAttribute(ipp_t
*ipp
, /* I - IPP message */
1753 const char *name
, /* I - Name of attribute */
1754 ipp_tag_t type
) /* I - Type of attribute */
1756 ipp_attribute_t
*attr
; /* Current atttribute */
1757 ipp_tag_t value_tag
; /* Value tag */
1760 DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))",
1761 ipp
, name
, type
, ippTagString(type
)));
1768 ipp
->prev
= ipp
->current
;
1769 attr
= ipp
->current
->next
;
1777 for (; attr
!= NULL
; ipp
->prev
= attr
, attr
= attr
->next
)
1779 DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", attr
,
1782 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_MASK
);
1784 if (attr
->name
!= NULL
&& _cups_strcasecmp(attr
->name
, name
) == 0 &&
1785 (value_tag
== type
|| type
== IPP_TAG_ZERO
||
1786 (value_tag
== IPP_TAG_TEXTLANG
&& type
== IPP_TAG_TEXT
) ||
1787 (value_tag
== IPP_TAG_NAMELANG
&& type
== IPP_TAG_NAME
)))
1789 ipp
->current
= attr
;
1795 ipp
->current
= NULL
;
1803 * 'ippFirstAttribute()' - Return the first attribute in the message.
1808 ipp_attribute_t
* /* O - First attribute or @code NULL@ if none */
1809 ippFirstAttribute(ipp_t
*ipp
) /* I - IPP message */
1812 * Range check input...
1819 * Return the first attribute...
1822 return (ipp
->current
= ipp
->attrs
);
1827 * 'ippGetBoolean()' - Get a boolean value for an attribute.
1829 * The @code element@ parameter specifies which value to get from 0 to
1830 * @link ippGetCount(attr)@ - 1.
1835 int /* O - Boolean value or -1 on error */
1836 ippGetBoolean(ipp_attribute_t
*attr
, /* I - IPP attribute */
1837 int element
) /* I - Value number (0-based) */
1840 * Range check input...
1843 if (!attr
|| attr
->value_tag
!= IPP_TAG_BOOLEAN
||
1844 element
< 0 || element
>= attr
->num_values
)
1848 * Return the value...
1851 return (attr
->values
[element
].boolean
);
1856 * 'ippGetCollection()' - Get a collection value for an attribute.
1858 * The @code element@ parameter specifies which value to get from 0 to
1859 * @link ippGetCount(attr)@ - 1.
1864 ipp_t
* /* O - Collection value or @code NULL@ on error */
1866 ipp_attribute_t
*attr
, /* I - IPP attribute */
1867 int element
) /* I - Value number (0-based) */
1870 * Range check input...
1873 if (!attr
|| attr
->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
1874 element
< 0 || element
>= attr
->num_values
)
1878 * Return the value...
1881 return (attr
->values
[element
].collection
);
1886 * 'ippGetCount()' - Get the number of values in an attribute.
1891 int /* O - Number of values or -1 on error */
1892 ippGetCount(ipp_attribute_t
*attr
) /* I - IPP attribute */
1895 * Range check input...
1902 * Return the number of values...
1905 return (attr
->num_values
);
1910 * 'ippGetDate()' - Get a date value for an attribute.
1912 * The @code element@ parameter specifies which value to get from 0 to
1913 * @link ippGetCount(attr)@ - 1.
1918 const ipp_uchar_t
* /* O - Date value or @code NULL@ */
1919 ippGetDate(ipp_attribute_t
*attr
, /* I - IPP attribute */
1920 int element
) /* I - Value number (0-based) */
1923 * Range check input...
1926 if (!attr
|| attr
->value_tag
!= IPP_TAG_DATE
||
1927 element
< 0 || element
>= attr
->num_values
)
1931 * Return the value...
1934 return (attr
->values
[element
].date
);
1939 * 'ippGetGroupTag()' - Get the group associated with an attribute.
1944 ipp_tag_t
/* O - Group tag or @code IPP_TAG_ZERO@ on error */
1945 ippGetGroupTag(ipp_attribute_t
*attr
) /* I - IPP attribute */
1948 * Range check input...
1952 return (IPP_TAG_ZERO
);
1955 * Return the group...
1958 return (attr
->group_tag
);
1963 * 'ippGetInteger()' - Get the integer/enum value for an attribute.
1965 * The @code element@ parameter specifies which value to get from 0 to
1966 * @link ippGetCount(attr)@ - 1.
1971 int /* O - Value or -1 on error */
1972 ippGetInteger(ipp_attribute_t
*attr
, /* I - IPP attribute */
1973 int element
) /* I - Value number (0-based) */
1976 * Range check input...
1979 if (!attr
|| (attr
->value_tag
!= IPP_TAG_INTEGER
&& attr
->value_tag
!= IPP_TAG_ENUM
) ||
1980 element
< 0 || element
>= attr
->num_values
)
1984 * Return the value...
1987 return (attr
->values
[element
].integer
);
1992 * 'ippGetName()' - Get the attribute name.
1997 const char * /* O - Attribute name or @code NULL@ for separators */
1998 ippGetName(ipp_attribute_t
*attr
) /* I - IPP attribute */
2001 * Range check input...
2008 * Return the name...
2011 return (attr
->name
);
2016 * 'ippGetOperation()' - Get the operation ID in an IPP message.
2021 ipp_op_t
/* O - Operation ID or -1 on error */
2022 ippGetOperation(ipp_t
*ipp
) /* I - IPP request message */
2025 * Range check input...
2029 return ((ipp_op_t
)-1);
2032 * Return the value...
2035 return (ipp
->request
.op
.operation_id
);
2040 * 'ippGetRange()' - Get a rangeOfInteger value from an attribute.
2042 * The @code element@ parameter specifies which value to get from 0 to
2043 * @link ippGetCount(attr)@ - 1.
2048 int /* O - Lower value of range or -1 */
2049 ippGetRange(ipp_attribute_t
*attr
, /* I - IPP attribute */
2050 int element
, /* I - Value number (0-based) */
2051 int *uppervalue
)/* O - Upper value of range */
2054 * Range check input...
2057 if (!attr
|| attr
->value_tag
!= IPP_TAG_RANGE
||
2058 element
< 0 || element
>= attr
->num_values
)
2067 * Return the values...
2071 *uppervalue
= attr
->values
[element
].range
.upper
;
2073 return (attr
->values
[element
].range
.lower
);
2078 * 'ippGetRequestId()' - Get the request ID from an IPP message.
2083 int /* O - Request ID or -1 on error */
2084 ippGetRequestId(ipp_t
*ipp
) /* I - IPP message */
2087 * Range check input...
2094 * Return the request ID...
2097 return (ipp
->request
.any
.request_id
);
2102 * 'ippGetResolution()' - Get a resolution value for an attribute.
2104 * The @code element@ parameter specifies which value to get from 0 to
2105 * @link ippGetCount(attr)@ - 1.
2110 int /* O - Horizontal/cross feed resolution or -1 */
2112 ipp_attribute_t
*attr
, /* I - IPP attribute */
2113 int element
, /* I - Value number (0-based) */
2114 int *yres
, /* O - Vertical/feed resolution */
2115 ipp_res_t
*units
) /* O - Units for resolution */
2118 * Range check input...
2121 if (!attr
|| attr
->value_tag
!= IPP_TAG_RESOLUTION
||
2122 element
< 0 || element
>= attr
->num_values
)
2126 * Return the value...
2130 *yres
= attr
->values
[element
].resolution
.yres
;
2133 *units
= attr
->values
[element
].resolution
.units
;
2135 return (attr
->values
[element
].resolution
.xres
);
2140 * 'ippGetState()' - Get the IPP message state.
2145 ipp_state_t
/* O - IPP message state value */
2146 ippGetState(ipp_t
*ipp
) /* I - IPP message */
2149 * Range check input...
2156 * Return the value...
2159 return (ipp
->state
);
2164 * 'ippGetStatusCode()' - Get the status code from an IPP response or event message.
2169 ipp_status_t
/* O - Status code in IPP message */
2170 ippGetStatusCode(ipp_t
*ipp
) /* I - IPP response or event message */
2173 * Range check input...
2177 return (IPP_INTERNAL_ERROR
);
2180 * Return the value...
2183 return (ipp
->request
.status
.status_code
);
2188 * 'ippGetString()' - Get the string and optionally the language code for an attribute.
2190 * The @code element@ parameter specifies which value to get from 0 to
2191 * @link ippGetCount(attr)@ - 1.
2197 ippGetString(ipp_attribute_t
*attr
, /* I - IPP attribute */
2198 int element
, /* I - Value number (0-based) */
2199 const char **language
)/* O - Language code (@code NULL@ for don't care) */
2202 * Range check input...
2205 if (!attr
|| element
< 0 || element
>= attr
->num_values
||
2206 (attr
->value_tag
!= IPP_TAG_TEXTLANG
&& attr
->value_tag
!= IPP_TAG_NAMELANG
&&
2207 (attr
->value_tag
< IPP_TAG_TEXT
|| attr
->value_tag
> IPP_TAG_MIMETYPE
)))
2211 * Return the value...
2215 *language
= attr
->values
[element
].string
.language
;
2217 return (attr
->values
[element
].string
.text
);
2222 * 'ippGetValueTag()' - Get the value tag for an attribute.
2227 ipp_tag_t
/* O - Value tag or @code IPP_TAG_ZERO@ on error */
2228 ippGetValueTag(ipp_attribute_t
*attr
) /* I - IPP attribute */
2231 * Range check input...
2235 return (IPP_TAG_ZERO
);
2238 * Return the value...
2241 return (attr
->value_tag
);
2246 * 'ippGetVersion()' - Get the major and minor version number from an IPP message.
2251 int /* O - Major version number or -1 on error */
2252 ippGetVersion(ipp_t
*ipp
, /* I - IPP message */
2253 int *minor
) /* O - Minor version number or @code NULL@ */
2256 * Range check input...
2268 * Return the value...
2272 *minor
= ipp
->request
.any
.version
[1];
2274 return (ipp
->request
.any
.version
[0]);
2279 * 'ippLength()' - Compute the length of an IPP message.
2282 size_t /* O - Size of IPP message */
2283 ippLength(ipp_t
*ipp
) /* I - IPP message */
2285 return (ipp_length(ipp
, 0));
2290 * 'ippNextAttribute()' - Return the next attribute in the message.
2295 ipp_attribute_t
* /* O - Next attribute or @code NULL@ if none */
2296 ippNextAttribute(ipp_t
*ipp
) /* I - IPP message */
2299 * Range check input...
2302 if (!ipp
|| !ipp
->current
)
2306 * Return the next attribute...
2309 return (ipp
->current
= ipp
->current
->next
);
2314 * 'ippNew()' - Allocate a new IPP message.
2317 ipp_t
* /* O - New IPP message */
2320 ipp_t
*temp
; /* New IPP message */
2323 DEBUG_puts("ippNew()");
2325 if ((temp
= (ipp_t
*)calloc(1, sizeof(ipp_t
))) != NULL
)
2328 * Default to IPP 2.0...
2331 temp
->request
.any
.version
[0] = 2;
2332 temp
->request
.any
.version
[1] = 0;
2336 DEBUG_printf(("1ippNew: Returning %p", temp
));
2343 * 'ippNewRequest()' - Allocate a new IPP request message.
2345 * The new request message is initialized with the attributes-charset and
2346 * attributes-natural-language attributes added. The
2347 * attributes-natural-language value is derived from the current locale.
2349 * @since CUPS 1.2/Mac OS X 10.5@
2352 ipp_t
* /* O - IPP request message */
2353 ippNewRequest(ipp_op_t op
) /* I - Operation code */
2355 ipp_t
*request
; /* IPP request message */
2356 cups_lang_t
*language
; /* Current language localization */
2357 static int request_id
= 0; /* Current request ID */
2358 static _cups_mutex_t request_mutex
= _CUPS_MUTEX_INITIALIZER
;
2359 /* Mutex for request ID */
2362 DEBUG_printf(("ippNewRequest(op=%02x(%s))", op
, ippOpString(op
)));
2365 * Create a new IPP message...
2368 if ((request
= ippNew()) == NULL
)
2372 * Set the operation and request ID...
2375 _cupsMutexLock(&request_mutex
);
2377 request
->request
.op
.operation_id
= op
;
2378 request
->request
.op
.request_id
= ++request_id
;
2380 _cupsMutexUnlock(&request_mutex
);
2383 * Use UTF-8 as the character set...
2386 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2387 "attributes-charset", NULL
, "utf-8");
2390 * Get the language from the current locale...
2393 language
= cupsLangDefault();
2395 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2396 "attributes-natural-language", NULL
, language
->language
);
2399 * Return the new request...
2407 * 'ippRead()' - Read data for an IPP message from a HTTP connection.
2410 ipp_state_t
/* O - Current state */
2411 ippRead(http_t
*http
, /* I - HTTP connection */
2412 ipp_t
*ipp
) /* I - IPP data */
2414 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT
,
2415 http
, ipp
, CUPS_LLCAST (http
? http
->data_remaining
: -1)));
2420 DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http
->state
,
2423 return (ippReadIO(http
, (ipp_iocb_t
)ipp_read_http
, http
->blocking
, NULL
,
2429 * 'ippReadFile()' - Read data for an IPP message from a file.
2431 * @since CUPS 1.1.19/Mac OS X 10.3@
2434 ipp_state_t
/* O - Current state */
2435 ippReadFile(int fd
, /* I - HTTP data */
2436 ipp_t
*ipp
) /* I - IPP data */
2438 DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd
, ipp
));
2440 return (ippReadIO(&fd
, (ipp_iocb_t
)ipp_read_file
, 1, NULL
, ipp
));
2445 * 'ippReadIO()' - Read data for an IPP message.
2447 * @since CUPS 1.2/Mac OS X 10.5@
2450 ipp_state_t
/* O - Current state */
2451 ippReadIO(void *src
, /* I - Data source */
2452 ipp_iocb_t cb
, /* I - Read callback function */
2453 int blocking
, /* I - Use blocking IO? */
2454 ipp_t
*parent
, /* I - Parent request, if any */
2455 ipp_t
*ipp
) /* I - IPP data */
2457 int n
; /* Length of data */
2458 unsigned char *buffer
, /* Data buffer */
2459 string
[IPP_MAX_NAME
],
2460 /* Small string buffer */
2461 *bufptr
; /* Pointer into buffer */
2462 ipp_attribute_t
*attr
; /* Current attribute */
2463 ipp_tag_t tag
; /* Current tag */
2464 ipp_tag_t value_tag
; /* Current value tag */
2465 _ipp_value_t
*value
; /* Current value */
2468 DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
2469 src
, cb
, blocking
, parent
, ipp
));
2470 DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp
->state
));
2475 if ((buffer
= (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE
)) == NULL
)
2477 DEBUG_puts("1ippReadIO: Unable to get read buffer.");
2484 ipp
->state
++; /* Avoid common problem... */
2490 * Get the request header...
2493 if ((*cb
)(src
, buffer
, 8) < 8)
2495 DEBUG_puts("1ippReadIO: Unable to read header.");
2496 _cupsBufferRelease((char *)buffer
);
2501 * Then copy the request header over...
2504 ipp
->request
.any
.version
[0] = buffer
[0];
2505 ipp
->request
.any
.version
[1] = buffer
[1];
2506 ipp
->request
.any
.op_status
= (buffer
[2] << 8) | buffer
[3];
2507 ipp
->request
.any
.request_id
= (((((buffer
[4] << 8) | buffer
[5]) << 8) |
2508 buffer
[6]) << 8) | buffer
[7];
2510 DEBUG_printf(("2ippReadIO: version=%d.%d", buffer
[0], buffer
[1]));
2511 DEBUG_printf(("2ippReadIO: op_status=%04x",
2512 ipp
->request
.any
.op_status
));
2513 DEBUG_printf(("2ippReadIO: request_id=%d",
2514 ipp
->request
.any
.request_id
));
2517 ipp
->state
= IPP_ATTRIBUTE
;
2518 ipp
->current
= NULL
;
2519 ipp
->curtag
= IPP_TAG_ZERO
;
2520 ipp
->prev
= ipp
->last
;
2523 * If blocking is disabled, stop here...
2529 case IPP_ATTRIBUTE
:
2532 if ((*cb
)(src
, buffer
, 1) < 1)
2534 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
2535 _cupsBufferRelease((char *)buffer
);
2539 DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p",
2540 ipp
->current
, ipp
->prev
));
2543 * Read this attribute...
2546 tag
= (ipp_tag_t
)buffer
[0];
2547 if (tag
== IPP_TAG_EXTENSION
)
2550 * Read 32-bit "extension" tag...
2553 if ((*cb
)(src
, buffer
, 4) < 1)
2555 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
2556 _cupsBufferRelease((char *)buffer
);
2560 tag
= (ipp_tag_t
)((((((buffer
[0] << 8) | buffer
[1]) << 8) |
2561 buffer
[2]) << 8) | buffer
[3]);
2563 if (tag
& IPP_TAG_COPY
)
2566 * Fail if the high bit is set in the tag...
2569 _cupsSetError(IPP_INTERNAL_ERROR
, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
2570 DEBUG_printf(("1ippReadIO: bad name length %d.", n
));
2571 _cupsBufferRelease((char *)buffer
);
2576 if (tag
== IPP_TAG_END
)
2579 * No more attributes left...
2582 DEBUG_puts("2ippReadIO: IPP_TAG_END.");
2584 ipp
->state
= IPP_DATA
;
2587 else if (tag
< IPP_TAG_UNSUPPORTED_VALUE
)
2590 * Group tag... Set the current group and continue...
2593 if (ipp
->curtag
== tag
)
2594 ipp
->prev
= ippAddSeparator(ipp
);
2595 else if (ipp
->current
)
2596 ipp
->prev
= ipp
->current
;
2599 ipp
->current
= NULL
;
2600 DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag
,
2601 ippTagString(tag
), ipp
->prev
));
2605 DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag
,
2606 ippTagString(tag
)));
2612 if ((*cb
)(src
, buffer
, 2) < 2)
2614 DEBUG_puts("1ippReadIO: unable to read name length.");
2615 _cupsBufferRelease((char *)buffer
);
2619 n
= (buffer
[0] << 8) | buffer
[1];
2621 if (n
>= IPP_BUF_SIZE
)
2623 _cupsSetError(IPP_INTERNAL_ERROR
, _("IPP name larger than 32767 bytes."), 1);
2624 DEBUG_printf(("1ippReadIO: bad name length %d.", n
));
2625 _cupsBufferRelease((char *)buffer
);
2629 DEBUG_printf(("2ippReadIO: name length=%d", n
));
2631 if (n
== 0 && tag
!= IPP_TAG_MEMBERNAME
&&
2632 tag
!= IPP_TAG_END_COLLECTION
)
2635 * More values for current attribute...
2638 if (ipp
->current
== NULL
)
2640 _cupsSetError(IPP_INTERNAL_ERROR
, _("IPP attribute has no name."), 1);
2641 DEBUG_puts("1ippReadIO: Attribute without name and no current.");
2642 _cupsBufferRelease((char *)buffer
);
2646 attr
= ipp
->current
;
2647 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_MASK
);
2650 * Make sure we aren't adding a new value of a different
2654 if (value_tag
== IPP_TAG_ZERO
)
2657 * Setting the value of a collection member...
2660 attr
->value_tag
= tag
;
2662 else if (value_tag
== IPP_TAG_TEXTLANG
||
2663 value_tag
== IPP_TAG_NAMELANG
||
2664 (value_tag
>= IPP_TAG_TEXT
&&
2665 value_tag
<= IPP_TAG_MIMETYPE
))
2668 * String values can sometimes come across in different
2669 * forms; accept sets of differing values...
2672 if (tag
!= IPP_TAG_TEXTLANG
&& tag
!= IPP_TAG_NAMELANG
&&
2673 (tag
< IPP_TAG_TEXT
|| tag
> IPP_TAG_MIMETYPE
) &&
2674 tag
!= IPP_TAG_NOVALUE
)
2676 _cupsSetError(IPP_INTERNAL_ERROR
,
2677 _("IPP 1setOf attribute with incompatible value "
2679 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
2680 value_tag
, ippTagString(value_tag
), tag
,
2681 ippTagString(tag
)));
2682 _cupsBufferRelease((char *)buffer
);
2686 if (value_tag
!= tag
)
2688 DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.",
2689 attr
->name
, ippTagString(value_tag
), ippTagString(tag
)));
2690 ippSetValueTag(ipp
, &attr
, tag
);
2693 else if (value_tag
== IPP_TAG_INTEGER
||
2694 value_tag
== IPP_TAG_RANGE
)
2697 * Integer and rangeOfInteger values can sometimes be mixed; accept
2698 * sets of differing values...
2701 if (tag
!= IPP_TAG_INTEGER
&& tag
!= IPP_TAG_RANGE
)
2703 _cupsSetError(IPP_INTERNAL_ERROR
,
2704 _("IPP 1setOf attribute with incompatible value "
2706 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
2707 value_tag
, ippTagString(value_tag
), tag
,
2708 ippTagString(tag
)));
2709 _cupsBufferRelease((char *)buffer
);
2713 if (value_tag
== IPP_TAG_INTEGER
&& tag
== IPP_TAG_RANGE
)
2716 * Convert integer values to rangeOfInteger values...
2719 DEBUG_printf(("1ippReadIO: Converting %s attribute to "
2720 "rangeOfInteger.", attr
->name
));
2721 ippSetValueTag(ipp
, &attr
, IPP_TAG_RANGE
);
2724 else if (value_tag
!= tag
)
2726 _cupsSetError(IPP_INTERNAL_ERROR
,
2727 _("IPP 1setOf attribute with incompatible value "
2729 DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
2730 value_tag
, ippTagString(value_tag
), tag
,
2731 ippTagString(tag
)));
2732 _cupsBufferRelease((char *)buffer
);
2737 * Finally, reallocate the attribute array as needed...
2740 if ((value
= ipp_set_value(ipp
, &attr
, attr
->num_values
)) == NULL
)
2742 _cupsBufferRelease((char *)buffer
);
2746 else if (tag
== IPP_TAG_MEMBERNAME
)
2749 * Name must be length 0!
2754 _cupsSetError(IPP_INTERNAL_ERROR
, _("IPP member name is not empty."), 1);
2755 DEBUG_puts("1ippReadIO: member name not empty.");
2756 _cupsBufferRelease((char *)buffer
);
2761 ipp
->prev
= ipp
->current
;
2763 attr
= ipp
->current
= ipp_add_attr(ipp
, NULL
, ipp
->curtag
, IPP_TAG_ZERO
, 1);
2765 DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p",
2766 ipp
->current
, ipp
->prev
));
2768 value
= attr
->values
;
2770 else if (tag
!= IPP_TAG_END_COLLECTION
)
2773 * New attribute; read the name and add it...
2776 if ((*cb
)(src
, buffer
, n
) < n
)
2778 DEBUG_puts("1ippReadIO: unable to read name.");
2779 _cupsBufferRelease((char *)buffer
);
2786 ipp
->prev
= ipp
->current
;
2788 if ((attr
= ipp
->current
= ipp_add_attr(ipp
, (char *)buffer
, ipp
->curtag
, tag
,
2791 _cupsSetHTTPError(HTTP_ERROR
);
2792 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
2793 _cupsBufferRelease((char *)buffer
);
2797 DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, "
2798 "ipp->prev=%p", buffer
, ipp
->current
, ipp
->prev
));
2800 value
= attr
->values
;
2808 if ((*cb
)(src
, buffer
, 2) < 2)
2810 DEBUG_puts("1ippReadIO: unable to read value length.");
2811 _cupsBufferRelease((char *)buffer
);
2815 n
= (buffer
[0] << 8) | buffer
[1];
2816 DEBUG_printf(("2ippReadIO: value length=%d", n
));
2818 if (n
>= IPP_BUF_SIZE
)
2820 _cupsSetError(IPP_INTERNAL_ERROR
,
2821 _("IPP value larger than 32767 bytes."), 1);
2822 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2823 _cupsBufferRelease((char *)buffer
);
2829 case IPP_TAG_INTEGER
:
2833 if (tag
== IPP_TAG_INTEGER
)
2834 _cupsSetError(IPP_INTERNAL_ERROR
,
2835 _("IPP integer value not 4 bytes."), 1);
2837 _cupsSetError(IPP_INTERNAL_ERROR
,
2838 _("IPP enum value not 4 bytes."), 1);
2839 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2840 _cupsBufferRelease((char *)buffer
);
2844 if ((*cb
)(src
, buffer
, 4) < 4)
2846 DEBUG_puts("1ippReadIO: Unable to read integer value.");
2847 _cupsBufferRelease((char *)buffer
);
2851 n
= (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
2854 if (attr
->value_tag
== IPP_TAG_RANGE
)
2855 value
->range
.lower
= value
->range
.upper
= n
;
2860 case IPP_TAG_BOOLEAN
:
2863 _cupsSetError(IPP_INTERNAL_ERROR
, _("IPP boolean value not 1 byte."),
2865 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2866 _cupsBufferRelease((char *)buffer
);
2870 if ((*cb
)(src
, buffer
, 1) < 1)
2872 DEBUG_puts("1ippReadIO: Unable to read boolean value.");
2873 _cupsBufferRelease((char *)buffer
);
2877 value
->boolean
= buffer
[0];
2880 case IPP_TAG_NOVALUE
:
2881 case IPP_TAG_NOTSETTABLE
:
2882 case IPP_TAG_DELETEATTR
:
2883 case IPP_TAG_ADMINDEFINE
:
2885 * These value types are not supposed to have values, however
2886 * some vendors (Brother) do not implement IPP correctly and so
2887 * we need to map non-empty values to text...
2890 if (attr
->value_tag
== tag
)
2895 attr
->value_tag
= IPP_TAG_TEXT
;
2900 case IPP_TAG_KEYWORD
:
2902 case IPP_TAG_URISCHEME
:
2903 case IPP_TAG_CHARSET
:
2904 case IPP_TAG_LANGUAGE
:
2905 case IPP_TAG_MIMETYPE
:
2906 if ((*cb
)(src
, buffer
, n
) < n
)
2908 DEBUG_puts("1ippReadIO: unable to read string value.");
2909 _cupsBufferRelease((char *)buffer
);
2914 value
->string
.text
= _cupsStrAlloc((char *)buffer
);
2915 DEBUG_printf(("2ippReadIO: value=\"%s\"", value
->string
.text
));
2921 _cupsSetError(IPP_INTERNAL_ERROR
, _("IPP date value not 11 bytes."), 1);
2922 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2923 _cupsBufferRelease((char *)buffer
);
2927 if ((*cb
)(src
, value
->date
, 11) < 11)
2929 DEBUG_puts("1ippReadIO: Unable to read date value.");
2930 _cupsBufferRelease((char *)buffer
);
2935 case IPP_TAG_RESOLUTION
:
2938 _cupsSetError(IPP_INTERNAL_ERROR
,
2939 _("IPP resolution value not 9 bytes."), 1);
2940 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2941 _cupsBufferRelease((char *)buffer
);
2945 if ((*cb
)(src
, buffer
, 9) < 9)
2947 DEBUG_puts("1ippReadIO: Unable to read resolution value.");
2948 _cupsBufferRelease((char *)buffer
);
2952 value
->resolution
.xres
=
2953 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
2955 value
->resolution
.yres
=
2956 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
2958 value
->resolution
.units
=
2959 (ipp_res_t
)buffer
[8];
2962 case IPP_TAG_RANGE
:
2965 _cupsSetError(IPP_INTERNAL_ERROR
,
2966 _("IPP rangeOfInteger value not 8 bytes."), 1);
2967 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2968 _cupsBufferRelease((char *)buffer
);
2972 if ((*cb
)(src
, buffer
, 8) < 8)
2974 DEBUG_puts("1ippReadIO: Unable to read range value.");
2975 _cupsBufferRelease((char *)buffer
);
2979 value
->range
.lower
=
2980 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
2982 value
->range
.upper
=
2983 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
2987 case IPP_TAG_TEXTLANG
:
2988 case IPP_TAG_NAMELANG
:
2991 if (tag
== IPP_TAG_TEXTLANG
)
2992 _cupsSetError(IPP_INTERNAL_ERROR
,
2993 _("IPP textWithLanguage value less than "
2994 "minimum 4 bytes."), 1);
2996 _cupsSetError(IPP_INTERNAL_ERROR
,
2997 _("IPP nameWithLanguage value less than "
2998 "minimum 4 bytes."), 1);
2999 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
3000 _cupsBufferRelease((char *)buffer
);
3004 if ((*cb
)(src
, buffer
, n
) < n
)
3006 DEBUG_puts("1ippReadIO: Unable to read string w/language "
3008 _cupsBufferRelease((char *)buffer
);
3015 * text-with-language and name-with-language are composite
3024 n
= (bufptr
[0] << 8) | bufptr
[1];
3026 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
) ||
3027 n
>= sizeof(string
))
3029 _cupsSetError(IPP_INTERNAL_ERROR
,
3030 _("IPP language length overflows value."), 1);
3031 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
3032 _cupsBufferRelease((char *)buffer
);
3036 memcpy(string
, bufptr
+ 2, n
);
3039 value
->string
.language
= _cupsStrAlloc((char *)string
);
3042 n
= (bufptr
[0] << 8) | bufptr
[1];
3044 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
))
3046 _cupsSetError(IPP_INTERNAL_ERROR
,
3047 _("IPP string length overflows value."), 1);
3048 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
3049 _cupsBufferRelease((char *)buffer
);
3053 bufptr
[2 + n
] = '\0';
3054 value
->string
.text
= _cupsStrAlloc((char *)bufptr
+ 2);
3057 case IPP_TAG_BEGIN_COLLECTION
:
3059 * Oh, boy, here comes a collection value, so read it...
3062 value
->collection
= ippNew();
3066 _cupsSetError(IPP_INTERNAL_ERROR
,
3067 _("IPP begCollection value not 0 bytes."), 1);
3068 DEBUG_puts("1ippReadIO: begCollection tag with value length "
3070 _cupsBufferRelease((char *)buffer
);
3074 if (ippReadIO(src
, cb
, 1, ipp
, value
->collection
) == IPP_ERROR
)
3076 DEBUG_puts("1ippReadIO: Unable to read collection value.");
3077 _cupsBufferRelease((char *)buffer
);
3082 case IPP_TAG_END_COLLECTION
:
3083 _cupsBufferRelease((char *)buffer
);
3087 _cupsSetError(IPP_INTERNAL_ERROR
,
3088 _("IPP endCollection value not 0 bytes."), 1);
3089 DEBUG_puts("1ippReadIO: endCollection tag with value length "
3094 DEBUG_puts("1ippReadIO: endCollection tag...");
3095 return (ipp
->state
= IPP_DATA
);
3097 case IPP_TAG_MEMBERNAME
:
3099 * The value the name of the member in the collection, which
3100 * we need to carry over...
3103 if ((*cb
)(src
, buffer
, n
) < n
)
3105 DEBUG_puts("1ippReadIO: Unable to read member name value.");
3106 _cupsBufferRelease((char *)buffer
);
3111 attr
->name
= _cupsStrAlloc((char *)buffer
);
3114 * Since collection members are encoded differently than
3115 * regular attributes, make sure we don't start with an
3119 attr
->num_values
--;
3121 DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr
->name
));
3124 default : /* Other unsupported values */
3125 value
->unknown
.length
= n
;
3128 if ((value
->unknown
.data
= malloc(n
)) == NULL
)
3130 _cupsSetHTTPError(HTTP_ERROR
);
3131 DEBUG_puts("1ippReadIO: Unable to allocate value");
3132 _cupsBufferRelease((char *)buffer
);
3136 if ((*cb
)(src
, value
->unknown
.data
, n
) < n
)
3138 DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
3139 _cupsBufferRelease((char *)buffer
);
3144 value
->unknown
.data
= NULL
;
3149 * If blocking is disabled, stop here...
3161 break; /* anti-compiler-warning-code */
3164 DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp
->state
));
3165 _cupsBufferRelease((char *)buffer
);
3167 return (ipp
->state
);
3172 * 'ippSetBoolean()' - Set a boolean value in an attribute.
3174 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3175 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3177 * The @code attr@ parameter may be modified as a result of setting the value.
3179 * The @code element@ parameter specifies which value to set from 0 to
3180 * @link ippGetCount(attr)@.
3185 int /* O - 1 on success, 0 on failure */
3186 ippSetBoolean(ipp_t
*ipp
, /* IO - IPP message */
3187 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3188 int element
, /* I - Value number (0-based) */
3189 int boolvalue
)/* I - Boolean value */
3191 _ipp_value_t
*value
; /* Current value */
3195 * Range check input...
3198 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BOOLEAN
||
3199 element
< 0 || element
> (*attr
)->num_values
)
3203 * Set the value and return...
3206 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3207 value
->boolean
= boolvalue
;
3209 return (value
!= NULL
);
3214 * 'ippSetCollection()' - Set a collection value in an attribute.
3216 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3217 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3219 * The @code attr@ parameter may be modified as a result of setting the value.
3221 * The @code element@ parameter specifies which value to set from 0 to
3222 * @link ippGetCount(attr)@.
3227 int /* O - 1 on success, 0 on failure */
3229 ipp_t
*ipp
, /* IO - IPP message */
3230 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3231 int element
, /* I - Value number (0-based) */
3232 ipp_t
*colvalue
) /* I - Collection value */
3234 _ipp_value_t
*value
; /* Current value */
3238 * Range check input...
3241 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
3242 element
< 0 || element
> (*attr
)->num_values
|| !colvalue
)
3246 * Set the value and return...
3249 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3251 if (value
->collection
)
3252 ippDelete(value
->collection
);
3254 value
->collection
= colvalue
;
3258 return (value
!= NULL
);
3263 * 'ippSetDate()' - Set a date value in an attribute.
3265 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3266 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3268 * The @code attr@ parameter may be modified as a result of setting the value.
3270 * The @code element@ parameter specifies which value to set from 0 to
3271 * @link ippGetCount(attr)@.
3276 int /* O - 1 on success, 0 on failure */
3277 ippSetDate(ipp_t
*ipp
, /* IO - IPP message */
3278 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3279 int element
, /* I - Value number (0-based) */
3280 const ipp_uchar_t
*datevalue
)/* I - Date value */
3282 _ipp_value_t
*value
; /* Current value */
3286 * Range check input...
3289 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_DATE
||
3290 element
< 0 || element
> (*attr
)->num_values
|| !datevalue
)
3294 * Set the value and return...
3297 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3298 memcpy(value
->date
, datevalue
, sizeof(value
->date
));
3300 return (value
!= NULL
);
3305 * 'ippSetGroupTag()' - Set the group tag of an attribute.
3307 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3308 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3310 * The @code attr@ parameter may be modified as a result of setting the value.
3312 * The @code group@ parameter specifies the IPP attribute group tag: none
3313 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
3314 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
3315 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
3316 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
3321 int /* O - 1 on success, 0 on failure */
3323 ipp_t
*ipp
, /* IO - IPP message */
3324 ipp_attribute_t
**attr
, /* IO - Attribute */
3325 ipp_tag_t group_tag
) /* I - Group tag */
3328 * Range check input - group tag must be 0x01 to 0x0F, per RFC 2911...
3331 if (!ipp
|| !attr
|| group_tag
< IPP_TAG_ZERO
|| group_tag
== IPP_TAG_END
||
3332 group_tag
>= IPP_TAG_UNSUPPORTED_VALUE
)
3336 * Set the group tag and return...
3339 (*attr
)->group_tag
= group_tag
;
3346 * 'ippSetInteger()' - Set an integer or enum value in an attribute.
3348 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3349 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3351 * The @code attr@ parameter may be modified as a result of setting the value.
3353 * The @code element@ parameter specifies which value to set from 0 to
3354 * @link ippGetCount(attr)@.
3359 int /* O - 1 on success, 0 on failure */
3360 ippSetInteger(ipp_t
*ipp
, /* IO - IPP message */
3361 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3362 int element
, /* I - Value number (0-based) */
3363 int intvalue
) /* I - Integer/enum value */
3365 _ipp_value_t
*value
; /* Current value */
3369 * Range check input...
3372 if (!ipp
|| !attr
|| !*attr
||
3373 ((*attr
)->value_tag
!= IPP_TAG_INTEGER
&& (*attr
)->value_tag
!= IPP_TAG_ENUM
) ||
3374 element
< 0 || element
> (*attr
)->num_values
)
3378 * Set the value and return...
3381 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3382 value
->integer
= intvalue
;
3384 return (value
!= NULL
);
3389 * 'ippSetName()' - Set the name of an attribute.
3391 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3392 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3394 * The @code attr@ parameter may be modified as a result of setting the value.
3399 int /* O - 1 on success, 0 on failure */
3400 ippSetName(ipp_t
*ipp
, /* IO - IPP message */
3401 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3402 const char *name
) /* I - Attribute name */
3404 char *temp
; /* Temporary name value */
3408 * Range check input...
3411 if (!ipp
|| !attr
|| !*attr
)
3415 * Set the value and return...
3418 if ((temp
= _cupsStrAlloc(name
)) != NULL
)
3421 _cupsStrFree((*attr
)->name
);
3423 (*attr
)->name
= temp
;
3426 return (temp
!= NULL
);
3431 * 'ippSetOperation()' - Set the operation ID in an IPP request message.
3433 * The @code ipp@ parameter refers to an IPP message previously created using the
3434 * @link ippNew@ or @link ippNewRequest@ functions.
3439 int /* O - 1 on success, 0 on failure */
3440 ippSetOperation(ipp_t
*ipp
, /* I - IPP request message */
3441 ipp_op_t op
) /* I - Operation ID */
3444 * Range check input...
3451 * Set the operation and return...
3454 ipp
->request
.op
.operation_id
= op
;
3461 * 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
3463 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3464 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3466 * The @code attr@ parameter may be modified as a result of setting the value.
3468 * The @code element@ parameter specifies which value to set from 0 to
3469 * @link ippGetCount(attr)@.
3474 int /* O - 1 on success, 0 on failure */
3475 ippSetRange(ipp_t
*ipp
, /* IO - IPP message */
3476 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3477 int element
, /* I - Value number (0-based) */
3478 int lowervalue
, /* I - Lower bound for range */
3479 int uppervalue
) /* I - Upper bound for range */
3481 _ipp_value_t
*value
; /* Current value */
3485 * Range check input...
3488 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RANGE
||
3489 element
< 0 || element
> (*attr
)->num_values
|| lowervalue
> uppervalue
)
3493 * Set the value and return...
3496 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3498 value
->range
.lower
= lowervalue
;
3499 value
->range
.upper
= uppervalue
;
3502 return (value
!= NULL
);
3507 * 'ippSetRequestId()' - Set the request ID in an IPP message.
3509 * The @code ipp@ parameter refers to an IPP message previously created using the
3510 * @link ippNew@ or @link ippNewRequest@ functions.
3512 * The @code request_id@ parameter must be greater than 0.
3517 int /* O - 1 on success, 0 on failure */
3518 ippSetRequestId(ipp_t
*ipp
, /* I - IPP message */
3519 int request_id
) /* I - Request ID */
3522 * Range check input; not checking request_id values since ipptool wants to send
3523 * invalid values for conformance testing and a bad request_id does not affect the
3524 * encoding of a message...
3531 * Set the request ID and return...
3534 ipp
->request
.any
.request_id
= request_id
;
3541 * 'ippSetResolution()' - Set a resolution value in an attribute.
3543 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3544 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3546 * The @code attr@ parameter may be modified as a result of setting the value.
3548 * The @code element@ parameter specifies which value to set from 0 to
3549 * @link ippGetCount(attr)@.
3554 int /* O - 1 on success, 0 on failure */
3556 ipp_t
*ipp
, /* IO - IPP message */
3557 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3558 int element
, /* I - Value number (0-based) */
3559 ipp_res_t unitsvalue
, /* I - Resolution units */
3560 int xresvalue
, /* I - Horizontal/cross feed resolution */
3561 int yresvalue
) /* I - Vertical/feed resolution */
3563 _ipp_value_t
*value
; /* Current value */
3567 * Range check input...
3570 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RESOLUTION
||
3571 element
< 0 || element
> (*attr
)->num_values
|| xresvalue
<= 0 || yresvalue
<= 0 ||
3572 unitsvalue
< IPP_RES_PER_INCH
|| unitsvalue
> IPP_RES_PER_CM
)
3576 * Set the value and return...
3579 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3581 value
->resolution
.units
= unitsvalue
;
3582 value
->resolution
.xres
= xresvalue
;
3583 value
->resolution
.yres
= yresvalue
;
3586 return (value
!= NULL
);
3591 * 'ippSetState()' - Set the current state of the IPP message.
3596 int /* O - 1 on success, 0 on failure */
3597 ippSetState(ipp_t
*ipp
, /* I - IPP message */
3598 ipp_state_t state
) /* I - IPP state value */
3601 * Range check input...
3608 * Set the state and return...
3612 ipp
->current
= NULL
;
3619 * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
3621 * The @code ipp@ parameter refers to an IPP message previously created using the
3622 * @link ippNew@ or @link ippNewRequest@ functions.
3627 int /* O - 1 on success, 0 on failure */
3628 ippSetStatusCode(ipp_t
*ipp
, /* I - IPP response or event message */
3629 ipp_status_t status
) /* I - Status code */
3632 * Range check input...
3639 * Set the status code and return...
3642 ipp
->request
.status
.status_code
= status
;
3649 * 'ippSetString()' - Set a string value in an attribute.
3651 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3652 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3654 * The @code attr@ parameter may be modified as a result of setting the value.
3656 * The @code element@ parameter specifies which value to set from 0 to
3657 * @link ippGetCount(attr)@.
3662 int /* O - 1 on success, 0 on failure */
3663 ippSetString(ipp_t
*ipp
, /* IO - IPP message */
3664 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3665 int element
, /* I - Value number (0-based) */
3666 const char *strvalue
) /* I - String value */
3668 char *temp
; /* Temporary string */
3669 _ipp_value_t
*value
; /* Current value */
3673 * Range check input...
3676 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_INTEGER
||
3677 element
< 0 || element
> (*attr
)->num_values
|| !strvalue
)
3681 * Set the value and return...
3684 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3687 value
->string
.language
= (*attr
)->values
[0].string
.language
;
3689 if ((int)((*attr
)->value_tag
) & IPP_TAG_COPY
)
3690 value
->string
.text
= (char *)strvalue
;
3691 else if ((temp
= _cupsStrAlloc(strvalue
)) != NULL
)
3693 if (value
->string
.text
)
3694 _cupsStrFree(value
->string
.text
);
3696 value
->string
.text
= temp
;
3702 return (value
!= NULL
);
3707 * 'ippSetValueTag()' - Set the value tag of an attribute.
3709 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3710 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3712 * The @code attr@ parameter may be modified as a result of setting the value.
3714 * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger
3715 * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name
3716 * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text
3717 * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage
3718 * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various
3719 * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes
3722 * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language
3723 * code in the "attributes-natural-language" attribute or, if not present, the language
3724 * code for the current locale.
3729 int /* O - 1 on success, 0 on failure */
3731 ipp_t
*ipp
, /* IO - IPP message */
3732 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3733 ipp_tag_t value_tag
) /* I - Value tag */
3735 int i
; /* Looping var */
3736 _ipp_value_t
*value
; /* Current value */
3737 int integer
; /* Current integer value */
3738 cups_lang_t
*language
; /* Current language */
3739 char code
[32]; /* Language code */
3740 ipp_tag_t temp_tag
; /* Temporary value tag */
3744 * Range check input...
3751 * If there is no change, return immediately...
3754 if (value_tag
== (*attr
)->value_tag
)
3758 * Otherwise implement changes as needed...
3761 temp_tag
= (ipp_tag_t
)((int)((*attr
)->value_tag
) & IPP_TAG_MASK
);
3765 case IPP_TAG_UNSUPPORTED_VALUE
:
3766 case IPP_TAG_DEFAULT
:
3767 case IPP_TAG_UNKNOWN
:
3768 case IPP_TAG_NOVALUE
:
3769 case IPP_TAG_NOTSETTABLE
:
3770 case IPP_TAG_DELETEATTR
:
3771 case IPP_TAG_ADMINDEFINE
:
3773 * Free any existing values...
3776 if ((*attr
)->num_values
> 0)
3777 ipp_free_values(*attr
, 0, (*attr
)->num_values
);
3780 * Set out-of-band value...
3783 (*attr
)->value_tag
= value_tag
;
3786 case IPP_TAG_RANGE
:
3787 if (temp_tag
!= IPP_TAG_INTEGER
)
3790 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
3794 integer
= value
->integer
;
3795 value
->range
.lower
= value
->range
.upper
= integer
;
3798 (*attr
)->value_tag
= IPP_TAG_RANGE
;
3802 if (temp_tag
!= IPP_TAG_KEYWORD
&& temp_tag
!= IPP_TAG_URI
&&
3803 temp_tag
!= IPP_TAG_URISCHEME
&& temp_tag
!= IPP_TAG_LANGUAGE
&&
3804 temp_tag
!= IPP_TAG_MIMETYPE
)
3807 (*attr
)->value_tag
= (ipp_tag_t
)(IPP_TAG_NAME
| ((*attr
)->value_tag
& IPP_TAG_COPY
));
3810 case IPP_TAG_NAMELANG
:
3811 case IPP_TAG_TEXTLANG
:
3812 if (value_tag
== IPP_TAG_NAMELANG
&&
3813 (temp_tag
!= IPP_TAG_NAME
&& temp_tag
!= IPP_TAG_KEYWORD
&&
3814 temp_tag
!= IPP_TAG_URI
&& temp_tag
!= IPP_TAG_URISCHEME
&&
3815 temp_tag
!= IPP_TAG_LANGUAGE
&& temp_tag
!= IPP_TAG_MIMETYPE
))
3818 if (value_tag
== IPP_TAG_TEXTLANG
&& temp_tag
!= IPP_TAG_TEXT
)
3821 if (ipp
->attrs
&& ipp
->attrs
->next
&& ipp
->attrs
->next
->name
&&
3822 !strcmp(ipp
->attrs
->next
->name
, "attributes-natural-language"))
3825 * Use the language code from the IPP message...
3828 (*attr
)->values
[0].string
.language
=
3829 _cupsStrAlloc(ipp
->attrs
->next
->values
[0].string
.text
);
3834 * Otherwise, use the language code corresponding to the locale...
3837 language
= cupsLangDefault();
3838 (*attr
)->values
[0].string
.language
= _cupsStrAlloc(ipp_lang_code(language
->language
,
3843 for (i
= (*attr
)->num_values
- 1, value
= (*attr
)->values
+ 1;
3846 value
->string
.language
= (*attr
)->values
[0].string
.language
;
3848 if ((int)(*attr
)->value_tag
& IPP_TAG_COPY
)
3851 * Make copies of all values...
3854 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
3857 value
->string
.text
= _cupsStrAlloc(value
->string
.text
);
3860 (*attr
)->value_tag
= IPP_TAG_NAMELANG
;
3863 case IPP_TAG_KEYWORD
:
3864 if (temp_tag
== IPP_TAG_NAME
|| temp_tag
== IPP_TAG_NAMELANG
)
3865 break; /* Silently "allow" name -> keyword */
3876 * 'ippSetVersion()' - Set the version number in an IPP message.
3878 * The @code ipp@ parameter refers to an IPP message previously created using the
3879 * @link ippNew@ or @link ippNewRequest@ functions.
3881 * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
3886 int /* O - 1 on success, 0 on failure */
3887 ippSetVersion(ipp_t
*ipp
, /* I - IPP message */
3888 int major
, /* I - Major version number (major.minor) */
3889 int minor
) /* I - Minor version number (major.minor) */
3892 * Range check input...
3895 if (!ipp
|| major
< 0 || minor
< 0)
3899 * Set the version number...
3902 ipp
->request
.any
.version
[0] = major
;
3903 ipp
->request
.any
.version
[1] = minor
;
3910 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
3913 const ipp_uchar_t
* /* O - RFC-1903 date/time data */
3914 ippTimeToDate(time_t t
) /* I - UNIX time value */
3916 struct tm
*unixdate
; /* UNIX unixdate/time info */
3917 ipp_uchar_t
*date
= _cupsGlobals()->ipp_date
;
3918 /* RFC-1903 date/time data */
3922 * RFC-1903 date/time format is:
3924 * Byte(s) Description
3925 * ------- -----------
3926 * 0-1 Year (0 to 65535)
3930 * 5 Minutes (0 to 59)
3931 * 6 Seconds (0 to 60, 60 = "leap second")
3932 * 7 Deciseconds (0 to 9)
3934 * 9 UTC hours (0 to 11)
3935 * 10 UTC minutes (0 to 59)
3938 unixdate
= gmtime(&t
);
3939 unixdate
->tm_year
+= 1900;
3941 date
[0] = unixdate
->tm_year
>> 8;
3942 date
[1] = unixdate
->tm_year
;
3943 date
[2] = unixdate
->tm_mon
+ 1;
3944 date
[3] = unixdate
->tm_mday
;
3945 date
[4] = unixdate
->tm_hour
;
3946 date
[5] = unixdate
->tm_min
;
3947 date
[6] = unixdate
->tm_sec
;
3958 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
3961 ipp_state_t
/* O - Current state */
3962 ippWrite(http_t
*http
, /* I - HTTP connection */
3963 ipp_t
*ipp
) /* I - IPP data */
3965 DEBUG_printf(("ippWrite(http=%p, ipp=%p)", http
, ipp
));
3970 return (ippWriteIO(http
, (ipp_iocb_t
)httpWrite2
, http
->blocking
, NULL
, ipp
));
3975 * 'ippWriteFile()' - Write data for an IPP message to a file.
3977 * @since CUPS 1.1.19/Mac OS X 10.3@
3980 ipp_state_t
/* O - Current state */
3981 ippWriteFile(int fd
, /* I - HTTP data */
3982 ipp_t
*ipp
) /* I - IPP data */
3984 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd
, ipp
));
3986 ipp
->state
= IPP_IDLE
;
3988 return (ippWriteIO(&fd
, (ipp_iocb_t
)ipp_write_file
, 1, NULL
, ipp
));
3993 * 'ippWriteIO()' - Write data for an IPP message.
3995 * @since CUPS 1.2/Mac OS X 10.5@
3998 ipp_state_t
/* O - Current state */
3999 ippWriteIO(void *dst
, /* I - Destination */
4000 ipp_iocb_t cb
, /* I - Write callback function */
4001 int blocking
, /* I - Use blocking IO? */
4002 ipp_t
*parent
, /* I - Parent IPP message */
4003 ipp_t
*ipp
) /* I - IPP data */
4005 int i
; /* Looping var */
4006 int n
; /* Length of data */
4007 unsigned char *buffer
, /* Data buffer */
4008 *bufptr
; /* Pointer into buffer */
4009 ipp_attribute_t
*attr
; /* Current attribute */
4010 _ipp_value_t
*value
; /* Current value */
4013 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
4014 dst
, cb
, blocking
, parent
, ipp
));
4019 if ((buffer
= (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE
)) == NULL
)
4021 DEBUG_puts("1ippWriteIO: Unable to get write buffer");
4028 ipp
->state
++; /* Avoid common problem... */
4034 * Send the request header:
4037 * Operation/Status Code = 2 bytes
4038 * Request ID = 4 bytes
4044 *bufptr
++ = ipp
->request
.any
.version
[0];
4045 *bufptr
++ = ipp
->request
.any
.version
[1];
4046 *bufptr
++ = ipp
->request
.any
.op_status
>> 8;
4047 *bufptr
++ = ipp
->request
.any
.op_status
;
4048 *bufptr
++ = ipp
->request
.any
.request_id
>> 24;
4049 *bufptr
++ = ipp
->request
.any
.request_id
>> 16;
4050 *bufptr
++ = ipp
->request
.any
.request_id
>> 8;
4051 *bufptr
++ = ipp
->request
.any
.request_id
;
4053 DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer
[0], buffer
[1]));
4054 DEBUG_printf(("2ippWriteIO: op_status=%04x",
4055 ipp
->request
.any
.op_status
));
4056 DEBUG_printf(("2ippWriteIO: request_id=%d",
4057 ipp
->request
.any
.request_id
));
4059 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4061 DEBUG_puts("1ippWriteIO: Could not write IPP header...");
4062 _cupsBufferRelease((char *)buffer
);
4068 * Reset the state engine to point to the first attribute
4069 * in the request/response, with no current group.
4072 ipp
->state
= IPP_ATTRIBUTE
;
4073 ipp
->current
= ipp
->attrs
;
4074 ipp
->curtag
= IPP_TAG_ZERO
;
4076 DEBUG_printf(("1ippWriteIO: ipp->current=%p", ipp
->current
));
4079 * If blocking is disabled, stop here...
4085 case IPP_ATTRIBUTE
:
4086 while (ipp
->current
!= NULL
)
4089 * Write this attribute...
4093 attr
= ipp
->current
;
4095 ipp
->current
= ipp
->current
->next
;
4099 if (ipp
->curtag
!= attr
->group_tag
)
4102 * Send a group tag byte...
4105 ipp
->curtag
= attr
->group_tag
;
4107 if (attr
->group_tag
== IPP_TAG_ZERO
)
4110 DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
4111 attr
->group_tag
, ippTagString(attr
->group_tag
)));
4112 *bufptr
++ = attr
->group_tag
;
4114 else if (attr
->group_tag
== IPP_TAG_ZERO
)
4118 DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr
->name
,
4119 attr
->num_values
> 1 ? "1setOf " : "",
4120 ippTagString(attr
->value_tag
)));
4123 * Write the attribute tag and name.
4125 * The attribute name length does not include the trailing nul
4126 * character in the source string.
4128 * Collection values (parent != NULL) are written differently...
4134 * Get the length of the attribute name, and make sure it won't
4135 * overflow the buffer...
4138 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 8))
4140 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
4141 _cupsBufferRelease((char *)buffer
);
4146 * Write the value tag, name length, and name string...
4149 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4150 attr
->value_tag
, ippTagString(attr
->value_tag
)));
4151 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
4154 if (attr
->value_tag
> 0xff)
4156 *bufptr
++ = IPP_TAG_EXTENSION
;
4157 *bufptr
++ = attr
->value_tag
>> 24;
4158 *bufptr
++ = attr
->value_tag
>> 16;
4159 *bufptr
++ = attr
->value_tag
>> 8;
4160 *bufptr
++ = attr
->value_tag
;
4163 *bufptr
++ = attr
->value_tag
;
4167 memcpy(bufptr
, attr
->name
, n
);
4173 * Get the length of the attribute name, and make sure it won't
4174 * overflow the buffer...
4177 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 12))
4179 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
4180 _cupsBufferRelease((char *)buffer
);
4185 * Write the member name tag, name length, name string, value tag,
4186 * and empty name for the collection member attribute...
4189 DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
4190 IPP_TAG_MEMBERNAME
));
4191 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
4193 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4194 attr
->value_tag
, ippTagString(attr
->value_tag
)));
4195 DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
4197 *bufptr
++ = IPP_TAG_MEMBERNAME
;
4202 memcpy(bufptr
, attr
->name
, n
);
4205 if (attr
->value_tag
> 0xff)
4207 *bufptr
++ = IPP_TAG_EXTENSION
;
4208 *bufptr
++ = attr
->value_tag
>> 24;
4209 *bufptr
++ = attr
->value_tag
>> 16;
4210 *bufptr
++ = attr
->value_tag
>> 8;
4211 *bufptr
++ = attr
->value_tag
;
4214 *bufptr
++ = attr
->value_tag
;
4221 * Now write the attribute value(s)...
4224 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
4226 case IPP_TAG_UNSUPPORTED_VALUE
:
4227 case IPP_TAG_DEFAULT
:
4228 case IPP_TAG_UNKNOWN
:
4229 case IPP_TAG_NOVALUE
:
4230 case IPP_TAG_NOTSETTABLE
:
4231 case IPP_TAG_DELETEATTR
:
4232 case IPP_TAG_ADMINDEFINE
:
4237 case IPP_TAG_INTEGER
:
4239 for (i
= 0, value
= attr
->values
;
4240 i
< attr
->num_values
;
4243 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 9)
4245 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4247 DEBUG_puts("1ippWriteIO: Could not write IPP "
4249 _cupsBufferRelease((char *)buffer
);
4259 * Arrays and sets are done by sending additional
4260 * values with a zero-length name...
4263 *bufptr
++ = attr
->value_tag
;
4269 * Integers and enumerations are both 4-byte signed
4270 * (twos-complement) values.
4272 * Put the 2-byte length and 4-byte value into the buffer...
4277 *bufptr
++ = value
->integer
>> 24;
4278 *bufptr
++ = value
->integer
>> 16;
4279 *bufptr
++ = value
->integer
>> 8;
4280 *bufptr
++ = value
->integer
;
4284 case IPP_TAG_BOOLEAN
:
4285 for (i
= 0, value
= attr
->values
;
4286 i
< attr
->num_values
;
4289 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 6)
4291 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4293 DEBUG_puts("1ippWriteIO: Could not write IPP "
4295 _cupsBufferRelease((char *)buffer
);
4305 * Arrays and sets are done by sending additional
4306 * values with a zero-length name...
4309 *bufptr
++ = attr
->value_tag
;
4315 * Boolean values are 1-byte; 0 = false, 1 = true.
4317 * Put the 2-byte length and 1-byte value into the buffer...
4322 *bufptr
++ = value
->boolean
;
4328 case IPP_TAG_KEYWORD
:
4330 case IPP_TAG_URISCHEME
:
4331 case IPP_TAG_CHARSET
:
4332 case IPP_TAG_LANGUAGE
:
4333 case IPP_TAG_MIMETYPE
:
4334 for (i
= 0, value
= attr
->values
;
4335 i
< attr
->num_values
;
4341 * Arrays and sets are done by sending additional
4342 * values with a zero-length name...
4345 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4347 ippTagString(attr
->value_tag
)));
4348 DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
4350 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
4352 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4354 DEBUG_puts("1ippWriteIO: Could not write IPP "
4356 _cupsBufferRelease((char *)buffer
);
4363 *bufptr
++ = attr
->value_tag
;
4368 if (value
->string
.text
!= NULL
)
4369 n
= (int)strlen(value
->string
.text
);
4373 if (n
> (IPP_BUF_SIZE
- 2))
4375 DEBUG_printf(("1ippWriteIO: String too long (%d)", n
));
4376 _cupsBufferRelease((char *)buffer
);
4380 DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n
,
4381 value
->string
.text
));
4383 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
4385 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4387 DEBUG_puts("1ippWriteIO: Could not write IPP "
4389 _cupsBufferRelease((char *)buffer
);
4397 * All simple strings consist of the 2-byte length and
4398 * character data without the trailing nul normally found
4399 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
4400 * bytes since the 2-byte length is a signed (twos-complement)
4403 * Put the 2-byte length and string characters in the buffer.
4411 memcpy(bufptr
, value
->string
.text
, n
);
4418 for (i
= 0, value
= attr
->values
;
4419 i
< attr
->num_values
;
4422 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 16)
4424 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4426 DEBUG_puts("1ippWriteIO: Could not write IPP "
4428 _cupsBufferRelease((char *)buffer
);
4438 * Arrays and sets are done by sending additional
4439 * values with a zero-length name...
4442 *bufptr
++ = attr
->value_tag
;
4448 * Date values consist of a 2-byte length and an
4449 * 11-byte date/time structure defined by RFC 1903.
4451 * Put the 2-byte length and 11-byte date/time
4452 * structure in the buffer.
4457 memcpy(bufptr
, value
->date
, 11);
4462 case IPP_TAG_RESOLUTION
:
4463 for (i
= 0, value
= attr
->values
;
4464 i
< attr
->num_values
;
4467 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 14)
4469 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4471 DEBUG_puts("1ippWriteIO: Could not write IPP "
4473 _cupsBufferRelease((char *)buffer
);
4483 * Arrays and sets are done by sending additional
4484 * values with a zero-length name...
4487 *bufptr
++ = attr
->value_tag
;
4493 * Resolution values consist of a 2-byte length,
4494 * 4-byte horizontal resolution value, 4-byte vertical
4495 * resolution value, and a 1-byte units value.
4497 * Put the 2-byte length and resolution value data
4503 *bufptr
++ = value
->resolution
.xres
>> 24;
4504 *bufptr
++ = value
->resolution
.xres
>> 16;
4505 *bufptr
++ = value
->resolution
.xres
>> 8;
4506 *bufptr
++ = value
->resolution
.xres
;
4507 *bufptr
++ = value
->resolution
.yres
>> 24;
4508 *bufptr
++ = value
->resolution
.yres
>> 16;
4509 *bufptr
++ = value
->resolution
.yres
>> 8;
4510 *bufptr
++ = value
->resolution
.yres
;
4511 *bufptr
++ = value
->resolution
.units
;
4515 case IPP_TAG_RANGE
:
4516 for (i
= 0, value
= attr
->values
;
4517 i
< attr
->num_values
;
4520 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 13)
4522 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4524 DEBUG_puts("1ippWriteIO: Could not write IPP "
4526 _cupsBufferRelease((char *)buffer
);
4536 * Arrays and sets are done by sending additional
4537 * values with a zero-length name...
4540 *bufptr
++ = attr
->value_tag
;
4546 * Range values consist of a 2-byte length,
4547 * 4-byte lower value, and 4-byte upper value.
4549 * Put the 2-byte length and range value data
4555 *bufptr
++ = value
->range
.lower
>> 24;
4556 *bufptr
++ = value
->range
.lower
>> 16;
4557 *bufptr
++ = value
->range
.lower
>> 8;
4558 *bufptr
++ = value
->range
.lower
;
4559 *bufptr
++ = value
->range
.upper
>> 24;
4560 *bufptr
++ = value
->range
.upper
>> 16;
4561 *bufptr
++ = value
->range
.upper
>> 8;
4562 *bufptr
++ = value
->range
.upper
;
4566 case IPP_TAG_TEXTLANG
:
4567 case IPP_TAG_NAMELANG
:
4568 for (i
= 0, value
= attr
->values
;
4569 i
< attr
->num_values
;
4575 * Arrays and sets are done by sending additional
4576 * values with a zero-length name...
4579 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
4581 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4583 DEBUG_puts("1ippWriteIO: Could not write IPP "
4585 _cupsBufferRelease((char *)buffer
);
4592 *bufptr
++ = attr
->value_tag
;
4598 * textWithLanguage and nameWithLanguage values consist
4599 * of a 2-byte length for both strings and their
4600 * individual lengths, a 2-byte length for the
4601 * character string, the character string without the
4602 * trailing nul, a 2-byte length for the character
4603 * set string, and the character set string without
4609 if (value
->string
.language
!= NULL
)
4610 n
+= (int)strlen(value
->string
.language
);
4612 if (value
->string
.text
!= NULL
)
4613 n
+= (int)strlen(value
->string
.text
);
4615 if (n
> (IPP_BUF_SIZE
- 2))
4617 DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
4618 "too long (%d)", n
));
4619 _cupsBufferRelease((char *)buffer
);
4623 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
4625 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4627 DEBUG_puts("1ippWriteIO: Could not write IPP "
4629 _cupsBufferRelease((char *)buffer
);
4636 /* Length of entire value */
4640 /* Length of language */
4641 if (value
->string
.language
!= NULL
)
4642 n
= (int)strlen(value
->string
.language
);
4652 memcpy(bufptr
, value
->string
.language
, n
);
4656 /* Length of text */
4657 if (value
->string
.text
!= NULL
)
4658 n
= (int)strlen(value
->string
.text
);
4668 memcpy(bufptr
, value
->string
.text
, n
);
4674 case IPP_TAG_BEGIN_COLLECTION
:
4675 for (i
= 0, value
= attr
->values
;
4676 i
< attr
->num_values
;
4680 * Collections are written with the begin-collection
4681 * tag first with a value of 0 length, followed by the
4682 * attributes in the collection, then the end-collection
4686 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 5)
4688 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4690 DEBUG_puts("1ippWriteIO: Could not write IPP "
4692 _cupsBufferRelease((char *)buffer
);
4702 * Arrays and sets are done by sending additional
4703 * values with a zero-length name...
4706 *bufptr
++ = attr
->value_tag
;
4712 * Write a data length of 0 and flush the buffer...
4718 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4720 DEBUG_puts("1ippWriteIO: Could not write IPP "
4722 _cupsBufferRelease((char *)buffer
);
4729 * Then write the collection attribute...
4732 value
->collection
->state
= IPP_IDLE
;
4734 if (ippWriteIO(dst
, cb
, 1, ipp
,
4735 value
->collection
) == IPP_ERROR
)
4737 DEBUG_puts("1ippWriteIO: Unable to write collection value");
4738 _cupsBufferRelease((char *)buffer
);
4745 for (i
= 0, value
= attr
->values
;
4746 i
< attr
->num_values
;
4752 * Arrays and sets are done by sending additional
4753 * values with a zero-length name...
4756 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
4758 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4760 DEBUG_puts("1ippWriteIO: Could not write IPP "
4762 _cupsBufferRelease((char *)buffer
);
4769 *bufptr
++ = attr
->value_tag
;
4775 * An unknown value might some new value that a
4776 * vendor has come up with. It consists of a
4777 * 2-byte length and the bytes in the unknown
4781 n
= value
->unknown
.length
;
4783 if (n
> (IPP_BUF_SIZE
- 2))
4785 DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
4787 _cupsBufferRelease((char *)buffer
);
4791 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
4793 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4795 DEBUG_puts("1ippWriteIO: Could not write IPP "
4797 _cupsBufferRelease((char *)buffer
);
4804 /* Length of unknown value */
4811 memcpy(bufptr
, value
->unknown
.data
, n
);
4819 * Write the data out...
4822 if (bufptr
> buffer
)
4824 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4826 DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4827 _cupsBufferRelease((char *)buffer
);
4831 DEBUG_printf(("2ippWriteIO: wrote %d bytes",
4832 (int)(bufptr
- buffer
)));
4836 * If blocking is disabled, stop here...
4843 if (ipp
->current
== NULL
)
4846 * Done with all of the attributes; add the end-of-attributes
4847 * tag or end-collection attribute...
4852 buffer
[0] = IPP_TAG_END
;
4857 buffer
[0] = IPP_TAG_END_COLLECTION
;
4858 buffer
[1] = 0; /* empty name */
4860 buffer
[3] = 0; /* empty value */
4865 if ((*cb
)(dst
, buffer
, n
) < 0)
4867 DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
4868 _cupsBufferRelease((char *)buffer
);
4872 ipp
->state
= IPP_DATA
;
4880 break; /* anti-compiler-warning-code */
4883 _cupsBufferRelease((char *)buffer
);
4885 return (ipp
->state
);
4890 * 'ipp_add_attr()' - Add a new attribute to the message.
4893 static ipp_attribute_t
* /* O - New attribute */
4894 ipp_add_attr(ipp_t
*ipp
, /* I - IPP message */
4895 const char *name
, /* I - Attribute name or NULL */
4896 ipp_tag_t group_tag
, /* I - Group tag or IPP_TAG_ZERO */
4897 ipp_tag_t value_tag
, /* I - Value tag or IPP_TAG_ZERO */
4898 int num_values
) /* I - Number of values */
4900 int alloc_values
; /* Number of values to allocate */
4901 ipp_attribute_t
*attr
; /* New attribute */
4904 DEBUG_printf(("4ipp_add_attr(ipp=%p, name=\"%s\", group_tag=0x%x, value_tag=0x%x, "
4905 "num_values=%d)", ipp
, name
, group_tag
, value_tag
, num_values
));
4908 * Range check input...
4911 if (!ipp
|| num_values
< 0)
4915 * Allocate memory, rounding the allocation up as needed...
4918 if (num_values
<= 1)
4921 alloc_values
= (num_values
+ IPP_MAX_VALUES
- 1) & ~(IPP_MAX_VALUES
- 1);
4923 attr
= calloc(sizeof(ipp_attribute_t
) +
4924 (alloc_values
- 1) * sizeof(_ipp_value_t
), 1);
4929 * Initialize attribute...
4933 attr
->name
= _cupsStrAlloc(name
);
4935 attr
->group_tag
= group_tag
;
4936 attr
->value_tag
= value_tag
;
4937 attr
->num_values
= num_values
;
4940 * Add it to the end of the linked list...
4944 ipp
->last
->next
= attr
;
4948 ipp
->prev
= ipp
->last
;
4949 ipp
->last
= ipp
->current
= attr
;
4952 DEBUG_printf(("5ipp_add_attr: Returning %p", attr
));
4959 * 'ipp_free_values()' - Free attribute values.
4963 ipp_free_values(ipp_attribute_t
*attr
, /* I - Attribute to free values from */
4964 int element
,/* I - First value to free */
4965 int count
) /* I - Number of values to free */
4967 int i
; /* Looping var */
4968 _ipp_value_t
*value
; /* Current value */
4971 DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", attr
, element
, count
));
4973 if (!(attr
->value_tag
& IPP_TAG_COPY
))
4976 * Free values as needed...
4979 switch (attr
->value_tag
)
4981 case IPP_TAG_TEXTLANG
:
4982 case IPP_TAG_NAMELANG
:
4983 if (element
== 0 && count
== attr
->num_values
&& attr
->values
[0].string
.language
)
4984 _cupsStrFree(attr
->values
[0].string
.language
);
4988 case IPP_TAG_RESERVED_STRING
:
4989 case IPP_TAG_KEYWORD
:
4991 case IPP_TAG_URISCHEME
:
4992 case IPP_TAG_CHARSET
:
4993 case IPP_TAG_LANGUAGE
:
4994 case IPP_TAG_MIMETYPE
:
4995 for (i
= count
, value
= attr
->values
+ element
;
4998 _cupsStrFree(value
->string
.text
);
5001 case IPP_TAG_DEFAULT
:
5002 case IPP_TAG_UNKNOWN
:
5003 case IPP_TAG_NOVALUE
:
5004 case IPP_TAG_NOTSETTABLE
:
5005 case IPP_TAG_DELETEATTR
:
5006 case IPP_TAG_ADMINDEFINE
:
5007 case IPP_TAG_INTEGER
:
5009 case IPP_TAG_BOOLEAN
:
5011 case IPP_TAG_RESOLUTION
:
5012 case IPP_TAG_RANGE
:
5015 case IPP_TAG_BEGIN_COLLECTION
:
5016 for (i
= count
, value
= attr
->values
+ element
;
5019 ippDelete(value
->collection
);
5022 case IPP_TAG_STRING
:
5024 for (i
= count
, value
= attr
->values
+ element
;
5027 if (value
->unknown
.data
)
5028 free(value
->unknown
.data
);
5034 * If we are not freeing values from the end, move the remaining values up...
5037 if ((element
+ count
) < attr
->num_values
)
5038 memmove(attr
->values
+ element
, attr
->values
+ element
+ count
,
5039 (attr
->num_values
- count
- element
) * sizeof(_ipp_value_t
));
5041 attr
->num_values
-= count
;
5046 * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
5048 * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
5049 * to "ll-cc", "ll-region", and "charset-number", respectively.
5052 static char * /* O - Language code string */
5053 ipp_get_code(const char *value
, /* I - Locale/charset string */
5054 char *buffer
, /* I - String buffer */
5055 size_t bufsize
) /* I - Size of string buffer */
5057 char *bufptr
, /* Pointer into buffer */
5058 *bufend
; /* End of buffer */
5062 * Convert values to lowercase and change _ to - as needed...
5065 for (bufptr
= buffer
, bufend
= buffer
+ bufsize
- 1;
5066 *value
&& bufptr
< bufend
;
5071 *bufptr
++ = _cups_tolower(*value
);
5076 * Return the converted string...
5084 * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
5086 * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
5087 * "ll-region", respectively. It also converts the "C" (POSIX) locale to "en".
5090 static char * /* O - Language code string */
5091 ipp_lang_code(const char *locale
, /* I - Locale string */
5092 char *buffer
, /* I - String buffer */
5093 size_t bufsize
) /* I - Size of string buffer */
5096 * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
5099 if (!_cups_strcasecmp(locale
, "c"))
5101 strlcpy(buffer
, "en", bufsize
);
5105 return (ipp_get_code(locale
, buffer
, bufsize
));
5110 * 'ipp_length()' - Compute the length of an IPP message or collection value.
5113 static size_t /* O - Size of IPP message */
5114 ipp_length(ipp_t
*ipp
, /* I - IPP message or collection */
5115 int collection
) /* I - 1 if a collection, 0 otherwise */
5117 int i
; /* Looping var */
5118 size_t bytes
; /* Number of bytes */
5119 ipp_attribute_t
*attr
; /* Current attribute */
5120 ipp_tag_t group
; /* Current group */
5121 _ipp_value_t
*value
; /* Current value */
5124 DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", ipp
, collection
));
5128 DEBUG_puts("4ipp_length: Returning 0 bytes");
5133 * Start with 8 bytes for the IPP message header...
5136 bytes
= collection
? 0 : 8;
5139 * Then add the lengths of each attribute...
5142 group
= IPP_TAG_ZERO
;
5144 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= attr
->next
)
5146 if (attr
->group_tag
!= group
&& !collection
)
5148 group
= attr
->group_tag
;
5149 if (group
== IPP_TAG_ZERO
)
5152 bytes
++; /* Group tag */
5158 DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
5159 "bytes=" CUPS_LLFMT
, attr
->name
, attr
->num_values
, CUPS_LLCAST bytes
));
5161 if (attr
->value_tag
< IPP_TAG_EXTENSION
)
5162 bytes
+= attr
->num_values
; /* Value tag for each value */
5164 bytes
+= 5 * attr
->num_values
; /* Value tag for each value */
5165 bytes
+= 2 * attr
->num_values
; /* Name lengths */
5166 bytes
+= (int)strlen(attr
->name
); /* Name */
5167 bytes
+= 2 * attr
->num_values
; /* Value lengths */
5170 bytes
+= 5; /* Add membername overhead */
5172 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
5174 case IPP_TAG_UNSUPPORTED_VALUE
:
5175 case IPP_TAG_DEFAULT
:
5176 case IPP_TAG_UNKNOWN
:
5177 case IPP_TAG_NOVALUE
:
5178 case IPP_TAG_NOTSETTABLE
:
5179 case IPP_TAG_DELETEATTR
:
5180 case IPP_TAG_ADMINDEFINE
:
5183 case IPP_TAG_INTEGER
:
5185 bytes
+= 4 * attr
->num_values
;
5188 case IPP_TAG_BOOLEAN
:
5189 bytes
+= attr
->num_values
;
5194 case IPP_TAG_KEYWORD
:
5196 case IPP_TAG_URISCHEME
:
5197 case IPP_TAG_CHARSET
:
5198 case IPP_TAG_LANGUAGE
:
5199 case IPP_TAG_MIMETYPE
:
5200 for (i
= 0, value
= attr
->values
;
5201 i
< attr
->num_values
;
5203 if (value
->string
.text
)
5204 bytes
+= strlen(value
->string
.text
);
5208 bytes
+= 11 * attr
->num_values
;
5211 case IPP_TAG_RESOLUTION
:
5212 bytes
+= 9 * attr
->num_values
;
5215 case IPP_TAG_RANGE
:
5216 bytes
+= 8 * attr
->num_values
;
5219 case IPP_TAG_TEXTLANG
:
5220 case IPP_TAG_NAMELANG
:
5221 bytes
+= 4 * attr
->num_values
;/* Charset + text length */
5223 for (i
= 0, value
= attr
->values
;
5224 i
< attr
->num_values
;
5227 if (value
->string
.language
)
5228 bytes
+= strlen(value
->string
.language
);
5230 if (value
->string
.text
)
5231 bytes
+= strlen(value
->string
.text
);
5235 case IPP_TAG_BEGIN_COLLECTION
:
5236 for (i
= 0, value
= attr
->values
;
5237 i
< attr
->num_values
;
5239 bytes
+= ipp_length(value
->collection
, 1);
5243 for (i
= 0, value
= attr
->values
;
5244 i
< attr
->num_values
;
5246 bytes
+= value
->unknown
.length
;
5252 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
5253 * for the "end of collection" tag and return...
5261 DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT
" bytes", CUPS_LLCAST bytes
));
5268 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
5271 static ssize_t
/* O - Number of bytes read */
5272 ipp_read_http(http_t
*http
, /* I - Client connection */
5273 ipp_uchar_t
*buffer
, /* O - Buffer for data */
5274 size_t length
) /* I - Total length */
5276 int tbytes
, /* Total bytes read */
5277 bytes
; /* Bytes read this pass */
5278 char len
[32]; /* Length string */
5281 DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)",
5282 http
, buffer
, (int)length
));
5285 * Loop until all bytes are read...
5288 for (tbytes
= 0, bytes
= 0;
5289 tbytes
< (int)length
;
5290 tbytes
+= bytes
, buffer
+= bytes
)
5292 DEBUG_printf(("9ipp_read_http: tbytes=%d, http->state=%d", tbytes
,
5295 if (http
->state
== HTTP_WAITING
)
5298 if (http
->used
> 0 && http
->data_encoding
== HTTP_ENCODE_LENGTH
)
5301 * Do "fast read" from HTTP buffer directly...
5304 if (http
->used
> (int)(length
- tbytes
))
5305 bytes
= (int)(length
- tbytes
);
5310 buffer
[0] = http
->buffer
[0];
5312 memcpy(buffer
, http
->buffer
, bytes
);
5314 http
->used
-= bytes
;
5315 http
->data_remaining
-= bytes
;
5317 if (http
->data_remaining
<= INT_MAX
)
5318 http
->_data_remaining
= (int)http
->data_remaining
;
5320 http
->_data_remaining
= INT_MAX
;
5323 memmove(http
->buffer
, http
->buffer
+ bytes
, http
->used
);
5325 if (http
->data_remaining
== 0)
5327 if (http
->data_encoding
== HTTP_ENCODE_CHUNKED
)
5330 * Get the trailing CR LF after the chunk...
5333 if (!httpGets(len
, sizeof(len
), http
))
5337 if (http
->data_encoding
!= HTTP_ENCODE_CHUNKED
)
5339 if (http
->state
== HTTP_POST_RECV
)
5342 http
->state
= HTTP_WAITING
;
5349 * Wait a maximum of 1 second for data...
5352 if (!http
->blocking
)
5355 * Wait up to 10 seconds for more data on non-blocking sockets...
5358 if (!httpWait(http
, 10000))
5369 if ((bytes
= httpRead2(http
, (char *)buffer
, length
- tbytes
)) < 0)
5374 if (errno
!= EAGAIN
&& errno
!= EINTR
)
5380 else if (bytes
== 0)
5386 * Return the number of bytes read...
5389 if (tbytes
== 0 && bytes
< 0)
5392 DEBUG_printf(("8ipp_read_http: Returning %d bytes", tbytes
));
5399 * 'ipp_read_file()' - Read IPP data from a file.
5402 static ssize_t
/* O - Number of bytes read */
5403 ipp_read_file(int *fd
, /* I - File descriptor */
5404 ipp_uchar_t
*buffer
, /* O - Read buffer */
5405 size_t length
) /* I - Number of bytes to read */
5408 return ((ssize_t
)read(*fd
, buffer
, (unsigned)length
));
5410 return (read(*fd
, buffer
, length
));
5416 * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
5420 static _ipp_value_t
* /* O - IPP value element or NULL on error */
5421 ipp_set_value(ipp_t
*ipp
, /* IO - IPP message */
5422 ipp_attribute_t
**attr
, /* IO - IPP attribute */
5423 int element
) /* I - Value number (0-based) */
5425 ipp_attribute_t
*temp
, /* New attribute pointer */
5426 *current
, /* Current attribute in list */
5427 *prev
; /* Previous attribute in list */
5428 int alloc_values
; /* Allocated values */
5432 * If we are setting an existing value element, return it...
5437 if (temp
->num_values
<= 1)
5440 alloc_values
= (temp
->num_values
+ IPP_MAX_VALUES
- 1) &
5441 ~(IPP_MAX_VALUES
- 1);
5443 if (element
< alloc_values
)
5445 if (element
>= temp
->num_values
)
5446 temp
->num_values
= element
+ 1;
5448 return (temp
->values
+ element
);
5452 * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
5453 * values when num_values > 1.
5456 if (alloc_values
< IPP_MAX_VALUES
)
5457 alloc_values
= IPP_MAX_VALUES
;
5459 alloc_values
+= IPP_MAX_VALUES
;
5461 DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
5465 * Reallocate memory...
5468 if ((temp
= realloc(temp
, sizeof(ipp_attribute_t
) +
5469 (alloc_values
- 1) * sizeof(_ipp_value_t
))) == NULL
)
5471 _cupsSetHTTPError(HTTP_ERROR
);
5472 DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
5477 * Zero the new memory...
5480 memset(temp
->values
+ temp
->num_values
, 0,
5481 (alloc_values
- temp
->num_values
) * sizeof(_ipp_value_t
));
5486 * Reset pointers in the list...
5489 if (ipp
->current
== *attr
&& ipp
->prev
)
5492 * Use current "previous" pointer...
5500 * Find this attribute in the linked list...
5503 for (prev
= NULL
, current
= ipp
->attrs
;
5504 current
&& current
!= *attr
;
5505 prev
= current
, current
= current
->next
);
5510 * This is a serious error!
5514 _cupsSetError(IPP_INTERNAL_ERROR
,
5515 _("IPP attribute is not a member of the message."), 1);
5516 DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
5526 ipp
->current
= temp
;
5529 if (ipp
->last
== *attr
)
5536 * Return the value element...
5539 if (element
>= temp
->num_values
)
5540 temp
->num_values
= element
+ 1;
5542 return (temp
->values
+ element
);
5547 * 'ipp_write_file()' - Write IPP data to a file.
5550 static ssize_t
/* O - Number of bytes written */
5551 ipp_write_file(int *fd
, /* I - File descriptor */
5552 ipp_uchar_t
*buffer
, /* I - Data to write */
5553 size_t length
) /* I - Number of bytes to write */
5556 return ((ssize_t
)write(*fd
, buffer
, (unsigned)length
));
5558 return (write(*fd
, buffer
, length
));
5564 * End of "$Id: ipp.c 10102 2011-11-02 23:52:39Z mike $".