2 * "$Id: ipp.c 10102 2011-11-02 23:52:39Z mike $"
4 * Internet Printing Protocol functions for CUPS.
6 * Copyright 2007-2011 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * ippAddBoolean() - Add a boolean attribute to an IPP message.
20 * ippAddBooleans() - Add an array of boolean values.
21 * ippAddCollection() - Add a collection value.
22 * ippAddCollections() - Add an array of collection values.
23 * ippAddDate() - Add a date attribute to an IPP message.
24 * ippAddInteger() - Add a integer attribute to an IPP message.
25 * ippAddIntegers() - Add an array of integer values.
26 * ippAddOctetString() - Add an octetString value to an IPP message.
27 * ippAddOutOfBand() - Add an out-of-band value to an IPP message.
28 * ippAddRange() - Add a range of values to an IPP message.
29 * ippAddRanges() - Add ranges of values to an IPP message.
30 * ippAddResolution() - Add a resolution value to an IPP message.
31 * ippAddResolutions() - Add resolution values to an IPP message.
32 * ippAddSeparator() - Add a group separator to an IPP message.
33 * ippAddString() - Add a language-encoded string to an IPP message.
34 * ippAddStrings() - Add language-encoded strings to an IPP message.
35 * ippCopyAttribute() - Copy an attribute.
36 * ippCopyAttributes() - Copy attributes from one IPP message to another.
37 * ippDateToTime() - Convert from RFC 1903 Date/Time format to UNIX
39 * ippDelete() - Delete an IPP message.
40 * ippDeleteAttribute() - Delete a single attribute in an IPP message.
41 * ippDeleteValues() - Delete values in an attribute.
42 * ippFindAttribute() - Find a named attribute in a request.
43 * ippFindNextAttribute() - Find the next named attribute in a request.
44 * ippFirstAttribute() - Return the first attribute in the message.
45 * ippGetBoolean() - Get a boolean value for an attribute.
46 * ippGetCollection() - Get a collection value for an attribute.
47 * ippGetCount() - Get the number of values in an attribute.
48 * ippGetDate() - Get a date value for an attribute.
49 * ippGetGroupTag() - Get the group associated with an attribute.
50 * ippGetInteger() - Get the integer/enum value for an attribute.
51 * ippGetName() - Get the attribute name.
52 * ippGetOperation() - Get the operation ID in an IPP message.
53 * ippGetRange() - Get a rangeOfInteger value from an attribute.
54 * ippGetRequestId() - Get the request ID from an IPP message.
55 * ippGetResolution() - Get a resolution value for an attribute.
56 * ippGetStatusCode() - Get the status code from an IPP response or event
58 * ippGetString() - Get the string and optionally the language code
60 * ippGetValueTag() - Get the value tag for an attribute.
61 * ippGetVersion() - Get the major and minor version number from an
63 * ippLength() - Compute the length of an IPP message.
64 * ippNextAttribute() - Return the next attribute in the message.
65 * ippNew() - Allocate a new IPP message.
66 * ippNewRequest() - Allocate a new IPP request message.
67 * ippRead() - Read data for an IPP message from a HTTP
69 * ippReadFile() - Read data for an IPP message from a file.
70 * ippReadIO() - Read data for an IPP message.
71 * ippSetBoolean() - Set a boolean value in an attribute.
72 * ippSetCollection() - Set a collection value in an attribute.
73 * ippSetDate() - Set a date value in an attribute.
74 * ippSetGroupTag() - Set the group tag of an attribute.
75 * ippSetInteger() - Set an integer or enum value in an attribute.
76 * ippSetName() - Set the name of an attribute.
77 * ippSetOperation() - Set the operation ID in an IPP request message.
78 * ippSetRange() - Set a rangeOfInteger value in an attribute.
79 * ippSetRequestId() - Set the request ID in an IPP message.
80 * ippSetResolution() - Set a resolution value in an attribute.
81 * ippSetState() - Set the current state of the IPP message.
82 * ippSetStatusCode() - Set the status code in an IPP response or event
84 * ippSetString() - Set a string value in an attribute.
85 * ippSetValueTag() - Set the value tag of an attribute.
86 * ippSetVersion() - Set the version number in an IPP message.
87 * ippTimeToDate() - Convert from UNIX time to RFC 1903 format.
88 * ippWrite() - Write data for an IPP message to a HTTP
90 * ippWriteFile() - Write data for an IPP message to a file.
91 * ippWriteIO() - Write data for an IPP message.
92 * ipp_add_attr() - Add a new attribute to the message.
93 * ipp_buffer_get() - Get a read/write buffer.
94 * ipp_buffer_release() - Release a read/write buffer.
95 * ipp_free_values() - Free attribute values.
96 * ipp_get_code() - Convert a C locale/charset name into an IPP
97 * language/charset code.
98 * ipp_lang_code() - Convert a C locale name into an IPP language
100 * ipp_length() - Compute the length of an IPP message or
102 * ipp_read_http() - Semi-blocking read on a HTTP connection...
103 * ipp_read_file() - Read IPP data from a file.
104 * ipp_set_value() - Get the value element from an attribute,
105 * expanding it as needed.
106 * ipp_write_file() - Write IPP data to a file.
110 * Include necessary headers...
113 #include "cups-private.h"
123 static ipp_attribute_t
*ipp_add_attr(ipp_t
*ipp
, const char *name
, ipp_tag_t group_tag
,
124 ipp_tag_t value_tag
, int num_values
);
125 static unsigned char *ipp_buffer_get(void);
126 static void ipp_buffer_release(unsigned char *b
);
127 static void ipp_free_values(ipp_attribute_t
*attr
, int element
, int count
);
128 static char *ipp_get_code(const char *locale
, char *buffer
, size_t bufsize
);
129 static char *ipp_lang_code(const char *locale
, char *buffer
, size_t bufsize
);
130 static size_t ipp_length(ipp_t
*ipp
, int collection
);
131 static ssize_t
ipp_read_http(http_t
*http
, ipp_uchar_t
*buffer
,
133 static ssize_t
ipp_read_file(int *fd
, ipp_uchar_t
*buffer
,
135 static _ipp_value_t
*ipp_set_value(ipp_t
*ipp
, ipp_attribute_t
**attr
, int element
);
136 static ssize_t
ipp_write_file(int *fd
, ipp_uchar_t
*buffer
,
141 * 'ippAddBoolean()' - Add a boolean attribute to an IPP message.
143 * The @code ipp@ parameter refers to an IPP message previously created using the
144 * @link ippNew@ or @link ippNewRequest@ functions.
146 * The @code group@ parameter specifies the IPP attribute group tag: none
147 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
148 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
149 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
150 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
153 ipp_attribute_t
* /* O - New attribute */
154 ippAddBoolean(ipp_t
*ipp
, /* I - IPP message */
155 ipp_tag_t group
, /* I - IPP group */
156 const char *name
, /* I - Name of attribute */
157 char value
) /* I - Value of attribute */
159 ipp_attribute_t
*attr
; /* New attribute */
162 DEBUG_printf(("ippAddBoolean(ipp=%p, group=%02x(%s), name=\"%s\", value=%d)",
163 ipp
, group
, ippTagString(group
), name
, value
));
166 * Range check input...
169 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
170 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
174 * Create the attribute...
177 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BOOLEAN
, 1)) == NULL
)
180 attr
->values
[0].boolean
= value
;
187 * 'ippAddBooleans()' - Add an array of boolean values.
189 * The @code ipp@ parameter refers to an IPP message previously created using the
190 * @link ippNew@ or @link ippNewRequest@ functions.
192 * The @code group@ parameter specifies the IPP attribute group tag: none
193 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
194 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
195 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
196 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
199 ipp_attribute_t
* /* O - New attribute */
200 ippAddBooleans(ipp_t
*ipp
, /* I - IPP message */
201 ipp_tag_t group
, /* I - IPP group */
202 const char *name
, /* I - Name of attribute */
203 int num_values
, /* I - Number of values */
204 const char *values
) /* I - Values */
206 int i
; /* Looping var */
207 ipp_attribute_t
*attr
; /* New attribute */
208 _ipp_value_t
*value
; /* Current value */
211 DEBUG_printf(("ippAddBooleans(ipp=%p, group=%02x(%s), name=\"%s\", "
212 "num_values=%d, values=%p)", ipp
, group
, ippTagString(group
),
213 name
, num_values
, values
));
216 * Range check input...
219 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
220 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
225 * Create the attribute...
228 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BOOLEAN
, num_values
)) == NULL
)
233 for (i
= num_values
, value
= attr
->values
;
236 value
->boolean
= *values
++;
244 * 'ippAddCollection()' - Add a collection value.
246 * The @code ipp@ parameter refers to an IPP message previously created using the
247 * @link ippNew@ or @link ippNewRequest@ functions.
249 * The @code group@ parameter specifies the IPP attribute group tag: none
250 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
251 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
252 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
253 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
255 * @since CUPS 1.1.19/Mac OS X 10.3@
258 ipp_attribute_t
* /* O - New attribute */
259 ippAddCollection(ipp_t
*ipp
, /* I - IPP message */
260 ipp_tag_t group
, /* I - IPP group */
261 const char *name
, /* I - Name of attribute */
262 ipp_t
*value
) /* I - Value */
264 ipp_attribute_t
*attr
; /* New attribute */
267 DEBUG_printf(("ippAddCollection(ipp=%p, group=%02x(%s), name=\"%s\", "
268 "value=%p)", ipp
, group
, ippTagString(group
), name
, value
));
271 * Range check input...
274 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
275 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
279 * Create the attribute...
282 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BEGIN_COLLECTION
, 1)) == NULL
)
285 attr
->values
[0].collection
= value
;
295 * 'ippAddCollections()' - Add an array of collection values.
297 * The @code ipp@ parameter refers to an IPP message previously created using the
298 * @link ippNew@ or @link ippNewRequest@ functions.
300 * The @code group@ parameter specifies the IPP attribute group tag: none
301 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
302 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
303 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
304 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
306 * @since CUPS 1.1.19/Mac OS X 10.3@
309 ipp_attribute_t
* /* O - New attribute */
311 ipp_t
*ipp
, /* I - IPP message */
312 ipp_tag_t group
, /* I - IPP group */
313 const char *name
, /* I - Name of attribute */
314 int num_values
, /* I - Number of values */
315 const ipp_t
**values
) /* I - Values */
317 int i
; /* Looping var */
318 ipp_attribute_t
*attr
; /* New attribute */
319 _ipp_value_t
*value
; /* Current value */
322 DEBUG_printf(("ippAddCollections(ipp=%p, group=%02x(%s), name=\"%s\", "
323 "num_values=%d, values=%p)", ipp
, group
, ippTagString(group
),
324 name
, num_values
, values
));
327 * Range check input...
330 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
331 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
336 * Create the attribute...
339 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_BEGIN_COLLECTION
,
340 num_values
)) == NULL
)
345 for (i
= num_values
, value
= attr
->values
;
349 value
->collection
= (ipp_t
*)*values
++;
350 value
->collection
->use
++;
359 * 'ippAddDate()' - Add a date attribute to an IPP message.
361 * The @code ipp@ parameter refers to an IPP message previously created using the
362 * @link ippNew@ or @link ippNewRequest@ functions.
364 * The @code group@ parameter specifies the IPP attribute group tag: none
365 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
366 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
367 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
368 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
371 ipp_attribute_t
* /* O - New attribute */
372 ippAddDate(ipp_t
*ipp
, /* I - IPP message */
373 ipp_tag_t group
, /* I - IPP group */
374 const char *name
, /* I - Name of attribute */
375 const ipp_uchar_t
*value
) /* I - Value */
377 ipp_attribute_t
*attr
; /* New attribute */
380 DEBUG_printf(("ippAddDate(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)",
381 ipp
, group
, ippTagString(group
), name
, value
));
384 * Range check input...
387 if (!ipp
|| !name
|| !value
|| group
< IPP_TAG_ZERO
||
388 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
392 * Create the attribute...
395 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_DATE
, 1)) == NULL
)
398 memcpy(attr
->values
[0].date
, value
, 11);
405 * 'ippAddInteger()' - Add a integer attribute to an IPP message.
407 * The @code ipp@ parameter refers to an IPP message previously created using the
408 * @link ippNew@ or @link ippNewRequest@ functions.
410 * The @code group@ parameter specifies the IPP attribute group tag: none
411 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
412 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
413 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
414 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
416 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
417 * (@code IPP_TAG_INTEGER@).
420 ipp_attribute_t
* /* O - New attribute */
421 ippAddInteger(ipp_t
*ipp
, /* I - IPP message */
422 ipp_tag_t group
, /* I - IPP group */
423 ipp_tag_t value_tag
, /* I - Type of attribute */
424 const char *name
, /* I - Name of attribute */
425 int value
) /* I - Value of attribute */
427 ipp_attribute_t
*attr
; /* New attribute */
430 DEBUG_printf(("ippAddInteger(ipp=%p, group=%02x(%s), type=%02x(%s), "
431 "name=\"%s\", value=%d)", ipp
, group
, ippTagString(group
),
432 value_tag
, ippTagString(value_tag
), name
, value
));
434 value_tag
&= IPP_TAG_MASK
;
437 * Special-case for legacy usage: map out-of-band attributes to new ippAddOutOfBand
441 if (value_tag
>= IPP_TAG_UNSUPPORTED_VALUE
&& value_tag
<= IPP_TAG_ADMINDEFINE
)
442 return (ippAddOutOfBand(ipp
, group
, value_tag
, name
));
445 * Range check input...
449 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
450 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
451 (value_tag
!= IPP_TAG_INTEGER
&& value_tag
!= IPP_TAG_ENUM
))
454 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
455 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
460 * Create the attribute...
463 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, 1)) == NULL
)
466 attr
->values
[0].integer
= value
;
473 * 'ippAddIntegers()' - Add an array of integer values.
475 * The @code ipp@ parameter refers to an IPP message previously created using the
476 * @link ippNew@ or @link ippNewRequest@ functions.
478 * The @code group@ parameter specifies the IPP attribute group tag: none
479 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
480 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
481 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
482 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
484 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
485 * (@code IPP_TAG_INTEGER@).
488 ipp_attribute_t
* /* O - New attribute */
489 ippAddIntegers(ipp_t
*ipp
, /* I - IPP message */
490 ipp_tag_t group
, /* I - IPP group */
491 ipp_tag_t value_tag
, /* I - Type of attribute */
492 const char *name
, /* I - Name of attribute */
493 int num_values
, /* I - Number of values */
494 const int *values
) /* I - Values */
496 int i
; /* Looping var */
497 ipp_attribute_t
*attr
; /* New attribute */
498 _ipp_value_t
*value
; /* Current value */
501 DEBUG_printf(("ippAddIntegers(ipp=%p, group=%02x(%s), type=%02x(%s), "
502 "name=\"%s\", num_values=%d, values=%p)", ipp
,
503 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
504 num_values
, values
));
506 value_tag
&= IPP_TAG_MASK
;
509 * Range check input...
513 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
514 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
515 (value_tag
!= IPP_TAG_INTEGER
&& value_tag
!= IPP_TAG_ENUM
) ||
519 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
520 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
526 * Create the attribute...
529 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, num_values
)) == NULL
)
534 for (i
= num_values
, value
= attr
->values
;
537 value
->integer
= *values
++;
545 * 'ippAddOctetString()' - Add an octetString value to an IPP message.
547 * The @code ipp@ parameter refers to an IPP message previously created using the
548 * @link ippNew@ or @link ippNewRequest@ functions.
550 * The @code group@ parameter specifies the IPP attribute group tag: none
551 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
552 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
553 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
554 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
556 * @since CUPS 1.2/Mac OS X 10.5@
559 ipp_attribute_t
* /* O - New attribute */
560 ippAddOctetString(ipp_t
*ipp
, /* I - IPP message */
561 ipp_tag_t group
, /* I - IPP group */
562 const char *name
, /* I - Name of attribute */
563 const void *data
, /* I - octetString data */
564 int datalen
) /* I - Length of data in bytes */
566 ipp_attribute_t
*attr
; /* New attribute */
569 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
570 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
573 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_STRING
, 1)) == NULL
)
577 * Initialize the attribute data...
580 attr
->values
[0].unknown
.length
= datalen
;
584 if ((attr
->values
[0].unknown
.data
= malloc(datalen
)) == NULL
)
586 ippDeleteAttribute(ipp
, attr
);
590 memcpy(attr
->values
[0].unknown
.data
, data
, datalen
);
594 * Return the new attribute...
602 * 'ippAddOutOfBand()' - Add an out-of-band value to an IPP message.
604 * The @code ipp@ parameter refers to an IPP message previously created using the
605 * @link ippNew@ or @link ippNewRequest@ functions.
607 * The @code group@ parameter specifies the IPP attribute group tag: none
608 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
609 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
610 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
611 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
613 * Supported out-of-band values include unsupported-value
614 * (@code IPP_TAG_UNSUPPORTED_VALUE@), default (@code IPP_TAG_DEFAULT@), unknown
615 * (@code IPP_TAG_UNKNOWN@), no-value (@code IPP_TAG_NOVALUE@), not-settable
616 * (@code IPP_TAG_NOTSETTABLE@), delete-attribute (@code IPP_TAG_DELETEATTR@), and
617 * admin-define (@code IPP_TAG_ADMINDEFINE@).
622 ipp_attribute_t
* /* O - New attribute */
623 ippAddOutOfBand(ipp_t
*ipp
, /* I - IPP message */
624 ipp_tag_t group
, /* I - IPP group */
625 ipp_tag_t value_tag
, /* I - Type of attribute */
626 const char *name
) /* I - Name of attribute */
628 DEBUG_printf(("ippAddOutOfBand(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
629 "name=\"%s\")", ipp
, group
, ippTagString(group
), value_tag
,
630 ippTagString(value_tag
), name
));
632 value_tag
&= IPP_TAG_MASK
;
635 * Range check input...
638 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
639 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
640 (value_tag
!= IPP_TAG_UNSUPPORTED_VALUE
&&
641 value_tag
!= IPP_TAG_DEFAULT
&&
642 value_tag
!= IPP_TAG_UNKNOWN
&&
643 value_tag
!= IPP_TAG_NOVALUE
&&
644 value_tag
!= IPP_TAG_NOTSETTABLE
&&
645 value_tag
!= IPP_TAG_DELETEATTR
&&
646 value_tag
!= IPP_TAG_ADMINDEFINE
))
650 * Create the attribute...
653 return (ipp_add_attr(ipp
, name
, group
, value_tag
, 1));
658 * 'ippAddRange()' - Add a range of values to an IPP message.
660 * The @code ipp@ parameter refers to an IPP message previously created using the
661 * @link ippNew@ or @link ippNewRequest@ functions.
663 * The @code group@ parameter specifies the IPP attribute group tag: none
664 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
665 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
666 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
667 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
669 * The @code lower@ parameter must be less than or equal to the @code upper@ parameter.
672 ipp_attribute_t
* /* O - New attribute */
673 ippAddRange(ipp_t
*ipp
, /* I - IPP message */
674 ipp_tag_t group
, /* I - IPP group */
675 const char *name
, /* I - Name of attribute */
676 int lower
, /* I - Lower value */
677 int upper
) /* I - Upper value */
679 ipp_attribute_t
*attr
; /* New attribute */
682 DEBUG_printf(("ippAddRange(ipp=%p, group=%02x(%s), name=\"%s\", lower=%d, "
683 "upper=%d)", ipp
, group
, ippTagString(group
), name
, lower
,
687 * Range check input...
690 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
691 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
695 * Create the attribute...
698 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RANGE
, 1)) == NULL
)
701 attr
->values
[0].range
.lower
= lower
;
702 attr
->values
[0].range
.upper
= upper
;
709 * 'ippAddRanges()' - Add ranges of values to an IPP message.
711 * The @code ipp@ parameter refers to an IPP message previously created using the
712 * @link ippNew@ or @link ippNewRequest@ functions.
714 * The @code group@ parameter specifies the IPP attribute group tag: none
715 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
716 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
717 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
718 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
721 ipp_attribute_t
* /* O - New attribute */
722 ippAddRanges(ipp_t
*ipp
, /* I - IPP message */
723 ipp_tag_t group
, /* I - IPP group */
724 const char *name
, /* I - Name of attribute */
725 int num_values
, /* I - Number of values */
726 const int *lower
, /* I - Lower values */
727 const int *upper
) /* I - Upper values */
729 int i
; /* Looping var */
730 ipp_attribute_t
*attr
; /* New attribute */
731 _ipp_value_t
*value
; /* Current value */
734 DEBUG_printf(("ippAddRanges(ipp=%p, group=%02x(%s), name=\"%s\", "
735 "num_values=%d, lower=%p, upper=%p)", ipp
, group
,
736 ippTagString(group
), name
, num_values
, lower
, upper
));
739 * Range check input...
742 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
743 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
748 * Create the attribute...
751 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RANGE
, num_values
)) == NULL
)
756 for (i
= num_values
, value
= attr
->values
;
760 value
->range
.lower
= *lower
++;
761 value
->range
.upper
= *upper
++;
770 * 'ippAddResolution()' - Add a resolution value to an IPP message.
772 * The @code ipp@ parameter refers to an IPP message previously created using the
773 * @link ippNew@ or @link ippNewRequest@ functions.
775 * The @code group@ parameter specifies the IPP attribute group tag: none
776 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
777 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
778 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
779 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
782 ipp_attribute_t
* /* O - New attribute */
783 ippAddResolution(ipp_t
*ipp
, /* I - IPP message */
784 ipp_tag_t group
, /* I - IPP group */
785 const char *name
, /* I - Name of attribute */
786 ipp_res_t units
, /* I - Units for resolution */
787 int xres
, /* I - X resolution */
788 int yres
) /* I - Y resolution */
790 ipp_attribute_t
*attr
; /* New attribute */
793 DEBUG_printf(("ippAddResolution(ipp=%p, group=%02x(%s), name=\"%s\", "
794 "units=%d, xres=%d, yres=%d)", ipp
, group
,
795 ippTagString(group
), name
, units
, xres
, yres
));
798 * Range check input...
801 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
802 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
803 units
< IPP_RES_PER_INCH
|| units
> IPP_RES_PER_CM
||
804 xres
< 0 || yres
< 0)
808 * Create the attribute...
811 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RESOLUTION
, 1)) == NULL
)
814 attr
->values
[0].resolution
.xres
= xres
;
815 attr
->values
[0].resolution
.yres
= yres
;
816 attr
->values
[0].resolution
.units
= units
;
823 * 'ippAddResolutions()' - Add resolution values to an IPP message.
825 * The @code ipp@ parameter refers to an IPP message previously created using the
826 * @link ippNew@ or @link ippNewRequest@ functions.
828 * The @code group@ parameter specifies the IPP attribute group tag: none
829 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
830 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
831 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
832 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
835 ipp_attribute_t
* /* O - New attribute */
836 ippAddResolutions(ipp_t
*ipp
, /* I - IPP message */
837 ipp_tag_t group
, /* I - IPP group */
838 const char *name
, /* I - Name of attribute */
839 int num_values
,/* I - Number of values */
840 ipp_res_t units
, /* I - Units for resolution */
841 const int *xres
, /* I - X resolutions */
842 const int *yres
) /* I - Y resolutions */
844 int i
; /* Looping var */
845 ipp_attribute_t
*attr
; /* New attribute */
846 _ipp_value_t
*value
; /* Current value */
849 DEBUG_printf(("ippAddResolutions(ipp=%p, group=%02x(%s), name=\"%s\", "
850 "num_value=%d, units=%d, xres=%p, yres=%p)", ipp
, group
,
851 ippTagString(group
), name
, num_values
, units
, xres
, yres
));
854 * Range check input...
857 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
858 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
860 units
< IPP_RES_PER_INCH
|| units
> IPP_RES_PER_CM
)
864 * Create the attribute...
867 if ((attr
= ipp_add_attr(ipp
, name
, group
, IPP_TAG_RESOLUTION
, num_values
)) == NULL
)
872 for (i
= num_values
, value
= attr
->values
;
876 value
->resolution
.xres
= *xres
++;
877 value
->resolution
.yres
= *yres
++;
878 value
->resolution
.units
= units
;
887 * 'ippAddSeparator()' - Add a group separator to an IPP message.
889 * The @code ipp@ parameter refers to an IPP message previously created using the
890 * @link ippNew@ or @link ippNewRequest@ functions.
893 ipp_attribute_t
* /* O - New attribute */
894 ippAddSeparator(ipp_t
*ipp
) /* I - IPP message */
896 DEBUG_printf(("ippAddSeparator(ipp=%p)", ipp
));
899 * Range check input...
906 * Create the attribute...
909 return (ipp_add_attr(ipp
, NULL
, IPP_TAG_ZERO
, IPP_TAG_ZERO
, 0));
914 * 'ippAddString()' - Add a language-encoded string to an IPP message.
916 * The @code ipp@ parameter refers to an IPP message previously created using the
917 * @link ippNew@ or @link ippNewRequest@ functions.
919 * The @code group@ parameter specifies the IPP attribute group tag: none
920 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
921 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
922 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
923 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
925 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
926 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
927 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
928 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
929 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
930 * (@code IPP_TAG_URISCHEME@).
932 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
933 * textWithLanguage string values and must be @code NULL@ for all other string values.
936 ipp_attribute_t
* /* O - New attribute */
937 ippAddString(ipp_t
*ipp
, /* I - IPP message */
938 ipp_tag_t group
, /* I - IPP group */
939 ipp_tag_t value_tag
, /* I - Type of attribute */
940 const char *name
, /* I - Name of attribute */
941 const char *language
, /* I - Language code */
942 const char *value
) /* I - Value */
944 ipp_tag_t temp_tag
; /* Temporary value tag (masked) */
945 ipp_attribute_t
*attr
; /* New attribute */
946 char code
[32]; /* Charset/language code buffer */
949 DEBUG_printf(("ippAddString(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
950 "name=\"%s\", language=\"%s\", value=\"%s\")", ipp
,
951 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
955 * Range check input...
958 temp_tag
= (ipp_tag_t
)((int)value_tag
& IPP_TAG_MASK
);
961 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
962 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
963 (temp_tag
< IPP_TAG_TEXT
&& temp_tag
!= IPP_TAG_TEXTLANG
&&
964 temp_tag
!= IPP_TAG_NAMELANG
) || temp_tag
> IPP_TAG_MIMETYPE
)
967 if ((temp_tag
== IPP_TAG_TEXTLANG
|| temp_tag
== IPP_TAG_NAMELANG
)
968 != (language
!= NULL
))
971 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
972 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
)
977 * See if we need to map charset, language, or locale values...
980 if (language
&& ((int)value_tag
& IPP_TAG_COPY
) &&
981 strcmp(language
, ipp_lang_code(language
, code
, sizeof(code
))))
982 value_tag
= temp_tag
; /* Don't do a fast copy */
983 else if (value
&& value_tag
== (ipp_tag_t
)(IPP_TAG_CHARSET
| IPP_TAG_COPY
) &&
984 strcmp(value
, ipp_get_code(value
, code
, sizeof(code
))))
985 value_tag
= temp_tag
; /* Don't do a fast copy */
986 else if (value
&& value_tag
== (ipp_tag_t
)(IPP_TAG_LANGUAGE
| IPP_TAG_COPY
) &&
987 strcmp(value
, ipp_lang_code(value
, code
, sizeof(code
))))
988 value_tag
= temp_tag
; /* Don't do a fast copy */
991 * Create the attribute...
994 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, 1)) == NULL
)
998 * Initialize the attribute data...
1001 if ((int)value_tag
& IPP_TAG_COPY
)
1003 attr
->values
[0].string
.language
= (char *)language
;
1004 attr
->values
[0].string
.text
= (char *)value
;
1009 attr
->values
[0].string
.language
= _cupsStrAlloc(ipp_lang_code(language
, code
,
1012 if (value_tag
== IPP_TAG_CHARSET
)
1013 attr
->values
[0].string
.text
= _cupsStrAlloc(ipp_get_code(value
, code
,
1015 else if (value_tag
== IPP_TAG_LANGUAGE
)
1016 attr
->values
[0].string
.text
= _cupsStrAlloc(ipp_lang_code(value
, code
,
1019 attr
->values
[0].string
.text
= _cupsStrAlloc(value
);
1027 * 'ippAddStrings()' - Add language-encoded strings to an IPP message.
1029 * The @code ipp@ parameter refers to an IPP message previously created using the
1030 * @link ippNew@ or @link ippNewRequest@ functions.
1032 * The @code group@ parameter specifies the IPP attribute group tag: none
1033 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
1034 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
1035 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
1036 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1038 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1039 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1040 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1041 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1042 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1043 * (@code IPP_TAG_URISCHEME@).
1045 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
1046 * textWithLanguage string values and must be @code NULL@ for all other string values.
1049 ipp_attribute_t
* /* O - New attribute */
1051 ipp_t
*ipp
, /* I - IPP message */
1052 ipp_tag_t group
, /* I - IPP group */
1053 ipp_tag_t value_tag
, /* I - Type of attribute */
1054 const char *name
, /* I - Name of attribute */
1055 int num_values
, /* I - Number of values */
1056 const char *language
, /* I - Language code (@code NULL@ for default) */
1057 const char * const *values
) /* I - Values */
1059 int i
; /* Looping var */
1060 ipp_tag_t temp_tag
; /* Temporary value tag (masked) */
1061 ipp_attribute_t
*attr
; /* New attribute */
1062 _ipp_value_t
*value
; /* Current value */
1063 char code
[32]; /* Language/charset value buffer */
1066 DEBUG_printf(("ippAddStrings(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
1067 "name=\"%s\", num_values=%d, language=\"%s\", values=%p)", ipp
,
1068 group
, ippTagString(group
), value_tag
, ippTagString(value_tag
), name
,
1069 num_values
, language
, values
));
1072 * Range check input...
1075 temp_tag
= (ipp_tag_t
)((int)value_tag
& IPP_TAG_MASK
);
1078 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1079 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1080 (temp_tag
< IPP_TAG_TEXT
&& temp_tag
!= IPP_TAG_TEXTLANG
&&
1081 temp_tag
!= IPP_TAG_NAMELANG
) || temp_tag
> IPP_TAG_MIMETYPE
||
1085 if ((temp_tag
== IPP_TAG_TEXTLANG
|| temp_tag
== IPP_TAG_NAMELANG
)
1086 != (language
!= NULL
))
1089 if (!ipp
|| !name
|| group
< IPP_TAG_ZERO
||
1090 group
== IPP_TAG_END
|| group
>= IPP_TAG_UNSUPPORTED_VALUE
||
1096 * See if we need to map charset, language, or locale values...
1099 if (language
&& ((int)value_tag
& IPP_TAG_COPY
) &&
1100 strcmp(language
, ipp_lang_code(language
, code
, sizeof(code
))))
1101 value_tag
= temp_tag
; /* Don't do a fast copy */
1102 else if (values
&& value_tag
== (ipp_tag_t
)(IPP_TAG_CHARSET
| IPP_TAG_COPY
))
1104 for (i
= 0; i
< num_values
; i
++)
1105 if (strcmp(values
[i
], ipp_get_code(values
[i
], code
, sizeof(code
))))
1107 value_tag
= temp_tag
; /* Don't do a fast copy */
1111 else if (values
&& value_tag
== (ipp_tag_t
)(IPP_TAG_LANGUAGE
| IPP_TAG_COPY
))
1113 for (i
= 0; i
< num_values
; i
++)
1114 if (strcmp(values
[i
], ipp_lang_code(values
[i
], code
, sizeof(code
))))
1116 value_tag
= temp_tag
; /* Don't do a fast copy */
1122 * Create the attribute...
1125 if ((attr
= ipp_add_attr(ipp
, name
, group
, value_tag
, num_values
)) == NULL
)
1129 * Initialize the attribute data...
1132 for (i
= num_values
, value
= attr
->values
;
1138 if (value
== attr
->values
)
1140 if ((int)value_tag
& IPP_TAG_COPY
)
1141 value
->string
.language
= (char *)language
;
1143 value
->string
.language
= _cupsStrAlloc(ipp_lang_code(language
, code
,
1147 value
->string
.language
= attr
->values
[0].string
.language
;
1152 if ((int)value_tag
& IPP_TAG_COPY
)
1153 value
->string
.text
= (char *)*values
++;
1154 else if (value_tag
== IPP_TAG_CHARSET
)
1155 value
->string
.text
= _cupsStrAlloc(ipp_get_code(*values
++, code
, sizeof(code
)));
1156 else if (value_tag
== IPP_TAG_LANGUAGE
)
1157 value
->string
.text
= _cupsStrAlloc(ipp_lang_code(*values
++, code
, sizeof(code
)));
1159 value
->string
.text
= _cupsStrAlloc(*values
++);
1168 * 'ippCopyAttribute()' - Copy an attribute.
1170 * The specified attribute, @code attr@, is copied to the destination IPP message.
1171 * When @code quickcopy@ is non-zero, a "shallow" reference copy of the attribute is
1172 * created - this should only be done as long as the original source IPP message will
1173 * not be freed for the life of the destination.
1179 ipp_attribute_t
* /* O - New attribute */
1181 ipp_t
*dst
, /* I - Destination IPP message */
1182 ipp_attribute_t
*srcattr
, /* I - Attribute to copy */
1183 int quickcopy
) /* I - 1 for a referenced copy, 0 for normal */
1185 int i
; /* Looping var */
1186 ipp_attribute_t
*dstattr
; /* Destination attribute */
1187 _ipp_value_t
*srcval
, /* Source value */
1188 *dstval
; /* Destination value */
1191 DEBUG_printf(("ippCopyAttribute(dst=%p, srcattr=%p, quickcopy=%d)", dst
, srcattr
,
1195 * Range check input...
1198 if (!dst
|| !srcattr
)
1205 quickcopy
= quickcopy
? IPP_TAG_COPY
: 0;
1207 switch (srcattr
->value_tag
& ~IPP_TAG_COPY
)
1210 dstattr
= ippAddSeparator(dst
);
1213 case IPP_TAG_INTEGER
:
1215 dstattr
= ippAddIntegers(dst
, srcattr
->group_tag
, srcattr
->value_tag
,
1216 srcattr
->name
, srcattr
->num_values
, NULL
);
1220 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1222 i
--, srcval
++, dstval
++)
1223 dstval
->integer
= srcval
->integer
;
1226 case IPP_TAG_BOOLEAN
:
1227 dstattr
= ippAddBooleans(dst
, srcattr
->group_tag
, srcattr
->name
,
1228 srcattr
->num_values
, NULL
);
1232 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1234 i
--, srcval
++, dstval
++)
1235 dstval
->boolean
= srcval
->boolean
;
1240 case IPP_TAG_KEYWORD
:
1242 case IPP_TAG_URISCHEME
:
1243 case IPP_TAG_CHARSET
:
1244 case IPP_TAG_LANGUAGE
:
1245 case IPP_TAG_MIMETYPE
:
1246 dstattr
= ippAddStrings(dst
, srcattr
->group_tag
,
1247 (ipp_tag_t
)(srcattr
->value_tag
| quickcopy
),
1248 srcattr
->name
, srcattr
->num_values
, NULL
, NULL
);
1254 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1255 dstval
= dstattr
->values
;
1257 i
--, srcval
++, dstval
++)
1258 dstval
->string
.text
= srcval
->string
.text
;
1260 else if (srcattr
->value_tag
& IPP_TAG_COPY
)
1262 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1263 dstval
= dstattr
->values
;
1265 i
--, srcval
++, dstval
++)
1266 dstval
->string
.text
= _cupsStrAlloc(srcval
->string
.text
);
1270 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1271 dstval
= dstattr
->values
;
1273 i
--, srcval
++, dstval
++)
1274 dstval
->string
.text
= _cupsStrRetain(srcval
->string
.text
);
1279 if (srcattr
->num_values
!= 1)
1282 dstattr
= ippAddDate(dst
, srcattr
->group_tag
, srcattr
->name
,
1283 srcattr
->values
[0].date
);
1286 case IPP_TAG_RESOLUTION
:
1287 dstattr
= ippAddResolutions(dst
, srcattr
->group_tag
, srcattr
->name
,
1288 srcattr
->num_values
, IPP_RES_PER_INCH
,
1293 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1295 i
--, srcval
++, dstval
++)
1297 dstval
->resolution
.xres
= srcval
->resolution
.xres
;
1298 dstval
->resolution
.yres
= srcval
->resolution
.yres
;
1299 dstval
->resolution
.units
= srcval
->resolution
.units
;
1303 case IPP_TAG_RANGE
:
1304 dstattr
= ippAddRanges(dst
, srcattr
->group_tag
, srcattr
->name
,
1305 srcattr
->num_values
, NULL
, NULL
);
1309 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1311 i
--, srcval
++, dstval
++)
1313 dstval
->range
.lower
= srcval
->range
.lower
;
1314 dstval
->range
.upper
= srcval
->range
.upper
;
1318 case IPP_TAG_TEXTLANG
:
1319 case IPP_TAG_NAMELANG
:
1320 dstattr
= ippAddStrings(dst
, srcattr
->group_tag
,
1321 (ipp_tag_t
)(srcattr
->value_tag
| quickcopy
),
1322 srcattr
->name
, srcattr
->num_values
, NULL
, NULL
);
1328 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1329 dstval
= dstattr
->values
;
1331 i
--, srcval
++, dstval
++)
1333 dstval
->string
.language
= srcval
->string
.language
;
1334 dstval
->string
.text
= srcval
->string
.text
;
1337 else if (srcattr
->value_tag
& IPP_TAG_COPY
)
1339 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1340 dstval
= dstattr
->values
;
1342 i
--, srcval
++, dstval
++)
1344 if (srcval
== srcattr
->values
)
1345 dstval
->string
.language
= _cupsStrAlloc(srcval
->string
.language
);
1347 dstval
->string
.language
= dstattr
->values
[0].string
.language
;
1349 dstval
->string
.text
= _cupsStrAlloc(srcval
->string
.text
);
1354 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
,
1355 dstval
= dstattr
->values
;
1357 i
--, srcval
++, dstval
++)
1359 if (srcval
== srcattr
->values
)
1360 dstval
->string
.language
= _cupsStrRetain(srcval
->string
.language
);
1362 dstval
->string
.language
= dstattr
->values
[0].string
.language
;
1364 dstval
->string
.text
= _cupsStrRetain(srcval
->string
.text
);
1369 case IPP_TAG_BEGIN_COLLECTION
:
1370 dstattr
= ippAddCollections(dst
, srcattr
->group_tag
, srcattr
->name
,
1371 srcattr
->num_values
, NULL
);
1375 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1377 i
--, srcval
++, dstval
++)
1379 dstval
->collection
= srcval
->collection
;
1380 srcval
->collection
->use
++;
1384 case IPP_TAG_STRING
:
1386 /* TODO: Implement quick copy for unknown/octetString values */
1387 dstattr
= ippAddIntegers(dst
, srcattr
->group_tag
, srcattr
->value_tag
,
1388 srcattr
->name
, srcattr
->num_values
, NULL
);
1392 for (i
= srcattr
->num_values
, srcval
= srcattr
->values
, dstval
= dstattr
->values
;
1394 i
--, srcval
++, dstval
++)
1396 dstval
->unknown
.length
= srcval
->unknown
.length
;
1398 if (dstval
->unknown
.length
> 0)
1400 if ((dstval
->unknown
.data
= malloc(dstval
->unknown
.length
)) == NULL
)
1401 dstval
->unknown
.length
= 0;
1403 memcpy(dstval
->unknown
.data
, srcval
->unknown
.data
, dstval
->unknown
.length
);
1406 break; /* anti-compiler-warning-code */
1414 * 'ippCopyAttributes()' - Copy attributes from one IPP message to another.
1416 * Zero or more attributes are copied from the source IPP message, @code@ src, to the
1417 * destination IPP message, @code dst@. When @code quickcopy@ is non-zero, a "shallow"
1418 * reference copy of the attribute is created - this should only be done as long as the
1419 * original source IPP message will not be freed for the life of the destination.
1421 * The @code cb@ and @code context@ parameters provide a generic way to "filter" the
1422 * attributes that are copied - the function must return 1 to copy the attribute or
1423 * 0 to skip it. The function may also choose to do a partial copy of the source attribute
1429 int /* O - 1 on success, 0 on error */
1431 ipp_t
*dst
, /* I - Destination IPP message */
1432 ipp_t
*src
, /* I - Source IPP message */
1433 int quickcopy
, /* I - 1 for a referenced copy, 0 for normal */
1434 ipp_copycb_t cb
, /* I - Copy callback or @code NULL@ for none */
1435 void *context
) /* I - Context pointer */
1437 ipp_attribute_t
*srcattr
; /* Source attribute */
1440 DEBUG_printf(("ippCopyAttributes(dst=%p, src=%p, quickcopy=%d, cb=%p, context=%p)",
1441 dst
, src
, quickcopy
, cb
, context
));
1444 * Range check input...
1451 * Loop through source attributes and copy as needed...
1454 for (srcattr
= src
->attrs
; srcattr
; srcattr
= srcattr
->next
)
1455 if (!cb
|| (*cb
)(context
, dst
, srcattr
))
1456 if (!ippCopyAttribute(dst
, srcattr
, quickcopy
))
1464 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
1468 time_t /* O - UNIX time value */
1469 ippDateToTime(const ipp_uchar_t
*date
) /* I - RFC 1903 date info */
1471 struct tm unixdate
; /* UNIX date/time info */
1472 time_t t
; /* Computed time */
1478 memset(&unixdate
, 0, sizeof(unixdate
));
1481 * RFC-1903 date/time format is:
1483 * Byte(s) Description
1484 * ------- -----------
1485 * 0-1 Year (0 to 65535)
1489 * 5 Minutes (0 to 59)
1490 * 6 Seconds (0 to 60, 60 = "leap second")
1491 * 7 Deciseconds (0 to 9)
1493 * 9 UTC hours (0 to 11)
1494 * 10 UTC minutes (0 to 59)
1497 unixdate
.tm_year
= ((date
[0] << 8) | date
[1]) - 1900;
1498 unixdate
.tm_mon
= date
[2] - 1;
1499 unixdate
.tm_mday
= date
[3];
1500 unixdate
.tm_hour
= date
[4];
1501 unixdate
.tm_min
= date
[5];
1502 unixdate
.tm_sec
= date
[6];
1504 t
= mktime(&unixdate
);
1507 t
+= date
[9] * 3600 + date
[10] * 60;
1509 t
-= date
[9] * 3600 + date
[10] * 60;
1516 * 'ippDelete()' - Delete an IPP message.
1520 ippDelete(ipp_t
*ipp
) /* I - IPP message */
1522 ipp_attribute_t
*attr
, /* Current attribute */
1523 *next
; /* Next attribute */
1526 DEBUG_printf(("ippDelete(ipp=%p)", ipp
));
1535 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= next
)
1539 ipp_free_values(attr
, 0, attr
->num_values
);
1542 _cupsStrFree(attr
->name
);
1552 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
1554 * @since CUPS 1.1.19/Mac OS X 10.3@
1559 ipp_t
*ipp
, /* I - IPP message */
1560 ipp_attribute_t
*attr
) /* I - Attribute to delete */
1562 ipp_attribute_t
*current
, /* Current attribute */
1563 *prev
; /* Previous attribute */
1566 DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p(%s))", ipp
, attr
,
1567 attr
? attr
->name
: "(null)"));
1570 * Range check input...
1577 * Find the attribute in the list...
1582 for (current
= ipp
->attrs
, prev
= NULL
;
1584 prev
= current
, current
= current
->next
)
1585 if (current
== attr
)
1588 * Found it, remove the attribute from the list...
1592 prev
->next
= current
->next
;
1594 ipp
->attrs
= current
->next
;
1596 if (current
== ipp
->last
)
1607 * Free memory used by the attribute...
1610 ipp_free_values(attr
, 0, attr
->num_values
);
1613 _cupsStrFree(attr
->name
);
1620 * 'ippDeleteValues()' - Delete values in an attribute.
1622 * The @code element@ parameter specifies the first value to delete, starting at
1623 * 0. It must be less than the number of values returned by @link ippGetCount@.
1625 * The @code attr@ parameter may be modified as a result of setting the value.
1627 * Deleting all values in an attribute deletes the attribute.
1632 int /* O - 1 on success, 0 on failure */
1634 ipp_t
*ipp
, /* I - IPP message */
1635 ipp_attribute_t
**attr
, /* IO - Attribute */
1636 int element
, /* I - Index of first value to delete (0-based) */
1637 int count
) /* I - Number of values to delete */
1640 * Range check input...
1643 if (!ipp
|| !attr
|| !*attr
||
1644 element
< 0 || element
>= (*attr
)->num_values
|| count
<= 0 ||
1645 (element
+ count
) >= (*attr
)->num_values
)
1649 * If we are deleting all values, just delete the attribute entirely.
1652 if (count
== (*attr
)->num_values
)
1654 ippDeleteAttribute(ipp
, *attr
);
1660 * Otherwise free the values in question and return.
1663 ipp_free_values(*attr
, element
, count
);
1670 * 'ippFindAttribute()' - Find a named attribute in a request.
1673 ipp_attribute_t
* /* O - Matching attribute */
1674 ippFindAttribute(ipp_t
*ipp
, /* I - IPP message */
1675 const char *name
, /* I - Name of attribute */
1676 ipp_tag_t type
) /* I - Type of attribute */
1678 DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", ipp
,
1679 name
, type
, ippTagString(type
)));
1685 * Reset the current pointer...
1688 ipp
->current
= NULL
;
1691 * Search for the attribute...
1694 return (ippFindNextAttribute(ipp
, name
, type
));
1699 * 'ippFindNextAttribute()' - Find the next named attribute in a request.
1702 ipp_attribute_t
* /* O - Matching attribute */
1703 ippFindNextAttribute(ipp_t
*ipp
, /* I - IPP message */
1704 const char *name
, /* I - Name of attribute */
1705 ipp_tag_t type
) /* I - Type of attribute */
1707 ipp_attribute_t
*attr
; /* Current atttribute */
1708 ipp_tag_t value_tag
; /* Value tag */
1711 DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))",
1712 ipp
, name
, type
, ippTagString(type
)));
1719 ipp
->prev
= ipp
->current
;
1720 attr
= ipp
->current
->next
;
1728 for (; attr
!= NULL
; ipp
->prev
= attr
, attr
= attr
->next
)
1730 DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", attr
,
1733 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_MASK
);
1735 if (attr
->name
!= NULL
&& _cups_strcasecmp(attr
->name
, name
) == 0 &&
1736 (value_tag
== type
|| type
== IPP_TAG_ZERO
||
1737 (value_tag
== IPP_TAG_TEXTLANG
&& type
== IPP_TAG_TEXT
) ||
1738 (value_tag
== IPP_TAG_NAMELANG
&& type
== IPP_TAG_NAME
)))
1740 ipp
->current
= attr
;
1746 ipp
->current
= NULL
;
1754 * 'ippFirstAttribute()' - Return the first attribute in the message.
1759 ipp_attribute_t
* /* O - First attribute or @code NULL@ if none */
1760 ippFirstAttribute(ipp_t
*ipp
) /* I - IPP message */
1763 * Range check input...
1770 * Return the first attribute...
1773 return (ipp
->current
= ipp
->attrs
);
1778 * 'ippGetBoolean()' - Get a boolean value for an attribute.
1780 * The @code element@ parameter specifies which value to get from 0 to
1781 * @link ippGetCount(attr)@ - 1.
1786 int /* O - Boolean value or -1 on error */
1787 ippGetBoolean(ipp_attribute_t
*attr
, /* I - IPP attribute */
1788 int element
) /* I - Value number (0-based) */
1791 * Range check input...
1794 if (!attr
|| attr
->value_tag
!= IPP_TAG_BOOLEAN
||
1795 element
< 0 || element
>= attr
->num_values
)
1799 * Return the value...
1802 return (attr
->values
[element
].boolean
);
1807 * 'ippGetCollection()' - Get a collection value for an attribute.
1809 * The @code element@ parameter specifies which value to get from 0 to
1810 * @link ippGetCount(attr)@ - 1.
1815 ipp_t
* /* O - Collection value or @code NULL@ on error */
1817 ipp_attribute_t
*attr
, /* I - IPP attribute */
1818 int element
) /* I - Value number (0-based) */
1821 * Range check input...
1824 if (!attr
|| attr
->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
1825 element
< 0 || element
>= attr
->num_values
)
1829 * Return the value...
1832 return (attr
->values
[element
].collection
);
1837 * 'ippGetCount()' - Get the number of values in an attribute.
1842 int /* O - Number of values or -1 on error */
1843 ippGetCount(ipp_attribute_t
*attr
) /* I - IPP attribute */
1846 * Range check input...
1853 * Return the number of values...
1856 return (attr
->num_values
);
1861 * 'ippGetDate()' - Get a date value for an attribute.
1863 * The @code element@ parameter specifies which value to get from 0 to
1864 * @link ippGetCount(attr)@ - 1.
1869 const ipp_uchar_t
* /* O - Date value or @code NULL@ */
1870 ippGetDate(ipp_attribute_t
*attr
, /* I - IPP attribute */
1871 int element
) /* I - Value number (0-based) */
1874 * Range check input...
1877 if (!attr
|| attr
->value_tag
!= IPP_TAG_DATE
||
1878 element
< 0 || element
>= attr
->num_values
)
1882 * Return the value...
1885 return (attr
->values
[element
].date
);
1890 * 'ippGetGroupTag()' - Get the group associated with an attribute.
1895 ipp_tag_t
/* O - Group tag or @code IPP_TAG_ZERO@ on error */
1896 ippGetGroupTag(ipp_attribute_t
*attr
) /* I - IPP attribute */
1899 * Range check input...
1903 return (IPP_TAG_ZERO
);
1906 * Return the group...
1909 return (attr
->group_tag
);
1914 * 'ippGetInteger()' - Get the integer/enum value for an attribute.
1916 * The @code element@ parameter specifies which value to get from 0 to
1917 * @link ippGetCount(attr)@ - 1.
1922 int /* O - Value or -1 on error */
1923 ippGetInteger(ipp_attribute_t
*attr
, /* I - IPP attribute */
1924 int element
) /* I - Value number (0-based) */
1927 * Range check input...
1930 if (!attr
|| (attr
->value_tag
!= IPP_TAG_INTEGER
&& attr
->value_tag
!= IPP_TAG_ENUM
) ||
1931 element
< 0 || element
>= attr
->num_values
)
1935 * Return the value...
1938 return (attr
->values
[element
].integer
);
1943 * 'ippGetName()' - Get the attribute name.
1948 const char * /* O - Attribute name or @code NULL@ for separators */
1949 ippGetName(ipp_attribute_t
*attr
) /* I - IPP attribute */
1952 * Range check input...
1959 * Return the name...
1962 return (attr
->name
);
1967 * 'ippGetOperation()' - Get the operation ID in an IPP message.
1972 ipp_op_t
/* O - Operation ID or -1 on error */
1973 ippGetOperation(ipp_t
*ipp
) /* I - IPP request message */
1976 * Range check input...
1980 return ((ipp_op_t
)-1);
1983 * Return the value...
1986 return (ipp
->request
.op
.operation_id
);
1991 * 'ippGetRange()' - Get a rangeOfInteger value from an attribute.
1993 * The @code element@ parameter specifies which value to get from 0 to
1994 * @link ippGetCount(attr)@ - 1.
1999 int /* O - Lower value of range or -1 */
2000 ippGetRange(ipp_attribute_t
*attr
, /* I - IPP attribute */
2001 int element
, /* I - Value number (0-based) */
2002 int *uppervalue
)/* O - Upper value of range */
2005 * Range check input...
2008 if (!attr
|| attr
->value_tag
!= IPP_TAG_RANGE
||
2009 element
< 0 || element
>= attr
->num_values
)
2018 * Return the values...
2022 *uppervalue
= attr
->values
[element
].range
.upper
;
2024 return (attr
->values
[element
].range
.lower
);
2029 * 'ippGetRequestId()' - Get the request ID from an IPP message.
2034 int /* O - Request ID or -1 on error */
2035 ippGetRequestId(ipp_t
*ipp
) /* I - IPP message */
2038 * Range check input...
2045 * Return the request ID...
2048 return (ipp
->request
.any
.request_id
);
2053 * 'ippGetResolution()' - Get a resolution value for an attribute.
2055 * The @code element@ parameter specifies which value to get from 0 to
2056 * @link ippGetCount(attr)@ - 1.
2061 int /* O - Horizontal/cross feed resolution or -1 */
2063 ipp_attribute_t
*attr
, /* I - IPP attribute */
2064 int element
, /* I - Value number (0-based) */
2065 int *yres
, /* O - Vertical/feed resolution */
2066 ipp_res_t
*units
) /* O - Units for resolution */
2069 * Range check input...
2072 if (!attr
|| attr
->value_tag
!= IPP_TAG_RESOLUTION
||
2073 element
< 0 || element
>= attr
->num_values
)
2077 * Return the value...
2081 *yres
= attr
->values
[element
].resolution
.yres
;
2084 *units
= attr
->values
[element
].resolution
.units
;
2086 return (attr
->values
[element
].resolution
.xres
);
2091 * 'ippGetState()' - Get the IPP message state.
2096 ipp_state_t
/* O - IPP message state value */
2097 ippGetState(ipp_t
*ipp
) /* I - IPP message */
2100 * Range check input...
2107 * Return the value...
2110 return (ipp
->state
);
2115 * 'ippGetStatusCode()' - Get the status code from an IPP response or event message.
2120 ipp_status_t
/* O - Status code in IPP message */
2121 ippGetStatusCode(ipp_t
*ipp
) /* I - IPP response or event message */
2124 * Range check input...
2128 return (IPP_INTERNAL_ERROR
);
2131 * Return the value...
2134 return (ipp
->request
.status
.status_code
);
2139 * 'ippGetString()' - Get the string and optionally the language code for an attribute.
2141 * The @code element@ parameter specifies which value to get from 0 to
2142 * @link ippGetCount(attr)@ - 1.
2148 ippGetString(ipp_attribute_t
*attr
, /* I - IPP attribute */
2149 int element
, /* I - Value number (0-based) */
2150 const char **language
)/* O - Language code (@code NULL@ for don't care) */
2153 * Range check input...
2156 if (!attr
|| element
< 0 || element
>= attr
->num_values
||
2157 (attr
->value_tag
!= IPP_TAG_TEXTLANG
&& attr
->value_tag
!= IPP_TAG_NAMELANG
&&
2158 (attr
->value_tag
< IPP_TAG_TEXT
|| attr
->value_tag
> IPP_TAG_MIMETYPE
)))
2162 * Return the value...
2166 *language
= attr
->values
[element
].string
.language
;
2168 return (attr
->values
[element
].string
.text
);
2173 * 'ippGetValueTag()' - Get the value tag for an attribute.
2178 ipp_tag_t
/* O - Value tag or @code IPP_TAG_ZERO@ on error */
2179 ippGetValueTag(ipp_attribute_t
*attr
) /* I - IPP attribute */
2182 * Range check input...
2186 return (IPP_TAG_ZERO
);
2189 * Return the value...
2192 return (attr
->value_tag
);
2197 * 'ippGetVersion()' - Get the major and minor version number from an IPP message.
2202 int /* O - Major version number or -1 on error */
2203 ippGetVersion(ipp_t
*ipp
, /* I - IPP message */
2204 int *minor
) /* O - Minor version number or @code NULL@ */
2207 * Range check input...
2219 * Return the value...
2223 *minor
= ipp
->request
.any
.version
[1];
2225 return (ipp
->request
.any
.version
[0]);
2230 * 'ippLength()' - Compute the length of an IPP message.
2233 size_t /* O - Size of IPP message */
2234 ippLength(ipp_t
*ipp
) /* I - IPP message */
2236 return (ipp_length(ipp
, 0));
2241 * 'ippNextAttribute()' - Return the next attribute in the message.
2246 ipp_attribute_t
* /* O - Next attribute or @code NULL@ if none */
2247 ippNextAttribute(ipp_t
*ipp
) /* I - IPP message */
2250 * Range check input...
2253 if (!ipp
|| !ipp
->current
)
2257 * Return the next attribute...
2260 return (ipp
->current
= ipp
->current
->next
);
2265 * 'ippNew()' - Allocate a new IPP message.
2268 ipp_t
* /* O - New IPP message */
2271 ipp_t
*temp
; /* New IPP message */
2274 DEBUG_puts("ippNew()");
2276 if ((temp
= (ipp_t
*)calloc(1, sizeof(ipp_t
))) != NULL
)
2279 * Default to IPP 2.0...
2282 temp
->request
.any
.version
[0] = 2;
2283 temp
->request
.any
.version
[1] = 0;
2287 DEBUG_printf(("1ippNew: Returning %p", temp
));
2294 * 'ippNewRequest()' - Allocate a new IPP request message.
2296 * The new request message is initialized with the attributes-charset and
2297 * attributes-natural-language attributes added. The
2298 * attributes-natural-language value is derived from the current locale.
2300 * @since CUPS 1.2/Mac OS X 10.5@
2303 ipp_t
* /* O - IPP request message */
2304 ippNewRequest(ipp_op_t op
) /* I - Operation code */
2306 ipp_t
*request
; /* IPP request message */
2307 cups_lang_t
*language
; /* Current language localization */
2308 static int request_id
= 0; /* Current request ID */
2309 static _cups_mutex_t request_mutex
= _CUPS_MUTEX_INITIALIZER
;
2310 /* Mutex for request ID */
2313 DEBUG_printf(("ippNewRequest(op=%02x(%s))", op
, ippOpString(op
)));
2316 * Create a new IPP message...
2319 if ((request
= ippNew()) == NULL
)
2323 * Set the operation and request ID...
2326 _cupsMutexLock(&request_mutex
);
2328 request
->request
.op
.operation_id
= op
;
2329 request
->request
.op
.request_id
= ++request_id
;
2331 _cupsMutexUnlock(&request_mutex
);
2334 * Use UTF-8 as the character set...
2337 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
2338 "attributes-charset", NULL
, "utf-8");
2341 * Get the language from the current locale...
2344 language
= cupsLangDefault();
2346 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
2347 "attributes-natural-language", NULL
, language
->language
);
2350 * Return the new request...
2358 * 'ippRead()' - Read data for an IPP message from a HTTP connection.
2361 ipp_state_t
/* O - Current state */
2362 ippRead(http_t
*http
, /* I - HTTP connection */
2363 ipp_t
*ipp
) /* I - IPP data */
2365 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT
,
2366 http
, ipp
, CUPS_LLCAST (http
? http
->data_remaining
: -1)));
2371 DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http
->state
,
2374 return (ippReadIO(http
, (ipp_iocb_t
)ipp_read_http
, http
->blocking
, NULL
,
2380 * 'ippReadFile()' - Read data for an IPP message from a file.
2382 * @since CUPS 1.1.19/Mac OS X 10.3@
2385 ipp_state_t
/* O - Current state */
2386 ippReadFile(int fd
, /* I - HTTP data */
2387 ipp_t
*ipp
) /* I - IPP data */
2389 DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd
, ipp
));
2391 return (ippReadIO(&fd
, (ipp_iocb_t
)ipp_read_file
, 1, NULL
, ipp
));
2396 * 'ippReadIO()' - Read data for an IPP message.
2398 * @since CUPS 1.2/Mac OS X 10.5@
2401 ipp_state_t
/* O - Current state */
2402 ippReadIO(void *src
, /* I - Data source */
2403 ipp_iocb_t cb
, /* I - Read callback function */
2404 int blocking
, /* I - Use blocking IO? */
2405 ipp_t
*parent
, /* I - Parent request, if any */
2406 ipp_t
*ipp
) /* I - IPP data */
2408 int n
; /* Length of data */
2409 unsigned char *buffer
, /* Data buffer */
2410 string
[IPP_MAX_NAME
],
2411 /* Small string buffer */
2412 *bufptr
; /* Pointer into buffer */
2413 ipp_attribute_t
*attr
; /* Current attribute */
2414 ipp_tag_t tag
; /* Current tag */
2415 ipp_tag_t value_tag
; /* Current value tag */
2416 _ipp_value_t
*value
; /* Current value */
2419 DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
2420 src
, cb
, blocking
, parent
, ipp
));
2421 DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp
->state
));
2426 if ((buffer
= ipp_buffer_get()) == NULL
)
2428 DEBUG_puts("1ippReadIO: Unable to get read buffer.");
2435 ipp
->state
++; /* Avoid common problem... */
2441 * Get the request header...
2444 if ((*cb
)(src
, buffer
, 8) < 8)
2446 DEBUG_puts("1ippReadIO: Unable to read header.");
2447 ipp_buffer_release(buffer
);
2452 * Then copy the request header over...
2455 ipp
->request
.any
.version
[0] = buffer
[0];
2456 ipp
->request
.any
.version
[1] = buffer
[1];
2457 ipp
->request
.any
.op_status
= (buffer
[2] << 8) | buffer
[3];
2458 ipp
->request
.any
.request_id
= (((((buffer
[4] << 8) | buffer
[5]) << 8) |
2459 buffer
[6]) << 8) | buffer
[7];
2461 DEBUG_printf(("2ippReadIO: version=%d.%d", buffer
[0], buffer
[1]));
2462 DEBUG_printf(("2ippReadIO: op_status=%04x",
2463 ipp
->request
.any
.op_status
));
2464 DEBUG_printf(("2ippReadIO: request_id=%d",
2465 ipp
->request
.any
.request_id
));
2468 ipp
->state
= IPP_ATTRIBUTE
;
2469 ipp
->current
= NULL
;
2470 ipp
->curtag
= IPP_TAG_ZERO
;
2471 ipp
->prev
= ipp
->last
;
2474 * If blocking is disabled, stop here...
2480 case IPP_ATTRIBUTE
:
2483 if ((*cb
)(src
, buffer
, 1) < 1)
2485 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
2486 ipp_buffer_release(buffer
);
2490 DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p",
2491 ipp
->current
, ipp
->prev
));
2494 * Read this attribute...
2497 tag
= (ipp_tag_t
)buffer
[0];
2498 if (tag
== IPP_TAG_EXTENSION
)
2501 * Read 32-bit "extension" tag...
2504 if ((*cb
)(src
, buffer
, 4) < 1)
2506 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
2507 ipp_buffer_release(buffer
);
2511 tag
= (ipp_tag_t
)((((((buffer
[0] << 8) | buffer
[1]) << 8) |
2512 buffer
[2]) << 8) | buffer
[3]);
2514 if (tag
& IPP_TAG_COPY
)
2517 * Fail if the high bit is set in the tag...
2520 _cupsSetError(IPP_ERROR
, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
2521 DEBUG_printf(("1ippReadIO: bad name length %d.", n
));
2522 ipp_buffer_release(buffer
);
2527 if (tag
== IPP_TAG_END
)
2530 * No more attributes left...
2533 DEBUG_puts("2ippReadIO: IPP_TAG_END.");
2535 ipp
->state
= IPP_DATA
;
2538 else if (tag
< IPP_TAG_UNSUPPORTED_VALUE
)
2541 * Group tag... Set the current group and continue...
2544 if (ipp
->curtag
== tag
)
2545 ipp
->prev
= ippAddSeparator(ipp
);
2546 else if (ipp
->current
)
2547 ipp
->prev
= ipp
->current
;
2550 ipp
->current
= NULL
;
2551 DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag
,
2552 ippTagString(tag
), ipp
->prev
));
2556 DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag
,
2557 ippTagString(tag
)));
2563 if ((*cb
)(src
, buffer
, 2) < 2)
2565 DEBUG_puts("1ippReadIO: unable to read name length.");
2566 ipp_buffer_release(buffer
);
2570 n
= (buffer
[0] << 8) | buffer
[1];
2572 if (n
>= IPP_BUF_SIZE
)
2574 _cupsSetError(IPP_ERROR
, _("IPP name larger than 32767 bytes."), 1);
2575 DEBUG_printf(("1ippReadIO: bad name length %d.", n
));
2576 ipp_buffer_release(buffer
);
2580 DEBUG_printf(("2ippReadIO: name length=%d", n
));
2582 if (n
== 0 && tag
!= IPP_TAG_MEMBERNAME
&&
2583 tag
!= IPP_TAG_END_COLLECTION
)
2586 * More values for current attribute...
2589 if (ipp
->current
== NULL
)
2591 _cupsSetError(IPP_ERROR
, _("IPP attribute has no name."), 1);
2592 DEBUG_puts("1ippReadIO: Attribute without name and no current.");
2593 ipp_buffer_release(buffer
);
2597 attr
= ipp
->current
;
2598 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_MASK
);
2601 * Make sure we aren't adding a new value of a different
2605 if (value_tag
== IPP_TAG_ZERO
)
2608 * Setting the value of a collection member...
2611 attr
->value_tag
= tag
;
2613 else if (value_tag
== IPP_TAG_TEXTLANG
||
2614 value_tag
== IPP_TAG_NAMELANG
||
2615 (value_tag
>= IPP_TAG_TEXT
&&
2616 value_tag
<= IPP_TAG_MIMETYPE
))
2619 * String values can sometimes come across in different
2620 * forms; accept sets of differing values...
2623 if (tag
!= IPP_TAG_TEXTLANG
&& tag
!= IPP_TAG_NAMELANG
&&
2624 (tag
< IPP_TAG_TEXT
|| tag
> IPP_TAG_MIMETYPE
) &&
2625 tag
!= IPP_TAG_NOVALUE
)
2627 _cupsSetError(IPP_ERROR
,
2628 _("IPP 1setOf attribute with incompatible value "
2630 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
2631 value_tag
, ippTagString(value_tag
), tag
,
2632 ippTagString(tag
)));
2633 ipp_buffer_release(buffer
);
2637 if (value_tag
!= tag
)
2639 DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.",
2640 attr
->name
, ippTagString(value_tag
), ippTagString(tag
)));
2641 ippSetValueTag(ipp
, &attr
, tag
);
2644 else if (value_tag
== IPP_TAG_INTEGER
||
2645 value_tag
== IPP_TAG_RANGE
)
2648 * Integer and rangeOfInteger values can sometimes be mixed; accept
2649 * sets of differing values...
2652 if (tag
!= IPP_TAG_INTEGER
&& tag
!= IPP_TAG_RANGE
)
2654 _cupsSetError(IPP_ERROR
,
2655 _("IPP 1setOf attribute with incompatible value "
2657 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
2658 value_tag
, ippTagString(value_tag
), tag
,
2659 ippTagString(tag
)));
2660 ipp_buffer_release(buffer
);
2664 if (value_tag
== IPP_TAG_INTEGER
&& tag
== IPP_TAG_RANGE
)
2667 * Convert integer values to rangeOfInteger values...
2670 DEBUG_printf(("1ippReadIO: Converting %s attribute to "
2671 "rangeOfInteger.", attr
->name
));
2672 ippSetValueTag(ipp
, &attr
, IPP_TAG_RANGE
);
2675 else if (value_tag
!= tag
)
2677 _cupsSetError(IPP_ERROR
,
2678 _("IPP 1setOf attribute with incompatible value "
2680 DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
2681 value_tag
, ippTagString(value_tag
), tag
,
2682 ippTagString(tag
)));
2683 ipp_buffer_release(buffer
);
2688 * Finally, reallocate the attribute array as needed...
2691 if ((value
= ipp_set_value(ipp
, &attr
, attr
->num_values
)) == NULL
)
2693 ipp_buffer_release(buffer
);
2697 else if (tag
== IPP_TAG_MEMBERNAME
)
2700 * Name must be length 0!
2705 _cupsSetError(IPP_ERROR
, _("IPP member name is not empty."), 1);
2706 DEBUG_puts("1ippReadIO: member name not empty.");
2707 ipp_buffer_release(buffer
);
2712 ipp
->prev
= ipp
->current
;
2714 attr
= ipp
->current
= ipp_add_attr(ipp
, NULL
, ipp
->curtag
, IPP_TAG_ZERO
, 1);
2716 DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p",
2717 ipp
->current
, ipp
->prev
));
2719 value
= attr
->values
;
2721 else if (tag
!= IPP_TAG_END_COLLECTION
)
2724 * New attribute; read the name and add it...
2727 if ((*cb
)(src
, buffer
, n
) < n
)
2729 DEBUG_puts("1ippReadIO: unable to read name.");
2730 ipp_buffer_release(buffer
);
2737 ipp
->prev
= ipp
->current
;
2739 if ((attr
= ipp
->current
= ipp_add_attr(ipp
, (char *)buffer
, ipp
->curtag
, tag
,
2742 _cupsSetHTTPError(HTTP_ERROR
);
2743 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
2744 ipp_buffer_release(buffer
);
2748 DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, "
2749 "ipp->prev=%p", buffer
, ipp
->current
, ipp
->prev
));
2751 value
= attr
->values
;
2759 if ((*cb
)(src
, buffer
, 2) < 2)
2761 DEBUG_puts("1ippReadIO: unable to read value length.");
2762 ipp_buffer_release(buffer
);
2766 n
= (buffer
[0] << 8) | buffer
[1];
2767 DEBUG_printf(("2ippReadIO: value length=%d", n
));
2769 if (n
>= IPP_BUF_SIZE
)
2771 _cupsSetError(IPP_ERROR
,
2772 _("IPP value larger than 32767 bytes."), 1);
2773 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2774 ipp_buffer_release(buffer
);
2780 case IPP_TAG_INTEGER
:
2784 if (tag
== IPP_TAG_INTEGER
)
2785 _cupsSetError(IPP_ERROR
,
2786 _("IPP integer value not 4 bytes."), 1);
2788 _cupsSetError(IPP_ERROR
,
2789 _("IPP enum value not 4 bytes."), 1);
2790 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2791 ipp_buffer_release(buffer
);
2795 if ((*cb
)(src
, buffer
, 4) < 4)
2797 DEBUG_puts("1ippReadIO: Unable to read integer value.");
2798 ipp_buffer_release(buffer
);
2802 n
= (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
2805 if (attr
->value_tag
== IPP_TAG_RANGE
)
2806 value
->range
.lower
= value
->range
.upper
= n
;
2811 case IPP_TAG_BOOLEAN
:
2814 _cupsSetError(IPP_ERROR
, _("IPP boolean value not 1 byte."),
2816 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2817 ipp_buffer_release(buffer
);
2821 if ((*cb
)(src
, buffer
, 1) < 1)
2823 DEBUG_puts("1ippReadIO: Unable to read boolean value.");
2824 ipp_buffer_release(buffer
);
2828 value
->boolean
= buffer
[0];
2831 case IPP_TAG_NOVALUE
:
2832 case IPP_TAG_NOTSETTABLE
:
2833 case IPP_TAG_DELETEATTR
:
2834 case IPP_TAG_ADMINDEFINE
:
2836 * These value types are not supposed to have values, however
2837 * some vendors (Brother) do not implement IPP correctly and so
2838 * we need to map non-empty values to text...
2841 if (attr
->value_tag
== tag
)
2846 attr
->value_tag
= IPP_TAG_TEXT
;
2851 case IPP_TAG_KEYWORD
:
2853 case IPP_TAG_URISCHEME
:
2854 case IPP_TAG_CHARSET
:
2855 case IPP_TAG_LANGUAGE
:
2856 case IPP_TAG_MIMETYPE
:
2857 if ((*cb
)(src
, buffer
, n
) < n
)
2859 DEBUG_puts("1ippReadIO: unable to read string value.");
2860 ipp_buffer_release(buffer
);
2865 value
->string
.text
= _cupsStrAlloc((char *)buffer
);
2866 DEBUG_printf(("2ippReadIO: value=\"%s\"", value
->string
.text
));
2872 _cupsSetError(IPP_ERROR
, _("IPP date value not 11 bytes."), 1);
2873 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2874 ipp_buffer_release(buffer
);
2878 if ((*cb
)(src
, value
->date
, 11) < 11)
2880 DEBUG_puts("1ippReadIO: Unable to read date value.");
2881 ipp_buffer_release(buffer
);
2886 case IPP_TAG_RESOLUTION
:
2889 _cupsSetError(IPP_ERROR
,
2890 _("IPP resolution value not 9 bytes."), 1);
2891 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2892 ipp_buffer_release(buffer
);
2896 if ((*cb
)(src
, buffer
, 9) < 9)
2898 DEBUG_puts("1ippReadIO: Unable to read resolution value.");
2899 ipp_buffer_release(buffer
);
2903 value
->resolution
.xres
=
2904 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
2906 value
->resolution
.yres
=
2907 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
2909 value
->resolution
.units
=
2910 (ipp_res_t
)buffer
[8];
2913 case IPP_TAG_RANGE
:
2916 _cupsSetError(IPP_ERROR
,
2917 _("IPP rangeOfInteger value not 8 bytes."), 1);
2918 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2919 ipp_buffer_release(buffer
);
2923 if ((*cb
)(src
, buffer
, 8) < 8)
2925 DEBUG_puts("1ippReadIO: Unable to read range value.");
2926 ipp_buffer_release(buffer
);
2930 value
->range
.lower
=
2931 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
2933 value
->range
.upper
=
2934 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
2938 case IPP_TAG_TEXTLANG
:
2939 case IPP_TAG_NAMELANG
:
2942 if (tag
== IPP_TAG_TEXTLANG
)
2943 _cupsSetError(IPP_ERROR
,
2944 _("IPP textWithLanguage value less than "
2945 "minimum 4 bytes."), 1);
2947 _cupsSetError(IPP_ERROR
,
2948 _("IPP nameWithLanguage value less than "
2949 "minimum 4 bytes."), 1);
2950 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2951 ipp_buffer_release(buffer
);
2955 if ((*cb
)(src
, buffer
, n
) < n
)
2957 DEBUG_puts("1ippReadIO: Unable to read string w/language "
2959 ipp_buffer_release(buffer
);
2966 * text-with-language and name-with-language are composite
2975 n
= (bufptr
[0] << 8) | bufptr
[1];
2977 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
) ||
2978 n
>= sizeof(string
))
2980 _cupsSetError(IPP_ERROR
,
2981 _("IPP language length overflows value."), 1);
2982 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
2983 ipp_buffer_release(buffer
);
2987 memcpy(string
, bufptr
+ 2, n
);
2990 value
->string
.language
= _cupsStrAlloc((char *)string
);
2993 n
= (bufptr
[0] << 8) | bufptr
[1];
2995 if ((bufptr
+ 2 + n
) >= (buffer
+ IPP_BUF_SIZE
))
2997 _cupsSetError(IPP_ERROR
,
2998 _("IPP string length overflows value."), 1);
2999 DEBUG_printf(("1ippReadIO: bad value length %d.", n
));
3000 ipp_buffer_release(buffer
);
3004 bufptr
[2 + n
] = '\0';
3005 value
->string
.text
= _cupsStrAlloc((char *)bufptr
+ 2);
3008 case IPP_TAG_BEGIN_COLLECTION
:
3010 * Oh, boy, here comes a collection value, so read it...
3013 value
->collection
= ippNew();
3017 _cupsSetError(IPP_ERROR
,
3018 _("IPP begCollection value not 0 bytes."), 1);
3019 DEBUG_puts("1ippReadIO: begCollection tag with value length "
3021 ipp_buffer_release(buffer
);
3025 if (ippReadIO(src
, cb
, 1, ipp
, value
->collection
) == IPP_ERROR
)
3027 DEBUG_puts("1ippReadIO: Unable to read collection value.");
3028 ipp_buffer_release(buffer
);
3033 case IPP_TAG_END_COLLECTION
:
3034 ipp_buffer_release(buffer
);
3038 _cupsSetError(IPP_ERROR
,
3039 _("IPP endCollection value not 0 bytes."), 1);
3040 DEBUG_puts("1ippReadIO: endCollection tag with value length "
3045 DEBUG_puts("1ippReadIO: endCollection tag...");
3046 return (ipp
->state
= IPP_DATA
);
3048 case IPP_TAG_MEMBERNAME
:
3050 * The value the name of the member in the collection, which
3051 * we need to carry over...
3054 if ((*cb
)(src
, buffer
, n
) < n
)
3056 DEBUG_puts("1ippReadIO: Unable to read member name value.");
3057 ipp_buffer_release(buffer
);
3062 attr
->name
= _cupsStrAlloc((char *)buffer
);
3065 * Since collection members are encoded differently than
3066 * regular attributes, make sure we don't start with an
3070 attr
->num_values
--;
3072 DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr
->name
));
3075 default : /* Other unsupported values */
3076 value
->unknown
.length
= n
;
3079 if ((value
->unknown
.data
= malloc(n
)) == NULL
)
3081 _cupsSetHTTPError(HTTP_ERROR
);
3082 DEBUG_puts("1ippReadIO: Unable to allocate value");
3083 ipp_buffer_release(buffer
);
3087 if ((*cb
)(src
, value
->unknown
.data
, n
) < n
)
3089 DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
3090 ipp_buffer_release(buffer
);
3095 value
->unknown
.data
= NULL
;
3100 * If blocking is disabled, stop here...
3112 break; /* anti-compiler-warning-code */
3115 DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp
->state
));
3116 ipp_buffer_release(buffer
);
3118 return (ipp
->state
);
3123 * 'ippSetBoolean()' - Set a boolean value in an attribute.
3125 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3126 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3128 * The @code attr@ parameter may be modified as a result of setting the value.
3130 * The @code element@ parameter specifies which value to set from 0 to
3131 * @link ippGetCount(attr)@.
3136 int /* O - 1 on success, 0 on failure */
3137 ippSetBoolean(ipp_t
*ipp
, /* IO - IPP message */
3138 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3139 int element
, /* I - Value number (0-based) */
3140 int boolvalue
)/* I - Boolean value */
3142 _ipp_value_t
*value
; /* Current value */
3146 * Range check input...
3149 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BOOLEAN
||
3150 element
< 0 || element
> (*attr
)->num_values
)
3154 * Set the value and return...
3157 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3158 value
->boolean
= boolvalue
;
3160 return (value
!= NULL
);
3165 * 'ippSetCollection()' - Set a collection value in an attribute.
3167 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3168 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3170 * The @code attr@ parameter may be modified as a result of setting the value.
3172 * The @code element@ parameter specifies which value to set from 0 to
3173 * @link ippGetCount(attr)@.
3178 int /* O - 1 on success, 0 on failure */
3180 ipp_t
*ipp
, /* IO - IPP message */
3181 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3182 int element
, /* I - Value number (0-based) */
3183 ipp_t
*colvalue
) /* I - Collection value */
3185 _ipp_value_t
*value
; /* Current value */
3189 * Range check input...
3192 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_BEGIN_COLLECTION
||
3193 element
< 0 || element
> (*attr
)->num_values
|| !colvalue
)
3197 * Set the value and return...
3200 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3202 if (value
->collection
)
3203 ippDelete(value
->collection
);
3205 value
->collection
= colvalue
;
3209 return (value
!= NULL
);
3214 * 'ippSetDate()' - Set a date value in an attribute.
3216 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3217 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3219 * The @code attr@ parameter may be modified as a result of setting the value.
3221 * The @code element@ parameter specifies which value to set from 0 to
3222 * @link ippGetCount(attr)@.
3227 int /* O - 1 on success, 0 on failure */
3228 ippSetDate(ipp_t
*ipp
, /* IO - IPP message */
3229 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3230 int element
, /* I - Value number (0-based) */
3231 const ipp_uchar_t
*datevalue
)/* I - Date value */
3233 _ipp_value_t
*value
; /* Current value */
3237 * Range check input...
3240 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_DATE
||
3241 element
< 0 || element
> (*attr
)->num_values
|| !datevalue
)
3245 * Set the value and return...
3248 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3249 memcpy(value
->date
, datevalue
, sizeof(value
->date
));
3251 return (value
!= NULL
);
3256 * 'ippSetGroupTag()' - Set the group tag of an attribute.
3258 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3259 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3261 * The @code attr@ parameter may be modified as a result of setting the value.
3263 * The @code group@ parameter specifies the IPP attribute group tag: none
3264 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
3265 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
3266 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
3267 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
3272 int /* O - 1 on success, 0 on failure */
3274 ipp_t
*ipp
, /* IO - IPP message */
3275 ipp_attribute_t
**attr
, /* IO - Attribute */
3276 ipp_tag_t group_tag
) /* I - Group tag */
3279 * Range check input - group tag must be 0x01 to 0x0F, per RFC 2911...
3282 if (!ipp
|| !attr
|| group_tag
< IPP_TAG_ZERO
|| group_tag
== IPP_TAG_END
||
3283 group_tag
>= IPP_TAG_UNSUPPORTED_VALUE
)
3287 * Set the group tag and return...
3290 (*attr
)->group_tag
= group_tag
;
3297 * 'ippSetInteger()' - Set an integer or enum value in an attribute.
3299 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3300 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3302 * The @code attr@ parameter may be modified as a result of setting the value.
3304 * The @code element@ parameter specifies which value to set from 0 to
3305 * @link ippGetCount(attr)@.
3310 int /* O - 1 on success, 0 on failure */
3311 ippSetInteger(ipp_t
*ipp
, /* IO - IPP message */
3312 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3313 int element
, /* I - Value number (0-based) */
3314 int intvalue
) /* I - Integer/enum value */
3316 _ipp_value_t
*value
; /* Current value */
3320 * Range check input...
3323 if (!ipp
|| !attr
|| !*attr
||
3324 ((*attr
)->value_tag
!= IPP_TAG_INTEGER
&& (*attr
)->value_tag
!= IPP_TAG_ENUM
) ||
3325 element
< 0 || element
> (*attr
)->num_values
)
3329 * Set the value and return...
3332 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3333 value
->integer
= intvalue
;
3335 return (value
!= NULL
);
3340 * 'ippSetName()' - Set the name of an attribute.
3342 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3343 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3345 * The @code attr@ parameter may be modified as a result of setting the value.
3350 int /* O - 1 on success, 0 on failure */
3351 ippSetName(ipp_t
*ipp
, /* IO - IPP message */
3352 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3353 const char *name
) /* I - Attribute name */
3355 char *temp
; /* Temporary name value */
3359 * Range check input...
3362 if (!ipp
|| !attr
|| !*attr
)
3366 * Set the value and return...
3369 if ((temp
= _cupsStrAlloc(name
)) != NULL
)
3372 _cupsStrFree((*attr
)->name
);
3374 (*attr
)->name
= temp
;
3377 return (temp
!= NULL
);
3382 * 'ippSetOperation()' - Set the operation ID in an IPP request message.
3384 * The @code ipp@ parameter refers to an IPP message previously created using the
3385 * @link ippNew@ or @link ippNewRequest@ functions.
3390 int /* O - 1 on success, 0 on failure */
3391 ippSetOperation(ipp_t
*ipp
, /* I - IPP request message */
3392 ipp_op_t op
) /* I - Operation ID */
3395 * Range check input...
3402 * Set the operation and return...
3405 ipp
->request
.op
.operation_id
= op
;
3412 * 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
3414 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3415 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3417 * The @code attr@ parameter may be modified as a result of setting the value.
3419 * The @code element@ parameter specifies which value to set from 0 to
3420 * @link ippGetCount(attr)@.
3425 int /* O - 1 on success, 0 on failure */
3426 ippSetRange(ipp_t
*ipp
, /* IO - IPP message */
3427 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3428 int element
, /* I - Value number (0-based) */
3429 int lowervalue
, /* I - Lower bound for range */
3430 int uppervalue
) /* I - Upper bound for range */
3432 _ipp_value_t
*value
; /* Current value */
3436 * Range check input...
3439 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RANGE
||
3440 element
< 0 || element
> (*attr
)->num_values
|| lowervalue
> uppervalue
)
3444 * Set the value and return...
3447 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3449 value
->range
.lower
= lowervalue
;
3450 value
->range
.upper
= uppervalue
;
3453 return (value
!= NULL
);
3458 * 'ippSetRequestId()' - Set the request ID in an IPP message.
3460 * The @code ipp@ parameter refers to an IPP message previously created using the
3461 * @link ippNew@ or @link ippNewRequest@ functions.
3463 * The @code request_id@ parameter must be greater than 0.
3468 int /* O - 1 on success, 0 on failure */
3469 ippSetRequestId(ipp_t
*ipp
, /* I - IPP message */
3470 int request_id
) /* I - Request ID */
3473 * Range check input; not checking request_id values since ipptool wants to send
3474 * invalid values for conformance testing and a bad request_id does not affect the
3475 * encoding of a message...
3482 * Set the request ID and return...
3485 ipp
->request
.any
.request_id
= request_id
;
3492 * 'ippSetResolution()' - Set a resolution value in an attribute.
3494 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3495 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3497 * The @code attr@ parameter may be modified as a result of setting the value.
3499 * The @code element@ parameter specifies which value to set from 0 to
3500 * @link ippGetCount(attr)@.
3505 int /* O - 1 on success, 0 on failure */
3507 ipp_t
*ipp
, /* IO - IPP message */
3508 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3509 int element
, /* I - Value number (0-based) */
3510 ipp_res_t unitsvalue
, /* I - Resolution units */
3511 int xresvalue
, /* I - Horizontal/cross feed resolution */
3512 int yresvalue
) /* I - Vertical/feed resolution */
3514 _ipp_value_t
*value
; /* Current value */
3518 * Range check input...
3521 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_RESOLUTION
||
3522 element
< 0 || element
> (*attr
)->num_values
|| xresvalue
<= 0 || yresvalue
<= 0 ||
3523 unitsvalue
< IPP_RES_PER_INCH
|| unitsvalue
> IPP_RES_PER_CM
)
3527 * Set the value and return...
3530 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3532 value
->resolution
.units
= unitsvalue
;
3533 value
->resolution
.xres
= xresvalue
;
3534 value
->resolution
.yres
= yresvalue
;
3537 return (value
!= NULL
);
3542 * 'ippSetState()' - Set the current state of the IPP message.
3547 int /* O - 1 on success, 0 on failure */
3548 ippSetState(ipp_t
*ipp
, /* I - IPP message */
3549 ipp_state_t state
) /* I - IPP state value */
3552 * Range check input...
3559 * Set the state and return...
3563 ipp
->current
= NULL
;
3570 * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
3572 * The @code ipp@ parameter refers to an IPP message previously created using the
3573 * @link ippNew@ or @link ippNewRequest@ functions.
3578 int /* O - 1 on success, 0 on failure */
3579 ippSetStatusCode(ipp_t
*ipp
, /* I - IPP response or event message */
3580 ipp_status_t status
) /* I - Status code */
3583 * Range check input...
3590 * Set the status code and return...
3593 ipp
->request
.status
.status_code
= status
;
3600 * 'ippSetString()' - Set a string value in an attribute.
3602 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3603 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3605 * The @code attr@ parameter may be modified as a result of setting the value.
3607 * The @code element@ parameter specifies which value to set from 0 to
3608 * @link ippGetCount(attr)@.
3613 int /* O - 1 on success, 0 on failure */
3614 ippSetString(ipp_t
*ipp
, /* IO - IPP message */
3615 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3616 int element
, /* I - Value number (0-based) */
3617 const char *strvalue
) /* I - String value */
3619 char *temp
; /* Temporary string */
3620 _ipp_value_t
*value
; /* Current value */
3624 * Range check input...
3627 if (!ipp
|| !attr
|| !*attr
|| (*attr
)->value_tag
!= IPP_TAG_INTEGER
||
3628 element
< 0 || element
> (*attr
)->num_values
|| !strvalue
)
3632 * Set the value and return...
3635 if ((value
= ipp_set_value(ipp
, attr
, element
)) != NULL
)
3638 value
->string
.language
= (*attr
)->values
[0].string
.language
;
3640 if ((int)((*attr
)->value_tag
) & IPP_TAG_COPY
)
3641 value
->string
.text
= (char *)strvalue
;
3642 else if ((temp
= _cupsStrAlloc(strvalue
)) != NULL
)
3644 if (value
->string
.text
)
3645 _cupsStrFree(value
->string
.text
);
3647 value
->string
.text
= temp
;
3653 return (value
!= NULL
);
3658 * 'ippSetValueTag()' - Set the value tag of an attribute.
3660 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3661 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3663 * The @code attr@ parameter may be modified as a result of setting the value.
3665 * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger
3666 * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name
3667 * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text
3668 * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage
3669 * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various
3670 * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes
3673 * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language
3674 * code in the "attributes-natural-language" attribute or, if not present, the language
3675 * code for the current locale.
3680 int /* O - 1 on success, 0 on failure */
3682 ipp_t
*ipp
, /* IO - IPP message */
3683 ipp_attribute_t
**attr
, /* IO - IPP attribute */
3684 ipp_tag_t value_tag
) /* I - Value tag */
3686 int i
; /* Looping var */
3687 _ipp_value_t
*value
; /* Current value */
3688 int integer
; /* Current integer value */
3689 cups_lang_t
*language
; /* Current language */
3690 char code
[32]; /* Language code */
3691 ipp_tag_t temp_tag
; /* Temporary value tag */
3695 * Range check input...
3702 * If there is no change, return immediately...
3705 if (value_tag
== (*attr
)->value_tag
)
3709 * Otherwise implement changes as needed...
3712 temp_tag
= (ipp_tag_t
)((int)((*attr
)->value_tag
) & IPP_TAG_MASK
);
3716 case IPP_TAG_UNSUPPORTED_VALUE
:
3717 case IPP_TAG_DEFAULT
:
3718 case IPP_TAG_UNKNOWN
:
3719 case IPP_TAG_NOVALUE
:
3720 case IPP_TAG_NOTSETTABLE
:
3721 case IPP_TAG_DELETEATTR
:
3722 case IPP_TAG_ADMINDEFINE
:
3724 * Free any existing values...
3727 if ((*attr
)->num_values
> 0)
3728 ipp_free_values(*attr
, 0, (*attr
)->num_values
);
3731 * Set out-of-band value...
3734 (*attr
)->value_tag
= value_tag
;
3737 case IPP_TAG_RANGE
:
3738 if (temp_tag
!= IPP_TAG_INTEGER
)
3741 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
3745 integer
= value
->integer
;
3746 value
->range
.lower
= value
->range
.upper
= integer
;
3749 (*attr
)->value_tag
= IPP_TAG_RANGE
;
3753 if (temp_tag
!= IPP_TAG_KEYWORD
&& temp_tag
!= IPP_TAG_URI
&&
3754 temp_tag
!= IPP_TAG_URISCHEME
&& temp_tag
!= IPP_TAG_LANGUAGE
&&
3755 temp_tag
!= IPP_TAG_MIMETYPE
)
3758 (*attr
)->value_tag
= (ipp_tag_t
)(IPP_TAG_NAME
| ((*attr
)->value_tag
& IPP_TAG_COPY
));
3761 case IPP_TAG_NAMELANG
:
3762 case IPP_TAG_TEXTLANG
:
3763 if (value_tag
== IPP_TAG_NAMELANG
&&
3764 (temp_tag
!= IPP_TAG_NAME
&& temp_tag
!= IPP_TAG_KEYWORD
&&
3765 temp_tag
!= IPP_TAG_URI
&& temp_tag
!= IPP_TAG_URISCHEME
&&
3766 temp_tag
!= IPP_TAG_LANGUAGE
&& temp_tag
!= IPP_TAG_MIMETYPE
))
3769 if (value_tag
== IPP_TAG_TEXTLANG
&& temp_tag
!= IPP_TAG_TEXT
)
3772 if (ipp
->attrs
&& ipp
->attrs
->next
&& ipp
->attrs
->next
->name
&&
3773 !strcmp(ipp
->attrs
->next
->name
, "attributes-natural-language"))
3776 * Use the language code from the IPP message...
3779 (*attr
)->values
[0].string
.language
=
3780 _cupsStrAlloc(ipp
->attrs
->next
->values
[0].string
.text
);
3785 * Otherwise, use the language code corresponding to the locale...
3788 language
= cupsLangDefault();
3789 (*attr
)->values
[0].string
.language
= _cupsStrAlloc(ipp_lang_code(language
->language
,
3794 for (i
= (*attr
)->num_values
- 1, value
= (*attr
)->values
+ 1;
3797 value
->string
.language
= (*attr
)->values
[0].string
.language
;
3799 if ((int)(*attr
)->value_tag
& IPP_TAG_COPY
)
3802 * Make copies of all values...
3805 for (i
= (*attr
)->num_values
, value
= (*attr
)->values
;
3808 value
->string
.text
= _cupsStrAlloc(value
->string
.text
);
3811 (*attr
)->value_tag
= IPP_TAG_NAMELANG
;
3814 case IPP_TAG_KEYWORD
:
3815 if (temp_tag
== IPP_TAG_NAME
|| temp_tag
== IPP_TAG_NAMELANG
)
3816 break; /* Silently "allow" name -> keyword */
3827 * 'ippSetVersion()' - Set the version number in an IPP message.
3829 * The @code ipp@ parameter refers to an IPP message previously created using the
3830 * @link ippNew@ or @link ippNewRequest@ functions.
3832 * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
3837 int /* O - 1 on success, 0 on failure */
3838 ippSetVersion(ipp_t
*ipp
, /* I - IPP message */
3839 int major
, /* I - Major version number (major.minor) */
3840 int minor
) /* I - Minor version number (major.minor) */
3843 * Range check input...
3846 if (!ipp
|| major
< 0 || minor
< 0)
3850 * Set the version number...
3853 ipp
->request
.any
.version
[0] = major
;
3854 ipp
->request
.any
.version
[1] = minor
;
3861 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
3864 const ipp_uchar_t
* /* O - RFC-1903 date/time data */
3865 ippTimeToDate(time_t t
) /* I - UNIX time value */
3867 struct tm
*unixdate
; /* UNIX unixdate/time info */
3868 ipp_uchar_t
*date
= _cupsGlobals()->ipp_date
;
3869 /* RFC-1903 date/time data */
3873 * RFC-1903 date/time format is:
3875 * Byte(s) Description
3876 * ------- -----------
3877 * 0-1 Year (0 to 65535)
3881 * 5 Minutes (0 to 59)
3882 * 6 Seconds (0 to 60, 60 = "leap second")
3883 * 7 Deciseconds (0 to 9)
3885 * 9 UTC hours (0 to 11)
3886 * 10 UTC minutes (0 to 59)
3889 unixdate
= gmtime(&t
);
3890 unixdate
->tm_year
+= 1900;
3892 date
[0] = unixdate
->tm_year
>> 8;
3893 date
[1] = unixdate
->tm_year
;
3894 date
[2] = unixdate
->tm_mon
+ 1;
3895 date
[3] = unixdate
->tm_mday
;
3896 date
[4] = unixdate
->tm_hour
;
3897 date
[5] = unixdate
->tm_min
;
3898 date
[6] = unixdate
->tm_sec
;
3909 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
3912 ipp_state_t
/* O - Current state */
3913 ippWrite(http_t
*http
, /* I - HTTP connection */
3914 ipp_t
*ipp
) /* I - IPP data */
3916 DEBUG_printf(("ippWrite(http=%p, ipp=%p)", http
, ipp
));
3921 return (ippWriteIO(http
, (ipp_iocb_t
)httpWrite2
, http
->blocking
, NULL
, ipp
));
3926 * 'ippWriteFile()' - Write data for an IPP message to a file.
3928 * @since CUPS 1.1.19/Mac OS X 10.3@
3931 ipp_state_t
/* O - Current state */
3932 ippWriteFile(int fd
, /* I - HTTP data */
3933 ipp_t
*ipp
) /* I - IPP data */
3935 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd
, ipp
));
3937 ipp
->state
= IPP_IDLE
;
3939 return (ippWriteIO(&fd
, (ipp_iocb_t
)ipp_write_file
, 1, NULL
, ipp
));
3944 * 'ippWriteIO()' - Write data for an IPP message.
3946 * @since CUPS 1.2/Mac OS X 10.5@
3949 ipp_state_t
/* O - Current state */
3950 ippWriteIO(void *dst
, /* I - Destination */
3951 ipp_iocb_t cb
, /* I - Write callback function */
3952 int blocking
, /* I - Use blocking IO? */
3953 ipp_t
*parent
, /* I - Parent IPP message */
3954 ipp_t
*ipp
) /* I - IPP data */
3956 int i
; /* Looping var */
3957 int n
; /* Length of data */
3958 unsigned char *buffer
, /* Data buffer */
3959 *bufptr
; /* Pointer into buffer */
3960 ipp_attribute_t
*attr
; /* Current attribute */
3961 _ipp_value_t
*value
; /* Current value */
3964 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
3965 dst
, cb
, blocking
, parent
, ipp
));
3970 if ((buffer
= ipp_buffer_get()) == NULL
)
3972 DEBUG_puts("1ippWriteIO: Unable to get write buffer");
3979 ipp
->state
++; /* Avoid common problem... */
3985 * Send the request header:
3988 * Operation/Status Code = 2 bytes
3989 * Request ID = 4 bytes
3995 *bufptr
++ = ipp
->request
.any
.version
[0];
3996 *bufptr
++ = ipp
->request
.any
.version
[1];
3997 *bufptr
++ = ipp
->request
.any
.op_status
>> 8;
3998 *bufptr
++ = ipp
->request
.any
.op_status
;
3999 *bufptr
++ = ipp
->request
.any
.request_id
>> 24;
4000 *bufptr
++ = ipp
->request
.any
.request_id
>> 16;
4001 *bufptr
++ = ipp
->request
.any
.request_id
>> 8;
4002 *bufptr
++ = ipp
->request
.any
.request_id
;
4004 DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer
[0], buffer
[1]));
4005 DEBUG_printf(("2ippWriteIO: op_status=%04x",
4006 ipp
->request
.any
.op_status
));
4007 DEBUG_printf(("2ippWriteIO: request_id=%d",
4008 ipp
->request
.any
.request_id
));
4010 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4012 DEBUG_puts("1ippWriteIO: Could not write IPP header...");
4013 ipp_buffer_release(buffer
);
4019 * Reset the state engine to point to the first attribute
4020 * in the request/response, with no current group.
4023 ipp
->state
= IPP_ATTRIBUTE
;
4024 ipp
->current
= ipp
->attrs
;
4025 ipp
->curtag
= IPP_TAG_ZERO
;
4027 DEBUG_printf(("1ippWriteIO: ipp->current=%p", ipp
->current
));
4030 * If blocking is disabled, stop here...
4036 case IPP_ATTRIBUTE
:
4037 while (ipp
->current
!= NULL
)
4040 * Write this attribute...
4044 attr
= ipp
->current
;
4046 ipp
->current
= ipp
->current
->next
;
4050 if (ipp
->curtag
!= attr
->group_tag
)
4053 * Send a group tag byte...
4056 ipp
->curtag
= attr
->group_tag
;
4058 if (attr
->group_tag
== IPP_TAG_ZERO
)
4061 DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
4062 attr
->group_tag
, ippTagString(attr
->group_tag
)));
4063 *bufptr
++ = attr
->group_tag
;
4065 else if (attr
->group_tag
== IPP_TAG_ZERO
)
4069 DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr
->name
,
4070 attr
->num_values
> 1 ? "1setOf " : "",
4071 ippTagString(attr
->value_tag
)));
4074 * Write the attribute tag and name.
4076 * The attribute name length does not include the trailing nul
4077 * character in the source string.
4079 * Collection values (parent != NULL) are written differently...
4085 * Get the length of the attribute name, and make sure it won't
4086 * overflow the buffer...
4089 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 8))
4091 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
4092 ipp_buffer_release(buffer
);
4097 * Write the value tag, name length, and name string...
4100 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4101 attr
->value_tag
, ippTagString(attr
->value_tag
)));
4102 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
4105 if (attr
->value_tag
> 0xff)
4107 *bufptr
++ = IPP_TAG_EXTENSION
;
4108 *bufptr
++ = attr
->value_tag
>> 24;
4109 *bufptr
++ = attr
->value_tag
>> 16;
4110 *bufptr
++ = attr
->value_tag
>> 8;
4111 *bufptr
++ = attr
->value_tag
;
4114 *bufptr
++ = attr
->value_tag
;
4118 memcpy(bufptr
, attr
->name
, n
);
4124 * Get the length of the attribute name, and make sure it won't
4125 * overflow the buffer...
4128 if ((n
= (int)strlen(attr
->name
)) > (IPP_BUF_SIZE
- 12))
4130 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n
));
4131 ipp_buffer_release(buffer
);
4136 * Write the member name tag, name length, name string, value tag,
4137 * and empty name for the collection member attribute...
4140 DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
4141 IPP_TAG_MEMBERNAME
));
4142 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n
,
4144 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4145 attr
->value_tag
, ippTagString(attr
->value_tag
)));
4146 DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
4148 *bufptr
++ = IPP_TAG_MEMBERNAME
;
4153 memcpy(bufptr
, attr
->name
, n
);
4156 if (attr
->value_tag
> 0xff)
4158 *bufptr
++ = IPP_TAG_EXTENSION
;
4159 *bufptr
++ = attr
->value_tag
>> 24;
4160 *bufptr
++ = attr
->value_tag
>> 16;
4161 *bufptr
++ = attr
->value_tag
>> 8;
4162 *bufptr
++ = attr
->value_tag
;
4165 *bufptr
++ = attr
->value_tag
;
4172 * Now write the attribute value(s)...
4175 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
4177 case IPP_TAG_UNSUPPORTED_VALUE
:
4178 case IPP_TAG_DEFAULT
:
4179 case IPP_TAG_UNKNOWN
:
4180 case IPP_TAG_NOVALUE
:
4181 case IPP_TAG_NOTSETTABLE
:
4182 case IPP_TAG_DELETEATTR
:
4183 case IPP_TAG_ADMINDEFINE
:
4188 case IPP_TAG_INTEGER
:
4190 for (i
= 0, value
= attr
->values
;
4191 i
< attr
->num_values
;
4194 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 9)
4196 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4198 DEBUG_puts("1ippWriteIO: Could not write IPP "
4200 ipp_buffer_release(buffer
);
4210 * Arrays and sets are done by sending additional
4211 * values with a zero-length name...
4214 *bufptr
++ = attr
->value_tag
;
4220 * Integers and enumerations are both 4-byte signed
4221 * (twos-complement) values.
4223 * Put the 2-byte length and 4-byte value into the buffer...
4228 *bufptr
++ = value
->integer
>> 24;
4229 *bufptr
++ = value
->integer
>> 16;
4230 *bufptr
++ = value
->integer
>> 8;
4231 *bufptr
++ = value
->integer
;
4235 case IPP_TAG_BOOLEAN
:
4236 for (i
= 0, value
= attr
->values
;
4237 i
< attr
->num_values
;
4240 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 6)
4242 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4244 DEBUG_puts("1ippWriteIO: Could not write IPP "
4246 ipp_buffer_release(buffer
);
4256 * Arrays and sets are done by sending additional
4257 * values with a zero-length name...
4260 *bufptr
++ = attr
->value_tag
;
4266 * Boolean values are 1-byte; 0 = false, 1 = true.
4268 * Put the 2-byte length and 1-byte value into the buffer...
4273 *bufptr
++ = value
->boolean
;
4279 case IPP_TAG_KEYWORD
:
4281 case IPP_TAG_URISCHEME
:
4282 case IPP_TAG_CHARSET
:
4283 case IPP_TAG_LANGUAGE
:
4284 case IPP_TAG_MIMETYPE
:
4285 for (i
= 0, value
= attr
->values
;
4286 i
< attr
->num_values
;
4292 * Arrays and sets are done by sending additional
4293 * values with a zero-length name...
4296 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4298 ippTagString(attr
->value_tag
)));
4299 DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
4301 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
4303 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4305 DEBUG_puts("1ippWriteIO: Could not write IPP "
4307 ipp_buffer_release(buffer
);
4314 *bufptr
++ = attr
->value_tag
;
4319 if (value
->string
.text
!= NULL
)
4320 n
= (int)strlen(value
->string
.text
);
4324 if (n
> (IPP_BUF_SIZE
- 2))
4326 DEBUG_printf(("1ippWriteIO: String too long (%d)", n
));
4327 ipp_buffer_release(buffer
);
4331 DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n
,
4332 value
->string
.text
));
4334 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
4336 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4338 DEBUG_puts("1ippWriteIO: Could not write IPP "
4340 ipp_buffer_release(buffer
);
4348 * All simple strings consist of the 2-byte length and
4349 * character data without the trailing nul normally found
4350 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
4351 * bytes since the 2-byte length is a signed (twos-complement)
4354 * Put the 2-byte length and string characters in the buffer.
4362 memcpy(bufptr
, value
->string
.text
, n
);
4369 for (i
= 0, value
= attr
->values
;
4370 i
< attr
->num_values
;
4373 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 16)
4375 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4377 DEBUG_puts("1ippWriteIO: Could not write IPP "
4379 ipp_buffer_release(buffer
);
4389 * Arrays and sets are done by sending additional
4390 * values with a zero-length name...
4393 *bufptr
++ = attr
->value_tag
;
4399 * Date values consist of a 2-byte length and an
4400 * 11-byte date/time structure defined by RFC 1903.
4402 * Put the 2-byte length and 11-byte date/time
4403 * structure in the buffer.
4408 memcpy(bufptr
, value
->date
, 11);
4413 case IPP_TAG_RESOLUTION
:
4414 for (i
= 0, value
= attr
->values
;
4415 i
< attr
->num_values
;
4418 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 14)
4420 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4422 DEBUG_puts("1ippWriteIO: Could not write IPP "
4424 ipp_buffer_release(buffer
);
4434 * Arrays and sets are done by sending additional
4435 * values with a zero-length name...
4438 *bufptr
++ = attr
->value_tag
;
4444 * Resolution values consist of a 2-byte length,
4445 * 4-byte horizontal resolution value, 4-byte vertical
4446 * resolution value, and a 1-byte units value.
4448 * Put the 2-byte length and resolution value data
4454 *bufptr
++ = value
->resolution
.xres
>> 24;
4455 *bufptr
++ = value
->resolution
.xres
>> 16;
4456 *bufptr
++ = value
->resolution
.xres
>> 8;
4457 *bufptr
++ = value
->resolution
.xres
;
4458 *bufptr
++ = value
->resolution
.yres
>> 24;
4459 *bufptr
++ = value
->resolution
.yres
>> 16;
4460 *bufptr
++ = value
->resolution
.yres
>> 8;
4461 *bufptr
++ = value
->resolution
.yres
;
4462 *bufptr
++ = value
->resolution
.units
;
4466 case IPP_TAG_RANGE
:
4467 for (i
= 0, value
= attr
->values
;
4468 i
< attr
->num_values
;
4471 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 13)
4473 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4475 DEBUG_puts("1ippWriteIO: Could not write IPP "
4477 ipp_buffer_release(buffer
);
4487 * Arrays and sets are done by sending additional
4488 * values with a zero-length name...
4491 *bufptr
++ = attr
->value_tag
;
4497 * Range values consist of a 2-byte length,
4498 * 4-byte lower value, and 4-byte upper value.
4500 * Put the 2-byte length and range value data
4506 *bufptr
++ = value
->range
.lower
>> 24;
4507 *bufptr
++ = value
->range
.lower
>> 16;
4508 *bufptr
++ = value
->range
.lower
>> 8;
4509 *bufptr
++ = value
->range
.lower
;
4510 *bufptr
++ = value
->range
.upper
>> 24;
4511 *bufptr
++ = value
->range
.upper
>> 16;
4512 *bufptr
++ = value
->range
.upper
>> 8;
4513 *bufptr
++ = value
->range
.upper
;
4517 case IPP_TAG_TEXTLANG
:
4518 case IPP_TAG_NAMELANG
:
4519 for (i
= 0, value
= attr
->values
;
4520 i
< attr
->num_values
;
4526 * Arrays and sets are done by sending additional
4527 * values with a zero-length name...
4530 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
4532 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4534 DEBUG_puts("1ippWriteIO: Could not write IPP "
4536 ipp_buffer_release(buffer
);
4543 *bufptr
++ = attr
->value_tag
;
4549 * textWithLanguage and nameWithLanguage values consist
4550 * of a 2-byte length for both strings and their
4551 * individual lengths, a 2-byte length for the
4552 * character string, the character string without the
4553 * trailing nul, a 2-byte length for the character
4554 * set string, and the character set string without
4560 if (value
->string
.language
!= NULL
)
4561 n
+= (int)strlen(value
->string
.language
);
4563 if (value
->string
.text
!= NULL
)
4564 n
+= (int)strlen(value
->string
.text
);
4566 if (n
> (IPP_BUF_SIZE
- 2))
4568 DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
4569 "too long (%d)", n
));
4570 ipp_buffer_release(buffer
);
4574 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
4576 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4578 DEBUG_puts("1ippWriteIO: Could not write IPP "
4580 ipp_buffer_release(buffer
);
4587 /* Length of entire value */
4591 /* Length of language */
4592 if (value
->string
.language
!= NULL
)
4593 n
= (int)strlen(value
->string
.language
);
4603 memcpy(bufptr
, value
->string
.language
, n
);
4607 /* Length of text */
4608 if (value
->string
.text
!= NULL
)
4609 n
= (int)strlen(value
->string
.text
);
4619 memcpy(bufptr
, value
->string
.text
, n
);
4625 case IPP_TAG_BEGIN_COLLECTION
:
4626 for (i
= 0, value
= attr
->values
;
4627 i
< attr
->num_values
;
4631 * Collections are written with the begin-collection
4632 * tag first with a value of 0 length, followed by the
4633 * attributes in the collection, then the end-collection
4637 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 5)
4639 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4641 DEBUG_puts("1ippWriteIO: Could not write IPP "
4643 ipp_buffer_release(buffer
);
4653 * Arrays and sets are done by sending additional
4654 * values with a zero-length name...
4657 *bufptr
++ = attr
->value_tag
;
4663 * Write a data length of 0 and flush the buffer...
4669 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4671 DEBUG_puts("1ippWriteIO: Could not write IPP "
4673 ipp_buffer_release(buffer
);
4680 * Then write the collection attribute...
4683 value
->collection
->state
= IPP_IDLE
;
4685 if (ippWriteIO(dst
, cb
, 1, ipp
,
4686 value
->collection
) == IPP_ERROR
)
4688 DEBUG_puts("1ippWriteIO: Unable to write collection value");
4689 ipp_buffer_release(buffer
);
4696 for (i
= 0, value
= attr
->values
;
4697 i
< attr
->num_values
;
4703 * Arrays and sets are done by sending additional
4704 * values with a zero-length name...
4707 if ((IPP_BUF_SIZE
- (bufptr
- buffer
)) < 3)
4709 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4711 DEBUG_puts("1ippWriteIO: Could not write IPP "
4713 ipp_buffer_release(buffer
);
4720 *bufptr
++ = attr
->value_tag
;
4726 * An unknown value might some new value that a
4727 * vendor has come up with. It consists of a
4728 * 2-byte length and the bytes in the unknown
4732 n
= value
->unknown
.length
;
4734 if (n
> (IPP_BUF_SIZE
- 2))
4736 DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
4738 ipp_buffer_release(buffer
);
4742 if ((int)(IPP_BUF_SIZE
- (bufptr
- buffer
)) < (n
+ 2))
4744 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4746 DEBUG_puts("1ippWriteIO: Could not write IPP "
4748 ipp_buffer_release(buffer
);
4755 /* Length of unknown value */
4762 memcpy(bufptr
, value
->unknown
.data
, n
);
4770 * Write the data out...
4773 if (bufptr
> buffer
)
4775 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
4777 DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4778 ipp_buffer_release(buffer
);
4782 DEBUG_printf(("2ippWriteIO: wrote %d bytes",
4783 (int)(bufptr
- buffer
)));
4787 * If blocking is disabled, stop here...
4794 if (ipp
->current
== NULL
)
4797 * Done with all of the attributes; add the end-of-attributes
4798 * tag or end-collection attribute...
4803 buffer
[0] = IPP_TAG_END
;
4808 buffer
[0] = IPP_TAG_END_COLLECTION
;
4809 buffer
[1] = 0; /* empty name */
4811 buffer
[3] = 0; /* empty value */
4816 if ((*cb
)(dst
, buffer
, n
) < 0)
4818 DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
4819 ipp_buffer_release(buffer
);
4823 ipp
->state
= IPP_DATA
;
4831 break; /* anti-compiler-warning-code */
4834 ipp_buffer_release(buffer
);
4836 return (ipp
->state
);
4841 * 'ipp_add_attr()' - Add a new attribute to the message.
4844 static ipp_attribute_t
* /* O - New attribute */
4845 ipp_add_attr(ipp_t
*ipp
, /* I - IPP message */
4846 const char *name
, /* I - Attribute name or NULL */
4847 ipp_tag_t group_tag
, /* I - Group tag or IPP_TAG_ZERO */
4848 ipp_tag_t value_tag
, /* I - Value tag or IPP_TAG_ZERO */
4849 int num_values
) /* I - Number of values */
4851 int alloc_values
; /* Number of values to allocate */
4852 ipp_attribute_t
*attr
; /* New attribute */
4855 DEBUG_printf(("4ipp_add_attr(ipp=%p, name=\"%s\", group_tag=0x%x, value_tag=0x%x, "
4856 "num_values=%d)", ipp
, name
, group_tag
, value_tag
, num_values
));
4859 * Range check input...
4862 if (!ipp
|| num_values
< 0)
4866 * Allocate memory, rounding the allocation up as needed...
4869 if (num_values
<= 1)
4872 alloc_values
= (num_values
+ IPP_MAX_VALUES
- 1) & ~(IPP_MAX_VALUES
- 1);
4874 attr
= calloc(sizeof(ipp_attribute_t
) +
4875 (alloc_values
- 1) * sizeof(_ipp_value_t
), 1);
4880 * Initialize attribute...
4884 attr
->name
= _cupsStrAlloc(name
);
4886 attr
->group_tag
= group_tag
;
4887 attr
->value_tag
= value_tag
;
4888 attr
->num_values
= num_values
;
4891 * Add it to the end of the linked list...
4895 ipp
->last
->next
= attr
;
4899 ipp
->prev
= ipp
->last
;
4900 ipp
->last
= ipp
->current
= attr
;
4903 DEBUG_printf(("5ipp_add_attr: Returning %p", attr
));
4910 * 'ipp_buffer_get()' - Get a read/write buffer.
4913 static unsigned char * /* O - Buffer */
4914 ipp_buffer_get(void)
4916 _ipp_buffer_t
*buffer
; /* Current buffer */
4917 _cups_globals_t
*cg
= _cupsGlobals();
4921 for (buffer
= cg
->ipp_buffers
; buffer
; buffer
= buffer
->next
)
4928 if ((buffer
= malloc(sizeof(_ipp_buffer_t
))) == NULL
)
4932 buffer
->next
= cg
->ipp_buffers
;
4933 cg
->ipp_buffers
= buffer
;
4940 * 'ipp_buffer_release()' - Release a read/write buffer.
4944 ipp_buffer_release(unsigned char *b
) /* I - Buffer to release */
4946 ((_ipp_buffer_t
*)b
)->used
= 0;
4951 * 'ipp_free_values()' - Free attribute values.
4955 ipp_free_values(ipp_attribute_t
*attr
, /* I - Attribute to free values from */
4956 int element
,/* I - First value to free */
4957 int count
) /* I - Number of values to free */
4959 int i
; /* Looping var */
4960 _ipp_value_t
*value
; /* Current value */
4963 DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", attr
, element
, count
));
4965 if (!(attr
->value_tag
& IPP_TAG_COPY
))
4968 * Free values as needed...
4971 switch (attr
->value_tag
)
4973 case IPP_TAG_TEXTLANG
:
4974 case IPP_TAG_NAMELANG
:
4975 if (element
== 0 && count
== attr
->num_values
&& attr
->values
[0].string
.language
)
4976 _cupsStrFree(attr
->values
[0].string
.language
);
4980 case IPP_TAG_RESERVED_STRING
:
4981 case IPP_TAG_KEYWORD
:
4983 case IPP_TAG_URISCHEME
:
4984 case IPP_TAG_CHARSET
:
4985 case IPP_TAG_LANGUAGE
:
4986 case IPP_TAG_MIMETYPE
:
4987 for (i
= count
, value
= attr
->values
+ element
;
4990 _cupsStrFree(value
->string
.text
);
4993 case IPP_TAG_DEFAULT
:
4994 case IPP_TAG_UNKNOWN
:
4995 case IPP_TAG_NOVALUE
:
4996 case IPP_TAG_NOTSETTABLE
:
4997 case IPP_TAG_DELETEATTR
:
4998 case IPP_TAG_ADMINDEFINE
:
4999 case IPP_TAG_INTEGER
:
5001 case IPP_TAG_BOOLEAN
:
5003 case IPP_TAG_RESOLUTION
:
5004 case IPP_TAG_RANGE
:
5007 case IPP_TAG_BEGIN_COLLECTION
:
5008 for (i
= count
, value
= attr
->values
+ element
;
5011 ippDelete(value
->collection
);
5014 case IPP_TAG_STRING
:
5016 for (i
= count
, value
= attr
->values
+ element
;
5019 if (value
->unknown
.data
)
5020 free(value
->unknown
.data
);
5026 * If we are not freeing values from the end, move the remaining values up...
5029 if ((element
+ count
) < attr
->num_values
)
5030 memmove(attr
->values
+ element
, attr
->values
+ element
+ count
,
5031 (attr
->num_values
- count
- element
) * sizeof(_ipp_value_t
));
5033 attr
->num_values
-= count
;
5038 * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
5040 * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
5041 * to "ll-cc", "ll-region", and "charset-number", respectively.
5044 static char * /* O - Language code string */
5045 ipp_get_code(const char *value
, /* I - Locale/charset string */
5046 char *buffer
, /* I - String buffer */
5047 size_t bufsize
) /* I - Size of string buffer */
5049 char *bufptr
, /* Pointer into buffer */
5050 *bufend
; /* End of buffer */
5054 * Convert values to lowercase and change _ to - as needed...
5057 for (bufptr
= buffer
, bufend
= buffer
+ bufsize
- 1;
5058 *value
&& bufptr
< bufend
;
5063 *bufptr
++ = _cups_tolower(*value
);
5068 * Return the converted string...
5076 * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
5078 * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
5079 * "ll-region", respectively. It also converts the "C" (POSIX) locale to "en".
5082 static char * /* O - Language code string */
5083 ipp_lang_code(const char *locale
, /* I - Locale string */
5084 char *buffer
, /* I - String buffer */
5085 size_t bufsize
) /* I - Size of string buffer */
5088 * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
5091 if (!_cups_strcasecmp(locale
, "c"))
5093 strlcpy(buffer
, "en", bufsize
);
5097 return (ipp_get_code(locale
, buffer
, bufsize
));
5102 * 'ipp_length()' - Compute the length of an IPP message or collection value.
5105 static size_t /* O - Size of IPP message */
5106 ipp_length(ipp_t
*ipp
, /* I - IPP message or collection */
5107 int collection
) /* I - 1 if a collection, 0 otherwise */
5109 int i
; /* Looping var */
5110 size_t bytes
; /* Number of bytes */
5111 ipp_attribute_t
*attr
; /* Current attribute */
5112 ipp_tag_t group
; /* Current group */
5113 _ipp_value_t
*value
; /* Current value */
5116 DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", ipp
, collection
));
5120 DEBUG_puts("4ipp_length: Returning 0 bytes");
5125 * Start with 8 bytes for the IPP message header...
5128 bytes
= collection
? 0 : 8;
5131 * Then add the lengths of each attribute...
5134 group
= IPP_TAG_ZERO
;
5136 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= attr
->next
)
5138 if (attr
->group_tag
!= group
&& !collection
)
5140 group
= attr
->group_tag
;
5141 if (group
== IPP_TAG_ZERO
)
5144 bytes
++; /* Group tag */
5150 DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
5151 "bytes=" CUPS_LLFMT
, attr
->name
, attr
->num_values
, CUPS_LLCAST bytes
));
5153 if (attr
->value_tag
< IPP_TAG_EXTENSION
)
5154 bytes
+= attr
->num_values
; /* Value tag for each value */
5156 bytes
+= 5 * attr
->num_values
; /* Value tag for each value */
5157 bytes
+= 2 * attr
->num_values
; /* Name lengths */
5158 bytes
+= (int)strlen(attr
->name
); /* Name */
5159 bytes
+= 2 * attr
->num_values
; /* Value lengths */
5162 bytes
+= 5; /* Add membername overhead */
5164 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
5166 case IPP_TAG_UNSUPPORTED_VALUE
:
5167 case IPP_TAG_DEFAULT
:
5168 case IPP_TAG_UNKNOWN
:
5169 case IPP_TAG_NOVALUE
:
5170 case IPP_TAG_NOTSETTABLE
:
5171 case IPP_TAG_DELETEATTR
:
5172 case IPP_TAG_ADMINDEFINE
:
5175 case IPP_TAG_INTEGER
:
5177 bytes
+= 4 * attr
->num_values
;
5180 case IPP_TAG_BOOLEAN
:
5181 bytes
+= attr
->num_values
;
5186 case IPP_TAG_KEYWORD
:
5188 case IPP_TAG_URISCHEME
:
5189 case IPP_TAG_CHARSET
:
5190 case IPP_TAG_LANGUAGE
:
5191 case IPP_TAG_MIMETYPE
:
5192 for (i
= 0, value
= attr
->values
;
5193 i
< attr
->num_values
;
5195 if (value
->string
.text
)
5196 bytes
+= strlen(value
->string
.text
);
5200 bytes
+= 11 * attr
->num_values
;
5203 case IPP_TAG_RESOLUTION
:
5204 bytes
+= 9 * attr
->num_values
;
5207 case IPP_TAG_RANGE
:
5208 bytes
+= 8 * attr
->num_values
;
5211 case IPP_TAG_TEXTLANG
:
5212 case IPP_TAG_NAMELANG
:
5213 bytes
+= 4 * attr
->num_values
;/* Charset + text length */
5215 for (i
= 0, value
= attr
->values
;
5216 i
< attr
->num_values
;
5219 if (value
->string
.language
)
5220 bytes
+= strlen(value
->string
.language
);
5222 if (value
->string
.text
)
5223 bytes
+= strlen(value
->string
.text
);
5227 case IPP_TAG_BEGIN_COLLECTION
:
5228 for (i
= 0, value
= attr
->values
;
5229 i
< attr
->num_values
;
5231 bytes
+= ipp_length(value
->collection
, 1);
5235 for (i
= 0, value
= attr
->values
;
5236 i
< attr
->num_values
;
5238 bytes
+= value
->unknown
.length
;
5244 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
5245 * for the "end of collection" tag and return...
5253 DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT
" bytes", CUPS_LLCAST bytes
));
5260 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
5263 static ssize_t
/* O - Number of bytes read */
5264 ipp_read_http(http_t
*http
, /* I - Client connection */
5265 ipp_uchar_t
*buffer
, /* O - Buffer for data */
5266 size_t length
) /* I - Total length */
5268 int tbytes
, /* Total bytes read */
5269 bytes
; /* Bytes read this pass */
5270 char len
[32]; /* Length string */
5273 DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)",
5274 http
, buffer
, (int)length
));
5277 * Loop until all bytes are read...
5280 for (tbytes
= 0, bytes
= 0;
5281 tbytes
< (int)length
;
5282 tbytes
+= bytes
, buffer
+= bytes
)
5284 DEBUG_printf(("9ipp_read_http: tbytes=%d, http->state=%d", tbytes
,
5287 if (http
->state
== HTTP_WAITING
)
5290 if (http
->used
> 0 && http
->data_encoding
== HTTP_ENCODE_LENGTH
)
5293 * Do "fast read" from HTTP buffer directly...
5296 if (http
->used
> (int)(length
- tbytes
))
5297 bytes
= (int)(length
- tbytes
);
5302 buffer
[0] = http
->buffer
[0];
5304 memcpy(buffer
, http
->buffer
, bytes
);
5306 http
->used
-= bytes
;
5307 http
->data_remaining
-= bytes
;
5309 if (http
->data_remaining
<= INT_MAX
)
5310 http
->_data_remaining
= (int)http
->data_remaining
;
5312 http
->_data_remaining
= INT_MAX
;
5315 memmove(http
->buffer
, http
->buffer
+ bytes
, http
->used
);
5317 if (http
->data_remaining
== 0)
5319 if (http
->data_encoding
== HTTP_ENCODE_CHUNKED
)
5322 * Get the trailing CR LF after the chunk...
5325 if (!httpGets(len
, sizeof(len
), http
))
5329 if (http
->data_encoding
!= HTTP_ENCODE_CHUNKED
)
5331 if (http
->state
== HTTP_POST_RECV
)
5334 http
->state
= HTTP_WAITING
;
5341 * Wait a maximum of 1 second for data...
5344 if (!http
->blocking
)
5347 * Wait up to 10 seconds for more data on non-blocking sockets...
5350 if (!httpWait(http
, 10000))
5361 if ((bytes
= httpRead2(http
, (char *)buffer
, length
- tbytes
)) < 0)
5366 if (errno
!= EAGAIN
&& errno
!= EINTR
)
5372 else if (bytes
== 0)
5378 * Return the number of bytes read...
5381 if (tbytes
== 0 && bytes
< 0)
5384 DEBUG_printf(("8ipp_read_http: Returning %d bytes", tbytes
));
5391 * 'ipp_read_file()' - Read IPP data from a file.
5394 static ssize_t
/* O - Number of bytes read */
5395 ipp_read_file(int *fd
, /* I - File descriptor */
5396 ipp_uchar_t
*buffer
, /* O - Read buffer */
5397 size_t length
) /* I - Number of bytes to read */
5400 return ((ssize_t
)read(*fd
, buffer
, (unsigned)length
));
5402 return (read(*fd
, buffer
, length
));
5408 * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
5412 static _ipp_value_t
* /* O - IPP value element or NULL on error */
5413 ipp_set_value(ipp_t
*ipp
, /* IO - IPP message */
5414 ipp_attribute_t
**attr
, /* IO - IPP attribute */
5415 int element
) /* I - Value number (0-based) */
5417 ipp_attribute_t
*temp
, /* New attribute pointer */
5418 *current
, /* Current attribute in list */
5419 *prev
; /* Previous attribute in list */
5420 int alloc_values
; /* Allocated values */
5424 * If we are setting an existing value element, return it...
5429 if (temp
->num_values
<= 1)
5432 alloc_values
= (temp
->num_values
+ IPP_MAX_VALUES
- 1) &
5433 ~(IPP_MAX_VALUES
- 1);
5435 if (element
< alloc_values
)
5437 if (element
>= temp
->num_values
)
5438 temp
->num_values
= element
+ 1;
5440 return (temp
->values
+ element
);
5444 * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
5445 * values when num_values > 1.
5448 if (alloc_values
< IPP_MAX_VALUES
)
5449 alloc_values
= IPP_MAX_VALUES
;
5451 alloc_values
+= IPP_MAX_VALUES
;
5453 DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
5457 * Reallocate memory...
5460 if ((temp
= realloc(temp
, sizeof(ipp_attribute_t
) +
5461 (alloc_values
- 1) * sizeof(_ipp_value_t
))) == NULL
)
5463 _cupsSetHTTPError(HTTP_ERROR
);
5464 DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
5469 * Zero the new memory...
5472 memset(temp
->values
+ temp
->num_values
, 0,
5473 (alloc_values
- temp
->num_values
) * sizeof(_ipp_value_t
));
5478 * Reset pointers in the list...
5481 if (ipp
->current
== *attr
&& ipp
->prev
)
5484 * Use current "previous" pointer...
5492 * Find this attribute in the linked list...
5495 for (prev
= NULL
, current
= ipp
->attrs
;
5496 current
&& current
!= *attr
;
5497 prev
= current
, current
= current
->next
);
5502 * This is a serious error!
5506 _cupsSetError(IPP_ERROR
,
5507 _("IPP attribute is not a member of the message."), 1);
5508 DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
5518 ipp
->current
= temp
;
5521 if (ipp
->last
== *attr
)
5528 * Return the value element...
5531 if (element
>= temp
->num_values
)
5532 temp
->num_values
= element
+ 1;
5534 return (temp
->values
+ element
);
5539 * 'ipp_write_file()' - Write IPP data to a file.
5542 static ssize_t
/* O - Number of bytes written */
5543 ipp_write_file(int *fd
, /* I - File descriptor */
5544 ipp_uchar_t
*buffer
, /* I - Data to write */
5545 size_t length
) /* I - Number of bytes to write */
5548 return ((ssize_t
)write(*fd
, buffer
, (unsigned)length
));
5550 return (write(*fd
, buffer
, length
));
5556 * End of "$Id: ipp.c 10102 2011-11-02 23:52:39Z mike $".