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