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