Coverage Report

Created: 2026-02-21 06:34

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