Coverage Report

Created: 2025-12-31 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cups/cups/encode.c
Line
Count
Source
1
/*
2
 * Option encoding routines for CUPS.
3
 *
4
 * Copyright 2007-2017 by Apple Inc.
5
 * Copyright 1997-2007 by Easy Software Products.
6
 *
7
 * These coded instructions, statements, and computer programs are the
8
 * property of Apple Inc. and are protected by Federal copyright
9
 * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
10
 * which should have been included with this file.  If this file is
11
 * missing or damaged, see the license at "http://www.cups.org/".
12
 *
13
 * This file is subject to the Apple OS-Developed Software exception.
14
 */
15
16
/*
17
 * Include necessary headers...
18
 */
19
20
#include "cups-private.h"
21
22
23
/*
24
 * Local list of option names, the value tags they should use, and the list of
25
 * supported operations...
26
 *
27
 * **** THIS LIST MUST BE SORTED BY ATTRIBUTE NAME ****
28
 */
29
30
static const ipp_op_t ipp_job_creation[] =
31
{
32
  IPP_OP_PRINT_JOB,
33
  IPP_OP_PRINT_URI,
34
  IPP_OP_VALIDATE_JOB,
35
  IPP_OP_CREATE_JOB,
36
  IPP_OP_HOLD_JOB,
37
  IPP_OP_SET_JOB_ATTRIBUTES,
38
  IPP_OP_CUPS_NONE
39
};
40
41
static const ipp_op_t ipp_doc_creation[] =
42
{
43
  IPP_OP_PRINT_JOB,
44
  IPP_OP_PRINT_URI,
45
  IPP_OP_SEND_DOCUMENT,
46
  IPP_OP_SEND_URI,
47
  IPP_OP_SET_JOB_ATTRIBUTES,
48
  IPP_OP_SET_DOCUMENT_ATTRIBUTES,
49
  IPP_OP_CUPS_NONE
50
};
51
52
static const ipp_op_t ipp_sub_creation[] =
53
{
54
  IPP_OP_PRINT_JOB,
55
  IPP_OP_PRINT_URI,
56
  IPP_OP_CREATE_JOB,
57
  IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS,
58
  IPP_OP_CREATE_JOB_SUBSCRIPTIONS,
59
  IPP_OP_CUPS_NONE
60
};
61
62
static const ipp_op_t ipp_all_print[] =
63
{
64
  IPP_OP_PRINT_JOB,
65
  IPP_OP_PRINT_URI,
66
  IPP_OP_VALIDATE_JOB,
67
  IPP_OP_CREATE_JOB,
68
  IPP_OP_SEND_DOCUMENT,
69
  IPP_OP_SEND_URI,
70
  IPP_OP_CUPS_NONE
71
};
72
73
static const ipp_op_t ipp_set_printer[] =
74
{
75
  IPP_OP_SET_PRINTER_ATTRIBUTES,
76
  IPP_OP_CUPS_ADD_MODIFY_PRINTER,
77
  IPP_OP_CUPS_ADD_MODIFY_CLASS,
78
  IPP_OP_CUPS_NONE
79
};
80
81
static const ipp_op_t cups_schemes[] =
82
{
83
  IPP_OP_CUPS_GET_DEVICES,
84
  IPP_OP_CUPS_GET_PPDS,
85
  IPP_OP_CUPS_NONE
86
};
87
88
static const ipp_op_t cups_get_ppds[] =
89
{
90
  IPP_OP_CUPS_GET_PPDS,
91
  IPP_OP_CUPS_NONE
92
};
93
94
static const ipp_op_t cups_ppd_name[] =
95
{
96
  IPP_OP_CUPS_ADD_MODIFY_PRINTER,
97
  IPP_OP_CUPS_GET_PPD,
98
  IPP_OP_CUPS_NONE
99
};
100
101
static const _ipp_option_t ipp_options[] =
102
{
103
  { 1, "auth-info",   IPP_TAG_TEXT,   IPP_TAG_JOB },
104
  { 1, "auth-info-default", IPP_TAG_TEXT,   IPP_TAG_PRINTER },
105
  { 1, "auth-info-required",  IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
106
  { 0, "blackplot",   IPP_TAG_BOOLEAN,  IPP_TAG_JOB },
107
  { 0, "blackplot-default", IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
108
  { 0, "brightness",    IPP_TAG_INTEGER,  IPP_TAG_JOB },
109
  { 0, "brightness-default",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
110
  { 0, "columns",   IPP_TAG_INTEGER,  IPP_TAG_JOB },
111
  { 0, "columns-default", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
112
  { 0, "compression",   IPP_TAG_KEYWORD,  IPP_TAG_OPERATION,
113
              IPP_TAG_ZERO,
114
              ipp_doc_creation },
115
  { 0, "copies",    IPP_TAG_INTEGER,  IPP_TAG_JOB,
116
              IPP_TAG_DOCUMENT },
117
  { 0, "copies-default",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
118
  { 0, "date-time-at-completed",IPP_TAG_DATE,   IPP_TAG_ZERO }, /* never send as option */
119
  { 0, "date-time-at-creation", IPP_TAG_DATE,   IPP_TAG_ZERO }, /* never send as option */
120
  { 0, "date-time-at-processing",IPP_TAG_DATE,    IPP_TAG_ZERO }, /* never send as option */
121
  { 0, "device-uri",    IPP_TAG_URI,    IPP_TAG_PRINTER },
122
  { 1, "document-copies", IPP_TAG_RANGE,    IPP_TAG_JOB,
123
              IPP_TAG_DOCUMENT,
124
              ipp_doc_creation },
125
  { 0, "document-format", IPP_TAG_MIMETYPE, IPP_TAG_OPERATION,
126
              IPP_TAG_ZERO,
127
              ipp_doc_creation },
128
  { 0, "document-format-default", IPP_TAG_MIMETYPE, IPP_TAG_PRINTER },
129
  { 1, "document-numbers",  IPP_TAG_RANGE,    IPP_TAG_JOB,
130
              IPP_TAG_DOCUMENT,
131
              ipp_all_print },
132
  { 1, "exclude-schemes", IPP_TAG_NAME,   IPP_TAG_OPERATION,
133
              IPP_TAG_ZERO,
134
              cups_schemes },
135
  { 1, "finishings",    IPP_TAG_ENUM,   IPP_TAG_JOB,
136
              IPP_TAG_DOCUMENT },
137
  { 1, "finishings-default",  IPP_TAG_ENUM,   IPP_TAG_PRINTER },
138
  { 0, "fit-to-page",   IPP_TAG_BOOLEAN,  IPP_TAG_JOB,
139
              IPP_TAG_DOCUMENT },
140
  { 0, "fit-to-page-default", IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
141
  { 0, "fitplot",   IPP_TAG_BOOLEAN,  IPP_TAG_JOB },
142
  { 0, "fitplot-default", IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
143
  { 0, "gamma",     IPP_TAG_INTEGER,  IPP_TAG_JOB },
144
  { 0, "gamma-default",   IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
145
  { 0, "hue",     IPP_TAG_INTEGER,  IPP_TAG_JOB },
146
  { 0, "hue-default",   IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
147
  { 1, "include-schemes", IPP_TAG_NAME,   IPP_TAG_OPERATION,
148
              IPP_TAG_ZERO,
149
              cups_schemes },
150
  { 0, "job-account-id",        IPP_TAG_NAME,           IPP_TAG_JOB },
151
  { 0, "job-account-id-default",IPP_TAG_NAME,           IPP_TAG_PRINTER },
152
  { 0, "job-accounting-user-id", IPP_TAG_NAME,          IPP_TAG_JOB },
153
  { 0, "job-accounting-user-id-default", IPP_TAG_NAME,  IPP_TAG_PRINTER },
154
  { 0, "job-authorization-uri", IPP_TAG_URI,    IPP_TAG_OPERATION },
155
  { 0, "job-cancel-after",  IPP_TAG_INTEGER,  IPP_TAG_JOB },
156
  { 0, "job-cancel-after-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
157
  { 0, "job-hold-until",  IPP_TAG_KEYWORD,  IPP_TAG_JOB },
158
  { 0, "job-id",    IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
159
  { 0, "job-impressions", IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
160
  { 0, "job-impressions-completed", IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
161
  { 0, "job-k-limit",   IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
162
  { 0, "job-k-octets",    IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
163
  { 0, "job-k-octets-completed",IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
164
  { 0, "job-media-sheets",  IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
165
  { 0, "job-media-sheets-completed", IPP_TAG_INTEGER, IPP_TAG_ZERO }, /* never send as option */
166
  { 0, "job-page-limit",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
167
  { 0, "job-password",          IPP_TAG_STRING,         IPP_TAG_OPERATION,
168
              IPP_TAG_ZERO,
169
              ipp_job_creation },
170
  { 0, "job-password-encryption", IPP_TAG_KEYWORD,      IPP_TAG_OPERATION,
171
              IPP_TAG_ZERO,
172
              ipp_job_creation },
173
  { 0, "job-priority",    IPP_TAG_INTEGER,  IPP_TAG_JOB },
174
  { 0, "job-quota-period",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
175
  { 1, "job-sheets",    IPP_TAG_NAME,   IPP_TAG_JOB },
176
  { 1, "job-sheets-default",  IPP_TAG_NAME,   IPP_TAG_PRINTER },
177
  { 0, "job-state",   IPP_TAG_ENUM,   IPP_TAG_ZERO }, /* never send as option */
178
  { 0, "job-state-message", IPP_TAG_TEXT,   IPP_TAG_ZERO }, /* never send as option */
179
  { 0, "job-state-reasons", IPP_TAG_KEYWORD,  IPP_TAG_ZERO }, /* never send as option */
180
  { 0, "job-uuid",    IPP_TAG_URI,    IPP_TAG_JOB },
181
  { 0, "landscape",   IPP_TAG_BOOLEAN,  IPP_TAG_JOB },
182
  { 1, "marker-change-time",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
183
  { 1, "marker-colors",   IPP_TAG_NAME,   IPP_TAG_PRINTER },
184
  { 1, "marker-high-levels",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
185
  { 1, "marker-levels",   IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
186
  { 1, "marker-low-levels", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
187
  { 0, "marker-message",  IPP_TAG_TEXT,   IPP_TAG_PRINTER },
188
  { 1, "marker-names",    IPP_TAG_NAME,   IPP_TAG_PRINTER },
189
  { 1, "marker-types",    IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
190
  { 1, "media",     IPP_TAG_KEYWORD,  IPP_TAG_JOB,
191
              IPP_TAG_DOCUMENT },
192
  { 0, "media-col",   IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB,
193
              IPP_TAG_DOCUMENT },
194
  { 0, "media-col-default", IPP_TAG_BEGIN_COLLECTION, IPP_TAG_PRINTER },
195
  { 0, "media-color",   IPP_TAG_KEYWORD,  IPP_TAG_JOB,
196
              IPP_TAG_DOCUMENT },
197
  { 1, "media-default",   IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
198
  { 0, "media-key",   IPP_TAG_KEYWORD,  IPP_TAG_JOB,
199
              IPP_TAG_DOCUMENT },
200
  { 0, "media-size",    IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB,
201
              IPP_TAG_DOCUMENT },
202
  { 0, "media-type",    IPP_TAG_KEYWORD,  IPP_TAG_JOB,
203
              IPP_TAG_DOCUMENT },
204
  { 0, "mirror",    IPP_TAG_BOOLEAN,  IPP_TAG_JOB },
205
  { 0, "mirror-default",  IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
206
  { 0, "natural-scaling", IPP_TAG_INTEGER,  IPP_TAG_JOB },
207
  { 0, "natural-scaling-default", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
208
  { 0, "notify-charset",  IPP_TAG_CHARSET,  IPP_TAG_SUBSCRIPTION },
209
  { 1, "notify-events",   IPP_TAG_KEYWORD,  IPP_TAG_SUBSCRIPTION },
210
  { 1, "notify-events-default", IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
211
  { 0, "notify-lease-duration", IPP_TAG_INTEGER,  IPP_TAG_SUBSCRIPTION },
212
  { 0, "notify-lease-duration-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
213
  { 0, "notify-natural-language", IPP_TAG_LANGUAGE, IPP_TAG_SUBSCRIPTION },
214
  { 0, "notify-pull-method",  IPP_TAG_KEYWORD,  IPP_TAG_SUBSCRIPTION },
215
  { 0, "notify-recipient-uri",  IPP_TAG_URI,    IPP_TAG_SUBSCRIPTION },
216
  { 0, "notify-time-interval",  IPP_TAG_INTEGER,  IPP_TAG_SUBSCRIPTION },
217
  { 0, "notify-user-data",  IPP_TAG_STRING,   IPP_TAG_SUBSCRIPTION },
218
  { 0, "number-up",   IPP_TAG_INTEGER,  IPP_TAG_JOB,
219
              IPP_TAG_DOCUMENT },
220
  { 0, "number-up-default", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
221
  { 0, "orientation-requested", IPP_TAG_ENUM,   IPP_TAG_JOB,
222
              IPP_TAG_DOCUMENT },
223
  { 0, "orientation-requested-default", IPP_TAG_ENUM, IPP_TAG_PRINTER },
224
  { 1, "overrides",   IPP_TAG_BEGIN_COLLECTION, IPP_TAG_JOB,
225
              IPP_TAG_DOCUMENT },
226
  { 0, "page-bottom",   IPP_TAG_INTEGER,  IPP_TAG_JOB },
227
  { 0, "page-bottom-default", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
228
  { 0, "page-left",   IPP_TAG_INTEGER,  IPP_TAG_JOB },
229
  { 0, "page-left-default", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
230
  { 1, "page-ranges",   IPP_TAG_RANGE,    IPP_TAG_JOB,
231
              IPP_TAG_DOCUMENT },
232
  { 1, "page-ranges-default", IPP_TAG_RANGE,    IPP_TAG_PRINTER },
233
  { 0, "page-right",    IPP_TAG_INTEGER,  IPP_TAG_JOB },
234
  { 0, "page-right-default",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
235
  { 0, "page-top",    IPP_TAG_INTEGER,  IPP_TAG_JOB },
236
  { 0, "page-top-default",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
237
  { 1, "pages",     IPP_TAG_RANGE,    IPP_TAG_JOB,
238
              IPP_TAG_DOCUMENT },
239
  { 0, "penwidth",    IPP_TAG_INTEGER,  IPP_TAG_JOB },
240
  { 0, "penwidth-default",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
241
  { 0, "port-monitor",    IPP_TAG_NAME,   IPP_TAG_PRINTER },
242
  { 0, "ppd-device-id",   IPP_TAG_TEXT,   IPP_TAG_OPERATION,
243
              IPP_TAG_ZERO,
244
              cups_get_ppds },
245
  { 0, "ppd-make",    IPP_TAG_TEXT,   IPP_TAG_OPERATION,
246
              IPP_TAG_ZERO,
247
              cups_get_ppds },
248
  { 0, "ppd-make-and-model",  IPP_TAG_TEXT,   IPP_TAG_OPERATION,
249
              IPP_TAG_ZERO,
250
              cups_get_ppds },
251
  { 0, "ppd-model-number",  IPP_TAG_INTEGER,  IPP_TAG_OPERATION,
252
              IPP_TAG_ZERO,
253
              cups_get_ppds },
254
  { 0, "ppd-name",    IPP_TAG_NAME,   IPP_TAG_OPERATION,
255
              IPP_TAG_ZERO,
256
              cups_ppd_name },
257
  { 0, "ppd-natural-language",  IPP_TAG_LANGUAGE, IPP_TAG_OPERATION,
258
              IPP_TAG_ZERO,
259
              cups_get_ppds },
260
  { 0, "ppd-product",   IPP_TAG_TEXT,   IPP_TAG_OPERATION,
261
              IPP_TAG_ZERO,
262
              cups_get_ppds },
263
  { 0, "ppd-psversion",   IPP_TAG_TEXT,   IPP_TAG_OPERATION,
264
              IPP_TAG_ZERO,
265
              cups_get_ppds },
266
  { 0, "ppd-type",    IPP_TAG_KEYWORD,  IPP_TAG_OPERATION,
267
              IPP_TAG_ZERO,
268
              cups_get_ppds },
269
  { 0, "ppi",     IPP_TAG_INTEGER,  IPP_TAG_JOB },
270
  { 0, "ppi-default",   IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
271
  { 0, "prettyprint",   IPP_TAG_BOOLEAN,  IPP_TAG_JOB },
272
  { 0, "prettyprint-default", IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
273
  { 0, "print-quality",   IPP_TAG_ENUM,   IPP_TAG_JOB,
274
              IPP_TAG_DOCUMENT },
275
  { 0, "print-quality-default", IPP_TAG_ENUM,   IPP_TAG_PRINTER },
276
  { 1, "printer-commands",  IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
277
  { 0, "printer-error-policy",  IPP_TAG_NAME,   IPP_TAG_PRINTER },
278
  { 0, "printer-geo-location",  IPP_TAG_URI,    IPP_TAG_PRINTER },
279
  { 0, "printer-info",    IPP_TAG_TEXT,   IPP_TAG_PRINTER },
280
  { 0, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
281
  { 0, "printer-is-shared", IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
282
  { 0, "printer-is-temporary",  IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
283
  { 0, "printer-location",  IPP_TAG_TEXT,   IPP_TAG_PRINTER },
284
  { 0, "printer-make-and-model", IPP_TAG_TEXT,    IPP_TAG_PRINTER },
285
  { 0, "printer-more-info", IPP_TAG_URI,    IPP_TAG_PRINTER },
286
  { 0, "printer-op-policy", IPP_TAG_NAME,   IPP_TAG_PRINTER },
287
  { 0, "printer-resolution",  IPP_TAG_RESOLUTION, IPP_TAG_JOB,
288
              IPP_TAG_DOCUMENT },
289
  { 0, "printer-state",   IPP_TAG_ENUM,   IPP_TAG_PRINTER },
290
  { 0, "printer-state-change-time", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
291
  { 1, "printer-state-reasons", IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
292
  { 0, "printer-type",    IPP_TAG_ENUM,   IPP_TAG_PRINTER },
293
  { 0, "printer-uri",   IPP_TAG_URI,    IPP_TAG_OPERATION },
294
  { 1, "printer-uri-supported", IPP_TAG_URI,    IPP_TAG_PRINTER },
295
  { 0, "queued-job-count",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
296
  { 0, "raw",     IPP_TAG_MIMETYPE, IPP_TAG_OPERATION },
297
  { 1, "requested-attributes",  IPP_TAG_NAME,   IPP_TAG_OPERATION },
298
  { 1, "requesting-user-name-allowed", IPP_TAG_NAME,  IPP_TAG_PRINTER },
299
  { 1, "requesting-user-name-denied", IPP_TAG_NAME, IPP_TAG_PRINTER },
300
  { 0, "resolution",    IPP_TAG_RESOLUTION, IPP_TAG_JOB },
301
  { 0, "resolution-default",  IPP_TAG_RESOLUTION, IPP_TAG_PRINTER },
302
  { 0, "saturation",    IPP_TAG_INTEGER,  IPP_TAG_JOB },
303
  { 0, "saturation-default",  IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
304
  { 0, "scaling",   IPP_TAG_INTEGER,  IPP_TAG_JOB },
305
  { 0, "scaling-default", IPP_TAG_INTEGER,  IPP_TAG_PRINTER },
306
  { 0, "sides",     IPP_TAG_KEYWORD,  IPP_TAG_JOB,
307
              IPP_TAG_DOCUMENT },
308
  { 0, "sides-default",   IPP_TAG_KEYWORD,  IPP_TAG_PRINTER },
309
  { 0, "time-at-completed", IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
310
  { 0, "time-at-creation",  IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
311
  { 0, "time-at-processing",  IPP_TAG_INTEGER,  IPP_TAG_ZERO }, /* never send as option */
312
  { 0, "wrap",      IPP_TAG_BOOLEAN,  IPP_TAG_JOB },
313
  { 0, "wrap-default",    IPP_TAG_BOOLEAN,  IPP_TAG_PRINTER },
314
  { 0, "x-dimension",   IPP_TAG_INTEGER,  IPP_TAG_JOB,
315
              IPP_TAG_DOCUMENT },
316
  { 0, "y-dimension",   IPP_TAG_INTEGER,  IPP_TAG_JOB,
317
              IPP_TAG_DOCUMENT }
318
};
319
320
321
/*
322
 * Local functions...
323
 */
324
325
static int  compare_ipp_options(_ipp_option_t *a, _ipp_option_t *b);
326
327
328
/*
329
 * 'cupsEncodeOptions()' - Encode printer options into IPP attributes.
330
 *
331
 * This function adds operation, job, and then subscription attributes,
332
 * in that order. Use the @link cupsEncodeOptions2@ function to add attributes
333
 * for a single group.
334
 */
335
336
void
337
cupsEncodeOptions(ipp_t         *ipp,   /* I - Request to add to */
338
            int           num_options,  /* I - Number of options */
339
      cups_option_t *options) /* I - Options */
340
0
{
341
0
  DEBUG_printf(("cupsEncodeOptions(%p, %d, %p)", (void *)ipp, num_options, (void *)options));
342
343
 /*
344
  * Add the options in the proper groups & order...
345
  */
346
347
0
  cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_OPERATION);
348
0
  cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_JOB);
349
0
  cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_SUBSCRIPTION);
350
0
}
351
352
353
/*
354
 * 'cupsEncodeOptions2()' - Encode printer options into IPP attributes for a group.
355
 *
356
 * This function only adds attributes for a single group. Call this
357
 * function multiple times for each group, or use @link cupsEncodeOptions@
358
 * to add the standard groups.
359
 *
360
 * @since CUPS 1.2/macOS 10.5@
361
 */
362
363
void
364
cupsEncodeOptions2(
365
    ipp_t         *ipp,     /* I - Request to add to */
366
    int           num_options,    /* I - Number of options */
367
    cups_option_t *options,   /* I - Options */
368
    ipp_tag_t     group_tag)    /* I - Group to encode */
369
0
{
370
0
  int     i, j;   /* Looping vars */
371
0
  int     count;    /* Number of values */
372
0
  char      *s,   /* Pointer into option value */
373
0
      *val,   /* Pointer to option value */
374
0
      *copy,    /* Copy of option value */
375
0
      *sep,   /* Option separator */
376
0
      quote;    /* Quote character */
377
0
  ipp_attribute_t *attr;    /* IPP attribute */
378
0
  ipp_tag_t   value_tag;  /* IPP value tag */
379
0
  cups_option_t   *option;  /* Current option */
380
0
  ipp_t     *collection;  /* Collection value */
381
0
  int     num_cols; /* Number of collection values */
382
0
  cups_option_t   *cols;    /* Collection values */
383
0
  ipp_op_t    op;   /* Operation for this request */
384
0
  const ipp_op_t  *ops;   /* List of allowed operations */
385
386
387
0
  DEBUG_printf(("cupsEncodeOptions2(ipp=%p(%s), num_options=%d, options=%p, group_tag=%x)", (void *)ipp, ipp ? ippOpString(ippGetOperation(ipp)) : "", num_options, (void *)options, group_tag));
388
389
 /*
390
  * Range check input...
391
  */
392
393
0
  if (!ipp || num_options < 1 || !options)
394
0
    return;
395
396
 /*
397
  * Do special handling for the document-format/raw options...
398
  */
399
400
0
  op = ippGetOperation(ipp);
401
402
0
  if (group_tag == IPP_TAG_OPERATION &&
403
0
      (op == IPP_OP_PRINT_JOB || op == IPP_OP_PRINT_URI ||
404
0
       op == IPP_OP_SEND_DOCUMENT || op == IPP_OP_SEND_URI))
405
0
  {
406
   /*
407
    * Handle the document format stuff first...
408
    */
409
410
0
    if ((val = (char *)cupsGetOption("document-format", num_options,
411
0
                                     options)) != NULL)
412
0
      ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
413
0
             NULL, val);
414
0
    else if (cupsGetOption("raw", num_options, options))
415
0
      ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
416
0
             NULL, "application/vnd.cups-raw");
417
0
    else
418
0
      ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
419
0
             NULL, "application/octet-stream");
420
0
  }
421
422
 /*
423
  * Then loop through the options...
424
  */
425
426
0
  for (i = num_options, option = options; i > 0; i --, option ++)
427
0
  {
428
0
    _ipp_option_t *match;   /* Matching attribute */
429
430
431
   /*
432
    * Skip document format options that are handled above...
433
    */
434
435
0
    if (!_cups_strcasecmp(option->name, "raw") ||
436
0
        !_cups_strcasecmp(option->name, "document-format") ||
437
0
  !option->name[0])
438
0
      continue;
439
440
   /*
441
    * Figure out the proper value and group tags for this option...
442
    */
443
444
0
    if ((match = _ippFindOption(option->name)) != NULL)
445
0
    {
446
0
      if (match->group_tag != group_tag && match->alt_group_tag != group_tag)
447
0
        continue;
448
449
0
      value_tag = match->value_tag;
450
451
0
      if (match->operations)
452
0
        ops = match->operations;
453
0
      else if (group_tag == IPP_TAG_JOB)
454
0
        ops = ipp_job_creation;
455
0
      else if (group_tag == IPP_TAG_DOCUMENT)
456
0
        ops = ipp_doc_creation;
457
0
      else if (group_tag == IPP_TAG_SUBSCRIPTION)
458
0
        ops = ipp_sub_creation;
459
0
      else if (group_tag == IPP_TAG_PRINTER)
460
0
        ops = ipp_set_printer;
461
0
      else
462
0
      {
463
0
  DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name));
464
0
        continue;
465
0
      }
466
0
    }
467
0
    else
468
0
    {
469
0
      int namelen;    /* Length of name */
470
471
472
0
      namelen = (int)strlen(option->name);
473
474
0
      if (namelen < 10 ||
475
0
          (strcmp(option->name + namelen - 8, "-default") &&
476
0
           strcmp(option->name + namelen - 10, "-supported")))
477
0
      {
478
0
  if (group_tag != IPP_TAG_JOB && group_tag != IPP_TAG_DOCUMENT)
479
0
  {
480
0
    DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name));
481
0
          continue;
482
0
        }
483
0
      }
484
0
      else if (group_tag != IPP_TAG_PRINTER)
485
0
      {
486
0
  DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name));
487
0
        continue;
488
0
      }
489
490
0
      if (group_tag == IPP_TAG_JOB)
491
0
        ops = ipp_job_creation;
492
0
      else if (group_tag == IPP_TAG_DOCUMENT)
493
0
        ops = ipp_doc_creation;
494
0
      else
495
0
        ops = ipp_set_printer;
496
497
0
      if (!_cups_strcasecmp(option->value, "true") ||
498
0
          !_cups_strcasecmp(option->value, "false"))
499
0
  value_tag = IPP_TAG_BOOLEAN;
500
0
      else
501
0
  value_tag = IPP_TAG_NAME;
502
0
    }
503
504
   /*
505
    * Verify that we send this attribute for this operation...
506
    */
507
508
0
    while (*ops != IPP_OP_CUPS_NONE)
509
0
      if (op == *ops)
510
0
        break;
511
0
      else
512
0
        ops ++;
513
514
0
    if (*ops == IPP_OP_CUPS_NONE && op != IPP_OP_CUPS_NONE)
515
0
    {
516
0
      DEBUG_printf(("2cupsEncodeOptions2: Skipping \"%s\".", option->name));
517
0
      continue;
518
0
    }
519
520
   /*
521
    * Count the number of values...
522
    */
523
524
0
    if (match && match->multivalue)
525
0
    {
526
0
      for (count = 1, sep = option->value, quote = 0; *sep; sep ++)
527
0
      {
528
0
  if (*sep == quote)
529
0
    quote = 0;
530
0
  else if (!quote && (*sep == '\'' || *sep == '\"'))
531
0
  {
532
   /*
533
    * Skip quoted option value...
534
    */
535
536
0
    quote = *sep++;
537
0
  }
538
0
  else if (*sep == ',' && !quote)
539
0
    count ++;
540
0
  else if (*sep == '\\' && sep[1])
541
0
    sep += 2;
542
0
      }
543
0
    }
544
0
    else
545
0
      count = 1;
546
547
0
    DEBUG_printf(("2cupsEncodeOptions2: option=\"%s\", value=\"%s\", count=%d", option->name, option->value, count));
548
549
   /*
550
    * Allocate memory for the attribute values...
551
    */
552
553
0
    if ((attr = ippAddStrings(ipp, group_tag, value_tag, option->name, count,
554
0
                              NULL, NULL)) == NULL)
555
0
    {
556
     /*
557
      * Ran out of memory!
558
      */
559
560
0
      DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for attributes!");
561
0
      return;
562
0
    }
563
564
0
    if (count > 1)
565
0
    {
566
     /*
567
      * Make a copy of the value we can fiddle with...
568
      */
569
570
0
      if ((copy = strdup(option->value)) == NULL)
571
0
      {
572
       /*
573
  * Ran out of memory!
574
  */
575
576
0
  DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for value copy!");
577
0
  ippDeleteAttribute(ipp, attr);
578
0
  return;
579
0
      }
580
581
0
      val = copy;
582
0
    }
583
0
    else
584
0
    {
585
     /*
586
      * Since we have a single value, use the value directly...
587
      */
588
589
0
      val  = option->value;
590
0
      copy = NULL;
591
0
    }
592
593
   /*
594
    * Scan the value string for values...
595
    */
596
597
0
    for (j = 0, sep = val; j < count; val = sep, j ++)
598
0
    {
599
     /*
600
      * Find the end of this value and mark it if needed...
601
      */
602
603
0
      if (count > 1)
604
0
      {
605
0
  for (quote = 0; *sep; sep ++)
606
0
  {
607
0
    if (*sep == quote)
608
0
    {
609
     /*
610
      * Finish quoted value...
611
      */
612
613
0
      quote = 0;
614
0
    }
615
0
    else if (!quote && (*sep == '\'' || *sep == '\"'))
616
0
    {
617
     /*
618
      * Handle quoted option value...
619
      */
620
621
0
      quote = *sep;
622
0
    }
623
0
    else if (*sep == ',' && count > 1)
624
0
      break;
625
0
    else if (*sep == '\\' && sep[1])
626
0
    {
627
     /*
628
      * Skip quoted character...
629
      */
630
631
0
      memmove(sep, sep + 1, strlen(sep));
632
0
      sep ++;
633
0
    }
634
0
  }
635
636
0
  if (*sep == ',')
637
0
    *sep++ = '\0';
638
0
      }
639
640
     /*
641
      * Copy the option value(s) over as needed by the type...
642
      */
643
644
0
      switch (attr->value_tag)
645
0
      {
646
0
  case IPP_TAG_INTEGER :
647
0
  case IPP_TAG_ENUM :
648
     /*
649
      * Integer/enumeration value...
650
      */
651
652
0
            attr->values[j].integer = (int)strtol(val, &s, 10);
653
654
0
            DEBUG_printf(("2cupsEncodeOptions2: Added integer option value "
655
0
                    "%d...", attr->values[j].integer));
656
0
            break;
657
658
0
  case IPP_TAG_BOOLEAN :
659
0
      if (!_cups_strcasecmp(val, "true") ||
660
0
          !_cups_strcasecmp(val, "on") ||
661
0
          !_cups_strcasecmp(val, "yes"))
662
0
      {
663
       /*
664
        * Boolean value - true...
665
        */
666
667
0
        attr->values[j].boolean = 1;
668
669
0
              DEBUG_puts("2cupsEncodeOptions2: Added boolean true value...");
670
0
      }
671
0
      else
672
0
      {
673
       /*
674
        * Boolean value - false...
675
        */
676
677
0
        attr->values[j].boolean = 0;
678
679
0
              DEBUG_puts("2cupsEncodeOptions2: Added boolean false value...");
680
0
      }
681
0
            break;
682
683
0
  case IPP_TAG_RANGE :
684
     /*
685
      * Range...
686
      */
687
688
0
            if (*val == '-')
689
0
      {
690
0
        attr->values[j].range.lower = 1;
691
0
        s = val;
692
0
      }
693
0
      else
694
0
        attr->values[j].range.lower = (int)strtol(val, &s, 10);
695
696
0
      if (*s == '-')
697
0
      {
698
0
        if (s[1])
699
0
    attr->values[j].range.upper = (int)strtol(s + 1, NULL, 10);
700
0
        else
701
0
    attr->values[j].range.upper = 2147483647;
702
0
            }
703
0
      else
704
0
        attr->values[j].range.upper = attr->values[j].range.lower;
705
706
0
      DEBUG_printf(("2cupsEncodeOptions2: Added range option value "
707
0
                    "%d-%d...", attr->values[j].range.lower,
708
0
        attr->values[j].range.upper));
709
0
            break;
710
711
0
  case IPP_TAG_RESOLUTION :
712
     /*
713
      * Resolution...
714
      */
715
716
0
      attr->values[j].resolution.xres = (int)strtol(val, &s, 10);
717
718
0
      if (*s == 'x')
719
0
        attr->values[j].resolution.yres = (int)strtol(s + 1, &s, 10);
720
0
      else
721
0
        attr->values[j].resolution.yres = attr->values[j].resolution.xres;
722
723
0
      if (!_cups_strcasecmp(s, "dpc") ||
724
0
          !_cups_strcasecmp(s, "dpcm"))
725
0
              attr->values[j].resolution.units = IPP_RES_PER_CM;
726
0
            else
727
0
              attr->values[j].resolution.units = IPP_RES_PER_INCH;
728
729
0
      DEBUG_printf(("2cupsEncodeOptions2: Added resolution option value "
730
0
                    "%s...", val));
731
0
            break;
732
733
0
  case IPP_TAG_STRING :
734
           /*
735
      * octet-string
736
      */
737
738
0
            attr->values[j].unknown.length = (int)strlen(val);
739
0
      attr->values[j].unknown.data   = strdup(val);
740
741
0
            DEBUG_printf(("2cupsEncodeOptions2: Added octet-string value "
742
0
                    "\"%s\"...", (char *)attr->values[j].unknown.data));
743
0
            break;
744
745
0
        case IPP_TAG_BEGIN_COLLECTION :
746
     /*
747
      * Collection value
748
      */
749
750
0
      num_cols   = cupsParseOptions(val, 0, &cols);
751
0
      if ((collection = ippNew()) == NULL)
752
0
      {
753
0
        cupsFreeOptions(num_cols, cols);
754
755
0
        if (copy)
756
0
          free(copy);
757
758
0
        ippDeleteAttribute(ipp, attr);
759
0
        return;
760
0
            }
761
762
0
      attr->values[j].collection = collection;
763
0
      cupsEncodeOptions2(collection, num_cols, cols, IPP_TAG_JOB);
764
0
            cupsFreeOptions(num_cols, cols);
765
0
      break;
766
767
0
  default :
768
0
      if ((attr->values[j].string.text = _cupsStrAlloc(val)) == NULL)
769
0
      {
770
       /*
771
        * Ran out of memory!
772
        */
773
774
0
        DEBUG_puts("1cupsEncodeOptions2: Ran out of memory for string!");
775
776
0
        if (copy)
777
0
          free(copy);
778
779
0
        ippDeleteAttribute(ipp, attr);
780
0
        return;
781
0
      }
782
783
0
      DEBUG_printf(("2cupsEncodeOptions2: Added string value \"%s\"...",
784
0
                    val));
785
0
            break;
786
0
      }
787
0
    }
788
789
0
    if (copy)
790
0
      free(copy);
791
0
  }
792
0
}
793
794
795
#ifdef DEBUG
796
/*
797
 * '_ippCheckOptions()' - Validate that the option array is sorted properly.
798
 */
799
800
const char *        /* O - First out-of-order option or NULL */
801
_ippCheckOptions(void)
802
{
803
  int i;        /* Looping var */
804
805
806
  for (i = 0; i < (int)(sizeof(ipp_options) / sizeof(ipp_options[0]) - 1); i ++)
807
    if (strcmp(ipp_options[i].name, ipp_options[i + 1].name) >= 0)
808
      return (ipp_options[i + 1].name);
809
810
  return (NULL);
811
}
812
#endif /* DEBUG */
813
814
815
/*
816
 * '_ippFindOption()' - Find the attribute information for an option.
817
 */
818
819
_ipp_option_t *       /* O - Attribute information */
820
_ippFindOption(const char *name)  /* I - Option/attribute name */
821
0
{
822
0
  _ipp_option_t key;      /* Search key */
823
824
825
 /*
826
  * Lookup the proper value and group tags for this option...
827
  */
828
829
0
  key.name = name;
830
831
0
  return ((_ipp_option_t *)bsearch(&key, ipp_options,
832
0
                                   sizeof(ipp_options) / sizeof(ipp_options[0]),
833
0
           sizeof(ipp_options[0]),
834
0
           (int (*)(const void *, const void *))
835
0
               compare_ipp_options));
836
0
}
837
838
839
/*
840
 * 'compare_ipp_options()' - Compare two IPP options.
841
 */
842
843
static int        /* O - Result of comparison */
844
compare_ipp_options(_ipp_option_t *a, /* I - First option */
845
                    _ipp_option_t *b) /* I - Second option */
846
0
{
847
0
  return (strcmp(a->name, b->name));
848
0
}