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