2 * "$Id: ipp.c 7847 2008-08-19 04:22:14Z mike $"
4 * Internet Printing Protocol support functions for the Common UNIX
5 * Printing System (CUPS).
7 * Copyright 2007-2008 by Apple Inc.
8 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
10 * These coded instructions, statements, and computer programs are the
11 * property of Apple Inc. and are protected by Federal copyright
12 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
13 * which should have been included with this file. If this file is
14 * file is missing or damaged, see the license at "http://www.cups.org/".
16 * This file is subject to the Apple OS-Developed Software exception.
20 * ippAddBoolean() - Add a boolean attribute to an IPP message.
21 * ippAddBooleans() - Add an array of boolean values.
22 * ippAddDate() - Add a date attribute to an IPP message.
23 * ippAddInteger() - Add a integer attribute to an IPP message.
24 * ippAddIntegers() - Add an array of integer values.
25 * ippAddOctetString() - Add an octetString value to an IPP message.
26 * ippAddString() - Add a language-encoded string to an IPP message.
27 * ippAddStrings() - Add language-encoded strings 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 * ippDateToTime() - Convert from RFC 1903 Date/Time format to
34 * UNIX time in seconds.
35 * ippDelete() - Delete an IPP message.
36 * ippDeleteAttribute() - Delete a single attribute in an IPP message.
37 * ippFindAttribute() - Find a named attribute in a request...
38 * ippFindNextAttribute() - Find the next named attribute in a request...
39 * ippLength() - Compute the length of an IPP message.
40 * ippNew() - Allocate a new IPP message.
41 * ippNewRequest() - Allocate a new IPP message.
42 * ippRead() - Read data for an IPP message from a HTTP
44 * ippReadFile() - Read data for an IPP message from a file.
45 * ippReadIO() - Read data for an IPP message.
46 * ippTimeToDate() - Convert from UNIX time to RFC 1903 format.
47 * ippWrite() - Write data for an IPP message to a HTTP
49 * ippWriteFile() - Write data for an IPP message to a file.
50 * ippWriteIO() - Write data for an IPP message.
51 * _ippAddAttr() - Add a new attribute to the request.
52 * _ippFreeAttr() - Free an attribute.
53 * ipp_length() - Compute the length of an IPP message or
55 * ipp_read_http() - Semi-blocking read on a HTTP connection...
56 * ipp_read_file() - Read IPP data from a file.
57 * ipp_write_file() - Write IPP data to a file.
61 * Include necessary headers...
64 #include "http-private.h"
78 static size_t ipp_length(ipp_t
*ipp
, int collection
);
79 static ssize_t
ipp_read_http(http_t
*http
, ipp_uchar_t
*buffer
,
81 static ssize_t
ipp_read_file(int *fd
, ipp_uchar_t
*buffer
,
83 static ssize_t
ipp_write_file(int *fd
, ipp_uchar_t
*buffer
,
88 * 'ippAddBoolean()' - Add a boolean attribute to an IPP message.
91 ipp_attribute_t
* /* O - New attribute */
92 ippAddBoolean(ipp_t
*ipp
, /* I - IPP message */
93 ipp_tag_t group
, /* I - IPP group */
94 const char *name
, /* I - Name of attribute */
95 char value
) /* I - Value of attribute */
97 ipp_attribute_t
*attr
; /* New attribute */
100 DEBUG_printf(("ippAddBoolean(ipp=%p, group=%02x(%s), name=\"%s\", value=%d)\n",
101 ipp
, group
, ippTagString(group
), name
, value
));
106 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
109 attr
->name
= _cupsStrAlloc(name
);
110 attr
->group_tag
= group
;
111 attr
->value_tag
= IPP_TAG_BOOLEAN
;
112 attr
->values
[0].boolean
= value
;
119 * 'ippAddBooleans()' - Add an array of boolean values.
122 ipp_attribute_t
* /* O - New attribute */
123 ippAddBooleans(ipp_t
*ipp
, /* I - IPP message */
124 ipp_tag_t group
, /* I - IPP group */
125 const char *name
, /* I - Name of attribute */
126 int num_values
, /* I - Number of values */
127 const char *values
) /* I - Values */
129 int i
; /* Looping var */
130 ipp_attribute_t
*attr
; /* New attribute */
131 ipp_value_t
*value
; /* Current value */
134 DEBUG_printf(("ippAddBooleans(ipp=%p, group=%02x(%s), name=\"%s\", "
135 "num_values=%d, values=%p)\n", ipp
, group
, ippTagString(group
),
136 name
, num_values
, values
));
138 if (!ipp
|| !name
|| num_values
< 1)
141 if ((attr
= _ippAddAttr(ipp
, num_values
)) == NULL
)
144 attr
->name
= _cupsStrAlloc(name
);
145 attr
->group_tag
= group
;
146 attr
->value_tag
= IPP_TAG_BOOLEAN
;
149 for (i
= 0, value
= attr
->values
;
152 value
->boolean
= values
[i
];
159 * 'ippAddCollection()' - Add a collection value.
161 * @since CUPS 1.1.19@
164 ipp_attribute_t
* /* O - New attribute */
165 ippAddCollection(ipp_t
*ipp
, /* I - IPP message */
166 ipp_tag_t group
, /* I - IPP group */
167 const char *name
, /* I - Name of attribute */
168 ipp_t
*value
) /* I - Value */
170 ipp_attribute_t
*attr
; /* New attribute */
173 DEBUG_printf(("ippAddCollection(ipp=%p, group=%02x(%s), name=\"%s\", "
174 "value=%p)\n", ipp
, group
, ippTagString(group
), name
, value
));
179 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
182 attr
->name
= _cupsStrAlloc(name
);
183 attr
->group_tag
= group
;
184 attr
->value_tag
= IPP_TAG_BEGIN_COLLECTION
;
185 attr
->values
[0].collection
= value
;
192 * 'ippAddCollections()' - Add an array of collection values.
194 * @since CUPS 1.1.19@
197 ipp_attribute_t
* /* O - New attribute */
199 ipp_t
*ipp
, /* I - IPP message */
200 ipp_tag_t group
, /* I - IPP group */
201 const char *name
, /* I - Name of attribute */
202 int num_values
, /* I - Number of values */
203 const ipp_t
**values
) /* I - Values */
205 int i
; /* Looping var */
206 ipp_attribute_t
*attr
; /* New attribute */
207 ipp_value_t
*value
; /* Current value */
210 DEBUG_printf(("ippAddCollections(ipp=%p, group=%02x(%s), name=\"%s\", "
211 "num_values=%d, values=%p)\n", ipp
, group
, ippTagString(group
),
212 name
, num_values
, values
));
214 if (!ipp
|| !name
|| num_values
< 1)
217 if ((attr
= _ippAddAttr(ipp
, num_values
)) == NULL
)
220 attr
->name
= _cupsStrAlloc(name
);
221 attr
->group_tag
= group
;
222 attr
->value_tag
= IPP_TAG_BEGIN_COLLECTION
;
225 for (i
= 0, value
= attr
->values
;
228 value
->collection
= (ipp_t
*)values
[i
];
235 * 'ippAddDate()' - Add a date attribute to an IPP message.
238 ipp_attribute_t
* /* O - New attribute */
239 ippAddDate(ipp_t
*ipp
, /* I - IPP message */
240 ipp_tag_t group
, /* I - IPP group */
241 const char *name
, /* I - Name of attribute */
242 const ipp_uchar_t
*value
) /* I - Value */
244 ipp_attribute_t
*attr
; /* New attribute */
247 DEBUG_printf(("ippAddDate(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)\n",
248 ipp
, group
, ippTagString(group
), name
, value
));
250 if (!ipp
|| !name
|| !value
)
253 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
256 attr
->name
= _cupsStrAlloc(name
);
257 attr
->group_tag
= group
;
258 attr
->value_tag
= IPP_TAG_DATE
;
259 memcpy(attr
->values
[0].date
, value
, 11);
266 * 'ippAddInteger()' - Add a integer attribute to an IPP message.
269 ipp_attribute_t
* /* O - New attribute */
270 ippAddInteger(ipp_t
*ipp
, /* I - IPP message */
271 ipp_tag_t group
, /* I - IPP group */
272 ipp_tag_t type
, /* I - Type of attribute */
273 const char *name
, /* I - Name of attribute */
274 int value
) /* I - Value of attribute */
276 ipp_attribute_t
*attr
; /* New attribute */
279 DEBUG_printf(("ippAddInteger(ipp=%p, group=%02x(%s), type=%02x(%s), "
280 "name=\"%s\", value=%d)\n", ipp
, group
, ippTagString(group
),
281 type
, ippTagString(type
), name
, value
));
286 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
289 attr
->name
= _cupsStrAlloc(name
);
290 attr
->group_tag
= group
;
291 attr
->value_tag
= type
;
292 attr
->values
[0].integer
= value
;
299 * 'ippAddIntegers()' - Add an array of integer values.
302 ipp_attribute_t
* /* O - New attribute */
303 ippAddIntegers(ipp_t
*ipp
, /* I - IPP message */
304 ipp_tag_t group
, /* I - IPP group */
305 ipp_tag_t type
, /* I - Type of attribute */
306 const char *name
, /* I - Name of attribute */
307 int num_values
, /* I - Number of values */
308 const int *values
) /* I - Values */
310 int i
; /* Looping var */
311 ipp_attribute_t
*attr
; /* New attribute */
312 ipp_value_t
*value
; /* Current value */
315 DEBUG_printf(("ippAddIntegers(ipp=%p, group=%02x(%s), type=%02x(%s), "
316 "name=\"%s\", num_values=%d, values=%p)\n", ipp
,
317 group
, ippTagString(group
), type
, ippTagString(type
), name
,
318 num_values
, values
));
320 if (!ipp
|| !name
|| num_values
< 1)
323 if ((attr
= _ippAddAttr(ipp
, num_values
)) == NULL
)
326 attr
->name
= _cupsStrAlloc(name
);
327 attr
->group_tag
= group
;
328 attr
->value_tag
= type
;
331 for (i
= 0, value
= attr
->values
;
334 value
->integer
= values
[i
];
341 * 'ippAddOctetString()' - Add an octetString value to an IPP message.
346 ipp_attribute_t
* /* O - New attribute */
347 ippAddOctetString(ipp_t
*ipp
, /* I - IPP message */
348 ipp_tag_t group
, /* I - IPP group */
349 const char *name
, /* I - Name of attribute */
350 const void *data
, /* I - octetString data */
351 int datalen
) /* I - Length of data in bytes */
353 ipp_attribute_t
*attr
; /* New attribute */
356 if (ipp
== NULL
|| name
== NULL
)
359 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
363 * Initialize the attribute data...
366 attr
->name
= _cupsStrAlloc(name
);
367 attr
->group_tag
= group
;
368 attr
->value_tag
= IPP_TAG_STRING
;
369 attr
->values
[0].unknown
.length
= datalen
;
373 if ((attr
->values
[0].unknown
.data
= malloc(datalen
)) == NULL
)
375 ippDeleteAttribute(ipp
, attr
);
379 memcpy(attr
->values
[0].unknown
.data
, data
, datalen
);
383 * Return the new attribute...
391 * 'ippAddString()' - Add a language-encoded string to an IPP message.
394 ipp_attribute_t
* /* O - New attribute */
395 ippAddString(ipp_t
*ipp
, /* I - IPP message */
396 ipp_tag_t group
, /* I - IPP group */
397 ipp_tag_t type
, /* I - Type of attribute */
398 const char *name
, /* I - Name of attribute */
399 const char *charset
, /* I - Character set */
400 const char *value
) /* I - Value */
402 ipp_attribute_t
*attr
; /* New attribute */
403 char buffer
[1024], /* Language/charset value buffer */
404 *bufptr
; /* Pointer into buffer */
407 DEBUG_printf(("ippAddString(ipp=%p, group=%02x(%s), type=%02x(%s), "
408 "name=\"%s\", charset=\"%s\", value=\"%s\")\n", ipp
,
409 group
, ippTagString(group
), type
, ippTagString(type
), name
,
415 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
419 * Force value to be English for the POSIX locale...
422 if (type
== IPP_TAG_LANGUAGE
&& !strcasecmp(value
, "C"))
426 * Convert language values to lowercase and change _ to - as needed...
429 if ((type
== IPP_TAG_LANGUAGE
|| type
== IPP_TAG_CHARSET
) && value
)
431 strlcpy(buffer
, value
, sizeof(buffer
));
434 for (bufptr
= buffer
; *bufptr
; bufptr
++)
438 *bufptr
= tolower(*bufptr
& 255);
442 * Initialize the attribute data...
445 attr
->name
= _cupsStrAlloc(name
);
446 attr
->group_tag
= group
;
447 attr
->value_tag
= type
;
448 attr
->values
[0].string
.charset
= ((int)type
& IPP_TAG_COPY
) ? (char *)charset
:
449 charset
? _cupsStrAlloc(charset
) : NULL
;
450 attr
->values
[0].string
.text
= ((int)type
& IPP_TAG_COPY
) ? (char *)value
:
451 value
? _cupsStrAlloc(value
) : NULL
;
458 * 'ippAddStrings()' - Add language-encoded strings to an IPP message.
461 ipp_attribute_t
* /* O - New attribute */
463 ipp_t
*ipp
, /* I - IPP message */
464 ipp_tag_t group
, /* I - IPP group */
465 ipp_tag_t type
, /* I - Type of attribute */
466 const char *name
, /* I - Name of attribute */
467 int num_values
, /* I - Number of values */
468 const char *charset
, /* I - Character set */
469 const char * const *values
) /* I - Values */
471 int i
; /* Looping var */
472 ipp_attribute_t
*attr
; /* New attribute */
473 ipp_value_t
*value
; /* Current value */
476 DEBUG_printf(("ippAddStrings(ipp=%p, group=%02x(%s), type=%02x(%s), "
477 "name=\"%s\", num_values=%d, charset=\"%s\", values=%p)\n", ipp
,
478 group
, ippTagString(group
), type
, ippTagString(type
), name
,
479 num_values
, charset
, values
));
481 if (!ipp
|| !name
|| num_values
< 1)
484 if ((attr
= _ippAddAttr(ipp
, num_values
)) == NULL
)
488 * Initialize the attribute data...
491 attr
->name
= _cupsStrAlloc(name
);
492 attr
->group_tag
= group
;
493 attr
->value_tag
= type
;
495 for (i
= 0, value
= attr
->values
;
500 value
->string
.charset
= ((int)type
& IPP_TAG_COPY
) ? (char *)charset
:
501 charset
? _cupsStrAlloc(charset
) : NULL
;
503 value
->string
.charset
= attr
->values
[0].string
.charset
;
508 * Force language to be English for the POSIX locale...
511 if (type
== IPP_TAG_LANGUAGE
&& !strcasecmp(values
[i
], "C"))
512 value
->string
.text
= ((int)type
& IPP_TAG_COPY
) ? "en" :
515 value
->string
.text
= ((int)type
& IPP_TAG_COPY
) ? (char *)values
[i
] :
516 _cupsStrAlloc(values
[i
]);
525 * 'ippAddRange()' - Add a range of values to an IPP message.
528 ipp_attribute_t
* /* O - New attribute */
529 ippAddRange(ipp_t
*ipp
, /* I - IPP message */
530 ipp_tag_t group
, /* I - IPP group */
531 const char *name
, /* I - Name of attribute */
532 int lower
, /* I - Lower value */
533 int upper
) /* I - Upper value */
535 ipp_attribute_t
*attr
; /* New attribute */
538 DEBUG_printf(("ippAddRange(ipp=%p, group=%02x(%s), name=\"%s\", lower=%d, "
539 "upper=%d)\n", ipp
, group
, ippTagString(group
), name
, lower
,
545 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
548 attr
->name
= _cupsStrAlloc(name
);
549 attr
->group_tag
= group
;
550 attr
->value_tag
= IPP_TAG_RANGE
;
551 attr
->values
[0].range
.lower
= lower
;
552 attr
->values
[0].range
.upper
= upper
;
559 * 'ippAddRanges()' - Add ranges of values to an IPP message.
562 ipp_attribute_t
* /* O - New attribute */
563 ippAddRanges(ipp_t
*ipp
, /* I - IPP message */
564 ipp_tag_t group
, /* I - IPP group */
565 const char *name
, /* I - Name of attribute */
566 int num_values
, /* I - Number of values */
567 const int *lower
, /* I - Lower values */
568 const int *upper
) /* I - Upper values */
570 int i
; /* Looping var */
571 ipp_attribute_t
*attr
; /* New attribute */
572 ipp_value_t
*value
; /* Current value */
575 DEBUG_printf(("ippAddRanges(ipp=%p, group=%02x(%s), name=\"%s\", "
576 "num_values=%d, lower=%p, upper=%p)\n", ipp
, group
,
577 ippTagString(group
), name
, num_values
, lower
, upper
));
579 if (!ipp
|| !name
|| num_values
< 1)
582 if ((attr
= _ippAddAttr(ipp
, num_values
)) == NULL
)
585 attr
->name
= _cupsStrAlloc(name
);
586 attr
->group_tag
= group
;
587 attr
->value_tag
= IPP_TAG_RANGE
;
589 if (lower
!= NULL
&& upper
!= NULL
)
590 for (i
= 0, value
= attr
->values
;
594 value
->range
.lower
= lower
[i
];
595 value
->range
.upper
= upper
[i
];
603 * 'ippAddResolution()' - Add a resolution value to an IPP message.
606 ipp_attribute_t
* /* O - New attribute */
607 ippAddResolution(ipp_t
*ipp
, /* I - IPP message */
608 ipp_tag_t group
, /* I - IPP group */
609 const char *name
, /* I - Name of attribute */
610 ipp_res_t units
, /* I - Units for resolution */
611 int xres
, /* I - X resolution */
612 int yres
) /* I - Y resolution */
614 ipp_attribute_t
*attr
; /* New attribute */
617 DEBUG_printf(("ippAddResolution(ipp=%p, group=%02x(%s), name=\"%s\", "
618 "units=%d, xres=%d, yres=%d)\n", ipp
, group
,
619 ippTagString(group
), name
, units
, xres
, yres
));
624 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
627 attr
->name
= _cupsStrAlloc(name
);
628 attr
->group_tag
= group
;
629 attr
->value_tag
= IPP_TAG_RESOLUTION
;
630 attr
->values
[0].resolution
.xres
= xres
;
631 attr
->values
[0].resolution
.yres
= yres
;
632 attr
->values
[0].resolution
.units
= units
;
639 * 'ippAddResolutions()' - Add resolution values to an IPP message.
642 ipp_attribute_t
* /* O - New attribute */
643 ippAddResolutions(ipp_t
*ipp
, /* I - IPP message */
644 ipp_tag_t group
, /* I - IPP group */
645 const char *name
, /* I - Name of attribute */
646 int num_values
,/* I - Number of values */
647 ipp_res_t units
, /* I - Units for resolution */
648 const int *xres
, /* I - X resolutions */
649 const int *yres
) /* I - Y resolutions */
651 int i
; /* Looping var */
652 ipp_attribute_t
*attr
; /* New attribute */
653 ipp_value_t
*value
; /* Current value */
656 DEBUG_printf(("ippAddResolutions(ipp=%p, group=%02x(%s), name=\"%s\", "
657 "num_value=%d, units=%d, xres=%p, yres=%p)\n", ipp
, group
,
658 ippTagString(group
), name
, num_values
, units
, xres
, yres
));
660 if (!ipp
|| !name
|| num_values
< 1)
663 if ((attr
= _ippAddAttr(ipp
, num_values
)) == NULL
)
666 attr
->name
= _cupsStrAlloc(name
);
667 attr
->group_tag
= group
;
668 attr
->value_tag
= IPP_TAG_RESOLUTION
;
670 if (xres
!= NULL
&& yres
!= NULL
)
671 for (i
= 0, value
= attr
->values
;
675 value
->resolution
.xres
= xres
[i
];
676 value
->resolution
.yres
= yres
[i
];
677 value
->resolution
.units
= units
;
685 * 'ippAddSeparator()' - Add a group separator to an IPP message.
688 ipp_attribute_t
* /* O - New attribute */
689 ippAddSeparator(ipp_t
*ipp
) /* I - IPP message */
691 ipp_attribute_t
*attr
; /* New attribute */
694 DEBUG_printf(("ippAddSeparator(ipp=%p)\n", ipp
));
699 if ((attr
= _ippAddAttr(ipp
, 0)) == NULL
)
702 attr
->group_tag
= IPP_TAG_ZERO
;
703 attr
->value_tag
= IPP_TAG_ZERO
;
710 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
714 time_t /* O - UNIX time value */
715 ippDateToTime(const ipp_uchar_t
*date
) /* I - RFC 1903 date info */
717 struct tm unixdate
; /* UNIX date/time info */
718 time_t t
; /* Computed time */
724 memset(&unixdate
, 0, sizeof(unixdate
));
727 * RFC-1903 date/time format is:
729 * Byte(s) Description
730 * ------- -----------
731 * 0-1 Year (0 to 65535)
735 * 5 Minutes (0 to 59)
736 * 6 Seconds (0 to 60, 60 = "leap second")
737 * 7 Deciseconds (0 to 9)
739 * 9 UTC hours (0 to 11)
740 * 10 UTC minutes (0 to 59)
743 unixdate
.tm_year
= ((date
[0] << 8) | date
[1]) - 1900;
744 unixdate
.tm_mon
= date
[2] - 1;
745 unixdate
.tm_mday
= date
[3];
746 unixdate
.tm_hour
= date
[4];
747 unixdate
.tm_min
= date
[5];
748 unixdate
.tm_sec
= date
[6];
750 t
= mktime(&unixdate
);
753 t
+= date
[9] * 3600 + date
[10] * 60;
755 t
-= date
[9] * 3600 + date
[10] * 60;
762 * 'ippDelete()' - Delete an IPP message.
766 ippDelete(ipp_t
*ipp
) /* I - IPP message */
768 ipp_attribute_t
*attr
, /* Current attribute */
769 *next
; /* Next attribute */
772 DEBUG_printf(("ippDelete(ipp=%p)\n", ipp
));
777 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= next
)
788 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
790 * @since CUPS 1.1.19@
795 ipp_t
*ipp
, /* I - IPP message */
796 ipp_attribute_t
*attr
) /* I - Attribute to delete */
798 ipp_attribute_t
*current
, /* Current attribute */
799 *prev
; /* Previous attribute */
802 DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p)\n", ipp
, attr
));
805 * Find the attribute in the list...
808 for (current
= ipp
->attrs
, prev
= NULL
;
809 current
!= NULL
&& current
!= attr
;
810 prev
= current
, current
= current
->next
);
815 * Found it, remove the attribute from the list...
819 prev
->next
= current
->next
;
821 ipp
->attrs
= current
->next
;
823 if (current
== ipp
->last
)
827 * Free memory used by the attribute...
830 _ippFreeAttr(current
);
836 * 'ippFindAttribute()' - Find a named attribute in a request...
839 ipp_attribute_t
* /* O - Matching attribute */
840 ippFindAttribute(ipp_t
*ipp
, /* I - IPP message */
841 const char *name
, /* I - Name of attribute */
842 ipp_tag_t type
) /* I - Type of attribute */
844 DEBUG_printf(("ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))\n", ipp
,
845 name
, type
, ippTagString(type
)));
851 * Reset the current pointer...
857 * Search for the attribute...
860 return (ippFindNextAttribute(ipp
, name
, type
));
865 * 'ippFindNextAttribute()' - Find the next named attribute in a request...
868 ipp_attribute_t
* /* O - Matching attribute */
869 ippFindNextAttribute(ipp_t
*ipp
, /* I - IPP message */
870 const char *name
, /* I - Name of attribute */
871 ipp_tag_t type
) /* I - Type of attribute */
873 ipp_attribute_t
*attr
; /* Current atttribute */
874 ipp_tag_t value_tag
; /* Value tag */
877 DEBUG_printf(("ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))\n",
878 ipp
, name
, type
, ippTagString(type
)));
885 ipp
->prev
= ipp
->current
;
886 attr
= ipp
->current
->next
;
894 for (; attr
!= NULL
; ipp
->prev
= attr
, attr
= attr
->next
)
896 DEBUG_printf(("ippFindAttribute: attr=%p, name=\"%s\"\n", attr
,
899 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_MASK
);
901 if (attr
->name
!= NULL
&& strcasecmp(attr
->name
, name
) == 0 &&
902 (value_tag
== type
|| type
== IPP_TAG_ZERO
||
903 (value_tag
== IPP_TAG_TEXTLANG
&& type
== IPP_TAG_TEXT
) ||
904 (value_tag
== IPP_TAG_NAMELANG
&& type
== IPP_TAG_NAME
)))
920 * 'ippLength()' - Compute the length of an IPP message.
923 size_t /* O - Size of IPP message */
924 ippLength(ipp_t
*ipp
) /* I - IPP message */
926 return (ipp_length(ipp
, 0));
931 * 'ippNew()' - Allocate a new IPP message.
934 ipp_t
* /* O - New IPP message */
937 ipp_t
*temp
; /* New IPP message */
940 DEBUG_puts("ippNew()");
942 if ((temp
= (ipp_t
*)calloc(1, sizeof(ipp_t
))) != NULL
)
945 * Default to IPP 1.1...
948 temp
->request
.any
.version
[0] = 1;
949 temp
->request
.any
.version
[1] = 1;
952 DEBUG_printf(("ippNew: %p\n", temp
));
959 * 'ippNewRequest()' - Allocate a new IPP request message.
961 * The new request message is initialized with the attributes-charset and
962 * attributes-natural-language attributes added. The
963 * attributes-natural-language value is derived from the current locale.
968 ipp_t
* /* O - IPP request message */
969 ippNewRequest(ipp_op_t op
) /* I - Operation code */
971 ipp_t
*request
; /* IPP request message */
972 cups_lang_t
*language
; /* Current language localization */
975 DEBUG_printf(("ippNewRequest(op=%02x(%s))\n", op
, ippOpString(op
)));
978 * Create a new IPP message...
981 if ((request
= ippNew()) == NULL
)
985 * Set the operation and request ID...
988 request
->request
.op
.operation_id
= op
;
989 request
->request
.op
.request_id
= 1;
992 * Use UTF-8 as the character set...
995 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
996 "attributes-charset", NULL
, "utf-8");
999 * Get the language from the current locale...
1002 language
= cupsLangDefault();
1004 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
1005 "attributes-natural-language", NULL
, language
->language
);
1008 * Return the new request...
1016 * 'ippRead()' - Read data for an IPP message from a HTTP connection.
1019 ipp_state_t
/* O - Current state */
1020 ippRead(http_t
*http
, /* I - HTTP connection */
1021 ipp_t
*ipp
) /* I - IPP data */
1023 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT
"\n",
1024 http
, ipp
, CUPS_LLCAST (http
? http
->data_remaining
: -1)));
1029 DEBUG_printf(("ippRead: http->state=%d, http->used=%d\n", http
->state
,
1032 return (ippReadIO(http
, (ipp_iocb_t
)ipp_read_http
, http
->blocking
, NULL
,
1038 * 'ippReadFile()' - Read data for an IPP message from a file.
1040 * @since CUPS 1.1.19@
1043 ipp_state_t
/* O - Current state */
1044 ippReadFile(int fd
, /* I - HTTP data */
1045 ipp_t
*ipp
) /* I - IPP data */
1047 DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)\n", fd
, ipp
));
1049 return (ippReadIO(&fd
, (ipp_iocb_t
)ipp_read_file
, 1, NULL
, ipp
));
1054 * 'ippReadIO()' - Read data for an IPP message.
1059 ipp_state_t
/* O - Current state */
1060 ippReadIO(void *src
, /* I - Data source */
1061 ipp_iocb_t cb
, /* I - Read callback function */
1062 int blocking
, /* I - Use blocking IO? */
1063 ipp_t
*parent
, /* I - Parent request, if any */
1064 ipp_t
*ipp
) /* I - IPP data */
1066 int n
; /* Length of data */
1067 unsigned char buffer
[IPP_MAX_LENGTH
+ 1],
1069 string
[IPP_MAX_NAME
],
1070 /* Small string buffer */
1071 *bufptr
; /* Pointer into buffer */
1072 ipp_attribute_t
*attr
; /* Current attribute */
1073 ipp_tag_t tag
; /* Current tag */
1074 ipp_tag_t value_tag
; /* Current value tag */
1075 ipp_value_t
*value
; /* Current value */
1078 DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)\n",
1079 src
, cb
, blocking
, parent
, ipp
));
1080 DEBUG_printf(("ippReadIO: ipp->state=%d\n", ipp
->state
));
1088 ipp
->state
++; /* Avoid common problem... */
1094 * Get the request header...
1097 if ((*cb
)(src
, buffer
, 8) < 8)
1099 DEBUG_puts("ippReadIO: Unable to read header!");
1104 * Verify the major version number...
1109 DEBUG_printf(("ippReadIO: version number (%d.%d) is bad.\n",
1110 buffer
[0], buffer
[1]));
1115 * Then copy the request header over...
1118 ipp
->request
.any
.version
[0] = buffer
[0];
1119 ipp
->request
.any
.version
[1] = buffer
[1];
1120 ipp
->request
.any
.op_status
= (buffer
[2] << 8) | buffer
[3];
1121 ipp
->request
.any
.request_id
= (((((buffer
[4] << 8) | buffer
[5]) << 8) |
1122 buffer
[6]) << 8) | buffer
[7];
1124 DEBUG_printf(("ippReadIO: version=%d.%d\n", buffer
[0], buffer
[1]));
1125 DEBUG_printf(("ippReadIO: op_status=%04x\n",
1126 ipp
->request
.any
.op_status
));
1127 DEBUG_printf(("ippReadIO: request_id=%d\n",
1128 ipp
->request
.any
.request_id
));
1131 ipp
->state
= IPP_ATTRIBUTE
;
1132 ipp
->current
= NULL
;
1133 ipp
->curtag
= IPP_TAG_ZERO
;
1134 ipp
->prev
= ipp
->last
;
1137 * If blocking is disabled, stop here...
1143 case IPP_ATTRIBUTE
:
1146 if ((*cb
)(src
, buffer
, 1) < 1)
1149 DEBUG_printf(("ippReadIO: ipp->current=%p, ipp->prev=%p\n",
1150 ipp
->current
, ipp
->prev
));
1153 * Read this attribute...
1156 tag
= (ipp_tag_t
)buffer
[0];
1158 if (tag
== IPP_TAG_END
)
1161 * No more attributes left...
1164 DEBUG_puts("ippReadIO: IPP_TAG_END!");
1166 ipp
->state
= IPP_DATA
;
1169 else if (tag
< IPP_TAG_UNSUPPORTED_VALUE
)
1172 * Group tag... Set the current group and continue...
1175 if (ipp
->curtag
== tag
)
1176 ipp
->prev
= ippAddSeparator(ipp
);
1177 else if (ipp
->current
)
1178 ipp
->prev
= ipp
->current
;
1181 ipp
->current
= NULL
;
1182 DEBUG_printf(("ippReadIO: group tag=%x(%s), ipp->prev=%p\n", tag
,
1183 ippTagString(tag
), ipp
->prev
));
1187 DEBUG_printf(("ippReadIO: value tag=%x(%s)\n", tag
,
1188 ippTagString(tag
)));
1194 if ((*cb
)(src
, buffer
, 2) < 2)
1196 DEBUG_puts("ippReadIO: unable to read name length!");
1200 n
= (buffer
[0] << 8) | buffer
[1];
1202 if (n
> (sizeof(buffer
) - 1))
1204 DEBUG_printf(("ippReadIO: bad name length %d!\n", n
));
1208 DEBUG_printf(("ippReadIO: name length=%d\n", n
));
1210 if (n
== 0 && tag
!= IPP_TAG_MEMBERNAME
&&
1211 tag
!= IPP_TAG_END_COLLECTION
)
1214 * More values for current attribute...
1217 if (ipp
->current
== NULL
)
1220 attr
= ipp
->current
;
1221 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_MASK
);
1224 * Make sure we aren't adding a new value of a different
1228 if (value_tag
== IPP_TAG_ZERO
)
1231 * Setting the value of a collection member...
1234 attr
->value_tag
= tag
;
1236 else if ((value_tag
>= IPP_TAG_TEXTLANG
&&
1237 value_tag
<= IPP_TAG_MIMETYPE
))
1240 * String values can sometimes come across in different
1241 * forms; accept sets of differing values...
1244 if ((tag
< IPP_TAG_TEXTLANG
|| tag
> IPP_TAG_MIMETYPE
) &&
1245 tag
!= IPP_TAG_NOVALUE
)
1247 DEBUG_printf(("ippReadIO: 1setOf value tag %x(%s) != %x(%s)\n",
1248 value_tag
, ippTagString(value_tag
), tag
,
1249 ippTagString(tag
)));
1253 else if (value_tag
!= tag
)
1255 DEBUG_printf(("ippReadIO: value tag %x(%s) != %x(%s)\n",
1256 value_tag
, ippTagString(value_tag
), tag
,
1257 ippTagString(tag
)));
1262 * Finally, reallocate the attribute array as needed...
1265 if (attr
->num_values
== 1 ||
1266 (attr
->num_values
> 0 &&
1267 (attr
->num_values
& (IPP_MAX_VALUES
- 1)) == 0))
1269 ipp_attribute_t
*temp
; /* Pointer to new buffer */
1272 DEBUG_printf(("ippReadIO: reallocating for up to %d values...\n",
1273 attr
->num_values
+ IPP_MAX_VALUES
));
1276 * Reallocate memory...
1279 if ((temp
= realloc(attr
, sizeof(ipp_attribute_t
) +
1280 (attr
->num_values
+ IPP_MAX_VALUES
- 1) *
1281 sizeof(ipp_value_t
))) == NULL
)
1287 * Reset pointers in the list...
1291 ipp
->prev
->next
= temp
;
1295 attr
= ipp
->current
= ipp
->last
= temp
;
1299 else if (tag
== IPP_TAG_MEMBERNAME
)
1302 * Name must be length 0!
1307 DEBUG_puts("ippReadIO: member name not empty!");
1312 ipp
->prev
= ipp
->current
;
1314 attr
= ipp
->current
= _ippAddAttr(ipp
, 1);
1316 DEBUG_printf(("ippReadIO: membername, ipp->current=%p, "
1317 "ipp->prev=%p\n", ipp
->current
, ipp
->prev
));
1319 attr
->group_tag
= ipp
->curtag
;
1320 attr
->value_tag
= IPP_TAG_ZERO
;
1321 attr
->num_values
= 0;
1323 else if (tag
!= IPP_TAG_END_COLLECTION
)
1326 * New attribute; read the name and add it...
1329 if ((*cb
)(src
, buffer
, n
) < n
)
1331 DEBUG_puts("ippReadIO: unable to read name!");
1338 ipp
->prev
= ipp
->current
;
1340 if ((attr
= ipp
->current
= _ippAddAttr(ipp
, 1)) == NULL
)
1342 DEBUG_puts("ippReadIO: unable to allocate attribute!");
1346 DEBUG_printf(("ippReadIO: name=\"%s\", ipp->current=%p, "
1347 "ipp->prev=%p\n", buffer
, ipp
->current
, ipp
->prev
));
1349 attr
->group_tag
= ipp
->curtag
;
1350 attr
->value_tag
= tag
;
1351 attr
->name
= _cupsStrAlloc((char *)buffer
);
1352 attr
->num_values
= 0;
1357 if (tag
!= IPP_TAG_END_COLLECTION
)
1358 value
= attr
->values
+ attr
->num_values
;
1362 if ((*cb
)(src
, buffer
, 2) < 2)
1364 DEBUG_puts("ippReadIO: unable to read value length!");
1368 n
= (buffer
[0] << 8) | buffer
[1];
1369 DEBUG_printf(("ippReadIO: value length=%d\n", n
));
1373 case IPP_TAG_INTEGER
:
1377 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1381 if ((*cb
)(src
, buffer
, 4) < 4)
1383 DEBUG_puts("ippReadIO: Unable to read integer value!");
1387 n
= (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
1393 case IPP_TAG_BOOLEAN
:
1396 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1400 if ((*cb
)(src
, buffer
, 1) < 1)
1402 DEBUG_puts("ippReadIO: Unable to read boolean value!");
1406 value
->boolean
= buffer
[0];
1409 case IPP_TAG_NOVALUE
:
1410 if (attr
->value_tag
== IPP_TAG_NOVALUE
)
1415 attr
->value_tag
= IPP_TAG_TEXT
;
1420 case IPP_TAG_KEYWORD
:
1422 case IPP_TAG_URISCHEME
:
1423 case IPP_TAG_CHARSET
:
1424 case IPP_TAG_LANGUAGE
:
1425 case IPP_TAG_MIMETYPE
:
1426 if (n
>= sizeof(buffer
))
1428 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1432 if ((*cb
)(src
, buffer
, n
) < n
)
1434 DEBUG_puts("ippReadIO: unable to read name!");
1439 value
->string
.text
= _cupsStrAlloc((char *)buffer
);
1440 DEBUG_printf(("ippReadIO: value=\"%s\"\n",
1441 value
->string
.text
));
1447 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1451 if ((*cb
)(src
, value
->date
, 11) < 11)
1453 DEBUG_puts("ippReadIO: Unable to date integer value!");
1458 case IPP_TAG_RESOLUTION
:
1461 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1465 if ((*cb
)(src
, buffer
, 9) < 9)
1467 DEBUG_puts("ippReadIO: Unable to read resolution value!");
1471 value
->resolution
.xres
=
1472 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
1474 value
->resolution
.yres
=
1475 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
1477 value
->resolution
.units
=
1478 (ipp_res_t
)buffer
[8];
1481 case IPP_TAG_RANGE
:
1484 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1488 if ((*cb
)(src
, buffer
, 8) < 8)
1490 DEBUG_puts("ippReadIO: Unable to read range value!");
1494 value
->range
.lower
=
1495 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
1497 value
->range
.upper
=
1498 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
1502 case IPP_TAG_TEXTLANG
:
1503 case IPP_TAG_NAMELANG
:
1504 if (n
>= sizeof(buffer
) || n
< 4)
1506 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1510 if ((*cb
)(src
, buffer
, n
) < n
)
1512 DEBUG_puts("ippReadIO: Unable to read string w/language value!");
1519 * text-with-language and name-with-language are composite
1528 n
= (bufptr
[0] << 8) | bufptr
[1];
1530 if ((bufptr
+ 2 + n
) >= (buffer
+ sizeof(buffer
)) ||
1531 n
>= sizeof(string
))
1533 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1537 memcpy(string
, bufptr
+ 2, n
);
1540 value
->string
.charset
= _cupsStrAlloc((char *)string
);
1543 n
= (bufptr
[0] << 8) | bufptr
[1];
1545 if ((bufptr
+ 2 + n
) >= (buffer
+ sizeof(buffer
)))
1547 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1551 bufptr
[2 + n
] = '\0';
1552 value
->string
.text
= _cupsStrAlloc((char *)bufptr
+ 2);
1555 case IPP_TAG_BEGIN_COLLECTION
:
1557 * Oh, boy, here comes a collection value, so read it...
1560 value
->collection
= ippNew();
1564 DEBUG_puts("ippReadIO: begCollection tag with value length "
1569 if (ippReadIO(src
, cb
, 1, ipp
, value
->collection
) == IPP_ERROR
)
1571 DEBUG_puts("ippReadIO: Unable to read collection value!");
1576 case IPP_TAG_END_COLLECTION
:
1579 DEBUG_puts("ippReadIO: endCollection tag with value length "
1584 DEBUG_puts("ippReadIO: endCollection tag...");
1586 return (ipp
->state
= IPP_DATA
);
1588 case IPP_TAG_MEMBERNAME
:
1590 * The value the name of the member in the collection, which
1591 * we need to carry over...
1594 if (n
>= sizeof(buffer
))
1596 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1600 if ((*cb
)(src
, buffer
, n
) < n
)
1602 DEBUG_puts("ippReadIO: Unable to read member name value!");
1607 attr
->name
= _cupsStrAlloc((char *)buffer
);
1610 * Since collection members are encoded differently than
1611 * regular attributes, make sure we don't start with an
1615 attr
->num_values
--;
1617 DEBUG_printf(("ippReadIO: member name=\"%s\"\n", attr
->name
));
1620 default : /* Other unsupported values */
1621 if (n
> IPP_MAX_LENGTH
)
1623 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1629 DEBUG_puts("ippReadIO: NULL value!");
1633 value
->unknown
.length
= n
;
1636 if ((value
->unknown
.data
= malloc(n
)) == NULL
)
1638 DEBUG_puts("ippReadIO: Unable to allocate value");
1642 if ((*cb
)(src
, value
->unknown
.data
, n
) < n
)
1644 DEBUG_puts("ippReadIO: Unable to read unsupported value!");
1649 value
->unknown
.data
= NULL
;
1653 attr
->num_values
++;
1656 * If blocking is disabled, stop here...
1668 break; /* anti-compiler-warning-code */
1671 DEBUG_printf(("ippReadIO: returning ipp->state=%d!\n", ipp
->state
));
1673 return (ipp
->state
);
1678 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
1681 const ipp_uchar_t
* /* O - RFC-1903 date/time data */
1682 ippTimeToDate(time_t t
) /* I - UNIX time value */
1684 struct tm
*unixdate
; /* UNIX unixdate/time info */
1685 ipp_uchar_t
*date
= _cupsGlobals()->ipp_date
;
1686 /* RFC-1903 date/time data */
1690 * RFC-1903 date/time format is:
1692 * Byte(s) Description
1693 * ------- -----------
1694 * 0-1 Year (0 to 65535)
1698 * 5 Minutes (0 to 59)
1699 * 6 Seconds (0 to 60, 60 = "leap second")
1700 * 7 Deciseconds (0 to 9)
1702 * 9 UTC hours (0 to 11)
1703 * 10 UTC minutes (0 to 59)
1706 unixdate
= gmtime(&t
);
1707 unixdate
->tm_year
+= 1900;
1709 date
[0] = unixdate
->tm_year
>> 8;
1710 date
[1] = unixdate
->tm_year
;
1711 date
[2] = unixdate
->tm_mon
+ 1;
1712 date
[3] = unixdate
->tm_mday
;
1713 date
[4] = unixdate
->tm_hour
;
1714 date
[5] = unixdate
->tm_min
;
1715 date
[6] = unixdate
->tm_sec
;
1726 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
1729 ipp_state_t
/* O - Current state */
1730 ippWrite(http_t
*http
, /* I - HTTP connection */
1731 ipp_t
*ipp
) /* I - IPP data */
1733 DEBUG_printf(("ippWrite(http=%p, ipp=%p)\n", http
, ipp
));
1738 return (ippWriteIO(http
, (ipp_iocb_t
)httpWrite2
,
1739 http
->blocking
, NULL
, ipp
));
1744 * 'ippWriteFile()' - Write data for an IPP message to a file.
1746 * @since CUPS 1.1.19@
1749 ipp_state_t
/* O - Current state */
1750 ippWriteFile(int fd
, /* I - HTTP data */
1751 ipp_t
*ipp
) /* I - IPP data */
1753 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)\n", fd
, ipp
));
1755 ipp
->state
= IPP_IDLE
;
1757 return (ippWriteIO(&fd
, (ipp_iocb_t
)ipp_write_file
, 1, NULL
, ipp
));
1762 * 'ippWriteIO()' - Write data for an IPP message.
1767 ipp_state_t
/* O - Current state */
1768 ippWriteIO(void *dst
, /* I - Destination */
1769 ipp_iocb_t cb
, /* I - Write callback function */
1770 int blocking
, /* I - Use blocking IO? */
1771 ipp_t
*parent
, /* I - Parent IPP message */
1772 ipp_t
*ipp
) /* I - IPP data */
1774 int i
; /* Looping var */
1775 int n
; /* Length of data */
1776 unsigned char buffer
[IPP_MAX_LENGTH
+ 2],
1777 /* Data buffer + length bytes */
1778 *bufptr
; /* Pointer into buffer */
1779 ipp_attribute_t
*attr
; /* Current attribute */
1780 ipp_value_t
*value
; /* Current value */
1783 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)\n",
1784 dst
, cb
, blocking
, parent
, ipp
));
1792 ipp
->state
++; /* Avoid common problem... */
1798 * Send the request header:
1801 * Operation/Status Code = 2 bytes
1802 * Request ID = 4 bytes
1808 *bufptr
++ = ipp
->request
.any
.version
[0];
1809 *bufptr
++ = ipp
->request
.any
.version
[1];
1810 *bufptr
++ = ipp
->request
.any
.op_status
>> 8;
1811 *bufptr
++ = ipp
->request
.any
.op_status
;
1812 *bufptr
++ = ipp
->request
.any
.request_id
>> 24;
1813 *bufptr
++ = ipp
->request
.any
.request_id
>> 16;
1814 *bufptr
++ = ipp
->request
.any
.request_id
>> 8;
1815 *bufptr
++ = ipp
->request
.any
.request_id
;
1817 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
1819 DEBUG_puts("ippWriteIO: Could not write IPP header...");
1825 * Reset the state engine to point to the first attribute
1826 * in the request/response, with no current group.
1829 ipp
->state
= IPP_ATTRIBUTE
;
1830 ipp
->current
= ipp
->attrs
;
1831 ipp
->curtag
= IPP_TAG_ZERO
;
1833 DEBUG_printf(("ippWriteIO: version=%d.%d\n", buffer
[0], buffer
[1]));
1834 DEBUG_printf(("ippWriteIO: op_status=%04x\n",
1835 ipp
->request
.any
.op_status
));
1836 DEBUG_printf(("ippWriteIO: request_id=%d\n",
1837 ipp
->request
.any
.request_id
));
1840 * If blocking is disabled, stop here...
1846 case IPP_ATTRIBUTE
:
1847 while (ipp
->current
!= NULL
)
1850 * Write this attribute...
1854 attr
= ipp
->current
;
1856 ipp
->current
= ipp
->current
->next
;
1858 if (ipp
->curtag
!= attr
->group_tag
&& parent
== NULL
)
1861 * Send a group tag byte...
1864 ipp
->curtag
= attr
->group_tag
;
1866 if (attr
->group_tag
== IPP_TAG_ZERO
)
1869 DEBUG_printf(("ippWriteIO: wrote group tag=%x(%s)\n",
1870 attr
->group_tag
, ippTagString(attr
->group_tag
)));
1871 *bufptr
++ = attr
->group_tag
;
1873 else if (attr
->group_tag
== IPP_TAG_ZERO
)
1877 * Write the attribute tag and name. The current implementation
1878 * does not support the extension value tags above 0x7f, so all
1879 * value tags are 1 byte.
1881 * The attribute name length does not include the trailing nul
1882 * character in the source string.
1884 * Collection values (parent != NULL) are written differently...
1890 * Get the length of the attribute name, and make sure it won't
1891 * overflow the buffer...
1894 if ((n
= (int)strlen(attr
->name
)) > (sizeof(buffer
) - 4))
1898 * Write the value tag, name length, and name string...
1901 DEBUG_printf(("ippWriteIO: writing value tag=%x(%s)\n",
1902 attr
->value_tag
, ippTagString(attr
->value_tag
)));
1903 DEBUG_printf(("ippWriteIO: writing name=%d,\"%s\"\n", n
,
1906 *bufptr
++ = attr
->value_tag
;
1909 memcpy(bufptr
, attr
->name
, n
);
1915 * Get the length of the attribute name, and make sure it won't
1916 * overflow the buffer...
1919 if ((n
= (int)strlen(attr
->name
)) > (sizeof(buffer
) - 7))
1923 * Write the member name tag, name length, name string, value tag,
1924 * and empty name for the collection member attribute...
1927 DEBUG_printf(("ippWriteIO: writing value tag=%x(memberName)\n",
1928 IPP_TAG_MEMBERNAME
));
1929 DEBUG_printf(("ippWriteIO: writing name=%d,\"%s\"\n", n
,
1931 DEBUG_printf(("ippWriteIO: writing value tag=%x(%s)\n",
1932 attr
->value_tag
, ippTagString(attr
->value_tag
)));
1933 DEBUG_puts("ippWriteIO: writing name=0,\"\"\n");
1935 *bufptr
++ = IPP_TAG_MEMBERNAME
;
1940 memcpy(bufptr
, attr
->name
, n
);
1943 *bufptr
++ = attr
->value_tag
;
1949 * Now write the attribute value(s)...
1952 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
1954 case IPP_TAG_INTEGER
:
1956 for (i
= 0, value
= attr
->values
;
1957 i
< attr
->num_values
;
1960 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 9)
1962 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
1964 DEBUG_puts("ippWriteIO: Could not write IPP "
1975 * Arrays and sets are done by sending additional
1976 * values with a zero-length name...
1979 *bufptr
++ = attr
->value_tag
;
1985 * Integers and enumerations are both 4-byte signed
1986 * (twos-complement) values.
1988 * Put the 2-byte length and 4-byte value into the buffer...
1993 *bufptr
++ = value
->integer
>> 24;
1994 *bufptr
++ = value
->integer
>> 16;
1995 *bufptr
++ = value
->integer
>> 8;
1996 *bufptr
++ = value
->integer
;
2000 case IPP_TAG_BOOLEAN
:
2001 for (i
= 0, value
= attr
->values
;
2002 i
< attr
->num_values
;
2005 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 6)
2007 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2009 DEBUG_puts("ippWriteIO: Could not write IPP "
2020 * Arrays and sets are done by sending additional
2021 * values with a zero-length name...
2024 *bufptr
++ = attr
->value_tag
;
2030 * Boolean values are 1-byte; 0 = false, 1 = true.
2032 * Put the 2-byte length and 1-byte value into the buffer...
2037 *bufptr
++ = value
->boolean
;
2043 case IPP_TAG_KEYWORD
:
2045 case IPP_TAG_URISCHEME
:
2046 case IPP_TAG_CHARSET
:
2047 case IPP_TAG_LANGUAGE
:
2048 case IPP_TAG_MIMETYPE
:
2049 for (i
= 0, value
= attr
->values
;
2050 i
< attr
->num_values
;
2056 * Arrays and sets are done by sending additional
2057 * values with a zero-length name...
2060 DEBUG_printf(("ippWriteIO: writing value tag=%x(%s)\n",
2062 ippTagString(attr
->value_tag
)));
2063 DEBUG_printf(("ippWriteIO: writing name=0,\"\"\n"));
2065 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 3)
2067 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2069 DEBUG_puts("ippWriteIO: Could not write IPP "
2077 *bufptr
++ = attr
->value_tag
;
2082 if (value
->string
.text
!= NULL
)
2083 n
= (int)strlen(value
->string
.text
);
2087 if (n
> (sizeof(buffer
) - 2))
2090 DEBUG_printf(("ippWriteIO: writing string=%d,\"%s\"\n", n
,
2091 value
->string
.text
));
2093 if ((int)(sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
2095 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2097 DEBUG_puts("ippWriteIO: Could not write IPP "
2106 * All simple strings consist of the 2-byte length and
2107 * character data without the trailing nul normally found
2108 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
2109 * bytes since the 2-byte length is a signed (twos-complement)
2112 * Put the 2-byte length and string characters in the buffer.
2120 memcpy(bufptr
, value
->string
.text
, n
);
2127 for (i
= 0, value
= attr
->values
;
2128 i
< attr
->num_values
;
2131 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 16)
2133 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2135 DEBUG_puts("ippWriteIO: Could not write IPP "
2146 * Arrays and sets are done by sending additional
2147 * values with a zero-length name...
2150 *bufptr
++ = attr
->value_tag
;
2156 * Date values consist of a 2-byte length and an
2157 * 11-byte date/time structure defined by RFC 1903.
2159 * Put the 2-byte length and 11-byte date/time
2160 * structure in the buffer.
2165 memcpy(bufptr
, value
->date
, 11);
2170 case IPP_TAG_RESOLUTION
:
2171 for (i
= 0, value
= attr
->values
;
2172 i
< attr
->num_values
;
2175 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 14)
2177 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2179 DEBUG_puts("ippWriteIO: Could not write IPP "
2190 * Arrays and sets are done by sending additional
2191 * values with a zero-length name...
2194 *bufptr
++ = attr
->value_tag
;
2200 * Resolution values consist of a 2-byte length,
2201 * 4-byte horizontal resolution value, 4-byte vertical
2202 * resolution value, and a 1-byte units value.
2204 * Put the 2-byte length and resolution value data
2210 *bufptr
++ = value
->resolution
.xres
>> 24;
2211 *bufptr
++ = value
->resolution
.xres
>> 16;
2212 *bufptr
++ = value
->resolution
.xres
>> 8;
2213 *bufptr
++ = value
->resolution
.xres
;
2214 *bufptr
++ = value
->resolution
.yres
>> 24;
2215 *bufptr
++ = value
->resolution
.yres
>> 16;
2216 *bufptr
++ = value
->resolution
.yres
>> 8;
2217 *bufptr
++ = value
->resolution
.yres
;
2218 *bufptr
++ = value
->resolution
.units
;
2222 case IPP_TAG_RANGE
:
2223 for (i
= 0, value
= attr
->values
;
2224 i
< attr
->num_values
;
2227 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 13)
2229 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2231 DEBUG_puts("ippWriteIO: Could not write IPP "
2242 * Arrays and sets are done by sending additional
2243 * values with a zero-length name...
2246 *bufptr
++ = attr
->value_tag
;
2252 * Range values consist of a 2-byte length,
2253 * 4-byte lower value, and 4-byte upper value.
2255 * Put the 2-byte length and range value data
2261 *bufptr
++ = value
->range
.lower
>> 24;
2262 *bufptr
++ = value
->range
.lower
>> 16;
2263 *bufptr
++ = value
->range
.lower
>> 8;
2264 *bufptr
++ = value
->range
.lower
;
2265 *bufptr
++ = value
->range
.upper
>> 24;
2266 *bufptr
++ = value
->range
.upper
>> 16;
2267 *bufptr
++ = value
->range
.upper
>> 8;
2268 *bufptr
++ = value
->range
.upper
;
2272 case IPP_TAG_TEXTLANG
:
2273 case IPP_TAG_NAMELANG
:
2274 for (i
= 0, value
= attr
->values
;
2275 i
< attr
->num_values
;
2281 * Arrays and sets are done by sending additional
2282 * values with a zero-length name...
2285 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 3)
2287 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2289 DEBUG_puts("ippWriteIO: Could not write IPP "
2297 *bufptr
++ = attr
->value_tag
;
2303 * textWithLanguage and nameWithLanguage values consist
2304 * of a 2-byte length for both strings and their
2305 * individual lengths, a 2-byte length for the
2306 * character string, the character string without the
2307 * trailing nul, a 2-byte length for the character
2308 * set string, and the character set string without
2314 if (value
->string
.charset
!= NULL
)
2315 n
+= (int)strlen(value
->string
.charset
);
2317 if (value
->string
.text
!= NULL
)
2318 n
+= (int)strlen(value
->string
.text
);
2320 if (n
> (sizeof(buffer
) - 2))
2323 if ((int)(sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
2325 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2327 DEBUG_puts("ippWriteIO: Could not write IPP "
2335 /* Length of entire value */
2339 /* Length of charset */
2340 if (value
->string
.charset
!= NULL
)
2341 n
= (int)strlen(value
->string
.charset
);
2351 memcpy(bufptr
, value
->string
.charset
, n
);
2355 /* Length of text */
2356 if (value
->string
.text
!= NULL
)
2357 n
= (int)strlen(value
->string
.text
);
2367 memcpy(bufptr
, value
->string
.text
, n
);
2373 case IPP_TAG_BEGIN_COLLECTION
:
2374 for (i
= 0, value
= attr
->values
;
2375 i
< attr
->num_values
;
2379 * Collections are written with the begin-collection
2380 * tag first with a value of 0 length, followed by the
2381 * attributes in the collection, then the end-collection
2385 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 5)
2387 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2389 DEBUG_puts("ippWriteIO: Could not write IPP "
2400 * Arrays and sets are done by sending additional
2401 * values with a zero-length name...
2404 *bufptr
++ = attr
->value_tag
;
2410 * Write a data length of 0 and flush the buffer...
2416 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2418 DEBUG_puts("ippWriteIO: Could not write IPP "
2426 * Then write the collection attribute...
2429 value
->collection
->state
= IPP_IDLE
;
2431 if (ippWriteIO(dst
, cb
, 1, ipp
, value
->collection
) == IPP_ERROR
)
2437 for (i
= 0, value
= attr
->values
;
2438 i
< attr
->num_values
;
2444 * Arrays and sets are done by sending additional
2445 * values with a zero-length name...
2448 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 3)
2450 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2452 DEBUG_puts("ippWriteIO: Could not write IPP "
2460 *bufptr
++ = attr
->value_tag
;
2466 * An unknown value might some new value that a
2467 * vendor has come up with. It consists of a
2468 * 2-byte length and the bytes in the unknown
2472 n
= value
->unknown
.length
;
2474 if (n
> (sizeof(buffer
) - 2))
2477 if ((int)(sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
2479 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2481 DEBUG_puts("ippWriteIO: Could not write IPP "
2489 /* Length of unknown value */
2496 memcpy(bufptr
, value
->unknown
.data
, n
);
2504 * Write the data out...
2507 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2509 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
2513 DEBUG_printf(("ippWriteIO: wrote %d bytes\n",
2514 (int)(bufptr
- buffer
)));
2517 * If blocking is disabled, stop here...
2524 if (ipp
->current
== NULL
)
2527 * Done with all of the attributes; add the end-of-attributes
2528 * tag or end-collection attribute...
2533 buffer
[0] = IPP_TAG_END
;
2538 buffer
[0] = IPP_TAG_END_COLLECTION
;
2539 buffer
[1] = 0; /* empty name */
2541 buffer
[3] = 0; /* empty value */
2546 if ((*cb
)(dst
, buffer
, n
) < 0)
2548 DEBUG_puts("ippWriteIO: Could not write IPP end-tag...");
2552 ipp
->state
= IPP_DATA
;
2560 break; /* anti-compiler-warning-code */
2563 return (ipp
->state
);
2568 * '_ippAddAttr()' - Add a new attribute to the request.
2571 ipp_attribute_t
* /* O - New attribute */
2572 _ippAddAttr(ipp_t
*ipp
, /* I - IPP message */
2573 int num_values
) /* I - Number of values */
2575 ipp_attribute_t
*attr
; /* New attribute */
2578 DEBUG_printf(("_ippAddAttr(ipp=%p, num_values=%d)\n", ipp
, num_values
));
2580 if (!ipp
|| num_values
< 0)
2583 attr
= calloc(sizeof(ipp_attribute_t
) +
2584 (num_values
- 1) * sizeof(ipp_value_t
), 1);
2588 attr
->num_values
= num_values
;
2590 if (ipp
->last
== NULL
)
2593 ipp
->last
->next
= attr
;
2598 DEBUG_printf(("_ippAddAttr(): %p\n", attr
));
2605 * '_ippFreeAttr()' - Free an attribute.
2609 _ippFreeAttr(ipp_attribute_t
*attr
) /* I - Attribute to free */
2611 int i
; /* Looping var */
2612 ipp_value_t
*value
; /* Current value */
2615 DEBUG_printf(("_ippFreeAttr(attr=%p)\n", attr
));
2617 switch (attr
->value_tag
)
2621 case IPP_TAG_KEYWORD
:
2623 case IPP_TAG_URISCHEME
:
2624 case IPP_TAG_CHARSET
:
2625 case IPP_TAG_LANGUAGE
:
2626 case IPP_TAG_MIMETYPE
:
2627 for (i
= 0, value
= attr
->values
;
2628 i
< attr
->num_values
;
2630 _cupsStrFree(value
->string
.text
);
2633 case IPP_TAG_TEXTLANG
:
2634 case IPP_TAG_NAMELANG
:
2635 for (i
= 0, value
= attr
->values
;
2636 i
< attr
->num_values
;
2639 if (value
->string
.charset
&& i
== 0)
2640 _cupsStrFree(value
->string
.charset
);
2641 _cupsStrFree(value
->string
.text
);
2645 case IPP_TAG_INTEGER
:
2647 case IPP_TAG_BOOLEAN
:
2649 case IPP_TAG_RESOLUTION
:
2650 case IPP_TAG_RANGE
:
2653 case IPP_TAG_BEGIN_COLLECTION
:
2654 for (i
= 0, value
= attr
->values
;
2655 i
< attr
->num_values
;
2657 ippDelete(value
->collection
);
2660 case IPP_TAG_STRING
:
2661 for (i
= 0, value
= attr
->values
;
2662 i
< attr
->num_values
;
2664 free(value
->unknown
.data
);
2668 if (!((int)attr
->value_tag
& IPP_TAG_COPY
))
2670 for (i
= 0, value
= attr
->values
;
2671 i
< attr
->num_values
;
2673 if (value
->unknown
.data
)
2674 free(value
->unknown
.data
);
2680 _cupsStrFree(attr
->name
);
2687 * 'ipp_length()' - Compute the length of an IPP message or collection value.
2690 static size_t /* O - Size of IPP message */
2691 ipp_length(ipp_t
*ipp
, /* I - IPP message or collection */
2692 int collection
) /* I - 1 if a collection, 0 otherwise */
2694 int i
; /* Looping var */
2695 int bytes
; /* Number of bytes */
2696 ipp_attribute_t
*attr
; /* Current attribute */
2697 ipp_tag_t group
; /* Current group */
2698 ipp_value_t
*value
; /* Current value */
2705 * Start with 8 bytes for the IPP message header...
2708 bytes
= collection
? 0 : 8;
2711 * Then add the lengths of each attribute...
2714 group
= IPP_TAG_ZERO
;
2716 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= attr
->next
)
2718 if (attr
->group_tag
!= group
&& !collection
)
2720 group
= attr
->group_tag
;
2721 if (group
== IPP_TAG_ZERO
)
2724 bytes
++; /* Group tag */
2730 DEBUG_printf(("ipp_length: attr->name=\"%s\", attr->num_values=%d, "
2731 "bytes=%d\n", attr
->name
, attr
->num_values
, bytes
));
2733 bytes
+= (int)strlen(attr
->name
); /* Name */
2734 bytes
+= attr
->num_values
; /* Value tag for each value */
2735 bytes
+= 2 * attr
->num_values
; /* Name lengths */
2736 bytes
+= 2 * attr
->num_values
; /* Value lengths */
2739 bytes
+= 5; /* Add membername overhead */
2741 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
2743 case IPP_TAG_INTEGER
:
2745 bytes
+= 4 * attr
->num_values
;
2748 case IPP_TAG_BOOLEAN
:
2749 bytes
+= attr
->num_values
;
2754 case IPP_TAG_KEYWORD
:
2756 case IPP_TAG_URISCHEME
:
2757 case IPP_TAG_CHARSET
:
2758 case IPP_TAG_LANGUAGE
:
2759 case IPP_TAG_MIMETYPE
:
2760 for (i
= 0, value
= attr
->values
;
2761 i
< attr
->num_values
;
2763 if (value
->string
.text
!= NULL
)
2764 bytes
+= (int)strlen(value
->string
.text
);
2768 bytes
+= 11 * attr
->num_values
;
2771 case IPP_TAG_RESOLUTION
:
2772 bytes
+= 9 * attr
->num_values
;
2775 case IPP_TAG_RANGE
:
2776 bytes
+= 8 * attr
->num_values
;
2779 case IPP_TAG_TEXTLANG
:
2780 case IPP_TAG_NAMELANG
:
2781 bytes
+= 4 * attr
->num_values
;/* Charset + text length */
2783 for (i
= 0, value
= attr
->values
;
2784 i
< attr
->num_values
;
2787 if (value
->string
.charset
!= NULL
)
2788 bytes
+= (int)strlen(value
->string
.charset
);
2790 if (value
->string
.text
!= NULL
)
2791 bytes
+= (int)strlen(value
->string
.text
);
2795 case IPP_TAG_BEGIN_COLLECTION
:
2796 for (i
= 0, value
= attr
->values
;
2797 i
< attr
->num_values
;
2799 bytes
+= (int)ipp_length(value
->collection
, 1);
2803 for (i
= 0, value
= attr
->values
;
2804 i
< attr
->num_values
;
2806 bytes
+= value
->unknown
.length
;
2812 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
2813 * for the "end of collection" tag and return...
2821 DEBUG_printf(("ipp_length: bytes=%d\n", bytes
));
2828 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
2831 static ssize_t
/* O - Number of bytes read */
2832 ipp_read_http(http_t
*http
, /* I - Client connection */
2833 ipp_uchar_t
*buffer
, /* O - Buffer for data */
2834 size_t length
) /* I - Total length */
2836 int tbytes
, /* Total bytes read */
2837 bytes
; /* Bytes read this pass */
2838 char len
[32]; /* Length string */
2841 DEBUG_printf(("ipp_read_http(http=%p, buffer=%p, length=%d)\n",
2842 http
, buffer
, (int)length
));
2845 * Loop until all bytes are read...
2848 for (tbytes
= 0, bytes
= 0;
2849 tbytes
< (int)length
;
2850 tbytes
+= bytes
, buffer
+= bytes
)
2852 DEBUG_printf(("ipp_read_http: tbytes=%d, http->state=%d\n", tbytes
,
2855 if (http
->state
== HTTP_WAITING
)
2858 if (http
->used
> 0 && http
->data_encoding
== HTTP_ENCODE_LENGTH
)
2861 * Do "fast read" from HTTP buffer directly...
2864 if (http
->used
> (int)(length
- tbytes
))
2865 bytes
= (int)(length
- tbytes
);
2870 buffer
[0] = http
->buffer
[0];
2872 memcpy(buffer
, http
->buffer
, bytes
);
2874 http
->used
-= bytes
;
2875 http
->data_remaining
-= bytes
;
2877 if (http
->data_remaining
<= INT_MAX
)
2878 http
->_data_remaining
= (int)http
->data_remaining
;
2880 http
->_data_remaining
= INT_MAX
;
2883 memmove(http
->buffer
, http
->buffer
+ bytes
, http
->used
);
2885 if (http
->data_remaining
== 0)
2887 if (http
->data_encoding
== HTTP_ENCODE_CHUNKED
)
2890 * Get the trailing CR LF after the chunk...
2893 if (!httpGets(len
, sizeof(len
), http
))
2897 if (http
->data_encoding
!= HTTP_ENCODE_CHUNKED
)
2899 if (http
->state
== HTTP_POST_RECV
)
2902 http
->state
= HTTP_WAITING
;
2909 * Wait a maximum of 1 second for data...
2912 if (!http
->blocking
)
2915 * Wait up to 10 seconds for more data on non-blocking sockets...
2918 if (!httpWait(http
, 10000))
2929 if ((bytes
= httpRead2(http
, (char *)buffer
, length
- tbytes
)) <= 0)
2935 * Return the number of bytes read...
2938 if (tbytes
== 0 && bytes
< 0)
2941 DEBUG_printf(("ipp_read_http: returning %d bytes...\n", tbytes
));
2948 * 'ipp_read_file()' - Read IPP data from a file.
2951 static ssize_t
/* O - Number of bytes read */
2952 ipp_read_file(int *fd
, /* I - File descriptor */
2953 ipp_uchar_t
*buffer
, /* O - Read buffer */
2954 size_t length
) /* I - Number of bytes to read */
2957 return ((ssize_t
)read(*fd
, buffer
, (unsigned)length
));
2959 return (read(*fd
, buffer
, length
));
2965 * 'ipp_write_file()' - Write IPP data to a file.
2968 static ssize_t
/* O - Number of bytes written */
2969 ipp_write_file(int *fd
, /* I - File descriptor */
2970 ipp_uchar_t
*buffer
, /* I - Data to write */
2971 size_t length
) /* I - Number of bytes to write */
2974 return ((ssize_t
)write(*fd
, buffer
, (unsigned)length
));
2976 return (write(*fd
, buffer
, length
));
2983 * The following symbol definitions are provided only for KDE
2984 * compatibility during the CUPS 1.2 testing period and will be
2985 * removed in a future release of CUPS. These are PRIVATE APIs
2986 * from CUPS 1.1.x that the KDE developers chose to use...
2989 ipp_attribute_t
* /* O - New attribute */
2990 _ipp_add_attr(ipp_t
*ipp
, /* I - IPP message */
2991 int num_values
) /* I - Number of values */
2993 return (_ippAddAttr(ipp
, num_values
));
2997 _ipp_free_attr(ipp_attribute_t
*attr
) /* I - Attribute to free */
3001 #endif /* __linux */
3005 * End of "$Id: ipp.c 7847 2008-08-19 04:22:14Z mike $".