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