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