Coverage Report

Created: 2025-06-10 07:27

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