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