]> git.ipfire.org Git - thirdparty/cups.git/blame - systemv/lpoptions.c
License change: Apache License, Version 2.0.
[thirdparty/cups.git] / systemv / lpoptions.c
CommitLineData
ef416fc2 1/*
7e86f2f6 2 * Printer option program for CUPS.
ef416fc2 3 *
bdbfacc7 4 * Copyright 2007-2016 by Apple Inc.
7e86f2f6 5 * Copyright 1997-2006 by Easy Software Products.
ef416fc2 6 *
e3101897 7 * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
ef416fc2 8 */
9
10/*
11 * Include necessary headers...
12 */
13
71e16022 14#include <cups/cups-private.h>
f787e1e3 15#include <cups/ppd-private.h>
ef416fc2 16
17
18/*
19 * Local functions...
20 */
21
dd1abb6b
MS
22static void list_group(ppd_file_t *ppd, ppd_group_t *group);
23static void list_options(cups_dest_t *dest);
85dda01c 24static void usage(void) __attribute__((noreturn));
ef416fc2 25
26
27/*
28 * 'main()' - Main entry.
29 */
30
31int /* O - Exit status */
32main(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 */
bdbfacc7
MS
42 char *opt, /* Option pointer */
43 *printer, /* Printer name */
88f9aafc 44 *instance, /* Instance name */
ef416fc2 45 *option; /* Current option */
46
47
07725fee 48 _cupsSetLocale(argv);
d09495fa 49
ef416fc2 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 ++)
bdbfacc7 62 {
ef416fc2 63 if (argv[i][0] == '-')
64 {
bdbfacc7 65 for (opt = argv[i] + 1; *opt; opt ++)
ef416fc2 66 {
bdbfacc7
MS
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();
ef416fc2 80
bdbfacc7
MS
81 printer = argv[i];
82 }
ef416fc2 83
bdbfacc7
MS
84 if ((instance = strrchr(printer, '/')) != NULL)
85 *instance++ = '\0';
ef416fc2 86
8ca02f3c 87 if (num_dests == 0)
88 num_dests = cupsGetDests(&dests);
89
bdbfacc7
MS
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 }
8ca02f3c 95
bdbfacc7
MS
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);
7594b224 106
8ca02f3c 107 for (j = 0; j < dest->num_options; j ++)
bdbfacc7
MS
108 if (cupsGetOption(dest->options[j].name, num_options,
109 options) == NULL)
8ca02f3c 110 num_options = cupsAddOption(dest->options[j].name,
bdbfacc7
MS
111 dest->options[j].value,
112 num_options, &options);
113 break;
114
115 case 'h' : /* -h server */
116 if (opt[1] != '\0')
ef416fc2 117 {
bdbfacc7
MS
118 cupsSetServer(opt + 1);
119 opt += strlen(opt) - 1;
ef416fc2 120 }
bdbfacc7
MS
121 else
122 {
123 i ++;
124 if (i >= argc)
125 usage();
8ca02f3c 126
bdbfacc7
MS
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 }
8ca02f3c 144
7594b224 145 if (dest == NULL)
0837b7e8 146 _cupsLangPuts(stderr, _("lpoptions: No printers."));
bdbfacc7
MS
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 }
7594b224 224
8ca02f3c 225 for (j = 0; j < dest->num_options; j ++)
bdbfacc7 226 if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
8ca02f3c 227 num_options = cupsAddOption(dest->options[j].name,
bdbfacc7
MS
228 dest->options[j].value,
229 num_options, &options);
230 break;
231
232 case 'r' : /* -r option (remove) */
233 if (dest == NULL)
ef416fc2 234 {
bdbfacc7
MS
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 }
ef416fc2 254
bdbfacc7 255 if (opt[1] != '\0')
ef416fc2 256 {
bdbfacc7
MS
257 option = opt + 1;
258 opt += strlen(opt) - 1;
ef416fc2 259 }
260 else
261 {
bdbfacc7
MS
262 i ++;
263 if (i >= argc)
264 usage();
ef416fc2 265
bdbfacc7 266 option = argv[i];
ef416fc2 267 }
ef416fc2 268
bdbfacc7
MS
269 num_options = cupsRemoveOption(option, num_options, &options);
270
271 changes = 1;
272 break;
ef416fc2 273
bdbfacc7
MS
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 }
ef416fc2 305 }
306 }
307 else
bdbfacc7 308 {
ef416fc2 309 usage();
bdbfacc7
MS
310 }
311 }
ef416fc2 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 {
0837b7e8
MS
346 char buffer[10240], /* String for options */
347 *ptr; /* Pointer into string */
348
ef416fc2 349 num_options = dest->num_options;
350 options = dest->options;
351
0837b7e8
MS
352 for (i = 0, ptr = buffer;
353 ptr < (buffer + sizeof(buffer) - 1) && i < num_options;
354 i ++)
ef416fc2 355 {
356 if (i)
0837b7e8 357 *ptr++ = ' ';
ef416fc2 358
359 if (!options[i].value[0])
7e86f2f6 360 strlcpy(ptr, options[i].name, sizeof(buffer) - (size_t)(ptr - buffer));
ef416fc2 361 else if (strchr(options[i].value, ' ') != NULL ||
362 strchr(options[i].value, '\t') != NULL)
7e86f2f6 363 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s=\'%s\'", options[i].name, options[i].value);
ef416fc2 364 else
7e86f2f6 365 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s=%s", options[i].name, options[i].value);
0837b7e8
MS
366
367 ptr += strlen(ptr);
ef416fc2 368 }
369
0837b7e8 370 _cupsLangPuts(stdout, buffer);
ef416fc2 371 }
372
373 return (0);
374}
375
376/*
377 * 'list_group()' - List printer-specific options from the PPD group.
378 */
379
dd1abb6b
MS
380static void
381list_group(ppd_file_t *ppd, /* I - PPD file */
382 ppd_group_t *group) /* I - Group to show */
ef416fc2 383{
dd1abb6b
MS
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 */
0837b7e8
MS
388 char buffer[10240], /* Option string buffer */
389 *ptr; /* Pointer into option string */
ef416fc2 390
391
392 for (i = group->num_options, option = group->options; i > 0; i --, option ++)
393 {
88f9aafc 394 if (!_cups_strcasecmp(option->keyword, "PageRegion"))
dd1abb6b
MS
395 continue;
396
0837b7e8 397 snprintf(buffer, sizeof(buffer), "%s/%s:", option->keyword, option->text);
ef416fc2 398
0837b7e8
MS
399 for (j = option->num_choices, choice = option->choices,
400 ptr = buffer + strlen(buffer);
401 j > 0 && ptr < (buffer + sizeof(buffer) - 1);
dd1abb6b 402 j --, choice ++)
0837b7e8 403 {
88f9aafc 404 if (!_cups_strcasecmp(choice->choice, "Custom"))
dd1abb6b
MS
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)
7e86f2f6 423 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom", choice->marked ? "*" : "");
88f9aafc
MS
424 else if (!_cups_strcasecmp(option->keyword, "PageSize") ||
425 !_cups_strcasecmp(option->keyword, "PageRegion"))
7e86f2f6 426 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.WIDTHxHEIGHT", choice->marked ? "*" : "");
dd1abb6b
MS
427 else
428 {
429 cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
430
431 if (cupsArrayCount(coption->params) == 1)
7e86f2f6 432 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.%s", choice->marked ? "*" : "", types[cparam->type]);
dd1abb6b
MS
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 {
7e86f2f6 445 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s%s=%s", prefix, cparam->name, types[cparam->type]);
dd1abb6b
MS
446 cparam = (ppd_cparam_t *)cupsArrayNext(coption->params);
447 prefix = " ";
0837b7e8 448 ptr += strlen(ptr);
dd1abb6b
MS
449 }
450
0837b7e8 451 if (ptr < (buffer + sizeof(buffer) - 1))
7e86f2f6 452 strlcpy(ptr, "}", sizeof(buffer) - (size_t)(ptr - buffer));
dd1abb6b
MS
453 }
454 }
455 }
456 else if (choice->marked)
7e86f2f6 457 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " *%s", choice->choice);
ef416fc2 458 else
7e86f2f6 459 snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %s", choice->choice);
0837b7e8
MS
460
461 ptr += strlen(ptr);
462 }
ef416fc2 463
0837b7e8 464 _cupsLangPuts(stdout, buffer);
ef416fc2 465 }
466
467 for (i = group->num_subgroups, subgroup = group->subgroups; i > 0; i --, subgroup ++)
dd1abb6b 468 list_group(ppd, subgroup);
ef416fc2 469}
470
471
472/*
473 * 'list_options()' - List printer-specific options from the PPD file.
474 */
475
dd1abb6b
MS
476static void
477list_options(cups_dest_t *dest) /* I - Destination to list */
ef416fc2 478{
dd1abb6b
MS
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 */
ef416fc2 483
484
485 if ((filename = cupsGetPPD(dest->name)) == NULL)
486 {
0837b7e8 487 _cupsLangPrintf(stderr, _("lpoptions: Unable to get PPD file for %s: %s"),
b86bc4cf 488 dest->name, cupsLastErrorString());
ef416fc2 489 return;
490 }
491
492 if ((ppd = ppdOpenFile(filename)) == NULL)
493 {
494 unlink(filename);
0837b7e8 495 _cupsLangPrintf(stderr, _("lpoptions: Unable to open PPD file for %s."),
ef416fc2 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 ++)
dd1abb6b 504 list_group(ppd, group);
ef416fc2 505
506 ppdClose(ppd);
507 unlink(filename);
508}
509
510
511/*
512 * 'usage()' - Show program usage and exit.
513 */
514
dd1abb6b 515static void
ef416fc2 516usage(void)
517{
fa73b229 518 _cupsLangPuts(stdout,
ef416fc2 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"
0837b7e8 523 " lpoptions [-h server] [-E] -x printer"));
ef416fc2 524
525 exit(1);
526}