mirror of https://gitee.com/openkylin/cups.git
516 lines
13 KiB
C
516 lines
13 KiB
C
/*
|
||
* "lpinfo" command for CUPS.
|
||
*
|
||
* Copyright © 2021-2023 by OpenPrinting.
|
||
* 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/adminutil.h>
|
||
|
||
|
||
/*
|
||
* Local functions...
|
||
*/
|
||
|
||
static void device_cb(const char *device_class, const char *device_id,
|
||
const char *device_info,
|
||
const char *device_make_and_model,
|
||
const char *device_uri, const char *device_location,
|
||
void *user_data);
|
||
static int show_devices(int long_status, int timeout,
|
||
const char *include_schemes,
|
||
const char *exclude_schemes);
|
||
static int show_models(int long_status,
|
||
const char *device_id, const char *language,
|
||
const char *make_model, const char *product,
|
||
const char *include_schemes,
|
||
const char *exclude_schemes);
|
||
static void usage(void) _CUPS_NORETURN;
|
||
|
||
|
||
/*
|
||
* 'main()' - Parse options and show status information.
|
||
*/
|
||
|
||
int
|
||
main(int argc, /* I - Number of command-line arguments */
|
||
char *argv[]) /* I - Command-line arguments */
|
||
{
|
||
int i; /* Looping var */
|
||
int long_status; /* Long listing? */
|
||
const char *opt, /* Option pointer */
|
||
*device_id, /* 1284 device ID */
|
||
*language, /* Language */
|
||
*make_model, /* Make and model */
|
||
*product, /* Product */
|
||
*include_schemes, /* Schemes to include */
|
||
*exclude_schemes; /* Schemes to exclude */
|
||
int timeout; /* Device timeout */
|
||
|
||
|
||
_cupsSetLocale(argv);
|
||
|
||
long_status = 0;
|
||
device_id = NULL;
|
||
language = NULL;
|
||
make_model = NULL;
|
||
product = NULL;
|
||
include_schemes = CUPS_INCLUDE_ALL;
|
||
exclude_schemes = CUPS_EXCLUDE_NONE;
|
||
timeout = CUPS_TIMEOUT_DEFAULT;
|
||
|
||
for (i = 1; i < argc; i ++)
|
||
{
|
||
if (!strcmp(argv[i], "--device-id"))
|
||
{
|
||
i ++;
|
||
|
||
if (i < argc)
|
||
device_id = argv[i];
|
||
else
|
||
{
|
||
_cupsLangPuts(stderr, _("lpinfo: Expected 1284 device ID string after \"--device-id\"."));
|
||
usage();
|
||
}
|
||
}
|
||
else if (!strncmp(argv[i], "--device-id=", 12) && argv[i][12])
|
||
{
|
||
device_id = argv[i] + 12;
|
||
}
|
||
else if (!strcmp(argv[i], "--exclude-schemes"))
|
||
{
|
||
i ++;
|
||
|
||
if (i < argc)
|
||
exclude_schemes = argv[i];
|
||
else
|
||
{
|
||
_cupsLangPuts(stderr, _("lpinfo: Expected scheme list after \"--exclude-schemes\"."));
|
||
usage();
|
||
}
|
||
}
|
||
else if (!strncmp(argv[i], "--exclude-schemes=", 18) && argv[i][18])
|
||
{
|
||
exclude_schemes = argv[i] + 18;
|
||
}
|
||
else if (!strcmp(argv[i], "--help"))
|
||
usage();
|
||
else if (!strcmp(argv[i], "--include-schemes"))
|
||
{
|
||
i ++;
|
||
|
||
if (i < argc)
|
||
include_schemes = argv[i];
|
||
else
|
||
{
|
||
_cupsLangPuts(stderr, _("lpinfo: Expected scheme list after \"--include-schemes\"."));
|
||
usage();
|
||
}
|
||
}
|
||
else if (!strncmp(argv[i], "--include-schemes=", 18) && argv[i][18])
|
||
{
|
||
include_schemes = argv[i] + 18;
|
||
}
|
||
else if (!strcmp(argv[i], "--language"))
|
||
{
|
||
i ++;
|
||
if (i < argc)
|
||
language = argv[i];
|
||
else
|
||
{
|
||
_cupsLangPuts(stderr, _("lpinfo: Expected language after \"--language\"."));
|
||
usage();
|
||
}
|
||
}
|
||
else if (!strncmp(argv[i], "--language=", 11) && argv[i][11])
|
||
{
|
||
language = argv[i] + 11;
|
||
}
|
||
else if (!strcmp(argv[i], "--make-and-model"))
|
||
{
|
||
i ++;
|
||
if (i < argc)
|
||
make_model= argv[i];
|
||
else
|
||
{
|
||
_cupsLangPuts(stderr, _("lpinfo: Expected make and model after \"--make-and-model\"."));
|
||
usage();
|
||
}
|
||
}
|
||
else if (!strncmp(argv[i], "--make-and-model=", 17) && argv[i][17])
|
||
{
|
||
make_model = argv[i] + 17;
|
||
}
|
||
else if (!strcmp(argv[i], "--product"))
|
||
{
|
||
i ++;
|
||
if (i < argc)
|
||
product = argv[i];
|
||
else
|
||
{
|
||
_cupsLangPuts(stderr, _("lpinfo: Expected product string after \"--product\"."));
|
||
usage();
|
||
}
|
||
}
|
||
else if (!strncmp(argv[i], "--product=", 10) && argv[i][10])
|
||
{
|
||
product = argv[i] + 10;
|
||
}
|
||
else if (!strcmp(argv[i], "--timeout"))
|
||
{
|
||
i ++;
|
||
if (i < argc)
|
||
timeout = atoi(argv[i]);
|
||
else
|
||
{
|
||
_cupsLangPuts(stderr, _("lpinfo: Expected timeout after \"--timeout\"."));
|
||
usage();
|
||
}
|
||
}
|
||
else if (!strncmp(argv[i], "--timeout=", 10) && argv[i][10])
|
||
{
|
||
timeout = atoi(argv[i] + 10);
|
||
}
|
||
else if (argv[i][0] == '-')
|
||
{
|
||
for (opt = argv[i] + 1; *opt; opt ++)
|
||
{
|
||
switch (*opt)
|
||
{
|
||
case 'E' : /* Encrypt */
|
||
#ifdef HAVE_TLS
|
||
cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
|
||
#else
|
||
_cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
|
||
#endif /* HAVE_TLS */
|
||
break;
|
||
|
||
case 'h' : /* Connect to host */
|
||
if (opt[1] != '\0')
|
||
{
|
||
cupsSetServer(opt + 1);
|
||
opt += strlen(opt) - 1;
|
||
}
|
||
else
|
||
{
|
||
i ++;
|
||
|
||
if (i >= argc)
|
||
{
|
||
_cupsLangPuts(stderr, _("Error: need hostname after \"-h\" option."));
|
||
usage();
|
||
}
|
||
|
||
cupsSetServer(argv[i]);
|
||
}
|
||
break;
|
||
|
||
case 'l' : /* Show long listing */
|
||
long_status = 1;
|
||
break;
|
||
|
||
case 'm' : /* Show models */
|
||
if (show_models(long_status, device_id, language, make_model, product, include_schemes, exclude_schemes))
|
||
return (1);
|
||
break;
|
||
|
||
case 'v' : /* Show available devices */
|
||
if (show_devices(long_status, timeout, include_schemes, exclude_schemes))
|
||
return (1);
|
||
break;
|
||
|
||
default :
|
||
_cupsLangPrintf(stderr, _("%s: Unknown option \"%c\"."), argv[0], *opt);
|
||
usage();
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Unknown argument \"%s\"."), argv[0], argv[i]);
|
||
usage();
|
||
}
|
||
}
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'device_cb()' - Device callback.
|
||
*/
|
||
|
||
static void
|
||
device_cb(
|
||
const char *device_class, /* I - device-class string */
|
||
const char *device_id, /* I - device-id string */
|
||
const char *device_info, /* I - device-info string */
|
||
const char *device_make_and_model, /* I - device-make-and-model string */
|
||
const char *device_uri, /* I - device-uri string */
|
||
const char *device_location, /* I - device-location string */
|
||
void *user_data) /* I - User data */
|
||
{
|
||
int *long_status; /* Show verbose info? */
|
||
|
||
|
||
/*
|
||
* Display the device...
|
||
*/
|
||
|
||
long_status = (int *)user_data;
|
||
|
||
if (*long_status)
|
||
{
|
||
_cupsLangPrintf(stdout,
|
||
_("Device: uri = %s\n"
|
||
" class = %s\n"
|
||
" info = %s\n"
|
||
" make-and-model = %s\n"
|
||
" device-id = %s\n"
|
||
" location = %s"),
|
||
device_uri, device_class, device_info,
|
||
device_make_and_model, device_id, device_location);
|
||
}
|
||
else
|
||
_cupsLangPrintf(stdout, "%s %s", device_class, device_uri);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'show_devices()' - Show available devices.
|
||
*/
|
||
|
||
static int /* O - 0 on success, 1 on failure */
|
||
show_devices(
|
||
int long_status, /* I - Long status report? */
|
||
int timeout, /* I - Timeout */
|
||
const char *include_schemes, /* I - List of schemes to include */
|
||
const char *exclude_schemes) /* I - List of schemes to exclude */
|
||
{
|
||
if (cupsGetDevices(CUPS_HTTP_DEFAULT, timeout, include_schemes,
|
||
exclude_schemes, device_cb, &long_status) != IPP_OK)
|
||
{
|
||
_cupsLangPrintf(stderr, "lpinfo: %s", cupsLastErrorString());
|
||
return (1);
|
||
}
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'show_models()' - Show available PPDs.
|
||
*/
|
||
|
||
static int /* O - 0 on success, 1 on failure */
|
||
show_models(
|
||
int long_status, /* I - Long status report? */
|
||
const char *device_id, /* I - 1284 device ID */
|
||
const char *language, /* I - Language */
|
||
const char *make_model, /* I - Make and model */
|
||
const char *product, /* I - Product */
|
||
const char *include_schemes, /* I - List of schemes to include */
|
||
const char *exclude_schemes) /* I - List of schemes to exclude */
|
||
{
|
||
ipp_t *request, /* IPP Request */
|
||
*response; /* IPP Response */
|
||
ipp_attribute_t *attr; /* Current attribute */
|
||
const char *ppd_device_id, /* Pointer to ppd-device-id */
|
||
*ppd_language, /* Pointer to ppd-natural-language */
|
||
*ppd_make_model, /* Pointer to ppd-make-and-model */
|
||
*ppd_name; /* Pointer to ppd-name */
|
||
cups_option_t option; /* in/exclude-schemes option */
|
||
|
||
|
||
/*
|
||
* Build a CUPS_GET_PPDS request...
|
||
*/
|
||
|
||
request = ippNewRequest(CUPS_GET_PPDS);
|
||
|
||
if (device_id)
|
||
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-device-id",
|
||
NULL, device_id);
|
||
if (language)
|
||
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "ppd-language",
|
||
NULL, language);
|
||
if (make_model)
|
||
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-make-and-model",
|
||
NULL, make_model);
|
||
if (product)
|
||
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-product",
|
||
NULL, product);
|
||
|
||
if (include_schemes)
|
||
{
|
||
option.name = "include-schemes";
|
||
option.value = (char *)include_schemes;
|
||
|
||
cupsEncodeOptions2(request, 1, &option, IPP_TAG_OPERATION);
|
||
}
|
||
|
||
if (exclude_schemes)
|
||
{
|
||
option.name = "exclude-schemes";
|
||
option.value = (char *)exclude_schemes;
|
||
|
||
cupsEncodeOptions2(request, 1, &option, IPP_TAG_OPERATION);
|
||
}
|
||
|
||
/*
|
||
* Do the request and get back a response...
|
||
*/
|
||
|
||
if ((response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
|
||
{
|
||
/*
|
||
* Loop through the device list and display them...
|
||
*/
|
||
|
||
if (response->request.status.status_code > IPP_OK_CONFLICT)
|
||
{
|
||
_cupsLangPrintf(stderr, "lpinfo: %s", cupsLastErrorString());
|
||
ippDelete(response);
|
||
return (1);
|
||
}
|
||
|
||
for (attr = response->attrs; attr != NULL; attr = attr->next)
|
||
{
|
||
/*
|
||
* Skip leading attributes until we hit a PPD...
|
||
*/
|
||
|
||
while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
|
||
attr = attr->next;
|
||
|
||
if (attr == NULL)
|
||
break;
|
||
|
||
/*
|
||
* Pull the needed attributes from this PPD...
|
||
*/
|
||
|
||
ppd_device_id = "NONE";
|
||
ppd_language = NULL;
|
||
ppd_make_model = NULL;
|
||
ppd_name = NULL;
|
||
|
||
while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
|
||
{
|
||
if (!strcmp(attr->name, "ppd-device-id") &&
|
||
attr->value_tag == IPP_TAG_TEXT)
|
||
ppd_device_id = attr->values[0].string.text;
|
||
else if (!strcmp(attr->name, "ppd-natural-language") &&
|
||
attr->value_tag == IPP_TAG_LANGUAGE)
|
||
ppd_language = attr->values[0].string.text;
|
||
else if (!strcmp(attr->name, "ppd-make-and-model") &&
|
||
attr->value_tag == IPP_TAG_TEXT)
|
||
ppd_make_model = attr->values[0].string.text;
|
||
else if (!strcmp(attr->name, "ppd-name") &&
|
||
attr->value_tag == IPP_TAG_NAME)
|
||
ppd_name = attr->values[0].string.text;
|
||
|
||
attr = attr->next;
|
||
}
|
||
|
||
/*
|
||
* See if we have everything needed...
|
||
*/
|
||
|
||
if (ppd_language == NULL || ppd_make_model == NULL || ppd_name == NULL)
|
||
{
|
||
if (attr == NULL)
|
||
break;
|
||
else
|
||
continue;
|
||
}
|
||
|
||
/*
|
||
* Display the device...
|
||
*/
|
||
|
||
if (long_status)
|
||
{
|
||
_cupsLangPrintf(stdout,
|
||
_("Model: name = %s\n"
|
||
" natural_language = %s\n"
|
||
" make-and-model = %s\n"
|
||
" device-id = %s"),
|
||
ppd_name, ppd_language, ppd_make_model, ppd_device_id);
|
||
}
|
||
else
|
||
_cupsLangPrintf(stdout, "%s %s", ppd_name, ppd_make_model);
|
||
|
||
if (attr == NULL)
|
||
break;
|
||
}
|
||
|
||
ippDelete(response);
|
||
|
||
/*
|
||
* Show the "everywhere" model, which is handled by the lpadmin command...
|
||
*/
|
||
|
||
if ((!include_schemes || strstr(include_schemes, "everywhere")) && (!exclude_schemes || !strstr(exclude_schemes, "everywhere")))
|
||
{
|
||
if (long_status)
|
||
{
|
||
_cupsLangPrintf(stdout,
|
||
_("Model: name = %s\n"
|
||
" natural_language = %s\n"
|
||
" make-and-model = %s\n"
|
||
" device-id = %s"),
|
||
"everywhere", cupsLangDefault()->language, "IPP Everywhere™", "CMD:PwgRaster");
|
||
}
|
||
else
|
||
_cupsLangPuts(stdout, "everywhere IPP Everywhere");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stderr, "lpinfo: %s", cupsLastErrorString());
|
||
|
||
return (1);
|
||
}
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'usage()' - Show program usage and exit.
|
||
*/
|
||
|
||
static void
|
||
usage(void)
|
||
{
|
||
_cupsLangPuts(stdout, _("Usage: lpinfo [options] -m\n"
|
||
" lpinfo [options] -v"));
|
||
_cupsLangPuts(stdout, _("Options:"));
|
||
_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 verbose (long) output"));
|
||
_cupsLangPuts(stdout, _("-m Show models"));
|
||
_cupsLangPuts(stdout, _("-v Show devices"));
|
||
_cupsLangPuts(stdout, _("--device-id device-id Show models matching the given IEEE 1284 device ID"));
|
||
_cupsLangPuts(stdout, _("--exclude-schemes scheme-list\n"
|
||
" Exclude the specified URI schemes"));
|
||
_cupsLangPuts(stdout, _("--include-schemes scheme-list\n"
|
||
" Include only the specified URI schemes"));
|
||
_cupsLangPuts(stdout, _("--language locale Show models matching the given locale"));
|
||
_cupsLangPuts(stdout, _("--make-and-model name Show models matching the given make and model name"));
|
||
_cupsLangPuts(stdout, _("--product name Show models matching the given PostScript product"));
|
||
_cupsLangPuts(stdout, _("--timeout seconds Specify the maximum number of seconds to discover devices"));
|
||
|
||
exit(1);
|
||
}
|