]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/ipp.c
Import CUPS v2.0rc1
[thirdparty/cups.git] / cups / ipp.c
CommitLineData
ef416fc2 1/*
5d2cc5d3 2 * "$Id: ipp.c 12093 2014-08-19 12:10:17Z msweet $"
1a18c85c
MS
3 *
4 * Internet Printing Protocol functions for CUPS.
5 *
6 * Copyright 2007-2014 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
ef416fc2 16 */
17
18/*
19 * Include necessary headers...
20 */
21
71e16022 22#include "cups-private.h"
c1420c87 23#include <regex.h>
ef416fc2 24#ifdef WIN32
25# include <io.h>
26#endif /* WIN32 */
27
28
29/*
30 * Local functions...
31 */
32
82cc1f9a
MS
33static ipp_attribute_t *ipp_add_attr(ipp_t *ipp, const char *name,
34 ipp_tag_t group_tag, ipp_tag_t value_tag,
35 int num_values);
36static void ipp_free_values(ipp_attribute_t *attr, int element,
37 int count);
38static char *ipp_get_code(const char *locale, char *buffer,
39 size_t bufsize)
40 __attribute__((nonnull(1,2)));
41static char *ipp_lang_code(const char *locale, char *buffer,
42 size_t bufsize)
43 __attribute__((nonnull(1,2)));
ef416fc2 44static size_t ipp_length(ipp_t *ipp, int collection);
a4d04587 45static ssize_t ipp_read_http(http_t *http, ipp_uchar_t *buffer,
46 size_t length);
47static ssize_t ipp_read_file(int *fd, ipp_uchar_t *buffer,
48 size_t length);
c1420c87
MS
49static void ipp_set_error(ipp_status_t status, const char *format,
50 ...);
82cc1f9a
MS
51static _ipp_value_t *ipp_set_value(ipp_t *ipp, ipp_attribute_t **attr,
52 int element);
a4d04587 53static ssize_t ipp_write_file(int *fd, ipp_uchar_t *buffer,
54 size_t length);
ef416fc2 55
56
dcb445bc
MS
57/*
58 * '_cupsBufferGet()' - Get a read/write buffer.
59 */
60
61char * /* O - Buffer */
62_cupsBufferGet(size_t size) /* I - Size required */
63{
64 _cups_buffer_t *buffer; /* Current buffer */
65 _cups_globals_t *cg = _cupsGlobals();
66 /* Global data */
67
68
69 for (buffer = cg->cups_buffers; buffer; buffer = buffer->next)
70 if (!buffer->used && buffer->size >= size)
71 break;
72
73 if (!buffer)
74 {
75 if ((buffer = malloc(sizeof(_cups_buffer_t) + size - 1)) == NULL)
76 return (NULL);
77
78 buffer->next = cg->cups_buffers;
79 buffer->size = size;
80 cg->cups_buffers = buffer;
81 }
82
83 buffer->used = 1;
84
85 return (buffer->d);
86}
87
88
89/*
90 * '_cupsBufferRelease()' - Release a read/write buffer.
91 */
92
93void
94_cupsBufferRelease(char *b) /* I - Buffer to release */
95{
96 _cups_buffer_t *buffer; /* Buffer */
97
98
99 /*
100 * Mark this buffer as unused...
101 */
102
103 buffer = (_cups_buffer_t *)(b - offsetof(_cups_buffer_t, d));
104 buffer->used = 0;
105}
106
107
ef416fc2 108/*
109 * 'ippAddBoolean()' - Add a boolean attribute to an IPP message.
a2326b5b 110 *
a469f8a5
MS
111 * The @code ipp@ parameter refers to an IPP message previously created using
112 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
113 *
114 * The @code group@ parameter specifies the IPP attribute group tag: none
115 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
116 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
117 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
118 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
ef416fc2 119 */
120
121ipp_attribute_t * /* O - New attribute */
122ippAddBoolean(ipp_t *ipp, /* I - IPP message */
123 ipp_tag_t group, /* I - IPP group */
124 const char *name, /* I - Name of attribute */
125 char value) /* I - Value of attribute */
126{
127 ipp_attribute_t *attr; /* New attribute */
128
129
e07d4801 130 DEBUG_printf(("ippAddBoolean(ipp=%p, group=%02x(%s), name=\"%s\", value=%d)",
1ff0402e 131 ipp, group, ippTagString(group), name, value));
ef416fc2 132
a2326b5b
MS
133 /*
134 * Range check input...
135 */
136
137 if (!ipp || !name || group < IPP_TAG_ZERO ||
138 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
ef416fc2 139 return (NULL);
140
a2326b5b
MS
141 /*
142 * Create the attribute...
143 */
144
145 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BOOLEAN, 1)) == NULL)
ef416fc2 146 return (NULL);
147
ef416fc2 148 attr->values[0].boolean = value;
149
150 return (attr);
151}
152
153
154/*
155 * 'ippAddBooleans()' - Add an array of boolean values.
a2326b5b 156 *
a469f8a5
MS
157 * The @code ipp@ parameter refers to an IPP message previously created using
158 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
159 *
160 * The @code group@ parameter specifies the IPP attribute group tag: none
161 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
162 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
163 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
164 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
ef416fc2 165 */
166
167ipp_attribute_t * /* O - New attribute */
168ippAddBooleans(ipp_t *ipp, /* I - IPP message */
169 ipp_tag_t group, /* I - IPP group */
170 const char *name, /* I - Name of attribute */
171 int num_values, /* I - Number of values */
172 const char *values) /* I - Values */
173{
174 int i; /* Looping var */
175 ipp_attribute_t *attr; /* New attribute */
a2326b5b 176 _ipp_value_t *value; /* Current value */
ef416fc2 177
178
1ff0402e 179 DEBUG_printf(("ippAddBooleans(ipp=%p, group=%02x(%s), name=\"%s\", "
e07d4801 180 "num_values=%d, values=%p)", ipp, group, ippTagString(group),
1ff0402e 181 name, num_values, values));
ef416fc2 182
a2326b5b
MS
183 /*
184 * Range check input...
185 */
ef416fc2 186
a2326b5b
MS
187 if (!ipp || !name || group < IPP_TAG_ZERO ||
188 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
189 num_values < 1)
ef416fc2 190 return (NULL);
191
a2326b5b
MS
192 /*
193 * Create the attribute...
194 */
195
196 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BOOLEAN, num_values)) == NULL)
197 return (NULL);
ef416fc2 198
a2326b5b
MS
199 if (values)
200 {
201 for (i = num_values, value = attr->values;
202 i > 0;
203 i --, value ++)
204 value->boolean = *values++;
205 }
ef416fc2 206
207 return (attr);
208}
209
210
211/*
212 * 'ippAddCollection()' - Add a collection value.
213 *
a469f8a5
MS
214 * The @code ipp@ parameter refers to an IPP message previously created using
215 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
216 *
217 * The @code group@ parameter specifies the IPP attribute group tag: none
218 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
219 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
220 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
221 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
222 *
f3c17241 223 * @since CUPS 1.1.19/OS X 10.3@
ef416fc2 224 */
225
226ipp_attribute_t * /* O - New attribute */
227ippAddCollection(ipp_t *ipp, /* I - IPP message */
228 ipp_tag_t group, /* I - IPP group */
229 const char *name, /* I - Name of attribute */
230 ipp_t *value) /* I - Value */
231{
232 ipp_attribute_t *attr; /* New attribute */
233
234
1ff0402e 235 DEBUG_printf(("ippAddCollection(ipp=%p, group=%02x(%s), name=\"%s\", "
e07d4801 236 "value=%p)", ipp, group, ippTagString(group), name, value));
ef416fc2 237
a2326b5b
MS
238 /*
239 * Range check input...
240 */
241
242 if (!ipp || !name || group < IPP_TAG_ZERO ||
243 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
ef416fc2 244 return (NULL);
245
a2326b5b
MS
246 /*
247 * Create the attribute...
248 */
249
250 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BEGIN_COLLECTION, 1)) == NULL)
ef416fc2 251 return (NULL);
252
ef416fc2 253 attr->values[0].collection = value;
254
9c80ffa2
MS
255 if (value)
256 value->use ++;
aaf19ab0 257
ef416fc2 258 return (attr);
259}
260
261
262/*
263 * 'ippAddCollections()' - Add an array of collection values.
264 *
a469f8a5
MS
265 * The @code ipp@ parameter refers to an IPP message previously created using
266 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
267 *
268 * The @code group@ parameter specifies the IPP attribute group tag: none
269 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
270 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
271 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
272 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
273 *
f3c17241 274 * @since CUPS 1.1.19/OS X 10.3@
ef416fc2 275 */
276
277ipp_attribute_t * /* O - New attribute */
278ippAddCollections(
279 ipp_t *ipp, /* I - IPP message */
280 ipp_tag_t group, /* I - IPP group */
281 const char *name, /* I - Name of attribute */
282 int num_values, /* I - Number of values */
283 const ipp_t **values) /* I - Values */
284{
285 int i; /* Looping var */
286 ipp_attribute_t *attr; /* New attribute */
a2326b5b 287 _ipp_value_t *value; /* Current value */
ef416fc2 288
289
1ff0402e 290 DEBUG_printf(("ippAddCollections(ipp=%p, group=%02x(%s), name=\"%s\", "
e07d4801 291 "num_values=%d, values=%p)", ipp, group, ippTagString(group),
1ff0402e 292 name, num_values, values));
ef416fc2 293
a2326b5b
MS
294 /*
295 * Range check input...
296 */
ef416fc2 297
a2326b5b
MS
298 if (!ipp || !name || group < IPP_TAG_ZERO ||
299 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
300 num_values < 1)
ef416fc2 301 return (NULL);
302
a2326b5b
MS
303 /*
304 * Create the attribute...
305 */
306
307 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BEGIN_COLLECTION,
308 num_values)) == NULL)
309 return (NULL);
ef416fc2 310
a2326b5b 311 if (values)
aaf19ab0 312 {
a2326b5b
MS
313 for (i = num_values, value = attr->values;
314 i > 0;
315 i --, value ++)
aaf19ab0 316 {
a2326b5b 317 value->collection = (ipp_t *)*values++;
aaf19ab0
MS
318 value->collection->use ++;
319 }
320 }
ef416fc2 321
322 return (attr);
323}
324
325
326/*
327 * 'ippAddDate()' - Add a date attribute to an IPP message.
a2326b5b 328 *
a469f8a5
MS
329 * The @code ipp@ parameter refers to an IPP message previously created using
330 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
331 *
332 * The @code group@ parameter specifies the IPP attribute group tag: none
333 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
334 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
335 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
336 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
ef416fc2 337 */
338
339ipp_attribute_t * /* O - New attribute */
340ippAddDate(ipp_t *ipp, /* I - IPP message */
341 ipp_tag_t group, /* I - IPP group */
342 const char *name, /* I - Name of attribute */
343 const ipp_uchar_t *value) /* I - Value */
344{
345 ipp_attribute_t *attr; /* New attribute */
346
347
e07d4801 348 DEBUG_printf(("ippAddDate(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)",
1ff0402e 349 ipp, group, ippTagString(group), name, value));
ef416fc2 350
a2326b5b
MS
351 /*
352 * Range check input...
353 */
354
355 if (!ipp || !name || !value || group < IPP_TAG_ZERO ||
356 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
ef416fc2 357 return (NULL);
358
a2326b5b
MS
359 /*
360 * Create the attribute...
361 */
362
363 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_DATE, 1)) == NULL)
ef416fc2 364 return (NULL);
365
ef416fc2 366 memcpy(attr->values[0].date, value, 11);
367
368 return (attr);
369}
370
371
372/*
373 * 'ippAddInteger()' - Add a integer attribute to an IPP message.
a2326b5b 374 *
a469f8a5
MS
375 * The @code ipp@ parameter refers to an IPP message previously created using
376 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
377 *
378 * The @code group@ parameter specifies the IPP attribute group tag: none
379 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
380 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
381 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
382 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
383 *
384 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
385 * (@code IPP_TAG_INTEGER@).
ef416fc2 386 */
387
388ipp_attribute_t * /* O - New attribute */
389ippAddInteger(ipp_t *ipp, /* I - IPP message */
390 ipp_tag_t group, /* I - IPP group */
a2326b5b 391 ipp_tag_t value_tag, /* I - Type of attribute */
ef416fc2 392 const char *name, /* I - Name of attribute */
393 int value) /* I - Value of attribute */
394{
395 ipp_attribute_t *attr; /* New attribute */
396
397
1ff0402e 398 DEBUG_printf(("ippAddInteger(ipp=%p, group=%02x(%s), type=%02x(%s), "
e07d4801 399 "name=\"%s\", value=%d)", ipp, group, ippTagString(group),
a2326b5b 400 value_tag, ippTagString(value_tag), name, value));
ef416fc2 401
cb7f98ee 402 value_tag &= IPP_TAG_CUPS_MASK;
a2326b5b
MS
403
404 /*
405 * Special-case for legacy usage: map out-of-band attributes to new ippAddOutOfBand
406 * function...
407 */
408
409 if (value_tag >= IPP_TAG_UNSUPPORTED_VALUE && value_tag <= IPP_TAG_ADMINDEFINE)
410 return (ippAddOutOfBand(ipp, group, value_tag, name));
411
412 /*
413 * Range check input...
414 */
415
416#if 0
417 if (!ipp || !name || group < IPP_TAG_ZERO ||
418 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
419 (value_tag != IPP_TAG_INTEGER && value_tag != IPP_TAG_ENUM))
420 return (NULL);
421#else
422 if (!ipp || !name || group < IPP_TAG_ZERO ||
423 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
ef416fc2 424 return (NULL);
a2326b5b 425#endif /* 0 */
ef416fc2 426
a2326b5b
MS
427 /*
428 * Create the attribute...
429 */
430
431 if ((attr = ipp_add_attr(ipp, name, group, value_tag, 1)) == NULL)
ef416fc2 432 return (NULL);
433
ef416fc2 434 attr->values[0].integer = value;
435
436 return (attr);
437}
438
439
440/*
441 * 'ippAddIntegers()' - Add an array of integer values.
a2326b5b 442 *
a469f8a5
MS
443 * The @code ipp@ parameter refers to an IPP message previously created using
444 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
445 *
446 * The @code group@ parameter specifies the IPP attribute group tag: none
447 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
448 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
449 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
450 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
451 *
452 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
453 * (@code IPP_TAG_INTEGER@).
ef416fc2 454 */
455
456ipp_attribute_t * /* O - New attribute */
457ippAddIntegers(ipp_t *ipp, /* I - IPP message */
458 ipp_tag_t group, /* I - IPP group */
a2326b5b 459 ipp_tag_t value_tag, /* I - Type of attribute */
ef416fc2 460 const char *name, /* I - Name of attribute */
461 int num_values, /* I - Number of values */
462 const int *values) /* I - Values */
463{
464 int i; /* Looping var */
465 ipp_attribute_t *attr; /* New attribute */
a2326b5b 466 _ipp_value_t *value; /* Current value */
ef416fc2 467
468
1ff0402e 469 DEBUG_printf(("ippAddIntegers(ipp=%p, group=%02x(%s), type=%02x(%s), "
e07d4801 470 "name=\"%s\", num_values=%d, values=%p)", ipp,
a2326b5b 471 group, ippTagString(group), value_tag, ippTagString(value_tag), name,
1ff0402e
MS
472 num_values, values));
473
cb7f98ee 474 value_tag &= IPP_TAG_CUPS_MASK;
a2326b5b
MS
475
476 /*
477 * Range check input...
478 */
ef416fc2 479
a2326b5b
MS
480#if 0
481 if (!ipp || !name || group < IPP_TAG_ZERO ||
482 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
483 (value_tag != IPP_TAG_INTEGER && value_tag != IPP_TAG_ENUM) ||
484 num_values < 1)
485 return (NULL);
486#else
487 if (!ipp || !name || group < IPP_TAG_ZERO ||
488 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
489 num_values < 1)
ef416fc2 490 return (NULL);
a2326b5b 491#endif /* 0 */
ef416fc2 492
a2326b5b
MS
493 /*
494 * Create the attribute...
495 */
496
497 if ((attr = ipp_add_attr(ipp, name, group, value_tag, num_values)) == NULL)
498 return (NULL);
ef416fc2 499
a2326b5b
MS
500 if (values)
501 {
502 for (i = num_values, value = attr->values;
503 i > 0;
504 i --, value ++)
505 value->integer = *values++;
506 }
ef416fc2 507
508 return (attr);
509}
510
511
512/*
513 * 'ippAddOctetString()' - Add an octetString value to an IPP message.
514 *
a469f8a5
MS
515 * The @code ipp@ parameter refers to an IPP message previously created using
516 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
517 *
518 * The @code group@ parameter specifies the IPP attribute group tag: none
519 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
520 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
521 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
522 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
523 *
f3c17241 524 * @since CUPS 1.2/OS X 10.5@
ef416fc2 525 */
526
527ipp_attribute_t * /* O - New attribute */
528ippAddOctetString(ipp_t *ipp, /* I - IPP message */
529 ipp_tag_t group, /* I - IPP group */
530 const char *name, /* I - Name of attribute */
531 const void *data, /* I - octetString data */
532 int datalen) /* I - Length of data in bytes */
533{
534 ipp_attribute_t *attr; /* New attribute */
535
536
a2326b5b 537 if (!ipp || !name || group < IPP_TAG_ZERO ||
5a9febac 538 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
a469f8a5 539 datalen < 0 || datalen > IPP_MAX_LENGTH)
ef416fc2 540 return (NULL);
541
a2326b5b 542 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_STRING, 1)) == NULL)
ef416fc2 543 return (NULL);
544
545 /*
546 * Initialize the attribute data...
547 */
548
ef416fc2 549 attr->values[0].unknown.length = datalen;
550
551 if (data)
552 {
1a18c85c 553 if ((attr->values[0].unknown.data = malloc((size_t)datalen)) == NULL)
91c84a35
MS
554 {
555 ippDeleteAttribute(ipp, attr);
556 return (NULL);
557 }
558
1a18c85c 559 memcpy(attr->values[0].unknown.data, data, (size_t)datalen);
ef416fc2 560 }
561
562 /*
563 * Return the new attribute...
564 */
565
566 return (attr);
567}
568
569
570/*
a2326b5b
MS
571 * 'ippAddOutOfBand()' - Add an out-of-band value to an IPP message.
572 *
a469f8a5
MS
573 * The @code ipp@ parameter refers to an IPP message previously created using
574 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
575 *
576 * The @code group@ parameter specifies the IPP attribute group tag: none
577 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
578 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
579 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
580 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
581 *
582 * Supported out-of-band values include unsupported-value
583 * (@code IPP_TAG_UNSUPPORTED_VALUE@), default (@code IPP_TAG_DEFAULT@), unknown
584 * (@code IPP_TAG_UNKNOWN@), no-value (@code IPP_TAG_NOVALUE@), not-settable
585 * (@code IPP_TAG_NOTSETTABLE@), delete-attribute (@code IPP_TAG_DELETEATTR@), and
586 * admin-define (@code IPP_TAG_ADMINDEFINE@).
587 *
f3c17241 588 * @since CUPS 1.6/OS X 10.8@
ef416fc2 589 */
590
a2326b5b
MS
591ipp_attribute_t * /* O - New attribute */
592ippAddOutOfBand(ipp_t *ipp, /* I - IPP message */
593 ipp_tag_t group, /* I - IPP group */
594 ipp_tag_t value_tag, /* I - Type of attribute */
595 const char *name) /* I - Name of attribute */
ef416fc2 596{
a2326b5b
MS
597 DEBUG_printf(("ippAddOutOfBand(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
598 "name=\"%s\")", ipp, group, ippTagString(group), value_tag,
599 ippTagString(value_tag), name));
ef416fc2 600
cb7f98ee 601 value_tag &= IPP_TAG_CUPS_MASK;
ef416fc2 602
4400e98d 603 /*
a2326b5b 604 * Range check input...
4400e98d 605 */
606
a2326b5b
MS
607 if (!ipp || !name || group < IPP_TAG_ZERO ||
608 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
609 (value_tag != IPP_TAG_UNSUPPORTED_VALUE &&
610 value_tag != IPP_TAG_DEFAULT &&
611 value_tag != IPP_TAG_UNKNOWN &&
612 value_tag != IPP_TAG_NOVALUE &&
613 value_tag != IPP_TAG_NOTSETTABLE &&
614 value_tag != IPP_TAG_DELETEATTR &&
615 value_tag != IPP_TAG_ADMINDEFINE))
ef416fc2 616 return (NULL);
617
618 /*
a2326b5b 619 * Create the attribute...
ef416fc2 620 */
621
a2326b5b 622 return (ipp_add_attr(ipp, name, group, value_tag, 1));
ef416fc2 623}
624
625
626/*
627 * 'ippAddRange()' - Add a range of values to an IPP message.
a2326b5b 628 *
a469f8a5
MS
629 * The @code ipp@ parameter refers to an IPP message previously created using
630 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
631 *
632 * The @code group@ parameter specifies the IPP attribute group tag: none
633 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
634 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
635 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
636 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
637 *
638 * The @code lower@ parameter must be less than or equal to the @code upper@ parameter.
ef416fc2 639 */
640
641ipp_attribute_t * /* O - New attribute */
642ippAddRange(ipp_t *ipp, /* I - IPP message */
643 ipp_tag_t group, /* I - IPP group */
644 const char *name, /* I - Name of attribute */
645 int lower, /* I - Lower value */
646 int upper) /* I - Upper value */
647{
648 ipp_attribute_t *attr; /* New attribute */
649
650
1ff0402e 651 DEBUG_printf(("ippAddRange(ipp=%p, group=%02x(%s), name=\"%s\", lower=%d, "
e07d4801 652 "upper=%d)", ipp, group, ippTagString(group), name, lower,
1ff0402e
MS
653 upper));
654
a2326b5b
MS
655 /*
656 * Range check input...
657 */
658
659 if (!ipp || !name || group < IPP_TAG_ZERO ||
660 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
ef416fc2 661 return (NULL);
662
a2326b5b
MS
663 /*
664 * Create the attribute...
665 */
666
667 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RANGE, 1)) == NULL)
ef416fc2 668 return (NULL);
669
ef416fc2 670 attr->values[0].range.lower = lower;
671 attr->values[0].range.upper = upper;
672
673 return (attr);
674}
675
676
677/*
678 * 'ippAddRanges()' - Add ranges of values to an IPP message.
a2326b5b 679 *
a469f8a5
MS
680 * The @code ipp@ parameter refers to an IPP message previously created using
681 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
682 *
683 * The @code group@ parameter specifies the IPP attribute group tag: none
684 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
685 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
686 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
687 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
ef416fc2 688 */
689
690ipp_attribute_t * /* O - New attribute */
691ippAddRanges(ipp_t *ipp, /* I - IPP message */
692 ipp_tag_t group, /* I - IPP group */
693 const char *name, /* I - Name of attribute */
694 int num_values, /* I - Number of values */
695 const int *lower, /* I - Lower values */
696 const int *upper) /* I - Upper values */
697{
698 int i; /* Looping var */
699 ipp_attribute_t *attr; /* New attribute */
a2326b5b 700 _ipp_value_t *value; /* Current value */
ef416fc2 701
702
1ff0402e 703 DEBUG_printf(("ippAddRanges(ipp=%p, group=%02x(%s), name=\"%s\", "
e07d4801 704 "num_values=%d, lower=%p, upper=%p)", ipp, group,
1ff0402e
MS
705 ippTagString(group), name, num_values, lower, upper));
706
a2326b5b
MS
707 /*
708 * Range check input...
709 */
ef416fc2 710
a2326b5b
MS
711 if (!ipp || !name || group < IPP_TAG_ZERO ||
712 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
713 num_values < 1)
ef416fc2 714 return (NULL);
715
a2326b5b
MS
716 /*
717 * Create the attribute...
718 */
719
720 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RANGE, num_values)) == NULL)
721 return (NULL);
ef416fc2 722
a2326b5b
MS
723 if (lower && upper)
724 {
725 for (i = num_values, value = attr->values;
726 i > 0;
727 i --, value ++)
ef416fc2 728 {
a2326b5b
MS
729 value->range.lower = *lower++;
730 value->range.upper = *upper++;
ef416fc2 731 }
a2326b5b 732 }
ef416fc2 733
734 return (attr);
735}
736
737
738/*
739 * 'ippAddResolution()' - Add a resolution value to an IPP message.
a2326b5b 740 *
a469f8a5
MS
741 * The @code ipp@ parameter refers to an IPP message previously created using
742 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
743 *
744 * The @code group@ parameter specifies the IPP attribute group tag: none
745 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
746 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
747 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
748 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
ef416fc2 749 */
750
751ipp_attribute_t * /* O - New attribute */
752ippAddResolution(ipp_t *ipp, /* I - IPP message */
753 ipp_tag_t group, /* I - IPP group */
754 const char *name, /* I - Name of attribute */
755 ipp_res_t units, /* I - Units for resolution */
756 int xres, /* I - X resolution */
757 int yres) /* I - Y resolution */
758{
759 ipp_attribute_t *attr; /* New attribute */
760
761
1ff0402e 762 DEBUG_printf(("ippAddResolution(ipp=%p, group=%02x(%s), name=\"%s\", "
e07d4801 763 "units=%d, xres=%d, yres=%d)", ipp, group,
1ff0402e
MS
764 ippTagString(group), name, units, xres, yres));
765
a2326b5b
MS
766 /*
767 * Range check input...
768 */
769
770 if (!ipp || !name || group < IPP_TAG_ZERO ||
771 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
772 units < IPP_RES_PER_INCH || units > IPP_RES_PER_CM ||
773 xres < 0 || yres < 0)
ef416fc2 774 return (NULL);
775
a2326b5b
MS
776 /*
777 * Create the attribute...
778 */
779
780 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RESOLUTION, 1)) == NULL)
ef416fc2 781 return (NULL);
782
ef416fc2 783 attr->values[0].resolution.xres = xres;
784 attr->values[0].resolution.yres = yres;
785 attr->values[0].resolution.units = units;
786
787 return (attr);
788}
789
790
791/*
792 * 'ippAddResolutions()' - Add resolution values to an IPP message.
a2326b5b 793 *
a469f8a5
MS
794 * The @code ipp@ parameter refers to an IPP message previously created using
795 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
796 *
797 * The @code group@ parameter specifies the IPP attribute group tag: none
798 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
799 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
800 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
801 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
ef416fc2 802 */
803
804ipp_attribute_t * /* O - New attribute */
805ippAddResolutions(ipp_t *ipp, /* I - IPP message */
806 ipp_tag_t group, /* I - IPP group */
807 const char *name, /* I - Name of attribute */
808 int num_values,/* I - Number of values */
809 ipp_res_t units, /* I - Units for resolution */
810 const int *xres, /* I - X resolutions */
811 const int *yres) /* I - Y resolutions */
812{
813 int i; /* Looping var */
814 ipp_attribute_t *attr; /* New attribute */
a2326b5b 815 _ipp_value_t *value; /* Current value */
ef416fc2 816
817
1ff0402e 818 DEBUG_printf(("ippAddResolutions(ipp=%p, group=%02x(%s), name=\"%s\", "
e07d4801 819 "num_value=%d, units=%d, xres=%p, yres=%p)", ipp, group,
1ff0402e
MS
820 ippTagString(group), name, num_values, units, xres, yres));
821
a2326b5b
MS
822 /*
823 * Range check input...
824 */
ef416fc2 825
a2326b5b
MS
826 if (!ipp || !name || group < IPP_TAG_ZERO ||
827 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
828 num_values < 1 ||
829 units < IPP_RES_PER_INCH || units > IPP_RES_PER_CM)
ef416fc2 830 return (NULL);
831
a2326b5b
MS
832 /*
833 * Create the attribute...
834 */
835
836 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RESOLUTION, num_values)) == NULL)
837 return (NULL);
ef416fc2 838
a2326b5b
MS
839 if (xres && yres)
840 {
841 for (i = num_values, value = attr->values;
842 i > 0;
843 i --, value ++)
ef416fc2 844 {
a2326b5b
MS
845 value->resolution.xres = *xres++;
846 value->resolution.yres = *yres++;
ef416fc2 847 value->resolution.units = units;
848 }
a2326b5b 849 }
ef416fc2 850
851 return (attr);
852}
853
854
855/*
856 * 'ippAddSeparator()' - Add a group separator to an IPP message.
a2326b5b 857 *
a469f8a5
MS
858 * The @code ipp@ parameter refers to an IPP message previously created using
859 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
ef416fc2 860 */
861
862ipp_attribute_t * /* O - New attribute */
863ippAddSeparator(ipp_t *ipp) /* I - IPP message */
864{
e07d4801 865 DEBUG_printf(("ippAddSeparator(ipp=%p)", ipp));
ef416fc2 866
a2326b5b
MS
867 /*
868 * Range check input...
869 */
ef416fc2 870
a2326b5b 871 if (!ipp)
ef416fc2 872 return (NULL);
873
a2326b5b
MS
874 /*
875 * Create the attribute...
876 */
ef416fc2 877
a2326b5b 878 return (ipp_add_attr(ipp, NULL, IPP_TAG_ZERO, IPP_TAG_ZERO, 0));
ef416fc2 879}
880
881
882/*
a2326b5b
MS
883 * 'ippAddString()' - Add a language-encoded string to an IPP message.
884 *
a469f8a5
MS
885 * The @code ipp@ parameter refers to an IPP message previously created using
886 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
887 *
888 * The @code group@ parameter specifies the IPP attribute group tag: none
889 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
890 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
891 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
892 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
893 *
894 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
895 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
896 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
897 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
898 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
899 * (@code IPP_TAG_URISCHEME@).
900 *
901 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
902 * textWithLanguage string values and must be @code NULL@ for all other string values.
ef416fc2 903 */
904
a2326b5b
MS
905ipp_attribute_t * /* O - New attribute */
906ippAddString(ipp_t *ipp, /* I - IPP message */
907 ipp_tag_t group, /* I - IPP group */
908 ipp_tag_t value_tag, /* I - Type of attribute */
909 const char *name, /* I - Name of attribute */
910 const char *language, /* I - Language code */
911 const char *value) /* I - Value */
ef416fc2 912{
a2326b5b
MS
913 ipp_tag_t temp_tag; /* Temporary value tag (masked) */
914 ipp_attribute_t *attr; /* New attribute */
5a9febac
MS
915 char code[IPP_MAX_LANGUAGE];
916 /* Charset/language code buffer */
ef416fc2 917
1ff0402e 918
a2326b5b
MS
919 DEBUG_printf(("ippAddString(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
920 "name=\"%s\", language=\"%s\", value=\"%s\")", ipp,
921 group, ippTagString(group), value_tag, ippTagString(value_tag), name,
922 language, value));
ef416fc2 923
924 /*
a2326b5b 925 * Range check input...
ef416fc2 926 */
927
cb7f98ee 928 temp_tag = (ipp_tag_t)((int)value_tag & IPP_TAG_CUPS_MASK);
ef416fc2 929
a2326b5b
MS
930#if 0
931 if (!ipp || !name || group < IPP_TAG_ZERO ||
932 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
933 (temp_tag < IPP_TAG_TEXT && temp_tag != IPP_TAG_TEXTLANG &&
934 temp_tag != IPP_TAG_NAMELANG) || temp_tag > IPP_TAG_MIMETYPE)
935 return (NULL);
ef416fc2 936
a2326b5b
MS
937 if ((temp_tag == IPP_TAG_TEXTLANG || temp_tag == IPP_TAG_NAMELANG)
938 != (language != NULL))
939 return (NULL);
940#else
941 if (!ipp || !name || group < IPP_TAG_ZERO ||
942 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
943 return (NULL);
944#endif /* 0 */
ef416fc2 945
a2326b5b
MS
946 /*
947 * See if we need to map charset, language, or locale values...
948 */
ef416fc2 949
cb7f98ee 950 if (language && ((int)value_tag & IPP_TAG_CUPS_CONST) &&
a2326b5b
MS
951 strcmp(language, ipp_lang_code(language, code, sizeof(code))))
952 value_tag = temp_tag; /* Don't do a fast copy */
cb7f98ee 953 else if (value && value_tag == (ipp_tag_t)(IPP_TAG_CHARSET | IPP_TAG_CUPS_CONST) &&
a2326b5b
MS
954 strcmp(value, ipp_get_code(value, code, sizeof(code))))
955 value_tag = temp_tag; /* Don't do a fast copy */
cb7f98ee 956 else if (value && value_tag == (ipp_tag_t)(IPP_TAG_LANGUAGE | IPP_TAG_CUPS_CONST) &&
a2326b5b
MS
957 strcmp(value, ipp_lang_code(value, code, sizeof(code))))
958 value_tag = temp_tag; /* Don't do a fast copy */
ef416fc2 959
a2326b5b
MS
960 /*
961 * Create the attribute...
962 */
ef416fc2 963
a2326b5b
MS
964 if ((attr = ipp_add_attr(ipp, name, group, value_tag, 1)) == NULL)
965 return (NULL);
ef416fc2 966
a2326b5b
MS
967 /*
968 * Initialize the attribute data...
969 */
aaf19ab0 970
cb7f98ee 971 if ((int)value_tag & IPP_TAG_CUPS_CONST)
ef416fc2 972 {
a2326b5b
MS
973 attr->values[0].string.language = (char *)language;
974 attr->values[0].string.text = (char *)value;
975 }
976 else
977 {
978 if (language)
979 attr->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language, code,
980 sizeof(code)));
981
82cc1f9a
MS
982 if (value)
983 {
984 if (value_tag == IPP_TAG_CHARSET)
985 attr->values[0].string.text = _cupsStrAlloc(ipp_get_code(value, code,
986 sizeof(code)));
987 else if (value_tag == IPP_TAG_LANGUAGE)
988 attr->values[0].string.text = _cupsStrAlloc(ipp_lang_code(value, code,
989 sizeof(code)));
990 else
991 attr->values[0].string.text = _cupsStrAlloc(value);
992 }
ef416fc2 993 }
994
a2326b5b 995 return (attr);
ef416fc2 996}
997
998
a469f8a5
MS
999/*
1000 * 'ippAddStringf()' - Add a formatted string to an IPP message.
1001 *
1002 * The @code ipp@ parameter refers to an IPP message previously created using
1003 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
1004 *
1005 * The @code group@ parameter specifies the IPP attribute group tag: none
1006 * (@code IPP_TAG_ZERO@, for member attributes), document
1007 * (@code IPP_TAG_DOCUMENT@), event notification
1008 * (@code IPP_TAG_EVENT_NOTIFICATION@), operation (@code IPP_TAG_OPERATION@),
1009 * printer (@code IPP_TAG_PRINTER@), subscription (@code IPP_TAG_SUBSCRIPTION@),
1010 * or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1011 *
1012 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1013 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1014 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1015 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1016 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1017 * (@code IPP_TAG_URISCHEME@).
1018 *
1019 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage
1020 * and textWithLanguage string values and must be @code NULL@ for all other
1021 * string values.
1022 *
1023 * The @code format@ parameter uses formatting characters compatible with the
1024 * printf family of standard functions. Additional arguments follow it as
1025 * needed. The formatted string is truncated as needed to the maximum length of
1026 * the corresponding value type.
1027 *
9c0e8e5d 1028 * @since CUPS 1.7/OS X 10.9@
a469f8a5
MS
1029 */
1030
1031ipp_attribute_t * /* O - New attribute */
1032ippAddStringf(ipp_t *ipp, /* I - IPP message */
1033 ipp_tag_t group, /* I - IPP group */
1034 ipp_tag_t value_tag, /* I - Type of attribute */
1035 const char *name, /* I - Name of attribute */
1036 const char *language, /* I - Language code (@code NULL@ for default) */
1037 const char *format, /* I - Printf-style format string */
1038 ...) /* I - Additional arguments as needed */
1039{
1040 ipp_attribute_t *attr; /* New attribute */
1041 va_list ap; /* Argument pointer */
1042
1043
1044 va_start(ap, format);
1045 attr = ippAddStringfv(ipp, group, value_tag, name, language, format, ap);
1046 va_end(ap);
1047
1048 return (attr);
1049}
1050
1051
1052/*
1053 * 'ippAddStringfv()' - Add a formatted string to an IPP message.
1054 *
1055 * The @code ipp@ parameter refers to an IPP message previously created using
1056 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
1057 *
1058 * The @code group@ parameter specifies the IPP attribute group tag: none
1059 * (@code IPP_TAG_ZERO@, for member attributes), document
1060 * (@code IPP_TAG_DOCUMENT@), event notification
1061 * (@code IPP_TAG_EVENT_NOTIFICATION@), operation (@code IPP_TAG_OPERATION@),
1062 * printer (@code IPP_TAG_PRINTER@), subscription (@code IPP_TAG_SUBSCRIPTION@),
1063 * or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1064 *
1065 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1066 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1067 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1068 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1069 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1070 * (@code IPP_TAG_URISCHEME@).
1071 *
1072 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage
1073 * and textWithLanguage string values and must be @code NULL@ for all other
1074 * string values.
1075 *
1076 * The @code format@ parameter uses formatting characters compatible with the
1077 * printf family of standard functions. Additional arguments are passed in the
1078 * stdarg pointer @code ap@. The formatted string is truncated as needed to the
1079 * maximum length of the corresponding value type.
1080 *
9c0e8e5d 1081 * @since CUPS 1.7/OS X 10.9@
a469f8a5
MS
1082 */
1083
1084ipp_attribute_t * /* O - New attribute */
1085ippAddStringfv(ipp_t *ipp, /* I - IPP message */
1086 ipp_tag_t group, /* I - IPP group */
1087 ipp_tag_t value_tag, /* I - Type of attribute */
1088 const char *name, /* I - Name of attribute */
1089 const char *language, /* I - Language code (@code NULL@ for default) */
1090 const char *format, /* I - Printf-style format string */
1091 va_list ap) /* I - Additional arguments */
1092{
1093 char buffer[IPP_MAX_TEXT + 4];
1094 /* Formatted text string */
1095 ssize_t bytes, /* Length of formatted value */
1096 max_bytes; /* Maximum number of bytes for value */
1097
1098
1099 /*
1100 * Range check input...
1101 */
1102
1103 if (!ipp || !name || group < IPP_TAG_ZERO ||
1104 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
1105 (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG &&
1106 value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE ||
56cd8959 1107 !format)
a469f8a5
MS
1108 return (NULL);
1109
1110 if ((value_tag == IPP_TAG_TEXTLANG || value_tag == IPP_TAG_NAMELANG)
1111 != (language != NULL))
1112 return (NULL);
1113
1114 /*
1115 * Format the string...
1116 */
1117
1118 if (!strcmp(format, "%s"))
1119 {
1120 /*
1121 * Optimize the simple case...
1122 */
1123
1124 const char *s = va_arg(ap, char *);
1125
1126 if (!s)
1127 s = "(null)";
1128
1a18c85c 1129 bytes = (ssize_t)strlen(s);
a469f8a5
MS
1130 strlcpy(buffer, s, sizeof(buffer));
1131 }
1132 else
1133 {
1134 /*
1135 * Do a full formatting of the message...
1136 */
1137
1138 if ((bytes = vsnprintf(buffer, sizeof(buffer), format, ap)) < 0)
1139 return (NULL);
1140 }
1141
1142 /*
1143 * Limit the length of the string...
1144 */
1145
1146 switch (value_tag)
1147 {
1148 default :
1149 case IPP_TAG_TEXT :
1150 case IPP_TAG_TEXTLANG :
1151 max_bytes = IPP_MAX_TEXT;
1152 break;
1153
1154 case IPP_TAG_NAME :
1155 case IPP_TAG_NAMELANG :
1156 max_bytes = IPP_MAX_NAME;
1157 break;
1158
1159 case IPP_TAG_CHARSET :
1160 max_bytes = IPP_MAX_CHARSET;
1161 break;
1162
1163 case IPP_TAG_KEYWORD :
1164 max_bytes = IPP_MAX_KEYWORD;
1165 break;
1166
1167 case IPP_TAG_LANGUAGE :
1168 max_bytes = IPP_MAX_LANGUAGE;
1169 break;
1170
1171 case IPP_TAG_MIMETYPE :
1172 max_bytes = IPP_MAX_MIMETYPE;
1173 break;
1174
1175 case IPP_TAG_URI :
1176 max_bytes = IPP_MAX_URI;
1177 break;
1178
1179 case IPP_TAG_URISCHEME :
1180 max_bytes = IPP_MAX_URISCHEME;
1181 break;
1182 }
1183
1184 if (bytes >= max_bytes)
1185 {
1186 char *bufmax, /* Buffer at max_bytes */
1187 *bufptr; /* Pointer into buffer */
1188
1189 bufptr = buffer + strlen(buffer) - 1;
1190 bufmax = buffer + max_bytes - 1;
1191
1192 while (bufptr > bufmax)
1193 {
1194 if (*bufptr & 0x80)
1195 {
1196 while ((*bufptr & 0xc0) == 0x80 && bufptr > buffer)
1197 bufptr --;
1198 }
1199
1200 bufptr --;
1201 }
1202
1203 *bufptr = '\0';
1204 }
1205
1206 /*
1207 * Add the formatted string and return...
1208 */
1209
1210 return (ippAddString(ipp, group, value_tag, name, language, buffer));
1211}
1212
1213
ef416fc2 1214/*
a2326b5b 1215 * 'ippAddStrings()' - Add language-encoded strings to an IPP message.
ef416fc2 1216 *
a469f8a5
MS
1217 * The @code ipp@ parameter refers to an IPP message previously created using
1218 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
1219 *
1220 * The @code group@ parameter specifies the IPP attribute group tag: none
1221 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
1222 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
1223 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
1224 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1225 *
1226 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1227 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1228 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1229 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1230 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1231 * (@code IPP_TAG_URISCHEME@).
1232 *
1233 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
1234 * textWithLanguage string values and must be @code NULL@ for all other string values.
ef416fc2 1235 */
1236
a2326b5b
MS
1237ipp_attribute_t * /* O - New attribute */
1238ippAddStrings(
1239 ipp_t *ipp, /* I - IPP message */
1240 ipp_tag_t group, /* I - IPP group */
1241 ipp_tag_t value_tag, /* I - Type of attribute */
1242 const char *name, /* I - Name of attribute */
1243 int num_values, /* I - Number of values */
1244 const char *language, /* I - Language code (@code NULL@ for default) */
1245 const char * const *values) /* I - Values */
ef416fc2 1246{
a2326b5b
MS
1247 int i; /* Looping var */
1248 ipp_tag_t temp_tag; /* Temporary value tag (masked) */
1249 ipp_attribute_t *attr; /* New attribute */
1250 _ipp_value_t *value; /* Current value */
1251 char code[32]; /* Language/charset value buffer */
ef416fc2 1252
1253
a2326b5b
MS
1254 DEBUG_printf(("ippAddStrings(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
1255 "name=\"%s\", num_values=%d, language=\"%s\", values=%p)", ipp,
1256 group, ippTagString(group), value_tag, ippTagString(value_tag), name,
1257 num_values, language, values));
1ff0402e 1258
ef416fc2 1259 /*
a2326b5b 1260 * Range check input...
ef416fc2 1261 */
1262
cb7f98ee 1263 temp_tag = (ipp_tag_t)((int)value_tag & IPP_TAG_CUPS_MASK);
ef416fc2 1264
a2326b5b
MS
1265#if 0
1266 if (!ipp || !name || group < IPP_TAG_ZERO ||
1267 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
1268 (temp_tag < IPP_TAG_TEXT && temp_tag != IPP_TAG_TEXTLANG &&
1269 temp_tag != IPP_TAG_NAMELANG) || temp_tag > IPP_TAG_MIMETYPE ||
1270 num_values < 1)
1271 return (NULL);
ef416fc2 1272
a2326b5b
MS
1273 if ((temp_tag == IPP_TAG_TEXTLANG || temp_tag == IPP_TAG_NAMELANG)
1274 != (language != NULL))
1275 return (NULL);
1276#else
1277 if (!ipp || !name || group < IPP_TAG_ZERO ||
1278 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
1279 num_values < 1)
1280 return (NULL);
1281#endif /* 0 */
ef416fc2 1282
a2326b5b
MS
1283 /*
1284 * See if we need to map charset, language, or locale values...
1285 */
ef416fc2 1286
cb7f98ee 1287 if (language && ((int)value_tag & IPP_TAG_CUPS_CONST) &&
a2326b5b
MS
1288 strcmp(language, ipp_lang_code(language, code, sizeof(code))))
1289 value_tag = temp_tag; /* Don't do a fast copy */
cb7f98ee 1290 else if (values && value_tag == (ipp_tag_t)(IPP_TAG_CHARSET | IPP_TAG_CUPS_CONST))
a2326b5b
MS
1291 {
1292 for (i = 0; i < num_values; i ++)
1293 if (strcmp(values[i], ipp_get_code(values[i], code, sizeof(code))))
1294 {
1295 value_tag = temp_tag; /* Don't do a fast copy */
1296 break;
1297 }
1298 }
cb7f98ee 1299 else if (values && value_tag == (ipp_tag_t)(IPP_TAG_LANGUAGE | IPP_TAG_CUPS_CONST))
a2326b5b
MS
1300 {
1301 for (i = 0; i < num_values; i ++)
1302 if (strcmp(values[i], ipp_lang_code(values[i], code, sizeof(code))))
1303 {
1304 value_tag = temp_tag; /* Don't do a fast copy */
1305 break;
1306 }
ef416fc2 1307 }
ef416fc2 1308
a2326b5b
MS
1309 /*
1310 * Create the attribute...
1311 */
ef416fc2 1312
a2326b5b 1313 if ((attr = ipp_add_attr(ipp, name, group, value_tag, num_values)) == NULL)
ef416fc2 1314 return (NULL);
1315
1316 /*
a2326b5b 1317 * Initialize the attribute data...
ef416fc2 1318 */
1319
a2326b5b
MS
1320 for (i = num_values, value = attr->values;
1321 i > 0;
1322 i --, value ++)
1323 {
1324 if (language)
1325 {
1326 if (value == attr->values)
1327 {
cb7f98ee 1328 if ((int)value_tag & IPP_TAG_CUPS_CONST)
a2326b5b
MS
1329 value->string.language = (char *)language;
1330 else
1331 value->string.language = _cupsStrAlloc(ipp_lang_code(language, code,
1332 sizeof(code)));
1333 }
1334 else
1335 value->string.language = attr->values[0].string.language;
1336 }
ef416fc2 1337
a2326b5b
MS
1338 if (values)
1339 {
cb7f98ee 1340 if ((int)value_tag & IPP_TAG_CUPS_CONST)
a2326b5b
MS
1341 value->string.text = (char *)*values++;
1342 else if (value_tag == IPP_TAG_CHARSET)
1343 value->string.text = _cupsStrAlloc(ipp_get_code(*values++, code, sizeof(code)));
1344 else if (value_tag == IPP_TAG_LANGUAGE)
1345 value->string.text = _cupsStrAlloc(ipp_lang_code(*values++, code, sizeof(code)));
1346 else
1347 value->string.text = _cupsStrAlloc(*values++);
1348 }
1349 }
ef416fc2 1350
a2326b5b 1351 return (attr);
ef416fc2 1352}
1353
1354
a469f8a5
MS
1355/*
1356 * 'ippContainsInteger()' - Determine whether an attribute contains the
1357 * specified value or is within the list of ranges.
1358 *
1359 * Returns non-zero when the attribute contains either a matching integer or
1360 * enum value, or the value falls within one of the rangeOfInteger values for
1361 * the attribute.
1362 *
9c0e8e5d 1363 * @since CUPS 1.7/OS X 10.9@
a469f8a5
MS
1364 */
1365
1366int /* O - 1 on a match, 0 on no match */
1367ippContainsInteger(
1368 ipp_attribute_t *attr, /* I - Attribute */
1369 int value) /* I - Integer/enum value */
1370{
1371 int i; /* Looping var */
1372 _ipp_value_t *avalue; /* Current attribute value */
1373
1374
1375 /*
1376 * Range check input...
1377 */
1378
1379 if (!attr)
1380 return (0);
1381
1382 if (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM &&
1383 attr->value_tag != IPP_TAG_RANGE)
1384 return (0);
1385
1386 /*
1387 * Compare...
1388 */
1389
1390 if (attr->value_tag == IPP_TAG_RANGE)
1391 {
1392 for (i = attr->num_values, avalue = attr->values; i > 0; i --, avalue ++)
1393 if (value >= avalue->range.lower && value <= avalue->range.upper)
1394 return (1);
1395 }
1396 else
1397 {
1398 for (i = attr->num_values, avalue = attr->values; i > 0; i --, avalue ++)
1399 if (value == avalue->integer)
1400 return (1);
1401 }
1402
1403 return (0);
1404}
1405
1406
1407/*
1408 * 'ippContainsString()' - Determine whether an attribute contains the
1409 * specified string value.
1410 *
1411 * Returns non-zero when the attribute contains a matching charset, keyword,
1412 * language, mimeMediaType, name, text, URI, or URI scheme value.
1413 *
9c0e8e5d 1414 * @since CUPS 1.7/OS X 10.9@
a469f8a5
MS
1415 */
1416
1417int /* O - 1 on a match, 0 on no match */
1418ippContainsString(
1419 ipp_attribute_t *attr, /* I - Attribute */
1420 const char *value) /* I - String value */
1421{
1422 int i; /* Looping var */
1423 _ipp_value_t *avalue; /* Current attribute value */
1424
1425
1426 DEBUG_printf(("ippContainsString(attr=%p, value=\"%s\")", attr, value));
1427
1428 /*
1429 * Range check input...
1430 */
1431
1432 if (!attr || !value)
1433 {
1434 DEBUG_puts("1ippContainsString: Returning 0 (bad input)");
1435 return (0);
1436 }
1437
1438 /*
1439 * Compare...
1440 */
1441
1442 DEBUG_printf(("1ippContainsString: attr %s, %s with %d values.",
1443 attr->name, ippTagString(attr->value_tag),
1444 attr->num_values));
1445
1446 switch (attr->value_tag & IPP_TAG_CUPS_MASK)
1447 {
1448 case IPP_TAG_CHARSET :
1449 case IPP_TAG_KEYWORD :
1450 case IPP_TAG_LANGUAGE :
1451 case IPP_TAG_MIMETYPE :
1452 case IPP_TAG_NAME :
1453 case IPP_TAG_NAMELANG :
1454 case IPP_TAG_TEXT :
1455 case IPP_TAG_TEXTLANG :
1456 case IPP_TAG_URI :
1457 case IPP_TAG_URISCHEME :
1458 for (i = attr->num_values, avalue = attr->values;
1459 i > 0;
1460 i --, avalue ++)
1461 {
1462 DEBUG_printf(("1ippContainsString: value[%d]=\"%s\"",
1463 attr->num_values - i, avalue->string.text));
1464
1465 if (!strcmp(value, avalue->string.text))
1466 {
1467 DEBUG_puts("1ippContainsString: Returning 1 (match)");
1468 return (1);
1469 }
1470 }
1471
1472 default :
1473 break;
1474 }
1475
1476 DEBUG_puts("1ippContainsString: Returning 0 (no match)");
1477
1478 return (0);
1479}
1480
1481
ef416fc2 1482/*
a2326b5b
MS
1483 * 'ippCopyAttribute()' - Copy an attribute.
1484 *
1485 * The specified attribute, @code attr@, is copied to the destination IPP message.
1486 * When @code quickcopy@ is non-zero, a "shallow" reference copy of the attribute is
1487 * created - this should only be done as long as the original source IPP message will
1488 * not be freed for the life of the destination.
1489 *
f3c17241 1490 * @since CUPS 1.6/OS X 10.8@
ef416fc2 1491 */
1492
a2326b5b
MS
1493
1494ipp_attribute_t * /* O - New attribute */
1495ippCopyAttribute(
1496 ipp_t *dst, /* I - Destination IPP message */
1497 ipp_attribute_t *srcattr, /* I - Attribute to copy */
1498 int quickcopy) /* I - 1 for a referenced copy, 0 for normal */
ef416fc2 1499{
a2326b5b
MS
1500 int i; /* Looping var */
1501 ipp_attribute_t *dstattr; /* Destination attribute */
1502 _ipp_value_t *srcval, /* Source value */
1503 *dstval; /* Destination value */
ef416fc2 1504
1505
a2326b5b
MS
1506 DEBUG_printf(("ippCopyAttribute(dst=%p, srcattr=%p, quickcopy=%d)", dst, srcattr,
1507 quickcopy));
ef416fc2 1508
a2326b5b
MS
1509 /*
1510 * Range check input...
1511 */
1512
1513 if (!dst || !srcattr)
ef416fc2 1514 return (NULL);
1515
a2326b5b
MS
1516 /*
1517 * Copy it...
1518 */
ef416fc2 1519
cb7f98ee 1520 quickcopy = quickcopy ? IPP_TAG_CUPS_CONST : 0;
a2326b5b 1521
cb7f98ee 1522 switch (srcattr->value_tag & ~IPP_TAG_CUPS_CONST)
ef416fc2 1523 {
a2326b5b
MS
1524 case IPP_TAG_ZERO :
1525 dstattr = ippAddSeparator(dst);
1526 break;
ef416fc2 1527
a2326b5b
MS
1528 case IPP_TAG_INTEGER :
1529 case IPP_TAG_ENUM :
1530 dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag,
1531 srcattr->name, srcattr->num_values, NULL);
1532 if (!dstattr)
1533 break;
1534
1535 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1536 i > 0;
1537 i --, srcval ++, dstval ++)
1538 dstval->integer = srcval->integer;
1539 break;
ef416fc2 1540
a2326b5b
MS
1541 case IPP_TAG_BOOLEAN :
1542 dstattr = ippAddBooleans(dst, srcattr->group_tag, srcattr->name,
1543 srcattr->num_values, NULL);
1544 if (!dstattr)
1545 break;
1546
1547 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1548 i > 0;
1549 i --, srcval ++, dstval ++)
1550 dstval->boolean = srcval->boolean;
1551 break;
ef416fc2 1552
a2326b5b
MS
1553 case IPP_TAG_TEXT :
1554 case IPP_TAG_NAME :
1555 case IPP_TAG_KEYWORD :
1556 case IPP_TAG_URI :
1557 case IPP_TAG_URISCHEME :
1558 case IPP_TAG_CHARSET :
1559 case IPP_TAG_LANGUAGE :
1560 case IPP_TAG_MIMETYPE :
1561 dstattr = ippAddStrings(dst, srcattr->group_tag,
1562 (ipp_tag_t)(srcattr->value_tag | quickcopy),
1563 srcattr->name, srcattr->num_values, NULL, NULL);
1564 if (!dstattr)
1565 break;
ef416fc2 1566
a2326b5b
MS
1567 if (quickcopy)
1568 {
1569 for (i = srcattr->num_values, srcval = srcattr->values,
1570 dstval = dstattr->values;
1571 i > 0;
1572 i --, srcval ++, dstval ++)
1573 dstval->string.text = srcval->string.text;
1574 }
cb7f98ee 1575 else if (srcattr->value_tag & IPP_TAG_CUPS_CONST)
a2326b5b
MS
1576 {
1577 for (i = srcattr->num_values, srcval = srcattr->values,
1578 dstval = dstattr->values;
1579 i > 0;
1580 i --, srcval ++, dstval ++)
1581 dstval->string.text = _cupsStrAlloc(srcval->string.text);
1582 }
1583 else
1584 {
1585 for (i = srcattr->num_values, srcval = srcattr->values,
1586 dstval = dstattr->values;
1587 i > 0;
1588 i --, srcval ++, dstval ++)
1589 dstval->string.text = _cupsStrRetain(srcval->string.text);
1590 }
1591 break;
ef416fc2 1592
a2326b5b
MS
1593 case IPP_TAG_DATE :
1594 if (srcattr->num_values != 1)
1595 return (NULL);
ef416fc2 1596
a2326b5b
MS
1597 dstattr = ippAddDate(dst, srcattr->group_tag, srcattr->name,
1598 srcattr->values[0].date);
1599 break;
ef416fc2 1600
a2326b5b
MS
1601 case IPP_TAG_RESOLUTION :
1602 dstattr = ippAddResolutions(dst, srcattr->group_tag, srcattr->name,
1603 srcattr->num_values, IPP_RES_PER_INCH,
1604 NULL, NULL);
1605 if (!dstattr)
1606 break;
1607
1608 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1609 i > 0;
1610 i --, srcval ++, dstval ++)
1611 {
1612 dstval->resolution.xres = srcval->resolution.xres;
1613 dstval->resolution.yres = srcval->resolution.yres;
1614 dstval->resolution.units = srcval->resolution.units;
1615 }
1616 break;
ef416fc2 1617
a2326b5b
MS
1618 case IPP_TAG_RANGE :
1619 dstattr = ippAddRanges(dst, srcattr->group_tag, srcattr->name,
1620 srcattr->num_values, NULL, NULL);
1621 if (!dstattr)
1622 break;
1623
1624 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1625 i > 0;
1626 i --, srcval ++, dstval ++)
1627 {
1628 dstval->range.lower = srcval->range.lower;
1629 dstval->range.upper = srcval->range.upper;
1630 }
1631 break;
ef416fc2 1632
a2326b5b
MS
1633 case IPP_TAG_TEXTLANG :
1634 case IPP_TAG_NAMELANG :
1635 dstattr = ippAddStrings(dst, srcattr->group_tag,
1636 (ipp_tag_t)(srcattr->value_tag | quickcopy),
1637 srcattr->name, srcattr->num_values, NULL, NULL);
1638 if (!dstattr)
1639 break;
ef416fc2 1640
a2326b5b
MS
1641 if (quickcopy)
1642 {
1643 for (i = srcattr->num_values, srcval = srcattr->values,
1644 dstval = dstattr->values;
1645 i > 0;
1646 i --, srcval ++, dstval ++)
1647 {
1648 dstval->string.language = srcval->string.language;
1649 dstval->string.text = srcval->string.text;
1650 }
1651 }
cb7f98ee 1652 else if (srcattr->value_tag & IPP_TAG_CUPS_CONST)
a2326b5b
MS
1653 {
1654 for (i = srcattr->num_values, srcval = srcattr->values,
1655 dstval = dstattr->values;
1656 i > 0;
1657 i --, srcval ++, dstval ++)
1658 {
1659 if (srcval == srcattr->values)
1660 dstval->string.language = _cupsStrAlloc(srcval->string.language);
1661 else
1662 dstval->string.language = dstattr->values[0].string.language;
ef416fc2 1663
a2326b5b
MS
1664 dstval->string.text = _cupsStrAlloc(srcval->string.text);
1665 }
1666 }
1667 else
1668 {
1669 for (i = srcattr->num_values, srcval = srcattr->values,
1670 dstval = dstattr->values;
1671 i > 0;
1672 i --, srcval ++, dstval ++)
1673 {
1674 if (srcval == srcattr->values)
1675 dstval->string.language = _cupsStrRetain(srcval->string.language);
1676 else
1677 dstval->string.language = dstattr->values[0].string.language;
ef416fc2 1678
a2326b5b
MS
1679 dstval->string.text = _cupsStrRetain(srcval->string.text);
1680 }
1681 }
1682 break;
ef416fc2 1683
a2326b5b
MS
1684 case IPP_TAG_BEGIN_COLLECTION :
1685 dstattr = ippAddCollections(dst, srcattr->group_tag, srcattr->name,
1686 srcattr->num_values, NULL);
1687 if (!dstattr)
1688 break;
1689
1690 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1691 i > 0;
1692 i --, srcval ++, dstval ++)
1693 {
1694 dstval->collection = srcval->collection;
1695 srcval->collection->use ++;
1696 }
1697 break;
ef416fc2 1698
a2326b5b
MS
1699 case IPP_TAG_STRING :
1700 default :
1701 /* TODO: Implement quick copy for unknown/octetString values */
1702 dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag,
1703 srcattr->name, srcattr->num_values, NULL);
1704 if (!dstattr)
1705 break;
1706
1707 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1708 i > 0;
1709 i --, srcval ++, dstval ++)
1710 {
1711 dstval->unknown.length = srcval->unknown.length;
ef416fc2 1712
a2326b5b
MS
1713 if (dstval->unknown.length > 0)
1714 {
1a18c85c 1715 if ((dstval->unknown.data = malloc((size_t)dstval->unknown.length)) == NULL)
a2326b5b
MS
1716 dstval->unknown.length = 0;
1717 else
1a18c85c 1718 memcpy(dstval->unknown.data, srcval->unknown.data, (size_t)dstval->unknown.length);
a2326b5b
MS
1719 }
1720 }
1721 break; /* anti-compiler-warning-code */
ef416fc2 1722 }
1723
a2326b5b 1724 return (dstattr);
ef416fc2 1725}
1726
1727
1728/*
a2326b5b 1729 * 'ippCopyAttributes()' - Copy attributes from one IPP message to another.
ef416fc2 1730 *
5d2cc5d3 1731 * Zero or more attributes are copied from the source IPP message, @code src@, to the
a2326b5b
MS
1732 * destination IPP message, @code dst@. When @code quickcopy@ is non-zero, a "shallow"
1733 * reference copy of the attribute is created - this should only be done as long as the
1734 * original source IPP message will not be freed for the life of the destination.
ef416fc2 1735 *
a2326b5b
MS
1736 * The @code cb@ and @code context@ parameters provide a generic way to "filter" the
1737 * attributes that are copied - the function must return 1 to copy the attribute or
1738 * 0 to skip it. The function may also choose to do a partial copy of the source attribute
1739 * itself.
1740 *
f3c17241 1741 * @since CUPS 1.6/OS X 10.8@
ef416fc2 1742 */
1743
a2326b5b
MS
1744int /* O - 1 on success, 0 on error */
1745ippCopyAttributes(
1746 ipp_t *dst, /* I - Destination IPP message */
1747 ipp_t *src, /* I - Source IPP message */
1748 int quickcopy, /* I - 1 for a referenced copy, 0 for normal */
1749 ipp_copycb_t cb, /* I - Copy callback or @code NULL@ for none */
1750 void *context) /* I - Context pointer */
ef416fc2 1751{
a2326b5b 1752 ipp_attribute_t *srcattr; /* Source attribute */
ef416fc2 1753
1754
a2326b5b
MS
1755 DEBUG_printf(("ippCopyAttributes(dst=%p, src=%p, quickcopy=%d, cb=%p, context=%p)",
1756 dst, src, quickcopy, cb, context));
1ff0402e 1757
ef416fc2 1758 /*
a2326b5b 1759 * Range check input...
ef416fc2 1760 */
1761
a2326b5b
MS
1762 if (!dst || !src)
1763 return (0);
ef416fc2 1764
1765 /*
a2326b5b 1766 * Loop through source attributes and copy as needed...
ef416fc2 1767 */
1768
a2326b5b
MS
1769 for (srcattr = src->attrs; srcattr; srcattr = srcattr->next)
1770 if (!cb || (*cb)(context, dst, srcattr))
1771 if (!ippCopyAttribute(dst, srcattr, quickcopy))
1772 return (0);
ef416fc2 1773
a2326b5b
MS
1774 return (1);
1775}
ef416fc2 1776
ef416fc2 1777
a2326b5b
MS
1778/*
1779 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
1780 * in seconds.
1781 */
ef416fc2 1782
a2326b5b
MS
1783time_t /* O - UNIX time value */
1784ippDateToTime(const ipp_uchar_t *date) /* I - RFC 1903 date info */
1785{
1786 struct tm unixdate; /* UNIX date/time info */
1787 time_t t; /* Computed time */
ef416fc2 1788
a2326b5b
MS
1789
1790 if (!date)
1791 return (0);
1792
1793 memset(&unixdate, 0, sizeof(unixdate));
ef416fc2 1794
1795 /*
a2326b5b
MS
1796 * RFC-1903 date/time format is:
1797 *
1798 * Byte(s) Description
1799 * ------- -----------
1800 * 0-1 Year (0 to 65535)
1801 * 2 Month (1 to 12)
1802 * 3 Day (1 to 31)
1803 * 4 Hours (0 to 23)
1804 * 5 Minutes (0 to 59)
1805 * 6 Seconds (0 to 60, 60 = "leap second")
1806 * 7 Deciseconds (0 to 9)
1807 * 8 +/- UTC
1808 * 9 UTC hours (0 to 11)
1809 * 10 UTC minutes (0 to 59)
ef416fc2 1810 */
1811
a2326b5b
MS
1812 unixdate.tm_year = ((date[0] << 8) | date[1]) - 1900;
1813 unixdate.tm_mon = date[2] - 1;
1814 unixdate.tm_mday = date[3];
1815 unixdate.tm_hour = date[4];
1816 unixdate.tm_min = date[5];
1817 unixdate.tm_sec = date[6];
1818
1819 t = mktime(&unixdate);
1820
1821 if (date[8] == '-')
1822 t += date[9] * 3600 + date[10] * 60;
1823 else
1824 t -= date[9] * 3600 + date[10] * 60;
1825
1826 return (t);
ef416fc2 1827}
1828
1829
1830/*
a2326b5b 1831 * 'ippDelete()' - Delete an IPP message.
ef416fc2 1832 */
1833
a2326b5b
MS
1834void
1835ippDelete(ipp_t *ipp) /* I - IPP message */
ef416fc2 1836{
a2326b5b
MS
1837 ipp_attribute_t *attr, /* Current attribute */
1838 *next; /* Next attribute */
ef416fc2 1839
ef416fc2 1840
a2326b5b 1841 DEBUG_printf(("ippDelete(ipp=%p)", ipp));
ef416fc2 1842
a2326b5b
MS
1843 if (!ipp)
1844 return;
1845
1846 ipp->use --;
1847 if (ipp->use > 0)
1848 return;
ef416fc2 1849
a2326b5b
MS
1850 for (attr = ipp->attrs; attr != NULL; attr = next)
1851 {
1852 next = attr->next;
ef416fc2 1853
a2326b5b 1854 ipp_free_values(attr, 0, attr->num_values);
ef416fc2 1855
a2326b5b
MS
1856 if (attr->name)
1857 _cupsStrFree(attr->name);
ef416fc2 1858
a2326b5b
MS
1859 free(attr);
1860 }
1861
1862 free(ipp);
ef416fc2 1863}
1864
1865
1866/*
a2326b5b 1867 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
ef416fc2 1868 *
f3c17241 1869 * @since CUPS 1.1.19/OS X 10.3@
ef416fc2 1870 */
1871
a2326b5b
MS
1872void
1873ippDeleteAttribute(
1874 ipp_t *ipp, /* I - IPP message */
1875 ipp_attribute_t *attr) /* I - Attribute to delete */
ef416fc2 1876{
a2326b5b
MS
1877 ipp_attribute_t *current, /* Current attribute */
1878 *prev; /* Previous attribute */
ef416fc2 1879
1880
a2326b5b
MS
1881 DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p(%s))", ipp, attr,
1882 attr ? attr->name : "(null)"));
ef416fc2 1883
a2326b5b
MS
1884 /*
1885 * Range check input...
1886 */
ef416fc2 1887
a2326b5b
MS
1888 if (!attr)
1889 return;
1f6f3dbc 1890
a2326b5b
MS
1891 /*
1892 * Find the attribute in the list...
1893 */
1894
1895 if (ipp)
ef416fc2 1896 {
a2326b5b
MS
1897 for (current = ipp->attrs, prev = NULL;
1898 current;
1899 prev = current, current = current->next)
1900 if (current == attr)
1901 {
1902 /*
1903 * Found it, remove the attribute from the list...
1904 */
ef416fc2 1905
a2326b5b
MS
1906 if (prev)
1907 prev->next = current->next;
1908 else
1909 ipp->attrs = current->next;
ef416fc2 1910
a2326b5b
MS
1911 if (current == ipp->last)
1912 ipp->last = prev;
ef416fc2 1913
a2326b5b
MS
1914 break;
1915 }
ef416fc2 1916
a2326b5b
MS
1917 if (!current)
1918 return;
1919 }
ef416fc2 1920
a2326b5b
MS
1921 /*
1922 * Free memory used by the attribute...
1923 */
ef416fc2 1924
a2326b5b 1925 ipp_free_values(attr, 0, attr->num_values);
ef416fc2 1926
a2326b5b
MS
1927 if (attr->name)
1928 _cupsStrFree(attr->name);
ef416fc2 1929
a2326b5b
MS
1930 free(attr);
1931}
ef416fc2 1932
b86bc4cf 1933
a2326b5b
MS
1934/*
1935 * 'ippDeleteValues()' - Delete values in an attribute.
1936 *
9c80ffa2
MS
1937 * The @code element@ parameter specifies the first value to delete, starting at
1938 * 0. It must be less than the number of values returned by @link ippGetCount@.
1939 *
1940 * The @code attr@ parameter may be modified as a result of setting the value.
a2326b5b
MS
1941 *
1942 * Deleting all values in an attribute deletes the attribute.
1943 *
f3c17241 1944 * @since CUPS 1.6/OS X 10.8@
a2326b5b 1945 */
ef416fc2 1946
9c80ffa2 1947int /* O - 1 on success, 0 on failure */
a2326b5b 1948ippDeleteValues(
9c80ffa2
MS
1949 ipp_t *ipp, /* I - IPP message */
1950 ipp_attribute_t **attr, /* IO - Attribute */
1951 int element, /* I - Index of first value to delete (0-based) */
1952 int count) /* I - Number of values to delete */
a2326b5b
MS
1953{
1954 /*
1955 * Range check input...
1956 */
ef416fc2 1957
9c80ffa2
MS
1958 if (!ipp || !attr || !*attr ||
1959 element < 0 || element >= (*attr)->num_values || count <= 0 ||
1960 (element + count) >= (*attr)->num_values)
a2326b5b 1961 return (0);
ef416fc2 1962
a2326b5b
MS
1963 /*
1964 * If we are deleting all values, just delete the attribute entirely.
1965 */
ef416fc2 1966
9c80ffa2 1967 if (count == (*attr)->num_values)
a2326b5b 1968 {
9c80ffa2
MS
1969 ippDeleteAttribute(ipp, *attr);
1970 *attr = NULL;
a2326b5b
MS
1971 return (1);
1972 }
ef416fc2 1973
a2326b5b
MS
1974 /*
1975 * Otherwise free the values in question and return.
1976 */
ef416fc2 1977
9c80ffa2 1978 ipp_free_values(*attr, element, count);
a2326b5b
MS
1979
1980 return (1);
1981}
1982
1983
1984/*
9c80ffa2 1985 * 'ippFindAttribute()' - Find a named attribute in a request.
1a18c85c
MS
1986 *
1987 * Starting with CUPS 2.0, the attribute name can contain a hierarchical list
1988 * of attribute and member names separated by slashes, for example
1989 * "media-col/media-size".
a2326b5b
MS
1990 */
1991
1992ipp_attribute_t * /* O - Matching attribute */
1993ippFindAttribute(ipp_t *ipp, /* I - IPP message */
1994 const char *name, /* I - Name of attribute */
1995 ipp_tag_t type) /* I - Type of attribute */
1996{
1997 DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", ipp,
1998 name, type, ippTagString(type)));
1999
2000 if (!ipp || !name)
2001 return (NULL);
2002
2003 /*
2004 * Reset the current pointer...
2005 */
2006
2007 ipp->current = NULL;
1a18c85c 2008 ipp->atend = 0;
a2326b5b
MS
2009
2010 /*
2011 * Search for the attribute...
2012 */
2013
2014 return (ippFindNextAttribute(ipp, name, type));
2015}
2016
2017
2018/*
9c80ffa2 2019 * 'ippFindNextAttribute()' - Find the next named attribute in a request.
1a18c85c
MS
2020 *
2021 * Starting with CUPS 2.0, the attribute name can contain a hierarchical list
2022 * of attribute and member names separated by slashes, for example
2023 * "media-col/media-size".
a2326b5b
MS
2024 */
2025
2026ipp_attribute_t * /* O - Matching attribute */
2027ippFindNextAttribute(ipp_t *ipp, /* I - IPP message */
2028 const char *name, /* I - Name of attribute */
2029 ipp_tag_t type) /* I - Type of attribute */
2030{
1a18c85c
MS
2031 ipp_attribute_t *attr, /* Current atttribute */
2032 *childattr; /* Child attribute */
a2326b5b 2033 ipp_tag_t value_tag; /* Value tag */
1a18c85c
MS
2034 char parent[1024], /* Parent attribute name */
2035 *child; /* Child attribute name */
a2326b5b
MS
2036
2037
2038 DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))",
2039 ipp, name, type, ippTagString(type)));
2040
2041 if (!ipp || !name)
2042 return (NULL);
2043
1a18c85c
MS
2044 DEBUG_printf(("3ippFindNextAttribute: atend=%d", ipp->atend));
2045
2046 if (ipp->atend)
2047 return (NULL);
2048
2049 if (strchr(name, '/'))
2050 {
2051 /*
2052 * Search for child attribute...
2053 */
2054
2055 strlcpy(parent, name, sizeof(parent));
2056 if ((child = strchr(parent, '/')) == NULL)
2057 {
2058 DEBUG_puts("3ippFindNextAttribute: Attribute name too long.");
2059 return (NULL);
2060 }
2061
2062 *child++ = '\0';
2063
2064 if (ipp->current && ipp->current->name && ipp->current->value_tag == IPP_TAG_BEGIN_COLLECTION && !strcmp(parent, ipp->current->name))
2065 {
2066 while (ipp->curindex < ipp->current->num_values)
2067 {
2068 if ((childattr = ippFindNextAttribute(ipp->current->values[ipp->curindex].collection, child, type)) != NULL)
2069 return (childattr);
2070
2071 ipp->curindex ++;
2072 if (ipp->curindex < ipp->current->num_values && ipp->current->values[ipp->curindex].collection)
2073 ipp->current->values[ipp->curindex].collection->current = NULL;
2074 }
2075
2076 ipp->prev = ipp->current;
2077 ipp->current = ipp->current->next;
2078 ipp->curindex = 0;
2079
2080 if (!ipp->current)
2081 {
2082 ipp->atend = 1;
2083 return (NULL);
2084 }
2085 }
2086
2087 if (!ipp->current)
2088 {
2089 ipp->prev = NULL;
2090 ipp->current = ipp->attrs;
2091 ipp->curindex = 0;
2092 }
2093
2094 name = parent;
2095 attr = ipp->current;
2096 }
2097 else if (ipp->current)
a2326b5b
MS
2098 {
2099 ipp->prev = ipp->current;
2100 attr = ipp->current->next;
2101 }
2102 else
2103 {
2104 ipp->prev = NULL;
2105 attr = ipp->attrs;
2106 }
2107
2108 for (; attr != NULL; ipp->prev = attr, attr = attr->next)
2109 {
2110 DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", attr,
2111 attr->name));
2112
cb7f98ee 2113 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK);
a2326b5b
MS
2114
2115 if (attr->name != NULL && _cups_strcasecmp(attr->name, name) == 0 &&
1a18c85c 2116 (value_tag == type || type == IPP_TAG_ZERO || name == parent ||
a2326b5b
MS
2117 (value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) ||
2118 (value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME)))
2119 {
2120 ipp->current = attr;
2121
1a18c85c
MS
2122 if (name == parent && attr->value_tag == IPP_TAG_BEGIN_COLLECTION)
2123 {
2124 int i; /* Looping var */
2125
2126 for (i = 0; i < attr->num_values; i ++)
2127 {
2128 if ((childattr = ippFindAttribute(attr->values[i].collection, child, type)) != NULL)
2129 {
2130 attr->values[0].collection->curindex = i;
2131 return (childattr);
2132 }
2133 }
2134 }
2135 else
2136 return (attr);
a2326b5b
MS
2137 }
2138 }
2139
2140 ipp->current = NULL;
2141 ipp->prev = NULL;
1a18c85c 2142 ipp->atend = 1;
a2326b5b
MS
2143
2144 return (NULL);
2145}
2146
2147
2148/*
2149 * 'ippFirstAttribute()' - Return the first attribute in the message.
2150 *
f3c17241 2151 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2152 */
2153
2154ipp_attribute_t * /* O - First attribute or @code NULL@ if none */
2155ippFirstAttribute(ipp_t *ipp) /* I - IPP message */
2156{
2157 /*
2158 * Range check input...
2159 */
2160
2161 if (!ipp)
2162 return (NULL);
2163
2164 /*
2165 * Return the first attribute...
2166 */
2167
2168 return (ipp->current = ipp->attrs);
2169}
2170
2171
2172/*
2173 * 'ippGetBoolean()' - Get a boolean value for an attribute.
2174 *
2175 * The @code element@ parameter specifies which value to get from 0 to
2176 * @link ippGetCount(attr)@ - 1.
2177 *
f3c17241 2178 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2179 */
2180
a51f28ec 2181int /* O - Boolean value or 0 on error */
a2326b5b
MS
2182ippGetBoolean(ipp_attribute_t *attr, /* I - IPP attribute */
2183 int element) /* I - Value number (0-based) */
2184{
2185 /*
2186 * Range check input...
2187 */
2188
2189 if (!attr || attr->value_tag != IPP_TAG_BOOLEAN ||
2190 element < 0 || element >= attr->num_values)
a51f28ec 2191 return (0);
a2326b5b
MS
2192
2193 /*
2194 * Return the value...
2195 */
2196
2197 return (attr->values[element].boolean);
2198}
2199
2200
2201/*
2202 * 'ippGetCollection()' - Get a collection value for an attribute.
2203 *
2204 * The @code element@ parameter specifies which value to get from 0 to
2205 * @link ippGetCount(attr)@ - 1.
2206 *
f3c17241 2207 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2208 */
2209
2210ipp_t * /* O - Collection value or @code NULL@ on error */
2211ippGetCollection(
2212 ipp_attribute_t *attr, /* I - IPP attribute */
2213 int element) /* I - Value number (0-based) */
2214{
2215 /*
2216 * Range check input...
2217 */
2218
2219 if (!attr || attr->value_tag != IPP_TAG_BEGIN_COLLECTION ||
2220 element < 0 || element >= attr->num_values)
2221 return (NULL);
2222
2223 /*
2224 * Return the value...
2225 */
2226
2227 return (attr->values[element].collection);
2228}
2229
2230
2231/*
2232 * 'ippGetCount()' - Get the number of values in an attribute.
2233 *
f3c17241 2234 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2235 */
2236
a51f28ec 2237int /* O - Number of values or 0 on error */
a2326b5b
MS
2238ippGetCount(ipp_attribute_t *attr) /* I - IPP attribute */
2239{
2240 /*
2241 * Range check input...
2242 */
2243
2244 if (!attr)
a51f28ec 2245 return (0);
a2326b5b
MS
2246
2247 /*
2248 * Return the number of values...
2249 */
2250
2251 return (attr->num_values);
2252}
2253
2254
9c80ffa2
MS
2255/*
2256 * 'ippGetDate()' - Get a date value for an attribute.
2257 *
2258 * The @code element@ parameter specifies which value to get from 0 to
2259 * @link ippGetCount(attr)@ - 1.
2260 *
f3c17241 2261 * @since CUPS 1.6/OS X 10.8@
9c80ffa2
MS
2262 */
2263
2264const ipp_uchar_t * /* O - Date value or @code NULL@ */
2265ippGetDate(ipp_attribute_t *attr, /* I - IPP attribute */
2266 int element) /* I - Value number (0-based) */
2267{
2268 /*
2269 * Range check input...
2270 */
2271
2272 if (!attr || attr->value_tag != IPP_TAG_DATE ||
2273 element < 0 || element >= attr->num_values)
2274 return (NULL);
2275
2276 /*
2277 * Return the value...
2278 */
2279
2280 return (attr->values[element].date);
2281}
2282
2283
a2326b5b
MS
2284/*
2285 * 'ippGetGroupTag()' - Get the group associated with an attribute.
2286 *
f3c17241 2287 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2288 */
2289
2290ipp_tag_t /* O - Group tag or @code IPP_TAG_ZERO@ on error */
2291ippGetGroupTag(ipp_attribute_t *attr) /* I - IPP attribute */
2292{
2293 /*
2294 * Range check input...
2295 */
2296
2297 if (!attr)
2298 return (IPP_TAG_ZERO);
2299
2300 /*
2301 * Return the group...
2302 */
2303
2304 return (attr->group_tag);
2305}
2306
2307
2308/*
2309 * 'ippGetInteger()' - Get the integer/enum value for an attribute.
2310 *
2311 * The @code element@ parameter specifies which value to get from 0 to
2312 * @link ippGetCount(attr)@ - 1.
2313 *
f3c17241 2314 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2315 */
2316
a51f28ec 2317int /* O - Value or 0 on error */
a2326b5b
MS
2318ippGetInteger(ipp_attribute_t *attr, /* I - IPP attribute */
2319 int element) /* I - Value number (0-based) */
2320{
2321 /*
2322 * Range check input...
2323 */
2324
2325 if (!attr || (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM) ||
2326 element < 0 || element >= attr->num_values)
a51f28ec 2327 return (0);
a2326b5b
MS
2328
2329 /*
2330 * Return the value...
2331 */
2332
2333 return (attr->values[element].integer);
2334}
2335
2336
2337/*
2338 * 'ippGetName()' - Get the attribute name.
2339 *
f3c17241 2340 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2341 */
2342
2343const char * /* O - Attribute name or @code NULL@ for separators */
2344ippGetName(ipp_attribute_t *attr) /* I - IPP attribute */
2345{
2346 /*
2347 * Range check input...
2348 */
2349
2350 if (!attr)
2351 return (NULL);
2352
2353 /*
2354 * Return the name...
2355 */
2356
2357 return (attr->name);
2358}
2359
2360
6961465f
MS
2361/*
2362 * 'ippGetOctetString()' - Get an octetString value from an IPP attribute.
2363 *
2364 * The @code element@ parameter specifies which value to get from 0 to
2365 * @link ippGetCount(attr)@ - 1.
2366 *
9c0e8e5d 2367 * @since CUPS 1.7/OS X 10.9@
6961465f
MS
2368 */
2369
2370void * /* O - Pointer to octetString data */
2371ippGetOctetString(
2372 ipp_attribute_t *attr, /* I - IPP attribute */
2373 int element, /* I - Value number (0-based) */
2374 int *datalen) /* O - Length of octetString data */
2375{
2376 /*
2377 * Range check input...
2378 */
2379
2380 if (!attr || attr->value_tag != IPP_TAG_STRING ||
2381 element < 0 || element >= attr->num_values)
2382 {
2383 if (datalen)
2384 *datalen = 0;
2385
2386 return (NULL);
2387 }
2388
2389 /*
2390 * Return the values...
2391 */
2392
2393 if (datalen)
2394 *datalen = attr->values[element].unknown.length;
2395
2396 return (attr->values[element].unknown.data);
2397}
2398
2399
a2326b5b
MS
2400/*
2401 * 'ippGetOperation()' - Get the operation ID in an IPP message.
2402 *
f3c17241 2403 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2404 */
2405
a51f28ec 2406ipp_op_t /* O - Operation ID or 0 on error */
a2326b5b
MS
2407ippGetOperation(ipp_t *ipp) /* I - IPP request message */
2408{
2409 /*
2410 * Range check input...
2411 */
2412
2413 if (!ipp)
a51f28ec 2414 return ((ipp_op_t)0);
a2326b5b
MS
2415
2416 /*
2417 * Return the value...
2418 */
2419
2420 return (ipp->request.op.operation_id);
2421}
2422
2423
9c80ffa2
MS
2424/*
2425 * 'ippGetRange()' - Get a rangeOfInteger value from an attribute.
2426 *
2427 * The @code element@ parameter specifies which value to get from 0 to
2428 * @link ippGetCount(attr)@ - 1.
2429 *
f3c17241 2430 * @since CUPS 1.6/OS X 10.8@
9c80ffa2
MS
2431 */
2432
a51f28ec 2433int /* O - Lower value of range or 0 */
9c80ffa2
MS
2434ippGetRange(ipp_attribute_t *attr, /* I - IPP attribute */
2435 int element, /* I - Value number (0-based) */
2436 int *uppervalue)/* O - Upper value of range */
2437{
2438 /*
2439 * Range check input...
2440 */
2441
2442 if (!attr || attr->value_tag != IPP_TAG_RANGE ||
2443 element < 0 || element >= attr->num_values)
2444 {
2445 if (uppervalue)
a51f28ec 2446 *uppervalue = 0;
9c80ffa2 2447
a51f28ec 2448 return (0);
9c80ffa2
MS
2449 }
2450
2451 /*
2452 * Return the values...
2453 */
2454
2455 if (uppervalue)
2456 *uppervalue = attr->values[element].range.upper;
2457
2458 return (attr->values[element].range.lower);
2459}
2460
2461
a2326b5b
MS
2462/*
2463 * 'ippGetRequestId()' - Get the request ID from an IPP message.
2464 *
f3c17241 2465 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2466 */
2467
a51f28ec 2468int /* O - Request ID or 0 on error */
a2326b5b
MS
2469ippGetRequestId(ipp_t *ipp) /* I - IPP message */
2470{
2471 /*
2472 * Range check input...
2473 */
2474
2475 if (!ipp)
a51f28ec 2476 return (0);
a2326b5b
MS
2477
2478 /*
2479 * Return the request ID...
2480 */
2481
2482 return (ipp->request.any.request_id);
2483}
2484
2485
2486/*
2487 * 'ippGetResolution()' - Get a resolution value for an attribute.
2488 *
2489 * The @code element@ parameter specifies which value to get from 0 to
2490 * @link ippGetCount(attr)@ - 1.
2491 *
f3c17241 2492 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2493 */
2494
a51f28ec 2495int /* O - Horizontal/cross feed resolution or 0 */
a2326b5b
MS
2496ippGetResolution(
2497 ipp_attribute_t *attr, /* I - IPP attribute */
2498 int element, /* I - Value number (0-based) */
2499 int *yres, /* O - Vertical/feed resolution */
2500 ipp_res_t *units) /* O - Units for resolution */
2501{
2502 /*
2503 * Range check input...
2504 */
2505
2506 if (!attr || attr->value_tag != IPP_TAG_RESOLUTION ||
2507 element < 0 || element >= attr->num_values)
a51f28ec
MS
2508 {
2509 if (yres)
2510 *yres = 0;
2511
2512 if (units)
2513 *units = (ipp_res_t)0;
2514
2515 return (0);
2516 }
a2326b5b
MS
2517
2518 /*
2519 * Return the value...
2520 */
2521
2522 if (yres)
2523 *yres = attr->values[element].resolution.yres;
2524
2525 if (units)
2526 *units = attr->values[element].resolution.units;
2527
2528 return (attr->values[element].resolution.xres);
2529}
2530
2531
9c80ffa2
MS
2532/*
2533 * 'ippGetState()' - Get the IPP message state.
2534 *
f3c17241 2535 * @since CUPS 1.6/OS X 10.8@
9c80ffa2
MS
2536 */
2537
2538ipp_state_t /* O - IPP message state value */
2539ippGetState(ipp_t *ipp) /* I - IPP message */
2540{
2541 /*
2542 * Range check input...
2543 */
2544
2545 if (!ipp)
cb7f98ee 2546 return (IPP_STATE_IDLE);
9c80ffa2
MS
2547
2548 /*
2549 * Return the value...
2550 */
2551
2552 return (ipp->state);
2553}
2554
2555
a2326b5b
MS
2556/*
2557 * 'ippGetStatusCode()' - Get the status code from an IPP response or event message.
2558 *
f3c17241 2559 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2560 */
2561
2562ipp_status_t /* O - Status code in IPP message */
2563ippGetStatusCode(ipp_t *ipp) /* I - IPP response or event message */
2564{
2565 /*
2566 * Range check input...
2567 */
2568
2569 if (!ipp)
cb7f98ee 2570 return (IPP_STATUS_ERROR_INTERNAL);
a2326b5b
MS
2571
2572 /*
2573 * Return the value...
2574 */
2575
2576 return (ipp->request.status.status_code);
2577}
2578
2579
2580/*
2581 * 'ippGetString()' - Get the string and optionally the language code for an attribute.
2582 *
2583 * The @code element@ parameter specifies which value to get from 0 to
2584 * @link ippGetCount(attr)@ - 1.
2585 *
f3c17241 2586 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2587 */
2588
2589const char *
2590ippGetString(ipp_attribute_t *attr, /* I - IPP attribute */
2591 int element, /* I - Value number (0-based) */
2592 const char **language)/* O - Language code (@code NULL@ for don't care) */
2593{
2594 /*
2595 * Range check input...
2596 */
2597
2598 if (!attr || element < 0 || element >= attr->num_values ||
2599 (attr->value_tag != IPP_TAG_TEXTLANG && attr->value_tag != IPP_TAG_NAMELANG &&
2600 (attr->value_tag < IPP_TAG_TEXT || attr->value_tag > IPP_TAG_MIMETYPE)))
2601 return (NULL);
2602
2603 /*
2604 * Return the value...
2605 */
2606
2607 if (language)
2608 *language = attr->values[element].string.language;
2609
2610 return (attr->values[element].string.text);
2611}
2612
2613
2614/*
2615 * 'ippGetValueTag()' - Get the value tag for an attribute.
2616 *
f3c17241 2617 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2618 */
2619
2620ipp_tag_t /* O - Value tag or @code IPP_TAG_ZERO@ on error */
2621ippGetValueTag(ipp_attribute_t *attr) /* I - IPP attribute */
2622{
2623 /*
2624 * Range check input...
2625 */
2626
2627 if (!attr)
2628 return (IPP_TAG_ZERO);
2629
2630 /*
2631 * Return the value...
2632 */
2633
cb7f98ee 2634 return (attr->value_tag & IPP_TAG_CUPS_MASK);
a2326b5b
MS
2635}
2636
2637
2638/*
2639 * 'ippGetVersion()' - Get the major and minor version number from an IPP message.
2640 *
f3c17241 2641 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2642 */
2643
a51f28ec 2644int /* O - Major version number or 0 on error */
a2326b5b
MS
2645ippGetVersion(ipp_t *ipp, /* I - IPP message */
2646 int *minor) /* O - Minor version number or @code NULL@ */
2647{
2648 /*
2649 * Range check input...
2650 */
2651
2652 if (!ipp)
2653 {
2654 if (minor)
a51f28ec 2655 *minor = 0;
a2326b5b 2656
a51f28ec 2657 return (0);
a2326b5b
MS
2658 }
2659
2660 /*
2661 * Return the value...
2662 */
2663
2664 if (minor)
2665 *minor = ipp->request.any.version[1];
2666
2667 return (ipp->request.any.version[0]);
2668}
2669
2670
2671/*
2672 * 'ippLength()' - Compute the length of an IPP message.
2673 */
2674
2675size_t /* O - Size of IPP message */
2676ippLength(ipp_t *ipp) /* I - IPP message */
2677{
2678 return (ipp_length(ipp, 0));
2679}
2680
2681
2682/*
2683 * 'ippNextAttribute()' - Return the next attribute in the message.
2684 *
f3c17241 2685 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
2686 */
2687
2688ipp_attribute_t * /* O - Next attribute or @code NULL@ if none */
2689ippNextAttribute(ipp_t *ipp) /* I - IPP message */
2690{
2691 /*
2692 * Range check input...
2693 */
2694
2695 if (!ipp || !ipp->current)
2696 return (NULL);
2697
2698 /*
2699 * Return the next attribute...
2700 */
2701
2702 return (ipp->current = ipp->current->next);
2703}
2704
2705
2706/*
2707 * 'ippNew()' - Allocate a new IPP message.
2708 */
2709
2710ipp_t * /* O - New IPP message */
2711ippNew(void)
2712{
0cb67df3
MS
2713 ipp_t *temp; /* New IPP message */
2714 _cups_globals_t *cg = _cupsGlobals();
2715 /* Global data */
a2326b5b
MS
2716
2717
2718 DEBUG_puts("ippNew()");
2719
2720 if ((temp = (ipp_t *)calloc(1, sizeof(ipp_t))) != NULL)
2721 {
2722 /*
0cb67df3 2723 * Set default version - usually 2.0...
a2326b5b
MS
2724 */
2725
567f49cb
MS
2726 if (cg->server_version == 0)
2727 _cupsSetDefaults();
2728
1a18c85c
MS
2729 temp->request.any.version[0] = (ipp_uchar_t)(cg->server_version / 10);
2730 temp->request.any.version[1] = (ipp_uchar_t)(cg->server_version % 10);
a2326b5b
MS
2731 temp->use = 1;
2732 }
2733
2734 DEBUG_printf(("1ippNew: Returning %p", temp));
2735
2736 return (temp);
2737}
2738
2739
2740/*
2741 * 'ippNewRequest()' - Allocate a new IPP request message.
2742 *
2743 * The new request message is initialized with the attributes-charset and
2744 * attributes-natural-language attributes added. The
2745 * attributes-natural-language value is derived from the current locale.
2746 *
f3c17241 2747 * @since CUPS 1.2/OS X 10.5@
a2326b5b
MS
2748 */
2749
2750ipp_t * /* O - IPP request message */
2751ippNewRequest(ipp_op_t op) /* I - Operation code */
2752{
2753 ipp_t *request; /* IPP request message */
2754 cups_lang_t *language; /* Current language localization */
2755 static int request_id = 0; /* Current request ID */
2756 static _cups_mutex_t request_mutex = _CUPS_MUTEX_INITIALIZER;
2757 /* Mutex for request ID */
2758
2759
2760 DEBUG_printf(("ippNewRequest(op=%02x(%s))", op, ippOpString(op)));
2761
2762 /*
2763 * Create a new IPP message...
2764 */
2765
2766 if ((request = ippNew()) == NULL)
2767 return (NULL);
2768
2769 /*
2770 * Set the operation and request ID...
2771 */
2772
2773 _cupsMutexLock(&request_mutex);
2774
2775 request->request.op.operation_id = op;
2776 request->request.op.request_id = ++request_id;
2777
2778 _cupsMutexUnlock(&request_mutex);
2779
2780 /*
2781 * Use UTF-8 as the character set...
2782 */
2783
2784 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2785 "attributes-charset", NULL, "utf-8");
2786
2787 /*
2788 * Get the language from the current locale...
2789 */
2790
2791 language = cupsLangDefault();
2792
2793 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2794 "attributes-natural-language", NULL, language->language);
2795
2796 /*
2797 * Return the new request...
2798 */
2799
2800 return (request);
2801}
2802
2803
a469f8a5
MS
2804/*
2805 * 'ippNewResponse()' - Allocate a new IPP response message.
2806 *
2807 * The new response message is initialized with the same version-number,
2808 * request-id, attributes-charset, and attributes-natural-language as the
2809 * provided request message. If the attributes-charset or
2810 * attributes-natural-language attributes are missing from the request,
2811 * "utf-8" and a value derived from the current locale are substituted,
2812 * respectively.
2813 *
9c0e8e5d 2814 * @since CUPS 1.7/OS X 10.9@
a469f8a5
MS
2815 */
2816
2817ipp_t * /* O - IPP response message */
2818ippNewResponse(ipp_t *request) /* I - IPP request message */
2819{
2820 ipp_t *response; /* IPP response message */
2821 ipp_attribute_t *attr; /* Current attribute */
2822
2823
2824 /*
2825 * Range check input...
2826 */
2827
2828 if (!request)
2829 return (NULL);
2830
2831 /*
2832 * Create a new IPP message...
2833 */
2834
2835 if ((response = ippNew()) == NULL)
2836 return (NULL);
2837
2838 /*
2839 * Copy the request values over to the response...
2840 */
2841
2842 response->request.status.version[0] = request->request.op.version[0];
2843 response->request.status.version[1] = request->request.op.version[1];
2844 response->request.status.request_id = request->request.op.request_id;
2845
2846 /*
2847 * The first attribute MUST be attributes-charset...
2848 */
2849
2850 attr = request->attrs;
2851
2852 if (attr && attr->name && !strcmp(attr->name, "attributes-charset") &&
2853 attr->group_tag == IPP_TAG_OPERATION &&
2854 attr->value_tag == IPP_TAG_CHARSET &&
2855 attr->num_values == 1)
2856 {
2857 /*
2858 * Copy charset from request...
2859 */
2860
2861 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2862 "attributes-charset", NULL, attr->values[0].string.text);
2863 }
2864 else
2865 {
2866 /*
2867 * Use "utf-8" as the default...
2868 */
2869
2870 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2871 "attributes-charset", NULL, "utf-8");
2872 }
2873
2874 /*
2875 * Then attributes-natural-language...
2876 */
2877
2878 if (attr)
2879 attr = attr->next;
2880
2881 if (attr && attr->name &&
2882 !strcmp(attr->name, "attributes-natural-language") &&
2883 attr->group_tag == IPP_TAG_OPERATION &&
2884 attr->value_tag == IPP_TAG_LANGUAGE &&
2885 attr->num_values == 1)
2886 {
2887 /*
2888 * Copy language from request...
2889 */
2890
2891 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2892 "attributes-natural-language", NULL,
2893 attr->values[0].string.text);
2894 }
2895 else
2896 {
2897 /*
2898 * Use the language from the current locale...
2899 */
2900
2901 cups_lang_t *language = cupsLangDefault();
2902 /* Current locale */
2903
2904 ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2905 "attributes-natural-language", NULL, language->language);
2906 }
2907
2908 return (response);
2909}
2910
2911
a2326b5b
MS
2912/*
2913 * 'ippRead()' - Read data for an IPP message from a HTTP connection.
2914 */
2915
2916ipp_state_t /* O - Current state */
2917ippRead(http_t *http, /* I - HTTP connection */
2918 ipp_t *ipp) /* I - IPP data */
2919{
2920 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT,
2921 http, ipp, CUPS_LLCAST (http ? http->data_remaining : -1)));
2922
2923 if (!http)
cb7f98ee 2924 return (IPP_STATE_ERROR);
a2326b5b
MS
2925
2926 DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http->state,
2927 http->used));
2928
2929 return (ippReadIO(http, (ipp_iocb_t)ipp_read_http, http->blocking, NULL,
2930 ipp));
2931}
2932
2933
2934/*
2935 * 'ippReadFile()' - Read data for an IPP message from a file.
2936 *
f3c17241 2937 * @since CUPS 1.1.19/OS X 10.3@
a2326b5b
MS
2938 */
2939
2940ipp_state_t /* O - Current state */
2941ippReadFile(int fd, /* I - HTTP data */
2942 ipp_t *ipp) /* I - IPP data */
2943{
2944 DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd, ipp));
2945
2946 return (ippReadIO(&fd, (ipp_iocb_t)ipp_read_file, 1, NULL, ipp));
2947}
2948
2949
2950/*
2951 * 'ippReadIO()' - Read data for an IPP message.
2952 *
f3c17241 2953 * @since CUPS 1.2/OS X 10.5@
a2326b5b
MS
2954 */
2955
2956ipp_state_t /* O - Current state */
2957ippReadIO(void *src, /* I - Data source */
2958 ipp_iocb_t cb, /* I - Read callback function */
2959 int blocking, /* I - Use blocking IO? */
2960 ipp_t *parent, /* I - Parent request, if any */
2961 ipp_t *ipp) /* I - IPP data */
2962{
2963 int n; /* Length of data */
2964 unsigned char *buffer, /* Data buffer */
5a9febac 2965 string[IPP_MAX_TEXT],
a2326b5b
MS
2966 /* Small string buffer */
2967 *bufptr; /* Pointer into buffer */
2968 ipp_attribute_t *attr; /* Current attribute */
2969 ipp_tag_t tag; /* Current tag */
2970 ipp_tag_t value_tag; /* Current value tag */
2971 _ipp_value_t *value; /* Current value */
2972
2973
2974 DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
2975 src, cb, blocking, parent, ipp));
cb7f98ee 2976 DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp ? ipp->state : IPP_STATE_ERROR));
a2326b5b
MS
2977
2978 if (!src || !ipp)
cb7f98ee 2979 return (IPP_STATE_ERROR);
a2326b5b 2980
dcb445bc 2981 if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
a2326b5b
MS
2982 {
2983 DEBUG_puts("1ippReadIO: Unable to get read buffer.");
cb7f98ee 2984 return (IPP_STATE_ERROR);
a2326b5b
MS
2985 }
2986
2987 switch (ipp->state)
2988 {
cb7f98ee 2989 case IPP_STATE_IDLE :
a2326b5b
MS
2990 ipp->state ++; /* Avoid common problem... */
2991
cb7f98ee 2992 case IPP_STATE_HEADER :
a2326b5b
MS
2993 if (parent == NULL)
2994 {
2995 /*
2996 * Get the request header...
2997 */
2998
2999 if ((*cb)(src, buffer, 8) < 8)
3000 {
3001 DEBUG_puts("1ippReadIO: Unable to read header.");
dcb445bc 3002 _cupsBufferRelease((char *)buffer);
cb7f98ee 3003 return (IPP_STATE_ERROR);
a2326b5b
MS
3004 }
3005
3006 /*
3007 * Then copy the request header over...
3008 */
3009
3010 ipp->request.any.version[0] = buffer[0];
3011 ipp->request.any.version[1] = buffer[1];
3012 ipp->request.any.op_status = (buffer[2] << 8) | buffer[3];
3013 ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) |
3014 buffer[6]) << 8) | buffer[7];
3015
3016 DEBUG_printf(("2ippReadIO: version=%d.%d", buffer[0], buffer[1]));
3017 DEBUG_printf(("2ippReadIO: op_status=%04x",
3018 ipp->request.any.op_status));
3019 DEBUG_printf(("2ippReadIO: request_id=%d",
3020 ipp->request.any.request_id));
3021 }
3022
cb7f98ee 3023 ipp->state = IPP_STATE_ATTRIBUTE;
a2326b5b
MS
3024 ipp->current = NULL;
3025 ipp->curtag = IPP_TAG_ZERO;
3026 ipp->prev = ipp->last;
3027
3028 /*
3029 * If blocking is disabled, stop here...
3030 */
3031
3032 if (!blocking)
3033 break;
3034
cb7f98ee 3035 case IPP_STATE_ATTRIBUTE :
a2326b5b
MS
3036 for (;;)
3037 {
3038 if ((*cb)(src, buffer, 1) < 1)
3039 {
3040 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
dcb445bc 3041 _cupsBufferRelease((char *)buffer);
cb7f98ee 3042 return (IPP_STATE_ERROR);
a2326b5b
MS
3043 }
3044
3045 DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p",
3046 ipp->current, ipp->prev));
3047
3048 /*
3049 * Read this attribute...
3050 */
3051
3052 tag = (ipp_tag_t)buffer[0];
3053 if (tag == IPP_TAG_EXTENSION)
3054 {
3055 /*
3056 * Read 32-bit "extension" tag...
3057 */
3058
3059 if ((*cb)(src, buffer, 4) < 1)
3060 {
3061 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
dcb445bc 3062 _cupsBufferRelease((char *)buffer);
cb7f98ee 3063 return (IPP_STATE_ERROR);
a2326b5b
MS
3064 }
3065
3066 tag = (ipp_tag_t)((((((buffer[0] << 8) | buffer[1]) << 8) |
3067 buffer[2]) << 8) | buffer[3]);
3068
cb7f98ee 3069 if (tag & IPP_TAG_CUPS_CONST)
a2326b5b
MS
3070 {
3071 /*
3072 * Fail if the high bit is set in the tag...
3073 */
3074
cb7f98ee 3075 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
a29fd7dd 3076 DEBUG_printf(("1ippReadIO: bad tag 0x%x.", tag));
dcb445bc 3077 _cupsBufferRelease((char *)buffer);
cb7f98ee 3078 return (IPP_STATE_ERROR);
a2326b5b
MS
3079 }
3080 }
3081
3082 if (tag == IPP_TAG_END)
3083 {
3084 /*
3085 * No more attributes left...
3086 */
3087
3088 DEBUG_puts("2ippReadIO: IPP_TAG_END.");
3089
cb7f98ee 3090 ipp->state = IPP_STATE_DATA;
a2326b5b
MS
3091 break;
3092 }
3093 else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
3094 {
3095 /*
3096 * Group tag... Set the current group and continue...
3097 */
3098
3099 if (ipp->curtag == tag)
3100 ipp->prev = ippAddSeparator(ipp);
3101 else if (ipp->current)
3102 ipp->prev = ipp->current;
ef416fc2 3103
3104 ipp->curtag = tag;
3105 ipp->current = NULL;
e07d4801 3106 DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag,
1ff0402e 3107 ippTagString(tag), ipp->prev));
ef416fc2 3108 continue;
3109 }
3110
a2326b5b
MS
3111 DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag,
3112 ippTagString(tag)));
3113
3114 /*
3115 * Get the name...
3116 */
3117
3118 if ((*cb)(src, buffer, 2) < 2)
3119 {
3120 DEBUG_puts("1ippReadIO: unable to read name length.");
dcb445bc 3121 _cupsBufferRelease((char *)buffer);
cb7f98ee 3122 return (IPP_STATE_ERROR);
a2326b5b
MS
3123 }
3124
3125 n = (buffer[0] << 8) | buffer[1];
3126
3127 if (n >= IPP_BUF_SIZE)
3128 {
cb7f98ee 3129 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP name larger than 32767 bytes."), 1);
a2326b5b 3130 DEBUG_printf(("1ippReadIO: bad name length %d.", n));
dcb445bc 3131 _cupsBufferRelease((char *)buffer);
cb7f98ee 3132 return (IPP_STATE_ERROR);
a2326b5b
MS
3133 }
3134
3135 DEBUG_printf(("2ippReadIO: name length=%d", n));
3136
3137 if (n == 0 && tag != IPP_TAG_MEMBERNAME &&
3138 tag != IPP_TAG_END_COLLECTION)
3139 {
3140 /*
3141 * More values for current attribute...
3142 */
3143
3144 if (ipp->current == NULL)
3145 {
cb7f98ee 3146 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP attribute has no name."), 1);
a2326b5b 3147 DEBUG_puts("1ippReadIO: Attribute without name and no current.");
dcb445bc 3148 _cupsBufferRelease((char *)buffer);
cb7f98ee 3149 return (IPP_STATE_ERROR);
a2326b5b
MS
3150 }
3151
3152 attr = ipp->current;
cb7f98ee 3153 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK);
a2326b5b
MS
3154
3155 /*
3156 * Make sure we aren't adding a new value of a different
3157 * type...
3158 */
3159
3160 if (value_tag == IPP_TAG_ZERO)
3161 {
3162 /*
3163 * Setting the value of a collection member...
3164 */
3165
3166 attr->value_tag = tag;
3167 }
3168 else if (value_tag == IPP_TAG_TEXTLANG ||
3169 value_tag == IPP_TAG_NAMELANG ||
3170 (value_tag >= IPP_TAG_TEXT &&
3171 value_tag <= IPP_TAG_MIMETYPE))
3172 {
3173 /*
3174 * String values can sometimes come across in different
3175 * forms; accept sets of differing values...
3176 */
3177
3178 if (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG &&
3179 (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE) &&
3180 tag != IPP_TAG_NOVALUE)
3181 {
cb7f98ee 3182 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a2326b5b
MS
3183 _("IPP 1setOf attribute with incompatible value "
3184 "tags."), 1);
3185 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3186 value_tag, ippTagString(value_tag), tag,
3187 ippTagString(tag)));
dcb445bc 3188 _cupsBufferRelease((char *)buffer);
cb7f98ee 3189 return (IPP_STATE_ERROR);
a2326b5b
MS
3190 }
3191
3192 if (value_tag != tag)
3193 {
3194 DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.",
3195 attr->name, ippTagString(value_tag), ippTagString(tag)));
3196 ippSetValueTag(ipp, &attr, tag);
3197 }
3198 }
3199 else if (value_tag == IPP_TAG_INTEGER ||
3200 value_tag == IPP_TAG_RANGE)
3201 {
3202 /*
3203 * Integer and rangeOfInteger values can sometimes be mixed; accept
3204 * sets of differing values...
3205 */
3206
3207 if (tag != IPP_TAG_INTEGER && tag != IPP_TAG_RANGE)
3208 {
cb7f98ee 3209 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a2326b5b
MS
3210 _("IPP 1setOf attribute with incompatible value "
3211 "tags."), 1);
3212 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
3213 value_tag, ippTagString(value_tag), tag,
3214 ippTagString(tag)));
dcb445bc 3215 _cupsBufferRelease((char *)buffer);
cb7f98ee 3216 return (IPP_STATE_ERROR);
a2326b5b
MS
3217 }
3218
3219 if (value_tag == IPP_TAG_INTEGER && tag == IPP_TAG_RANGE)
3220 {
3221 /*
3222 * Convert integer values to rangeOfInteger values...
3223 */
3224
3225 DEBUG_printf(("1ippReadIO: Converting %s attribute to "
3226 "rangeOfInteger.", attr->name));
3227 ippSetValueTag(ipp, &attr, IPP_TAG_RANGE);
3228 }
3229 }
3230 else if (value_tag != tag)
3231 {
cb7f98ee 3232 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a2326b5b
MS
3233 _("IPP 1setOf attribute with incompatible value "
3234 "tags."), 1);
3235 DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
3236 value_tag, ippTagString(value_tag), tag,
3237 ippTagString(tag)));
dcb445bc 3238 _cupsBufferRelease((char *)buffer);
cb7f98ee 3239 return (IPP_STATE_ERROR);
a2326b5b
MS
3240 }
3241
3242 /*
3243 * Finally, reallocate the attribute array as needed...
3244 */
3245
3246 if ((value = ipp_set_value(ipp, &attr, attr->num_values)) == NULL)
3247 {
dcb445bc 3248 _cupsBufferRelease((char *)buffer);
cb7f98ee 3249 return (IPP_STATE_ERROR);
a2326b5b
MS
3250 }
3251 }
3252 else if (tag == IPP_TAG_MEMBERNAME)
3253 {
3254 /*
3255 * Name must be length 0!
3256 */
3257
3258 if (n)
3259 {
cb7f98ee 3260 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP member name is not empty."), 1);
a2326b5b 3261 DEBUG_puts("1ippReadIO: member name not empty.");
dcb445bc 3262 _cupsBufferRelease((char *)buffer);
cb7f98ee 3263 return (IPP_STATE_ERROR);
a2326b5b
MS
3264 }
3265
3266 if (ipp->current)
3267 ipp->prev = ipp->current;
3268
3269 attr = ipp->current = ipp_add_attr(ipp, NULL, ipp->curtag, IPP_TAG_ZERO, 1);
0fa6c7fa
MS
3270 if (!attr)
3271 {
cb7f98ee 3272 _cupsSetHTTPError(HTTP_STATUS_ERROR);
0fa6c7fa
MS
3273 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
3274 _cupsBufferRelease((char *)buffer);
cb7f98ee 3275 return (IPP_STATE_ERROR);
0fa6c7fa 3276 }
a2326b5b
MS
3277
3278 DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p",
3279 ipp->current, ipp->prev));
3280
9c80ffa2 3281 value = attr->values;
a2326b5b
MS
3282 }
3283 else if (tag != IPP_TAG_END_COLLECTION)
3284 {
3285 /*
3286 * New attribute; read the name and add it...
3287 */
3288
1a18c85c 3289 if ((*cb)(src, buffer, (size_t)n) < n)
a2326b5b
MS
3290 {
3291 DEBUG_puts("1ippReadIO: unable to read name.");
dcb445bc 3292 _cupsBufferRelease((char *)buffer);
cb7f98ee 3293 return (IPP_STATE_ERROR);
a2326b5b
MS
3294 }
3295
3296 buffer[n] = '\0';
3297
3298 if (ipp->current)
3299 ipp->prev = ipp->current;
3300
3301 if ((attr = ipp->current = ipp_add_attr(ipp, (char *)buffer, ipp->curtag, tag,
3302 1)) == NULL)
3303 {
cb7f98ee 3304 _cupsSetHTTPError(HTTP_STATUS_ERROR);
a2326b5b 3305 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
dcb445bc 3306 _cupsBufferRelease((char *)buffer);
cb7f98ee 3307 return (IPP_STATE_ERROR);
a2326b5b
MS
3308 }
3309
3310 DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, "
3311 "ipp->prev=%p", buffer, ipp->current, ipp->prev));
3312
9c80ffa2 3313 value = attr->values;
a2326b5b
MS
3314 }
3315 else
3316 {
3317 attr = NULL;
3318 value = NULL;
3319 }
3320
3321 if ((*cb)(src, buffer, 2) < 2)
3322 {
3323 DEBUG_puts("1ippReadIO: unable to read value length.");
dcb445bc 3324 _cupsBufferRelease((char *)buffer);
cb7f98ee 3325 return (IPP_STATE_ERROR);
a2326b5b
MS
3326 }
3327
3328 n = (buffer[0] << 8) | buffer[1];
3329 DEBUG_printf(("2ippReadIO: value length=%d", n));
3330
3331 if (n >= IPP_BUF_SIZE)
3332 {
cb7f98ee 3333 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a2326b5b
MS
3334 _("IPP value larger than 32767 bytes."), 1);
3335 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
dcb445bc 3336 _cupsBufferRelease((char *)buffer);
cb7f98ee 3337 return (IPP_STATE_ERROR);
a2326b5b
MS
3338 }
3339
3340 switch (tag)
3341 {
3342 case IPP_TAG_INTEGER :
3343 case IPP_TAG_ENUM :
3344 if (n != 4)
3345 {
3346 if (tag == IPP_TAG_INTEGER)
cb7f98ee 3347 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a2326b5b
MS
3348 _("IPP integer value not 4 bytes."), 1);
3349 else
cb7f98ee 3350 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a2326b5b 3351 _("IPP enum value not 4 bytes."), 1);
a29fd7dd 3352 DEBUG_printf(("1ippReadIO: bad integer value length %d.", n));
dcb445bc 3353 _cupsBufferRelease((char *)buffer);
cb7f98ee 3354 return (IPP_STATE_ERROR);
a2326b5b
MS
3355 }
3356
3357 if ((*cb)(src, buffer, 4) < 4)
3358 {
3359 DEBUG_puts("1ippReadIO: Unable to read integer value.");
dcb445bc 3360 _cupsBufferRelease((char *)buffer);
cb7f98ee 3361 return (IPP_STATE_ERROR);
a2326b5b
MS
3362 }
3363
3364 n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3365 buffer[3];
3366
3367 if (attr->value_tag == IPP_TAG_RANGE)
3368 value->range.lower = value->range.upper = n;
3369 else
3370 value->integer = n;
3371 break;
3372
3373 case IPP_TAG_BOOLEAN :
3374 if (n != 1)
3375 {
cb7f98ee 3376 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP boolean value not 1 byte."),
a2326b5b 3377 1);
a29fd7dd 3378 DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n));
dcb445bc 3379 _cupsBufferRelease((char *)buffer);
cb7f98ee 3380 return (IPP_STATE_ERROR);
a2326b5b
MS
3381 }
3382
3383 if ((*cb)(src, buffer, 1) < 1)
3384 {
3385 DEBUG_puts("1ippReadIO: Unable to read boolean value.");
dcb445bc 3386 _cupsBufferRelease((char *)buffer);
cb7f98ee 3387 return (IPP_STATE_ERROR);
a2326b5b
MS
3388 }
3389
1a18c85c 3390 value->boolean = (char)buffer[0];
a2326b5b
MS
3391 break;
3392
3393 case IPP_TAG_NOVALUE :
3394 case IPP_TAG_NOTSETTABLE :
3395 case IPP_TAG_DELETEATTR :
3396 case IPP_TAG_ADMINDEFINE :
3397 /*
3398 * These value types are not supposed to have values, however
3399 * some vendors (Brother) do not implement IPP correctly and so
3400 * we need to map non-empty values to text...
3401 */
3402
3403 if (attr->value_tag == tag)
3404 {
3405 if (n == 0)
3406 break;
3407
3408 attr->value_tag = IPP_TAG_TEXT;
3409 }
3410
3411 case IPP_TAG_TEXT :
3412 case IPP_TAG_NAME :
3413 case IPP_TAG_KEYWORD :
3414 case IPP_TAG_URI :
3415 case IPP_TAG_URISCHEME :
3416 case IPP_TAG_CHARSET :
3417 case IPP_TAG_LANGUAGE :
3418 case IPP_TAG_MIMETYPE :
a29fd7dd
MS
3419 if (n > 0)
3420 {
1a18c85c 3421 if ((*cb)(src, buffer, (size_t)n) < n)
a29fd7dd
MS
3422 {
3423 DEBUG_puts("1ippReadIO: unable to read string value.");
3424 _cupsBufferRelease((char *)buffer);
cb7f98ee 3425 return (IPP_STATE_ERROR);
a29fd7dd 3426 }
a2326b5b
MS
3427 }
3428
3429 buffer[n] = '\0';
3430 value->string.text = _cupsStrAlloc((char *)buffer);
3431 DEBUG_printf(("2ippReadIO: value=\"%s\"", value->string.text));
3432 break;
3433
3434 case IPP_TAG_DATE :
3435 if (n != 11)
3436 {
cb7f98ee 3437 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP date value not 11 bytes."), 1);
a29fd7dd 3438 DEBUG_printf(("1ippReadIO: bad date value length %d.", n));
dcb445bc 3439 _cupsBufferRelease((char *)buffer);
cb7f98ee 3440 return (IPP_STATE_ERROR);
a2326b5b
MS
3441 }
3442
3443 if ((*cb)(src, value->date, 11) < 11)
3444 {
3445 DEBUG_puts("1ippReadIO: Unable to read date value.");
dcb445bc 3446 _cupsBufferRelease((char *)buffer);
cb7f98ee 3447 return (IPP_STATE_ERROR);
a2326b5b
MS
3448 }
3449 break;
3450
3451 case IPP_TAG_RESOLUTION :
3452 if (n != 9)
3453 {
cb7f98ee 3454 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a2326b5b 3455 _("IPP resolution value not 9 bytes."), 1);
a29fd7dd 3456 DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n));
dcb445bc 3457 _cupsBufferRelease((char *)buffer);
cb7f98ee 3458 return (IPP_STATE_ERROR);
a2326b5b
MS
3459 }
3460
3461 if ((*cb)(src, buffer, 9) < 9)
3462 {
3463 DEBUG_puts("1ippReadIO: Unable to read resolution value.");
dcb445bc 3464 _cupsBufferRelease((char *)buffer);
cb7f98ee 3465 return (IPP_STATE_ERROR);
a2326b5b
MS
3466 }
3467
3468 value->resolution.xres =
3469 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3470 buffer[3];
3471 value->resolution.yres =
3472 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
3473 buffer[7];
3474 value->resolution.units =
3475 (ipp_res_t)buffer[8];
3476 break;
3477
3478 case IPP_TAG_RANGE :
3479 if (n != 8)
3480 {
cb7f98ee 3481 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a2326b5b 3482 _("IPP rangeOfInteger value not 8 bytes."), 1);
a29fd7dd
MS
3483 DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length "
3484 "%d.", n));
dcb445bc 3485 _cupsBufferRelease((char *)buffer);
cb7f98ee 3486 return (IPP_STATE_ERROR);
a2326b5b
MS
3487 }
3488
3489 if ((*cb)(src, buffer, 8) < 8)
3490 {
3491 DEBUG_puts("1ippReadIO: Unable to read range value.");
dcb445bc 3492 _cupsBufferRelease((char *)buffer);
cb7f98ee 3493 return (IPP_STATE_ERROR);
a2326b5b
MS
3494 }
3495
3496 value->range.lower =
3497 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
3498 buffer[3];
3499 value->range.upper =
3500 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
3501 buffer[7];
3502 break;
3503
3504 case IPP_TAG_TEXTLANG :
3505 case IPP_TAG_NAMELANG :
3506 if (n < 4)
3507 {
3508 if (tag == IPP_TAG_TEXTLANG)
cb7f98ee 3509 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a2326b5b
MS
3510 _("IPP textWithLanguage value less than "
3511 "minimum 4 bytes."), 1);
3512 else
cb7f98ee 3513 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a2326b5b
MS
3514 _("IPP nameWithLanguage value less than "
3515 "minimum 4 bytes."), 1);
a29fd7dd
MS
3516 DEBUG_printf(("1ippReadIO: bad stringWithLanguage value "
3517 "length %d.", n));
dcb445bc 3518 _cupsBufferRelease((char *)buffer);
cb7f98ee 3519 return (IPP_STATE_ERROR);
a2326b5b
MS
3520 }
3521
1a18c85c 3522 if ((*cb)(src, buffer, (size_t)n) < n)
a2326b5b
MS
3523 {
3524 DEBUG_puts("1ippReadIO: Unable to read string w/language "
3525 "value.");
dcb445bc 3526 _cupsBufferRelease((char *)buffer);
cb7f98ee 3527 return (IPP_STATE_ERROR);
a2326b5b
MS
3528 }
3529
3530 bufptr = buffer;
3531
3532 /*
3533 * text-with-language and name-with-language are composite
3534 * values:
3535 *
3536 * language-length
3537 * language
3538 * text-length
3539 * text
3540 */
3541
3542 n = (bufptr[0] << 8) | bufptr[1];
3543
1a18c85c 3544 if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) || n >= (int)sizeof(string))
a2326b5b 3545 {
cb7f98ee 3546 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a2326b5b 3547 _("IPP language length overflows value."), 1);
a29fd7dd
MS
3548 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3549 n));
dcb445bc 3550 _cupsBufferRelease((char *)buffer);
cb7f98ee 3551 return (IPP_STATE_ERROR);
a2326b5b 3552 }
5a9febac
MS
3553 else if (n >= IPP_MAX_LANGUAGE)
3554 {
cb7f98ee 3555 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
5a9febac
MS
3556 _("IPP language length too large."), 1);
3557 DEBUG_printf(("1ippReadIO: bad language value length %d.",
3558 n));
3559 _cupsBufferRelease((char *)buffer);
cb7f98ee 3560 return (IPP_STATE_ERROR);
5a9febac 3561 }
a2326b5b 3562
1a18c85c 3563 memcpy(string, bufptr + 2, (size_t)n);
a2326b5b
MS
3564 string[n] = '\0';
3565
3566 value->string.language = _cupsStrAlloc((char *)string);
3567
3568 bufptr += 2 + n;
3569 n = (bufptr[0] << 8) | bufptr[1];
3570
3571 if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE))
3572 {
cb7f98ee 3573 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a2326b5b 3574 _("IPP string length overflows value."), 1);
a29fd7dd 3575 DEBUG_printf(("1ippReadIO: bad string value length %d.", n));
dcb445bc 3576 _cupsBufferRelease((char *)buffer);
cb7f98ee 3577 return (IPP_STATE_ERROR);
a2326b5b
MS
3578 }
3579
3580 bufptr[2 + n] = '\0';
3581 value->string.text = _cupsStrAlloc((char *)bufptr + 2);
3582 break;
3583
3584 case IPP_TAG_BEGIN_COLLECTION :
3585 /*
3586 * Oh, boy, here comes a collection value, so read it...
3587 */
3588
3589 value->collection = ippNew();
3590
3591 if (n > 0)
3592 {
cb7f98ee 3593 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a2326b5b
MS
3594 _("IPP begCollection value not 0 bytes."), 1);
3595 DEBUG_puts("1ippReadIO: begCollection tag with value length "
3596 "> 0.");
dcb445bc 3597 _cupsBufferRelease((char *)buffer);
cb7f98ee 3598 return (IPP_STATE_ERROR);
a2326b5b
MS
3599 }
3600
cb7f98ee 3601 if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_STATE_ERROR)
a2326b5b
MS
3602 {
3603 DEBUG_puts("1ippReadIO: Unable to read collection value.");
dcb445bc 3604 _cupsBufferRelease((char *)buffer);
cb7f98ee 3605 return (IPP_STATE_ERROR);
a2326b5b
MS
3606 }
3607 break;
3608
3609 case IPP_TAG_END_COLLECTION :
dcb445bc 3610 _cupsBufferRelease((char *)buffer);
a2326b5b
MS
3611
3612 if (n > 0)
3613 {
cb7f98ee 3614 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a2326b5b
MS
3615 _("IPP endCollection value not 0 bytes."), 1);
3616 DEBUG_puts("1ippReadIO: endCollection tag with value length "
3617 "> 0.");
cb7f98ee 3618 return (IPP_STATE_ERROR);
a2326b5b
MS
3619 }
3620
3621 DEBUG_puts("1ippReadIO: endCollection tag...");
cb7f98ee 3622 return (ipp->state = IPP_STATE_DATA);
a2326b5b
MS
3623
3624 case IPP_TAG_MEMBERNAME :
3625 /*
3626 * The value the name of the member in the collection, which
3627 * we need to carry over...
3628 */
3629
5a9febac
MS
3630 if (!attr)
3631 {
cb7f98ee 3632 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
5a9febac
MS
3633 _("IPP memberName with no attribute."), 1);
3634 DEBUG_puts("1ippReadIO: Member name without attribute.");
3635 _cupsBufferRelease((char *)buffer);
cb7f98ee 3636 return (IPP_STATE_ERROR);
5a9febac
MS
3637 }
3638 else if (n == 0)
a29fd7dd 3639 {
cb7f98ee 3640 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
a29fd7dd
MS
3641 _("IPP memberName value is empty."), 1);
3642 DEBUG_puts("1ippReadIO: Empty member name value.");
3643 _cupsBufferRelease((char *)buffer);
cb7f98ee 3644 return (IPP_STATE_ERROR);
a29fd7dd 3645 }
1a18c85c 3646 else if ((*cb)(src, buffer, (size_t)n) < n)
a2326b5b
MS
3647 {
3648 DEBUG_puts("1ippReadIO: Unable to read member name value.");
dcb445bc 3649 _cupsBufferRelease((char *)buffer);
cb7f98ee 3650 return (IPP_STATE_ERROR);
a2326b5b
MS
3651 }
3652
3653 buffer[n] = '\0';
3654 attr->name = _cupsStrAlloc((char *)buffer);
3655
3656 /*
3657 * Since collection members are encoded differently than
3658 * regular attributes, make sure we don't start with an
3659 * empty value...
3660 */
3661
3662 attr->num_values --;
3663
3664 DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr->name));
3665 break;
3666
3667 default : /* Other unsupported values */
a469f8a5 3668 if (tag == IPP_TAG_STRING && n > IPP_MAX_LENGTH)
5a9febac 3669 {
cb7f98ee 3670 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
5a9febac
MS
3671 _("IPP octetString length too large."), 1);
3672 DEBUG_printf(("1ippReadIO: bad octetString value length %d.",
3673 n));
3674 _cupsBufferRelease((char *)buffer);
cb7f98ee 3675 return (IPP_STATE_ERROR);
5a9febac
MS
3676 }
3677
a2326b5b 3678 value->unknown.length = n;
5a9febac 3679
a2326b5b
MS
3680 if (n > 0)
3681 {
1a18c85c 3682 if ((value->unknown.data = malloc((size_t)n)) == NULL)
a2326b5b 3683 {
cb7f98ee 3684 _cupsSetHTTPError(HTTP_STATUS_ERROR);
a2326b5b 3685 DEBUG_puts("1ippReadIO: Unable to allocate value");
dcb445bc 3686 _cupsBufferRelease((char *)buffer);
cb7f98ee 3687 return (IPP_STATE_ERROR);
a2326b5b
MS
3688 }
3689
1a18c85c 3690 if ((*cb)(src, value->unknown.data, (size_t)n) < n)
a2326b5b
MS
3691 {
3692 DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
dcb445bc 3693 _cupsBufferRelease((char *)buffer);
cb7f98ee 3694 return (IPP_STATE_ERROR);
a2326b5b
MS
3695 }
3696 }
3697 else
3698 value->unknown.data = NULL;
3699 break;
3700 }
3701
a2326b5b
MS
3702 /*
3703 * If blocking is disabled, stop here...
ef416fc2 3704 */
3705
a2326b5b
MS
3706 if (!blocking)
3707 break;
3708 }
3709 break;
ef416fc2 3710
cb7f98ee 3711 case IPP_STATE_DATA :
a2326b5b 3712 break;
ef416fc2 3713
a2326b5b
MS
3714 default :
3715 break; /* anti-compiler-warning-code */
3716 }
ef416fc2 3717
a2326b5b 3718 DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp->state));
dcb445bc 3719 _cupsBufferRelease((char *)buffer);
ef416fc2 3720
a2326b5b
MS
3721 return (ipp->state);
3722}
ef416fc2 3723
ef416fc2 3724
a2326b5b
MS
3725/*
3726 * 'ippSetBoolean()' - Set a boolean value in an attribute.
3727 *
a469f8a5
MS
3728 * The @code ipp@ parameter refers to an IPP message previously created using
3729 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
3730 *
3731 * The @code attr@ parameter may be modified as a result of setting the value.
3732 *
3733 * The @code element@ parameter specifies which value to set from 0 to
3734 * @link ippGetCount(attr)@.
3735 *
f3c17241 3736 * @since CUPS 1.6/OS X 10.8@
a2326b5b 3737 */
ef416fc2 3738
a2326b5b 3739int /* O - 1 on success, 0 on failure */
6961465f 3740ippSetBoolean(ipp_t *ipp, /* I - IPP message */
a2326b5b
MS
3741 ipp_attribute_t **attr, /* IO - IPP attribute */
3742 int element, /* I - Value number (0-based) */
3743 int boolvalue)/* I - Boolean value */
3744{
3745 _ipp_value_t *value; /* Current value */
ef416fc2 3746
ef416fc2 3747
a2326b5b
MS
3748 /*
3749 * Range check input...
3750 */
ef416fc2 3751
a2326b5b
MS
3752 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BOOLEAN ||
3753 element < 0 || element > (*attr)->num_values)
3754 return (0);
83e08001 3755
a2326b5b
MS
3756 /*
3757 * Set the value and return...
3758 */
83e08001 3759
a2326b5b 3760 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
1a18c85c 3761 value->boolean = (char)boolvalue;
83e08001 3762
a2326b5b
MS
3763 return (value != NULL);
3764}
83e08001 3765
83e08001 3766
a2326b5b
MS
3767/*
3768 * 'ippSetCollection()' - Set a collection value in an attribute.
3769 *
a469f8a5
MS
3770 * The @code ipp@ parameter refers to an IPP message previously created using
3771 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
3772 *
3773 * The @code attr@ parameter may be modified as a result of setting the value.
3774 *
3775 * The @code element@ parameter specifies which value to set from 0 to
3776 * @link ippGetCount(attr)@.
3777 *
f3c17241 3778 * @since CUPS 1.6/OS X 10.8@
a2326b5b 3779 */
83e08001 3780
a2326b5b
MS
3781int /* O - 1 on success, 0 on failure */
3782ippSetCollection(
6961465f 3783 ipp_t *ipp, /* I - IPP message */
a2326b5b
MS
3784 ipp_attribute_t **attr, /* IO - IPP attribute */
3785 int element, /* I - Value number (0-based) */
3786 ipp_t *colvalue) /* I - Collection value */
3787{
3788 _ipp_value_t *value; /* Current value */
3789
3790
3791 /*
3792 * Range check input...
3793 */
3794
3795 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BEGIN_COLLECTION ||
3796 element < 0 || element > (*attr)->num_values || !colvalue)
3797 return (0);
3798
3799 /*
3800 * Set the value and return...
3801 */
3802
3803 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3804 {
3805 if (value->collection)
3806 ippDelete(value->collection);
3807
3808 value->collection = colvalue;
3809 colvalue->use ++;
3810 }
3811
3812 return (value != NULL);
3813}
3814
3815
9c80ffa2
MS
3816/*
3817 * 'ippSetDate()' - Set a date value in an attribute.
3818 *
a469f8a5
MS
3819 * The @code ipp@ parameter refers to an IPP message previously created using
3820 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
9c80ffa2
MS
3821 *
3822 * The @code attr@ parameter may be modified as a result of setting the value.
3823 *
3824 * The @code element@ parameter specifies which value to set from 0 to
3825 * @link ippGetCount(attr)@.
3826 *
f3c17241 3827 * @since CUPS 1.6/OS X 10.8@
9c80ffa2
MS
3828 */
3829
3830int /* O - 1 on success, 0 on failure */
6961465f 3831ippSetDate(ipp_t *ipp, /* I - IPP message */
9c80ffa2
MS
3832 ipp_attribute_t **attr, /* IO - IPP attribute */
3833 int element, /* I - Value number (0-based) */
3834 const ipp_uchar_t *datevalue)/* I - Date value */
3835{
3836 _ipp_value_t *value; /* Current value */
3837
3838
3839 /*
3840 * Range check input...
3841 */
3842
3843 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_DATE ||
3844 element < 0 || element > (*attr)->num_values || !datevalue)
3845 return (0);
3846
3847 /*
3848 * Set the value and return...
3849 */
3850
3851 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3852 memcpy(value->date, datevalue, sizeof(value->date));
3853
3854 return (value != NULL);
3855}
3856
3857
a2326b5b
MS
3858/*
3859 * 'ippSetGroupTag()' - Set the group tag of an attribute.
3860 *
a469f8a5
MS
3861 * The @code ipp@ parameter refers to an IPP message previously created using
3862 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
3863 *
3864 * The @code attr@ parameter may be modified as a result of setting the value.
3865 *
3866 * The @code group@ parameter specifies the IPP attribute group tag: none
3867 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
3868 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
3869 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
3870 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
3871 *
f3c17241 3872 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
3873 */
3874
3875int /* O - 1 on success, 0 on failure */
3876ippSetGroupTag(
6961465f 3877 ipp_t *ipp, /* I - IPP message */
a2326b5b
MS
3878 ipp_attribute_t **attr, /* IO - Attribute */
3879 ipp_tag_t group_tag) /* I - Group tag */
3880{
3881 /*
3882 * Range check input - group tag must be 0x01 to 0x0F, per RFC 2911...
3883 */
3884
a469f8a5
MS
3885 if (!ipp || !attr || !*attr ||
3886 group_tag < IPP_TAG_ZERO || group_tag == IPP_TAG_END ||
a2326b5b
MS
3887 group_tag >= IPP_TAG_UNSUPPORTED_VALUE)
3888 return (0);
3889
3890 /*
3891 * Set the group tag and return...
3892 */
3893
3894 (*attr)->group_tag = group_tag;
3895
3896 return (1);
3897}
3898
3899
3900/*
3901 * 'ippSetInteger()' - Set an integer or enum value in an attribute.
3902 *
a469f8a5
MS
3903 * The @code ipp@ parameter refers to an IPP message previously created using
3904 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
3905 *
3906 * The @code attr@ parameter may be modified as a result of setting the value.
3907 *
3908 * The @code element@ parameter specifies which value to set from 0 to
3909 * @link ippGetCount(attr)@.
3910 *
f3c17241 3911 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
3912 */
3913
3914int /* O - 1 on success, 0 on failure */
6961465f 3915ippSetInteger(ipp_t *ipp, /* I - IPP message */
a2326b5b
MS
3916 ipp_attribute_t **attr, /* IO - IPP attribute */
3917 int element, /* I - Value number (0-based) */
3918 int intvalue) /* I - Integer/enum value */
3919{
3920 _ipp_value_t *value; /* Current value */
3921
3922
3923 /*
3924 * Range check input...
3925 */
3926
3927 if (!ipp || !attr || !*attr ||
3928 ((*attr)->value_tag != IPP_TAG_INTEGER && (*attr)->value_tag != IPP_TAG_ENUM) ||
3929 element < 0 || element > (*attr)->num_values)
3930 return (0);
3931
3932 /*
3933 * Set the value and return...
3934 */
3935
3936 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3937 value->integer = intvalue;
3938
3939 return (value != NULL);
3940}
3941
3942
3943/*
3944 * 'ippSetName()' - Set the name of an attribute.
3945 *
a469f8a5
MS
3946 * The @code ipp@ parameter refers to an IPP message previously created using
3947 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
3948 *
3949 * The @code attr@ parameter may be modified as a result of setting the value.
3950 *
f3c17241 3951 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
3952 */
3953
3954int /* O - 1 on success, 0 on failure */
6961465f 3955ippSetName(ipp_t *ipp, /* I - IPP message */
a2326b5b
MS
3956 ipp_attribute_t **attr, /* IO - IPP attribute */
3957 const char *name) /* I - Attribute name */
3958{
3959 char *temp; /* Temporary name value */
3960
3961
3962 /*
3963 * Range check input...
3964 */
3965
3966 if (!ipp || !attr || !*attr)
3967 return (0);
ef416fc2 3968
a2326b5b
MS
3969 /*
3970 * Set the value and return...
3971 */
ef416fc2 3972
a2326b5b
MS
3973 if ((temp = _cupsStrAlloc(name)) != NULL)
3974 {
3975 if ((*attr)->name)
3976 _cupsStrFree((*attr)->name);
ef416fc2 3977
a2326b5b
MS
3978 (*attr)->name = temp;
3979 }
ef416fc2 3980
a2326b5b
MS
3981 return (temp != NULL);
3982}
ef416fc2 3983
ef416fc2 3984
6961465f
MS
3985/*
3986 * 'ippSetOctetString()' - Set an octetString value in an IPP attribute.
3987 *
3988 * The @code ipp@ parameter refers to an IPP message previously created using
3989 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
3990 *
3991 * The @code attr@ parameter may be modified as a result of setting the value.
3992 *
3993 * The @code element@ parameter specifies which value to set from 0 to
3994 * @link ippGetCount(attr)@.
3995 *
9c0e8e5d 3996 * @since CUPS 1.7/OS X 10.9@
6961465f
MS
3997 */
3998
3999int /* O - 1 on success, 0 on failure */
4000ippSetOctetString(
4001 ipp_t *ipp, /* I - IPP message */
4002 ipp_attribute_t **attr, /* IO - IPP attribute */
4003 int element, /* I - Value number (0-based) */
4004 const void *data, /* I - Pointer to octetString data */
4005 int datalen) /* I - Length of octetString data */
4006{
4007 _ipp_value_t *value; /* Current value */
4008
4009
4010 /*
4011 * Range check input...
4012 */
4013
4014 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_STRING ||
4015 element < 0 || element > (*attr)->num_values ||
4016 datalen < 0 || datalen > IPP_MAX_LENGTH)
4017 return (0);
4018
4019 /*
4020 * Set the value and return...
4021 */
4022
4023 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4024 {
4025 if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST)
4026 {
4027 /*
4028 * Just copy the pointer...
4029 */
4030
4031 value->unknown.data = (void *)data;
4032 value->unknown.length = datalen;
4033 }
4034 else
4035 {
4036 /*
4037 * Copy the data...
4038 */
4039
4040 if (value->unknown.data)
4041 {
4042 /*
4043 * Free previous data...
4044 */
4045
4046 free(value->unknown.data);
4047
4048 value->unknown.data = NULL;
4049 value->unknown.length = 0;
4050 }
4051
4052 if (datalen > 0)
4053 {
4054 void *temp; /* Temporary data pointer */
4055
1a18c85c 4056 if ((temp = malloc((size_t)datalen)) != NULL)
6961465f 4057 {
1a18c85c 4058 memcpy(temp, data, (size_t)datalen);
6961465f
MS
4059
4060 value->unknown.data = temp;
4061 value->unknown.length = datalen;
4062 }
4063 else
4064 return (0);
4065 }
4066 }
4067 }
4068
4069 return (value != NULL);
4070}
4071
4072
a2326b5b
MS
4073/*
4074 * 'ippSetOperation()' - Set the operation ID in an IPP request message.
4075 *
a469f8a5
MS
4076 * The @code ipp@ parameter refers to an IPP message previously created using
4077 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b 4078 *
f3c17241 4079 * @since CUPS 1.6/OS X 10.8@
a2326b5b 4080 */
ef416fc2 4081
a2326b5b
MS
4082int /* O - 1 on success, 0 on failure */
4083ippSetOperation(ipp_t *ipp, /* I - IPP request message */
4084 ipp_op_t op) /* I - Operation ID */
4085{
4086 /*
4087 * Range check input...
4088 */
ef416fc2 4089
a2326b5b
MS
4090 if (!ipp)
4091 return (0);
ef416fc2 4092
a2326b5b
MS
4093 /*
4094 * Set the operation and return...
4095 */
ef416fc2 4096
a2326b5b 4097 ipp->request.op.operation_id = op;
ef416fc2 4098
a2326b5b
MS
4099 return (1);
4100}
ef416fc2 4101
ef416fc2 4102
a2326b5b
MS
4103/*
4104 * 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
4105 *
a469f8a5
MS
4106 * The @code ipp@ parameter refers to an IPP message previously created using
4107 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
4108 *
4109 * The @code attr@ parameter may be modified as a result of setting the value.
4110 *
4111 * The @code element@ parameter specifies which value to set from 0 to
4112 * @link ippGetCount(attr)@.
4113 *
f3c17241 4114 * @since CUPS 1.6/OS X 10.8@
a2326b5b 4115 */
ef416fc2 4116
a2326b5b 4117int /* O - 1 on success, 0 on failure */
6961465f 4118ippSetRange(ipp_t *ipp, /* I - IPP message */
a2326b5b
MS
4119 ipp_attribute_t **attr, /* IO - IPP attribute */
4120 int element, /* I - Value number (0-based) */
4121 int lowervalue, /* I - Lower bound for range */
4122 int uppervalue) /* I - Upper bound for range */
4123{
4124 _ipp_value_t *value; /* Current value */
ef416fc2 4125
ef416fc2 4126
a2326b5b
MS
4127 /*
4128 * Range check input...
4129 */
ef416fc2 4130
a2326b5b
MS
4131 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_RANGE ||
4132 element < 0 || element > (*attr)->num_values || lowervalue > uppervalue)
4133 return (0);
ef416fc2 4134
a2326b5b
MS
4135 /*
4136 * Set the value and return...
4137 */
ef416fc2 4138
a2326b5b
MS
4139 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4140 {
4141 value->range.lower = lowervalue;
4142 value->range.upper = uppervalue;
4143 }
ef416fc2 4144
a2326b5b
MS
4145 return (value != NULL);
4146}
ef416fc2 4147
ef416fc2 4148
a2326b5b
MS
4149/*
4150 * 'ippSetRequestId()' - Set the request ID in an IPP message.
4151 *
a469f8a5
MS
4152 * The @code ipp@ parameter refers to an IPP message previously created using
4153 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
4154 *
4155 * The @code request_id@ parameter must be greater than 0.
4156 *
f3c17241 4157 * @since CUPS 1.6/OS X 10.8@
a2326b5b 4158 */
ef416fc2 4159
a2326b5b
MS
4160int /* O - 1 on success, 0 on failure */
4161ippSetRequestId(ipp_t *ipp, /* I - IPP message */
4162 int request_id) /* I - Request ID */
4163{
4164 /*
4165 * Range check input; not checking request_id values since ipptool wants to send
4166 * invalid values for conformance testing and a bad request_id does not affect the
4167 * encoding of a message...
4168 */
83e08001 4169
a2326b5b
MS
4170 if (!ipp)
4171 return (0);
a41f09e2 4172
a2326b5b
MS
4173 /*
4174 * Set the request ID and return...
4175 */
ef416fc2 4176
a2326b5b 4177 ipp->request.any.request_id = request_id;
ef416fc2 4178
a2326b5b
MS
4179 return (1);
4180}
5a738aea 4181
a41f09e2 4182
a2326b5b
MS
4183/*
4184 * 'ippSetResolution()' - Set a resolution value in an attribute.
4185 *
a469f8a5
MS
4186 * The @code ipp@ parameter refers to an IPP message previously created using
4187 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
4188 *
4189 * The @code attr@ parameter may be modified as a result of setting the value.
4190 *
4191 * The @code element@ parameter specifies which value to set from 0 to
4192 * @link ippGetCount(attr)@.
4193 *
f3c17241 4194 * @since CUPS 1.6/OS X 10.8@
a2326b5b 4195 */
ef416fc2 4196
a2326b5b
MS
4197int /* O - 1 on success, 0 on failure */
4198ippSetResolution(
6961465f 4199 ipp_t *ipp, /* I - IPP message */
a2326b5b
MS
4200 ipp_attribute_t **attr, /* IO - IPP attribute */
4201 int element, /* I - Value number (0-based) */
4202 ipp_res_t unitsvalue, /* I - Resolution units */
4203 int xresvalue, /* I - Horizontal/cross feed resolution */
4204 int yresvalue) /* I - Vertical/feed resolution */
4205{
4206 _ipp_value_t *value; /* Current value */
5a738aea 4207
536bc2c6 4208
a2326b5b
MS
4209 /*
4210 * Range check input...
4211 */
1ff0402e 4212
a2326b5b
MS
4213 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_RESOLUTION ||
4214 element < 0 || element > (*attr)->num_values || xresvalue <= 0 || yresvalue <= 0 ||
4215 unitsvalue < IPP_RES_PER_INCH || unitsvalue > IPP_RES_PER_CM)
4216 return (0);
1ff0402e 4217
a2326b5b
MS
4218 /*
4219 * Set the value and return...
4220 */
ef416fc2 4221
a2326b5b
MS
4222 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4223 {
4224 value->resolution.units = unitsvalue;
4225 value->resolution.xres = xresvalue;
4226 value->resolution.yres = yresvalue;
4227 }
5a738aea 4228
a2326b5b
MS
4229 return (value != NULL);
4230}
a41f09e2 4231
5a738aea 4232
9c80ffa2
MS
4233/*
4234 * 'ippSetState()' - Set the current state of the IPP message.
4235 *
f3c17241 4236 * @since CUPS 1.6/OS X 10.8@
9c80ffa2
MS
4237 */
4238
4239int /* O - 1 on success, 0 on failure */
4240ippSetState(ipp_t *ipp, /* I - IPP message */
4241 ipp_state_t state) /* I - IPP state value */
4242{
4243 /*
4244 * Range check input...
4245 */
4246
4247 if (!ipp)
4248 return (0);
4249
4250 /*
4251 * Set the state and return...
4252 */
4253
4254 ipp->state = state;
4255 ipp->current = NULL;
4256
4257 return (1);
4258}
4259
4260
a2326b5b
MS
4261/*
4262 * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
4263 *
a469f8a5
MS
4264 * The @code ipp@ parameter refers to an IPP message previously created using
4265 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b 4266 *
f3c17241 4267 * @since CUPS 1.6/OS X 10.8@
a2326b5b 4268 */
a41f09e2 4269
a2326b5b
MS
4270int /* O - 1 on success, 0 on failure */
4271ippSetStatusCode(ipp_t *ipp, /* I - IPP response or event message */
4272 ipp_status_t status) /* I - Status code */
4273{
4274 /*
4275 * Range check input...
4276 */
4277
4278 if (!ipp)
4279 return (0);
ef416fc2 4280
a2326b5b
MS
4281 /*
4282 * Set the status code and return...
4283 */
5a738aea 4284
a2326b5b 4285 ipp->request.status.status_code = status;
a41f09e2 4286
a2326b5b 4287 return (1);
a2326b5b 4288}
5a738aea 4289
ef416fc2 4290
a2326b5b
MS
4291/*
4292 * 'ippSetString()' - Set a string value in an attribute.
4293 *
a469f8a5
MS
4294 * The @code ipp@ parameter refers to an IPP message previously created using
4295 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
4296 *
4297 * The @code attr@ parameter may be modified as a result of setting the value.
4298 *
4299 * The @code element@ parameter specifies which value to set from 0 to
4300 * @link ippGetCount(attr)@.
4301 *
f3c17241 4302 * @since CUPS 1.6/OS X 10.8@
a2326b5b 4303 */
ef416fc2 4304
a2326b5b 4305int /* O - 1 on success, 0 on failure */
6961465f 4306ippSetString(ipp_t *ipp, /* I - IPP message */
a2326b5b
MS
4307 ipp_attribute_t **attr, /* IO - IPP attribute */
4308 int element, /* I - Value number (0-based) */
4309 const char *strvalue) /* I - String value */
4310{
4311 char *temp; /* Temporary string */
4312 _ipp_value_t *value; /* Current value */
ef416fc2 4313
ef416fc2 4314
a2326b5b
MS
4315 /*
4316 * Range check input...
4317 */
ef416fc2 4318
3e7fe0ca
MS
4319 if (!ipp || !attr || !*attr ||
4320 ((*attr)->value_tag != IPP_TAG_TEXTLANG &&
4321 (*attr)->value_tag != IPP_TAG_NAMELANG &&
4322 ((*attr)->value_tag < IPP_TAG_TEXT ||
4323 (*attr)->value_tag > IPP_TAG_MIMETYPE)) ||
a2326b5b
MS
4324 element < 0 || element > (*attr)->num_values || !strvalue)
4325 return (0);
a41f09e2 4326
a2326b5b
MS
4327 /*
4328 * Set the value and return...
4329 */
ef416fc2 4330
a2326b5b
MS
4331 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
4332 {
4333 if (element > 0)
4334 value->string.language = (*attr)->values[0].string.language;
ef416fc2 4335
cb7f98ee 4336 if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST)
a2326b5b
MS
4337 value->string.text = (char *)strvalue;
4338 else if ((temp = _cupsStrAlloc(strvalue)) != NULL)
4339 {
4340 if (value->string.text)
4341 _cupsStrFree(value->string.text);
ef416fc2 4342
a2326b5b
MS
4343 value->string.text = temp;
4344 }
4345 else
4346 return (0);
4347 }
a41f09e2 4348
a2326b5b
MS
4349 return (value != NULL);
4350}
ef416fc2 4351
ef416fc2 4352
a469f8a5
MS
4353/*
4354 * 'ippSetStringf()' - Set a formatted string value of an attribute.
4355 *
4356 * The @code ipp@ parameter refers to an IPP message previously created using
4357 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4358 *
4359 * The @code attr@ parameter may be modified as a result of setting the value.
4360 *
4361 * The @code element@ parameter specifies which value to set from 0 to
4362 * @link ippGetCount(attr)@.
4363 *
4364 * The @code format@ parameter uses formatting characters compatible with the
4365 * printf family of standard functions. Additional arguments follow it as
4366 * needed. The formatted string is truncated as needed to the maximum length of
4367 * the corresponding value type.
4368 *
9c0e8e5d 4369 * @since CUPS 1.7/OS X 10.9@
a469f8a5
MS
4370 */
4371
4372int /* O - 1 on success, 0 on failure */
6961465f 4373ippSetStringf(ipp_t *ipp, /* I - IPP message */
a469f8a5
MS
4374 ipp_attribute_t **attr, /* IO - IPP attribute */
4375 int element, /* I - Value number (0-based) */
4376 const char *format, /* I - Printf-style format string */
4377 ...) /* I - Additional arguments as needed */
4378{
4379 int ret; /* Return value */
4380 va_list ap; /* Pointer to additional arguments */
4381
4382
4383 va_start(ap, format);
4384 ret = ippSetStringfv(ipp, attr, element, format, ap);
4385 va_end(ap);
4386
4387 return (ret);
4388}
4389
4390
4391/*
4392 * 'ippSetStringf()' - Set a formatted string value of an attribute.
4393 *
4394 * The @code ipp@ parameter refers to an IPP message previously created using
4395 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
4396 *
4397 * The @code attr@ parameter may be modified as a result of setting the value.
4398 *
4399 * The @code element@ parameter specifies which value to set from 0 to
4400 * @link ippGetCount(attr)@.
4401 *
4402 * The @code format@ parameter uses formatting characters compatible with the
4403 * printf family of standard functions. Additional arguments follow it as
4404 * needed. The formatted string is truncated as needed to the maximum length of
4405 * the corresponding value type.
4406 *
9c0e8e5d 4407 * @since CUPS 1.7/OS X 10.9@
a469f8a5
MS
4408 */
4409
4410int /* O - 1 on success, 0 on failure */
6961465f 4411ippSetStringfv(ipp_t *ipp, /* I - IPP message */
a469f8a5
MS
4412 ipp_attribute_t **attr, /* IO - IPP attribute */
4413 int element, /* I - Value number (0-based) */
4414 const char *format, /* I - Printf-style format string */
4415 va_list ap) /* I - Pointer to additional arguments */
4416{
4417 ipp_tag_t value_tag; /* Value tag */
4418 char buffer[IPP_MAX_TEXT + 4];
4419 /* Formatted text string */
4420 ssize_t bytes, /* Length of formatted value */
4421 max_bytes; /* Maximum number of bytes for value */
4422
4423
4424 /*
4425 * Range check input...
4426 */
4427
4428 if (attr && *attr)
4429 value_tag = (*attr)->value_tag & IPP_TAG_CUPS_MASK;
4430 else
4431 value_tag = IPP_TAG_ZERO;
4432
4433 if (!ipp || !attr || !*attr ||
4434 (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG &&
4435 value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE ||
56cd8959 4436 !format)
a469f8a5
MS
4437 return (0);
4438
4439 /*
4440 * Format the string...
4441 */
4442
4443 if (!strcmp(format, "%s"))
4444 {
4445 /*
4446 * Optimize the simple case...
4447 */
4448
4449 const char *s = va_arg(ap, char *);
4450
4451 if (!s)
4452 s = "(null)";
4453
1a18c85c 4454 bytes = (ssize_t)strlen(s);
a469f8a5
MS
4455 strlcpy(buffer, s, sizeof(buffer));
4456 }
4457 else
4458 {
4459 /*
4460 * Do a full formatting of the message...
4461 */
4462
4463 if ((bytes = vsnprintf(buffer, sizeof(buffer), format, ap)) < 0)
4464 return (0);
4465 }
4466
4467 /*
4468 * Limit the length of the string...
4469 */
4470
4471 switch (value_tag)
4472 {
4473 default :
4474 case IPP_TAG_TEXT :
4475 case IPP_TAG_TEXTLANG :
4476 max_bytes = IPP_MAX_TEXT;
4477 break;
4478
4479 case IPP_TAG_NAME :
4480 case IPP_TAG_NAMELANG :
4481 max_bytes = IPP_MAX_NAME;
4482 break;
4483
4484 case IPP_TAG_CHARSET :
4485 max_bytes = IPP_MAX_CHARSET;
4486 break;
4487
4488 case IPP_TAG_KEYWORD :
4489 max_bytes = IPP_MAX_KEYWORD;
4490 break;
4491
4492 case IPP_TAG_LANGUAGE :
4493 max_bytes = IPP_MAX_LANGUAGE;
4494 break;
4495
4496 case IPP_TAG_MIMETYPE :
4497 max_bytes = IPP_MAX_MIMETYPE;
4498 break;
4499
4500 case IPP_TAG_URI :
4501 max_bytes = IPP_MAX_URI;
4502 break;
4503
4504 case IPP_TAG_URISCHEME :
4505 max_bytes = IPP_MAX_URISCHEME;
4506 break;
4507 }
4508
4509 if (bytes >= max_bytes)
4510 {
4511 char *bufmax, /* Buffer at max_bytes */
4512 *bufptr; /* Pointer into buffer */
4513
4514 bufptr = buffer + strlen(buffer) - 1;
4515 bufmax = buffer + max_bytes - 1;
4516
4517 while (bufptr > bufmax)
4518 {
4519 if (*bufptr & 0x80)
4520 {
4521 while ((*bufptr & 0xc0) == 0x80 && bufptr > buffer)
4522 bufptr --;
4523 }
4524
4525 bufptr --;
4526 }
4527
4528 *bufptr = '\0';
4529 }
4530
4531 /*
4532 * Set the formatted string and return...
4533 */
4534
4535 return (ippSetString(ipp, attr, element, buffer));
4536}
4537
4538
a2326b5b
MS
4539/*
4540 * 'ippSetValueTag()' - Set the value tag of an attribute.
4541 *
a469f8a5
MS
4542 * The @code ipp@ parameter refers to an IPP message previously created using
4543 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
4544 *
4545 * The @code attr@ parameter may be modified as a result of setting the value.
4546 *
4547 * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger
4548 * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name
4549 * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text
4550 * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage
4551 * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various
4552 * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes
4553 * will be rejected.
4554 *
4555 * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language
4556 * code in the "attributes-natural-language" attribute or, if not present, the language
4557 * code for the current locale.
4558 *
f3c17241 4559 * @since CUPS 1.6/OS X 10.8@
a2326b5b 4560 */
ef416fc2 4561
a2326b5b
MS
4562int /* O - 1 on success, 0 on failure */
4563ippSetValueTag(
6961465f 4564 ipp_t *ipp, /* I - IPP message */
a2326b5b
MS
4565 ipp_attribute_t **attr, /* IO - IPP attribute */
4566 ipp_tag_t value_tag) /* I - Value tag */
4567{
4568 int i; /* Looping var */
4569 _ipp_value_t *value; /* Current value */
4570 int integer; /* Current integer value */
4571 cups_lang_t *language; /* Current language */
4572 char code[32]; /* Language code */
4573 ipp_tag_t temp_tag; /* Temporary value tag */
ef416fc2 4574
ef416fc2 4575
a2326b5b
MS
4576 /*
4577 * Range check input...
4578 */
1f6f3dbc 4579
a469f8a5 4580 if (!ipp || !attr || !*attr)
a2326b5b 4581 return (0);
ef416fc2 4582
a2326b5b
MS
4583 /*
4584 * If there is no change, return immediately...
4585 */
ef416fc2 4586
a2326b5b
MS
4587 if (value_tag == (*attr)->value_tag)
4588 return (1);
ef416fc2 4589
a2326b5b
MS
4590 /*
4591 * Otherwise implement changes as needed...
4592 */
ef416fc2 4593
cb7f98ee 4594 temp_tag = (ipp_tag_t)((int)((*attr)->value_tag) & IPP_TAG_CUPS_MASK);
4400e98d 4595
a2326b5b
MS
4596 switch (value_tag)
4597 {
4598 case IPP_TAG_UNSUPPORTED_VALUE :
4599 case IPP_TAG_DEFAULT :
4600 case IPP_TAG_UNKNOWN :
4601 case IPP_TAG_NOVALUE :
4602 case IPP_TAG_NOTSETTABLE :
4603 case IPP_TAG_DELETEATTR :
4604 case IPP_TAG_ADMINDEFINE :
4605 /*
4606 * Free any existing values...
4607 */
ef416fc2 4608
a2326b5b
MS
4609 if ((*attr)->num_values > 0)
4610 ipp_free_values(*attr, 0, (*attr)->num_values);
ef416fc2 4611
a2326b5b
MS
4612 /*
4613 * Set out-of-band value...
4614 */
ef416fc2 4615
a2326b5b
MS
4616 (*attr)->value_tag = value_tag;
4617 break;
91c84a35 4618
a2326b5b
MS
4619 case IPP_TAG_RANGE :
4620 if (temp_tag != IPP_TAG_INTEGER)
4621 return (0);
4622
4623 for (i = (*attr)->num_values, value = (*attr)->values;
4624 i > 0;
4625 i --, value ++)
4626 {
4627 integer = value->integer;
4628 value->range.lower = value->range.upper = integer;
4629 }
ef416fc2 4630
a2326b5b
MS
4631 (*attr)->value_tag = IPP_TAG_RANGE;
4632 break;
ef416fc2 4633
a2326b5b
MS
4634 case IPP_TAG_NAME :
4635 if (temp_tag != IPP_TAG_KEYWORD && temp_tag != IPP_TAG_URI &&
4636 temp_tag != IPP_TAG_URISCHEME && temp_tag != IPP_TAG_LANGUAGE &&
4637 temp_tag != IPP_TAG_MIMETYPE)
4638 return (0);
ef416fc2 4639
cb7f98ee 4640 (*attr)->value_tag = (ipp_tag_t)(IPP_TAG_NAME | ((*attr)->value_tag & IPP_TAG_CUPS_CONST));
ef416fc2 4641 break;
4642
a2326b5b
MS
4643 case IPP_TAG_NAMELANG :
4644 case IPP_TAG_TEXTLANG :
4645 if (value_tag == IPP_TAG_NAMELANG &&
4646 (temp_tag != IPP_TAG_NAME && temp_tag != IPP_TAG_KEYWORD &&
4647 temp_tag != IPP_TAG_URI && temp_tag != IPP_TAG_URISCHEME &&
4648 temp_tag != IPP_TAG_LANGUAGE && temp_tag != IPP_TAG_MIMETYPE))
4649 return (0);
4650
4651 if (value_tag == IPP_TAG_TEXTLANG && temp_tag != IPP_TAG_TEXT)
4652 return (0);
4653
4654 if (ipp->attrs && ipp->attrs->next && ipp->attrs->next->name &&
4655 !strcmp(ipp->attrs->next->name, "attributes-natural-language"))
4656 {
4657 /*
4658 * Use the language code from the IPP message...
4659 */
4660
4661 (*attr)->values[0].string.language =
4662 _cupsStrAlloc(ipp->attrs->next->values[0].string.text);
4663 }
4664 else
4665 {
4666 /*
4667 * Otherwise, use the language code corresponding to the locale...
4668 */
4669
4670 language = cupsLangDefault();
4671 (*attr)->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language->language,
4672 code,
4673 sizeof(code)));
4674 }
4675
4676 for (i = (*attr)->num_values - 1, value = (*attr)->values + 1;
4677 i > 0;
4678 i --, value ++)
4679 value->string.language = (*attr)->values[0].string.language;
4680
cb7f98ee 4681 if ((int)(*attr)->value_tag & IPP_TAG_CUPS_CONST)
a2326b5b
MS
4682 {
4683 /*
4684 * Make copies of all values...
4685 */
4686
4687 for (i = (*attr)->num_values, value = (*attr)->values;
4688 i > 0;
4689 i --, value ++)
4690 value->string.text = _cupsStrAlloc(value->string.text);
4691 }
4692
4693 (*attr)->value_tag = IPP_TAG_NAMELANG;
ef416fc2 4694 break;
4695
a2326b5b
MS
4696 case IPP_TAG_KEYWORD :
4697 if (temp_tag == IPP_TAG_NAME || temp_tag == IPP_TAG_NAMELANG)
4698 break; /* Silently "allow" name -> keyword */
4699
ef416fc2 4700 default :
a2326b5b 4701 return (0);
ef416fc2 4702 }
4703
a2326b5b
MS
4704 return (1);
4705}
4706
4707
4708/*
4709 * 'ippSetVersion()' - Set the version number in an IPP message.
4710 *
a469f8a5
MS
4711 * The @code ipp@ parameter refers to an IPP message previously created using
4712 * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions.
a2326b5b
MS
4713 *
4714 * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
4715 *
f3c17241 4716 * @since CUPS 1.6/OS X 10.8@
a2326b5b
MS
4717 */
4718
4719int /* O - 1 on success, 0 on failure */
4720ippSetVersion(ipp_t *ipp, /* I - IPP message */
4721 int major, /* I - Major version number (major.minor) */
4722 int minor) /* I - Minor version number (major.minor) */
4723{
4724 /*
4725 * Range check input...
4726 */
4727
4728 if (!ipp || major < 0 || minor < 0)
4729 return (0);
4730
4731 /*
4732 * Set the version number...
4733 */
4734
1a18c85c
MS
4735 ipp->request.any.version[0] = (ipp_uchar_t)major;
4736 ipp->request.any.version[1] = (ipp_uchar_t)minor;
89d46774 4737
a2326b5b 4738 return (1);
ef416fc2 4739}
4740
4741
4742/*
4743 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
4744 */
4745
4746const ipp_uchar_t * /* O - RFC-1903 date/time data */
4747ippTimeToDate(time_t t) /* I - UNIX time value */
4748{
4749 struct tm *unixdate; /* UNIX unixdate/time info */
4750 ipp_uchar_t *date = _cupsGlobals()->ipp_date;
4751 /* RFC-1903 date/time data */
4752
4753
4754 /*
4755 * RFC-1903 date/time format is:
4756 *
4757 * Byte(s) Description
4758 * ------- -----------
4759 * 0-1 Year (0 to 65535)
4760 * 2 Month (1 to 12)
4761 * 3 Day (1 to 31)
4762 * 4 Hours (0 to 23)
4763 * 5 Minutes (0 to 59)
4764 * 6 Seconds (0 to 60, 60 = "leap second")
4765 * 7 Deciseconds (0 to 9)
4766 * 8 +/- UTC
4767 * 9 UTC hours (0 to 11)
4768 * 10 UTC minutes (0 to 59)
4769 */
4770
4771 unixdate = gmtime(&t);
4772 unixdate->tm_year += 1900;
4773
1a18c85c
MS
4774 date[0] = (ipp_uchar_t)(unixdate->tm_year >> 8);
4775 date[1] = (ipp_uchar_t)(unixdate->tm_year);
4776 date[2] = (ipp_uchar_t)(unixdate->tm_mon + 1);
4777 date[3] = (ipp_uchar_t)unixdate->tm_mday;
4778 date[4] = (ipp_uchar_t)unixdate->tm_hour;
4779 date[5] = (ipp_uchar_t)unixdate->tm_min;
4780 date[6] = (ipp_uchar_t)unixdate->tm_sec;
ef416fc2 4781 date[7] = 0;
4782 date[8] = '+';
4783 date[9] = 0;
4784 date[10] = 0;
4785
4786 return (date);
4787}
4788
4789
c1420c87
MS
4790/*
4791 * 'ippValidateAttribute()' - Validate the contents of an attribute.
4792 *
4793 * This function validates the contents of an attribute based on the name and
4794 * value tag. 1 is returned if the attribute is valid, 0 otherwise. On
4795 * failure, cupsLastErrorString() is set to a human-readable message.
4796 *
9c0e8e5d 4797 * @since CUPS 1.7/OS X 10.9@
c1420c87
MS
4798 */
4799
4800int /* O - 1 if valid, 0 otherwise */
4801ippValidateAttribute(
4802 ipp_attribute_t *attr) /* I - Attribute */
4803{
4804 int i; /* Looping var */
4805 char scheme[64], /* Scheme from URI */
4806 userpass[256], /* Username/password from URI */
4807 hostname[256], /* Hostname from URI */
4808 resource[1024]; /* Resource from URI */
4809 int port, /* Port number from URI */
4810 uri_status; /* URI separation status */
4811 const char *ptr; /* Pointer into string */
4812 ipp_attribute_t *colattr; /* Collection attribute */
4813 regex_t re; /* Regular expression */
4814 ipp_uchar_t *date; /* Current date value */
4815 static const char * const uri_status_strings[] =
4816 { /* URI status strings */
4817 "URI too large",
4818 "Bad arguments to function",
4819 "Bad resource in URI",
4820 "Bad port number in URI",
4821 "Bad hostname/address in URI",
4822 "Bad username in URI",
4823 "Bad scheme in URI",
4824 "Bad/empty URI",
4825 "OK",
4826 "Missing scheme in URI",
4827 "Unknown scheme in URI",
4828 "Missing resource in URI"
4829 };
4830
4831
4832 /*
4833 * Skip separators.
4834 */
4835
4836 if (!attr->name)
4837 return (1);
4838
4839 /*
4840 * Validate the attribute name.
4841 */
4842
4843 for (ptr = attr->name; *ptr; ptr ++)
4844 if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' && *ptr != '_')
4845 break;
4846
4847 if (*ptr || ptr == attr->name)
4848 {
4849 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4850 _("\"%s\": Bad attribute name - invalid character "
4851 "(RFC 2911 section 4.1.3)."), attr->name);
4852 return (0);
4853 }
4854
4855 if ((ptr - attr->name) > 255)
4856 {
4857 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4858 _("\"%s\": Bad attribute name - bad length %d "
4859 "(RFC 2911 section 4.1.3)."), attr->name,
4860 (int)(ptr - attr->name));
4861 return (0);
4862 }
4863
4864 switch (attr->value_tag)
4865 {
4866 case IPP_TAG_INTEGER :
4867 break;
4868
4869 case IPP_TAG_BOOLEAN :
4870 for (i = 0; i < attr->num_values; i ++)
4871 {
4872 if (attr->values[i].boolean != 0 &&
4873 attr->values[i].boolean != 1)
4874 {
4875 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4876 _("\"%s\": Bad boolen value %d "
4877 "(RFC 2911 section 4.1.11)."), attr->name,
4878 attr->values[i].boolean);
4879 return (0);
4880 }
4881 }
4882 break;
4883
4884 case IPP_TAG_ENUM :
4885 for (i = 0; i < attr->num_values; i ++)
4886 {
4887 if (attr->values[i].integer < 1)
4888 {
4889 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4890 _("\"%s\": Bad enum value %d - out of range "
4891 "(RFC 2911 section 4.1.4)."), attr->name,
4892 attr->values[i].integer);
4893 return (0);
4894 }
4895 }
4896 break;
4897
4898 case IPP_TAG_STRING :
4899 for (i = 0; i < attr->num_values; i ++)
4900 {
4901 if (attr->values[i].unknown.length > IPP_MAX_OCTETSTRING)
4902 {
4903 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4904 _("\"%s\": Bad octetString value - bad length %d "
4905 "(RFC 2911 section 4.1.10)."), attr->name,
4906 attr->values[i].unknown.length);
4907 return (0);
4908 }
4909 }
4910 break;
4911
4912 case IPP_TAG_DATE :
4913 for (i = 0; i < attr->num_values; i ++)
4914 {
4915 date = attr->values[i].date;
4916
4917 if (date[2] < 1 || date[2] > 12)
4918 {
4919 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4920 _("\"%s\": Bad dateTime month %u "
4921 "(RFC 2911 section 4.1.14)."), attr->name, date[2]);
4922 return (0);
4923 }
4924
4925 if (date[3] < 1 || date[3] > 31)
4926 {
4927 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4928 _("\"%s\": Bad dateTime day %u "
4929 "(RFC 2911 section 4.1.14)."), attr->name, date[3]);
4930 return (0);
4931 }
4932
4933 if (date[4] > 23)
4934 {
4935 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4936 _("\"%s\": Bad dateTime hours %u "
4937 "(RFC 2911 section 4.1.14)."), attr->name, date[4]);
4938 return (0);
4939 }
4940
4941 if (date[5] > 59)
4942 {
4943 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4944 _("\"%s\": Bad dateTime minutes %u "
4945 "(RFC 2911 section 4.1.14)."), attr->name, date[5]);
4946 return (0);
4947 }
4948
4949 if (date[6] > 60)
4950 {
4951 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4952 _("\"%s\": Bad dateTime seconds %u "
4953 "(RFC 2911 section 4.1.14)."), attr->name, date[6]);
4954 return (0);
4955 }
4956
4957 if (date[7] > 9)
4958 {
4959 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4960 _("\"%s\": Bad dateTime deciseconds %u "
4961 "(RFC 2911 section 4.1.14)."), attr->name, date[7]);
4962 return (0);
4963 }
4964
4965 if (date[8] != '-' && date[8] != '+')
4966 {
4967 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4968 _("\"%s\": Bad dateTime UTC sign '%c' "
4969 "(RFC 2911 section 4.1.14)."), attr->name, date[8]);
4970 return (0);
4971 }
4972
4973 if (date[9] > 11)
4974 {
4975 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4976 _("\"%s\": Bad dateTime UTC hours %u "
4977 "(RFC 2911 section 4.1.14)."), attr->name, date[9]);
4978 return (0);
4979 }
4980
4981 if (date[10] > 59)
4982 {
4983 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4984 _("\"%s\": Bad dateTime UTC minutes %u "
4985 "(RFC 2911 section 4.1.14)."), attr->name, date[10]);
4986 return (0);
4987 }
4988 }
4989 break;
4990
4991 case IPP_TAG_RESOLUTION :
4992 for (i = 0; i < attr->num_values; i ++)
4993 {
4994 if (attr->values[i].resolution.xres <= 0)
4995 {
4996 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
4997 _("\"%s\": Bad resolution value %dx%d%s - cross "
4998 "feed resolution must be positive "
4999 "(RFC 2911 section 4.1.15)."), attr->name,
5000 attr->values[i].resolution.xres,
5001 attr->values[i].resolution.yres,
5002 attr->values[i].resolution.units ==
5003 IPP_RES_PER_INCH ? "dpi" :
5004 attr->values[i].resolution.units ==
5005 IPP_RES_PER_CM ? "dpcm" : "unknown");
5006 return (0);
5007 }
5008
5009 if (attr->values[i].resolution.yres <= 0)
5010 {
5011 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5012 _("\"%s\": Bad resolution value %dx%d%s - feed "
5013 "resolution must be positive "
5014 "(RFC 2911 section 4.1.15)."), attr->name,
5015 attr->values[i].resolution.xres,
5016 attr->values[i].resolution.yres,
5017 attr->values[i].resolution.units ==
5018 IPP_RES_PER_INCH ? "dpi" :
5019 attr->values[i].resolution.units ==
5020 IPP_RES_PER_CM ? "dpcm" : "unknown");
5021 return (0);
5022 }
5023
5024 if (attr->values[i].resolution.units != IPP_RES_PER_INCH &&
5025 attr->values[i].resolution.units != IPP_RES_PER_CM)
5026 {
5027 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5028 _("\"%s\": Bad resolution value %dx%d%s - bad "
5029 "units value (RFC 2911 section 4.1.15)."),
5030 attr->name, attr->values[i].resolution.xres,
5031 attr->values[i].resolution.yres,
5032 attr->values[i].resolution.units ==
5033 IPP_RES_PER_INCH ? "dpi" :
5034 attr->values[i].resolution.units ==
5035 IPP_RES_PER_CM ? "dpcm" : "unknown");
5036 return (0);
5037 }
5038 }
5039 break;
5040
5041 case IPP_TAG_RANGE :
5042 for (i = 0; i < attr->num_values; i ++)
5043 {
5044 if (attr->values[i].range.lower > attr->values[i].range.upper)
5045 {
5046 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5047 _("\"%s\": Bad rangeOfInteger value %d-%d - lower "
5048 "greater than upper (RFC 2911 section 4.1.13)."),
5049 attr->name, attr->values[i].range.lower,
5050 attr->values[i].range.upper);
5051 return (0);
5052 }
5053 }
5054 break;
5055
5056 case IPP_TAG_BEGIN_COLLECTION :
5057 for (i = 0; i < attr->num_values; i ++)
5058 {
5059 for (colattr = attr->values[i].collection->attrs;
5060 colattr;
5061 colattr = colattr->next)
5062 {
5063 if (!ippValidateAttribute(colattr))
5064 return (0);
5065 }
5066 }
5067 break;
5068
5069 case IPP_TAG_TEXT :
5070 case IPP_TAG_TEXTLANG :
5071 for (i = 0; i < attr->num_values; i ++)
5072 {
5073 for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5074 {
5075 if ((*ptr & 0xe0) == 0xc0)
5076 {
5077 ptr ++;
5078 if ((*ptr & 0xc0) != 0x80)
5079 break;
5080 }
5081 else if ((*ptr & 0xf0) == 0xe0)
5082 {
5083 ptr ++;
5084 if ((*ptr & 0xc0) != 0x80)
5085 break;
5086 ptr ++;
5087 if ((*ptr & 0xc0) != 0x80)
5088 break;
5089 }
5090 else if ((*ptr & 0xf8) == 0xf0)
5091 {
5092 ptr ++;
5093 if ((*ptr & 0xc0) != 0x80)
5094 break;
5095 ptr ++;
5096 if ((*ptr & 0xc0) != 0x80)
5097 break;
5098 ptr ++;
5099 if ((*ptr & 0xc0) != 0x80)
5100 break;
5101 }
5102 else if (*ptr & 0x80)
5103 break;
5104 }
5105
5106 if (*ptr)
5107 {
5108 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5109 _("\"%s\": Bad text value \"%s\" - bad UTF-8 "
5110 "sequence (RFC 2911 section 4.1.1)."), attr->name,
5111 attr->values[i].string.text);
5112 return (0);
5113 }
5114
5115 if ((ptr - attr->values[i].string.text) > (IPP_MAX_TEXT - 1))
5116 {
5117 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5118 _("\"%s\": Bad text value \"%s\" - bad length %d "
5119 "(RFC 2911 section 4.1.1)."), attr->name,
5120 attr->values[i].string.text,
5121 (int)(ptr - attr->values[i].string.text));
5122 return (0);
5123 }
5124 }
5125 break;
5126
5127 case IPP_TAG_NAME :
5128 case IPP_TAG_NAMELANG :
5129 for (i = 0; i < attr->num_values; i ++)
5130 {
5131 for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5132 {
5133 if ((*ptr & 0xe0) == 0xc0)
5134 {
5135 ptr ++;
5136 if ((*ptr & 0xc0) != 0x80)
5137 break;
5138 }
5139 else if ((*ptr & 0xf0) == 0xe0)
5140 {
5141 ptr ++;
5142 if ((*ptr & 0xc0) != 0x80)
5143 break;
5144 ptr ++;
5145 if ((*ptr & 0xc0) != 0x80)
5146 break;
5147 }
5148 else if ((*ptr & 0xf8) == 0xf0)
5149 {
5150 ptr ++;
5151 if ((*ptr & 0xc0) != 0x80)
5152 break;
5153 ptr ++;
5154 if ((*ptr & 0xc0) != 0x80)
5155 break;
5156 ptr ++;
5157 if ((*ptr & 0xc0) != 0x80)
5158 break;
5159 }
5160 else if (*ptr & 0x80)
5161 break;
5162 }
5163
5164 if (*ptr)
5165 {
5166 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5167 _("\"%s\": Bad name value \"%s\" - bad UTF-8 "
5168 "sequence (RFC 2911 section 4.1.2)."), attr->name,
5169 attr->values[i].string.text);
5170 return (0);
5171 }
5172
5173 if ((ptr - attr->values[i].string.text) > (IPP_MAX_NAME - 1))
5174 {
5175 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5176 _("\"%s\": Bad name value \"%s\" - bad length %d "
5177 "(RFC 2911 section 4.1.2)."), attr->name,
5178 attr->values[i].string.text,
5179 (int)(ptr - attr->values[i].string.text));
5180 return (0);
5181 }
5182 }
5183 break;
5184
5185 case IPP_TAG_KEYWORD :
5186 for (i = 0; i < attr->num_values; i ++)
5187 {
5188 for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5189 if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' &&
5190 *ptr != '_')
5191 break;
5192
5193 if (*ptr || ptr == attr->values[i].string.text)
5194 {
5195 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5196 _("\"%s\": Bad keyword value \"%s\" - invalid "
5197 "character (RFC 2911 section 4.1.3)."),
5198 attr->name, attr->values[i].string.text);
5199 return (0);
5200 }
5201
5202 if ((ptr - attr->values[i].string.text) > (IPP_MAX_KEYWORD - 1))
5203 {
5204 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5205 _("\"%s\": Bad keyword value \"%s\" - bad "
5206 "length %d (RFC 2911 section 4.1.3)."),
5207 attr->name, attr->values[i].string.text,
5208 (int)(ptr - attr->values[i].string.text));
5209 return (0);
5210 }
5211 }
5212 break;
5213
5214 case IPP_TAG_URI :
5215 for (i = 0; i < attr->num_values; i ++)
5216 {
5217 uri_status = httpSeparateURI(HTTP_URI_CODING_ALL,
5218 attr->values[i].string.text,
5219 scheme, sizeof(scheme),
5220 userpass, sizeof(userpass),
5221 hostname, sizeof(hostname),
5222 &port, resource, sizeof(resource));
5223
cb7f98ee 5224 if (uri_status < HTTP_URI_STATUS_OK)
c1420c87
MS
5225 {
5226 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5227 _("\"%s\": Bad URI value \"%s\" - %s "
5228 "(RFC 2911 section 4.1.5)."), attr->name,
5229 attr->values[i].string.text,
5230 uri_status_strings[uri_status -
cb7f98ee 5231 HTTP_URI_STATUS_OVERFLOW]);
c1420c87
MS
5232 return (0);
5233 }
5234
5235 if (strlen(attr->values[i].string.text) > (IPP_MAX_URI - 1))
5236 {
5237 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5238 _("\"%s\": Bad URI value \"%s\" - bad length %d "
5239 "(RFC 2911 section 4.1.5)."), attr->name,
5240 attr->values[i].string.text,
5241 (int)strlen(attr->values[i].string.text));
5242 }
5243 }
5244 break;
5245
5246 case IPP_TAG_URISCHEME :
5247 for (i = 0; i < attr->num_values; i ++)
5248 {
5249 ptr = attr->values[i].string.text;
5250 if (islower(*ptr & 255))
5251 {
5252 for (ptr ++; *ptr; ptr ++)
5253 if (!islower(*ptr & 255) && !isdigit(*ptr & 255) &&
5254 *ptr != '+' && *ptr != '-' && *ptr != '.')
5255 break;
5256 }
5257
5258 if (*ptr || ptr == attr->values[i].string.text)
5259 {
5260 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5261 _("\"%s\": Bad uriScheme value \"%s\" - bad "
5262 "characters (RFC 2911 section 4.1.6)."),
5263 attr->name, attr->values[i].string.text);
5264 return (0);
5265 }
5266
5267 if ((ptr - attr->values[i].string.text) > (IPP_MAX_URISCHEME - 1))
5268 {
5269 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5270 _("\"%s\": Bad uriScheme value \"%s\" - bad "
5271 "length %d (RFC 2911 section 4.1.6)."),
5272 attr->name, attr->values[i].string.text,
5273 (int)(ptr - attr->values[i].string.text));
5274 return (0);
5275 }
5276 }
5277 break;
5278
5279 case IPP_TAG_CHARSET :
5280 for (i = 0; i < attr->num_values; i ++)
5281 {
5282 for (ptr = attr->values[i].string.text; *ptr; ptr ++)
5283 if (!isprint(*ptr & 255) || isupper(*ptr & 255) ||
5284 isspace(*ptr & 255))
5285 break;
5286
5287 if (*ptr || ptr == attr->values[i].string.text)
5288 {
5289 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5290 _("\"%s\": Bad charset value \"%s\" - bad "
5291 "characters (RFC 2911 section 4.1.7)."),
5292 attr->name, attr->values[i].string.text);
5293 return (0);
5294 }
5295
5296 if ((ptr - attr->values[i].string.text) > (IPP_MAX_CHARSET - 1))
5297 {
5298 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5299 _("\"%s\": Bad charset value \"%s\" - bad "
5300 "length %d (RFC 2911 section 4.1.7)."),
5301 attr->name, attr->values[i].string.text,
5302 (int)(ptr - attr->values[i].string.text));
5303 return (0);
5304 }
5305 }
5306 break;
5307
5308 case IPP_TAG_LANGUAGE :
5309 /*
5310 * The following regular expression is derived from the ABNF for
5311 * language tags in RFC 4646. All I can say is that this is the
5312 * easiest way to check the values...
5313 */
5314
5315 if ((i = regcomp(&re,
5316 "^("
5317 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
5318 /* language */
5319 "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */
5320 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */
5321 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */
5322 "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */
5323 "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */
5324 "|"
5325 "x(-[a-z0-9]{1,8})+" /* privateuse */
5326 "|"
5327 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
5328 ")$",
5329 REG_NOSUB | REG_EXTENDED)) != 0)
5330 {
5331 char temp[256]; /* Temporary error string */
5332
5333 regerror(i, &re, temp, sizeof(temp));
5334 ipp_set_error(IPP_STATUS_ERROR_INTERNAL,
5335 _("Unable to compile naturalLanguage regular "
5336 "expression: %s."), temp);
5337 return (0);
5338 }
5339
5340 for (i = 0; i < attr->num_values; i ++)
5341 {
5342 if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
5343 {
5344 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5345 _("\"%s\": Bad naturalLanguage value \"%s\" - bad "
5346 "characters (RFC 2911 section 4.1.8)."),
5347 attr->name, attr->values[i].string.text);
5348 regfree(&re);
5349 return (0);
5350 }
5351
5352 if (strlen(attr->values[i].string.text) > (IPP_MAX_LANGUAGE - 1))
5353 {
5354 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5355 _("\"%s\": Bad naturalLanguage value \"%s\" - bad "
5356 "length %d (RFC 2911 section 4.1.8)."),
5357 attr->name, attr->values[i].string.text,
5358 (int)strlen(attr->values[i].string.text));
5359 regfree(&re);
5360 return (0);
5361 }
5362 }
5363
5364 regfree(&re);
5365 break;
5366
5367 case IPP_TAG_MIMETYPE :
5368 /*
5369 * The following regular expression is derived from the ABNF for
5370 * MIME media types in RFC 2045 and 4288. All I can say is that this is
5371 * the easiest way to check the values...
5372 */
5373
5374 if ((i = regcomp(&re,
5375 "^"
5376 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
5377 "/"
5378 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
5379 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
5380 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
5381 /* value */
5382 "$",
5383 REG_NOSUB | REG_EXTENDED)) != 0)
5384 {
5385 char temp[256]; /* Temporary error string */
5386
5387 regerror(i, &re, temp, sizeof(temp));
5388 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5389 _("Unable to compile mimeMediaType regular "
5390 "expression: %s."), temp);
5391 return (0);
5392 }
5393
5394 for (i = 0; i < attr->num_values; i ++)
5395 {
5396 if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
5397 {
5398 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5399 _("\"%s\": Bad mimeMediaType value \"%s\" - bad "
5400 "characters (RFC 2911 section 4.1.9)."),
5401 attr->name, attr->values[i].string.text);
5402 regfree(&re);
5403 return (0);
5404 }
5405
5406 if (strlen(attr->values[i].string.text) > (IPP_MAX_MIMETYPE - 1))
5407 {
5408 ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
5409 _("\"%s\": Bad mimeMediaType value \"%s\" - bad "
5410 "length %d (RFC 2911 section 4.1.9)."),
5411 attr->name, attr->values[i].string.text,
5412 (int)strlen(attr->values[i].string.text));
5413 regfree(&re);
5414 return (0);
5415 }
5416 }
5417
5418 regfree(&re);
5419 break;
5420
5421 default :
5422 break;
5423 }
5424
5425 return (1);
5426}
5427
5428
5429/*
5430 * 'ippValidateAttributes()' - Validate all attributes in an IPP message.
5431 *
5432 * This function validates the contents of the IPP message, including each
5433 * attribute. Like @link ippValidateAttribute@, cupsLastErrorString() is set
5434 * to a human-readable message on failure.
5435 *
9c0e8e5d 5436 * @since CUPS 1.7/OS X 10.9@
c1420c87
MS
5437 */
5438
5439int /* O - 1 if valid, 0 otherwise */
5440ippValidateAttributes(ipp_t *ipp) /* I - IPP message */
5441{
5442 ipp_attribute_t *attr; /* Current attribute */
5443
5444
5445 if (!ipp)
5446 return (1);
5447
5448 for (attr = ipp->attrs; attr; attr = attr->next)
5449 if (!ippValidateAttribute(attr))
5450 return (0);
5451
5452 return (1);
5453}
5454
5455
ef416fc2 5456/*
5457 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
5458 */
5459
5460ipp_state_t /* O - Current state */
5461ippWrite(http_t *http, /* I - HTTP connection */
5462 ipp_t *ipp) /* I - IPP data */
5463{
e07d4801 5464 DEBUG_printf(("ippWrite(http=%p, ipp=%p)", http, ipp));
ef416fc2 5465
1ff0402e 5466 if (!http)
cb7f98ee 5467 return (IPP_STATE_ERROR);
ef416fc2 5468
e07d4801 5469 return (ippWriteIO(http, (ipp_iocb_t)httpWrite2, http->blocking, NULL, ipp));
ef416fc2 5470}
5471
5472
5473/*
5474 * 'ippWriteFile()' - Write data for an IPP message to a file.
5475 *
f3c17241 5476 * @since CUPS 1.1.19/OS X 10.3@
ef416fc2 5477 */
5478
5479ipp_state_t /* O - Current state */
5480ippWriteFile(int fd, /* I - HTTP data */
5481 ipp_t *ipp) /* I - IPP data */
5482{
e07d4801 5483 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd, ipp));
ef416fc2 5484
cb7f98ee 5485 ipp->state = IPP_STATE_IDLE;
ef416fc2 5486
5487 return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp));
5488}
5489
5490
5491/*
5492 * 'ippWriteIO()' - Write data for an IPP message.
5493 *
f3c17241 5494 * @since CUPS 1.2/OS X 10.5@
ef416fc2 5495 */
5496
5497ipp_state_t /* O - Current state */
5498ippWriteIO(void *dst, /* I - Destination */
5499 ipp_iocb_t cb, /* I - Write callback function */
5500 int blocking, /* I - Use blocking IO? */
5501 ipp_t *parent, /* I - Parent IPP message */
5502 ipp_t *ipp) /* I - IPP data */
5503{
5504 int i; /* Looping var */
5505 int n; /* Length of data */
1f6f3dbc 5506 unsigned char *buffer, /* Data buffer */
ef416fc2 5507 *bufptr; /* Pointer into buffer */
5508 ipp_attribute_t *attr; /* Current attribute */
a2326b5b 5509 _ipp_value_t *value; /* Current value */
ef416fc2 5510
5511
e07d4801 5512 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
1ff0402e 5513 dst, cb, blocking, parent, ipp));
ef416fc2 5514
1ff0402e 5515 if (!dst || !ipp)
cb7f98ee 5516 return (IPP_STATE_ERROR);
ef416fc2 5517
dcb445bc 5518 if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
1f6f3dbc 5519 {
e07d4801 5520 DEBUG_puts("1ippWriteIO: Unable to get write buffer");
cb7f98ee 5521 return (IPP_STATE_ERROR);
1f6f3dbc
MS
5522 }
5523
ef416fc2 5524 switch (ipp->state)
5525 {
cb7f98ee 5526 case IPP_STATE_IDLE :
ef416fc2 5527 ipp->state ++; /* Avoid common problem... */
5528
cb7f98ee 5529 case IPP_STATE_HEADER :
ef416fc2 5530 if (parent == NULL)
5531 {
5532 /*
5533 * Send the request header:
5534 *
5535 * Version = 2 bytes
5536 * Operation/Status Code = 2 bytes
5537 * Request ID = 4 bytes
5538 * Total = 8 bytes
5539 */
5540
5541 bufptr = buffer;
5542
5543 *bufptr++ = ipp->request.any.version[0];
5544 *bufptr++ = ipp->request.any.version[1];
1a18c85c
MS
5545 *bufptr++ = (ipp_uchar_t)(ipp->request.any.op_status >> 8);
5546 *bufptr++ = (ipp_uchar_t)ipp->request.any.op_status;
5547 *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 24);
5548 *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 16);
5549 *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 8);
5550 *bufptr++ = (ipp_uchar_t)ipp->request.any.request_id;
ef416fc2 5551
ba55dc12
MS
5552 DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer[0], buffer[1]));
5553 DEBUG_printf(("2ippWriteIO: op_status=%04x",
5554 ipp->request.any.op_status));
5555 DEBUG_printf(("2ippWriteIO: request_id=%d",
5556 ipp->request.any.request_id));
5557
1a18c85c 5558 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ef416fc2 5559 {
e07d4801 5560 DEBUG_puts("1ippWriteIO: Could not write IPP header...");
dcb445bc 5561 _cupsBufferRelease((char *)buffer);
cb7f98ee 5562 return (IPP_STATE_ERROR);
ef416fc2 5563 }
5564 }
5565
5566 /*
5567 * Reset the state engine to point to the first attribute
5568 * in the request/response, with no current group.
5569 */
5570
cb7f98ee 5571 ipp->state = IPP_STATE_ATTRIBUTE;
ef416fc2 5572 ipp->current = ipp->attrs;
5573 ipp->curtag = IPP_TAG_ZERO;
5574
ba55dc12 5575 DEBUG_printf(("1ippWriteIO: ipp->current=%p", ipp->current));
ef416fc2 5576
5577 /*
5578 * If blocking is disabled, stop here...
5579 */
5580
5581 if (!blocking)
5582 break;
5583
cb7f98ee 5584 case IPP_STATE_ATTRIBUTE :
ef416fc2 5585 while (ipp->current != NULL)
5586 {
5587 /*
5588 * Write this attribute...
5589 */
5590
5591 bufptr = buffer;
5592 attr = ipp->current;
5593
5594 ipp->current = ipp->current->next;
5595
ba55dc12 5596 if (!parent)
ef416fc2 5597 {
ba55dc12
MS
5598 if (ipp->curtag != attr->group_tag)
5599 {
5600 /*
5601 * Send a group tag byte...
5602 */
ef416fc2 5603
ba55dc12 5604 ipp->curtag = attr->group_tag;
ef416fc2 5605
ba55dc12
MS
5606 if (attr->group_tag == IPP_TAG_ZERO)
5607 continue;
ef416fc2 5608
ba55dc12
MS
5609 DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
5610 attr->group_tag, ippTagString(attr->group_tag)));
1a18c85c 5611 *bufptr++ = (ipp_uchar_t)attr->group_tag;
ba55dc12
MS
5612 }
5613 else if (attr->group_tag == IPP_TAG_ZERO)
5614 continue;
ef416fc2 5615 }
ba55dc12
MS
5616
5617 DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr->name,
5618 attr->num_values > 1 ? "1setOf " : "",
5619 ippTagString(attr->value_tag)));
ef416fc2 5620
5621 /*
a2326b5b 5622 * Write the attribute tag and name.
ef416fc2 5623 *
5624 * The attribute name length does not include the trailing nul
5625 * character in the source string.
5626 *
5627 * Collection values (parent != NULL) are written differently...
5628 */
5629
5630 if (parent == NULL)
5631 {
5632 /*
5633 * Get the length of the attribute name, and make sure it won't
5634 * overflow the buffer...
5635 */
5636
a2326b5b 5637 if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 8))
1f6f3dbc 5638 {
e07d4801 5639 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
dcb445bc 5640 _cupsBufferRelease((char *)buffer);
cb7f98ee 5641 return (IPP_STATE_ERROR);
1f6f3dbc 5642 }
ef416fc2 5643
5644 /*
5645 * Write the value tag, name length, and name string...
5646 */
5647
e07d4801 5648 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
1ff0402e 5649 attr->value_tag, ippTagString(attr->value_tag)));
e07d4801 5650 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
1ff0402e 5651 attr->name));
ef416fc2 5652
a2326b5b
MS
5653 if (attr->value_tag > 0xff)
5654 {
5655 *bufptr++ = IPP_TAG_EXTENSION;
1a18c85c
MS
5656 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
5657 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
5658 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
5659 *bufptr++ = (ipp_uchar_t)attr->value_tag;
a2326b5b
MS
5660 }
5661 else
1a18c85c 5662 *bufptr++ = (ipp_uchar_t)attr->value_tag;
a2326b5b 5663
1a18c85c
MS
5664 *bufptr++ = (ipp_uchar_t)(n >> 8);
5665 *bufptr++ = (ipp_uchar_t)n;
5666 memcpy(bufptr, attr->name, (size_t)n);
ef416fc2 5667 bufptr += n;
5668 }
5669 else
5670 {
5671 /*
5672 * Get the length of the attribute name, and make sure it won't
5673 * overflow the buffer...
5674 */
5675
a2326b5b 5676 if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 12))
1f6f3dbc 5677 {
e07d4801 5678 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
dcb445bc 5679 _cupsBufferRelease((char *)buffer);
cb7f98ee 5680 return (IPP_STATE_ERROR);
1f6f3dbc 5681 }
ef416fc2 5682
5683 /*
5684 * Write the member name tag, name length, name string, value tag,
5685 * and empty name for the collection member attribute...
5686 */
5687
e07d4801 5688 DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
ef416fc2 5689 IPP_TAG_MEMBERNAME));
e07d4801 5690 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
1ff0402e 5691 attr->name));
e07d4801 5692 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
1ff0402e 5693 attr->value_tag, ippTagString(attr->value_tag)));
e07d4801 5694 DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
ef416fc2 5695
5696 *bufptr++ = IPP_TAG_MEMBERNAME;
5697 *bufptr++ = 0;
5698 *bufptr++ = 0;
1a18c85c
MS
5699 *bufptr++ = (ipp_uchar_t)(n >> 8);
5700 *bufptr++ = (ipp_uchar_t)n;
5701 memcpy(bufptr, attr->name, (size_t)n);
ef416fc2 5702 bufptr += n;
5703
a2326b5b
MS
5704 if (attr->value_tag > 0xff)
5705 {
5706 *bufptr++ = IPP_TAG_EXTENSION;
1a18c85c
MS
5707 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
5708 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
5709 *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
5710 *bufptr++ = (ipp_uchar_t)attr->value_tag;
a2326b5b
MS
5711 }
5712 else
1a18c85c 5713 *bufptr++ = (ipp_uchar_t)attr->value_tag;
a2326b5b 5714
ef416fc2 5715 *bufptr++ = 0;
5716 *bufptr++ = 0;
5717 }
5718
5719 /*
5720 * Now write the attribute value(s)...
5721 */
5722
cb7f98ee 5723 switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
ef416fc2 5724 {
a2326b5b
MS
5725 case IPP_TAG_UNSUPPORTED_VALUE :
5726 case IPP_TAG_DEFAULT :
5727 case IPP_TAG_UNKNOWN :
5728 case IPP_TAG_NOVALUE :
5729 case IPP_TAG_NOTSETTABLE :
5730 case IPP_TAG_DELETEATTR :
5731 case IPP_TAG_ADMINDEFINE :
5732 *bufptr++ = 0;
5733 *bufptr++ = 0;
5734 break;
5735
ef416fc2 5736 case IPP_TAG_INTEGER :
5737 case IPP_TAG_ENUM :
5738 for (i = 0, value = attr->values;
5739 i < attr->num_values;
5740 i ++, value ++)
5741 {
1f6f3dbc 5742 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 9)
ef416fc2 5743 {
1a18c85c 5744 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ef416fc2 5745 {
e07d4801 5746 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 5747 "attribute...");
dcb445bc 5748 _cupsBufferRelease((char *)buffer);
cb7f98ee 5749 return (IPP_STATE_ERROR);
ef416fc2 5750 }
5751
5752 bufptr = buffer;
5753 }
5754
5755 if (i)
5756 {
5757 /*
5758 * Arrays and sets are done by sending additional
5759 * values with a zero-length name...
5760 */
5761
1a18c85c 5762 *bufptr++ = (ipp_uchar_t)attr->value_tag;
ef416fc2 5763 *bufptr++ = 0;
5764 *bufptr++ = 0;
5765 }
5766
5767 /*
5768 * Integers and enumerations are both 4-byte signed
5769 * (twos-complement) values.
5770 *
5771 * Put the 2-byte length and 4-byte value into the buffer...
5772 */
5773
5774 *bufptr++ = 0;
5775 *bufptr++ = 4;
1a18c85c
MS
5776 *bufptr++ = (ipp_uchar_t)(value->integer >> 24);
5777 *bufptr++ = (ipp_uchar_t)(value->integer >> 16);
5778 *bufptr++ = (ipp_uchar_t)(value->integer >> 8);
5779 *bufptr++ = (ipp_uchar_t)value->integer;
ef416fc2 5780 }
5781 break;
5782
5783 case IPP_TAG_BOOLEAN :
5784 for (i = 0, value = attr->values;
5785 i < attr->num_values;
5786 i ++, value ++)
5787 {
1f6f3dbc 5788 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 6)
ef416fc2 5789 {
1a18c85c 5790 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ef416fc2 5791 {
e07d4801 5792 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 5793 "attribute...");
dcb445bc 5794 _cupsBufferRelease((char *)buffer);
cb7f98ee 5795 return (IPP_STATE_ERROR);
ef416fc2 5796 }
5797
5798 bufptr = buffer;
5799 }
5800
5801 if (i)
5802 {
5803 /*
5804 * Arrays and sets are done by sending additional
5805 * values with a zero-length name...
5806 */
5807
1a18c85c 5808 *bufptr++ = (ipp_uchar_t)attr->value_tag;
ef416fc2 5809 *bufptr++ = 0;
5810 *bufptr++ = 0;
5811 }
5812
5813 /*
5814 * Boolean values are 1-byte; 0 = false, 1 = true.
5815 *
5816 * Put the 2-byte length and 1-byte value into the buffer...
5817 */
5818
5819 *bufptr++ = 0;
5820 *bufptr++ = 1;
1a18c85c 5821 *bufptr++ = (ipp_uchar_t)value->boolean;
ef416fc2 5822 }
5823 break;
5824
5825 case IPP_TAG_TEXT :
5826 case IPP_TAG_NAME :
5827 case IPP_TAG_KEYWORD :
ef416fc2 5828 case IPP_TAG_URI :
5829 case IPP_TAG_URISCHEME :
5830 case IPP_TAG_CHARSET :
5831 case IPP_TAG_LANGUAGE :
5832 case IPP_TAG_MIMETYPE :
5833 for (i = 0, value = attr->values;
5834 i < attr->num_values;
5835 i ++, value ++)
5836 {
5837 if (i)
5838 {
5839 /*
5840 * Arrays and sets are done by sending additional
5841 * values with a zero-length name...
5842 */
5843
e07d4801 5844 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
1ff0402e
MS
5845 attr->value_tag,
5846 ippTagString(attr->value_tag)));
e07d4801 5847 DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
ef416fc2 5848
1f6f3dbc 5849 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
ef416fc2 5850 {
1a18c85c 5851 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ef416fc2 5852 {
e07d4801 5853 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 5854 "attribute...");
dcb445bc 5855 _cupsBufferRelease((char *)buffer);
cb7f98ee 5856 return (IPP_STATE_ERROR);
ef416fc2 5857 }
5858
5859 bufptr = buffer;
5860 }
5861
1a18c85c 5862 *bufptr++ = (ipp_uchar_t)attr->value_tag;
ef416fc2 5863 *bufptr++ = 0;
5864 *bufptr++ = 0;
5865 }
5866
5867 if (value->string.text != NULL)
5868 n = (int)strlen(value->string.text);
5869 else
5870 n = 0;
5871
1f6f3dbc
MS
5872 if (n > (IPP_BUF_SIZE - 2))
5873 {
e07d4801 5874 DEBUG_printf(("1ippWriteIO: String too long (%d)", n));
dcb445bc 5875 _cupsBufferRelease((char *)buffer);
cb7f98ee 5876 return (IPP_STATE_ERROR);
1f6f3dbc 5877 }
ef416fc2 5878
e07d4801 5879 DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n,
ef416fc2 5880 value->string.text));
5881
1f6f3dbc 5882 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
ef416fc2 5883 {
1a18c85c 5884 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ef416fc2 5885 {
e07d4801 5886 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 5887 "attribute...");
dcb445bc 5888 _cupsBufferRelease((char *)buffer);
cb7f98ee 5889 return (IPP_STATE_ERROR);
ef416fc2 5890 }
5891
5892 bufptr = buffer;
5893 }
5894
5895 /*
5896 * All simple strings consist of the 2-byte length and
5897 * character data without the trailing nul normally found
a41f09e2 5898 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
ef416fc2 5899 * bytes since the 2-byte length is a signed (twos-complement)
5900 * value.
5901 *
5902 * Put the 2-byte length and string characters in the buffer.
5903 */
5904
1a18c85c
MS
5905 *bufptr++ = (ipp_uchar_t)(n >> 8);
5906 *bufptr++ = (ipp_uchar_t)n;
ef416fc2 5907
5908 if (n > 0)
5909 {
1a18c85c 5910 memcpy(bufptr, value->string.text, (size_t)n);
ef416fc2 5911 bufptr += n;
5912 }
5913 }
5914 break;
5915
5916 case IPP_TAG_DATE :
5917 for (i = 0, value = attr->values;
5918 i < attr->num_values;
5919 i ++, value ++)
5920 {
1f6f3dbc 5921 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 16)
ef416fc2 5922 {
1a18c85c 5923 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ef416fc2 5924 {
e07d4801 5925 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 5926 "attribute...");
dcb445bc 5927 _cupsBufferRelease((char *)buffer);
cb7f98ee 5928 return (IPP_STATE_ERROR);
ef416fc2 5929 }
5930
5931 bufptr = buffer;
5932 }
5933
5934 if (i)
5935 {
5936 /*
5937 * Arrays and sets are done by sending additional
5938 * values with a zero-length name...
5939 */
5940
1a18c85c 5941 *bufptr++ = (ipp_uchar_t)attr->value_tag;
ef416fc2 5942 *bufptr++ = 0;
5943 *bufptr++ = 0;
5944 }
5945
5946 /*
5947 * Date values consist of a 2-byte length and an
5948 * 11-byte date/time structure defined by RFC 1903.
5949 *
5950 * Put the 2-byte length and 11-byte date/time
5951 * structure in the buffer.
5952 */
5953
5954 *bufptr++ = 0;
5955 *bufptr++ = 11;
5956 memcpy(bufptr, value->date, 11);
5957 bufptr += 11;
5958 }
5959 break;
5960
5961 case IPP_TAG_RESOLUTION :
5962 for (i = 0, value = attr->values;
5963 i < attr->num_values;
5964 i ++, value ++)
5965 {
1f6f3dbc 5966 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 14)
ef416fc2 5967 {
1a18c85c 5968 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ef416fc2 5969 {
e07d4801 5970 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 5971 "attribute...");
dcb445bc 5972 _cupsBufferRelease((char *)buffer);
cb7f98ee 5973 return (IPP_STATE_ERROR);
ef416fc2 5974 }
5975
5976 bufptr = buffer;
5977 }
5978
5979 if (i)
5980 {
5981 /*
5982 * Arrays and sets are done by sending additional
5983 * values with a zero-length name...
5984 */
5985
1a18c85c 5986 *bufptr++ = (ipp_uchar_t)attr->value_tag;
ef416fc2 5987 *bufptr++ = 0;
5988 *bufptr++ = 0;
5989 }
5990
5991 /*
5992 * Resolution values consist of a 2-byte length,
5993 * 4-byte horizontal resolution value, 4-byte vertical
5994 * resolution value, and a 1-byte units value.
5995 *
5996 * Put the 2-byte length and resolution value data
5997 * into the buffer.
5998 */
5999
6000 *bufptr++ = 0;
6001 *bufptr++ = 9;
1a18c85c
MS
6002 *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 24);
6003 *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 16);
6004 *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 8);
6005 *bufptr++ = (ipp_uchar_t)value->resolution.xres;
6006 *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 24);
6007 *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 16);
6008 *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 8);
6009 *bufptr++ = (ipp_uchar_t)value->resolution.yres;
6010 *bufptr++ = (ipp_uchar_t)value->resolution.units;
ef416fc2 6011 }
6012 break;
6013
6014 case IPP_TAG_RANGE :
6015 for (i = 0, value = attr->values;
6016 i < attr->num_values;
6017 i ++, value ++)
6018 {
1f6f3dbc 6019 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 13)
ef416fc2 6020 {
1a18c85c 6021 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ef416fc2 6022 {
e07d4801 6023 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 6024 "attribute...");
dcb445bc 6025 _cupsBufferRelease((char *)buffer);
cb7f98ee 6026 return (IPP_STATE_ERROR);
ef416fc2 6027 }
6028
6029 bufptr = buffer;
6030 }
6031
6032 if (i)
6033 {
6034 /*
6035 * Arrays and sets are done by sending additional
6036 * values with a zero-length name...
6037 */
6038
1a18c85c 6039 *bufptr++ = (ipp_uchar_t)attr->value_tag;
ef416fc2 6040 *bufptr++ = 0;
6041 *bufptr++ = 0;
6042 }
6043
6044 /*
6045 * Range values consist of a 2-byte length,
6046 * 4-byte lower value, and 4-byte upper value.
6047 *
6048 * Put the 2-byte length and range value data
6049 * into the buffer.
6050 */
6051
6052 *bufptr++ = 0;
6053 *bufptr++ = 8;
1a18c85c
MS
6054 *bufptr++ = (ipp_uchar_t)(value->range.lower >> 24);
6055 *bufptr++ = (ipp_uchar_t)(value->range.lower >> 16);
6056 *bufptr++ = (ipp_uchar_t)(value->range.lower >> 8);
6057 *bufptr++ = (ipp_uchar_t)value->range.lower;
6058 *bufptr++ = (ipp_uchar_t)(value->range.upper >> 24);
6059 *bufptr++ = (ipp_uchar_t)(value->range.upper >> 16);
6060 *bufptr++ = (ipp_uchar_t)(value->range.upper >> 8);
6061 *bufptr++ = (ipp_uchar_t)value->range.upper;
ef416fc2 6062 }
6063 break;
6064
6065 case IPP_TAG_TEXTLANG :
6066 case IPP_TAG_NAMELANG :
6067 for (i = 0, value = attr->values;
6068 i < attr->num_values;
6069 i ++, value ++)
6070 {
6071 if (i)
6072 {
6073 /*
6074 * Arrays and sets are done by sending additional
6075 * values with a zero-length name...
6076 */
6077
1f6f3dbc 6078 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
ef416fc2 6079 {
1a18c85c 6080 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ef416fc2 6081 {
e07d4801 6082 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 6083 "attribute...");
dcb445bc 6084 _cupsBufferRelease((char *)buffer);
cb7f98ee 6085 return (IPP_STATE_ERROR);
ef416fc2 6086 }
6087
6088 bufptr = buffer;
6089 }
6090
1a18c85c 6091 *bufptr++ = (ipp_uchar_t)attr->value_tag;
ef416fc2 6092 *bufptr++ = 0;
6093 *bufptr++ = 0;
6094 }
6095
6096 /*
6097 * textWithLanguage and nameWithLanguage values consist
6098 * of a 2-byte length for both strings and their
6099 * individual lengths, a 2-byte length for the
6100 * character string, the character string without the
6101 * trailing nul, a 2-byte length for the character
6102 * set string, and the character set string without
6103 * the trailing nul.
6104 */
6105
6106 n = 4;
6107
a2326b5b
MS
6108 if (value->string.language != NULL)
6109 n += (int)strlen(value->string.language);
ef416fc2 6110
6111 if (value->string.text != NULL)
b86bc4cf 6112 n += (int)strlen(value->string.text);
ef416fc2 6113
1f6f3dbc
MS
6114 if (n > (IPP_BUF_SIZE - 2))
6115 {
e07d4801
MS
6116 DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
6117 "too long (%d)", n));
dcb445bc 6118 _cupsBufferRelease((char *)buffer);
cb7f98ee 6119 return (IPP_STATE_ERROR);
1f6f3dbc 6120 }
ef416fc2 6121
1f6f3dbc 6122 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
ef416fc2 6123 {
1a18c85c 6124 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ef416fc2 6125 {
e07d4801 6126 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 6127 "attribute...");
dcb445bc 6128 _cupsBufferRelease((char *)buffer);
cb7f98ee 6129 return (IPP_STATE_ERROR);
ef416fc2 6130 }
6131
6132 bufptr = buffer;
6133 }
6134
6135 /* Length of entire value */
1a18c85c
MS
6136 *bufptr++ = (ipp_uchar_t)(n >> 8);
6137 *bufptr++ = (ipp_uchar_t)n;
ef416fc2 6138
a2326b5b
MS
6139 /* Length of language */
6140 if (value->string.language != NULL)
6141 n = (int)strlen(value->string.language);
ef416fc2 6142 else
6143 n = 0;
6144
1a18c85c
MS
6145 *bufptr++ = (ipp_uchar_t)(n >> 8);
6146 *bufptr++ = (ipp_uchar_t)n;
ef416fc2 6147
a2326b5b 6148 /* Language */
ef416fc2 6149 if (n > 0)
6150 {
1a18c85c 6151 memcpy(bufptr, value->string.language, (size_t)n);
ef416fc2 6152 bufptr += n;
6153 }
6154
6155 /* Length of text */
6156 if (value->string.text != NULL)
6157 n = (int)strlen(value->string.text);
6158 else
6159 n = 0;
6160
1a18c85c
MS
6161 *bufptr++ = (ipp_uchar_t)(n >> 8);
6162 *bufptr++ = (ipp_uchar_t)n;
ef416fc2 6163
6164 /* Text */
6165 if (n > 0)
6166 {
1a18c85c 6167 memcpy(bufptr, value->string.text, (size_t)n);
ef416fc2 6168 bufptr += n;
6169 }
6170 }
6171 break;
6172
6173 case IPP_TAG_BEGIN_COLLECTION :
6174 for (i = 0, value = attr->values;
6175 i < attr->num_values;
6176 i ++, value ++)
6177 {
6178 /*
6179 * Collections are written with the begin-collection
6180 * tag first with a value of 0 length, followed by the
6181 * attributes in the collection, then the end-collection
6182 * value...
6183 */
6184
1f6f3dbc 6185 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 5)
ef416fc2 6186 {
1a18c85c 6187 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ef416fc2 6188 {
e07d4801 6189 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 6190 "attribute...");
dcb445bc 6191 _cupsBufferRelease((char *)buffer);
cb7f98ee 6192 return (IPP_STATE_ERROR);
ef416fc2 6193 }
6194
6195 bufptr = buffer;
6196 }
6197
6198 if (i)
6199 {
6200 /*
6201 * Arrays and sets are done by sending additional
6202 * values with a zero-length name...
6203 */
6204
1a18c85c 6205 *bufptr++ = (ipp_uchar_t)attr->value_tag;
ef416fc2 6206 *bufptr++ = 0;
6207 *bufptr++ = 0;
6208 }
6209
6210 /*
6211 * Write a data length of 0 and flush the buffer...
6212 */
6213
6214 *bufptr++ = 0;
6215 *bufptr++ = 0;
6216
1a18c85c 6217 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ef416fc2 6218 {
e07d4801 6219 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 6220 "attribute...");
dcb445bc 6221 _cupsBufferRelease((char *)buffer);
cb7f98ee 6222 return (IPP_STATE_ERROR);
ef416fc2 6223 }
6224
6225 bufptr = buffer;
6226
6227 /*
6228 * Then write the collection attribute...
6229 */
6230
cb7f98ee 6231 value->collection->state = IPP_STATE_IDLE;
ef416fc2 6232
1f6f3dbc 6233 if (ippWriteIO(dst, cb, 1, ipp,
cb7f98ee 6234 value->collection) == IPP_STATE_ERROR)
1f6f3dbc 6235 {
e07d4801 6236 DEBUG_puts("1ippWriteIO: Unable to write collection value");
dcb445bc 6237 _cupsBufferRelease((char *)buffer);
cb7f98ee 6238 return (IPP_STATE_ERROR);
1f6f3dbc 6239 }
ef416fc2 6240 }
6241 break;
6242
6243 default :
6244 for (i = 0, value = attr->values;
6245 i < attr->num_values;
6246 i ++, value ++)
6247 {
6248 if (i)
6249 {
6250 /*
6251 * Arrays and sets are done by sending additional
6252 * values with a zero-length name...
6253 */
6254
1f6f3dbc 6255 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
ef416fc2 6256 {
1a18c85c 6257 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ef416fc2 6258 {
e07d4801 6259 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 6260 "attribute...");
dcb445bc 6261 _cupsBufferRelease((char *)buffer);
cb7f98ee 6262 return (IPP_STATE_ERROR);
ef416fc2 6263 }
6264
6265 bufptr = buffer;
6266 }
6267
1a18c85c 6268 *bufptr++ = (ipp_uchar_t)attr->value_tag;
ef416fc2 6269 *bufptr++ = 0;
6270 *bufptr++ = 0;
6271 }
6272
6273 /*
6274 * An unknown value might some new value that a
6275 * vendor has come up with. It consists of a
6276 * 2-byte length and the bytes in the unknown
6277 * value buffer.
6278 */
6279
6280 n = value->unknown.length;
6281
1f6f3dbc
MS
6282 if (n > (IPP_BUF_SIZE - 2))
6283 {
e07d4801 6284 DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
1f6f3dbc 6285 n));
dcb445bc 6286 _cupsBufferRelease((char *)buffer);
cb7f98ee 6287 return (IPP_STATE_ERROR);
1f6f3dbc 6288 }
ef416fc2 6289
1f6f3dbc 6290 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
ef416fc2 6291 {
1a18c85c 6292 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ef416fc2 6293 {
e07d4801 6294 DEBUG_puts("1ippWriteIO: Could not write IPP "
1ff0402e 6295 "attribute...");
dcb445bc 6296 _cupsBufferRelease((char *)buffer);
cb7f98ee 6297 return (IPP_STATE_ERROR);
ef416fc2 6298 }
6299
6300 bufptr = buffer;
6301 }
6302
6303 /* Length of unknown value */
1a18c85c
MS
6304 *bufptr++ = (ipp_uchar_t)(n >> 8);
6305 *bufptr++ = (ipp_uchar_t)n;
ef416fc2 6306
6307 /* Value */
6308 if (n > 0)
6309 {
1a18c85c 6310 memcpy(bufptr, value->unknown.data, (size_t)n);
ef416fc2 6311 bufptr += n;
6312 }
6313 }
6314 break;
6315 }
6316
6317 /*
6318 * Write the data out...
6319 */
6320
ba55dc12 6321 if (bufptr > buffer)
ef416fc2 6322 {
1a18c85c 6323 if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
ba55dc12
MS
6324 {
6325 DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
dcb445bc 6326 _cupsBufferRelease((char *)buffer);
cb7f98ee 6327 return (IPP_STATE_ERROR);
ba55dc12 6328 }
ef416fc2 6329
ba55dc12
MS
6330 DEBUG_printf(("2ippWriteIO: wrote %d bytes",
6331 (int)(bufptr - buffer)));
6332 }
ef416fc2 6333
6334 /*
21f36711
MS
6335 * If blocking is disabled and we aren't at the end of the attribute
6336 * list, stop here...
ef416fc2 6337 */
6338
21f36711 6339 if (!blocking && ipp->current)
ef416fc2 6340 break;
6341 }
6342
6343 if (ipp->current == NULL)
6344 {
6345 /*
6346 * Done with all of the attributes; add the end-of-attributes
6347 * tag or end-collection attribute...
6348 */
6349
6350 if (parent == NULL)
6351 {
6352 buffer[0] = IPP_TAG_END;
6353 n = 1;
6354 }
6355 else
6356 {
6357 buffer[0] = IPP_TAG_END_COLLECTION;
6358 buffer[1] = 0; /* empty name */
6359 buffer[2] = 0;
6360 buffer[3] = 0; /* empty value */
6361 buffer[4] = 0;
6362 n = 5;
6363 }
6364
1a18c85c 6365 if ((*cb)(dst, buffer, (size_t)n) < 0)
ef416fc2 6366 {
e07d4801 6367 DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
dcb445bc 6368 _cupsBufferRelease((char *)buffer);
cb7f98ee 6369 return (IPP_STATE_ERROR);
ef416fc2 6370 }
6371
cb7f98ee 6372 ipp->state = IPP_STATE_DATA;
ef416fc2 6373 }
6374 break;
6375
cb7f98ee 6376 case IPP_STATE_DATA :
ef416fc2 6377 break;
6378
6379 default :
6380 break; /* anti-compiler-warning-code */
6381 }
6382
dcb445bc 6383 _cupsBufferRelease((char *)buffer);
1f6f3dbc 6384
ef416fc2 6385 return (ipp->state);
6386}
6387
6388
6389/*
a2326b5b 6390 * 'ipp_add_attr()' - Add a new attribute to the message.
ef416fc2 6391 */
6392
a2326b5b
MS
6393static ipp_attribute_t * /* O - New attribute */
6394ipp_add_attr(ipp_t *ipp, /* I - IPP message */
6395 const char *name, /* I - Attribute name or NULL */
6396 ipp_tag_t group_tag, /* I - Group tag or IPP_TAG_ZERO */
6397 ipp_tag_t value_tag, /* I - Value tag or IPP_TAG_ZERO */
6398 int num_values) /* I - Number of values */
ef416fc2 6399{
a2326b5b 6400 int alloc_values; /* Number of values to allocate */
ef416fc2 6401 ipp_attribute_t *attr; /* New attribute */
6402
6403
a2326b5b
MS
6404 DEBUG_printf(("4ipp_add_attr(ipp=%p, name=\"%s\", group_tag=0x%x, value_tag=0x%x, "
6405 "num_values=%d)", ipp, name, group_tag, value_tag, num_values));
6406
6407 /*
6408 * Range check input...
6409 */
ef416fc2 6410
1ff0402e 6411 if (!ipp || num_values < 0)
ef416fc2 6412 return (NULL);
6413
a2326b5b
MS
6414 /*
6415 * Allocate memory, rounding the allocation up as needed...
6416 */
ef416fc2 6417
a2326b5b 6418 if (num_values <= 1)
9c80ffa2 6419 alloc_values = 1;
a2326b5b
MS
6420 else
6421 alloc_values = (num_values + IPP_MAX_VALUES - 1) & ~(IPP_MAX_VALUES - 1);
ef416fc2 6422
a2326b5b 6423 attr = calloc(sizeof(ipp_attribute_t) +
1a18c85c 6424 (size_t)(alloc_values - 1) * sizeof(_ipp_value_t), 1);
ef416fc2 6425
a2326b5b 6426 if (attr)
ef416fc2 6427 {
a2326b5b
MS
6428 /*
6429 * Initialize attribute...
6430 */
ef416fc2 6431
a2326b5b
MS
6432 if (name)
6433 attr->name = _cupsStrAlloc(name);
ef416fc2 6434
a2326b5b
MS
6435 attr->group_tag = group_tag;
6436 attr->value_tag = value_tag;
6437 attr->num_values = num_values;
4400e98d 6438
a2326b5b
MS
6439 /*
6440 * Add it to the end of the linked list...
6441 */
4400e98d 6442
a2326b5b
MS
6443 if (ipp->last)
6444 ipp->last->next = attr;
6445 else
6446 ipp->attrs = attr;
5a738aea 6447
a2326b5b
MS
6448 ipp->prev = ipp->last;
6449 ipp->last = ipp->current = attr;
ef416fc2 6450 }
6451
a2326b5b 6452 DEBUG_printf(("5ipp_add_attr: Returning %p", attr));
ef416fc2 6453
a2326b5b 6454 return (attr);
ef416fc2 6455}
6456
6457
a2326b5b
MS
6458/*
6459 * 'ipp_free_values()' - Free attribute values.
6460 */
6461
6462static void
6463ipp_free_values(ipp_attribute_t *attr, /* I - Attribute to free values from */
6464 int element,/* I - First value to free */
6465 int count) /* I - Number of values to free */
6466{
6467 int i; /* Looping var */
6468 _ipp_value_t *value; /* Current value */
6469
6470
5a9febac
MS
6471 DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", attr,
6472 element, count));
a2326b5b 6473
cb7f98ee 6474 if (!(attr->value_tag & IPP_TAG_CUPS_CONST))
a2326b5b
MS
6475 {
6476 /*
6477 * Free values as needed...
6478 */
6479
6480 switch (attr->value_tag)
6481 {
6482 case IPP_TAG_TEXTLANG :
6483 case IPP_TAG_NAMELANG :
5a9febac
MS
6484 if (element == 0 && count == attr->num_values &&
6485 attr->values[0].string.language)
6486 {
a2326b5b 6487 _cupsStrFree(attr->values[0].string.language);
5a9febac
MS
6488 attr->values[0].string.language = NULL;
6489 }
0fa6c7fa 6490 /* Fall through to other string values */
a2326b5b
MS
6491
6492 case IPP_TAG_TEXT :
6493 case IPP_TAG_NAME :
6494 case IPP_TAG_RESERVED_STRING :
6495 case IPP_TAG_KEYWORD :
6496 case IPP_TAG_URI :
6497 case IPP_TAG_URISCHEME :
6498 case IPP_TAG_CHARSET :
6499 case IPP_TAG_LANGUAGE :
6500 case IPP_TAG_MIMETYPE :
6501 for (i = count, value = attr->values + element;
6502 i > 0;
6503 i --, value ++)
5a9febac 6504 {
a2326b5b 6505 _cupsStrFree(value->string.text);
5a9febac
MS
6506 value->string.text = NULL;
6507 }
a2326b5b
MS
6508 break;
6509
6510 case IPP_TAG_DEFAULT :
6511 case IPP_TAG_UNKNOWN :
6512 case IPP_TAG_NOVALUE :
6513 case IPP_TAG_NOTSETTABLE :
6514 case IPP_TAG_DELETEATTR :
6515 case IPP_TAG_ADMINDEFINE :
6516 case IPP_TAG_INTEGER :
6517 case IPP_TAG_ENUM :
6518 case IPP_TAG_BOOLEAN :
6519 case IPP_TAG_DATE :
6520 case IPP_TAG_RESOLUTION :
6521 case IPP_TAG_RANGE :
6522 break;
6523
6524 case IPP_TAG_BEGIN_COLLECTION :
6525 for (i = count, value = attr->values + element;
6526 i > 0;
6527 i --, value ++)
5a9febac 6528 {
a2326b5b 6529 ippDelete(value->collection);
5a9febac
MS
6530 value->collection = NULL;
6531 }
a2326b5b
MS
6532 break;
6533
6534 case IPP_TAG_STRING :
6535 default :
6536 for (i = count, value = attr->values + element;
6537 i > 0;
6538 i --, value ++)
5a9febac 6539 {
a2326b5b 6540 if (value->unknown.data)
5a9febac 6541 {
a2326b5b 6542 free(value->unknown.data);
5a9febac
MS
6543 value->unknown.data = NULL;
6544 }
6545 }
a2326b5b
MS
6546 break;
6547 }
6548 }
6549
6550 /*
6551 * If we are not freeing values from the end, move the remaining values up...
6552 */
6553
6554 if ((element + count) < attr->num_values)
6555 memmove(attr->values + element, attr->values + element + count,
1a18c85c 6556 (size_t)(attr->num_values - count - element) * sizeof(_ipp_value_t));
a2326b5b
MS
6557
6558 attr->num_values -= count;
6559}
6560
6561
6562/*
6563 * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
6564 *
6565 * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
6566 * to "ll-cc", "ll-region", and "charset-number", respectively.
6567 */
6568
6569static char * /* O - Language code string */
6570ipp_get_code(const char *value, /* I - Locale/charset string */
6571 char *buffer, /* I - String buffer */
6572 size_t bufsize) /* I - Size of string buffer */
6573{
6574 char *bufptr, /* Pointer into buffer */
6575 *bufend; /* End of buffer */
6576
6577
6578 /*
6579 * Convert values to lowercase and change _ to - as needed...
6580 */
6581
6582 for (bufptr = buffer, bufend = buffer + bufsize - 1;
6583 *value && bufptr < bufend;
6584 value ++)
6585 if (*value == '_')
6586 *bufptr++ = '-';
6587 else
1a18c85c 6588 *bufptr++ = (char)_cups_tolower(*value);
a2326b5b
MS
6589
6590 *bufptr = '\0';
6591
6592 /*
6593 * Return the converted string...
6594 */
6595
6596 return (buffer);
6597}
6598
6599
6600/*
6601 * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
6602 *
6603 * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
6604 * "ll-region", respectively. It also converts the "C" (POSIX) locale to "en".
6605 */
6606
6607static char * /* O - Language code string */
6608ipp_lang_code(const char *locale, /* I - Locale string */
6609 char *buffer, /* I - String buffer */
6610 size_t bufsize) /* I - Size of string buffer */
6611{
6612 /*
6613 * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
6614 */
6615
6616 if (!_cups_strcasecmp(locale, "c"))
6617 {
6618 strlcpy(buffer, "en", bufsize);
6619 return (buffer);
6620 }
6621 else
6622 return (ipp_get_code(locale, buffer, bufsize));
6623}
6624
6625
ef416fc2 6626/*
6627 * 'ipp_length()' - Compute the length of an IPP message or collection value.
6628 */
6629
6630static size_t /* O - Size of IPP message */
6631ipp_length(ipp_t *ipp, /* I - IPP message or collection */
6632 int collection) /* I - 1 if a collection, 0 otherwise */
6633{
6634 int i; /* Looping var */
a2326b5b 6635 size_t bytes; /* Number of bytes */
ef416fc2 6636 ipp_attribute_t *attr; /* Current attribute */
6637 ipp_tag_t group; /* Current group */
a2326b5b
MS
6638 _ipp_value_t *value; /* Current value */
6639
ef416fc2 6640
a2326b5b 6641 DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", ipp, collection));
ef416fc2 6642
a2326b5b
MS
6643 if (!ipp)
6644 {
6645 DEBUG_puts("4ipp_length: Returning 0 bytes");
ef416fc2 6646 return (0);
a2326b5b 6647 }
ef416fc2 6648
6649 /*
6650 * Start with 8 bytes for the IPP message header...
6651 */
6652
6653 bytes = collection ? 0 : 8;
6654
6655 /*
6656 * Then add the lengths of each attribute...
6657 */
6658
6659 group = IPP_TAG_ZERO;
6660
6661 for (attr = ipp->attrs; attr != NULL; attr = attr->next)
6662 {
6663 if (attr->group_tag != group && !collection)
6664 {
6665 group = attr->group_tag;
6666 if (group == IPP_TAG_ZERO)
6667 continue;
6668
6669 bytes ++; /* Group tag */
6670 }
6671
6672 if (!attr->name)
6673 continue;
6674
a2326b5b
MS
6675 DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
6676 "bytes=" CUPS_LLFMT, attr->name, attr->num_values, CUPS_LLCAST bytes));
ef416fc2 6677
a2326b5b 6678 if (attr->value_tag < IPP_TAG_EXTENSION)
1a18c85c 6679 bytes += (size_t)attr->num_values;/* Value tag for each value */
a2326b5b 6680 else
1a18c85c
MS
6681 bytes += (size_t)(5 * attr->num_values);
6682 /* Value tag for each value */
6683 bytes += (size_t)(2 * attr->num_values);
6684 /* Name lengths */
6685 bytes += strlen(attr->name); /* Name */
6686 bytes += (size_t)(2 * attr->num_values);
6687 /* Value lengths */
ef416fc2 6688
6689 if (collection)
6690 bytes += 5; /* Add membername overhead */
6691
cb7f98ee 6692 switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
ef416fc2 6693 {
a2326b5b
MS
6694 case IPP_TAG_UNSUPPORTED_VALUE :
6695 case IPP_TAG_DEFAULT :
6696 case IPP_TAG_UNKNOWN :
6697 case IPP_TAG_NOVALUE :
6698 case IPP_TAG_NOTSETTABLE :
6699 case IPP_TAG_DELETEATTR :
6700 case IPP_TAG_ADMINDEFINE :
6701 break;
6702
ef416fc2 6703 case IPP_TAG_INTEGER :
6704 case IPP_TAG_ENUM :
1a18c85c 6705 bytes += (size_t)(4 * attr->num_values);
ef416fc2 6706 break;
6707
6708 case IPP_TAG_BOOLEAN :
1a18c85c 6709 bytes += (size_t)attr->num_values;
ef416fc2 6710 break;
6711
6712 case IPP_TAG_TEXT :
6713 case IPP_TAG_NAME :
6714 case IPP_TAG_KEYWORD :
ef416fc2 6715 case IPP_TAG_URI :
6716 case IPP_TAG_URISCHEME :
6717 case IPP_TAG_CHARSET :
6718 case IPP_TAG_LANGUAGE :
6719 case IPP_TAG_MIMETYPE :
6720 for (i = 0, value = attr->values;
6721 i < attr->num_values;
6722 i ++, value ++)
a2326b5b
MS
6723 if (value->string.text)
6724 bytes += strlen(value->string.text);
ef416fc2 6725 break;
6726
6727 case IPP_TAG_DATE :
1a18c85c 6728 bytes += (size_t)(11 * attr->num_values);
ef416fc2 6729 break;
6730
6731 case IPP_TAG_RESOLUTION :
1a18c85c 6732 bytes += (size_t)(9 * attr->num_values);
ef416fc2 6733 break;
6734
6735 case IPP_TAG_RANGE :
1a18c85c 6736 bytes += (size_t)(8 * attr->num_values);
ef416fc2 6737 break;
6738
6739 case IPP_TAG_TEXTLANG :
6740 case IPP_TAG_NAMELANG :
1a18c85c
MS
6741 bytes += (size_t)(4 * attr->num_values);
6742 /* Charset + text length */
ef416fc2 6743
6744 for (i = 0, value = attr->values;
6745 i < attr->num_values;
6746 i ++, value ++)
6747 {
a2326b5b
MS
6748 if (value->string.language)
6749 bytes += strlen(value->string.language);
ef416fc2 6750
a2326b5b
MS
6751 if (value->string.text)
6752 bytes += strlen(value->string.text);
ef416fc2 6753 }
6754 break;
6755
6756 case IPP_TAG_BEGIN_COLLECTION :
6757 for (i = 0, value = attr->values;
6758 i < attr->num_values;
6759 i ++, value ++)
a2326b5b 6760 bytes += ipp_length(value->collection, 1);
ef416fc2 6761 break;
6762
6763 default :
6764 for (i = 0, value = attr->values;
6765 i < attr->num_values;
6766 i ++, value ++)
1a18c85c 6767 bytes += (size_t)value->unknown.length;
ef416fc2 6768 break;
6769 }
6770 }
6771
6772 /*
6773 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
6774 * for the "end of collection" tag and return...
6775 */
6776
6777 if (collection)
6778 bytes += 5;
6779 else
6780 bytes ++;
6781
a2326b5b 6782 DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST bytes));
ef416fc2 6783
6784 return (bytes);
6785}
6786
6787
6788/*
6789 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
6790 */
6791
a4d04587 6792static ssize_t /* O - Number of bytes read */
ef416fc2 6793ipp_read_http(http_t *http, /* I - Client connection */
6794 ipp_uchar_t *buffer, /* O - Buffer for data */
a4d04587 6795 size_t length) /* I - Total length */
ef416fc2 6796{
1a18c85c
MS
6797 ssize_t tbytes, /* Total bytes read */
6798 bytes; /* Bytes read this pass */
aaf19ab0 6799
ef416fc2 6800
e07d4801 6801 DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)",
568fa3fa 6802 http, buffer, (int)length));
ef416fc2 6803
6804 /*
6805 * Loop until all bytes are read...
6806 */
6807
ae71f5de
MS
6808 for (tbytes = 0, bytes = 0;
6809 tbytes < (int)length;
6810 tbytes += bytes, buffer += bytes)
ef416fc2 6811 {
1a18c85c 6812 DEBUG_printf(("9ipp_read_http: tbytes=" CUPS_LLFMT ", http->state=%d", CUPS_LLCAST tbytes, http->state));
ef416fc2 6813
cb7f98ee 6814 if (http->state == HTTP_STATE_WAITING)
ef416fc2 6815 break;
6816
a29fd7dd 6817 if (http->used == 0 && !http->blocking)
ef416fc2 6818 {
6819 /*
a29fd7dd 6820 * Wait up to 10 seconds for more data on non-blocking sockets...
ef416fc2 6821 */
6822
a29fd7dd 6823 if (!httpWait(http, 10000))
ef416fc2 6824 {
6825 /*
a29fd7dd 6826 * Signal no data...
ef416fc2 6827 */
6828
a29fd7dd
MS
6829 bytes = -1;
6830 break;
ef416fc2 6831 }
a29fd7dd 6832 }
ef416fc2 6833
1a18c85c 6834 if ((bytes = httpRead2(http, (char *)buffer, length - (size_t)tbytes)) < 0)
a29fd7dd 6835 {
d1c13e16 6836#ifdef WIN32
a29fd7dd 6837 break;
d1c13e16 6838#else
a29fd7dd
MS
6839 if (errno != EAGAIN && errno != EINTR)
6840 break;
d1c13e16 6841
a29fd7dd 6842 bytes = 0;
d1c13e16 6843#endif /* WIN32 */
ef416fc2 6844 }
a29fd7dd
MS
6845 else if (bytes == 0)
6846 break;
ef416fc2 6847 }
6848
6849 /*
6850 * Return the number of bytes read...
6851 */
6852
6853 if (tbytes == 0 && bytes < 0)
6854 tbytes = -1;
6855
1a18c85c 6856 DEBUG_printf(("8ipp_read_http: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST tbytes));
ef416fc2 6857
6858 return (tbytes);
6859}
6860
6861
6862/*
6863 * 'ipp_read_file()' - Read IPP data from a file.
6864 */
6865
a4d04587 6866static ssize_t /* O - Number of bytes read */
ef416fc2 6867ipp_read_file(int *fd, /* I - File descriptor */
6868 ipp_uchar_t *buffer, /* O - Read buffer */
a4d04587 6869 size_t length) /* I - Number of bytes to read */
ef416fc2 6870{
b86bc4cf 6871#ifdef WIN32
6872 return ((ssize_t)read(*fd, buffer, (unsigned)length));
6873#else
ef416fc2 6874 return (read(*fd, buffer, length));
b86bc4cf 6875#endif /* WIN32 */
ef416fc2 6876}
6877
6878
c1420c87
MS
6879/*
6880 * 'ipp_set_error()' - Set a formatted, localized error string.
6881 */
6882
6883static void
6884ipp_set_error(ipp_status_t status, /* I - Status code */
6885 const char *format, /* I - Printf-style error string */
6886 ...) /* I - Additional arguments as needed */
6887{
6888 va_list ap; /* Pointer to additional args */
6889 char buffer[2048]; /* Message buffer */
6890 cups_lang_t *lang = cupsLangDefault();
6891 /* Current language */
6892
6893
6894 va_start(ap, format);
6895 vsnprintf(buffer, sizeof(buffer), _cupsLangString(lang, format), ap);
6896 va_end(ap);
6897
6898 _cupsSetError(status, buffer, 0);
6899}
6900
6901
a2326b5b 6902/*
9c80ffa2
MS
6903 * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
6904 * needed.
a2326b5b
MS
6905 */
6906
6907static _ipp_value_t * /* O - IPP value element or NULL on error */
9c80ffa2 6908ipp_set_value(ipp_t *ipp, /* IO - IPP message */
a2326b5b
MS
6909 ipp_attribute_t **attr, /* IO - IPP attribute */
6910 int element) /* I - Value number (0-based) */
6911{
6912 ipp_attribute_t *temp, /* New attribute pointer */
6913 *current, /* Current attribute in list */
6914 *prev; /* Previous attribute in list */
6915 int alloc_values; /* Allocated values */
6916
6917
6918 /*
6919 * If we are setting an existing value element, return it...
6920 */
6921
6922 temp = *attr;
6923
6924 if (temp->num_values <= 1)
9c80ffa2 6925 alloc_values = 1;
a2326b5b 6926 else
9c80ffa2
MS
6927 alloc_values = (temp->num_values + IPP_MAX_VALUES - 1) &
6928 ~(IPP_MAX_VALUES - 1);
a2326b5b
MS
6929
6930 if (element < alloc_values)
9c80ffa2
MS
6931 {
6932 if (element >= temp->num_values)
6933 temp->num_values = element + 1;
6934
a2326b5b 6935 return (temp->values + element);
9c80ffa2 6936 }
a2326b5b
MS
6937
6938 /*
9c80ffa2
MS
6939 * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
6940 * values when num_values > 1.
a2326b5b
MS
6941 */
6942
6943 if (alloc_values < IPP_MAX_VALUES)
6944 alloc_values = IPP_MAX_VALUES;
6945 else
6946 alloc_values += IPP_MAX_VALUES;
6947
9c80ffa2
MS
6948 DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
6949 alloc_values));
a2326b5b
MS
6950
6951 /*
6952 * Reallocate memory...
6953 */
6954
1a18c85c 6955 if ((temp = realloc(temp, sizeof(ipp_attribute_t) + (size_t)(alloc_values - 1) * sizeof(_ipp_value_t))) == NULL)
a2326b5b 6956 {
cb7f98ee 6957 _cupsSetHTTPError(HTTP_STATUS_ERROR);
a2326b5b
MS
6958 DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
6959 return (NULL);
6960 }
6961
6962 /*
6963 * Zero the new memory...
6964 */
6965
1a18c85c 6966 memset(temp->values + temp->num_values, 0, (size_t)(alloc_values - temp->num_values) * sizeof(_ipp_value_t));
a2326b5b
MS
6967
6968 if (temp != *attr)
6969 {
6970 /*
6971 * Reset pointers in the list...
6972 */
6973
6974 if (ipp->current == *attr && ipp->prev)
6975 {
6976 /*
6977 * Use current "previous" pointer...
6978 */
6979
6980 prev = ipp->prev;
6981 }
6982 else
6983 {
6984 /*
6985 * Find this attribute in the linked list...
6986 */
6987
6988 for (prev = NULL, current = ipp->attrs;
6989 current && current != *attr;
6990 prev = current, current = current->next);
6991
6992 if (!current)
6993 {
6994 /*
6995 * This is a serious error!
6996 */
6997
6998 *attr = temp;
cb7f98ee 6999 _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
9c80ffa2 7000 _("IPP attribute is not a member of the message."), 1);
a2326b5b
MS
7001 DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
7002 return (NULL);
7003 }
7004 }
7005
7006 if (prev)
7007 prev->next = temp;
7008 else
7009 ipp->attrs = temp;
7010
7011 ipp->current = temp;
7012 ipp->prev = prev;
7013
7014 if (ipp->last == *attr)
7015 ipp->last = temp;
7016
7017 *attr = temp;
7018 }
7019
7020 /*
7021 * Return the value element...
7022 */
7023
9c80ffa2
MS
7024 if (element >= temp->num_values)
7025 temp->num_values = element + 1;
7026
a2326b5b
MS
7027 return (temp->values + element);
7028}
7029
7030
ef416fc2 7031/*
7032 * 'ipp_write_file()' - Write IPP data to a file.
7033 */
7034
a4d04587 7035static ssize_t /* O - Number of bytes written */
ef416fc2 7036ipp_write_file(int *fd, /* I - File descriptor */
7037 ipp_uchar_t *buffer, /* I - Data to write */
a4d04587 7038 size_t length) /* I - Number of bytes to write */
ef416fc2 7039{
b86bc4cf 7040#ifdef WIN32
7041 return ((ssize_t)write(*fd, buffer, (unsigned)length));
7042#else
ef416fc2 7043 return (write(*fd, buffer, length));
b86bc4cf 7044#endif /* WIN32 */
ef416fc2 7045}
7046
7047
80ca4592 7048/*
5d2cc5d3 7049 * End of "$Id: ipp.c 12093 2014-08-19 12:10:17Z msweet $".
ef416fc2 7050 */