Coverage Report

Created: 2025-11-15 06:13

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