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