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