Coverage Report

Created: 2026-09-14 07:07

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