Coverage Report

Created: 2026-10-17 07:24

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