Coverage Report

Created: 2026-05-30 06:20

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