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