2 * "$Id: ipp.c 6649 2007-07-11 21:46:42Z 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(%p, %02x, \'%s\', %d)\n", ipp
, group
, name
, value
));
102 if (ipp
== NULL
|| name
== NULL
)
105 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
108 attr
->name
= _cupsStrAlloc(name
);
109 attr
->group_tag
= group
;
110 attr
->value_tag
= IPP_TAG_BOOLEAN
;
111 attr
->values
[0].boolean
= value
;
118 * 'ippAddBooleans()' - Add an array of boolean values.
121 ipp_attribute_t
* /* O - New attribute */
122 ippAddBooleans(ipp_t
*ipp
, /* I - IPP message */
123 ipp_tag_t group
, /* I - IPP group */
124 const char *name
, /* I - Name of attribute */
125 int num_values
, /* I - Number of values */
126 const char *values
) /* I - Values */
128 int i
; /* Looping var */
129 ipp_attribute_t
*attr
; /* New attribute */
130 ipp_value_t
*value
; /* Current value */
133 DEBUG_printf(("ippAddBooleans(%p, %02x, \'%s\', %d, %p)\n", ipp
,
134 group
, name
, num_values
, values
));
136 if (ipp
== NULL
|| name
== NULL
|| num_values
< 1)
139 if ((attr
= _ippAddAttr(ipp
, num_values
)) == NULL
)
142 attr
->name
= _cupsStrAlloc(name
);
143 attr
->group_tag
= group
;
144 attr
->value_tag
= IPP_TAG_BOOLEAN
;
147 for (i
= 0, value
= attr
->values
;
150 value
->boolean
= values
[i
];
157 * 'ippAddCollection()' - Add a collection value.
159 * @since CUPS 1.1.19@
162 ipp_attribute_t
* /* O - New attribute */
163 ippAddCollection(ipp_t
*ipp
, /* I - IPP message */
164 ipp_tag_t group
, /* I - IPP group */
165 const char *name
, /* I - Name of attribute */
166 ipp_t
*value
) /* I - Value */
168 ipp_attribute_t
*attr
; /* New attribute */
171 DEBUG_printf(("ippAddCollection(%p, %02x, \'%s\', %p)\n", ipp
, group
, name
,
174 if (ipp
== NULL
|| name
== NULL
)
177 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
180 attr
->name
= _cupsStrAlloc(name
);
181 attr
->group_tag
= group
;
182 attr
->value_tag
= IPP_TAG_BEGIN_COLLECTION
;
183 attr
->values
[0].collection
= value
;
190 * 'ippAddCollections()' - Add an array of collection values.
192 * @since CUPS 1.1.19@
195 ipp_attribute_t
* /* O - New attribute */
197 ipp_t
*ipp
, /* I - IPP message */
198 ipp_tag_t group
, /* I - IPP group */
199 const char *name
, /* I - Name of attribute */
200 int num_values
, /* I - Number of values */
201 const ipp_t
**values
) /* I - Values */
203 int i
; /* Looping var */
204 ipp_attribute_t
*attr
; /* New attribute */
205 ipp_value_t
*value
; /* Current value */
208 DEBUG_printf(("ippAddCollections(%p, %02x, \'%s\', %d, %p)\n", ipp
,
209 group
, name
, num_values
, values
));
211 if (ipp
== NULL
|| name
== NULL
|| num_values
< 1)
214 if ((attr
= _ippAddAttr(ipp
, num_values
)) == NULL
)
217 attr
->name
= _cupsStrAlloc(name
);
218 attr
->group_tag
= group
;
219 attr
->value_tag
= IPP_TAG_BEGIN_COLLECTION
;
222 for (i
= 0, value
= attr
->values
;
225 value
->collection
= (ipp_t
*)values
[i
];
232 * 'ippAddDate()' - Add a date attribute to an IPP message.
235 ipp_attribute_t
* /* O - New attribute */
236 ippAddDate(ipp_t
*ipp
, /* I - IPP message */
237 ipp_tag_t group
, /* I - IPP group */
238 const char *name
, /* I - Name of attribute */
239 const ipp_uchar_t
*value
) /* I - Value */
241 ipp_attribute_t
*attr
; /* New attribute */
244 DEBUG_printf(("ippAddDate(%p, %02x, \'%s\', %p)\n", ipp
, group
, name
,
247 if (ipp
== NULL
|| name
== NULL
|| value
== NULL
)
250 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
253 attr
->name
= _cupsStrAlloc(name
);
254 attr
->group_tag
= group
;
255 attr
->value_tag
= IPP_TAG_DATE
;
256 memcpy(attr
->values
[0].date
, value
, 11);
263 * 'ippAddInteger()' - Add a integer attribute to an IPP message.
266 ipp_attribute_t
* /* O - New attribute */
267 ippAddInteger(ipp_t
*ipp
, /* I - IPP message */
268 ipp_tag_t group
, /* I - IPP group */
269 ipp_tag_t type
, /* I - Type of attribute */
270 const char *name
, /* I - Name of attribute */
271 int value
) /* I - Value of attribute */
273 ipp_attribute_t
*attr
; /* New attribute */
276 DEBUG_printf(("ippAddInteger(%p, %d, \'%s\', %d)\n", ipp
, group
, name
,
279 if (ipp
== NULL
|| name
== NULL
)
282 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
285 attr
->name
= _cupsStrAlloc(name
);
286 attr
->group_tag
= group
;
287 attr
->value_tag
= type
;
288 attr
->values
[0].integer
= value
;
295 * 'ippAddIntegers()' - Add an array of integer values.
298 ipp_attribute_t
* /* O - New attribute */
299 ippAddIntegers(ipp_t
*ipp
, /* I - IPP message */
300 ipp_tag_t group
, /* I - IPP group */
301 ipp_tag_t type
, /* I - Type of attribute */
302 const char *name
, /* I - Name of attribute */
303 int num_values
, /* I - Number of values */
304 const int *values
) /* I - Values */
306 int i
; /* Looping var */
307 ipp_attribute_t
*attr
; /* New attribute */
308 ipp_value_t
*value
; /* Current value */
311 if (ipp
== NULL
|| name
== NULL
|| num_values
< 1)
314 if ((attr
= _ippAddAttr(ipp
, num_values
)) == NULL
)
317 attr
->name
= _cupsStrAlloc(name
);
318 attr
->group_tag
= group
;
319 attr
->value_tag
= type
;
322 for (i
= 0, value
= attr
->values
;
325 value
->integer
= values
[i
];
332 * 'ippAddOctetString()' - Add an octetString value to an IPP message.
337 ipp_attribute_t
* /* O - New attribute */
338 ippAddOctetString(ipp_t
*ipp
, /* I - IPP message */
339 ipp_tag_t group
, /* I - IPP group */
340 const char *name
, /* I - Name of attribute */
341 const void *data
, /* I - octetString data */
342 int datalen
) /* I - Length of data in bytes */
344 ipp_attribute_t
*attr
; /* New attribute */
347 if (ipp
== NULL
|| name
== NULL
)
350 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
354 * Initialize the attribute data...
357 attr
->name
= _cupsStrAlloc(name
);
358 attr
->group_tag
= group
;
359 attr
->value_tag
= IPP_TAG_STRING
;
360 attr
->values
[0].unknown
.length
= datalen
;
364 if ((attr
->values
[0].unknown
.data
= malloc(datalen
)) == NULL
)
366 ippDeleteAttribute(ipp
, attr
);
370 memcpy(attr
->values
[0].unknown
.data
, data
, datalen
);
374 * Return the new attribute...
382 * 'ippAddString()' - Add a language-encoded string to an IPP message.
385 ipp_attribute_t
* /* O - New attribute */
386 ippAddString(ipp_t
*ipp
, /* I - IPP message */
387 ipp_tag_t group
, /* I - IPP group */
388 ipp_tag_t type
, /* I - Type of attribute */
389 const char *name
, /* I - Name of attribute */
390 const char *charset
, /* I - Character set */
391 const char *value
) /* I - Value */
393 ipp_attribute_t
*attr
; /* New attribute */
394 char buffer
[1024], /* Language/charset value buffer */
395 *bufptr
; /* Pointer into buffer */
398 if (ipp
== NULL
|| name
== NULL
)
401 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
405 * Force value to be English for the POSIX locale...
408 if (type
== IPP_TAG_LANGUAGE
&& !strcasecmp(value
, "C"))
412 * Convert language values to lowercase and change _ to - as needed...
415 if ((type
== IPP_TAG_LANGUAGE
|| type
== IPP_TAG_CHARSET
) && value
)
417 strlcpy(buffer
, value
, sizeof(buffer
));
420 for (bufptr
= buffer
; *bufptr
; bufptr
++)
424 *bufptr
= tolower(*bufptr
& 255);
428 * Initialize the attribute data...
431 attr
->name
= _cupsStrAlloc(name
);
432 attr
->group_tag
= group
;
433 attr
->value_tag
= type
;
434 attr
->values
[0].string
.charset
= ((int)type
& IPP_TAG_COPY
) ? (char *)charset
:
435 charset
? _cupsStrAlloc(charset
) : NULL
;
436 attr
->values
[0].string
.text
= ((int)type
& IPP_TAG_COPY
) ? (char *)value
:
437 value
? _cupsStrAlloc(value
) : NULL
;
444 * 'ippAddStrings()' - Add language-encoded strings to an IPP message.
447 ipp_attribute_t
* /* O - New attribute */
449 ipp_t
*ipp
, /* I - IPP message */
450 ipp_tag_t group
, /* I - IPP group */
451 ipp_tag_t type
, /* I - Type of attribute */
452 const char *name
, /* I - Name of attribute */
453 int num_values
, /* I - Number of values */
454 const char *charset
, /* I - Character set */
455 const char * const *values
) /* I - Values */
457 int i
; /* Looping var */
458 ipp_attribute_t
*attr
; /* New attribute */
459 ipp_value_t
*value
; /* Current value */
462 if (ipp
== NULL
|| name
== NULL
|| num_values
< 1)
465 if ((attr
= _ippAddAttr(ipp
, num_values
)) == NULL
)
469 * Initialize the attribute data...
472 attr
->name
= _cupsStrAlloc(name
);
473 attr
->group_tag
= group
;
474 attr
->value_tag
= type
;
476 for (i
= 0, value
= attr
->values
;
481 value
->string
.charset
= ((int)type
& IPP_TAG_COPY
) ? (char *)charset
:
482 charset
? _cupsStrAlloc(charset
) : NULL
;
484 value
->string
.charset
= attr
->values
[0].string
.charset
;
489 * Force language to be English for the POSIX locale...
492 if (type
== IPP_TAG_LANGUAGE
&& !strcasecmp(values
[i
], "C"))
493 value
->string
.text
= ((int)type
& IPP_TAG_COPY
) ? "en" :
496 value
->string
.text
= ((int)type
& IPP_TAG_COPY
) ? (char *)values
[i
] :
497 _cupsStrAlloc(values
[i
]);
506 * 'ippAddRange()' - Add a range of values to an IPP message.
509 ipp_attribute_t
* /* O - New attribute */
510 ippAddRange(ipp_t
*ipp
, /* I - IPP message */
511 ipp_tag_t group
, /* I - IPP group */
512 const char *name
, /* I - Name of attribute */
513 int lower
, /* I - Lower value */
514 int upper
) /* I - Upper value */
516 ipp_attribute_t
*attr
; /* New attribute */
519 if (ipp
== NULL
|| name
== NULL
)
522 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
525 attr
->name
= _cupsStrAlloc(name
);
526 attr
->group_tag
= group
;
527 attr
->value_tag
= IPP_TAG_RANGE
;
528 attr
->values
[0].range
.lower
= lower
;
529 attr
->values
[0].range
.upper
= upper
;
536 * 'ippAddRanges()' - Add ranges of values to an IPP message.
539 ipp_attribute_t
* /* O - New attribute */
540 ippAddRanges(ipp_t
*ipp
, /* I - IPP message */
541 ipp_tag_t group
, /* I - IPP group */
542 const char *name
, /* I - Name of attribute */
543 int num_values
, /* I - Number of values */
544 const int *lower
, /* I - Lower values */
545 const int *upper
) /* I - Upper values */
547 int i
; /* Looping var */
548 ipp_attribute_t
*attr
; /* New attribute */
549 ipp_value_t
*value
; /* Current value */
552 if (ipp
== NULL
|| name
== NULL
|| num_values
< 1)
555 if ((attr
= _ippAddAttr(ipp
, num_values
)) == NULL
)
558 attr
->name
= _cupsStrAlloc(name
);
559 attr
->group_tag
= group
;
560 attr
->value_tag
= IPP_TAG_RANGE
;
562 if (lower
!= NULL
&& upper
!= NULL
)
563 for (i
= 0, value
= attr
->values
;
567 value
->range
.lower
= lower
[i
];
568 value
->range
.upper
= upper
[i
];
576 * 'ippAddResolution()' - Add a resolution value to an IPP message.
579 ipp_attribute_t
* /* O - New attribute */
580 ippAddResolution(ipp_t
*ipp
, /* I - IPP message */
581 ipp_tag_t group
, /* I - IPP group */
582 const char *name
, /* I - Name of attribute */
583 ipp_res_t units
, /* I - Units for resolution */
584 int xres
, /* I - X resolution */
585 int yres
) /* I - Y resolution */
587 ipp_attribute_t
*attr
; /* New attribute */
590 if (ipp
== NULL
|| name
== NULL
)
593 if ((attr
= _ippAddAttr(ipp
, 1)) == NULL
)
596 attr
->name
= _cupsStrAlloc(name
);
597 attr
->group_tag
= group
;
598 attr
->value_tag
= IPP_TAG_RESOLUTION
;
599 attr
->values
[0].resolution
.xres
= xres
;
600 attr
->values
[0].resolution
.yres
= yres
;
601 attr
->values
[0].resolution
.units
= units
;
608 * 'ippAddResolutions()' - Add resolution values to an IPP message.
611 ipp_attribute_t
* /* O - New attribute */
612 ippAddResolutions(ipp_t
*ipp
, /* I - IPP message */
613 ipp_tag_t group
, /* I - IPP group */
614 const char *name
, /* I - Name of attribute */
615 int num_values
,/* I - Number of values */
616 ipp_res_t units
, /* I - Units for resolution */
617 const int *xres
, /* I - X resolutions */
618 const int *yres
) /* I - Y resolutions */
620 int i
; /* Looping var */
621 ipp_attribute_t
*attr
; /* New attribute */
622 ipp_value_t
*value
; /* Current value */
625 if (ipp
== NULL
|| name
== NULL
|| num_values
< 1)
628 if ((attr
= _ippAddAttr(ipp
, num_values
)) == NULL
)
631 attr
->name
= _cupsStrAlloc(name
);
632 attr
->group_tag
= group
;
633 attr
->value_tag
= IPP_TAG_RESOLUTION
;
635 if (xres
!= NULL
&& yres
!= NULL
)
636 for (i
= 0, value
= attr
->values
;
640 value
->resolution
.xres
= xres
[i
];
641 value
->resolution
.yres
= yres
[i
];
642 value
->resolution
.units
= units
;
650 * 'ippAddSeparator()' - Add a group separator to an IPP message.
653 ipp_attribute_t
* /* O - New attribute */
654 ippAddSeparator(ipp_t
*ipp
) /* I - IPP message */
656 ipp_attribute_t
*attr
; /* New attribute */
659 DEBUG_printf(("ippAddSeparator(%p)\n", ipp
));
664 if ((attr
= _ippAddAttr(ipp
, 0)) == NULL
)
667 attr
->group_tag
= IPP_TAG_ZERO
;
668 attr
->value_tag
= IPP_TAG_ZERO
;
675 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
679 time_t /* O - UNIX time value */
680 ippDateToTime(const ipp_uchar_t
*date
) /* I - RFC 1903 date info */
682 struct tm unixdate
; /* UNIX date/time info */
683 time_t t
; /* Computed time */
686 memset(&unixdate
, 0, sizeof(unixdate
));
689 * RFC-1903 date/time format is:
691 * Byte(s) Description
692 * ------- -----------
693 * 0-1 Year (0 to 65535)
697 * 5 Minutes (0 to 59)
698 * 6 Seconds (0 to 60, 60 = "leap second")
699 * 7 Deciseconds (0 to 9)
701 * 9 UTC hours (0 to 11)
702 * 10 UTC minutes (0 to 59)
705 unixdate
.tm_year
= ((date
[0] << 8) | date
[1]) - 1900;
706 unixdate
.tm_mon
= date
[2] - 1;
707 unixdate
.tm_mday
= date
[3];
708 unixdate
.tm_hour
= date
[4];
709 unixdate
.tm_min
= date
[5];
710 unixdate
.tm_sec
= date
[6];
712 t
= mktime(&unixdate
);
715 t
+= date
[9] * 3600 + date
[10] * 60;
717 t
-= date
[9] * 3600 + date
[10] * 60;
724 * 'ippDelete()' - Delete an IPP message.
728 ippDelete(ipp_t
*ipp
) /* I - IPP message */
730 ipp_attribute_t
*attr
, /* Current attribute */
731 *next
; /* Next attribute */
734 DEBUG_printf(("ippDelete(): %p\n", ipp
));
739 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= next
)
750 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
752 * @since CUPS 1.1.19@
757 ipp_t
*ipp
, /* I - IPP message */
758 ipp_attribute_t
*attr
) /* I - Attribute to delete */
760 ipp_attribute_t
*current
, /* Current attribute */
761 *prev
; /* Previous attribute */
765 * Find the attribute in the list...
768 for (current
= ipp
->attrs
, prev
= NULL
;
769 current
!= NULL
&& current
!= attr
;
770 prev
= current
, current
= current
->next
);
775 * Found it, remove the attribute from the list...
779 prev
->next
= current
->next
;
781 ipp
->attrs
= current
->next
;
783 if (current
== ipp
->last
)
787 * Free memory used by the attribute...
790 _ippFreeAttr(current
);
796 * 'ippFindAttribute()' - Find a named attribute in a request...
799 ipp_attribute_t
* /* O - Matching attribute */
800 ippFindAttribute(ipp_t
*ipp
, /* I - IPP message */
801 const char *name
, /* I - Name of attribute */
802 ipp_tag_t type
) /* I - Type of attribute */
804 DEBUG_printf(("ippFindAttribute(%p, \'%s\')\n", ipp
, name
));
806 if (ipp
== NULL
|| name
== NULL
)
810 * Reset the current pointer...
816 * Search for the attribute...
819 return (ippFindNextAttribute(ipp
, name
, type
));
824 * 'ippFindNextAttribute()' - Find the next named attribute in a request...
827 ipp_attribute_t
* /* O - Matching attribute */
828 ippFindNextAttribute(ipp_t
*ipp
, /* I - IPP message */
829 const char *name
, /* I - Name of attribute */
830 ipp_tag_t type
) /* I - Type of attribute */
832 ipp_attribute_t
*attr
; /* Current atttribute */
833 ipp_tag_t value_tag
; /* Value tag */
836 DEBUG_printf(("ippFindNextAttribute(%p, \'%s\')\n", ipp
, name
));
838 if (ipp
== NULL
|| name
== NULL
)
843 ipp
->prev
= ipp
->current
;
844 attr
= ipp
->current
->next
;
852 for (; attr
!= NULL
; ipp
->prev
= attr
, attr
= attr
->next
)
854 DEBUG_printf(("ippFindAttribute: attr = %p, name = \'%s\'\n", attr
,
857 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_MASK
);
859 if (attr
->name
!= NULL
&& strcasecmp(attr
->name
, name
) == 0 &&
860 (value_tag
== type
|| type
== IPP_TAG_ZERO
||
861 (value_tag
== IPP_TAG_TEXTLANG
&& type
== IPP_TAG_TEXT
) ||
862 (value_tag
== IPP_TAG_NAMELANG
&& type
== IPP_TAG_NAME
)))
878 * 'ippLength()' - Compute the length of an IPP message.
881 size_t /* O - Size of IPP message */
882 ippLength(ipp_t
*ipp
) /* I - IPP message */
884 return (ipp_length(ipp
, 0));
889 * 'ippNew()' - Allocate a new IPP message.
892 ipp_t
* /* O - New IPP message */
895 ipp_t
*temp
; /* New IPP message */
898 DEBUG_puts("ippNew()");
900 if ((temp
= (ipp_t
*)calloc(1, sizeof(ipp_t
))) != NULL
)
903 * Default to IPP 1.1...
906 temp
->request
.any
.version
[0] = 1;
907 temp
->request
.any
.version
[1] = 1;
910 DEBUG_printf(("ippNew: %p\n", temp
));
917 * 'ippNewRequest()' - Allocate a new IPP request message.
919 * The new request message is initialized with the attributes-charset and
920 * attributes-natural-language attributes added. The
921 * attributes-natural-language value is derived from the current locale.
926 ipp_t
* /* O - IPP request message */
927 ippNewRequest(ipp_op_t op
) /* I - Operation code */
929 ipp_t
*request
; /* IPP request message */
930 cups_lang_t
*language
; /* Current language localization */
934 * Create a new IPP message...
937 if ((request
= ippNew()) == NULL
)
941 * Set the operation and request ID...
944 request
->request
.op
.operation_id
= op
;
945 request
->request
.op
.request_id
= 1;
948 * Use UTF-8 as the character set...
951 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_CHARSET
,
952 "attributes-charset", NULL
, "utf-8");
955 * Get the language from the current locale...
958 language
= cupsLangDefault();
960 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_LANGUAGE
,
961 "attributes-natural-language", NULL
, language
->language
);
964 * Return the new request...
972 * 'ippRead()' - Read data for an IPP message from a HTTP connection.
975 ipp_state_t
/* O - Current state */
976 ippRead(http_t
*http
, /* I - HTTP connection */
977 ipp_t
*ipp
) /* I - IPP data */
979 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT
"\n",
980 http
, ipp
, CUPS_LLCAST (http
? http
->data_remaining
: -1)));
985 DEBUG_printf(("ippRead: http->state=%d, http->used=%d\n", http
->state
,
988 return (ippReadIO(http
, (ipp_iocb_t
)ipp_read_http
, http
->blocking
, NULL
,
994 * 'ippReadFile()' - Read data for an IPP message from a file.
996 * @since CUPS 1.1.19@
999 ipp_state_t
/* O - Current state */
1000 ippReadFile(int fd
, /* I - HTTP data */
1001 ipp_t
*ipp
) /* I - IPP data */
1003 DEBUG_printf(("ippReadFile(%d, %p)\n", fd
, ipp
));
1005 return (ippReadIO(&fd
, (ipp_iocb_t
)ipp_read_file
, 1, NULL
, ipp
));
1010 * 'ippReadIO()' - Read data for an IPP message.
1015 ipp_state_t
/* O - Current state */
1016 ippReadIO(void *src
, /* I - Data source */
1017 ipp_iocb_t cb
, /* I - Read callback function */
1018 int blocking
, /* I - Use blocking IO? */
1019 ipp_t
*parent
, /* I - Parent request, if any */
1020 ipp_t
*ipp
) /* I - IPP data */
1022 int n
; /* Length of data */
1023 unsigned char buffer
[IPP_MAX_LENGTH
+ 1],
1025 string
[IPP_MAX_NAME
],
1026 /* Small string buffer */
1027 *bufptr
; /* Pointer into buffer */
1028 ipp_attribute_t
*attr
; /* Current attribute */
1029 ipp_tag_t tag
; /* Current tag */
1030 ipp_tag_t value_tag
; /* Current value tag */
1031 ipp_value_t
*value
; /* Current value */
1034 DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)\n",
1035 src
, cb
, blocking
, parent
, ipp
));
1036 DEBUG_printf(("ippReadIO: ipp->state=%d\n", ipp
->state
));
1038 if (src
== NULL
|| ipp
== NULL
)
1044 ipp
->state
++; /* Avoid common problem... */
1050 * Get the request header...
1053 if ((n
= (*cb
)(src
, buffer
, 8)) < 8)
1055 DEBUG_printf(("ippReadIO: Unable to read header (%d bytes read)!\n", n
));
1060 * Verify the major version number...
1065 DEBUG_printf(("ippReadIO: version number (%d.%d) is bad.\n", buffer
[0],
1071 * Then copy the request header over...
1074 ipp
->request
.any
.version
[0] = buffer
[0];
1075 ipp
->request
.any
.version
[1] = buffer
[1];
1076 ipp
->request
.any
.op_status
= (buffer
[2] << 8) | buffer
[3];
1077 ipp
->request
.any
.request_id
= (((((buffer
[4] << 8) | buffer
[5]) << 8) |
1078 buffer
[6]) << 8) | buffer
[7];
1080 DEBUG_printf(("ippReadIO: version=%d.%d\n", buffer
[0], buffer
[1]));
1081 DEBUG_printf(("ippReadIO: op_status=%04x\n",
1082 ipp
->request
.any
.op_status
));
1083 DEBUG_printf(("ippReadIO: request_id=%d\n",
1084 ipp
->request
.any
.request_id
));
1087 ipp
->state
= IPP_ATTRIBUTE
;
1088 ipp
->current
= NULL
;
1089 ipp
->curtag
= IPP_TAG_ZERO
;
1090 ipp
->prev
= ipp
->last
;
1093 * If blocking is disabled, stop here...
1099 case IPP_ATTRIBUTE
:
1102 if ((*cb
)(src
, buffer
, 1) < 1)
1105 DEBUG_printf(("ippReadIO: ipp->current=%p, ipp->prev=%p\n",
1106 ipp
->current
, ipp
->prev
));
1109 * Read this attribute...
1112 tag
= (ipp_tag_t
)buffer
[0];
1114 if (tag
== IPP_TAG_END
)
1117 * No more attributes left...
1120 DEBUG_puts("ippReadIO: IPP_TAG_END!");
1122 ipp
->state
= IPP_DATA
;
1125 else if (tag
< IPP_TAG_UNSUPPORTED_VALUE
)
1128 * Group tag... Set the current group and continue...
1131 if (ipp
->curtag
== tag
)
1132 ipp
->prev
= ippAddSeparator(ipp
);
1133 else if (ipp
->current
)
1134 ipp
->prev
= ipp
->current
;
1137 ipp
->current
= NULL
;
1138 DEBUG_printf(("ippReadIO: group tag = %x, ipp->prev=%p\n", tag
,
1143 DEBUG_printf(("ippReadIO: value tag = %x\n", tag
));
1149 if ((*cb
)(src
, buffer
, 2) < 2)
1151 DEBUG_puts("ippReadIO: unable to read name length!");
1155 n
= (buffer
[0] << 8) | buffer
[1];
1157 if (n
> (sizeof(buffer
) - 1))
1159 DEBUG_printf(("ippReadIO: bad name length %d!\n", n
));
1163 DEBUG_printf(("ippReadIO: name length = %d\n", n
));
1165 if (n
== 0 && tag
!= IPP_TAG_MEMBERNAME
&&
1166 tag
!= IPP_TAG_END_COLLECTION
)
1169 * More values for current attribute...
1172 if (ipp
->current
== NULL
)
1175 attr
= ipp
->current
;
1176 value_tag
= (ipp_tag_t
)(attr
->value_tag
& IPP_TAG_MASK
);
1179 * Make sure we aren't adding a new value of a different
1183 if (value_tag
== IPP_TAG_ZERO
)
1186 * Setting the value of a collection member...
1189 attr
->value_tag
= tag
;
1191 else if (value_tag
>= IPP_TAG_TEXTLANG
&&
1192 value_tag
<= IPP_TAG_MIMETYPE
)
1195 * String values can sometimes come across in different
1196 * forms; accept sets of differing values...
1199 if (tag
< IPP_TAG_TEXTLANG
|| tag
> IPP_TAG_MIMETYPE
)
1202 else if (value_tag
!= tag
)
1206 * Finally, reallocate the attribute array as needed...
1209 if (attr
->num_values
== 1 ||
1210 (attr
->num_values
> 0 &&
1211 (attr
->num_values
& (IPP_MAX_VALUES
- 1)) == 0))
1213 ipp_attribute_t
*temp
; /* Pointer to new buffer */
1216 DEBUG_printf(("ippReadIO: reallocating for up to %d values...\n",
1217 attr
->num_values
+ IPP_MAX_VALUES
));
1220 * Reallocate memory...
1223 if ((temp
= realloc(attr
, sizeof(ipp_attribute_t
) +
1224 (attr
->num_values
+ IPP_MAX_VALUES
- 1) *
1225 sizeof(ipp_value_t
))) == NULL
)
1231 * Reset pointers in the list...
1235 ipp
->prev
->next
= temp
;
1239 attr
= ipp
->current
= ipp
->last
= temp
;
1243 else if (tag
== IPP_TAG_MEMBERNAME
)
1246 * Name must be length 0!
1251 DEBUG_puts("ippReadIO: member name not empty!");
1256 ipp
->prev
= ipp
->current
;
1258 attr
= ipp
->current
= _ippAddAttr(ipp
, 1);
1260 DEBUG_printf(("ippReadIO: membername, ipp->current=%p, ipp->prev=%p\n",
1261 ipp
->current
, ipp
->prev
));
1263 attr
->group_tag
= ipp
->curtag
;
1264 attr
->value_tag
= IPP_TAG_ZERO
;
1265 attr
->num_values
= 0;
1267 else if (tag
!= IPP_TAG_END_COLLECTION
)
1270 * New attribute; read the name and add it...
1273 if ((*cb
)(src
, buffer
, n
) < n
)
1275 DEBUG_puts("ippReadIO: unable to read name!");
1282 ipp
->prev
= ipp
->current
;
1284 if ((attr
= ipp
->current
= _ippAddAttr(ipp
, 1)) == NULL
)
1286 DEBUG_puts("ippReadIO: unable to allocate attribute!");
1290 DEBUG_printf(("ippReadIO: name=\'%s\', ipp->current=%p, ipp->prev=%p\n",
1291 buffer
, ipp
->current
, ipp
->prev
));
1293 attr
->group_tag
= ipp
->curtag
;
1294 attr
->value_tag
= tag
;
1295 attr
->name
= _cupsStrAlloc((char *)buffer
);
1296 attr
->num_values
= 0;
1301 if (tag
!= IPP_TAG_END_COLLECTION
)
1302 value
= attr
->values
+ attr
->num_values
;
1306 if ((*cb
)(src
, buffer
, 2) < 2)
1308 DEBUG_puts("ippReadIO: unable to read value length!");
1312 n
= (buffer
[0] << 8) | buffer
[1];
1313 DEBUG_printf(("ippReadIO: value length = %d\n", n
));
1317 case IPP_TAG_INTEGER
:
1321 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1325 if ((*cb
)(src
, buffer
, 4) < 4)
1327 DEBUG_puts("ippReadIO: Unable to read integer value!");
1331 n
= (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
1337 case IPP_TAG_BOOLEAN
:
1340 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1344 if ((*cb
)(src
, buffer
, 1) < 1)
1346 DEBUG_puts("ippReadIO: Unable to read boolean value!");
1350 value
->boolean
= buffer
[0];
1355 case IPP_TAG_KEYWORD
:
1357 case IPP_TAG_URISCHEME
:
1358 case IPP_TAG_CHARSET
:
1359 case IPP_TAG_LANGUAGE
:
1360 case IPP_TAG_MIMETYPE
:
1361 if (n
>= sizeof(buffer
))
1363 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1367 if ((*cb
)(src
, buffer
, n
) < n
)
1369 DEBUG_puts("ippReadIO: unable to read name!");
1374 value
->string
.text
= _cupsStrAlloc((char *)buffer
);
1375 DEBUG_printf(("ippReadIO: value = \'%s\'\n",
1376 value
->string
.text
));
1382 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1386 if ((*cb
)(src
, value
->date
, 11) < 11)
1388 DEBUG_puts("ippReadIO: Unable to date integer value!");
1393 case IPP_TAG_RESOLUTION
:
1396 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1400 if ((*cb
)(src
, buffer
, 9) < 9)
1402 DEBUG_puts("ippReadIO: Unable to read resolution value!");
1406 value
->resolution
.xres
=
1407 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
1409 value
->resolution
.yres
=
1410 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
1412 value
->resolution
.units
=
1413 (ipp_res_t
)buffer
[8];
1416 case IPP_TAG_RANGE
:
1419 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1423 if ((*cb
)(src
, buffer
, 8) < 8)
1425 DEBUG_puts("ippReadIO: Unable to read range value!");
1429 value
->range
.lower
=
1430 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
1432 value
->range
.upper
=
1433 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
1437 case IPP_TAG_TEXTLANG
:
1438 case IPP_TAG_NAMELANG
:
1439 if (n
>= sizeof(buffer
) || n
< 4)
1441 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1445 if ((*cb
)(src
, buffer
, n
) < n
)
1447 DEBUG_puts("ippReadIO: Unable to read string w/language value!");
1454 * text-with-language and name-with-language are composite
1463 n
= (bufptr
[0] << 8) | bufptr
[1];
1465 if ((bufptr
+ 2 + n
) >= (buffer
+ sizeof(buffer
)) ||
1466 n
>= sizeof(string
))
1468 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1472 memcpy(string
, bufptr
+ 2, n
);
1475 value
->string
.charset
= _cupsStrAlloc((char *)string
);
1478 n
= (bufptr
[0] << 8) | bufptr
[1];
1480 if ((bufptr
+ 2 + n
) >= (buffer
+ sizeof(buffer
)))
1482 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1486 bufptr
[2 + n
] = '\0';
1487 value
->string
.text
= _cupsStrAlloc((char *)bufptr
+ 2);
1490 case IPP_TAG_BEGIN_COLLECTION
:
1492 * Oh, boy, here comes a collection value, so read it...
1495 value
->collection
= ippNew();
1499 DEBUG_puts("ippReadIO: begCollection tag with value length > 0!");
1503 if (ippReadIO(src
, cb
, 1, ipp
, value
->collection
) == IPP_ERROR
)
1505 DEBUG_puts("ippReadIO: Unable to read collection value!");
1510 case IPP_TAG_END_COLLECTION
:
1513 DEBUG_puts("ippReadIO: endCollection tag with value length > 0!");
1517 DEBUG_puts("ippReadIO: endCollection tag...");
1519 return (ipp
->state
= IPP_DATA
);
1521 case IPP_TAG_MEMBERNAME
:
1523 * The value the name of the member in the collection, which
1524 * we need to carry over...
1527 if (n
>= sizeof(buffer
))
1529 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1533 if ((*cb
)(src
, buffer
, n
) < n
)
1535 DEBUG_puts("ippReadIO: Unable to read member name value!");
1540 attr
->name
= _cupsStrAlloc((char *)buffer
);
1543 * Since collection members are encoded differently than
1544 * regular attributes, make sure we don't start with an
1548 attr
->num_values
--;
1550 DEBUG_printf(("ippReadIO: member name = \"%s\"\n", attr
->name
));
1553 default : /* Other unsupported values */
1554 if (n
> IPP_MAX_LENGTH
)
1556 DEBUG_printf(("ippReadIO: bad value length %d!\n", n
));
1560 value
->unknown
.length
= n
;
1563 if ((value
->unknown
.data
= malloc(n
)) == NULL
)
1565 DEBUG_puts("ippReadIO: Unable to allocate value");
1569 if ((*cb
)(src
, value
->unknown
.data
, n
) < n
)
1571 DEBUG_puts("ippReadIO: Unable to read unsupported value!");
1576 value
->unknown
.data
= NULL
;
1580 attr
->num_values
++;
1583 * If blocking is disabled, stop here...
1595 break; /* anti-compiler-warning-code */
1598 DEBUG_printf(("ippReadIO: returning ipp->state=%d!\n", ipp
->state
));
1600 return (ipp
->state
);
1605 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
1608 const ipp_uchar_t
* /* O - RFC-1903 date/time data */
1609 ippTimeToDate(time_t t
) /* I - UNIX time value */
1611 struct tm
*unixdate
; /* UNIX unixdate/time info */
1612 ipp_uchar_t
*date
= _cupsGlobals()->ipp_date
;
1613 /* RFC-1903 date/time data */
1617 * RFC-1903 date/time format is:
1619 * Byte(s) Description
1620 * ------- -----------
1621 * 0-1 Year (0 to 65535)
1625 * 5 Minutes (0 to 59)
1626 * 6 Seconds (0 to 60, 60 = "leap second")
1627 * 7 Deciseconds (0 to 9)
1629 * 9 UTC hours (0 to 11)
1630 * 10 UTC minutes (0 to 59)
1633 unixdate
= gmtime(&t
);
1634 unixdate
->tm_year
+= 1900;
1636 date
[0] = unixdate
->tm_year
>> 8;
1637 date
[1] = unixdate
->tm_year
;
1638 date
[2] = unixdate
->tm_mon
+ 1;
1639 date
[3] = unixdate
->tm_mday
;
1640 date
[4] = unixdate
->tm_hour
;
1641 date
[5] = unixdate
->tm_min
;
1642 date
[6] = unixdate
->tm_sec
;
1653 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
1656 ipp_state_t
/* O - Current state */
1657 ippWrite(http_t
*http
, /* I - HTTP connection */
1658 ipp_t
*ipp
) /* I - IPP data */
1660 DEBUG_printf(("ippWrite(%p, %p)\n", http
, ipp
));
1665 return (ippWriteIO(http
, (ipp_iocb_t
)httpWrite2
,
1666 http
->blocking
, NULL
, ipp
));
1671 * 'ippWriteFile()' - Write data for an IPP message to a file.
1673 * @since CUPS 1.1.19@
1676 ipp_state_t
/* O - Current state */
1677 ippWriteFile(int fd
, /* I - HTTP data */
1678 ipp_t
*ipp
) /* I - IPP data */
1680 DEBUG_printf(("ippWriteFile(%d, %p)\n", fd
, ipp
));
1682 ipp
->state
= IPP_IDLE
;
1684 return (ippWriteIO(&fd
, (ipp_iocb_t
)ipp_write_file
, 1, NULL
, ipp
));
1689 * 'ippWriteIO()' - Write data for an IPP message.
1694 ipp_state_t
/* O - Current state */
1695 ippWriteIO(void *dst
, /* I - Destination */
1696 ipp_iocb_t cb
, /* I - Write callback function */
1697 int blocking
, /* I - Use blocking IO? */
1698 ipp_t
*parent
, /* I - Parent IPP message */
1699 ipp_t
*ipp
) /* I - IPP data */
1701 int i
; /* Looping var */
1702 int n
; /* Length of data */
1703 unsigned char buffer
[IPP_MAX_LENGTH
+ 2],
1704 /* Data buffer + length bytes */
1705 *bufptr
; /* Pointer into buffer */
1706 ipp_attribute_t
*attr
; /* Current attribute */
1707 ipp_value_t
*value
; /* Current value */
1710 DEBUG_printf(("ippWriteIO(%p, %p, %d, %p, %p)\n", dst
, cb
, blocking
,
1713 if (dst
== NULL
|| ipp
== NULL
)
1719 ipp
->state
++; /* Avoid common problem... */
1725 * Send the request header:
1728 * Operation/Status Code = 2 bytes
1729 * Request ID = 4 bytes
1735 *bufptr
++ = ipp
->request
.any
.version
[0];
1736 *bufptr
++ = ipp
->request
.any
.version
[1];
1737 *bufptr
++ = ipp
->request
.any
.op_status
>> 8;
1738 *bufptr
++ = ipp
->request
.any
.op_status
;
1739 *bufptr
++ = ipp
->request
.any
.request_id
>> 24;
1740 *bufptr
++ = ipp
->request
.any
.request_id
>> 16;
1741 *bufptr
++ = ipp
->request
.any
.request_id
>> 8;
1742 *bufptr
++ = ipp
->request
.any
.request_id
;
1744 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
1746 DEBUG_puts("ippWriteIO: Could not write IPP header...");
1752 * Reset the state engine to point to the first attribute
1753 * in the request/response, with no current group.
1756 ipp
->state
= IPP_ATTRIBUTE
;
1757 ipp
->current
= ipp
->attrs
;
1758 ipp
->curtag
= IPP_TAG_ZERO
;
1760 DEBUG_printf(("ippWriteIO: version=%d.%d\n", buffer
[0], buffer
[1]));
1761 DEBUG_printf(("ippWriteIO: op_status=%04x\n", ipp
->request
.any
.op_status
));
1762 DEBUG_printf(("ippWriteIO: request_id=%d\n", ipp
->request
.any
.request_id
));
1765 * If blocking is disabled, stop here...
1771 case IPP_ATTRIBUTE
:
1772 while (ipp
->current
!= NULL
)
1775 * Write this attribute...
1779 attr
= ipp
->current
;
1781 ipp
->current
= ipp
->current
->next
;
1783 if (ipp
->curtag
!= attr
->group_tag
&& parent
== NULL
)
1786 * Send a group tag byte...
1789 ipp
->curtag
= attr
->group_tag
;
1791 if (attr
->group_tag
== IPP_TAG_ZERO
)
1794 DEBUG_printf(("ippWriteIO: wrote group tag = %x\n", attr
->group_tag
));
1795 *bufptr
++ = attr
->group_tag
;
1797 else if (attr
->group_tag
== IPP_TAG_ZERO
)
1801 * Write the attribute tag and name. The current implementation
1802 * does not support the extension value tags above 0x7f, so all
1803 * value tags are 1 byte.
1805 * The attribute name length does not include the trailing nul
1806 * character in the source string.
1808 * Collection values (parent != NULL) are written differently...
1814 * Get the length of the attribute name, and make sure it won't
1815 * overflow the buffer...
1818 if ((n
= (int)strlen(attr
->name
)) > (sizeof(buffer
) - 4))
1822 * Write the value tag, name length, and name string...
1825 DEBUG_printf(("ippWriteIO: writing value tag = %x\n", attr
->value_tag
));
1826 DEBUG_printf(("ippWriteIO: writing name = %d, \'%s\'\n", n
, attr
->name
));
1828 *bufptr
++ = attr
->value_tag
;
1831 memcpy(bufptr
, attr
->name
, n
);
1837 * Get the length of the attribute name, and make sure it won't
1838 * overflow the buffer...
1841 if ((n
= (int)strlen(attr
->name
)) > (sizeof(buffer
) - 7))
1845 * Write the member name tag, name length, name string, value tag,
1846 * and empty name for the collection member attribute...
1849 DEBUG_printf(("ippWriteIO: writing value tag = %x\n",
1850 IPP_TAG_MEMBERNAME
));
1851 DEBUG_printf(("ippWriteIO: writing name = %d, \'%s\'\n", n
, attr
->name
));
1852 DEBUG_printf(("ippWriteIO: writing value tag = %x\n", attr
->value_tag
));
1853 DEBUG_puts("ippWriteIO: writing name = 0, \'\'\n");
1855 *bufptr
++ = IPP_TAG_MEMBERNAME
;
1860 memcpy(bufptr
, attr
->name
, n
);
1863 *bufptr
++ = attr
->value_tag
;
1869 * Now write the attribute value(s)...
1872 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
1874 case IPP_TAG_INTEGER
:
1876 for (i
= 0, value
= attr
->values
;
1877 i
< attr
->num_values
;
1880 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 9)
1882 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
1884 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
1894 * Arrays and sets are done by sending additional
1895 * values with a zero-length name...
1898 *bufptr
++ = attr
->value_tag
;
1904 * Integers and enumerations are both 4-byte signed
1905 * (twos-complement) values.
1907 * Put the 2-byte length and 4-byte value into the buffer...
1912 *bufptr
++ = value
->integer
>> 24;
1913 *bufptr
++ = value
->integer
>> 16;
1914 *bufptr
++ = value
->integer
>> 8;
1915 *bufptr
++ = value
->integer
;
1919 case IPP_TAG_BOOLEAN
:
1920 for (i
= 0, value
= attr
->values
;
1921 i
< attr
->num_values
;
1924 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 6)
1926 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
1928 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
1938 * Arrays and sets are done by sending additional
1939 * values with a zero-length name...
1942 *bufptr
++ = attr
->value_tag
;
1948 * Boolean values are 1-byte; 0 = false, 1 = true.
1950 * Put the 2-byte length and 1-byte value into the buffer...
1955 *bufptr
++ = value
->boolean
;
1961 case IPP_TAG_KEYWORD
:
1963 case IPP_TAG_URISCHEME
:
1964 case IPP_TAG_CHARSET
:
1965 case IPP_TAG_LANGUAGE
:
1966 case IPP_TAG_MIMETYPE
:
1967 for (i
= 0, value
= attr
->values
;
1968 i
< attr
->num_values
;
1974 * Arrays and sets are done by sending additional
1975 * values with a zero-length name...
1978 DEBUG_printf(("ippWriteIO: writing value tag = %x\n",
1980 DEBUG_printf(("ippWriteIO: writing name = 0, \'\'\n"));
1982 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 3)
1984 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
1986 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
1993 *bufptr
++ = attr
->value_tag
;
1998 if (value
->string
.text
!= NULL
)
1999 n
= (int)strlen(value
->string
.text
);
2003 if (n
> (sizeof(buffer
) - 2))
2006 DEBUG_printf(("ippWriteIO: writing string = %d, \'%s\'\n", n
,
2007 value
->string
.text
));
2009 if ((int)(sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
2011 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2013 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
2021 * All simple strings consist of the 2-byte length and
2022 * character data without the trailing nul normally found
2023 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
2024 * bytes since the 2-byte length is a signed (twos-complement)
2027 * Put the 2-byte length and string characters in the buffer.
2035 memcpy(bufptr
, value
->string
.text
, n
);
2042 for (i
= 0, value
= attr
->values
;
2043 i
< attr
->num_values
;
2046 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 16)
2048 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2050 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
2060 * Arrays and sets are done by sending additional
2061 * values with a zero-length name...
2064 *bufptr
++ = attr
->value_tag
;
2070 * Date values consist of a 2-byte length and an
2071 * 11-byte date/time structure defined by RFC 1903.
2073 * Put the 2-byte length and 11-byte date/time
2074 * structure in the buffer.
2079 memcpy(bufptr
, value
->date
, 11);
2084 case IPP_TAG_RESOLUTION
:
2085 for (i
= 0, value
= attr
->values
;
2086 i
< attr
->num_values
;
2089 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 14)
2091 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2093 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
2103 * Arrays and sets are done by sending additional
2104 * values with a zero-length name...
2107 *bufptr
++ = attr
->value_tag
;
2113 * Resolution values consist of a 2-byte length,
2114 * 4-byte horizontal resolution value, 4-byte vertical
2115 * resolution value, and a 1-byte units value.
2117 * Put the 2-byte length and resolution value data
2123 *bufptr
++ = value
->resolution
.xres
>> 24;
2124 *bufptr
++ = value
->resolution
.xres
>> 16;
2125 *bufptr
++ = value
->resolution
.xres
>> 8;
2126 *bufptr
++ = value
->resolution
.xres
;
2127 *bufptr
++ = value
->resolution
.yres
>> 24;
2128 *bufptr
++ = value
->resolution
.yres
>> 16;
2129 *bufptr
++ = value
->resolution
.yres
>> 8;
2130 *bufptr
++ = value
->resolution
.yres
;
2131 *bufptr
++ = value
->resolution
.units
;
2135 case IPP_TAG_RANGE
:
2136 for (i
= 0, value
= attr
->values
;
2137 i
< attr
->num_values
;
2140 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 13)
2142 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2144 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
2154 * Arrays and sets are done by sending additional
2155 * values with a zero-length name...
2158 *bufptr
++ = attr
->value_tag
;
2164 * Range values consist of a 2-byte length,
2165 * 4-byte lower value, and 4-byte upper value.
2167 * Put the 2-byte length and range value data
2173 *bufptr
++ = value
->range
.lower
>> 24;
2174 *bufptr
++ = value
->range
.lower
>> 16;
2175 *bufptr
++ = value
->range
.lower
>> 8;
2176 *bufptr
++ = value
->range
.lower
;
2177 *bufptr
++ = value
->range
.upper
>> 24;
2178 *bufptr
++ = value
->range
.upper
>> 16;
2179 *bufptr
++ = value
->range
.upper
>> 8;
2180 *bufptr
++ = value
->range
.upper
;
2184 case IPP_TAG_TEXTLANG
:
2185 case IPP_TAG_NAMELANG
:
2186 for (i
= 0, value
= attr
->values
;
2187 i
< attr
->num_values
;
2193 * Arrays and sets are done by sending additional
2194 * values with a zero-length name...
2197 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 3)
2199 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2201 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
2208 *bufptr
++ = attr
->value_tag
;
2214 * textWithLanguage and nameWithLanguage values consist
2215 * of a 2-byte length for both strings and their
2216 * individual lengths, a 2-byte length for the
2217 * character string, the character string without the
2218 * trailing nul, a 2-byte length for the character
2219 * set string, and the character set string without
2225 if (value
->string
.charset
!= NULL
)
2226 n
+= (int)strlen(value
->string
.charset
);
2228 if (value
->string
.text
!= NULL
)
2229 n
+= (int)strlen(value
->string
.text
);
2231 if (n
> (sizeof(buffer
) - 2))
2234 if ((int)(sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
2236 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2238 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
2245 /* Length of entire value */
2249 /* Length of charset */
2250 if (value
->string
.charset
!= NULL
)
2251 n
= (int)strlen(value
->string
.charset
);
2261 memcpy(bufptr
, value
->string
.charset
, n
);
2265 /* Length of text */
2266 if (value
->string
.text
!= NULL
)
2267 n
= (int)strlen(value
->string
.text
);
2277 memcpy(bufptr
, value
->string
.text
, n
);
2283 case IPP_TAG_BEGIN_COLLECTION
:
2284 for (i
= 0, value
= attr
->values
;
2285 i
< attr
->num_values
;
2289 * Collections are written with the begin-collection
2290 * tag first with a value of 0 length, followed by the
2291 * attributes in the collection, then the end-collection
2295 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 5)
2297 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2299 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
2309 * Arrays and sets are done by sending additional
2310 * values with a zero-length name...
2313 *bufptr
++ = attr
->value_tag
;
2319 * Write a data length of 0 and flush the buffer...
2325 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2327 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
2334 * Then write the collection attribute...
2337 value
->collection
->state
= IPP_IDLE
;
2339 if (ippWriteIO(dst
, cb
, 1, ipp
, value
->collection
) == IPP_ERROR
)
2345 for (i
= 0, value
= attr
->values
;
2346 i
< attr
->num_values
;
2352 * Arrays and sets are done by sending additional
2353 * values with a zero-length name...
2356 if ((sizeof(buffer
) - (bufptr
- buffer
)) < 3)
2358 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2360 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
2367 *bufptr
++ = attr
->value_tag
;
2373 * An unknown value might some new value that a
2374 * vendor has come up with. It consists of a
2375 * 2-byte length and the bytes in the unknown
2379 n
= value
->unknown
.length
;
2381 if (n
> (sizeof(buffer
) - 2))
2384 if ((int)(sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
2386 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2388 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
2395 /* Length of unknown value */
2402 memcpy(bufptr
, value
->unknown
.data
, n
);
2410 * Write the data out...
2413 if ((*cb
)(dst
, buffer
, (int)(bufptr
- buffer
)) < 0)
2415 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
2419 DEBUG_printf(("ippWriteIO: wrote %d bytes\n",
2420 (int)(bufptr
- buffer
)));
2423 * If blocking is disabled, stop here...
2430 if (ipp
->current
== NULL
)
2433 * Done with all of the attributes; add the end-of-attributes
2434 * tag or end-collection attribute...
2439 buffer
[0] = IPP_TAG_END
;
2444 buffer
[0] = IPP_TAG_END_COLLECTION
;
2445 buffer
[1] = 0; /* empty name */
2447 buffer
[3] = 0; /* empty value */
2452 if ((*cb
)(dst
, buffer
, n
) < 0)
2454 DEBUG_puts("ippWriteIO: Could not write IPP end-tag...");
2458 ipp
->state
= IPP_DATA
;
2466 break; /* anti-compiler-warning-code */
2469 return (ipp
->state
);
2474 * '_ippAddAttr()' - Add a new attribute to the request.
2477 ipp_attribute_t
* /* O - New attribute */
2478 _ippAddAttr(ipp_t
*ipp
, /* I - IPP message */
2479 int num_values
) /* I - Number of values */
2481 ipp_attribute_t
*attr
; /* New attribute */
2484 DEBUG_printf(("_ippAddAttr(%p, %d)\n", ipp
, num_values
));
2486 if (ipp
== NULL
|| num_values
< 0)
2489 attr
= calloc(sizeof(ipp_attribute_t
) +
2490 (num_values
- 1) * sizeof(ipp_value_t
), 1);
2494 attr
->num_values
= num_values
;
2496 if (ipp
->last
== NULL
)
2499 ipp
->last
->next
= attr
;
2504 DEBUG_printf(("_ippAddAttr(): %p\n", attr
));
2511 * '_ippFreeAttr()' - Free an attribute.
2515 _ippFreeAttr(ipp_attribute_t
*attr
) /* I - Attribute to free */
2517 int i
; /* Looping var */
2518 ipp_value_t
*value
; /* Current value */
2521 DEBUG_printf(("_ippFreeAttr(): %p\n", attr
));
2523 switch (attr
->value_tag
)
2527 case IPP_TAG_KEYWORD
:
2529 case IPP_TAG_URISCHEME
:
2530 case IPP_TAG_CHARSET
:
2531 case IPP_TAG_LANGUAGE
:
2532 case IPP_TAG_MIMETYPE
:
2533 for (i
= 0, value
= attr
->values
;
2534 i
< attr
->num_values
;
2536 _cupsStrFree(value
->string
.text
);
2539 case IPP_TAG_TEXTLANG
:
2540 case IPP_TAG_NAMELANG
:
2541 for (i
= 0, value
= attr
->values
;
2542 i
< attr
->num_values
;
2545 if (value
->string
.charset
&& i
== 0)
2546 _cupsStrFree(value
->string
.charset
);
2547 _cupsStrFree(value
->string
.text
);
2551 case IPP_TAG_INTEGER
:
2553 case IPP_TAG_BOOLEAN
:
2555 case IPP_TAG_RESOLUTION
:
2556 case IPP_TAG_RANGE
:
2559 case IPP_TAG_BEGIN_COLLECTION
:
2560 for (i
= 0, value
= attr
->values
;
2561 i
< attr
->num_values
;
2563 ippDelete(value
->collection
);
2566 case IPP_TAG_STRING
:
2567 for (i
= 0, value
= attr
->values
;
2568 i
< attr
->num_values
;
2570 free(value
->unknown
.data
);
2574 if (!((int)attr
->value_tag
& IPP_TAG_COPY
))
2576 for (i
= 0, value
= attr
->values
;
2577 i
< attr
->num_values
;
2579 if (value
->unknown
.data
)
2580 free(value
->unknown
.data
);
2586 _cupsStrFree(attr
->name
);
2593 * 'ipp_length()' - Compute the length of an IPP message or collection value.
2596 static size_t /* O - Size of IPP message */
2597 ipp_length(ipp_t
*ipp
, /* I - IPP message or collection */
2598 int collection
) /* I - 1 if a collection, 0 otherwise */
2600 int i
; /* Looping var */
2601 int bytes
; /* Number of bytes */
2602 ipp_attribute_t
*attr
; /* Current attribute */
2603 ipp_tag_t group
; /* Current group */
2604 ipp_value_t
*value
; /* Current value */
2611 * Start with 8 bytes for the IPP message header...
2614 bytes
= collection
? 0 : 8;
2617 * Then add the lengths of each attribute...
2620 group
= IPP_TAG_ZERO
;
2622 for (attr
= ipp
->attrs
; attr
!= NULL
; attr
= attr
->next
)
2624 if (attr
->group_tag
!= group
&& !collection
)
2626 group
= attr
->group_tag
;
2627 if (group
== IPP_TAG_ZERO
)
2630 bytes
++; /* Group tag */
2636 DEBUG_printf(("ipp_length: attr->name=\"%s\", attr->num_values=%d, "
2637 "bytes=%d\n", attr
->name
, attr
->num_values
, bytes
));
2639 bytes
+= (int)strlen(attr
->name
); /* Name */
2640 bytes
+= attr
->num_values
; /* Value tag for each value */
2641 bytes
+= 2 * attr
->num_values
; /* Name lengths */
2642 bytes
+= 2 * attr
->num_values
; /* Value lengths */
2645 bytes
+= 5; /* Add membername overhead */
2647 switch (attr
->value_tag
& ~IPP_TAG_COPY
)
2649 case IPP_TAG_INTEGER
:
2651 bytes
+= 4 * attr
->num_values
;
2654 case IPP_TAG_BOOLEAN
:
2655 bytes
+= attr
->num_values
;
2660 case IPP_TAG_KEYWORD
:
2662 case IPP_TAG_URISCHEME
:
2663 case IPP_TAG_CHARSET
:
2664 case IPP_TAG_LANGUAGE
:
2665 case IPP_TAG_MIMETYPE
:
2666 for (i
= 0, value
= attr
->values
;
2667 i
< attr
->num_values
;
2669 if (value
->string
.text
!= NULL
)
2670 bytes
+= (int)strlen(value
->string
.text
);
2674 bytes
+= 11 * attr
->num_values
;
2677 case IPP_TAG_RESOLUTION
:
2678 bytes
+= 9 * attr
->num_values
;
2681 case IPP_TAG_RANGE
:
2682 bytes
+= 8 * attr
->num_values
;
2685 case IPP_TAG_TEXTLANG
:
2686 case IPP_TAG_NAMELANG
:
2687 bytes
+= 4 * attr
->num_values
;/* Charset + text length */
2689 for (i
= 0, value
= attr
->values
;
2690 i
< attr
->num_values
;
2693 if (value
->string
.charset
!= NULL
)
2694 bytes
+= (int)strlen(value
->string
.charset
);
2696 if (value
->string
.text
!= NULL
)
2697 bytes
+= (int)strlen(value
->string
.text
);
2701 case IPP_TAG_BEGIN_COLLECTION
:
2702 for (i
= 0, value
= attr
->values
;
2703 i
< attr
->num_values
;
2705 bytes
+= (int)ipp_length(value
->collection
, 1);
2709 for (i
= 0, value
= attr
->values
;
2710 i
< attr
->num_values
;
2712 bytes
+= value
->unknown
.length
;
2718 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
2719 * for the "end of collection" tag and return...
2727 DEBUG_printf(("ipp_length: bytes=%d\n", bytes
));
2734 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
2737 static ssize_t
/* O - Number of bytes read */
2738 ipp_read_http(http_t
*http
, /* I - Client connection */
2739 ipp_uchar_t
*buffer
, /* O - Buffer for data */
2740 size_t length
) /* I - Total length */
2742 int tbytes
, /* Total bytes read */
2743 bytes
; /* Bytes read this pass */
2744 char len
[32]; /* Length string */
2747 DEBUG_printf(("ipp_read_http(http=%p, buffer=%p, length=%d)\n",
2748 http
, buffer
, (int)length
));
2751 * Loop until all bytes are read...
2754 for (tbytes
= 0, bytes
= 0;
2755 tbytes
< (int)length
;
2756 tbytes
+= bytes
, buffer
+= bytes
)
2758 DEBUG_printf(("ipp_read_http: tbytes=%d, http->state=%d\n", tbytes
,
2761 if (http
->state
== HTTP_WAITING
)
2764 if (http
->used
> 0 && http
->data_encoding
== HTTP_ENCODE_LENGTH
)
2767 * Do "fast read" from HTTP buffer directly...
2770 if (http
->used
> (int)(length
- tbytes
))
2771 bytes
= (int)(length
- tbytes
);
2776 buffer
[0] = http
->buffer
[0];
2778 memcpy(buffer
, http
->buffer
, bytes
);
2780 http
->used
-= bytes
;
2781 http
->data_remaining
-= bytes
;
2783 if (http
->data_remaining
<= INT_MAX
)
2784 http
->_data_remaining
= (int)http
->data_remaining
;
2786 http
->_data_remaining
= INT_MAX
;
2789 memmove(http
->buffer
, http
->buffer
+ bytes
, http
->used
);
2791 if (http
->data_remaining
== 0)
2793 if (http
->data_encoding
== HTTP_ENCODE_CHUNKED
)
2796 * Get the trailing CR LF after the chunk...
2799 if (!httpGets(len
, sizeof(len
), http
))
2803 if (http
->data_encoding
!= HTTP_ENCODE_CHUNKED
)
2805 if (http
->state
== HTTP_POST_RECV
)
2808 http
->state
= HTTP_WAITING
;
2815 * Wait a maximum of 1 second for data...
2818 if (!http
->blocking
)
2821 * Wait up to 10 seconds for more data on non-blocking sockets...
2824 if (!httpWait(http
, 10000))
2835 if ((bytes
= httpRead2(http
, (char *)buffer
, length
- tbytes
)) <= 0)
2841 * Return the number of bytes read...
2844 if (tbytes
== 0 && bytes
< 0)
2847 DEBUG_printf(("ipp_read_http: returning %d bytes...\n", tbytes
));
2854 * 'ipp_read_file()' - Read IPP data from a file.
2857 static ssize_t
/* O - Number of bytes read */
2858 ipp_read_file(int *fd
, /* I - File descriptor */
2859 ipp_uchar_t
*buffer
, /* O - Read buffer */
2860 size_t length
) /* I - Number of bytes to read */
2863 return ((ssize_t
)read(*fd
, buffer
, (unsigned)length
));
2865 return (read(*fd
, buffer
, length
));
2871 * 'ipp_write_file()' - Write IPP data to a file.
2874 static ssize_t
/* O - Number of bytes written */
2875 ipp_write_file(int *fd
, /* I - File descriptor */
2876 ipp_uchar_t
*buffer
, /* I - Data to write */
2877 size_t length
) /* I - Number of bytes to write */
2880 return ((ssize_t
)write(*fd
, buffer
, (unsigned)length
));
2882 return (write(*fd
, buffer
, length
));
2889 * The following symbol definitions are provided only for KDE
2890 * compatibility during the CUPS 1.2 testing period and will be
2891 * removed in a future release of CUPS. These are PRIVATE APIs
2892 * from CUPS 1.1.x that the KDE developers chose to use...
2895 ipp_attribute_t
* /* O - New attribute */
2896 _ipp_add_attr(ipp_t
*ipp
, /* I - IPP message */
2897 int num_values
) /* I - Number of values */
2899 return (_ippAddAttr(ipp
, num_values
));
2903 _ipp_free_attr(ipp_attribute_t
*attr
) /* I - Attribute to free */
2907 #endif /* __linux */
2911 * End of "$Id: ipp.c 6649 2007-07-11 21:46:42Z mike $".