2 * "$Id: ipp.c 11113 2013-07-10 14:08:39Z msweet $"
4 * Internet Printing Protocol functions for CUPS.
6 * Copyright 2007-2013 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 * ippAddStringf() - Add a formatted string to an IPP message.
37 * ippAddStringfv() - Add a formatted string to an IPP message.
38 * ippAddStrings() - Add language-encoded strings to an IPP message.
39 * ippContainsInteger() - Determine whether an attribute contains the
40 * specified value or is within the list of ranges.
41 * ippContainsString() - Determine whether an attribute contains the
42 * specified string value.
43 * ippCopyAttribute() - Copy an attribute.
44 * ippCopyAttributes() - Copy attributes from one IPP message to another.
45 * ippDateToTime() - Convert from RFC 1903 Date/Time format to UNIX
47 * ippDelete() - Delete an IPP message.
48 * ippDeleteAttribute() - Delete a single attribute in an IPP message.
49 * ippDeleteValues() - Delete values in an attribute.
50 * ippFindAttribute() - Find a named attribute in a request.
51 * ippFindNextAttribute() - Find the next named attribute in a request.
52 * ippFirstAttribute() - Return the first attribute in the message.
53 * ippGetBoolean() - Get a boolean value for an attribute.
54 * ippGetCollection() - Get a collection value for an attribute.
55 * ippGetCount() - Get the number of values in an attribute.
56 * ippGetDate() - Get a date value for an attribute.
57 * ippGetGroupTag() - Get the group associated with an attribute.
58 * ippGetInteger() - Get the integer/enum value for an attribute.
59 * ippGetName() - Get the attribute name.
60 * ippGetOctetString() - Get an octetString value from an IPP attribute.
61 * ippGetOperation() - Get the operation ID in an IPP message.
62 * ippGetRange() - Get a rangeOfInteger value from an attribute.
63 * ippGetRequestId() - Get the request ID from an IPP message.
64 * ippGetResolution() - Get a resolution value for an attribute.
65 * ippGetState() - Get the IPP message state.
66 * ippGetStatusCode() - Get the status code from an IPP response or
68 * ippGetString() - Get the string and optionally the language code
70 * ippGetValueTag() - Get the value tag for an attribute.
71 * ippGetVersion() - Get the major and minor version number from an
73 * ippLength() - Compute the length of an IPP message.
74 * ippNextAttribute() - Return the next attribute in the message.
75 * ippNew() - Allocate a new IPP message.
76 * ippNewRequest() - Allocate a new IPP request message.
77 * ippNewResponse() - Allocate a new IPP response message.
78 * ippRead() - Read data for an IPP message from a HTTP
80 * ippReadFile() - Read data for an IPP message from a file.
81 * ippReadIO() - Read data for an IPP message.
82 * ippSetBoolean() - Set a boolean value in an attribute.
83 * ippSetCollection() - Set a collection value in an attribute.
84 * ippSetDate() - Set a date value in an attribute.
85 * ippSetGroupTag() - Set the group tag of an attribute.
86 * ippSetInteger() - Set an integer or enum value in an attribute.
87 * ippSetName() - Set the name of an attribute.
88 * ippSetOctetString() - Set an octetString value in an IPP attribute.
89 * ippSetOperation() - Set the operation ID in an IPP request message.
90 * ippSetRange() - Set a rangeOfInteger value in an attribute.
91 * ippSetRequestId() - Set the request ID in an IPP message.
92 * ippSetResolution() - Set a resolution value in an attribute.
93 * ippSetState() - Set the current state of the IPP message.
94 * ippSetStatusCode() - Set the status code in an IPP response or event
96 * ippSetString() - Set a string value in an attribute.
97 * ippSetStringf() - Set a formatted string value of an attribute.
98 * ippSetStringf() - Set a formatted string value of an attribute.
99 * ippSetValueTag() - Set the value tag of an attribute.
100 * ippSetVersion() - Set the version number in an IPP message.
101 * ippTimeToDate() - Convert from UNIX time to RFC 1903 format.
102 * ippValidateAttribute() - Validate the contents of an attribute.
103 * ippValidateAttributes() - Validate all attributes in an IPP message.
104 * ippWrite() - Write data for an IPP message to a HTTP
106 * ippWriteFile() - Write data for an IPP message to a file.
107 * ippWriteIO() - Write data for an IPP message.
108 * ipp_add_attr() - Add a new attribute to the message.
109 * ipp_free_values() - Free attribute values.
110 * ipp_get_code() - Convert a C locale/charset name into an IPP
111 * language/charset code.
112 * ipp_lang_code() - Convert a C locale name into an IPP language
114 * ipp_length() - Compute the length of an IPP message or
116 * ipp_read_http() - Semi-blocking read on a HTTP connection...
117 * ipp_read_file() - Read IPP data from a file.
118 * ipp_set_error() - Set a formatted, localized error string.
119 * ipp_set_value() - Get the value element from an attribute,
120 * expanding it as needed.
121 * ipp_write_file() - Write IPP data to a file.
125 * Include necessary headers...
128 #include "cups-private.h"
139 static ipp_attribute_t
*ipp_add_attr(ipp_t
*ipp
, const char *name
,
140 ipp_tag_t group_tag
, ipp_tag_t value_tag
,
142 static void ipp_free_values(ipp_attribute_t
*attr
, int element
,
144 static char *ipp_get_code(const char *locale
, char *buffer
,
146 __attribute__((nonnull(1,2)));
147 static char *ipp_lang_code(const char *locale
, char *buffer
,
149 __attribute__((nonnull(1,2)));
150 static size_t ipp_length(ipp_t
*ipp
, int collection
);
151 static ssize_t
ipp_read_http(http_t
*http
, ipp_uchar_t
*buffer
,
153 static ssize_t
ipp_read_file(int *fd
, ipp_uchar_t
*buffer
,
155 static void ipp_set_error(ipp_status_t status
, const char *format
,
157 static _ipp_value_t
*ipp_set_value(ipp_t
*ipp
, ipp_attribute_t
**attr
,
159 static ssize_t
ipp_write_file(int *fd
, ipp_uchar_t
*buffer
,
164 * '_cupsBufferGet()' - Get a read/write buffer.
167 char * /* O - Buffer */
168 _cupsBufferGet(size_t size
) /* I - Size required */
170 _cups_buffer_t
*buffer
; /* Current buffer */
171 _cups_globals_t
*cg
= _cupsGlobals();
175 for (buffer
= cg
->cups_buffers
; buffer
; buffer
= buffer
->next
)
176 if (!buffer
->used
&& buffer
->size
>= size
)
181 if ((buffer
= malloc(sizeof(_cups_buffer_t
) + size
- 1)) == NULL
)
184 buffer
->next
= cg
->cups_buffers
;
186 cg
->cups_buffers
= buffer
;
196 * '_cupsBufferRelease()' - Release a read/write buffer.
200 _cupsBufferRelease(char *b
) /* I - Buffer to release */
202 _cups_buffer_t
*buffer
; /* Buffer */
206 * Mark this buffer as unused...
209 buffer
= (_cups_buffer_t
*)(b
- offsetof(_cups_buffer_t
, d
));
215 * 'ippAddBoolean()' - Add a boolean attribute to an IPP message.
217 * The @code ipp@ parameter refers to an IPP message previously created using
218 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
220 * The @code group@ parameter specifies the IPP attribute group tag: none
221 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
222 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
223 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
224 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
227 ipp_attribute_t
* /* O - New attribute */
228 ippAddBoolean(ipp_t
*ipp
, /* I - IPP message */
229 ipp_tag_t group
, /* I - IPP group */
230 const char *name
, /* I - Name of attribute */
231 char value
) /* I - Value of attribute */
233 ipp_attribute_t
*attr
; /* New attribute */
236 DEBUG_printf(("ippAddBoolean(ipp=%p, group=%02x(%s), name=\"%s\", value=%d)",
237 ipp
, group
, ippTagString(group
), name
, value
));
240 * Range check input...
243 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
244 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
248 * Create the attribute...
251 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BOOLEAN
, 1)) == NULL
)
254 attr
->values
[0].boolean
= value
;
261 * 'ippAddBooleans()' - Add an array of boolean values.
263 * The @code ipp@ parameter refers to an IPP message previously created using
264 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
266 * The @code group@ parameter specifies the IPP attribute group tag: none
267 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
268 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
269 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
270 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
273 ipp_attribute_t
* /* O - New attribute */
274 ippAddBooleans(ipp_t
*ipp
, /* I - IPP message */
275 ipp_tag_t group
, /* I - IPP group */
276 const char *name
, /* I - Name of attribute */
277 int num_values
, /* I - Number of values */
278 const char *values
) /* I - Values */
280 int i
; /* Looping var */
281 ipp_attribute_t
*attr
; /* New attribute */
282 _ipp_value_t
*value
; /* Current value */
285 DEBUG_printf(("ippAddBooleans(ipp=%p, group=%02x(%s), name=\"%s\", "
286 "num_values=%d, values=%p)", ipp
, group
, ippTagString(group
),
287 name
, num_values
, values
));
290 * Range check input...
293 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
294 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
299 * Create the attribute...
302 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BOOLEAN
, num_values
)) == NULL
)
307 for (i
= num_values
, value
= attr
->values
;
310 value
->boolean
= *values
++;
318 * 'ippAddCollection()' - Add a collection value.
320 * The @code ipp@ parameter refers to an IPP message previously created using
321 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
323 * The @code group@ parameter specifies the IPP attribute group tag: none
324 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
325 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
326 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
327 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
329 * @since CUPS 1.1.19/OS X 10.3@
332 ipp_attribute_t
* /* O - New attribute */
333 ippAddCollection(ipp_t
*ipp
, /* I - IPP message */
334 ipp_tag_t group
, /* I - IPP group */
335 const char *name
, /* I - Name of attribute */
336 ipp_t
*value
) /* I - Value */
338 ipp_attribute_t
*attr
; /* New attribute */
341 DEBUG_printf(("ippAddCollection(ipp=%p, group=%02x(%s), name=\"%s\", "
342 "value=%p)", ipp
, group
, ippTagString(group
), name
, value
));
345 * Range check input...
348 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
349 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
353 * Create the attribute...
356 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BEGIN_COLLECTION
, 1)) == NULL
)
359 attr
->values
[0].collection
= value
;
369 * 'ippAddCollections()' - Add an array of collection values.
371 * The @code ipp@ parameter refers to an IPP message previously created using
372 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
374 * The @code group@ parameter specifies the IPP attribute group tag: none
375 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
376 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
377 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
378 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
380 * @since CUPS 1.1.19/OS X 10.3@
383 ipp_attribute_t
* /* O - New attribute */
385 ipp_t
*ipp
, /* I - IPP message */
386 ipp_tag_t group
, /* I - IPP group */
387 const char *name
, /* I - Name of attribute */
388 int num_values
, /* I - Number of values */
389 const ipp_t
**values
) /* I - Values */
391 int i
; /* Looping var */
392 ipp_attribute_t
*attr
; /* New attribute */
393 _ipp_value_t
*value
; /* Current value */
396 DEBUG_printf(("ippAddCollections(ipp=%p, group=%02x(%s), name=\"%s\", "
397 "num_values=%d, values=%p)", ipp
, group
, ippTagString(group
),
398 name
, num_values
, values
));
401 * Range check input...
404 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
405 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
410 * Create the attribute...
413 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BEGIN_COLLECTION
,
414 num_values
)) == NULL
)
419 for (i
= num_values
, value
= attr
->values
;
423 value
->collection
= (ipp_t
*)*values
++;
424 value
->collection
->use
++;
433 * 'ippAddDate()' - Add a date attribute to an IPP message.
435 * The @code ipp@ parameter refers to an IPP message previously created using
436 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
438 * The @code group@ parameter specifies the IPP attribute group tag: none
439 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
440 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
441 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
442 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
445 ipp_attribute_t
* /* O - New attribute */
446 ippAddDate(ipp_t
*ipp
, /* I - IPP message */
447 ipp_tag_t group
, /* I - IPP group */
448 const char *name
, /* I - Name of attribute */
449 const ipp_uchar_t
*value
) /* I - Value */
451 ipp_attribute_t
*attr
; /* New attribute */
454 DEBUG_printf(("ippAddDate(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)",
455 ipp
, group
, ippTagString(group
), name
, value
));
458 * Range check input...
461 if (!ipp
|| !name
|| !value
|| group
< IPP_TAG_ZERO
||
462 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
466 * Create the attribute...
469 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_DATE
, 1)) == NULL
)
472 memcpy(attr
->values
[0].date
, value
, 11);
479 * 'ippAddInteger()' - Add a integer attribute to an IPP message.
481 * The @code ipp@ parameter refers to an IPP message previously created using
482 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
484 * The @code group@ parameter specifies the IPP attribute group tag: none
485 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
486 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
487 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
488 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
490 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
491 * (@code IPP_TAG_INTEGER@).
494 ipp_attribute_t
* /* O - New attribute */
495 ippAddInteger(ipp_t
*ipp
, /* I - IPP message */
496 ipp_tag_t group
, /* I - IPP group */
497 ipp_tag_t value_tag
, /* I - Type of attribute */
498 const char *name
, /* I - Name of attribute */
499 int value
) /* I - Value of attribute */
501 ipp_attribute_t
*attr
; /* New attribute */
504 DEBUG_printf(("ippAddInteger(ipp=%p, group=%02x(%s), type=%02x(%s), "
505 "name=\"%s\", value=%d)", ipp
, group
, ippTagString(group
),
506 value_tag
, ippTagString(value_tag
), name
, value
));
508 value_tag
&= IPP_TAG_CUPS_MASK
;
511 * Special-case for legacy usage: map out-of-band attributes to new ippAddOutOfBand
515 if (value_tag
>= IPP_TAG_UNSUPPORTED_VALUE
&& value_tag
<= IPP_TAG_ADMINDEFINE
)
516 return (ippAddOutOfBand(ipp
, group
, value_tag
, name
));
519 * Range check input...
523 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
524 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
525 (value_tag
!= IPP_TAG_INTEGER
&& value_tag
!= IPP_TAG_ENUM
))
528 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
529 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
534 * Create the attribute...
537 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, 1)) == NULL
)
540 attr
->values
[0].integer
= value
;
547 * 'ippAddIntegers()' - Add an array of integer values.
549 * The @code ipp@ parameter refers to an IPP message previously created using
550 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
552 * The @code group@ parameter specifies the IPP attribute group tag: none
553 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
554 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
555 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
556 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
558 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
559 * (@code IPP_TAG_INTEGER@).
562 ipp_attribute_t
* /* O - New attribute */
563 ippAddIntegers(ipp_t
*ipp
, /* I - IPP message */
564 ipp_tag_t group
, /* I - IPP group */
565 ipp_tag_t value_tag
, /* I - Type of attribute */
566 const char *name
, /* I - Name of attribute */
567 int num_values
, /* I - Number of values */
568 const int *values
) /* I - Values */
570 int i
; /* Looping var */
571 ipp_attribute_t
*attr
; /* New attribute */
572 _ipp_value_t
*value
; /* Current value */
575 DEBUG_printf(("ippAddIntegers(ipp=%p, group=%02x(%s), type=%02x(%s), "
576 "name=\"%s\", num_values=%d, values=%p)", ipp
,
577 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
578 num_values
, values
));
580 value_tag
&= IPP_TAG_CUPS_MASK
;
583 * Range check input...
587 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
588 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
589 (value_tag
!= IPP_TAG_INTEGER
&& value_tag
!= IPP_TAG_ENUM
) ||
593 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
594 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
600 * Create the attribute...
603 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, num_values
)) == NULL
)
608 for (i
= num_values
, value
= attr
->values
;
611 value
->integer
= *values
++;
619 * 'ippAddOctetString()' - Add an octetString value to an IPP message.
621 * The @code ipp@ parameter refers to an IPP message previously created using
622 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
624 * The @code group@ parameter specifies the IPP attribute group tag: none
625 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
626 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
627 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
628 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
630 * @since CUPS 1.2/OS X 10.5@
633 ipp_attribute_t
* /* O - New attribute */
634 ippAddOctetString(ipp_t
*ipp
, /* I - IPP message */
635 ipp_tag_t group
, /* I - IPP group */
636 const char *name
, /* I - Name of attribute */
637 const void *data
, /* I - octetString data */
638 int datalen
) /* I - Length of data in bytes */
640 ipp_attribute_t
*attr
; /* New attribute */
643 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
644 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
645 datalen
< 0 || datalen
> IPP_MAX_LENGTH
)
648 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_STRING
, 1)) == NULL
)
652 * Initialize the attribute data...
655 attr
->values
[0].unknown
.length
= datalen
;
659 if ((attr
->values
[0].unknown
.data
= malloc(datalen
)) == NULL
)
661 ippDeleteAttribute(ipp
, attr
);
665 memcpy(attr
->values
[0].unknown
.data
, data
, datalen
);
669 * Return the new attribute...
677 * 'ippAddOutOfBand()' - Add an out-of-band value to an IPP message.
679 * The @code ipp@ parameter refers to an IPP message previously created using
680 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
682 * The @code group@ parameter specifies the IPP attribute group tag: none
683 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
684 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
685 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
686 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
688 * Supported out-of-band values include unsupported-value
689 * (@code IPP_TAG_UNSUPPORTED_VALUE@), default (@code IPP_TAG_DEFAULT@), unknown
690 * (@code IPP_TAG_UNKNOWN@), no-value (@code IPP_TAG_NOVALUE@), not-settable
691 * (@code IPP_TAG_NOTSETTABLE@), delete-attribute (@code IPP_TAG_DELETEATTR@), and
692 * admin-define (@code IPP_TAG_ADMINDEFINE@).
694 * @since CUPS 1.6/OS X 10.8@
697 ipp_attribute_t
* /* O - New attribute */
698 ippAddOutOfBand(ipp_t
*ipp
, /* I - IPP message */
699 ipp_tag_t group
, /* I - IPP group */
700 ipp_tag_t value_tag
, /* I - Type of attribute */
701 const char *name
) /* I - Name of attribute */
703 DEBUG_printf(("ippAddOutOfBand(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
704 "name=\"%s\")", ipp
, group
, ippTagString(group
), value_tag
,
705 ippTagString(value_tag
), name
));
707 value_tag
&= IPP_TAG_CUPS_MASK
;
710 * Range check input...
713 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
714 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
715 (value_tag
!= IPP_TAG_UNSUPPORTED_VALUE
&&
716 value_tag
!= IPP_TAG_DEFAULT
&&
717 value_tag
!= IPP_TAG_UNKNOWN
&&
718 value_tag
!= IPP_TAG_NOVALUE
&&
719 value_tag
!= IPP_TAG_NOTSETTABLE
&&
720 value_tag
!= IPP_TAG_DELETEATTR
&&
721 value_tag
!= IPP_TAG_ADMINDEFINE
))
725 * Create the attribute...
728 return (ipp_add_attr(ipp
, name
, group
, value_tag
, 1));
733 * 'ippAddRange()' - Add a range of values to an IPP message.
735 * The @code ipp@ parameter refers to an IPP message previously created using
736 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
738 * The @code group@ parameter specifies the IPP attribute group tag: none
739 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
740 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
741 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
742 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
744 * The @code lower@ parameter must be less than or equal to the @code upper@ parameter.
747 ipp_attribute_t
* /* O - New attribute */
748 ippAddRange(ipp_t
*ipp
, /* I - IPP message */
749 ipp_tag_t group
, /* I - IPP group */
750 const char *name
, /* I - Name of attribute */
751 int lower
, /* I - Lower value */
752 int upper
) /* I - Upper value */
754 ipp_attribute_t
*attr
; /* New attribute */
757 DEBUG_printf(("ippAddRange(ipp=%p, group=%02x(%s), name=\"%s\", lower=%d, "
758 "upper=%d)", ipp
, group
, ippTagString(group
), name
, lower
,
762 * Range check input...
765 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
766 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
770 * Create the attribute...
773 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RANGE
, 1)) == NULL
)
776 attr
->values
[0].range
.lower
= lower
;
777 attr
->values
[0].range
.upper
= upper
;
784 * 'ippAddRanges()' - Add ranges of values to an IPP message.
786 * The @code ipp@ parameter refers to an IPP message previously created using
787 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
789 * The @code group@ parameter specifies the IPP attribute group tag: none
790 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
791 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
792 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
793 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
796 ipp_attribute_t
* /* O - New attribute */
797 ippAddRanges(ipp_t
*ipp
, /* I - IPP message */
798 ipp_tag_t group
, /* I - IPP group */
799 const char *name
, /* I - Name of attribute */
800 int num_values
, /* I - Number of values */
801 const int *lower
, /* I - Lower values */
802 const int *upper
) /* I - Upper values */
804 int i
; /* Looping var */
805 ipp_attribute_t
*attr
; /* New attribute */
806 _ipp_value_t
*value
; /* Current value */
809 DEBUG_printf(("ippAddRanges(ipp=%p, group=%02x(%s), name=\"%s\", "
810 "num_values=%d, lower=%p, upper=%p)", ipp
, group
,
811 ippTagString(group
), name
, num_values
, lower
, upper
));
814 * Range check input...
817 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
818 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
823 * Create the attribute...
826 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RANGE
, num_values
)) == NULL
)
831 for (i
= num_values
, value
= attr
->values
;
835 value
->range
.lower
= *lower
++;
836 value
->range
.upper
= *upper
++;
845 * 'ippAddResolution()' - Add a resolution value to an IPP message.
847 * The @code ipp@ parameter refers to an IPP message previously created using
848 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
850 * The @code group@ parameter specifies the IPP attribute group tag: none
851 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
852 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
853 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
854 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
857 ipp_attribute_t
* /* O - New attribute */
858 ippAddResolution(ipp_t
*ipp
, /* I - IPP message */
859 ipp_tag_t group
, /* I - IPP group */
860 const char *name
, /* I - Name of attribute */
861 ipp_res_t units
, /* I - Units for resolution */
862 int xres
, /* I - X resolution */
863 int yres
) /* I - Y resolution */
865 ipp_attribute_t
*attr
; /* New attribute */
868 DEBUG_printf(("ippAddResolution(ipp=%p, group=%02x(%s), name=\"%s\", "
869 "units=%d, xres=%d, yres=%d)", ipp
, group
,
870 ippTagString(group
), name
, units
, xres
, yres
));
873 * Range check input...
876 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
877 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
878 units
< IPP_RES_PER_INCH
|| units
> IPP_RES_PER_CM
||
879 xres
< 0 || yres
< 0)
883 * Create the attribute...
886 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RESOLUTION
, 1)) == NULL
)
889 attr
->values
[0].resolution
.xres
= xres
;
890 attr
->values
[0].resolution
.yres
= yres
;
891 attr
->values
[0].resolution
.units
= units
;
898 * 'ippAddResolutions()' - Add resolution values to an IPP message.
900 * The @code ipp@ parameter refers to an IPP message previously created using
901 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
903 * The @code group@ parameter specifies the IPP attribute group tag: none
904 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
905 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
906 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
907 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
910 ipp_attribute_t
* /* O - New attribute */
911 ippAddResolutions(ipp_t
*ipp
, /* I - IPP message */
912 ipp_tag_t group
, /* I - IPP group */
913 const char *name
, /* I - Name of attribute */
914 int num_values
,/* I - Number of values */
915 ipp_res_t units
, /* I - Units for resolution */
916 const int *xres
, /* I - X resolutions */
917 const int *yres
) /* I - Y resolutions */
919 int i
; /* Looping var */
920 ipp_attribute_t
*attr
; /* New attribute */
921 _ipp_value_t
*value
; /* Current value */
924 DEBUG_printf(("ippAddResolutions(ipp=%p, group=%02x(%s), name=\"%s\", "
925 "num_value=%d, units=%d, xres=%p, yres=%p)", ipp
, group
,
926 ippTagString(group
), name
, num_values
, units
, xres
, yres
));
929 * Range check input...
932 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
933 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
935 units
< IPP_RES_PER_INCH
|| units
> IPP_RES_PER_CM
)
939 * Create the attribute...
942 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RESOLUTION
, num_values
)) == NULL
)
947 for (i
= num_values
, value
= attr
->values
;
951 value
->resolution
.xres
= *xres
++;
952 value
->resolution
.yres
= *yres
++;
953 value
->resolution
.units
= units
;
962 * 'ippAddSeparator()' - Add a group separator to an IPP message.
964 * The @code ipp@ parameter refers to an IPP message previously created using
965 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
968 ipp_attribute_t
* /* O - New attribute */
969 ippAddSeparator(ipp_t
*ipp
) /* I - IPP message */
971 DEBUG_printf(("ippAddSeparator(ipp=%p)", ipp
));
974 * Range check input...
981 * Create the attribute...
984 return (ipp_add_attr(ipp
, NULL
, IPP_TAG_ZERO
, IPP_TAG_ZERO
, 0));
989 * 'ippAddString()' - Add a language-encoded string to an IPP message.
991 * The @code ipp@ parameter refers to an IPP message previously created using
992 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
994 * The @code group@ parameter specifies the IPP attribute group tag: none
995 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
996 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
997 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
998 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1000 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1001 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1002 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1003 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1004 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1005 * (@code IPP_TAG_URISCHEME@).
1007 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
1008 * textWithLanguage string values and must be @code NULL@ for all other string values.
1011 ipp_attribute_t
* /* O - New attribute */
1012 ippAddString(ipp_t
*ipp
, /* I - IPP message */
1013 ipp_tag_t group
, /* I - IPP group */
1014 ipp_tag_t value_tag
, /* I - Type of attribute */
1015 const char *name
, /* I - Name of attribute */
1016 const char *language
, /* I - Language code */
1017 const char *value
) /* I - Value */
1019 ipp_tag_t temp_tag
; /* Temporary value tag (masked) */
1020 ipp_attribute_t
*attr
; /* New attribute */
1021 char code
[IPP_MAX_LANGUAGE
];
1022 /* Charset/language code buffer */
1025 DEBUG_printf(("ippAddString(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
1026 "name=\"%s\", language=\"%s\", value=\"%s\")", ipp
,
1027 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
1031 * Range check input...
1034 temp_tag
= (ipp_tag_t
)((int)value_tag
& IPP_TAG_CUPS_MASK
);
1037 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1038 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1039 (temp_tag
< IPP_TAG_TEXT
&& temp_tag
!= IPP_TAG_TEXTLANG
&&
1040 temp_tag
!= IPP_TAG_NAMELANG
) || temp_tag
> IPP_TAG_MIMETYPE
)
1043 if ((temp_tag
== IPP_TAG_TEXTLANG
|| temp_tag
== IPP_TAG_NAMELANG
)
1044 != (language
!= NULL
))
1047 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1048 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
1053 * See if we need to map charset, language, or locale values...
1056 if (language
&& ((int)value_tag
& IPP_TAG_CUPS_CONST
) &&
1057 strcmp(language
, ipp_lang_code(language
, code
, sizeof(code
))))
1058 value_tag
= temp_tag
; /* Don't do a fast copy */
1059 else if (value
&& value_tag
== (ipp_tag_t
)(IPP_TAG_CHARSET
| IPP_TAG_CUPS_CONST
) &&
1060 strcmp(value
, ipp_get_code(value
, code
, sizeof(code
))))
1061 value_tag
= temp_tag
; /* Don't do a fast copy */
1062 else if (value
&& value_tag
== (ipp_tag_t
)(IPP_TAG_LANGUAGE
| IPP_TAG_CUPS_CONST
) &&
1063 strcmp(value
, ipp_lang_code(value
, code
, sizeof(code
))))
1064 value_tag
= temp_tag
; /* Don't do a fast copy */
1067 * Create the attribute...
1070 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, 1)) == NULL
)
1074 * Initialize the attribute data...
1077 if ((int)value_tag
& IPP_TAG_CUPS_CONST
)
1079 attr
->values
[0].string
.language
= (char *)language
;
1080 attr
->values
[0].string
.text
= (char *)value
;
1085 attr
->values
[0].string
.language
= _cupsStrAlloc(ipp_lang_code(language
, code
,
1090 if (value_tag
== IPP_TAG_CHARSET
)
1091 attr
->values
[0].string
.text
= _cupsStrAlloc(ipp_get_code(value
, code
,
1093 else if (value_tag
== IPP_TAG_LANGUAGE
)
1094 attr
->values
[0].string
.text
= _cupsStrAlloc(ipp_lang_code(value
, code
,
1097 attr
->values
[0].string
.text
= _cupsStrAlloc(value
);
1106 * 'ippAddStringf()' - Add a formatted string to an IPP message.
1108 * The @code ipp@ parameter refers to an IPP message previously created using
1109 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
1111 * The @code group@ parameter specifies the IPP attribute group tag: none
1112 * (@code IPP_TAG_ZERO@, for member attributes), document
1113 * (@code IPP_TAG_DOCUMENT@), event notification
1114 * (@code IPP_TAG_EVENT_NOTIFICATION@), operation (@code IPP_TAG_OPERATION@),
1115 * printer (@code IPP_TAG_PRINTER@), subscription (@code IPP_TAG_SUBSCRIPTION@),
1116 * or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1118 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1119 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1120 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1121 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1122 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1123 * (@code IPP_TAG_URISCHEME@).
1125 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage
1126 * and textWithLanguage string values and must be @code NULL@ for all other
1129 * The @code format@ parameter uses formatting characters compatible with the
1130 * printf family of standard functions. Additional arguments follow it as
1131 * needed. The formatted string is truncated as needed to the maximum length of
1132 * the corresponding value type.
1134 * @since CUPS 1.7/OS X 10.9@
1137 ipp_attribute_t
* /* O - New attribute */
1138 ippAddStringf(ipp_t
*ipp
, /* I - IPP message */
1139 ipp_tag_t group
, /* I - IPP group */
1140 ipp_tag_t value_tag
, /* I - Type of attribute */
1141 const char *name
, /* I - Name of attribute */
1142 const char *language
, /* I - Language code (@code NULL@ for default) */
1143 const char *format
, /* I - Printf-style format string */
1144 ...) /* I - Additional arguments as needed */
1146 ipp_attribute_t
*attr
; /* New attribute */
1147 va_list ap
; /* Argument pointer */
1150 va_start(ap
, format
);
1151 attr
= ippAddStringfv(ipp
, group
, value_tag
, name
, language
, format
, ap
);
1159 * 'ippAddStringfv()' - Add a formatted string to an IPP message.
1161 * The @code ipp@ parameter refers to an IPP message previously created using
1162 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
1164 * The @code group@ parameter specifies the IPP attribute group tag: none
1165 * (@code IPP_TAG_ZERO@, for member attributes), document
1166 * (@code IPP_TAG_DOCUMENT@), event notification
1167 * (@code IPP_TAG_EVENT_NOTIFICATION@), operation (@code IPP_TAG_OPERATION@),
1168 * printer (@code IPP_TAG_PRINTER@), subscription (@code IPP_TAG_SUBSCRIPTION@),
1169 * or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1171 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1172 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1173 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1174 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1175 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1176 * (@code IPP_TAG_URISCHEME@).
1178 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage
1179 * and textWithLanguage string values and must be @code NULL@ for all other
1182 * The @code format@ parameter uses formatting characters compatible with the
1183 * printf family of standard functions. Additional arguments are passed in the
1184 * stdarg pointer @code ap@. The formatted string is truncated as needed to the
1185 * maximum length of the corresponding value type.
1187 * @since CUPS 1.7/OS X 10.9@
1190 ipp_attribute_t
* /* O - New attribute */
1191 ippAddStringfv(ipp_t
*ipp
, /* I - IPP message */
1192 ipp_tag_t group
, /* I - IPP group */
1193 ipp_tag_t value_tag
, /* I - Type of attribute */
1194 const char *name
, /* I - Name of attribute */
1195 const char *language
, /* I - Language code (@code NULL@ for default) */
1196 const char *format
, /* I - Printf-style format string */
1197 va_list ap
) /* I - Additional arguments */
1199 char buffer
[IPP_MAX_TEXT
+ 4];
1200 /* Formatted text string */
1201 ssize_t bytes
, /* Length of formatted value */
1202 max_bytes
; /* Maximum number of bytes for value */
1206 * Range check input...
1209 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1210 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1211 (value_tag
< IPP_TAG_TEXT
&& value_tag
!= IPP_TAG_TEXTLANG
&&
1212 value_tag
!= IPP_TAG_NAMELANG
) || value_tag
> IPP_TAG_MIMETYPE
||
1216 if ((value_tag
== IPP_TAG_TEXTLANG
|| value_tag
== IPP_TAG_NAMELANG
)
1217 != (language
!= NULL
))
1221 * Format the string...
1224 if (!strcmp(format
, "%s"))
1227 * Optimize the simple case...
1230 const char *s
= va_arg(ap
, char *);
1236 strlcpy(buffer
, s
, sizeof(buffer
));
1241 * Do a full formatting of the message...
1244 if ((bytes
= vsnprintf(buffer
, sizeof(buffer
), format
, ap
)) < 0)
1249 * Limit the length of the string...
1256 case IPP_TAG_TEXTLANG
:
1257 max_bytes
= IPP_MAX_TEXT
;
1261 case IPP_TAG_NAMELANG
:
1262 max_bytes
= IPP_MAX_NAME
;
1265 case IPP_TAG_CHARSET
:
1266 max_bytes
= IPP_MAX_CHARSET
;
1269 case IPP_TAG_KEYWORD
:
1270 max_bytes
= IPP_MAX_KEYWORD
;
1273 case IPP_TAG_LANGUAGE
:
1274 max_bytes
= IPP_MAX_LANGUAGE
;
1277 case IPP_TAG_MIMETYPE
:
1278 max_bytes
= IPP_MAX_MIMETYPE
;
1282 max_bytes
= IPP_MAX_URI
;
1285 case IPP_TAG_URISCHEME
:
1286 max_bytes
= IPP_MAX_URISCHEME
;
1290 if (bytes
>= max_bytes
)
1292 char *bufmax
, /* Buffer at max_bytes */
1293 *bufptr
; /* Pointer into buffer */
1295 bufptr
= buffer
+ strlen(buffer
) - 1;
1296 bufmax
= buffer
+ max_bytes
- 1;
1298 while (bufptr
> bufmax
)
1302 while ((*bufptr
& 0xc0) == 0x80 && bufptr
> buffer
)
1313 * Add the formatted string and return...
1316 return (ippAddString(ipp
, group
, value_tag
, name
, language
, buffer
));
1321 * 'ippAddStrings()' - Add language-encoded strings to an IPP message.
1323 * The @code ipp@ parameter refers to an IPP message previously created using
1324 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
1326 * The @code group@ parameter specifies the IPP attribute group tag: none
1327 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
1328 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
1329 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
1330 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1332 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1333 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1334 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1335 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1336 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1337 * (@code IPP_TAG_URISCHEME@).
1339 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
1340 * textWithLanguage string values and must be @code NULL@ for all other string values.
1343 ipp_attribute_t
* /* O - New attribute */
1345 ipp_t
*ipp
, /* I - IPP message */
1346 ipp_tag_t group
, /* I - IPP group */
1347 ipp_tag_t value_tag
, /* I - Type of attribute */
1348 const char *name
, /* I - Name of attribute */
1349 int num_values
, /* I - Number of values */
1350 const char *language
, /* I - Language code (@code NULL@ for default) */
1351 const char * const *values
) /* I - Values */
1353 int i
; /* Looping var */
1354 ipp_tag_t temp_tag
; /* Temporary value tag (masked) */
1355 ipp_attribute_t
*attr
; /* New attribute */
1356 _ipp_value_t
*value
; /* Current value */
1357 char code
[32]; /* Language/charset value buffer */
1360 DEBUG_printf(("ippAddStrings(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
1361 "name=\"%s\", num_values=%d, language=\"%s\", values=%p)", ipp
,
1362 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
1363 num_values
, language
, values
));
1366 * Range check input...
1369 temp_tag
= (ipp_tag_t
)((int)value_tag
& IPP_TAG_CUPS_MASK
);
1372 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1373 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1374 (temp_tag
< IPP_TAG_TEXT
&& temp_tag
!= IPP_TAG_TEXTLANG
&&
1375 temp_tag
!= IPP_TAG_NAMELANG
) || temp_tag
> IPP_TAG_MIMETYPE
||
1379 if ((temp_tag
== IPP_TAG_TEXTLANG
|| temp_tag
== IPP_TAG_NAMELANG
)
1380 != (language
!= NULL
))
1383 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1384 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1390 * See if we need to map charset, language, or locale values...
1393 if (language
&& ((int)value_tag
& IPP_TAG_CUPS_CONST
) &&
1394 strcmp(language
, ipp_lang_code(language
, code
, sizeof(code
))))
1395 value_tag
= temp_tag
; /* Don't do a fast copy */
1396 else if (values
&& value_tag
== (ipp_tag_t
)(IPP_TAG_CHARSET
| IPP_TAG_CUPS_CONST
))
1398 for (i
= 0; i
< num_values
; i
++)
1399 if (strcmp(values
[i
], ipp_get_code(values
[i
], code
, sizeof(code
))))
1401 value_tag
= temp_tag
; /* Don't do a fast copy */
1405 else if (values
&& value_tag
== (ipp_tag_t
)(IPP_TAG_LANGUAGE
| IPP_TAG_CUPS_CONST
))
1407 for (i
= 0; i
< num_values
; i
++)
1408 if (strcmp(values
[i
], ipp_lang_code(values
[i
], code
, sizeof(code
))))
1410 value_tag
= temp_tag
; /* Don't do a fast copy */
1416 * Create the attribute...
1419 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, num_values
)) == NULL
)
1423 * Initialize the attribute data...
1426 for (i
= num_values
, value
= attr
->values
;
1432 if (value
== attr
->values
)
1434 if ((int)value_tag
& IPP_TAG_CUPS_CONST
)
1435 value
->string
.language
= (char *)language
;
1437 value
->string
.language
= _cupsStrAlloc(ipp_lang_code(language
, code
,
1441 value
->string
.language
= attr
->values
[0].string
.language
;
1446 if ((int)value_tag
& IPP_TAG_CUPS_CONST
)
1447 value
->string
.text
= (char *)*values
++;
1448 else if (value_tag
== IPP_TAG_CHARSET
)
1449 value
->string
.text
= _cupsStrAlloc(ipp_get_code(*values
++, code
, sizeof(code
)));
1450 else if (value_tag
== IPP_TAG_LANGUAGE
)
1451 value
->string
.text
= _cupsStrAlloc(ipp_lang_code(*values
++, code
, sizeof(code
)));
1453 value
->string
.text
= _cupsStrAlloc(*values
++);
1462 * 'ippContainsInteger()' - Determine whether an attribute contains the
1463 * specified value or is within the list of ranges.
1465 * Returns non-zero when the attribute contains either a matching integer or
1466 * enum value, or the value falls within one of the rangeOfInteger values for
1469 * @since CUPS 1.7/OS X 10.9@
1472 int /* O - 1 on a match, 0 on no match */
1474 ipp_attribute_t
*attr
, /* I - Attribute */
1475 int value
) /* I - Integer/enum value */
1477 int i
; /* Looping var */
1478 _ipp_value_t
*avalue
; /* Current attribute value */
1482 * Range check input...
1488 if (attr
->value_tag
!= IPP_TAG_INTEGER
&& attr
->value_tag
!= IPP_TAG_ENUM
&&
1489 attr
->value_tag
!= IPP_TAG_RANGE
)
1496 if (attr
->value_tag
== IPP_TAG_RANGE
)
1498 for (i
= attr
->num_values
, avalue
= attr
->values
; i
> 0; i
--, avalue
++)
1499 if (value
>= avalue
->range
.lower
&& value
<= avalue
->range
.upper
)
1504 for (i
= attr
->num_values
, avalue
= attr
->values
; i
> 0; i
--, avalue
++)
1505 if (value
== avalue
->integer
)
1514 * 'ippContainsString()' - Determine whether an attribute contains the
1515 * specified string value.
1517 * Returns non-zero when the attribute contains a matching charset, keyword,
1518 * language, mimeMediaType, name, text, URI, or URI scheme value.
1520 * @since CUPS 1.7/OS X 10.9@
1523 int /* O - 1 on a match, 0 on no match */
1525 ipp_attribute_t
*attr
, /* I - Attribute */
1526 const char *value
) /* I - String value */
1528 int i
; /* Looping var */
1529 _ipp_value_t
*avalue
; /* Current attribute value */
1532 DEBUG_printf(("ippContainsString(attr=%p, value=\"%s\")", attr
, value
));
1535 * Range check input...
1538 if (!attr
|| !value
)
1540 DEBUG_puts("1ippContainsString: Returning 0 (bad input)");
1548 DEBUG_printf(("1ippContainsString: attr %s, %s with %d values.",
1549 attr
->name
, ippTagString(attr
->value_tag
),
1552 switch (attr
->value_tag
& IPP_TAG_CUPS_MASK
)
1554 case IPP_TAG_CHARSET
:
1555 case IPP_TAG_KEYWORD
:
1556 case IPP_TAG_LANGUAGE
:
1557 case IPP_TAG_MIMETYPE
:
1559 case IPP_TAG_NAMELANG
:
1561 case IPP_TAG_TEXTLANG
:
1563 case IPP_TAG_URISCHEME
:
1564 for (i
= attr
->num_values
, avalue
= attr
->values
;
1568 DEBUG_printf(("1ippContainsString: value[%d]=\"%s\"",
1569 attr
->num_values
- i
, avalue
->string
.text
));
1571 if (!strcmp(value
, avalue
->string
.text
))
1573 DEBUG_puts("1ippContainsString: Returning 1 (match)");
1582 DEBUG_puts("1ippContainsString: Returning 0 (no match)");
1589 * 'ippCopyAttribute()' - Copy an attribute.
1591 * The specified attribute, @code attr@, is copied to the destination IPP message.
1592 * When @code quickcopy@ is non-zero, a "shallow" reference copy of the attribute is
1593 * created - this should only be done as long as the original source IPP message will
1594 * not be freed for the life of the destination.
1596 * @since CUPS 1.6/OS X 10.8@
1600 ipp_attribute_t
* /* O - New attribute */
1602 ipp_t
*dst
, /* I - Destination IPP message */
1603 ipp_attribute_t
*srcattr
, /* I - Attribute to copy */
1604 int quickcopy
) /* I - 1 for a referenced copy, 0 for normal */
1606 int i
; /* Looping var */
1607 ipp_attribute_t
*dstattr
; /* Destination attribute */
1608 _ipp_value_t
*srcval
, /* Source value */
1609 *dstval
; /* Destination value */
1612 DEBUG_printf(("ippCopyAttribute(dst=%p, srcattr=%p, quickcopy=%d)", dst
, srcattr
,
1616 * Range check input...
1619 if (!dst
|| !srcattr
)
1626 quickcopy
= quickcopy
? IPP_TAG_CUPS_CONST
: 0;
1628 switch (srcattr
->value_tag
& ~IPP_TAG_CUPS_CONST
)
1631 dstattr
= ippAddSeparator(dst
);
1634 case IPP_TAG_INTEGER
:
1636 dstattr
= ippAddIntegers(dst
, srcattr
->group_tag
, srcattr
->value_tag
,
1637 srcattr
->name
, srcattr
->num_values
, NULL
);
1641 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1643 i
--, srcval
++, dstval
++)
1644 dstval
->integer
= srcval
->integer
;
1647 case IPP_TAG_BOOLEAN
:
1648 dstattr
= ippAddBooleans(dst
, srcattr
->group_tag
, srcattr
->name
,
1649 srcattr
->num_values
, NULL
);
1653 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1655 i
--, srcval
++, dstval
++)
1656 dstval
->boolean
= srcval
->boolean
;
1661 case IPP_TAG_KEYWORD
:
1663 case IPP_TAG_URISCHEME
:
1664 case IPP_TAG_CHARSET
:
1665 case IPP_TAG_LANGUAGE
:
1666 case IPP_TAG_MIMETYPE
:
1667 dstattr
= ippAddStrings(dst
, srcattr
->group_tag
,
1668 (ipp_tag_t
)(srcattr
->value_tag
| quickcopy
),
1669 srcattr
->name
, srcattr
->num_values
, NULL
, NULL
);
1675 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1676 dstval
= dstattr
->values
;
1678 i
--, srcval
++, dstval
++)
1679 dstval
->string
.text
= srcval
->string
.text
;
1681 else if (srcattr
->value_tag
& IPP_TAG_CUPS_CONST
)
1683 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1684 dstval
= dstattr
->values
;
1686 i
--, srcval
++, dstval
++)
1687 dstval
->string
.text
= _cupsStrAlloc(srcval
->string
.text
);
1691 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1692 dstval
= dstattr
->values
;
1694 i
--, srcval
++, dstval
++)
1695 dstval
->string
.text
= _cupsStrRetain(srcval
->string
.text
);
1700 if (srcattr
->num_values
!= 1)
1703 dstattr
= ippAddDate(dst
, srcattr
->group_tag
, srcattr
->name
,
1704 srcattr
->values
[0].date
);
1707 case IPP_TAG_RESOLUTION
:
1708 dstattr
= ippAddResolutions(dst
, srcattr
->group_tag
, srcattr
->name
,
1709 srcattr
->num_values
, IPP_RES_PER_INCH
,
1714 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1716 i
--, srcval
++, dstval
++)
1718 dstval
->resolution
.xres
= srcval
->resolution
.xres
;
1719 dstval
->resolution
.yres
= srcval
->resolution
.yres
;
1720 dstval
->resolution
.units
= srcval
->resolution
.units
;
1724 case IPP_TAG_RANGE
:
1725 dstattr
= ippAddRanges(dst
, srcattr
->group_tag
, srcattr
->name
,
1726 srcattr
->num_values
, NULL
, NULL
);
1730 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1732 i
--, srcval
++, dstval
++)
1734 dstval
->range
.lower
= srcval
->range
.lower
;
1735 dstval
->range
.upper
= srcval
->range
.upper
;
1739 case IPP_TAG_TEXTLANG
:
1740 case IPP_TAG_NAMELANG
:
1741 dstattr
= ippAddStrings(dst
, srcattr
->group_tag
,
1742 (ipp_tag_t
)(srcattr
->value_tag
| quickcopy
),
1743 srcattr
->name
, srcattr
->num_values
, NULL
, NULL
);
1749 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1750 dstval
= dstattr
->values
;
1752 i
--, srcval
++, dstval
++)
1754 dstval
->string
.language
= srcval
->string
.language
;
1755 dstval
->string
.text
= srcval
->string
.text
;
1758 else if (srcattr
->value_tag
& IPP_TAG_CUPS_CONST
)
1760 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1761 dstval
= dstattr
->values
;
1763 i
--, srcval
++, dstval
++)
1765 if (srcval
== srcattr
->values
)
1766 dstval
->string
.language
= _cupsStrAlloc(srcval
->string
.language
);
1768 dstval
->string
.language
= dstattr
->values
[0].string
.language
;
1770 dstval
->string
.text
= _cupsStrAlloc(srcval
->string
.text
);
1775 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1776 dstval
= dstattr
->values
;
1778 i
--, srcval
++, dstval
++)
1780 if (srcval
== srcattr
->values
)
1781 dstval
->string
.language
= _cupsStrRetain(srcval
->string
.language
);
1783 dstval
->string
.language
= dstattr
->values
[0].string
.language
;
1785 dstval
->string
.text
= _cupsStrRetain(srcval
->string
.text
);
1790 case IPP_TAG_BEGIN_COLLECTION
:
1791 dstattr
= ippAddCollections(dst
, srcattr
->group_tag
, srcattr
->name
,
1792 srcattr
->num_values
, NULL
);
1796 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1798 i
--, srcval
++, dstval
++)
1800 dstval
->collection
= srcval
->collection
;
1801 srcval
->collection
->use
++;
1805 case IPP_TAG_STRING
:
1807 /* TODO: Implement quick copy for unknown/octetString values */
1808 dstattr
= ippAddIntegers(dst
, srcattr
->group_tag
, srcattr
->value_tag
,
1809 srcattr
->name
, srcattr
->num_values
, NULL
);
1813 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1815 i
--, srcval
++, dstval
++)
1817 dstval
->unknown
.length
= srcval
->unknown
.length
;
1819 if (dstval
->unknown
.length
> 0)
1821 if ((dstval
->unknown
.data
= malloc(dstval
->unknown
.length
)) == NULL
)
1822 dstval
->unknown
.length
= 0;
1824 memcpy(dstval
->unknown
.data
, srcval
->unknown
.data
, dstval
->unknown
.length
);
1827 break; /* anti-compiler-warning-code */
1835 * 'ippCopyAttributes()' - Copy attributes from one IPP message to another.
1837 * Zero or more attributes are copied from the source IPP message, @code@ src, to the
1838 * destination IPP message, @code dst@. When @code quickcopy@ is non-zero, a "shallow"
1839 * reference copy of the attribute is created - this should only be done as long as the
1840 * original source IPP message will not be freed for the life of the destination.
1842 * The @code cb@ and @code context@ parameters provide a generic way to "filter" the
1843 * attributes that are copied - the function must return 1 to copy the attribute or
1844 * 0 to skip it. The function may also choose to do a partial copy of the source attribute
1847 * @since CUPS 1.6/OS X 10.8@
1850 int /* O - 1 on success, 0 on error */
1852 ipp_t
*dst
, /* I - Destination IPP message */
1853 ipp_t
*src
, /* I - Source IPP message */
1854 int quickcopy
, /* I - 1 for a referenced copy, 0 for normal */
1855 ipp_copycb_t cb
, /* I - Copy callback or @code NULL@ for none */
1856 void *context
) /* I - Context pointer */
1858 ipp_attribute_t
*srcattr
; /* Source attribute */
1861 DEBUG_printf(("ippCopyAttributes(dst=%p, src=%p, quickcopy=%d, cb=%p, context=%p)",
1862 dst
, src
, quickcopy
, cb
, context
));
1865 * Range check input...
1872 * Loop through source attributes and copy as needed...
1875 for (srcattr
= src
->attrs
; srcattr
; srcattr
= srcattr
->next
)
1876 if (!cb
|| (*cb
)(context
, dst
, srcattr
))
1877 if (!ippCopyAttribute(dst
, srcattr
, quickcopy
))
1885 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
1889 time_t /* O - UNIX time value */
1890 ippDateToTime(const ipp_uchar_t
*date
) /* I - RFC 1903 date info */
1892 struct tm unixdate
; /* UNIX date/time info */
1893 time_t t
; /* Computed time */
1899 memset(&unixdate
, 0, sizeof(unixdate
));
1902 * RFC-1903 date/time format is:
1904 * Byte(s) Description
1905 * ------- -----------
1906 * 0-1 Year (0 to 65535)
1910 * 5 Minutes (0 to 59)
1911 * 6 Seconds (0 to 60, 60 = "leap second")
1912 * 7 Deciseconds (0 to 9)
1914 * 9 UTC hours (0 to 11)
1915 * 10 UTC minutes (0 to 59)
1918 unixdate
.tm_year
= ((date
[0] << 8) | date
[1]) - 1900;
1919 unixdate
.tm_mon
= date
[2] - 1;
1920 unixdate
.tm_mday
= date
[3];
1921 unixdate
.tm_hour
= date
[4];
1922 unixdate
.tm_min
= date
[5];
1923 unixdate
.tm_sec
= date
[6];
1925 t
= mktime(&unixdate
);
1928 t
+= date
[9] * 3600 + date
[10] * 60;
1930 t
-= date
[9] * 3600 + date
[10] * 60;
1937 * 'ippDelete()' - Delete an IPP message.
1941 ippDelete(ipp_t
*ipp
) /* I - IPP message */
1943 ipp_attribute_t
*attr
, /* Current attribute */
1944 *next
; /* Next attribute */
1947 DEBUG_printf(("ippDelete(ipp=%p)", ipp
));
1956 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= next
)
1960 ipp_free_values(attr
, 0, attr
->num_values
);
1963 _cupsStrFree(attr
->name
);
1973 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
1975 * @since CUPS 1.1.19/OS X 10.3@
1980 ipp_t
*ipp
, /* I - IPP message */
1981 ipp_attribute_t
*attr
) /* I - Attribute to delete */
1983 ipp_attribute_t
*current
, /* Current attribute */
1984 *prev
; /* Previous attribute */
1987 DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p(%s))", ipp
, attr
,
1988 attr
? attr
->name
: "(null)"));
1991 * Range check input...
1998 * Find the attribute in the list...
2003 for (current
= ipp
->attrs
, prev
= NULL
;
2005 prev
= current
, current
= current
->next
)
2006 if (current
== attr
)
2009 * Found it, remove the attribute from the list...
2013 prev
->next
= current
->next
;
2015 ipp
->attrs
= current
->next
;
2017 if (current
== ipp
->last
)
2028 * Free memory used by the attribute...
2031 ipp_free_values(attr
, 0, attr
->num_values
);
2034 _cupsStrFree(attr
->name
);
2041 * 'ippDeleteValues()' - Delete values in an attribute.
2043 * The @code element@ parameter specifies the first value to delete, starting at
2044 * 0. It must be less than the number of values returned by @link ippGetCount@.
2046 * The @code attr@ parameter may be modified as a result of setting the value.
2048 * Deleting all values in an attribute deletes the attribute.
2050 * @since CUPS 1.6/OS X 10.8@
2053 int /* O - 1 on success, 0 on failure */
2055 ipp_t
*ipp
, /* I - IPP message */
2056 ipp_attribute_t
**attr
, /* IO - Attribute */
2057 int element
, /* I - Index of first value to delete (0-based) */
2058 int count
) /* I - Number of values to delete */
2061 * Range check input...
2064 if (!ipp
|| !attr
|| !*attr
||
2065 element
< 0 || element
>= (*attr
)->num_values
|| count
<= 0 ||
2066 (element
+ count
) >= (*attr
)->num_values
)
2070 * If we are deleting all values, just delete the attribute entirely.
2073 if (count
== (*attr
)->num_values
)
2075 ippDeleteAttribute(ipp
, *attr
);
2081 * Otherwise free the values in question and return.
2084 ipp_free_values(*attr
, element
, count
);
2091 * 'ippFindAttribute()' - Find a named attribute in a request.
2094 ipp_attribute_t
* /* O - Matching attribute */
2095 ippFindAttribute(ipp_t
*ipp
, /* I - IPP message */
2096 const char *name
, /* I - Name of attribute */
2097 ipp_tag_t type
) /* I - Type of attribute */
2099 DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", ipp
,
2100 name
, type
, ippTagString(type
)));
2106 * Reset the current pointer...
2109 ipp
->current
= NULL
;
2112 * Search for the attribute...
2115 return (ippFindNextAttribute(ipp
, name
, type
));
2120 * 'ippFindNextAttribute()' - Find the next named attribute in a request.
2123 ipp_attribute_t
* /* O - Matching attribute */
2124 ippFindNextAttribute(ipp_t
*ipp
, /* I - IPP message */
2125 const char *name
, /* I - Name of attribute */
2126 ipp_tag_t type
) /* I - Type of attribute */
2128 ipp_attribute_t
*attr
; /* Current atttribute */
2129 ipp_tag_t value_tag
; /* Value tag */
2132 DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))",
2133 ipp
, name
, type
, ippTagString(type
)));
2140 ipp
->prev
= ipp
->current
;
2141 attr
= ipp
->current
->next
;
2149 for (; attr
!= NULL
; ipp
->prev
= attr
, attr
= attr
->next
)
2151 DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", attr
,
2154 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_CUPS_MASK
);
2156 if (attr
->name
!= NULL
&& _cups_strcasecmp(attr
->name
, name
) == 0 &&
2157 (value_tag
== type
|| type
== IPP_TAG_ZERO
||
2158 (value_tag
== IPP_TAG_TEXTLANG
&& type
== IPP_TAG_TEXT
) ||
2159 (value_tag
== IPP_TAG_NAMELANG
&& type
== IPP_TAG_NAME
)))
2161 ipp
->current
= attr
;
2167 ipp
->current
= NULL
;
2175 * 'ippFirstAttribute()' - Return the first attribute in the message.
2177 * @since CUPS 1.6/OS X 10.8@
2180 ipp_attribute_t
* /* O - First attribute or @code NULL@ if none */
2181 ippFirstAttribute(ipp_t
*ipp
) /* I - IPP message */
2184 * Range check input...
2191 * Return the first attribute...
2194 return (ipp
->current
= ipp
->attrs
);
2199 * 'ippGetBoolean()' - Get a boolean value for an attribute.
2201 * The @code element@ parameter specifies which value to get from 0 to
2202 * @link ippGetCount(attr)@ - 1.
2204 * @since CUPS 1.6/OS X 10.8@
2207 int /* O - Boolean value or -1 on error */
2208 ippGetBoolean(ipp_attribute_t
*attr
, /* I - IPP attribute */
2209 int element
) /* I - Value number (0-based) */
2212 * Range check input...
2215 if (!attr
|| attr
->value_tag
!= IPP_TAG_BOOLEAN
||
2216 element
< 0 || element
>= attr
->num_values
)
2220 * Return the value...
2223 return (attr
->values
[element
].boolean
);
2228 * 'ippGetCollection()' - Get a collection value for an attribute.
2230 * The @code element@ parameter specifies which value to get from 0 to
2231 * @link ippGetCount(attr)@ - 1.
2233 * @since CUPS 1.6/OS X 10.8@
2236 ipp_t
* /* O - Collection value or @code NULL@ on error */
2238 ipp_attribute_t
*attr
, /* I - IPP attribute */
2239 int element
) /* I - Value number (0-based) */
2242 * Range check input...
2245 if (!attr
|| attr
->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
2246 element
< 0 || element
>= attr
->num_values
)
2250 * Return the value...
2253 return (attr
->values
[element
].collection
);
2258 * 'ippGetCount()' - Get the number of values in an attribute.
2260 * @since CUPS 1.6/OS X 10.8@
2263 int /* O - Number of values or -1 on error */
2264 ippGetCount(ipp_attribute_t
*attr
) /* I - IPP attribute */
2267 * Range check input...
2274 * Return the number of values...
2277 return (attr
->num_values
);
2282 * 'ippGetDate()' - Get a date value for an attribute.
2284 * The @code element@ parameter specifies which value to get from 0 to
2285 * @link ippGetCount(attr)@ - 1.
2287 * @since CUPS 1.6/OS X 10.8@
2290 const ipp_uchar_t
* /* O - Date value or @code NULL@ */
2291 ippGetDate(ipp_attribute_t
*attr
, /* I - IPP attribute */
2292 int element
) /* I - Value number (0-based) */
2295 * Range check input...
2298 if (!attr
|| attr
->value_tag
!= IPP_TAG_DATE
||
2299 element
< 0 || element
>= attr
->num_values
)
2303 * Return the value...
2306 return (attr
->values
[element
].date
);
2311 * 'ippGetGroupTag()' - Get the group associated with an attribute.
2313 * @since CUPS 1.6/OS X 10.8@
2316 ipp_tag_t
/* O - Group tag or @code IPP_TAG_ZERO@ on error */
2317 ippGetGroupTag(ipp_attribute_t
*attr
) /* I - IPP attribute */
2320 * Range check input...
2324 return (IPP_TAG_ZERO
);
2327 * Return the group...
2330 return (attr
->group_tag
);
2335 * 'ippGetInteger()' - Get the integer/enum value for an attribute.
2337 * The @code element@ parameter specifies which value to get from 0 to
2338 * @link ippGetCount(attr)@ - 1.
2340 * @since CUPS 1.6/OS X 10.8@
2343 int /* O - Value or -1 on error */
2344 ippGetInteger(ipp_attribute_t
*attr
, /* I - IPP attribute */
2345 int element
) /* I - Value number (0-based) */
2348 * Range check input...
2351 if (!attr
|| (attr
->value_tag
!= IPP_TAG_INTEGER
&& attr
->value_tag
!= IPP_TAG_ENUM
) ||
2352 element
< 0 || element
>= attr
->num_values
)
2356 * Return the value...
2359 return (attr
->values
[element
].integer
);
2364 * 'ippGetName()' - Get the attribute name.
2366 * @since CUPS 1.6/OS X 10.8@
2369 const char * /* O - Attribute name or @code NULL@ for separators */
2370 ippGetName(ipp_attribute_t
*attr
) /* I - IPP attribute */
2373 * Range check input...
2380 * Return the name...
2383 return (attr
->name
);
2388 * 'ippGetOctetString()' - Get an octetString value from an IPP attribute.
2390 * The @code element@ parameter specifies which value to get from 0 to
2391 * @link ippGetCount(attr)@ - 1.
2393 * @since CUPS 1.7/OS X 10.9@
2396 void * /* O - Pointer to octetString data */
2398 ipp_attribute_t
*attr
, /* I - IPP attribute */
2399 int element
, /* I - Value number (0-based) */
2400 int *datalen
) /* O - Length of octetString data */
2403 * Range check input...
2406 if (!attr
|| attr
->value_tag
!= IPP_TAG_STRING
||
2407 element
< 0 || element
>= attr
->num_values
)
2416 * Return the values...
2420 *datalen
= attr
->values
[element
].unknown
.length
;
2422 return (attr
->values
[element
].unknown
.data
);
2427 * 'ippGetOperation()' - Get the operation ID in an IPP message.
2429 * @since CUPS 1.6/OS X 10.8@
2432 ipp_op_t
/* O - Operation ID or -1 on error */
2433 ippGetOperation(ipp_t
*ipp
) /* I - IPP request message */
2436 * Range check input...
2440 return ((ipp_op_t
)-1);
2443 * Return the value...
2446 return (ipp
->request
.op
.operation_id
);
2451 * 'ippGetRange()' - Get a rangeOfInteger value from an attribute.
2453 * The @code element@ parameter specifies which value to get from 0 to
2454 * @link ippGetCount(attr)@ - 1.
2456 * @since CUPS 1.6/OS X 10.8@
2459 int /* O - Lower value of range or -1 */
2460 ippGetRange(ipp_attribute_t
*attr
, /* I - IPP attribute */
2461 int element
, /* I - Value number (0-based) */
2462 int *uppervalue
)/* O - Upper value of range */
2465 * Range check input...
2468 if (!attr
|| attr
->value_tag
!= IPP_TAG_RANGE
||
2469 element
< 0 || element
>= attr
->num_values
)
2478 * Return the values...
2482 *uppervalue
= attr
->values
[element
].range
.upper
;
2484 return (attr
->values
[element
].range
.lower
);
2489 * 'ippGetRequestId()' - Get the request ID from an IPP message.
2491 * @since CUPS 1.6/OS X 10.8@
2494 int /* O - Request ID or -1 on error */
2495 ippGetRequestId(ipp_t
*ipp
) /* I - IPP message */
2498 * Range check input...
2505 * Return the request ID...
2508 return (ipp
->request
.any
.request_id
);
2513 * 'ippGetResolution()' - Get a resolution value for an attribute.
2515 * The @code element@ parameter specifies which value to get from 0 to
2516 * @link ippGetCount(attr)@ - 1.
2518 * @since CUPS 1.6/OS X 10.8@
2521 int /* O - Horizontal/cross feed resolution or -1 */
2523 ipp_attribute_t
*attr
, /* I - IPP attribute */
2524 int element
, /* I - Value number (0-based) */
2525 int *yres
, /* O - Vertical/feed resolution */
2526 ipp_res_t
*units
) /* O - Units for resolution */
2529 * Range check input...
2532 if (!attr
|| attr
->value_tag
!= IPP_TAG_RESOLUTION
||
2533 element
< 0 || element
>= attr
->num_values
)
2537 * Return the value...
2541 *yres
= attr
->values
[element
].resolution
.yres
;
2544 *units
= attr
->values
[element
].resolution
.units
;
2546 return (attr
->values
[element
].resolution
.xres
);
2551 * 'ippGetState()' - Get the IPP message state.
2553 * @since CUPS 1.6/OS X 10.8@
2556 ipp_state_t
/* O - IPP message state value */
2557 ippGetState(ipp_t
*ipp
) /* I - IPP message */
2560 * Range check input...
2564 return (IPP_STATE_IDLE
);
2567 * Return the value...
2570 return (ipp
->state
);
2575 * 'ippGetStatusCode()' - Get the status code from an IPP response or event message.
2577 * @since CUPS 1.6/OS X 10.8@
2580 ipp_status_t
/* O - Status code in IPP message */
2581 ippGetStatusCode(ipp_t
*ipp
) /* I - IPP response or event message */
2584 * Range check input...
2588 return (IPP_STATUS_ERROR_INTERNAL
);
2591 * Return the value...
2594 return (ipp
->request
.status
.status_code
);
2599 * 'ippGetString()' - Get the string and optionally the language code for an attribute.
2601 * The @code element@ parameter specifies which value to get from 0 to
2602 * @link ippGetCount(attr)@ - 1.
2604 * @since CUPS 1.6/OS X 10.8@
2608 ippGetString(ipp_attribute_t
*attr
, /* I - IPP attribute */
2609 int element
, /* I - Value number (0-based) */
2610 const char **language
)/* O - Language code (@code NULL@ for don't care) */
2613 * Range check input...
2616 if (!attr
|| element
< 0 || element
>= attr
->num_values
||
2617 (attr
->value_tag
!= IPP_TAG_TEXTLANG
&& attr
->value_tag
!= IPP_TAG_NAMELANG
&&
2618 (attr
->value_tag
< IPP_TAG_TEXT
|| attr
->value_tag
> IPP_TAG_MIMETYPE
)))
2622 * Return the value...
2626 *language
= attr
->values
[element
].string
.language
;
2628 return (attr
->values
[element
].string
.text
);
2633 * 'ippGetValueTag()' - Get the value tag for an attribute.
2635 * @since CUPS 1.6/OS X 10.8@
2638 ipp_tag_t
/* O - Value tag or @code IPP_TAG_ZERO@ on error */
2639 ippGetValueTag(ipp_attribute_t
*attr
) /* I - IPP attribute */
2642 * Range check input...
2646 return (IPP_TAG_ZERO
);
2649 * Return the value...
2652 return (attr
->value_tag
& IPP_TAG_CUPS_MASK
);
2657 * 'ippGetVersion()' - Get the major and minor version number from an IPP message.
2659 * @since CUPS 1.6/OS X 10.8@
2662 int /* O - Major version number or -1 on error */
2663 ippGetVersion(ipp_t
*ipp
, /* I - IPP message */
2664 int *minor
) /* O - Minor version number or @code NULL@ */
2667 * Range check input...
2679 * Return the value...
2683 *minor
= ipp
->request
.any
.version
[1];
2685 return (ipp
->request
.any
.version
[0]);
2690 * 'ippLength()' - Compute the length of an IPP message.
2693 size_t /* O - Size of IPP message */
2694 ippLength(ipp_t
*ipp
) /* I - IPP message */
2696 return (ipp_length(ipp
, 0));
2701 * 'ippNextAttribute()' - Return the next attribute in the message.
2703 * @since CUPS 1.6/OS X 10.8@
2706 ipp_attribute_t
* /* O - Next attribute or @code NULL@ if none */
2707 ippNextAttribute(ipp_t
*ipp
) /* I - IPP message */
2710 * Range check input...
2713 if (!ipp
|| !ipp
->current
)
2717 * Return the next attribute...
2720 return (ipp
->current
= ipp
->current
->next
);
2725 * 'ippNew()' - Allocate a new IPP message.
2728 ipp_t
* /* O - New IPP message */
2731 ipp_t
*temp
; /* New IPP message */
2732 _cups_globals_t
*cg
= _cupsGlobals();
2736 DEBUG_puts("ippNew()");
2738 if ((temp
= (ipp_t
*)calloc(1, sizeof(ipp_t
))) != NULL
)
2741 * Set default version - usually 2.0...
2744 if (cg
->server_version
== 0)
2747 temp
->request
.any
.version
[0] = cg
->server_version
/ 10;
2748 temp
->request
.any
.version
[1] = cg
->server_version
% 10;
2752 DEBUG_printf(("1ippNew: Returning %p", temp
));
2759 * 'ippNewRequest()' - Allocate a new IPP request message.
2761 * The new request message is initialized with the attributes-charset and
2762 * attributes-natural-language attributes added. The
2763 * attributes-natural-language value is derived from the current locale.
2765 * @since CUPS 1.2/OS X 10.5@
2768 ipp_t
* /* O - IPP request message */
2769 ippNewRequest(ipp_op_t op
) /* I - Operation code */
2771 ipp_t
*request
; /* IPP request message */
2772 cups_lang_t
*language
; /* Current language localization */
2773 static int request_id
= 0; /* Current request ID */
2774 static _cups_mutex_t request_mutex
= _CUPS_MUTEX_INITIALIZER
;
2775 /* Mutex for request ID */
2778 DEBUG_printf(("ippNewRequest(op=%02x(%s))", op
, ippOpString(op
)));
2781 * Create a new IPP message...
2784 if ((request
= ippNew()) == NULL
)
2788 * Set the operation and request ID...
2791 _cupsMutexLock(&request_mutex
);
2793 request
->request
.op
.operation_id
= op
;
2794 request
->request
.op
.request_id
= ++request_id
;
2796 _cupsMutexUnlock(&request_mutex
);
2799 * Use UTF-8 as the character set...
2802 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2803 "attributes-charset", NULL
, "utf-8");
2806 * Get the language from the current locale...
2809 language
= cupsLangDefault();
2811 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2812 "attributes-natural-language", NULL
, language
->language
);
2815 * Return the new request...
2823 * 'ippNewResponse()' - Allocate a new IPP response message.
2825 * The new response message is initialized with the same version-number,
2826 * request-id, attributes-charset, and attributes-natural-language as the
2827 * provided request message. If the attributes-charset or
2828 * attributes-natural-language attributes are missing from the request,
2829 * "utf-8" and a value derived from the current locale are substituted,
2832 * @since CUPS 1.7/OS X 10.9@
2835 ipp_t
* /* O - IPP response message */
2836 ippNewResponse(ipp_t
*request
) /* I - IPP request message */
2838 ipp_t
*response
; /* IPP response message */
2839 ipp_attribute_t
*attr
; /* Current attribute */
2843 * Range check input...
2850 * Create a new IPP message...
2853 if ((response
= ippNew()) == NULL
)
2857 * Copy the request values over to the response...
2860 response
->request
.status
.version
[0] = request
->request
.op
.version
[0];
2861 response
->request
.status
.version
[1] = request
->request
.op
.version
[1];
2862 response
->request
.status
.request_id
= request
->request
.op
.request_id
;
2865 * The first attribute MUST be attributes-charset...
2868 attr
= request
->attrs
;
2870 if (attr
&& attr
->name
&& !strcmp(attr
->name
, "attributes-charset") &&
2871 attr
->group_tag
== IPP_TAG_OPERATION
&&
2872 attr
->value_tag
== IPP_TAG_CHARSET
&&
2873 attr
->num_values
== 1)
2876 * Copy charset from request...
2879 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2880 "attributes-charset", NULL
, attr
->values
[0].string
.text
);
2885 * Use "utf-8" as the default...
2888 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2889 "attributes-charset", NULL
, "utf-8");
2893 * Then attributes-natural-language...
2899 if (attr
&& attr
->name
&&
2900 !strcmp(attr
->name
, "attributes-natural-language") &&
2901 attr
->group_tag
== IPP_TAG_OPERATION
&&
2902 attr
->value_tag
== IPP_TAG_LANGUAGE
&&
2903 attr
->num_values
== 1)
2906 * Copy language from request...
2909 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2910 "attributes-natural-language", NULL
,
2911 attr
->values
[0].string
.text
);
2916 * Use the language from the current locale...
2919 cups_lang_t
*language
= cupsLangDefault();
2920 /* Current locale */
2922 ippAddString(response
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2923 "attributes-natural-language", NULL
, language
->language
);
2931 * 'ippRead()' - Read data for an IPP message from a HTTP connection.
2934 ipp_state_t
/* O - Current state */
2935 ippRead(http_t
*http
, /* I - HTTP connection */
2936 ipp_t
*ipp
) /* I - IPP data */
2938 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT
,
2939 http
, ipp
, CUPS_LLCAST (http
? http
->data_remaining
: -1)));
2942 return (IPP_STATE_ERROR
);
2944 DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http
->state
,
2947 return (ippReadIO(http
, (ipp_iocb_t
)ipp_read_http
, http
->blocking
, NULL
,
2953 * 'ippReadFile()' - Read data for an IPP message from a file.
2955 * @since CUPS 1.1.19/OS X 10.3@
2958 ipp_state_t
/* O - Current state */
2959 ippReadFile(int fd
, /* I - HTTP data */
2960 ipp_t
*ipp
) /* I - IPP data */
2962 DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd
, ipp
));
2964 return (ippReadIO(&fd
, (ipp_iocb_t
)ipp_read_file
, 1, NULL
, ipp
));
2969 * 'ippReadIO()' - Read data for an IPP message.
2971 * @since CUPS 1.2/OS X 10.5@
2974 ipp_state_t
/* O - Current state */
2975 ippReadIO(void *src
, /* I - Data source */
2976 ipp_iocb_t cb
, /* I - Read callback function */
2977 int blocking
, /* I - Use blocking IO? */
2978 ipp_t
*parent
, /* I - Parent request, if any */
2979 ipp_t
*ipp
) /* I - IPP data */
2981 int n
; /* Length of data */
2982 unsigned char *buffer
, /* Data buffer */
2983 string
[IPP_MAX_TEXT
],
2984 /* Small string buffer */
2985 *bufptr
; /* Pointer into buffer */
2986 ipp_attribute_t
*attr
; /* Current attribute */
2987 ipp_tag_t tag
; /* Current tag */
2988 ipp_tag_t value_tag
; /* Current value tag */
2989 _ipp_value_t
*value
; /* Current value */
2992 DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
2993 src
, cb
, blocking
, parent
, ipp
));
2994 DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp
? ipp
->state
: IPP_STATE_ERROR
));
2997 return (IPP_STATE_ERROR
);
2999 if ((buffer
= (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE
)) == NULL
)
3001 DEBUG_puts("1ippReadIO: Unable to get read buffer.");
3002 return (IPP_STATE_ERROR
);
3007 case IPP_STATE_IDLE
:
3008 ipp
->state
++; /* Avoid common problem... */
3010 case IPP_STATE_HEADER
:
3014 * Get the request header...
3017 if ((*cb
)(src
, buffer
, 8) < 8)
3019 DEBUG_puts("1ippReadIO: Unable to read header.");
3020 _cupsBufferRelease((char *)buffer
);
3021 return (IPP_STATE_ERROR
);
3025 * Then copy the request header over...
3028 ipp
->request
.any
.version
[0] = buffer
[0];
3029 ipp
->request
.any
.version
[1] = buffer
[1];
3030 ipp
->request
.any
.op_status
= (buffer
[2] << 8) | buffer
[3];
3031 ipp
->request
.any
.request_id
= (((((buffer
[4] << 8) | buffer
[5]) << 8) |
3032 buffer
[6]) << 8) | buffer
[7];
3034 DEBUG_printf(("2ippReadIO: version=%d.%d", buffer
[0], buffer
[1]));
3035 DEBUG_printf(("2ippReadIO: op_status=%04x",
3036 ipp
->request
.any
.op_status
));
3037 DEBUG_printf(("2ippReadIO: request_id=%d",
3038 ipp
->request
.any
.request_id
));
3041 ipp
->state
= IPP_STATE_ATTRIBUTE
;
3042 ipp
->current
= NULL
;
3043 ipp
->curtag
= IPP_TAG_ZERO
;
3044 ipp
->prev
= ipp
->last
;
3047 * If blocking is disabled, stop here...
3053 case IPP_STATE_ATTRIBUTE
:
3056 if ((*cb
)(src
, buffer
, 1) < 1)
3058 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
3059 _cupsBufferRelease((char *)buffer
);
3060 return (IPP_STATE_ERROR
);
3063 DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p",
3064 ipp
->current
, ipp
->prev
));
3067 * Read this attribute...
3070 tag
= (ipp_tag_t
)buffer
[0];
3071 if (tag
== IPP_TAG_EXTENSION
)
3074 * Read 32-bit "extension" tag...
3077 if ((*cb
)(src
, buffer
, 4) < 1)
3079 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
3080 _cupsBufferRelease((char *)buffer
);
3081 return (IPP_STATE_ERROR
);
3084 tag
= (ipp_tag_t
)((((((buffer
[0] << 8) | buffer
[1]) << 8) |
3085 buffer
[2]) << 8) | buffer
[3]);
3087 if (tag
& IPP_TAG_CUPS_CONST
)
3090 * Fail if the high bit is set in the tag...
3093 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
3094 DEBUG_printf(("1ippReadIO: bad tag 0x%x.", tag
));
3095 _cupsBufferRelease((char *)buffer
);
3096 return (IPP_STATE_ERROR
);
3100 if (tag
== IPP_TAG_END
)
3103 * No more attributes left...
3106 DEBUG_puts("2ippReadIO: IPP_TAG_END.");
3108 ipp
->state
= IPP_STATE_DATA
;
3111 else if (tag
< IPP_TAG_UNSUPPORTED_VALUE
)
3114 * Group tag... Set the current group and continue...
3117 if (ipp
->curtag
== tag
)
3118 ipp
->prev
= ippAddSeparator(ipp
);
3119 else if (ipp
->current
)
3120 ipp
->prev
= ipp
->current
;
3123 ipp
->current
= NULL
;
3124 DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag
,
3125 ippTagString(tag
), ipp
->prev
));
3129 DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag
,
3130 ippTagString(tag
)));
3136 if ((*cb
)(src
, buffer
, 2) < 2)
3138 DEBUG_puts("1ippReadIO: unable to read name length.");
3139 _cupsBufferRelease((char *)buffer
);
3140 return (IPP_STATE_ERROR
);
3143 n
= (buffer
[0] << 8) | buffer
[1];
3145 if (n
>= IPP_BUF_SIZE
)
3147 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP name larger than 32767 bytes."), 1);
3148 DEBUG_printf(("1ippReadIO: bad name length %d.", n
));
3149 _cupsBufferRelease((char *)buffer
);
3150 return (IPP_STATE_ERROR
);
3153 DEBUG_printf(("2ippReadIO: name length=%d", n
));
3155 if (n
== 0 && tag
!= IPP_TAG_MEMBERNAME
&&
3156 tag
!= IPP_TAG_END_COLLECTION
)
3159 * More values for current attribute...
3162 if (ipp
->current
== NULL
)
3164 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP attribute has no name."), 1);
3165 DEBUG_puts("1ippReadIO: Attribute without name and no current.");
3166 _cupsBufferRelease((char *)buffer
);
3167 return (IPP_STATE_ERROR
);
3170 attr
= ipp
->current
;
3171 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_CUPS_MASK
);
3174 * Make sure we aren't adding a new value of a different
3178 if (value_tag
== IPP_TAG_ZERO
)
3181 * Setting the value of a collection member...
3184 attr
->value_tag
= tag
;
3186 else if (value_tag
== IPP_TAG_TEXTLANG
||
3187 value_tag
== IPP_TAG_NAMELANG
||
3188 (value_tag
>= IPP_TAG_TEXT
&&
3189 value_tag
<= IPP_TAG_MIMETYPE
))
3192 * String values can sometimes come across in different
3193 * forms; accept sets of differing values...
3196 if (tag
!= IPP_TAG_TEXTLANG
&& tag
!= IPP_TAG_NAMELANG
&&
3197 (tag
< IPP_TAG_TEXT
|| tag
> IPP_TAG_MIMETYPE
) &&
3198 tag
!= IPP_TAG_NOVALUE
)
3200 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3201 _("IPP 1setOf attribute with incompatible value "
3203 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3204 value_tag
, ippTagString(value_tag
), tag
,
3205 ippTagString(tag
)));
3206 _cupsBufferRelease((char *)buffer
);
3207 return (IPP_STATE_ERROR
);
3210 if (value_tag
!= tag
)
3212 DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.",
3213 attr
->name
, ippTagString(value_tag
), ippTagString(tag
)));
3214 ippSetValueTag(ipp
, &attr
, tag
);
3217 else if (value_tag
== IPP_TAG_INTEGER
||
3218 value_tag
== IPP_TAG_RANGE
)
3221 * Integer and rangeOfInteger values can sometimes be mixed; accept
3222 * sets of differing values...
3225 if (tag
!= IPP_TAG_INTEGER
&& tag
!= IPP_TAG_RANGE
)
3227 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3228 _("IPP 1setOf attribute with incompatible value "
3230 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3231 value_tag
, ippTagString(value_tag
), tag
,
3232 ippTagString(tag
)));
3233 _cupsBufferRelease((char *)buffer
);
3234 return (IPP_STATE_ERROR
);
3237 if (value_tag
== IPP_TAG_INTEGER
&& tag
== IPP_TAG_RANGE
)
3240 * Convert integer values to rangeOfInteger values...
3243 DEBUG_printf(("1ippReadIO: Converting %s attribute to "
3244 "rangeOfInteger.", attr
->name
));
3245 ippSetValueTag(ipp
, &attr
, IPP_TAG_RANGE
);
3248 else if (value_tag
!= tag
)
3250 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3251 _("IPP 1setOf attribute with incompatible value "
3253 DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
3254 value_tag
, ippTagString(value_tag
), tag
,
3255 ippTagString(tag
)));
3256 _cupsBufferRelease((char *)buffer
);
3257 return (IPP_STATE_ERROR
);
3261 * Finally, reallocate the attribute array as needed...
3264 if ((value
= ipp_set_value(ipp
, &attr
, attr
->num_values
)) == NULL
)
3266 _cupsBufferRelease((char *)buffer
);
3267 return (IPP_STATE_ERROR
);
3270 else if (tag
== IPP_TAG_MEMBERNAME
)
3273 * Name must be length 0!
3278 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP member name is not empty."), 1);
3279 DEBUG_puts("1ippReadIO: member name not empty.");
3280 _cupsBufferRelease((char *)buffer
);
3281 return (IPP_STATE_ERROR
);
3285 ipp
->prev
= ipp
->current
;
3287 attr
= ipp
->current
= ipp_add_attr(ipp
, NULL
, ipp
->curtag
, IPP_TAG_ZERO
, 1);
3290 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
3291 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3292 _cupsBufferRelease((char *)buffer
);
3293 return (IPP_STATE_ERROR
);
3296 DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p",
3297 ipp
->current
, ipp
->prev
));
3299 value
= attr
->values
;
3301 else if (tag
!= IPP_TAG_END_COLLECTION
)
3304 * New attribute; read the name and add it...
3307 if ((*cb
)(src
, buffer
, n
) < n
)
3309 DEBUG_puts("1ippReadIO: unable to read name.");
3310 _cupsBufferRelease((char *)buffer
);
3311 return (IPP_STATE_ERROR
);
3317 ipp
->prev
= ipp
->current
;
3319 if ((attr
= ipp
->current
= ipp_add_attr(ipp
, (char *)buffer
, ipp
->curtag
, tag
,
3322 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
3323 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3324 _cupsBufferRelease((char *)buffer
);
3325 return (IPP_STATE_ERROR
);
3328 DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, "
3329 "ipp->prev=%p", buffer
, ipp
->current
, ipp
->prev
));
3331 value
= attr
->values
;
3339 if ((*cb
)(src
, buffer
, 2) < 2)
3341 DEBUG_puts("1ippReadIO: unable to read value length.");
3342 _cupsBufferRelease((char *)buffer
);
3343 return (IPP_STATE_ERROR
);
3346 n
= (buffer
[0] << 8) | buffer
[1];
3347 DEBUG_printf(("2ippReadIO: value length=%d", n
));
3349 if (n
>= IPP_BUF_SIZE
)
3351 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3352 _("IPP value larger than 32767 bytes."), 1);
3353 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
3354 _cupsBufferRelease((char *)buffer
);
3355 return (IPP_STATE_ERROR
);
3360 case IPP_TAG_INTEGER
:
3364 if (tag
== IPP_TAG_INTEGER
)
3365 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3366 _("IPP integer value not 4 bytes."), 1);
3368 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3369 _("IPP enum value not 4 bytes."), 1);
3370 DEBUG_printf(("1ippReadIO: bad integer value length %d.", n
));
3371 _cupsBufferRelease((char *)buffer
);
3372 return (IPP_STATE_ERROR
);
3375 if ((*cb
)(src
, buffer
, 4) < 4)
3377 DEBUG_puts("1ippReadIO: Unable to read integer value.");
3378 _cupsBufferRelease((char *)buffer
);
3379 return (IPP_STATE_ERROR
);
3382 n
= (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
3385 if (attr
->value_tag
== IPP_TAG_RANGE
)
3386 value
->range
.lower
= value
->range
.upper
= n
;
3391 case IPP_TAG_BOOLEAN
:
3394 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP boolean value not 1 byte."),
3396 DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n
));
3397 _cupsBufferRelease((char *)buffer
);
3398 return (IPP_STATE_ERROR
);
3401 if ((*cb
)(src
, buffer
, 1) < 1)
3403 DEBUG_puts("1ippReadIO: Unable to read boolean value.");
3404 _cupsBufferRelease((char *)buffer
);
3405 return (IPP_STATE_ERROR
);
3408 value
->boolean
= buffer
[0];
3411 case IPP_TAG_NOVALUE
:
3412 case IPP_TAG_NOTSETTABLE
:
3413 case IPP_TAG_DELETEATTR
:
3414 case IPP_TAG_ADMINDEFINE
:
3416 * These value types are not supposed to have values, however
3417 * some vendors (Brother) do not implement IPP correctly and so
3418 * we need to map non-empty values to text...
3421 if (attr
->value_tag
== tag
)
3426 attr
->value_tag
= IPP_TAG_TEXT
;
3431 case IPP_TAG_KEYWORD
:
3433 case IPP_TAG_URISCHEME
:
3434 case IPP_TAG_CHARSET
:
3435 case IPP_TAG_LANGUAGE
:
3436 case IPP_TAG_MIMETYPE
:
3439 if ((*cb
)(src
, buffer
, n
) < n
)
3441 DEBUG_puts("1ippReadIO: unable to read string value.");
3442 _cupsBufferRelease((char *)buffer
);
3443 return (IPP_STATE_ERROR
);
3448 value
->string
.text
= _cupsStrAlloc((char *)buffer
);
3449 DEBUG_printf(("2ippReadIO: value=\"%s\"", value
->string
.text
));
3455 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
, _("IPP date value not 11 bytes."), 1);
3456 DEBUG_printf(("1ippReadIO: bad date value length %d.", n
));
3457 _cupsBufferRelease((char *)buffer
);
3458 return (IPP_STATE_ERROR
);
3461 if ((*cb
)(src
, value
->date
, 11) < 11)
3463 DEBUG_puts("1ippReadIO: Unable to read date value.");
3464 _cupsBufferRelease((char *)buffer
);
3465 return (IPP_STATE_ERROR
);
3469 case IPP_TAG_RESOLUTION
:
3472 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3473 _("IPP resolution value not 9 bytes."), 1);
3474 DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n
));
3475 _cupsBufferRelease((char *)buffer
);
3476 return (IPP_STATE_ERROR
);
3479 if ((*cb
)(src
, buffer
, 9) < 9)
3481 DEBUG_puts("1ippReadIO: Unable to read resolution value.");
3482 _cupsBufferRelease((char *)buffer
);
3483 return (IPP_STATE_ERROR
);
3486 value
->resolution
.xres
=
3487 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
3489 value
->resolution
.yres
=
3490 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
3492 value
->resolution
.units
=
3493 (ipp_res_t
)buffer
[8];
3496 case IPP_TAG_RANGE
:
3499 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3500 _("IPP rangeOfInteger value not 8 bytes."), 1);
3501 DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length "
3503 _cupsBufferRelease((char *)buffer
);
3504 return (IPP_STATE_ERROR
);
3507 if ((*cb
)(src
, buffer
, 8) < 8)
3509 DEBUG_puts("1ippReadIO: Unable to read range value.");
3510 _cupsBufferRelease((char *)buffer
);
3511 return (IPP_STATE_ERROR
);
3514 value
->range
.lower
=
3515 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
3517 value
->range
.upper
=
3518 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
3522 case IPP_TAG_TEXTLANG
:
3523 case IPP_TAG_NAMELANG
:
3526 if (tag
== IPP_TAG_TEXTLANG
)
3527 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3528 _("IPP textWithLanguage value less than "
3529 "minimum 4 bytes."), 1);
3531 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3532 _("IPP nameWithLanguage value less than "
3533 "minimum 4 bytes."), 1);
3534 DEBUG_printf(("1ippReadIO: bad stringWithLanguage value "
3536 _cupsBufferRelease((char *)buffer
);
3537 return (IPP_STATE_ERROR
);
3540 if ((*cb
)(src
, buffer
, n
) < n
)
3542 DEBUG_puts("1ippReadIO: Unable to read string w/language "
3544 _cupsBufferRelease((char *)buffer
);
3545 return (IPP_STATE_ERROR
);
3551 * text-with-language and name-with-language are composite
3560 n
= (bufptr
[0] << 8) | bufptr
[1];
3562 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
) ||
3563 n
>= sizeof(string
))
3565 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3566 _("IPP language length overflows value."), 1);
3567 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3569 _cupsBufferRelease((char *)buffer
);
3570 return (IPP_STATE_ERROR
);
3572 else if (n
>= IPP_MAX_LANGUAGE
)
3574 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3575 _("IPP language length too large."), 1);
3576 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3578 _cupsBufferRelease((char *)buffer
);
3579 return (IPP_STATE_ERROR
);
3582 memcpy(string
, bufptr
+ 2, n
);
3585 value
->string
.language
= _cupsStrAlloc((char *)string
);
3588 n
= (bufptr
[0] << 8) | bufptr
[1];
3590 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
))
3592 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3593 _("IPP string length overflows value."), 1);
3594 DEBUG_printf(("1ippReadIO: bad string value length %d.", n
));
3595 _cupsBufferRelease((char *)buffer
);
3596 return (IPP_STATE_ERROR
);
3599 bufptr
[2 + n
] = '\0';
3600 value
->string
.text
= _cupsStrAlloc((char *)bufptr
+ 2);
3603 case IPP_TAG_BEGIN_COLLECTION
:
3605 * Oh, boy, here comes a collection value, so read it...
3608 value
->collection
= ippNew();
3612 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3613 _("IPP begCollection value not 0 bytes."), 1);
3614 DEBUG_puts("1ippReadIO: begCollection tag with value length "
3616 _cupsBufferRelease((char *)buffer
);
3617 return (IPP_STATE_ERROR
);
3620 if (ippReadIO(src
, cb
, 1, ipp
, value
->collection
) == IPP_STATE_ERROR
)
3622 DEBUG_puts("1ippReadIO: Unable to read collection value.");
3623 _cupsBufferRelease((char *)buffer
);
3624 return (IPP_STATE_ERROR
);
3628 case IPP_TAG_END_COLLECTION
:
3629 _cupsBufferRelease((char *)buffer
);
3633 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3634 _("IPP endCollection value not 0 bytes."), 1);
3635 DEBUG_puts("1ippReadIO: endCollection tag with value length "
3637 return (IPP_STATE_ERROR
);
3640 DEBUG_puts("1ippReadIO: endCollection tag...");
3641 return (ipp
->state
= IPP_STATE_DATA
);
3643 case IPP_TAG_MEMBERNAME
:
3645 * The value the name of the member in the collection, which
3646 * we need to carry over...
3651 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3652 _("IPP memberName with no attribute."), 1);
3653 DEBUG_puts("1ippReadIO: Member name without attribute.");
3654 _cupsBufferRelease((char *)buffer
);
3655 return (IPP_STATE_ERROR
);
3659 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3660 _("IPP memberName value is empty."), 1);
3661 DEBUG_puts("1ippReadIO: Empty member name value.");
3662 _cupsBufferRelease((char *)buffer
);
3663 return (IPP_STATE_ERROR
);
3665 else if ((*cb
)(src
, buffer
, n
) < n
)
3667 DEBUG_puts("1ippReadIO: Unable to read member name value.");
3668 _cupsBufferRelease((char *)buffer
);
3669 return (IPP_STATE_ERROR
);
3673 attr
->name
= _cupsStrAlloc((char *)buffer
);
3676 * Since collection members are encoded differently than
3677 * regular attributes, make sure we don't start with an
3681 attr
->num_values
--;
3683 DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr
->name
));
3686 default : /* Other unsupported values */
3687 if (tag
== IPP_TAG_STRING
&& n
> IPP_MAX_LENGTH
)
3689 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
3690 _("IPP octetString length too large."), 1);
3691 DEBUG_printf(("1ippReadIO: bad octetString value length %d.",
3693 _cupsBufferRelease((char *)buffer
);
3694 return (IPP_STATE_ERROR
);
3697 value
->unknown
.length
= n
;
3701 if ((value
->unknown
.data
= malloc(n
)) == NULL
)
3703 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
3704 DEBUG_puts("1ippReadIO: Unable to allocate value");
3705 _cupsBufferRelease((char *)buffer
);
3706 return (IPP_STATE_ERROR
);
3709 if ((*cb
)(src
, value
->unknown
.data
, n
) < n
)
3711 DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
3712 _cupsBufferRelease((char *)buffer
);
3713 return (IPP_STATE_ERROR
);
3717 value
->unknown
.data
= NULL
;
3722 * If blocking is disabled, stop here...
3730 case IPP_STATE_DATA
:
3734 break; /* anti-compiler-warning-code */
3737 DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp
->state
));
3738 _cupsBufferRelease((char *)buffer
);
3740 return (ipp
->state
);
3745 * 'ippSetBoolean()' - Set a boolean value in an attribute.
3747 * The @code ipp@ parameter refers to an IPP message previously created using
3748 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3750 * The @code attr@ parameter may be modified as a result of setting the value.
3752 * The @code element@ parameter specifies which value to set from 0 to
3753 * @link ippGetCount(attr)@.
3755 * @since CUPS 1.6/OS X 10.8@
3758 int /* O - 1 on success, 0 on failure */
3759 ippSetBoolean(ipp_t
*ipp
, /* I - IPP message */
3760 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3761 int element
, /* I - Value number (0-based) */
3762 int boolvalue
)/* I - Boolean value */
3764 _ipp_value_t
*value
; /* Current value */
3768 * Range check input...
3771 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BOOLEAN
||
3772 element
< 0 || element
> (*attr
)->num_values
)
3776 * Set the value and return...
3779 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3780 value
->boolean
= boolvalue
;
3782 return (value
!= NULL
);
3787 * 'ippSetCollection()' - Set a collection value in an attribute.
3789 * The @code ipp@ parameter refers to an IPP message previously created using
3790 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3792 * The @code attr@ parameter may be modified as a result of setting the value.
3794 * The @code element@ parameter specifies which value to set from 0 to
3795 * @link ippGetCount(attr)@.
3797 * @since CUPS 1.6/OS X 10.8@
3800 int /* O - 1 on success, 0 on failure */
3802 ipp_t
*ipp
, /* I - IPP message */
3803 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3804 int element
, /* I - Value number (0-based) */
3805 ipp_t
*colvalue
) /* I - Collection value */
3807 _ipp_value_t
*value
; /* Current value */
3811 * Range check input...
3814 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
3815 element
< 0 || element
> (*attr
)->num_values
|| !colvalue
)
3819 * Set the value and return...
3822 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3824 if (value
->collection
)
3825 ippDelete(value
->collection
);
3827 value
->collection
= colvalue
;
3831 return (value
!= NULL
);
3836 * 'ippSetDate()' - Set a date value in an attribute.
3838 * The @code ipp@ parameter refers to an IPP message previously created using
3839 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3841 * The @code attr@ parameter may be modified as a result of setting the value.
3843 * The @code element@ parameter specifies which value to set from 0 to
3844 * @link ippGetCount(attr)@.
3846 * @since CUPS 1.6/OS X 10.8@
3849 int /* O - 1 on success, 0 on failure */
3850 ippSetDate(ipp_t
*ipp
, /* I - IPP message */
3851 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3852 int element
, /* I - Value number (0-based) */
3853 const ipp_uchar_t
*datevalue
)/* I - Date value */
3855 _ipp_value_t
*value
; /* Current value */
3859 * Range check input...
3862 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_DATE
||
3863 element
< 0 || element
> (*attr
)->num_values
|| !datevalue
)
3867 * Set the value and return...
3870 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3871 memcpy(value
->date
, datevalue
, sizeof(value
->date
));
3873 return (value
!= NULL
);
3878 * 'ippSetGroupTag()' - Set the group tag of an attribute.
3880 * The @code ipp@ parameter refers to an IPP message previously created using
3881 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3883 * The @code attr@ parameter may be modified as a result of setting the value.
3885 * The @code group@ parameter specifies the IPP attribute group tag: none
3886 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
3887 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
3888 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
3889 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
3891 * @since CUPS 1.6/OS X 10.8@
3894 int /* O - 1 on success, 0 on failure */
3896 ipp_t
*ipp
, /* I - IPP message */
3897 ipp_attribute_t
**attr
, /* IO - Attribute */
3898 ipp_tag_t group_tag
) /* I - Group tag */
3901 * Range check input - group tag must be 0x01 to 0x0F, per RFC 2911...
3904 if (!ipp
|| !attr
|| !*attr
||
3905 group_tag
< IPP_TAG_ZERO
|| group_tag
== IPP_TAG_END
||
3906 group_tag
>= IPP_TAG_UNSUPPORTED_VALUE
)
3910 * Set the group tag and return...
3913 (*attr
)->group_tag
= group_tag
;
3920 * 'ippSetInteger()' - Set an integer or enum value in an attribute.
3922 * The @code ipp@ parameter refers to an IPP message previously created using
3923 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3925 * The @code attr@ parameter may be modified as a result of setting the value.
3927 * The @code element@ parameter specifies which value to set from 0 to
3928 * @link ippGetCount(attr)@.
3930 * @since CUPS 1.6/OS X 10.8@
3933 int /* O - 1 on success, 0 on failure */
3934 ippSetInteger(ipp_t
*ipp
, /* I - IPP message */
3935 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3936 int element
, /* I - Value number (0-based) */
3937 int intvalue
) /* I - Integer/enum value */
3939 _ipp_value_t
*value
; /* Current value */
3943 * Range check input...
3946 if (!ipp
|| !attr
|| !*attr
||
3947 ((*attr
)->value_tag
!= IPP_TAG_INTEGER
&& (*attr
)->value_tag
!= IPP_TAG_ENUM
) ||
3948 element
< 0 || element
> (*attr
)->num_values
)
3952 * Set the value and return...
3955 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3956 value
->integer
= intvalue
;
3958 return (value
!= NULL
);
3963 * 'ippSetName()' - Set the name of an attribute.
3965 * The @code ipp@ parameter refers to an IPP message previously created using
3966 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3968 * The @code attr@ parameter may be modified as a result of setting the value.
3970 * @since CUPS 1.6/OS X 10.8@
3973 int /* O - 1 on success, 0 on failure */
3974 ippSetName(ipp_t
*ipp
, /* I - IPP message */
3975 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3976 const char *name
) /* I - Attribute name */
3978 char *temp
; /* Temporary name value */
3982 * Range check input...
3985 if (!ipp
|| !attr
|| !*attr
)
3989 * Set the value and return...
3992 if ((temp
= _cupsStrAlloc(name
)) != NULL
)
3995 _cupsStrFree((*attr
)->name
);
3997 (*attr
)->name
= temp
;
4000 return (temp
!= NULL
);
4005 * 'ippSetOctetString()' - Set an octetString value in an IPP attribute.
4007 * The @code ipp@ parameter refers to an IPP message previously created using
4008 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4010 * The @code attr@ parameter may be modified as a result of setting the value.
4012 * The @code element@ parameter specifies which value to set from 0 to
4013 * @link ippGetCount(attr)@.
4015 * @since CUPS 1.7/OS X 10.9@
4018 int /* O - 1 on success, 0 on failure */
4020 ipp_t
*ipp
, /* I - IPP message */
4021 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4022 int element
, /* I - Value number (0-based) */
4023 const void *data
, /* I - Pointer to octetString data */
4024 int datalen
) /* I - Length of octetString data */
4026 _ipp_value_t
*value
; /* Current value */
4030 * Range check input...
4033 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_STRING
||
4034 element
< 0 || element
> (*attr
)->num_values
||
4035 datalen
< 0 || datalen
> IPP_MAX_LENGTH
)
4039 * Set the value and return...
4042 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4044 if ((int)((*attr
)->value_tag
) & IPP_TAG_CUPS_CONST
)
4047 * Just copy the pointer...
4050 value
->unknown
.data
= (void *)data
;
4051 value
->unknown
.length
= datalen
;
4059 if (value
->unknown
.data
)
4062 * Free previous data...
4065 free(value
->unknown
.data
);
4067 value
->unknown
.data
= NULL
;
4068 value
->unknown
.length
= 0;
4073 void *temp
; /* Temporary data pointer */
4075 if ((temp
= malloc(datalen
)) != NULL
)
4077 memcpy(temp
, data
, datalen
);
4079 value
->unknown
.data
= temp
;
4080 value
->unknown
.length
= datalen
;
4088 return (value
!= NULL
);
4093 * 'ippSetOperation()' - Set the operation ID in an IPP request message.
4095 * The @code ipp@ parameter refers to an IPP message previously created using
4096 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4098 * @since CUPS 1.6/OS X 10.8@
4101 int /* O - 1 on success, 0 on failure */
4102 ippSetOperation(ipp_t
*ipp
, /* I - IPP request message */
4103 ipp_op_t op
) /* I - Operation ID */
4106 * Range check input...
4113 * Set the operation and return...
4116 ipp
->request
.op
.operation_id
= op
;
4123 * 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
4125 * The @code ipp@ parameter refers to an IPP message previously created using
4126 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4128 * The @code attr@ parameter may be modified as a result of setting the value.
4130 * The @code element@ parameter specifies which value to set from 0 to
4131 * @link ippGetCount(attr)@.
4133 * @since CUPS 1.6/OS X 10.8@
4136 int /* O - 1 on success, 0 on failure */
4137 ippSetRange(ipp_t
*ipp
, /* I - IPP message */
4138 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4139 int element
, /* I - Value number (0-based) */
4140 int lowervalue
, /* I - Lower bound for range */
4141 int uppervalue
) /* I - Upper bound for range */
4143 _ipp_value_t
*value
; /* Current value */
4147 * Range check input...
4150 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RANGE
||
4151 element
< 0 || element
> (*attr
)->num_values
|| lowervalue
> uppervalue
)
4155 * Set the value and return...
4158 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4160 value
->range
.lower
= lowervalue
;
4161 value
->range
.upper
= uppervalue
;
4164 return (value
!= NULL
);
4169 * 'ippSetRequestId()' - Set the request ID in an IPP message.
4171 * The @code ipp@ parameter refers to an IPP message previously created using
4172 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4174 * The @code request_id@ parameter must be greater than 0.
4176 * @since CUPS 1.6/OS X 10.8@
4179 int /* O - 1 on success, 0 on failure */
4180 ippSetRequestId(ipp_t
*ipp
, /* I - IPP message */
4181 int request_id
) /* I - Request ID */
4184 * Range check input; not checking request_id values since ipptool wants to send
4185 * invalid values for conformance testing and a bad request_id does not affect the
4186 * encoding of a message...
4193 * Set the request ID and return...
4196 ipp
->request
.any
.request_id
= request_id
;
4203 * 'ippSetResolution()' - Set a resolution value in an attribute.
4205 * The @code ipp@ parameter refers to an IPP message previously created using
4206 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4208 * The @code attr@ parameter may be modified as a result of setting the value.
4210 * The @code element@ parameter specifies which value to set from 0 to
4211 * @link ippGetCount(attr)@.
4213 * @since CUPS 1.6/OS X 10.8@
4216 int /* O - 1 on success, 0 on failure */
4218 ipp_t
*ipp
, /* I - IPP message */
4219 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4220 int element
, /* I - Value number (0-based) */
4221 ipp_res_t unitsvalue
, /* I - Resolution units */
4222 int xresvalue
, /* I - Horizontal/cross feed resolution */
4223 int yresvalue
) /* I - Vertical/feed resolution */
4225 _ipp_value_t
*value
; /* Current value */
4229 * Range check input...
4232 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RESOLUTION
||
4233 element
< 0 || element
> (*attr
)->num_values
|| xresvalue
<= 0 || yresvalue
<= 0 ||
4234 unitsvalue
< IPP_RES_PER_INCH
|| unitsvalue
> IPP_RES_PER_CM
)
4238 * Set the value and return...
4241 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4243 value
->resolution
.units
= unitsvalue
;
4244 value
->resolution
.xres
= xresvalue
;
4245 value
->resolution
.yres
= yresvalue
;
4248 return (value
!= NULL
);
4253 * 'ippSetState()' - Set the current state of the IPP message.
4255 * @since CUPS 1.6/OS X 10.8@
4258 int /* O - 1 on success, 0 on failure */
4259 ippSetState(ipp_t
*ipp
, /* I - IPP message */
4260 ipp_state_t state
) /* I - IPP state value */
4263 * Range check input...
4270 * Set the state and return...
4274 ipp
->current
= NULL
;
4281 * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
4283 * The @code ipp@ parameter refers to an IPP message previously created using
4284 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4286 * @since CUPS 1.6/OS X 10.8@
4289 int /* O - 1 on success, 0 on failure */
4290 ippSetStatusCode(ipp_t
*ipp
, /* I - IPP response or event message */
4291 ipp_status_t status
) /* I - Status code */
4294 * Range check input...
4301 * Set the status code and return...
4304 ipp
->request
.status
.status_code
= status
;
4311 * 'ippSetString()' - Set a string value in an attribute.
4313 * The @code ipp@ parameter refers to an IPP message previously created using
4314 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4316 * The @code attr@ parameter may be modified as a result of setting the value.
4318 * The @code element@ parameter specifies which value to set from 0 to
4319 * @link ippGetCount(attr)@.
4321 * @since CUPS 1.6/OS X 10.8@
4324 int /* O - 1 on success, 0 on failure */
4325 ippSetString(ipp_t
*ipp
, /* I - IPP message */
4326 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4327 int element
, /* I - Value number (0-based) */
4328 const char *strvalue
) /* I - String value */
4330 char *temp
; /* Temporary string */
4331 _ipp_value_t
*value
; /* Current value */
4335 * Range check input...
4338 if (!ipp
|| !attr
|| !*attr
||
4339 ((*attr
)->value_tag
!= IPP_TAG_TEXTLANG
&&
4340 (*attr
)->value_tag
!= IPP_TAG_NAMELANG
&&
4341 ((*attr
)->value_tag
< IPP_TAG_TEXT
||
4342 (*attr
)->value_tag
> IPP_TAG_MIMETYPE
)) ||
4343 element
< 0 || element
> (*attr
)->num_values
|| !strvalue
)
4347 * Set the value and return...
4350 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
4353 value
->string
.language
= (*attr
)->values
[0].string
.language
;
4355 if ((int)((*attr
)->value_tag
) & IPP_TAG_CUPS_CONST
)
4356 value
->string
.text
= (char *)strvalue
;
4357 else if ((temp
= _cupsStrAlloc(strvalue
)) != NULL
)
4359 if (value
->string
.text
)
4360 _cupsStrFree(value
->string
.text
);
4362 value
->string
.text
= temp
;
4368 return (value
!= NULL
);
4373 * 'ippSetStringf()' - Set a formatted string value of an attribute.
4375 * The @code ipp@ parameter refers to an IPP message previously created using
4376 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4378 * The @code attr@ parameter may be modified as a result of setting the value.
4380 * The @code element@ parameter specifies which value to set from 0 to
4381 * @link ippGetCount(attr)@.
4383 * The @code format@ parameter uses formatting characters compatible with the
4384 * printf family of standard functions. Additional arguments follow it as
4385 * needed. The formatted string is truncated as needed to the maximum length of
4386 * the corresponding value type.
4388 * @since CUPS 1.7/OS X 10.9@
4391 int /* O - 1 on success, 0 on failure */
4392 ippSetStringf(ipp_t
*ipp
, /* I - IPP message */
4393 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4394 int element
, /* I - Value number (0-based) */
4395 const char *format
, /* I - Printf-style format string */
4396 ...) /* I - Additional arguments as needed */
4398 int ret
; /* Return value */
4399 va_list ap
; /* Pointer to additional arguments */
4402 va_start(ap
, format
);
4403 ret
= ippSetStringfv(ipp
, attr
, element
, format
, ap
);
4411 * 'ippSetStringf()' - Set a formatted string value of an attribute.
4413 * The @code ipp@ parameter refers to an IPP message previously created using
4414 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4416 * The @code attr@ parameter may be modified as a result of setting the value.
4418 * The @code element@ parameter specifies which value to set from 0 to
4419 * @link ippGetCount(attr)@.
4421 * The @code format@ parameter uses formatting characters compatible with the
4422 * printf family of standard functions. Additional arguments follow it as
4423 * needed. The formatted string is truncated as needed to the maximum length of
4424 * the corresponding value type.
4426 * @since CUPS 1.7/OS X 10.9@
4429 int /* O - 1 on success, 0 on failure */
4430 ippSetStringfv(ipp_t
*ipp
, /* I - IPP message */
4431 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4432 int element
, /* I - Value number (0-based) */
4433 const char *format
, /* I - Printf-style format string */
4434 va_list ap
) /* I - Pointer to additional arguments */
4436 ipp_tag_t value_tag
; /* Value tag */
4437 char buffer
[IPP_MAX_TEXT
+ 4];
4438 /* Formatted text string */
4439 ssize_t bytes
, /* Length of formatted value */
4440 max_bytes
; /* Maximum number of bytes for value */
4444 * Range check input...
4448 value_tag
= (*attr
)->value_tag
& IPP_TAG_CUPS_MASK
;
4450 value_tag
= IPP_TAG_ZERO
;
4452 if (!ipp
|| !attr
|| !*attr
||
4453 (value_tag
< IPP_TAG_TEXT
&& value_tag
!= IPP_TAG_TEXTLANG
&&
4454 value_tag
!= IPP_TAG_NAMELANG
) || value_tag
> IPP_TAG_MIMETYPE
||
4459 * Format the string...
4462 if (!strcmp(format
, "%s"))
4465 * Optimize the simple case...
4468 const char *s
= va_arg(ap
, char *);
4474 strlcpy(buffer
, s
, sizeof(buffer
));
4479 * Do a full formatting of the message...
4482 if ((bytes
= vsnprintf(buffer
, sizeof(buffer
), format
, ap
)) < 0)
4487 * Limit the length of the string...
4494 case IPP_TAG_TEXTLANG
:
4495 max_bytes
= IPP_MAX_TEXT
;
4499 case IPP_TAG_NAMELANG
:
4500 max_bytes
= IPP_MAX_NAME
;
4503 case IPP_TAG_CHARSET
:
4504 max_bytes
= IPP_MAX_CHARSET
;
4507 case IPP_TAG_KEYWORD
:
4508 max_bytes
= IPP_MAX_KEYWORD
;
4511 case IPP_TAG_LANGUAGE
:
4512 max_bytes
= IPP_MAX_LANGUAGE
;
4515 case IPP_TAG_MIMETYPE
:
4516 max_bytes
= IPP_MAX_MIMETYPE
;
4520 max_bytes
= IPP_MAX_URI
;
4523 case IPP_TAG_URISCHEME
:
4524 max_bytes
= IPP_MAX_URISCHEME
;
4528 if (bytes
>= max_bytes
)
4530 char *bufmax
, /* Buffer at max_bytes */
4531 *bufptr
; /* Pointer into buffer */
4533 bufptr
= buffer
+ strlen(buffer
) - 1;
4534 bufmax
= buffer
+ max_bytes
- 1;
4536 while (bufptr
> bufmax
)
4540 while ((*bufptr
& 0xc0) == 0x80 && bufptr
> buffer
)
4551 * Set the formatted string and return...
4554 return (ippSetString(ipp
, attr
, element
, buffer
));
4559 * 'ippSetValueTag()' - Set the value tag of an attribute.
4561 * The @code ipp@ parameter refers to an IPP message previously created using
4562 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4564 * The @code attr@ parameter may be modified as a result of setting the value.
4566 * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger
4567 * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name
4568 * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text
4569 * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage
4570 * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various
4571 * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes
4574 * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language
4575 * code in the "attributes-natural-language" attribute or, if not present, the language
4576 * code for the current locale.
4578 * @since CUPS 1.6/OS X 10.8@
4581 int /* O - 1 on success, 0 on failure */
4583 ipp_t
*ipp
, /* I - IPP message */
4584 ipp_attribute_t
**attr
, /* IO - IPP attribute */
4585 ipp_tag_t value_tag
) /* I - Value tag */
4587 int i
; /* Looping var */
4588 _ipp_value_t
*value
; /* Current value */
4589 int integer
; /* Current integer value */
4590 cups_lang_t
*language
; /* Current language */
4591 char code
[32]; /* Language code */
4592 ipp_tag_t temp_tag
; /* Temporary value tag */
4596 * Range check input...
4599 if (!ipp
|| !attr
|| !*attr
)
4603 * If there is no change, return immediately...
4606 if (value_tag
== (*attr
)->value_tag
)
4610 * Otherwise implement changes as needed...
4613 temp_tag
= (ipp_tag_t
)((int)((*attr
)->value_tag
) & IPP_TAG_CUPS_MASK
);
4617 case IPP_TAG_UNSUPPORTED_VALUE
:
4618 case IPP_TAG_DEFAULT
:
4619 case IPP_TAG_UNKNOWN
:
4620 case IPP_TAG_NOVALUE
:
4621 case IPP_TAG_NOTSETTABLE
:
4622 case IPP_TAG_DELETEATTR
:
4623 case IPP_TAG_ADMINDEFINE
:
4625 * Free any existing values...
4628 if ((*attr
)->num_values
> 0)
4629 ipp_free_values(*attr
, 0, (*attr
)->num_values
);
4632 * Set out-of-band value...
4635 (*attr
)->value_tag
= value_tag
;
4638 case IPP_TAG_RANGE
:
4639 if (temp_tag
!= IPP_TAG_INTEGER
)
4642 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
4646 integer
= value
->integer
;
4647 value
->range
.lower
= value
->range
.upper
= integer
;
4650 (*attr
)->value_tag
= IPP_TAG_RANGE
;
4654 if (temp_tag
!= IPP_TAG_KEYWORD
&& temp_tag
!= IPP_TAG_URI
&&
4655 temp_tag
!= IPP_TAG_URISCHEME
&& temp_tag
!= IPP_TAG_LANGUAGE
&&
4656 temp_tag
!= IPP_TAG_MIMETYPE
)
4659 (*attr
)->value_tag
= (ipp_tag_t
)(IPP_TAG_NAME
| ((*attr
)->value_tag
& IPP_TAG_CUPS_CONST
));
4662 case IPP_TAG_NAMELANG
:
4663 case IPP_TAG_TEXTLANG
:
4664 if (value_tag
== IPP_TAG_NAMELANG
&&
4665 (temp_tag
!= IPP_TAG_NAME
&& temp_tag
!= IPP_TAG_KEYWORD
&&
4666 temp_tag
!= IPP_TAG_URI
&& temp_tag
!= IPP_TAG_URISCHEME
&&
4667 temp_tag
!= IPP_TAG_LANGUAGE
&& temp_tag
!= IPP_TAG_MIMETYPE
))
4670 if (value_tag
== IPP_TAG_TEXTLANG
&& temp_tag
!= IPP_TAG_TEXT
)
4673 if (ipp
->attrs
&& ipp
->attrs
->next
&& ipp
->attrs
->next
->name
&&
4674 !strcmp(ipp
->attrs
->next
->name
, "attributes-natural-language"))
4677 * Use the language code from the IPP message...
4680 (*attr
)->values
[0].string
.language
=
4681 _cupsStrAlloc(ipp
->attrs
->next
->values
[0].string
.text
);
4686 * Otherwise, use the language code corresponding to the locale...
4689 language
= cupsLangDefault();
4690 (*attr
)->values
[0].string
.language
= _cupsStrAlloc(ipp_lang_code(language
->language
,
4695 for (i
= (*attr
)->num_values
- 1, value
= (*attr
)->values
+ 1;
4698 value
->string
.language
= (*attr
)->values
[0].string
.language
;
4700 if ((int)(*attr
)->value_tag
& IPP_TAG_CUPS_CONST
)
4703 * Make copies of all values...
4706 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
4709 value
->string
.text
= _cupsStrAlloc(value
->string
.text
);
4712 (*attr
)->value_tag
= IPP_TAG_NAMELANG
;
4715 case IPP_TAG_KEYWORD
:
4716 if (temp_tag
== IPP_TAG_NAME
|| temp_tag
== IPP_TAG_NAMELANG
)
4717 break; /* Silently "allow" name -> keyword */
4728 * 'ippSetVersion()' - Set the version number in an IPP message.
4730 * The @code ipp@ parameter refers to an IPP message previously created using
4731 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4733 * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
4735 * @since CUPS 1.6/OS X 10.8@
4738 int /* O - 1 on success, 0 on failure */
4739 ippSetVersion(ipp_t
*ipp
, /* I - IPP message */
4740 int major
, /* I - Major version number (major.minor) */
4741 int minor
) /* I - Minor version number (major.minor) */
4744 * Range check input...
4747 if (!ipp
|| major
< 0 || minor
< 0)
4751 * Set the version number...
4754 ipp
->request
.any
.version
[0] = major
;
4755 ipp
->request
.any
.version
[1] = minor
;
4762 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
4765 const ipp_uchar_t
* /* O - RFC-1903 date/time data */
4766 ippTimeToDate(time_t t
) /* I - UNIX time value */
4768 struct tm
*unixdate
; /* UNIX unixdate/time info */
4769 ipp_uchar_t
*date
= _cupsGlobals()->ipp_date
;
4770 /* RFC-1903 date/time data */
4774 * RFC-1903 date/time format is:
4776 * Byte(s) Description
4777 * ------- -----------
4778 * 0-1 Year (0 to 65535)
4782 * 5 Minutes (0 to 59)
4783 * 6 Seconds (0 to 60, 60 = "leap second")
4784 * 7 Deciseconds (0 to 9)
4786 * 9 UTC hours (0 to 11)
4787 * 10 UTC minutes (0 to 59)
4790 unixdate
= gmtime(&t
);
4791 unixdate
->tm_year
+= 1900;
4793 date
[0] = unixdate
->tm_year
>> 8;
4794 date
[1] = unixdate
->tm_year
;
4795 date
[2] = unixdate
->tm_mon
+ 1;
4796 date
[3] = unixdate
->tm_mday
;
4797 date
[4] = unixdate
->tm_hour
;
4798 date
[5] = unixdate
->tm_min
;
4799 date
[6] = unixdate
->tm_sec
;
4810 * 'ippValidateAttribute()' - Validate the contents of an attribute.
4812 * This function validates the contents of an attribute based on the name and
4813 * value tag. 1 is returned if the attribute is valid, 0 otherwise. On
4814 * failure, cupsLastErrorString() is set to a human-readable message.
4816 * @since CUPS 1.7/OS X 10.9@
4819 int /* O - 1 if valid, 0 otherwise */
4820 ippValidateAttribute(
4821 ipp_attribute_t
*attr
) /* I - Attribute */
4823 int i
; /* Looping var */
4824 char scheme
[64], /* Scheme from URI */
4825 userpass
[256], /* Username/password from URI */
4826 hostname
[256], /* Hostname from URI */
4827 resource
[1024]; /* Resource from URI */
4828 int port
, /* Port number from URI */
4829 uri_status
; /* URI separation status */
4830 const char *ptr
; /* Pointer into string */
4831 ipp_attribute_t
*colattr
; /* Collection attribute */
4832 regex_t re
; /* Regular expression */
4833 ipp_uchar_t
*date
; /* Current date value */
4834 static const char * const uri_status_strings
[] =
4835 { /* URI status strings */
4837 "Bad arguments to function",
4838 "Bad resource in URI",
4839 "Bad port number in URI",
4840 "Bad hostname/address in URI",
4841 "Bad username in URI",
4842 "Bad scheme in URI",
4845 "Missing scheme in URI",
4846 "Unknown scheme in URI",
4847 "Missing resource in URI"
4859 * Validate the attribute name.
4862 for (ptr
= attr
->name
; *ptr
; ptr
++)
4863 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' && *ptr
!= '_')
4866 if (*ptr
|| ptr
== attr
->name
)
4868 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4869 _("\"%s\": Bad attribute name - invalid character "
4870 "(RFC 2911 section 4.1.3)."), attr
->name
);
4874 if ((ptr
- attr
->name
) > 255)
4876 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4877 _("\"%s\": Bad attribute name - bad length %d "
4878 "(RFC 2911 section 4.1.3)."), attr
->name
,
4879 (int)(ptr
- attr
->name
));
4883 switch (attr
->value_tag
)
4885 case IPP_TAG_INTEGER
:
4888 case IPP_TAG_BOOLEAN
:
4889 for (i
= 0; i
< attr
->num_values
; i
++)
4891 if (attr
->values
[i
].boolean
!= 0 &&
4892 attr
->values
[i
].boolean
!= 1)
4894 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4895 _("\"%s\": Bad boolen value %d "
4896 "(RFC 2911 section 4.1.11)."), attr
->name
,
4897 attr
->values
[i
].boolean
);
4904 for (i
= 0; i
< attr
->num_values
; i
++)
4906 if (attr
->values
[i
].integer
< 1)
4908 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4909 _("\"%s\": Bad enum value %d - out of range "
4910 "(RFC 2911 section 4.1.4)."), attr
->name
,
4911 attr
->values
[i
].integer
);
4917 case IPP_TAG_STRING
:
4918 for (i
= 0; i
< attr
->num_values
; i
++)
4920 if (attr
->values
[i
].unknown
.length
> IPP_MAX_OCTETSTRING
)
4922 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4923 _("\"%s\": Bad octetString value - bad length %d "
4924 "(RFC 2911 section 4.1.10)."), attr
->name
,
4925 attr
->values
[i
].unknown
.length
);
4932 for (i
= 0; i
< attr
->num_values
; i
++)
4934 date
= attr
->values
[i
].date
;
4936 if (date
[2] < 1 || date
[2] > 12)
4938 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4939 _("\"%s\": Bad dateTime month %u "
4940 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[2]);
4944 if (date
[3] < 1 || date
[3] > 31)
4946 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4947 _("\"%s\": Bad dateTime day %u "
4948 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[3]);
4954 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4955 _("\"%s\": Bad dateTime hours %u "
4956 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[4]);
4962 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4963 _("\"%s\": Bad dateTime minutes %u "
4964 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[5]);
4970 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4971 _("\"%s\": Bad dateTime seconds %u "
4972 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[6]);
4978 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4979 _("\"%s\": Bad dateTime deciseconds %u "
4980 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[7]);
4984 if (date
[8] != '-' && date
[8] != '+')
4986 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4987 _("\"%s\": Bad dateTime UTC sign '%c' "
4988 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[8]);
4994 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
4995 _("\"%s\": Bad dateTime UTC hours %u "
4996 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[9]);
5002 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5003 _("\"%s\": Bad dateTime UTC minutes %u "
5004 "(RFC 2911 section 4.1.14)."), attr
->name
, date
[10]);
5010 case IPP_TAG_RESOLUTION
:
5011 for (i
= 0; i
< attr
->num_values
; i
++)
5013 if (attr
->values
[i
].resolution
.xres
<= 0)
5015 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5016 _("\"%s\": Bad resolution value %dx%d%s - cross "
5017 "feed resolution must be positive "
5018 "(RFC 2911 section 4.1.15)."), attr
->name
,
5019 attr
->values
[i
].resolution
.xres
,
5020 attr
->values
[i
].resolution
.yres
,
5021 attr
->values
[i
].resolution
.units
==
5022 IPP_RES_PER_INCH
? "dpi" :
5023 attr
->values
[i
].resolution
.units
==
5024 IPP_RES_PER_CM
? "dpcm" : "unknown");
5028 if (attr
->values
[i
].resolution
.yres
<= 0)
5030 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5031 _("\"%s\": Bad resolution value %dx%d%s - feed "
5032 "resolution must be positive "
5033 "(RFC 2911 section 4.1.15)."), attr
->name
,
5034 attr
->values
[i
].resolution
.xres
,
5035 attr
->values
[i
].resolution
.yres
,
5036 attr
->values
[i
].resolution
.units
==
5037 IPP_RES_PER_INCH
? "dpi" :
5038 attr
->values
[i
].resolution
.units
==
5039 IPP_RES_PER_CM
? "dpcm" : "unknown");
5043 if (attr
->values
[i
].resolution
.units
!= IPP_RES_PER_INCH
&&
5044 attr
->values
[i
].resolution
.units
!= IPP_RES_PER_CM
)
5046 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5047 _("\"%s\": Bad resolution value %dx%d%s - bad "
5048 "units value (RFC 2911 section 4.1.15)."),
5049 attr
->name
, attr
->values
[i
].resolution
.xres
,
5050 attr
->values
[i
].resolution
.yres
,
5051 attr
->values
[i
].resolution
.units
==
5052 IPP_RES_PER_INCH
? "dpi" :
5053 attr
->values
[i
].resolution
.units
==
5054 IPP_RES_PER_CM
? "dpcm" : "unknown");
5060 case IPP_TAG_RANGE
:
5061 for (i
= 0; i
< attr
->num_values
; i
++)
5063 if (attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
5065 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5066 _("\"%s\": Bad rangeOfInteger value %d-%d - lower "
5067 "greater than upper (RFC 2911 section 4.1.13)."),
5068 attr
->name
, attr
->values
[i
].range
.lower
,
5069 attr
->values
[i
].range
.upper
);
5075 case IPP_TAG_BEGIN_COLLECTION
:
5076 for (i
= 0; i
< attr
->num_values
; i
++)
5078 for (colattr
= attr
->values
[i
].collection
->attrs
;
5080 colattr
= colattr
->next
)
5082 if (!ippValidateAttribute(colattr
))
5089 case IPP_TAG_TEXTLANG
:
5090 for (i
= 0; i
< attr
->num_values
; i
++)
5092 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5094 if ((*ptr
& 0xe0) == 0xc0)
5097 if ((*ptr
& 0xc0) != 0x80)
5100 else if ((*ptr
& 0xf0) == 0xe0)
5103 if ((*ptr
& 0xc0) != 0x80)
5106 if ((*ptr
& 0xc0) != 0x80)
5109 else if ((*ptr
& 0xf8) == 0xf0)
5112 if ((*ptr
& 0xc0) != 0x80)
5115 if ((*ptr
& 0xc0) != 0x80)
5118 if ((*ptr
& 0xc0) != 0x80)
5121 else if (*ptr
& 0x80)
5127 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5128 _("\"%s\": Bad text value \"%s\" - bad UTF-8 "
5129 "sequence (RFC 2911 section 4.1.1)."), attr
->name
,
5130 attr
->values
[i
].string
.text
);
5134 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_TEXT
- 1))
5136 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5137 _("\"%s\": Bad text value \"%s\" - bad length %d "
5138 "(RFC 2911 section 4.1.1)."), attr
->name
,
5139 attr
->values
[i
].string
.text
,
5140 (int)(ptr
- attr
->values
[i
].string
.text
));
5147 case IPP_TAG_NAMELANG
:
5148 for (i
= 0; i
< attr
->num_values
; i
++)
5150 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5152 if ((*ptr
& 0xe0) == 0xc0)
5155 if ((*ptr
& 0xc0) != 0x80)
5158 else if ((*ptr
& 0xf0) == 0xe0)
5161 if ((*ptr
& 0xc0) != 0x80)
5164 if ((*ptr
& 0xc0) != 0x80)
5167 else if ((*ptr
& 0xf8) == 0xf0)
5170 if ((*ptr
& 0xc0) != 0x80)
5173 if ((*ptr
& 0xc0) != 0x80)
5176 if ((*ptr
& 0xc0) != 0x80)
5179 else if (*ptr
& 0x80)
5185 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5186 _("\"%s\": Bad name value \"%s\" - bad UTF-8 "
5187 "sequence (RFC 2911 section 4.1.2)."), attr
->name
,
5188 attr
->values
[i
].string
.text
);
5192 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_NAME
- 1))
5194 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5195 _("\"%s\": Bad name value \"%s\" - bad length %d "
5196 "(RFC 2911 section 4.1.2)."), attr
->name
,
5197 attr
->values
[i
].string
.text
,
5198 (int)(ptr
- attr
->values
[i
].string
.text
));
5204 case IPP_TAG_KEYWORD
:
5205 for (i
= 0; i
< attr
->num_values
; i
++)
5207 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5208 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' &&
5212 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
5214 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5215 _("\"%s\": Bad keyword value \"%s\" - invalid "
5216 "character (RFC 2911 section 4.1.3)."),
5217 attr
->name
, attr
->values
[i
].string
.text
);
5221 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_KEYWORD
- 1))
5223 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5224 _("\"%s\": Bad keyword value \"%s\" - bad "
5225 "length %d (RFC 2911 section 4.1.3)."),
5226 attr
->name
, attr
->values
[i
].string
.text
,
5227 (int)(ptr
- attr
->values
[i
].string
.text
));
5234 for (i
= 0; i
< attr
->num_values
; i
++)
5236 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
,
5237 attr
->values
[i
].string
.text
,
5238 scheme
, sizeof(scheme
),
5239 userpass
, sizeof(userpass
),
5240 hostname
, sizeof(hostname
),
5241 &port
, resource
, sizeof(resource
));
5243 if (uri_status
< HTTP_URI_STATUS_OK
)
5245 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5246 _("\"%s\": Bad URI value \"%s\" - %s "
5247 "(RFC 2911 section 4.1.5)."), attr
->name
,
5248 attr
->values
[i
].string
.text
,
5249 uri_status_strings
[uri_status
-
5250 HTTP_URI_STATUS_OVERFLOW
]);
5254 if (strlen(attr
->values
[i
].string
.text
) > (IPP_MAX_URI
- 1))
5256 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5257 _("\"%s\": Bad URI value \"%s\" - bad length %d "
5258 "(RFC 2911 section 4.1.5)."), attr
->name
,
5259 attr
->values
[i
].string
.text
,
5260 (int)strlen(attr
->values
[i
].string
.text
));
5265 case IPP_TAG_URISCHEME
:
5266 for (i
= 0; i
< attr
->num_values
; i
++)
5268 ptr
= attr
->values
[i
].string
.text
;
5269 if (islower(*ptr
& 255))
5271 for (ptr
++; *ptr
; ptr
++)
5272 if (!islower(*ptr
& 255) && !isdigit(*ptr
& 255) &&
5273 *ptr
!= '+' && *ptr
!= '-' && *ptr
!= '.')
5277 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
5279 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5280 _("\"%s\": Bad uriScheme value \"%s\" - bad "
5281 "characters (RFC 2911 section 4.1.6)."),
5282 attr
->name
, attr
->values
[i
].string
.text
);
5286 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_URISCHEME
- 1))
5288 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5289 _("\"%s\": Bad uriScheme value \"%s\" - bad "
5290 "length %d (RFC 2911 section 4.1.6)."),
5291 attr
->name
, attr
->values
[i
].string
.text
,
5292 (int)(ptr
- attr
->values
[i
].string
.text
));
5298 case IPP_TAG_CHARSET
:
5299 for (i
= 0; i
< attr
->num_values
; i
++)
5301 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
5302 if (!isprint(*ptr
& 255) || isupper(*ptr
& 255) ||
5303 isspace(*ptr
& 255))
5306 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
5308 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5309 _("\"%s\": Bad charset value \"%s\" - bad "
5310 "characters (RFC 2911 section 4.1.7)."),
5311 attr
->name
, attr
->values
[i
].string
.text
);
5315 if ((ptr
- attr
->values
[i
].string
.text
) > (IPP_MAX_CHARSET
- 1))
5317 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5318 _("\"%s\": Bad charset value \"%s\" - bad "
5319 "length %d (RFC 2911 section 4.1.7)."),
5320 attr
->name
, attr
->values
[i
].string
.text
,
5321 (int)(ptr
- attr
->values
[i
].string
.text
));
5327 case IPP_TAG_LANGUAGE
:
5329 * The following regular expression is derived from the ABNF for
5330 * language tags in RFC 4646. All I can say is that this is the
5331 * easiest way to check the values...
5334 if ((i
= regcomp(&re
,
5336 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
5338 "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */
5339 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */
5340 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */
5341 "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */
5342 "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */
5344 "x(-[a-z0-9]{1,8})+" /* privateuse */
5346 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
5348 REG_NOSUB
| REG_EXTENDED
)) != 0)
5350 char temp
[256]; /* Temporary error string */
5352 regerror(i
, &re
, temp
, sizeof(temp
));
5353 ipp_set_error(IPP_STATUS_ERROR_INTERNAL
,
5354 _("Unable to compile naturalLanguage regular "
5355 "expression: %s."), temp
);
5359 for (i
= 0; i
< attr
->num_values
; i
++)
5361 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
5363 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5364 _("\"%s\": Bad naturalLanguage value \"%s\" - bad "
5365 "characters (RFC 2911 section 4.1.8)."),
5366 attr
->name
, attr
->values
[i
].string
.text
);
5371 if (strlen(attr
->values
[i
].string
.text
) > (IPP_MAX_LANGUAGE
- 1))
5373 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5374 _("\"%s\": Bad naturalLanguage value \"%s\" - bad "
5375 "length %d (RFC 2911 section 4.1.8)."),
5376 attr
->name
, attr
->values
[i
].string
.text
,
5377 (int)strlen(attr
->values
[i
].string
.text
));
5386 case IPP_TAG_MIMETYPE
:
5388 * The following regular expression is derived from the ABNF for
5389 * MIME media types in RFC 2045 and 4288. All I can say is that this is
5390 * the easiest way to check the values...
5393 if ((i
= regcomp(&re
,
5395 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
5397 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
5398 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
5399 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
5402 REG_NOSUB
| REG_EXTENDED
)) != 0)
5404 char temp
[256]; /* Temporary error string */
5406 regerror(i
, &re
, temp
, sizeof(temp
));
5407 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5408 _("Unable to compile mimeMediaType regular "
5409 "expression: %s."), temp
);
5413 for (i
= 0; i
< attr
->num_values
; i
++)
5415 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
5417 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5418 _("\"%s\": Bad mimeMediaType value \"%s\" - bad "
5419 "characters (RFC 2911 section 4.1.9)."),
5420 attr
->name
, attr
->values
[i
].string
.text
);
5425 if (strlen(attr
->values
[i
].string
.text
) > (IPP_MAX_MIMETYPE
- 1))
5427 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST
,
5428 _("\"%s\": Bad mimeMediaType value \"%s\" - bad "
5429 "length %d (RFC 2911 section 4.1.9)."),
5430 attr
->name
, attr
->values
[i
].string
.text
,
5431 (int)strlen(attr
->values
[i
].string
.text
));
5449 * 'ippValidateAttributes()' - Validate all attributes in an IPP message.
5451 * This function validates the contents of the IPP message, including each
5452 * attribute. Like @link ippValidateAttribute@, cupsLastErrorString() is set
5453 * to a human-readable message on failure.
5455 * @since CUPS 1.7/OS X 10.9@
5458 int /* O - 1 if valid, 0 otherwise */
5459 ippValidateAttributes(ipp_t
*ipp
) /* I - IPP message */
5461 ipp_attribute_t
*attr
; /* Current attribute */
5467 for (attr
= ipp
->attrs
; attr
; attr
= attr
->next
)
5468 if (!ippValidateAttribute(attr
))
5476 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
5479 ipp_state_t
/* O - Current state */
5480 ippWrite(http_t
*http
, /* I - HTTP connection */
5481 ipp_t
*ipp
) /* I - IPP data */
5483 DEBUG_printf(("ippWrite(http=%p, ipp=%p)", http
, ipp
));
5486 return (IPP_STATE_ERROR
);
5488 return (ippWriteIO(http
, (ipp_iocb_t
)httpWrite2
, http
->blocking
, NULL
, ipp
));
5493 * 'ippWriteFile()' - Write data for an IPP message to a file.
5495 * @since CUPS 1.1.19/OS X 10.3@
5498 ipp_state_t
/* O - Current state */
5499 ippWriteFile(int fd
, /* I - HTTP data */
5500 ipp_t
*ipp
) /* I - IPP data */
5502 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd
, ipp
));
5504 ipp
->state
= IPP_STATE_IDLE
;
5506 return (ippWriteIO(&fd
, (ipp_iocb_t
)ipp_write_file
, 1, NULL
, ipp
));
5511 * 'ippWriteIO()' - Write data for an IPP message.
5513 * @since CUPS 1.2/OS X 10.5@
5516 ipp_state_t
/* O - Current state */
5517 ippWriteIO(void *dst
, /* I - Destination */
5518 ipp_iocb_t cb
, /* I - Write callback function */
5519 int blocking
, /* I - Use blocking IO? */
5520 ipp_t
*parent
, /* I - Parent IPP message */
5521 ipp_t
*ipp
) /* I - IPP data */
5523 int i
; /* Looping var */
5524 int n
; /* Length of data */
5525 unsigned char *buffer
, /* Data buffer */
5526 *bufptr
; /* Pointer into buffer */
5527 ipp_attribute_t
*attr
; /* Current attribute */
5528 _ipp_value_t
*value
; /* Current value */
5531 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
5532 dst
, cb
, blocking
, parent
, ipp
));
5535 return (IPP_STATE_ERROR
);
5537 if ((buffer
= (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE
)) == NULL
)
5539 DEBUG_puts("1ippWriteIO: Unable to get write buffer");
5540 return (IPP_STATE_ERROR
);
5545 case IPP_STATE_IDLE
:
5546 ipp
->state
++; /* Avoid common problem... */
5548 case IPP_STATE_HEADER
:
5552 * Send the request header:
5555 * Operation/Status Code = 2 bytes
5556 * Request ID = 4 bytes
5562 *bufptr
++ = ipp
->request
.any
.version
[0];
5563 *bufptr
++ = ipp
->request
.any
.version
[1];
5564 *bufptr
++ = ipp
->request
.any
.op_status
>> 8;
5565 *bufptr
++ = ipp
->request
.any
.op_status
;
5566 *bufptr
++ = ipp
->request
.any
.request_id
>> 24;
5567 *bufptr
++ = ipp
->request
.any
.request_id
>> 16;
5568 *bufptr
++ = ipp
->request
.any
.request_id
>> 8;
5569 *bufptr
++ = ipp
->request
.any
.request_id
;
5571 DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer
[0], buffer
[1]));
5572 DEBUG_printf(("2ippWriteIO: op_status=%04x",
5573 ipp
->request
.any
.op_status
));
5574 DEBUG_printf(("2ippWriteIO: request_id=%d",
5575 ipp
->request
.any
.request_id
));
5577 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
5579 DEBUG_puts("1ippWriteIO: Could not write IPP header...");
5580 _cupsBufferRelease((char *)buffer
);
5581 return (IPP_STATE_ERROR
);
5586 * Reset the state engine to point to the first attribute
5587 * in the request/response, with no current group.
5590 ipp
->state
= IPP_STATE_ATTRIBUTE
;
5591 ipp
->current
= ipp
->attrs
;
5592 ipp
->curtag
= IPP_TAG_ZERO
;
5594 DEBUG_printf(("1ippWriteIO: ipp->current=%p", ipp
->current
));
5597 * If blocking is disabled, stop here...
5603 case IPP_STATE_ATTRIBUTE
:
5604 while (ipp
->current
!= NULL
)
5607 * Write this attribute...
5611 attr
= ipp
->current
;
5613 ipp
->current
= ipp
->current
->next
;
5617 if (ipp
->curtag
!= attr
->group_tag
)
5620 * Send a group tag byte...
5623 ipp
->curtag
= attr
->group_tag
;
5625 if (attr
->group_tag
== IPP_TAG_ZERO
)
5628 DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
5629 attr
->group_tag
, ippTagString(attr
->group_tag
)));
5630 *bufptr
++ = attr
->group_tag
;
5632 else if (attr
->group_tag
== IPP_TAG_ZERO
)
5636 DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr
->name
,
5637 attr
->num_values
> 1 ? "1setOf " : "",
5638 ippTagString(attr
->value_tag
)));
5641 * Write the attribute tag and name.
5643 * The attribute name length does not include the trailing nul
5644 * character in the source string.
5646 * Collection values (parent != NULL) are written differently...
5652 * Get the length of the attribute name, and make sure it won't
5653 * overflow the buffer...
5656 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 8))
5658 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
5659 _cupsBufferRelease((char *)buffer
);
5660 return (IPP_STATE_ERROR
);
5664 * Write the value tag, name length, and name string...
5667 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5668 attr
->value_tag
, ippTagString(attr
->value_tag
)));
5669 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
5672 if (attr
->value_tag
> 0xff)
5674 *bufptr
++ = IPP_TAG_EXTENSION
;
5675 *bufptr
++ = attr
->value_tag
>> 24;
5676 *bufptr
++ = attr
->value_tag
>> 16;
5677 *bufptr
++ = attr
->value_tag
>> 8;
5678 *bufptr
++ = attr
->value_tag
;
5681 *bufptr
++ = attr
->value_tag
;
5685 memcpy(bufptr
, attr
->name
, n
);
5691 * Get the length of the attribute name, and make sure it won't
5692 * overflow the buffer...
5695 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 12))
5697 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
5698 _cupsBufferRelease((char *)buffer
);
5699 return (IPP_STATE_ERROR
);
5703 * Write the member name tag, name length, name string, value tag,
5704 * and empty name for the collection member attribute...
5707 DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
5708 IPP_TAG_MEMBERNAME
));
5709 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
5711 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5712 attr
->value_tag
, ippTagString(attr
->value_tag
)));
5713 DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
5715 *bufptr
++ = IPP_TAG_MEMBERNAME
;
5720 memcpy(bufptr
, attr
->name
, n
);
5723 if (attr
->value_tag
> 0xff)
5725 *bufptr
++ = IPP_TAG_EXTENSION
;
5726 *bufptr
++ = attr
->value_tag
>> 24;
5727 *bufptr
++ = attr
->value_tag
>> 16;
5728 *bufptr
++ = attr
->value_tag
>> 8;
5729 *bufptr
++ = attr
->value_tag
;
5732 *bufptr
++ = attr
->value_tag
;
5739 * Now write the attribute value(s)...
5742 switch (attr
->value_tag
& ~IPP_TAG_CUPS_CONST
)
5744 case IPP_TAG_UNSUPPORTED_VALUE
:
5745 case IPP_TAG_DEFAULT
:
5746 case IPP_TAG_UNKNOWN
:
5747 case IPP_TAG_NOVALUE
:
5748 case IPP_TAG_NOTSETTABLE
:
5749 case IPP_TAG_DELETEATTR
:
5750 case IPP_TAG_ADMINDEFINE
:
5755 case IPP_TAG_INTEGER
:
5757 for (i
= 0, value
= attr
->values
;
5758 i
< attr
->num_values
;
5761 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 9)
5763 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
5765 DEBUG_puts("1ippWriteIO: Could not write IPP "
5767 _cupsBufferRelease((char *)buffer
);
5768 return (IPP_STATE_ERROR
);
5777 * Arrays and sets are done by sending additional
5778 * values with a zero-length name...
5781 *bufptr
++ = attr
->value_tag
;
5787 * Integers and enumerations are both 4-byte signed
5788 * (twos-complement) values.
5790 * Put the 2-byte length and 4-byte value into the buffer...
5795 *bufptr
++ = value
->integer
>> 24;
5796 *bufptr
++ = value
->integer
>> 16;
5797 *bufptr
++ = value
->integer
>> 8;
5798 *bufptr
++ = value
->integer
;
5802 case IPP_TAG_BOOLEAN
:
5803 for (i
= 0, value
= attr
->values
;
5804 i
< attr
->num_values
;
5807 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 6)
5809 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
5811 DEBUG_puts("1ippWriteIO: Could not write IPP "
5813 _cupsBufferRelease((char *)buffer
);
5814 return (IPP_STATE_ERROR
);
5823 * Arrays and sets are done by sending additional
5824 * values with a zero-length name...
5827 *bufptr
++ = attr
->value_tag
;
5833 * Boolean values are 1-byte; 0 = false, 1 = true.
5835 * Put the 2-byte length and 1-byte value into the buffer...
5840 *bufptr
++ = value
->boolean
;
5846 case IPP_TAG_KEYWORD
:
5848 case IPP_TAG_URISCHEME
:
5849 case IPP_TAG_CHARSET
:
5850 case IPP_TAG_LANGUAGE
:
5851 case IPP_TAG_MIMETYPE
:
5852 for (i
= 0, value
= attr
->values
;
5853 i
< attr
->num_values
;
5859 * Arrays and sets are done by sending additional
5860 * values with a zero-length name...
5863 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
5865 ippTagString(attr
->value_tag
)));
5866 DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
5868 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
5870 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
5872 DEBUG_puts("1ippWriteIO: Could not write IPP "
5874 _cupsBufferRelease((char *)buffer
);
5875 return (IPP_STATE_ERROR
);
5881 *bufptr
++ = attr
->value_tag
;
5886 if (value
->string
.text
!= NULL
)
5887 n
= (int)strlen(value
->string
.text
);
5891 if (n
> (IPP_BUF_SIZE
- 2))
5893 DEBUG_printf(("1ippWriteIO: String too long (%d)", n
));
5894 _cupsBufferRelease((char *)buffer
);
5895 return (IPP_STATE_ERROR
);
5898 DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n
,
5899 value
->string
.text
));
5901 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
5903 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
5905 DEBUG_puts("1ippWriteIO: Could not write IPP "
5907 _cupsBufferRelease((char *)buffer
);
5908 return (IPP_STATE_ERROR
);
5915 * All simple strings consist of the 2-byte length and
5916 * character data without the trailing nul normally found
5917 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
5918 * bytes since the 2-byte length is a signed (twos-complement)
5921 * Put the 2-byte length and string characters in the buffer.
5929 memcpy(bufptr
, value
->string
.text
, n
);
5936 for (i
= 0, value
= attr
->values
;
5937 i
< attr
->num_values
;
5940 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 16)
5942 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
5944 DEBUG_puts("1ippWriteIO: Could not write IPP "
5946 _cupsBufferRelease((char *)buffer
);
5947 return (IPP_STATE_ERROR
);
5956 * Arrays and sets are done by sending additional
5957 * values with a zero-length name...
5960 *bufptr
++ = attr
->value_tag
;
5966 * Date values consist of a 2-byte length and an
5967 * 11-byte date/time structure defined by RFC 1903.
5969 * Put the 2-byte length and 11-byte date/time
5970 * structure in the buffer.
5975 memcpy(bufptr
, value
->date
, 11);
5980 case IPP_TAG_RESOLUTION
:
5981 for (i
= 0, value
= attr
->values
;
5982 i
< attr
->num_values
;
5985 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 14)
5987 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
5989 DEBUG_puts("1ippWriteIO: Could not write IPP "
5991 _cupsBufferRelease((char *)buffer
);
5992 return (IPP_STATE_ERROR
);
6001 * Arrays and sets are done by sending additional
6002 * values with a zero-length name...
6005 *bufptr
++ = attr
->value_tag
;
6011 * Resolution values consist of a 2-byte length,
6012 * 4-byte horizontal resolution value, 4-byte vertical
6013 * resolution value, and a 1-byte units value.
6015 * Put the 2-byte length and resolution value data
6021 *bufptr
++ = value
->resolution
.xres
>> 24;
6022 *bufptr
++ = value
->resolution
.xres
>> 16;
6023 *bufptr
++ = value
->resolution
.xres
>> 8;
6024 *bufptr
++ = value
->resolution
.xres
;
6025 *bufptr
++ = value
->resolution
.yres
>> 24;
6026 *bufptr
++ = value
->resolution
.yres
>> 16;
6027 *bufptr
++ = value
->resolution
.yres
>> 8;
6028 *bufptr
++ = value
->resolution
.yres
;
6029 *bufptr
++ = value
->resolution
.units
;
6033 case IPP_TAG_RANGE
:
6034 for (i
= 0, value
= attr
->values
;
6035 i
< attr
->num_values
;
6038 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 13)
6040 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
6042 DEBUG_puts("1ippWriteIO: Could not write IPP "
6044 _cupsBufferRelease((char *)buffer
);
6045 return (IPP_STATE_ERROR
);
6054 * Arrays and sets are done by sending additional
6055 * values with a zero-length name...
6058 *bufptr
++ = attr
->value_tag
;
6064 * Range values consist of a 2-byte length,
6065 * 4-byte lower value, and 4-byte upper value.
6067 * Put the 2-byte length and range value data
6073 *bufptr
++ = value
->range
.lower
>> 24;
6074 *bufptr
++ = value
->range
.lower
>> 16;
6075 *bufptr
++ = value
->range
.lower
>> 8;
6076 *bufptr
++ = value
->range
.lower
;
6077 *bufptr
++ = value
->range
.upper
>> 24;
6078 *bufptr
++ = value
->range
.upper
>> 16;
6079 *bufptr
++ = value
->range
.upper
>> 8;
6080 *bufptr
++ = value
->range
.upper
;
6084 case IPP_TAG_TEXTLANG
:
6085 case IPP_TAG_NAMELANG
:
6086 for (i
= 0, value
= attr
->values
;
6087 i
< attr
->num_values
;
6093 * Arrays and sets are done by sending additional
6094 * values with a zero-length name...
6097 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
6099 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
6101 DEBUG_puts("1ippWriteIO: Could not write IPP "
6103 _cupsBufferRelease((char *)buffer
);
6104 return (IPP_STATE_ERROR
);
6110 *bufptr
++ = attr
->value_tag
;
6116 * textWithLanguage and nameWithLanguage values consist
6117 * of a 2-byte length for both strings and their
6118 * individual lengths, a 2-byte length for the
6119 * character string, the character string without the
6120 * trailing nul, a 2-byte length for the character
6121 * set string, and the character set string without
6127 if (value
->string
.language
!= NULL
)
6128 n
+= (int)strlen(value
->string
.language
);
6130 if (value
->string
.text
!= NULL
)
6131 n
+= (int)strlen(value
->string
.text
);
6133 if (n
> (IPP_BUF_SIZE
- 2))
6135 DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
6136 "too long (%d)", n
));
6137 _cupsBufferRelease((char *)buffer
);
6138 return (IPP_STATE_ERROR
);
6141 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
6143 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
6145 DEBUG_puts("1ippWriteIO: Could not write IPP "
6147 _cupsBufferRelease((char *)buffer
);
6148 return (IPP_STATE_ERROR
);
6154 /* Length of entire value */
6158 /* Length of language */
6159 if (value
->string
.language
!= NULL
)
6160 n
= (int)strlen(value
->string
.language
);
6170 memcpy(bufptr
, value
->string
.language
, n
);
6174 /* Length of text */
6175 if (value
->string
.text
!= NULL
)
6176 n
= (int)strlen(value
->string
.text
);
6186 memcpy(bufptr
, value
->string
.text
, n
);
6192 case IPP_TAG_BEGIN_COLLECTION
:
6193 for (i
= 0, value
= attr
->values
;
6194 i
< attr
->num_values
;
6198 * Collections are written with the begin-collection
6199 * tag first with a value of 0 length, followed by the
6200 * attributes in the collection, then the end-collection
6204 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 5)
6206 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
6208 DEBUG_puts("1ippWriteIO: Could not write IPP "
6210 _cupsBufferRelease((char *)buffer
);
6211 return (IPP_STATE_ERROR
);
6220 * Arrays and sets are done by sending additional
6221 * values with a zero-length name...
6224 *bufptr
++ = attr
->value_tag
;
6230 * Write a data length of 0 and flush the buffer...
6236 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
6238 DEBUG_puts("1ippWriteIO: Could not write IPP "
6240 _cupsBufferRelease((char *)buffer
);
6241 return (IPP_STATE_ERROR
);
6247 * Then write the collection attribute...
6250 value
->collection
->state
= IPP_STATE_IDLE
;
6252 if (ippWriteIO(dst
, cb
, 1, ipp
,
6253 value
->collection
) == IPP_STATE_ERROR
)
6255 DEBUG_puts("1ippWriteIO: Unable to write collection value");
6256 _cupsBufferRelease((char *)buffer
);
6257 return (IPP_STATE_ERROR
);
6263 for (i
= 0, value
= attr
->values
;
6264 i
< attr
->num_values
;
6270 * Arrays and sets are done by sending additional
6271 * values with a zero-length name...
6274 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
6276 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
6278 DEBUG_puts("1ippWriteIO: Could not write IPP "
6280 _cupsBufferRelease((char *)buffer
);
6281 return (IPP_STATE_ERROR
);
6287 *bufptr
++ = attr
->value_tag
;
6293 * An unknown value might some new value that a
6294 * vendor has come up with. It consists of a
6295 * 2-byte length and the bytes in the unknown
6299 n
= value
->unknown
.length
;
6301 if (n
> (IPP_BUF_SIZE
- 2))
6303 DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
6305 _cupsBufferRelease((char *)buffer
);
6306 return (IPP_STATE_ERROR
);
6309 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
6311 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
6313 DEBUG_puts("1ippWriteIO: Could not write IPP "
6315 _cupsBufferRelease((char *)buffer
);
6316 return (IPP_STATE_ERROR
);
6322 /* Length of unknown value */
6329 memcpy(bufptr
, value
->unknown
.data
, n
);
6337 * Write the data out...
6340 if (bufptr
> buffer
)
6342 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
6344 DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
6345 _cupsBufferRelease((char *)buffer
);
6346 return (IPP_STATE_ERROR
);
6349 DEBUG_printf(("2ippWriteIO: wrote %d bytes",
6350 (int)(bufptr
- buffer
)));
6354 * If blocking is disabled and we aren't at the end of the attribute
6355 * list, stop here...
6358 if (!blocking
&& ipp
->current
)
6362 if (ipp
->current
== NULL
)
6365 * Done with all of the attributes; add the end-of-attributes
6366 * tag or end-collection attribute...
6371 buffer
[0] = IPP_TAG_END
;
6376 buffer
[0] = IPP_TAG_END_COLLECTION
;
6377 buffer
[1] = 0; /* empty name */
6379 buffer
[3] = 0; /* empty value */
6384 if ((*cb
)(dst
, buffer
, n
) < 0)
6386 DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
6387 _cupsBufferRelease((char *)buffer
);
6388 return (IPP_STATE_ERROR
);
6391 ipp
->state
= IPP_STATE_DATA
;
6395 case IPP_STATE_DATA
:
6399 break; /* anti-compiler-warning-code */
6402 _cupsBufferRelease((char *)buffer
);
6404 return (ipp
->state
);
6409 * 'ipp_add_attr()' - Add a new attribute to the message.
6412 static ipp_attribute_t
* /* O - New attribute */
6413 ipp_add_attr(ipp_t
*ipp
, /* I - IPP message */
6414 const char *name
, /* I - Attribute name or NULL */
6415 ipp_tag_t group_tag
, /* I - Group tag or IPP_TAG_ZERO */
6416 ipp_tag_t value_tag
, /* I - Value tag or IPP_TAG_ZERO */
6417 int num_values
) /* I - Number of values */
6419 int alloc_values
; /* Number of values to allocate */
6420 ipp_attribute_t
*attr
; /* New attribute */
6423 DEBUG_printf(("4ipp_add_attr(ipp=%p, name=\"%s\", group_tag=0x%x, value_tag=0x%x, "
6424 "num_values=%d)", ipp
, name
, group_tag
, value_tag
, num_values
));
6427 * Range check input...
6430 if (!ipp
|| num_values
< 0)
6434 * Allocate memory, rounding the allocation up as needed...
6437 if (num_values
<= 1)
6440 alloc_values
= (num_values
+ IPP_MAX_VALUES
- 1) & ~(IPP_MAX_VALUES
- 1);
6442 attr
= calloc(sizeof(ipp_attribute_t
) +
6443 (alloc_values
- 1) * sizeof(_ipp_value_t
), 1);
6448 * Initialize attribute...
6452 attr
->name
= _cupsStrAlloc(name
);
6454 attr
->group_tag
= group_tag
;
6455 attr
->value_tag
= value_tag
;
6456 attr
->num_values
= num_values
;
6459 * Add it to the end of the linked list...
6463 ipp
->last
->next
= attr
;
6467 ipp
->prev
= ipp
->last
;
6468 ipp
->last
= ipp
->current
= attr
;
6471 DEBUG_printf(("5ipp_add_attr: Returning %p", attr
));
6478 * 'ipp_free_values()' - Free attribute values.
6482 ipp_free_values(ipp_attribute_t
*attr
, /* I - Attribute to free values from */
6483 int element
,/* I - First value to free */
6484 int count
) /* I - Number of values to free */
6486 int i
; /* Looping var */
6487 _ipp_value_t
*value
; /* Current value */
6490 DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", attr
,
6493 if (!(attr
->value_tag
& IPP_TAG_CUPS_CONST
))
6496 * Free values as needed...
6499 switch (attr
->value_tag
)
6501 case IPP_TAG_TEXTLANG
:
6502 case IPP_TAG_NAMELANG
:
6503 if (element
== 0 && count
== attr
->num_values
&&
6504 attr
->values
[0].string
.language
)
6506 _cupsStrFree(attr
->values
[0].string
.language
);
6507 attr
->values
[0].string
.language
= NULL
;
6509 /* Fall through to other string values */
6513 case IPP_TAG_RESERVED_STRING
:
6514 case IPP_TAG_KEYWORD
:
6516 case IPP_TAG_URISCHEME
:
6517 case IPP_TAG_CHARSET
:
6518 case IPP_TAG_LANGUAGE
:
6519 case IPP_TAG_MIMETYPE
:
6520 for (i
= count
, value
= attr
->values
+ element
;
6524 _cupsStrFree(value
->string
.text
);
6525 value
->string
.text
= NULL
;
6529 case IPP_TAG_DEFAULT
:
6530 case IPP_TAG_UNKNOWN
:
6531 case IPP_TAG_NOVALUE
:
6532 case IPP_TAG_NOTSETTABLE
:
6533 case IPP_TAG_DELETEATTR
:
6534 case IPP_TAG_ADMINDEFINE
:
6535 case IPP_TAG_INTEGER
:
6537 case IPP_TAG_BOOLEAN
:
6539 case IPP_TAG_RESOLUTION
:
6540 case IPP_TAG_RANGE
:
6543 case IPP_TAG_BEGIN_COLLECTION
:
6544 for (i
= count
, value
= attr
->values
+ element
;
6548 ippDelete(value
->collection
);
6549 value
->collection
= NULL
;
6553 case IPP_TAG_STRING
:
6555 for (i
= count
, value
= attr
->values
+ element
;
6559 if (value
->unknown
.data
)
6561 free(value
->unknown
.data
);
6562 value
->unknown
.data
= NULL
;
6570 * If we are not freeing values from the end, move the remaining values up...
6573 if ((element
+ count
) < attr
->num_values
)
6574 memmove(attr
->values
+ element
, attr
->values
+ element
+ count
,
6575 (attr
->num_values
- count
- element
) * sizeof(_ipp_value_t
));
6577 attr
->num_values
-= count
;
6582 * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
6584 * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
6585 * to "ll-cc", "ll-region", and "charset-number", respectively.
6588 static char * /* O - Language code string */
6589 ipp_get_code(const char *value
, /* I - Locale/charset string */
6590 char *buffer
, /* I - String buffer */
6591 size_t bufsize
) /* I - Size of string buffer */
6593 char *bufptr
, /* Pointer into buffer */
6594 *bufend
; /* End of buffer */
6598 * Convert values to lowercase and change _ to - as needed...
6601 for (bufptr
= buffer
, bufend
= buffer
+ bufsize
- 1;
6602 *value
&& bufptr
< bufend
;
6607 *bufptr
++ = _cups_tolower(*value
);
6612 * Return the converted string...
6620 * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
6622 * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
6623 * "ll-region", respectively. It also converts the "C" (POSIX) locale to "en".
6626 static char * /* O - Language code string */
6627 ipp_lang_code(const char *locale
, /* I - Locale string */
6628 char *buffer
, /* I - String buffer */
6629 size_t bufsize
) /* I - Size of string buffer */
6632 * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
6635 if (!_cups_strcasecmp(locale
, "c"))
6637 strlcpy(buffer
, "en", bufsize
);
6641 return (ipp_get_code(locale
, buffer
, bufsize
));
6646 * 'ipp_length()' - Compute the length of an IPP message or collection value.
6649 static size_t /* O - Size of IPP message */
6650 ipp_length(ipp_t
*ipp
, /* I - IPP message or collection */
6651 int collection
) /* I - 1 if a collection, 0 otherwise */
6653 int i
; /* Looping var */
6654 size_t bytes
; /* Number of bytes */
6655 ipp_attribute_t
*attr
; /* Current attribute */
6656 ipp_tag_t group
; /* Current group */
6657 _ipp_value_t
*value
; /* Current value */
6660 DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", ipp
, collection
));
6664 DEBUG_puts("4ipp_length: Returning 0 bytes");
6669 * Start with 8 bytes for the IPP message header...
6672 bytes
= collection
? 0 : 8;
6675 * Then add the lengths of each attribute...
6678 group
= IPP_TAG_ZERO
;
6680 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= attr
->next
)
6682 if (attr
->group_tag
!= group
&& !collection
)
6684 group
= attr
->group_tag
;
6685 if (group
== IPP_TAG_ZERO
)
6688 bytes
++; /* Group tag */
6694 DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
6695 "bytes=" CUPS_LLFMT
, attr
->name
, attr
->num_values
, CUPS_LLCAST bytes
));
6697 if (attr
->value_tag
< IPP_TAG_EXTENSION
)
6698 bytes
+= attr
->num_values
; /* Value tag for each value */
6700 bytes
+= 5 * attr
->num_values
; /* Value tag for each value */
6701 bytes
+= 2 * attr
->num_values
; /* Name lengths */
6702 bytes
+= (int)strlen(attr
->name
); /* Name */
6703 bytes
+= 2 * attr
->num_values
; /* Value lengths */
6706 bytes
+= 5; /* Add membername overhead */
6708 switch (attr
->value_tag
& ~IPP_TAG_CUPS_CONST
)
6710 case IPP_TAG_UNSUPPORTED_VALUE
:
6711 case IPP_TAG_DEFAULT
:
6712 case IPP_TAG_UNKNOWN
:
6713 case IPP_TAG_NOVALUE
:
6714 case IPP_TAG_NOTSETTABLE
:
6715 case IPP_TAG_DELETEATTR
:
6716 case IPP_TAG_ADMINDEFINE
:
6719 case IPP_TAG_INTEGER
:
6721 bytes
+= 4 * attr
->num_values
;
6724 case IPP_TAG_BOOLEAN
:
6725 bytes
+= attr
->num_values
;
6730 case IPP_TAG_KEYWORD
:
6732 case IPP_TAG_URISCHEME
:
6733 case IPP_TAG_CHARSET
:
6734 case IPP_TAG_LANGUAGE
:
6735 case IPP_TAG_MIMETYPE
:
6736 for (i
= 0, value
= attr
->values
;
6737 i
< attr
->num_values
;
6739 if (value
->string
.text
)
6740 bytes
+= strlen(value
->string
.text
);
6744 bytes
+= 11 * attr
->num_values
;
6747 case IPP_TAG_RESOLUTION
:
6748 bytes
+= 9 * attr
->num_values
;
6751 case IPP_TAG_RANGE
:
6752 bytes
+= 8 * attr
->num_values
;
6755 case IPP_TAG_TEXTLANG
:
6756 case IPP_TAG_NAMELANG
:
6757 bytes
+= 4 * attr
->num_values
;/* Charset + text length */
6759 for (i
= 0, value
= attr
->values
;
6760 i
< attr
->num_values
;
6763 if (value
->string
.language
)
6764 bytes
+= strlen(value
->string
.language
);
6766 if (value
->string
.text
)
6767 bytes
+= strlen(value
->string
.text
);
6771 case IPP_TAG_BEGIN_COLLECTION
:
6772 for (i
= 0, value
= attr
->values
;
6773 i
< attr
->num_values
;
6775 bytes
+= ipp_length(value
->collection
, 1);
6779 for (i
= 0, value
= attr
->values
;
6780 i
< attr
->num_values
;
6782 bytes
+= value
->unknown
.length
;
6788 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
6789 * for the "end of collection" tag and return...
6797 DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT
" bytes", CUPS_LLCAST bytes
));
6804 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
6807 static ssize_t
/* O - Number of bytes read */
6808 ipp_read_http(http_t
*http
, /* I - Client connection */
6809 ipp_uchar_t
*buffer
, /* O - Buffer for data */
6810 size_t length
) /* I - Total length */
6812 int tbytes
, /* Total bytes read */
6813 bytes
; /* Bytes read this pass */
6816 DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)",
6817 http
, buffer
, (int)length
));
6820 * Loop until all bytes are read...
6823 for (tbytes
= 0, bytes
= 0;
6824 tbytes
< (int)length
;
6825 tbytes
+= bytes
, buffer
+= bytes
)
6827 DEBUG_printf(("9ipp_read_http: tbytes=%d, http->state=%d", tbytes
,
6830 if (http
->state
== HTTP_STATE_WAITING
)
6833 if (http
->used
== 0 && !http
->blocking
)
6836 * Wait up to 10 seconds for more data on non-blocking sockets...
6839 if (!httpWait(http
, 10000))
6850 if ((bytes
= httpRead2(http
, (char *)buffer
, length
- tbytes
)) < 0)
6855 if (errno
!= EAGAIN
&& errno
!= EINTR
)
6861 else if (bytes
== 0)
6866 * Return the number of bytes read...
6869 if (tbytes
== 0 && bytes
< 0)
6872 DEBUG_printf(("8ipp_read_http: Returning %d bytes", tbytes
));
6879 * 'ipp_read_file()' - Read IPP data from a file.
6882 static ssize_t
/* O - Number of bytes read */
6883 ipp_read_file(int *fd
, /* I - File descriptor */
6884 ipp_uchar_t
*buffer
, /* O - Read buffer */
6885 size_t length
) /* I - Number of bytes to read */
6888 return ((ssize_t
)read(*fd
, buffer
, (unsigned)length
));
6890 return (read(*fd
, buffer
, length
));
6896 * 'ipp_set_error()' - Set a formatted, localized error string.
6900 ipp_set_error(ipp_status_t status
, /* I - Status code */
6901 const char *format
, /* I - Printf-style error string */
6902 ...) /* I - Additional arguments as needed */
6904 va_list ap
; /* Pointer to additional args */
6905 char buffer
[2048]; /* Message buffer */
6906 cups_lang_t
*lang
= cupsLangDefault();
6907 /* Current language */
6910 va_start(ap
, format
);
6911 vsnprintf(buffer
, sizeof(buffer
), _cupsLangString(lang
, format
), ap
);
6914 _cupsSetError(status
, buffer
, 0);
6919 * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
6923 static _ipp_value_t
* /* O - IPP value element or NULL on error */
6924 ipp_set_value(ipp_t
*ipp
, /* IO - IPP message */
6925 ipp_attribute_t
**attr
, /* IO - IPP attribute */
6926 int element
) /* I - Value number (0-based) */
6928 ipp_attribute_t
*temp
, /* New attribute pointer */
6929 *current
, /* Current attribute in list */
6930 *prev
; /* Previous attribute in list */
6931 int alloc_values
; /* Allocated values */
6935 * If we are setting an existing value element, return it...
6940 if (temp
->num_values
<= 1)
6943 alloc_values
= (temp
->num_values
+ IPP_MAX_VALUES
- 1) &
6944 ~(IPP_MAX_VALUES
- 1);
6946 if (element
< alloc_values
)
6948 if (element
>= temp
->num_values
)
6949 temp
->num_values
= element
+ 1;
6951 return (temp
->values
+ element
);
6955 * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
6956 * values when num_values > 1.
6959 if (alloc_values
< IPP_MAX_VALUES
)
6960 alloc_values
= IPP_MAX_VALUES
;
6962 alloc_values
+= IPP_MAX_VALUES
;
6964 DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
6968 * Reallocate memory...
6971 if ((temp
= realloc(temp
, sizeof(ipp_attribute_t
) +
6972 (alloc_values
- 1) * sizeof(_ipp_value_t
))) == NULL
)
6974 _cupsSetHTTPError(HTTP_STATUS_ERROR
);
6975 DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
6980 * Zero the new memory...
6983 memset(temp
->values
+ temp
->num_values
, 0,
6984 (alloc_values
- temp
->num_values
) * sizeof(_ipp_value_t
));
6989 * Reset pointers in the list...
6992 if (ipp
->current
== *attr
&& ipp
->prev
)
6995 * Use current "previous" pointer...
7003 * Find this attribute in the linked list...
7006 for (prev
= NULL
, current
= ipp
->attrs
;
7007 current
&& current
!= *attr
;
7008 prev
= current
, current
= current
->next
);
7013 * This is a serious error!
7017 _cupsSetError(IPP_STATUS_ERROR_INTERNAL
,
7018 _("IPP attribute is not a member of the message."), 1);
7019 DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
7029 ipp
->current
= temp
;
7032 if (ipp
->last
== *attr
)
7039 * Return the value element...
7042 if (element
>= temp
->num_values
)
7043 temp
->num_values
= element
+ 1;
7045 return (temp
->values
+ element
);
7050 * 'ipp_write_file()' - Write IPP data to a file.
7053 static ssize_t
/* O - Number of bytes written */
7054 ipp_write_file(int *fd
, /* I - File descriptor */
7055 ipp_uchar_t
*buffer
, /* I - Data to write */
7056 size_t length
) /* I - Number of bytes to write */
7059 return ((ssize_t
)write(*fd
, buffer
, (unsigned)length
));
7061 return (write(*fd
, buffer
, length
));
7067 * End of "$Id: ipp.c 11113 2013-07-10 14:08:39Z msweet $".