You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

550 lines
13 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/*
* Printer option program for CUPS.
*
* Copyright © 2007-2018 by Apple Inc.
* Copyright © 1997-2006 by Easy Software Products.
*
* Licensed under Apache License v2.0. See the file "LICENSE" for more
* information.
*/
/*
* Include necessary headers...
*/
#include <cups/cups-private.h>
#include <cups/ppd-private.h>
/*
* Local functions...
*/
static void list_group(ppd_file_t *ppd, ppd_group_t *group);
static void list_options(cups_dest_t *dest);
static void usage(void) _CUPS_NORETURN;
/*
* 'main()' - Main entry.
*/
int /* O - Exit status */
main(int argc, /* I - Number of command-line arguments */
char *argv[]) /* I - Command-line arguments */
{
int i, j; /* Looping vars */
int changes; /* Did we make changes? */
int num_options; /* Number of options */
cups_option_t *options; /* Options */
int num_dests; /* Number of destinations */
cups_dest_t *dests; /* Destinations */
cups_dest_t *dest; /* Current destination */
char *opt, /* Option pointer */
*printer, /* Printer name */
*instance, /* Instance name */
*option; /* Current option */
_cupsSetLocale(argv);
/*
* Loop through the command-line arguments...
*/
dest = NULL;
num_dests = 0;
dests = NULL;
num_options = 0;
options = NULL;
changes = 0;
for (i = 1; i < argc; i ++)
{
if (!strcmp(argv[i], "--help"))
usage();
else if (argv[i][0] == '-')
{
for (opt = argv[i] + 1; *opt; opt ++)
{
switch (*opt)
{
case 'd' : /* -d printer */
if (opt[1] != '\0')
{
printer = opt + 1;
opt += strlen(opt) - 1;
}
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 (num_dests == 0 || !dests || (dest = cupsGetDest(printer, instance, num_dests, dests)) == NULL)
{
_cupsLangPuts(stderr, _("lpoptions: Unknown printer or class."));
return (1);
}
/*
* Set the default destination...
*/
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' : /* -h server */
if (opt[1] != '\0')
{
cupsSetServer(opt + 1);
opt += strlen(opt) - 1;
}
else
{
i ++;
if (i >= argc)
usage();
cupsSetServer(argv[i]);
}
break;
case 'E' : /* Encrypt connection */
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
break;
case 'l' : /* -l (list options) */
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)
_cupsLangPuts(stderr, _("lpoptions: No printers."));
else
list_options(dest);
changes = -1;
break;
case 'o' : /* -o option[=value] */
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)
{
_cupsLangPuts(stderr, _("lpoptions: No printers."));
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);
}
if (opt[1] != '\0')
{
num_options = cupsParseOptions(opt + 1, num_options, &options);
opt += strlen(opt) - 1;
}
else
{
i ++;
if (i >= argc)
usage();
num_options = cupsParseOptions(argv[i], num_options, &options);
}
changes = 1;
break;
case 'p' : /* -p printer */
if (opt[1] != '\0')
{
printer = opt + 1;
opt += strlen(opt) - 1;
}
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)
{
_cupsLangPrintf(stderr, _("lpoptions: Unable to add printer or instance: %s"), strerror(errno));
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' : /* -r option (remove) */
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)
{
_cupsLangPuts(stderr, _("lpoptions: No printers."));
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);
}
if (opt[1] != '\0')
{
option = opt + 1;
opt += strlen(opt) - 1;
}
else
{
i ++;
if (i >= argc)
usage();
option = argv[i];
}
num_options = cupsRemoveOption(option, num_options, &options);
changes = 1;
break;
case 'x' : /* -x printer */
if (opt[1] != '\0')
{
printer = opt + 1;
opt += strlen(opt) - 1;
}
else
{
i ++;
if (i >= argc)
usage();
printer = argv[i];
}
if ((instance = strrchr(printer, '/')) != NULL)
*instance++ = '\0';
if (num_dests == 0)
num_dests = cupsGetDests(&dests);
num_dests = cupsRemoveDest(printer, instance, num_dests, &dests);
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)
{
/*
* Set printer options...
*/
cupsFreeOptions(dest->num_options, dest->options);
dest->num_options = num_options;
dest->options = options;
cupsSetDests(num_dests, dests);
}
else if (changes == 0)
{
char buffer[10240], /* String for options */
*ptr; /* Pointer into string */
num_options = dest->num_options;
options = dest->options;
for (i = 0, ptr = buffer;
ptr < (buffer + sizeof(buffer) - 1) && i < num_options;
i ++)
{
if (i)
*ptr++ = ' ';
if (!options[i].value[0])
strlcpy(ptr, options[i].name, sizeof(buffer) - (size_t)(ptr - buffer));
else if (strchr(options[i].value, ' ') != NULL ||
strchr(options[i].value, '\t') != NULL)
snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s=\'%s\'", options[i].name, options[i].value);
else
snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s=%s", options[i].name, options[i].value);
ptr += strlen(ptr);
}
_cupsLangPuts(stdout, buffer);
}
return (0);
}
/*
* 'list_group()' - List printer-specific options from the PPD group.
*/
static void
list_group(ppd_file_t *ppd, /* I - PPD file */
ppd_group_t *group) /* I - Group to show */
{
int i, j; /* Looping vars */
ppd_option_t *option; /* Current option */
ppd_choice_t *choice; /* Current choice */
ppd_group_t *subgroup; /* Current subgroup */
char buffer[10240], /* Option string buffer */
*ptr; /* Pointer into option string */
for (i = group->num_options, option = group->options; i > 0; i --, option ++)
{
if (!_cups_strcasecmp(option->keyword, "PageRegion"))
continue;
snprintf(buffer, sizeof(buffer), "%s/%s:", option->keyword, option->text);
for (j = option->num_choices, choice = option->choices,
ptr = buffer + strlen(buffer);
j > 0 && ptr < (buffer + sizeof(buffer) - 1);
j --, choice ++)
{
if (!_cups_strcasecmp(choice->choice, "Custom"))
{
ppd_coption_t *coption; /* Custom option */
ppd_cparam_t *cparam; /* Custom parameter */
static const char * const types[] =
{ /* Parameter types */
"CURVE",
"INTEGER",
"INVCURVE",
"PASSCODE",
"PASSWORD",
"POINTS",
"REAL",
"STRING"
};
if ((coption = ppdFindCustomOption(ppd, option->keyword)) == NULL ||
cupsArrayCount(coption->params) == 0)
snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom", choice->marked ? "*" : "");
else if (!_cups_strcasecmp(option->keyword, "PageSize") ||
!_cups_strcasecmp(option->keyword, "PageRegion"))
snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.WIDTHxHEIGHT", choice->marked ? "*" : "");
else
{
cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
if (cupsArrayCount(coption->params) == 1)
snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %sCustom.%s", choice->marked ? "*" : "", types[cparam->type]);
else
{
const char *prefix; /* Prefix string */
if (choice->marked)
prefix = " *{";
else
prefix = " {";
while (cparam)
{
snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), "%s%s=%s", prefix, cparam->name, types[cparam->type]);
cparam = (ppd_cparam_t *)cupsArrayNext(coption->params);
prefix = " ";
ptr += strlen(ptr);
}
if (ptr < (buffer + sizeof(buffer) - 1))
strlcpy(ptr, "}", sizeof(buffer) - (size_t)(ptr - buffer));
}
}
}
else if (choice->marked)
snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " *%s", choice->choice);
else
snprintf(ptr, sizeof(buffer) - (size_t)(ptr - buffer), " %s", choice->choice);
ptr += strlen(ptr);
}
_cupsLangPuts(stdout, buffer);
}
for (i = group->num_subgroups, subgroup = group->subgroups; i > 0; i --, subgroup ++)
list_group(ppd, subgroup);
}
/*
* 'list_options()' - List printer-specific options from the PPD file.
*/
static void
list_options(cups_dest_t *dest) /* I - Destination to list */
{
http_t *http; /* Connection to destination */
char resource[1024]; /* Resource path */
int i; /* Looping var */
const char *filename; /* PPD filename */
ppd_file_t *ppd; /* PPD data */
ppd_group_t *group; /* Current group */
if ((http = cupsConnectDest(dest, CUPS_DEST_FLAGS_NONE, 30000, NULL, resource, sizeof(resource), NULL, NULL)) == NULL)
{
_cupsLangPrintf(stderr, _("lpoptions: Unable to get PPD file for %s: %s"),
dest->name, cupsLastErrorString());
return;
}
if ((filename = cupsGetPPD2(http, dest->name)) == NULL)
{
httpClose(http);
_cupsLangPrintf(stderr, _("lpoptions: Unable to get PPD file for %s: %s"),
dest->name, cupsLastErrorString());
return;
}
httpClose(http);
if ((ppd = ppdOpenFile(filename)) == NULL)
{
unlink(filename);
_cupsLangPrintf(stderr, _("lpoptions: Unable to open PPD file for %s."),
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(ppd, group);
ppdClose(ppd);
unlink(filename);
}
/*
* 'usage()' - Show program usage and exit.
*/
static void
usage(void)
{
_cupsLangPuts(stdout, _("Usage: lpoptions [options] -d destination\n"
" lpoptions [options] [-p destination] [-l]\n"
" lpoptions [options] [-p destination] -o option[=value]\n"
" lpoptions [options] -x destination"));
_cupsLangPuts(stdout, _("Options:"));
_cupsLangPuts(stdout, _("-d destination Set default destination"));
_cupsLangPuts(stdout, _("-E Encrypt the connection to the server"));
_cupsLangPuts(stdout, _("-h server[:port] Connect to the named server and port"));
_cupsLangPuts(stdout, _("-l Show supported options and values"));
_cupsLangPuts(stdout, _("-o name[=value] Set default option and value"));
_cupsLangPuts(stdout, _("-p destination Specify a destination"));
_cupsLangPuts(stdout, _("-U username Specify the username to use for authentication"));
_cupsLangPuts(stdout, _("-x destination Remove default options for destination"));
exit(1);
}