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