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