]> git.ipfire.org Git - thirdparty/cups.git/blob - systemv/lpoptions.c
ca148cd63f24fc7d5384db53c5c7e65c53f5819a
[thirdparty/cups.git] / systemv / lpoptions.c
1 /*
2 * Printer option program for CUPS.
3 *
4 * Copyright 2007-2016 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
8 */
9
10 /*
11 * Include necessary headers...
12 */
13
14 #include <cups/cups-private.h>
15 #include <cups/ppd-private.h>
16
17
18 /*
19 * Local functions...
20 */
21
22 static void list_group(ppd_file_t *ppd, ppd_group_t *group);
23 static void list_options(cups_dest_t *dest);
24 static void usage(void) __attribute__((noreturn));
25
26
27 /*
28 * 'main()' - Main entry.
29 */
30
31 int /* O - Exit status */
32 main(int argc, /* I - Number of command-line arguments */
33 char *argv[]) /* I - Command-line arguments */
34 {
35 int i, j; /* Looping vars */
36 int changes; /* Did we make changes? */
37 int num_options; /* Number of options */
38 cups_option_t *options; /* Options */
39 int num_dests; /* Number of destinations */
40 cups_dest_t *dests; /* Destinations */
41 cups_dest_t *dest; /* Current destination */
42 char *opt, /* Option pointer */
43 *printer, /* Printer name */
44 *instance, /* Instance name */
45 *option; /* Current option */
46
47
48 _cupsSetLocale(argv);
49
50 /*
51 * Loop through the command-line arguments...
52 */
53
54 dest = NULL;
55 num_dests = 0;
56 dests = NULL;
57 num_options = 0;
58 options = NULL;
59 changes = 0;
60
61 for (i = 1; i < argc; i ++)
62 {
63 if (argv[i][0] == '-')
64 {
65 for (opt = argv[i] + 1; *opt; opt ++)
66 {
67 switch (*opt)
68 {
69 case 'd' : /* -d printer */
70 if (opt[1] != '\0')
71 {
72 printer = opt + 1;
73 opt += strlen(opt) - 1;
74 }
75 else
76 {
77 i ++;
78 if (i >= argc)
79 usage();
80
81 printer = argv[i];
82 }
83
84 if ((instance = strrchr(printer, '/')) != NULL)
85 *instance++ = '\0';
86
87 if (num_dests == 0)
88 num_dests = cupsGetDests(&dests);
89
90 if (num_dests == 0 || !dests || (dest = cupsGetDest(printer, instance, num_dests, dests)) == NULL)
91 {
92 _cupsLangPuts(stderr, _("lpoptions: Unknown printer or class."));
93 return (1);
94 }
95
96 /*
97 * Set the default destination...
98 */
99
100 for (j = 0; j < num_dests; j ++)
101 dests[j].is_default = 0;
102
103 dest->is_default = 1;
104
105 cupsSetDests(num_dests, dests);
106
107 for (j = 0; j < dest->num_options; j ++)
108 if (cupsGetOption(dest->options[j].name, num_options,
109 options) == NULL)
110 num_options = cupsAddOption(dest->options[j].name,
111 dest->options[j].value,
112 num_options, &options);
113 break;
114
115 case 'h' : /* -h server */
116 if (opt[1] != '\0')
117 {
118 cupsSetServer(opt + 1);
119 opt += strlen(opt) - 1;
120 }
121 else
122 {
123 i ++;
124 if (i >= argc)
125 usage();
126
127 cupsSetServer(argv[i]);
128 }
129 break;
130
131 case 'E' : /* Encrypt connection */
132 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
133 break;
134
135 case 'l' : /* -l (list options) */
136 if (dest == NULL)
137 {
138 if (num_dests == 0)
139 num_dests = cupsGetDests(&dests);
140
141 if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
142 dest = dests;
143 }
144
145 if (dest == NULL)
146 _cupsLangPuts(stderr, _("lpoptions: No printers."));
147 else
148 list_options(dest);
149
150 changes = -1;
151 break;
152
153 case 'o' : /* -o option[=value] */
154 if (dest == NULL)
155 {
156 if (num_dests == 0)
157 num_dests = cupsGetDests(&dests);
158
159 if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
160 dest = dests;
161
162 if (dest == NULL)
163 {
164 _cupsLangPuts(stderr, _("lpoptions: No printers."));
165 return (1);
166 }
167
168 for (j = 0; j < dest->num_options; j ++)
169 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
170 num_options = cupsAddOption(dest->options[j].name,
171 dest->options[j].value,
172 num_options, &options);
173 }
174
175 if (opt[1] != '\0')
176 {
177 num_options = cupsParseOptions(opt + 1, num_options, &options);
178 opt += strlen(opt) - 1;
179 }
180 else
181 {
182 i ++;
183 if (i >= argc)
184 usage();
185
186 num_options = cupsParseOptions(argv[i], num_options, &options);
187 }
188
189 changes = 1;
190 break;
191
192 case 'p' : /* -p printer */
193 if (opt[1] != '\0')
194 {
195 printer = opt + 1;
196 opt += strlen(opt) - 1;
197 }
198 else
199 {
200 i ++;
201 if (i >= argc)
202 usage();
203
204 printer = argv[i];
205 }
206
207 if ((instance = strrchr(printer, '/')) != NULL)
208 *instance++ = '\0';
209
210 if (num_dests == 0)
211 num_dests = cupsGetDests(&dests);
212
213 if ((dest = cupsGetDest(printer, instance, num_dests, dests)) == NULL)
214 {
215 num_dests = cupsAddDest(printer, instance, num_dests, &dests);
216 dest = cupsGetDest(printer, instance, num_dests, dests);
217
218 if (dest == NULL)
219 {
220 _cupsLangPrintf(stderr, _("lpoptions: Unable to add printer or instance: %s"), strerror(errno));
221 return (1);
222 }
223 }
224
225 for (j = 0; j < dest->num_options; j ++)
226 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
227 num_options = cupsAddOption(dest->options[j].name,
228 dest->options[j].value,
229 num_options, &options);
230 break;
231
232 case 'r' : /* -r option (remove) */
233 if (dest == NULL)
234 {
235 if (num_dests == 0)
236 num_dests = cupsGetDests(&dests);
237
238 if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
239 dest = dests;
240
241 if (dest == NULL)
242 {
243 _cupsLangPuts(stderr, _("lpoptions: No printers."));
244 return (1);
245 }
246
247 for (j = 0; j < dest->num_options; j ++)
248 if (cupsGetOption(dest->options[j].name, num_options,
249 options) == NULL)
250 num_options = cupsAddOption(dest->options[j].name,
251 dest->options[j].value,
252 num_options, &options);
253 }
254
255 if (opt[1] != '\0')
256 {
257 option = opt + 1;
258 opt += strlen(opt) - 1;
259 }
260 else
261 {
262 i ++;
263 if (i >= argc)
264 usage();
265
266 option = argv[i];
267 }
268
269 num_options = cupsRemoveOption(option, num_options, &options);
270
271 changes = 1;
272 break;
273
274 case 'x' : /* -x printer */
275 if (opt[1] != '\0')
276 {
277 printer = opt + 1;
278 opt += strlen(opt) - 1;
279 }
280 else
281 {
282 i ++;
283 if (i >= argc)
284 usage();
285
286 printer = argv[i];
287 }
288
289 if ((instance = strrchr(printer, '/')) != NULL)
290 *instance++ = '\0';
291
292 if (num_dests == 0)
293 num_dests = cupsGetDests(&dests);
294
295 num_dests = cupsRemoveDest(printer, instance, num_dests, &dests);
296
297 cupsSetDests(num_dests, dests);
298 dest = NULL;
299 changes = -1;
300 break;
301
302 default :
303 usage();
304 }
305 }
306 }
307 else
308 {
309 usage();
310 }
311 }
312
313 if (num_dests == 0)
314 num_dests = cupsGetDests(&dests);
315
316 if (dest == NULL)
317 {
318 if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL)
319 {
320 for (j = 0; j < dest->num_options; j ++)
321 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
322 num_options = cupsAddOption(dest->options[j].name,
323 dest->options[j].value,
324 num_options, &options);
325 }
326 }
327
328 if (dest == NULL)
329 return (0);
330
331 if (changes > 0)
332 {
333 /*
334 * Set printer options...
335 */
336
337 cupsFreeOptions(dest->num_options, dest->options);
338
339 dest->num_options = num_options;
340 dest->options = options;
341
342 cupsSetDests(num_dests, dests);
343 }
344 else if (changes == 0)
345 {
346 char buffer[10240], /* String for options */
347 *ptr; /* Pointer into string */
348
349 num_options = dest->num_options;
350 options = dest->options;
351
352 for (i = 0, ptr = buffer;
353 ptr < (buffer + sizeof(buffer) - 1) && i < num_options;
354 i ++)
355 {
356 if (i)
357 *ptr++ = ' ';
358
359 if (!options[i].value[0])
360 strlcpy(ptr, options[i].name, sizeof(buffer) - (size_t)(ptr - buffer));
361 else if (strchr(options[i].value, ' ') != NULL ||
362 strchr(options[i].value, '\t') != NULL)
363 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s=\'%s\'", options[i].name, options[i].value);
364 else
365 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s=%s", options[i].name, options[i].value);
366
367 ptr += strlen(ptr);
368 }
369
370 _cupsLangPuts(stdout, buffer);
371 }
372
373 return (0);
374 }
375
376 /*
377 * 'list_group()' - List printer-specific options from the PPD group.
378 */
379
380 static void
381 list_group(ppd_file_t *ppd, /* I - PPD file */
382 ppd_group_t *group) /* I - Group to show */
383 {
384 int i, j; /* Looping vars */
385 ppd_option_t *option; /* Current option */
386 ppd_choice_t *choice; /* Current choice */
387 ppd_group_t *subgroup; /* Current subgroup */
388 char buffer[10240], /* Option string buffer */
389 *ptr; /* Pointer into option string */
390
391
392 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
393 {
394 if (!_cups_strcasecmp(option->keyword, "PageRegion"))
395 continue;
396
397 snprintf(buffer, sizeof(buffer), "%s/%s:", option->keyword, option->text);
398
399 for (j = option->num_choices, choice = option->choices,
400 ptr = buffer + strlen(buffer);
401 j > 0 && ptr < (buffer + sizeof(buffer) - 1);
402 j --, choice ++)
403 {
404 if (!_cups_strcasecmp(choice->choice, "Custom"))
405 {
406 ppd_coption_t *coption; /* Custom option */
407 ppd_cparam_t *cparam; /* Custom parameter */
408 static const char * const types[] =
409 { /* Parameter types */
410 "CURVE",
411 "INTEGER",
412 "INVCURVE",
413 "PASSCODE",
414 "PASSWORD",
415 "POINTS",
416 "REAL",
417 "STRING"
418 };
419
420
421 if ((coption = ppdFindCustomOption(ppd, option->keyword)) == NULL ||
422 cupsArrayCount(coption->params) == 0)
423 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom", choice->marked ? "*" : "");
424 else if (!_cups_strcasecmp(option->keyword, "PageSize") ||
425 !_cups_strcasecmp(option->keyword, "PageRegion"))
426 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.WIDTHxHEIGHT", choice->marked ? "*" : "");
427 else
428 {
429 cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
430
431 if (cupsArrayCount(coption->params) == 1)
432 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.%s", choice->marked ? "*" : "", types[cparam->type]);
433 else
434 {
435 const char *prefix; /* Prefix string */
436
437
438 if (choice->marked)
439 prefix = " *{";
440 else
441 prefix = " {";
442
443 while (cparam)
444 {
445 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s%s=%s", prefix, cparam->name, types[cparam->type]);
446 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params);
447 prefix = " ";
448 ptr += strlen(ptr);
449 }
450
451 if (ptr < (buffer + sizeof(buffer) - 1))
452 strlcpy(ptr, "}", sizeof(buffer) - (size_t)(ptr - buffer));
453 }
454 }
455 }
456 else if (choice->marked)
457 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " *%s", choice->choice);
458 else
459 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %s", choice->choice);
460
461 ptr += strlen(ptr);
462 }
463
464 _cupsLangPuts(stdout, buffer);
465 }
466
467 for (i = group->num_subgroups, subgroup = group->subgroups; i > 0; i --, subgroup ++)
468 list_group(ppd, subgroup);
469 }
470
471
472 /*
473 * 'list_options()' - List printer-specific options from the PPD file.
474 */
475
476 static void
477 list_options(cups_dest_t *dest) /* I - Destination to list */
478 {
479 int i; /* Looping var */
480 const char *filename; /* PPD filename */
481 ppd_file_t *ppd; /* PPD data */
482 ppd_group_t *group; /* Current group */
483
484
485 if ((filename = cupsGetPPD(dest->name)) == NULL)
486 {
487 _cupsLangPrintf(stderr, _("lpoptions: Unable to get PPD file for %s: %s"),
488 dest->name, cupsLastErrorString());
489 return;
490 }
491
492 if ((ppd = ppdOpenFile(filename)) == NULL)
493 {
494 unlink(filename);
495 _cupsLangPrintf(stderr, _("lpoptions: Unable to open PPD file for %s."),
496 dest->name);
497 return;
498 }
499
500 ppdMarkDefaults(ppd);
501 cupsMarkOptions(ppd, dest->num_options, dest->options);
502
503 for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
504 list_group(ppd, group);
505
506 ppdClose(ppd);
507 unlink(filename);
508 }
509
510
511 /*
512 * 'usage()' - Show program usage and exit.
513 */
514
515 static void
516 usage(void)
517 {
518 _cupsLangPuts(stdout,
519 _("Usage: lpoptions [-h server] [-E] -d printer\n"
520 " lpoptions [-h server] [-E] [-p printer] -l\n"
521 " lpoptions [-h server] [-E] -p printer -o "
522 "option[=value] ...\n"
523 " lpoptions [-h server] [-E] -x printer"));
524
525 exit(1);
526 }