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