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