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