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