]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ipp.c
Merge changes from CUPS 1.5svn-r9352.
[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 *
ba55dc12 6 * Copyright 2007-2010 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
4400e98d 426 if (type == IPP_TAG_LANGUAGE && !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];
516 else if (type == IPP_TAG_LANGUAGE && !strcasecmp(values[i], "C"))
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
933 if (attr->name != NULL && strcasecmp(attr->name, name) == 0 &&
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 {
e07d4801 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 {
e07d4801 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
e07d4801 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 {
e07d4801 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 {
e07d4801 1237 DEBUG_printf(("1ippReadIO: bad name length %d!", n));
1f6f3dbc 1238 ipp_buffer_release(buffer);
ef416fc2 1239 return (IPP_ERROR);
1240 }
1241
e07d4801 1242 DEBUG_printf(("2ippReadIO: name length=%d", n));
ef416fc2 1243
1244 if (n == 0 && tag != IPP_TAG_MEMBERNAME &&
1245 tag != IPP_TAG_END_COLLECTION)
1246 {
1247 /*
1248 * More values for current attribute...
1249 */
1250
1251 if (ipp->current == NULL)
1f6f3dbc 1252 {
e07d4801 1253 DEBUG_puts("1ippReadIO: Attribute without name and no current");
1f6f3dbc 1254 ipp_buffer_release(buffer);
ef416fc2 1255 return (IPP_ERROR);
1f6f3dbc 1256 }
ef416fc2 1257
fa73b229 1258 attr = ipp->current;
1259 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_MASK);
ef416fc2 1260
1261 /*
1262 * Make sure we aren't adding a new value of a different
1263 * type...
1264 */
1265
fa73b229 1266 if (value_tag == IPP_TAG_ZERO)
ef416fc2 1267 {
1268 /*
1269 * Setting the value of a collection member...
1270 */
1271
1272 attr->value_tag = tag;
1273 }
1ff0402e
MS
1274 else if ((value_tag >= IPP_TAG_TEXTLANG &&
1275 value_tag <= IPP_TAG_MIMETYPE))
ef416fc2 1276 {
1277 /*
1278 * String values can sometimes come across in different
1279 * forms; accept sets of differing values...
1280 */
1281
1ff0402e
MS
1282 if ((tag < IPP_TAG_TEXTLANG || tag > IPP_TAG_MIMETYPE) &&
1283 tag != IPP_TAG_NOVALUE)
1284 {
e07d4801 1285 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
1ff0402e
MS
1286 value_tag, ippTagString(value_tag), tag,
1287 ippTagString(tag)));
1f6f3dbc 1288 ipp_buffer_release(buffer);
ef416fc2 1289 return (IPP_ERROR);
1ff0402e 1290 }
ef416fc2 1291 }
fa73b229 1292 else if (value_tag != tag)
1ff0402e 1293 {
e07d4801 1294 DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
1ff0402e
MS
1295 value_tag, ippTagString(value_tag), tag,
1296 ippTagString(tag)));
1f6f3dbc 1297 ipp_buffer_release(buffer);
ef416fc2 1298 return (IPP_ERROR);
1ff0402e 1299 }
ef416fc2 1300
1301 /*
1302 * Finally, reallocate the attribute array as needed...
1303 */
1304
1305 if (attr->num_values == 1 ||
1306 (attr->num_values > 0 &&
1307 (attr->num_values & (IPP_MAX_VALUES - 1)) == 0))
1308 {
1309 ipp_attribute_t *temp; /* Pointer to new buffer */
1310
1311
e07d4801 1312 DEBUG_printf(("2ippReadIO: reallocating for up to %d values...",
ef416fc2 1313 attr->num_values + IPP_MAX_VALUES));
1314
1315 /*
1316 * Reallocate memory...
1317 */
1318
1319 if ((temp = realloc(attr, sizeof(ipp_attribute_t) +
1320 (attr->num_values + IPP_MAX_VALUES - 1) *
1321 sizeof(ipp_value_t))) == NULL)
1f6f3dbc 1322 {
e07d4801 1323 DEBUG_puts("1ippReadIO: Unable to resize attribute");
1f6f3dbc 1324 ipp_buffer_release(buffer);
ef416fc2 1325 return (IPP_ERROR);
1f6f3dbc 1326 }
ef416fc2 1327
1328 if (temp != attr)
1329 {
1330 /*
1331 * Reset pointers in the list...
1332 */
1333
1334 if (ipp->prev)
1335 ipp->prev->next = temp;
1336 else
1337 ipp->attrs = temp;
1338
1339 attr = ipp->current = ipp->last = temp;
1340 }
1341 }
1342 }
1343 else if (tag == IPP_TAG_MEMBERNAME)
1344 {
1345 /*
1346 * Name must be length 0!
1347 */
1348
1349 if (n)
1350 {
e07d4801 1351 DEBUG_puts("1ippReadIO: member name not empty!");
1f6f3dbc 1352 ipp_buffer_release(buffer);
ef416fc2 1353 return (IPP_ERROR);
1354 }
1355
1356 if (ipp->current)
1357 ipp->prev = ipp->current;
1358
757d2cad 1359 attr = ipp->current = _ippAddAttr(ipp, 1);
ef416fc2 1360
e07d4801
MS
1361 DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, "
1362 "ipp->prev=%p", ipp->current, ipp->prev));
ef416fc2 1363
1364 attr->group_tag = ipp->curtag;
1365 attr->value_tag = IPP_TAG_ZERO;
1366 attr->num_values = 0;
1367 }
1368 else if (tag != IPP_TAG_END_COLLECTION)
1369 {
1370 /*
1371 * New attribute; read the name and add it...
1372 */
1373
1374 if ((*cb)(src, buffer, n) < n)
1375 {
e07d4801 1376 DEBUG_puts("1ippReadIO: unable to read name!");
1f6f3dbc 1377 ipp_buffer_release(buffer);
ef416fc2 1378 return (IPP_ERROR);
1379 }
1380
1381 buffer[n] = '\0';
1382
1383 if (ipp->current)
1384 ipp->prev = ipp->current;
1385
91c84a35
MS
1386 if ((attr = ipp->current = _ippAddAttr(ipp, 1)) == NULL)
1387 {
e07d4801 1388 DEBUG_puts("1ippReadIO: unable to allocate attribute!");
1f6f3dbc 1389 ipp_buffer_release(buffer);
91c84a35
MS
1390 return (IPP_ERROR);
1391 }
ef416fc2 1392
e07d4801
MS
1393 DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, "
1394 "ipp->prev=%p", buffer, ipp->current, ipp->prev));
ef416fc2 1395
1396 attr->group_tag = ipp->curtag;
1397 attr->value_tag = tag;
757d2cad 1398 attr->name = _cupsStrAlloc((char *)buffer);
ef416fc2 1399 attr->num_values = 0;
1400 }
1401 else
1402 attr = NULL;
1403
1404 if (tag != IPP_TAG_END_COLLECTION)
1405 value = attr->values + attr->num_values;
1406 else
1407 value = NULL;
1408
1409 if ((*cb)(src, buffer, 2) < 2)
1410 {
e07d4801 1411 DEBUG_puts("1ippReadIO: unable to read value length!");
1f6f3dbc 1412 ipp_buffer_release(buffer);
ef416fc2 1413 return (IPP_ERROR);
1414 }
1415
1416 n = (buffer[0] << 8) | buffer[1];
e07d4801 1417 DEBUG_printf(("2ippReadIO: value length=%d", n));
ef416fc2 1418
1419 switch (tag)
1420 {
1421 case IPP_TAG_INTEGER :
1422 case IPP_TAG_ENUM :
a41f09e2
MS
1423 if (n != 4)
1424 {
e07d4801 1425 DEBUG_printf(("1ippReadIO: bad value length %d!", n));
1f6f3dbc 1426 ipp_buffer_release(buffer);
a41f09e2
MS
1427 return (IPP_ERROR);
1428 }
1429
ef416fc2 1430 if ((*cb)(src, buffer, 4) < 4)
1431 {
e07d4801 1432 DEBUG_puts("1ippReadIO: Unable to read integer value!");
1f6f3dbc 1433 ipp_buffer_release(buffer);
ef416fc2 1434 return (IPP_ERROR);
1435 }
1436
1437 n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
1438 buffer[3];
1439
1440 value->integer = n;
1441 break;
5a738aea 1442
ef416fc2 1443 case IPP_TAG_BOOLEAN :
a41f09e2
MS
1444 if (n != 1)
1445 {
e07d4801 1446 DEBUG_printf(("1ippReadIO: bad value length %d!", n));
1f6f3dbc 1447 ipp_buffer_release(buffer);
a41f09e2
MS
1448 return (IPP_ERROR);
1449 }
1450
ef416fc2 1451 if ((*cb)(src, buffer, 1) < 1)
1452 {
e07d4801 1453 DEBUG_puts("1ippReadIO: Unable to read boolean value!");
1f6f3dbc 1454 ipp_buffer_release(buffer);
ef416fc2 1455 return (IPP_ERROR);
1456 }
1457
1458 value->boolean = buffer[0];
1459 break;
5a738aea 1460
1ff0402e 1461 case IPP_TAG_NOVALUE :
c168a833
MS
1462 case IPP_TAG_NOTSETTABLE :
1463 case IPP_TAG_DELETEATTR :
1464 case IPP_TAG_ADMINDEFINE :
536bc2c6
MS
1465 /*
1466 * These value types are not supposed to have values, however
1467 * some vendors (Brother) do not implement IPP correctly and so
1468 * we need to map non-empty values to text...
1469 */
1470
1471 if (attr->value_tag == tag)
1ff0402e
MS
1472 {
1473 if (n == 0)
1474 break;
1475
1476 attr->value_tag = IPP_TAG_TEXT;
1477 }
1478
ef416fc2 1479 case IPP_TAG_TEXT :
1480 case IPP_TAG_NAME :
1481 case IPP_TAG_KEYWORD :
ef416fc2 1482 case IPP_TAG_URI :
1483 case IPP_TAG_URISCHEME :
1484 case IPP_TAG_CHARSET :
1485 case IPP_TAG_LANGUAGE :
1486 case IPP_TAG_MIMETYPE :
1f6f3dbc 1487 if (n >= IPP_BUF_SIZE)
a41f09e2 1488 {
e07d4801 1489 DEBUG_printf(("1ippReadIO: bad value length %d!", n));
1f6f3dbc 1490 ipp_buffer_release(buffer);
a41f09e2
MS
1491 return (IPP_ERROR);
1492 }
1493
4400e98d 1494 if ((*cb)(src, buffer, n) < n)
ef416fc2 1495 {
e07d4801 1496 DEBUG_puts("1ippReadIO: unable to read name!");
1f6f3dbc 1497 ipp_buffer_release(buffer);
ef416fc2 1498 return (IPP_ERROR);
1499 }
1500
4400e98d 1501 buffer[n] = '\0';
757d2cad 1502 value->string.text = _cupsStrAlloc((char *)buffer);
e07d4801 1503 DEBUG_printf(("2ippReadIO: value=\"%s\"", value->string.text));
ef416fc2 1504 break;
5a738aea 1505
ef416fc2 1506 case IPP_TAG_DATE :
a41f09e2
MS
1507 if (n != 11)
1508 {
e07d4801 1509 DEBUG_printf(("1ippReadIO: bad value length %d!", n));
1f6f3dbc 1510 ipp_buffer_release(buffer);
a41f09e2
MS
1511 return (IPP_ERROR);
1512 }
1513
ef416fc2 1514 if ((*cb)(src, value->date, 11) < 11)
1515 {
e07d4801 1516 DEBUG_puts("1ippReadIO: Unable to read date value!");
1f6f3dbc 1517 ipp_buffer_release(buffer);
ef416fc2 1518 return (IPP_ERROR);
1519 }
1520 break;
5a738aea 1521
ef416fc2 1522 case IPP_TAG_RESOLUTION :
a41f09e2
MS
1523 if (n != 9)
1524 {
e07d4801 1525 DEBUG_printf(("1ippReadIO: bad value length %d!", n));
1f6f3dbc 1526 ipp_buffer_release(buffer);
a41f09e2
MS
1527 return (IPP_ERROR);
1528 }
1529
ef416fc2 1530 if ((*cb)(src, buffer, 9) < 9)
1531 {
e07d4801 1532 DEBUG_puts("1ippReadIO: Unable to read resolution value!");
1f6f3dbc 1533 ipp_buffer_release(buffer);
ef416fc2 1534 return (IPP_ERROR);
1535 }
1536
1537 value->resolution.xres =
1538 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
1539 buffer[3];
1540 value->resolution.yres =
1541 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
1542 buffer[7];
1543 value->resolution.units =
1544 (ipp_res_t)buffer[8];
1545 break;
5a738aea 1546
ef416fc2 1547 case IPP_TAG_RANGE :
a41f09e2
MS
1548 if (n != 8)
1549 {
e07d4801 1550 DEBUG_printf(("1ippReadIO: bad value length %d!", n));
1f6f3dbc 1551 ipp_buffer_release(buffer);
a41f09e2
MS
1552 return (IPP_ERROR);
1553 }
1554
ef416fc2 1555 if ((*cb)(src, buffer, 8) < 8)
1556 {
e07d4801 1557 DEBUG_puts("1ippReadIO: Unable to read range value!");
1f6f3dbc 1558 ipp_buffer_release(buffer);
ef416fc2 1559 return (IPP_ERROR);
1560 }
1561
1562 value->range.lower =
1563 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
1564 buffer[3];
1565 value->range.upper =
1566 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
1567 buffer[7];
1568 break;
5a738aea 1569
ef416fc2 1570 case IPP_TAG_TEXTLANG :
1571 case IPP_TAG_NAMELANG :
1f6f3dbc 1572 if (n >= IPP_BUF_SIZE || n < 4)
ef416fc2 1573 {
e07d4801 1574 DEBUG_printf(("1ippReadIO: bad value length %d!", n));
1f6f3dbc 1575 ipp_buffer_release(buffer);
ef416fc2 1576 return (IPP_ERROR);
1577 }
1578
1579 if ((*cb)(src, buffer, n) < n)
1580 {
e07d4801
MS
1581 DEBUG_puts("1ippReadIO: Unable to read string w/language "
1582 "value!");
1f6f3dbc 1583 ipp_buffer_release(buffer);
ef416fc2 1584 return (IPP_ERROR);
1585 }
1586
1587 bufptr = buffer;
1588
1589 /*
1590 * text-with-language and name-with-language are composite
1591 * values:
1592 *
1593 * charset-length
1594 * charset
1595 * text-length
1596 * text
1597 */
1598
1599 n = (bufptr[0] << 8) | bufptr[1];
1600
1f6f3dbc 1601 if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) ||
a41f09e2 1602 n >= sizeof(string))
4400e98d 1603 {
e07d4801 1604 DEBUG_printf(("1ippReadIO: bad value length %d!", n));
1f6f3dbc 1605 ipp_buffer_release(buffer);
a41f09e2 1606 return (IPP_ERROR);
4400e98d 1607 }
a41f09e2
MS
1608
1609 memcpy(string, bufptr + 2, n);
1610 string[n] = '\0';
ef416fc2 1611
757d2cad 1612 value->string.charset = _cupsStrAlloc((char *)string);
ef416fc2 1613
1614 bufptr += 2 + n;
1615 n = (bufptr[0] << 8) | bufptr[1];
1616
1f6f3dbc 1617 if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE))
a41f09e2 1618 {
e07d4801 1619 DEBUG_printf(("1ippReadIO: bad value length %d!", n));
1f6f3dbc 1620 ipp_buffer_release(buffer);
a41f09e2
MS
1621 return (IPP_ERROR);
1622 }
1623
4400e98d 1624 bufptr[2 + n] = '\0';
757d2cad 1625 value->string.text = _cupsStrAlloc((char *)bufptr + 2);
ef416fc2 1626 break;
1627
1628 case IPP_TAG_BEGIN_COLLECTION :
1629 /*
1630 * Oh, boy, here comes a collection value, so read it...
1631 */
1632
1633 value->collection = ippNew();
1634
1635 if (n > 0)
1636 {
e07d4801 1637 DEBUG_puts("1ippReadIO: begCollection tag with value length "
1ff0402e 1638 "> 0!");
1f6f3dbc 1639 ipp_buffer_release(buffer);
ef416fc2 1640 return (IPP_ERROR);
1641 }
1642
1643 if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_ERROR)
1644 {
e07d4801 1645 DEBUG_puts("1ippReadIO: Unable to read collection value!");
1f6f3dbc 1646 ipp_buffer_release(buffer);
ef416fc2 1647 return (IPP_ERROR);
1648 }
1649 break;
1650
1651 case IPP_TAG_END_COLLECTION :
1f6f3dbc
MS
1652 ipp_buffer_release(buffer);
1653
ef416fc2 1654 if (n > 0)
1655 {
e07d4801 1656 DEBUG_puts("1ippReadIO: endCollection tag with value length "
1ff0402e 1657 "> 0!");
ef416fc2 1658 return (IPP_ERROR);
1659 }
1660
e07d4801 1661 DEBUG_puts("1ippReadIO: endCollection tag...");
ef416fc2 1662 return (ipp->state = IPP_DATA);
1663
1664 case IPP_TAG_MEMBERNAME :
1665 /*
4400e98d 1666 * The value the name of the member in the collection, which
1667 * we need to carry over...
ef416fc2 1668 */
1669
1f6f3dbc 1670 if (n >= IPP_BUF_SIZE)
a41f09e2 1671 {
e07d4801 1672 DEBUG_printf(("1ippReadIO: bad value length %d!", n));
1f6f3dbc 1673 ipp_buffer_release(buffer);
a41f09e2
MS
1674 return (IPP_ERROR);
1675 }
1676
4400e98d 1677 if ((*cb)(src, buffer, n) < n)
ef416fc2 1678 {
e07d4801 1679 DEBUG_puts("1ippReadIO: Unable to read member name value!");
1f6f3dbc 1680 ipp_buffer_release(buffer);
ef416fc2 1681 return (IPP_ERROR);
1682 }
1683
4400e98d 1684 buffer[n] = '\0';
757d2cad 1685 attr->name = _cupsStrAlloc((char *)buffer);
4400e98d 1686
ef416fc2 1687 /*
1688 * Since collection members are encoded differently than
1689 * regular attributes, make sure we don't start with an
1690 * empty value...
1691 */
1692
1693 attr->num_values --;
1694
e07d4801 1695 DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr->name));
ef416fc2 1696 break;
1697
1698 default : /* Other unsupported values */
91c84a35 1699 if (n > IPP_MAX_LENGTH)
a41f09e2 1700 {
e07d4801 1701 DEBUG_printf(("1ippReadIO: bad value length %d!", n));
1f6f3dbc 1702 ipp_buffer_release(buffer);
a41f09e2
MS
1703 return (IPP_ERROR);
1704 }
1705
1f0275e3
MS
1706 if (!value)
1707 {
e07d4801 1708 DEBUG_puts("1ippReadIO: NULL value!");
1f6f3dbc 1709 ipp_buffer_release(buffer);
1f0275e3
MS
1710 return (IPP_ERROR);
1711 }
1712
ef416fc2 1713 value->unknown.length = n;
1714 if (n > 0)
1715 {
91c84a35
MS
1716 if ((value->unknown.data = malloc(n)) == NULL)
1717 {
e07d4801 1718 DEBUG_puts("1ippReadIO: Unable to allocate value");
1f6f3dbc 1719 ipp_buffer_release(buffer);
91c84a35
MS
1720 return (IPP_ERROR);
1721 }
1722
ef416fc2 1723 if ((*cb)(src, value->unknown.data, n) < n)
1724 {
e07d4801 1725 DEBUG_puts("1ippReadIO: Unable to read unsupported value!");
1f6f3dbc 1726 ipp_buffer_release(buffer);
ef416fc2 1727 return (IPP_ERROR);
1728 }
1729 }
1730 else
1731 value->unknown.data = NULL;
1732 break;
1733 }
1734
1735 attr->num_values ++;
1736
1737 /*
1738 * If blocking is disabled, stop here...
1739 */
1740
1741 if (!blocking)
1742 break;
1743 }
1744 break;
1745
1746 case IPP_DATA :
1747 break;
1748
1749 default :
1750 break; /* anti-compiler-warning-code */
1751 }
1752
e07d4801 1753 DEBUG_printf(("1ippReadIO: returning ipp->state=%d!", ipp->state));
1f6f3dbc 1754 ipp_buffer_release(buffer);
89d46774 1755
ef416fc2 1756 return (ipp->state);
1757}
1758
1759
1760/*
1761 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
1762 */
1763
1764const ipp_uchar_t * /* O - RFC-1903 date/time data */
1765ippTimeToDate(time_t t) /* I - UNIX time value */
1766{
1767 struct tm *unixdate; /* UNIX unixdate/time info */
1768 ipp_uchar_t *date = _cupsGlobals()->ipp_date;
1769 /* RFC-1903 date/time data */
1770
1771
1772 /*
1773 * RFC-1903 date/time format is:
1774 *
1775 * Byte(s) Description
1776 * ------- -----------
1777 * 0-1 Year (0 to 65535)
1778 * 2 Month (1 to 12)
1779 * 3 Day (1 to 31)
1780 * 4 Hours (0 to 23)
1781 * 5 Minutes (0 to 59)
1782 * 6 Seconds (0 to 60, 60 = "leap second")
1783 * 7 Deciseconds (0 to 9)
1784 * 8 +/- UTC
1785 * 9 UTC hours (0 to 11)
1786 * 10 UTC minutes (0 to 59)
1787 */
1788
1789 unixdate = gmtime(&t);
1790 unixdate->tm_year += 1900;
1791
1792 date[0] = unixdate->tm_year >> 8;
1793 date[1] = unixdate->tm_year;
1794 date[2] = unixdate->tm_mon + 1;
1795 date[3] = unixdate->tm_mday;
1796 date[4] = unixdate->tm_hour;
1797 date[5] = unixdate->tm_min;
1798 date[6] = unixdate->tm_sec;
1799 date[7] = 0;
1800 date[8] = '+';
1801 date[9] = 0;
1802 date[10] = 0;
1803
1804 return (date);
1805}
1806
1807
1808/*
1809 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
1810 */
1811
1812ipp_state_t /* O - Current state */
1813ippWrite(http_t *http, /* I - HTTP connection */
1814 ipp_t *ipp) /* I - IPP data */
1815{
e07d4801 1816 DEBUG_printf(("ippWrite(http=%p, ipp=%p)", http, ipp));
ef416fc2 1817
1ff0402e 1818 if (!http)
ef416fc2 1819 return (IPP_ERROR);
1820
e07d4801 1821 return (ippWriteIO(http, (ipp_iocb_t)httpWrite2, http->blocking, NULL, ipp));
ef416fc2 1822}
1823
1824
1825/*
1826 * 'ippWriteFile()' - Write data for an IPP message to a file.
1827 *
426c6a59 1828 * @since CUPS 1.1.19/Mac OS X 10.3@
ef416fc2 1829 */
1830
1831ipp_state_t /* O - Current state */
1832ippWriteFile(int fd, /* I - HTTP data */
1833 ipp_t *ipp) /* I - IPP data */
1834{
e07d4801 1835 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd, ipp));
ef416fc2 1836
1837 ipp->state = IPP_IDLE;
1838
1839 return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp));
1840}
1841
1842
1843/*
1844 * 'ippWriteIO()' - Write data for an IPP message.
1845 *
426c6a59 1846 * @since CUPS 1.2/Mac OS X 10.5@
ef416fc2 1847 */
1848
1849ipp_state_t /* O - Current state */
1850ippWriteIO(void *dst, /* I - Destination */
1851 ipp_iocb_t cb, /* I - Write callback function */
1852 int blocking, /* I - Use blocking IO? */
1853 ipp_t *parent, /* I - Parent IPP message */
1854 ipp_t *ipp) /* I - IPP data */
1855{
1856 int i; /* Looping var */
1857 int n; /* Length of data */
1f6f3dbc 1858 unsigned char *buffer, /* Data buffer */
ef416fc2 1859 *bufptr; /* Pointer into buffer */
1860 ipp_attribute_t *attr; /* Current attribute */
1861 ipp_value_t *value; /* Current value */
1862
1863
e07d4801 1864 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
1ff0402e 1865 dst, cb, blocking, parent, ipp));
ef416fc2 1866
1ff0402e 1867 if (!dst || !ipp)
ef416fc2 1868 return (IPP_ERROR);
1869
1f6f3dbc
MS
1870 if ((buffer = ipp_buffer_get()) == NULL)
1871 {
e07d4801 1872 DEBUG_puts("1ippWriteIO: Unable to get write buffer");
1f6f3dbc
MS
1873 return (IPP_ERROR);
1874 }
1875
ef416fc2 1876 switch (ipp->state)
1877 {
1878 case IPP_IDLE :
1879 ipp->state ++; /* Avoid common problem... */
1880
1881 case IPP_HEADER :
1882 if (parent == NULL)
1883 {
1884 /*
1885 * Send the request header:
1886 *
1887 * Version = 2 bytes
1888 * Operation/Status Code = 2 bytes
1889 * Request ID = 4 bytes
1890 * Total = 8 bytes
1891 */
1892
1893 bufptr = buffer;
1894
1895 *bufptr++ = ipp->request.any.version[0];
1896 *bufptr++ = ipp->request.any.version[1];
1897 *bufptr++ = ipp->request.any.op_status >> 8;
1898 *bufptr++ = ipp->request.any.op_status;
1899 *bufptr++ = ipp->request.any.request_id >> 24;
1900 *bufptr++ = ipp->request.any.request_id >> 16;
1901 *bufptr++ = ipp->request.any.request_id >> 8;
1902 *bufptr++ = ipp->request.any.request_id;
1903
ba55dc12
MS
1904 DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer[0], buffer[1]));
1905 DEBUG_printf(("2ippWriteIO: op_status=%04x",
1906 ipp->request.any.op_status));
1907 DEBUG_printf(("2ippWriteIO: request_id=%d",
1908 ipp->request.any.request_id));
1909
ef416fc2 1910 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
1911 {
e07d4801 1912 DEBUG_puts("1ippWriteIO: Could not write IPP header...");
1f6f3dbc 1913 ipp_buffer_release(buffer);
ef416fc2 1914 return (IPP_ERROR);
1915 }
1916 }
1917
1918 /*
1919 * Reset the state engine to point to the first attribute
1920 * in the request/response, with no current group.
1921 */
1922
1923 ipp->state = IPP_ATTRIBUTE;
1924 ipp->current = ipp->attrs;
1925 ipp->curtag = IPP_TAG_ZERO;
1926
ba55dc12 1927 DEBUG_printf(("1ippWriteIO: ipp->current=%p", ipp->current));
ef416fc2 1928
1929 /*
1930 * If blocking is disabled, stop here...
1931 */
1932
1933 if (!blocking)
1934 break;
1935
1936 case IPP_ATTRIBUTE :
1937 while (ipp->current != NULL)
1938 {
1939 /*
1940 * Write this attribute...
1941 */
1942
1943 bufptr = buffer;
1944 attr = ipp->current;
1945
1946 ipp->current = ipp->current->next;
1947
ba55dc12 1948 if (!parent)
ef416fc2 1949 {
ba55dc12
MS
1950 if (ipp->curtag != attr->group_tag)
1951 {
1952 /*
1953 * Send a group tag byte...
1954 */
ef416fc2 1955
ba55dc12 1956 ipp->curtag = attr->group_tag;
ef416fc2 1957
ba55dc12
MS
1958 if (attr->group_tag == IPP_TAG_ZERO)
1959 continue;
ef416fc2 1960
ba55dc12
MS
1961 DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
1962 attr->group_tag, ippTagString(attr->group_tag)));
1963 *bufptr++ = attr->group_tag;
1964 }
1965 else if (attr->group_tag == IPP_TAG_ZERO)
1966 continue;
ef416fc2 1967 }
ba55dc12
MS
1968
1969 DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr->name,
1970 attr->num_values > 1 ? "1setOf " : "",
1971 ippTagString(attr->value_tag)));
ef416fc2 1972
1973 /*
1974 * Write the attribute tag and name. The current implementation
1975 * does not support the extension value tags above 0x7f, so all
1976 * value tags are 1 byte.
1977 *
1978 * The attribute name length does not include the trailing nul
1979 * character in the source string.
1980 *
1981 * Collection values (parent != NULL) are written differently...
1982 */
1983
1984 if (parent == NULL)
1985 {
1986 /*
1987 * Get the length of the attribute name, and make sure it won't
1988 * overflow the buffer...
1989 */
1990
1f6f3dbc
MS
1991 if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 4))
1992 {
e07d4801 1993 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
1f6f3dbc 1994 ipp_buffer_release(buffer);
ef416fc2 1995 return (IPP_ERROR);
1f6f3dbc 1996 }
ef416fc2 1997
1998 /*
1999 * Write the value tag, name length, and name string...
2000 */
2001
e07d4801 2002 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
1ff0402e 2003 attr->value_tag, ippTagString(attr->value_tag)));
e07d4801 2004 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
1ff0402e 2005 attr->name));
ef416fc2 2006
2007 *bufptr++ = attr->value_tag;
2008 *bufptr++ = n >> 8;
2009 *bufptr++ = n;
2010 memcpy(bufptr, attr->name, n);
2011 bufptr += n;
2012 }
2013 else
2014 {
2015 /*
2016 * Get the length of the attribute name, and make sure it won't
2017 * overflow the buffer...
2018 */
2019
1f6f3dbc
MS
2020 if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 7))
2021 {
e07d4801 2022 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
1f6f3dbc 2023 ipp_buffer_release(buffer);
ef416fc2 2024 return (IPP_ERROR);
1f6f3dbc 2025 }
ef416fc2 2026
2027 /*
2028 * Write the member name tag, name length, name string, value tag,
2029 * and empty name for the collection member attribute...
2030 */
2031
e07d4801 2032 DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
ef416fc2 2033 IPP_TAG_MEMBERNAME));
e07d4801 2034 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
1ff0402e 2035 attr->name));
e07d4801 2036 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
1ff0402e 2037 attr->value_tag, ippTagString(attr->value_tag)));
e07d4801 2038 DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
ef416fc2 2039
2040 *bufptr++ = IPP_TAG_MEMBERNAME;
2041 *bufptr++ = 0;
2042 *bufptr++ = 0;
2043 *bufptr++ = n >> 8;
2044 *bufptr++ = n;
2045 memcpy(bufptr, attr->name, n);
2046 bufptr += n;
2047
2048 *bufptr++ = attr->value_tag;
2049 *bufptr++ = 0;
2050 *bufptr++ = 0;
2051 }
2052
2053 /*
2054 * Now write the attribute value(s)...
2055 */
2056
2057 switch (attr->value_tag & ~IPP_TAG_COPY)
2058 {
2059 case IPP_TAG_INTEGER :
2060 case IPP_TAG_ENUM :
2061 for (i = 0, value = attr->values;
2062 i < attr->num_values;
2063 i ++, value ++)
2064 {
1f6f3dbc 2065 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 9)
ef416fc2 2066 {
2067 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2068 {
e07d4801 2069 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 2070 "attribute...");
1f6f3dbc 2071 ipp_buffer_release(buffer);
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 * Integers and enumerations are both 4-byte signed
2092 * (twos-complement) values.
2093 *
2094 * Put the 2-byte length and 4-byte value into the buffer...
2095 */
2096
2097 *bufptr++ = 0;
2098 *bufptr++ = 4;
2099 *bufptr++ = value->integer >> 24;
2100 *bufptr++ = value->integer >> 16;
2101 *bufptr++ = value->integer >> 8;
2102 *bufptr++ = value->integer;
2103 }
2104 break;
2105
2106 case IPP_TAG_BOOLEAN :
2107 for (i = 0, value = attr->values;
2108 i < attr->num_values;
2109 i ++, value ++)
2110 {
1f6f3dbc 2111 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 6)
ef416fc2 2112 {
2113 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2114 {
e07d4801 2115 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 2116 "attribute...");
1f6f3dbc 2117 ipp_buffer_release(buffer);
ef416fc2 2118 return (IPP_ERROR);
2119 }
2120
2121 bufptr = buffer;
2122 }
2123
2124 if (i)
2125 {
2126 /*
2127 * Arrays and sets are done by sending additional
2128 * values with a zero-length name...
2129 */
2130
2131 *bufptr++ = attr->value_tag;
2132 *bufptr++ = 0;
2133 *bufptr++ = 0;
2134 }
2135
2136 /*
2137 * Boolean values are 1-byte; 0 = false, 1 = true.
2138 *
2139 * Put the 2-byte length and 1-byte value into the buffer...
2140 */
2141
2142 *bufptr++ = 0;
2143 *bufptr++ = 1;
2144 *bufptr++ = value->boolean;
2145 }
2146 break;
2147
2148 case IPP_TAG_TEXT :
2149 case IPP_TAG_NAME :
2150 case IPP_TAG_KEYWORD :
ef416fc2 2151 case IPP_TAG_URI :
2152 case IPP_TAG_URISCHEME :
2153 case IPP_TAG_CHARSET :
2154 case IPP_TAG_LANGUAGE :
2155 case IPP_TAG_MIMETYPE :
2156 for (i = 0, value = attr->values;
2157 i < attr->num_values;
2158 i ++, value ++)
2159 {
2160 if (i)
2161 {
2162 /*
2163 * Arrays and sets are done by sending additional
2164 * values with a zero-length name...
2165 */
2166
e07d4801 2167 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
1ff0402e
MS
2168 attr->value_tag,
2169 ippTagString(attr->value_tag)));
e07d4801 2170 DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
ef416fc2 2171
1f6f3dbc 2172 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
ef416fc2 2173 {
2174 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2175 {
e07d4801 2176 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 2177 "attribute...");
1f6f3dbc 2178 ipp_buffer_release(buffer);
ef416fc2 2179 return (IPP_ERROR);
2180 }
2181
2182 bufptr = buffer;
2183 }
2184
2185 *bufptr++ = attr->value_tag;
2186 *bufptr++ = 0;
2187 *bufptr++ = 0;
2188 }
2189
2190 if (value->string.text != NULL)
2191 n = (int)strlen(value->string.text);
2192 else
2193 n = 0;
2194
1f6f3dbc
MS
2195 if (n > (IPP_BUF_SIZE - 2))
2196 {
e07d4801 2197 DEBUG_printf(("1ippWriteIO: String too long (%d)", n));
1f6f3dbc 2198 ipp_buffer_release(buffer);
ef416fc2 2199 return (IPP_ERROR);
1f6f3dbc 2200 }
ef416fc2 2201
e07d4801 2202 DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n,
ef416fc2 2203 value->string.text));
2204
1f6f3dbc 2205 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
ef416fc2 2206 {
2207 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2208 {
e07d4801 2209 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 2210 "attribute...");
1f6f3dbc 2211 ipp_buffer_release(buffer);
ef416fc2 2212 return (IPP_ERROR);
2213 }
2214
2215 bufptr = buffer;
2216 }
2217
2218 /*
2219 * All simple strings consist of the 2-byte length and
2220 * character data without the trailing nul normally found
a41f09e2 2221 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
ef416fc2 2222 * bytes since the 2-byte length is a signed (twos-complement)
2223 * value.
2224 *
2225 * Put the 2-byte length and string characters in the buffer.
2226 */
2227
2228 *bufptr++ = n >> 8;
2229 *bufptr++ = n;
2230
2231 if (n > 0)
2232 {
2233 memcpy(bufptr, value->string.text, n);
2234 bufptr += n;
2235 }
2236 }
2237 break;
2238
2239 case IPP_TAG_DATE :
2240 for (i = 0, value = attr->values;
2241 i < attr->num_values;
2242 i ++, value ++)
2243 {
1f6f3dbc 2244 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 16)
ef416fc2 2245 {
2246 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2247 {
e07d4801 2248 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 2249 "attribute...");
1f6f3dbc 2250 ipp_buffer_release(buffer);
ef416fc2 2251 return (IPP_ERROR);
2252 }
2253
2254 bufptr = buffer;
2255 }
2256
2257 if (i)
2258 {
2259 /*
2260 * Arrays and sets are done by sending additional
2261 * values with a zero-length name...
2262 */
2263
2264 *bufptr++ = attr->value_tag;
2265 *bufptr++ = 0;
2266 *bufptr++ = 0;
2267 }
2268
2269 /*
2270 * Date values consist of a 2-byte length and an
2271 * 11-byte date/time structure defined by RFC 1903.
2272 *
2273 * Put the 2-byte length and 11-byte date/time
2274 * structure in the buffer.
2275 */
2276
2277 *bufptr++ = 0;
2278 *bufptr++ = 11;
2279 memcpy(bufptr, value->date, 11);
2280 bufptr += 11;
2281 }
2282 break;
2283
2284 case IPP_TAG_RESOLUTION :
2285 for (i = 0, value = attr->values;
2286 i < attr->num_values;
2287 i ++, value ++)
2288 {
1f6f3dbc 2289 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 14)
ef416fc2 2290 {
2291 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2292 {
e07d4801 2293 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 2294 "attribute...");
1f6f3dbc
MS
2295 ipp_buffer_release(buffer);
2296 return (IPP_ERROR);
ef416fc2 2297 }
2298
2299 bufptr = buffer;
2300 }
2301
2302 if (i)
2303 {
2304 /*
2305 * Arrays and sets are done by sending additional
2306 * values with a zero-length name...
2307 */
2308
2309 *bufptr++ = attr->value_tag;
2310 *bufptr++ = 0;
2311 *bufptr++ = 0;
2312 }
2313
2314 /*
2315 * Resolution values consist of a 2-byte length,
2316 * 4-byte horizontal resolution value, 4-byte vertical
2317 * resolution value, and a 1-byte units value.
2318 *
2319 * Put the 2-byte length and resolution value data
2320 * into the buffer.
2321 */
2322
2323 *bufptr++ = 0;
2324 *bufptr++ = 9;
2325 *bufptr++ = value->resolution.xres >> 24;
2326 *bufptr++ = value->resolution.xres >> 16;
2327 *bufptr++ = value->resolution.xres >> 8;
2328 *bufptr++ = value->resolution.xres;
2329 *bufptr++ = value->resolution.yres >> 24;
2330 *bufptr++ = value->resolution.yres >> 16;
2331 *bufptr++ = value->resolution.yres >> 8;
2332 *bufptr++ = value->resolution.yres;
2333 *bufptr++ = value->resolution.units;
2334 }
2335 break;
2336
2337 case IPP_TAG_RANGE :
2338 for (i = 0, value = attr->values;
2339 i < attr->num_values;
2340 i ++, value ++)
2341 {
1f6f3dbc 2342 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 13)
ef416fc2 2343 {
2344 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2345 {
e07d4801 2346 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 2347 "attribute...");
1f6f3dbc 2348 ipp_buffer_release(buffer);
ef416fc2 2349 return (IPP_ERROR);
2350 }
2351
2352 bufptr = buffer;
2353 }
2354
2355 if (i)
2356 {
2357 /*
2358 * Arrays and sets are done by sending additional
2359 * values with a zero-length name...
2360 */
2361
2362 *bufptr++ = attr->value_tag;
2363 *bufptr++ = 0;
2364 *bufptr++ = 0;
2365 }
2366
2367 /*
2368 * Range values consist of a 2-byte length,
2369 * 4-byte lower value, and 4-byte upper value.
2370 *
2371 * Put the 2-byte length and range value data
2372 * into the buffer.
2373 */
2374
2375 *bufptr++ = 0;
2376 *bufptr++ = 8;
2377 *bufptr++ = value->range.lower >> 24;
2378 *bufptr++ = value->range.lower >> 16;
2379 *bufptr++ = value->range.lower >> 8;
2380 *bufptr++ = value->range.lower;
2381 *bufptr++ = value->range.upper >> 24;
2382 *bufptr++ = value->range.upper >> 16;
2383 *bufptr++ = value->range.upper >> 8;
2384 *bufptr++ = value->range.upper;
2385 }
2386 break;
2387
2388 case IPP_TAG_TEXTLANG :
2389 case IPP_TAG_NAMELANG :
2390 for (i = 0, value = attr->values;
2391 i < attr->num_values;
2392 i ++, value ++)
2393 {
2394 if (i)
2395 {
2396 /*
2397 * Arrays and sets are done by sending additional
2398 * values with a zero-length name...
2399 */
2400
1f6f3dbc 2401 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
ef416fc2 2402 {
2403 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2404 {
e07d4801 2405 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 2406 "attribute...");
1f6f3dbc 2407 ipp_buffer_release(buffer);
ef416fc2 2408 return (IPP_ERROR);
2409 }
2410
2411 bufptr = buffer;
2412 }
2413
2414 *bufptr++ = attr->value_tag;
2415 *bufptr++ = 0;
2416 *bufptr++ = 0;
2417 }
2418
2419 /*
2420 * textWithLanguage and nameWithLanguage values consist
2421 * of a 2-byte length for both strings and their
2422 * individual lengths, a 2-byte length for the
2423 * character string, the character string without the
2424 * trailing nul, a 2-byte length for the character
2425 * set string, and the character set string without
2426 * the trailing nul.
2427 */
2428
2429 n = 4;
2430
2431 if (value->string.charset != NULL)
b86bc4cf 2432 n += (int)strlen(value->string.charset);
ef416fc2 2433
2434 if (value->string.text != NULL)
b86bc4cf 2435 n += (int)strlen(value->string.text);
ef416fc2 2436
1f6f3dbc
MS
2437 if (n > (IPP_BUF_SIZE - 2))
2438 {
e07d4801
MS
2439 DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
2440 "too long (%d)", n));
1f6f3dbc 2441 ipp_buffer_release(buffer);
ef416fc2 2442 return (IPP_ERROR);
1f6f3dbc 2443 }
ef416fc2 2444
1f6f3dbc 2445 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
ef416fc2 2446 {
2447 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2448 {
e07d4801 2449 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 2450 "attribute...");
1f6f3dbc 2451 ipp_buffer_release(buffer);
ef416fc2 2452 return (IPP_ERROR);
2453 }
2454
2455 bufptr = buffer;
2456 }
2457
2458 /* Length of entire value */
2459 *bufptr++ = n >> 8;
2460 *bufptr++ = n;
2461
2462 /* Length of charset */
2463 if (value->string.charset != NULL)
2464 n = (int)strlen(value->string.charset);
2465 else
2466 n = 0;
2467
2468 *bufptr++ = n >> 8;
2469 *bufptr++ = n;
2470
2471 /* Charset */
2472 if (n > 0)
2473 {
2474 memcpy(bufptr, value->string.charset, n);
2475 bufptr += n;
2476 }
2477
2478 /* Length of text */
2479 if (value->string.text != NULL)
2480 n = (int)strlen(value->string.text);
2481 else
2482 n = 0;
2483
2484 *bufptr++ = n >> 8;
2485 *bufptr++ = n;
2486
2487 /* Text */
2488 if (n > 0)
2489 {
2490 memcpy(bufptr, value->string.text, n);
2491 bufptr += n;
2492 }
2493 }
2494 break;
2495
2496 case IPP_TAG_BEGIN_COLLECTION :
2497 for (i = 0, value = attr->values;
2498 i < attr->num_values;
2499 i ++, value ++)
2500 {
2501 /*
2502 * Collections are written with the begin-collection
2503 * tag first with a value of 0 length, followed by the
2504 * attributes in the collection, then the end-collection
2505 * value...
2506 */
2507
1f6f3dbc 2508 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 5)
ef416fc2 2509 {
2510 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2511 {
e07d4801 2512 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 2513 "attribute...");
1f6f3dbc 2514 ipp_buffer_release(buffer);
ef416fc2 2515 return (IPP_ERROR);
2516 }
2517
2518 bufptr = buffer;
2519 }
2520
2521 if (i)
2522 {
2523 /*
2524 * Arrays and sets are done by sending additional
2525 * values with a zero-length name...
2526 */
2527
2528 *bufptr++ = attr->value_tag;
2529 *bufptr++ = 0;
2530 *bufptr++ = 0;
2531 }
2532
2533 /*
2534 * Write a data length of 0 and flush the buffer...
2535 */
2536
2537 *bufptr++ = 0;
2538 *bufptr++ = 0;
2539
2540 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2541 {
e07d4801 2542 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 2543 "attribute...");
1f6f3dbc 2544 ipp_buffer_release(buffer);
ef416fc2 2545 return (IPP_ERROR);
2546 }
2547
2548 bufptr = buffer;
2549
2550 /*
2551 * Then write the collection attribute...
2552 */
2553
2554 value->collection->state = IPP_IDLE;
2555
1f6f3dbc
MS
2556 if (ippWriteIO(dst, cb, 1, ipp,
2557 value->collection) == IPP_ERROR)
2558 {
e07d4801 2559 DEBUG_puts("1ippWriteIO: Unable to write collection value");
1f6f3dbc 2560 ipp_buffer_release(buffer);
ef416fc2 2561 return (IPP_ERROR);
1f6f3dbc 2562 }
ef416fc2 2563 }
2564 break;
2565
2566 default :
2567 for (i = 0, value = attr->values;
2568 i < attr->num_values;
2569 i ++, value ++)
2570 {
2571 if (i)
2572 {
2573 /*
2574 * Arrays and sets are done by sending additional
2575 * values with a zero-length name...
2576 */
2577
1f6f3dbc 2578 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
ef416fc2 2579 {
2580 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2581 {
e07d4801 2582 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 2583 "attribute...");
1f6f3dbc 2584 ipp_buffer_release(buffer);
ef416fc2 2585 return (IPP_ERROR);
2586 }
2587
2588 bufptr = buffer;
2589 }
2590
2591 *bufptr++ = attr->value_tag;
2592 *bufptr++ = 0;
2593 *bufptr++ = 0;
2594 }
2595
2596 /*
2597 * An unknown value might some new value that a
2598 * vendor has come up with. It consists of a
2599 * 2-byte length and the bytes in the unknown
2600 * value buffer.
2601 */
2602
2603 n = value->unknown.length;
2604
1f6f3dbc
MS
2605 if (n > (IPP_BUF_SIZE - 2))
2606 {
e07d4801 2607 DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
1f6f3dbc
MS
2608 n));
2609 ipp_buffer_release(buffer);
ef416fc2 2610 return (IPP_ERROR);
1f6f3dbc 2611 }
ef416fc2 2612
1f6f3dbc 2613 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
ef416fc2 2614 {
2615 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2616 {
e07d4801 2617 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 2618 "attribute...");
1f6f3dbc 2619 ipp_buffer_release(buffer);
ef416fc2 2620 return (IPP_ERROR);
2621 }
2622
2623 bufptr = buffer;
2624 }
2625
2626 /* Length of unknown value */
2627 *bufptr++ = n >> 8;
2628 *bufptr++ = n;
2629
2630 /* Value */
2631 if (n > 0)
2632 {
2633 memcpy(bufptr, value->unknown.data, n);
2634 bufptr += n;
2635 }
2636 }
2637 break;
2638 }
2639
2640 /*
2641 * Write the data out...
2642 */
2643
ba55dc12 2644 if (bufptr > buffer)
ef416fc2 2645 {
ba55dc12
MS
2646 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
2647 {
2648 DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
2649 ipp_buffer_release(buffer);
2650 return (IPP_ERROR);
2651 }
ef416fc2 2652
ba55dc12
MS
2653 DEBUG_printf(("2ippWriteIO: wrote %d bytes",
2654 (int)(bufptr - buffer)));
2655 }
ef416fc2 2656
2657 /*
2658 * If blocking is disabled, stop here...
2659 */
2660
2661 if (!blocking)
2662 break;
2663 }
2664
2665 if (ipp->current == NULL)
2666 {
2667 /*
2668 * Done with all of the attributes; add the end-of-attributes
2669 * tag or end-collection attribute...
2670 */
2671
2672 if (parent == NULL)
2673 {
2674 buffer[0] = IPP_TAG_END;
2675 n = 1;
2676 }
2677 else
2678 {
2679 buffer[0] = IPP_TAG_END_COLLECTION;
2680 buffer[1] = 0; /* empty name */
2681 buffer[2] = 0;
2682 buffer[3] = 0; /* empty value */
2683 buffer[4] = 0;
2684 n = 5;
2685 }
2686
2687 if ((*cb)(dst, buffer, n) < 0)
2688 {
e07d4801 2689 DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
1f6f3dbc 2690 ipp_buffer_release(buffer);
ef416fc2 2691 return (IPP_ERROR);
2692 }
2693
2694 ipp->state = IPP_DATA;
2695 }
2696 break;
2697
2698 case IPP_DATA :
2699 break;
2700
2701 default :
2702 break; /* anti-compiler-warning-code */
2703 }
2704
1f6f3dbc
MS
2705 ipp_buffer_release(buffer);
2706
ef416fc2 2707 return (ipp->state);
2708}
2709
2710
2711/*
757d2cad 2712 * '_ippAddAttr()' - Add a new attribute to the request.
ef416fc2 2713 */
2714
2715ipp_attribute_t * /* O - New attribute */
80ca4592 2716_ippAddAttr(ipp_t *ipp, /* I - IPP message */
2717 int num_values) /* I - Number of values */
ef416fc2 2718{
2719 ipp_attribute_t *attr; /* New attribute */
2720
2721
e07d4801 2722 DEBUG_printf(("4_ippAddAttr(ipp=%p, num_values=%d)", ipp, num_values));
ef416fc2 2723
1ff0402e 2724 if (!ipp || num_values < 0)
ef416fc2 2725 return (NULL);
2726
2727 attr = calloc(sizeof(ipp_attribute_t) +
2728 (num_values - 1) * sizeof(ipp_value_t), 1);
2729
ef416fc2 2730 if (attr != NULL)
2731 {
fa73b229 2732 attr->num_values = num_values;
2733
ef416fc2 2734 if (ipp->last == NULL)
2735 ipp->attrs = attr;
2736 else
2737 ipp->last->next = attr;
2738
2739 ipp->last = attr;
2740 }
2741
e07d4801 2742 DEBUG_printf(("5_ippAddAttr: Returning %p", attr));
ef416fc2 2743
2744 return (attr);
2745}
2746
2747
2748/*
757d2cad 2749 * '_ippFreeAttr()' - Free an attribute.
ef416fc2 2750 */
2751
2752void
757d2cad 2753_ippFreeAttr(ipp_attribute_t *attr) /* I - Attribute to free */
ef416fc2 2754{
2755 int i; /* Looping var */
2756 ipp_value_t *value; /* Current value */
2757
2758
e07d4801 2759 DEBUG_printf(("4_ippFreeAttr(attr=%p)", attr));
ef416fc2 2760
2761 switch (attr->value_tag)
2762 {
2763 case IPP_TAG_TEXT :
2764 case IPP_TAG_NAME :
2765 case IPP_TAG_KEYWORD :
ef416fc2 2766 case IPP_TAG_URI :
2767 case IPP_TAG_URISCHEME :
2768 case IPP_TAG_CHARSET :
2769 case IPP_TAG_LANGUAGE :
2770 case IPP_TAG_MIMETYPE :
2771 for (i = 0, value = attr->values;
2772 i < attr->num_values;
2773 i ++, value ++)
757d2cad 2774 _cupsStrFree(value->string.text);
ef416fc2 2775 break;
2776
2777 case IPP_TAG_TEXTLANG :
2778 case IPP_TAG_NAMELANG :
2779 for (i = 0, value = attr->values;
2780 i < attr->num_values;
2781 i ++, value ++)
2782 {
2783 if (value->string.charset && i == 0)
757d2cad 2784 _cupsStrFree(value->string.charset);
2785 _cupsStrFree(value->string.text);
ef416fc2 2786 }
2787 break;
2788
4400e98d 2789 case IPP_TAG_INTEGER :
2790 case IPP_TAG_ENUM :
2791 case IPP_TAG_BOOLEAN :
2792 case IPP_TAG_DATE :
2793 case IPP_TAG_RESOLUTION :
2794 case IPP_TAG_RANGE :
2795 break;
2796
2797 case IPP_TAG_BEGIN_COLLECTION :
2798 for (i = 0, value = attr->values;
2799 i < attr->num_values;
2800 i ++, value ++)
2801 ippDelete(value->collection);
2802 break;
2803
5a738aea
MS
2804 case IPP_TAG_STRING :
2805 for (i = 0, value = attr->values;
2806 i < attr->num_values;
2807 i ++, value ++)
2808 free(value->unknown.data);
2809 break;
2810
ef416fc2 2811 default :
4400e98d 2812 if (!((int)attr->value_tag & IPP_TAG_COPY))
2813 {
2814 for (i = 0, value = attr->values;
2815 i < attr->num_values;
2816 i ++, value ++)
2817 if (value->unknown.data)
2818 free(value->unknown.data);
2819 }
2820 break;
ef416fc2 2821 }
2822
fa73b229 2823 if (attr->name)
757d2cad 2824 _cupsStrFree(attr->name);
ef416fc2 2825
2826 free(attr);
2827}
2828
2829
1f6f3dbc
MS
2830/*
2831 * 'ipp_buffer_get()' - Get a read/write buffer.
2832 */
2833
2834static unsigned char * /* O - Buffer */
2835ipp_buffer_get(void)
2836{
2837 _ipp_buffer_t *buffer; /* Current buffer */
2838 _cups_globals_t *cg = _cupsGlobals();
2839 /* Global data */
2840
2841
2842 for (buffer = cg->ipp_buffers; buffer; buffer = buffer->next)
2843 if (!buffer->used)
2844 {
2845 buffer->used = 1;
2846 return (buffer->d);
2847 }
2848
2849 if ((buffer = malloc(sizeof(_ipp_buffer_t))) == NULL)
2850 return (NULL);
2851
2852 buffer->used = 1;
2853 buffer->next = cg->ipp_buffers;
2854 cg->ipp_buffers = buffer;
2855
2856 return (buffer->d);
2857}
2858
2859
2860/*
2861 * 'ipp_buffer_release()' - Release a read/write buffer.
2862 */
2863
2864static void
2865ipp_buffer_release(unsigned char *b) /* I - Buffer to release */
2866{
2867 ((_ipp_buffer_t *)b)->used = 0;
2868}
2869
2870
ef416fc2 2871/*
2872 * 'ipp_length()' - Compute the length of an IPP message or collection value.
2873 */
2874
2875static size_t /* O - Size of IPP message */
2876ipp_length(ipp_t *ipp, /* I - IPP message or collection */
2877 int collection) /* I - 1 if a collection, 0 otherwise */
2878{
2879 int i; /* Looping var */
2880 int bytes; /* Number of bytes */
2881 ipp_attribute_t *attr; /* Current attribute */
2882 ipp_tag_t group; /* Current group */
2883 ipp_value_t *value; /* Current value */
2884
2885
2886 if (ipp == NULL)
2887 return (0);
2888
2889 /*
2890 * Start with 8 bytes for the IPP message header...
2891 */
2892
2893 bytes = collection ? 0 : 8;
2894
2895 /*
2896 * Then add the lengths of each attribute...
2897 */
2898
2899 group = IPP_TAG_ZERO;
2900
2901 for (attr = ipp->attrs; attr != NULL; attr = attr->next)
2902 {
2903 if (attr->group_tag != group && !collection)
2904 {
2905 group = attr->group_tag;
2906 if (group == IPP_TAG_ZERO)
2907 continue;
2908
2909 bytes ++; /* Group tag */
2910 }
2911
2912 if (!attr->name)
2913 continue;
2914
e07d4801
MS
2915 DEBUG_printf(("9ipp_length: attr->name=\"%s\", attr->num_values=%d, "
2916 "bytes=%d", attr->name, attr->num_values, bytes));
ef416fc2 2917
b86bc4cf 2918 bytes += (int)strlen(attr->name); /* Name */
ef416fc2 2919 bytes += attr->num_values; /* Value tag for each value */
2920 bytes += 2 * attr->num_values; /* Name lengths */
2921 bytes += 2 * attr->num_values; /* Value lengths */
2922
2923 if (collection)
2924 bytes += 5; /* Add membername overhead */
2925
2926 switch (attr->value_tag & ~IPP_TAG_COPY)
2927 {
2928 case IPP_TAG_INTEGER :
2929 case IPP_TAG_ENUM :
2930 bytes += 4 * attr->num_values;
2931 break;
2932
2933 case IPP_TAG_BOOLEAN :
2934 bytes += attr->num_values;
2935 break;
2936
2937 case IPP_TAG_TEXT :
2938 case IPP_TAG_NAME :
2939 case IPP_TAG_KEYWORD :
ef416fc2 2940 case IPP_TAG_URI :
2941 case IPP_TAG_URISCHEME :
2942 case IPP_TAG_CHARSET :
2943 case IPP_TAG_LANGUAGE :
2944 case IPP_TAG_MIMETYPE :
2945 for (i = 0, value = attr->values;
2946 i < attr->num_values;
2947 i ++, value ++)
2948 if (value->string.text != NULL)
b86bc4cf 2949 bytes += (int)strlen(value->string.text);
ef416fc2 2950 break;
2951
2952 case IPP_TAG_DATE :
2953 bytes += 11 * attr->num_values;
2954 break;
2955
2956 case IPP_TAG_RESOLUTION :
2957 bytes += 9 * attr->num_values;
2958 break;
2959
2960 case IPP_TAG_RANGE :
2961 bytes += 8 * attr->num_values;
2962 break;
2963
2964 case IPP_TAG_TEXTLANG :
2965 case IPP_TAG_NAMELANG :
2966 bytes += 4 * attr->num_values;/* Charset + text length */
2967
2968 for (i = 0, value = attr->values;
2969 i < attr->num_values;
2970 i ++, value ++)
2971 {
2972 if (value->string.charset != NULL)
b86bc4cf 2973 bytes += (int)strlen(value->string.charset);
ef416fc2 2974
2975 if (value->string.text != NULL)
b86bc4cf 2976 bytes += (int)strlen(value->string.text);
ef416fc2 2977 }
2978 break;
2979
2980 case IPP_TAG_BEGIN_COLLECTION :
2981 for (i = 0, value = attr->values;
2982 i < attr->num_values;
2983 i ++, value ++)
b86bc4cf 2984 bytes += (int)ipp_length(value->collection, 1);
ef416fc2 2985 break;
2986
2987 default :
2988 for (i = 0, value = attr->values;
2989 i < attr->num_values;
2990 i ++, value ++)
4400e98d 2991 bytes += value->unknown.length;
ef416fc2 2992 break;
2993 }
2994 }
2995
2996 /*
2997 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
2998 * for the "end of collection" tag and return...
2999 */
3000
3001 if (collection)
3002 bytes += 5;
3003 else
3004 bytes ++;
3005
e07d4801 3006 DEBUG_printf(("8ipp_length: Returning %d bytes", bytes));
ef416fc2 3007
3008 return (bytes);
3009}
3010
3011
3012/*
3013 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
3014 */
3015
a4d04587 3016static ssize_t /* O - Number of bytes read */
ef416fc2 3017ipp_read_http(http_t *http, /* I - Client connection */
3018 ipp_uchar_t *buffer, /* O - Buffer for data */
a4d04587 3019 size_t length) /* I - Total length */
ef416fc2 3020{
3021 int tbytes, /* Total bytes read */
3022 bytes; /* Bytes read this pass */
3023 char len[32]; /* Length string */
aaf19ab0 3024
ef416fc2 3025
e07d4801 3026 DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)",
568fa3fa 3027 http, buffer, (int)length));
ef416fc2 3028
3029 /*
3030 * Loop until all bytes are read...
3031 */
3032
ae71f5de
MS
3033 for (tbytes = 0, bytes = 0;
3034 tbytes < (int)length;
3035 tbytes += bytes, buffer += bytes)
ef416fc2 3036 {
e07d4801 3037 DEBUG_printf(("9ipp_read_http: tbytes=%d, http->state=%d", tbytes,
ae71f5de 3038 http->state));
ef416fc2 3039
3040 if (http->state == HTTP_WAITING)
3041 break;
3042
3043 if (http->used > 0 && http->data_encoding == HTTP_ENCODE_LENGTH)
3044 {
3045 /*
3046 * Do "fast read" from HTTP buffer directly...
3047 */
3048
b86bc4cf 3049 if (http->used > (int)(length - tbytes))
3050 bytes = (int)(length - tbytes);
ef416fc2 3051 else
3052 bytes = http->used;
3053
3054 if (bytes == 1)
3055 buffer[0] = http->buffer[0];
3056 else
3057 memcpy(buffer, http->buffer, bytes);
3058
3059 http->used -= bytes;
3060 http->data_remaining -= bytes;
3061
3062 if (http->data_remaining <= INT_MAX)
3063 http->_data_remaining = (int)http->data_remaining;
3064 else
3065 http->_data_remaining = INT_MAX;
3066
3067 if (http->used > 0)
3068 memmove(http->buffer, http->buffer + bytes, http->used);
3069
3070 if (http->data_remaining == 0)
3071 {
3072 if (http->data_encoding == HTTP_ENCODE_CHUNKED)
3073 {
3074 /*
3075 * Get the trailing CR LF after the chunk...
3076 */
3077
3078 if (!httpGets(len, sizeof(len), http))
3079 return (-1);
3080 }
3081
3082 if (http->data_encoding != HTTP_ENCODE_CHUNKED)
3083 {
3084 if (http->state == HTTP_POST_RECV)
3085 http->state ++;
3086 else
3087 http->state = HTTP_WAITING;
3088 }
3089 }
3090 }
3091 else
3092 {
3093 /*
3094 * Wait a maximum of 1 second for data...
3095 */
3096
3097 if (!http->blocking)
3098 {
3099 /*
ed486911 3100 * Wait up to 10 seconds for more data on non-blocking sockets...
ef416fc2 3101 */
3102
ed486911 3103 if (!httpWait(http, 10000))
ef416fc2 3104 {
3105 /*
3106 * Signal no data...
3107 */
3108
3109 bytes = -1;
3110 break;
3111 }
3112 }
3113
d1c13e16
MS
3114 if ((bytes = httpRead2(http, (char *)buffer, length - tbytes)) < 0)
3115 {
3116#ifdef WIN32
3117 break;
3118#else
3119 if (errno != EAGAIN && errno != EINTR)
3120 break;
3121
3122 bytes = 0;
3123#endif /* WIN32 */
3124 }
3125 else if (bytes == 0)
ef416fc2 3126 break;
3127 }
3128 }
3129
3130 /*
3131 * Return the number of bytes read...
3132 */
3133
3134 if (tbytes == 0 && bytes < 0)
3135 tbytes = -1;
3136
e07d4801 3137 DEBUG_printf(("8ipp_read_http: Returning %d bytes", tbytes));
ef416fc2 3138
3139 return (tbytes);
3140}
3141
3142
3143/*
3144 * 'ipp_read_file()' - Read IPP data from a file.
3145 */
3146
a4d04587 3147static ssize_t /* O - Number of bytes read */
ef416fc2 3148ipp_read_file(int *fd, /* I - File descriptor */
3149 ipp_uchar_t *buffer, /* O - Read buffer */
a4d04587 3150 size_t length) /* I - Number of bytes to read */
ef416fc2 3151{
b86bc4cf 3152#ifdef WIN32
3153 return ((ssize_t)read(*fd, buffer, (unsigned)length));
3154#else
ef416fc2 3155 return (read(*fd, buffer, length));
b86bc4cf 3156#endif /* WIN32 */
ef416fc2 3157}
3158
3159
3160/*
3161 * 'ipp_write_file()' - Write IPP data to a file.
3162 */
3163
a4d04587 3164static ssize_t /* O - Number of bytes written */
ef416fc2 3165ipp_write_file(int *fd, /* I - File descriptor */
3166 ipp_uchar_t *buffer, /* I - Data to write */
a4d04587 3167 size_t length) /* I - Number of bytes to write */
ef416fc2 3168{
b86bc4cf 3169#ifdef WIN32
3170 return ((ssize_t)write(*fd, buffer, (unsigned)length));
3171#else
ef416fc2 3172 return (write(*fd, buffer, length));
b86bc4cf 3173#endif /* WIN32 */
ef416fc2 3174}
3175
3176
80ca4592 3177#ifdef __linux
ef416fc2 3178/*
80ca4592 3179 * The following symbol definitions are provided only for KDE
3180 * compatibility during the CUPS 1.2 testing period and will be
3181 * removed in a future release of CUPS. These are PRIVATE APIs
3182 * from CUPS 1.1.x that the KDE developers chose to use...
3183 */
3184
3185ipp_attribute_t * /* O - New attribute */
89d46774 3186_ipp_add_attr(ipp_t *ipp, /* I - IPP message */
3187 int num_values) /* I - Number of values */
80ca4592 3188{
3189 return (_ippAddAttr(ipp, num_values));
3190}
3191
3192void
89d46774 3193_ipp_free_attr(ipp_attribute_t *attr) /* I - Attribute to free */
80ca4592 3194{
3195 _ippFreeAttr(attr);
3196}
3197#endif /* __linux */
3198
3199
3200/*
b19ccc9e 3201 * End of "$Id: ipp.c 7847 2008-08-19 04:22:14Z mike $".
ef416fc2 3202 */