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