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