Coverage Report

Created: 2025-08-11 06:21

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