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