Coverage Report

Created: 2025-07-14 06:27

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