Coverage Report

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