]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/ipp.c
Merge changes from CUPS 1.4svn-r8227.
[thirdparty/cups.git] / cups / ipp.c
1 /*
2 * "$Id: ipp.c 7847 2008-08-19 04:22:14Z mike $"
3 *
4 * Internet Printing Protocol support functions for the Common UNIX
5 * Printing System (CUPS).
6 *
7 * Copyright 2007-2009 by Apple Inc.
8 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
9 *
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/".
15 *
16 * This file is subject to the Apple OS-Developed Software exception.
17 *
18 * Contents:
19 *
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
43 * connection.
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
48 * connection.
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
54 * collection value.
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.
58 */
59
60 /*
61 * Include necessary headers...
62 */
63
64 #include "http-private.h"
65 #include "globals.h"
66 #include "debug.h"
67 #include <stdlib.h>
68 #include <errno.h>
69 #ifdef WIN32
70 # include <io.h>
71 #endif /* WIN32 */
72
73
74 /*
75 * Local functions...
76 */
77
78 static unsigned char *ipp_buffer_get(void);
79 static void ipp_buffer_release(unsigned char *b);
80 static size_t ipp_length(ipp_t *ipp, int collection);
81 static ssize_t ipp_read_http(http_t *http, ipp_uchar_t *buffer,
82 size_t length);
83 static ssize_t ipp_read_file(int *fd, ipp_uchar_t *buffer,
84 size_t length);
85 static ssize_t ipp_write_file(int *fd, ipp_uchar_t *buffer,
86 size_t length);
87
88
89 /*
90 * 'ippAddBoolean()' - Add a boolean attribute to an IPP message.
91 */
92
93 ipp_attribute_t * /* O - New attribute */
94 ippAddBoolean(ipp_t *ipp, /* I - IPP message */
95 ipp_tag_t group, /* I - IPP group */
96 const char *name, /* I - Name of attribute */
97 char value) /* I - Value of attribute */
98 {
99 ipp_attribute_t *attr; /* New attribute */
100
101
102 DEBUG_printf(("ippAddBoolean(ipp=%p, group=%02x(%s), name=\"%s\", value=%d)\n",
103 ipp, group, ippTagString(group), name, value));
104
105 if (!ipp || !name)
106 return (NULL);
107
108 if ((attr = _ippAddAttr(ipp, 1)) == NULL)
109 return (NULL);
110
111 attr->name = _cupsStrAlloc(name);
112 attr->group_tag = group;
113 attr->value_tag = IPP_TAG_BOOLEAN;
114 attr->values[0].boolean = value;
115
116 return (attr);
117 }
118
119
120 /*
121 * 'ippAddBooleans()' - Add an array of boolean values.
122 */
123
124 ipp_attribute_t * /* O - New attribute */
125 ippAddBooleans(ipp_t *ipp, /* I - IPP message */
126 ipp_tag_t group, /* I - IPP group */
127 const char *name, /* I - Name of attribute */
128 int num_values, /* I - Number of values */
129 const char *values) /* I - Values */
130 {
131 int i; /* Looping var */
132 ipp_attribute_t *attr; /* New attribute */
133 ipp_value_t *value; /* Current value */
134
135
136 DEBUG_printf(("ippAddBooleans(ipp=%p, group=%02x(%s), name=\"%s\", "
137 "num_values=%d, values=%p)\n", ipp, group, ippTagString(group),
138 name, num_values, values));
139
140 if (!ipp || !name || num_values < 1)
141 return (NULL);
142
143 if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
144 return (NULL);
145
146 attr->name = _cupsStrAlloc(name);
147 attr->group_tag = group;
148 attr->value_tag = IPP_TAG_BOOLEAN;
149
150 if (values != NULL)
151 for (i = 0, value = attr->values;
152 i < num_values;
153 i ++, value ++)
154 value->boolean = values[i];
155
156 return (attr);
157 }
158
159
160 /*
161 * 'ippAddCollection()' - Add a collection value.
162 *
163 * @since CUPS 1.1.19/Mac OS X 10.3@
164 */
165
166 ipp_attribute_t * /* O - New attribute */
167 ippAddCollection(ipp_t *ipp, /* I - IPP message */
168 ipp_tag_t group, /* I - IPP group */
169 const char *name, /* I - Name of attribute */
170 ipp_t *value) /* I - Value */
171 {
172 ipp_attribute_t *attr; /* New attribute */
173
174
175 DEBUG_printf(("ippAddCollection(ipp=%p, group=%02x(%s), name=\"%s\", "
176 "value=%p)\n", ipp, group, ippTagString(group), name, value));
177
178 if (!ipp || !name)
179 return (NULL);
180
181 if ((attr = _ippAddAttr(ipp, 1)) == NULL)
182 return (NULL);
183
184 attr->name = _cupsStrAlloc(name);
185 attr->group_tag = group;
186 attr->value_tag = IPP_TAG_BEGIN_COLLECTION;
187 attr->values[0].collection = value;
188
189 return (attr);
190 }
191
192
193 /*
194 * 'ippAddCollections()' - Add an array of collection values.
195 *
196 * @since CUPS 1.1.19/Mac OS X 10.3@
197 */
198
199 ipp_attribute_t * /* O - New attribute */
200 ippAddCollections(
201 ipp_t *ipp, /* I - IPP message */
202 ipp_tag_t group, /* I - IPP group */
203 const char *name, /* I - Name of attribute */
204 int num_values, /* I - Number of values */
205 const ipp_t **values) /* I - Values */
206 {
207 int i; /* Looping var */
208 ipp_attribute_t *attr; /* New attribute */
209 ipp_value_t *value; /* Current value */
210
211
212 DEBUG_printf(("ippAddCollections(ipp=%p, group=%02x(%s), name=\"%s\", "
213 "num_values=%d, values=%p)\n", ipp, group, ippTagString(group),
214 name, num_values, values));
215
216 if (!ipp || !name || num_values < 1)
217 return (NULL);
218
219 if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
220 return (NULL);
221
222 attr->name = _cupsStrAlloc(name);
223 attr->group_tag = group;
224 attr->value_tag = IPP_TAG_BEGIN_COLLECTION;
225
226 if (values != NULL)
227 for (i = 0, value = attr->values;
228 i < num_values;
229 i ++, value ++)
230 value->collection = (ipp_t *)values[i];
231
232 return (attr);
233 }
234
235
236 /*
237 * 'ippAddDate()' - Add a date attribute to an IPP message.
238 */
239
240 ipp_attribute_t * /* O - New attribute */
241 ippAddDate(ipp_t *ipp, /* I - IPP message */
242 ipp_tag_t group, /* I - IPP group */
243 const char *name, /* I - Name of attribute */
244 const ipp_uchar_t *value) /* I - Value */
245 {
246 ipp_attribute_t *attr; /* New attribute */
247
248
249 DEBUG_printf(("ippAddDate(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)\n",
250 ipp, group, ippTagString(group), name, value));
251
252 if (!ipp || !name || !value)
253 return (NULL);
254
255 if ((attr = _ippAddAttr(ipp, 1)) == NULL)
256 return (NULL);
257
258 attr->name = _cupsStrAlloc(name);
259 attr->group_tag = group;
260 attr->value_tag = IPP_TAG_DATE;
261 memcpy(attr->values[0].date, value, 11);
262
263 return (attr);
264 }
265
266
267 /*
268 * 'ippAddInteger()' - Add a integer attribute to an IPP message.
269 */
270
271 ipp_attribute_t * /* O - New attribute */
272 ippAddInteger(ipp_t *ipp, /* I - IPP message */
273 ipp_tag_t group, /* I - IPP group */
274 ipp_tag_t type, /* I - Type of attribute */
275 const char *name, /* I - Name of attribute */
276 int value) /* I - Value of attribute */
277 {
278 ipp_attribute_t *attr; /* New attribute */
279
280
281 DEBUG_printf(("ippAddInteger(ipp=%p, group=%02x(%s), type=%02x(%s), "
282 "name=\"%s\", value=%d)\n", ipp, group, ippTagString(group),
283 type, ippTagString(type), name, value));
284
285 if (!ipp || !name)
286 return (NULL);
287
288 if ((attr = _ippAddAttr(ipp, 1)) == NULL)
289 return (NULL);
290
291 attr->name = _cupsStrAlloc(name);
292 attr->group_tag = group;
293 attr->value_tag = type;
294 attr->values[0].integer = value;
295
296 return (attr);
297 }
298
299
300 /*
301 * 'ippAddIntegers()' - Add an array of integer values.
302 */
303
304 ipp_attribute_t * /* O - New attribute */
305 ippAddIntegers(ipp_t *ipp, /* I - IPP message */
306 ipp_tag_t group, /* I - IPP group */
307 ipp_tag_t type, /* I - Type of attribute */
308 const char *name, /* I - Name of attribute */
309 int num_values, /* I - Number of values */
310 const int *values) /* I - Values */
311 {
312 int i; /* Looping var */
313 ipp_attribute_t *attr; /* New attribute */
314 ipp_value_t *value; /* Current value */
315
316
317 DEBUG_printf(("ippAddIntegers(ipp=%p, group=%02x(%s), type=%02x(%s), "
318 "name=\"%s\", num_values=%d, values=%p)\n", ipp,
319 group, ippTagString(group), type, ippTagString(type), name,
320 num_values, values));
321
322 if (!ipp || !name || num_values < 1)
323 return (NULL);
324
325 if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
326 return (NULL);
327
328 attr->name = _cupsStrAlloc(name);
329 attr->group_tag = group;
330 attr->value_tag = type;
331
332 if (values != NULL)
333 for (i = 0, value = attr->values;
334 i < num_values;
335 i ++, value ++)
336 value->integer = values[i];
337
338 return (attr);
339 }
340
341
342 /*
343 * 'ippAddOctetString()' - Add an octetString value to an IPP message.
344 *
345 * @since CUPS 1.2/Mac OS X 10.5@
346 */
347
348 ipp_attribute_t * /* O - New attribute */
349 ippAddOctetString(ipp_t *ipp, /* I - IPP message */
350 ipp_tag_t group, /* I - IPP group */
351 const char *name, /* I - Name of attribute */
352 const void *data, /* I - octetString data */
353 int datalen) /* I - Length of data in bytes */
354 {
355 ipp_attribute_t *attr; /* New attribute */
356
357
358 if (ipp == NULL || name == NULL)
359 return (NULL);
360
361 if ((attr = _ippAddAttr(ipp, 1)) == NULL)
362 return (NULL);
363
364 /*
365 * Initialize the attribute data...
366 */
367
368 attr->name = _cupsStrAlloc(name);
369 attr->group_tag = group;
370 attr->value_tag = IPP_TAG_STRING;
371 attr->values[0].unknown.length = datalen;
372
373 if (data)
374 {
375 if ((attr->values[0].unknown.data = malloc(datalen)) == NULL)
376 {
377 ippDeleteAttribute(ipp, attr);
378 return (NULL);
379 }
380
381 memcpy(attr->values[0].unknown.data, data, datalen);
382 }
383
384 /*
385 * Return the new attribute...
386 */
387
388 return (attr);
389 }
390
391
392 /*
393 * 'ippAddString()' - Add a language-encoded string to an IPP message.
394 */
395
396 ipp_attribute_t * /* O - New attribute */
397 ippAddString(ipp_t *ipp, /* I - IPP message */
398 ipp_tag_t group, /* I - IPP group */
399 ipp_tag_t type, /* I - Type of attribute */
400 const char *name, /* I - Name of attribute */
401 const char *charset, /* I - Character set */
402 const char *value) /* I - Value */
403 {
404 ipp_attribute_t *attr; /* New attribute */
405 char buffer[1024], /* Language/charset value buffer */
406 *bufptr; /* Pointer into buffer */
407
408
409 DEBUG_printf(("ippAddString(ipp=%p, group=%02x(%s), type=%02x(%s), "
410 "name=\"%s\", charset=\"%s\", value=\"%s\")\n", ipp,
411 group, ippTagString(group), type, ippTagString(type), name,
412 charset, value));
413
414 if (!ipp || !name)
415 return (NULL);
416
417 if ((attr = _ippAddAttr(ipp, 1)) == NULL)
418 return (NULL);
419
420 /*
421 * Force value to be English for the POSIX locale...
422 */
423
424 if (type == IPP_TAG_LANGUAGE && !strcasecmp(value, "C"))
425 value = "en";
426
427 /*
428 * Convert language values to lowercase and change _ to - as needed...
429 */
430
431 if ((type == IPP_TAG_LANGUAGE || type == IPP_TAG_CHARSET) && value)
432 {
433 strlcpy(buffer, value, sizeof(buffer));
434 value = buffer;
435
436 for (bufptr = buffer; *bufptr; bufptr ++)
437 if (*bufptr == '_')
438 *bufptr = '-';
439 else
440 *bufptr = tolower(*bufptr & 255);
441 }
442
443 /*
444 * Initialize the attribute data...
445 */
446
447 attr->name = _cupsStrAlloc(name);
448 attr->group_tag = group;
449 attr->value_tag = type;
450 attr->values[0].string.charset = ((int)type & IPP_TAG_COPY) ? (char *)charset :
451 charset ? _cupsStrAlloc(charset) : NULL;
452 attr->values[0].string.text = ((int)type & IPP_TAG_COPY) ? (char *)value :
453 value ? _cupsStrAlloc(value) : NULL;
454
455 return (attr);
456 }
457
458
459 /*
460 * 'ippAddStrings()' - Add language-encoded strings to an IPP message.
461 */
462
463 ipp_attribute_t * /* O - New attribute */
464 ippAddStrings(
465 ipp_t *ipp, /* I - IPP message */
466 ipp_tag_t group, /* I - IPP group */
467 ipp_tag_t type, /* I - Type of attribute */
468 const char *name, /* I - Name of attribute */
469 int num_values, /* I - Number of values */
470 const char *charset, /* I - Character set */
471 const char * const *values) /* I - Values */
472 {
473 int i; /* Looping var */
474 ipp_attribute_t *attr; /* New attribute */
475 ipp_value_t *value; /* Current value */
476
477
478 DEBUG_printf(("ippAddStrings(ipp=%p, group=%02x(%s), type=%02x(%s), "
479 "name=\"%s\", num_values=%d, charset=\"%s\", values=%p)\n", ipp,
480 group, ippTagString(group), type, ippTagString(type), name,
481 num_values, charset, values));
482
483 if (!ipp || !name || num_values < 1)
484 return (NULL);
485
486 if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
487 return (NULL);
488
489 /*
490 * Initialize the attribute data...
491 */
492
493 attr->name = _cupsStrAlloc(name);
494 attr->group_tag = group;
495 attr->value_tag = type;
496
497 for (i = 0, value = attr->values;
498 i < num_values;
499 i ++, value ++)
500 {
501 if (i == 0)
502 value->string.charset = ((int)type & IPP_TAG_COPY) ? (char *)charset :
503 charset ? _cupsStrAlloc(charset) : NULL;
504 else
505 value->string.charset = attr->values[0].string.charset;
506
507 if (values != NULL)
508 {
509 /*
510 * Force language to be English for the POSIX locale...
511 */
512
513 if (type == IPP_TAG_LANGUAGE && !strcasecmp(values[i], "C"))
514 value->string.text = ((int)type & IPP_TAG_COPY) ? "en" :
515 _cupsStrAlloc("en");
516 else
517 value->string.text = ((int)type & IPP_TAG_COPY) ? (char *)values[i] :
518 _cupsStrAlloc(values[i]);
519 }
520 }
521
522 return (attr);
523 }
524
525
526 /*
527 * 'ippAddRange()' - Add a range of values to an IPP message.
528 */
529
530 ipp_attribute_t * /* O - New attribute */
531 ippAddRange(ipp_t *ipp, /* I - IPP message */
532 ipp_tag_t group, /* I - IPP group */
533 const char *name, /* I - Name of attribute */
534 int lower, /* I - Lower value */
535 int upper) /* I - Upper value */
536 {
537 ipp_attribute_t *attr; /* New attribute */
538
539
540 DEBUG_printf(("ippAddRange(ipp=%p, group=%02x(%s), name=\"%s\", lower=%d, "
541 "upper=%d)\n", ipp, group, ippTagString(group), name, lower,
542 upper));
543
544 if (!ipp || !name)
545 return (NULL);
546
547 if ((attr = _ippAddAttr(ipp, 1)) == NULL)
548 return (NULL);
549
550 attr->name = _cupsStrAlloc(name);
551 attr->group_tag = group;
552 attr->value_tag = IPP_TAG_RANGE;
553 attr->values[0].range.lower = lower;
554 attr->values[0].range.upper = upper;
555
556 return (attr);
557 }
558
559
560 /*
561 * 'ippAddRanges()' - Add ranges of values to an IPP message.
562 */
563
564 ipp_attribute_t * /* O - New attribute */
565 ippAddRanges(ipp_t *ipp, /* I - IPP message */
566 ipp_tag_t group, /* I - IPP group */
567 const char *name, /* I - Name of attribute */
568 int num_values, /* I - Number of values */
569 const int *lower, /* I - Lower values */
570 const int *upper) /* I - Upper values */
571 {
572 int i; /* Looping var */
573 ipp_attribute_t *attr; /* New attribute */
574 ipp_value_t *value; /* Current value */
575
576
577 DEBUG_printf(("ippAddRanges(ipp=%p, group=%02x(%s), name=\"%s\", "
578 "num_values=%d, lower=%p, upper=%p)\n", ipp, group,
579 ippTagString(group), name, num_values, lower, upper));
580
581 if (!ipp || !name || num_values < 1)
582 return (NULL);
583
584 if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
585 return (NULL);
586
587 attr->name = _cupsStrAlloc(name);
588 attr->group_tag = group;
589 attr->value_tag = IPP_TAG_RANGE;
590
591 if (lower != NULL && upper != NULL)
592 for (i = 0, value = attr->values;
593 i < num_values;
594 i ++, value ++)
595 {
596 value->range.lower = lower[i];
597 value->range.upper = upper[i];
598 }
599
600 return (attr);
601 }
602
603
604 /*
605 * 'ippAddResolution()' - Add a resolution value to an IPP message.
606 */
607
608 ipp_attribute_t * /* O - New attribute */
609 ippAddResolution(ipp_t *ipp, /* I - IPP message */
610 ipp_tag_t group, /* I - IPP group */
611 const char *name, /* I - Name of attribute */
612 ipp_res_t units, /* I - Units for resolution */
613 int xres, /* I - X resolution */
614 int yres) /* I - Y resolution */
615 {
616 ipp_attribute_t *attr; /* New attribute */
617
618
619 DEBUG_printf(("ippAddResolution(ipp=%p, group=%02x(%s), name=\"%s\", "
620 "units=%d, xres=%d, yres=%d)\n", ipp, group,
621 ippTagString(group), name, units, xres, yres));
622
623 if (!ipp || !name)
624 return (NULL);
625
626 if ((attr = _ippAddAttr(ipp, 1)) == NULL)
627 return (NULL);
628
629 attr->name = _cupsStrAlloc(name);
630 attr->group_tag = group;
631 attr->value_tag = IPP_TAG_RESOLUTION;
632 attr->values[0].resolution.xres = xres;
633 attr->values[0].resolution.yres = yres;
634 attr->values[0].resolution.units = units;
635
636 return (attr);
637 }
638
639
640 /*
641 * 'ippAddResolutions()' - Add resolution values to an IPP message.
642 */
643
644 ipp_attribute_t * /* O - New attribute */
645 ippAddResolutions(ipp_t *ipp, /* I - IPP message */
646 ipp_tag_t group, /* I - IPP group */
647 const char *name, /* I - Name of attribute */
648 int num_values,/* I - Number of values */
649 ipp_res_t units, /* I - Units for resolution */
650 const int *xres, /* I - X resolutions */
651 const int *yres) /* I - Y resolutions */
652 {
653 int i; /* Looping var */
654 ipp_attribute_t *attr; /* New attribute */
655 ipp_value_t *value; /* Current value */
656
657
658 DEBUG_printf(("ippAddResolutions(ipp=%p, group=%02x(%s), name=\"%s\", "
659 "num_value=%d, units=%d, xres=%p, yres=%p)\n", ipp, group,
660 ippTagString(group), name, num_values, units, xres, yres));
661
662 if (!ipp || !name || num_values < 1)
663 return (NULL);
664
665 if ((attr = _ippAddAttr(ipp, num_values)) == NULL)
666 return (NULL);
667
668 attr->name = _cupsStrAlloc(name);
669 attr->group_tag = group;
670 attr->value_tag = IPP_TAG_RESOLUTION;
671
672 if (xres != NULL && yres != NULL)
673 for (i = 0, value = attr->values;
674 i < num_values;
675 i ++, value ++)
676 {
677 value->resolution.xres = xres[i];
678 value->resolution.yres = yres[i];
679 value->resolution.units = units;
680 }
681
682 return (attr);
683 }
684
685
686 /*
687 * 'ippAddSeparator()' - Add a group separator to an IPP message.
688 */
689
690 ipp_attribute_t * /* O - New attribute */
691 ippAddSeparator(ipp_t *ipp) /* I - IPP message */
692 {
693 ipp_attribute_t *attr; /* New attribute */
694
695
696 DEBUG_printf(("ippAddSeparator(ipp=%p)\n", ipp));
697
698 if (!ipp)
699 return (NULL);
700
701 if ((attr = _ippAddAttr(ipp, 0)) == NULL)
702 return (NULL);
703
704 attr->group_tag = IPP_TAG_ZERO;
705 attr->value_tag = IPP_TAG_ZERO;
706
707 return (attr);
708 }
709
710
711 /*
712 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
713 * in seconds.
714 */
715
716 time_t /* O - UNIX time value */
717 ippDateToTime(const ipp_uchar_t *date) /* I - RFC 1903 date info */
718 {
719 struct tm unixdate; /* UNIX date/time info */
720 time_t t; /* Computed time */
721
722
723 if (!date)
724 return (0);
725
726 memset(&unixdate, 0, sizeof(unixdate));
727
728 /*
729 * RFC-1903 date/time format is:
730 *
731 * Byte(s) Description
732 * ------- -----------
733 * 0-1 Year (0 to 65535)
734 * 2 Month (1 to 12)
735 * 3 Day (1 to 31)
736 * 4 Hours (0 to 23)
737 * 5 Minutes (0 to 59)
738 * 6 Seconds (0 to 60, 60 = "leap second")
739 * 7 Deciseconds (0 to 9)
740 * 8 +/- UTC
741 * 9 UTC hours (0 to 11)
742 * 10 UTC minutes (0 to 59)
743 */
744
745 unixdate.tm_year = ((date[0] << 8) | date[1]) - 1900;
746 unixdate.tm_mon = date[2] - 1;
747 unixdate.tm_mday = date[3];
748 unixdate.tm_hour = date[4];
749 unixdate.tm_min = date[5];
750 unixdate.tm_sec = date[6];
751
752 t = mktime(&unixdate);
753
754 if (date[8] == '-')
755 t += date[9] * 3600 + date[10] * 60;
756 else
757 t -= date[9] * 3600 + date[10] * 60;
758
759 return (t);
760 }
761
762
763 /*
764 * 'ippDelete()' - Delete an IPP message.
765 */
766
767 void
768 ippDelete(ipp_t *ipp) /* I - IPP message */
769 {
770 ipp_attribute_t *attr, /* Current attribute */
771 *next; /* Next attribute */
772
773
774 DEBUG_printf(("ippDelete(ipp=%p)\n", ipp));
775
776 if (!ipp)
777 return;
778
779 for (attr = ipp->attrs; attr != NULL; attr = next)
780 {
781 next = attr->next;
782 _ippFreeAttr(attr);
783 }
784
785 free(ipp);
786 }
787
788
789 /*
790 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
791 *
792 * @since CUPS 1.1.19/Mac OS X 10.3@
793 */
794
795 void
796 ippDeleteAttribute(
797 ipp_t *ipp, /* I - IPP message */
798 ipp_attribute_t *attr) /* I - Attribute to delete */
799 {
800 ipp_attribute_t *current, /* Current attribute */
801 *prev; /* Previous attribute */
802
803
804 DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p)\n", ipp, attr));
805
806 /*
807 * Find the attribute in the list...
808 */
809
810 for (current = ipp->attrs, prev = NULL;
811 current != NULL && current != attr;
812 prev = current, current = current->next);
813
814 if (current)
815 {
816 /*
817 * Found it, remove the attribute from the list...
818 */
819
820 if (prev)
821 prev->next = current->next;
822 else
823 ipp->attrs = current->next;
824
825 if (current == ipp->last)
826 ipp->last = prev;
827
828 /*
829 * Free memory used by the attribute...
830 */
831
832 _ippFreeAttr(current);
833 }
834 }
835
836
837 /*
838 * 'ippFindAttribute()' - Find a named attribute in a request...
839 */
840
841 ipp_attribute_t * /* O - Matching attribute */
842 ippFindAttribute(ipp_t *ipp, /* I - IPP message */
843 const char *name, /* I - Name of attribute */
844 ipp_tag_t type) /* I - Type of attribute */
845 {
846 DEBUG_printf(("ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))\n", ipp,
847 name, type, ippTagString(type)));
848
849 if (!ipp || !name)
850 return (NULL);
851
852 /*
853 * Reset the current pointer...
854 */
855
856 ipp->current = NULL;
857
858 /*
859 * Search for the attribute...
860 */
861
862 return (ippFindNextAttribute(ipp, name, type));
863 }
864
865
866 /*
867 * 'ippFindNextAttribute()' - Find the next named attribute in a request...
868 */
869
870 ipp_attribute_t * /* O - Matching attribute */
871 ippFindNextAttribute(ipp_t *ipp, /* I - IPP message */
872 const char *name, /* I - Name of attribute */
873 ipp_tag_t type) /* I - Type of attribute */
874 {
875 ipp_attribute_t *attr; /* Current atttribute */
876 ipp_tag_t value_tag; /* Value tag */
877
878
879 DEBUG_printf(("ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))\n",
880 ipp, name, type, ippTagString(type)));
881
882 if (!ipp || !name)
883 return (NULL);
884
885 if (ipp->current)
886 {
887 ipp->prev = ipp->current;
888 attr = ipp->current->next;
889 }
890 else
891 {
892 ipp->prev = NULL;
893 attr = ipp->attrs;
894 }
895
896 for (; attr != NULL; ipp->prev = attr, attr = attr->next)
897 {
898 DEBUG_printf(("ippFindAttribute: attr=%p, name=\"%s\"\n", attr,
899 attr->name));
900
901 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_MASK);
902
903 if (attr->name != NULL && strcasecmp(attr->name, name) == 0 &&
904 (value_tag == type || type == IPP_TAG_ZERO ||
905 (value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) ||
906 (value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME)))
907 {
908 ipp->current = attr;
909
910 return (attr);
911 }
912 }
913
914 ipp->current = NULL;
915 ipp->prev = NULL;
916
917 return (NULL);
918 }
919
920
921 /*
922 * 'ippLength()' - Compute the length of an IPP message.
923 */
924
925 size_t /* O - Size of IPP message */
926 ippLength(ipp_t *ipp) /* I - IPP message */
927 {
928 return (ipp_length(ipp, 0));
929 }
930
931
932 /*
933 * 'ippNew()' - Allocate a new IPP message.
934 */
935
936 ipp_t * /* O - New IPP message */
937 ippNew(void)
938 {
939 ipp_t *temp; /* New IPP message */
940
941
942 DEBUG_puts("ippNew()");
943
944 if ((temp = (ipp_t *)calloc(1, sizeof(ipp_t))) != NULL)
945 {
946 /*
947 * Default to IPP 1.1...
948 */
949
950 temp->request.any.version[0] = 1;
951 temp->request.any.version[1] = 1;
952 }
953
954 DEBUG_printf(("ippNew: %p\n", temp));
955
956 return (temp);
957 }
958
959
960 /*
961 * 'ippNewRequest()' - Allocate a new IPP request message.
962 *
963 * The new request message is initialized with the attributes-charset and
964 * attributes-natural-language attributes added. The
965 * attributes-natural-language value is derived from the current locale.
966 *
967 * @since CUPS 1.2/Mac OS X 10.5@
968 */
969
970 ipp_t * /* O - IPP request message */
971 ippNewRequest(ipp_op_t op) /* I - Operation code */
972 {
973 ipp_t *request; /* IPP request message */
974 cups_lang_t *language; /* Current language localization */
975
976
977 DEBUG_printf(("ippNewRequest(op=%02x(%s))\n", op, ippOpString(op)));
978
979 /*
980 * Create a new IPP message...
981 */
982
983 if ((request = ippNew()) == NULL)
984 return (NULL);
985
986 /*
987 * Set the operation and request ID...
988 */
989
990 request->request.op.operation_id = op;
991 request->request.op.request_id = 1;
992
993 /*
994 * Use UTF-8 as the character set...
995 */
996
997 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
998 "attributes-charset", NULL, "utf-8");
999
1000 /*
1001 * Get the language from the current locale...
1002 */
1003
1004 language = cupsLangDefault();
1005
1006 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
1007 "attributes-natural-language", NULL, language->language);
1008
1009 /*
1010 * Return the new request...
1011 */
1012
1013 return (request);
1014 }
1015
1016
1017 /*
1018 * 'ippRead()' - Read data for an IPP message from a HTTP connection.
1019 */
1020
1021 ipp_state_t /* O - Current state */
1022 ippRead(http_t *http, /* I - HTTP connection */
1023 ipp_t *ipp) /* I - IPP data */
1024 {
1025 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT "\n",
1026 http, ipp, CUPS_LLCAST (http ? http->data_remaining : -1)));
1027
1028 if (!http)
1029 return (IPP_ERROR);
1030
1031 DEBUG_printf(("ippRead: http->state=%d, http->used=%d\n", http->state,
1032 http->used));
1033
1034 return (ippReadIO(http, (ipp_iocb_t)ipp_read_http, http->blocking, NULL,
1035 ipp));
1036 }
1037
1038
1039 /*
1040 * 'ippReadFile()' - Read data for an IPP message from a file.
1041 *
1042 * @since CUPS 1.1.19/Mac OS X 10.3@
1043 */
1044
1045 ipp_state_t /* O - Current state */
1046 ippReadFile(int fd, /* I - HTTP data */
1047 ipp_t *ipp) /* I - IPP data */
1048 {
1049 DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)\n", fd, ipp));
1050
1051 return (ippReadIO(&fd, (ipp_iocb_t)ipp_read_file, 1, NULL, ipp));
1052 }
1053
1054
1055 /*
1056 * 'ippReadIO()' - Read data for an IPP message.
1057 *
1058 * @since CUPS 1.2/Mac OS X 10.5@
1059 */
1060
1061 ipp_state_t /* O - Current state */
1062 ippReadIO(void *src, /* I - Data source */
1063 ipp_iocb_t cb, /* I - Read callback function */
1064 int blocking, /* I - Use blocking IO? */
1065 ipp_t *parent, /* I - Parent request, if any */
1066 ipp_t *ipp) /* I - IPP data */
1067 {
1068 int n; /* Length of data */
1069 unsigned char *buffer, /* Data buffer */
1070 string[IPP_MAX_NAME],
1071 /* Small string buffer */
1072 *bufptr; /* Pointer into buffer */
1073 ipp_attribute_t *attr; /* Current attribute */
1074 ipp_tag_t tag; /* Current tag */
1075 ipp_tag_t value_tag; /* Current value tag */
1076 ipp_value_t *value; /* Current value */
1077
1078
1079 DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)\n",
1080 src, cb, blocking, parent, ipp));
1081 DEBUG_printf(("ippReadIO: ipp->state=%d\n", ipp->state));
1082
1083 if (!src || !ipp)
1084 return (IPP_ERROR);
1085
1086 if ((buffer = ipp_buffer_get()) == NULL)
1087 {
1088 DEBUG_puts("ippReadIO: Unable to get read buffer!");
1089 return (IPP_ERROR);
1090 }
1091
1092 switch (ipp->state)
1093 {
1094 case IPP_IDLE :
1095 ipp->state ++; /* Avoid common problem... */
1096
1097 case IPP_HEADER :
1098 if (parent == NULL)
1099 {
1100 /*
1101 * Get the request header...
1102 */
1103
1104 if ((*cb)(src, buffer, 8) < 8)
1105 {
1106 DEBUG_puts("ippReadIO: Unable to read header!");
1107 ipp_buffer_release(buffer);
1108 return (IPP_ERROR);
1109 }
1110
1111 /*
1112 * Verify the major version number...
1113 */
1114
1115 if (buffer[0] != 1 && buffer[0] != 2)
1116 {
1117 DEBUG_printf(("ippReadIO: version number (%d.%d) is bad.\n",
1118 buffer[0], buffer[1]));
1119 ipp_buffer_release(buffer);
1120 return (IPP_ERROR);
1121 }
1122
1123 /*
1124 * Then copy the request header over...
1125 */
1126
1127 ipp->request.any.version[0] = buffer[0];
1128 ipp->request.any.version[1] = buffer[1];
1129 ipp->request.any.op_status = (buffer[2] << 8) | buffer[3];
1130 ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) |
1131 buffer[6]) << 8) | buffer[7];
1132
1133 DEBUG_printf(("ippReadIO: version=%d.%d\n", buffer[0], buffer[1]));
1134 DEBUG_printf(("ippReadIO: op_status=%04x\n",
1135 ipp->request.any.op_status));
1136 DEBUG_printf(("ippReadIO: request_id=%d\n",
1137 ipp->request.any.request_id));
1138 }
1139
1140 ipp->state = IPP_ATTRIBUTE;
1141 ipp->current = NULL;
1142 ipp->curtag = IPP_TAG_ZERO;
1143 ipp->prev = ipp->last;
1144
1145 /*
1146 * If blocking is disabled, stop here...
1147 */
1148
1149 if (!blocking)
1150 break;
1151
1152 case IPP_ATTRIBUTE :
1153 for (;;)
1154 {
1155 if ((*cb)(src, buffer, 1) < 1)
1156 {
1157 DEBUG_puts("ippReadIO: Callback returned EOF/error");
1158 ipp_buffer_release(buffer);
1159 return (IPP_ERROR);
1160 }
1161
1162 DEBUG_printf(("ippReadIO: ipp->current=%p, ipp->prev=%p\n",
1163 ipp->current, ipp->prev));
1164
1165 /*
1166 * Read this attribute...
1167 */
1168
1169 tag = (ipp_tag_t)buffer[0];
1170
1171 if (tag == IPP_TAG_END)
1172 {
1173 /*
1174 * No more attributes left...
1175 */
1176
1177 DEBUG_puts("ippReadIO: IPP_TAG_END!");
1178
1179 ipp->state = IPP_DATA;
1180 break;
1181 }
1182 else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
1183 {
1184 /*
1185 * Group tag... Set the current group and continue...
1186 */
1187
1188 if (ipp->curtag == tag)
1189 ipp->prev = ippAddSeparator(ipp);
1190 else if (ipp->current)
1191 ipp->prev = ipp->current;
1192
1193 ipp->curtag = tag;
1194 ipp->current = NULL;
1195 DEBUG_printf(("ippReadIO: group tag=%x(%s), ipp->prev=%p\n", tag,
1196 ippTagString(tag), ipp->prev));
1197 continue;
1198 }
1199
1200 DEBUG_printf(("ippReadIO: value tag=%x(%s)\n", tag,
1201 ippTagString(tag)));
1202
1203 /*
1204 * Get the name...
1205 */
1206
1207 if ((*cb)(src, buffer, 2) < 2)
1208 {
1209 DEBUG_puts("ippReadIO: unable to read name length!");
1210 ipp_buffer_release(buffer);
1211 return (IPP_ERROR);
1212 }
1213
1214 n = (buffer[0] << 8) | buffer[1];
1215
1216 if (n >= IPP_BUF_SIZE)
1217 {
1218 DEBUG_printf(("ippReadIO: bad name length %d!\n", n));
1219 ipp_buffer_release(buffer);
1220 return (IPP_ERROR);
1221 }
1222
1223 DEBUG_printf(("ippReadIO: name length=%d\n", n));
1224
1225 if (n == 0 && tag != IPP_TAG_MEMBERNAME &&
1226 tag != IPP_TAG_END_COLLECTION)
1227 {
1228 /*
1229 * More values for current attribute...
1230 */
1231
1232 if (ipp->current == NULL)
1233 {
1234 DEBUG_puts("ippReadIO: Attribute without name and no current");
1235 ipp_buffer_release(buffer);
1236 return (IPP_ERROR);
1237 }
1238
1239 attr = ipp->current;
1240 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_MASK);
1241
1242 /*
1243 * Make sure we aren't adding a new value of a different
1244 * type...
1245 */
1246
1247 if (value_tag == IPP_TAG_ZERO)
1248 {
1249 /*
1250 * Setting the value of a collection member...
1251 */
1252
1253 attr->value_tag = tag;
1254 }
1255 else if ((value_tag >= IPP_TAG_TEXTLANG &&
1256 value_tag <= IPP_TAG_MIMETYPE))
1257 {
1258 /*
1259 * String values can sometimes come across in different
1260 * forms; accept sets of differing values...
1261 */
1262
1263 if ((tag < IPP_TAG_TEXTLANG || tag > IPP_TAG_MIMETYPE) &&
1264 tag != IPP_TAG_NOVALUE)
1265 {
1266 DEBUG_printf(("ippReadIO: 1setOf value tag %x(%s) != %x(%s)\n",
1267 value_tag, ippTagString(value_tag), tag,
1268 ippTagString(tag)));
1269 ipp_buffer_release(buffer);
1270 return (IPP_ERROR);
1271 }
1272 }
1273 else if (value_tag != tag)
1274 {
1275 DEBUG_printf(("ippReadIO: value tag %x(%s) != %x(%s)\n",
1276 value_tag, ippTagString(value_tag), tag,
1277 ippTagString(tag)));
1278 ipp_buffer_release(buffer);
1279 return (IPP_ERROR);
1280 }
1281
1282 /*
1283 * Finally, reallocate the attribute array as needed...
1284 */
1285
1286 if (attr->num_values == 1 ||
1287 (attr->num_values > 0 &&
1288 (attr->num_values & (IPP_MAX_VALUES - 1)) == 0))
1289 {
1290 ipp_attribute_t *temp; /* Pointer to new buffer */
1291
1292
1293 DEBUG_printf(("ippReadIO: reallocating for up to %d values...\n",
1294 attr->num_values + IPP_MAX_VALUES));
1295
1296 /*
1297 * Reallocate memory...
1298 */
1299
1300 if ((temp = realloc(attr, sizeof(ipp_attribute_t) +
1301 (attr->num_values + IPP_MAX_VALUES - 1) *
1302 sizeof(ipp_value_t))) == NULL)
1303 {
1304 DEBUG_puts("ippReadIO: Unable to resize attribute");
1305 ipp_buffer_release(buffer);
1306 return (IPP_ERROR);
1307 }
1308
1309 if (temp != attr)
1310 {
1311 /*
1312 * Reset pointers in the list...
1313 */
1314
1315 if (ipp->prev)
1316 ipp->prev->next = temp;
1317 else
1318 ipp->attrs = temp;
1319
1320 attr = ipp->current = ipp->last = temp;
1321 }
1322 }
1323 }
1324 else if (tag == IPP_TAG_MEMBERNAME)
1325 {
1326 /*
1327 * Name must be length 0!
1328 */
1329
1330 if (n)
1331 {
1332 DEBUG_puts("ippReadIO: member name not empty!");
1333 ipp_buffer_release(buffer);
1334 return (IPP_ERROR);
1335 }
1336
1337 if (ipp->current)
1338 ipp->prev = ipp->current;
1339
1340 attr = ipp->current = _ippAddAttr(ipp, 1);
1341
1342 DEBUG_printf(("ippReadIO: membername, ipp->current=%p, "
1343 "ipp->prev=%p\n", ipp->current, ipp->prev));
1344
1345 attr->group_tag = ipp->curtag;
1346 attr->value_tag = IPP_TAG_ZERO;
1347 attr->num_values = 0;
1348 }
1349 else if (tag != IPP_TAG_END_COLLECTION)
1350 {
1351 /*
1352 * New attribute; read the name and add it...
1353 */
1354
1355 if ((*cb)(src, buffer, n) < n)
1356 {
1357 DEBUG_puts("ippReadIO: unable to read name!");
1358 ipp_buffer_release(buffer);
1359 return (IPP_ERROR);
1360 }
1361
1362 buffer[n] = '\0';
1363
1364 if (ipp->current)
1365 ipp->prev = ipp->current;
1366
1367 if ((attr = ipp->current = _ippAddAttr(ipp, 1)) == NULL)
1368 {
1369 DEBUG_puts("ippReadIO: unable to allocate attribute!");
1370 ipp_buffer_release(buffer);
1371 return (IPP_ERROR);
1372 }
1373
1374 DEBUG_printf(("ippReadIO: name=\"%s\", ipp->current=%p, "
1375 "ipp->prev=%p\n", buffer, ipp->current, ipp->prev));
1376
1377 attr->group_tag = ipp->curtag;
1378 attr->value_tag = tag;
1379 attr->name = _cupsStrAlloc((char *)buffer);
1380 attr->num_values = 0;
1381 }
1382 else
1383 attr = NULL;
1384
1385 if (tag != IPP_TAG_END_COLLECTION)
1386 value = attr->values + attr->num_values;
1387 else
1388 value = NULL;
1389
1390 if ((*cb)(src, buffer, 2) < 2)
1391 {
1392 DEBUG_puts("ippReadIO: unable to read value length!");
1393 ipp_buffer_release(buffer);
1394 return (IPP_ERROR);
1395 }
1396
1397 n = (buffer[0] << 8) | buffer[1];
1398 DEBUG_printf(("ippReadIO: value length=%d\n", n));
1399
1400 switch (tag)
1401 {
1402 case IPP_TAG_INTEGER :
1403 case IPP_TAG_ENUM :
1404 if (n != 4)
1405 {
1406 DEBUG_printf(("ippReadIO: bad value length %d!\n", n));
1407 ipp_buffer_release(buffer);
1408 return (IPP_ERROR);
1409 }
1410
1411 if ((*cb)(src, buffer, 4) < 4)
1412 {
1413 DEBUG_puts("ippReadIO: Unable to read integer value!");
1414 ipp_buffer_release(buffer);
1415 return (IPP_ERROR);
1416 }
1417
1418 n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
1419 buffer[3];
1420
1421 value->integer = n;
1422 break;
1423
1424 case IPP_TAG_BOOLEAN :
1425 if (n != 1)
1426 {
1427 DEBUG_printf(("ippReadIO: bad value length %d!\n", n));
1428 ipp_buffer_release(buffer);
1429 return (IPP_ERROR);
1430 }
1431
1432 if ((*cb)(src, buffer, 1) < 1)
1433 {
1434 DEBUG_puts("ippReadIO: Unable to read boolean value!");
1435 ipp_buffer_release(buffer);
1436 return (IPP_ERROR);
1437 }
1438
1439 value->boolean = buffer[0];
1440 break;
1441
1442 case IPP_TAG_NOVALUE :
1443 case IPP_TAG_NOTSETTABLE :
1444 case IPP_TAG_DELETEATTR :
1445 case IPP_TAG_ADMINDEFINE :
1446 if (attr->value_tag == IPP_TAG_NOVALUE)
1447 {
1448 if (n == 0)
1449 break;
1450
1451 attr->value_tag = IPP_TAG_TEXT;
1452 }
1453
1454 case IPP_TAG_TEXT :
1455 case IPP_TAG_NAME :
1456 case IPP_TAG_KEYWORD :
1457 case IPP_TAG_URI :
1458 case IPP_TAG_URISCHEME :
1459 case IPP_TAG_CHARSET :
1460 case IPP_TAG_LANGUAGE :
1461 case IPP_TAG_MIMETYPE :
1462 if (n >= IPP_BUF_SIZE)
1463 {
1464 DEBUG_printf(("ippReadIO: bad value length %d!\n", n));
1465 ipp_buffer_release(buffer);
1466 return (IPP_ERROR);
1467 }
1468
1469 if ((*cb)(src, buffer, n) < n)
1470 {
1471 DEBUG_puts("ippReadIO: unable to read name!");
1472 ipp_buffer_release(buffer);
1473 return (IPP_ERROR);
1474 }
1475
1476 buffer[n] = '\0';
1477 value->string.text = _cupsStrAlloc((char *)buffer);
1478 DEBUG_printf(("ippReadIO: value=\"%s\"\n",
1479 value->string.text));
1480 break;
1481
1482 case IPP_TAG_DATE :
1483 if (n != 11)
1484 {
1485 DEBUG_printf(("ippReadIO: bad value length %d!\n", n));
1486 ipp_buffer_release(buffer);
1487 return (IPP_ERROR);
1488 }
1489
1490 if ((*cb)(src, value->date, 11) < 11)
1491 {
1492 DEBUG_puts("ippReadIO: Unable to date integer value!");
1493 ipp_buffer_release(buffer);
1494 return (IPP_ERROR);
1495 }
1496 break;
1497
1498 case IPP_TAG_RESOLUTION :
1499 if (n != 9)
1500 {
1501 DEBUG_printf(("ippReadIO: bad value length %d!\n", n));
1502 ipp_buffer_release(buffer);
1503 return (IPP_ERROR);
1504 }
1505
1506 if ((*cb)(src, buffer, 9) < 9)
1507 {
1508 DEBUG_puts("ippReadIO: Unable to read resolution value!");
1509 ipp_buffer_release(buffer);
1510 return (IPP_ERROR);
1511 }
1512
1513 value->resolution.xres =
1514 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
1515 buffer[3];
1516 value->resolution.yres =
1517 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
1518 buffer[7];
1519 value->resolution.units =
1520 (ipp_res_t)buffer[8];
1521 break;
1522
1523 case IPP_TAG_RANGE :
1524 if (n != 8)
1525 {
1526 DEBUG_printf(("ippReadIO: bad value length %d!\n", n));
1527 ipp_buffer_release(buffer);
1528 return (IPP_ERROR);
1529 }
1530
1531 if ((*cb)(src, buffer, 8) < 8)
1532 {
1533 DEBUG_puts("ippReadIO: Unable to read range value!");
1534 ipp_buffer_release(buffer);
1535 return (IPP_ERROR);
1536 }
1537
1538 value->range.lower =
1539 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
1540 buffer[3];
1541 value->range.upper =
1542 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
1543 buffer[7];
1544 break;
1545
1546 case IPP_TAG_TEXTLANG :
1547 case IPP_TAG_NAMELANG :
1548 if (n >= IPP_BUF_SIZE || n < 4)
1549 {
1550 DEBUG_printf(("ippReadIO: bad value length %d!\n", n));
1551 ipp_buffer_release(buffer);
1552 return (IPP_ERROR);
1553 }
1554
1555 if ((*cb)(src, buffer, n) < n)
1556 {
1557 DEBUG_puts("ippReadIO: Unable to read string w/language value!");
1558 ipp_buffer_release(buffer);
1559 return (IPP_ERROR);
1560 }
1561
1562 bufptr = buffer;
1563
1564 /*
1565 * text-with-language and name-with-language are composite
1566 * values:
1567 *
1568 * charset-length
1569 * charset
1570 * text-length
1571 * text
1572 */
1573
1574 n = (bufptr[0] << 8) | bufptr[1];
1575
1576 if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) ||
1577 n >= sizeof(string))
1578 {
1579 DEBUG_printf(("ippReadIO: bad value length %d!\n", n));
1580 ipp_buffer_release(buffer);
1581 return (IPP_ERROR);
1582 }
1583
1584 memcpy(string, bufptr + 2, n);
1585 string[n] = '\0';
1586
1587 value->string.charset = _cupsStrAlloc((char *)string);
1588
1589 bufptr += 2 + n;
1590 n = (bufptr[0] << 8) | bufptr[1];
1591
1592 if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE))
1593 {
1594 DEBUG_printf(("ippReadIO: bad value length %d!\n", n));
1595 ipp_buffer_release(buffer);
1596 return (IPP_ERROR);
1597 }
1598
1599 bufptr[2 + n] = '\0';
1600 value->string.text = _cupsStrAlloc((char *)bufptr + 2);
1601 break;
1602
1603 case IPP_TAG_BEGIN_COLLECTION :
1604 /*
1605 * Oh, boy, here comes a collection value, so read it...
1606 */
1607
1608 value->collection = ippNew();
1609
1610 if (n > 0)
1611 {
1612 DEBUG_puts("ippReadIO: begCollection tag with value length "
1613 "> 0!");
1614 ipp_buffer_release(buffer);
1615 return (IPP_ERROR);
1616 }
1617
1618 if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_ERROR)
1619 {
1620 DEBUG_puts("ippReadIO: Unable to read collection value!");
1621 ipp_buffer_release(buffer);
1622 return (IPP_ERROR);
1623 }
1624 break;
1625
1626 case IPP_TAG_END_COLLECTION :
1627 ipp_buffer_release(buffer);
1628
1629 if (n > 0)
1630 {
1631 DEBUG_puts("ippReadIO: endCollection tag with value length "
1632 "> 0!");
1633 return (IPP_ERROR);
1634 }
1635
1636 DEBUG_puts("ippReadIO: endCollection tag...");
1637 return (ipp->state = IPP_DATA);
1638
1639 case IPP_TAG_MEMBERNAME :
1640 /*
1641 * The value the name of the member in the collection, which
1642 * we need to carry over...
1643 */
1644
1645 if (n >= IPP_BUF_SIZE)
1646 {
1647 DEBUG_printf(("ippReadIO: bad value length %d!\n", n));
1648 ipp_buffer_release(buffer);
1649 return (IPP_ERROR);
1650 }
1651
1652 if ((*cb)(src, buffer, n) < n)
1653 {
1654 DEBUG_puts("ippReadIO: Unable to read member name value!");
1655 ipp_buffer_release(buffer);
1656 return (IPP_ERROR);
1657 }
1658
1659 buffer[n] = '\0';
1660 attr->name = _cupsStrAlloc((char *)buffer);
1661
1662 /*
1663 * Since collection members are encoded differently than
1664 * regular attributes, make sure we don't start with an
1665 * empty value...
1666 */
1667
1668 attr->num_values --;
1669
1670 DEBUG_printf(("ippReadIO: member name=\"%s\"\n", attr->name));
1671 break;
1672
1673 default : /* Other unsupported values */
1674 if (n > IPP_MAX_LENGTH)
1675 {
1676 DEBUG_printf(("ippReadIO: bad value length %d!\n", n));
1677 ipp_buffer_release(buffer);
1678 return (IPP_ERROR);
1679 }
1680
1681 if (!value)
1682 {
1683 DEBUG_puts("ippReadIO: NULL value!");
1684 ipp_buffer_release(buffer);
1685 return (IPP_ERROR);
1686 }
1687
1688 value->unknown.length = n;
1689 if (n > 0)
1690 {
1691 if ((value->unknown.data = malloc(n)) == NULL)
1692 {
1693 DEBUG_puts("ippReadIO: Unable to allocate value");
1694 ipp_buffer_release(buffer);
1695 return (IPP_ERROR);
1696 }
1697
1698 if ((*cb)(src, value->unknown.data, n) < n)
1699 {
1700 DEBUG_puts("ippReadIO: Unable to read unsupported value!");
1701 ipp_buffer_release(buffer);
1702 return (IPP_ERROR);
1703 }
1704 }
1705 else
1706 value->unknown.data = NULL;
1707 break;
1708 }
1709
1710 attr->num_values ++;
1711
1712 /*
1713 * If blocking is disabled, stop here...
1714 */
1715
1716 if (!blocking)
1717 break;
1718 }
1719 break;
1720
1721 case IPP_DATA :
1722 break;
1723
1724 default :
1725 break; /* anti-compiler-warning-code */
1726 }
1727
1728 DEBUG_printf(("ippReadIO: returning ipp->state=%d!\n", ipp->state));
1729 ipp_buffer_release(buffer);
1730
1731 return (ipp->state);
1732 }
1733
1734
1735 /*
1736 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
1737 */
1738
1739 const ipp_uchar_t * /* O - RFC-1903 date/time data */
1740 ippTimeToDate(time_t t) /* I - UNIX time value */
1741 {
1742 struct tm *unixdate; /* UNIX unixdate/time info */
1743 ipp_uchar_t *date = _cupsGlobals()->ipp_date;
1744 /* RFC-1903 date/time data */
1745
1746
1747 /*
1748 * RFC-1903 date/time format is:
1749 *
1750 * Byte(s) Description
1751 * ------- -----------
1752 * 0-1 Year (0 to 65535)
1753 * 2 Month (1 to 12)
1754 * 3 Day (1 to 31)
1755 * 4 Hours (0 to 23)
1756 * 5 Minutes (0 to 59)
1757 * 6 Seconds (0 to 60, 60 = "leap second")
1758 * 7 Deciseconds (0 to 9)
1759 * 8 +/- UTC
1760 * 9 UTC hours (0 to 11)
1761 * 10 UTC minutes (0 to 59)
1762 */
1763
1764 unixdate = gmtime(&t);
1765 unixdate->tm_year += 1900;
1766
1767 date[0] = unixdate->tm_year >> 8;
1768 date[1] = unixdate->tm_year;
1769 date[2] = unixdate->tm_mon + 1;
1770 date[3] = unixdate->tm_mday;
1771 date[4] = unixdate->tm_hour;
1772 date[5] = unixdate->tm_min;
1773 date[6] = unixdate->tm_sec;
1774 date[7] = 0;
1775 date[8] = '+';
1776 date[9] = 0;
1777 date[10] = 0;
1778
1779 return (date);
1780 }
1781
1782
1783 /*
1784 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
1785 */
1786
1787 ipp_state_t /* O - Current state */
1788 ippWrite(http_t *http, /* I - HTTP connection */
1789 ipp_t *ipp) /* I - IPP data */
1790 {
1791 DEBUG_printf(("ippWrite(http=%p, ipp=%p)\n", http, ipp));
1792
1793 if (!http)
1794 return (IPP_ERROR);
1795
1796 return (ippWriteIO(http, (ipp_iocb_t)httpWrite2,
1797 http->blocking, NULL, ipp));
1798 }
1799
1800
1801 /*
1802 * 'ippWriteFile()' - Write data for an IPP message to a file.
1803 *
1804 * @since CUPS 1.1.19/Mac OS X 10.3@
1805 */
1806
1807 ipp_state_t /* O - Current state */
1808 ippWriteFile(int fd, /* I - HTTP data */
1809 ipp_t *ipp) /* I - IPP data */
1810 {
1811 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)\n", fd, ipp));
1812
1813 ipp->state = IPP_IDLE;
1814
1815 return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp));
1816 }
1817
1818
1819 /*
1820 * 'ippWriteIO()' - Write data for an IPP message.
1821 *
1822 * @since CUPS 1.2/Mac OS X 10.5@
1823 */
1824
1825 ipp_state_t /* O - Current state */
1826 ippWriteIO(void *dst, /* I - Destination */
1827 ipp_iocb_t cb, /* I - Write callback function */
1828 int blocking, /* I - Use blocking IO? */
1829 ipp_t *parent, /* I - Parent IPP message */
1830 ipp_t *ipp) /* I - IPP data */
1831 {
1832 int i; /* Looping var */
1833 int n; /* Length of data */
1834 unsigned char *buffer, /* Data buffer */
1835 *bufptr; /* Pointer into buffer */
1836 ipp_attribute_t *attr; /* Current attribute */
1837 ipp_value_t *value; /* Current value */
1838
1839
1840 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)\n",
1841 dst, cb, blocking, parent, ipp));
1842
1843 if (!dst || !ipp)
1844 return (IPP_ERROR);
1845
1846 if ((buffer = ipp_buffer_get()) == NULL)
1847 {
1848 DEBUG_puts("ippWriteIO: Unable to get write buffer");
1849 return (IPP_ERROR);
1850 }
1851
1852 switch (ipp->state)
1853 {
1854 case IPP_IDLE :
1855 ipp->state ++; /* Avoid common problem... */
1856
1857 case IPP_HEADER :
1858 if (parent == NULL)
1859 {
1860 /*
1861 * Send the request header:
1862 *
1863 * Version = 2 bytes
1864 * Operation/Status Code = 2 bytes
1865 * Request ID = 4 bytes
1866 * Total = 8 bytes
1867 */
1868
1869 bufptr = buffer;
1870
1871 *bufptr++ = ipp->request.any.version[0];
1872 *bufptr++ = ipp->request.any.version[1];
1873 *bufptr++ = ipp->request.any.op_status >> 8;
1874 *bufptr++ = ipp->request.any.op_status;
1875 *bufptr++ = ipp->request.any.request_id >> 24;
1876 *bufptr++ = ipp->request.any.request_id >> 16;
1877 *bufptr++ = ipp->request.any.request_id >> 8;
1878 *bufptr++ = ipp->request.any.request_id;
1879
1880 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
1881 {
1882 DEBUG_puts("ippWriteIO: Could not write IPP header...");
1883 ipp_buffer_release(buffer);
1884 return (IPP_ERROR);
1885 }
1886 }
1887
1888 /*
1889 * Reset the state engine to point to the first attribute
1890 * in the request/response, with no current group.
1891 */
1892
1893 ipp->state = IPP_ATTRIBUTE;
1894 ipp->current = ipp->attrs;
1895 ipp->curtag = IPP_TAG_ZERO;
1896
1897 DEBUG_printf(("ippWriteIO: version=%d.%d\n", buffer[0], buffer[1]));
1898 DEBUG_printf(("ippWriteIO: op_status=%04x\n",
1899 ipp->request.any.op_status));
1900 DEBUG_printf(("ippWriteIO: request_id=%d\n",
1901 ipp->request.any.request_id));
1902
1903 /*
1904 * If blocking is disabled, stop here...
1905 */
1906
1907 if (!blocking)
1908 break;
1909
1910 case IPP_ATTRIBUTE :
1911 while (ipp->current != NULL)
1912 {
1913 /*
1914 * Write this attribute...
1915 */
1916
1917 bufptr = buffer;
1918 attr = ipp->current;
1919
1920 ipp->current = ipp->current->next;
1921
1922 if (ipp->curtag != attr->group_tag && parent == NULL)
1923 {
1924 /*
1925 * Send a group tag byte...
1926 */
1927
1928 ipp->curtag = attr->group_tag;
1929
1930 if (attr->group_tag == IPP_TAG_ZERO)
1931 continue;
1932
1933 DEBUG_printf(("ippWriteIO: wrote group tag=%x(%s)\n",
1934 attr->group_tag, ippTagString(attr->group_tag)));
1935 *bufptr++ = attr->group_tag;
1936 }
1937 else if (attr->group_tag == IPP_TAG_ZERO)
1938 continue;
1939
1940 /*
1941 * Write the attribute tag and name. The current implementation
1942 * does not support the extension value tags above 0x7f, so all
1943 * value tags are 1 byte.
1944 *
1945 * The attribute name length does not include the trailing nul
1946 * character in the source string.
1947 *
1948 * Collection values (parent != NULL) are written differently...
1949 */
1950
1951 if (parent == NULL)
1952 {
1953 /*
1954 * Get the length of the attribute name, and make sure it won't
1955 * overflow the buffer...
1956 */
1957
1958 if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 4))
1959 {
1960 DEBUG_printf(("ippWriteIO: Attribute name too long (%d)\n", n));
1961 ipp_buffer_release(buffer);
1962 return (IPP_ERROR);
1963 }
1964
1965 /*
1966 * Write the value tag, name length, and name string...
1967 */
1968
1969 DEBUG_printf(("ippWriteIO: writing value tag=%x(%s)\n",
1970 attr->value_tag, ippTagString(attr->value_tag)));
1971 DEBUG_printf(("ippWriteIO: writing name=%d,\"%s\"\n", n,
1972 attr->name));
1973
1974 *bufptr++ = attr->value_tag;
1975 *bufptr++ = n >> 8;
1976 *bufptr++ = n;
1977 memcpy(bufptr, attr->name, n);
1978 bufptr += n;
1979 }
1980 else
1981 {
1982 /*
1983 * Get the length of the attribute name, and make sure it won't
1984 * overflow the buffer...
1985 */
1986
1987 if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 7))
1988 {
1989 DEBUG_printf(("ippWriteIO: Attribute name too long (%d)\n", n));
1990 ipp_buffer_release(buffer);
1991 return (IPP_ERROR);
1992 }
1993
1994 /*
1995 * Write the member name tag, name length, name string, value tag,
1996 * and empty name for the collection member attribute...
1997 */
1998
1999 DEBUG_printf(("ippWriteIO: writing value tag=%x(memberName)\n",
2000 IPP_TAG_MEMBERNAME));
2001 DEBUG_printf(("ippWriteIO: writing name=%d,\"%s\"\n", n,
2002 attr->name));
2003 DEBUG_printf(("ippWriteIO: writing value tag=%x(%s)\n",
2004 attr->value_tag, ippTagString(attr->value_tag)));
2005 DEBUG_puts("ippWriteIO: writing name=0,\"\"\n");
2006
2007 *bufptr++ = IPP_TAG_MEMBERNAME;
2008 *bufptr++ = 0;
2009 *bufptr++ = 0;
2010 *bufptr++ = n >> 8;
2011 *bufptr++ = n;
2012 memcpy(bufptr, attr->name, n);
2013 bufptr += n;
2014
2015 *bufptr++ = attr->value_tag;
2016 *bufptr++ = 0;
2017 *bufptr++ = 0;
2018 }
2019
2020 /*
2021 * Now write the attribute value(s)...
2022 */
2023
2024 switch (attr->value_tag & ~IPP_TAG_COPY)
2025 {
2026 case IPP_TAG_INTEGER :
2027 case IPP_TAG_ENUM :
2028 for (i = 0, value = attr->values;
2029 i < attr->num_values;
2030 i ++, value ++)
2031 {
2032 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 9)
2033 {
2034 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2035 {
2036 DEBUG_puts("ippWriteIO: Could not write IPP "
2037 "attribute...");
2038 ipp_buffer_release(buffer);
2039 return (IPP_ERROR);
2040 }
2041
2042 bufptr = buffer;
2043 }
2044
2045 if (i)
2046 {
2047 /*
2048 * Arrays and sets are done by sending additional
2049 * values with a zero-length name...
2050 */
2051
2052 *bufptr++ = attr->value_tag;
2053 *bufptr++ = 0;
2054 *bufptr++ = 0;
2055 }
2056
2057 /*
2058 * Integers and enumerations are both 4-byte signed
2059 * (twos-complement) values.
2060 *
2061 * Put the 2-byte length and 4-byte value into the buffer...
2062 */
2063
2064 *bufptr++ = 0;
2065 *bufptr++ = 4;
2066 *bufptr++ = value->integer >> 24;
2067 *bufptr++ = value->integer >> 16;
2068 *bufptr++ = value->integer >> 8;
2069 *bufptr++ = value->integer;
2070 }
2071 break;
2072
2073 case IPP_TAG_BOOLEAN :
2074 for (i = 0, value = attr->values;
2075 i < attr->num_values;
2076 i ++, value ++)
2077 {
2078 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 6)
2079 {
2080 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2081 {
2082 DEBUG_puts("ippWriteIO: Could not write IPP "
2083 "attribute...");
2084 ipp_buffer_release(buffer);
2085 return (IPP_ERROR);
2086 }
2087
2088 bufptr = buffer;
2089 }
2090
2091 if (i)
2092 {
2093 /*
2094 * Arrays and sets are done by sending additional
2095 * values with a zero-length name...
2096 */
2097
2098 *bufptr++ = attr->value_tag;
2099 *bufptr++ = 0;
2100 *bufptr++ = 0;
2101 }
2102
2103 /*
2104 * Boolean values are 1-byte; 0 = false, 1 = true.
2105 *
2106 * Put the 2-byte length and 1-byte value into the buffer...
2107 */
2108
2109 *bufptr++ = 0;
2110 *bufptr++ = 1;
2111 *bufptr++ = value->boolean;
2112 }
2113 break;
2114
2115 case IPP_TAG_TEXT :
2116 case IPP_TAG_NAME :
2117 case IPP_TAG_KEYWORD :
2118 case IPP_TAG_URI :
2119 case IPP_TAG_URISCHEME :
2120 case IPP_TAG_CHARSET :
2121 case IPP_TAG_LANGUAGE :
2122 case IPP_TAG_MIMETYPE :
2123 for (i = 0, value = attr->values;
2124 i < attr->num_values;
2125 i ++, value ++)
2126 {
2127 if (i)
2128 {
2129 /*
2130 * Arrays and sets are done by sending additional
2131 * values with a zero-length name...
2132 */
2133
2134 DEBUG_printf(("ippWriteIO: writing value tag=%x(%s)\n",
2135 attr->value_tag,
2136 ippTagString(attr->value_tag)));
2137 DEBUG_printf(("ippWriteIO: writing name=0,\"\"\n"));
2138
2139 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
2140 {
2141 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2142 {
2143 DEBUG_puts("ippWriteIO: Could not write IPP "
2144 "attribute...");
2145 ipp_buffer_release(buffer);
2146 return (IPP_ERROR);
2147 }
2148
2149 bufptr = buffer;
2150 }
2151
2152 *bufptr++ = attr->value_tag;
2153 *bufptr++ = 0;
2154 *bufptr++ = 0;
2155 }
2156
2157 if (value->string.text != NULL)
2158 n = (int)strlen(value->string.text);
2159 else
2160 n = 0;
2161
2162 if (n > (IPP_BUF_SIZE - 2))
2163 {
2164 DEBUG_printf(("ippWriteIO: String too long (%d)\n", n));
2165 ipp_buffer_release(buffer);
2166 return (IPP_ERROR);
2167 }
2168
2169 DEBUG_printf(("ippWriteIO: writing string=%d,\"%s\"\n", n,
2170 value->string.text));
2171
2172 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
2173 {
2174 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2175 {
2176 DEBUG_puts("ippWriteIO: Could not write IPP "
2177 "attribute...");
2178 ipp_buffer_release(buffer);
2179 return (IPP_ERROR);
2180 }
2181
2182 bufptr = buffer;
2183 }
2184
2185 /*
2186 * All simple strings consist of the 2-byte length and
2187 * character data without the trailing nul normally found
2188 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
2189 * bytes since the 2-byte length is a signed (twos-complement)
2190 * value.
2191 *
2192 * Put the 2-byte length and string characters in the buffer.
2193 */
2194
2195 *bufptr++ = n >> 8;
2196 *bufptr++ = n;
2197
2198 if (n > 0)
2199 {
2200 memcpy(bufptr, value->string.text, n);
2201 bufptr += n;
2202 }
2203 }
2204 break;
2205
2206 case IPP_TAG_DATE :
2207 for (i = 0, value = attr->values;
2208 i < attr->num_values;
2209 i ++, value ++)
2210 {
2211 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 16)
2212 {
2213 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2214 {
2215 DEBUG_puts("ippWriteIO: Could not write IPP "
2216 "attribute...");
2217 ipp_buffer_release(buffer);
2218 return (IPP_ERROR);
2219 }
2220
2221 bufptr = buffer;
2222 }
2223
2224 if (i)
2225 {
2226 /*
2227 * Arrays and sets are done by sending additional
2228 * values with a zero-length name...
2229 */
2230
2231 *bufptr++ = attr->value_tag;
2232 *bufptr++ = 0;
2233 *bufptr++ = 0;
2234 }
2235
2236 /*
2237 * Date values consist of a 2-byte length and an
2238 * 11-byte date/time structure defined by RFC 1903.
2239 *
2240 * Put the 2-byte length and 11-byte date/time
2241 * structure in the buffer.
2242 */
2243
2244 *bufptr++ = 0;
2245 *bufptr++ = 11;
2246 memcpy(bufptr, value->date, 11);
2247 bufptr += 11;
2248 }
2249 break;
2250
2251 case IPP_TAG_RESOLUTION :
2252 for (i = 0, value = attr->values;
2253 i < attr->num_values;
2254 i ++, value ++)
2255 {
2256 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 14)
2257 {
2258 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2259 {
2260 DEBUG_puts("ippWriteIO: Could not write IPP "
2261 "attribute...");
2262 ipp_buffer_release(buffer);
2263 return (IPP_ERROR);
2264 }
2265
2266 bufptr = buffer;
2267 }
2268
2269 if (i)
2270 {
2271 /*
2272 * Arrays and sets are done by sending additional
2273 * values with a zero-length name...
2274 */
2275
2276 *bufptr++ = attr->value_tag;
2277 *bufptr++ = 0;
2278 *bufptr++ = 0;
2279 }
2280
2281 /*
2282 * Resolution values consist of a 2-byte length,
2283 * 4-byte horizontal resolution value, 4-byte vertical
2284 * resolution value, and a 1-byte units value.
2285 *
2286 * Put the 2-byte length and resolution value data
2287 * into the buffer.
2288 */
2289
2290 *bufptr++ = 0;
2291 *bufptr++ = 9;
2292 *bufptr++ = value->resolution.xres >> 24;
2293 *bufptr++ = value->resolution.xres >> 16;
2294 *bufptr++ = value->resolution.xres >> 8;
2295 *bufptr++ = value->resolution.xres;
2296 *bufptr++ = value->resolution.yres >> 24;
2297 *bufptr++ = value->resolution.yres >> 16;
2298 *bufptr++ = value->resolution.yres >> 8;
2299 *bufptr++ = value->resolution.yres;
2300 *bufptr++ = value->resolution.units;
2301 }
2302 break;
2303
2304 case IPP_TAG_RANGE :
2305 for (i = 0, value = attr->values;
2306 i < attr->num_values;
2307 i ++, value ++)
2308 {
2309 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 13)
2310 {
2311 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2312 {
2313 DEBUG_puts("ippWriteIO: Could not write IPP "
2314 "attribute...");
2315 ipp_buffer_release(buffer);
2316 return (IPP_ERROR);
2317 }
2318
2319 bufptr = buffer;
2320 }
2321
2322 if (i)
2323 {
2324 /*
2325 * Arrays and sets are done by sending additional
2326 * values with a zero-length name...
2327 */
2328
2329 *bufptr++ = attr->value_tag;
2330 *bufptr++ = 0;
2331 *bufptr++ = 0;
2332 }
2333
2334 /*
2335 * Range values consist of a 2-byte length,
2336 * 4-byte lower value, and 4-byte upper value.
2337 *
2338 * Put the 2-byte length and range value data
2339 * into the buffer.
2340 */
2341
2342 *bufptr++ = 0;
2343 *bufptr++ = 8;
2344 *bufptr++ = value->range.lower >> 24;
2345 *bufptr++ = value->range.lower >> 16;
2346 *bufptr++ = value->range.lower >> 8;
2347 *bufptr++ = value->range.lower;
2348 *bufptr++ = value->range.upper >> 24;
2349 *bufptr++ = value->range.upper >> 16;
2350 *bufptr++ = value->range.upper >> 8;
2351 *bufptr++ = value->range.upper;
2352 }
2353 break;
2354
2355 case IPP_TAG_TEXTLANG :
2356 case IPP_TAG_NAMELANG :
2357 for (i = 0, value = attr->values;
2358 i < attr->num_values;
2359 i ++, value ++)
2360 {
2361 if (i)
2362 {
2363 /*
2364 * Arrays and sets are done by sending additional
2365 * values with a zero-length name...
2366 */
2367
2368 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
2369 {
2370 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2371 {
2372 DEBUG_puts("ippWriteIO: Could not write IPP "
2373 "attribute...");
2374 ipp_buffer_release(buffer);
2375 return (IPP_ERROR);
2376 }
2377
2378 bufptr = buffer;
2379 }
2380
2381 *bufptr++ = attr->value_tag;
2382 *bufptr++ = 0;
2383 *bufptr++ = 0;
2384 }
2385
2386 /*
2387 * textWithLanguage and nameWithLanguage values consist
2388 * of a 2-byte length for both strings and their
2389 * individual lengths, a 2-byte length for the
2390 * character string, the character string without the
2391 * trailing nul, a 2-byte length for the character
2392 * set string, and the character set string without
2393 * the trailing nul.
2394 */
2395
2396 n = 4;
2397
2398 if (value->string.charset != NULL)
2399 n += (int)strlen(value->string.charset);
2400
2401 if (value->string.text != NULL)
2402 n += (int)strlen(value->string.text);
2403
2404 if (n > (IPP_BUF_SIZE - 2))
2405 {
2406 DEBUG_printf(("ippWriteIO: text/nameWithLanguage value "
2407 "too long (%d)\n", n));
2408 ipp_buffer_release(buffer);
2409 return (IPP_ERROR);
2410 }
2411
2412 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
2413 {
2414 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2415 {
2416 DEBUG_puts("ippWriteIO: Could not write IPP "
2417 "attribute...");
2418 ipp_buffer_release(buffer);
2419 return (IPP_ERROR);
2420 }
2421
2422 bufptr = buffer;
2423 }
2424
2425 /* Length of entire value */
2426 *bufptr++ = n >> 8;
2427 *bufptr++ = n;
2428
2429 /* Length of charset */
2430 if (value->string.charset != NULL)
2431 n = (int)strlen(value->string.charset);
2432 else
2433 n = 0;
2434
2435 *bufptr++ = n >> 8;
2436 *bufptr++ = n;
2437
2438 /* Charset */
2439 if (n > 0)
2440 {
2441 memcpy(bufptr, value->string.charset, n);
2442 bufptr += n;
2443 }
2444
2445 /* Length of text */
2446 if (value->string.text != NULL)
2447 n = (int)strlen(value->string.text);
2448 else
2449 n = 0;
2450
2451 *bufptr++ = n >> 8;
2452 *bufptr++ = n;
2453
2454 /* Text */
2455 if (n > 0)
2456 {
2457 memcpy(bufptr, value->string.text, n);
2458 bufptr += n;
2459 }
2460 }
2461 break;
2462
2463 case IPP_TAG_BEGIN_COLLECTION :
2464 for (i = 0, value = attr->values;
2465 i < attr->num_values;
2466 i ++, value ++)
2467 {
2468 /*
2469 * Collections are written with the begin-collection
2470 * tag first with a value of 0 length, followed by the
2471 * attributes in the collection, then the end-collection
2472 * value...
2473 */
2474
2475 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 5)
2476 {
2477 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2478 {
2479 DEBUG_puts("ippWriteIO: Could not write IPP "
2480 "attribute...");
2481 ipp_buffer_release(buffer);
2482 return (IPP_ERROR);
2483 }
2484
2485 bufptr = buffer;
2486 }
2487
2488 if (i)
2489 {
2490 /*
2491 * Arrays and sets are done by sending additional
2492 * values with a zero-length name...
2493 */
2494
2495 *bufptr++ = attr->value_tag;
2496 *bufptr++ = 0;
2497 *bufptr++ = 0;
2498 }
2499
2500 /*
2501 * Write a data length of 0 and flush the buffer...
2502 */
2503
2504 *bufptr++ = 0;
2505 *bufptr++ = 0;
2506
2507 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2508 {
2509 DEBUG_puts("ippWriteIO: Could not write IPP "
2510 "attribute...");
2511 ipp_buffer_release(buffer);
2512 return (IPP_ERROR);
2513 }
2514
2515 bufptr = buffer;
2516
2517 /*
2518 * Then write the collection attribute...
2519 */
2520
2521 value->collection->state = IPP_IDLE;
2522
2523 if (ippWriteIO(dst, cb, 1, ipp,
2524 value->collection) == IPP_ERROR)
2525 {
2526 DEBUG_puts("ippWriteIO: Unable to write collection value");
2527 ipp_buffer_release(buffer);
2528 return (IPP_ERROR);
2529 }
2530 }
2531 break;
2532
2533 default :
2534 for (i = 0, value = attr->values;
2535 i < attr->num_values;
2536 i ++, value ++)
2537 {
2538 if (i)
2539 {
2540 /*
2541 * Arrays and sets are done by sending additional
2542 * values with a zero-length name...
2543 */
2544
2545 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
2546 {
2547 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2548 {
2549 DEBUG_puts("ippWriteIO: Could not write IPP "
2550 "attribute...");
2551 ipp_buffer_release(buffer);
2552 return (IPP_ERROR);
2553 }
2554
2555 bufptr = buffer;
2556 }
2557
2558 *bufptr++ = attr->value_tag;
2559 *bufptr++ = 0;
2560 *bufptr++ = 0;
2561 }
2562
2563 /*
2564 * An unknown value might some new value that a
2565 * vendor has come up with. It consists of a
2566 * 2-byte length and the bytes in the unknown
2567 * value buffer.
2568 */
2569
2570 n = value->unknown.length;
2571
2572 if (n > (IPP_BUF_SIZE - 2))
2573 {
2574 DEBUG_printf(("ippWriteIO: Data length too long (%d)\n",
2575 n));
2576 ipp_buffer_release(buffer);
2577 return (IPP_ERROR);
2578 }
2579
2580 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
2581 {
2582 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2583 {
2584 DEBUG_puts("ippWriteIO: Could not write IPP "
2585 "attribute...");
2586 ipp_buffer_release(buffer);
2587 return (IPP_ERROR);
2588 }
2589
2590 bufptr = buffer;
2591 }
2592
2593 /* Length of unknown value */
2594 *bufptr++ = n >> 8;
2595 *bufptr++ = n;
2596
2597 /* Value */
2598 if (n > 0)
2599 {
2600 memcpy(bufptr, value->unknown.data, n);
2601 bufptr += n;
2602 }
2603 }
2604 break;
2605 }
2606
2607 /*
2608 * Write the data out...
2609 */
2610
2611 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2612 {
2613 DEBUG_puts("ippWriteIO: Could not write IPP attribute...");
2614 ipp_buffer_release(buffer);
2615 return (IPP_ERROR);
2616 }
2617
2618 DEBUG_printf(("ippWriteIO: wrote %d bytes\n",
2619 (int)(bufptr - buffer)));
2620
2621 /*
2622 * If blocking is disabled, stop here...
2623 */
2624
2625 if (!blocking)
2626 break;
2627 }
2628
2629 if (ipp->current == NULL)
2630 {
2631 /*
2632 * Done with all of the attributes; add the end-of-attributes
2633 * tag or end-collection attribute...
2634 */
2635
2636 if (parent == NULL)
2637 {
2638 buffer[0] = IPP_TAG_END;
2639 n = 1;
2640 }
2641 else
2642 {
2643 buffer[0] = IPP_TAG_END_COLLECTION;
2644 buffer[1] = 0; /* empty name */
2645 buffer[2] = 0;
2646 buffer[3] = 0; /* empty value */
2647 buffer[4] = 0;
2648 n = 5;
2649 }
2650
2651 if ((*cb)(dst, buffer, n) < 0)
2652 {
2653 DEBUG_puts("ippWriteIO: Could not write IPP end-tag...");
2654 ipp_buffer_release(buffer);
2655 return (IPP_ERROR);
2656 }
2657
2658 ipp->state = IPP_DATA;
2659 }
2660 break;
2661
2662 case IPP_DATA :
2663 break;
2664
2665 default :
2666 break; /* anti-compiler-warning-code */
2667 }
2668
2669 ipp_buffer_release(buffer);
2670
2671 return (ipp->state);
2672 }
2673
2674
2675 /*
2676 * '_ippAddAttr()' - Add a new attribute to the request.
2677 */
2678
2679 ipp_attribute_t * /* O - New attribute */
2680 _ippAddAttr(ipp_t *ipp, /* I - IPP message */
2681 int num_values) /* I - Number of values */
2682 {
2683 ipp_attribute_t *attr; /* New attribute */
2684
2685
2686 DEBUG_printf(("_ippAddAttr(ipp=%p, num_values=%d)\n", ipp, num_values));
2687
2688 if (!ipp || num_values < 0)
2689 return (NULL);
2690
2691 attr = calloc(sizeof(ipp_attribute_t) +
2692 (num_values - 1) * sizeof(ipp_value_t), 1);
2693
2694 if (attr != NULL)
2695 {
2696 attr->num_values = num_values;
2697
2698 if (ipp->last == NULL)
2699 ipp->attrs = attr;
2700 else
2701 ipp->last->next = attr;
2702
2703 ipp->last = attr;
2704 }
2705
2706 DEBUG_printf(("_ippAddAttr(): %p\n", attr));
2707
2708 return (attr);
2709 }
2710
2711
2712 /*
2713 * '_ippFreeAttr()' - Free an attribute.
2714 */
2715
2716 void
2717 _ippFreeAttr(ipp_attribute_t *attr) /* I - Attribute to free */
2718 {
2719 int i; /* Looping var */
2720 ipp_value_t *value; /* Current value */
2721
2722
2723 DEBUG_printf(("_ippFreeAttr(attr=%p)\n", attr));
2724
2725 switch (attr->value_tag)
2726 {
2727 case IPP_TAG_TEXT :
2728 case IPP_TAG_NAME :
2729 case IPP_TAG_KEYWORD :
2730 case IPP_TAG_URI :
2731 case IPP_TAG_URISCHEME :
2732 case IPP_TAG_CHARSET :
2733 case IPP_TAG_LANGUAGE :
2734 case IPP_TAG_MIMETYPE :
2735 for (i = 0, value = attr->values;
2736 i < attr->num_values;
2737 i ++, value ++)
2738 _cupsStrFree(value->string.text);
2739 break;
2740
2741 case IPP_TAG_TEXTLANG :
2742 case IPP_TAG_NAMELANG :
2743 for (i = 0, value = attr->values;
2744 i < attr->num_values;
2745 i ++, value ++)
2746 {
2747 if (value->string.charset && i == 0)
2748 _cupsStrFree(value->string.charset);
2749 _cupsStrFree(value->string.text);
2750 }
2751 break;
2752
2753 case IPP_TAG_INTEGER :
2754 case IPP_TAG_ENUM :
2755 case IPP_TAG_BOOLEAN :
2756 case IPP_TAG_DATE :
2757 case IPP_TAG_RESOLUTION :
2758 case IPP_TAG_RANGE :
2759 break;
2760
2761 case IPP_TAG_BEGIN_COLLECTION :
2762 for (i = 0, value = attr->values;
2763 i < attr->num_values;
2764 i ++, value ++)
2765 ippDelete(value->collection);
2766 break;
2767
2768 case IPP_TAG_STRING :
2769 for (i = 0, value = attr->values;
2770 i < attr->num_values;
2771 i ++, value ++)
2772 free(value->unknown.data);
2773 break;
2774
2775 default :
2776 if (!((int)attr->value_tag & IPP_TAG_COPY))
2777 {
2778 for (i = 0, value = attr->values;
2779 i < attr->num_values;
2780 i ++, value ++)
2781 if (value->unknown.data)
2782 free(value->unknown.data);
2783 }
2784 break;
2785 }
2786
2787 if (attr->name)
2788 _cupsStrFree(attr->name);
2789
2790 free(attr);
2791 }
2792
2793
2794 /*
2795 * 'ipp_buffer_get()' - Get a read/write buffer.
2796 */
2797
2798 static unsigned char * /* O - Buffer */
2799 ipp_buffer_get(void)
2800 {
2801 _ipp_buffer_t *buffer; /* Current buffer */
2802 _cups_globals_t *cg = _cupsGlobals();
2803 /* Global data */
2804
2805
2806 for (buffer = cg->ipp_buffers; buffer; buffer = buffer->next)
2807 if (!buffer->used)
2808 {
2809 buffer->used = 1;
2810 return (buffer->d);
2811 }
2812
2813 if ((buffer = malloc(sizeof(_ipp_buffer_t))) == NULL)
2814 return (NULL);
2815
2816 buffer->used = 1;
2817 buffer->next = cg->ipp_buffers;
2818 cg->ipp_buffers = buffer;
2819
2820 return (buffer->d);
2821 }
2822
2823
2824 /*
2825 * 'ipp_buffer_release()' - Release a read/write buffer.
2826 */
2827
2828 static void
2829 ipp_buffer_release(unsigned char *b) /* I - Buffer to release */
2830 {
2831 ((_ipp_buffer_t *)b)->used = 0;
2832 }
2833
2834
2835 /*
2836 * 'ipp_length()' - Compute the length of an IPP message or collection value.
2837 */
2838
2839 static size_t /* O - Size of IPP message */
2840 ipp_length(ipp_t *ipp, /* I - IPP message or collection */
2841 int collection) /* I - 1 if a collection, 0 otherwise */
2842 {
2843 int i; /* Looping var */
2844 int bytes; /* Number of bytes */
2845 ipp_attribute_t *attr; /* Current attribute */
2846 ipp_tag_t group; /* Current group */
2847 ipp_value_t *value; /* Current value */
2848
2849
2850 if (ipp == NULL)
2851 return (0);
2852
2853 /*
2854 * Start with 8 bytes for the IPP message header...
2855 */
2856
2857 bytes = collection ? 0 : 8;
2858
2859 /*
2860 * Then add the lengths of each attribute...
2861 */
2862
2863 group = IPP_TAG_ZERO;
2864
2865 for (attr = ipp->attrs; attr != NULL; attr = attr->next)
2866 {
2867 if (attr->group_tag != group && !collection)
2868 {
2869 group = attr->group_tag;
2870 if (group == IPP_TAG_ZERO)
2871 continue;
2872
2873 bytes ++; /* Group tag */
2874 }
2875
2876 if (!attr->name)
2877 continue;
2878
2879 DEBUG_printf(("ipp_length: attr->name=\"%s\", attr->num_values=%d, "
2880 "bytes=%d\n", attr->name, attr->num_values, bytes));
2881
2882 bytes += (int)strlen(attr->name); /* Name */
2883 bytes += attr->num_values; /* Value tag for each value */
2884 bytes += 2 * attr->num_values; /* Name lengths */
2885 bytes += 2 * attr->num_values; /* Value lengths */
2886
2887 if (collection)
2888 bytes += 5; /* Add membername overhead */
2889
2890 switch (attr->value_tag & ~IPP_TAG_COPY)
2891 {
2892 case IPP_TAG_INTEGER :
2893 case IPP_TAG_ENUM :
2894 bytes += 4 * attr->num_values;
2895 break;
2896
2897 case IPP_TAG_BOOLEAN :
2898 bytes += attr->num_values;
2899 break;
2900
2901 case IPP_TAG_TEXT :
2902 case IPP_TAG_NAME :
2903 case IPP_TAG_KEYWORD :
2904 case IPP_TAG_URI :
2905 case IPP_TAG_URISCHEME :
2906 case IPP_TAG_CHARSET :
2907 case IPP_TAG_LANGUAGE :
2908 case IPP_TAG_MIMETYPE :
2909 for (i = 0, value = attr->values;
2910 i < attr->num_values;
2911 i ++, value ++)
2912 if (value->string.text != NULL)
2913 bytes += (int)strlen(value->string.text);
2914 break;
2915
2916 case IPP_TAG_DATE :
2917 bytes += 11 * attr->num_values;
2918 break;
2919
2920 case IPP_TAG_RESOLUTION :
2921 bytes += 9 * attr->num_values;
2922 break;
2923
2924 case IPP_TAG_RANGE :
2925 bytes += 8 * attr->num_values;
2926 break;
2927
2928 case IPP_TAG_TEXTLANG :
2929 case IPP_TAG_NAMELANG :
2930 bytes += 4 * attr->num_values;/* Charset + text length */
2931
2932 for (i = 0, value = attr->values;
2933 i < attr->num_values;
2934 i ++, value ++)
2935 {
2936 if (value->string.charset != NULL)
2937 bytes += (int)strlen(value->string.charset);
2938
2939 if (value->string.text != NULL)
2940 bytes += (int)strlen(value->string.text);
2941 }
2942 break;
2943
2944 case IPP_TAG_BEGIN_COLLECTION :
2945 for (i = 0, value = attr->values;
2946 i < attr->num_values;
2947 i ++, value ++)
2948 bytes += (int)ipp_length(value->collection, 1);
2949 break;
2950
2951 default :
2952 for (i = 0, value = attr->values;
2953 i < attr->num_values;
2954 i ++, value ++)
2955 bytes += value->unknown.length;
2956 break;
2957 }
2958 }
2959
2960 /*
2961 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
2962 * for the "end of collection" tag and return...
2963 */
2964
2965 if (collection)
2966 bytes += 5;
2967 else
2968 bytes ++;
2969
2970 DEBUG_printf(("ipp_length: bytes=%d\n", bytes));
2971
2972 return (bytes);
2973 }
2974
2975
2976 /*
2977 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
2978 */
2979
2980 static ssize_t /* O - Number of bytes read */
2981 ipp_read_http(http_t *http, /* I - Client connection */
2982 ipp_uchar_t *buffer, /* O - Buffer for data */
2983 size_t length) /* I - Total length */
2984 {
2985 int tbytes, /* Total bytes read */
2986 bytes; /* Bytes read this pass */
2987 char len[32]; /* Length string */
2988
2989
2990 DEBUG_printf(("ipp_read_http(http=%p, buffer=%p, length=%d)\n",
2991 http, buffer, (int)length));
2992
2993 /*
2994 * Loop until all bytes are read...
2995 */
2996
2997 for (tbytes = 0, bytes = 0;
2998 tbytes < (int)length;
2999 tbytes += bytes, buffer += bytes)
3000 {
3001 DEBUG_printf(("ipp_read_http: tbytes=%d, http->state=%d\n", tbytes,
3002 http->state));
3003
3004 if (http->state == HTTP_WAITING)
3005 break;
3006
3007 if (http->used > 0 && http->data_encoding == HTTP_ENCODE_LENGTH)
3008 {
3009 /*
3010 * Do "fast read" from HTTP buffer directly...
3011 */
3012
3013 if (http->used > (int)(length - tbytes))
3014 bytes = (int)(length - tbytes);
3015 else
3016 bytes = http->used;
3017
3018 if (bytes == 1)
3019 buffer[0] = http->buffer[0];
3020 else
3021 memcpy(buffer, http->buffer, bytes);
3022
3023 http->used -= bytes;
3024 http->data_remaining -= bytes;
3025
3026 if (http->data_remaining <= INT_MAX)
3027 http->_data_remaining = (int)http->data_remaining;
3028 else
3029 http->_data_remaining = INT_MAX;
3030
3031 if (http->used > 0)
3032 memmove(http->buffer, http->buffer + bytes, http->used);
3033
3034 if (http->data_remaining == 0)
3035 {
3036 if (http->data_encoding == HTTP_ENCODE_CHUNKED)
3037 {
3038 /*
3039 * Get the trailing CR LF after the chunk...
3040 */
3041
3042 if (!httpGets(len, sizeof(len), http))
3043 return (-1);
3044 }
3045
3046 if (http->data_encoding != HTTP_ENCODE_CHUNKED)
3047 {
3048 if (http->state == HTTP_POST_RECV)
3049 http->state ++;
3050 else
3051 http->state = HTTP_WAITING;
3052 }
3053 }
3054 }
3055 else
3056 {
3057 /*
3058 * Wait a maximum of 1 second for data...
3059 */
3060
3061 if (!http->blocking)
3062 {
3063 /*
3064 * Wait up to 10 seconds for more data on non-blocking sockets...
3065 */
3066
3067 if (!httpWait(http, 10000))
3068 {
3069 /*
3070 * Signal no data...
3071 */
3072
3073 bytes = -1;
3074 break;
3075 }
3076 }
3077
3078 if ((bytes = httpRead2(http, (char *)buffer, length - tbytes)) <= 0)
3079 break;
3080 }
3081 }
3082
3083 /*
3084 * Return the number of bytes read...
3085 */
3086
3087 if (tbytes == 0 && bytes < 0)
3088 tbytes = -1;
3089
3090 DEBUG_printf(("ipp_read_http: returning %d bytes...\n", tbytes));
3091
3092 return (tbytes);
3093 }
3094
3095
3096 /*
3097 * 'ipp_read_file()' - Read IPP data from a file.
3098 */
3099
3100 static ssize_t /* O - Number of bytes read */
3101 ipp_read_file(int *fd, /* I - File descriptor */
3102 ipp_uchar_t *buffer, /* O - Read buffer */
3103 size_t length) /* I - Number of bytes to read */
3104 {
3105 #ifdef WIN32
3106 return ((ssize_t)read(*fd, buffer, (unsigned)length));
3107 #else
3108 return (read(*fd, buffer, length));
3109 #endif /* WIN32 */
3110 }
3111
3112
3113 /*
3114 * 'ipp_write_file()' - Write IPP data to a file.
3115 */
3116
3117 static ssize_t /* O - Number of bytes written */
3118 ipp_write_file(int *fd, /* I - File descriptor */
3119 ipp_uchar_t *buffer, /* I - Data to write */
3120 size_t length) /* I - Number of bytes to write */
3121 {
3122 #ifdef WIN32
3123 return ((ssize_t)write(*fd, buffer, (unsigned)length));
3124 #else
3125 return (write(*fd, buffer, length));
3126 #endif /* WIN32 */
3127 }
3128
3129
3130 #ifdef __linux
3131 /*
3132 * The following symbol definitions are provided only for KDE
3133 * compatibility during the CUPS 1.2 testing period and will be
3134 * removed in a future release of CUPS. These are PRIVATE APIs
3135 * from CUPS 1.1.x that the KDE developers chose to use...
3136 */
3137
3138 ipp_attribute_t * /* O - New attribute */
3139 _ipp_add_attr(ipp_t *ipp, /* I - IPP message */
3140 int num_values) /* I - Number of values */
3141 {
3142 return (_ippAddAttr(ipp, num_values));
3143 }
3144
3145 void
3146 _ipp_free_attr(ipp_attribute_t *attr) /* I - Attribute to free */
3147 {
3148 _ippFreeAttr(attr);
3149 }
3150 #endif /* __linux */
3151
3152
3153 /*
3154 * End of "$Id: ipp.c 7847 2008-08-19 04:22:14Z mike $".
3155 */