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