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