#include <cups/cups.h>
#include <cups/string.h>
#include <stdlib.h>
void list_group(ppd_group_t *group);
void list_options(cups_dest_t *dest);
void usage(void);
int
main(int argc,
char *argv[])
{
int i, j;
int changes;
int num_options;
cups_option_t *options;
int num_dests;
cups_dest_t *dests;
cups_dest_t *dest;
char *printer,
*instance,
*option;
dest = NULL;
num_dests = 0;
dests = NULL;
num_options = 0;
options = NULL;
changes = 0;
for (i = 1; i < argc; i ++)
if (argv[i][0] == '-')
{
switch (argv[i][1])
{
case 'd' :
if (argv[i][2])
printer = argv[i] + 2;
else
{
i ++;
if (i >= argc)
usage();
printer = argv[i];
}
if ((instance = strrchr(printer, '/')) != NULL)
*instance++ = '\0';
if (num_dests == 0)
num_dests = cupsGetDests(&dests);
if ((dest = cupsGetDest(printer, instance, num_dests, dests)) == NULL)
{
fputs("lpoptions: Unknown printer or class!\n", stderr);
return (1);
}
for (j = 0; j < num_dests; j ++)
dests[j].is_default = 0;
dest->is_default = 1;
cupsSetDests(num_dests, dests);
for (j = 0; j < dest->num_options; j ++)
if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
num_options = cupsAddOption(dest->options[j].name,
dest->options[j].value,
num_options, &options);
break;
case 'h' :
if (argv[i][2])
cupsSetServer(argv[i] + 2);
else
{
i ++;
if (i >= argc)
usage();
cupsSetServer(argv[i]);
}
break;
case 'E' :
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
break;
case 'l' :
if (dest == NULL)
{
if (num_dests == 0)
num_dests = cupsGetDests(&dests);
if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL)
dest = dests;
}
if (dest == NULL)
fputs("lpoptions: No printers!?!\n", stderr);
else
list_options(dest);
changes = -1;
break;
case 'o' :
if (argv[i][2])
num_options = cupsParseOptions(argv[i] + 2, num_options, &options);
else
{
i ++;
if (i >= argc)
usage();
num_options = cupsParseOptions(argv[i], num_options, &options);
}
changes = 1;
break;
case 'p' :
if (argv[i][2])
printer = argv[i] + 2;
else
{
i ++;
if (i >= argc)
usage();
printer = argv[i];
}
if ((instance = strrchr(printer, '/')) != NULL)
*instance++ = '\0';
if (num_dests == 0)
num_dests = cupsGetDests(&dests);
if ((dest = cupsGetDest(printer, instance, num_dests, dests)) == NULL)
{
num_dests = cupsAddDest(printer, instance, num_dests, &dests);
dest = cupsGetDest(printer, instance, num_dests, dests);
if (dest == NULL)
{
perror("lpoptions: Unable to add printer or instance");
return (1);
}
}
for (j = 0; j < dest->num_options; j ++)
if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
num_options = cupsAddOption(dest->options[j].name,
dest->options[j].value,
num_options, &options);
break;
case 'r' :
if (argv[i][2])
option = argv[i] + 2;
else
{
i ++;
if (i >= argc)
usage();
option = argv[i];
}
for (j = 0; j < num_options; j ++)
if (strcasecmp(options[j].name, option) == 0)
{
num_options --;
if (j < num_options)
memcpy(options + j, options + j + 1,
sizeof(cups_option_t) * (num_options - j));
break;
}
changes = 1;
break;
case 'x' :
if (argv[i][2])
printer = argv[i] + 2;
else
{
i ++;
if (i >= argc)
usage();
printer = argv[i];
}
if ((instance = strrchr(printer, '/')) != NULL)
*instance++ = '\0';
if (num_dests == 0)
num_dests = cupsGetDests(&dests);
if ((dest = cupsGetDest(printer, instance, num_dests, dests)) != NULL)
{
cupsFreeOptions(dest->num_options, dest->options);
if (dest->is_default)
{
dest->num_options = 0;
dest->options = NULL;
}
else
{
num_dests --;
j = dest - dests;
if (j < num_dests)
memcpy(dest, dest + 1, (num_dests - j) * sizeof(cups_dest_t));
}
}
cupsSetDests(num_dests, dests);
dest = NULL;
changes = -1;
break;
default :
usage();
}
}
else
usage();
if (num_dests == 0)
num_dests = cupsGetDests(&dests);
if (dest == NULL)
{
if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL)
{
for (j = 0; j < dest->num_options; j ++)
if (cupsGetOption(dest->options[j].name, num_options, options) == NULL)
num_options = cupsAddOption(dest->options[j].name,
dest->options[j].value,
num_options, &options);
}
}
if (dest == NULL)
return (0);
if (changes > 0)
{
cupsFreeOptions(dest->num_options, dest->options);
dest->num_options = num_options;
dest->options = options;
cupsSetDests(num_dests, dests);
}
else if (changes == 0)
{
num_options = dest->num_options;
options = dest->options;
for (i = 0; i < num_options; i ++)
{
if (i)
putchar(' ');
if (!options[i].value[0])
printf("%s", options[i].name);
else if (strchr(options[i].value, ' ') != NULL ||
strchr(options[i].value, '\t') != NULL)
printf("%s=\'%s\'", options[i].name, options[i].value);
else
printf("%s=%s", options[i].name, options[i].value);
}
putchar('\n');
}
return (0);
}
void
list_group(ppd_group_t *group)
{
int i, j;
ppd_option_t *option;
ppd_choice_t *choice;
ppd_group_t *subgroup;
for (i = group->num_options, option = group->options; i > 0; i --, option ++)
{
printf("%s/%s:", option->keyword, option->text);
for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++)
if (choice->marked)
printf(" *%s", choice->choice);
else
printf(" %s", choice->choice);
putchar('\n');
}
for (i = group->num_subgroups, subgroup = group->subgroups; i > 0; i --, subgroup ++)
list_group(subgroup);
}
void
list_options(cups_dest_t *dest)
{
int i;
const char *filename;
ppd_file_t *ppd;
ppd_group_t *group;
if ((filename = cupsGetPPD(dest->name)) == NULL)
{
fprintf(stderr, "lpoptions: Destination %s has no PPD file!\n", dest->name);
return;
}
if ((ppd = ppdOpenFile(filename)) == NULL)
{
unlink(filename);
fprintf(stderr, "lpoptions: Unable to open PPD file for %s!\n", dest->name);
return;
}
ppdMarkDefaults(ppd);
cupsMarkOptions(ppd, dest->num_options, dest->options);
for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
list_group(group);
ppdClose(ppd);
unlink(filename);
}
void
usage(void)
{
puts("Usage: lpoptions [-h server] [-E] -d printer");
puts(" lpoptions [-h server] [-E] [-p printer] -l");
puts(" lpoptions [-h server] [-E] -p printer -o option[=value] ...");
puts(" lpoptions [-h server] [-E] -x printer");
exit(1);
}