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