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