]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/encode.c
Load cups into easysw/current.
[thirdparty/cups.git] / cups / encode.c
1 /*
2 * "$Id: encode.c 4977 2006-01-25 15:52:30Z mike $"
3 *
4 * Option encoding routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * cupsEncodeOptions() - Encode printer options into IPP attributes.
29 * cupsEncodeOptions2() - Encode printer options into IPP attributes for
30 * a group.
31 * compare_ipp_options() - Compare two IPP options.
32 */
33
34 /*
35 * Include necessary headers...
36 */
37
38 #include "cups.h"
39 #include "ipp-private.h"
40 #include <stdlib.h>
41 #include <ctype.h>
42 #include "string.h"
43 #include "debug.h"
44
45
46 /*
47 * Local list of option names and the value tags they should use...
48 *
49 * **** THIS LIST MUST BE SORTED ****
50 */
51
52 typedef struct
53 {
54 const char *name;
55 ipp_tag_t value_tag;
56 ipp_tag_t group_tag;
57 } _ipp_option_t;
58
59 static const _ipp_option_t ipp_options[] =
60 {
61 { "blackplot", IPP_TAG_BOOLEAN, IPP_TAG_JOB },
62 { "brightness", IPP_TAG_INTEGER, IPP_TAG_JOB },
63 { "columns", IPP_TAG_INTEGER, IPP_TAG_JOB },
64 { "copies", IPP_TAG_INTEGER, IPP_TAG_JOB },
65 { "document-format", IPP_TAG_MIMETYPE, IPP_TAG_OPERATION },
66 { "finishings", IPP_TAG_ENUM, IPP_TAG_JOB },
67 { "fitplot", IPP_TAG_BOOLEAN, IPP_TAG_JOB },
68 { "gamma", IPP_TAG_INTEGER, IPP_TAG_JOB },
69 { "hue", IPP_TAG_INTEGER, IPP_TAG_JOB },
70 { "job-k-limit", IPP_TAG_INTEGER, IPP_TAG_JOB },
71 { "job-page-limit", IPP_TAG_INTEGER, IPP_TAG_JOB },
72 { "job-priority", IPP_TAG_INTEGER, IPP_TAG_JOB },
73 { "job-quota-period", IPP_TAG_INTEGER, IPP_TAG_JOB },
74 { "landscape", IPP_TAG_BOOLEAN, IPP_TAG_JOB },
75 { "media", IPP_TAG_KEYWORD, IPP_TAG_JOB },
76 { "mirror", IPP_TAG_BOOLEAN, IPP_TAG_JOB },
77 { "natural-scaling", IPP_TAG_INTEGER, IPP_TAG_JOB },
78 { "notify-charset", IPP_TAG_CHARSET, IPP_TAG_SUBSCRIPTION },
79 { "notify-events", IPP_TAG_KEYWORD, IPP_TAG_SUBSCRIPTION },
80 { "notify-lease-time", IPP_TAG_INTEGER, IPP_TAG_SUBSCRIPTION },
81 { "notify-natural-language", IPP_TAG_LANGUAGE, IPP_TAG_SUBSCRIPTION },
82 { "notify-pull-method", IPP_TAG_KEYWORD, IPP_TAG_SUBSCRIPTION },
83 { "notify-recipient", IPP_TAG_URI, IPP_TAG_SUBSCRIPTION },
84 { "notify-time-interval", IPP_TAG_INTEGER, IPP_TAG_SUBSCRIPTION },
85 { "notify-user-data", IPP_TAG_STRING, IPP_TAG_SUBSCRIPTION },
86 { "number-up", IPP_TAG_INTEGER, IPP_TAG_JOB },
87 { "orientation-requested", IPP_TAG_ENUM, IPP_TAG_JOB },
88 { "page-bottom", IPP_TAG_INTEGER, IPP_TAG_JOB },
89 { "page-left", IPP_TAG_INTEGER, IPP_TAG_JOB },
90 { "page-ranges", IPP_TAG_RANGE, IPP_TAG_JOB },
91 { "page-right", IPP_TAG_INTEGER, IPP_TAG_JOB },
92 { "page-top", IPP_TAG_INTEGER, IPP_TAG_JOB },
93 { "penwidth", IPP_TAG_INTEGER, IPP_TAG_JOB },
94 { "ppi", IPP_TAG_INTEGER, IPP_TAG_JOB },
95 { "prettyprint", IPP_TAG_BOOLEAN, IPP_TAG_JOB },
96 { "printer-info", IPP_TAG_TEXT, IPP_TAG_PRINTER },
97 { "printer-is-accepting-jobs",IPP_TAG_BOOLEAN, IPP_TAG_PRINTER },
98 { "printer-is-shared", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER },
99 { "printer-make-and-model", IPP_TAG_TEXT, IPP_TAG_PRINTER },
100 { "printer-more-info", IPP_TAG_URI, IPP_TAG_PRINTER },
101 { "printer-resolution", IPP_TAG_RESOLUTION, IPP_TAG_JOB },
102 { "printer-state", IPP_TAG_ENUM, IPP_TAG_PRINTER },
103 { "printer-state-change-time",IPP_TAG_INTEGER, IPP_TAG_PRINTER },
104 { "printer-state-reasons", IPP_TAG_KEYWORD, IPP_TAG_PRINTER },
105 { "printer-type", IPP_TAG_ENUM, IPP_TAG_PRINTER },
106 { "printer-uri", IPP_TAG_URI, IPP_TAG_OPERATION },
107 { "print-quality", IPP_TAG_ENUM, IPP_TAG_JOB },
108 { "queued-job-count", IPP_TAG_INTEGER, IPP_TAG_PRINTER },
109 { "raw", IPP_TAG_MIMETYPE, IPP_TAG_OPERATION },
110 { "saturation", IPP_TAG_INTEGER, IPP_TAG_JOB },
111 { "scaling", IPP_TAG_INTEGER, IPP_TAG_JOB },
112 { "sides", IPP_TAG_KEYWORD, IPP_TAG_JOB },
113 { "wrap", IPP_TAG_BOOLEAN, IPP_TAG_JOB }
114 };
115
116
117 /*
118 * Local functions...
119 */
120
121 static int compare_ipp_options(_ipp_option_t *a, _ipp_option_t *b);
122
123
124 /*
125 * 'cupsEncodeOptions()' - Encode printer options into IPP attributes.
126 *
127 * This function adds operation, job, and then subscription attributes,
128 * in that order. Use the cupsEncodeOptions2() function to add attributes
129 * for a single group.
130 */
131
132 void
133 cupsEncodeOptions(ipp_t *ipp, /* I - Request to add to */
134 int num_options, /* I - Number of options */
135 cups_option_t *options) /* I - Options */
136 {
137 DEBUG_printf(("cupsEncodeOptions(%p, %d, %p)\n", ipp, num_options, options));
138
139 /*
140 * Add the options in the proper groups & order...
141 */
142
143 cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_OPERATION);
144 cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_JOB);
145 cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_SUBSCRIPTION);
146 }
147
148
149 /*
150 * 'cupsEncodeOptions2()' - Encode printer options into IPP attributes for a group.
151 *
152 * This function only adds attributes for a single group. Call this
153 * function multiple times for each group, or use cupsEncodeOptions()
154 * to add the standard groups.
155 *
156 * @since CUPS 1.2@
157 */
158
159 void
160 cupsEncodeOptions2(
161 ipp_t *ipp, /* I - Request to add to */
162 int num_options, /* I - Number of options */
163 cups_option_t *options, /* I - Options */
164 ipp_tag_t group_tag) /* I - Group to encode */
165 {
166 int i, j; /* Looping vars */
167 int count; /* Number of values */
168 char *s, /* Pointer into option value */
169 *val, /* Pointer to option value */
170 *copy, /* Copy of option value */
171 *sep; /* Option separator */
172 ipp_attribute_t *attr; /* IPP attribute */
173 ipp_tag_t value_tag; /* IPP value tag */
174
175
176 DEBUG_printf(("cupsEncodeOptions2(ipp=%p, num_options=%d, options=%p, group_tag=%x)\n",
177 ipp, num_options, options, group_tag));
178
179 /*
180 * Range check input...
181 */
182
183 if (ipp == NULL || num_options < 1 || options == NULL)
184 return;
185
186 /*
187 * Do special handling for the document-format/raw options...
188 */
189
190 if (group_tag == IPP_TAG_OPERATION)
191 {
192 /*
193 * Handle the document format stuff first...
194 */
195
196 if ((val = (char *)cupsGetOption("document-format", num_options, options)) != NULL)
197 ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
198 NULL, val);
199 else if (cupsGetOption("raw", num_options, options))
200 ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
201 NULL, "application/vnd.cups-raw");
202 else
203 ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format",
204 NULL, "application/octet-stream");
205 }
206
207 /*
208 * Then loop through the options...
209 */
210
211 for (i = 0; i < num_options; i ++)
212 {
213 _ipp_option_t key, /* Search key */
214 *match; /* Matching attribute */
215
216
217 /*
218 * Skip document format options that are handled above...
219 */
220
221 if (!strcasecmp(options[i].name, "raw") ||
222 !strcasecmp(options[i].name, "document-format") ||
223 !options[i].name[0])
224 continue;
225
226 /*
227 * Figure out the proper value and group tags for this option...
228 */
229
230 key.name = options[i].name;
231 match = (_ipp_option_t *)bsearch(&key, ipp_options,
232 sizeof(ipp_options) /
233 sizeof(ipp_options[0]),
234 sizeof(ipp_options[0]),
235 (int (*)(const void *,
236 const void *))
237 compare_ipp_options);
238
239 if (match)
240 {
241 if (match->group_tag != group_tag)
242 continue;
243
244 value_tag = match->value_tag;
245 }
246 else if (group_tag != IPP_TAG_JOB)
247 continue;
248 else if (!strcasecmp(options[i].value, "true") ||
249 !strcasecmp(options[i].value, "false"))
250 value_tag = IPP_TAG_BOOLEAN;
251 else
252 value_tag = IPP_TAG_NAME;
253
254 /*
255 * Count the number of values...
256 */
257
258 for (count = 1, sep = options[i].value; *sep; sep ++)
259 {
260 if (*sep == '\'')
261 {
262 /*
263 * Skip quoted option value...
264 */
265
266 sep ++;
267
268 while (*sep && *sep != '\'')
269 sep ++;
270
271 if (!*sep)
272 sep --;
273 }
274 else if (*sep == '\"')
275 {
276 /*
277 * Skip quoted option value...
278 */
279
280 sep ++;
281
282 while (*sep && *sep != '\"')
283 sep ++;
284
285 if (!*sep)
286 sep --;
287 }
288 else if (*sep == ',')
289 count ++;
290 else if (*sep == '\\' && sep[1])
291 sep ++;
292 }
293
294 DEBUG_printf(("cupsEncodeOptions2: option = \'%s\', count = %d\n",
295 options[i].name, count));
296
297 /*
298 * Allocate memory for the attribute values...
299 */
300
301 if ((attr = _ipp_add_attr(ipp, count)) == NULL)
302 {
303 /*
304 * Ran out of memory!
305 */
306
307 DEBUG_puts("cupsEncodeOptions2: Ran out of memory for attributes!");
308 return;
309 }
310
311 /*
312 * Now figure out what type of value we have...
313 */
314
315 attr->group_tag = group_tag;
316 attr->value_tag = value_tag;
317
318 /*
319 * Copy the name over...
320 */
321
322 if ((attr->name = strdup(options[i].name)) == NULL)
323 {
324 /*
325 * Ran out of memory!
326 */
327
328 DEBUG_puts("cupsEncodeOptions2: Ran out of memory for name!");
329 return;
330 }
331
332 if (count > 1)
333 {
334 /*
335 * Make a copy of the value we can fiddle with...
336 */
337
338 if ((copy = strdup(options[i].value)) == NULL)
339 {
340 /*
341 * Ran out of memory!
342 */
343
344 DEBUG_puts("cupsEncodeOptions2: Ran out of memory for value copy!");
345 return;
346 }
347
348 val = copy;
349 }
350 else
351 {
352 /*
353 * Since we have a single value, use the value directly...
354 */
355
356 val = options[i].value;
357 copy = NULL;
358 }
359
360 /*
361 * Scan the value string for values...
362 */
363
364 for (j = 0; j < count; val = sep, j ++)
365 {
366 /*
367 * Find the end of this value and mark it if needed...
368 */
369
370 if ((sep = strchr(val, ',')) != NULL)
371 *sep++ = '\0';
372 else
373 sep = val + strlen(val);
374
375 /*
376 * Copy the option value(s) over as needed by the type...
377 */
378
379 switch (attr->value_tag)
380 {
381 case IPP_TAG_INTEGER :
382 case IPP_TAG_ENUM :
383 /*
384 * Integer/enumeration value...
385 */
386
387 attr->values[j].integer = strtol(val, &s, 0);
388
389 DEBUG_printf(("cupsEncodeOptions2: Added integer option value %d...\n",
390 attr->values[j].integer));
391 break;
392
393 case IPP_TAG_BOOLEAN :
394 if (!strcasecmp(val, "true") ||
395 !strcasecmp(val, "on") ||
396 !strcasecmp(val, "yes"))
397 {
398 /*
399 * Boolean value - true...
400 */
401
402 attr->values[j].boolean = 1;
403
404 DEBUG_puts("cupsEncodeOptions2: Added boolean true value...");
405 }
406 else
407 {
408 /*
409 * Boolean value - false...
410 */
411
412 attr->values[j].boolean = 0;
413
414 DEBUG_puts("cupsEncodeOptions2: Added boolean false value...");
415 }
416 break;
417
418 case IPP_TAG_RANGE :
419 /*
420 * Range...
421 */
422
423 if (*val == '-')
424 {
425 attr->values[j].range.lower = 1;
426 s = val;
427 }
428 else
429 attr->values[j].range.lower = strtol(val, &s, 0);
430
431 if (*s == '-')
432 {
433 if (s[1])
434 attr->values[j].range.upper = strtol(s + 1, NULL, 0);
435 else
436 attr->values[j].range.upper = 2147483647;
437 }
438 else
439 attr->values[j].range.upper = attr->values[j].range.lower;
440
441 DEBUG_printf(("cupsEncodeOptions2: Added range option value %d-%d...\n",
442 attr->values[j].range.lower,
443 attr->values[j].range.upper));
444 break;
445
446 case IPP_TAG_RESOLUTION :
447 /*
448 * Resolution...
449 */
450
451 attr->values[j].resolution.xres = strtol(val, &s, 0);
452
453 if (*s == 'x')
454 attr->values[j].resolution.yres = strtol(s + 1, &s, 0);
455 else
456 attr->values[j].resolution.yres = attr->values[j].resolution.xres;
457
458 if (strcasecmp(s, "dpc") == 0)
459 attr->values[j].resolution.units = IPP_RES_PER_CM;
460 else
461 attr->values[j].resolution.units = IPP_RES_PER_INCH;
462
463 DEBUG_printf(("cupsEncodeOptions2: Added resolution option value %s...\n",
464 val));
465 break;
466
467 case IPP_TAG_STRING :
468 /*
469 * octet-string
470 */
471
472 attr->values[j].unknown.length = strlen(val);
473 attr->values[j].unknown.data = strdup(val);
474
475 DEBUG_printf(("cupsEncodeOptions2: Added octet-string value \"%s\"...\n",
476 attr->values[j].unknown.data));
477 break;
478
479 default :
480 if ((attr->values[j].string.text = strdup(val)) == NULL)
481 {
482 /*
483 * Ran out of memory!
484 */
485
486 DEBUG_puts("cupsEncodeOptions2: Ran out of memory for string!");
487 return;
488 }
489
490 DEBUG_printf(("cupsEncodeOptions2: Added string value \"%s\"...\n",
491 val));
492 break;
493 }
494 }
495 }
496 }
497
498
499 /*
500 * 'compare_ipp_options()' - Compare two IPP options.
501 */
502
503 static int /* O - Result of comparison */
504 compare_ipp_options(_ipp_option_t *a, /* I - First option */
505 _ipp_option_t *b) /* I - Second option */
506 {
507 return (strcmp(a->name, b->name));
508 }
509
510
511 /*
512 * End of "$Id: encode.c 4977 2006-01-25 15:52:30Z mike $".
513 */