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