Coverage Report

Created: 2024-11-04 06:16

/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-2024 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
822k
{
43
822k
  _cups_buffer_t  *buffer;  // Current buffer
44
822k
  _cups_globals_t *cg = _cupsGlobals();
45
          // Global data
46
47
48
1.64M
  for (buffer = cg->cups_buffers; buffer; buffer = buffer->next)
49
1.64M
    if (!buffer->used && buffer->size >= size)
50
822k
      break;
51
52
822k
  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
822k
  buffer->used = 1;
63
64
822k
  return (buffer->d);
65
822k
}
66
67
68
//
69
// '_cupsBufferRelease()' - Release a read/write buffer.
70
//
71
72
void
73
_cupsBufferRelease(char *b)   // I - Buffer to release
74
822k
{
75
822k
  _cups_buffer_t  *buffer;  // Buffer
76
77
78
  // Mark this buffer as unused...
79
822k
  buffer       = (_cups_buffer_t *)(b - offsetof(_cups_buffer_t, d));
80
822k
  buffer->used = 0;
81
822k
}
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
11.1M
{
769
11.1M
  DEBUG_printf("ippAddSeparator(ipp=%p)", (void *)ipp);
770
771
  // Range check input...
772
11.1M
  if (!ipp)
773
0
    return (NULL);
774
775
  // Create the attribute...
776
11.1M
  return (ipp_add_attr(ipp, NULL, IPP_TAG_ZERO, IPP_TAG_ZERO, 0));
777
11.1M
}
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.39k
{
811
5.39k
  ipp_tag_t   temp_tag; // Temporary value tag (masked)
812
5.39k
  ipp_attribute_t *attr;    // New attribute
813
5.39k
  char      code[IPP_MAX_LANGUAGE];
814
          // Charset/language code buffer
815
816
817
5.39k
  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.39k
  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.39k
  if (!ipp || !name || group < IPP_TAG_ZERO || group == IPP_TAG_END || group >= IPP_TAG_UNSUPPORTED_VALUE)
834
0
    return (NULL);
835
5.39k
#endif // 0
836
837
  // See if we need to map charset, language, or locale values...
838
5.39k
  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.39k
  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.39k
  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.69k
    value_tag = temp_tag;   // Don't do a fast copy
844
845
  // Create the attribute...
846
5.39k
  if ((attr = ipp_add_attr(ipp, name, group, value_tag, 1)) == NULL)
847
0
    return (NULL);
848
849
  // Initialize the attribute data...
850
5.39k
  if ((int)value_tag & IPP_TAG_CUPS_CONST)
851
2.69k
  {
852
2.69k
    attr->values[0].string.language = (char *)language;
853
2.69k
    attr->values[0].string.text     = (char *)value;
854
2.69k
  }
855
2.69k
  else
856
2.69k
  {
857
2.69k
    if (language)
858
0
      attr->values[0].string.language = _cupsStrAlloc(ipp_lang_code(language, code, sizeof(code)));
859
860
2.69k
    if (value)
861
2.69k
    {
862
2.69k
      if (value_tag == IPP_TAG_CHARSET)
863
0
  attr->values[0].string.text = _cupsStrAlloc(ipp_get_code(value, code, sizeof(code)));
864
2.69k
      else if (value_tag == IPP_TAG_LANGUAGE)
865
2.69k
  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.69k
    }
869
2.69k
  }
870
871
5.39k
  return (attr);
872
5.39k
}
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 11)
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
0
  if ((t = mktime(&unixdate)) < 0)
1618
0
    return (0);
1619
1620
0
  if (date[8] == '-')
1621
0
    t += date[9] * 3600 + date[10] * 60;
1622
0
  else
1623
0
    t -= date[9] * 3600 + date[10] * 60;
1624
1625
0
  return (t);
1626
0
}
1627
1628
1629
//
1630
// 'ippDelete()' - Delete an IPP message.
1631
//
1632
1633
void
1634
ippDelete(ipp_t *ipp)     // I - IPP message
1635
452k
{
1636
452k
  ipp_attribute_t *attr,    // Current attribute
1637
452k
      *next;    // Next attribute
1638
1639
1640
452k
  DEBUG_printf("ippDelete(ipp=%p)", (void *)ipp);
1641
1642
452k
  if (!ipp)
1643
14
    return;
1644
1645
452k
  ipp->use --;
1646
452k
  if (ipp->use > 0)
1647
0
  {
1648
0
    DEBUG_printf("4debug_retain: %p IPP message (use=%u)", (void *)ipp, (unsigned)ipp->use);
1649
0
    return;
1650
0
  }
1651
1652
452k
  DEBUG_printf("4debug_free: %p IPP message", (void *)ipp);
1653
1654
16.0M
  for (attr = ipp->attrs; attr != NULL; attr = next)
1655
15.6M
  {
1656
15.6M
    next = attr->next;
1657
1658
15.6M
    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);
1659
1660
15.6M
    ipp_free_values(attr, 0, attr->num_values);
1661
1662
15.6M
    if (attr->name)
1663
4.49M
      _cupsStrFree(attr->name);
1664
1665
15.6M
    free(attr);
1666
15.6M
  }
1667
1668
452k
  free(ipp);
1669
452k
}
1670
1671
1672
//
1673
// 'ippDeleteAttribute()' - Delete a single attribute in an IPP message.
1674
//
1675
1676
void
1677
ippDeleteAttribute(
1678
    ipp_t           *ipp,   // I - IPP message
1679
    ipp_attribute_t *attr)    // I - Attribute to delete
1680
2.29k
{
1681
2.29k
  ipp_attribute_t *current, // Current attribute
1682
2.29k
      *prev;    // Previous attribute
1683
1684
1685
2.29k
  DEBUG_printf("ippDeleteAttribute(ipp=%p, attr=%p(%s))", (void *)ipp, (void *)attr, attr ? attr->name : "(null)");
1686
1687
  // Range check input...
1688
2.29k
  if (!attr)
1689
0
    return;
1690
1691
2.29k
  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);
1692
1693
  // Find the attribute in the list...
1694
2.29k
  if (ipp)
1695
2.29k
  {
1696
9.73M
    for (current = ipp->attrs, prev = NULL; current; prev = current, current = current->next)
1697
9.73M
    {
1698
9.73M
      if (current == attr)
1699
2.29k
      {
1700
  // Found it, remove the attribute from the list...
1701
2.29k
  if (prev)
1702
1.09k
    prev->next = current->next;
1703
1.20k
  else
1704
1.20k
    ipp->attrs = current->next;
1705
1706
2.29k
  if (current == ipp->last)
1707
2.29k
    ipp->last = prev;
1708
1709
2.29k
        break;
1710
2.29k
      }
1711
9.73M
    }
1712
1713
2.29k
    if (!current)
1714
0
      return;
1715
2.29k
  }
1716
1717
  // Free memory used by the attribute...
1718
2.29k
  ipp_free_values(attr, 0, attr->num_values);
1719
1720
2.29k
  if (attr->name)
1721
2.25k
    _cupsStrFree(attr->name);
1722
1723
2.29k
  free(attr);
1724
2.29k
}
1725
1726
1727
//
1728
// 'ippDeleteValues()' - Delete values in an attribute.
1729
//
1730
// This function deletes one or more values in an attribute.  The "element"
1731
// parameter specifies the first value to delete, starting at `0`.  It must be
1732
// less than the number of values returned by @link ippGetCount@.
1733
//
1734
// The "attr" parameter may be modified as a result of setting the value,
1735
// which will set the variable to `NULL`.
1736
//
1737
// Deleting all values in an attribute deletes the attribute.
1738
//
1739
1740
bool          // O  - `true` on success, `false` on failure
1741
ippDeleteValues(
1742
    ipp_t           *ipp,   // I  - IPP message
1743
    ipp_attribute_t **attr,   // IO - Attribute
1744
    size_t          element,    // I  - Index of first value to delete (`0`-based)
1745
    size_t          count)    // I  - Number of values to delete
1746
0
{
1747
  // Range check input...
1748
0
  if (!ipp || !attr || !*attr || element >= (*attr)->num_values || !count || (element + count) >= (*attr)->num_values)
1749
0
    return (false);
1750
1751
  // If we are deleting all values, just delete the attribute entirely.
1752
0
  if (count == (*attr)->num_values)
1753
0
  {
1754
0
    ippDeleteAttribute(ipp, *attr);
1755
0
    *attr = NULL;
1756
0
    return (true);
1757
0
  }
1758
1759
  // Otherwise free the values in question and return.
1760
0
  ipp_free_values(*attr, element, count);
1761
1762
0
  return (true);
1763
0
}
1764
1765
1766
//
1767
// 'ippFindAttribute()' - Find a named attribute in an IPP message.
1768
//
1769
// This function finds the first occurrence of a named attribute in an IPP
1770
// message.  The attribute name can contain a hierarchical list of attribute and
1771
// member names separated by slashes, for example "media-col/media-size".
1772
//
1773
1774
ipp_attribute_t *     // O - Matching attribute
1775
ippFindAttribute(ipp_t      *ipp, // I - IPP message
1776
                 const char *name,  // I - Name of attribute
1777
     ipp_tag_t  type) // I - Type of attribute
1778
0
{
1779
0
  DEBUG_printf("2ippFindAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", (void *)ipp, name, type, ippTagString(type));
1780
1781
  // Range check input...
1782
0
  if (!ipp || !name)
1783
0
    return (NULL);
1784
1785
  // Reset the current attribute pointer...
1786
0
  ipp->find->attr  = NULL;
1787
0
  ipp->find->idx   = 0;
1788
0
  ipp->find->atend = false;
1789
1790
  // Search for the attribute...
1791
0
  return (ippFindNextAttribute(ipp, name, type));
1792
0
}
1793
1794
1795
//
1796
// 'ippFindNextAttribute()' - Find the next named attribute in an IPP message.
1797
//
1798
// This function finds the next named attribute in an IPP message.  The
1799
// attribute name can contain a hierarchical list of attribute and member names
1800
// separated by slashes, for example "media-col/media-size".
1801
//
1802
1803
ipp_attribute_t *     // O - Matching attribute
1804
ippFindNextAttribute(ipp_t      *ipp, // I - IPP message
1805
                     const char *name,  // I - Name of attribute
1806
         ipp_tag_t  type) // I - Type of attribute
1807
0
{
1808
0
  ipp_attribute_t *attr,    // Current attribute
1809
0
      *childattr; // Child attribute
1810
0
  ipp_tag_t   value_tag;  // Value tag
1811
0
  char      parent[1024], // Parent attribute name
1812
0
      *child = NULL;  // Child attribute name
1813
1814
1815
0
  DEBUG_printf("2ippFindNextAttribute(ipp=%p, name=\"%s\", type=%02x(%s))", (void *)ipp, name, type, ippTagString(type));
1816
1817
  // Range check input...
1818
0
  if (!ipp || !name)
1819
0
    return (NULL);
1820
1821
0
  DEBUG_printf("3ippFindNextAttribute: atend=%s", ipp->find->atend ? "true" : "false");
1822
1823
0
  if (ipp->find->atend)
1824
0
    return (NULL);
1825
1826
0
  if (strchr(name, '/'))
1827
0
  {
1828
    // Search for child attribute...
1829
0
    cupsCopyString(parent, name, sizeof(parent));
1830
0
    if ((child = strchr(parent, '/')) == NULL)
1831
0
    {
1832
0
      DEBUG_puts("3ippFindNextAttribute: Attribute name too long.");
1833
0
      return (NULL);
1834
0
    }
1835
1836
0
    *child++ = '\0';
1837
1838
0
    if (ipp->find->attr && ipp->find->attr->name && ipp->find->attr->value_tag == IPP_TAG_BEGIN_COLLECTION && !strcmp(parent, ipp->find->attr->name))
1839
0
    {
1840
0
      while (ipp->find->idx < ipp->find->attr->num_values)
1841
0
      {
1842
0
        if ((childattr = ippFindNextAttribute(ipp->find->attr->values[ipp->find->idx].collection, child, type)) != NULL)
1843
0
          return (childattr);
1844
1845
0
        ipp->find->idx ++;
1846
0
        if (ipp->find->idx < ipp->find->attr->num_values && ipp->find->attr->values[ipp->find->idx].collection)
1847
0
          ipp->find->attr->values[ipp->find->idx].collection->find->attr = NULL;
1848
0
      }
1849
1850
0
      ipp->find->attr = ipp->find->attr->next;
1851
0
      ipp->find->idx  = 0;
1852
1853
0
      if (!ipp->find->attr)
1854
0
      {
1855
0
        ipp->find->atend = true;
1856
0
        return (NULL);
1857
0
      }
1858
0
    }
1859
1860
0
    if (!ipp->find->attr)
1861
0
    {
1862
0
      ipp->find->attr = ipp->attrs;
1863
0
      ipp->find->idx  = 0;
1864
0
    }
1865
1866
0
    name = parent;
1867
0
    attr = ipp->find->attr;
1868
0
  }
1869
0
  else if (ipp->find->attr)
1870
0
  {
1871
0
    attr = ipp->find->attr->next;
1872
0
  }
1873
0
  else
1874
0
  {
1875
0
    attr = ipp->attrs;
1876
0
  }
1877
1878
0
  for (; attr != NULL; attr = attr->next)
1879
0
  {
1880
0
    DEBUG_printf("4ippFindAttribute: attr=%p, name=\"%s\"", (void *)attr, attr->name);
1881
1882
0
    value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK);
1883
1884
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)))
1885
0
    {
1886
0
      ipp->find->attr = attr;
1887
1888
0
      if (name == parent && attr->value_tag == IPP_TAG_BEGIN_COLLECTION)
1889
0
      {
1890
0
        size_t i;     // Looping var
1891
1892
0
        for (i = 0; i < attr->num_values; i ++)
1893
0
        {
1894
0
    if ((childattr = ippFindAttribute(attr->values[i].collection, child, type)) != NULL)
1895
0
    {
1896
0
      attr->values[0].collection->find->idx = i;
1897
0
      return (childattr);
1898
0
    }
1899
0
        }
1900
0
      }
1901
0
      else
1902
0
      {
1903
0
        return (attr);
1904
0
      }
1905
0
    }
1906
0
  }
1907
1908
  // If we get this far, we didn't find it...
1909
0
  ipp->find->attr  = NULL;
1910
0
  ipp->find->atend = true;
1911
1912
0
  return (NULL);
1913
0
}
1914
1915
1916
//
1917
// 'ippGetBoolean()' - Get a boolean value for an attribute.
1918
//
1919
// The "element" parameter specifies which value to get from `0` to
1920
// `ippGetCount(attr)` - 1.
1921
//
1922
1923
bool          // O - Boolean value or `false` on error
1924
ippGetBoolean(ipp_attribute_t *attr,  // I - IPP attribute
1925
              size_t          element)  // I - Value number (`0`-based)
1926
0
{
1927
  // Range check input...
1928
0
  if (!attr || attr->value_tag != IPP_TAG_BOOLEAN || element >= attr->num_values)
1929
0
    return (false);
1930
1931
  // Return the value...
1932
0
  return (attr->values[element].boolean);
1933
0
}
1934
1935
1936
//
1937
// 'ippGetCollection()' - Get a collection value for an attribute.
1938
//
1939
// The "element" parameter specifies which value to get from `0` to
1940
// `ippGetCount(attr)` - 1.
1941
//
1942
1943
ipp_t *         // O - Collection value or `NULL` on error
1944
ippGetCollection(
1945
    ipp_attribute_t *attr,    // I - IPP attribute
1946
    size_t          element)    // I - Value number (`0`-based)
1947
0
{
1948
  // Range check input...
1949
0
  if (!attr || attr->value_tag != IPP_TAG_BEGIN_COLLECTION || element >= attr->num_values)
1950
0
    return (NULL);
1951
1952
  // Return the value...
1953
0
  return (attr->values[element].collection);
1954
0
}
1955
1956
1957
//
1958
// 'ippGetCount()' - Get the number of values in an attribute.
1959
//
1960
1961
size_t          // O - Number of values or 0 on error
1962
ippGetCount(ipp_attribute_t *attr)  // I - IPP attribute
1963
0
{
1964
  // Range check input...
1965
0
  if (!attr)
1966
0
    return (0);
1967
1968
  // Return the number of values...
1969
0
  return (attr->num_values);
1970
0
}
1971
1972
1973
//
1974
// 'ippGetDate()' - Get a dateTime value for an attribute.
1975
//
1976
// The "element" parameter specifies which value to get from `0` to
1977
// `ippGetCount(attr)` - 1.
1978
//
1979
1980
const ipp_uchar_t *     // O - dateTime value or `NULL`
1981
ippGetDate(ipp_attribute_t *attr, // I - IPP attribute
1982
           size_t          element) // I - Value number (`0`-based)
1983
0
{
1984
  // Range check input...
1985
0
  if (!attr || attr->value_tag != IPP_TAG_DATE || element >= attr->num_values)
1986
0
    return (NULL);
1987
1988
  // Return the value...
1989
0
  return (attr->values[element].date);
1990
0
}
1991
1992
1993
//
1994
// 'ippGetFirstAttribute()' - Return the first attribute in the message.
1995
//
1996
1997
ipp_attribute_t *     // O - First attribute or `NULL` if none
1998
ippGetFirstAttribute(ipp_t *ipp)  // I - IPP message
1999
0
{
2000
  // Range check input...
2001
0
  if (!ipp)
2002
0
    return (NULL);
2003
2004
0
  if (!ipp->find)
2005
0
    ipp->find = ipp->fstack;
2006
2007
0
  ipp->find->attr  = ipp->attrs;
2008
0
  ipp->find->idx   = 0;
2009
0
  ipp->find->atend = ipp->find->attr == NULL;
2010
2011
  // Return the first attribute...
2012
0
  return (ipp->find->attr);
2013
0
}
2014
2015
2016
//
2017
// 'ippGetGroupTag()' - Get the group associated with an attribute.
2018
//
2019
2020
ipp_tag_t       // O - Group tag or `IPP_TAG_ZERO` on error
2021
ippGetGroupTag(ipp_attribute_t *attr) // I - IPP attribute
2022
0
{
2023
  // Range check input...
2024
0
  if (!attr)
2025
0
    return (IPP_TAG_ZERO);
2026
2027
  // Return the group...
2028
0
  return (attr->group_tag);
2029
0
}
2030
2031
2032
//
2033
// 'ippGetInteger()' - Get the integer/enum value for an attribute.
2034
//
2035
// The "element" parameter specifies which value to get from `0` to
2036
// `ippGetCount(attr)` - 1.
2037
//
2038
2039
int         // O - Value or `0` on error
2040
ippGetInteger(ipp_attribute_t *attr,  // I - IPP attribute
2041
              size_t          element)  // I - Value number (`0`-based)
2042
0
{
2043
  // Range check input...
2044
0
  if (!attr || (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM) || element >= attr->num_values)
2045
0
    return (0);
2046
2047
  // Return the value...
2048
0
  return (attr->values[element].integer);
2049
0
}
2050
2051
2052
//
2053
// 'ippGetLength()' - Compute the length of an IPP message.
2054
//
2055
2056
size_t          // O - Size of IPP message
2057
ippGetLength(ipp_t *ipp)    // I - IPP message
2058
0
{
2059
0
  return (ipp_length(ipp, 0));
2060
0
}
2061
2062
2063
//
2064
// 'ippGetName()' - Get the attribute name.
2065
//
2066
2067
const char *        // O - Attribute name or `NULL` for separators
2068
ippGetName(ipp_attribute_t *attr) // I - IPP attribute
2069
0
{
2070
  // Range check input...
2071
0
  if (!attr)
2072
0
    return (NULL);
2073
2074
  // Return the name...
2075
0
  return (attr->name);
2076
0
}
2077
2078
2079
//
2080
// 'ippGetNextAttribute()' - Return the next attribute in the message.
2081
//
2082
2083
ipp_attribute_t *     // O - Next attribute or `NULL` if none
2084
ippGetNextAttribute(ipp_t *ipp)   // I - IPP message
2085
0
{
2086
  // Range check input...
2087
0
  if (!ipp || !ipp->find || !ipp->find->attr)
2088
0
    return (NULL);
2089
2090
0
  ipp->find->attr  = ipp->find->attr->next;
2091
0
  ipp->find->atend = ipp->find->attr == NULL;
2092
2093
  // Return the next attribute...
2094
0
  return (ipp->find->attr);
2095
0
}
2096
2097
2098
//
2099
// 'ippGetOctetString()' - Get an octetString value from an IPP attribute.
2100
//
2101
// The "element" parameter specifies which value to get from '0' to
2102
// `ippGetCount(attr)` - 1.
2103
//
2104
2105
void *          // O - Pointer to octetString data
2106
ippGetOctetString(
2107
    ipp_attribute_t *attr,    // I - IPP attribute
2108
    size_t          element,    // I - Value number (`0`-based)
2109
    size_t          *datalen)   // O - Length of octetString data
2110
0
{
2111
  // Range check input...
2112
0
  if (!attr || (attr->value_tag != IPP_TAG_STRING && attr->value_tag != IPP_TAG_EXTENSION) || element >= attr->num_values)
2113
0
  {
2114
0
    if (datalen)
2115
0
      *datalen = 0;
2116
2117
0
    return (NULL);
2118
0
  }
2119
2120
  // Return the values...
2121
0
  if (datalen)
2122
0
    *datalen = attr->values[element].unknown.length;
2123
2124
0
  return (attr->values[element].unknown.data);
2125
0
}
2126
2127
2128
//
2129
// 'ippGetOperation()' - Get the operation ID in an IPP message.
2130
//
2131
2132
ipp_op_t        // O - Operation ID or 0 on error
2133
ippGetOperation(ipp_t *ipp)   // I - IPP request message
2134
0
{
2135
  // Range check input...
2136
0
  if (!ipp)
2137
0
    return ((ipp_op_t)0);
2138
2139
  // Return the value...
2140
0
  return (ipp->request.op.operation_id);
2141
0
}
2142
2143
2144
//
2145
// 'ippGetRange()' - Get a rangeOfInteger value from an attribute.
2146
//
2147
// The "element" parameter specifies which value to get from `0` to
2148
// `ippGetCount(attr)` - 1.
2149
//
2150
2151
int         // O - Lower value of range or 0
2152
ippGetRange(ipp_attribute_t *attr,  // I - IPP attribute
2153
      size_t          element,  // I - Value number (`0`-based)
2154
      int             *uppervalue)// O - Upper value of range
2155
0
{
2156
  // Range check input...
2157
0
  if (!attr || attr->value_tag != IPP_TAG_RANGE || element >= attr->num_values)
2158
0
  {
2159
0
    if (uppervalue)
2160
0
      *uppervalue = 0;
2161
2162
0
    return (0);
2163
0
  }
2164
2165
  // Return the values...
2166
0
  if (uppervalue)
2167
0
    *uppervalue = attr->values[element].range.upper;
2168
2169
0
  return (attr->values[element].range.lower);
2170
0
}
2171
2172
2173
//
2174
// 'ippGetRequestId()' - Get the request ID from an IPP message.
2175
//
2176
2177
int         // O - Request ID or 0 on error
2178
ippGetRequestId(ipp_t *ipp)   // I - IPP message
2179
0
{
2180
  // Range check input...
2181
0
  if (!ipp)
2182
0
    return (0);
2183
2184
  // Return the request ID...
2185
0
  return (ipp->request.any.request_id);
2186
0
}
2187
2188
2189
//
2190
// 'ippGetResolution()' - Get a resolution value for an attribute.
2191
//
2192
// The "element" parameter specifies which value to get from `0` to
2193
// `ippGetCount(attr)` - 1.
2194
//
2195
2196
int         // O - Horizontal/cross feed resolution or 0
2197
ippGetResolution(
2198
    ipp_attribute_t *attr,    // I - IPP attribute
2199
    size_t          element,    // I - Value number (`0`-based)
2200
    int             *yres,    // O - Vertical/feed resolution
2201
    ipp_res_t       *units)   // O - Units for resolution
2202
0
{
2203
  // Range check input...
2204
0
  if (!attr || attr->value_tag != IPP_TAG_RESOLUTION || element >= attr->num_values)
2205
0
  {
2206
0
    if (yres)
2207
0
      *yres = 0;
2208
2209
0
    if (units)
2210
0
      *units = (ipp_res_t)0;
2211
2212
0
    return (0);
2213
0
  }
2214
2215
  // Return the value...
2216
0
  if (yres)
2217
0
    *yres = attr->values[element].resolution.yres;
2218
2219
0
  if (units)
2220
0
    *units = attr->values[element].resolution.units;
2221
2222
0
  return (attr->values[element].resolution.xres);
2223
0
}
2224
2225
2226
//
2227
// 'ippGetState()' - Get the IPP message state.
2228
//
2229
2230
ipp_state_t       // O - IPP message state value
2231
ippGetState(ipp_t *ipp)     // I - IPP message
2232
0
{
2233
  // Range check input...
2234
0
  if (!ipp)
2235
0
    return (IPP_STATE_IDLE);
2236
2237
  // Return the value...
2238
0
  return (ipp->state);
2239
0
}
2240
2241
2242
//
2243
// 'ippGetStatusCode()' - Get the status code from an IPP response or event message.
2244
//
2245
2246
ipp_status_t        // O - Status code in IPP message
2247
ippGetStatusCode(ipp_t *ipp)    // I - IPP response or event message
2248
0
{
2249
  // Range check input...
2250
0
  if (!ipp)
2251
0
    return (IPP_STATUS_ERROR_INTERNAL);
2252
2253
  // Return the value...
2254
0
  return (ipp->request.status.status_code);
2255
0
}
2256
2257
2258
//
2259
// 'ippGetString()' - Get the string and optionally the language code for an attribute.
2260
//
2261
// The "element" parameter specifies which value to get from `0` to
2262
// `ippGetCount(attr) - 1`.
2263
//
2264
2265
const char *
2266
ippGetString(ipp_attribute_t *attr, // I - IPP attribute
2267
             size_t          element, // I - Value number (`0`-based)
2268
       const char      **language)// O - Language code (`NULL` for don't care)
2269
0
{
2270
0
  ipp_tag_t tag;      // Value tag
2271
2272
2273
  // Range check input...
2274
0
  tag = ippGetValueTag(attr);
2275
2276
0
  if (!attr || element >= attr->num_values || (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG && (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE)))
2277
0
    return (NULL);
2278
2279
  // Return the value...
2280
0
  if (language)
2281
0
    *language = attr->values[element].string.language;
2282
2283
0
  return (attr->values[element].string.text);
2284
0
}
2285
2286
2287
//
2288
// 'ippGetValueTag()' - Get the value tag for an attribute.
2289
//
2290
2291
ipp_tag_t       // O - Value tag or `IPP_TAG_ZERO` on error
2292
ippGetValueTag(ipp_attribute_t *attr) // I - IPP attribute
2293
0
{
2294
  // Range check input...
2295
0
  if (!attr)
2296
0
    return (IPP_TAG_ZERO);
2297
2298
  // Return the value...
2299
0
  return (attr->value_tag & IPP_TAG_CUPS_MASK);
2300
0
}
2301
2302
2303
//
2304
// 'ippGetVersion()' - Get the major and minor version number from an IPP message.
2305
//
2306
2307
int         // O - Major version number or 0 on error
2308
ippGetVersion(ipp_t *ipp,   // I - IPP message
2309
              int   *minor)   // O - Minor version number or `NULL` for don't care
2310
0
{
2311
  // Range check input...
2312
0
  if (!ipp)
2313
0
  {
2314
0
    if (minor)
2315
0
      *minor = 0;
2316
2317
0
    return (0);
2318
0
  }
2319
2320
  // Return the value...
2321
0
  if (minor)
2322
0
    *minor = ipp->request.any.version[1];
2323
2324
0
  return (ipp->request.any.version[0]);
2325
0
}
2326
2327
2328
//
2329
// 'ippNew()' - Allocate a new IPP message.
2330
//
2331
2332
ipp_t *         // O - New IPP message
2333
ippNew(void)
2334
452k
{
2335
452k
  ipp_t     *temp;    // New IPP message
2336
452k
  _cups_globals_t *cg = _cupsGlobals();
2337
          // Global data
2338
2339
2340
452k
  DEBUG_puts("ippNew()");
2341
2342
452k
  if ((temp = (ipp_t *)calloc(1, sizeof(ipp_t))) != NULL)
2343
452k
  {
2344
    // Set default version - usually 2.0...
2345
452k
    DEBUG_printf("4debug_alloc: %p IPP message", (void *)temp);
2346
2347
452k
    if (cg->server_version == 0)
2348
1
      _cupsSetDefaults();
2349
2350
452k
    temp->request.any.version[0] = (ipp_uchar_t)(cg->server_version / 10);
2351
452k
    temp->request.any.version[1] = (ipp_uchar_t)(cg->server_version % 10);
2352
452k
    temp->use                    = 1;
2353
452k
    temp->find                   = temp->fstack;
2354
452k
  }
2355
2356
452k
  DEBUG_printf("1ippNew: Returning %p", (void *)temp);
2357
2358
452k
  return (temp);
2359
452k
}
2360
2361
2362
//
2363
//  'ippNewRequest()' - Allocate a new IPP request message.
2364
//
2365
// The new request message is initialized with the "attributes-charset" and
2366
// "attributes-natural-language" attributes added. The
2367
// "attributes-natural-language" value is derived from the current locale.
2368
//
2369
2370
ipp_t *         // O - IPP request message
2371
ippNewRequest(ipp_op_t op)    // I - Operation code
2372
2.69k
{
2373
2.69k
  ipp_t   *request;   // IPP request message
2374
2.69k
  cups_lang_t *language;    // Current language localization
2375
2.69k
  static int  request_id = 0;   // Current request ID
2376
2.69k
  static cups_mutex_t request_mutex = CUPS_MUTEX_INITIALIZER;
2377
          // Mutex for request ID
2378
2379
2380
2.69k
  DEBUG_printf("ippNewRequest(op=%02x(%s))", op, ippOpString(op));
2381
2382
  // Create a new IPP message...
2383
2.69k
  if ((request = ippNew()) == NULL)
2384
0
    return (NULL);
2385
2386
  // Set the operation and request ID...
2387
2.69k
  cupsMutexLock(&request_mutex);
2388
2389
2.69k
  request->request.op.operation_id = op;
2390
2.69k
  request->request.op.request_id   = ++request_id;
2391
2392
2.69k
  cupsMutexUnlock(&request_mutex);
2393
2394
  // Use UTF-8 as the character set...
2395
2.69k
  ippAddString(request, IPP_TAG_OPERATION, IPP_CONST_TAG(IPP_TAG_CHARSET), "attributes-charset", NULL, "utf-8");
2396
2397
  // Get the language from the current locale...
2398
2.69k
  language = cupsLangDefault();
2399
2400
2.69k
  ippAddString(request, IPP_TAG_OPERATION, IPP_CONST_TAG(IPP_TAG_LANGUAGE), "attributes-natural-language", NULL, cupsLangGetName(language));
2401
2402
  // Return the new request...
2403
2.69k
  return (request);
2404
2.69k
}
2405
2406
2407
//
2408
// 'ippNewResponse()' - Allocate a new IPP response message.
2409
//
2410
// The new response message is initialized with the same "version-number",
2411
// "request-id", "attributes-charset", and "attributes-natural-language" as the
2412
// provided request message.  If the "attributes-charset" or
2413
// "attributes-natural-language" attributes are missing from the request,
2414
// 'utf-8' and a value derived from the current locale are substituted,
2415
// respectively.
2416
//
2417
2418
ipp_t *         // O - IPP response message
2419
ippNewResponse(ipp_t *request)    // I - IPP request message
2420
0
{
2421
0
  ipp_t     *response;  // IPP response message
2422
0
  ipp_attribute_t *attr;    // Current attribute
2423
2424
2425
  // Range check input...
2426
0
  if (!request)
2427
0
    return (NULL);
2428
2429
  // Create a new IPP message...
2430
0
  if ((response = ippNew()) == NULL)
2431
0
    return (NULL);
2432
2433
  // Copy the request values over to the response...
2434
0
  response->request.status.version[0] = request->request.op.version[0];
2435
0
  response->request.status.version[1] = request->request.op.version[1];
2436
0
  response->request.status.request_id = request->request.op.request_id;
2437
2438
  // The first attribute MUST be attributes-charset...
2439
0
  attr = request->attrs;
2440
2441
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)
2442
0
  {
2443
    // Copy charset from request...
2444
0
    ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, attr->values[0].string.text);
2445
0
  }
2446
0
  else
2447
0
  {
2448
    // Use "utf-8" as the default...
2449
0
    ippAddString(response, IPP_TAG_OPERATION, IPP_CONST_TAG(IPP_TAG_CHARSET), "attributes-charset", NULL, "utf-8");
2450
0
  }
2451
2452
  // Then attributes-natural-language...
2453
0
  if (attr)
2454
0
    attr = attr->next;
2455
2456
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)
2457
0
  {
2458
    // Copy language from request...
2459
0
    ippAddString(response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, attr->values[0].string.text);
2460
0
  }
2461
0
  else
2462
0
  {
2463
    // Use the language from the current locale...
2464
0
    cups_lang_t *language = cupsLangDefault();
2465
          // Current locale
2466
2467
0
    ippAddString(response, IPP_TAG_OPERATION, IPP_CONST_TAG(IPP_TAG_LANGUAGE), "attributes-natural-language", NULL, cupsLangGetName(language));
2468
0
  }
2469
2470
0
  return (response);
2471
0
}
2472
2473
2474
//
2475
// 'ippRead()' - Read data for an IPP message from a HTTP connection.
2476
//
2477
2478
ipp_state_t       // O - Current state
2479
ippRead(http_t *http,     // I - HTTP connection
2480
        ipp_t  *ipp)      // I - IPP data
2481
0
{
2482
0
  DEBUG_printf("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT, (void *)http, (void *)ipp, CUPS_LLCAST (http ? http->data_remaining : -1));
2483
2484
0
  if (!http || !ipp)
2485
0
    return (IPP_STATE_ERROR);
2486
2487
0
  DEBUG_printf("2ippRead: http->state=%d, http->used=%d", http->state, http->used);
2488
2489
0
  return (ipp_read_io(http, (ipp_io_cb_t)ipp_read_http, http->blocking, /*parent*/NULL, ipp, /*depth*/0));
2490
0
}
2491
2492
2493
//
2494
// 'ippReadFile()' - Read data for an IPP message from a file.
2495
//
2496
2497
ipp_state_t       // O - Current state
2498
ippReadFile(int   fd,     // I - HTTP data
2499
            ipp_t *ipp)     // I - IPP data
2500
0
{
2501
0
  DEBUG_printf("ippReadFile(fd=%d, ipp=%p)", fd, (void *)ipp);
2502
2503
0
  if (!ipp)
2504
0
    return (IPP_STATE_ERROR);
2505
2506
0
  return (ipp_read_io(&fd, (ipp_io_cb_t)ipp_read_file, /*blocking*/true, /*parent*/NULL, ipp, /*depth*/0));
2507
0
}
2508
2509
2510
//
2511
// 'ippReadIO()' - Read data for an IPP message.
2512
//
2513
2514
ipp_state_t       // O - Current state
2515
ippReadIO(void        *src,   // I - Data source
2516
          ipp_io_cb_t cb,   // I - Read callback function
2517
    bool        blocking,   // I - Use blocking IO?
2518
    ipp_t       *parent,    // I - Parent request, if any
2519
          ipp_t       *ipp)   // I - IPP data
2520
2.69k
{
2521
2.69k
  DEBUG_printf("ippReadIO(src=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)src, (void *)cb, blocking, (void *)parent, (void *)ipp);
2522
2523
2.69k
  if (!src || !ipp)
2524
0
    return (IPP_STATE_ERROR);
2525
2526
2.69k
  return (ipp_read_io(src, cb, blocking, parent, ipp, /*depth*/0));
2527
2.69k
}
2528
2529
2530
//
2531
// 'ippRestore()' - Restore a previously saved find position.
2532
//
2533
2534
void
2535
ippRestore(ipp_t *ipp)      // I - IPP message
2536
0
{
2537
0
  if (ipp)
2538
0
  {
2539
0
    if (ipp->find > ipp->fstack)
2540
0
      ipp->find --;
2541
0
    else
2542
0
      ipp->find = NULL;
2543
0
  }
2544
0
}
2545
2546
2547
//
2548
// 'ippSave()' - Save the current find position.
2549
//
2550
2551
void
2552
ippSave(ipp_t *ipp)     // I - IPP message
2553
0
{
2554
0
  if (ipp && ipp->find < (ipp->fstack + _IPP_MAX_FIND))
2555
0
  {
2556
0
    ipp->find[1] = ipp->find[0];
2557
0
    ipp->find ++;
2558
0
  }
2559
0
}
2560
2561
2562
//
2563
// 'ippSetBoolean()' - Set a boolean value in an attribute.
2564
//
2565
// The "ipp" parameter refers to an IPP message previously created using
2566
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
2567
//
2568
// The "attr" parameter may be modified as a result of setting the value.
2569
//
2570
// The "element" parameter specifies which value to set from `0` to
2571
// `ippGetCount(attr)`.
2572
//
2573
2574
bool          // O  - `true` on success, `false` on failure
2575
ippSetBoolean(ipp_t           *ipp, // I  - IPP message
2576
              ipp_attribute_t **attr, // IO - IPP attribute
2577
              size_t          element,  // I  - Value number (`0`-based)
2578
              bool            boolvalue)// I  - Boolean value
2579
0
{
2580
0
  _ipp_value_t  *value;     // Current value
2581
2582
2583
  // Range check input...
2584
0
  if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BOOLEAN || element > (*attr)->num_values)
2585
0
    return (false);
2586
2587
  // Set the value and return...
2588
0
  if ((value = ipp_set_value(ipp, attr, element)) != NULL)
2589
0
    value->boolean = boolvalue;
2590
2591
0
  return (value != NULL);
2592
0
}
2593
2594
2595
//
2596
// 'ippSetCollection()' - Set a collection value in an attribute.
2597
//
2598
// The "ipp" parameter refers to an IPP message previously created using
2599
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
2600
//
2601
// The "attr" parameter may be modified as a result of setting the value.
2602
//
2603
// The "element" parameter specifies which value to set from `0` to
2604
// `ippGetCount(attr)`.
2605
//
2606
2607
bool          // O  - `true` on success, `false` on failure
2608
ippSetCollection(
2609
    ipp_t           *ipp,   // I  - IPP message
2610
    ipp_attribute_t **attr,   // IO - IPP attribute
2611
    size_t          element,    // I  - Value number (`0`-based)
2612
    ipp_t           *colvalue)    // I  - Collection value
2613
0
{
2614
0
  _ipp_value_t  *value;     // Current value
2615
2616
2617
  // Range check input...
2618
0
  if (!ipp || !attr || !*attr || (*attr)->value_tag != IPP_TAG_BEGIN_COLLECTION || element > (*attr)->num_values || !colvalue)
2619
0
    return (false);
2620
2621
  // Set the value and return...
2622
0
  if ((value = ipp_set_value(ipp, attr, element)) != NULL)
2623
0
  {
2624
0
    if (value->collection)
2625
0
      ippDelete(value->collection);
2626
2627
0
    value->collection = colvalue;
2628
0
    colvalue->use ++;
2629
0
  }
2630
2631
0
  return (value != NULL);
2632
0
}
2633
2634
2635
//
2636
// 'ippSetDate()' - Set a dateTime value in an attribute.
2637
//
2638
// The "ipp" parameter refers to an IPP message previously created using
2639
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
2640
//
2641
// The "attr" parameter may be modified as a result of setting the value.
2642
//
2643
// The "element" parameter specifies which value to set from `0` to
2644
// `ippGetCount(attr)`.
2645
//
2646
2647
bool          // O  - `true` on success, `false` on failure
2648
ippSetDate(ipp_t             *ipp,  // I  - IPP message
2649
           ipp_attribute_t   **attr,  // IO - IPP attribute
2650
           size_t            element, // I  - Value number (`0`-based)
2651
           const ipp_uchar_t *datevalue)// I  - dateTime value
2652
0
{
2653
0
  _ipp_value_t  *value;     // Current value
2654
2655
2656
  // Range check input...
2657
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)
2658
0
    return (false);
2659
2660
  // Set the value and return...
2661
0
  if ((value = ipp_set_value(ipp, attr, element)) != NULL)
2662
0
  {
2663
0
    (*attr)->value_tag = IPP_TAG_DATE;
2664
0
    memcpy(value->date, datevalue, sizeof(value->date));
2665
0
  }
2666
2667
0
  return (value != NULL);
2668
0
}
2669
2670
2671
//
2672
// 'ippSetGroupTag()' - Set the group tag of an attribute.
2673
//
2674
// The "ipp" parameter refers to an IPP message previously created using
2675
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
2676
//
2677
// The "attr" parameter may be modified as a result of setting the value.
2678
//
2679
// The "group" parameter specifies the IPP attribute group tag: none
2680
// (`IPP_TAG_ZERO`, for member attributes), document (`IPP_TAG_DOCUMENT`),
2681
// event notification (`IPP_TAG_EVENT_NOTIFICATION`), operation
2682
// (`IPP_TAG_OPERATION`), printer (`IPP_TAG_PRINTER`), subscription
2683
// (`IPP_TAG_SUBSCRIPTION`), or unsupported (`IPP_TAG_UNSUPPORTED_GROUP`).
2684
//
2685
2686
bool          // O  - `true` on success, `false` on failure
2687
ippSetGroupTag(
2688
    ipp_t           *ipp,   // I  - IPP message
2689
    ipp_attribute_t **attr,   // IO - Attribute
2690
    ipp_tag_t       group_tag)    // I  - Group tag
2691
0
{
2692
  // Range check input - group tag must be 0x01 to 0x0F, per RFC 8011...
2693
0
  if (!ipp || !attr || !*attr || group_tag < IPP_TAG_ZERO || group_tag == IPP_TAG_END || group_tag >= IPP_TAG_UNSUPPORTED_VALUE)
2694
0
    return (false);
2695
2696
  // Set the group tag and return...
2697
0
  (*attr)->group_tag = group_tag;
2698
2699
0
  return (true);
2700
0
}
2701
2702
2703
//
2704
// 'ippSetInteger()' - Set an integer or enum value in an attribute.
2705
//
2706
// The "ipp" parameter refers to an IPP message previously created using
2707
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
2708
//
2709
// The "attr" parameter may be modified as a result of setting the value.
2710
//
2711
// The "element" parameter specifies which value to set from `0` to
2712
// `ippGetCount(attr)`.
2713
//
2714
2715
bool          // O  - `true` on success, `false` on failure
2716
ippSetInteger(ipp_t           *ipp, // I  - IPP message
2717
              ipp_attribute_t **attr, // IO - IPP attribute
2718
              size_t          element,  // I  - Value number (`0`-based)
2719
              int             intvalue) // I  - Integer/enum value
2720
0
{
2721
0
  _ipp_value_t  *value;     // Current value
2722
2723
2724
  // Range check input...
2725
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)
2726
0
    return (false);
2727
2728
  // Set the value and return...
2729
0
  if ((value = ipp_set_value(ipp, attr, element)) != NULL)
2730
0
  {
2731
0
    if ((*attr)->value_tag != IPP_TAG_ENUM)
2732
0
      (*attr)->value_tag = IPP_TAG_INTEGER;
2733
2734
0
    value->integer = intvalue;
2735
0
  }
2736
2737
0
  return (value != NULL);
2738
0
}
2739
2740
2741
//
2742
// 'ippSetName()' - Set the name of an attribute.
2743
//
2744
// The "ipp" parameter refers to an IPP message previously created using
2745
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
2746
//
2747
// The "attr" parameter may be modified as a result of setting the value.
2748
//
2749
2750
bool          // O  - `true` on success, `false` on failure
2751
ippSetName(ipp_t           *ipp,  // I  - IPP message
2752
     ipp_attribute_t **attr,  // IO - IPP attribute
2753
     const char      *name) // I  - Attribute name
2754
0
{
2755
0
  char  *temp;        // Temporary name value
2756
2757
2758
  // Range check input...
2759
0
  if (!ipp || !attr || !*attr || !name)
2760
0
    return (false);
2761
2762
  // Set the value and return...
2763
0
  if ((temp = _cupsStrAlloc(name)) != NULL)
2764
0
  {
2765
0
    if ((*attr)->name)
2766
0
      _cupsStrFree((*attr)->name);
2767
2768
0
    (*attr)->name = temp;
2769
0
  }
2770
2771
0
  return (temp != NULL);
2772
0
}
2773
2774
2775
//
2776
// 'ippSetOctetString()' - Set an octetString value in an IPP attribute.
2777
//
2778
// The "ipp" parameter refers to an IPP message previously created using
2779
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
2780
//
2781
// The "attr" parameter may be modified as a result of setting the value.
2782
//
2783
// The "element" parameter specifies which value to set from `0` to
2784
// `ippGetCount(attr)`.
2785
//
2786
2787
bool          // O  - `true` on success, `false` on failure
2788
ippSetOctetString(
2789
    ipp_t           *ipp,   // I  - IPP message
2790
    ipp_attribute_t **attr,   // IO - IPP attribute
2791
    size_t          element,    // I  - Value number (`0`-based)
2792
    const void      *data,    // I  - Pointer to octetString data
2793
    size_t          datalen)    // I  - Length of octetString data
2794
0
{
2795
0
  _ipp_value_t  *value;     // Current value
2796
2797
2798
  // Range check input...
2799
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)
2800
0
    return (false);
2801
2802
  // Set the value and return...
2803
0
  if ((value = ipp_set_value(ipp, attr, element)) != NULL)
2804
0
  {
2805
0
    if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST)
2806
0
    {
2807
      // Just copy the pointer...
2808
0
      value->unknown.data   = (void *)data;
2809
0
      value->unknown.length = datalen;
2810
0
    }
2811
0
    else
2812
0
    {
2813
      // Copy the data...
2814
0
      (*attr)->value_tag = IPP_TAG_STRING;
2815
2816
0
      if (value->unknown.data)
2817
0
      {
2818
        // Free previous data...
2819
0
  free(value->unknown.data);
2820
2821
0
  value->unknown.data   = NULL;
2822
0
        value->unknown.length = 0;
2823
0
      }
2824
2825
0
      if (datalen > 0)
2826
0
      {
2827
0
  void  *temp;      // Temporary data pointer
2828
2829
0
  if ((temp = malloc((size_t)datalen)) != NULL)
2830
0
  {
2831
0
    memcpy(temp, data, (size_t)datalen);
2832
2833
0
    value->unknown.data   = temp;
2834
0
    value->unknown.length = datalen;
2835
0
  }
2836
0
  else
2837
0
    return (false);
2838
0
      }
2839
0
    }
2840
0
  }
2841
2842
0
  return (value != NULL);
2843
0
}
2844
2845
2846
//
2847
// 'ippSetOperation()' - Set the operation ID in an IPP request message.
2848
//
2849
// The "ipp" parameter refers to an IPP message previously created using
2850
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
2851
//
2852
2853
bool          // O  - `true` on success, `false` on failure
2854
ippSetOperation(ipp_t    *ipp,    // I - IPP request message
2855
                ipp_op_t op)    // I - Operation ID
2856
0
{
2857
  // Range check input...
2858
0
  if (!ipp)
2859
0
    return (false);
2860
2861
  // Set the operation and return...
2862
0
  ipp->request.op.operation_id = op;
2863
2864
0
  return (true);
2865
0
}
2866
2867
2868
//
2869
// 'ippSetRange()' - Set a rangeOfInteger value in an attribute.
2870
//
2871
// The "ipp" parameter refers to an IPP message previously created using
2872
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
2873
//
2874
// The "attr" parameter may be modified as a result of setting the value.
2875
//
2876
// The "element" parameter specifies which value to set from `0` to
2877
// `ippGetCount(attr)`.
2878
//
2879
2880
bool          // O  - `true` on success, `false` on failure
2881
ippSetRange(ipp_t           *ipp, // I  - IPP message
2882
            ipp_attribute_t **attr, // IO - IPP attribute
2883
            size_t          element,  // I  - Value number (`0`-based)
2884
      int             lowervalue, // I  - Lower bound for range
2885
      int             uppervalue) // I  - Upper bound for range
2886
0
{
2887
0
  _ipp_value_t  *value;     // Current value
2888
2889
2890
  // Range check input...
2891
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)
2892
0
    return (false);
2893
2894
  // Set the value and return...
2895
0
  if ((value = ipp_set_value(ipp, attr, element)) != NULL)
2896
0
  {
2897
0
    (*attr)->value_tag = IPP_TAG_RANGE;
2898
0
    value->range.lower = lowervalue;
2899
0
    value->range.upper = uppervalue;
2900
0
  }
2901
2902
0
  return (value != NULL);
2903
0
}
2904
2905
2906
//
2907
// 'ippSetRequestId()' - Set the request ID in an IPP message.
2908
//
2909
// The "ipp" parameter refers to an IPP message previously created using
2910
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
2911
//
2912
// The "request_id" parameter must be greater than 0.
2913
//
2914
2915
bool          // O  - `true` on success, `false` on failure
2916
ippSetRequestId(ipp_t *ipp,   // I - IPP message
2917
                int   request_id) // I - Request ID
2918
0
{
2919
  // Range check input; not checking request_id values since ipptool wants to send
2920
  // invalid values for conformance testing and a bad request_id does not affect the
2921
  // encoding of a message...
2922
0
  if (!ipp)
2923
0
    return (false);
2924
2925
  // Set the request ID and return...
2926
0
  ipp->request.any.request_id = request_id;
2927
2928
0
  return (true);
2929
0
}
2930
2931
2932
//
2933
// 'ippSetResolution()' - Set a resolution value in an attribute.
2934
//
2935
// The "ipp" parameter refers to an IPP message previously created using
2936
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
2937
//
2938
// The "attr" parameter may be modified as a result of setting the value.
2939
//
2940
// The "element" parameter specifies which value to set from `0` to
2941
// `ippGetCount(attr)`.
2942
//
2943
2944
bool          // O  - `true` on success, `false` on failure
2945
ippSetResolution(
2946
    ipp_t           *ipp,   // I  - IPP message
2947
    ipp_attribute_t **attr,   // IO - IPP attribute
2948
    size_t          element,    // I  - Value number (`0`-based)
2949
    ipp_res_t       unitsvalue,   // I  - Resolution units
2950
    int             xresvalue,    // I  - Horizontal/cross feed resolution
2951
    int             yresvalue)    // I  - Vertical/feed resolution
2952
0
{
2953
0
  _ipp_value_t  *value;     // Current value
2954
2955
2956
  // Range check input...
2957
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)
2958
0
    return (false);
2959
2960
  // Set the value and return...
2961
0
  if ((value = ipp_set_value(ipp, attr, element)) != NULL)
2962
0
  {
2963
0
    (*attr)->value_tag      = IPP_TAG_RESOLUTION;
2964
0
    value->resolution.units = unitsvalue;
2965
0
    value->resolution.xres  = xresvalue;
2966
0
    value->resolution.yres  = yresvalue;
2967
0
  }
2968
2969
0
  return (value != NULL);
2970
0
}
2971
2972
2973
//
2974
// 'ippSetState()' - Set the current state of the IPP message.
2975
//
2976
2977
bool          // O  - `true` on success, `false` on failure
2978
ippSetState(ipp_t       *ipp,   // I - IPP message
2979
            ipp_state_t state)    // I - IPP state value
2980
2.69k
{
2981
  // Range check input...
2982
2.69k
  if (!ipp)
2983
0
    return (false);
2984
2985
  // Set the state and return...
2986
2.69k
  ipp->state   = state;
2987
2.69k
  ipp->current = NULL;
2988
2989
2.69k
  return (true);
2990
2.69k
}
2991
2992
2993
//
2994
// 'ippSetStatusCode()' - Set the status code in an IPP response or event message.
2995
//
2996
// The "ipp" parameter refers to an IPP message previously created using
2997
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
2998
//
2999
3000
bool          // O  - `true` on success, `false` on failure
3001
ippSetStatusCode(ipp_t        *ipp, // I - IPP response or event message
3002
                 ipp_status_t status) // I - Status code
3003
0
{
3004
  // Range check input...
3005
0
  if (!ipp)
3006
0
    return (false);
3007
3008
  // Set the status code and return...
3009
0
  ipp->request.status.status_code = status;
3010
3011
0
  return (true);
3012
0
}
3013
3014
3015
//
3016
// 'ippSetString()' - Set a string value in an attribute.
3017
//
3018
// The "ipp" parameter refers to an IPP message previously created using
3019
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3020
//
3021
// The "attr" parameter may be modified as a result of setting the value.
3022
//
3023
// The "element" parameter specifies which value to set from `0` to
3024
// `ippGetCount(attr)`.
3025
//
3026
3027
bool          // O  - `true` on success, `false` on failure
3028
ippSetString(ipp_t           *ipp,  // I  - IPP message
3029
             ipp_attribute_t **attr,  // IO - IPP attribute
3030
             size_t          element, // I  - Value number (`0`-based)
3031
       const char      *strvalue) // I  - String value
3032
0
{
3033
0
  char    *temp;      // Temporary string
3034
0
  _ipp_value_t  *value;     // Current value
3035
0
  ipp_tag_t value_tag;    // Value tag
3036
3037
3038
  // Range check input...
3039
0
  if (attr && *attr)
3040
0
    value_tag = (*attr)->value_tag & IPP_TAG_CUPS_MASK;
3041
0
  else
3042
0
    value_tag = IPP_TAG_ZERO;
3043
3044
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)
3045
0
    return (false);
3046
3047
  // Set the value and return...
3048
0
  if ((value = ipp_set_value(ipp, attr, element)) != NULL)
3049
0
  {
3050
0
    if (value_tag == IPP_TAG_NOVALUE || value_tag == IPP_TAG_UNKNOWN)
3051
0
      (*attr)->value_tag = IPP_TAG_KEYWORD;
3052
3053
0
    if (element > 0)
3054
0
      value->string.language = (*attr)->values[0].string.language;
3055
3056
0
    if ((int)((*attr)->value_tag) & IPP_TAG_CUPS_CONST)
3057
0
    {
3058
0
      value->string.text = (char *)strvalue;
3059
0
    }
3060
0
    else if ((temp = _cupsStrAlloc(strvalue)) != NULL)
3061
0
    {
3062
0
      if (value->string.text)
3063
0
        _cupsStrFree(value->string.text);
3064
3065
0
      value->string.text = temp;
3066
0
    }
3067
0
    else
3068
0
    {
3069
0
      return (false);
3070
0
    }
3071
0
  }
3072
3073
0
  return (value != NULL);
3074
0
}
3075
3076
3077
//
3078
// 'ippSetStringf()' - Set a formatted string value of an attribute.
3079
//
3080
// The "ipp" parameter refers to an IPP message previously created using
3081
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3082
//
3083
// The "attr" parameter may be modified as a result of setting the value.
3084
//
3085
// The "element" parameter specifies which value to set from `0` to
3086
// `ippGetCount(attr)`.
3087
//
3088
// The "format" parameter uses formatting characters compatible with the
3089
// printf family of standard functions.  Additional arguments follow it as
3090
// needed.  The formatted string is truncated as needed to the maximum length of
3091
// the corresponding value type.
3092
//
3093
3094
bool          // O  - `true` on success, `false` on failure
3095
ippSetStringf(ipp_t           *ipp, // I  - IPP message
3096
              ipp_attribute_t **attr, // IO - IPP attribute
3097
              size_t          element,  // I  - Value number (`0`-based)
3098
        const char      *format,  // I  - Printf-style format string
3099
        ...)      // I  - Additional arguments as needed
3100
0
{
3101
0
  int   ret;      // Return value
3102
0
  va_list ap;     // Pointer to additional arguments
3103
3104
3105
0
  va_start(ap, format);
3106
0
  ret = ippSetStringfv(ipp, attr, element, format, ap);
3107
0
  va_end(ap);
3108
3109
0
  return (ret);
3110
0
}
3111
3112
3113
//
3114
// 'ippSetStringf()' - Set a formatted string value of an attribute.
3115
//
3116
// The "ipp" parameter refers to an IPP message previously created using
3117
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3118
//
3119
// The "attr" parameter may be modified as a result of setting the value.
3120
//
3121
// The "element" parameter specifies which value to set from `0` to
3122
// `ippGetCount(attr)`.
3123
//
3124
// The "format" parameter uses formatting characters compatible with the
3125
// printf family of standard functions.  Additional arguments follow it as
3126
// needed.  The formatted string is truncated as needed to the maximum length of
3127
// the corresponding value type.
3128
//
3129
3130
bool          // O  - `true` on success, `false` on failure
3131
ippSetStringfv(ipp_t           *ipp,  // I  - IPP message
3132
               ipp_attribute_t **attr,  // IO - IPP attribute
3133
               size_t          element, // I  - Value number (`0`-based)
3134
         const char      *format, // I  - Printf-style format string
3135
         va_list         ap)  // I  - Pointer to additional arguments
3136
0
{
3137
0
  ipp_tag_t value_tag;    // Value tag
3138
0
  char    buffer[IPP_MAX_TEXT + 4];
3139
          // Formatted text string
3140
0
  ssize_t bytes,      // Length of formatted value
3141
0
    max_bytes;    // Maximum number of bytes for value
3142
3143
3144
  // Range check input...
3145
0
  if (attr && *attr)
3146
0
    value_tag = (*attr)->value_tag & IPP_TAG_CUPS_MASK;
3147
0
  else
3148
0
    value_tag = IPP_TAG_ZERO;
3149
3150
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)
3151
0
    return (false);
3152
3153
  // Format the string...
3154
0
  if (!strcmp(format, "%s"))
3155
0
  {
3156
    // Optimize the simple case...
3157
0
    const char *s = va_arg(ap, char *);
3158
3159
0
    if (!s)
3160
0
      s = "(null)";
3161
3162
0
    bytes = (ssize_t)strlen(s);
3163
0
    cupsCopyString(buffer, s, sizeof(buffer));
3164
0
  }
3165
0
  else
3166
0
  {
3167
    // Do a full formatting of the message...
3168
0
    if ((bytes = vsnprintf(buffer, sizeof(buffer), format, ap)) < 0)
3169
0
      return (0);
3170
0
  }
3171
3172
  // Limit the length of the string...
3173
0
  switch (value_tag)
3174
0
  {
3175
0
    default :
3176
0
    case IPP_TAG_TEXT :
3177
0
    case IPP_TAG_TEXTLANG :
3178
0
        max_bytes = IPP_MAX_TEXT;
3179
0
        break;
3180
3181
0
    case IPP_TAG_NAME :
3182
0
    case IPP_TAG_NAMELANG :
3183
0
        max_bytes = IPP_MAX_NAME;
3184
0
        break;
3185
3186
0
    case IPP_TAG_CHARSET :
3187
0
        max_bytes = IPP_MAX_CHARSET;
3188
0
        break;
3189
3190
0
    case IPP_TAG_NOVALUE :
3191
0
    case IPP_TAG_UNKNOWN :
3192
0
    case IPP_TAG_KEYWORD :
3193
0
        max_bytes = IPP_MAX_KEYWORD;
3194
0
        break;
3195
3196
0
    case IPP_TAG_LANGUAGE :
3197
0
        max_bytes = IPP_MAX_LANGUAGE;
3198
0
        break;
3199
3200
0
    case IPP_TAG_MIMETYPE :
3201
0
        max_bytes = IPP_MAX_MIMETYPE;
3202
0
        break;
3203
3204
0
    case IPP_TAG_URI :
3205
0
        max_bytes = IPP_MAX_URI;
3206
0
        break;
3207
3208
0
    case IPP_TAG_URISCHEME :
3209
0
        max_bytes = IPP_MAX_URISCHEME;
3210
0
        break;
3211
0
  }
3212
3213
0
  if (bytes >= max_bytes)
3214
0
  {
3215
0
    char  *bufmax,    // Buffer at max_bytes
3216
0
    *bufptr;    // Pointer into buffer
3217
3218
0
    bufptr = buffer + strlen(buffer) - 1;
3219
0
    bufmax = buffer + max_bytes - 1;
3220
3221
0
    while (bufptr > bufmax)
3222
0
    {
3223
0
      if (*bufptr & 0x80)
3224
0
      {
3225
0
        while ((*bufptr & 0xc0) == 0x80 && bufptr > buffer)
3226
0
          bufptr --;
3227
0
      }
3228
3229
0
      bufptr --;
3230
0
    }
3231
3232
0
    *bufptr = '\0';
3233
0
  }
3234
3235
  // Set the formatted string and return...
3236
0
  return (ippSetString(ipp, attr, element, buffer));
3237
0
}
3238
3239
3240
//
3241
// 'ippSetValueTag()' - Set the value tag of an attribute.
3242
//
3243
// The "ipp" parameter refers to an IPP message previously created using
3244
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3245
//
3246
// The "attr" parameter may be modified as a result of setting the value.
3247
//
3248
// Integer (`IPP_TAG_INTEGER`) values can be promoted to rangeOfInteger
3249
// (`IPP_TAG_RANGE`) values, the various string tags can be promoted to name
3250
// (`IPP_TAG_NAME`) or nameWithLanguage (`IPP_TAG_NAMELANG`) values, text
3251
// (`IPP_TAG_TEXT`) values can be promoted to textWithLanguage
3252
// (`IPP_TAG_TEXTLANG`) values, and all values can be demoted to the various
3253
// out-of-band value tags such as no-value (`IPP_TAG_NOVALUE`). All other changes
3254
// will be rejected.
3255
//
3256
// Promoting a string attribute to nameWithLanguage or textWithLanguage adds the language
3257
// code in the "attributes-natural-language" attribute or, if not present, the language
3258
// code for the current locale.
3259
//
3260
3261
bool          // O  - `true` on success, `false` on failure
3262
ippSetValueTag(
3263
    ipp_t          *ipp,    // I  - IPP message
3264
    ipp_attribute_t **attr,   // IO - IPP attribute
3265
    ipp_tag_t       value_tag)    // I  - Value tag
3266
757k
{
3267
757k
  size_t  i;      // Looping var
3268
757k
  _ipp_value_t  *value;     // Current value
3269
757k
  int   integer;    // Current integer value
3270
757k
  cups_lang_t *language;    // Current language
3271
757k
  char    code[32];   // Language code
3272
757k
  ipp_tag_t temp_tag;   // Temporary value tag
3273
3274
3275
757k
  DEBUG_printf("ippSetValueTag(ipp=%p, attr=%p(%p), value_tag=0x%x(%s))", ipp, attr, attr ? *attr : NULL, value_tag, ippTagString(value_tag));
3276
3277
  // Range check input...
3278
757k
  if (!ipp || !attr || !*attr)
3279
0
    return (false);
3280
3281
  // If there is no change, return immediately...
3282
757k
  temp_tag = (ipp_tag_t)((int)((*attr)->value_tag) & IPP_TAG_CUPS_MASK);
3283
3284
757k
  if (value_tag == temp_tag)
3285
0
  {
3286
0
    DEBUG_puts("2ippSetValueTag: No change.");
3287
0
    return (true);
3288
0
  }
3289
3290
  // Otherwise implement changes as needed...
3291
757k
  switch (value_tag)
3292
757k
  {
3293
0
    case IPP_TAG_UNSUPPORTED_VALUE :
3294
0
    case IPP_TAG_DEFAULT :
3295
0
    case IPP_TAG_UNKNOWN :
3296
3.99k
    case IPP_TAG_NOVALUE :
3297
3.99k
    case IPP_TAG_NOTSETTABLE :
3298
3.99k
    case IPP_TAG_DELETEATTR :
3299
3.99k
    case IPP_TAG_ADMINDEFINE :
3300
        // Free any existing values...
3301
3.99k
        if ((*attr)->num_values > 0)
3302
3.99k
          ipp_free_values(*attr, 0, (*attr)->num_values);
3303
3304
        // Set out-of-band value...
3305
3.99k
        (*attr)->value_tag = value_tag;
3306
3.99k
        break;
3307
3308
205
    case IPP_TAG_RANGE :
3309
205
        if (temp_tag != IPP_TAG_INTEGER)
3310
0
        {
3311
0
          DEBUG_printf("2ippSetValueTag: Unable to convert %s to rangeOfInteger.", ippTagString(temp_tag));
3312
0
          return (false);
3313
0
        }
3314
3315
506
        for (i = (*attr)->num_values, value = (*attr)->values; i > 0; i --, value ++)
3316
301
        {
3317
301
          integer            = value->integer;
3318
301
          value->range.lower = value->range.upper = integer;
3319
301
          DEBUG_printf("2ippSetValueTag: values[%u].lower=%d, .upper=%d", (unsigned)((*attr)->num_values - i), value->range.lower, value->range.upper);
3320
301
        }
3321
3322
205
        (*attr)->value_tag = IPP_TAG_RANGE;
3323
205
        break;
3324
3325
213
    case IPP_TAG_NAME :
3326
213
        if (temp_tag != IPP_TAG_KEYWORD)
3327
5
        {
3328
5
          DEBUG_printf("2ippSetValueTag: Unable to convert %s to name.", ippTagString(temp_tag));
3329
5
          return (false);
3330
5
        }
3331
3332
208
        (*attr)->value_tag = (ipp_tag_t)(IPP_TAG_NAME | ((*attr)->value_tag & IPP_TAG_CUPS_CONST));
3333
208
        break;
3334
3335
551
    case IPP_TAG_NAMELANG :
3336
3.12k
    case IPP_TAG_TEXTLANG :
3337
3.12k
        if (value_tag == IPP_TAG_NAMELANG && (temp_tag != IPP_TAG_NAME && temp_tag != IPP_TAG_KEYWORD))
3338
7
        {
3339
7
          DEBUG_printf("2ippSetValueTag: Unable to convert %s to nameWithLanguage.", ippTagString(temp_tag));
3340
7
          return (false);
3341
7
        }
3342
3343
3.11k
        if (value_tag == IPP_TAG_TEXTLANG && temp_tag != IPP_TAG_TEXT)
3344
7
        {
3345
7
          DEBUG_printf("2ippSetValueTag: Unable to convert %s to textWithLanguage.", ippTagString(temp_tag));
3346
7
          return (false);
3347
7
        }
3348
3349
3.10k
        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)
3350
148
        {
3351
          // Use the language code from the IPP message...
3352
148
    (*attr)->values[0].string.language = _cupsStrAlloc(ipp->attrs->next->values[0].string.text);
3353
148
        }
3354
2.96k
        else
3355
2.96k
        {
3356
          // Otherwise, use the language code corresponding to the locale...
3357
2.96k
    language = cupsLangDefault();
3358
2.96k
    (*attr)->values[0].string.language = _cupsStrAlloc(ipp_lang_code(cupsLangGetName(language), code, sizeof(code)));
3359
2.96k
        }
3360
3361
3.10k
  DEBUG_printf("2ippSetValueTag: values[0].string.language=\"%s\"(%p)", (*attr)->values[0].string.language, (*attr)->values[0].string.language);
3362
3363
5.42k
        for (i = (*attr)->num_values - 1, value = (*attr)->values + 1; i > 0; i --, value ++)
3364
2.31k
        {
3365
2.31k
          value->string.language = (*attr)->values[0].string.language;
3366
2.31k
          DEBUG_printf("2ippSetValueTag: values[%u].string.language=\"%s\"(%s)", (unsigned)((*attr)->num_values - i), value->string.language, value->string.language);
3367
2.31k
        }
3368
3369
3.10k
        if ((int)(*attr)->value_tag & IPP_TAG_CUPS_CONST)
3370
0
        {
3371
          // Make copies of all values...
3372
0
    for (i = (*attr)->num_values, value = (*attr)->values; i > 0; i --, value ++)
3373
0
    {
3374
0
      value->string.text = _cupsStrAlloc(value->string.text);
3375
0
      DEBUG_printf("2ippSetValueTag: values[%u].string.text=\"%s\"(%s)", (unsigned)((*attr)->num_values - i), value->string.text, value->string.text);
3376
0
    }
3377
0
        }
3378
3379
3.10k
        (*attr)->value_tag = IPP_TAG_NAMELANG;
3380
3.10k
        break;
3381
3382
749k
    case IPP_TAG_KEYWORD :
3383
749k
        if (temp_tag == IPP_TAG_NAME || temp_tag == IPP_TAG_NAMELANG)
3384
749k
        {
3385
749k
          DEBUG_printf("2ippSetValueTag: Ignoring change of %s to keyword.", ippTagString(temp_tag));
3386
749k
          break;      // Silently "allow" name -> keyword
3387
749k
        }
3388
3389
7
        DEBUG_printf("2ippSetValueTag: Unable to convert %s to keyword.", ippTagString(temp_tag));
3390
7
        return (false);
3391
3392
0
    case IPP_TAG_EXTENSION :
3393
0
        if (temp_tag == IPP_TAG_STRING && value_tag == IPP_TAG_EXTENSION)
3394
0
        {
3395
          // Allow octetString -> extension
3396
0
          (*attr)->value_tag = value_tag;
3397
0
          DEBUG_puts("2ippSetValueTag: Changing octetString to extension.");
3398
0
          break;
3399
0
        }
3400
3401
2
    default :
3402
2
        DEBUG_printf("2ippSetValueTag: Unable to convert %s to %s.", ippTagString(temp_tag), ippTagString(value_tag));
3403
2
        return (false);
3404
757k
  }
3405
3406
757k
  DEBUG_puts("2ippSetValueTag: Successful.");
3407
757k
  return (true);
3408
757k
}
3409
3410
3411
//
3412
// 'ippSetVersion()' - Set the version number in an IPP message.
3413
//
3414
// The "ipp" parameter refers to an IPP message previously created using
3415
// the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
3416
//
3417
// The valid version numbers are currently 1.0, 1.1, 2.0, 2.1, and 2.2.
3418
//
3419
3420
bool          // O - `true` on success, `false` on failure
3421
ippSetVersion(ipp_t *ipp,   // I - IPP message
3422
              int   major,    // I - Major version number (major.minor)
3423
              int   minor)    // I - Minor version number (major.minor)
3424
0
{
3425
  // Range check input...
3426
0
  if (!ipp || major < 0 || minor < 0)
3427
0
    return (false);
3428
3429
  // Set the version number...
3430
0
  ipp->request.any.version[0] = (ipp_uchar_t)major;
3431
0
  ipp->request.any.version[1] = (ipp_uchar_t)minor;
3432
3433
0
  return (true);
3434
0
}
3435
3436
3437
//
3438
// 'ippTimeToDate()' - Convert from time in seconds to RFC 2579 format.
3439
//
3440
3441
const ipp_uchar_t *     // O - RFC-2579 date/time data
3442
ippTimeToDate(time_t t)     // I - Time in seconds
3443
0
{
3444
0
  struct tm unixdate;   // UNIX unixdate/time info
3445
0
  ipp_uchar_t *date = _cupsGlobals()->ipp_date;
3446
          // RFC-2579 date/time data
3447
3448
3449
  // RFC-2579 date/time format is:
3450
  //
3451
  //   Byte(s)  Description
3452
  //   -------  -----------
3453
  //   0-1      Year (0 to 65535)
3454
  //   2        Month (1 to 12)
3455
  //   3        Day (1 to 31)
3456
  //   4        Hours (0 to 23)
3457
  //   5        Minutes (0 to 59)
3458
  //   6        Seconds (0 to 60, 60 = "leap second")
3459
  //   7        Deciseconds (0 to 9)
3460
  //   8        +/- UTC
3461
  //   9        UTC hours (0 to 11)
3462
  //   10       UTC minutes (0 to 59)
3463
0
  gmtime_r(&t, &unixdate);
3464
0
  unixdate.tm_year += 1900;
3465
3466
0
  date[0]  = (ipp_uchar_t)(unixdate.tm_year >> 8);
3467
0
  date[1]  = (ipp_uchar_t)(unixdate.tm_year);
3468
0
  date[2]  = (ipp_uchar_t)(unixdate.tm_mon + 1);
3469
0
  date[3]  = (ipp_uchar_t)unixdate.tm_mday;
3470
0
  date[4]  = (ipp_uchar_t)unixdate.tm_hour;
3471
0
  date[5]  = (ipp_uchar_t)unixdate.tm_min;
3472
0
  date[6]  = (ipp_uchar_t)unixdate.tm_sec;
3473
0
  date[7]  = 0;
3474
0
  date[8]  = '+';
3475
0
  date[9]  = 0;
3476
0
  date[10] = 0;
3477
3478
0
  return (date);
3479
0
}
3480
3481
3482
//
3483
// 'ippValidateAttribute()' - Validate the contents of an attribute.
3484
//
3485
// This function validates the contents of an attribute based on the name and
3486
// value tag.  `true` is returned if the attribute is valid, `false` otherwise.
3487
// On failure, @link cupsGetErrorString@ is set to a human-readable message.
3488
//
3489
3490
bool          // O - `true` if valid, `false` otherwise
3491
ippValidateAttribute(
3492
    ipp_attribute_t *attr)    // I - Attribute
3493
0
{
3494
0
  size_t  i;      // Looping var
3495
0
  int   r;      // regcomp() error code
3496
0
  char    scheme[64],   // Scheme from URI
3497
0
    userpass[256],    // Username/password from URI
3498
0
    hostname[256],    // Hostname from URI
3499
0
    resource[1024];   // Resource from URI
3500
0
  int   port,     // Port number from URI
3501
0
    uri_status;   // URI separation status
3502
0
  const char  *ptr;     // Pointer into string
3503
0
  ipp_attribute_t *colattr;   // Collection attribute
3504
0
  regex_t re;     // Regular expression
3505
0
  ipp_uchar_t *date;      // Current date value
3506
3507
3508
  // Skip separators.
3509
0
  if (!attr->name)
3510
0
    return (true);
3511
3512
  // Validate the attribute name.
3513
0
  for (ptr = attr->name; *ptr; ptr ++)
3514
0
  {
3515
0
    if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' && *ptr != '_')
3516
0
      break;
3517
0
  }
3518
3519
0
  if (*ptr || ptr == attr->name)
3520
0
  {
3521
0
    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad attribute name - invalid character (RFC 8011 section 5.1.4)."), attr->name);
3522
0
    return (false);
3523
0
  }
3524
3525
0
  if ((ptr - attr->name) > 255)
3526
0
  {
3527
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));
3528
0
    return (false);
3529
0
  }
3530
3531
0
  switch (attr->value_tag & IPP_TAG_CUPS_MASK)
3532
0
  {
3533
0
    case IPP_TAG_INTEGER :
3534
0
        break;
3535
3536
0
    case IPP_TAG_BOOLEAN :
3537
0
        for (i = 0; i < attr->num_values; i ++)
3538
0
  {
3539
0
    if (attr->values[i].boolean != 0 && attr->values[i].boolean != 1)
3540
0
    {
3541
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);
3542
0
      return (false);
3543
0
    }
3544
0
  }
3545
0
        break;
3546
3547
0
    case IPP_TAG_ENUM :
3548
0
        for (i = 0; i < attr->num_values; i ++)
3549
0
  {
3550
0
    if (attr->values[i].integer < 1)
3551
0
    {
3552
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);
3553
0
            return (false);
3554
0
    }
3555
0
  }
3556
0
        break;
3557
3558
0
    case IPP_TAG_STRING :
3559
0
        for (i = 0; i < attr->num_values; i ++)
3560
0
  {
3561
0
    if (attr->values[i].unknown.length > IPP_MAX_OCTETSTRING)
3562
0
    {
3563
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);
3564
0
      return (false);
3565
0
    }
3566
0
  }
3567
0
        break;
3568
3569
0
    case IPP_TAG_DATE :
3570
0
        for (i = 0; i < attr->num_values; i ++)
3571
0
  {
3572
0
    date = attr->values[i].date;
3573
3574
0
          if (date[2] < 1 || date[2] > 12)
3575
0
    {
3576
0
      ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime month %u (RFC 8011 section 5.1.15)."), attr->name, date[2]);
3577
0
      return (false);
3578
0
    }
3579
3580
0
          if (date[3] < 1 || date[3] > 31)
3581
0
    {
3582
0
      ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime day %u (RFC 8011 section 5.1.15)."), attr->name, date[3]);
3583
0
      return (false);
3584
0
    }
3585
3586
0
          if (date[4] > 23)
3587
0
    {
3588
0
      ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime hours %u (RFC 8011 section 5.1.15)."), attr->name, date[4]);
3589
0
      return (false);
3590
0
    }
3591
3592
0
          if (date[5] > 59)
3593
0
    {
3594
0
      ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime minutes %u (RFC 8011 section 5.1.15)."), attr->name, date[5]);
3595
0
      return (false);
3596
0
    }
3597
3598
0
          if (date[6] > 60)
3599
0
    {
3600
0
      ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime seconds %u (RFC 8011 section 5.1.15)."), attr->name, date[6]);
3601
0
      return (false);
3602
0
    }
3603
3604
0
          if (date[7] > 9)
3605
0
    {
3606
0
      ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad dateTime deciseconds %u (RFC 8011 section 5.1.15)."), attr->name, date[7]);
3607
0
      return (false);
3608
0
    }
3609
3610
0
          if (date[8] != '-' && date[8] != '+')
3611
0
    {
3612
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]);
3613
0
      return (false);
3614
0
    }
3615
3616
0
          if (date[9] > 11)
3617
0
    {
3618
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]);
3619
0
      return (false);
3620
0
    }
3621
3622
0
          if (date[10] > 59)
3623
0
    {
3624
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]);
3625
0
      return (false);
3626
0
    }
3627
0
  }
3628
0
        break;
3629
3630
0
    case IPP_TAG_RESOLUTION :
3631
0
        for (i = 0; i < attr->num_values; i ++)
3632
0
  {
3633
0
    if (attr->values[i].resolution.xres <= 0)
3634
0
    {
3635
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");
3636
0
      return (false);
3637
0
    }
3638
3639
0
    if (attr->values[i].resolution.yres <= 0)
3640
0
    {
3641
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");
3642
0
            return (false);
3643
0
    }
3644
3645
0
    if (attr->values[i].resolution.units != IPP_RES_PER_INCH && attr->values[i].resolution.units != IPP_RES_PER_CM)
3646
0
    {
3647
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");
3648
0
      return (false);
3649
0
    }
3650
0
  }
3651
0
        break;
3652
3653
0
    case IPP_TAG_RANGE :
3654
0
        for (i = 0; i < attr->num_values; i ++)
3655
0
  {
3656
0
    if (attr->values[i].range.lower > attr->values[i].range.upper)
3657
0
    {
3658
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);
3659
0
      return (false);
3660
0
    }
3661
0
  }
3662
0
        break;
3663
3664
0
    case IPP_TAG_BEGIN_COLLECTION :
3665
0
        for (i = 0; i < attr->num_values; i ++)
3666
0
  {
3667
0
    for (colattr = attr->values[i].collection->attrs;
3668
0
         colattr;
3669
0
         colattr = colattr->next)
3670
0
    {
3671
0
      if (!ippValidateAttribute(colattr))
3672
0
        return (false);
3673
0
    }
3674
0
  }
3675
0
        break;
3676
3677
0
    case IPP_TAG_TEXT :
3678
0
    case IPP_TAG_TEXTLANG :
3679
0
        for (i = 0; i < attr->num_values; i ++)
3680
0
  {
3681
0
    for (ptr = attr->values[i].string.text; *ptr; ptr ++)
3682
0
    {
3683
0
      if ((*ptr & 0xe0) == 0xc0)
3684
0
      {
3685
0
        if ((ptr[1] & 0xc0) != 0x80)
3686
0
          break;
3687
3688
0
        ptr ++;
3689
0
      }
3690
0
      else if ((*ptr & 0xf0) == 0xe0)
3691
0
      {
3692
0
        if ((ptr[1] & 0xc0) != 0x80 || (ptr[2] & 0xc0) != 0x80)
3693
0
          break;
3694
3695
0
        ptr += 2;
3696
0
      }
3697
0
      else if ((*ptr & 0xf8) == 0xf0)
3698
0
      {
3699
0
        if ((ptr[1] & 0xc0) != 0x80 || (ptr[2] & 0xc0) != 0x80 || (ptr[3] & 0xc0) != 0x80)
3700
0
          break;
3701
3702
0
        ptr += 3;
3703
0
      }
3704
0
      else if (*ptr & 0x80)
3705
0
      {
3706
0
        break;
3707
0
      }
3708
0
      else if ((*ptr < ' ' && *ptr != '\n' && *ptr != '\r' && *ptr != '\t') || *ptr == 0x7f)
3709
0
      {
3710
0
        break;
3711
0
      }
3712
0
    }
3713
3714
0
          if (*ptr)
3715
0
          {
3716
0
      if (*ptr < ' ' || *ptr == 0x7f)
3717
0
      {
3718
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);
3719
0
        return (false);
3720
0
      }
3721
0
      else
3722
0
      {
3723
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);
3724
0
        return (false);
3725
0
      }
3726
0
          }
3727
3728
0
    if ((ptr - attr->values[i].string.text) > (IPP_MAX_TEXT - 1))
3729
0
    {
3730
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));
3731
0
      return (false);
3732
0
    }
3733
0
  }
3734
0
        break;
3735
3736
0
    case IPP_TAG_NAME :
3737
0
    case IPP_TAG_NAMELANG :
3738
0
        for (i = 0; i < attr->num_values; i ++)
3739
0
  {
3740
0
    for (ptr = attr->values[i].string.text; *ptr; ptr ++)
3741
0
    {
3742
0
      if ((*ptr & 0xe0) == 0xc0)
3743
0
      {
3744
0
        if ((ptr[1] & 0xc0) != 0x80)
3745
0
          break;
3746
3747
0
        ptr ++;
3748
0
      }
3749
0
      else if ((*ptr & 0xf0) == 0xe0)
3750
0
      {
3751
0
        if ((ptr[1] & 0xc0) != 0x80 || (ptr[2] & 0xc0) != 0x80)
3752
0
          break;
3753
3754
0
        ptr += 2;
3755
0
      }
3756
0
      else if ((*ptr & 0xf8) == 0xf0)
3757
0
      {
3758
0
        if ((ptr[1] & 0xc0) != 0x80 || (ptr[2] & 0xc0) != 0x80 || (ptr[3] & 0xc0) != 0x80)
3759
0
          break;
3760
3761
0
        ptr += 3;
3762
0
      }
3763
0
      else if (*ptr & 0x80)
3764
0
      {
3765
0
        break;
3766
0
      }
3767
0
      else if (*ptr < ' ' || *ptr == 0x7f)
3768
0
      {
3769
0
        break;
3770
0
      }
3771
0
    }
3772
3773
0
    if (*ptr)
3774
0
    {
3775
0
      if (*ptr < ' ' || *ptr == 0x7f)
3776
0
      {
3777
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);
3778
0
        return (false);
3779
0
      }
3780
0
      else
3781
0
      {
3782
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);
3783
0
        return (false);
3784
0
      }
3785
0
          }
3786
3787
0
    if ((ptr - attr->values[i].string.text) > (IPP_MAX_NAME - 1))
3788
0
    {
3789
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));
3790
0
      return (false);
3791
0
    }
3792
0
  }
3793
0
        break;
3794
3795
0
    case IPP_TAG_KEYWORD :
3796
0
        for (i = 0; i < attr->num_values; i ++)
3797
0
  {
3798
0
    for (ptr = attr->values[i].string.text; *ptr; ptr ++)
3799
0
    {
3800
0
      if (!isalnum(*ptr & 255) && *ptr != '-' && *ptr != '.' && *ptr != '_')
3801
0
        break;
3802
0
    }
3803
3804
0
    if (*ptr || ptr == attr->values[i].string.text)
3805
0
    {
3806
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);
3807
0
      return (false);
3808
0
    }
3809
3810
0
    if ((ptr - attr->values[i].string.text) > (IPP_MAX_KEYWORD - 1))
3811
0
    {
3812
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));
3813
0
      return (false);
3814
0
    }
3815
0
  }
3816
0
        break;
3817
3818
0
    case IPP_TAG_URI :
3819
0
        for (i = 0; i < attr->num_values; i ++)
3820
0
  {
3821
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));
3822
3823
0
    if (uri_status < HTTP_URI_STATUS_OK)
3824
0
    {
3825
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));
3826
0
      return (false);
3827
0
    }
3828
3829
0
    if (strlen(attr->values[i].string.text) > (IPP_MAX_URI - 1))
3830
0
    {
3831
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));
3832
0
    }
3833
0
  }
3834
0
        break;
3835
3836
0
    case IPP_TAG_URISCHEME :
3837
0
        for (i = 0; i < attr->num_values; i ++)
3838
0
  {
3839
0
    ptr = attr->values[i].string.text;
3840
0
    if (islower(*ptr & 255))
3841
0
    {
3842
0
      for (ptr ++; *ptr; ptr ++)
3843
0
      {
3844
0
        if (!islower(*ptr & 255) && !isdigit(*ptr & 255) && *ptr != '+' && *ptr != '-' && *ptr != '.')
3845
0
                break;
3846
0
      }
3847
0
    }
3848
3849
0
    if (*ptr || ptr == attr->values[i].string.text)
3850
0
    {
3851
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);
3852
0
      return (false);
3853
0
    }
3854
3855
0
    if ((ptr - attr->values[i].string.text) > (IPP_MAX_URISCHEME - 1))
3856
0
    {
3857
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));
3858
0
      return (false);
3859
0
    }
3860
0
  }
3861
0
        break;
3862
3863
0
    case IPP_TAG_CHARSET :
3864
0
        for (i = 0; i < attr->num_values; i ++)
3865
0
  {
3866
0
    for (ptr = attr->values[i].string.text; *ptr; ptr ++)
3867
0
    {
3868
0
      if (!isprint(*ptr & 255) || isupper(*ptr & 255) || isspace(*ptr & 255))
3869
0
        break;
3870
0
    }
3871
3872
0
    if (*ptr || ptr == attr->values[i].string.text)
3873
0
    {
3874
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);
3875
0
      return (false);
3876
0
    }
3877
3878
0
    if ((ptr - attr->values[i].string.text) > (IPP_MAX_CHARSET - 1))
3879
0
    {
3880
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));
3881
0
      return (false);
3882
0
    }
3883
0
  }
3884
0
        break;
3885
3886
0
    case IPP_TAG_LANGUAGE :
3887
        // The following regular expression is derived from the ABNF for
3888
  // language tags in RFC 4646.  All I can say is that this is the
3889
  // easiest way to check the values...
3890
0
        if ((r = regcomp(&re,
3891
0
       "^("
3892
0
       "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
3893
                // language
3894
0
       "(-[a-z][a-z][a-z][a-z]){0,1}"   // script
3895
0
       "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" // region
3896
0
       "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" // variant
3897
0
       "(-[a-wy-z](-[a-z0-9]{2,8})+)*"  // extension
3898
0
       "(-x(-[a-z0-9]{1,8})+)*"   // privateuse
3899
0
       "|"
3900
0
       "x(-[a-z0-9]{1,8})+"     // privateuse
3901
0
       "|"
3902
0
       "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}"  // grandfathered
3903
0
       ")$",
3904
0
       REG_NOSUB | REG_EXTENDED)) != 0)
3905
0
        {
3906
0
          char  temp[256];    // Temporary error string
3907
3908
0
          regerror(r, &re, temp, sizeof(temp));
3909
0
    ipp_set_error(IPP_STATUS_ERROR_INTERNAL, _("Unable to compile naturalLanguage regular expression: %s."), temp);
3910
0
    return (false);
3911
0
        }
3912
3913
0
        for (i = 0; i < attr->num_values; i ++)
3914
0
  {
3915
0
    if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
3916
0
    {
3917
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);
3918
0
      regfree(&re);
3919
0
      return (false);
3920
0
    }
3921
3922
0
    if (strlen(attr->values[i].string.text) > (IPP_MAX_LANGUAGE - 1))
3923
0
    {
3924
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));
3925
0
      regfree(&re);
3926
0
      return (false);
3927
0
    }
3928
0
  }
3929
3930
0
  regfree(&re);
3931
0
        break;
3932
3933
0
    case IPP_TAG_MIMETYPE :
3934
        // The following regular expression is derived from the ABNF for
3935
  // MIME media types in RFC 2045 and 4288.  All I can say is that this is
3936
  // the easiest way to check the values...
3937
0
        if ((r = regcomp(&re,
3938
0
       "^"
3939
0
       "[-a-zA-Z0-9!#$&.+^_]{1,127}"    // type-name
3940
0
       "/"
3941
0
       "[-a-zA-Z0-9!#$&.+^_]{1,127}"    // subtype-name
3942
0
       "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" // parameter=
3943
0
       "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
3944
                // value
3945
0
       "$",
3946
0
       REG_NOSUB | REG_EXTENDED)) != 0)
3947
0
        {
3948
0
          char  temp[256];    // Temporary error string
3949
3950
0
          regerror(r, &re, temp, sizeof(temp));
3951
0
    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("Unable to compile mimeMediaType regular expression: %s."), temp);
3952
0
    return (false);
3953
0
        }
3954
3955
0
        for (i = 0; i < attr->num_values; i ++)
3956
0
  {
3957
0
    if (regexec(&re, attr->values[i].string.text, 0, NULL, 0))
3958
0
    {
3959
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);
3960
0
      regfree(&re);
3961
0
      return (false);
3962
0
    }
3963
3964
0
    if (strlen(attr->values[i].string.text) > (IPP_MAX_MIMETYPE - 1))
3965
0
    {
3966
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));
3967
0
      regfree(&re);
3968
0
      return (false);
3969
0
    }
3970
0
  }
3971
3972
0
  regfree(&re);
3973
0
        break;
3974
3975
0
    default :
3976
0
        break;
3977
0
  }
3978
3979
0
  return (true);
3980
0
}
3981
3982
3983
//
3984
// 'ippValidateAttributes()' - Validate all attributes in an IPP message.
3985
//
3986
// This function validates the contents of the IPP message, including each
3987
// attribute.  Like @link ippValidateAttribute@, @link cupsGetErrorString@ is
3988
// set to a human-readable message on failure.
3989
//
3990
3991
bool          // O - `true` if valid, `false` otherwise
3992
ippValidateAttributes(ipp_t *ipp) // I - IPP message
3993
0
{
3994
0
  ipp_attribute_t *attr;    // Current attribute
3995
3996
3997
0
  if (!ipp)
3998
0
    return (true);
3999
4000
0
  for (attr = ipp->attrs; attr; attr = attr->next)
4001
0
  {
4002
0
    if (!ippValidateAttribute(attr))
4003
0
      return (false);
4004
0
  }
4005
4006
0
  return (true);
4007
0
}
4008
4009
4010
//
4011
// 'ippWrite()' - Write data for an IPP message to a HTTP connection.
4012
//
4013
4014
ipp_state_t       // O - Current state
4015
ippWrite(http_t *http,      // I - HTTP connection
4016
         ipp_t  *ipp)     // I - IPP data
4017
0
{
4018
0
  DEBUG_printf("ippWrite(http=%p, ipp=%p)", (void *)http, (void *)ipp);
4019
4020
0
  if (!http)
4021
0
    return (IPP_STATE_ERROR);
4022
4023
0
  return (ippWriteIO(http, (ipp_io_cb_t)httpWrite, http->blocking, NULL, ipp));
4024
0
}
4025
4026
4027
//
4028
// 'ippWriteFile()' - Write data for an IPP message to a file.
4029
//
4030
4031
ipp_state_t       // O - Current state
4032
ippWriteFile(int   fd,      // I - HTTP data
4033
             ipp_t *ipp)    // I - IPP data
4034
0
{
4035
0
  DEBUG_printf("ippWriteFile(fd=%d, ipp=%p)", fd, (void *)ipp);
4036
4037
0
  ipp->state = IPP_STATE_IDLE;
4038
4039
0
  return (ippWriteIO(&fd, (ipp_io_cb_t)ipp_write_file, true, NULL, ipp));
4040
0
}
4041
4042
4043
//
4044
// 'ippWriteIO()' - Write data for an IPP message.
4045
//
4046
4047
ipp_state_t       // O - Current state
4048
ippWriteIO(void        *dst,    // I - Destination
4049
           ipp_io_cb_t cb,    // I - Write callback function
4050
     bool        blocking,  // I - Use blocking IO?
4051
     ipp_t       *parent,   // I - Parent IPP message
4052
           ipp_t       *ipp)    // I - IPP data
4053
372k
{
4054
372k
  size_t    i;    // Looping var
4055
372k
  int     n;    // Length of data
4056
372k
  unsigned char   *buffer,  // Data buffer
4057
372k
      *bufptr;  // Pointer into buffer
4058
372k
  ipp_attribute_t *attr;    // Current attribute
4059
372k
  _ipp_value_t    *value;   // Current value
4060
4061
4062
372k
  DEBUG_printf("ippWriteIO(dst=%p, cb=%p, blocking=%d, parent=%p, ipp=%p)", (void *)dst, (void *)cb, blocking, (void *)parent, (void *)ipp);
4063
4064
372k
  if (!dst || !ipp)
4065
0
    return (IPP_STATE_ERROR);
4066
4067
372k
  if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
4068
0
  {
4069
0
    DEBUG_puts("1ippWriteIO: Unable to get write buffer");
4070
0
    return (IPP_STATE_ERROR);
4071
0
  }
4072
4073
372k
  switch (ipp->state)
4074
372k
  {
4075
372k
    case IPP_STATE_IDLE :
4076
372k
        ipp->state ++; // Avoid common problem...
4077
4078
372k
    case IPP_STATE_HEADER :
4079
372k
        if (parent == NULL)
4080
5.39k
  {
4081
    // Send the request header:
4082
    //
4083
    //                 Version = 2 bytes
4084
    //   Operation/Status Code = 2 bytes
4085
    //              Request ID = 4 bytes
4086
    //                   Total = 8 bytes
4087
5.39k
          bufptr = buffer;
4088
4089
5.39k
    *bufptr++ = ipp->request.any.version[0];
4090
5.39k
    *bufptr++ = ipp->request.any.version[1];
4091
5.39k
    *bufptr++ = (ipp_uchar_t)(ipp->request.any.op_status >> 8);
4092
5.39k
    *bufptr++ = (ipp_uchar_t)ipp->request.any.op_status;
4093
5.39k
    *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 24);
4094
5.39k
    *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 16);
4095
5.39k
    *bufptr++ = (ipp_uchar_t)(ipp->request.any.request_id >> 8);
4096
5.39k
    *bufptr++ = (ipp_uchar_t)ipp->request.any.request_id;
4097
4098
5.39k
    DEBUG_printf("2ippWriteIO: version=%d.%d", buffer[0], buffer[1]);
4099
5.39k
    DEBUG_printf("2ippWriteIO: op_status=%04x", ipp->request.any.op_status);
4100
5.39k
    DEBUG_printf("2ippWriteIO: request_id=%d", ipp->request.any.request_id);
4101
4102
5.39k
          if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4103
0
    {
4104
0
      DEBUG_puts("1ippWriteIO: Could not write IPP header...");
4105
0
      _cupsBufferRelease((char *)buffer);
4106
0
      return (IPP_STATE_ERROR);
4107
0
    }
4108
5.39k
  }
4109
4110
  // Reset the state engine to point to the first attribute
4111
  // in the request/response, with no current group.
4112
372k
        ipp->state   = IPP_STATE_ATTRIBUTE;
4113
372k
  ipp->current = ipp->attrs;
4114
372k
  ipp->curtag  = IPP_TAG_ZERO;
4115
4116
372k
  DEBUG_printf("1ippWriteIO: ipp->current=%p", (void *)ipp->current);
4117
4118
        // If blocking is disabled, stop here...
4119
372k
        if (!blocking)
4120
0
    break;
4121
4122
372k
    case IPP_STATE_ATTRIBUTE :
4123
15.9M
        while (ipp->current != NULL)
4124
15.6M
  {
4125
    // Write this attribute...
4126
15.6M
    bufptr = buffer;
4127
15.6M
    attr   = ipp->current;
4128
4129
15.6M
    ipp->current = ipp->current->next;
4130
4131
15.6M
          if (!parent)
4132
15.6M
    {
4133
15.6M
      if (ipp->curtag != attr->group_tag)
4134
702k
      {
4135
        // Send a group tag byte...
4136
702k
        ipp->curtag = attr->group_tag;
4137
4138
702k
        if (attr->group_tag == IPP_TAG_ZERO)
4139
348k
    continue;
4140
4141
353k
        DEBUG_printf("2ippWriteIO: wrote group tag=%x(%s)", attr->group_tag, ippTagString(attr->group_tag));
4142
353k
        *bufptr++ = (ipp_uchar_t)attr->group_tag;
4143
353k
      }
4144
14.9M
      else if (attr->group_tag == IPP_TAG_ZERO)
4145
10.7M
      {
4146
10.7M
        continue;
4147
10.7M
      }
4148
15.6M
    }
4149
4150
4.49M
    DEBUG_printf("1ippWriteIO: %s (%s%s)", attr->name, attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag));
4151
4152
    // Write the attribute tag and name.
4153
    //
4154
    // The attribute name length does not include the trailing nul
4155
    // character in the source string.
4156
    //
4157
    // Collection values (parent != NULL) are written differently...
4158
4.49M
          if (parent == NULL)
4159
4.49M
    {
4160
      // Get the length of the attribute name, and make sure it won't overflow the buffer...
4161
4.49M
            if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 8))
4162
1
      {
4163
1
        DEBUG_printf("1ippWriteIO: Attribute name too long (%d)", n);
4164
1
        _cupsBufferRelease((char *)buffer);
4165
1
        return (IPP_STATE_ERROR);
4166
1
      }
4167
4168
      // Write the value tag, name length, and name string...
4169
4.49M
      DEBUG_printf("2ippWriteIO: writing value tag=%x(%s)", attr->value_tag, ippTagString(attr->value_tag));
4170
4.49M
            DEBUG_printf("2ippWriteIO: writing name=%d,\"%s\"", n, attr->name);
4171
4172
4.49M
      *bufptr++ = (ipp_uchar_t)attr->value_tag;
4173
4.49M
      *bufptr++ = (ipp_uchar_t)(n >> 8);
4174
4.49M
      *bufptr++ = (ipp_uchar_t)n;
4175
4.49M
      memcpy(bufptr, attr->name, (size_t)n);
4176
4.49M
      bufptr += n;
4177
4.49M
          }
4178
279
    else
4179
279
    {
4180
      // Get the length of the attribute name, and make sure it won't overflow the buffer...
4181
279
            if ((n = (int)strlen(attr->name)) > (IPP_BUF_SIZE - 12))
4182
0
      {
4183
0
        DEBUG_printf("1ippWriteIO: Attribute name too long (%d)", n);
4184
0
        _cupsBufferRelease((char *)buffer);
4185
0
        return (IPP_STATE_ERROR);
4186
0
      }
4187
4188
      // Write the member name tag, name length, name string, value tag,
4189
      // and empty name for the collection member attribute...
4190
279
            DEBUG_printf("2ippWriteIO: writing value tag=%x(memberName)", IPP_TAG_MEMBERNAME);
4191
279
            DEBUG_printf("2ippWriteIO: writing name=%d,\"%s\"", n, attr->name);
4192
279
            DEBUG_printf("2ippWriteIO: writing value tag=%x(%s)", attr->value_tag, ippTagString(attr->value_tag));
4193
279
            DEBUG_puts("2ippWriteIO: writing name=0,\"\"");
4194
4195
279
            *bufptr++ = IPP_TAG_MEMBERNAME;
4196
279
      *bufptr++ = 0;
4197
279
      *bufptr++ = 0;
4198
279
      *bufptr++ = (ipp_uchar_t)(n >> 8);
4199
279
      *bufptr++ = (ipp_uchar_t)n;
4200
279
      memcpy(bufptr, attr->name, (size_t)n);
4201
279
      bufptr += n;
4202
4203
279
            if (attr->value_tag > 0xff)
4204
0
            {
4205
0
              *bufptr++ = IPP_TAG_EXTENSION;
4206
0
        *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 24);
4207
0
        *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 16);
4208
0
        *bufptr++ = (ipp_uchar_t)(attr->value_tag >> 8);
4209
0
        *bufptr++ = (ipp_uchar_t)attr->value_tag;
4210
0
            }
4211
279
            else
4212
279
            {
4213
279
        *bufptr++ = (ipp_uchar_t)attr->value_tag;
4214
279
      }
4215
4216
279
            *bufptr++ = 0;
4217
279
            *bufptr++ = 0;
4218
279
    }
4219
4220
    // Now write the attribute value(s)...
4221
4.49M
    switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
4222
4.49M
    {
4223
248
      case IPP_TAG_UNSUPPORTED_VALUE :
4224
525
      case IPP_TAG_DEFAULT :
4225
1.03k
      case IPP_TAG_UNKNOWN :
4226
1.29k
      case IPP_TAG_NOVALUE :
4227
1.53k
      case IPP_TAG_NOTSETTABLE :
4228
1.79k
      case IPP_TAG_DELETEATTR :
4229
2.04k
      case IPP_TAG_ADMINDEFINE :
4230
2.04k
    *bufptr++ = 0;
4231
2.04k
    *bufptr++ = 0;
4232
2.04k
          break;
4233
4234
395
      case IPP_TAG_INTEGER :
4235
732
      case IPP_TAG_ENUM :
4236
364k
          for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++)
4237
363k
    {
4238
363k
                  if ((IPP_BUF_SIZE - (bufptr - buffer)) < 9)
4239
89
      {
4240
89
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4241
0
              {
4242
0
          DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4243
0
          _cupsBufferRelease((char *)buffer);
4244
0
                return (IPP_STATE_ERROR);
4245
0
              }
4246
4247
89
        bufptr = buffer;
4248
89
      }
4249
4250
363k
      if (i)
4251
362k
      {
4252
        // Arrays and sets are done by sending additional values with a zero-length name...
4253
362k
                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
4254
362k
        *bufptr++ = 0;
4255
362k
        *bufptr++ = 0;
4256
362k
      }
4257
4258
            // Integers and enumerations are both 4-byte signed
4259
      // (twos-complement) values.
4260
      //
4261
      // Put the 2-byte length and 4-byte value into the buffer...
4262
363k
            *bufptr++ = 0;
4263
363k
      *bufptr++ = 4;
4264
363k
      *bufptr++ = (ipp_uchar_t)(value->integer >> 24);
4265
363k
      *bufptr++ = (ipp_uchar_t)(value->integer >> 16);
4266
363k
      *bufptr++ = (ipp_uchar_t)(value->integer >> 8);
4267
363k
      *bufptr++ = (ipp_uchar_t)value->integer;
4268
363k
    }
4269
732
    break;
4270
4271
732
      case IPP_TAG_BOOLEAN :
4272
178k
          for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++)
4273
178k
    {
4274
178k
                  if ((IPP_BUF_SIZE - (bufptr - buffer)) < 6)
4275
23
      {
4276
23
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4277
0
              {
4278
0
          DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4279
0
          _cupsBufferRelease((char *)buffer);
4280
0
                return (IPP_STATE_ERROR);
4281
0
              }
4282
4283
23
        bufptr = buffer;
4284
23
      }
4285
4286
178k
      if (i)
4287
177k
      {
4288
        // Arrays and sets are done by sending additional values with a zero-length name...
4289
177k
                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
4290
177k
        *bufptr++ = 0;
4291
177k
        *bufptr++ = 0;
4292
177k
      }
4293
4294
      // Boolean values are 1-byte; 0 = false, 1 = true.
4295
      //
4296
      // Put the 2-byte length and 1-byte value into the buffer...
4297
178k
            *bufptr++ = 0;
4298
178k
      *bufptr++ = 1;
4299
178k
      *bufptr++ = (ipp_uchar_t)value->boolean;
4300
178k
    }
4301
348
    break;
4302
4303
372k
      case IPP_TAG_TEXT :
4304
373k
      case IPP_TAG_NAME :
4305
4.46M
      case IPP_TAG_KEYWORD :
4306
4.46M
      case IPP_TAG_URI :
4307
4.46M
      case IPP_TAG_URISCHEME :
4308
4.46M
      case IPP_TAG_CHARSET :
4309
4.47M
      case IPP_TAG_LANGUAGE :
4310
4.47M
      case IPP_TAG_MIMETYPE :
4311
9.27M
          for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++)
4312
4.80M
    {
4313
4.80M
      if (i)
4314
327k
      {
4315
        // Arrays and sets are done by sending additional values with a zero-length name...
4316
327k
              DEBUG_printf("2ippWriteIO: writing value tag=%x(%s)", attr->value_tag, ippTagString(attr->value_tag));
4317
327k
              DEBUG_printf("2ippWriteIO: writing name=0,\"\"");
4318
4319
327k
                    if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
4320
49
        {
4321
49
                      if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4322
0
                {
4323
0
      DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4324
0
      _cupsBufferRelease((char *)buffer);
4325
0
            return (IPP_STATE_ERROR);
4326
0
                }
4327
4328
49
          bufptr = buffer;
4329
49
        }
4330
4331
327k
                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
4332
327k
        *bufptr++ = 0;
4333
327k
        *bufptr++ = 0;
4334
327k
      }
4335
4336
4.80M
                  if (value->string.text != NULL)
4337
4.79M
                    n = (int)strlen(value->string.text);
4338
411
      else
4339
411
        n = 0;
4340
4341
4.80M
                  if (n > (IPP_BUF_SIZE - 2))
4342
1
      {
4343
1
        DEBUG_printf("1ippWriteIO: String too long (%d)", n);
4344
1
        _cupsBufferRelease((char *)buffer);
4345
1
        return (IPP_STATE_ERROR);
4346
1
      }
4347
4348
4.80M
                  DEBUG_printf("2ippWriteIO: writing string=%d,\"%s\"", n, value->string.text);
4349
4350
4.80M
                  if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
4351
313
      {
4352
313
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4353
0
              {
4354
0
          DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4355
0
          _cupsBufferRelease((char *)buffer);
4356
0
                return (IPP_STATE_ERROR);
4357
0
              }
4358
4359
313
        bufptr = buffer;
4360
313
      }
4361
4362
      // All simple strings consist of the 2-byte length and
4363
      // character data without the trailing nul normally found
4364
      // in C strings.  Also, strings cannot be longer than IPP_MAX_LENGTH
4365
      // bytes since the 2-byte length is a signed (twos-complement)
4366
      // value.
4367
      //
4368
      // Put the 2-byte length and string characters in the buffer.
4369
4.80M
            *bufptr++ = (ipp_uchar_t)(n >> 8);
4370
4.80M
      *bufptr++ = (ipp_uchar_t)n;
4371
4372
4.80M
      if (n > 0)
4373
534k
      {
4374
534k
        memcpy(bufptr, value->string.text, (size_t)n);
4375
534k
        bufptr += n;
4376
534k
      }
4377
4.80M
    }
4378
4.47M
    break;
4379
4380
4.47M
      case IPP_TAG_DATE :
4381
311k
          for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++)
4382
310k
    {
4383
310k
                  if ((IPP_BUF_SIZE - (bufptr - buffer)) < 16)
4384
135
      {
4385
135
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4386
0
              {
4387
0
          DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4388
0
          _cupsBufferRelease((char *)buffer);
4389
0
                return (IPP_STATE_ERROR);
4390
0
              }
4391
4392
135
        bufptr = buffer;
4393
135
      }
4394
4395
310k
      if (i)
4396
310k
      {
4397
        // Arrays and sets are done by sending additional values with a zero-length name...
4398
310k
                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
4399
310k
        *bufptr++ = 0;
4400
310k
        *bufptr++ = 0;
4401
310k
      }
4402
4403
      // Date values consist of a 2-byte length and an
4404
      // 11-byte date/time structure defined by RFC 1903.
4405
      //
4406
      // Put the 2-byte length and 11-byte date/time
4407
      // structure in the buffer.
4408
310k
            *bufptr++ = 0;
4409
310k
      *bufptr++ = 11;
4410
310k
      memcpy(bufptr, value->date, 11);
4411
310k
      bufptr += 11;
4412
310k
    }
4413
443
    break;
4414
4415
1.63k
      case IPP_TAG_RESOLUTION :
4416
186k
          for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++)
4417
184k
    {
4418
184k
                  if ((IPP_BUF_SIZE - (bufptr - buffer)) < 14)
4419
66
      {
4420
66
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4421
0
              {
4422
0
          DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4423
0
          _cupsBufferRelease((char *)buffer);
4424
0
          return (IPP_STATE_ERROR);
4425
0
              }
4426
4427
66
        bufptr = buffer;
4428
66
      }
4429
4430
184k
      if (i)
4431
183k
      {
4432
        // Arrays and sets are done by sending additional values with a zero-length name...
4433
183k
                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
4434
183k
        *bufptr++ = 0;
4435
183k
        *bufptr++ = 0;
4436
183k
      }
4437
4438
      // Resolution values consist of a 2-byte length,
4439
      // 4-byte horizontal resolution value, 4-byte vertical
4440
      // resolution value, and a 1-byte units value.
4441
      //
4442
      // Put the 2-byte length and resolution value data
4443
      // into the buffer.
4444
184k
            *bufptr++ = 0;
4445
184k
      *bufptr++ = 9;
4446
184k
      *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 24);
4447
184k
      *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 16);
4448
184k
      *bufptr++ = (ipp_uchar_t)(value->resolution.xres >> 8);
4449
184k
      *bufptr++ = (ipp_uchar_t)value->resolution.xres;
4450
184k
      *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 24);
4451
184k
      *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 16);
4452
184k
      *bufptr++ = (ipp_uchar_t)(value->resolution.yres >> 8);
4453
184k
      *bufptr++ = (ipp_uchar_t)value->resolution.yres;
4454
184k
      *bufptr++ = (ipp_uchar_t)value->resolution.units;
4455
184k
    }
4456
1.63k
    break;
4457
4458
1.63k
      case IPP_TAG_RANGE :
4459
408k
          for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++)
4460
407k
    {
4461
407k
                  if ((IPP_BUF_SIZE - (bufptr - buffer)) < 13)
4462
149
      {
4463
149
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4464
0
              {
4465
0
          DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4466
0
          _cupsBufferRelease((char *)buffer);
4467
0
                return (IPP_STATE_ERROR);
4468
0
              }
4469
4470
149
        bufptr = buffer;
4471
149
      }
4472
4473
407k
      if (i)
4474
407k
      {
4475
        // Arrays and sets are done by sending additional values with a zero-length name...
4476
407k
                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
4477
407k
        *bufptr++ = 0;
4478
407k
        *bufptr++ = 0;
4479
407k
      }
4480
4481
      // Range values consist of a 2-byte length,
4482
      // 4-byte lower value, and 4-byte upper value.
4483
      //
4484
      // Put the 2-byte length and range value data
4485
      // into the buffer.
4486
407k
            *bufptr++ = 0;
4487
407k
      *bufptr++ = 8;
4488
407k
      *bufptr++ = (ipp_uchar_t)(value->range.lower >> 24);
4489
407k
      *bufptr++ = (ipp_uchar_t)(value->range.lower >> 16);
4490
407k
      *bufptr++ = (ipp_uchar_t)(value->range.lower >> 8);
4491
407k
      *bufptr++ = (ipp_uchar_t)value->range.lower;
4492
407k
      *bufptr++ = (ipp_uchar_t)(value->range.upper >> 24);
4493
407k
      *bufptr++ = (ipp_uchar_t)(value->range.upper >> 16);
4494
407k
      *bufptr++ = (ipp_uchar_t)(value->range.upper >> 8);
4495
407k
      *bufptr++ = (ipp_uchar_t)value->range.upper;
4496
407k
    }
4497
478
    break;
4498
4499
478
      case IPP_TAG_TEXTLANG :
4500
1.41k
      case IPP_TAG_NAMELANG :
4501
457k
          for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++)
4502
455k
    {
4503
455k
      if (i)
4504
454k
      {
4505
        // Arrays and sets are done by sending additional values with a zero-length name...
4506
454k
                    if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
4507
68
        {
4508
68
                      if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4509
0
                {
4510
0
      DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4511
0
      _cupsBufferRelease((char *)buffer);
4512
0
            return (IPP_STATE_ERROR);
4513
0
                }
4514
4515
68
          bufptr = buffer;
4516
68
        }
4517
4518
454k
                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
4519
454k
        *bufptr++ = 0;
4520
454k
        *bufptr++ = 0;
4521
454k
      }
4522
4523
      // textWithLanguage and nameWithLanguage values consist
4524
      // of a 2-byte length for both strings and their
4525
      // individual lengths, a 2-byte length for the
4526
      // character string, the character string without the
4527
      // trailing nul, a 2-byte length for the character
4528
      // set string, and the character set string without
4529
      // the trailing nul.
4530
455k
                  n = 4;
4531
4532
455k
      if (value->string.language != NULL)
4533
3.36k
                    n += (int)strlen(value->string.language);
4534
4535
455k
      if (value->string.text != NULL)
4536
455k
                    n += (int)strlen(value->string.text);
4537
4538
455k
                  if (n > (IPP_BUF_SIZE - 2))
4539
3
      {
4540
3
        DEBUG_printf("1ippWriteIO: text/nameWithLanguage value too long (%d)", n);
4541
3
        _cupsBufferRelease((char *)buffer);
4542
3
        return (IPP_STATE_ERROR);
4543
3
                  }
4544
4545
455k
                  if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
4546
293
      {
4547
293
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4548
0
              {
4549
0
          DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4550
0
          _cupsBufferRelease((char *)buffer);
4551
0
                return (IPP_STATE_ERROR);
4552
0
              }
4553
4554
293
        bufptr = buffer;
4555
293
      }
4556
4557
      // Length of entire value
4558
455k
            *bufptr++ = (ipp_uchar_t)(n >> 8);
4559
455k
      *bufptr++ = (ipp_uchar_t)n;
4560
4561
      // Length of language
4562
455k
      if (value->string.language != NULL)
4563
3.36k
        n = (int)strlen(value->string.language);
4564
452k
      else
4565
452k
        n = 0;
4566
4567
455k
            *bufptr++ = (ipp_uchar_t)(n >> 8);
4568
455k
      *bufptr++ = (ipp_uchar_t)n;
4569
4570
      // Language
4571
455k
      if (n > 0)
4572
1.51k
      {
4573
1.51k
        memcpy(bufptr, value->string.language, (size_t)n);
4574
1.51k
        bufptr += n;
4575
1.51k
      }
4576
4577
      // Length of text
4578
455k
                  if (value->string.text != NULL)
4579
455k
        n = (int)strlen(value->string.text);
4580
433
      else
4581
433
        n = 0;
4582
4583
455k
            *bufptr++ = (ipp_uchar_t)(n >> 8);
4584
455k
      *bufptr++ = (ipp_uchar_t)n;
4585
4586
      // Text
4587
455k
      if (n > 0)
4588
417k
      {
4589
417k
        memcpy(bufptr, value->string.text, (size_t)n);
4590
417k
        bufptr += n;
4591
417k
      }
4592
455k
    }
4593
1.41k
    break;
4594
4595
2.24k
            case IPP_TAG_BEGIN_COLLECTION :
4596
369k
          for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++)
4597
367k
    {
4598
      // Collections are written with the begin-collection
4599
      // tag first with a value of 0 length, followed by the
4600
      // attributes in the collection, then the end-collection
4601
      // value...
4602
367k
                  if ((IPP_BUF_SIZE - (bufptr - buffer)) < 5)
4603
0
      {
4604
0
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4605
0
              {
4606
0
          DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4607
0
          _cupsBufferRelease((char *)buffer);
4608
0
                return (IPP_STATE_ERROR);
4609
0
              }
4610
4611
0
        bufptr = buffer;
4612
0
      }
4613
4614
367k
      if (i)
4615
365k
      {
4616
        // Arrays and sets are done by sending additional values with a zero-length name...
4617
365k
                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
4618
365k
        *bufptr++ = 0;
4619
365k
        *bufptr++ = 0;
4620
365k
      }
4621
4622
      // Write a data length of 0 and flush the buffer...
4623
367k
            *bufptr++ = 0;
4624
367k
      *bufptr++ = 0;
4625
4626
367k
                  if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4627
0
            {
4628
0
        DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4629
0
        _cupsBufferRelease((char *)buffer);
4630
0
              return (IPP_STATE_ERROR);
4631
0
            }
4632
4633
367k
      bufptr = buffer;
4634
4635
      // Then write the collection attribute...
4636
367k
                  value->collection->state = IPP_STATE_IDLE;
4637
4638
367k
      if (ippWriteIO(dst, cb, 1, ipp, value->collection) == IPP_STATE_ERROR)
4639
0
      {
4640
0
        DEBUG_puts("1ippWriteIO: Unable to write collection value");
4641
0
        _cupsBufferRelease((char *)buffer);
4642
0
        return (IPP_STATE_ERROR);
4643
0
      }
4644
367k
    }
4645
2.24k
    break;
4646
4647
11.5k
            default :
4648
364k
          for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++)
4649
352k
    {
4650
352k
      if (i)
4651
341k
      {
4652
        // Arrays and sets are done by sending additional values with a zero-length name...
4653
341k
                    if ((IPP_BUF_SIZE - (bufptr - buffer)) < 3)
4654
56
        {
4655
56
                      if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4656
0
                {
4657
0
      DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4658
0
      _cupsBufferRelease((char *)buffer);
4659
0
            return (IPP_STATE_ERROR);
4660
0
                }
4661
4662
56
          bufptr = buffer;
4663
56
        }
4664
4665
341k
                    *bufptr++ = (ipp_uchar_t)attr->value_tag;
4666
341k
        *bufptr++ = 0;
4667
341k
        *bufptr++ = 0;
4668
341k
      }
4669
4670
      // An unknown value might some new value that a
4671
      // vendor has come up with. It consists of a
4672
      // 2-byte length and the bytes in the unknown
4673
      // value buffer.
4674
352k
                  n = value->unknown.length;
4675
4676
352k
                  if (n > (IPP_BUF_SIZE - 2))
4677
1
      {
4678
1
        DEBUG_printf("1ippWriteIO: Data length too long (%d)", n);
4679
1
        _cupsBufferRelease((char *)buffer);
4680
1
        return (IPP_STATE_ERROR);
4681
1
      }
4682
4683
352k
                  if ((int)(IPP_BUF_SIZE - (bufptr - buffer)) < (n + 2))
4684
516
      {
4685
516
                    if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4686
0
              {
4687
0
          DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4688
0
          _cupsBufferRelease((char *)buffer);
4689
0
                return (IPP_STATE_ERROR);
4690
0
              }
4691
4692
516
        bufptr = buffer;
4693
516
      }
4694
4695
      // Length of unknown value
4696
352k
            *bufptr++ = (ipp_uchar_t)(n >> 8);
4697
352k
      *bufptr++ = (ipp_uchar_t)n;
4698
4699
      // Value
4700
352k
      if (n > 0)
4701
85.8k
      {
4702
85.8k
        memcpy(bufptr, value->unknown.data, (size_t)n);
4703
85.8k
        bufptr += n;
4704
85.8k
      }
4705
352k
    }
4706
11.5k
    break;
4707
4.49M
    }
4708
4709
    // Write the data out...
4710
4.49M
    if (bufptr > buffer)
4711
4.49M
    {
4712
4.49M
      if ((*cb)(dst, buffer, (size_t)(bufptr - buffer)) < 0)
4713
0
      {
4714
0
        DEBUG_puts("1ippWriteIO: Could not write IPP attribute...");
4715
0
        _cupsBufferRelease((char *)buffer);
4716
0
        return (IPP_STATE_ERROR);
4717
0
      }
4718
4719
4.49M
      DEBUG_printf("2ippWriteIO: wrote %d bytes", (int)(bufptr - buffer));
4720
4.49M
    }
4721
4722
          // If blocking is disabled and we aren't at the end of the attribute
4723
          // list, stop here...
4724
4.49M
          if (!blocking && ipp->current)
4725
0
      break;
4726
4.49M
  }
4727
4728
372k
  if (ipp->current == NULL)
4729
372k
  {
4730
    // Done with all of the attributes; add the end-of-attributes
4731
    // tag or end-collection attribute...
4732
372k
          if (parent == NULL)
4733
5.39k
    {
4734
5.39k
            buffer[0] = IPP_TAG_END;
4735
5.39k
      n         = 1;
4736
5.39k
    }
4737
367k
    else
4738
367k
    {
4739
367k
            buffer[0] = IPP_TAG_END_COLLECTION;
4740
367k
      buffer[1] = 0; // empty name
4741
367k
      buffer[2] = 0;
4742
367k
      buffer[3] = 0; // empty value
4743
367k
      buffer[4] = 0;
4744
367k
      n         = 5;
4745
367k
    }
4746
4747
372k
    if ((*cb)(dst, buffer, (size_t)n) < 0)
4748
0
    {
4749
0
      DEBUG_puts("1ippWriteIO: Could not write IPP end-tag...");
4750
0
      _cupsBufferRelease((char *)buffer);
4751
0
      return (IPP_STATE_ERROR);
4752
0
    }
4753
4754
372k
    ipp->state = IPP_STATE_DATA;
4755
372k
  }
4756
372k
        break;
4757
4758
372k
    case IPP_STATE_DATA :
4759
0
        break;
4760
4761
0
    default :
4762
0
        break; // anti-compiler-warning-code
4763
372k
  }
4764
4765
372k
  _cupsBufferRelease((char *)buffer);
4766
4767
372k
  return (ipp->state);
4768
372k
}
4769
4770
4771
//
4772
// 'ipp_add_attr()' - Add a new attribute to the message.
4773
//
4774
4775
static ipp_attribute_t *    // O - New attribute
4776
ipp_add_attr(ipp_t      *ipp,   // I - IPP message
4777
             const char *name,    // I - Attribute name or NULL
4778
             ipp_tag_t  group_tag,  // I - Group tag or IPP_TAG_ZERO
4779
             ipp_tag_t  value_tag,  // I - Value tag or IPP_TAG_ZERO
4780
             size_t     num_values) // I - Number of values
4781
15.6M
{
4782
15.6M
  size_t    alloc_values; // Number of values to allocate
4783
15.6M
  ipp_attribute_t *attr;    // New attribute
4784
4785
4786
15.6M
  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);
4787
4788
  // Range check input...
4789
15.6M
  if (!ipp)
4790
0
    return (NULL);
4791
4792
  // Allocate memory, rounding the allocation up as needed...
4793
15.6M
  if (num_values <= 1)
4794
15.6M
    alloc_values = 1;
4795
0
  else
4796
0
    alloc_values = (num_values + IPP_MAX_VALUES - 1) & (size_t)~(IPP_MAX_VALUES - 1);
4797
4798
15.6M
  attr = calloc(1, sizeof(ipp_attribute_t) + (size_t)(alloc_values - 1) * sizeof(_ipp_value_t));
4799
4800
15.6M
  if (attr)
4801
15.6M
  {
4802
    // Initialize attribute...
4803
15.6M
    DEBUG_printf("4debug_alloc: %p %s %s%s (%u values)", (void *)attr, name, num_values > 1 ? "1setOf " : "", ippTagString(value_tag), (unsigned)num_values);
4804
4805
15.6M
    if (name)
4806
4.49M
      attr->name = _cupsStrAlloc(name);
4807
4808
15.6M
    attr->group_tag  = group_tag;
4809
15.6M
    attr->value_tag  = value_tag;
4810
15.6M
    attr->num_values = num_values;
4811
4812
    // Add it to the end of the linked list...
4813
15.6M
    if (ipp->last)
4814
15.6M
      ipp->last->next = attr;
4815
6.28k
    else
4816
6.28k
      ipp->attrs = attr;
4817
4818
15.6M
    ipp->prev = ipp->last;
4819
15.6M
    ipp->last = ipp->current = attr;
4820
15.6M
  }
4821
4822
15.6M
  DEBUG_printf("5ipp_add_attr: Returning %p", (void *)attr);
4823
4824
15.6M
  return (attr);
4825
15.6M
}
4826
4827
4828
//
4829
// 'ipp_free_values()' - Free attribute values.
4830
//
4831
4832
static void
4833
ipp_free_values(ipp_attribute_t *attr,  // I - Attribute to free values from
4834
                size_t          element,// I - First value to free
4835
                size_t          count)  // I - Number of values to free
4836
15.6M
{
4837
15.6M
  size_t  i;      // Looping var
4838
15.6M
  _ipp_value_t  *value;     // Current value
4839
4840
4841
15.6M
  DEBUG_printf("4ipp_free_values(attr=%p, element=%u, count=%u)", (void *)attr, (unsigned)element, (unsigned)count);
4842
4843
15.6M
  if (!(attr->value_tag & IPP_TAG_CUPS_CONST))
4844
15.6M
  {
4845
    // Free values as needed...
4846
15.6M
    switch (attr->value_tag)
4847
15.6M
    {
4848
551
      case IPP_TAG_TEXTLANG :
4849
4.30k
      case IPP_TAG_NAMELANG :
4850
4.30k
    if (element == 0 && count == attr->num_values && attr->values[0].string.language)
4851
4.22k
    {
4852
4.22k
      _cupsStrFree(attr->values[0].string.language);
4853
4.22k
      attr->values[0].string.language = NULL;
4854
4.22k
    }
4855
    // Fall through to other string values
4856
4857
378k
      case IPP_TAG_TEXT :
4858
379k
      case IPP_TAG_NAME :
4859
380k
      case IPP_TAG_RESERVED_STRING :
4860
4.47M
      case IPP_TAG_KEYWORD :
4861
4.47M
      case IPP_TAG_URI :
4862
4.47M
      case IPP_TAG_URISCHEME :
4863
4.47M
      case IPP_TAG_CHARSET :
4864
4.47M
      case IPP_TAG_LANGUAGE :
4865
4.47M
      case IPP_TAG_MIMETYPE :
4866
9.85M
    for (i = count, value = attr->values + element; i > 0; i --, value ++)
4867
5.38M
    {
4868
5.38M
      _cupsStrFree(value->string.text);
4869
5.38M
      value->string.text = NULL;
4870
5.38M
    }
4871
4.47M
    break;
4872
4873
306
      case IPP_TAG_UNSUPPORTED_VALUE :
4874
624
      case IPP_TAG_DEFAULT :
4875
1.15k
      case IPP_TAG_UNKNOWN :
4876
1.58k
      case IPP_TAG_NOVALUE :
4877
1.86k
      case IPP_TAG_NOTSETTABLE :
4878
2.14k
      case IPP_TAG_DELETEATTR :
4879
2.42k
      case IPP_TAG_ADMINDEFINE :
4880
2.86k
      case IPP_TAG_INTEGER :
4881
3.21k
      case IPP_TAG_ENUM :
4882
3.64k
      case IPP_TAG_BOOLEAN :
4883
4.13k
      case IPP_TAG_DATE :
4884
5.81k
      case IPP_TAG_RESOLUTION :
4885
6.35k
      case IPP_TAG_RANGE :
4886
6.35k
    break;
4887
4888
3.03k
      case IPP_TAG_BEGIN_COLLECTION :
4889
450k
    for (i = count, value = attr->values + element; i > 0; i --, value ++)
4890
447k
    {
4891
447k
      ippDelete(value->collection);
4892
447k
      value->collection = NULL;
4893
447k
    }
4894
3.03k
    break;
4895
4896
579
      case IPP_TAG_STRING :
4897
11.1M
      default :
4898
11.5M
    for (i = count, value = attr->values + element; i > 0; i --, value ++)
4899
414k
    {
4900
414k
      if (value->unknown.data)
4901
119k
      {
4902
119k
        free(value->unknown.data);
4903
119k
        value->unknown.data = NULL;
4904
119k
      }
4905
414k
    }
4906
11.1M
    break;
4907
15.6M
    }
4908
15.6M
  }
4909
4910
  // If we are not freeing values from the end, move the remaining values up...
4911
15.6M
  if ((element + count) < attr->num_values)
4912
0
    memmove(attr->values + element, attr->values + element + count, (size_t)(attr->num_values - count - element) * sizeof(_ipp_value_t));
4913
4914
15.6M
  attr->num_values -= count;
4915
15.6M
}
4916
4917
4918
//
4919
// 'ipp_get_code()' - Convert a C locale/charset name into an IPP language/charset code.
4920
//
4921
// This typically converts strings of the form "ll_CC", "ll-REGION", and "CHARSET_NUMBER"
4922
// to "ll-cc", "ll-region", and "charset-number", respectively.
4923
//
4924
4925
static char *       // O - Language code string
4926
ipp_get_code(const char *value,   // I - Locale/charset string
4927
             char       *buffer,  // I - String buffer
4928
             size_t     bufsize)  // I - Size of string buffer
4929
11.0k
{
4930
11.0k
  char  *bufptr,      // Pointer into buffer
4931
11.0k
  *bufend;      // End of buffer
4932
4933
4934
  // Convert values to lowercase and change _ to - as needed...
4935
66.3k
  for (bufptr = buffer, bufend = buffer + bufsize - 1; *value && bufptr < bufend; value ++)
4936
55.2k
  {
4937
55.2k
    if (*value == '_')
4938
8.35k
      *bufptr++ = '-';
4939
46.9k
    else
4940
46.9k
      *bufptr++ = (char)_cups_tolower(*value);
4941
55.2k
  }
4942
11.0k
  *bufptr = '\0';
4943
4944
  // Return the converted string...
4945
11.0k
  return (buffer);
4946
11.0k
}
4947
4948
4949
//
4950
// 'ipp_lang_code()' - Convert a C locale name into an IPP language code.
4951
//
4952
// This typically converts strings of the form "ll_CC" and "ll-REGION" to "ll-cc" and
4953
// "ll-region", respectively.  It also converts the "C" (POSIX) locale to "en".
4954
//
4955
4956
static char *       // O - Language code string
4957
ipp_lang_code(const char *locale, // I - Locale string
4958
              char       *buffer, // I - String buffer
4959
              size_t     bufsize) // I - Size of string buffer
4960
8.35k
{
4961
  // Map POSIX ("C") locale to generic English, otherwise convert the locale string as-is.
4962
8.35k
  if (!_cups_strcasecmp(locale, "c"))
4963
0
  {
4964
0
    cupsCopyString(buffer, "en", bufsize);
4965
0
    return (buffer);
4966
0
  }
4967
8.35k
  else
4968
8.35k
    return (ipp_get_code(locale, buffer, bufsize));
4969
8.35k
}
4970
4971
4972
//
4973
// 'ipp_length()' - Compute the length of an IPP message or collection value.
4974
//
4975
4976
static size_t       // O - Size of IPP message
4977
ipp_length(ipp_t *ipp,      // I - IPP message or collection
4978
           int   collection)    // I - 1 if a collection, 0 otherwise
4979
0
{
4980
0
  size_t    i;    // Looping var
4981
0
  size_t    bytes;    // Number of bytes
4982
0
  ipp_attribute_t *attr;    // Current attribute
4983
0
  ipp_tag_t   group;    // Current group
4984
0
  _ipp_value_t    *value;   // Current value
4985
4986
4987
0
  DEBUG_printf("3ipp_length(ipp=%p, collection=%d)", (void *)ipp, collection);
4988
4989
0
  if (!ipp)
4990
0
  {
4991
0
    DEBUG_puts("4ipp_length: Returning 0 bytes");
4992
0
    return (0);
4993
0
  }
4994
4995
  // Start with 8 bytes for the IPP message header...
4996
0
  bytes = collection ? 0 : 8;
4997
4998
  // Then add the lengths of each attribute...
4999
0
  group = IPP_TAG_ZERO;
5000
5001
0
  for (attr = ipp->attrs; attr != NULL; attr = attr->next)
5002
0
  {
5003
0
    if (attr->group_tag != group && !collection)
5004
0
    {
5005
0
      group = attr->group_tag;
5006
0
      if (group == IPP_TAG_ZERO)
5007
0
  continue;
5008
5009
0
      bytes ++; // Group tag
5010
0
    }
5011
5012
0
    if (!attr->name)
5013
0
      continue;
5014
5015
0
    DEBUG_printf("5ipp_length: attr->name=\"%s\", attr->num_values=%u, bytes=" CUPS_LLFMT, attr->name, (unsigned)attr->num_values, CUPS_LLCAST bytes);
5016
5017
0
    if ((attr->value_tag & ~IPP_TAG_CUPS_CONST) < IPP_TAG_EXTENSION)
5018
0
      bytes += (size_t)attr->num_values;// Value tag for each value
5019
0
    else
5020
0
      bytes += (size_t)(5 * attr->num_values);
5021
          // Value tag for each value
5022
0
    bytes += (size_t)(2 * attr->num_values);
5023
          // Name lengths
5024
0
    bytes += strlen(attr->name);  // Name
5025
0
    bytes += (size_t)(2 * attr->num_values);
5026
          // Value lengths
5027
5028
0
    if (collection)
5029
0
      bytes += 5;     // Add membername overhead
5030
5031
0
    switch (attr->value_tag & ~IPP_TAG_CUPS_CONST)
5032
0
    {
5033
0
      case IPP_TAG_UNSUPPORTED_VALUE :
5034
0
      case IPP_TAG_DEFAULT :
5035
0
      case IPP_TAG_UNKNOWN :
5036
0
      case IPP_TAG_NOVALUE :
5037
0
      case IPP_TAG_NOTSETTABLE :
5038
0
      case IPP_TAG_DELETEATTR :
5039
0
      case IPP_TAG_ADMINDEFINE :
5040
0
          break;
5041
5042
0
      case IPP_TAG_INTEGER :
5043
0
      case IPP_TAG_ENUM :
5044
0
          bytes += (size_t)(4 * attr->num_values);
5045
0
    break;
5046
5047
0
      case IPP_TAG_BOOLEAN :
5048
0
          bytes += (size_t)attr->num_values;
5049
0
    break;
5050
5051
0
      case IPP_TAG_TEXT :
5052
0
      case IPP_TAG_NAME :
5053
0
      case IPP_TAG_KEYWORD :
5054
0
      case IPP_TAG_URI :
5055
0
      case IPP_TAG_URISCHEME :
5056
0
      case IPP_TAG_CHARSET :
5057
0
      case IPP_TAG_LANGUAGE :
5058
0
      case IPP_TAG_MIMETYPE :
5059
0
    for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++)
5060
0
    {
5061
0
      if (value->string.text)
5062
0
        bytes += strlen(value->string.text);
5063
0
    }
5064
0
    break;
5065
5066
0
      case IPP_TAG_DATE :
5067
0
          bytes += (size_t)(11 * attr->num_values);
5068
0
    break;
5069
5070
0
      case IPP_TAG_RESOLUTION :
5071
0
          bytes += (size_t)(9 * attr->num_values);
5072
0
    break;
5073
5074
0
      case IPP_TAG_RANGE :
5075
0
          bytes += (size_t)(8 * attr->num_values);
5076
0
    break;
5077
5078
0
      case IPP_TAG_TEXTLANG :
5079
0
      case IPP_TAG_NAMELANG :
5080
0
          bytes += (size_t)(4 * attr->num_values);
5081
          // Charset + text length
5082
5083
0
    for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++)
5084
0
    {
5085
0
      if (value->string.language)
5086
0
        bytes += strlen(value->string.language);
5087
5088
0
      if (value->string.text)
5089
0
        bytes += strlen(value->string.text);
5090
0
    }
5091
0
    break;
5092
5093
0
      case IPP_TAG_BEGIN_COLLECTION :
5094
0
    for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++)
5095
0
            bytes += ipp_length(value->collection, 1);
5096
0
    break;
5097
5098
0
      default :
5099
0
    for (i = 0, value = attr->values; i < attr->num_values; i ++, value ++)
5100
0
            bytes += (size_t)value->unknown.length;
5101
0
    break;
5102
0
    }
5103
0
  }
5104
5105
  // Finally, add 1 byte for the "end of attributes" tag or 5 bytes for the "end of collection" tag and return...
5106
0
  if (collection)
5107
0
    bytes += 5;
5108
0
  else
5109
0
    bytes ++;
5110
5111
0
  DEBUG_printf("4ipp_length: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST bytes);
5112
5113
0
  return (bytes);
5114
0
}
5115
5116
5117
//
5118
// 'ipp_read_file()' - Read IPP data from a file.
5119
//
5120
5121
static ssize_t        // O - Number of bytes read
5122
ipp_read_file(int         *fd,    // I - File descriptor
5123
              ipp_uchar_t *buffer,  // O - Read buffer
5124
        size_t      length) // I - Number of bytes to read
5125
0
{
5126
#ifdef _WIN32
5127
  return ((ssize_t)read(*fd, buffer, (unsigned)length));
5128
#else
5129
0
  return (read(*fd, buffer, length));
5130
0
#endif // _WIN32
5131
0
}
5132
5133
5134
//
5135
// 'ipp_read_http()' - Semi-blocking read on a HTTP connection...
5136
//
5137
5138
static ssize_t        // O - Number of bytes read
5139
ipp_read_http(http_t      *http,  // I - Client connection
5140
              ipp_uchar_t *buffer,  // O - Buffer for data
5141
        size_t      length) // I - Total length
5142
0
{
5143
0
  ssize_t tbytes,     // Total bytes read
5144
0
    bytes;      // Bytes read this pass
5145
5146
5147
0
  DEBUG_printf("7ipp_read_http(http=%p, buffer=%p, length=%d)", (void *)http, (void *)buffer, (int)length);
5148
5149
  // Loop until all bytes are read...
5150
0
  for (tbytes = 0, bytes = 0; tbytes < (int)length; tbytes += bytes, buffer += bytes)
5151
0
  {
5152
0
    DEBUG_printf("9ipp_read_http: tbytes=" CUPS_LLFMT ", http->state=%d", CUPS_LLCAST tbytes, http->state);
5153
5154
0
    if (http->state == HTTP_STATE_WAITING)
5155
0
      break;
5156
5157
0
    if (http->used == 0 && !http->blocking)
5158
0
    {
5159
      // Wait up to 10 seconds for more data on non-blocking sockets...
5160
0
      if (!httpWait(http, 10000))
5161
0
      {
5162
  // Signal no data...
5163
0
  bytes = -1;
5164
0
  break;
5165
0
      }
5166
0
    }
5167
0
    else if (http->used == 0 && http->timeout_value > 0)
5168
0
    {
5169
      // Wait up to timeout seconds for more data on blocking sockets...
5170
0
      if (!httpWait(http, (int)(1000 * http->timeout_value)))
5171
0
      {
5172
  // Signal no data...
5173
0
  bytes = -1;
5174
0
  break;
5175
0
      }
5176
0
    }
5177
5178
0
    if ((bytes = httpRead(http, (char *)buffer, length - (size_t)tbytes)) < 0)
5179
0
    {
5180
#ifdef _WIN32
5181
      break;
5182
#else
5183
0
      if (errno != EAGAIN && errno != EINTR)
5184
0
  break;
5185
5186
0
      bytes = 0;
5187
0
#endif // _WIN32
5188
0
    }
5189
0
    else if (bytes == 0)
5190
0
    {
5191
0
      break;
5192
0
    }
5193
0
  }
5194
5195
  // Return the number of bytes read...
5196
0
  if (tbytes == 0 && bytes < 0)
5197
0
    tbytes = -1;
5198
5199
0
  DEBUG_printf("8ipp_read_http: Returning " CUPS_LLFMT " bytes", CUPS_LLCAST tbytes);
5200
5201
0
  return (tbytes);
5202
0
}
5203
5204
5205
//
5206
// 'ipp_read_io()' - Read data for an IPP message.
5207
//
5208
5209
static ipp_state_t      // O - Current state
5210
ipp_read_io(void        *src,   // I - Data source
5211
            ipp_io_cb_t cb,   // I - Read callback function
5212
      bool        blocking, // I - Use blocking IO?
5213
      ipp_t       *parent,  // I - Parent request, if any
5214
            ipp_t       *ipp,   // I - IPP data
5215
            int         depth)    // I - Depth of collection
5216
449k
{
5217
449k
  int     n;    // Length of data
5218
449k
  unsigned char   *buffer,  // Data buffer
5219
449k
      string[IPP_MAX_TEXT],
5220
          // Small string buffer
5221
449k
      *bufptr,  // Pointer into buffer
5222
449k
      *bufend;  // End of buffer
5223
449k
  ipp_attribute_t *attr = NULL; // Current attribute
5224
449k
  ipp_tag_t   tag;    // Current tag
5225
449k
  ipp_tag_t   value_tag;  // Current value tag
5226
449k
  _ipp_value_t    *value;   // Current value
5227
5228
5229
449k
  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);
5230
449k
  DEBUG_printf("2ipp_read_io: ipp->state=%d", ipp->state);
5231
5232
449k
  if (depth > 10)
5233
56
  {
5234
56
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP message nested too deeply."), true);
5235
56
    return (IPP_STATE_ERROR);
5236
56
  }
5237
5238
449k
  if ((buffer = (unsigned char *)_cupsBufferGet(IPP_BUF_SIZE)) == NULL)
5239
0
  {
5240
0
    DEBUG_puts("1ipp_read_io: Unable to get read buffer.");
5241
0
    return (IPP_STATE_ERROR);
5242
0
  }
5243
5244
449k
  switch (ipp->state)
5245
449k
  {
5246
449k
    case IPP_STATE_IDLE :
5247
449k
        ipp->state ++; // Avoid common problem...
5248
5249
449k
    case IPP_STATE_HEADER :
5250
449k
        if (parent == NULL)
5251
2.69k
  {
5252
          // Get the request header...
5253
2.69k
          if ((*cb)(src, buffer, 8) < 8)
5254
129
    {
5255
129
      DEBUG_puts("1ipp_read_io: Unable to read header.");
5256
129
      goto rollback;
5257
129
    }
5258
5259
          // Then copy the request header over...
5260
2.56k
          ipp->request.any.version[0]  = buffer[0];
5261
2.56k
          ipp->request.any.version[1]  = buffer[1];
5262
2.56k
          ipp->request.any.op_status   = (buffer[2] << 8) | buffer[3];
5263
2.56k
          ipp->request.any.request_id  = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
5264
5265
2.56k
          DEBUG_printf("2ipp_read_io: version=%d.%d", buffer[0], buffer[1]);
5266
2.56k
    DEBUG_printf("2ipp_read_io: op_status=%04x", ipp->request.any.op_status);
5267
2.56k
    DEBUG_printf("2ipp_read_io: request_id=%d", ipp->request.any.request_id);
5268
2.56k
        }
5269
5270
449k
        ipp->state   = IPP_STATE_ATTRIBUTE;
5271
449k
  ipp->current = NULL;
5272
449k
  ipp->curtag  = IPP_TAG_ZERO;
5273
449k
  ipp->prev    = ipp->last;
5274
5275
        // If blocking is disabled, stop here...
5276
449k
        if (!blocking)
5277
0
    break;
5278
5279
449k
    case IPP_STATE_ATTRIBUTE :
5280
449k
        for (;;)
5281
20.5M
  {
5282
20.5M
    if ((*cb)(src, buffer, 1) < 1)
5283
286
    {
5284
286
      DEBUG_puts("1ipp_read_io: Callback returned EOF/error");
5285
286
      goto rollback;
5286
286
    }
5287
5288
20.5M
    DEBUG_printf("2ipp_read_io: ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev);
5289
5290
    // Read this attribute...
5291
20.5M
          tag = (ipp_tag_t)buffer[0];
5292
5293
20.5M
    if (tag == IPP_TAG_END)
5294
446k
    {
5295
      // No more attributes left...
5296
446k
            DEBUG_puts("2ipp_read_io: IPP_TAG_END.");
5297
5298
446k
      ipp->state = IPP_STATE_DATA;
5299
446k
      break;
5300
446k
    }
5301
20.1M
    else if (tag == IPP_TAG_ZERO || (tag == IPP_TAG_OPERATION && ipp->curtag != IPP_TAG_ZERO))
5302
122
    {
5303
122
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid group tag."), true);
5304
122
      DEBUG_printf("1ipp_read_io: bad tag 0x%02x.", tag);
5305
122
      goto rollback;
5306
122
    }
5307
20.1M
          else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
5308
12.4M
    {
5309
      // Group tag...  Set the current group and continue...
5310
12.4M
            if (parent)
5311
2
            {
5312
2
        _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid group tag."), true);
5313
2
        DEBUG_printf("1ipp_read_io: bad tag 0x%02x.", tag);
5314
2
        goto rollback;
5315
2
            }
5316
12.4M
            else if (ipp->curtag == tag)
5317
11.1M
            {
5318
11.1M
        ipp->prev = ippAddSeparator(ipp);
5319
11.1M
            }
5320
1.31M
            else if (ipp->current)
5321
16.9k
      {
5322
16.9k
        ipp->prev = ipp->current;
5323
16.9k
      }
5324
5325
12.4M
      ipp->curtag  = tag;
5326
12.4M
      ipp->current = NULL;
5327
12.4M
      attr         = NULL;
5328
12.4M
      DEBUG_printf("2ipp_read_io: group tag=%x(%s), ipp->prev=%p", tag, ippTagString(tag), (void *)ipp->prev);
5329
12.4M
      continue;
5330
12.4M
    }
5331
5332
7.69M
          DEBUG_printf("2ipp_read_io: value tag=%x(%s)", tag, ippTagString(tag));
5333
5334
    // Get the name...
5335
7.69M
          if ((*cb)(src, buffer, 2) < 2)
5336
141
    {
5337
141
      DEBUG_puts("1ipp_read_io: unable to read name length.");
5338
141
      goto rollback;
5339
141
    }
5340
5341
7.69M
          n = (buffer[0] << 8) | buffer[1];
5342
5343
7.69M
          if (n >= IPP_BUF_SIZE)
5344
52
    {
5345
52
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP name larger than 32767 bytes."), true);
5346
52
      DEBUG_printf("1ipp_read_io: bad name length %d.", n);
5347
52
      goto rollback;
5348
52
    }
5349
5350
7.69M
          DEBUG_printf("2ipp_read_io: name length=%d", n);
5351
5352
7.69M
          if (n && parent)
5353
1
          {
5354
1
            _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid named IPP attribute in collection."), true);
5355
1
            DEBUG_puts("1ipp_read_io: bad attribute name in collection.");
5356
1
      goto rollback;
5357
1
          }
5358
7.69M
          else if (n == 0 && tag != IPP_TAG_MEMBERNAME && tag != IPP_TAG_END_COLLECTION)
5359
3.20M
    {
5360
      // More values for current attribute...
5361
3.20M
            if (ipp->current == NULL)
5362
70
      {
5363
70
        _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP attribute has no name."), true);
5364
70
        DEBUG_puts("1ipp_read_io: Attribute without name and no current.");
5365
70
        goto rollback;
5366
70
      }
5367
5368
3.20M
            attr      = ipp->current;
5369
3.20M
      value_tag = (ipp_tag_t)(attr->value_tag & IPP_TAG_CUPS_MASK);
5370
5371
      // Make sure we aren't adding a new value of a different type...
5372
3.20M
      if (value_tag == IPP_TAG_ZERO)
5373
990
      {
5374
        // Setting the value of a collection member...
5375
990
        attr->value_tag = tag;
5376
990
      }
5377
3.20M
      else if (value_tag == IPP_TAG_TEXTLANG || value_tag == IPP_TAG_NAMELANG || (value_tag >= IPP_TAG_TEXT && value_tag <= IPP_TAG_MIMETYPE))
5378
904k
            {
5379
        // String values can sometimes come across in different forms; accept sets of differing values...
5380
904k
        if (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG && (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE) && tag != IPP_TAG_NOVALUE)
5381
19
        {
5382
19
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP 1setOf attribute with incompatible value tags."), true);
5383
19
    DEBUG_printf("1ipp_read_io: 1setOf value tag %x(%s) != %x(%s)", value_tag, ippTagString(value_tag), tag, ippTagString(tag));
5384
19
    goto rollback;
5385
19
        }
5386
5387
904k
              if (value_tag != tag)
5388
757k
              {
5389
757k
                DEBUG_printf("1ipp_read_io: Converting %s attribute from %s to %s.", attr->name, ippTagString(value_tag), ippTagString(tag));
5390
757k
    if (!ippSetValueTag(ipp, &attr, tag))
5391
28
      goto rollback;
5392
757k
        }
5393
904k
            }
5394
2.30M
      else if (value_tag == IPP_TAG_INTEGER || value_tag == IPP_TAG_RANGE)
5395
408k
            {
5396
        // Integer and rangeOfInteger values can sometimes be mixed; accept sets of differing values...
5397
408k
        if (tag != IPP_TAG_INTEGER && tag != IPP_TAG_RANGE)
5398
12
        {
5399
12
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP 1setOf attribute with incompatible value tags."), true);
5400
12
    DEBUG_printf("1ipp_read_io: 1setOf value tag %x(%s) != %x(%s)", value_tag, ippTagString(value_tag), tag, ippTagString(tag));
5401
12
    goto rollback;
5402
12
        }
5403
5404
408k
              if (value_tag == IPP_TAG_INTEGER && tag == IPP_TAG_RANGE)
5405
205
              {
5406
                // Convert integer values to rangeOfInteger values...
5407
205
    DEBUG_printf("1ipp_read_io: Converting %s attribute to rangeOfInteger.", attr->name);
5408
205
                ippSetValueTag(ipp, &attr, IPP_TAG_RANGE);
5409
205
              }
5410
408k
            }
5411
1.89M
      else if (value_tag != tag)
5412
34
      {
5413
34
        _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP 1setOf attribute with incompatible value tags."), true);
5414
34
        DEBUG_printf("1ipp_read_io: value tag %x(%s) != %x(%s)", value_tag, ippTagString(value_tag), tag, ippTagString(tag));
5415
34
        goto rollback;
5416
34
            }
5417
5418
      // Finally, reallocate the attribute array as needed...
5419
3.20M
      if ((value = ipp_set_value(ipp, &attr, attr->num_values)) == NULL)
5420
0
        goto rollback;
5421
3.20M
    }
5422
4.49M
    else if (tag == IPP_TAG_MEMBERNAME)
5423
1.67k
    {
5424
      // Name must be length 0!
5425
1.67k
      if (n)
5426
1
      {
5427
1
        _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP member name is not empty."), true);
5428
1
        DEBUG_puts("1ipp_read_io: member name not empty.");
5429
1
        goto rollback;
5430
1
      }
5431
1.67k
      else if (!parent)
5432
2
      {
5433
2
        _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP member attribute outside of collection."), true);
5434
2
        DEBUG_puts("1ipp_read_io: member attribute outside of collection.");
5435
2
        goto rollback;
5436
2
      }
5437
5438
1.67k
            if (ipp->current)
5439
469
        ipp->prev = ipp->current;
5440
5441
1.67k
      attr = ipp->current = ipp_add_attr(ipp, NULL, ipp->curtag, IPP_TAG_ZERO, 1);
5442
1.67k
      if (!attr)
5443
0
      {
5444
0
        _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), false);
5445
0
        DEBUG_puts("1ipp_read_io: unable to allocate attribute.");
5446
0
        goto rollback;
5447
0
      }
5448
5449
1.67k
      DEBUG_printf("2ipp_read_io: membername, ipp->current=%p, ipp->prev=%p", (void *)ipp->current, (void *)ipp->prev);
5450
5451
1.67k
      value = attr->values;
5452
1.67k
    }
5453
4.49M
    else if (tag != IPP_TAG_END_COLLECTION)
5454
4.49M
    {
5455
      // New attribute; read the name and add it...
5456
4.49M
      if ((*cb)(src, buffer, (size_t)n) < n)
5457
481
      {
5458
481
        DEBUG_puts("1ipp_read_io: unable to read name.");
5459
481
        goto rollback;
5460
481
      }
5461
5462
4.49M
      buffer[n] = '\0';
5463
5464
4.49M
            if (ipp->current)
5465
4.13M
        ipp->prev = ipp->current;
5466
5467
4.49M
      if ((attr = ipp->current = ipp_add_attr(ipp, (char *)buffer, ipp->curtag, tag, 1)) == NULL)
5468
0
      {
5469
0
        _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), false);
5470
0
        DEBUG_puts("1ipp_read_io: unable to allocate attribute.");
5471
0
        goto rollback;
5472
0
      }
5473
5474
4.49M
      DEBUG_printf("2ipp_read_io: name=\"%s\", ipp->current=%p, ipp->prev=%p", buffer, (void *)ipp->current, (void *)ipp->prev);
5475
5476
4.49M
      value = attr->values;
5477
4.49M
    }
5478
57
    else
5479
57
    {
5480
57
      attr  = NULL;
5481
57
      value = NULL;
5482
57
    }
5483
5484
7.69M
    if ((*cb)(src, buffer, 2) < 2)
5485
439
    {
5486
439
      DEBUG_puts("1ipp_read_io: unable to read value length.");
5487
439
      goto rollback;
5488
439
    }
5489
5490
7.69M
    n = (buffer[0] << 8) | buffer[1];
5491
7.69M
          DEBUG_printf("2ipp_read_io: value length=%d", n);
5492
5493
7.69M
    if (n >= IPP_BUF_SIZE)
5494
8
    {
5495
8
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL,
5496
8
        _("IPP value larger than 32767 bytes."), true);
5497
8
      DEBUG_printf("1ipp_read_io: bad value length %d.", n);
5498
8
      goto rollback;
5499
8
    }
5500
5501
7.69M
    switch (tag)
5502
7.69M
    {
5503
1.38k
      case IPP_TAG_INTEGER :
5504
369k
      case IPP_TAG_ENUM :
5505
369k
    if (n != 4)
5506
10
    {
5507
10
      if (tag == IPP_TAG_INTEGER)
5508
4
        _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP integer value not 4 bytes."), true);
5509
6
      else
5510
6
        _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP enum value not 4 bytes."), true);
5511
10
      DEBUG_printf("1ipp_read_io: bad integer value length %d.", n);
5512
10
      goto rollback;
5513
10
    }
5514
5515
369k
          if ((*cb)(src, buffer, 4) < 4)
5516
23
    {
5517
23
            DEBUG_puts("1ipp_read_io: Unable to read integer value.");
5518
23
      goto rollback;
5519
23
    }
5520
5521
369k
    n = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
5522
5523
369k
                if (attr->value_tag == IPP_TAG_RANGE)
5524
194
                  value->range.lower = value->range.upper = n;
5525
369k
                else
5526
369k
      value->integer = n;
5527
369k
          break;
5528
5529
178k
      case IPP_TAG_BOOLEAN :
5530
178k
    if (n != 1)
5531
35
    {
5532
35
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP boolean value not 1 byte."),
5533
35
                    1);
5534
35
      DEBUG_printf("1ipp_read_io: bad boolean value length %d.", n);
5535
35
      goto rollback;
5536
35
    }
5537
5538
178k
          if ((*cb)(src, buffer, 1) < 1)
5539
4
    {
5540
4
            DEBUG_puts("1ipp_read_io: Unable to read boolean value.");
5541
4
      goto rollback;
5542
4
    }
5543
5544
178k
                value->boolean = (char)buffer[0];
5545
178k
          break;
5546
5547
809
      case IPP_TAG_UNSUPPORTED_VALUE :
5548
135k
      case IPP_TAG_DEFAULT :
5549
136k
      case IPP_TAG_UNKNOWN :
5550
143k
      case IPP_TAG_NOVALUE :
5551
144k
      case IPP_TAG_NOTSETTABLE :
5552
278k
      case IPP_TAG_DELETEATTR :
5553
279k
      case IPP_TAG_ADMINDEFINE :
5554
          // These value types are not supposed to have values, however
5555
    // some vendors (Brother) do not implement IPP correctly and so
5556
    // we need to map non-empty values to text...
5557
279k
          if (attr->value_tag == tag)
5558
279k
    {
5559
279k
      if (n == 0)
5560
8.44k
        break;
5561
5562
270k
      attr->value_tag = IPP_TAG_TEXT;
5563
270k
    }
5564
5565
377k
      case IPP_TAG_TEXT :
5566
387k
      case IPP_TAG_NAME :
5567
388k
      case IPP_TAG_RESERVED_STRING :
5568
5.35M
      case IPP_TAG_KEYWORD :
5569
5.35M
      case IPP_TAG_URI :
5570
5.35M
      case IPP_TAG_URISCHEME :
5571
5.36M
      case IPP_TAG_CHARSET :
5572
5.36M
      case IPP_TAG_LANGUAGE :
5573
5.36M
      case IPP_TAG_MIMETYPE :
5574
5.36M
          if (n > 0)
5575
1.14M
          {
5576
1.14M
      if ((*cb)(src, buffer, (size_t)n) < n)
5577
208
      {
5578
208
        DEBUG_puts("1ipp_read_io: unable to read string value.");
5579
208
        goto rollback;
5580
208
      }
5581
1.14M
    }
5582
5583
5.36M
    buffer[n] = '\0';
5584
5.36M
    value->string.text = _cupsStrAlloc((char *)buffer);
5585
5.36M
    DEBUG_printf("2ipp_read_io: value=\"%s\"(%p)", value->string.text, value->string.text);
5586
5.36M
          break;
5587
5588
310k
      case IPP_TAG_DATE :
5589
310k
    if (n != 11)
5590
26
    {
5591
26
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP date value not 11 bytes."), true);
5592
26
      DEBUG_printf("1ipp_read_io: bad date value length %d.", n);
5593
26
      goto rollback;
5594
26
    }
5595
5596
310k
          if ((*cb)(src, value->date, 11) < 11)
5597
13
    {
5598
13
            DEBUG_puts("1ipp_read_io: Unable to read date value.");
5599
13
      goto rollback;
5600
13
    }
5601
310k
          break;
5602
5603
310k
      case IPP_TAG_RESOLUTION :
5604
184k
    if (n != 9)
5605
21
    {
5606
21
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP resolution value not 9 bytes."), true);
5607
21
      DEBUG_printf("1ipp_read_io: bad resolution value length %d.", n);
5608
21
      goto rollback;
5609
21
    }
5610
5611
184k
          if ((*cb)(src, buffer, 9) < 9)
5612
9
    {
5613
9
            DEBUG_puts("1ipp_read_io: Unable to read resolution value.");
5614
9
      goto rollback;
5615
9
    }
5616
5617
184k
                value->resolution.xres  = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
5618
184k
                value->resolution.yres  = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
5619
184k
                value->resolution.units =
5620
184k
        (ipp_res_t)buffer[8];
5621
184k
          break;
5622
5623
407k
      case IPP_TAG_RANGE :
5624
407k
    if (n != 8)
5625
23
    {
5626
23
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP rangeOfInteger value not 8 bytes."), true);
5627
23
      DEBUG_printf("1ipp_read_io: bad rangeOfInteger value length %d.", n);
5628
23
      goto rollback;
5629
23
    }
5630
5631
407k
          if ((*cb)(src, buffer, 8) < 8)
5632
17
    {
5633
17
            DEBUG_puts("1ipp_read_io: Unable to read range value.");
5634
17
      goto rollback;
5635
17
    }
5636
5637
407k
                value->range.lower = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
5638
407k
                value->range.upper = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
5639
407k
          break;
5640
5641
4.02k
      case IPP_TAG_TEXTLANG :
5642
5.44k
      case IPP_TAG_NAMELANG :
5643
5.44k
          if (n < 4)
5644
7
    {
5645
7
      if (tag == IPP_TAG_TEXTLANG)
5646
5
        _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP textWithLanguage value less than minimum 4 bytes."), true);
5647
2
      else
5648
2
        _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP nameWithLanguage value less than minimum 4 bytes."), true);
5649
7
      DEBUG_printf("1ipp_read_io: bad stringWithLanguage value length %d.", n);
5650
7
      goto rollback;
5651
7
    }
5652
5653
5.43k
          if ((*cb)(src, buffer, (size_t)n) < n)
5654
80
    {
5655
80
            DEBUG_puts("1ipp_read_io: Unable to read string w/language value.");
5656
80
      goto rollback;
5657
80
    }
5658
5659
5.35k
                bufptr = buffer;
5660
5.35k
                bufend = buffer + n;
5661
5662
          // textWithLanguage and nameWithLanguage are composite values:
5663
    //
5664
    //   language-length
5665
    //   language
5666
    //   text-length
5667
    //   text
5668
5.35k
    n = (bufptr[0] << 8) | bufptr[1];
5669
5670
5.35k
    if ((bufptr + 2 + n + 2) > bufend || n >= (int)sizeof(string))
5671
8
    {
5672
8
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP language length overflows value."), true);
5673
8
      DEBUG_printf("1ipp_read_io: bad language value length %d.", n);
5674
8
      goto rollback;
5675
8
    }
5676
5.34k
    else if (n >= IPP_MAX_LANGUAGE)
5677
17
    {
5678
17
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP language length too large."), true);
5679
17
      DEBUG_printf("1ipp_read_io: bad language value length %d.", n);
5680
17
      goto rollback;
5681
17
    }
5682
5683
5.33k
    memcpy(string, bufptr + 2, (size_t)n);
5684
5.33k
    string[n] = '\0';
5685
5686
5.33k
    value->string.language = _cupsStrAlloc((char *)string);
5687
5688
5.33k
                bufptr += 2 + n;
5689
5.33k
    n = (bufptr[0] << 8) | bufptr[1];
5690
5691
5.33k
    if ((bufptr + 2 + n) > bufend)
5692
10
    {
5693
10
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP string length overflows value."), true);
5694
10
      DEBUG_printf("1ipp_read_io: bad string value length %d.", n);
5695
10
      goto rollback;
5696
10
    }
5697
5698
5.32k
    bufptr[2 + n] = '\0';
5699
5.32k
                value->string.text = _cupsStrAlloc((char *)bufptr + 2);
5700
5.32k
          break;
5701
5702
447k
            case IPP_TAG_BEGIN_COLLECTION :
5703
          // Oh boy, here comes a collection value, so read it...
5704
447k
                value->collection = ippNew();
5705
5706
447k
                if (n > 0)
5707
31
    {
5708
31
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP begCollection value not 0 bytes."), true);
5709
31
            DEBUG_puts("1ipp_read_io: begCollection tag with value length > 0.");
5710
31
      goto rollback;
5711
31
    }
5712
5713
447k
    if (ipp_read_io(src, cb, 1, ipp, value->collection, depth + 1) == IPP_STATE_ERROR)
5714
702
    {
5715
702
            DEBUG_puts("1ipp_read_io: Unable to read collection value.");
5716
702
      goto rollback;
5717
702
    }
5718
446k
                break;
5719
5720
446k
            case IPP_TAG_END_COLLECTION :
5721
50
                if (n > 0)
5722
26
    {
5723
26
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP endCollection value not 0 bytes."), true);
5724
26
            DEBUG_puts("1ipp_read_io: endCollection tag with value length > 0.");
5725
26
      goto rollback;
5726
26
    }
5727
5728
24
    _cupsBufferRelease((char *)buffer);
5729
5730
24
          DEBUG_puts("1ipp_read_io: endCollection tag...");
5731
24
    return (ipp->state = IPP_STATE_DATA);
5732
5733
1.66k
            case IPP_TAG_MEMBERNAME :
5734
          // The value is the name of the member in the collection, which
5735
    // we need to carry over...
5736
1.66k
    if (n == 0)
5737
1
    {
5738
1
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP memberName value is empty."), true);
5739
1
            DEBUG_puts("1ipp_read_io: Empty member name value.");
5740
1
      goto rollback;
5741
1
    }
5742
1.66k
    else if ((*cb)(src, buffer, (size_t)n) < n)
5743
33
    {
5744
33
            DEBUG_puts("1ipp_read_io: Unable to read member name value.");
5745
33
      goto rollback;
5746
33
    }
5747
5748
1.63k
    buffer[n] = '\0';
5749
1.63k
    attr->name = _cupsStrAlloc((char *)buffer);
5750
5751
          // Since collection members are encoded differently than
5752
    // regular attributes, make sure we don't start with an
5753
    // empty value...
5754
1.63k
                attr->num_values --;
5755
5756
1.63k
    DEBUG_printf("2ipp_read_io: member name=\"%s\"", attr->name);
5757
1.63k
    break;
5758
5759
12.4k
            case IPP_TAG_STRING :
5760
414k
            default : // Other unsupported values
5761
414k
                if (tag == IPP_TAG_STRING && n > IPP_MAX_LENGTH)
5762
1
    {
5763
1
      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP octetString length too large."), true);
5764
1
      DEBUG_printf("1ipp_read_io: bad octetString value length %d.", n);
5765
1
      goto rollback;
5766
1
    }
5767
5768
414k
                value->unknown.length = (size_t)n;
5769
5770
414k
          if (n > 0)
5771
119k
    {
5772
119k
      if ((value->unknown.data = malloc((size_t)n)) == NULL)
5773
0
      {
5774
0
        _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), false);
5775
0
        DEBUG_puts("1ipp_read_io: Unable to allocate value");
5776
0
        goto rollback;
5777
0
      }
5778
5779
119k
            if ((*cb)(src, value->unknown.data, (size_t)n) < n)
5780
139
      {
5781
139
              DEBUG_puts("1ipp_read_io: Unable to read unsupported value.");
5782
139
        goto rollback;
5783
139
      }
5784
119k
    }
5785
294k
    else
5786
294k
    {
5787
294k
      value->unknown.data = NULL;
5788
294k
    }
5789
414k
          break;
5790
7.69M
    }
5791
5792
          // If blocking is disabled, stop here...
5793
7.69M
          if (!blocking)
5794
0
      break;
5795
7.69M
  }
5796
446k
        break;
5797
5798
446k
    case IPP_STATE_DATA :
5799
0
        break;
5800
5801
0
    default :
5802
0
        break; // anti-compiler-warning-code
5803
449k
  }
5804
5805
446k
  DEBUG_printf("1ipp_read_io: returning ipp->state=%d.", ipp->state);
5806
446k
  _cupsBufferRelease((char *)buffer);
5807
5808
446k
  return (ipp->state);
5809
5810
  // If we get here, there was an error that required us to roll back the last
5811
  // attribute read in order to keep the IPP message valid...
5812
3.27k
  rollback:
5813
5814
3.27k
  _cupsBufferRelease((char *)buffer);
5815
5816
3.27k
  if (attr)
5817
2.29k
    ippDeleteAttribute(ipp, attr);
5818
5819
3.27k
  return (IPP_STATE_ERROR);
5820
449k
}
5821
5822
5823
//
5824
// 'ipp_set_error()' - Set a formatted, localized error string.
5825
//
5826
5827
static void
5828
ipp_set_error(ipp_status_t status,  // I - Status code
5829
              const char   *format, // I - Printf-style error string
5830
        ...)      // I - Additional arguments as needed
5831
0
{
5832
0
  va_list ap;     // Pointer to additional args
5833
0
  char    buffer[2048];   // Message buffer
5834
0
  cups_lang_t *lang = cupsLangDefault();
5835
          // Current language
5836
5837
5838
0
  va_start(ap, format);
5839
0
  vsnprintf(buffer, sizeof(buffer), cupsLangGetString(lang, format), ap);
5840
0
  va_end(ap);
5841
5842
0
  _cupsSetError(status, buffer, 0);
5843
0
}
5844
5845
5846
//
5847
// 'ipp_set_value()' - Get the value element from an attribute, expanding it as
5848
//                     needed.
5849
//
5850
5851
static _ipp_value_t *     // O  - IPP value element or NULL on error
5852
ipp_set_value(ipp_t           *ipp, // IO - IPP message
5853
              ipp_attribute_t **attr, // IO - IPP attribute
5854
              size_t          element)  // I  - Value number (`0`-based)
5855
3.20M
{
5856
3.20M
  ipp_attribute_t *temp,    // New attribute pointer
5857
3.20M
      *current, // Current attribute in list
5858
3.20M
      *prev;    // Previous attribute in list
5859
3.20M
  size_t    alloc_values; // Allocated values
5860
5861
5862
  // If we are setting an existing value element, return it...
5863
3.20M
  temp = *attr;
5864
5865
3.20M
  if (temp->num_values <= 1)
5866
10.4k
    alloc_values = 1;
5867
3.19M
  else
5868
3.19M
    alloc_values = (temp->num_values + IPP_MAX_VALUES - 1) & (size_t)~(IPP_MAX_VALUES - 1);
5869
5870
3.20M
  if (element < alloc_values)
5871
2.80M
  {
5872
2.80M
    if (element >= temp->num_values)
5873
2.80M
      temp->num_values = element + 1;
5874
5875
2.80M
    return (temp->values + element);
5876
2.80M
  }
5877
5878
  // Otherwise re-allocate the attribute - we allocate in groups of IPP_MAX_VALUE
5879
  // values when num_values > 1.
5880
404k
  if (alloc_values < IPP_MAX_VALUES)
5881
5.45k
    alloc_values = IPP_MAX_VALUES;
5882
398k
  else
5883
398k
    alloc_values += IPP_MAX_VALUES;
5884
5885
404k
  DEBUG_printf("4ipp_set_value: Reallocating for up to %u values.", (unsigned)alloc_values);
5886
5887
  // Reallocate memory...
5888
404k
  if ((temp = realloc(temp, sizeof(ipp_attribute_t) + (size_t)(alloc_values - 1) * sizeof(_ipp_value_t))) == NULL)
5889
0
  {
5890
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), false);
5891
0
    DEBUG_puts("4ipp_set_value: Unable to resize attribute.");
5892
0
    return (NULL);
5893
0
  }
5894
5895
  // Zero the new memory...
5896
404k
  memset(temp->values + temp->num_values, 0, (size_t)(alloc_values - temp->num_values) * sizeof(_ipp_value_t));
5897
5898
404k
  if (temp != *attr)
5899
7.88k
  {
5900
    // Reset pointers in the list...
5901
7.88k
#ifndef __clang_analyzer__
5902
7.88k
    DEBUG_printf("4debug_free: %p %s", (void *)*attr, temp->name);
5903
7.88k
#endif // !__clang_analyzer__
5904
7.88k
    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);
5905
5906
7.88k
    if (ipp->current == *attr && ipp->prev)
5907
7.70k
    {
5908
      // Use current "previous" pointer...
5909
7.70k
      prev = ipp->prev;
5910
7.70k
    }
5911
182
    else
5912
182
    {
5913
      // Find this attribute in the linked list...
5914
182
      for (prev = NULL, current = ipp->attrs; current && current != *attr; prev = current, current = current->next)
5915
0
        ;        // Loop until we find the attribute
5916
5917
182
      if (!current)
5918
0
      {
5919
  // This is a serious error!
5920
0
  *attr = temp;
5921
0
  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("IPP attribute is not a member of the message."), true);
5922
0
  DEBUG_puts("4ipp_set_value: Unable to find attribute in message.");
5923
0
  return (NULL);
5924
0
      }
5925
182
    }
5926
5927
7.88k
    if (prev)
5928
7.70k
      prev->next = temp;
5929
182
    else
5930
182
      ipp->attrs = temp;
5931
5932
7.88k
    ipp->current = temp;
5933
7.88k
    ipp->prev    = prev;
5934
5935
7.88k
    if (ipp->last == *attr)
5936
7.88k
      ipp->last = temp;
5937
5938
7.88k
    *attr = temp;
5939
7.88k
  }
5940
5941
  // Return the value element...
5942
404k
  if (element >= temp->num_values)
5943
404k
    temp->num_values = element + 1;
5944
5945
404k
  return (temp->values + element);
5946
404k
}
5947
5948
5949
//
5950
// 'ipp_write_file()' - Write IPP data to a file.
5951
//
5952
5953
static ssize_t        // O - Number of bytes written
5954
ipp_write_file(int         *fd,   // I - File descriptor
5955
               ipp_uchar_t *buffer, // I - Data to write
5956
               size_t      length)  // I - Number of bytes to write
5957
0
{
5958
#ifdef _WIN32
5959
  return ((ssize_t)write(*fd, buffer, (unsigned)length));
5960
#else
5961
0
  return (write(*fd, buffer, length));
5962
0
#endif // _WIN32
5963
0
}