]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/ipp.c
Merge changes from CUPS 1.6svn-r10437.
[thirdparty/cups.git] / cups / ipp.c
1 /*
2 * "$Id: ipp.c 10102 2011-11-02 23:52:39Z mike $"
3 *
4 * Internet Printing Protocol functions for CUPS.
5 *
6 * Copyright 2007-2012 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 * Contents:
18 *
19 * _cupsBufferGet() - Get a read/write buffer.
20 * _cupsBufferRelease() - Release a read/write buffer.
21 * ippAddBoolean() - Add a boolean attribute to an IPP message.
22 * ippAddBooleans() - Add an array of boolean values.
23 * ippAddCollection() - Add a collection value.
24 * ippAddCollections() - Add an array of collection values.
25 * ippAddDate() - Add a date attribute to an IPP message.
26 * ippAddInteger() - Add a integer attribute to an IPP message.
27 * ippAddIntegers() - Add an array of integer values.
28 * ippAddOctetString() - Add an octetString value to an IPP message.
29 * ippAddOutOfBand() - Add an out-of-band value to an IPP message.
30 * ippAddRange() - Add a range of values to an IPP message.
31 * ippAddRanges() - Add ranges of values to an IPP message.
32 * ippAddResolution() - Add a resolution value to an IPP message.
33 * ippAddResolutions() - Add resolution values to an IPP message.
34 * ippAddSeparator() - Add a group separator to an IPP message.
35 * ippAddString() - Add a language-encoded string to an IPP message.
36 * ippAddStrings() - Add language-encoded strings to an IPP message.
37 * ippCopyAttribute() - Copy an attribute.
38 * ippCopyAttributes() - Copy attributes from one IPP message to another.
39 * ippDateToTime() - Convert from RFC 1903 Date/Time format to UNIX
40 * time in seconds.
41 * ippDelete() - Delete an IPP message.
42 * ippDeleteAttribute() - Delete a single attribute in an IPP message.
43 * ippDeleteValues() - Delete values in an attribute.
44 * ippFindAttribute() - Find a named attribute in a request.
45 * ippFindNextAttribute() - Find the next named attribute in a request.
46 * ippFirstAttribute() - Return the first attribute in the message.
47 * ippGetBoolean() - Get a boolean value for an attribute.
48 * ippGetCollection() - Get a collection value for an attribute.
49 * ippGetCount() - Get the number of values in an attribute.
50 * ippGetDate() - Get a date value for an attribute.
51 * ippGetGroupTag() - Get the group associated with an attribute.
52 * ippGetInteger() - Get the integer/enum value for an attribute.
53 * ippGetName() - Get the attribute name.
54 * ippGetOperation() - Get the operation ID in an IPP message.
55 * ippGetRange() - Get a rangeOfInteger value from an attribute.
56 * ippGetRequestId() - Get the request ID from an IPP message.
57 * ippGetResolution() - Get a resolution value for an attribute.
58 * ippGetStatusCode() - Get the status code from an IPP response or event
59 * message.
60 * ippGetString() - Get the string and optionally the language code
61 * for an attribute.
62 * ippGetValueTag() - Get the value tag for an attribute.
63 * ippGetVersion() - Get the major and minor version number from an
64 * IPP message.
65 * ippLength() - Compute the length of an IPP message.
66 * ippNextAttribute() - Return the next attribute in the message.
67 * ippNew() - Allocate a new IPP message.
68 * ippNewRequest() - Allocate a new IPP request message.
69 * ippRead() - Read data for an IPP message from a HTTP
70 * connection.
71 * ippReadFile() - Read data for an IPP message from a file.
72 * ippReadIO() - Read data for an IPP message.
73 * ippSetBoolean() - Set a boolean value in an attribute.
74 * ippSetCollection() - Set a collection value in an attribute.
75 * ippSetDate() - Set a date value in an attribute.
76 * ippSetGroupTag() - Set the group tag of an attribute.
77 * ippSetInteger() - Set an integer or enum value in an attribute.
78 * ippSetName() - Set the name of an attribute.
79 * ippSetOperation() - Set the operation ID in an IPP request message.
80 * ippSetRange() - Set a rangeOfInteger value in an attribute.
81 * ippSetRequestId() - Set the request ID in an IPP message.
82 * ippSetResolution() - Set a resolution value in an attribute.
83 * ippSetState() - Set the current state of the IPP message.
84 * ippSetStatusCode() - Set the status code in an IPP response or event
85 * message.
86 * ippSetString() - Set a string value in an attribute.
87 * ippSetValueTag() - Set the value tag of an attribute.
88 * ippSetVersion() - Set the version number in an IPP message.
89 * ippTimeToDate() - Convert from UNIX time to RFC 1903 format.
90 * ippWrite() - Write data for an IPP message to a HTTP
91 * connection.
92 * ippWriteFile() - Write data for an IPP message to a file.
93 * ippWriteIO() - Write data for an IPP message.
94 * ipp_add_attr() - Add a new attribute to the message.
95 * ipp_free_values() - Free attribute values.
96 * ipp_get_code() - Convert a C locale/charset name into an IPP
97 * language/charset code.
98 * ipp_lang_code() - Convert a C locale name into an IPP language
99 * code.
100 * ipp_length() - Compute the length of an IPP message or
101 * collection value.
102 * ipp_read_http() - Semi-blocking read on a HTTP connection...
103 * ipp_read_file() - Read IPP data from a file.
104 * ipp_set_value() - Get the value element from an attribute,
105 * expanding it as needed.
106 * ipp_write_file() - Write IPP data to a file.
107 */
108
109 /*
110 * Include necessary headers...
111 */
112
113 #include "cups-private.h"
114 #ifdef WIN32
115 # include <io.h>
116 #endif /* WIN32 */
117
118
119 /*
120 * Local functions...
121 */
122
123 static ipp_attribute_t *ipp_add_attr(ipp_t *ipp, const char *name,
124 ipp_tag_t group_tag, ipp_tag_t value_tag,
125 int num_values);
126 static void ipp_free_values(ipp_attribute_t *attr, int element,
127 int count);
128 static char *ipp_get_code(const char *locale, char *buffer,
129 size_t bufsize)
130 __attribute__((nonnull(1,2)));
131 static char *ipp_lang_code(const char *locale, char *buffer,
132 size_t bufsize)
133 __attribute__((nonnull(1,2)));
134 static size_t ipp_length(ipp_t *ipp, int collection);
135 static ssize_t ipp_read_http(http_t *http, ipp_uchar_t *buffer,
136 size_t length);
137 static ssize_t ipp_read_file(int *fd, ipp_uchar_t *buffer,
138 size_t length);
139 static _ipp_value_t *ipp_set_value(ipp_t *ipp, ipp_attribute_t **attr,
140 int element);
141 static ssize_t ipp_write_file(int *fd, ipp_uchar_t *buffer,
142 size_t length);
143
144
145 /*
146 * '_cupsBufferGet()' - Get a read/write buffer.
147 */
148
149 char * /* O - Buffer */
150 _cupsBufferGet(size_t size) /* I - Size required */
151 {
152 _cups_buffer_t *buffer; /* Current buffer */
153 _cups_globals_t *cg = _cupsGlobals();
154 /* Global data */
155
156
157 for (buffer = cg->cups_buffers; buffer; buffer = buffer->next)
158 if (!buffer->used && buffer->size >= size)
159 break;
160
161 if (!buffer)
162 {
163 if ((buffer = malloc(sizeof(_cups_buffer_t) + size - 1)) == NULL)
164 return (NULL);
165
166 buffer->next = cg->cups_buffers;
167 buffer->size = size;
168 cg->cups_buffers = buffer;
169 }
170
171 buffer->used = 1;
172
173 return (buffer->d);
174 }
175
176
177 /*
178 * '_cupsBufferRelease()' - Release a read/write buffer.
179 */
180
181 void
182 _cupsBufferRelease(char *b) /* I - Buffer to release */
183 {
184 _cups_buffer_t *buffer; /* Buffer */
185
186
187 /*
188 * Mark this buffer as unused...
189 */
190
191 buffer = (_cups_buffer_t *)(b - offsetof(_cups_buffer_t, d));
192 buffer->used = 0;
193 }
194
195
196 /*
197 * 'ippAddBoolean()' - Add a boolean attribute to an IPP message.
198 *
199 * The @code ipp@ parameter refers to an IPP message previously created using the
200 * @link ippNew@ or @link ippNewRequest@ functions.
201 *
202 * The @code group@ parameter specifies the IPP attribute group tag: none
203 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
204 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
205 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
206 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
207 */
208
209 ipp_attribute_t * /* O - New attribute */
210 ippAddBoolean(ipp_t *ipp, /* I - IPP message */
211 ipp_tag_t group, /* I - IPP group */
212 const char *name, /* I - Name of attribute */
213 char value) /* I - Value of attribute */
214 {
215 ipp_attribute_t *attr; /* New attribute */
216
217
218 DEBUG_printf(("ippAddBoolean(ipp=%p, group=%02x(%s), name=\"%s\", value=%d)",
219 ipp, group, ippTagString(group), name, value));
220
221 /*
222 * Range check input...
223 */
224
225 if (!ipp || !name || group < IPP_TAG_ZERO ||
226 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
227 return (NULL);
228
229 /*
230 * Create the attribute...
231 */
232
233 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BOOLEAN, 1)) == NULL)
234 return (NULL);
235
236 attr->values[0].boolean = value;
237
238 return (attr);
239 }
240
241
242 /*
243 * 'ippAddBooleans()' - Add an array of boolean values.
244 *
245 * The @code ipp@ parameter refers to an IPP message previously created using the
246 * @link ippNew@ or @link ippNewRequest@ functions.
247 *
248 * The @code group@ parameter specifies the IPP attribute group tag: none
249 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
250 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
251 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
252 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
253 */
254
255 ipp_attribute_t * /* O - New attribute */
256 ippAddBooleans(ipp_t *ipp, /* I - IPP message */
257 ipp_tag_t group, /* I - IPP group */
258 const char *name, /* I - Name of attribute */
259 int num_values, /* I - Number of values */
260 const char *values) /* I - Values */
261 {
262 int i; /* Looping var */
263 ipp_attribute_t *attr; /* New attribute */
264 _ipp_value_t *value; /* Current value */
265
266
267 DEBUG_printf(("ippAddBooleans(ipp=%p, group=%02x(%s), name=\"%s\", "
268 "num_values=%d, values=%p)", ipp, group, ippTagString(group),
269 name, num_values, values));
270
271 /*
272 * Range check input...
273 */
274
275 if (!ipp || !name || group < IPP_TAG_ZERO ||
276 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
277 num_values < 1)
278 return (NULL);
279
280 /*
281 * Create the attribute...
282 */
283
284 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BOOLEAN, num_values)) == NULL)
285 return (NULL);
286
287 if (values)
288 {
289 for (i = num_values, value = attr->values;
290 i > 0;
291 i --, value ++)
292 value->boolean = *values++;
293 }
294
295 return (attr);
296 }
297
298
299 /*
300 * 'ippAddCollection()' - Add a collection value.
301 *
302 * The @code ipp@ parameter refers to an IPP message previously created using the
303 * @link ippNew@ or @link ippNewRequest@ functions.
304 *
305 * The @code group@ parameter specifies the IPP attribute group tag: none
306 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
307 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
308 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
309 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
310 *
311 * @since CUPS 1.1.19/OS X 10.3@
312 */
313
314 ipp_attribute_t * /* O - New attribute */
315 ippAddCollection(ipp_t *ipp, /* I - IPP message */
316 ipp_tag_t group, /* I - IPP group */
317 const char *name, /* I - Name of attribute */
318 ipp_t *value) /* I - Value */
319 {
320 ipp_attribute_t *attr; /* New attribute */
321
322
323 DEBUG_printf(("ippAddCollection(ipp=%p, group=%02x(%s), name=\"%s\", "
324 "value=%p)", ipp, group, ippTagString(group), name, value));
325
326 /*
327 * Range check input...
328 */
329
330 if (!ipp || !name || group < IPP_TAG_ZERO ||
331 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
332 return (NULL);
333
334 /*
335 * Create the attribute...
336 */
337
338 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BEGIN_COLLECTION, 1)) == NULL)
339 return (NULL);
340
341 attr->values[0].collection = value;
342
343 if (value)
344 value->use ++;
345
346 return (attr);
347 }
348
349
350 /*
351 * 'ippAddCollections()' - Add an array of collection values.
352 *
353 * The @code ipp@ parameter refers to an IPP message previously created using the
354 * @link ippNew@ or @link ippNewRequest@ functions.
355 *
356 * The @code group@ parameter specifies the IPP attribute group tag: none
357 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
358 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
359 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
360 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
361 *
362 * @since CUPS 1.1.19/OS X 10.3@
363 */
364
365 ipp_attribute_t * /* O - New attribute */
366 ippAddCollections(
367 ipp_t *ipp, /* I - IPP message */
368 ipp_tag_t group, /* I - IPP group */
369 const char *name, /* I - Name of attribute */
370 int num_values, /* I - Number of values */
371 const ipp_t **values) /* I - Values */
372 {
373 int i; /* Looping var */
374 ipp_attribute_t *attr; /* New attribute */
375 _ipp_value_t *value; /* Current value */
376
377
378 DEBUG_printf(("ippAddCollections(ipp=%p, group=%02x(%s), name=\"%s\", "
379 "num_values=%d, values=%p)", ipp, group, ippTagString(group),
380 name, num_values, values));
381
382 /*
383 * Range check input...
384 */
385
386 if (!ipp || !name || group < IPP_TAG_ZERO ||
387 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
388 num_values < 1)
389 return (NULL);
390
391 /*
392 * Create the attribute...
393 */
394
395 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_BEGIN_COLLECTION,
396 num_values)) == NULL)
397 return (NULL);
398
399 if (values)
400 {
401 for (i = num_values, value = attr->values;
402 i > 0;
403 i --, value ++)
404 {
405 value->collection = (ipp_t *)*values++;
406 value->collection->use ++;
407 }
408 }
409
410 return (attr);
411 }
412
413
414 /*
415 * 'ippAddDate()' - Add a date attribute to an IPP message.
416 *
417 * The @code ipp@ parameter refers to an IPP message previously created using the
418 * @link ippNew@ or @link ippNewRequest@ functions.
419 *
420 * The @code group@ parameter specifies the IPP attribute group tag: none
421 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
422 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
423 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
424 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
425 */
426
427 ipp_attribute_t * /* O - New attribute */
428 ippAddDate(ipp_t *ipp, /* I - IPP message */
429 ipp_tag_t group, /* I - IPP group */
430 const char *name, /* I - Name of attribute */
431 const ipp_uchar_t *value) /* I - Value */
432 {
433 ipp_attribute_t *attr; /* New attribute */
434
435
436 DEBUG_printf(("ippAddDate(ipp=%p, group=%02x(%s), name=\"%s\", value=%p)",
437 ipp, group, ippTagString(group), name, value));
438
439 /*
440 * Range check input...
441 */
442
443 if (!ipp || !name || !value || group < IPP_TAG_ZERO ||
444 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
445 return (NULL);
446
447 /*
448 * Create the attribute...
449 */
450
451 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_DATE, 1)) == NULL)
452 return (NULL);
453
454 memcpy(attr->values[0].date, value, 11);
455
456 return (attr);
457 }
458
459
460 /*
461 * 'ippAddInteger()' - Add a integer attribute to an IPP message.
462 *
463 * The @code ipp@ parameter refers to an IPP message previously created using the
464 * @link ippNew@ or @link ippNewRequest@ functions.
465 *
466 * The @code group@ parameter specifies the IPP attribute group tag: none
467 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
468 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
469 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
470 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
471 *
472 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
473 * (@code IPP_TAG_INTEGER@).
474 */
475
476 ipp_attribute_t * /* O - New attribute */
477 ippAddInteger(ipp_t *ipp, /* I - IPP message */
478 ipp_tag_t group, /* I - IPP group */
479 ipp_tag_t value_tag, /* I - Type of attribute */
480 const char *name, /* I - Name of attribute */
481 int value) /* I - Value of attribute */
482 {
483 ipp_attribute_t *attr; /* New attribute */
484
485
486 DEBUG_printf(("ippAddInteger(ipp=%p, group=%02x(%s), type=%02x(%s), "
487 "name=\"%s\", value=%d)", ipp, group, ippTagString(group),
488 value_tag, ippTagString(value_tag), name, value));
489
490 value_tag &= IPP_TAG_MASK;
491
492 /*
493 * Special-case for legacy usage: map out-of-band attributes to new ippAddOutOfBand
494 * function...
495 */
496
497 if (value_tag >= IPP_TAG_UNSUPPORTED_VALUE && value_tag <= IPP_TAG_ADMINDEFINE)
498 return (ippAddOutOfBand(ipp, group, value_tag, name));
499
500 /*
501 * Range check input...
502 */
503
504 #if 0
505 if (!ipp || !name || group < IPP_TAG_ZERO ||
506 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
507 (value_tag != IPP_TAG_INTEGER && value_tag != IPP_TAG_ENUM))
508 return (NULL);
509 #else
510 if (!ipp || !name || group < IPP_TAG_ZERO ||
511 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
512 return (NULL);
513 #endif /* 0 */
514
515 /*
516 * Create the attribute...
517 */
518
519 if ((attr = ipp_add_attr(ipp, name, group, value_tag, 1)) == NULL)
520 return (NULL);
521
522 attr->values[0].integer = value;
523
524 return (attr);
525 }
526
527
528 /*
529 * 'ippAddIntegers()' - Add an array of integer values.
530 *
531 * The @code ipp@ parameter refers to an IPP message previously created using the
532 * @link ippNew@ or @link ippNewRequest@ functions.
533 *
534 * The @code group@ parameter specifies the IPP attribute group tag: none
535 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
536 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
537 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
538 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
539 *
540 * Supported values include enum (@code IPP_TAG_ENUM@) and integer
541 * (@code IPP_TAG_INTEGER@).
542 */
543
544 ipp_attribute_t * /* O - New attribute */
545 ippAddIntegers(ipp_t *ipp, /* I - IPP message */
546 ipp_tag_t group, /* I - IPP group */
547 ipp_tag_t value_tag, /* I - Type of attribute */
548 const char *name, /* I - Name of attribute */
549 int num_values, /* I - Number of values */
550 const int *values) /* I - Values */
551 {
552 int i; /* Looping var */
553 ipp_attribute_t *attr; /* New attribute */
554 _ipp_value_t *value; /* Current value */
555
556
557 DEBUG_printf(("ippAddIntegers(ipp=%p, group=%02x(%s), type=%02x(%s), "
558 "name=\"%s\", num_values=%d, values=%p)", ipp,
559 group, ippTagString(group), value_tag, ippTagString(value_tag), name,
560 num_values, values));
561
562 value_tag &= IPP_TAG_MASK;
563
564 /*
565 * Range check input...
566 */
567
568 #if 0
569 if (!ipp || !name || group < IPP_TAG_ZERO ||
570 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
571 (value_tag != IPP_TAG_INTEGER && value_tag != IPP_TAG_ENUM) ||
572 num_values < 1)
573 return (NULL);
574 #else
575 if (!ipp || !name || group < IPP_TAG_ZERO ||
576 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
577 num_values < 1)
578 return (NULL);
579 #endif /* 0 */
580
581 /*
582 * Create the attribute...
583 */
584
585 if ((attr = ipp_add_attr(ipp, name, group, value_tag, num_values)) == NULL)
586 return (NULL);
587
588 if (values)
589 {
590 for (i = num_values, value = attr->values;
591 i > 0;
592 i --, value ++)
593 value->integer = *values++;
594 }
595
596 return (attr);
597 }
598
599
600 /*
601 * 'ippAddOctetString()' - Add an octetString value to an IPP message.
602 *
603 * The @code ipp@ parameter refers to an IPP message previously created using the
604 * @link ippNew@ or @link ippNewRequest@ functions.
605 *
606 * The @code group@ parameter specifies the IPP attribute group tag: none
607 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
608 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
609 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
610 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
611 *
612 * @since CUPS 1.2/OS X 10.5@
613 */
614
615 ipp_attribute_t * /* O - New attribute */
616 ippAddOctetString(ipp_t *ipp, /* I - IPP message */
617 ipp_tag_t group, /* I - IPP group */
618 const char *name, /* I - Name of attribute */
619 const void *data, /* I - octetString data */
620 int datalen) /* I - Length of data in bytes */
621 {
622 ipp_attribute_t *attr; /* New attribute */
623
624
625 if (!ipp || !name || group < IPP_TAG_ZERO ||
626 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
627 return (NULL);
628
629 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_STRING, 1)) == NULL)
630 return (NULL);
631
632 /*
633 * Initialize the attribute data...
634 */
635
636 attr->values[0].unknown.length = datalen;
637
638 if (data)
639 {
640 if ((attr->values[0].unknown.data = malloc(datalen)) == NULL)
641 {
642 ippDeleteAttribute(ipp, attr);
643 return (NULL);
644 }
645
646 memcpy(attr->values[0].unknown.data, data, datalen);
647 }
648
649 /*
650 * Return the new attribute...
651 */
652
653 return (attr);
654 }
655
656
657 /*
658 * 'ippAddOutOfBand()' - Add an out-of-band value to an IPP message.
659 *
660 * The @code ipp@ parameter refers to an IPP message previously created using the
661 * @link ippNew@ or @link ippNewRequest@ functions.
662 *
663 * The @code group@ parameter specifies the IPP attribute group tag: none
664 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
665 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
666 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
667 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
668 *
669 * Supported out-of-band values include unsupported-value
670 * (@code IPP_TAG_UNSUPPORTED_VALUE@), default (@code IPP_TAG_DEFAULT@), unknown
671 * (@code IPP_TAG_UNKNOWN@), no-value (@code IPP_TAG_NOVALUE@), not-settable
672 * (@code IPP_TAG_NOTSETTABLE@), delete-attribute (@code IPP_TAG_DELETEATTR@), and
673 * admin-define (@code IPP_TAG_ADMINDEFINE@).
674 *
675 * @since CUPS 1.6/OS X 10.8@
676 */
677
678 ipp_attribute_t * /* O - New attribute */
679 ippAddOutOfBand(ipp_t *ipp, /* I - IPP message */
680 ipp_tag_t group, /* I - IPP group */
681 ipp_tag_t value_tag, /* I - Type of attribute */
682 const char *name) /* I - Name of attribute */
683 {
684 DEBUG_printf(("ippAddOutOfBand(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
685 "name=\"%s\")", ipp, group, ippTagString(group), value_tag,
686 ippTagString(value_tag), name));
687
688 value_tag &= IPP_TAG_MASK;
689
690 /*
691 * Range check input...
692 */
693
694 if (!ipp || !name || group < IPP_TAG_ZERO ||
695 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
696 (value_tag != IPP_TAG_UNSUPPORTED_VALUE &&
697 value_tag != IPP_TAG_DEFAULT &&
698 value_tag != IPP_TAG_UNKNOWN &&
699 value_tag != IPP_TAG_NOVALUE &&
700 value_tag != IPP_TAG_NOTSETTABLE &&
701 value_tag != IPP_TAG_DELETEATTR &&
702 value_tag != IPP_TAG_ADMINDEFINE))
703 return (NULL);
704
705 /*
706 * Create the attribute...
707 */
708
709 return (ipp_add_attr(ipp, name, group, value_tag, 1));
710 }
711
712
713 /*
714 * 'ippAddRange()' - Add a range of values to an IPP message.
715 *
716 * The @code ipp@ parameter refers to an IPP message previously created using the
717 * @link ippNew@ or @link ippNewRequest@ functions.
718 *
719 * The @code group@ parameter specifies the IPP attribute group tag: none
720 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
721 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
722 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
723 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
724 *
725 * The @code lower@ parameter must be less than or equal to the @code upper@ parameter.
726 */
727
728 ipp_attribute_t * /* O - New attribute */
729 ippAddRange(ipp_t *ipp, /* I - IPP message */
730 ipp_tag_t group, /* I - IPP group */
731 const char *name, /* I - Name of attribute */
732 int lower, /* I - Lower value */
733 int upper) /* I - Upper value */
734 {
735 ipp_attribute_t *attr; /* New attribute */
736
737
738 DEBUG_printf(("ippAddRange(ipp=%p, group=%02x(%s), name=\"%s\", lower=%d, "
739 "upper=%d)", ipp, group, ippTagString(group), name, lower,
740 upper));
741
742 /*
743 * Range check input...
744 */
745
746 if (!ipp || !name || group < IPP_TAG_ZERO ||
747 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
748 return (NULL);
749
750 /*
751 * Create the attribute...
752 */
753
754 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RANGE, 1)) == NULL)
755 return (NULL);
756
757 attr->values[0].range.lower = lower;
758 attr->values[0].range.upper = upper;
759
760 return (attr);
761 }
762
763
764 /*
765 * 'ippAddRanges()' - Add ranges of values to an IPP message.
766 *
767 * The @code ipp@ parameter refers to an IPP message previously created using the
768 * @link ippNew@ or @link ippNewRequest@ functions.
769 *
770 * The @code group@ parameter specifies the IPP attribute group tag: none
771 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
772 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
773 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
774 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
775 */
776
777 ipp_attribute_t * /* O - New attribute */
778 ippAddRanges(ipp_t *ipp, /* I - IPP message */
779 ipp_tag_t group, /* I - IPP group */
780 const char *name, /* I - Name of attribute */
781 int num_values, /* I - Number of values */
782 const int *lower, /* I - Lower values */
783 const int *upper) /* I - Upper values */
784 {
785 int i; /* Looping var */
786 ipp_attribute_t *attr; /* New attribute */
787 _ipp_value_t *value; /* Current value */
788
789
790 DEBUG_printf(("ippAddRanges(ipp=%p, group=%02x(%s), name=\"%s\", "
791 "num_values=%d, lower=%p, upper=%p)", ipp, group,
792 ippTagString(group), name, num_values, lower, upper));
793
794 /*
795 * Range check input...
796 */
797
798 if (!ipp || !name || group < IPP_TAG_ZERO ||
799 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
800 num_values < 1)
801 return (NULL);
802
803 /*
804 * Create the attribute...
805 */
806
807 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RANGE, num_values)) == NULL)
808 return (NULL);
809
810 if (lower && upper)
811 {
812 for (i = num_values, value = attr->values;
813 i > 0;
814 i --, value ++)
815 {
816 value->range.lower = *lower++;
817 value->range.upper = *upper++;
818 }
819 }
820
821 return (attr);
822 }
823
824
825 /*
826 * 'ippAddResolution()' - Add a resolution value to an IPP message.
827 *
828 * The @code ipp@ parameter refers to an IPP message previously created using the
829 * @link ippNew@ or @link ippNewRequest@ functions.
830 *
831 * The @code group@ parameter specifies the IPP attribute group tag: none
832 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
833 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
834 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
835 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
836 */
837
838 ipp_attribute_t * /* O - New attribute */
839 ippAddResolution(ipp_t *ipp, /* I - IPP message */
840 ipp_tag_t group, /* I - IPP group */
841 const char *name, /* I - Name of attribute */
842 ipp_res_t units, /* I - Units for resolution */
843 int xres, /* I - X resolution */
844 int yres) /* I - Y resolution */
845 {
846 ipp_attribute_t *attr; /* New attribute */
847
848
849 DEBUG_printf(("ippAddResolution(ipp=%p, group=%02x(%s), name=\"%s\", "
850 "units=%d, xres=%d, yres=%d)", ipp, group,
851 ippTagString(group), name, units, xres, yres));
852
853 /*
854 * Range check input...
855 */
856
857 if (!ipp || !name || group < IPP_TAG_ZERO ||
858 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
859 units < IPP_RES_PER_INCH || units > IPP_RES_PER_CM ||
860 xres < 0 || yres < 0)
861 return (NULL);
862
863 /*
864 * Create the attribute...
865 */
866
867 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RESOLUTION, 1)) == NULL)
868 return (NULL);
869
870 attr->values[0].resolution.xres = xres;
871 attr->values[0].resolution.yres = yres;
872 attr->values[0].resolution.units = units;
873
874 return (attr);
875 }
876
877
878 /*
879 * 'ippAddResolutions()' - Add resolution values to an IPP message.
880 *
881 * The @code ipp@ parameter refers to an IPP message previously created using the
882 * @link ippNew@ or @link ippNewRequest@ functions.
883 *
884 * The @code group@ parameter specifies the IPP attribute group tag: none
885 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
886 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
887 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
888 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
889 */
890
891 ipp_attribute_t * /* O - New attribute */
892 ippAddResolutions(ipp_t *ipp, /* I - IPP message */
893 ipp_tag_t group, /* I - IPP group */
894 const char *name, /* I - Name of attribute */
895 int num_values,/* I - Number of values */
896 ipp_res_t units, /* I - Units for resolution */
897 const int *xres, /* I - X resolutions */
898 const int *yres) /* I - Y resolutions */
899 {
900 int i; /* Looping var */
901 ipp_attribute_t *attr; /* New attribute */
902 _ipp_value_t *value; /* Current value */
903
904
905 DEBUG_printf(("ippAddResolutions(ipp=%p, group=%02x(%s), name=\"%s\", "
906 "num_value=%d, units=%d, xres=%p, yres=%p)", ipp, group,
907 ippTagString(group), name, num_values, units, xres, yres));
908
909 /*
910 * Range check input...
911 */
912
913 if (!ipp || !name || group < IPP_TAG_ZERO ||
914 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
915 num_values < 1 ||
916 units < IPP_RES_PER_INCH || units > IPP_RES_PER_CM)
917 return (NULL);
918
919 /*
920 * Create the attribute...
921 */
922
923 if ((attr = ipp_add_attr(ipp, name, group, IPP_TAG_RESOLUTION, num_values)) == NULL)
924 return (NULL);
925
926 if (xres && yres)
927 {
928 for (i = num_values, value = attr->values;
929 i > 0;
930 i --, value ++)
931 {
932 value->resolution.xres = *xres++;
933 value->resolution.yres = *yres++;
934 value->resolution.units = units;
935 }
936 }
937
938 return (attr);
939 }
940
941
942 /*
943 * 'ippAddSeparator()' - Add a group separator to an IPP message.
944 *
945 * The @code ipp@ parameter refers to an IPP message previously created using the
946 * @link ippNew@ or @link ippNewRequest@ functions.
947 */
948
949 ipp_attribute_t * /* O - New attribute */
950 ippAddSeparator(ipp_t *ipp) /* I - IPP message */
951 {
952 DEBUG_printf(("ippAddSeparator(ipp=%p)", ipp));
953
954 /*
955 * Range check input...
956 */
957
958 if (!ipp)
959 return (NULL);
960
961 /*
962 * Create the attribute...
963 */
964
965 return (ipp_add_attr(ipp, NULL, IPP_TAG_ZERO, IPP_TAG_ZERO, 0));
966 }
967
968
969 /*
970 * 'ippAddString()' - Add a language-encoded string to an IPP message.
971 *
972 * The @code ipp@ parameter refers to an IPP message previously created using the
973 * @link ippNew@ or @link ippNewRequest@ functions.
974 *
975 * The @code group@ parameter specifies the IPP attribute group tag: none
976 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
977 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
978 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
979 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
980 *
981 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
982 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
983 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
984 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
985 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
986 * (@code IPP_TAG_URISCHEME@).
987 *
988 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
989 * textWithLanguage string values and must be @code NULL@ for all other string values.
990 */
991
992 ipp_attribute_t * /* O - New attribute */
993 ippAddString(ipp_t *ipp, /* I - IPP message */
994 ipp_tag_t group, /* I - IPP group */
995 ipp_tag_t value_tag, /* I - Type of attribute */
996 const char *name, /* I - Name of attribute */
997 const char *language, /* I - Language code */
998 const char *value) /* I - Value */
999 {
1000 ipp_tag_t temp_tag; /* Temporary value tag (masked) */
1001 ipp_attribute_t *attr; /* New attribute */
1002 char code[32]; /* Charset/language code buffer */
1003
1004
1005 DEBUG_printf(("ippAddString(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
1006 "name=\"%s\", language=\"%s\", value=\"%s\")", ipp,
1007 group, ippTagString(group), value_tag, ippTagString(value_tag), name,
1008 language, value));
1009
1010 /*
1011 * Range check input...
1012 */
1013
1014 temp_tag = (ipp_tag_t)((int)value_tag & IPP_TAG_MASK);
1015
1016 #if 0
1017 if (!ipp || !name || group < IPP_TAG_ZERO ||
1018 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
1019 (temp_tag < IPP_TAG_TEXT && temp_tag != IPP_TAG_TEXTLANG &&
1020 temp_tag != IPP_TAG_NAMELANG) || temp_tag > IPP_TAG_MIMETYPE)
1021 return (NULL);
1022
1023 if ((temp_tag == IPP_TAG_TEXTLANG || temp_tag == IPP_TAG_NAMELANG)
1024 != (language != NULL))
1025 return (NULL);
1026 #else
1027 if (!ipp || !name || group < IPP_TAG_ZERO ||
1028 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
1029 return (NULL);
1030 #endif /* 0 */
1031
1032 /*
1033 * See if we need to map charset, language, or locale values...
1034 */
1035
1036 if (language && ((int)value_tag & IPP_TAG_COPY) &&
1037 strcmp(language, ipp_lang_code(language, code, sizeof(code))))
1038 value_tag = temp_tag; /* Don't do a fast copy */
1039 else if (value && value_tag == (ipp_tag_t)(IPP_TAG_CHARSET | IPP_TAG_COPY) &&
1040 strcmp(value, ipp_get_code(value, code, sizeof(code))))
1041 value_tag = temp_tag; /* Don't do a fast copy */
1042 else if (value && value_tag == (ipp_tag_t)(IPP_TAG_LANGUAGE | IPP_TAG_COPY) &&
1043 strcmp(value, ipp_lang_code(value, code, sizeof(code))))
1044 value_tag = temp_tag; /* Don't do a fast copy */
1045
1046 /*
1047 * Create the attribute...
1048 */
1049
1050 if ((attr = ipp_add_attr(ipp, name, group, value_tag, 1)) == NULL)
1051 return (NULL);
1052
1053 /*
1054 * Initialize the attribute data...
1055 */
1056
1057 if ((int)value_tag & IPP_TAG_COPY)
1058 {
1059 attr->values[0].string.language = (char *)language;
1060 attr->values[0].string.text = (char *)value;
1061 }
1062 else
1063 {
1064 if (language)
1065 attr->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language, code,
1066 sizeof(code)));
1067
1068 if (value)
1069 {
1070 if (value_tag == IPP_TAG_CHARSET)
1071 attr->values[0].string.text = _cupsStrAlloc(ipp_get_code(value, code,
1072 sizeof(code)));
1073 else if (value_tag == IPP_TAG_LANGUAGE)
1074 attr->values[0].string.text = _cupsStrAlloc(ipp_lang_code(value, code,
1075 sizeof(code)));
1076 else
1077 attr->values[0].string.text = _cupsStrAlloc(value);
1078 }
1079 }
1080
1081 return (attr);
1082 }
1083
1084
1085 /*
1086 * 'ippAddStrings()' - Add language-encoded strings to an IPP message.
1087 *
1088 * The @code ipp@ parameter refers to an IPP message previously created using the
1089 * @link ippNew@ or @link ippNewRequest@ functions.
1090 *
1091 * The @code group@ parameter specifies the IPP attribute group tag: none
1092 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
1093 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
1094 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
1095 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
1096 *
1097 * Supported string values include charset (@code IPP_TAG_CHARSET@), keyword
1098 * (@code IPP_TAG_KEYWORD@), language (@code IPP_TAG_LANGUAGE@), mimeMediaType
1099 * (@code IPP_TAG_MIMETYPE@), name (@code IPP_TAG_NAME@), nameWithLanguage
1100 * (@code IPP_TAG_NAMELANG), text (@code IPP_TAG_TEXT@), textWithLanguage
1101 * (@code IPP_TAG_TEXTLANG@), uri (@code IPP_TAG_URI@), and uriScheme
1102 * (@code IPP_TAG_URISCHEME@).
1103 *
1104 * The @code language@ parameter must be non-@code NULL@ for nameWithLanguage and
1105 * textWithLanguage string values and must be @code NULL@ for all other string values.
1106 */
1107
1108 ipp_attribute_t * /* O - New attribute */
1109 ippAddStrings(
1110 ipp_t *ipp, /* I - IPP message */
1111 ipp_tag_t group, /* I - IPP group */
1112 ipp_tag_t value_tag, /* I - Type of attribute */
1113 const char *name, /* I - Name of attribute */
1114 int num_values, /* I - Number of values */
1115 const char *language, /* I - Language code (@code NULL@ for default) */
1116 const char * const *values) /* I - Values */
1117 {
1118 int i; /* Looping var */
1119 ipp_tag_t temp_tag; /* Temporary value tag (masked) */
1120 ipp_attribute_t *attr; /* New attribute */
1121 _ipp_value_t *value; /* Current value */
1122 char code[32]; /* Language/charset value buffer */
1123
1124
1125 DEBUG_printf(("ippAddStrings(ipp=%p, group=%02x(%s), value_tag=%02x(%s), "
1126 "name=\"%s\", num_values=%d, language=\"%s\", values=%p)", ipp,
1127 group, ippTagString(group), value_tag, ippTagString(value_tag), name,
1128 num_values, language, values));
1129
1130 /*
1131 * Range check input...
1132 */
1133
1134 temp_tag = (ipp_tag_t)((int)value_tag & IPP_TAG_MASK);
1135
1136 #if 0
1137 if (!ipp || !name || group < IPP_TAG_ZERO ||
1138 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
1139 (temp_tag < IPP_TAG_TEXT && temp_tag != IPP_TAG_TEXTLANG &&
1140 temp_tag != IPP_TAG_NAMELANG) || temp_tag > IPP_TAG_MIMETYPE ||
1141 num_values < 1)
1142 return (NULL);
1143
1144 if ((temp_tag == IPP_TAG_TEXTLANG || temp_tag == IPP_TAG_NAMELANG)
1145 != (language != NULL))
1146 return (NULL);
1147 #else
1148 if (!ipp || !name || group < IPP_TAG_ZERO ||
1149 group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE ||
1150 num_values < 1)
1151 return (NULL);
1152 #endif /* 0 */
1153
1154 /*
1155 * See if we need to map charset, language, or locale values...
1156 */
1157
1158 if (language && ((int)value_tag & IPP_TAG_COPY) &&
1159 strcmp(language, ipp_lang_code(language, code, sizeof(code))))
1160 value_tag = temp_tag; /* Don't do a fast copy */
1161 else if (values && value_tag == (ipp_tag_t)(IPP_TAG_CHARSET | IPP_TAG_COPY))
1162 {
1163 for (i = 0; i < num_values; i ++)
1164 if (strcmp(values[i], ipp_get_code(values[i], code, sizeof(code))))
1165 {
1166 value_tag = temp_tag; /* Don't do a fast copy */
1167 break;
1168 }
1169 }
1170 else if (values && value_tag == (ipp_tag_t)(IPP_TAG_LANGUAGE | IPP_TAG_COPY))
1171 {
1172 for (i = 0; i < num_values; i ++)
1173 if (strcmp(values[i], ipp_lang_code(values[i], code, sizeof(code))))
1174 {
1175 value_tag = temp_tag; /* Don't do a fast copy */
1176 break;
1177 }
1178 }
1179
1180 /*
1181 * Create the attribute...
1182 */
1183
1184 if ((attr = ipp_add_attr(ipp, name, group, value_tag, num_values)) == NULL)
1185 return (NULL);
1186
1187 /*
1188 * Initialize the attribute data...
1189 */
1190
1191 for (i = num_values, value = attr->values;
1192 i > 0;
1193 i --, value ++)
1194 {
1195 if (language)
1196 {
1197 if (value == attr->values)
1198 {
1199 if ((int)value_tag & IPP_TAG_COPY)
1200 value->string.language = (char *)language;
1201 else
1202 value->string.language = _cupsStrAlloc(ipp_lang_code(language, code,
1203 sizeof(code)));
1204 }
1205 else
1206 value->string.language = attr->values[0].string.language;
1207 }
1208
1209 if (values)
1210 {
1211 if ((int)value_tag & IPP_TAG_COPY)
1212 value->string.text = (char *)*values++;
1213 else if (value_tag == IPP_TAG_CHARSET)
1214 value->string.text = _cupsStrAlloc(ipp_get_code(*values++, code, sizeof(code)));
1215 else if (value_tag == IPP_TAG_LANGUAGE)
1216 value->string.text = _cupsStrAlloc(ipp_lang_code(*values++, code, sizeof(code)));
1217 else
1218 value->string.text = _cupsStrAlloc(*values++);
1219 }
1220 }
1221
1222 return (attr);
1223 }
1224
1225
1226 /*
1227 * 'ippCopyAttribute()' - Copy an attribute.
1228 *
1229 * The specified attribute, @code attr@, is copied to the destination IPP message.
1230 * When @code quickcopy@ is non-zero, a "shallow" reference copy of the attribute is
1231 * created - this should only be done as long as the original source IPP message will
1232 * not be freed for the life of the destination.
1233 *
1234 * @since CUPS 1.6/OS X 10.8@
1235 */
1236
1237
1238 ipp_attribute_t * /* O - New attribute */
1239 ippCopyAttribute(
1240 ipp_t *dst, /* I - Destination IPP message */
1241 ipp_attribute_t *srcattr, /* I - Attribute to copy */
1242 int quickcopy) /* I - 1 for a referenced copy, 0 for normal */
1243 {
1244 int i; /* Looping var */
1245 ipp_attribute_t *dstattr; /* Destination attribute */
1246 _ipp_value_t *srcval, /* Source value */
1247 *dstval; /* Destination value */
1248
1249
1250 DEBUG_printf(("ippCopyAttribute(dst=%p, srcattr=%p, quickcopy=%d)", dst, srcattr,
1251 quickcopy));
1252
1253 /*
1254 * Range check input...
1255 */
1256
1257 if (!dst || !srcattr)
1258 return (NULL);
1259
1260 /*
1261 * Copy it...
1262 */
1263
1264 quickcopy = quickcopy ? IPP_TAG_COPY : 0;
1265
1266 switch (srcattr->value_tag & ~IPP_TAG_COPY)
1267 {
1268 case IPP_TAG_ZERO :
1269 dstattr = ippAddSeparator(dst);
1270 break;
1271
1272 case IPP_TAG_INTEGER :
1273 case IPP_TAG_ENUM :
1274 dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag,
1275 srcattr->name, srcattr->num_values, NULL);
1276 if (!dstattr)
1277 break;
1278
1279 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1280 i > 0;
1281 i --, srcval ++, dstval ++)
1282 dstval->integer = srcval->integer;
1283 break;
1284
1285 case IPP_TAG_BOOLEAN :
1286 dstattr = ippAddBooleans(dst, srcattr->group_tag, srcattr->name,
1287 srcattr->num_values, NULL);
1288 if (!dstattr)
1289 break;
1290
1291 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1292 i > 0;
1293 i --, srcval ++, dstval ++)
1294 dstval->boolean = srcval->boolean;
1295 break;
1296
1297 case IPP_TAG_TEXT :
1298 case IPP_TAG_NAME :
1299 case IPP_TAG_KEYWORD :
1300 case IPP_TAG_URI :
1301 case IPP_TAG_URISCHEME :
1302 case IPP_TAG_CHARSET :
1303 case IPP_TAG_LANGUAGE :
1304 case IPP_TAG_MIMETYPE :
1305 dstattr = ippAddStrings(dst, srcattr->group_tag,
1306 (ipp_tag_t)(srcattr->value_tag | quickcopy),
1307 srcattr->name, srcattr->num_values, NULL, NULL);
1308 if (!dstattr)
1309 break;
1310
1311 if (quickcopy)
1312 {
1313 for (i = srcattr->num_values, srcval = srcattr->values,
1314 dstval = dstattr->values;
1315 i > 0;
1316 i --, srcval ++, dstval ++)
1317 dstval->string.text = srcval->string.text;
1318 }
1319 else if (srcattr->value_tag & IPP_TAG_COPY)
1320 {
1321 for (i = srcattr->num_values, srcval = srcattr->values,
1322 dstval = dstattr->values;
1323 i > 0;
1324 i --, srcval ++, dstval ++)
1325 dstval->string.text = _cupsStrAlloc(srcval->string.text);
1326 }
1327 else
1328 {
1329 for (i = srcattr->num_values, srcval = srcattr->values,
1330 dstval = dstattr->values;
1331 i > 0;
1332 i --, srcval ++, dstval ++)
1333 dstval->string.text = _cupsStrRetain(srcval->string.text);
1334 }
1335 break;
1336
1337 case IPP_TAG_DATE :
1338 if (srcattr->num_values != 1)
1339 return (NULL);
1340
1341 dstattr = ippAddDate(dst, srcattr->group_tag, srcattr->name,
1342 srcattr->values[0].date);
1343 break;
1344
1345 case IPP_TAG_RESOLUTION :
1346 dstattr = ippAddResolutions(dst, srcattr->group_tag, srcattr->name,
1347 srcattr->num_values, IPP_RES_PER_INCH,
1348 NULL, NULL);
1349 if (!dstattr)
1350 break;
1351
1352 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1353 i > 0;
1354 i --, srcval ++, dstval ++)
1355 {
1356 dstval->resolution.xres = srcval->resolution.xres;
1357 dstval->resolution.yres = srcval->resolution.yres;
1358 dstval->resolution.units = srcval->resolution.units;
1359 }
1360 break;
1361
1362 case IPP_TAG_RANGE :
1363 dstattr = ippAddRanges(dst, srcattr->group_tag, srcattr->name,
1364 srcattr->num_values, NULL, NULL);
1365 if (!dstattr)
1366 break;
1367
1368 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1369 i > 0;
1370 i --, srcval ++, dstval ++)
1371 {
1372 dstval->range.lower = srcval->range.lower;
1373 dstval->range.upper = srcval->range.upper;
1374 }
1375 break;
1376
1377 case IPP_TAG_TEXTLANG :
1378 case IPP_TAG_NAMELANG :
1379 dstattr = ippAddStrings(dst, srcattr->group_tag,
1380 (ipp_tag_t)(srcattr->value_tag | quickcopy),
1381 srcattr->name, srcattr->num_values, NULL, NULL);
1382 if (!dstattr)
1383 break;
1384
1385 if (quickcopy)
1386 {
1387 for (i = srcattr->num_values, srcval = srcattr->values,
1388 dstval = dstattr->values;
1389 i > 0;
1390 i --, srcval ++, dstval ++)
1391 {
1392 dstval->string.language = srcval->string.language;
1393 dstval->string.text = srcval->string.text;
1394 }
1395 }
1396 else if (srcattr->value_tag & IPP_TAG_COPY)
1397 {
1398 for (i = srcattr->num_values, srcval = srcattr->values,
1399 dstval = dstattr->values;
1400 i > 0;
1401 i --, srcval ++, dstval ++)
1402 {
1403 if (srcval == srcattr->values)
1404 dstval->string.language = _cupsStrAlloc(srcval->string.language);
1405 else
1406 dstval->string.language = dstattr->values[0].string.language;
1407
1408 dstval->string.text = _cupsStrAlloc(srcval->string.text);
1409 }
1410 }
1411 else
1412 {
1413 for (i = srcattr->num_values, srcval = srcattr->values,
1414 dstval = dstattr->values;
1415 i > 0;
1416 i --, srcval ++, dstval ++)
1417 {
1418 if (srcval == srcattr->values)
1419 dstval->string.language = _cupsStrRetain(srcval->string.language);
1420 else
1421 dstval->string.language = dstattr->values[0].string.language;
1422
1423 dstval->string.text = _cupsStrRetain(srcval->string.text);
1424 }
1425 }
1426 break;
1427
1428 case IPP_TAG_BEGIN_COLLECTION :
1429 dstattr = ippAddCollections(dst, srcattr->group_tag, srcattr->name,
1430 srcattr->num_values, NULL);
1431 if (!dstattr)
1432 break;
1433
1434 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1435 i > 0;
1436 i --, srcval ++, dstval ++)
1437 {
1438 dstval->collection = srcval->collection;
1439 srcval->collection->use ++;
1440 }
1441 break;
1442
1443 case IPP_TAG_STRING :
1444 default :
1445 /* TODO: Implement quick copy for unknown/octetString values */
1446 dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag,
1447 srcattr->name, srcattr->num_values, NULL);
1448 if (!dstattr)
1449 break;
1450
1451 for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values;
1452 i > 0;
1453 i --, srcval ++, dstval ++)
1454 {
1455 dstval->unknown.length = srcval->unknown.length;
1456
1457 if (dstval->unknown.length > 0)
1458 {
1459 if ((dstval->unknown.data = malloc(dstval->unknown.length)) == NULL)
1460 dstval->unknown.length = 0;
1461 else
1462 memcpy(dstval->unknown.data, srcval->unknown.data, dstval->unknown.length);
1463 }
1464 }
1465 break; /* anti-compiler-warning-code */
1466 }
1467
1468 return (dstattr);
1469 }
1470
1471
1472 /*
1473 * 'ippCopyAttributes()' - Copy attributes from one IPP message to another.
1474 *
1475 * Zero or more attributes are copied from the source IPP message, @code@ src, to the
1476 * destination IPP message, @code dst@. When @code quickcopy@ is non-zero, a "shallow"
1477 * reference copy of the attribute is created - this should only be done as long as the
1478 * original source IPP message will not be freed for the life of the destination.
1479 *
1480 * The @code cb@ and @code context@ parameters provide a generic way to "filter" the
1481 * attributes that are copied - the function must return 1 to copy the attribute or
1482 * 0 to skip it. The function may also choose to do a partial copy of the source attribute
1483 * itself.
1484 *
1485 * @since CUPS 1.6/OS X 10.8@
1486 */
1487
1488 int /* O - 1 on success, 0 on error */
1489 ippCopyAttributes(
1490 ipp_t *dst, /* I - Destination IPP message */
1491 ipp_t *src, /* I - Source IPP message */
1492 int quickcopy, /* I - 1 for a referenced copy, 0 for normal */
1493 ipp_copycb_t cb, /* I - Copy callback or @code NULL@ for none */
1494 void *context) /* I - Context pointer */
1495 {
1496 ipp_attribute_t *srcattr; /* Source attribute */
1497
1498
1499 DEBUG_printf(("ippCopyAttributes(dst=%p, src=%p, quickcopy=%d, cb=%p, context=%p)",
1500 dst, src, quickcopy, cb, context));
1501
1502 /*
1503 * Range check input...
1504 */
1505
1506 if (!dst || !src)
1507 return (0);
1508
1509 /*
1510 * Loop through source attributes and copy as needed...
1511 */
1512
1513 for (srcattr = src->attrs; srcattr; srcattr = srcattr->next)
1514 if (!cb || (*cb)(context, dst, srcattr))
1515 if (!ippCopyAttribute(dst, srcattr, quickcopy))
1516 return (0);
1517
1518 return (1);
1519 }
1520
1521
1522 /*
1523 * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
1524 * in seconds.
1525 */
1526
1527 time_t /* O - UNIX time value */
1528 ippDateToTime(const ipp_uchar_t *date) /* I - RFC 1903 date info */
1529 {
1530 struct tm unixdate; /* UNIX date/time info */
1531 time_t t; /* Computed time */
1532
1533
1534 if (!date)
1535 return (0);
1536
1537 memset(&unixdate, 0, sizeof(unixdate));
1538
1539 /*
1540 * RFC-1903 date/time format is:
1541 *
1542 * Byte(s) Description
1543 * ------- -----------
1544 * 0-1 Year (0 to 65535)
1545 * 2 Month (1 to 12)
1546 * 3 Day (1 to 31)
1547 * 4 Hours (0 to 23)
1548 * 5 Minutes (0 to 59)
1549 * 6 Seconds (0 to 60, 60 = "leap second")
1550 * 7 Deciseconds (0 to 9)
1551 * 8 +/- UTC
1552 * 9 UTC hours (0 to 11)
1553 * 10 UTC minutes (0 to 59)
1554 */
1555
1556 unixdate.tm_year = ((date[0] << 8) | date[1]) - 1900;
1557 unixdate.tm_mon = date[2] - 1;
1558 unixdate.tm_mday = date[3];
1559 unixdate.tm_hour = date[4];
1560 unixdate.tm_min = date[5];
1561 unixdate.tm_sec = date[6];
1562
1563 t = mktime(&unixdate);
1564
1565 if (date[8] == '-')
1566 t += date[9] * 3600 + date[10] * 60;
1567 else
1568 t -= date[9] * 3600 + date[10] * 60;
1569
1570 return (t);
1571 }
1572
1573
1574 /*
1575 * 'ippDelete()' - Delete an IPP message.
1576 */
1577
1578 void
1579 ippDelete(ipp_t *ipp) /* I - IPP message */
1580 {
1581 ipp_attribute_t *attr, /* Current attribute */
1582 *next; /* Next attribute */
1583
1584
1585 DEBUG_printf(("ippDelete(ipp=%p)", ipp));
1586
1587 if (!ipp)
1588 return;
1589
1590 ipp->use --;
1591 if (ipp->use > 0)
1592 return;
1593
1594 for (attr = ipp->attrs; attr != NULL; attr = next)
1595 {
1596 next = attr->next;
1597
1598 ipp_free_values(attr, 0, attr->num_values);
1599
1600 if (attr->name)
1601 _cupsStrFree(attr->name);
1602
1603 free(attr);
1604 }
1605
1606 free(ipp);
1607 }
1608
1609
1610 /*
1611 * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
1612 *
1613 * @since CUPS 1.1.19/OS X 10.3@
1614 */
1615
1616 void
1617 ippDeleteAttribute(
1618 ipp_t *ipp, /* I - IPP message */
1619 ipp_attribute_t *attr) /* I - Attribute to delete */
1620 {
1621 ipp_attribute_t *current, /* Current attribute */
1622 *prev; /* Previous attribute */
1623
1624
1625 DEBUG_printf(("ippDeleteAttribute(ipp=%p, attr=%p(%s))", ipp, attr,
1626 attr ? attr->name : "(null)"));
1627
1628 /*
1629 * Range check input...
1630 */
1631
1632 if (!attr)
1633 return;
1634
1635 /*
1636 * Find the attribute in the list...
1637 */
1638
1639 if (ipp)
1640 {
1641 for (current = ipp->attrs, prev = NULL;
1642 current;
1643 prev = current, current = current->next)
1644 if (current == attr)
1645 {
1646 /*
1647 * Found it, remove the attribute from the list...
1648 */
1649
1650 if (prev)
1651 prev->next = current->next;
1652 else
1653 ipp->attrs = current->next;
1654
1655 if (current == ipp->last)
1656 ipp->last = prev;
1657
1658 break;
1659 }
1660
1661 if (!current)
1662 return;
1663 }
1664
1665 /*
1666 * Free memory used by the attribute...
1667 */
1668
1669 ipp_free_values(attr, 0, attr->num_values);
1670
1671 if (attr->name)
1672 _cupsStrFree(attr->name);
1673
1674 free(attr);
1675 }
1676
1677
1678 /*
1679 * 'ippDeleteValues()' - Delete values in an attribute.
1680 *
1681 * The @code element@ parameter specifies the first value to delete, starting at
1682 * 0. It must be less than the number of values returned by @link ippGetCount@.
1683 *
1684 * The @code attr@ parameter may be modified as a result of setting the value.
1685 *
1686 * Deleting all values in an attribute deletes the attribute.
1687 *
1688 * @since CUPS 1.6/OS X 10.8@
1689 */
1690
1691 int /* O - 1 on success, 0 on failure */
1692 ippDeleteValues(
1693 ipp_t *ipp, /* I - IPP message */
1694 ipp_attribute_t **attr, /* IO - Attribute */
1695 int element, /* I - Index of first value to delete (0-based) */
1696 int count) /* I - Number of values to delete */
1697 {
1698 /*
1699 * Range check input...
1700 */
1701
1702 if (!ipp || !attr || !*attr ||
1703 element < 0 || element >= (*attr)->num_values || count <= 0 ||
1704 (element + count) >= (*attr)->num_values)
1705 return (0);
1706
1707 /*
1708 * If we are deleting all values, just delete the attribute entirely.
1709 */
1710
1711 if (count == (*attr)->num_values)
1712 {
1713 ippDeleteAttribute(ipp, *attr);
1714 *attr = NULL;
1715 return (1);
1716 }
1717
1718 /*
1719 * Otherwise free the values in question and return.
1720 */
1721
1722 ipp_free_values(*attr, element, count);
1723
1724 return (1);
1725 }
1726
1727
1728 /*
1729 * 'ippFindAttribute()' - Find a named attribute in a request.
1730 */
1731
1732 ipp_attribute_t * /* O - Matching attribute */
1733 ippFindAttribute(ipp_t *ipp, /* I - IPP message */
1734 const char *name, /* I - Name of attribute */
1735 ipp_tag_t type) /* I - Type of attribute */
1736 {
1737 DEBUG_printf(("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", ipp,
1738 name, type, ippTagString(type)));
1739
1740 if (!ipp || !name)
1741 return (NULL);
1742
1743 /*
1744 * Reset the current pointer...
1745 */
1746
1747 ipp->current = NULL;
1748
1749 /*
1750 * Search for the attribute...
1751 */
1752
1753 return (ippFindNextAttribute(ipp, name, type));
1754 }
1755
1756
1757 /*
1758 * 'ippFindNextAttribute()' - Find the next named attribute in a request.
1759 */
1760
1761 ipp_attribute_t * /* O - Matching attribute */
1762 ippFindNextAttribute(ipp_t *ipp, /* I - IPP message */
1763 const char *name, /* I - Name of attribute */
1764 ipp_tag_t type) /* I - Type of attribute */
1765 {
1766 ipp_attribute_t *attr; /* Current atttribute */
1767 ipp_tag_t value_tag; /* Value tag */
1768
1769
1770 DEBUG_printf(("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))",
1771 ipp, name, type, ippTagString(type)));
1772
1773 if (!ipp || !name)
1774 return (NULL);
1775
1776 if (ipp->current)
1777 {
1778 ipp->prev = ipp->current;
1779 attr = ipp->current->next;
1780 }
1781 else
1782 {
1783 ipp->prev = NULL;
1784 attr = ipp->attrs;
1785 }
1786
1787 for (; attr != NULL; ipp->prev = attr, attr = attr->next)
1788 {
1789 DEBUG_printf(("4ippFindAttribute: attr=%p, name=\"%s\"", attr,
1790 attr->name));
1791
1792 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_MASK);
1793
1794 if (attr->name != NULL && _cups_strcasecmp(attr->name, name) == 0 &&
1795 (value_tag == type || type == IPP_TAG_ZERO ||
1796 (value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) ||
1797 (value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME)))
1798 {
1799 ipp->current = attr;
1800
1801 return (attr);
1802 }
1803 }
1804
1805 ipp->current = NULL;
1806 ipp->prev = NULL;
1807
1808 return (NULL);
1809 }
1810
1811
1812 /*
1813 * 'ippFirstAttribute()' - Return the first attribute in the message.
1814 *
1815 * @since CUPS 1.6/OS X 10.8@
1816 */
1817
1818 ipp_attribute_t * /* O - First attribute or @code NULL@ if none */
1819 ippFirstAttribute(ipp_t *ipp) /* I - IPP message */
1820 {
1821 /*
1822 * Range check input...
1823 */
1824
1825 if (!ipp)
1826 return (NULL);
1827
1828 /*
1829 * Return the first attribute...
1830 */
1831
1832 return (ipp->current = ipp->attrs);
1833 }
1834
1835
1836 /*
1837 * 'ippGetBoolean()' - Get a boolean value for an attribute.
1838 *
1839 * The @code element@ parameter specifies which value to get from 0 to
1840 * @link ippGetCount(attr)@ - 1.
1841 *
1842 * @since CUPS 1.6/OS X 10.8@
1843 */
1844
1845 int /* O - Boolean value or -1 on error */
1846 ippGetBoolean(ipp_attribute_t *attr, /* I - IPP attribute */
1847 int element) /* I - Value number (0-based) */
1848 {
1849 /*
1850 * Range check input...
1851 */
1852
1853 if (!attr || attr->value_tag != IPP_TAG_BOOLEAN ||
1854 element < 0 || element >= attr->num_values)
1855 return (-1);
1856
1857 /*
1858 * Return the value...
1859 */
1860
1861 return (attr->values[element].boolean);
1862 }
1863
1864
1865 /*
1866 * 'ippGetCollection()' - Get a collection value for an attribute.
1867 *
1868 * The @code element@ parameter specifies which value to get from 0 to
1869 * @link ippGetCount(attr)@ - 1.
1870 *
1871 * @since CUPS 1.6/OS X 10.8@
1872 */
1873
1874 ipp_t * /* O - Collection value or @code NULL@ on error */
1875 ippGetCollection(
1876 ipp_attribute_t *attr, /* I - IPP attribute */
1877 int element) /* I - Value number (0-based) */
1878 {
1879 /*
1880 * Range check input...
1881 */
1882
1883 if (!attr || attr->value_tag != IPP_TAG_BEGIN_COLLECTION ||
1884 element < 0 || element >= attr->num_values)
1885 return (NULL);
1886
1887 /*
1888 * Return the value...
1889 */
1890
1891 return (attr->values[element].collection);
1892 }
1893
1894
1895 /*
1896 * 'ippGetCount()' - Get the number of values in an attribute.
1897 *
1898 * @since CUPS 1.6/OS X 10.8@
1899 */
1900
1901 int /* O - Number of values or -1 on error */
1902 ippGetCount(ipp_attribute_t *attr) /* I - IPP attribute */
1903 {
1904 /*
1905 * Range check input...
1906 */
1907
1908 if (!attr)
1909 return (-1);
1910
1911 /*
1912 * Return the number of values...
1913 */
1914
1915 return (attr->num_values);
1916 }
1917
1918
1919 /*
1920 * 'ippGetDate()' - Get a date value for an attribute.
1921 *
1922 * The @code element@ parameter specifies which value to get from 0 to
1923 * @link ippGetCount(attr)@ - 1.
1924 *
1925 * @since CUPS 1.6/OS X 10.8@
1926 */
1927
1928 const ipp_uchar_t * /* O - Date value or @code NULL@ */
1929 ippGetDate(ipp_attribute_t *attr, /* I - IPP attribute */
1930 int element) /* I - Value number (0-based) */
1931 {
1932 /*
1933 * Range check input...
1934 */
1935
1936 if (!attr || attr->value_tag != IPP_TAG_DATE ||
1937 element < 0 || element >= attr->num_values)
1938 return (NULL);
1939
1940 /*
1941 * Return the value...
1942 */
1943
1944 return (attr->values[element].date);
1945 }
1946
1947
1948 /*
1949 * 'ippGetGroupTag()' - Get the group associated with an attribute.
1950 *
1951 * @since CUPS 1.6/OS X 10.8@
1952 */
1953
1954 ipp_tag_t /* O - Group tag or @code IPP_TAG_ZERO@ on error */
1955 ippGetGroupTag(ipp_attribute_t *attr) /* I - IPP attribute */
1956 {
1957 /*
1958 * Range check input...
1959 */
1960
1961 if (!attr)
1962 return (IPP_TAG_ZERO);
1963
1964 /*
1965 * Return the group...
1966 */
1967
1968 return (attr->group_tag);
1969 }
1970
1971
1972 /*
1973 * 'ippGetInteger()' - Get the integer/enum value for an attribute.
1974 *
1975 * The @code element@ parameter specifies which value to get from 0 to
1976 * @link ippGetCount(attr)@ - 1.
1977 *
1978 * @since CUPS 1.6/OS X 10.8@
1979 */
1980
1981 int /* O - Value or -1 on error */
1982 ippGetInteger(ipp_attribute_t *attr, /* I - IPP attribute */
1983 int element) /* I - Value number (0-based) */
1984 {
1985 /*
1986 * Range check input...
1987 */
1988
1989 if (!attr || (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM) ||
1990 element < 0 || element >= attr->num_values)
1991 return (-1);
1992
1993 /*
1994 * Return the value...
1995 */
1996
1997 return (attr->values[element].integer);
1998 }
1999
2000
2001 /*
2002 * 'ippGetName()' - Get the attribute name.
2003 *
2004 * @since CUPS 1.6/OS X 10.8@
2005 */
2006
2007 const char * /* O - Attribute name or @code NULL@ for separators */
2008 ippGetName(ipp_attribute_t *attr) /* I - IPP attribute */
2009 {
2010 /*
2011 * Range check input...
2012 */
2013
2014 if (!attr)
2015 return (NULL);
2016
2017 /*
2018 * Return the name...
2019 */
2020
2021 return (attr->name);
2022 }
2023
2024
2025 /*
2026 * 'ippGetOperation()' - Get the operation ID in an IPP message.
2027 *
2028 * @since CUPS 1.6/OS X 10.8@
2029 */
2030
2031 ipp_op_t /* O - Operation ID or -1 on error */
2032 ippGetOperation(ipp_t *ipp) /* I - IPP request message */
2033 {
2034 /*
2035 * Range check input...
2036 */
2037
2038 if (!ipp)
2039 return ((ipp_op_t)-1);
2040
2041 /*
2042 * Return the value...
2043 */
2044
2045 return (ipp->request.op.operation_id);
2046 }
2047
2048
2049 /*
2050 * 'ippGetRange()' - Get a rangeOfInteger value from an attribute.
2051 *
2052 * The @code element@ parameter specifies which value to get from 0 to
2053 * @link ippGetCount(attr)@ - 1.
2054 *
2055 * @since CUPS 1.6/OS X 10.8@
2056 */
2057
2058 int /* O - Lower value of range or -1 */
2059 ippGetRange(ipp_attribute_t *attr, /* I - IPP attribute */
2060 int element, /* I - Value number (0-based) */
2061 int *uppervalue)/* O - Upper value of range */
2062 {
2063 /*
2064 * Range check input...
2065 */
2066
2067 if (!attr || attr->value_tag != IPP_TAG_RANGE ||
2068 element < 0 || element >= attr->num_values)
2069 {
2070 if (uppervalue)
2071 *uppervalue = -1;
2072
2073 return (-1);
2074 }
2075
2076 /*
2077 * Return the values...
2078 */
2079
2080 if (uppervalue)
2081 *uppervalue = attr->values[element].range.upper;
2082
2083 return (attr->values[element].range.lower);
2084 }
2085
2086
2087 /*
2088 * 'ippGetRequestId()' - Get the request ID from an IPP message.
2089 *
2090 * @since CUPS 1.6/OS X 10.8@
2091 */
2092
2093 int /* O - Request ID or -1 on error */
2094 ippGetRequestId(ipp_t *ipp) /* I - IPP message */
2095 {
2096 /*
2097 * Range check input...
2098 */
2099
2100 if (!ipp)
2101 return (-1);
2102
2103 /*
2104 * Return the request ID...
2105 */
2106
2107 return (ipp->request.any.request_id);
2108 }
2109
2110
2111 /*
2112 * 'ippGetResolution()' - Get a resolution value for an attribute.
2113 *
2114 * The @code element@ parameter specifies which value to get from 0 to
2115 * @link ippGetCount(attr)@ - 1.
2116 *
2117 * @since CUPS 1.6/OS X 10.8@
2118 */
2119
2120 int /* O - Horizontal/cross feed resolution or -1 */
2121 ippGetResolution(
2122 ipp_attribute_t *attr, /* I - IPP attribute */
2123 int element, /* I - Value number (0-based) */
2124 int *yres, /* O - Vertical/feed resolution */
2125 ipp_res_t *units) /* O - Units for resolution */
2126 {
2127 /*
2128 * Range check input...
2129 */
2130
2131 if (!attr || attr->value_tag != IPP_TAG_RESOLUTION ||
2132 element < 0 || element >= attr->num_values)
2133 return (-1);
2134
2135 /*
2136 * Return the value...
2137 */
2138
2139 if (yres)
2140 *yres = attr->values[element].resolution.yres;
2141
2142 if (units)
2143 *units = attr->values[element].resolution.units;
2144
2145 return (attr->values[element].resolution.xres);
2146 }
2147
2148
2149 /*
2150 * 'ippGetState()' - Get the IPP message state.
2151 *
2152 * @since CUPS 1.6/OS X 10.8@
2153 */
2154
2155 ipp_state_t /* O - IPP message state value */
2156 ippGetState(ipp_t *ipp) /* I - IPP message */
2157 {
2158 /*
2159 * Range check input...
2160 */
2161
2162 if (!ipp)
2163 return (IPP_IDLE);
2164
2165 /*
2166 * Return the value...
2167 */
2168
2169 return (ipp->state);
2170 }
2171
2172
2173 /*
2174 * 'ippGetStatusCode()' - Get the status code from an IPP response or event message.
2175 *
2176 * @since CUPS 1.6/OS X 10.8@
2177 */
2178
2179 ipp_status_t /* O - Status code in IPP message */
2180 ippGetStatusCode(ipp_t *ipp) /* I - IPP response or event message */
2181 {
2182 /*
2183 * Range check input...
2184 */
2185
2186 if (!ipp)
2187 return (IPP_INTERNAL_ERROR);
2188
2189 /*
2190 * Return the value...
2191 */
2192
2193 return (ipp->request.status.status_code);
2194 }
2195
2196
2197 /*
2198 * 'ippGetString()' - Get the string and optionally the language code for an attribute.
2199 *
2200 * The @code element@ parameter specifies which value to get from 0 to
2201 * @link ippGetCount(attr)@ - 1.
2202 *
2203 * @since CUPS 1.6/OS X 10.8@
2204 */
2205
2206 const char *
2207 ippGetString(ipp_attribute_t *attr, /* I - IPP attribute */
2208 int element, /* I - Value number (0-based) */
2209 const char **language)/* O - Language code (@code NULL@ for don't care) */
2210 {
2211 /*
2212 * Range check input...
2213 */
2214
2215 if (!attr || element < 0 || element >= attr->num_values ||
2216 (attr->value_tag != IPP_TAG_TEXTLANG && attr->value_tag != IPP_TAG_NAMELANG &&
2217 (attr->value_tag < IPP_TAG_TEXT || attr->value_tag > IPP_TAG_MIMETYPE)))
2218 return (NULL);
2219
2220 /*
2221 * Return the value...
2222 */
2223
2224 if (language)
2225 *language = attr->values[element].string.language;
2226
2227 return (attr->values[element].string.text);
2228 }
2229
2230
2231 /*
2232 * 'ippGetValueTag()' - Get the value tag for an attribute.
2233 *
2234 * @since CUPS 1.6/OS X 10.8@
2235 */
2236
2237 ipp_tag_t /* O - Value tag or @code IPP_TAG_ZERO@ on error */
2238 ippGetValueTag(ipp_attribute_t *attr) /* I - IPP attribute */
2239 {
2240 /*
2241 * Range check input...
2242 */
2243
2244 if (!attr)
2245 return (IPP_TAG_ZERO);
2246
2247 /*
2248 * Return the value...
2249 */
2250
2251 return (attr->value_tag);
2252 }
2253
2254
2255 /*
2256 * 'ippGetVersion()' - Get the major and minor version number from an IPP message.
2257 *
2258 * @since CUPS 1.6/OS X 10.8@
2259 */
2260
2261 int /* O - Major version number or -1 on error */
2262 ippGetVersion(ipp_t *ipp, /* I - IPP message */
2263 int *minor) /* O - Minor version number or @code NULL@ */
2264 {
2265 /*
2266 * Range check input...
2267 */
2268
2269 if (!ipp)
2270 {
2271 if (minor)
2272 *minor = -1;
2273
2274 return (-1);
2275 }
2276
2277 /*
2278 * Return the value...
2279 */
2280
2281 if (minor)
2282 *minor = ipp->request.any.version[1];
2283
2284 return (ipp->request.any.version[0]);
2285 }
2286
2287
2288 /*
2289 * 'ippLength()' - Compute the length of an IPP message.
2290 */
2291
2292 size_t /* O - Size of IPP message */
2293 ippLength(ipp_t *ipp) /* I - IPP message */
2294 {
2295 return (ipp_length(ipp, 0));
2296 }
2297
2298
2299 /*
2300 * 'ippNextAttribute()' - Return the next attribute in the message.
2301 *
2302 * @since CUPS 1.6/OS X 10.8@
2303 */
2304
2305 ipp_attribute_t * /* O - Next attribute or @code NULL@ if none */
2306 ippNextAttribute(ipp_t *ipp) /* I - IPP message */
2307 {
2308 /*
2309 * Range check input...
2310 */
2311
2312 if (!ipp || !ipp->current)
2313 return (NULL);
2314
2315 /*
2316 * Return the next attribute...
2317 */
2318
2319 return (ipp->current = ipp->current->next);
2320 }
2321
2322
2323 /*
2324 * 'ippNew()' - Allocate a new IPP message.
2325 */
2326
2327 ipp_t * /* O - New IPP message */
2328 ippNew(void)
2329 {
2330 ipp_t *temp; /* New IPP message */
2331
2332
2333 DEBUG_puts("ippNew()");
2334
2335 if ((temp = (ipp_t *)calloc(1, sizeof(ipp_t))) != NULL)
2336 {
2337 /*
2338 * Default to IPP 2.0...
2339 */
2340
2341 temp->request.any.version[0] = 2;
2342 temp->request.any.version[1] = 0;
2343 temp->use = 1;
2344 }
2345
2346 DEBUG_printf(("1ippNew: Returning %p", temp));
2347
2348 return (temp);
2349 }
2350
2351
2352 /*
2353 * 'ippNewRequest()' - Allocate a new IPP request message.
2354 *
2355 * The new request message is initialized with the attributes-charset and
2356 * attributes-natural-language attributes added. The
2357 * attributes-natural-language value is derived from the current locale.
2358 *
2359 * @since CUPS 1.2/OS X 10.5@
2360 */
2361
2362 ipp_t * /* O - IPP request message */
2363 ippNewRequest(ipp_op_t op) /* I - Operation code */
2364 {
2365 ipp_t *request; /* IPP request message */
2366 cups_lang_t *language; /* Current language localization */
2367 static int request_id = 0; /* Current request ID */
2368 static _cups_mutex_t request_mutex = _CUPS_MUTEX_INITIALIZER;
2369 /* Mutex for request ID */
2370
2371
2372 DEBUG_printf(("ippNewRequest(op=%02x(%s))", op, ippOpString(op)));
2373
2374 /*
2375 * Create a new IPP message...
2376 */
2377
2378 if ((request = ippNew()) == NULL)
2379 return (NULL);
2380
2381 /*
2382 * Set the operation and request ID...
2383 */
2384
2385 _cupsMutexLock(&request_mutex);
2386
2387 request->request.op.operation_id = op;
2388 request->request.op.request_id = ++request_id;
2389
2390 _cupsMutexUnlock(&request_mutex);
2391
2392 /*
2393 * Use UTF-8 as the character set...
2394 */
2395
2396 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
2397 "attributes-charset", NULL, "utf-8");
2398
2399 /*
2400 * Get the language from the current locale...
2401 */
2402
2403 language = cupsLangDefault();
2404
2405 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
2406 "attributes-natural-language", NULL, language->language);
2407
2408 /*
2409 * Return the new request...
2410 */
2411
2412 return (request);
2413 }
2414
2415
2416 /*
2417 * 'ippRead()' - Read data for an IPP message from a HTTP connection.
2418 */
2419
2420 ipp_state_t /* O - Current state */
2421 ippRead(http_t *http, /* I - HTTP connection */
2422 ipp_t *ipp) /* I - IPP data */
2423 {
2424 DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT,
2425 http, ipp, CUPS_LLCAST (http ? http->data_remaining : -1)));
2426
2427 if (!http)
2428 return (IPP_ERROR);
2429
2430 DEBUG_printf(("2ippRead: http->state=%d, http->used=%d", http->state,
2431 http->used));
2432
2433 return (ippReadIO(http, (ipp_iocb_t)ipp_read_http, http->blocking, NULL,
2434 ipp));
2435 }
2436
2437
2438 /*
2439 * 'ippReadFile()' - Read data for an IPP message from a file.
2440 *
2441 * @since CUPS 1.1.19/OS X 10.3@
2442 */
2443
2444 ipp_state_t /* O - Current state */
2445 ippReadFile(int fd, /* I - HTTP data */
2446 ipp_t *ipp) /* I - IPP data */
2447 {
2448 DEBUG_printf(("ippReadFile(fd=%d, ipp=%p)", fd, ipp));
2449
2450 return (ippReadIO(&fd, (ipp_iocb_t)ipp_read_file, 1, NULL, ipp));
2451 }
2452
2453
2454 /*
2455 * 'ippReadIO()' - Read data for an IPP message.
2456 *
2457 * @since CUPS 1.2/OS X 10.5@
2458 */
2459
2460 ipp_state_t /* O - Current state */
2461 ippReadIO(void *src, /* I - Data source */
2462 ipp_iocb_t cb, /* I - Read callback function */
2463 int blocking, /* I - Use blocking IO? */
2464 ipp_t *parent, /* I - Parent request, if any */
2465 ipp_t *ipp) /* I - IPP data */
2466 {
2467 int n; /* Length of data */
2468 unsigned char *buffer, /* Data buffer */
2469 string[IPP_MAX_NAME],
2470 /* Small string buffer */
2471 *bufptr; /* Pointer into buffer */
2472 ipp_attribute_t *attr; /* Current attribute */
2473 ipp_tag_t tag; /* Current tag */
2474 ipp_tag_t value_tag; /* Current value tag */
2475 _ipp_value_t *value; /* Current value */
2476
2477
2478 DEBUG_printf(("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
2479 src, cb, blocking, parent, ipp));
2480 DEBUG_printf(("2ippReadIO: ipp->state=%d", ipp ? ipp->state : IPP_ERROR));
2481
2482 if (!src || !ipp)
2483 return (IPP_ERROR);
2484
2485 if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
2486 {
2487 DEBUG_puts("1ippReadIO: Unable to get read buffer.");
2488 return (IPP_ERROR);
2489 }
2490
2491 switch (ipp->state)
2492 {
2493 case IPP_IDLE :
2494 ipp->state ++; /* Avoid common problem... */
2495
2496 case IPP_HEADER :
2497 if (parent == NULL)
2498 {
2499 /*
2500 * Get the request header...
2501 */
2502
2503 if ((*cb)(src, buffer, 8) < 8)
2504 {
2505 DEBUG_puts("1ippReadIO: Unable to read header.");
2506 _cupsBufferRelease((char *)buffer);
2507 return (IPP_ERROR);
2508 }
2509
2510 /*
2511 * Then copy the request header over...
2512 */
2513
2514 ipp->request.any.version[0] = buffer[0];
2515 ipp->request.any.version[1] = buffer[1];
2516 ipp->request.any.op_status = (buffer[2] << 8) | buffer[3];
2517 ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) |
2518 buffer[6]) << 8) | buffer[7];
2519
2520 DEBUG_printf(("2ippReadIO: version=%d.%d", buffer[0], buffer[1]));
2521 DEBUG_printf(("2ippReadIO: op_status=%04x",
2522 ipp->request.any.op_status));
2523 DEBUG_printf(("2ippReadIO: request_id=%d",
2524 ipp->request.any.request_id));
2525 }
2526
2527 ipp->state = IPP_ATTRIBUTE;
2528 ipp->current = NULL;
2529 ipp->curtag = IPP_TAG_ZERO;
2530 ipp->prev = ipp->last;
2531
2532 /*
2533 * If blocking is disabled, stop here...
2534 */
2535
2536 if (!blocking)
2537 break;
2538
2539 case IPP_ATTRIBUTE :
2540 for (;;)
2541 {
2542 if ((*cb)(src, buffer, 1) < 1)
2543 {
2544 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
2545 _cupsBufferRelease((char *)buffer);
2546 return (IPP_ERROR);
2547 }
2548
2549 DEBUG_printf(("2ippReadIO: ipp->current=%p, ipp->prev=%p",
2550 ipp->current, ipp->prev));
2551
2552 /*
2553 * Read this attribute...
2554 */
2555
2556 tag = (ipp_tag_t)buffer[0];
2557 if (tag == IPP_TAG_EXTENSION)
2558 {
2559 /*
2560 * Read 32-bit "extension" tag...
2561 */
2562
2563 if ((*cb)(src, buffer, 4) < 1)
2564 {
2565 DEBUG_puts("1ippReadIO: Callback returned EOF/error");
2566 _cupsBufferRelease((char *)buffer);
2567 return (IPP_ERROR);
2568 }
2569
2570 tag = (ipp_tag_t)((((((buffer[0] << 8) | buffer[1]) << 8) |
2571 buffer[2]) << 8) | buffer[3]);
2572
2573 if (tag & IPP_TAG_COPY)
2574 {
2575 /*
2576 * Fail if the high bit is set in the tag...
2577 */
2578
2579 _cupsSetError(IPP_INTERNAL_ERROR, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
2580 DEBUG_printf(("1ippReadIO: bad name length %d.", n));
2581 _cupsBufferRelease((char *)buffer);
2582 return (IPP_ERROR);
2583 }
2584 }
2585
2586 if (tag == IPP_TAG_END)
2587 {
2588 /*
2589 * No more attributes left...
2590 */
2591
2592 DEBUG_puts("2ippReadIO: IPP_TAG_END.");
2593
2594 ipp->state = IPP_DATA;
2595 break;
2596 }
2597 else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
2598 {
2599 /*
2600 * Group tag... Set the current group and continue...
2601 */
2602
2603 if (ipp->curtag == tag)
2604 ipp->prev = ippAddSeparator(ipp);
2605 else if (ipp->current)
2606 ipp->prev = ipp->current;
2607
2608 ipp->curtag = tag;
2609 ipp->current = NULL;
2610 DEBUG_printf(("2ippReadIO: group tag=%x(%s), ipp->prev=%p", tag,
2611 ippTagString(tag), ipp->prev));
2612 continue;
2613 }
2614
2615 DEBUG_printf(("2ippReadIO: value tag=%x(%s)", tag,
2616 ippTagString(tag)));
2617
2618 /*
2619 * Get the name...
2620 */
2621
2622 if ((*cb)(src, buffer, 2) < 2)
2623 {
2624 DEBUG_puts("1ippReadIO: unable to read name length.");
2625 _cupsBufferRelease((char *)buffer);
2626 return (IPP_ERROR);
2627 }
2628
2629 n = (buffer[0] << 8) | buffer[1];
2630
2631 if (n >= IPP_BUF_SIZE)
2632 {
2633 _cupsSetError(IPP_INTERNAL_ERROR, _("IPP name larger than 32767 bytes."), 1);
2634 DEBUG_printf(("1ippReadIO: bad name length %d.", n));
2635 _cupsBufferRelease((char *)buffer);
2636 return (IPP_ERROR);
2637 }
2638
2639 DEBUG_printf(("2ippReadIO: name length=%d", n));
2640
2641 if (n == 0 && tag != IPP_TAG_MEMBERNAME &&
2642 tag != IPP_TAG_END_COLLECTION)
2643 {
2644 /*
2645 * More values for current attribute...
2646 */
2647
2648 if (ipp->current == NULL)
2649 {
2650 _cupsSetError(IPP_INTERNAL_ERROR, _("IPP attribute has no name."), 1);
2651 DEBUG_puts("1ippReadIO: Attribute without name and no current.");
2652 _cupsBufferRelease((char *)buffer);
2653 return (IPP_ERROR);
2654 }
2655
2656 attr = ipp->current;
2657 value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_MASK);
2658
2659 /*
2660 * Make sure we aren't adding a new value of a different
2661 * type...
2662 */
2663
2664 if (value_tag == IPP_TAG_ZERO)
2665 {
2666 /*
2667 * Setting the value of a collection member...
2668 */
2669
2670 attr->value_tag = tag;
2671 }
2672 else if (value_tag == IPP_TAG_TEXTLANG ||
2673 value_tag == IPP_TAG_NAMELANG ||
2674 (value_tag >= IPP_TAG_TEXT &&
2675 value_tag <= IPP_TAG_MIMETYPE))
2676 {
2677 /*
2678 * String values can sometimes come across in different
2679 * forms; accept sets of differing values...
2680 */
2681
2682 if (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG &&
2683 (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE) &&
2684 tag != IPP_TAG_NOVALUE)
2685 {
2686 _cupsSetError(IPP_INTERNAL_ERROR,
2687 _("IPP 1setOf attribute with incompatible value "
2688 "tags."), 1);
2689 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
2690 value_tag, ippTagString(value_tag), tag,
2691 ippTagString(tag)));
2692 _cupsBufferRelease((char *)buffer);
2693 return (IPP_ERROR);
2694 }
2695
2696 if (value_tag != tag)
2697 {
2698 DEBUG_printf(("1ippReadIO: Converting %s attribute from %s to %s.",
2699 attr->name, ippTagString(value_tag), ippTagString(tag)));
2700 ippSetValueTag(ipp, &attr, tag);
2701 }
2702 }
2703 else if (value_tag == IPP_TAG_INTEGER ||
2704 value_tag == IPP_TAG_RANGE)
2705 {
2706 /*
2707 * Integer and rangeOfInteger values can sometimes be mixed; accept
2708 * sets of differing values...
2709 */
2710
2711 if (tag != IPP_TAG_INTEGER && tag != IPP_TAG_RANGE)
2712 {
2713 _cupsSetError(IPP_INTERNAL_ERROR,
2714 _("IPP 1setOf attribute with incompatible value "
2715 "tags."), 1);
2716 DEBUG_printf(("1ippReadIO: 1setOf value tag %x(%s) != %x(%s)",
2717 value_tag, ippTagString(value_tag), tag,
2718 ippTagString(tag)));
2719 _cupsBufferRelease((char *)buffer);
2720 return (IPP_ERROR);
2721 }
2722
2723 if (value_tag == IPP_TAG_INTEGER && tag == IPP_TAG_RANGE)
2724 {
2725 /*
2726 * Convert integer values to rangeOfInteger values...
2727 */
2728
2729 DEBUG_printf(("1ippReadIO: Converting %s attribute to "
2730 "rangeOfInteger.", attr->name));
2731 ippSetValueTag(ipp, &attr, IPP_TAG_RANGE);
2732 }
2733 }
2734 else if (value_tag != tag)
2735 {
2736 _cupsSetError(IPP_INTERNAL_ERROR,
2737 _("IPP 1setOf attribute with incompatible value "
2738 "tags."), 1);
2739 DEBUG_printf(("1ippReadIO: value tag %x(%s) != %x(%s)",
2740 value_tag, ippTagString(value_tag), tag,
2741 ippTagString(tag)));
2742 _cupsBufferRelease((char *)buffer);
2743 return (IPP_ERROR);
2744 }
2745
2746 /*
2747 * Finally, reallocate the attribute array as needed...
2748 */
2749
2750 if ((value = ipp_set_value(ipp, &attr, attr->num_values)) == NULL)
2751 {
2752 _cupsBufferRelease((char *)buffer);
2753 return (IPP_ERROR);
2754 }
2755 }
2756 else if (tag == IPP_TAG_MEMBERNAME)
2757 {
2758 /*
2759 * Name must be length 0!
2760 */
2761
2762 if (n)
2763 {
2764 _cupsSetError(IPP_INTERNAL_ERROR, _("IPP member name is not empty."), 1);
2765 DEBUG_puts("1ippReadIO: member name not empty.");
2766 _cupsBufferRelease((char *)buffer);
2767 return (IPP_ERROR);
2768 }
2769
2770 if (ipp->current)
2771 ipp->prev = ipp->current;
2772
2773 attr = ipp->current = ipp_add_attr(ipp, NULL, ipp->curtag, IPP_TAG_ZERO, 1);
2774
2775 DEBUG_printf(("2ippReadIO: membername, ipp->current=%p, ipp->prev=%p",
2776 ipp->current, ipp->prev));
2777
2778 value = attr->values;
2779 }
2780 else if (tag != IPP_TAG_END_COLLECTION)
2781 {
2782 /*
2783 * New attribute; read the name and add it...
2784 */
2785
2786 if ((*cb)(src, buffer, n) < n)
2787 {
2788 DEBUG_puts("1ippReadIO: unable to read name.");
2789 _cupsBufferRelease((char *)buffer);
2790 return (IPP_ERROR);
2791 }
2792
2793 buffer[n] = '\0';
2794
2795 if (ipp->current)
2796 ipp->prev = ipp->current;
2797
2798 if ((attr = ipp->current = ipp_add_attr(ipp, (char *)buffer, ipp->curtag, tag,
2799 1)) == NULL)
2800 {
2801 _cupsSetHTTPError(HTTP_ERROR);
2802 DEBUG_puts("1ippReadIO: unable to allocate attribute.");
2803 _cupsBufferRelease((char *)buffer);
2804 return (IPP_ERROR);
2805 }
2806
2807 DEBUG_printf(("2ippReadIO: name=\"%s\", ipp->current=%p, "
2808 "ipp->prev=%p", buffer, ipp->current, ipp->prev));
2809
2810 value = attr->values;
2811 }
2812 else
2813 {
2814 attr = NULL;
2815 value = NULL;
2816 }
2817
2818 if ((*cb)(src, buffer, 2) < 2)
2819 {
2820 DEBUG_puts("1ippReadIO: unable to read value length.");
2821 _cupsBufferRelease((char *)buffer);
2822 return (IPP_ERROR);
2823 }
2824
2825 n = (buffer[0] << 8) | buffer[1];
2826 DEBUG_printf(("2ippReadIO: value length=%d", n));
2827
2828 if (n >= IPP_BUF_SIZE)
2829 {
2830 _cupsSetError(IPP_INTERNAL_ERROR,
2831 _("IPP value larger than 32767 bytes."), 1);
2832 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
2833 _cupsBufferRelease((char *)buffer);
2834 return (IPP_ERROR);
2835 }
2836
2837 switch (tag)
2838 {
2839 case IPP_TAG_INTEGER :
2840 case IPP_TAG_ENUM :
2841 if (n != 4)
2842 {
2843 if (tag == IPP_TAG_INTEGER)
2844 _cupsSetError(IPP_INTERNAL_ERROR,
2845 _("IPP integer value not 4 bytes."), 1);
2846 else
2847 _cupsSetError(IPP_INTERNAL_ERROR,
2848 _("IPP enum value not 4 bytes."), 1);
2849 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
2850 _cupsBufferRelease((char *)buffer);
2851 return (IPP_ERROR);
2852 }
2853
2854 if ((*cb)(src, buffer, 4) < 4)
2855 {
2856 DEBUG_puts("1ippReadIO: Unable to read integer value.");
2857 _cupsBufferRelease((char *)buffer);
2858 return (IPP_ERROR);
2859 }
2860
2861 n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
2862 buffer[3];
2863
2864 if (attr->value_tag == IPP_TAG_RANGE)
2865 value->range.lower = value->range.upper = n;
2866 else
2867 value->integer = n;
2868 break;
2869
2870 case IPP_TAG_BOOLEAN :
2871 if (n != 1)
2872 {
2873 _cupsSetError(IPP_INTERNAL_ERROR, _("IPP boolean value not 1 byte."),
2874 1);
2875 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
2876 _cupsBufferRelease((char *)buffer);
2877 return (IPP_ERROR);
2878 }
2879
2880 if ((*cb)(src, buffer, 1) < 1)
2881 {
2882 DEBUG_puts("1ippReadIO: Unable to read boolean value.");
2883 _cupsBufferRelease((char *)buffer);
2884 return (IPP_ERROR);
2885 }
2886
2887 value->boolean = buffer[0];
2888 break;
2889
2890 case IPP_TAG_NOVALUE :
2891 case IPP_TAG_NOTSETTABLE :
2892 case IPP_TAG_DELETEATTR :
2893 case IPP_TAG_ADMINDEFINE :
2894 /*
2895 * These value types are not supposed to have values, however
2896 * some vendors (Brother) do not implement IPP correctly and so
2897 * we need to map non-empty values to text...
2898 */
2899
2900 if (attr->value_tag == tag)
2901 {
2902 if (n == 0)
2903 break;
2904
2905 attr->value_tag = IPP_TAG_TEXT;
2906 }
2907
2908 case IPP_TAG_TEXT :
2909 case IPP_TAG_NAME :
2910 case IPP_TAG_KEYWORD :
2911 case IPP_TAG_URI :
2912 case IPP_TAG_URISCHEME :
2913 case IPP_TAG_CHARSET :
2914 case IPP_TAG_LANGUAGE :
2915 case IPP_TAG_MIMETYPE :
2916 if ((*cb)(src, buffer, n) < n)
2917 {
2918 DEBUG_puts("1ippReadIO: unable to read string value.");
2919 _cupsBufferRelease((char *)buffer);
2920 return (IPP_ERROR);
2921 }
2922
2923 buffer[n] = '\0';
2924 value->string.text = _cupsStrAlloc((char *)buffer);
2925 DEBUG_printf(("2ippReadIO: value=\"%s\"", value->string.text));
2926 break;
2927
2928 case IPP_TAG_DATE :
2929 if (n != 11)
2930 {
2931 _cupsSetError(IPP_INTERNAL_ERROR, _("IPP date value not 11 bytes."), 1);
2932 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
2933 _cupsBufferRelease((char *)buffer);
2934 return (IPP_ERROR);
2935 }
2936
2937 if ((*cb)(src, value->date, 11) < 11)
2938 {
2939 DEBUG_puts("1ippReadIO: Unable to read date value.");
2940 _cupsBufferRelease((char *)buffer);
2941 return (IPP_ERROR);
2942 }
2943 break;
2944
2945 case IPP_TAG_RESOLUTION :
2946 if (n != 9)
2947 {
2948 _cupsSetError(IPP_INTERNAL_ERROR,
2949 _("IPP resolution value not 9 bytes."), 1);
2950 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
2951 _cupsBufferRelease((char *)buffer);
2952 return (IPP_ERROR);
2953 }
2954
2955 if ((*cb)(src, buffer, 9) < 9)
2956 {
2957 DEBUG_puts("1ippReadIO: Unable to read resolution value.");
2958 _cupsBufferRelease((char *)buffer);
2959 return (IPP_ERROR);
2960 }
2961
2962 value->resolution.xres =
2963 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
2964 buffer[3];
2965 value->resolution.yres =
2966 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
2967 buffer[7];
2968 value->resolution.units =
2969 (ipp_res_t)buffer[8];
2970 break;
2971
2972 case IPP_TAG_RANGE :
2973 if (n != 8)
2974 {
2975 _cupsSetError(IPP_INTERNAL_ERROR,
2976 _("IPP rangeOfInteger value not 8 bytes."), 1);
2977 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
2978 _cupsBufferRelease((char *)buffer);
2979 return (IPP_ERROR);
2980 }
2981
2982 if ((*cb)(src, buffer, 8) < 8)
2983 {
2984 DEBUG_puts("1ippReadIO: Unable to read range value.");
2985 _cupsBufferRelease((char *)buffer);
2986 return (IPP_ERROR);
2987 }
2988
2989 value->range.lower =
2990 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
2991 buffer[3];
2992 value->range.upper =
2993 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
2994 buffer[7];
2995 break;
2996
2997 case IPP_TAG_TEXTLANG :
2998 case IPP_TAG_NAMELANG :
2999 if (n < 4)
3000 {
3001 if (tag == IPP_TAG_TEXTLANG)
3002 _cupsSetError(IPP_INTERNAL_ERROR,
3003 _("IPP textWithLanguage value less than "
3004 "minimum 4 bytes."), 1);
3005 else
3006 _cupsSetError(IPP_INTERNAL_ERROR,
3007 _("IPP nameWithLanguage value less than "
3008 "minimum 4 bytes."), 1);
3009 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
3010 _cupsBufferRelease((char *)buffer);
3011 return (IPP_ERROR);
3012 }
3013
3014 if ((*cb)(src, buffer, n) < n)
3015 {
3016 DEBUG_puts("1ippReadIO: Unable to read string w/language "
3017 "value.");
3018 _cupsBufferRelease((char *)buffer);
3019 return (IPP_ERROR);
3020 }
3021
3022 bufptr = buffer;
3023
3024 /*
3025 * text-with-language and name-with-language are composite
3026 * values:
3027 *
3028 * language-length
3029 * language
3030 * text-length
3031 * text
3032 */
3033
3034 n = (bufptr[0] << 8) | bufptr[1];
3035
3036 if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE) ||
3037 n >= sizeof(string))
3038 {
3039 _cupsSetError(IPP_INTERNAL_ERROR,
3040 _("IPP language length overflows value."), 1);
3041 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
3042 _cupsBufferRelease((char *)buffer);
3043 return (IPP_ERROR);
3044 }
3045
3046 memcpy(string, bufptr + 2, n);
3047 string[n] = '\0';
3048
3049 value->string.language = _cupsStrAlloc((char *)string);
3050
3051 bufptr += 2 + n;
3052 n = (bufptr[0] << 8) | bufptr[1];
3053
3054 if ((bufptr + 2 + n) >= (buffer + IPP_BUF_SIZE))
3055 {
3056 _cupsSetError(IPP_INTERNAL_ERROR,
3057 _("IPP string length overflows value."), 1);
3058 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
3059 _cupsBufferRelease((char *)buffer);
3060 return (IPP_ERROR);
3061 }
3062
3063 bufptr[2 + n] = '\0';
3064 value->string.text = _cupsStrAlloc((char *)bufptr + 2);
3065 break;
3066
3067 case IPP_TAG_BEGIN_COLLECTION :
3068 /*
3069 * Oh, boy, here comes a collection value, so read it...
3070 */
3071
3072 value->collection = ippNew();
3073
3074 if (n > 0)
3075 {
3076 _cupsSetError(IPP_INTERNAL_ERROR,
3077 _("IPP begCollection value not 0 bytes."), 1);
3078 DEBUG_puts("1ippReadIO: begCollection tag with value length "
3079 "> 0.");
3080 _cupsBufferRelease((char *)buffer);
3081 return (IPP_ERROR);
3082 }
3083
3084 if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_ERROR)
3085 {
3086 DEBUG_puts("1ippReadIO: Unable to read collection value.");
3087 _cupsBufferRelease((char *)buffer);
3088 return (IPP_ERROR);
3089 }
3090 break;
3091
3092 case IPP_TAG_END_COLLECTION :
3093 _cupsBufferRelease((char *)buffer);
3094
3095 if (n > 0)
3096 {
3097 _cupsSetError(IPP_INTERNAL_ERROR,
3098 _("IPP endCollection value not 0 bytes."), 1);
3099 DEBUG_puts("1ippReadIO: endCollection tag with value length "
3100 "> 0.");
3101 return (IPP_ERROR);
3102 }
3103
3104 DEBUG_puts("1ippReadIO: endCollection tag...");
3105 return (ipp->state = IPP_DATA);
3106
3107 case IPP_TAG_MEMBERNAME :
3108 /*
3109 * The value the name of the member in the collection, which
3110 * we need to carry over...
3111 */
3112
3113 if ((*cb)(src, buffer, n) < n)
3114 {
3115 DEBUG_puts("1ippReadIO: Unable to read member name value.");
3116 _cupsBufferRelease((char *)buffer);
3117 return (IPP_ERROR);
3118 }
3119
3120 buffer[n] = '\0';
3121 attr->name = _cupsStrAlloc((char *)buffer);
3122
3123 /*
3124 * Since collection members are encoded differently than
3125 * regular attributes, make sure we don't start with an
3126 * empty value...
3127 */
3128
3129 attr->num_values --;
3130
3131 DEBUG_printf(("2ippReadIO: member name=\"%s\"", attr->name));
3132 break;
3133
3134 default : /* Other unsupported values */
3135 value->unknown.length = n;
3136 if (n > 0)
3137 {
3138 if ((value->unknown.data = malloc(n)) == NULL)
3139 {
3140 _cupsSetHTTPError(HTTP_ERROR);
3141 DEBUG_puts("1ippReadIO: Unable to allocate value");
3142 _cupsBufferRelease((char *)buffer);
3143 return (IPP_ERROR);
3144 }
3145
3146 if ((*cb)(src, value->unknown.data, n) < n)
3147 {
3148 DEBUG_puts("1ippReadIO: Unable to read unsupported value.");
3149 _cupsBufferRelease((char *)buffer);
3150 return (IPP_ERROR);
3151 }
3152 }
3153 else
3154 value->unknown.data = NULL;
3155 break;
3156 }
3157
3158 /*
3159 * If blocking is disabled, stop here...
3160 */
3161
3162 if (!blocking)
3163 break;
3164 }
3165 break;
3166
3167 case IPP_DATA :
3168 break;
3169
3170 default :
3171 break; /* anti-compiler-warning-code */
3172 }
3173
3174 DEBUG_printf(("1ippReadIO: returning ipp->state=%d.", ipp->state));
3175 _cupsBufferRelease((char *)buffer);
3176
3177 return (ipp->state);
3178 }
3179
3180
3181 /*
3182 * 'ippSetBoolean()' - Set a boolean value in an attribute.
3183 *
3184 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3185 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3186 *
3187 * The @code attr@ parameter may be modified as a result of setting the value.
3188 *
3189 * The @code element@ parameter specifies which value to set from 0 to
3190 * @link ippGetCount(attr)@.
3191 *
3192 * @since CUPS 1.6/OS X 10.8@
3193 */
3194
3195 int /* O - 1 on success, 0 on failure */
3196 ippSetBoolean(ipp_t *ipp, /* IO - IPP message */
3197 ipp_attribute_t **attr, /* IO - IPP attribute */
3198 int element, /* I - Value number (0-based) */
3199 int boolvalue)/* I - Boolean value */
3200 {
3201 _ipp_value_t *value; /* Current value */
3202
3203
3204 /*
3205 * Range check input...
3206 */
3207
3208 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BOOLEAN ||
3209 element < 0 || element > (*attr)->num_values)
3210 return (0);
3211
3212 /*
3213 * Set the value and return...
3214 */
3215
3216 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3217 value->boolean = boolvalue;
3218
3219 return (value != NULL);
3220 }
3221
3222
3223 /*
3224 * 'ippSetCollection()' - Set a collection value in an attribute.
3225 *
3226 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3227 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3228 *
3229 * The @code attr@ parameter may be modified as a result of setting the value.
3230 *
3231 * The @code element@ parameter specifies which value to set from 0 to
3232 * @link ippGetCount(attr)@.
3233 *
3234 * @since CUPS 1.6/OS X 10.8@
3235 */
3236
3237 int /* O - 1 on success, 0 on failure */
3238 ippSetCollection(
3239 ipp_t *ipp, /* IO - IPP message */
3240 ipp_attribute_t **attr, /* IO - IPP attribute */
3241 int element, /* I - Value number (0-based) */
3242 ipp_t *colvalue) /* I - Collection value */
3243 {
3244 _ipp_value_t *value; /* Current value */
3245
3246
3247 /*
3248 * Range check input...
3249 */
3250
3251 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BEGIN_COLLECTION ||
3252 element < 0 || element > (*attr)->num_values || !colvalue)
3253 return (0);
3254
3255 /*
3256 * Set the value and return...
3257 */
3258
3259 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3260 {
3261 if (value->collection)
3262 ippDelete(value->collection);
3263
3264 value->collection = colvalue;
3265 colvalue->use ++;
3266 }
3267
3268 return (value != NULL);
3269 }
3270
3271
3272 /*
3273 * 'ippSetDate()' - Set a date value in an attribute.
3274 *
3275 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3276 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3277 *
3278 * The @code attr@ parameter may be modified as a result of setting the value.
3279 *
3280 * The @code element@ parameter specifies which value to set from 0 to
3281 * @link ippGetCount(attr)@.
3282 *
3283 * @since CUPS 1.6/OS X 10.8@
3284 */
3285
3286 int /* O - 1 on success, 0 on failure */
3287 ippSetDate(ipp_t *ipp, /* IO - IPP message */
3288 ipp_attribute_t **attr, /* IO - IPP attribute */
3289 int element, /* I - Value number (0-based) */
3290 const ipp_uchar_t *datevalue)/* I - Date value */
3291 {
3292 _ipp_value_t *value; /* Current value */
3293
3294
3295 /*
3296 * Range check input...
3297 */
3298
3299 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_DATE ||
3300 element < 0 || element > (*attr)->num_values || !datevalue)
3301 return (0);
3302
3303 /*
3304 * Set the value and return...
3305 */
3306
3307 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3308 memcpy(value->date, datevalue, sizeof(value->date));
3309
3310 return (value != NULL);
3311 }
3312
3313
3314 /*
3315 * 'ippSetGroupTag()' - Set the group tag of an attribute.
3316 *
3317 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3318 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3319 *
3320 * The @code attr@ parameter may be modified as a result of setting the value.
3321 *
3322 * The @code group@ parameter specifies the IPP attribute group tag: none
3323 * (@code IPP_TAG_ZERO@, for member attributes), document (@code IPP_TAG_DOCUMENT@),
3324 * event notification (@code IPP_TAG_EVENT_NOTIFICATION@), operation
3325 * (@code IPP_TAG_OPERATION@), printer (@code IPP_TAG_PRINTER@), subscription
3326 * (@code IPP_TAG_SUBSCRIPTION@), or unsupported (@code IPP_TAG_UNSUPPORTED_GROUP@).
3327 *
3328 * @since CUPS 1.6/OS X 10.8@
3329 */
3330
3331 int /* O - 1 on success, 0 on failure */
3332 ippSetGroupTag(
3333 ipp_t *ipp, /* IO - IPP message */
3334 ipp_attribute_t **attr, /* IO - Attribute */
3335 ipp_tag_t group_tag) /* I - Group tag */
3336 {
3337 /*
3338 * Range check input - group tag must be 0x01 to 0x0F, per RFC 2911...
3339 */
3340
3341 if (!ipp || !attr || group_tag < IPP_TAG_ZERO || group_tag == IPP_TAG_END ||
3342 group_tag >= IPP_TAG_UNSUPPORTED_VALUE)
3343 return (0);
3344
3345 /*
3346 * Set the group tag and return...
3347 */
3348
3349 (*attr)->group_tag = group_tag;
3350
3351 return (1);
3352 }
3353
3354
3355 /*
3356 * 'ippSetInteger()' - Set an integer or enum value in an attribute.
3357 *
3358 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3359 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3360 *
3361 * The @code attr@ parameter may be modified as a result of setting the value.
3362 *
3363 * The @code element@ parameter specifies which value to set from 0 to
3364 * @link ippGetCount(attr)@.
3365 *
3366 * @since CUPS 1.6/OS X 10.8@
3367 */
3368
3369 int /* O - 1 on success, 0 on failure */
3370 ippSetInteger(ipp_t *ipp, /* IO - IPP message */
3371 ipp_attribute_t **attr, /* IO - IPP attribute */
3372 int element, /* I - Value number (0-based) */
3373 int intvalue) /* I - Integer/enum value */
3374 {
3375 _ipp_value_t *value; /* Current value */
3376
3377
3378 /*
3379 * Range check input...
3380 */
3381
3382 if (!ipp || !attr || !*attr ||
3383 ((*attr)->value_tag != IPP_TAG_INTEGER && (*attr)->value_tag != IPP_TAG_ENUM) ||
3384 element < 0 || element > (*attr)->num_values)
3385 return (0);
3386
3387 /*
3388 * Set the value and return...
3389 */
3390
3391 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3392 value->integer = intvalue;
3393
3394 return (value != NULL);
3395 }
3396
3397
3398 /*
3399 * 'ippSetName()' - Set the name of an attribute.
3400 *
3401 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3402 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3403 *
3404 * The @code attr@ parameter may be modified as a result of setting the value.
3405 *
3406 * @since CUPS 1.6/OS X 10.8@
3407 */
3408
3409 int /* O - 1 on success, 0 on failure */
3410 ippSetName(ipp_t *ipp, /* IO - IPP message */
3411 ipp_attribute_t **attr, /* IO - IPP attribute */
3412 const char *name) /* I - Attribute name */
3413 {
3414 char *temp; /* Temporary name value */
3415
3416
3417 /*
3418 * Range check input...
3419 */
3420
3421 if (!ipp || !attr || !*attr)
3422 return (0);
3423
3424 /*
3425 * Set the value and return...
3426 */
3427
3428 if ((temp = _cupsStrAlloc(name)) != NULL)
3429 {
3430 if ((*attr)->name)
3431 _cupsStrFree((*attr)->name);
3432
3433 (*attr)->name = temp;
3434 }
3435
3436 return (temp != NULL);
3437 }
3438
3439
3440 /*
3441 * 'ippSetOperation()' - Set the operation ID in an IPP request message.
3442 *
3443 * The @code ipp@ parameter refers to an IPP message previously created using the
3444 * @link ippNew@ or @link ippNewRequest@ functions.
3445 *
3446 * @since CUPS 1.6/OS X 10.8@
3447 */
3448
3449 int /* O - 1 on success, 0 on failure */
3450 ippSetOperation(ipp_t *ipp, /* I - IPP request message */
3451 ipp_op_t op) /* I - Operation ID */
3452 {
3453 /*
3454 * Range check input...
3455 */
3456
3457 if (!ipp)
3458 return (0);
3459
3460 /*
3461 * Set the operation and return...
3462 */
3463
3464 ipp->request.op.operation_id = op;
3465
3466 return (1);
3467 }
3468
3469
3470 /*
3471 * 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
3472 *
3473 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3474 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3475 *
3476 * The @code attr@ parameter may be modified as a result of setting the value.
3477 *
3478 * The @code element@ parameter specifies which value to set from 0 to
3479 * @link ippGetCount(attr)@.
3480 *
3481 * @since CUPS 1.6/OS X 10.8@
3482 */
3483
3484 int /* O - 1 on success, 0 on failure */
3485 ippSetRange(ipp_t *ipp, /* IO - IPP message */
3486 ipp_attribute_t **attr, /* IO - IPP attribute */
3487 int element, /* I - Value number (0-based) */
3488 int lowervalue, /* I - Lower bound for range */
3489 int uppervalue) /* I - Upper bound for range */
3490 {
3491 _ipp_value_t *value; /* Current value */
3492
3493
3494 /*
3495 * Range check input...
3496 */
3497
3498 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_RANGE ||
3499 element < 0 || element > (*attr)->num_values || lowervalue > uppervalue)
3500 return (0);
3501
3502 /*
3503 * Set the value and return...
3504 */
3505
3506 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3507 {
3508 value->range.lower = lowervalue;
3509 value->range.upper = uppervalue;
3510 }
3511
3512 return (value != NULL);
3513 }
3514
3515
3516 /*
3517 * 'ippSetRequestId()' - Set the request ID in an IPP message.
3518 *
3519 * The @code ipp@ parameter refers to an IPP message previously created using the
3520 * @link ippNew@ or @link ippNewRequest@ functions.
3521 *
3522 * The @code request_id@ parameter must be greater than 0.
3523 *
3524 * @since CUPS 1.6/OS X 10.8@
3525 */
3526
3527 int /* O - 1 on success, 0 on failure */
3528 ippSetRequestId(ipp_t *ipp, /* I - IPP message */
3529 int request_id) /* I - Request ID */
3530 {
3531 /*
3532 * Range check input; not checking request_id values since ipptool wants to send
3533 * invalid values for conformance testing and a bad request_id does not affect the
3534 * encoding of a message...
3535 */
3536
3537 if (!ipp)
3538 return (0);
3539
3540 /*
3541 * Set the request ID and return...
3542 */
3543
3544 ipp->request.any.request_id = request_id;
3545
3546 return (1);
3547 }
3548
3549
3550 /*
3551 * 'ippSetResolution()' - Set a resolution value in an attribute.
3552 *
3553 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3554 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3555 *
3556 * The @code attr@ parameter may be modified as a result of setting the value.
3557 *
3558 * The @code element@ parameter specifies which value to set from 0 to
3559 * @link ippGetCount(attr)@.
3560 *
3561 * @since CUPS 1.6/OS X 10.8@
3562 */
3563
3564 int /* O - 1 on success, 0 on failure */
3565 ippSetResolution(
3566 ipp_t *ipp, /* IO - IPP message */
3567 ipp_attribute_t **attr, /* IO - IPP attribute */
3568 int element, /* I - Value number (0-based) */
3569 ipp_res_t unitsvalue, /* I - Resolution units */
3570 int xresvalue, /* I - Horizontal/cross feed resolution */
3571 int yresvalue) /* I - Vertical/feed resolution */
3572 {
3573 _ipp_value_t *value; /* Current value */
3574
3575
3576 /*
3577 * Range check input...
3578 */
3579
3580 if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_RESOLUTION ||
3581 element < 0 || element > (*attr)->num_values || xresvalue <= 0 || yresvalue <= 0 ||
3582 unitsvalue < IPP_RES_PER_INCH || unitsvalue > IPP_RES_PER_CM)
3583 return (0);
3584
3585 /*
3586 * Set the value and return...
3587 */
3588
3589 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3590 {
3591 value->resolution.units = unitsvalue;
3592 value->resolution.xres = xresvalue;
3593 value->resolution.yres = yresvalue;
3594 }
3595
3596 return (value != NULL);
3597 }
3598
3599
3600 /*
3601 * 'ippSetState()' - Set the current state of the IPP message.
3602 *
3603 * @since CUPS 1.6/OS X 10.8@
3604 */
3605
3606 int /* O - 1 on success, 0 on failure */
3607 ippSetState(ipp_t *ipp, /* I - IPP message */
3608 ipp_state_t state) /* I - IPP state value */
3609 {
3610 /*
3611 * Range check input...
3612 */
3613
3614 if (!ipp)
3615 return (0);
3616
3617 /*
3618 * Set the state and return...
3619 */
3620
3621 ipp->state = state;
3622 ipp->current = NULL;
3623
3624 return (1);
3625 }
3626
3627
3628 /*
3629 * 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
3630 *
3631 * The @code ipp@ parameter refers to an IPP message previously created using the
3632 * @link ippNew@ or @link ippNewRequest@ functions.
3633 *
3634 * @since CUPS 1.6/OS X 10.8@
3635 */
3636
3637 int /* O - 1 on success, 0 on failure */
3638 ippSetStatusCode(ipp_t *ipp, /* I - IPP response or event message */
3639 ipp_status_t status) /* I - Status code */
3640 {
3641 /*
3642 * Range check input...
3643 */
3644
3645 if (!ipp)
3646 return (0);
3647
3648 /*
3649 * Set the status code and return...
3650 */
3651
3652 ipp->request.status.status_code = status;
3653
3654 return (1);
3655 }
3656
3657
3658 /*
3659 * 'ippSetString()' - Set a string value in an attribute.
3660 *
3661 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3662 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3663 *
3664 * The @code attr@ parameter may be modified as a result of setting the value.
3665 *
3666 * The @code element@ parameter specifies which value to set from 0 to
3667 * @link ippGetCount(attr)@.
3668 *
3669 * @since CUPS 1.6/OS X 10.8@
3670 */
3671
3672 int /* O - 1 on success, 0 on failure */
3673 ippSetString(ipp_t *ipp, /* IO - IPP message */
3674 ipp_attribute_t **attr, /* IO - IPP attribute */
3675 int element, /* I - Value number (0-based) */
3676 const char *strvalue) /* I - String value */
3677 {
3678 char *temp; /* Temporary string */
3679 _ipp_value_t *value; /* Current value */
3680
3681
3682 /*
3683 * Range check input...
3684 */
3685
3686 if (!ipp || !attr || !*attr ||
3687 ((*attr)->value_tag != IPP_TAG_TEXTLANG &&
3688 (*attr)->value_tag != IPP_TAG_NAMELANG &&
3689 ((*attr)->value_tag < IPP_TAG_TEXT ||
3690 (*attr)->value_tag > IPP_TAG_MIMETYPE)) ||
3691 element < 0 || element > (*attr)->num_values || !strvalue)
3692 return (0);
3693
3694 /*
3695 * Set the value and return...
3696 */
3697
3698 if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3699 {
3700 if (element > 0)
3701 value->string.language = (*attr)->values[0].string.language;
3702
3703 if ((int)((*attr)->value_tag) & IPP_TAG_COPY)
3704 value->string.text = (char *)strvalue;
3705 else if ((temp = _cupsStrAlloc(strvalue)) != NULL)
3706 {
3707 if (value->string.text)
3708 _cupsStrFree(value->string.text);
3709
3710 value->string.text = temp;
3711 }
3712 else
3713 return (0);
3714 }
3715
3716 return (value != NULL);
3717 }
3718
3719
3720 /*
3721 * 'ippSetValueTag()' - Set the value tag of an attribute.
3722 *
3723 * The @code ipp@ parameter refers to the IPP message containing the attribute that was
3724 * previously created using the @link ippNew@ or @link ippNewRequest@ functions.
3725 *
3726 * The @code attr@ parameter may be modified as a result of setting the value.
3727 *
3728 * Integer (@code IPP_TAG_INTEGER@) values can be promoted to rangeOfInteger
3729 * (@code IPP_TAG_RANGE@) values, the various string tags can be promoted to name
3730 * (@code IPP_TAG_NAME@) or nameWithLanguage (@code IPP_TAG_NAMELANG@) values, text
3731 * (@code IPP_TAG_TEXT@) values can be promoted to textWithLanguage
3732 * (@code IPP_TAG_TEXTLANG@) values, and all values can be demoted to the various
3733 * out-of-band value tags such as no-value (@code IPP_TAG_NOVALUE@). All other changes
3734 * will be rejected.
3735 *
3736 * Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language
3737 * code in the "attributes-natural-language" attribute or, if not present, the language
3738 * code for the current locale.
3739 *
3740 * @since CUPS 1.6/OS X 10.8@
3741 */
3742
3743 int /* O - 1 on success, 0 on failure */
3744 ippSetValueTag(
3745 ipp_t *ipp, /* IO - IPP message */
3746 ipp_attribute_t **attr, /* IO - IPP attribute */
3747 ipp_tag_t value_tag) /* I - Value tag */
3748 {
3749 int i; /* Looping var */
3750 _ipp_value_t *value; /* Current value */
3751 int integer; /* Current integer value */
3752 cups_lang_t *language; /* Current language */
3753 char code[32]; /* Language code */
3754 ipp_tag_t temp_tag; /* Temporary value tag */
3755
3756
3757 /*
3758 * Range check input...
3759 */
3760
3761 if (!ipp || !attr)
3762 return (0);
3763
3764 /*
3765 * If there is no change, return immediately...
3766 */
3767
3768 if (value_tag == (*attr)->value_tag)
3769 return (1);
3770
3771 /*
3772 * Otherwise implement changes as needed...
3773 */
3774
3775 temp_tag = (ipp_tag_t)((int)((*attr)->value_tag) & IPP_TAG_MASK);
3776
3777 switch (value_tag)
3778 {
3779 case IPP_TAG_UNSUPPORTED_VALUE :
3780 case IPP_TAG_DEFAULT :
3781 case IPP_TAG_UNKNOWN :
3782 case IPP_TAG_NOVALUE :
3783 case IPP_TAG_NOTSETTABLE :
3784 case IPP_TAG_DELETEATTR :
3785 case IPP_TAG_ADMINDEFINE :
3786 /*
3787 * Free any existing values...
3788 */
3789
3790 if ((*attr)->num_values > 0)
3791 ipp_free_values(*attr, 0, (*attr)->num_values);
3792
3793 /*
3794 * Set out-of-band value...
3795 */
3796
3797 (*attr)->value_tag = value_tag;
3798 break;
3799
3800 case IPP_TAG_RANGE :
3801 if (temp_tag != IPP_TAG_INTEGER)
3802 return (0);
3803
3804 for (i = (*attr)->num_values, value = (*attr)->values;
3805 i > 0;
3806 i --, value ++)
3807 {
3808 integer = value->integer;
3809 value->range.lower = value->range.upper = integer;
3810 }
3811
3812 (*attr)->value_tag = IPP_TAG_RANGE;
3813 break;
3814
3815 case IPP_TAG_NAME :
3816 if (temp_tag != IPP_TAG_KEYWORD && temp_tag != IPP_TAG_URI &&
3817 temp_tag != IPP_TAG_URISCHEME && temp_tag != IPP_TAG_LANGUAGE &&
3818 temp_tag != IPP_TAG_MIMETYPE)
3819 return (0);
3820
3821 (*attr)->value_tag = (ipp_tag_t)(IPP_TAG_NAME | ((*attr)->value_tag & IPP_TAG_COPY));
3822 break;
3823
3824 case IPP_TAG_NAMELANG :
3825 case IPP_TAG_TEXTLANG :
3826 if (value_tag == IPP_TAG_NAMELANG &&
3827 (temp_tag != IPP_TAG_NAME && temp_tag != IPP_TAG_KEYWORD &&
3828 temp_tag != IPP_TAG_URI && temp_tag != IPP_TAG_URISCHEME &&
3829 temp_tag != IPP_TAG_LANGUAGE && temp_tag != IPP_TAG_MIMETYPE))
3830 return (0);
3831
3832 if (value_tag == IPP_TAG_TEXTLANG && temp_tag != IPP_TAG_TEXT)
3833 return (0);
3834
3835 if (ipp->attrs && ipp->attrs->next && ipp->attrs->next->name &&
3836 !strcmp(ipp->attrs->next->name, "attributes-natural-language"))
3837 {
3838 /*
3839 * Use the language code from the IPP message...
3840 */
3841
3842 (*attr)->values[0].string.language =
3843 _cupsStrAlloc(ipp->attrs->next->values[0].string.text);
3844 }
3845 else
3846 {
3847 /*
3848 * Otherwise, use the language code corresponding to the locale...
3849 */
3850
3851 language = cupsLangDefault();
3852 (*attr)->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language->language,
3853 code,
3854 sizeof(code)));
3855 }
3856
3857 for (i = (*attr)->num_values - 1, value = (*attr)->values + 1;
3858 i > 0;
3859 i --, value ++)
3860 value->string.language = (*attr)->values[0].string.language;
3861
3862 if ((int)(*attr)->value_tag & IPP_TAG_COPY)
3863 {
3864 /*
3865 * Make copies of all values...
3866 */
3867
3868 for (i = (*attr)->num_values, value = (*attr)->values;
3869 i > 0;
3870 i --, value ++)
3871 value->string.text = _cupsStrAlloc(value->string.text);
3872 }
3873
3874 (*attr)->value_tag = IPP_TAG_NAMELANG;
3875 break;
3876
3877 case IPP_TAG_KEYWORD :
3878 if (temp_tag == IPP_TAG_NAME || temp_tag == IPP_TAG_NAMELANG)
3879 break; /* Silently "allow" name -> keyword */
3880
3881 default :
3882 return (0);
3883 }
3884
3885 return (1);
3886 }
3887
3888
3889 /*
3890 * 'ippSetVersion()' - Set the version number in an IPP message.
3891 *
3892 * The @code ipp@ parameter refers to an IPP message previously created using the
3893 * @link ippNew@ or @link ippNewRequest@ functions.
3894 *
3895 * The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
3896 *
3897 * @since CUPS 1.6/OS X 10.8@
3898 */
3899
3900 int /* O - 1 on success, 0 on failure */
3901 ippSetVersion(ipp_t *ipp, /* I - IPP message */
3902 int major, /* I - Major version number (major.minor) */
3903 int minor) /* I - Minor version number (major.minor) */
3904 {
3905 /*
3906 * Range check input...
3907 */
3908
3909 if (!ipp || major < 0 || minor < 0)
3910 return (0);
3911
3912 /*
3913 * Set the version number...
3914 */
3915
3916 ipp->request.any.version[0] = major;
3917 ipp->request.any.version[1] = minor;
3918
3919 return (1);
3920 }
3921
3922
3923 /*
3924 * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
3925 */
3926
3927 const ipp_uchar_t * /* O - RFC-1903 date/time data */
3928 ippTimeToDate(time_t t) /* I - UNIX time value */
3929 {
3930 struct tm *unixdate; /* UNIX unixdate/time info */
3931 ipp_uchar_t *date = _cupsGlobals()->ipp_date;
3932 /* RFC-1903 date/time data */
3933
3934
3935 /*
3936 * RFC-1903 date/time format is:
3937 *
3938 * Byte(s) Description
3939 * ------- -----------
3940 * 0-1 Year (0 to 65535)
3941 * 2 Month (1 to 12)
3942 * 3 Day (1 to 31)
3943 * 4 Hours (0 to 23)
3944 * 5 Minutes (0 to 59)
3945 * 6 Seconds (0 to 60, 60 = "leap second")
3946 * 7 Deciseconds (0 to 9)
3947 * 8 +/- UTC
3948 * 9 UTC hours (0 to 11)
3949 * 10 UTC minutes (0 to 59)
3950 */
3951
3952 unixdate = gmtime(&t);
3953 unixdate->tm_year += 1900;
3954
3955 date[0] = unixdate->tm_year >> 8;
3956 date[1] = unixdate->tm_year;
3957 date[2] = unixdate->tm_mon + 1;
3958 date[3] = unixdate->tm_mday;
3959 date[4] = unixdate->tm_hour;
3960 date[5] = unixdate->tm_min;
3961 date[6] = unixdate->tm_sec;
3962 date[7] = 0;
3963 date[8] = '+';
3964 date[9] = 0;
3965 date[10] = 0;
3966
3967 return (date);
3968 }
3969
3970
3971 /*
3972 * 'ippWrite()' - Write data for an IPP message to a HTTP connection.
3973 */
3974
3975 ipp_state_t /* O - Current state */
3976 ippWrite(http_t *http, /* I - HTTP connection */
3977 ipp_t *ipp) /* I - IPP data */
3978 {
3979 DEBUG_printf(("ippWrite(http=%p, ipp=%p)", http, ipp));
3980
3981 if (!http)
3982 return (IPP_ERROR);
3983
3984 return (ippWriteIO(http, (ipp_iocb_t)httpWrite2, http->blocking, NULL, ipp));
3985 }
3986
3987
3988 /*
3989 * 'ippWriteFile()' - Write data for an IPP message to a file.
3990 *
3991 * @since CUPS 1.1.19/OS X 10.3@
3992 */
3993
3994 ipp_state_t /* O - Current state */
3995 ippWriteFile(int fd, /* I - HTTP data */
3996 ipp_t *ipp) /* I - IPP data */
3997 {
3998 DEBUG_printf(("ippWriteFile(fd=%d, ipp=%p)", fd, ipp));
3999
4000 ipp->state = IPP_IDLE;
4001
4002 return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp));
4003 }
4004
4005
4006 /*
4007 * 'ippWriteIO()' - Write data for an IPP message.
4008 *
4009 * @since CUPS 1.2/OS X 10.5@
4010 */
4011
4012 ipp_state_t /* O - Current state */
4013 ippWriteIO(void *dst, /* I - Destination */
4014 ipp_iocb_t cb, /* I - Write callback function */
4015 int blocking, /* I - Use blocking IO? */
4016 ipp_t *parent, /* I - Parent IPP message */
4017 ipp_t *ipp) /* I - IPP data */
4018 {
4019 int i; /* Looping var */
4020 int n; /* Length of data */
4021 unsigned char *buffer, /* Data buffer */
4022 *bufptr; /* Pointer into buffer */
4023 ipp_attribute_t *attr; /* Current attribute */
4024 _ipp_value_t *value; /* Current value */
4025
4026
4027 DEBUG_printf(("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)",
4028 dst, cb, blocking, parent, ipp));
4029
4030 if (!dst || !ipp)
4031 return (IPP_ERROR);
4032
4033 if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
4034 {
4035 DEBUG_puts("1ippWriteIO: Unable to get write buffer");
4036 return (IPP_ERROR);
4037 }
4038
4039 switch (ipp->state)
4040 {
4041 case IPP_IDLE :
4042 ipp->state ++; /* Avoid common problem... */
4043
4044 case IPP_HEADER :
4045 if (parent == NULL)
4046 {
4047 /*
4048 * Send the request header:
4049 *
4050 * Version = 2 bytes
4051 * Operation/Status Code = 2 bytes
4052 * Request ID = 4 bytes
4053 * Total = 8 bytes
4054 */
4055
4056 bufptr = buffer;
4057
4058 *bufptr++ = ipp->request.any.version[0];
4059 *bufptr++ = ipp->request.any.version[1];
4060 *bufptr++ = ipp->request.any.op_status >> 8;
4061 *bufptr++ = ipp->request.any.op_status;
4062 *bufptr++ = ipp->request.any.request_id >> 24;
4063 *bufptr++ = ipp->request.any.request_id >> 16;
4064 *bufptr++ = ipp->request.any.request_id >> 8;
4065 *bufptr++ = ipp->request.any.request_id;
4066
4067 DEBUG_printf(("2ippWriteIO: version=%d.%d", buffer[0], buffer[1]));
4068 DEBUG_printf(("2ippWriteIO: op_status=%04x",
4069 ipp->request.any.op_status));
4070 DEBUG_printf(("2ippWriteIO: request_id=%d",
4071 ipp->request.any.request_id));
4072
4073 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4074 {
4075 DEBUG_puts("1ippWriteIO: Could not write IPP header...");
4076 _cupsBufferRelease((char *)buffer);
4077 return (IPP_ERROR);
4078 }
4079 }
4080
4081 /*
4082 * Reset the state engine to point to the first attribute
4083 * in the request/response, with no current group.
4084 */
4085
4086 ipp->state = IPP_ATTRIBUTE;
4087 ipp->current = ipp->attrs;
4088 ipp->curtag = IPP_TAG_ZERO;
4089
4090 DEBUG_printf(("1ippWriteIO: ipp->current=%p", ipp->current));
4091
4092 /*
4093 * If blocking is disabled, stop here...
4094 */
4095
4096 if (!blocking)
4097 break;
4098
4099 case IPP_ATTRIBUTE :
4100 while (ipp->current != NULL)
4101 {
4102 /*
4103 * Write this attribute...
4104 */
4105
4106 bufptr = buffer;
4107 attr = ipp->current;
4108
4109 ipp->current = ipp->current->next;
4110
4111 if (!parent)
4112 {
4113 if (ipp->curtag != attr->group_tag)
4114 {
4115 /*
4116 * Send a group tag byte...
4117 */
4118
4119 ipp->curtag = attr->group_tag;
4120
4121 if (attr->group_tag == IPP_TAG_ZERO)
4122 continue;
4123
4124 DEBUG_printf(("2ippWriteIO: wrote group tag=%x(%s)",
4125 attr->group_tag, ippTagString(attr->group_tag)));
4126 *bufptr++ = attr->group_tag;
4127 }
4128 else if (attr->group_tag == IPP_TAG_ZERO)
4129 continue;
4130 }
4131
4132 DEBUG_printf(("1ippWriteIO: %s (%s%s)", attr->name,
4133 attr->num_values > 1 ? "1setOf " : "",
4134 ippTagString(attr->value_tag)));
4135
4136 /*
4137 * Write the attribute tag and name.
4138 *
4139 * The attribute name length does not include the trailing nul
4140 * character in the source string.
4141 *
4142 * Collection values (parent != NULL) are written differently...
4143 */
4144
4145 if (parent == NULL)
4146 {
4147 /*
4148 * Get the length of the attribute name, and make sure it won't
4149 * overflow the buffer...
4150 */
4151
4152 if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 8))
4153 {
4154 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
4155 _cupsBufferRelease((char *)buffer);
4156 return (IPP_ERROR);
4157 }
4158
4159 /*
4160 * Write the value tag, name length, and name string...
4161 */
4162
4163 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4164 attr->value_tag, ippTagString(attr->value_tag)));
4165 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
4166 attr->name));
4167
4168 if (attr->value_tag > 0xff)
4169 {
4170 *bufptr++ = IPP_TAG_EXTENSION;
4171 *bufptr++ = attr->value_tag >> 24;
4172 *bufptr++ = attr->value_tag >> 16;
4173 *bufptr++ = attr->value_tag >> 8;
4174 *bufptr++ = attr->value_tag;
4175 }
4176 else
4177 *bufptr++ = attr->value_tag;
4178
4179 *bufptr++ = n >> 8;
4180 *bufptr++ = n;
4181 memcpy(bufptr, attr->name, n);
4182 bufptr += n;
4183 }
4184 else
4185 {
4186 /*
4187 * Get the length of the attribute name, and make sure it won't
4188 * overflow the buffer...
4189 */
4190
4191 if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 12))
4192 {
4193 DEBUG_printf(("1ippWriteIO: Attribute name too long (%d)", n));
4194 _cupsBufferRelease((char *)buffer);
4195 return (IPP_ERROR);
4196 }
4197
4198 /*
4199 * Write the member name tag, name length, name string, value tag,
4200 * and empty name for the collection member attribute...
4201 */
4202
4203 DEBUG_printf(("2ippWriteIO: writing value tag=%x(memberName)",
4204 IPP_TAG_MEMBERNAME));
4205 DEBUG_printf(("2ippWriteIO: writing name=%d,\"%s\"", n,
4206 attr->name));
4207 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4208 attr->value_tag, ippTagString(attr->value_tag)));
4209 DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
4210
4211 *bufptr++ = IPP_TAG_MEMBERNAME;
4212 *bufptr++ = 0;
4213 *bufptr++ = 0;
4214 *bufptr++ = n >> 8;
4215 *bufptr++ = n;
4216 memcpy(bufptr, attr->name, n);
4217 bufptr += n;
4218
4219 if (attr->value_tag > 0xff)
4220 {
4221 *bufptr++ = IPP_TAG_EXTENSION;
4222 *bufptr++ = attr->value_tag >> 24;
4223 *bufptr++ = attr->value_tag >> 16;
4224 *bufptr++ = attr->value_tag >> 8;
4225 *bufptr++ = attr->value_tag;
4226 }
4227 else
4228 *bufptr++ = attr->value_tag;
4229
4230 *bufptr++ = 0;
4231 *bufptr++ = 0;
4232 }
4233
4234 /*
4235 * Now write the attribute value(s)...
4236 */
4237
4238 switch (attr->value_tag & ~IPP_TAG_COPY)
4239 {
4240 case IPP_TAG_UNSUPPORTED_VALUE :
4241 case IPP_TAG_DEFAULT :
4242 case IPP_TAG_UNKNOWN :
4243 case IPP_TAG_NOVALUE :
4244 case IPP_TAG_NOTSETTABLE :
4245 case IPP_TAG_DELETEATTR :
4246 case IPP_TAG_ADMINDEFINE :
4247 *bufptr++ = 0;
4248 *bufptr++ = 0;
4249 break;
4250
4251 case IPP_TAG_INTEGER :
4252 case IPP_TAG_ENUM :
4253 for (i = 0, value = attr->values;
4254 i < attr->num_values;
4255 i ++, value ++)
4256 {
4257 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 9)
4258 {
4259 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4260 {
4261 DEBUG_puts("1ippWriteIO: Could not write IPP "
4262 "attribute...");
4263 _cupsBufferRelease((char *)buffer);
4264 return (IPP_ERROR);
4265 }
4266
4267 bufptr = buffer;
4268 }
4269
4270 if (i)
4271 {
4272 /*
4273 * Arrays and sets are done by sending additional
4274 * values with a zero-length name...
4275 */
4276
4277 *bufptr++ = attr->value_tag;
4278 *bufptr++ = 0;
4279 *bufptr++ = 0;
4280 }
4281
4282 /*
4283 * Integers and enumerations are both 4-byte signed
4284 * (twos-complement) values.
4285 *
4286 * Put the 2-byte length and 4-byte value into the buffer...
4287 */
4288
4289 *bufptr++ = 0;
4290 *bufptr++ = 4;
4291 *bufptr++ = value->integer >> 24;
4292 *bufptr++ = value->integer >> 16;
4293 *bufptr++ = value->integer >> 8;
4294 *bufptr++ = value->integer;
4295 }
4296 break;
4297
4298 case IPP_TAG_BOOLEAN :
4299 for (i = 0, value = attr->values;
4300 i < attr->num_values;
4301 i ++, value ++)
4302 {
4303 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 6)
4304 {
4305 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4306 {
4307 DEBUG_puts("1ippWriteIO: Could not write IPP "
4308 "attribute...");
4309 _cupsBufferRelease((char *)buffer);
4310 return (IPP_ERROR);
4311 }
4312
4313 bufptr = buffer;
4314 }
4315
4316 if (i)
4317 {
4318 /*
4319 * Arrays and sets are done by sending additional
4320 * values with a zero-length name...
4321 */
4322
4323 *bufptr++ = attr->value_tag;
4324 *bufptr++ = 0;
4325 *bufptr++ = 0;
4326 }
4327
4328 /*
4329 * Boolean values are 1-byte; 0 = false, 1 = true.
4330 *
4331 * Put the 2-byte length and 1-byte value into the buffer...
4332 */
4333
4334 *bufptr++ = 0;
4335 *bufptr++ = 1;
4336 *bufptr++ = value->boolean;
4337 }
4338 break;
4339
4340 case IPP_TAG_TEXT :
4341 case IPP_TAG_NAME :
4342 case IPP_TAG_KEYWORD :
4343 case IPP_TAG_URI :
4344 case IPP_TAG_URISCHEME :
4345 case IPP_TAG_CHARSET :
4346 case IPP_TAG_LANGUAGE :
4347 case IPP_TAG_MIMETYPE :
4348 for (i = 0, value = attr->values;
4349 i < attr->num_values;
4350 i ++, value ++)
4351 {
4352 if (i)
4353 {
4354 /*
4355 * Arrays and sets are done by sending additional
4356 * values with a zero-length name...
4357 */
4358
4359 DEBUG_printf(("2ippWriteIO: writing value tag=%x(%s)",
4360 attr->value_tag,
4361 ippTagString(attr->value_tag)));
4362 DEBUG_printf(("2ippWriteIO: writing name=0,\"\""));
4363
4364 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
4365 {
4366 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4367 {
4368 DEBUG_puts("1ippWriteIO: Could not write IPP "
4369 "attribute...");
4370 _cupsBufferRelease((char *)buffer);
4371 return (IPP_ERROR);
4372 }
4373
4374 bufptr = buffer;
4375 }
4376
4377 *bufptr++ = attr->value_tag;
4378 *bufptr++ = 0;
4379 *bufptr++ = 0;
4380 }
4381
4382 if (value->string.text != NULL)
4383 n = (int)strlen(value->string.text);
4384 else
4385 n = 0;
4386
4387 if (n > (IPP_BUF_SIZE - 2))
4388 {
4389 DEBUG_printf(("1ippWriteIO: String too long (%d)", n));
4390 _cupsBufferRelease((char *)buffer);
4391 return (IPP_ERROR);
4392 }
4393
4394 DEBUG_printf(("2ippWriteIO: writing string=%d,\"%s\"", n,
4395 value->string.text));
4396
4397 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
4398 {
4399 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4400 {
4401 DEBUG_puts("1ippWriteIO: Could not write IPP "
4402 "attribute...");
4403 _cupsBufferRelease((char *)buffer);
4404 return (IPP_ERROR);
4405 }
4406
4407 bufptr = buffer;
4408 }
4409
4410 /*
4411 * All simple strings consist of the 2-byte length and
4412 * character data without the trailing nul normally found
4413 * in C strings. Also, strings cannot be longer than IPP_MAX_LENGTH
4414 * bytes since the 2-byte length is a signed (twos-complement)
4415 * value.
4416 *
4417 * Put the 2-byte length and string characters in the buffer.
4418 */
4419
4420 *bufptr++ = n >> 8;
4421 *bufptr++ = n;
4422
4423 if (n > 0)
4424 {
4425 memcpy(bufptr, value->string.text, n);
4426 bufptr += n;
4427 }
4428 }
4429 break;
4430
4431 case IPP_TAG_DATE :
4432 for (i = 0, value = attr->values;
4433 i < attr->num_values;
4434 i ++, value ++)
4435 {
4436 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 16)
4437 {
4438 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4439 {
4440 DEBUG_puts("1ippWriteIO: Could not write IPP "
4441 "attribute...");
4442 _cupsBufferRelease((char *)buffer);
4443 return (IPP_ERROR);
4444 }
4445
4446 bufptr = buffer;
4447 }
4448
4449 if (i)
4450 {
4451 /*
4452 * Arrays and sets are done by sending additional
4453 * values with a zero-length name...
4454 */
4455
4456 *bufptr++ = attr->value_tag;
4457 *bufptr++ = 0;
4458 *bufptr++ = 0;
4459 }
4460
4461 /*
4462 * Date values consist of a 2-byte length and an
4463 * 11-byte date/time structure defined by RFC 1903.
4464 *
4465 * Put the 2-byte length and 11-byte date/time
4466 * structure in the buffer.
4467 */
4468
4469 *bufptr++ = 0;
4470 *bufptr++ = 11;
4471 memcpy(bufptr, value->date, 11);
4472 bufptr += 11;
4473 }
4474 break;
4475
4476 case IPP_TAG_RESOLUTION :
4477 for (i = 0, value = attr->values;
4478 i < attr->num_values;
4479 i ++, value ++)
4480 {
4481 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 14)
4482 {
4483 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4484 {
4485 DEBUG_puts("1ippWriteIO: Could not write IPP "
4486 "attribute...");
4487 _cupsBufferRelease((char *)buffer);
4488 return (IPP_ERROR);
4489 }
4490
4491 bufptr = buffer;
4492 }
4493
4494 if (i)
4495 {
4496 /*
4497 * Arrays and sets are done by sending additional
4498 * values with a zero-length name...
4499 */
4500
4501 *bufptr++ = attr->value_tag;
4502 *bufptr++ = 0;
4503 *bufptr++ = 0;
4504 }
4505
4506 /*
4507 * Resolution values consist of a 2-byte length,
4508 * 4-byte horizontal resolution value, 4-byte vertical
4509 * resolution value, and a 1-byte units value.
4510 *
4511 * Put the 2-byte length and resolution value data
4512 * into the buffer.
4513 */
4514
4515 *bufptr++ = 0;
4516 *bufptr++ = 9;
4517 *bufptr++ = value->resolution.xres >> 24;
4518 *bufptr++ = value->resolution.xres >> 16;
4519 *bufptr++ = value->resolution.xres >> 8;
4520 *bufptr++ = value->resolution.xres;
4521 *bufptr++ = value->resolution.yres >> 24;
4522 *bufptr++ = value->resolution.yres >> 16;
4523 *bufptr++ = value->resolution.yres >> 8;
4524 *bufptr++ = value->resolution.yres;
4525 *bufptr++ = value->resolution.units;
4526 }
4527 break;
4528
4529 case IPP_TAG_RANGE :
4530 for (i = 0, value = attr->values;
4531 i < attr->num_values;
4532 i ++, value ++)
4533 {
4534 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 13)
4535 {
4536 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4537 {
4538 DEBUG_puts("1ippWriteIO: Could not write IPP "
4539 "attribute...");
4540 _cupsBufferRelease((char *)buffer);
4541 return (IPP_ERROR);
4542 }
4543
4544 bufptr = buffer;
4545 }
4546
4547 if (i)
4548 {
4549 /*
4550 * Arrays and sets are done by sending additional
4551 * values with a zero-length name...
4552 */
4553
4554 *bufptr++ = attr->value_tag;
4555 *bufptr++ = 0;
4556 *bufptr++ = 0;
4557 }
4558
4559 /*
4560 * Range values consist of a 2-byte length,
4561 * 4-byte lower value, and 4-byte upper value.
4562 *
4563 * Put the 2-byte length and range value data
4564 * into the buffer.
4565 */
4566
4567 *bufptr++ = 0;
4568 *bufptr++ = 8;
4569 *bufptr++ = value->range.lower >> 24;
4570 *bufptr++ = value->range.lower >> 16;
4571 *bufptr++ = value->range.lower >> 8;
4572 *bufptr++ = value->range.lower;
4573 *bufptr++ = value->range.upper >> 24;
4574 *bufptr++ = value->range.upper >> 16;
4575 *bufptr++ = value->range.upper >> 8;
4576 *bufptr++ = value->range.upper;
4577 }
4578 break;
4579
4580 case IPP_TAG_TEXTLANG :
4581 case IPP_TAG_NAMELANG :
4582 for (i = 0, value = attr->values;
4583 i < attr->num_values;
4584 i ++, value ++)
4585 {
4586 if (i)
4587 {
4588 /*
4589 * Arrays and sets are done by sending additional
4590 * values with a zero-length name...
4591 */
4592
4593 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
4594 {
4595 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4596 {
4597 DEBUG_puts("1ippWriteIO: Could not write IPP "
4598 "attribute...");
4599 _cupsBufferRelease((char *)buffer);
4600 return (IPP_ERROR);
4601 }
4602
4603 bufptr = buffer;
4604 }
4605
4606 *bufptr++ = attr->value_tag;
4607 *bufptr++ = 0;
4608 *bufptr++ = 0;
4609 }
4610
4611 /*
4612 * textWithLanguage and nameWithLanguage values consist
4613 * of a 2-byte length for both strings and their
4614 * individual lengths, a 2-byte length for the
4615 * character string, the character string without the
4616 * trailing nul, a 2-byte length for the character
4617 * set string, and the character set string without
4618 * the trailing nul.
4619 */
4620
4621 n = 4;
4622
4623 if (value->string.language != NULL)
4624 n += (int)strlen(value->string.language);
4625
4626 if (value->string.text != NULL)
4627 n += (int)strlen(value->string.text);
4628
4629 if (n > (IPP_BUF_SIZE - 2))
4630 {
4631 DEBUG_printf(("1ippWriteIO: text/nameWithLanguage value "
4632 "too long (%d)", n));
4633 _cupsBufferRelease((char *)buffer);
4634 return (IPP_ERROR);
4635 }
4636
4637 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
4638 {
4639 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4640 {
4641 DEBUG_puts("1ippWriteIO: Could not write IPP "
4642 "attribute...");
4643 _cupsBufferRelease((char *)buffer);
4644 return (IPP_ERROR);
4645 }
4646
4647 bufptr = buffer;
4648 }
4649
4650 /* Length of entire value */
4651 *bufptr++ = n >> 8;
4652 *bufptr++ = n;
4653
4654 /* Length of language */
4655 if (value->string.language != NULL)
4656 n = (int)strlen(value->string.language);
4657 else
4658 n = 0;
4659
4660 *bufptr++ = n >> 8;
4661 *bufptr++ = n;
4662
4663 /* Language */
4664 if (n > 0)
4665 {
4666 memcpy(bufptr, value->string.language, n);
4667 bufptr += n;
4668 }
4669
4670 /* Length of text */
4671 if (value->string.text != NULL)
4672 n = (int)strlen(value->string.text);
4673 else
4674 n = 0;
4675
4676 *bufptr++ = n >> 8;
4677 *bufptr++ = n;
4678
4679 /* Text */
4680 if (n > 0)
4681 {
4682 memcpy(bufptr, value->string.text, n);
4683 bufptr += n;
4684 }
4685 }
4686 break;
4687
4688 case IPP_TAG_BEGIN_COLLECTION :
4689 for (i = 0, value = attr->values;
4690 i < attr->num_values;
4691 i ++, value ++)
4692 {
4693 /*
4694 * Collections are written with the begin-collection
4695 * tag first with a value of 0 length, followed by the
4696 * attributes in the collection, then the end-collection
4697 * value...
4698 */
4699
4700 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 5)
4701 {
4702 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4703 {
4704 DEBUG_puts("1ippWriteIO: Could not write IPP "
4705 "attribute...");
4706 _cupsBufferRelease((char *)buffer);
4707 return (IPP_ERROR);
4708 }
4709
4710 bufptr = buffer;
4711 }
4712
4713 if (i)
4714 {
4715 /*
4716 * Arrays and sets are done by sending additional
4717 * values with a zero-length name...
4718 */
4719
4720 *bufptr++ = attr->value_tag;
4721 *bufptr++ = 0;
4722 *bufptr++ = 0;
4723 }
4724
4725 /*
4726 * Write a data length of 0 and flush the buffer...
4727 */
4728
4729 *bufptr++ = 0;
4730 *bufptr++ = 0;
4731
4732 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4733 {
4734 DEBUG_puts("1ippWriteIO: Could not write IPP "
4735 "attribute...");
4736 _cupsBufferRelease((char *)buffer);
4737 return (IPP_ERROR);
4738 }
4739
4740 bufptr = buffer;
4741
4742 /*
4743 * Then write the collection attribute...
4744 */
4745
4746 value->collection->state = IPP_IDLE;
4747
4748 if (ippWriteIO(dst, cb, 1, ipp,
4749 value->collection) == IPP_ERROR)
4750 {
4751 DEBUG_puts("1ippWriteIO: Unable to write collection value");
4752 _cupsBufferRelease((char *)buffer);
4753 return (IPP_ERROR);
4754 }
4755 }
4756 break;
4757
4758 default :
4759 for (i = 0, value = attr->values;
4760 i < attr->num_values;
4761 i ++, value ++)
4762 {
4763 if (i)
4764 {
4765 /*
4766 * Arrays and sets are done by sending additional
4767 * values with a zero-length name...
4768 */
4769
4770 if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
4771 {
4772 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4773 {
4774 DEBUG_puts("1ippWriteIO: Could not write IPP "
4775 "attribute...");
4776 _cupsBufferRelease((char *)buffer);
4777 return (IPP_ERROR);
4778 }
4779
4780 bufptr = buffer;
4781 }
4782
4783 *bufptr++ = attr->value_tag;
4784 *bufptr++ = 0;
4785 *bufptr++ = 0;
4786 }
4787
4788 /*
4789 * An unknown value might some new value that a
4790 * vendor has come up with. It consists of a
4791 * 2-byte length and the bytes in the unknown
4792 * value buffer.
4793 */
4794
4795 n = value->unknown.length;
4796
4797 if (n > (IPP_BUF_SIZE - 2))
4798 {
4799 DEBUG_printf(("1ippWriteIO: Data length too long (%d)",
4800 n));
4801 _cupsBufferRelease((char *)buffer);
4802 return (IPP_ERROR);
4803 }
4804
4805 if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
4806 {
4807 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4808 {
4809 DEBUG_puts("1ippWriteIO: Could not write IPP "
4810 "attribute...");
4811 _cupsBufferRelease((char *)buffer);
4812 return (IPP_ERROR);
4813 }
4814
4815 bufptr = buffer;
4816 }
4817
4818 /* Length of unknown value */
4819 *bufptr++ = n >> 8;
4820 *bufptr++ = n;
4821
4822 /* Value */
4823 if (n > 0)
4824 {
4825 memcpy(bufptr, value->unknown.data, n);
4826 bufptr += n;
4827 }
4828 }
4829 break;
4830 }
4831
4832 /*
4833 * Write the data out...
4834 */
4835
4836 if (bufptr > buffer)
4837 {
4838 if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0)
4839 {
4840 DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4841 _cupsBufferRelease((char *)buffer);
4842 return (IPP_ERROR);
4843 }
4844
4845 DEBUG_printf(("2ippWriteIO: wrote %d bytes",
4846 (int)(bufptr - buffer)));
4847 }
4848
4849 /*
4850 * If blocking is disabled, stop here...
4851 */
4852
4853 if (!blocking)
4854 break;
4855 }
4856
4857 if (ipp->current == NULL)
4858 {
4859 /*
4860 * Done with all of the attributes; add the end-of-attributes
4861 * tag or end-collection attribute...
4862 */
4863
4864 if (parent == NULL)
4865 {
4866 buffer[0] = IPP_TAG_END;
4867 n = 1;
4868 }
4869 else
4870 {
4871 buffer[0] = IPP_TAG_END_COLLECTION;
4872 buffer[1] = 0; /* empty name */
4873 buffer[2] = 0;
4874 buffer[3] = 0; /* empty value */
4875 buffer[4] = 0;
4876 n = 5;
4877 }
4878
4879 if ((*cb)(dst, buffer, n) < 0)
4880 {
4881 DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
4882 _cupsBufferRelease((char *)buffer);
4883 return (IPP_ERROR);
4884 }
4885
4886 ipp->state = IPP_DATA;
4887 }
4888 break;
4889
4890 case IPP_DATA :
4891 break;
4892
4893 default :
4894 break; /* anti-compiler-warning-code */
4895 }
4896
4897 _cupsBufferRelease((char *)buffer);
4898
4899 return (ipp->state);
4900 }
4901
4902
4903 /*
4904 * 'ipp_add_attr()' - Add a new attribute to the message.
4905 */
4906
4907 static ipp_attribute_t * /* O - New attribute */
4908 ipp_add_attr(ipp_t *ipp, /* I - IPP message */
4909 const char *name, /* I - Attribute name or NULL */
4910 ipp_tag_t group_tag, /* I - Group tag or IPP_TAG_ZERO */
4911 ipp_tag_t value_tag, /* I - Value tag or IPP_TAG_ZERO */
4912 int num_values) /* I - Number of values */
4913 {
4914 int alloc_values; /* Number of values to allocate */
4915 ipp_attribute_t *attr; /* New attribute */
4916
4917
4918 DEBUG_printf(("4ipp_add_attr(ipp=%p, name=\"%s\", group_tag=0x%x, value_tag=0x%x, "
4919 "num_values=%d)", ipp, name, group_tag, value_tag, num_values));
4920
4921 /*
4922 * Range check input...
4923 */
4924
4925 if (!ipp || num_values < 0)
4926 return (NULL);
4927
4928 /*
4929 * Allocate memory, rounding the allocation up as needed...
4930 */
4931
4932 if (num_values <= 1)
4933 alloc_values = 1;
4934 else
4935 alloc_values = (num_values + IPP_MAX_VALUES - 1) & ~(IPP_MAX_VALUES - 1);
4936
4937 attr = calloc(sizeof(ipp_attribute_t) +
4938 (alloc_values - 1) * sizeof(_ipp_value_t), 1);
4939
4940 if (attr)
4941 {
4942 /*
4943 * Initialize attribute...
4944 */
4945
4946 if (name)
4947 attr->name = _cupsStrAlloc(name);
4948
4949 attr->group_tag = group_tag;
4950 attr->value_tag = value_tag;
4951 attr->num_values = num_values;
4952
4953 /*
4954 * Add it to the end of the linked list...
4955 */
4956
4957 if (ipp->last)
4958 ipp->last->next = attr;
4959 else
4960 ipp->attrs = attr;
4961
4962 ipp->prev = ipp->last;
4963 ipp->last = ipp->current = attr;
4964 }
4965
4966 DEBUG_printf(("5ipp_add_attr: Returning %p", attr));
4967
4968 return (attr);
4969 }
4970
4971
4972 /*
4973 * 'ipp_free_values()' - Free attribute values.
4974 */
4975
4976 static void
4977 ipp_free_values(ipp_attribute_t *attr, /* I - Attribute to free values from */
4978 int element,/* I - First value to free */
4979 int count) /* I - Number of values to free */
4980 {
4981 int i; /* Looping var */
4982 _ipp_value_t *value; /* Current value */
4983
4984
4985 DEBUG_printf(("4ipp_free_values(attr=%p, element=%d, count=%d)", attr, element, count));
4986
4987 if (!(attr->value_tag & IPP_TAG_COPY))
4988 {
4989 /*
4990 * Free values as needed...
4991 */
4992
4993 switch (attr->value_tag)
4994 {
4995 case IPP_TAG_TEXTLANG :
4996 case IPP_TAG_NAMELANG :
4997 if (element == 0 && count == attr->num_values && attr->values[0].string.language)
4998 _cupsStrFree(attr->values[0].string.language);
4999
5000 case IPP_TAG_TEXT :
5001 case IPP_TAG_NAME :
5002 case IPP_TAG_RESERVED_STRING :
5003 case IPP_TAG_KEYWORD :
5004 case IPP_TAG_URI :
5005 case IPP_TAG_URISCHEME :
5006 case IPP_TAG_CHARSET :
5007 case IPP_TAG_LANGUAGE :
5008 case IPP_TAG_MIMETYPE :
5009 for (i = count, value = attr->values + element;
5010 i > 0;
5011 i --, value ++)
5012 _cupsStrFree(value->string.text);
5013 break;
5014
5015 case IPP_TAG_DEFAULT :
5016 case IPP_TAG_UNKNOWN :
5017 case IPP_TAG_NOVALUE :
5018 case IPP_TAG_NOTSETTABLE :
5019 case IPP_TAG_DELETEATTR :
5020 case IPP_TAG_ADMINDEFINE :
5021 case IPP_TAG_INTEGER :
5022 case IPP_TAG_ENUM :
5023 case IPP_TAG_BOOLEAN :
5024 case IPP_TAG_DATE :
5025 case IPP_TAG_RESOLUTION :
5026 case IPP_TAG_RANGE :
5027 break;
5028
5029 case IPP_TAG_BEGIN_COLLECTION :
5030 for (i = count, value = attr->values + element;
5031 i > 0;
5032 i --, value ++)
5033 ippDelete(value->collection);
5034 break;
5035
5036 case IPP_TAG_STRING :
5037 default :
5038 for (i = count, value = attr->values + element;
5039 i > 0;
5040 i --, value ++)
5041 if (value->unknown.data)
5042 free(value->unknown.data);
5043 break;
5044 }
5045 }
5046
5047 /*
5048 * If we are not freeing values from the end, move the remaining values up...
5049 */
5050
5051 if ((element + count) < attr->num_values)
5052 memmove(attr->values + element, attr->values + element + count,
5053 (attr->num_values - count - element) * sizeof(_ipp_value_t));
5054
5055 attr->num_values -= count;
5056 }
5057
5058
5059 /*
5060 * 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
5061 *
5062 * This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
5063 * to "ll-cc", "ll-region", and "charset-number", respectively.
5064 */
5065
5066 static char * /* O - Language code string */
5067 ipp_get_code(const char *value, /* I - Locale/charset string */
5068 char *buffer, /* I - String buffer */
5069 size_t bufsize) /* I - Size of string buffer */
5070 {
5071 char *bufptr, /* Pointer into buffer */
5072 *bufend; /* End of buffer */
5073
5074
5075 /*
5076 * Convert values to lowercase and change _ to - as needed...
5077 */
5078
5079 for (bufptr = buffer, bufend = buffer + bufsize - 1;
5080 *value && bufptr < bufend;
5081 value ++)
5082 if (*value == '_')
5083 *bufptr++ = '-';
5084 else
5085 *bufptr++ = _cups_tolower(*value);
5086
5087 *bufptr = '\0';
5088
5089 /*
5090 * Return the converted string...
5091 */
5092
5093 return (buffer);
5094 }
5095
5096
5097 /*
5098 * 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
5099 *
5100 * This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
5101 * "ll-region", respectively. It also converts the "C" (POSIX) locale to "en".
5102 */
5103
5104 static char * /* O - Language code string */
5105 ipp_lang_code(const char *locale, /* I - Locale string */
5106 char *buffer, /* I - String buffer */
5107 size_t bufsize) /* I - Size of string buffer */
5108 {
5109 /*
5110 * Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
5111 */
5112
5113 if (!_cups_strcasecmp(locale, "c"))
5114 {
5115 strlcpy(buffer, "en", bufsize);
5116 return (buffer);
5117 }
5118 else
5119 return (ipp_get_code(locale, buffer, bufsize));
5120 }
5121
5122
5123 /*
5124 * 'ipp_length()' - Compute the length of an IPP message or collection value.
5125 */
5126
5127 static size_t /* O - Size of IPP message */
5128 ipp_length(ipp_t *ipp, /* I - IPP message or collection */
5129 int collection) /* I - 1 if a collection, 0 otherwise */
5130 {
5131 int i; /* Looping var */
5132 size_t bytes; /* Number of bytes */
5133 ipp_attribute_t *attr; /* Current attribute */
5134 ipp_tag_t group; /* Current group */
5135 _ipp_value_t *value; /* Current value */
5136
5137
5138 DEBUG_printf(("3ipp_length(ipp=%p, collection=%d)", ipp, collection));
5139
5140 if (!ipp)
5141 {
5142 DEBUG_puts("4ipp_length: Returning 0 bytes");
5143 return (0);
5144 }
5145
5146 /*
5147 * Start with 8 bytes for the IPP message header...
5148 */
5149
5150 bytes = collection ? 0 : 8;
5151
5152 /*
5153 * Then add the lengths of each attribute...
5154 */
5155
5156 group = IPP_TAG_ZERO;
5157
5158 for (attr = ipp->attrs; attr != NULL; attr = attr->next)
5159 {
5160 if (attr->group_tag != group && !collection)
5161 {
5162 group = attr->group_tag;
5163 if (group == IPP_TAG_ZERO)
5164 continue;
5165
5166 bytes ++; /* Group tag */
5167 }
5168
5169 if (!attr->name)
5170 continue;
5171
5172 DEBUG_printf(("5ipp_length: attr->name=\"%s\", attr->num_values=%d, "
5173 "bytes=" CUPS_LLFMT, attr->name, attr->num_values, CUPS_LLCAST bytes));
5174
5175 if (attr->value_tag < IPP_TAG_EXTENSION)
5176 bytes += attr->num_values; /* Value tag for each value */
5177 else
5178 bytes += 5 * attr->num_values; /* Value tag for each value */
5179 bytes += 2 * attr->num_values; /* Name lengths */
5180 bytes += (int)strlen(attr->name); /* Name */
5181 bytes += 2 * attr->num_values; /* Value lengths */
5182
5183 if (collection)
5184 bytes += 5; /* Add membername overhead */
5185
5186 switch (attr->value_tag & ~IPP_TAG_COPY)
5187 {
5188 case IPP_TAG_UNSUPPORTED_VALUE :
5189 case IPP_TAG_DEFAULT :
5190 case IPP_TAG_UNKNOWN :
5191 case IPP_TAG_NOVALUE :
5192 case IPP_TAG_NOTSETTABLE :
5193 case IPP_TAG_DELETEATTR :
5194 case IPP_TAG_ADMINDEFINE :
5195 break;
5196
5197 case IPP_TAG_INTEGER :
5198 case IPP_TAG_ENUM :
5199 bytes += 4 * attr->num_values;
5200 break;
5201
5202 case IPP_TAG_BOOLEAN :
5203 bytes += attr->num_values;
5204 break;
5205
5206 case IPP_TAG_TEXT :
5207 case IPP_TAG_NAME :
5208 case IPP_TAG_KEYWORD :
5209 case IPP_TAG_URI :
5210 case IPP_TAG_URISCHEME :
5211 case IPP_TAG_CHARSET :
5212 case IPP_TAG_LANGUAGE :
5213 case IPP_TAG_MIMETYPE :
5214 for (i = 0, value = attr->values;
5215 i < attr->num_values;
5216 i ++, value ++)
5217 if (value->string.text)
5218 bytes += strlen(value->string.text);
5219 break;
5220
5221 case IPP_TAG_DATE :
5222 bytes += 11 * attr->num_values;
5223 break;
5224
5225 case IPP_TAG_RESOLUTION :
5226 bytes += 9 * attr->num_values;
5227 break;
5228
5229 case IPP_TAG_RANGE :
5230 bytes += 8 * attr->num_values;
5231 break;
5232
5233 case IPP_TAG_TEXTLANG :
5234 case IPP_TAG_NAMELANG :
5235 bytes += 4 * attr->num_values;/* Charset + text length */
5236
5237 for (i = 0, value = attr->values;
5238 i < attr->num_values;
5239 i ++, value ++)
5240 {
5241 if (value->string.language)
5242 bytes += strlen(value->string.language);
5243
5244 if (value->string.text)
5245 bytes += strlen(value->string.text);
5246 }
5247 break;
5248
5249 case IPP_TAG_BEGIN_COLLECTION :
5250 for (i = 0, value = attr->values;
5251 i < attr->num_values;
5252 i ++, value ++)
5253 bytes += ipp_length(value->collection, 1);
5254 break;
5255
5256 default :
5257 for (i = 0, value = attr->values;
5258 i < attr->num_values;
5259 i ++, value ++)
5260 bytes += value->unknown.length;
5261 break;
5262 }
5263 }
5264
5265 /*
5266 * Finally, add 1 byte for the "end of attributes" tag or 5 bytes
5267 * for the "end of collection" tag and return...
5268 */
5269
5270 if (collection)
5271 bytes += 5;
5272 else
5273 bytes ++;
5274
5275 DEBUG_printf(("4ipp_length: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST bytes));
5276
5277 return (bytes);
5278 }
5279
5280
5281 /*
5282 * 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
5283 */
5284
5285 static ssize_t /* O - Number of bytes read */
5286 ipp_read_http(http_t *http, /* I - Client connection */
5287 ipp_uchar_t *buffer, /* O - Buffer for data */
5288 size_t length) /* I - Total length */
5289 {
5290 int tbytes, /* Total bytes read */
5291 bytes; /* Bytes read this pass */
5292 char len[32]; /* Length string */
5293
5294
5295 DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)",
5296 http, buffer, (int)length));
5297
5298 /*
5299 * Loop until all bytes are read...
5300 */
5301
5302 for (tbytes = 0, bytes = 0;
5303 tbytes < (int)length;
5304 tbytes += bytes, buffer += bytes)
5305 {
5306 DEBUG_printf(("9ipp_read_http: tbytes=%d, http->state=%d", tbytes,
5307 http->state));
5308
5309 if (http->state == HTTP_WAITING)
5310 break;
5311
5312 if (http->used > 0 && http->data_encoding == HTTP_ENCODE_LENGTH)
5313 {
5314 /*
5315 * Do "fast read" from HTTP buffer directly...
5316 */
5317
5318 if (http->used > (int)(length - tbytes))
5319 bytes = (int)(length - tbytes);
5320 else
5321 bytes = http->used;
5322
5323 if (bytes == 1)
5324 buffer[0] = http->buffer[0];
5325 else
5326 memcpy(buffer, http->buffer, bytes);
5327
5328 http->used -= bytes;
5329 http->data_remaining -= bytes;
5330
5331 if (http->data_remaining <= INT_MAX)
5332 http->_data_remaining = (int)http->data_remaining;
5333 else
5334 http->_data_remaining = INT_MAX;
5335
5336 if (http->used > 0)
5337 memmove(http->buffer, http->buffer + bytes, http->used);
5338
5339 if (http->data_remaining == 0)
5340 {
5341 if (http->data_encoding == HTTP_ENCODE_CHUNKED)
5342 {
5343 /*
5344 * Get the trailing CR LF after the chunk...
5345 */
5346
5347 if (!httpGets(len, sizeof(len), http))
5348 return (-1);
5349 }
5350
5351 if (http->data_encoding != HTTP_ENCODE_CHUNKED)
5352 {
5353 if (http->state == HTTP_POST_RECV)
5354 http->state ++;
5355 else
5356 http->state = HTTP_WAITING;
5357 }
5358 }
5359 }
5360 else
5361 {
5362 if (!http->blocking)
5363 {
5364 /*
5365 * Wait up to 10 seconds for more data on non-blocking sockets...
5366 */
5367
5368 if (!httpWait(http, 10000))
5369 {
5370 /*
5371 * Signal no data...
5372 */
5373
5374 bytes = -1;
5375 break;
5376 }
5377 }
5378
5379 if ((bytes = httpRead2(http, (char *)buffer, length - tbytes)) < 0)
5380 {
5381 #ifdef WIN32
5382 break;
5383 #else
5384 if (errno != EAGAIN && errno != EINTR)
5385 break;
5386
5387 bytes = 0;
5388 #endif /* WIN32 */
5389 }
5390 else if (bytes == 0)
5391 break;
5392 }
5393 }
5394
5395 /*
5396 * Return the number of bytes read...
5397 */
5398
5399 if (tbytes == 0 && bytes < 0)
5400 tbytes = -1;
5401
5402 DEBUG_printf(("8ipp_read_http: Returning %d bytes", tbytes));
5403
5404 return (tbytes);
5405 }
5406
5407
5408 /*
5409 * 'ipp_read_file()' - Read IPP data from a file.
5410 */
5411
5412 static ssize_t /* O - Number of bytes read */
5413 ipp_read_file(int *fd, /* I - File descriptor */
5414 ipp_uchar_t *buffer, /* O - Read buffer */
5415 size_t length) /* I - Number of bytes to read */
5416 {
5417 #ifdef WIN32
5418 return ((ssize_t)read(*fd, buffer, (unsigned)length));
5419 #else
5420 return (read(*fd, buffer, length));
5421 #endif /* WIN32 */
5422 }
5423
5424
5425 /*
5426 * 'ipp_set_value()' - Get the value element from an attribute, expanding it as
5427 * needed.
5428 */
5429
5430 static _ipp_value_t * /* O - IPP value element or NULL on error */
5431 ipp_set_value(ipp_t *ipp, /* IO - IPP message */
5432 ipp_attribute_t **attr, /* IO - IPP attribute */
5433 int element) /* I - Value number (0-based) */
5434 {
5435 ipp_attribute_t *temp, /* New attribute pointer */
5436 *current, /* Current attribute in list */
5437 *prev; /* Previous attribute in list */
5438 int alloc_values; /* Allocated values */
5439
5440
5441 /*
5442 * If we are setting an existing value element, return it...
5443 */
5444
5445 temp = *attr;
5446
5447 if (temp->num_values <= 1)
5448 alloc_values = 1;
5449 else
5450 alloc_values = (temp->num_values + IPP_MAX_VALUES - 1) &
5451 ~(IPP_MAX_VALUES - 1);
5452
5453 if (element < alloc_values)
5454 {
5455 if (element >= temp->num_values)
5456 temp->num_values = element + 1;
5457
5458 return (temp->values + element);
5459 }
5460
5461 /*
5462 * Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
5463 * values when num_values > 1.
5464 */
5465
5466 if (alloc_values < IPP_MAX_VALUES)
5467 alloc_values = IPP_MAX_VALUES;
5468 else
5469 alloc_values += IPP_MAX_VALUES;
5470
5471 DEBUG_printf(("4ipp_set_value: Reallocating for up to %d values.",
5472 alloc_values));
5473
5474 /*
5475 * Reallocate memory...
5476 */
5477
5478 if ((temp = realloc(temp, sizeof(ipp_attribute_t) +
5479 (alloc_values - 1) * sizeof(_ipp_value_t))) == NULL)
5480 {
5481 _cupsSetHTTPError(HTTP_ERROR);
5482 DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
5483 return (NULL);
5484 }
5485
5486 /*
5487 * Zero the new memory...
5488 */
5489
5490 memset(temp->values + temp->num_values, 0,
5491 (alloc_values - temp->num_values) * sizeof(_ipp_value_t));
5492
5493 if (temp != *attr)
5494 {
5495 /*
5496 * Reset pointers in the list...
5497 */
5498
5499 if (ipp->current == *attr && ipp->prev)
5500 {
5501 /*
5502 * Use current "previous" pointer...
5503 */
5504
5505 prev = ipp->prev;
5506 }
5507 else
5508 {
5509 /*
5510 * Find this attribute in the linked list...
5511 */
5512
5513 for (prev = NULL, current = ipp->attrs;
5514 current && current != *attr;
5515 prev = current, current = current->next);
5516
5517 if (!current)
5518 {
5519 /*
5520 * This is a serious error!
5521 */
5522
5523 *attr = temp;
5524 _cupsSetError(IPP_INTERNAL_ERROR,
5525 _("IPP attribute is not a member of the message."), 1);
5526 DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
5527 return (NULL);
5528 }
5529 }
5530
5531 if (prev)
5532 prev->next = temp;
5533 else
5534 ipp->attrs = temp;
5535
5536 ipp->current = temp;
5537 ipp->prev = prev;
5538
5539 if (ipp->last == *attr)
5540 ipp->last = temp;
5541
5542 *attr = temp;
5543 }
5544
5545 /*
5546 * Return the value element...
5547 */
5548
5549 if (element >= temp->num_values)
5550 temp->num_values = element + 1;
5551
5552 return (temp->values + element);
5553 }
5554
5555
5556 /*
5557 * 'ipp_write_file()' - Write IPP data to a file.
5558 */
5559
5560 static ssize_t /* O - Number of bytes written */
5561 ipp_write_file(int *fd, /* I - File descriptor */
5562 ipp_uchar_t *buffer, /* I - Data to write */
5563 size_t length) /* I - Number of bytes to write */
5564 {
5565 #ifdef WIN32
5566 return ((ssize_t)write(*fd, buffer, (unsigned)length));
5567 #else
5568 return (write(*fd, buffer, length));
5569 #endif /* WIN32 */
5570 }
5571
5572
5573 /*
5574 * End of "$Id: ipp.c 10102 2011-11-02 23:52:39Z mike $".
5575 */