mirror of https://gitee.com/openkylin/cups.git
3810 lines
98 KiB
C
3810 lines
98 KiB
C
|
/*
|
|||
|
* Administration CGI for CUPS.
|
|||
|
*
|
|||
|
* Copyright © 2007-2019 by Apple Inc.
|
|||
|
* Copyright © 1997-2007 by Easy Software Products.
|
|||
|
*
|
|||
|
* Licensed under Apache License v2.0. See the file "LICENSE" for more
|
|||
|
* information.
|
|||
|
*/
|
|||
|
|
|||
|
/*
|
|||
|
* Include necessary headers...
|
|||
|
*/
|
|||
|
|
|||
|
#include "cgi-private.h"
|
|||
|
#include <cups/http-private.h>
|
|||
|
#include <cups/ppd-private.h>
|
|||
|
#include <cups/adminutil.h>
|
|||
|
#include <cups/ppd.h>
|
|||
|
#include <errno.h>
|
|||
|
#include <unistd.h>
|
|||
|
#include <fcntl.h>
|
|||
|
#include <sys/wait.h>
|
|||
|
#include <limits.h>
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Local globals...
|
|||
|
*/
|
|||
|
|
|||
|
static int current_device = 0; /* Current device shown */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Local functions...
|
|||
|
*/
|
|||
|
|
|||
|
static void choose_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, const char *title);
|
|||
|
static void do_am_class(http_t *http, int modify);
|
|||
|
static void do_am_printer(http_t *http, int modify);
|
|||
|
static void do_config_server(http_t *http);
|
|||
|
static void do_delete_class(http_t *http);
|
|||
|
static void do_delete_printer(http_t *http);
|
|||
|
static void do_list_printers(http_t *http);
|
|||
|
static void do_menu(http_t *http);
|
|||
|
static void do_set_allowed_users(http_t *http);
|
|||
|
static void do_set_default(http_t *http);
|
|||
|
static void do_set_options(http_t *http, int is_class);
|
|||
|
static void do_set_sharing(http_t *http);
|
|||
|
static char *get_option_value(ppd_file_t *ppd, const char *name,
|
|||
|
char *buffer, size_t bufsize);
|
|||
|
static double get_points(double number, const char *uval);
|
|||
|
static char *get_printer_ppd(const char *uri, char *buffer, size_t bufsize);
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'main()' - Main entry for CGI.
|
|||
|
*/
|
|||
|
|
|||
|
int /* O - Exit status */
|
|||
|
main(void)
|
|||
|
{
|
|||
|
http_t *http; /* Connection to the server */
|
|||
|
const char *op; /* Operation name */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Connect to the HTTP server...
|
|||
|
*/
|
|||
|
|
|||
|
fputs("DEBUG: admin.cgi started...\n", stderr);
|
|||
|
|
|||
|
http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
|
|||
|
|
|||
|
if (!http)
|
|||
|
{
|
|||
|
perror("ERROR: Unable to connect to cupsd");
|
|||
|
fprintf(stderr, "DEBUG: cupsServer()=\"%s\"\n",
|
|||
|
cupsServer() ? cupsServer() : "(null)");
|
|||
|
fprintf(stderr, "DEBUG: ippPort()=%d\n", ippPort());
|
|||
|
fprintf(stderr, "DEBUG: cupsEncryption()=%d\n", cupsEncryption());
|
|||
|
exit(1);
|
|||
|
}
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG: http=%p\n", http);
|
|||
|
|
|||
|
/*
|
|||
|
* Set the web interface section...
|
|||
|
*/
|
|||
|
|
|||
|
cgiSetVariable("SECTION", "admin");
|
|||
|
cgiSetVariable("REFRESH_PAGE", "");
|
|||
|
|
|||
|
/*
|
|||
|
* See if we have form data...
|
|||
|
*/
|
|||
|
|
|||
|
if (!cgiInitialize() || !cgiGetVariable("OP"))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Nope, send the administration menu...
|
|||
|
*/
|
|||
|
|
|||
|
fputs("DEBUG: No form data, showing main menu...\n", stderr);
|
|||
|
|
|||
|
do_menu(http);
|
|||
|
}
|
|||
|
else if ((op = cgiGetVariable("OP")) != NULL && cgiIsPOST())
|
|||
|
{
|
|||
|
/*
|
|||
|
* Do the operation...
|
|||
|
*/
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG: op=\"%s\"...\n", op);
|
|||
|
|
|||
|
if (!*op)
|
|||
|
{
|
|||
|
const char *printer = getenv("PRINTER_NAME"),
|
|||
|
/* Printer or class name */
|
|||
|
*server_port = getenv("SERVER_PORT");
|
|||
|
/* Port number string */
|
|||
|
int port = atoi(server_port ? server_port : "0");
|
|||
|
/* Port number */
|
|||
|
char uri[1024]; /* URL */
|
|||
|
|
|||
|
if (printer)
|
|||
|
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri),
|
|||
|
getenv("HTTPS") ? "https" : "http", NULL,
|
|||
|
getenv("SERVER_NAME"), port, "/%s/%s",
|
|||
|
cgiGetVariable("IS_CLASS") ? "classes" : "printers",
|
|||
|
printer);
|
|||
|
else
|
|||
|
httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri),
|
|||
|
getenv("HTTPS") ? "https" : "http", NULL,
|
|||
|
getenv("SERVER_NAME"), port, "/admin");
|
|||
|
|
|||
|
printf("Location: %s\n\n", uri);
|
|||
|
}
|
|||
|
else if (!strcmp(op, "set-allowed-users"))
|
|||
|
do_set_allowed_users(http);
|
|||
|
else if (!strcmp(op, "set-as-default"))
|
|||
|
do_set_default(http);
|
|||
|
else if (!strcmp(op, "set-sharing"))
|
|||
|
do_set_sharing(http);
|
|||
|
else if (!strcmp(op, "find-new-printers") ||
|
|||
|
!strcmp(op, "list-available-printers"))
|
|||
|
do_list_printers(http);
|
|||
|
else if (!strcmp(op, "add-class"))
|
|||
|
do_am_class(http, 0);
|
|||
|
else if (!strcmp(op, "add-printer"))
|
|||
|
do_am_printer(http, 0);
|
|||
|
else if (!strcmp(op, "modify-class"))
|
|||
|
do_am_class(http, 1);
|
|||
|
else if (!strcmp(op, "modify-printer"))
|
|||
|
do_am_printer(http, 1);
|
|||
|
else if (!strcmp(op, "delete-class"))
|
|||
|
do_delete_class(http);
|
|||
|
else if (!strcmp(op, "delete-printer"))
|
|||
|
do_delete_printer(http);
|
|||
|
else if (!strcmp(op, "set-class-options"))
|
|||
|
do_set_options(http, 1);
|
|||
|
else if (!strcmp(op, "set-printer-options"))
|
|||
|
do_set_options(http, 0);
|
|||
|
else if (!strcmp(op, "config-server"))
|
|||
|
do_config_server(http);
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Bad operation code - display an error...
|
|||
|
*/
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("Administration")));
|
|||
|
cgiCopyTemplateLang("error-op.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
}
|
|||
|
else if (op && !strcmp(op, "redirect"))
|
|||
|
{
|
|||
|
const char *url; /* Redirection URL... */
|
|||
|
char prefix[1024]; /* URL prefix */
|
|||
|
|
|||
|
|
|||
|
if (getenv("HTTPS"))
|
|||
|
snprintf(prefix, sizeof(prefix), "https://%s:%s",
|
|||
|
getenv("SERVER_NAME"), getenv("SERVER_PORT"));
|
|||
|
else
|
|||
|
snprintf(prefix, sizeof(prefix), "http://%s:%s",
|
|||
|
getenv("SERVER_NAME"), getenv("SERVER_PORT"));
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG: redirecting with prefix %s!\n", prefix);
|
|||
|
|
|||
|
if ((url = cgiGetVariable("URL")) != NULL)
|
|||
|
{
|
|||
|
char encoded[1024], /* Encoded URL string */
|
|||
|
*ptr; /* Pointer into encoded string */
|
|||
|
|
|||
|
|
|||
|
ptr = encoded;
|
|||
|
if (*url != '/')
|
|||
|
*ptr++ = '/';
|
|||
|
|
|||
|
for (; *url && ptr < (encoded + sizeof(encoded) - 4); url ++)
|
|||
|
{
|
|||
|
if (strchr("%@&+ <>#=", *url) || *url < ' ' || *url & 128)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Percent-encode this character; safe because we have at least 4
|
|||
|
* bytes left in the array...
|
|||
|
*/
|
|||
|
|
|||
|
sprintf(ptr, "%%%02X", *url & 255);
|
|||
|
ptr += 3;
|
|||
|
}
|
|||
|
else
|
|||
|
*ptr++ = *url;
|
|||
|
}
|
|||
|
|
|||
|
*ptr = '\0';
|
|||
|
|
|||
|
if (*url)
|
|||
|
{
|
|||
|
/*
|
|||
|
* URL was too long, just redirect to the admin page...
|
|||
|
*/
|
|||
|
|
|||
|
printf("Location: %s/admin\n\n", prefix);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* URL is OK, redirect there...
|
|||
|
*/
|
|||
|
|
|||
|
printf("Location: %s%s\n\n", prefix, encoded);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
printf("Location: %s/admin\n\n", prefix);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Form data but no operation code - display an error...
|
|||
|
*/
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("Administration")));
|
|||
|
cgiCopyTemplateLang("error-op.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Close the HTTP server connection...
|
|||
|
*/
|
|||
|
|
|||
|
httpClose(http);
|
|||
|
|
|||
|
/*
|
|||
|
* Return with no errors...
|
|||
|
*/
|
|||
|
|
|||
|
return (0);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'choose_device_cb()' - Add a device to the device selection page.
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
choose_device_cb(
|
|||
|
const char *device_class, /* I - Class */
|
|||
|
const char *device_id, /* I - 1284 device ID */
|
|||
|
const char *device_info, /* I - Description */
|
|||
|
const char *device_make_and_model, /* I - Make and model */
|
|||
|
const char *device_uri, /* I - Device URI */
|
|||
|
const char *device_location, /* I - Location */
|
|||
|
const char *title) /* I - Page title */
|
|||
|
{
|
|||
|
/*
|
|||
|
* For modern browsers, start a multi-part page so we can show that something
|
|||
|
* is happening. Non-modern browsers just get everything at the end...
|
|||
|
*/
|
|||
|
|
|||
|
if (current_device == 0 && cgiSupportsMultipart())
|
|||
|
{
|
|||
|
cgiStartMultipart();
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiCopyTemplateLang("choose-device.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
fflush(stdout);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Add the device to the array...
|
|||
|
*/
|
|||
|
|
|||
|
cgiSetArray("device_class", current_device, device_class);
|
|||
|
cgiSetArray("device_id", current_device, device_id);
|
|||
|
cgiSetArray("device_info", current_device, device_info);
|
|||
|
cgiSetArray("device_make_and_model", current_device, device_make_and_model);
|
|||
|
cgiSetArray("device_uri", current_device, device_uri);
|
|||
|
cgiSetArray("device_location", current_device, device_location);
|
|||
|
|
|||
|
current_device ++;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'do_am_class()' - Add or modify a class.
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
do_am_class(http_t *http, /* I - HTTP connection */
|
|||
|
int modify) /* I - Modify the printer? */
|
|||
|
{
|
|||
|
int i, j; /* Looping vars */
|
|||
|
int element; /* Element number */
|
|||
|
int num_printers; /* Number of printers */
|
|||
|
ipp_t *request, /* IPP request */
|
|||
|
*response; /* IPP response */
|
|||
|
ipp_attribute_t *attr; /* member-uris attribute */
|
|||
|
char uri[HTTP_MAX_URI]; /* Device or printer URI */
|
|||
|
const char *name, /* Pointer to class name */
|
|||
|
*op, /* Operation name */
|
|||
|
*ptr; /* Pointer to CGI variable */
|
|||
|
const char *title; /* Title of page */
|
|||
|
static const char * const pattrs[] = /* Requested printer attributes */
|
|||
|
{
|
|||
|
"member-names",
|
|||
|
"printer-info",
|
|||
|
"printer-location"
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
title = cgiText(modify ? _("Modify Class") : _("Add Class"));
|
|||
|
op = cgiGetVariable("OP");
|
|||
|
name = cgiGetVariable("PRINTER_NAME");
|
|||
|
|
|||
|
if (cgiGetVariable("PRINTER_LOCATION") == NULL)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Build a CUPS_GET_PRINTERS request, which requires the
|
|||
|
* following attributes:
|
|||
|
*
|
|||
|
* attributes-charset
|
|||
|
* attributes-natural-language
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(CUPS_GET_PRINTERS);
|
|||
|
|
|||
|
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
|
|||
|
CUPS_PRINTER_LOCAL);
|
|||
|
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
|
|||
|
CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
|
|||
|
|
|||
|
/*
|
|||
|
* Do the request and get back a response...
|
|||
|
*/
|
|||
|
|
|||
|
cgiClearVariables();
|
|||
|
if (op)
|
|||
|
cgiSetVariable("OP", op);
|
|||
|
if (name)
|
|||
|
cgiSetVariable("PRINTER_NAME", name);
|
|||
|
|
|||
|
if ((response = cupsDoRequest(http, request, "/")) != NULL)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Create MEMBER_URIS and MEMBER_NAMES arrays...
|
|||
|
*/
|
|||
|
|
|||
|
for (element = 0, attr = response->attrs;
|
|||
|
attr != NULL;
|
|||
|
attr = attr->next)
|
|||
|
if (attr->name && !strcmp(attr->name, "printer-uri-supported"))
|
|||
|
{
|
|||
|
if ((ptr = strrchr(attr->values[0].string.text, '/')) != NULL &&
|
|||
|
(!name || _cups_strcasecmp(name, ptr + 1)))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Don't show the current class...
|
|||
|
*/
|
|||
|
|
|||
|
cgiSetArray("MEMBER_URIS", element, attr->values[0].string.text);
|
|||
|
element ++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
for (element = 0, attr = response->attrs;
|
|||
|
attr != NULL;
|
|||
|
attr = attr->next)
|
|||
|
if (attr->name && !strcmp(attr->name, "printer-name"))
|
|||
|
{
|
|||
|
if (!name || _cups_strcasecmp(name, attr->values[0].string.text))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Don't show the current class...
|
|||
|
*/
|
|||
|
|
|||
|
cgiSetArray("MEMBER_NAMES", element, attr->values[0].string.text);
|
|||
|
element ++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
num_printers = cgiGetSize("MEMBER_URIS");
|
|||
|
|
|||
|
ippDelete(response);
|
|||
|
}
|
|||
|
else
|
|||
|
num_printers = 0;
|
|||
|
|
|||
|
if (modify)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
|
|||
|
* following attributes:
|
|||
|
*
|
|||
|
* attributes-charset
|
|||
|
* attributes-natural-language
|
|||
|
* printer-uri
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
|
|||
|
|
|||
|
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
|
|||
|
"localhost", 0, "/classes/%s", name);
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
|
|||
|
NULL, uri);
|
|||
|
|
|||
|
ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
|
|||
|
"requested-attributes",
|
|||
|
(int)(sizeof(pattrs) / sizeof(pattrs[0])),
|
|||
|
NULL, pattrs);
|
|||
|
|
|||
|
/*
|
|||
|
* Do the request and get back a response...
|
|||
|
*/
|
|||
|
|
|||
|
if ((response = cupsDoRequest(http, request, "/")) != NULL)
|
|||
|
{
|
|||
|
if ((attr = ippFindAttribute(response, "member-names",
|
|||
|
IPP_TAG_NAME)) != NULL)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Mark any current members in the class...
|
|||
|
*/
|
|||
|
|
|||
|
for (j = 0; j < num_printers; j ++)
|
|||
|
cgiSetArray("MEMBER_SELECTED", j, "");
|
|||
|
|
|||
|
for (i = 0; i < attr->num_values; i ++)
|
|||
|
{
|
|||
|
for (j = 0; j < num_printers; j ++)
|
|||
|
{
|
|||
|
if (!_cups_strcasecmp(attr->values[i].string.text,
|
|||
|
cgiGetArray("MEMBER_NAMES", j)))
|
|||
|
{
|
|||
|
cgiSetArray("MEMBER_SELECTED", j, "SELECTED");
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((attr = ippFindAttribute(response, "printer-info",
|
|||
|
IPP_TAG_TEXT)) != NULL)
|
|||
|
cgiSetVariable("PRINTER_INFO", attr->values[0].string.text);
|
|||
|
|
|||
|
if ((attr = ippFindAttribute(response, "printer-location",
|
|||
|
IPP_TAG_TEXT)) != NULL)
|
|||
|
cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text);
|
|||
|
|
|||
|
ippDelete(response);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Update the location and description of an existing printer...
|
|||
|
*/
|
|||
|
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiCopyTemplateLang("modify-class.tmpl");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Get the name, location, and description for a new printer...
|
|||
|
*/
|
|||
|
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiCopyTemplateLang("add-class.tmpl");
|
|||
|
}
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (!name)
|
|||
|
{
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
for (ptr = name; *ptr; ptr ++)
|
|||
|
if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#')
|
|||
|
break;
|
|||
|
|
|||
|
if (*ptr || ptr == name || strlen(name) > 127)
|
|||
|
{
|
|||
|
cgiSetVariable("ERROR",
|
|||
|
cgiText(_("The class name may only contain up to "
|
|||
|
"127 printable characters and may not "
|
|||
|
"contain spaces, slashes (/), or the "
|
|||
|
"pound sign (#).")));
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Build a CUPS_ADD_CLASS request, which requires the following
|
|||
|
* attributes:
|
|||
|
*
|
|||
|
* attributes-charset
|
|||
|
* attributes-natural-language
|
|||
|
* printer-uri
|
|||
|
* printer-location
|
|||
|
* printer-info
|
|||
|
* printer-is-accepting-jobs
|
|||
|
* printer-state
|
|||
|
* member-uris
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(CUPS_ADD_CLASS);
|
|||
|
|
|||
|
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
|
|||
|
"localhost", 0, "/classes/%s", name);
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
|
|||
|
NULL, uri);
|
|||
|
|
|||
|
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
|
|||
|
NULL, cgiGetVariable("PRINTER_LOCATION"));
|
|||
|
|
|||
|
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
|
|||
|
NULL, cgiGetVariable("PRINTER_INFO"));
|
|||
|
|
|||
|
ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
|
|||
|
|
|||
|
ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
|
|||
|
IPP_PRINTER_IDLE);
|
|||
|
|
|||
|
if ((num_printers = cgiGetSize("MEMBER_URIS")) > 0)
|
|||
|
{
|
|||
|
attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris",
|
|||
|
num_printers, NULL, NULL);
|
|||
|
for (i = 0; i < num_printers; i ++)
|
|||
|
ippSetString(request, &attr, i, cgiGetArray("MEMBER_URIS", i));
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Do the request and get back a response...
|
|||
|
*/
|
|||
|
|
|||
|
ippDelete(cupsDoRequest(http, request, "/admin/"));
|
|||
|
|
|||
|
if (cupsLastError() == IPP_NOT_AUTHORIZED)
|
|||
|
{
|
|||
|
puts("Status: 401\n");
|
|||
|
exit(0);
|
|||
|
}
|
|||
|
else if (cupsLastError() > IPP_OK_CONFLICT)
|
|||
|
{
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiShowIPPError(modify ? _("Unable to modify class") :
|
|||
|
_("Unable to add class"));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Redirect successful updates back to the class page...
|
|||
|
*/
|
|||
|
|
|||
|
char refresh[1024]; /* Refresh URL */
|
|||
|
|
|||
|
cgiFormEncode(uri, name, sizeof(uri));
|
|||
|
snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/classes/%s",
|
|||
|
uri);
|
|||
|
cgiSetVariable("refresh_page", refresh);
|
|||
|
|
|||
|
cgiStartHTML(title);
|
|||
|
|
|||
|
if (modify)
|
|||
|
cgiCopyTemplateLang("class-modified.tmpl");
|
|||
|
else
|
|||
|
cgiCopyTemplateLang("class-added.tmpl");
|
|||
|
}
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'do_am_printer()' - Add or modify a printer.
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
do_am_printer(http_t *http, /* I - HTTP connection */
|
|||
|
int modify) /* I - Modify the printer? */
|
|||
|
{
|
|||
|
int i; /* Looping var */
|
|||
|
ipp_attribute_t *attr; /* Current attribute */
|
|||
|
ipp_t *request, /* IPP request */
|
|||
|
*response, /* IPP response */
|
|||
|
*oldinfo; /* Old printer information */
|
|||
|
const cgi_file_t *file; /* Uploaded file, if any */
|
|||
|
const char *var; /* CGI variable */
|
|||
|
char uri[HTTP_MAX_URI], /* Device or printer URI */
|
|||
|
*uriptr, /* Pointer into URI */
|
|||
|
evefile[1024] = ""; /* IPP Everywhere PPD file */
|
|||
|
int maxrate; /* Maximum baud rate */
|
|||
|
char baudrate[255]; /* Baud rate string */
|
|||
|
const char *name, /* Pointer to class name */
|
|||
|
*ptr; /* Pointer to CGI variable */
|
|||
|
const char *title; /* Title of page */
|
|||
|
static int baudrates[] = /* Baud rates */
|
|||
|
{
|
|||
|
1200,
|
|||
|
2400,
|
|||
|
4800,
|
|||
|
9600,
|
|||
|
19200,
|
|||
|
38400,
|
|||
|
57600,
|
|||
|
115200,
|
|||
|
230400,
|
|||
|
460800
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
ptr = cgiGetVariable("DEVICE_URI");
|
|||
|
fprintf(stderr, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n",
|
|||
|
ptr ? ptr : "(null)");
|
|||
|
|
|||
|
title = cgiText(modify ? _("Modify Printer") : _("Add Printer"));
|
|||
|
|
|||
|
if (modify)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
|
|||
|
* following attributes:
|
|||
|
*
|
|||
|
* attributes-charset
|
|||
|
* attributes-natural-language
|
|||
|
* printer-uri
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
|
|||
|
|
|||
|
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
|
|||
|
"localhost", 0, "/printers/%s",
|
|||
|
cgiGetVariable("PRINTER_NAME"));
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
|
|||
|
NULL, uri);
|
|||
|
|
|||
|
/*
|
|||
|
* Do the request and get back a response...
|
|||
|
*/
|
|||
|
|
|||
|
oldinfo = cupsDoRequest(http, request, "/");
|
|||
|
}
|
|||
|
else
|
|||
|
oldinfo = NULL;
|
|||
|
|
|||
|
file = cgiGetFile();
|
|||
|
|
|||
|
if (file)
|
|||
|
{
|
|||
|
fprintf(stderr, "DEBUG: file->tempfile=%s\n", file->tempfile);
|
|||
|
fprintf(stderr, "DEBUG: file->name=%s\n", file->name);
|
|||
|
fprintf(stderr, "DEBUG: file->filename=%s\n", file->filename);
|
|||
|
fprintf(stderr, "DEBUG: file->mimetype=%s\n", file->mimetype);
|
|||
|
}
|
|||
|
|
|||
|
if ((name = cgiGetVariable("PRINTER_NAME")) != NULL)
|
|||
|
{
|
|||
|
for (ptr = name; *ptr; ptr ++)
|
|||
|
if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '\\' || *ptr == '?' || *ptr == '\'' || *ptr == '\"' || *ptr == '#')
|
|||
|
break;
|
|||
|
|
|||
|
if (*ptr || ptr == name || strlen(name) > 127)
|
|||
|
{
|
|||
|
cgiSetVariable("ERROR",
|
|||
|
cgiText(_("The printer name may only contain up to 127 printable characters and may not contain spaces, slashes (/ \\), quotes (' \"), question mark (?), or the pound sign (#).")));
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((var = cgiGetVariable("DEVICE_URI")) != NULL)
|
|||
|
{
|
|||
|
if ((uriptr = strrchr(var, '|')) != NULL)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Extract make and make/model from device URI string...
|
|||
|
*/
|
|||
|
|
|||
|
char make[1024], /* Make string */
|
|||
|
*makeptr; /* Pointer into make */
|
|||
|
|
|||
|
|
|||
|
*uriptr++ = '\0';
|
|||
|
|
|||
|
strlcpy(make, uriptr, sizeof(make));
|
|||
|
|
|||
|
if ((makeptr = strchr(make, ' ')) != NULL)
|
|||
|
*makeptr = '\0';
|
|||
|
else if ((makeptr = strchr(make, '-')) != NULL)
|
|||
|
*makeptr = '\0';
|
|||
|
else if (!_cups_strncasecmp(make, "laserjet", 8) ||
|
|||
|
!_cups_strncasecmp(make, "deskjet", 7) ||
|
|||
|
!_cups_strncasecmp(make, "designjet", 9))
|
|||
|
strlcpy(make, "HP", sizeof(make));
|
|||
|
else if (!_cups_strncasecmp(make, "phaser", 6))
|
|||
|
strlcpy(make, "Xerox", sizeof(make));
|
|||
|
else if (!_cups_strncasecmp(make, "stylus", 6))
|
|||
|
strlcpy(make, "Epson", sizeof(make));
|
|||
|
else
|
|||
|
strlcpy(make, "Generic", sizeof(make));
|
|||
|
|
|||
|
if (!cgiGetVariable("CURRENT_MAKE"))
|
|||
|
cgiSetVariable("CURRENT_MAKE", make);
|
|||
|
|
|||
|
if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL"))
|
|||
|
cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr);
|
|||
|
|
|||
|
if (!modify)
|
|||
|
{
|
|||
|
char template[128], /* Template name */
|
|||
|
*tptr; /* Pointer into template name */
|
|||
|
|
|||
|
cgiSetVariable("PRINTER_INFO", uriptr);
|
|||
|
|
|||
|
for (tptr = template;
|
|||
|
tptr < (template + sizeof(template) - 1) && *uriptr;
|
|||
|
uriptr ++)
|
|||
|
if (isalnum(*uriptr & 255) || *uriptr == '_' || *uriptr == '-' ||
|
|||
|
*uriptr == '.')
|
|||
|
*tptr++ = *uriptr;
|
|||
|
else if ((*uriptr == ' ' || *uriptr == '/') && tptr > template &&
|
|||
|
tptr[-1] != '_')
|
|||
|
*tptr++ = '_';
|
|||
|
else if (*uriptr == '?' || *uriptr == '(')
|
|||
|
break;
|
|||
|
|
|||
|
*tptr = '\0';
|
|||
|
|
|||
|
cgiSetVariable("TEMPLATE_NAME", template);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!var)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Look for devices so the user can pick something...
|
|||
|
*/
|
|||
|
|
|||
|
if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
|
|||
|
{
|
|||
|
strlcpy(uri, attr->values[0].string.text, sizeof(uri));
|
|||
|
if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0)
|
|||
|
*uriptr = '\0';
|
|||
|
|
|||
|
cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text);
|
|||
|
cgiSetVariable("CURRENT_DEVICE_SCHEME", uri);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Scan for devices for up to 30 seconds...
|
|||
|
*/
|
|||
|
|
|||
|
fputs("DEBUG: Getting list of devices...\n", stderr);
|
|||
|
|
|||
|
current_device = 0;
|
|||
|
if (cupsGetDevices(http, 5, CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE,
|
|||
|
(cups_device_cb_t)choose_device_cb,
|
|||
|
(void *)title) == IPP_OK)
|
|||
|
{
|
|||
|
fputs("DEBUG: Got device list!\n", stderr);
|
|||
|
|
|||
|
if (cgiSupportsMultipart())
|
|||
|
cgiStartMultipart();
|
|||
|
|
|||
|
cgiSetVariable("CUPS_GET_DEVICES_DONE", "1");
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiCopyTemplateLang("choose-device.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
|
|||
|
if (cgiSupportsMultipart())
|
|||
|
cgiEndMultipart();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
fprintf(stderr,
|
|||
|
"ERROR: CUPS-Get-Devices request failed with status %x: %s\n",
|
|||
|
cupsLastError(), cupsLastErrorString());
|
|||
|
if (cupsLastError() == IPP_NOT_AUTHORIZED)
|
|||
|
{
|
|||
|
puts("Status: 401\n");
|
|||
|
exit(0);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiShowIPPError(modify ? _("Unable to modify printer") :
|
|||
|
_("Unable to add printer"));
|
|||
|
cgiEndHTML();
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else if (!strchr(var, '/') ||
|
|||
|
(!strncmp(var, "lpd://", 6) && !strchr(var + 6, '/')))
|
|||
|
{
|
|||
|
if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Set the current device URI for the form to the old one...
|
|||
|
*/
|
|||
|
|
|||
|
if (strncmp(attr->values[0].string.text, var, strlen(var)) == 0)
|
|||
|
cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* User needs to set the full URI...
|
|||
|
*/
|
|||
|
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiCopyTemplateLang("choose-uri.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
else if (!strncmp(var, "serial:", 7) && !cgiGetVariable("BAUDRATE"))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Need baud rate, parity, etc.
|
|||
|
*/
|
|||
|
|
|||
|
if ((var = strchr(var, '?')) != NULL &&
|
|||
|
strncmp(var, "?baud=", 6) == 0)
|
|||
|
maxrate = atoi(var + 6);
|
|||
|
else
|
|||
|
maxrate = 19200;
|
|||
|
|
|||
|
for (i = 0; i < 10; i ++)
|
|||
|
if (baudrates[i] > maxrate)
|
|||
|
break;
|
|||
|
else
|
|||
|
{
|
|||
|
sprintf(baudrate, "%d", baudrates[i]);
|
|||
|
cgiSetArray("BAUDRATES", i, baudrate);
|
|||
|
}
|
|||
|
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiCopyTemplateLang("choose-serial.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
else if (!name || !cgiGetVariable("PRINTER_LOCATION"))
|
|||
|
{
|
|||
|
cgiStartHTML(title);
|
|||
|
|
|||
|
if (modify)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Update the location and description of an existing printer...
|
|||
|
*/
|
|||
|
|
|||
|
if (oldinfo)
|
|||
|
{
|
|||
|
if ((attr = ippFindAttribute(oldinfo, "printer-info",
|
|||
|
IPP_TAG_TEXT)) != NULL)
|
|||
|
cgiSetVariable("PRINTER_INFO", attr->values[0].string.text);
|
|||
|
|
|||
|
if ((attr = ippFindAttribute(oldinfo, "printer-location",
|
|||
|
IPP_TAG_TEXT)) != NULL)
|
|||
|
cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text);
|
|||
|
|
|||
|
if ((attr = ippFindAttribute(oldinfo, "printer-is-shared",
|
|||
|
IPP_TAG_BOOLEAN)) != NULL)
|
|||
|
cgiSetVariable("PRINTER_IS_SHARED",
|
|||
|
attr->values[0].boolean ? "1" : "0");
|
|||
|
}
|
|||
|
|
|||
|
cgiCopyTemplateLang("modify-printer.tmpl");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Get the name, location, and description for a new printer...
|
|||
|
*/
|
|||
|
|
|||
|
#ifdef __APPLE__
|
|||
|
if (!strncmp(var, "usb:", 4))
|
|||
|
cgiSetVariable("printer_is_shared", "1");
|
|||
|
else
|
|||
|
#endif /* __APPLE__ */
|
|||
|
cgiSetVariable("printer_is_shared", "0");
|
|||
|
|
|||
|
cgiCopyTemplateLang("add-printer.tmpl");
|
|||
|
}
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
|
|||
|
if (oldinfo)
|
|||
|
ippDelete(oldinfo);
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
else if (!file &&
|
|||
|
(!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE")))
|
|||
|
{
|
|||
|
int ipp_everywhere = !strncmp(var, "ipp://", 6) || !strncmp(var, "ipps://", 7) || (!strncmp(var, "dnssd://", 8) && (strstr(var, "_ipp._tcp") || strstr(var, "_ipps._tcp")));
|
|||
|
|
|||
|
if (modify && !cgiGetVariable("SELECT_MAKE"))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Get the PPD file...
|
|||
|
*/
|
|||
|
|
|||
|
int fd; /* PPD file */
|
|||
|
char filename[1024]; /* PPD filename */
|
|||
|
ppd_file_t *ppd; /* PPD information */
|
|||
|
char buffer[1024]; /* Buffer */
|
|||
|
ssize_t bytes; /* Number of bytes */
|
|||
|
http_status_t get_status; /* Status of GET */
|
|||
|
|
|||
|
|
|||
|
/* TODO: Use cupsGetFile() API... */
|
|||
|
snprintf(uri, sizeof(uri), "/printers/%s.ppd", name);
|
|||
|
|
|||
|
if (httpGet(http, uri))
|
|||
|
httpGet(http, uri);
|
|||
|
|
|||
|
while ((get_status = httpUpdate(http)) == HTTP_CONTINUE);
|
|||
|
|
|||
|
if (get_status != HTTP_OK)
|
|||
|
{
|
|||
|
httpFlush(http);
|
|||
|
|
|||
|
fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n",
|
|||
|
uri, get_status, httpStatus(get_status));
|
|||
|
}
|
|||
|
else if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0)
|
|||
|
{
|
|||
|
while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
|
|||
|
write(fd, buffer, (size_t)bytes);
|
|||
|
|
|||
|
close(fd);
|
|||
|
|
|||
|
if ((ppd = ppdOpenFile(filename)) != NULL)
|
|||
|
{
|
|||
|
if (ppd->manufacturer)
|
|||
|
cgiSetVariable("CURRENT_MAKE", ppd->manufacturer);
|
|||
|
|
|||
|
if (ppd->nickname)
|
|||
|
cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd->nickname);
|
|||
|
|
|||
|
ppdClose(ppd);
|
|||
|
unlink(filename);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
int linenum; /* Line number */
|
|||
|
|
|||
|
fprintf(stderr, "ERROR: Unable to open PPD file %s: %s\n",
|
|||
|
filename, ppdErrorString(ppdLastError(&linenum)));
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
httpFlush(http);
|
|||
|
|
|||
|
fprintf(stderr,
|
|||
|
"ERROR: Unable to create temporary file for PPD file: %s\n",
|
|||
|
strerror(errno));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Build a CUPS_GET_PPDS request, which requires the following
|
|||
|
* attributes:
|
|||
|
*
|
|||
|
* attributes-charset
|
|||
|
* attributes-natural-language
|
|||
|
* printer-uri
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(CUPS_GET_PPDS);
|
|||
|
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
|
|||
|
NULL, "ipp://localhost/printers/");
|
|||
|
|
|||
|
if ((var = cgiGetVariable("PPD_MAKE")) == NULL)
|
|||
|
var = cgiGetVariable("CURRENT_MAKE");
|
|||
|
if (var && !cgiGetVariable("SELECT_MAKE"))
|
|||
|
{
|
|||
|
const char *make_model; /* Make and model */
|
|||
|
|
|||
|
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
|
|||
|
"ppd-make", NULL, var);
|
|||
|
|
|||
|
if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL)
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
|
|||
|
"ppd-make-and-model", NULL, make_model);
|
|||
|
}
|
|||
|
else
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
|
|||
|
"requested-attributes", NULL, "ppd-make");
|
|||
|
|
|||
|
/*
|
|||
|
* Do the request and get back a response...
|
|||
|
*/
|
|||
|
|
|||
|
if ((response = cupsDoRequest(http, request, "/")) != NULL)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Got the list of PPDs, see if the user has selected a make...
|
|||
|
*/
|
|||
|
|
|||
|
if (cgiSetIPPVars(response, NULL, NULL, NULL, 0) == 0 && !modify)
|
|||
|
{
|
|||
|
/*
|
|||
|
* No PPD files with this make, try again with all makes...
|
|||
|
*/
|
|||
|
|
|||
|
ippDelete(response);
|
|||
|
|
|||
|
request = ippNewRequest(CUPS_GET_PPDS);
|
|||
|
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
|
|||
|
NULL, "ipp://localhost/printers/");
|
|||
|
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
|
|||
|
"requested-attributes", NULL, "ppd-make");
|
|||
|
|
|||
|
if ((response = cupsDoRequest(http, request, "/")) != NULL)
|
|||
|
cgiSetIPPVars(response, NULL, NULL, NULL, 0);
|
|||
|
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiCopyTemplateLang("choose-make.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
else if (!var || cgiGetVariable("SELECT_MAKE"))
|
|||
|
{
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiCopyTemplateLang("choose-make.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Let the user choose a model...
|
|||
|
*/
|
|||
|
|
|||
|
cgiStartHTML(title);
|
|||
|
if (!cgiGetVariable("PPD_MAKE"))
|
|||
|
cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE"));
|
|||
|
if (ipp_everywhere)
|
|||
|
cgiSetVariable("SHOW_IPP_EVERYWHERE", "1");
|
|||
|
cgiCopyTemplateLang("choose-model.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
|
|||
|
ippDelete(response);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiShowIPPError(_("Unable to get list of printer drivers"));
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Build a CUPS_ADD_PRINTER request, which requires the following
|
|||
|
* attributes:
|
|||
|
*
|
|||
|
* attributes-charset
|
|||
|
* attributes-natural-language
|
|||
|
* printer-uri
|
|||
|
* printer-location
|
|||
|
* printer-info
|
|||
|
* ppd-name
|
|||
|
* device-uri
|
|||
|
* printer-is-accepting-jobs
|
|||
|
* printer-is-shared
|
|||
|
* printer-state
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(CUPS_ADD_PRINTER);
|
|||
|
|
|||
|
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
|
|||
|
"localhost", 0, "/printers/%s",
|
|||
|
cgiGetVariable("PRINTER_NAME"));
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
|
|||
|
NULL, uri);
|
|||
|
|
|||
|
if (!file)
|
|||
|
{
|
|||
|
var = cgiGetVariable("PPD_NAME");
|
|||
|
if (!strcmp(var, "everywhere"))
|
|||
|
get_printer_ppd(cgiGetVariable("DEVICE_URI"), evefile, sizeof(evefile));
|
|||
|
else if (strcmp(var, "__no_change__"))
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name",
|
|||
|
NULL, var);
|
|||
|
}
|
|||
|
|
|||
|
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
|
|||
|
NULL, cgiGetVariable("PRINTER_LOCATION"));
|
|||
|
|
|||
|
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
|
|||
|
NULL, cgiGetVariable("PRINTER_INFO"));
|
|||
|
|
|||
|
strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri));
|
|||
|
|
|||
|
/*
|
|||
|
* Strip make and model from URI...
|
|||
|
*/
|
|||
|
|
|||
|
if ((uriptr = strrchr(uri, '|')) != NULL)
|
|||
|
*uriptr = '\0';
|
|||
|
|
|||
|
if (!strncmp(uri, "serial:", 7))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Update serial port URI to include baud rate, etc.
|
|||
|
*/
|
|||
|
|
|||
|
if ((uriptr = strchr(uri, '?')) == NULL)
|
|||
|
uriptr = uri + strlen(uri);
|
|||
|
|
|||
|
snprintf(uriptr, sizeof(uri) - (size_t)(uriptr - uri),
|
|||
|
"?baud=%s+bits=%s+parity=%s+flow=%s",
|
|||
|
cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"),
|
|||
|
cgiGetVariable("PARITY"), cgiGetVariable("FLOW"));
|
|||
|
}
|
|||
|
|
|||
|
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri",
|
|||
|
NULL, uri);
|
|||
|
|
|||
|
ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1);
|
|||
|
|
|||
|
var = cgiGetVariable("printer_is_shared");
|
|||
|
ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-shared",
|
|||
|
var && (!strcmp(var, "1") || !strcmp(var, "on")));
|
|||
|
|
|||
|
ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
|
|||
|
IPP_PRINTER_IDLE);
|
|||
|
|
|||
|
/*
|
|||
|
* Do the request and get back a response...
|
|||
|
*/
|
|||
|
|
|||
|
if (file)
|
|||
|
ippDelete(cupsDoFileRequest(http, request, "/admin/", file->tempfile));
|
|||
|
else if (evefile[0])
|
|||
|
{
|
|||
|
ippDelete(cupsDoFileRequest(http, request, "/admin/", evefile));
|
|||
|
unlink(evefile);
|
|||
|
}
|
|||
|
else
|
|||
|
ippDelete(cupsDoRequest(http, request, "/admin/"));
|
|||
|
|
|||
|
if (cupsLastError() == IPP_NOT_AUTHORIZED)
|
|||
|
{
|
|||
|
puts("Status: 401\n");
|
|||
|
exit(0);
|
|||
|
}
|
|||
|
else if (cupsLastError() > IPP_OK_CONFLICT)
|
|||
|
{
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiShowIPPError(modify ? _("Unable to modify printer") :
|
|||
|
_("Unable to add printer"));
|
|||
|
}
|
|||
|
else if (modify)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Redirect successful updates back to the printer page...
|
|||
|
*/
|
|||
|
|
|||
|
char refresh[1024]; /* Refresh URL */
|
|||
|
|
|||
|
|
|||
|
cgiFormEncode(uri, name, sizeof(uri));
|
|||
|
|
|||
|
snprintf(refresh, sizeof(refresh),
|
|||
|
"5;/admin/?OP=redirect&URL=/printers/%s", uri);
|
|||
|
|
|||
|
cgiSetVariable("refresh_page", refresh);
|
|||
|
|
|||
|
cgiStartHTML(title);
|
|||
|
|
|||
|
cgiCopyTemplateLang("printer-modified.tmpl");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Set the printer options...
|
|||
|
*/
|
|||
|
|
|||
|
cgiSetVariable("OP", "set-printer-options");
|
|||
|
do_set_options(http, 0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
|
|||
|
if (oldinfo)
|
|||
|
ippDelete(oldinfo);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'do_config_server()' - Configure server settings.
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
do_config_server(http_t *http) /* I - HTTP connection */
|
|||
|
{
|
|||
|
if (cgiGetVariable("CHANGESETTINGS"))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Save basic setting changes...
|
|||
|
*/
|
|||
|
|
|||
|
int num_settings; /* Number of server settings */
|
|||
|
cups_option_t *settings; /* Server settings */
|
|||
|
int advanced, /* Advanced settings shown? */
|
|||
|
changed; /* Have settings changed? */
|
|||
|
const char *debug_logging, /* DEBUG_LOGGING value */
|
|||
|
*preserve_jobs = NULL,
|
|||
|
/* PRESERVE_JOBS value */
|
|||
|
*remote_admin, /* REMOTE_ADMIN value */
|
|||
|
*remote_any, /* REMOTE_ANY value */
|
|||
|
*share_printers,/* SHARE_PRINTERS value */
|
|||
|
*user_cancel_any,
|
|||
|
/* USER_CANCEL_ANY value */
|
|||
|
*browse_web_if = NULL,
|
|||
|
/* BrowseWebIF value */
|
|||
|
*preserve_job_history = NULL,
|
|||
|
/* PreserveJobHistory value */
|
|||
|
*preserve_job_files = NULL,
|
|||
|
/* PreserveJobFiles value */
|
|||
|
*max_clients = NULL,
|
|||
|
/* MaxClients value */
|
|||
|
*max_jobs = NULL,
|
|||
|
/* MaxJobs value */
|
|||
|
*max_log_size = NULL;
|
|||
|
/* MaxLogSize value */
|
|||
|
const char *current_browse_web_if,
|
|||
|
/* BrowseWebIF value */
|
|||
|
*current_preserve_job_history,
|
|||
|
/* PreserveJobHistory value */
|
|||
|
*current_preserve_job_files,
|
|||
|
/* PreserveJobFiles value */
|
|||
|
*current_max_clients,
|
|||
|
/* MaxClients value */
|
|||
|
*current_max_jobs,
|
|||
|
/* MaxJobs value */
|
|||
|
*current_max_log_size;
|
|||
|
/* MaxLogSize value */
|
|||
|
#ifdef HAVE_GSSAPI
|
|||
|
char default_auth_type[255];
|
|||
|
/* DefaultAuthType value */
|
|||
|
const char *val; /* Setting value */
|
|||
|
#endif /* HAVE_GSSAPI */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Get the checkbox values from the form...
|
|||
|
*/
|
|||
|
|
|||
|
debug_logging = cgiGetVariable("DEBUG_LOGGING") ? "1" : "0";
|
|||
|
remote_admin = cgiGetVariable("REMOTE_ADMIN") ? "1" : "0";
|
|||
|
remote_any = cgiGetVariable("REMOTE_ANY") ? "1" : "0";
|
|||
|
share_printers = cgiGetVariable("SHARE_PRINTERS") ? "1" : "0";
|
|||
|
user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0";
|
|||
|
|
|||
|
advanced = cgiGetVariable("ADVANCEDSETTINGS") != NULL;
|
|||
|
if (advanced)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Get advanced settings...
|
|||
|
*/
|
|||
|
|
|||
|
browse_web_if = cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No";
|
|||
|
max_clients = cgiGetVariable("MAX_CLIENTS");
|
|||
|
max_log_size = cgiGetVariable("MAX_LOG_SIZE");
|
|||
|
preserve_jobs = cgiGetVariable("PRESERVE_JOBS");
|
|||
|
|
|||
|
if (preserve_jobs)
|
|||
|
{
|
|||
|
max_jobs = cgiGetVariable("MAX_JOBS");
|
|||
|
preserve_job_history = cgiGetVariable("PRESERVE_JOB_HISTORY");
|
|||
|
preserve_job_files = cgiGetVariable("PRESERVE_JOB_FILES");
|
|||
|
|
|||
|
if (!max_jobs || atoi(max_jobs) < 0)
|
|||
|
max_jobs = "500";
|
|||
|
|
|||
|
if (!preserve_job_history)
|
|||
|
preserve_job_history = "On";
|
|||
|
|
|||
|
if (!preserve_job_files)
|
|||
|
preserve_job_files = "1d";
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
max_jobs = "0";
|
|||
|
preserve_job_history = "No";
|
|||
|
preserve_job_files = "No";
|
|||
|
}
|
|||
|
|
|||
|
if (!max_clients || atoi(max_clients) <= 0)
|
|||
|
max_clients = "100";
|
|||
|
|
|||
|
if (!max_log_size || atoi(max_log_size) <= 0.0)
|
|||
|
max_log_size = "1m";
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Get the current server settings...
|
|||
|
*/
|
|||
|
|
|||
|
if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
|
|||
|
{
|
|||
|
cgiStartHTML(cgiText(_("Change Settings")));
|
|||
|
cgiSetVariable("MESSAGE",
|
|||
|
cgiText(_("Unable to change server settings")));
|
|||
|
cgiSetVariable("ERROR", cupsLastErrorString());
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
#ifdef HAVE_GSSAPI
|
|||
|
/*
|
|||
|
* Get authentication settings...
|
|||
|
*/
|
|||
|
|
|||
|
if (cgiGetVariable("KERBEROS"))
|
|||
|
strlcpy(default_auth_type, "Negotiate", sizeof(default_auth_type));
|
|||
|
else
|
|||
|
{
|
|||
|
val = cupsGetOption("DefaultAuthType", num_settings, settings);
|
|||
|
|
|||
|
if (!val || !_cups_strcasecmp(val, "Negotiate"))
|
|||
|
strlcpy(default_auth_type, "Basic", sizeof(default_auth_type));
|
|||
|
else
|
|||
|
strlcpy(default_auth_type, val, sizeof(default_auth_type));
|
|||
|
}
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG: DefaultAuthType %s\n", default_auth_type);
|
|||
|
#endif /* HAVE_GSSAPI */
|
|||
|
|
|||
|
if ((current_browse_web_if = cupsGetOption("BrowseWebIF", num_settings,
|
|||
|
settings)) == NULL)
|
|||
|
current_browse_web_if = "No";
|
|||
|
|
|||
|
if ((current_preserve_job_history = cupsGetOption("PreserveJobHistory",
|
|||
|
num_settings,
|
|||
|
settings)) == NULL)
|
|||
|
current_preserve_job_history = "Yes";
|
|||
|
|
|||
|
if ((current_preserve_job_files = cupsGetOption("PreserveJobFiles",
|
|||
|
num_settings,
|
|||
|
settings)) == NULL)
|
|||
|
current_preserve_job_files = "1d";
|
|||
|
|
|||
|
if ((current_max_clients = cupsGetOption("MaxClients", num_settings,
|
|||
|
settings)) == NULL)
|
|||
|
current_max_clients = "100";
|
|||
|
|
|||
|
if ((current_max_jobs = cupsGetOption("MaxJobs", num_settings,
|
|||
|
settings)) == NULL)
|
|||
|
current_max_jobs = "500";
|
|||
|
|
|||
|
if ((current_max_log_size = cupsGetOption("MaxLogSize", num_settings,
|
|||
|
settings)) == NULL)
|
|||
|
current_max_log_size = "1m";
|
|||
|
|
|||
|
/*
|
|||
|
* See if the settings have changed...
|
|||
|
*/
|
|||
|
|
|||
|
changed = strcmp(debug_logging, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING,
|
|||
|
num_settings, settings)) ||
|
|||
|
strcmp(remote_admin, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN,
|
|||
|
num_settings, settings)) ||
|
|||
|
strcmp(remote_any, cupsGetOption(CUPS_SERVER_REMOTE_ANY,
|
|||
|
num_settings, settings)) ||
|
|||
|
strcmp(share_printers, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS,
|
|||
|
num_settings, settings)) ||
|
|||
|
#ifdef HAVE_GSSAPI
|
|||
|
!cupsGetOption("DefaultAuthType", num_settings, settings) ||
|
|||
|
strcmp(default_auth_type, cupsGetOption("DefaultAuthType",
|
|||
|
num_settings, settings)) ||
|
|||
|
#endif /* HAVE_GSSAPI */
|
|||
|
strcmp(user_cancel_any, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY,
|
|||
|
num_settings, settings));
|
|||
|
|
|||
|
if (advanced && !changed)
|
|||
|
changed = _cups_strcasecmp(browse_web_if, current_browse_web_if) ||
|
|||
|
_cups_strcasecmp(preserve_job_history, current_preserve_job_history) ||
|
|||
|
_cups_strcasecmp(preserve_job_files, current_preserve_job_files) ||
|
|||
|
_cups_strcasecmp(max_clients, current_max_clients) ||
|
|||
|
_cups_strcasecmp(max_jobs, current_max_jobs) ||
|
|||
|
_cups_strcasecmp(max_log_size, current_max_log_size);
|
|||
|
|
|||
|
if (changed)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Settings *have* changed, so save the changes...
|
|||
|
*/
|
|||
|
|
|||
|
cupsFreeOptions(num_settings, settings);
|
|||
|
|
|||
|
num_settings = 0;
|
|||
|
num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING,
|
|||
|
debug_logging, num_settings, &settings);
|
|||
|
num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN,
|
|||
|
remote_admin, num_settings, &settings);
|
|||
|
num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY,
|
|||
|
remote_any, num_settings, &settings);
|
|||
|
num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS,
|
|||
|
share_printers, num_settings, &settings);
|
|||
|
num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY,
|
|||
|
user_cancel_any, num_settings, &settings);
|
|||
|
#ifdef HAVE_GSSAPI
|
|||
|
num_settings = cupsAddOption("DefaultAuthType", default_auth_type,
|
|||
|
num_settings, &settings);
|
|||
|
#endif /* HAVE_GSSAPI */
|
|||
|
|
|||
|
if (advanced)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Add advanced settings...
|
|||
|
*/
|
|||
|
|
|||
|
if (_cups_strcasecmp(browse_web_if, current_browse_web_if))
|
|||
|
num_settings = cupsAddOption("BrowseWebIF", browse_web_if,
|
|||
|
num_settings, &settings);
|
|||
|
if (_cups_strcasecmp(preserve_job_history, current_preserve_job_history))
|
|||
|
num_settings = cupsAddOption("PreserveJobHistory",
|
|||
|
preserve_job_history, num_settings,
|
|||
|
&settings);
|
|||
|
if (_cups_strcasecmp(preserve_job_files, current_preserve_job_files))
|
|||
|
num_settings = cupsAddOption("PreserveJobFiles", preserve_job_files,
|
|||
|
num_settings, &settings);
|
|||
|
if (_cups_strcasecmp(max_clients, current_max_clients))
|
|||
|
num_settings = cupsAddOption("MaxClients", max_clients, num_settings,
|
|||
|
&settings);
|
|||
|
if (_cups_strcasecmp(max_jobs, current_max_jobs))
|
|||
|
num_settings = cupsAddOption("MaxJobs", max_jobs, num_settings,
|
|||
|
&settings);
|
|||
|
if (_cups_strcasecmp(max_log_size, current_max_log_size))
|
|||
|
num_settings = cupsAddOption("MaxLogSize", max_log_size, num_settings,
|
|||
|
&settings);
|
|||
|
}
|
|||
|
|
|||
|
if (!cupsAdminSetServerSettings(http, num_settings, settings))
|
|||
|
{
|
|||
|
if (cupsLastError() == IPP_NOT_AUTHORIZED)
|
|||
|
{
|
|||
|
puts("Status: 401\n");
|
|||
|
exit(0);
|
|||
|
}
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("Change Settings")));
|
|||
|
cgiSetVariable("MESSAGE",
|
|||
|
cgiText(_("Unable to change server settings")));
|
|||
|
cgiSetVariable("ERROR", cupsLastErrorString());
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (advanced)
|
|||
|
cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&"
|
|||
|
"URL=/admin/?ADVANCEDSETTINGS=YES");
|
|||
|
else
|
|||
|
cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
|
|||
|
cgiStartHTML(cgiText(_("Change Settings")));
|
|||
|
cgiCopyTemplateLang("restart.tmpl");
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* No changes...
|
|||
|
*/
|
|||
|
|
|||
|
cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect");
|
|||
|
cgiStartHTML(cgiText(_("Change Settings")));
|
|||
|
cgiCopyTemplateLang("norestart.tmpl");
|
|||
|
}
|
|||
|
|
|||
|
cupsFreeOptions(num_settings, settings);
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF"))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Save hand-edited config file...
|
|||
|
*/
|
|||
|
|
|||
|
http_status_t status; /* PUT status */
|
|||
|
char tempfile[1024]; /* Temporary new cupsd.conf */
|
|||
|
int tempfd; /* Temporary file descriptor */
|
|||
|
cups_file_t *temp; /* Temporary file */
|
|||
|
const char *start, /* Start of line */
|
|||
|
*end; /* End of line */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Create a temporary file for the new cupsd.conf file...
|
|||
|
*/
|
|||
|
|
|||
|
if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
|
|||
|
{
|
|||
|
cgiStartHTML(cgiText(_("Edit Configuration File")));
|
|||
|
cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
|
|||
|
cgiSetVariable("ERROR", strerror(errno));
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
|
|||
|
perror(tempfile);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
|
|||
|
{
|
|||
|
cgiStartHTML(cgiText(_("Edit Configuration File")));
|
|||
|
cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file")));
|
|||
|
cgiSetVariable("ERROR", strerror(errno));
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
|
|||
|
perror(tempfile);
|
|||
|
close(tempfd);
|
|||
|
unlink(tempfile);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Copy the cupsd.conf text from the form variable...
|
|||
|
*/
|
|||
|
|
|||
|
start = cgiGetVariable("CUPSDCONF");
|
|||
|
while (start)
|
|||
|
{
|
|||
|
if ((end = strstr(start, "\r\n")) == NULL)
|
|||
|
if ((end = strstr(start, "\n")) == NULL)
|
|||
|
end = start + strlen(start);
|
|||
|
|
|||
|
cupsFileWrite(temp, start, (size_t)(end - start));
|
|||
|
cupsFilePutChar(temp, '\n');
|
|||
|
|
|||
|
if (*end == '\r')
|
|||
|
start = end + 2;
|
|||
|
else if (*end == '\n')
|
|||
|
start = end + 1;
|
|||
|
else
|
|||
|
start = NULL;
|
|||
|
}
|
|||
|
|
|||
|
cupsFileClose(temp);
|
|||
|
|
|||
|
/*
|
|||
|
* Upload the configuration file to the server...
|
|||
|
*/
|
|||
|
|
|||
|
status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile);
|
|||
|
|
|||
|
if (status == HTTP_UNAUTHORIZED)
|
|||
|
{
|
|||
|
puts("Status: 401\n");
|
|||
|
unlink(tempfile);
|
|||
|
exit(0);
|
|||
|
}
|
|||
|
else if (status != HTTP_CREATED)
|
|||
|
{
|
|||
|
cgiSetVariable("MESSAGE",
|
|||
|
cgiText(_("Unable to upload cupsd.conf file")));
|
|||
|
cgiSetVariable("ERROR", httpStatus(status));
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("Edit Configuration File")));
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
cgiSetVariable("refresh_page", "5;URL=/admin/");
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("Edit Configuration File")));
|
|||
|
cgiCopyTemplateLang("restart.tmpl");
|
|||
|
}
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
|
|||
|
unlink(tempfile);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
struct stat info; /* cupsd.conf information */
|
|||
|
cups_file_t *cupsd; /* cupsd.conf file */
|
|||
|
char *buffer, /* Buffer for entire file */
|
|||
|
*bufptr, /* Pointer into buffer */
|
|||
|
*bufend; /* End of buffer */
|
|||
|
int ch; /* Character from file */
|
|||
|
char filename[1024]; /* Filename */
|
|||
|
const char *server_root; /* Location of config files */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Locate the cupsd.conf file...
|
|||
|
*/
|
|||
|
|
|||
|
if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
|
|||
|
server_root = CUPS_SERVERROOT;
|
|||
|
|
|||
|
snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root);
|
|||
|
|
|||
|
/*
|
|||
|
* Figure out the size...
|
|||
|
*/
|
|||
|
|
|||
|
if (stat(filename, &info))
|
|||
|
{
|
|||
|
cgiStartHTML(cgiText(_("Edit Configuration File")));
|
|||
|
cgiSetVariable("MESSAGE",
|
|||
|
cgiText(_("Unable to access cupsd.conf file")));
|
|||
|
cgiSetVariable("ERROR", strerror(errno));
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
|
|||
|
perror(filename);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (info.st_size > (1024 * 1024))
|
|||
|
{
|
|||
|
cgiStartHTML(cgiText(_("Edit Configuration File")));
|
|||
|
cgiSetVariable("MESSAGE",
|
|||
|
cgiText(_("Unable to access cupsd.conf file")));
|
|||
|
cgiSetVariable("ERROR",
|
|||
|
cgiText(_("Unable to edit cupsd.conf files larger than "
|
|||
|
"1MB")));
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
|
|||
|
fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename,
|
|||
|
(long)info.st_size);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Open the cupsd.conf file...
|
|||
|
*/
|
|||
|
|
|||
|
if ((cupsd = cupsFileOpen(filename, "r")) == NULL)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Unable to open - log an error...
|
|||
|
*/
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("Edit Configuration File")));
|
|||
|
cgiSetVariable("MESSAGE",
|
|||
|
cgiText(_("Unable to access cupsd.conf file")));
|
|||
|
cgiSetVariable("ERROR", strerror(errno));
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
|
|||
|
perror(filename);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Allocate memory and load the file into a string buffer...
|
|||
|
*/
|
|||
|
|
|||
|
if ((buffer = calloc(1, (size_t)info.st_size + 1)) != NULL)
|
|||
|
{
|
|||
|
cupsFileRead(cupsd, buffer, (size_t)info.st_size);
|
|||
|
cgiSetVariable("CUPSDCONF", buffer);
|
|||
|
free(buffer);
|
|||
|
}
|
|||
|
|
|||
|
cupsFileClose(cupsd);
|
|||
|
|
|||
|
/*
|
|||
|
* Then get the default cupsd.conf file and put that into a string as
|
|||
|
* well...
|
|||
|
*/
|
|||
|
|
|||
|
strlcat(filename, ".default", sizeof(filename));
|
|||
|
|
|||
|
if (!stat(filename, &info) && info.st_size < (1024 * 1024) &&
|
|||
|
(cupsd = cupsFileOpen(filename, "r")) != NULL)
|
|||
|
{
|
|||
|
if ((buffer = calloc(1, 2 * (size_t)info.st_size + 1)) != NULL)
|
|||
|
{
|
|||
|
bufend = buffer + 2 * info.st_size - 1;
|
|||
|
|
|||
|
for (bufptr = buffer;
|
|||
|
bufptr < bufend && (ch = cupsFileGetChar(cupsd)) != EOF;)
|
|||
|
{
|
|||
|
if (ch == '\\' || ch == '\"')
|
|||
|
{
|
|||
|
*bufptr++ = '\\';
|
|||
|
*bufptr++ = (char)ch;
|
|||
|
}
|
|||
|
else if (ch == '\n')
|
|||
|
{
|
|||
|
*bufptr++ = '\\';
|
|||
|
*bufptr++ = 'n';
|
|||
|
}
|
|||
|
else if (ch == '\t')
|
|||
|
{
|
|||
|
*bufptr++ = '\\';
|
|||
|
*bufptr++ = 't';
|
|||
|
}
|
|||
|
else if (ch >= ' ')
|
|||
|
*bufptr++ = (char)ch;
|
|||
|
}
|
|||
|
|
|||
|
*bufptr = '\0';
|
|||
|
|
|||
|
cgiSetVariable("CUPSDCONF_DEFAULT", buffer);
|
|||
|
free(buffer);
|
|||
|
}
|
|||
|
|
|||
|
cupsFileClose(cupsd);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Show the current config file...
|
|||
|
*/
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("Edit Configuration File")));
|
|||
|
|
|||
|
cgiCopyTemplateLang("edit-config.tmpl");
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'do_delete_class()' - Delete a class.
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
do_delete_class(http_t *http) /* I - HTTP connection */
|
|||
|
{
|
|||
|
ipp_t *request; /* IPP request */
|
|||
|
char uri[HTTP_MAX_URI]; /* Job URI */
|
|||
|
const char *pclass; /* Printer class name */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Get form variables...
|
|||
|
*/
|
|||
|
|
|||
|
if (cgiGetVariable("CONFIRM") == NULL)
|
|||
|
{
|
|||
|
cgiStartHTML(cgiText(_("Delete Class")));
|
|||
|
cgiCopyTemplateLang("class-confirm.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL)
|
|||
|
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
|
|||
|
"localhost", 0, "/classes/%s", pclass);
|
|||
|
else
|
|||
|
{
|
|||
|
cgiStartHTML(cgiText(_("Delete Class")));
|
|||
|
cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Build a CUPS_DELETE_CLASS request, which requires the following
|
|||
|
* attributes:
|
|||
|
*
|
|||
|
* attributes-charset
|
|||
|
* attributes-natural-language
|
|||
|
* printer-uri
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(CUPS_DELETE_CLASS);
|
|||
|
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
|
|||
|
NULL, uri);
|
|||
|
|
|||
|
/*
|
|||
|
* Do the request and get back a response...
|
|||
|
*/
|
|||
|
|
|||
|
ippDelete(cupsDoRequest(http, request, "/admin/"));
|
|||
|
|
|||
|
/*
|
|||
|
* Show the results...
|
|||
|
*/
|
|||
|
|
|||
|
if (cupsLastError() == IPP_NOT_AUTHORIZED)
|
|||
|
{
|
|||
|
puts("Status: 401\n");
|
|||
|
exit(0);
|
|||
|
}
|
|||
|
else if (cupsLastError() <= IPP_OK_CONFLICT)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Redirect successful updates back to the classes page...
|
|||
|
*/
|
|||
|
|
|||
|
cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes");
|
|||
|
}
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("Delete Class")));
|
|||
|
|
|||
|
if (cupsLastError() > IPP_OK_CONFLICT)
|
|||
|
cgiShowIPPError(_("Unable to delete class"));
|
|||
|
else
|
|||
|
cgiCopyTemplateLang("class-deleted.tmpl");
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'do_delete_printer()' - Delete a printer.
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
do_delete_printer(http_t *http) /* I - HTTP connection */
|
|||
|
{
|
|||
|
ipp_t *request; /* IPP request */
|
|||
|
char uri[HTTP_MAX_URI]; /* Job URI */
|
|||
|
const char *printer; /* Printer printer name */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Get form variables...
|
|||
|
*/
|
|||
|
|
|||
|
if (cgiGetVariable("CONFIRM") == NULL)
|
|||
|
{
|
|||
|
cgiStartHTML(cgiText(_("Delete Printer")));
|
|||
|
cgiCopyTemplateLang("printer-confirm.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
|
|||
|
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
|
|||
|
"localhost", 0, "/printers/%s", printer);
|
|||
|
else
|
|||
|
{
|
|||
|
cgiStartHTML(cgiText(_("Delete Printer")));
|
|||
|
cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Build a CUPS_DELETE_PRINTER request, which requires the following
|
|||
|
* attributes:
|
|||
|
*
|
|||
|
* attributes-charset
|
|||
|
* attributes-natural-language
|
|||
|
* printer-uri
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(CUPS_DELETE_PRINTER);
|
|||
|
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
|
|||
|
NULL, uri);
|
|||
|
|
|||
|
/*
|
|||
|
* Do the request and get back a response...
|
|||
|
*/
|
|||
|
|
|||
|
ippDelete(cupsDoRequest(http, request, "/admin/"));
|
|||
|
|
|||
|
/*
|
|||
|
* Show the results...
|
|||
|
*/
|
|||
|
|
|||
|
if (cupsLastError() == IPP_NOT_AUTHORIZED)
|
|||
|
{
|
|||
|
puts("Status: 401\n");
|
|||
|
exit(0);
|
|||
|
}
|
|||
|
else if (cupsLastError() <= IPP_OK_CONFLICT)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Redirect successful updates back to the printers page...
|
|||
|
*/
|
|||
|
|
|||
|
cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers");
|
|||
|
}
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("Delete Printer")));
|
|||
|
|
|||
|
if (cupsLastError() > IPP_OK_CONFLICT)
|
|||
|
cgiShowIPPError(_("Unable to delete printer"));
|
|||
|
else
|
|||
|
cgiCopyTemplateLang("printer-deleted.tmpl");
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'do_list_printers()' - List available printers.
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
do_list_printers(http_t *http) /* I - HTTP connection */
|
|||
|
{
|
|||
|
ipp_t *request, /* IPP request */
|
|||
|
*response; /* IPP response */
|
|||
|
ipp_attribute_t *attr; /* IPP attribute */
|
|||
|
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("List Available Printers")));
|
|||
|
fflush(stdout);
|
|||
|
|
|||
|
/*
|
|||
|
* Get the list of printers and their devices...
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(CUPS_GET_PRINTERS);
|
|||
|
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
|
|||
|
"requested-attributes", NULL, "device-uri");
|
|||
|
|
|||
|
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
|
|||
|
CUPS_PRINTER_LOCAL);
|
|||
|
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
|
|||
|
CUPS_PRINTER_LOCAL);
|
|||
|
|
|||
|
if ((response = cupsDoRequest(http, request, "/")) != NULL)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Got the printer list, now load the devices...
|
|||
|
*/
|
|||
|
|
|||
|
int i; /* Looping var */
|
|||
|
cups_array_t *printer_devices; /* Printer devices for local printers */
|
|||
|
char *printer_device; /* Current printer device */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Allocate an array and copy the device strings...
|
|||
|
*/
|
|||
|
|
|||
|
printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL);
|
|||
|
|
|||
|
for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
|
|||
|
attr;
|
|||
|
attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
|
|||
|
{
|
|||
|
cupsArrayAdd(printer_devices, strdup(attr->values[0].string.text));
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Free the printer list and get the device list...
|
|||
|
*/
|
|||
|
|
|||
|
ippDelete(response);
|
|||
|
|
|||
|
request = ippNewRequest(CUPS_GET_DEVICES);
|
|||
|
|
|||
|
if ((response = cupsDoRequest(http, request, "/")) != NULL)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Got the device list, let's parse it...
|
|||
|
*/
|
|||
|
|
|||
|
const char *device_uri, /* device-uri attribute value */
|
|||
|
*device_make_and_model, /* device-make-and-model value */
|
|||
|
*device_info; /* device-info value */
|
|||
|
|
|||
|
|
|||
|
for (i = 0, attr = response->attrs; attr; attr = attr->next)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Skip leading attributes until we hit a device...
|
|||
|
*/
|
|||
|
|
|||
|
while (attr && attr->group_tag != IPP_TAG_PRINTER)
|
|||
|
attr = attr->next;
|
|||
|
|
|||
|
if (!attr)
|
|||
|
break;
|
|||
|
|
|||
|
/*
|
|||
|
* Pull the needed attributes from this device...
|
|||
|
*/
|
|||
|
|
|||
|
device_info = NULL;
|
|||
|
device_make_and_model = NULL;
|
|||
|
device_uri = NULL;
|
|||
|
|
|||
|
while (attr && attr->group_tag == IPP_TAG_PRINTER)
|
|||
|
{
|
|||
|
if (!strcmp(attr->name, "device-info") &&
|
|||
|
attr->value_tag == IPP_TAG_TEXT)
|
|||
|
device_info = attr->values[0].string.text;
|
|||
|
|
|||
|
if (!strcmp(attr->name, "device-make-and-model") &&
|
|||
|
attr->value_tag == IPP_TAG_TEXT)
|
|||
|
device_make_and_model = attr->values[0].string.text;
|
|||
|
|
|||
|
if (!strcmp(attr->name, "device-uri") &&
|
|||
|
attr->value_tag == IPP_TAG_URI)
|
|||
|
device_uri = attr->values[0].string.text;
|
|||
|
|
|||
|
attr = attr->next;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* See if we have everything needed...
|
|||
|
*/
|
|||
|
|
|||
|
if (device_info && device_make_and_model && device_uri &&
|
|||
|
_cups_strcasecmp(device_make_and_model, "unknown") &&
|
|||
|
strchr(device_uri, ':'))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Yes, now see if there is already a printer for this
|
|||
|
* device...
|
|||
|
*/
|
|||
|
|
|||
|
if (!cupsArrayFind(printer_devices, (void *)device_uri))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Not found, so it must be a new printer...
|
|||
|
*/
|
|||
|
|
|||
|
char option[1024], /* Form variables for this device */
|
|||
|
*option_ptr; /* Pointer into string */
|
|||
|
const char *ptr; /* Pointer into device string */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Format the printer name variable for this device...
|
|||
|
*
|
|||
|
* We use the device-info string first, then device-uri,
|
|||
|
* and finally device-make-and-model to come up with a
|
|||
|
* suitable name.
|
|||
|
*/
|
|||
|
|
|||
|
if (_cups_strncasecmp(device_info, "unknown", 7))
|
|||
|
ptr = device_info;
|
|||
|
else if ((ptr = strstr(device_uri, "://")) != NULL)
|
|||
|
ptr += 3;
|
|||
|
else
|
|||
|
ptr = device_make_and_model;
|
|||
|
|
|||
|
for (option_ptr = option;
|
|||
|
option_ptr < (option + sizeof(option) - 1) && *ptr;
|
|||
|
ptr ++)
|
|||
|
if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' ||
|
|||
|
*ptr == '.')
|
|||
|
*option_ptr++ = *ptr;
|
|||
|
else if ((*ptr == ' ' || *ptr == '/') && option_ptr > option &&
|
|||
|
option_ptr[-1] != '_')
|
|||
|
*option_ptr++ = '_';
|
|||
|
else if (*ptr == '?' || *ptr == '(')
|
|||
|
break;
|
|||
|
|
|||
|
*option_ptr = '\0';
|
|||
|
|
|||
|
cgiSetArray("TEMPLATE_NAME", i, option);
|
|||
|
|
|||
|
/*
|
|||
|
* Finally, set the form variables for this printer...
|
|||
|
*/
|
|||
|
|
|||
|
cgiSetArray("device_info", i, device_info);
|
|||
|
cgiSetArray("device_make_and_model", i, device_make_and_model);
|
|||
|
cgiSetArray("device_uri", i, device_uri);
|
|||
|
i ++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!attr)
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
ippDelete(response);
|
|||
|
|
|||
|
/*
|
|||
|
* Free the device list...
|
|||
|
*/
|
|||
|
|
|||
|
for (printer_device = (char *)cupsArrayFirst(printer_devices);
|
|||
|
printer_device;
|
|||
|
printer_device = (char *)cupsArrayNext(printer_devices))
|
|||
|
free(printer_device);
|
|||
|
|
|||
|
cupsArrayDelete(printer_devices);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Finally, show the printer list...
|
|||
|
*/
|
|||
|
|
|||
|
cgiCopyTemplateLang("list-available-printers.tmpl");
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'do_menu()' - Show the main menu.
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
do_menu(http_t *http) /* I - HTTP connection */
|
|||
|
{
|
|||
|
int num_settings; /* Number of server settings */
|
|||
|
cups_option_t *settings; /* Server settings */
|
|||
|
const char *val; /* Setting value */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Get the current server settings...
|
|||
|
*/
|
|||
|
|
|||
|
if (!cupsAdminGetServerSettings(http, &num_settings, &settings))
|
|||
|
{
|
|||
|
cgiSetVariable("SETTINGS_MESSAGE",
|
|||
|
cgiText(_("Unable to open cupsd.conf file:")));
|
|||
|
cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString());
|
|||
|
}
|
|||
|
|
|||
|
if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings,
|
|||
|
settings)) != NULL && atoi(val))
|
|||
|
cgiSetVariable("DEBUG_LOGGING", "CHECKED");
|
|||
|
|
|||
|
if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings,
|
|||
|
settings)) != NULL && atoi(val))
|
|||
|
cgiSetVariable("REMOTE_ADMIN", "CHECKED");
|
|||
|
|
|||
|
if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings,
|
|||
|
settings)) != NULL && atoi(val))
|
|||
|
cgiSetVariable("REMOTE_ANY", "CHECKED");
|
|||
|
|
|||
|
if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings,
|
|||
|
settings)) != NULL && atoi(val))
|
|||
|
cgiSetVariable("SHARE_PRINTERS", "CHECKED");
|
|||
|
|
|||
|
if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings,
|
|||
|
settings)) != NULL && atoi(val))
|
|||
|
cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
|
|||
|
|
|||
|
#ifdef HAVE_GSSAPI
|
|||
|
cgiSetVariable("HAVE_GSSAPI", "1");
|
|||
|
|
|||
|
if ((val = cupsGetOption("DefaultAuthType", num_settings,
|
|||
|
settings)) != NULL && !_cups_strcasecmp(val, "Negotiate"))
|
|||
|
cgiSetVariable("KERBEROS", "CHECKED");
|
|||
|
else
|
|||
|
#endif /* HAVE_GSSAPI */
|
|||
|
cgiSetVariable("KERBEROS", "");
|
|||
|
|
|||
|
if ((val = cupsGetOption("BrowseWebIF", num_settings,
|
|||
|
settings)) == NULL)
|
|||
|
val = "No";
|
|||
|
|
|||
|
if (!_cups_strcasecmp(val, "yes") || !_cups_strcasecmp(val, "on") ||
|
|||
|
!_cups_strcasecmp(val, "true"))
|
|||
|
cgiSetVariable("BROWSE_WEB_IF", "CHECKED");
|
|||
|
|
|||
|
if ((val = cupsGetOption("PreserveJobHistory", num_settings,
|
|||
|
settings)) == NULL)
|
|||
|
val = "Yes";
|
|||
|
|
|||
|
if (val &&
|
|||
|
(!_cups_strcasecmp(val, "0") || !_cups_strcasecmp(val, "no") ||
|
|||
|
!_cups_strcasecmp(val, "off") || !_cups_strcasecmp(val, "false") ||
|
|||
|
!_cups_strcasecmp(val, "disabled")))
|
|||
|
{
|
|||
|
cgiSetVariable("PRESERVE_JOB_HISTORY", "0");
|
|||
|
cgiSetVariable("PRESERVE_JOB_FILES", "0");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
cgiSetVariable("PRESERVE_JOBS", "CHECKED");
|
|||
|
cgiSetVariable("PRESERVE_JOB_HISTORY", val);
|
|||
|
|
|||
|
if ((val = cupsGetOption("PreserveJobFiles", num_settings,
|
|||
|
settings)) == NULL)
|
|||
|
val = "1d";
|
|||
|
|
|||
|
cgiSetVariable("PRESERVE_JOB_FILES", val);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if ((val = cupsGetOption("MaxClients", num_settings, settings)) == NULL)
|
|||
|
val = "100";
|
|||
|
|
|||
|
cgiSetVariable("MAX_CLIENTS", val);
|
|||
|
|
|||
|
if ((val = cupsGetOption("MaxJobs", num_settings, settings)) == NULL)
|
|||
|
val = "500";
|
|||
|
|
|||
|
cgiSetVariable("MAX_JOBS", val);
|
|||
|
|
|||
|
if ((val = cupsGetOption("MaxLogSize", num_settings, settings)) == NULL)
|
|||
|
val = "1m";
|
|||
|
|
|||
|
cgiSetVariable("MAX_LOG_SIZE", val);
|
|||
|
|
|||
|
cupsFreeOptions(num_settings, settings);
|
|||
|
|
|||
|
/*
|
|||
|
* Finally, show the main menu template...
|
|||
|
*/
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("Administration")));
|
|||
|
|
|||
|
cgiCopyTemplateLang("admin.tmpl");
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'do_set_allowed_users()' - Set the allowed/denied users for a queue.
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
do_set_allowed_users(http_t *http) /* I - HTTP connection */
|
|||
|
{
|
|||
|
int i; /* Looping var */
|
|||
|
ipp_t *request, /* IPP request */
|
|||
|
*response; /* IPP response */
|
|||
|
char uri[HTTP_MAX_URI]; /* Printer URI */
|
|||
|
const char *printer, /* Printer name (purge-jobs) */
|
|||
|
*is_class, /* Is a class? */
|
|||
|
*users, /* List of users or groups */
|
|||
|
*type; /* Allow/deny type */
|
|||
|
int num_users; /* Number of users */
|
|||
|
char *ptr, /* Pointer into users string */
|
|||
|
*end, /* Pointer to end of users string */
|
|||
|
quote; /* Quote character */
|
|||
|
ipp_attribute_t *attr; /* Attribute */
|
|||
|
static const char * const attrs[] = /* Requested attributes */
|
|||
|
{
|
|||
|
"requesting-user-name-allowed",
|
|||
|
"requesting-user-name-denied"
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
is_class = cgiGetVariable("IS_CLASS");
|
|||
|
printer = cgiGetVariable("PRINTER_NAME");
|
|||
|
|
|||
|
if (!printer)
|
|||
|
{
|
|||
|
cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
|
|||
|
cgiStartHTML(cgiText(_("Set Allowed Users")));
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
users = cgiGetVariable("users");
|
|||
|
type = cgiGetVariable("type");
|
|||
|
|
|||
|
if (!users || !type ||
|
|||
|
(strcmp(type, "requesting-user-name-allowed") &&
|
|||
|
strcmp(type, "requesting-user-name-denied")))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Build a Get-Printer-Attributes request, which requires the following
|
|||
|
* attributes:
|
|||
|
*
|
|||
|
* attributes-charset
|
|||
|
* attributes-natural-language
|
|||
|
* printer-uri
|
|||
|
* requested-attributes
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
|
|||
|
|
|||
|
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
|
|||
|
"localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
|
|||
|
printer);
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
|
|||
|
NULL, uri);
|
|||
|
|
|||
|
ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
|
|||
|
"requested-attributes",
|
|||
|
(int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs);
|
|||
|
|
|||
|
/*
|
|||
|
* Do the request and get back a response...
|
|||
|
*/
|
|||
|
|
|||
|
if ((response = cupsDoRequest(http, request, "/")) != NULL)
|
|||
|
{
|
|||
|
cgiSetIPPVars(response, NULL, NULL, NULL, 0);
|
|||
|
|
|||
|
ippDelete(response);
|
|||
|
}
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("Set Allowed Users")));
|
|||
|
|
|||
|
if (cupsLastError() == IPP_NOT_AUTHORIZED)
|
|||
|
{
|
|||
|
puts("Status: 401\n");
|
|||
|
exit(0);
|
|||
|
}
|
|||
|
else if (cupsLastError() > IPP_OK_CONFLICT)
|
|||
|
cgiShowIPPError(_("Unable to get printer attributes"));
|
|||
|
else
|
|||
|
cgiCopyTemplateLang("users.tmpl");
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Save the changes...
|
|||
|
*/
|
|||
|
|
|||
|
for (num_users = 0, ptr = (char *)users; *ptr; num_users ++)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Skip whitespace and commas...
|
|||
|
*/
|
|||
|
|
|||
|
while (*ptr == ',' || isspace(*ptr & 255))
|
|||
|
ptr ++;
|
|||
|
|
|||
|
if (!*ptr)
|
|||
|
break;
|
|||
|
|
|||
|
if (*ptr == '\'' || *ptr == '\"')
|
|||
|
{
|
|||
|
/*
|
|||
|
* Scan quoted name...
|
|||
|
*/
|
|||
|
|
|||
|
quote = *ptr++;
|
|||
|
|
|||
|
for (end = ptr; *end; end ++)
|
|||
|
if (*end == quote)
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Scan space or comma-delimited name...
|
|||
|
*/
|
|||
|
|
|||
|
for (end = ptr; *end; end ++)
|
|||
|
if (isspace(*end & 255) || *end == ',')
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Advance to the next name...
|
|||
|
*/
|
|||
|
|
|||
|
ptr = end;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Build a CUPS-Add-Printer/Class request, which requires the following
|
|||
|
* attributes:
|
|||
|
*
|
|||
|
* attributes-charset
|
|||
|
* attributes-natural-language
|
|||
|
* printer-uri
|
|||
|
* requesting-user-name-{allowed,denied}
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
|
|||
|
|
|||
|
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
|
|||
|
"localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
|
|||
|
printer);
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
|
|||
|
NULL, uri);
|
|||
|
|
|||
|
if (num_users == 0)
|
|||
|
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
|
|||
|
"requesting-user-name-allowed", NULL, "all");
|
|||
|
else
|
|||
|
{
|
|||
|
attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
|
|||
|
type, num_users, NULL, NULL);
|
|||
|
|
|||
|
for (i = 0, ptr = (char *)users; *ptr; i ++)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Skip whitespace and commas...
|
|||
|
*/
|
|||
|
|
|||
|
while (*ptr == ',' || isspace(*ptr & 255))
|
|||
|
ptr ++;
|
|||
|
|
|||
|
if (!*ptr)
|
|||
|
break;
|
|||
|
|
|||
|
if (*ptr == '\'' || *ptr == '\"')
|
|||
|
{
|
|||
|
/*
|
|||
|
* Scan quoted name...
|
|||
|
*/
|
|||
|
|
|||
|
quote = *ptr++;
|
|||
|
|
|||
|
for (end = ptr; *end; end ++)
|
|||
|
if (*end == quote)
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Scan space or comma-delimited name...
|
|||
|
*/
|
|||
|
|
|||
|
for (end = ptr; *end; end ++)
|
|||
|
if (isspace(*end & 255) || *end == ',')
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Terminate the name...
|
|||
|
*/
|
|||
|
|
|||
|
if (*end)
|
|||
|
*end++ = '\0';
|
|||
|
|
|||
|
/*
|
|||
|
* Add the name...
|
|||
|
*/
|
|||
|
|
|||
|
ippSetString(request, &attr, i, ptr);
|
|||
|
|
|||
|
/*
|
|||
|
* Advance to the next name...
|
|||
|
*/
|
|||
|
|
|||
|
ptr = end;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Do the request and get back a response...
|
|||
|
*/
|
|||
|
|
|||
|
ippDelete(cupsDoRequest(http, request, "/admin/"));
|
|||
|
|
|||
|
if (cupsLastError() == IPP_NOT_AUTHORIZED)
|
|||
|
{
|
|||
|
puts("Status: 401\n");
|
|||
|
exit(0);
|
|||
|
}
|
|||
|
else if (cupsLastError() > IPP_OK_CONFLICT)
|
|||
|
{
|
|||
|
cgiStartHTML(cgiText(_("Set Allowed Users")));
|
|||
|
cgiShowIPPError(_("Unable to change printer"));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Redirect successful updates back to the printer page...
|
|||
|
*/
|
|||
|
|
|||
|
char url[1024], /* Printer/class URL */
|
|||
|
refresh[1024]; /* Refresh URL */
|
|||
|
|
|||
|
|
|||
|
cgiRewriteURL(uri, url, sizeof(url), NULL);
|
|||
|
cgiFormEncode(uri, url, sizeof(uri));
|
|||
|
snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s",
|
|||
|
uri);
|
|||
|
cgiSetVariable("refresh_page", refresh);
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("Set Allowed Users")));
|
|||
|
|
|||
|
cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
|
|||
|
"printer-modified.tmpl");
|
|||
|
}
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'do_set_default()' - Set the server default printer/class.
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
do_set_default(http_t *http) /* I - HTTP connection */
|
|||
|
{
|
|||
|
const char *title; /* Page title */
|
|||
|
ipp_t *request; /* IPP request */
|
|||
|
char uri[HTTP_MAX_URI]; /* Printer URI */
|
|||
|
const char *printer, /* Printer name (purge-jobs) */
|
|||
|
*is_class; /* Is a class? */
|
|||
|
|
|||
|
|
|||
|
is_class = cgiGetVariable("IS_CLASS");
|
|||
|
printer = cgiGetVariable("PRINTER_NAME");
|
|||
|
title = cgiText(_("Set As Server Default"));
|
|||
|
|
|||
|
if (!printer)
|
|||
|
{
|
|||
|
cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Build a printer request, which requires the following
|
|||
|
* attributes:
|
|||
|
*
|
|||
|
* attributes-charset
|
|||
|
* attributes-natural-language
|
|||
|
* printer-uri
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(CUPS_SET_DEFAULT);
|
|||
|
|
|||
|
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
|
|||
|
"localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
|
|||
|
printer);
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
|
|||
|
NULL, uri);
|
|||
|
|
|||
|
/*
|
|||
|
* Do the request and get back a response...
|
|||
|
*/
|
|||
|
|
|||
|
ippDelete(cupsDoRequest(http, request, "/admin/"));
|
|||
|
|
|||
|
if (cupsLastError() == IPP_NOT_AUTHORIZED)
|
|||
|
{
|
|||
|
puts("Status: 401\n");
|
|||
|
exit(0);
|
|||
|
}
|
|||
|
else if (cupsLastError() > IPP_OK_CONFLICT)
|
|||
|
{
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiShowIPPError(_("Unable to set server default"));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Redirect successful updates back to the printer page...
|
|||
|
*/
|
|||
|
|
|||
|
char url[1024], /* Printer/class URL */
|
|||
|
refresh[1024]; /* Refresh URL */
|
|||
|
|
|||
|
|
|||
|
cgiRewriteURL(uri, url, sizeof(url), NULL);
|
|||
|
cgiFormEncode(uri, url, sizeof(uri));
|
|||
|
snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
|
|||
|
cgiSetVariable("refresh_page", refresh);
|
|||
|
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiCopyTemplateLang("printer-default.tmpl");
|
|||
|
}
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'do_set_options()' - Configure the default options for a queue.
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
do_set_options(http_t *http, /* I - HTTP connection */
|
|||
|
int is_class) /* I - Set options for class? */
|
|||
|
{
|
|||
|
int i, j, k, m; /* Looping vars */
|
|||
|
int have_options; /* Have options? */
|
|||
|
ipp_t *request, /* IPP request */
|
|||
|
*response; /* IPP response */
|
|||
|
ipp_attribute_t *attr; /* IPP attribute */
|
|||
|
char uri[HTTP_MAX_URI]; /* Job URI */
|
|||
|
const char *var; /* Variable value */
|
|||
|
const char *printer; /* Printer printer name */
|
|||
|
const char *filename; /* PPD filename */
|
|||
|
char tempfile[1024]; /* Temporary filename */
|
|||
|
cups_file_t *in, /* Input file */
|
|||
|
*out; /* Output file */
|
|||
|
char line[1024], /* Line from PPD file */
|
|||
|
value[1024], /* Option value */
|
|||
|
keyword[1024], /* Keyword from Default line */
|
|||
|
*keyptr; /* Pointer into keyword... */
|
|||
|
ppd_file_t *ppd; /* PPD file */
|
|||
|
ppd_group_t *group; /* Option group */
|
|||
|
ppd_option_t *option; /* Option */
|
|||
|
ppd_coption_t *coption; /* Custom option */
|
|||
|
ppd_cparam_t *cparam; /* Custom parameter */
|
|||
|
ppd_attr_t *ppdattr; /* PPD attribute */
|
|||
|
const char *title; /* Page title */
|
|||
|
|
|||
|
|
|||
|
title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options"));
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http,
|
|||
|
is_class);
|
|||
|
|
|||
|
/*
|
|||
|
* Get the printer name...
|
|||
|
*/
|
|||
|
|
|||
|
if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL)
|
|||
|
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
|
|||
|
"localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
|
|||
|
printer);
|
|||
|
else
|
|||
|
{
|
|||
|
cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri);
|
|||
|
|
|||
|
/*
|
|||
|
* If the user clicks on the Auto-Configure button, send an AutoConfigure
|
|||
|
* command file to the printer...
|
|||
|
*/
|
|||
|
|
|||
|
if (cgiGetVariable("AUTOCONFIGURE"))
|
|||
|
{
|
|||
|
cgiPrintCommand(http, printer, "AutoConfigure", "Set Default Options");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Get the PPD file...
|
|||
|
*/
|
|||
|
|
|||
|
if (is_class)
|
|||
|
filename = NULL;
|
|||
|
else
|
|||
|
filename = cupsGetPPD2(http, printer);
|
|||
|
|
|||
|
if (filename)
|
|||
|
{
|
|||
|
fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename);
|
|||
|
|
|||
|
if ((ppd = ppdOpenFile(filename)) == NULL)
|
|||
|
{
|
|||
|
cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i)));
|
|||
|
cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file")));
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
fputs("DEBUG: No PPD file\n", stderr);
|
|||
|
ppd = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (cgiGetVariable("job_sheets_start") != NULL ||
|
|||
|
cgiGetVariable("job_sheets_end") != NULL)
|
|||
|
have_options = 1;
|
|||
|
else
|
|||
|
have_options = 0;
|
|||
|
|
|||
|
if (ppd)
|
|||
|
{
|
|||
|
ppdMarkDefaults(ppd);
|
|||
|
|
|||
|
for (option = ppdFirstOption(ppd);
|
|||
|
option;
|
|||
|
option = ppdNextOption(ppd))
|
|||
|
{
|
|||
|
if ((var = cgiGetVariable(option->keyword)) != NULL)
|
|||
|
{
|
|||
|
have_options = 1;
|
|||
|
ppdMarkOption(ppd, option->keyword, var);
|
|||
|
fprintf(stderr, "DEBUG: Set %s to %s...\n", option->keyword, var);
|
|||
|
}
|
|||
|
else
|
|||
|
fprintf(stderr, "DEBUG: Didn't find %s...\n", option->keyword);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!have_options || ppdConflicts(ppd))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Show the options to the user...
|
|||
|
*/
|
|||
|
|
|||
|
fputs("DEBUG: Showing options...\n", stderr);
|
|||
|
|
|||
|
/*
|
|||
|
* Show auto-configure button if supported...
|
|||
|
*/
|
|||
|
|
|||
|
if (ppd)
|
|||
|
{
|
|||
|
if (ppd->num_filters == 0 ||
|
|||
|
((ppdattr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL &&
|
|||
|
ppdattr->value && strstr(ppdattr->value, "AutoConfigure")))
|
|||
|
cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
|
|||
|
else
|
|||
|
{
|
|||
|
for (i = 0; i < ppd->num_filters; i ++)
|
|||
|
if (!strncmp(ppd->filters[i], "application/vnd.cups-postscript", 31))
|
|||
|
{
|
|||
|
cgiSetVariable("HAVE_AUTOCONFIGURE", "YES");
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Get the printer attributes...
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
|
|||
|
|
|||
|
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
|
|||
|
"localhost", 0, "/printers/%s", printer);
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
|
|||
|
NULL, uri);
|
|||
|
|
|||
|
response = cupsDoRequest(http, request, "/");
|
|||
|
|
|||
|
/*
|
|||
|
* List the groups used as "tabs"...
|
|||
|
*/
|
|||
|
|
|||
|
i = 0;
|
|||
|
|
|||
|
if (ppd)
|
|||
|
{
|
|||
|
for (group = ppd->groups;
|
|||
|
i < ppd->num_groups;
|
|||
|
i ++, group ++)
|
|||
|
{
|
|||
|
cgiSetArray("GROUP_ID", i, group->name);
|
|||
|
|
|||
|
if (!strcmp(group->name, "InstallableOptions"))
|
|||
|
cgiSetArray("GROUP", i, cgiText(_("Options Installed")));
|
|||
|
else
|
|||
|
cgiSetArray("GROUP", i, group->text);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO))
|
|||
|
{
|
|||
|
cgiSetArray("GROUP_ID", i, "CUPS_BANNERS");
|
|||
|
cgiSetArray("GROUP", i ++, cgiText(_("Banners")));
|
|||
|
}
|
|||
|
|
|||
|
if (ippFindAttribute(response, "printer-error-policy-supported",
|
|||
|
IPP_TAG_ZERO) ||
|
|||
|
ippFindAttribute(response, "printer-op-policy-supported",
|
|||
|
IPP_TAG_ZERO))
|
|||
|
{
|
|||
|
cgiSetArray("GROUP_ID", i, "CUPS_POLICIES");
|
|||
|
cgiSetArray("GROUP", i ++, cgiText(_("Policies")));
|
|||
|
}
|
|||
|
|
|||
|
if ((attr = ippFindAttribute(response, "port-monitor-supported",
|
|||
|
IPP_TAG_NAME)) != NULL && attr->num_values > 1)
|
|||
|
{
|
|||
|
cgiSetArray("GROUP_ID", i, "CUPS_PORT_MONITOR");
|
|||
|
cgiSetArray("GROUP", i, cgiText(_("Port Monitor")));
|
|||
|
}
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("Set Printer Options")));
|
|||
|
cgiCopyTemplateLang("set-printer-options-header.tmpl");
|
|||
|
|
|||
|
if (ppd)
|
|||
|
{
|
|||
|
ppdLocalize(ppd);
|
|||
|
|
|||
|
if (ppdConflicts(ppd))
|
|||
|
{
|
|||
|
for (i = ppd->num_groups, k = 0, group = ppd->groups;
|
|||
|
i > 0;
|
|||
|
i --, group ++)
|
|||
|
for (j = group->num_options, option = group->options;
|
|||
|
j > 0;
|
|||
|
j --, option ++)
|
|||
|
if (option->conflicted)
|
|||
|
{
|
|||
|
cgiSetArray("ckeyword", k, option->keyword);
|
|||
|
cgiSetArray("ckeytext", k, option->text);
|
|||
|
|
|||
|
for (m = 0; m < option->num_choices; m ++)
|
|||
|
{
|
|||
|
if (option->choices[m].marked)
|
|||
|
{
|
|||
|
cgiSetArray("cchoice", k, option->choices[m].text);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
k ++;
|
|||
|
}
|
|||
|
|
|||
|
cgiCopyTemplateLang("option-conflict.tmpl");
|
|||
|
}
|
|||
|
|
|||
|
for (i = ppd->num_groups, group = ppd->groups;
|
|||
|
i > 0;
|
|||
|
i --, group ++)
|
|||
|
{
|
|||
|
for (j = group->num_options, option = group->options;
|
|||
|
j > 0;
|
|||
|
j --, option ++)
|
|||
|
{
|
|||
|
if (!strcmp(option->keyword, "PageRegion"))
|
|||
|
continue;
|
|||
|
|
|||
|
if (option->num_choices > 1)
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (j == 0)
|
|||
|
continue;
|
|||
|
|
|||
|
cgiSetVariable("GROUP_ID", group->name);
|
|||
|
|
|||
|
if (!strcmp(group->name, "InstallableOptions"))
|
|||
|
cgiSetVariable("GROUP", cgiText(_("Options Installed")));
|
|||
|
else
|
|||
|
cgiSetVariable("GROUP", group->text);
|
|||
|
|
|||
|
cgiCopyTemplateLang("option-header.tmpl");
|
|||
|
|
|||
|
for (j = group->num_options, option = group->options;
|
|||
|
j > 0;
|
|||
|
j --, option ++)
|
|||
|
{
|
|||
|
if (!strcmp(option->keyword, "PageRegion") || option->num_choices < 2)
|
|||
|
continue;
|
|||
|
|
|||
|
cgiSetVariable("KEYWORD", option->keyword);
|
|||
|
cgiSetVariable("KEYTEXT", option->text);
|
|||
|
|
|||
|
if (option->conflicted)
|
|||
|
cgiSetVariable("CONFLICTED", "1");
|
|||
|
else
|
|||
|
cgiSetVariable("CONFLICTED", "0");
|
|||
|
|
|||
|
cgiSetSize("CHOICES", 0);
|
|||
|
cgiSetSize("TEXT", 0);
|
|||
|
for (k = 0, m = 0; k < option->num_choices; k ++)
|
|||
|
{
|
|||
|
cgiSetArray("CHOICES", m, option->choices[k].choice);
|
|||
|
cgiSetArray("TEXT", m, option->choices[k].text);
|
|||
|
|
|||
|
m ++;
|
|||
|
|
|||
|
if (option->choices[k].marked)
|
|||
|
cgiSetVariable("DEFCHOICE", option->choices[k].choice);
|
|||
|
}
|
|||
|
|
|||
|
cgiSetSize("PARAMS", 0);
|
|||
|
cgiSetSize("PARAMTEXT", 0);
|
|||
|
cgiSetSize("PARAMVALUE", 0);
|
|||
|
cgiSetSize("INPUTTYPE", 0);
|
|||
|
|
|||
|
if ((coption = ppdFindCustomOption(ppd, option->keyword)))
|
|||
|
{
|
|||
|
const char *units = NULL; /* Units value, if any */
|
|||
|
|
|||
|
cgiSetVariable("ISCUSTOM", "1");
|
|||
|
|
|||
|
for (cparam = ppdFirstCustomParam(coption), m = 0;
|
|||
|
cparam;
|
|||
|
cparam = ppdNextCustomParam(coption), m ++)
|
|||
|
{
|
|||
|
if (!_cups_strcasecmp(option->keyword, "PageSize") &&
|
|||
|
_cups_strcasecmp(cparam->name, "Width") &&
|
|||
|
_cups_strcasecmp(cparam->name, "Height"))
|
|||
|
{
|
|||
|
m --;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
cgiSetArray("PARAMS", m, cparam->name);
|
|||
|
cgiSetArray("PARAMTEXT", m, cparam->text);
|
|||
|
cgiSetArray("INPUTTYPE", m, "text");
|
|||
|
|
|||
|
switch (cparam->type)
|
|||
|
{
|
|||
|
case PPD_CUSTOM_UNKNOWN :
|
|||
|
break;
|
|||
|
|
|||
|
case PPD_CUSTOM_POINTS :
|
|||
|
if (!_cups_strncasecmp(option->defchoice, "Custom.", 7))
|
|||
|
{
|
|||
|
units = option->defchoice + strlen(option->defchoice) - 2;
|
|||
|
|
|||
|
if (strcmp(units, "mm") && strcmp(units, "cm") &&
|
|||
|
strcmp(units, "in") && strcmp(units, "ft"))
|
|||
|
{
|
|||
|
if (units[1] == 'm')
|
|||
|
units ++;
|
|||
|
else
|
|||
|
units = "pt";
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
units = "pt";
|
|||
|
|
|||
|
if (!strcmp(units, "mm"))
|
|||
|
snprintf(value, sizeof(value), "%g",
|
|||
|
cparam->current.custom_points / 72.0 * 25.4);
|
|||
|
else if (!strcmp(units, "cm"))
|
|||
|
snprintf(value, sizeof(value), "%g",
|
|||
|
cparam->current.custom_points / 72.0 * 2.54);
|
|||
|
else if (!strcmp(units, "in"))
|
|||
|
snprintf(value, sizeof(value), "%g",
|
|||
|
cparam->current.custom_points / 72.0);
|
|||
|
else if (!strcmp(units, "ft"))
|
|||
|
snprintf(value, sizeof(value), "%g",
|
|||
|
cparam->current.custom_points / 72.0 / 12.0);
|
|||
|
else if (!strcmp(units, "m"))
|
|||
|
snprintf(value, sizeof(value), "%g",
|
|||
|
cparam->current.custom_points / 72.0 * 0.0254);
|
|||
|
else
|
|||
|
snprintf(value, sizeof(value), "%g",
|
|||
|
cparam->current.custom_points);
|
|||
|
cgiSetArray("PARAMVALUE", m, value);
|
|||
|
break;
|
|||
|
|
|||
|
case PPD_CUSTOM_CURVE :
|
|||
|
case PPD_CUSTOM_INVCURVE :
|
|||
|
case PPD_CUSTOM_REAL :
|
|||
|
snprintf(value, sizeof(value), "%g",
|
|||
|
cparam->current.custom_real);
|
|||
|
cgiSetArray("PARAMVALUE", m, value);
|
|||
|
break;
|
|||
|
|
|||
|
case PPD_CUSTOM_INT:
|
|||
|
snprintf(value, sizeof(value), "%d",
|
|||
|
cparam->current.custom_int);
|
|||
|
cgiSetArray("PARAMVALUE", m, value);
|
|||
|
break;
|
|||
|
|
|||
|
case PPD_CUSTOM_PASSCODE:
|
|||
|
case PPD_CUSTOM_PASSWORD:
|
|||
|
if (cparam->current.custom_password)
|
|||
|
cgiSetArray("PARAMVALUE", m,
|
|||
|
cparam->current.custom_password);
|
|||
|
else
|
|||
|
cgiSetArray("PARAMVALUE", m, "");
|
|||
|
cgiSetArray("INPUTTYPE", m, "password");
|
|||
|
break;
|
|||
|
|
|||
|
case PPD_CUSTOM_STRING:
|
|||
|
if (cparam->current.custom_string)
|
|||
|
cgiSetArray("PARAMVALUE", m,
|
|||
|
cparam->current.custom_string);
|
|||
|
else
|
|||
|
cgiSetArray("PARAMVALUE", m, "");
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (units)
|
|||
|
{
|
|||
|
cgiSetArray("PARAMS", m, "Units");
|
|||
|
cgiSetArray("PARAMTEXT", m, cgiText(_("Units")));
|
|||
|
cgiSetArray("PARAMVALUE", m, units);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
cgiSetVariable("ISCUSTOM", "0");
|
|||
|
|
|||
|
switch (option->ui)
|
|||
|
{
|
|||
|
case PPD_UI_BOOLEAN :
|
|||
|
cgiCopyTemplateLang("option-boolean.tmpl");
|
|||
|
break;
|
|||
|
case PPD_UI_PICKONE :
|
|||
|
cgiCopyTemplateLang("option-pickone.tmpl");
|
|||
|
break;
|
|||
|
case PPD_UI_PICKMANY :
|
|||
|
cgiCopyTemplateLang("option-pickmany.tmpl");
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
cgiCopyTemplateLang("option-trailer.tmpl");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ((attr = ippFindAttribute(response, "job-sheets-supported",
|
|||
|
IPP_TAG_ZERO)) != NULL)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Add the job sheets options...
|
|||
|
*/
|
|||
|
|
|||
|
cgiSetVariable("GROUP_ID", "CUPS_BANNERS");
|
|||
|
cgiSetVariable("GROUP", cgiText(_("Banners")));
|
|||
|
cgiCopyTemplateLang("option-header.tmpl");
|
|||
|
|
|||
|
cgiSetSize("CHOICES", attr->num_values);
|
|||
|
cgiSetSize("TEXT", attr->num_values);
|
|||
|
for (k = 0; k < attr->num_values; k ++)
|
|||
|
{
|
|||
|
cgiSetArray("CHOICES", k, attr->values[k].string.text);
|
|||
|
cgiSetArray("TEXT", k, attr->values[k].string.text);
|
|||
|
}
|
|||
|
|
|||
|
attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO);
|
|||
|
|
|||
|
cgiSetVariable("KEYWORD", "job_sheets_start");
|
|||
|
cgiSetVariable("KEYTEXT",
|
|||
|
/* TRANSLATORS: Banner/cover sheet before the print job. */
|
|||
|
cgiText(_("Starting Banner")));
|
|||
|
cgiSetVariable("DEFCHOICE", attr != NULL ?
|
|||
|
attr->values[0].string.text : "");
|
|||
|
|
|||
|
cgiCopyTemplateLang("option-pickone.tmpl");
|
|||
|
|
|||
|
cgiSetVariable("KEYWORD", "job_sheets_end");
|
|||
|
cgiSetVariable("KEYTEXT",
|
|||
|
/* TRANSLATORS: Banner/cover sheet after the print job. */
|
|||
|
cgiText(_("Ending Banner")));
|
|||
|
cgiSetVariable("DEFCHOICE", attr != NULL && attr->num_values > 1 ?
|
|||
|
attr->values[1].string.text : "");
|
|||
|
|
|||
|
cgiCopyTemplateLang("option-pickone.tmpl");
|
|||
|
|
|||
|
cgiCopyTemplateLang("option-trailer.tmpl");
|
|||
|
}
|
|||
|
|
|||
|
if (ippFindAttribute(response, "printer-error-policy-supported",
|
|||
|
IPP_TAG_ZERO) ||
|
|||
|
ippFindAttribute(response, "printer-op-policy-supported",
|
|||
|
IPP_TAG_ZERO))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Add the error and operation policy options...
|
|||
|
*/
|
|||
|
|
|||
|
cgiSetVariable("GROUP_ID", "CUPS_POLICIES");
|
|||
|
cgiSetVariable("GROUP", cgiText(_("Policies")));
|
|||
|
cgiCopyTemplateLang("option-header.tmpl");
|
|||
|
|
|||
|
/*
|
|||
|
* Error policy...
|
|||
|
*/
|
|||
|
|
|||
|
attr = ippFindAttribute(response, "printer-error-policy-supported",
|
|||
|
IPP_TAG_ZERO);
|
|||
|
|
|||
|
if (attr)
|
|||
|
{
|
|||
|
cgiSetSize("CHOICES", attr->num_values);
|
|||
|
cgiSetSize("TEXT", attr->num_values);
|
|||
|
for (k = 0; k < attr->num_values; k ++)
|
|||
|
{
|
|||
|
cgiSetArray("CHOICES", k, attr->values[k].string.text);
|
|||
|
cgiSetArray("TEXT", k, attr->values[k].string.text);
|
|||
|
}
|
|||
|
|
|||
|
attr = ippFindAttribute(response, "printer-error-policy",
|
|||
|
IPP_TAG_ZERO);
|
|||
|
|
|||
|
cgiSetVariable("KEYWORD", "printer_error_policy");
|
|||
|
cgiSetVariable("KEYTEXT", cgiText(_("Error Policy")));
|
|||
|
cgiSetVariable("DEFCHOICE", attr == NULL ?
|
|||
|
"" : attr->values[0].string.text);
|
|||
|
}
|
|||
|
|
|||
|
cgiCopyTemplateLang("option-pickone.tmpl");
|
|||
|
|
|||
|
/*
|
|||
|
* Operation policy...
|
|||
|
*/
|
|||
|
|
|||
|
attr = ippFindAttribute(response, "printer-op-policy-supported",
|
|||
|
IPP_TAG_ZERO);
|
|||
|
|
|||
|
if (attr)
|
|||
|
{
|
|||
|
cgiSetSize("CHOICES", attr->num_values);
|
|||
|
cgiSetSize("TEXT", attr->num_values);
|
|||
|
for (k = 0; k < attr->num_values; k ++)
|
|||
|
{
|
|||
|
cgiSetArray("CHOICES", k, attr->values[k].string.text);
|
|||
|
cgiSetArray("TEXT", k, attr->values[k].string.text);
|
|||
|
}
|
|||
|
|
|||
|
attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO);
|
|||
|
|
|||
|
cgiSetVariable("KEYWORD", "printer_op_policy");
|
|||
|
cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy")));
|
|||
|
cgiSetVariable("DEFCHOICE", attr == NULL ?
|
|||
|
"" : attr->values[0].string.text);
|
|||
|
|
|||
|
cgiCopyTemplateLang("option-pickone.tmpl");
|
|||
|
}
|
|||
|
|
|||
|
cgiCopyTemplateLang("option-trailer.tmpl");
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Binary protocol support...
|
|||
|
*/
|
|||
|
|
|||
|
if ((attr = ippFindAttribute(response, "port-monitor-supported",
|
|||
|
IPP_TAG_NAME)) != NULL && attr->num_values > 1)
|
|||
|
{
|
|||
|
cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR");
|
|||
|
cgiSetVariable("GROUP", cgiText(_("Port Monitor")));
|
|||
|
|
|||
|
cgiSetSize("CHOICES", attr->num_values);
|
|||
|
cgiSetSize("TEXT", attr->num_values);
|
|||
|
|
|||
|
for (i = 0; i < attr->num_values; i ++)
|
|||
|
{
|
|||
|
cgiSetArray("CHOICES", i, attr->values[i].string.text);
|
|||
|
cgiSetArray("TEXT", i, attr->values[i].string.text);
|
|||
|
}
|
|||
|
|
|||
|
attr = ippFindAttribute(response, "port-monitor", IPP_TAG_NAME);
|
|||
|
cgiSetVariable("KEYWORD", "port_monitor");
|
|||
|
cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor")));
|
|||
|
cgiSetVariable("DEFCHOICE", attr ? attr->values[0].string.text : "none");
|
|||
|
|
|||
|
cgiCopyTemplateLang("option-header.tmpl");
|
|||
|
cgiCopyTemplateLang("option-pickone.tmpl");
|
|||
|
cgiCopyTemplateLang("option-trailer.tmpl");
|
|||
|
}
|
|||
|
|
|||
|
cgiCopyTemplateLang("set-printer-options-trailer.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
|
|||
|
ippDelete(response);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Set default options...
|
|||
|
*/
|
|||
|
|
|||
|
fputs("DEBUG: Setting options...\n", stderr);
|
|||
|
|
|||
|
if (filename)
|
|||
|
{
|
|||
|
out = cupsTempFile2(tempfile, sizeof(tempfile));
|
|||
|
in = cupsFileOpen(filename, "r");
|
|||
|
|
|||
|
if (!in || !out)
|
|||
|
{
|
|||
|
cgiSetVariable("ERROR", strerror(errno));
|
|||
|
cgiStartHTML(cgiText(_("Set Printer Options")));
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
|
|||
|
if (in)
|
|||
|
cupsFileClose(in);
|
|||
|
|
|||
|
if (out)
|
|||
|
{
|
|||
|
cupsFileClose(out);
|
|||
|
unlink(tempfile);
|
|||
|
}
|
|||
|
|
|||
|
unlink(filename);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
while (cupsFileGets(in, line, sizeof(line)))
|
|||
|
{
|
|||
|
if (!strncmp(line, "*cupsProtocol:", 14))
|
|||
|
continue;
|
|||
|
else if (strncmp(line, "*Default", 8))
|
|||
|
cupsFilePrintf(out, "%s\n", line);
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Get default option name...
|
|||
|
*/
|
|||
|
|
|||
|
strlcpy(keyword, line + 8, sizeof(keyword));
|
|||
|
|
|||
|
for (keyptr = keyword; *keyptr; keyptr ++)
|
|||
|
if (*keyptr == ':' || isspace(*keyptr & 255))
|
|||
|
break;
|
|||
|
|
|||
|
*keyptr = '\0';
|
|||
|
|
|||
|
if (!strcmp(keyword, "PageRegion") ||
|
|||
|
!strcmp(keyword, "PaperDimension") ||
|
|||
|
!strcmp(keyword, "ImageableArea"))
|
|||
|
var = get_option_value(ppd, "PageSize", value, sizeof(value));
|
|||
|
else
|
|||
|
var = get_option_value(ppd, keyword, value, sizeof(value));
|
|||
|
|
|||
|
if (!var)
|
|||
|
cupsFilePrintf(out, "%s\n", line);
|
|||
|
else
|
|||
|
cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
cupsFileClose(in);
|
|||
|
cupsFileClose(out);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Make sure temporary filename is cleared when there is no PPD...
|
|||
|
*/
|
|||
|
|
|||
|
tempfile[0] = '\0';
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the
|
|||
|
* following attributes:
|
|||
|
*
|
|||
|
* attributes-charset
|
|||
|
* attributes-natural-language
|
|||
|
* printer-uri
|
|||
|
* job-sheets-default
|
|||
|
* printer-error-policy
|
|||
|
* printer-op-policy
|
|||
|
* [ppd file]
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS :
|
|||
|
CUPS_ADD_MODIFY_PRINTER);
|
|||
|
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
|
|||
|
NULL, uri);
|
|||
|
|
|||
|
attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
|
|||
|
"job-sheets-default", 2, NULL, NULL);
|
|||
|
ippSetString(request, &attr, 0, cgiGetVariable("job_sheets_start"));
|
|||
|
ippSetString(request, &attr, 1, cgiGetVariable("job_sheets_end"));
|
|||
|
|
|||
|
if ((var = cgiGetVariable("printer_error_policy")) != NULL)
|
|||
|
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
|
|||
|
"printer-error-policy", NULL, var);
|
|||
|
|
|||
|
if ((var = cgiGetVariable("printer_op_policy")) != NULL)
|
|||
|
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
|
|||
|
"printer-op-policy", NULL, var);
|
|||
|
|
|||
|
if ((var = cgiGetVariable("port_monitor")) != NULL)
|
|||
|
ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME,
|
|||
|
"port-monitor", NULL, var);
|
|||
|
|
|||
|
/*
|
|||
|
* Do the request and get back a response...
|
|||
|
*/
|
|||
|
|
|||
|
if (filename)
|
|||
|
ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile));
|
|||
|
else
|
|||
|
ippDelete(cupsDoRequest(http, request, "/admin/"));
|
|||
|
|
|||
|
if (cupsLastError() == IPP_NOT_AUTHORIZED)
|
|||
|
{
|
|||
|
puts("Status: 401\n");
|
|||
|
exit(0);
|
|||
|
}
|
|||
|
else if (cupsLastError() > IPP_OK_CONFLICT)
|
|||
|
{
|
|||
|
cgiStartHTML(title);
|
|||
|
cgiShowIPPError(_("Unable to set options"));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Redirect successful updates back to the printer page...
|
|||
|
*/
|
|||
|
|
|||
|
char refresh[1024]; /* Refresh URL */
|
|||
|
|
|||
|
|
|||
|
cgiFormEncode(uri, printer, sizeof(uri));
|
|||
|
snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
|
|||
|
is_class ? "classes" : "printers", uri);
|
|||
|
cgiSetVariable("refresh_page", refresh);
|
|||
|
|
|||
|
cgiStartHTML(title);
|
|||
|
|
|||
|
cgiCopyTemplateLang("printer-configured.tmpl");
|
|||
|
}
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
|
|||
|
if (filename)
|
|||
|
unlink(tempfile);
|
|||
|
}
|
|||
|
|
|||
|
if (filename)
|
|||
|
unlink(filename);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'do_set_sharing()' - Set printer-is-shared value.
|
|||
|
*/
|
|||
|
|
|||
|
static void
|
|||
|
do_set_sharing(http_t *http) /* I - HTTP connection */
|
|||
|
{
|
|||
|
ipp_t *request, /* IPP request */
|
|||
|
*response; /* IPP response */
|
|||
|
char uri[HTTP_MAX_URI]; /* Printer URI */
|
|||
|
const char *printer, /* Printer name */
|
|||
|
*is_class, /* Is a class? */
|
|||
|
*shared; /* Sharing value */
|
|||
|
|
|||
|
|
|||
|
is_class = cgiGetVariable("IS_CLASS");
|
|||
|
printer = cgiGetVariable("PRINTER_NAME");
|
|||
|
shared = cgiGetVariable("SHARED");
|
|||
|
|
|||
|
if (!printer || !shared)
|
|||
|
{
|
|||
|
cgiSetVariable("ERROR", cgiText(_("Missing form variable")));
|
|||
|
cgiStartHTML(cgiText(_("Set Publishing")));
|
|||
|
cgiCopyTemplateLang("error.tmpl");
|
|||
|
cgiEndHTML();
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the
|
|||
|
* following attributes:
|
|||
|
*
|
|||
|
* attributes-charset
|
|||
|
* attributes-natural-language
|
|||
|
* printer-uri
|
|||
|
* printer-is-shared
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER);
|
|||
|
|
|||
|
httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
|
|||
|
"localhost", 0, is_class ? "/classes/%s" : "/printers/%s",
|
|||
|
printer);
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
|
|||
|
NULL, uri);
|
|||
|
|
|||
|
ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", (char)atoi(shared));
|
|||
|
|
|||
|
/*
|
|||
|
* Do the request and get back a response...
|
|||
|
*/
|
|||
|
|
|||
|
if ((response = cupsDoRequest(http, request, "/admin/")) != NULL)
|
|||
|
{
|
|||
|
cgiSetIPPVars(response, NULL, NULL, NULL, 0);
|
|||
|
|
|||
|
ippDelete(response);
|
|||
|
}
|
|||
|
|
|||
|
if (cupsLastError() == IPP_NOT_AUTHORIZED)
|
|||
|
{
|
|||
|
puts("Status: 401\n");
|
|||
|
exit(0);
|
|||
|
}
|
|||
|
else if (cupsLastError() > IPP_OK_CONFLICT)
|
|||
|
{
|
|||
|
cgiStartHTML(cgiText(_("Set Publishing")));
|
|||
|
cgiShowIPPError(_("Unable to change printer-is-shared attribute"));
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*
|
|||
|
* Redirect successful updates back to the printer page...
|
|||
|
*/
|
|||
|
|
|||
|
char url[1024], /* Printer/class URL */
|
|||
|
refresh[1024]; /* Refresh URL */
|
|||
|
|
|||
|
|
|||
|
cgiRewriteURL(uri, url, sizeof(url), NULL);
|
|||
|
cgiFormEncode(uri, url, sizeof(uri));
|
|||
|
snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri);
|
|||
|
cgiSetVariable("refresh_page", refresh);
|
|||
|
|
|||
|
cgiStartHTML(cgiText(_("Set Publishing")));
|
|||
|
cgiCopyTemplateLang(is_class ? "class-modified.tmpl" :
|
|||
|
"printer-modified.tmpl");
|
|||
|
}
|
|||
|
|
|||
|
cgiEndHTML();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'get_option_value()' - Return the value of an option.
|
|||
|
*
|
|||
|
* This function also handles generation of custom option values.
|
|||
|
*/
|
|||
|
|
|||
|
static char * /* O - Value string or NULL on error */
|
|||
|
get_option_value(
|
|||
|
ppd_file_t *ppd, /* I - PPD file */
|
|||
|
const char *name, /* I - Option name */
|
|||
|
char *buffer, /* I - String buffer */
|
|||
|
size_t bufsize) /* I - Size of buffer */
|
|||
|
{
|
|||
|
char *bufptr, /* Pointer into buffer */
|
|||
|
*bufend; /* End of buffer */
|
|||
|
ppd_coption_t *coption; /* Custom option */
|
|||
|
ppd_cparam_t *cparam; /* Current custom parameter */
|
|||
|
char keyword[256]; /* Parameter name */
|
|||
|
const char *val, /* Parameter value */
|
|||
|
*uval; /* Units value */
|
|||
|
long integer; /* Integer value */
|
|||
|
double number, /* Number value */
|
|||
|
number_points; /* Number in points */
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* See if we have a custom option choice...
|
|||
|
*/
|
|||
|
|
|||
|
if ((val = cgiGetVariable(name)) == NULL)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Option not found!
|
|||
|
*/
|
|||
|
|
|||
|
return (NULL);
|
|||
|
}
|
|||
|
else if (_cups_strcasecmp(val, "Custom") ||
|
|||
|
(coption = ppdFindCustomOption(ppd, name)) == NULL)
|
|||
|
{
|
|||
|
/*
|
|||
|
* Not a custom choice...
|
|||
|
*/
|
|||
|
|
|||
|
strlcpy(buffer, val, bufsize);
|
|||
|
return (buffer);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* OK, we have a custom option choice, format it...
|
|||
|
*/
|
|||
|
|
|||
|
*buffer = '\0';
|
|||
|
|
|||
|
if (!strcmp(coption->keyword, "PageSize"))
|
|||
|
{
|
|||
|
const char *lval; /* Length string value */
|
|||
|
double width, /* Width value */
|
|||
|
width_points, /* Width in points */
|
|||
|
length, /* Length value */
|
|||
|
length_points; /* Length in points */
|
|||
|
|
|||
|
|
|||
|
val = cgiGetVariable("PageSize.Width");
|
|||
|
lval = cgiGetVariable("PageSize.Height");
|
|||
|
uval = cgiGetVariable("PageSize.Units");
|
|||
|
|
|||
|
if (!val || !lval || !uval ||
|
|||
|
(width = strtod(val, NULL)) == 0.0 ||
|
|||
|
(length = strtod(lval, NULL)) == 0.0 ||
|
|||
|
(strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
|
|||
|
strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
|
|||
|
return (NULL);
|
|||
|
|
|||
|
width_points = get_points(width, uval);
|
|||
|
length_points = get_points(length, uval);
|
|||
|
|
|||
|
if (width_points < ppd->custom_min[0] ||
|
|||
|
width_points > ppd->custom_max[0] ||
|
|||
|
length_points < ppd->custom_min[1] ||
|
|||
|
length_points > ppd->custom_max[1])
|
|||
|
return (NULL);
|
|||
|
|
|||
|
snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval);
|
|||
|
}
|
|||
|
else if (cupsArrayCount(coption->params) == 1)
|
|||
|
{
|
|||
|
cparam = ppdFirstCustomParam(coption);
|
|||
|
snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name);
|
|||
|
|
|||
|
if ((val = cgiGetVariable(keyword)) == NULL)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
switch (cparam->type)
|
|||
|
{
|
|||
|
case PPD_CUSTOM_UNKNOWN :
|
|||
|
break;
|
|||
|
|
|||
|
case PPD_CUSTOM_CURVE :
|
|||
|
case PPD_CUSTOM_INVCURVE :
|
|||
|
case PPD_CUSTOM_REAL :
|
|||
|
if ((number = strtod(val, NULL)) == 0.0 ||
|
|||
|
number < cparam->minimum.custom_real ||
|
|||
|
number > cparam->maximum.custom_real)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
snprintf(buffer, bufsize, "Custom.%g", number);
|
|||
|
break;
|
|||
|
|
|||
|
case PPD_CUSTOM_INT :
|
|||
|
if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
|
|||
|
integer == LONG_MAX ||
|
|||
|
integer < cparam->minimum.custom_int ||
|
|||
|
integer > cparam->maximum.custom_int)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
snprintf(buffer, bufsize, "Custom.%ld", integer);
|
|||
|
break;
|
|||
|
|
|||
|
case PPD_CUSTOM_POINTS :
|
|||
|
snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
|
|||
|
|
|||
|
if ((number = strtod(val, NULL)) == 0.0 ||
|
|||
|
(uval = cgiGetVariable(keyword)) == NULL ||
|
|||
|
(strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
|
|||
|
strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
|
|||
|
return (NULL);
|
|||
|
|
|||
|
number_points = get_points(number, uval);
|
|||
|
if (number_points < cparam->minimum.custom_points ||
|
|||
|
number_points > cparam->maximum.custom_points)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
snprintf(buffer, bufsize, "Custom.%g%s", number, uval);
|
|||
|
break;
|
|||
|
|
|||
|
case PPD_CUSTOM_PASSCODE :
|
|||
|
for (uval = val; *uval; uval ++)
|
|||
|
if (!isdigit(*uval & 255))
|
|||
|
return (NULL);
|
|||
|
|
|||
|
case PPD_CUSTOM_PASSWORD :
|
|||
|
case PPD_CUSTOM_STRING :
|
|||
|
integer = (long)strlen(val);
|
|||
|
if (integer < cparam->minimum.custom_string ||
|
|||
|
integer > cparam->maximum.custom_string)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
snprintf(buffer, bufsize, "Custom.%s", val);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
const char *prefix = "{"; /* Prefix string */
|
|||
|
|
|||
|
|
|||
|
bufptr = buffer;
|
|||
|
bufend = buffer + bufsize;
|
|||
|
|
|||
|
for (cparam = ppdFirstCustomParam(coption);
|
|||
|
cparam;
|
|||
|
cparam = ppdNextCustomParam(coption))
|
|||
|
{
|
|||
|
snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword,
|
|||
|
cparam->name);
|
|||
|
|
|||
|
if ((val = cgiGetVariable(keyword)) == NULL)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
snprintf(bufptr, (size_t)(bufend - bufptr), "%s%s=", prefix, cparam->name);
|
|||
|
bufptr += strlen(bufptr);
|
|||
|
prefix = " ";
|
|||
|
|
|||
|
switch (cparam->type)
|
|||
|
{
|
|||
|
case PPD_CUSTOM_UNKNOWN :
|
|||
|
break;
|
|||
|
|
|||
|
case PPD_CUSTOM_CURVE :
|
|||
|
case PPD_CUSTOM_INVCURVE :
|
|||
|
case PPD_CUSTOM_REAL :
|
|||
|
if ((number = strtod(val, NULL)) == 0.0 ||
|
|||
|
number < cparam->minimum.custom_real ||
|
|||
|
number > cparam->maximum.custom_real)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
snprintf(bufptr, (size_t)(bufend - bufptr), "%g", number);
|
|||
|
break;
|
|||
|
|
|||
|
case PPD_CUSTOM_INT :
|
|||
|
if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
|
|||
|
integer == LONG_MAX ||
|
|||
|
integer < cparam->minimum.custom_int ||
|
|||
|
integer > cparam->maximum.custom_int)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
snprintf(bufptr, (size_t)(bufend - bufptr), "%ld", integer);
|
|||
|
break;
|
|||
|
|
|||
|
case PPD_CUSTOM_POINTS :
|
|||
|
snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
|
|||
|
|
|||
|
if ((number = strtod(val, NULL)) == 0.0 ||
|
|||
|
(uval = cgiGetVariable(keyword)) == NULL ||
|
|||
|
(strcmp(uval, "pt") && strcmp(uval, "in") &&
|
|||
|
strcmp(uval, "ft") && strcmp(uval, "cm") &&
|
|||
|
strcmp(uval, "mm") && strcmp(uval, "m")))
|
|||
|
return (NULL);
|
|||
|
|
|||
|
number_points = get_points(number, uval);
|
|||
|
if (number_points < cparam->minimum.custom_points ||
|
|||
|
number_points > cparam->maximum.custom_points)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
snprintf(bufptr, (size_t)(bufend - bufptr), "%g%s", number, uval);
|
|||
|
break;
|
|||
|
|
|||
|
case PPD_CUSTOM_PASSCODE :
|
|||
|
for (uval = val; *uval; uval ++)
|
|||
|
if (!isdigit(*uval & 255))
|
|||
|
return (NULL);
|
|||
|
|
|||
|
case PPD_CUSTOM_PASSWORD :
|
|||
|
case PPD_CUSTOM_STRING :
|
|||
|
integer = (long)strlen(val);
|
|||
|
if (integer < cparam->minimum.custom_string ||
|
|||
|
integer > cparam->maximum.custom_string)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
if ((bufptr + 2) > bufend)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
bufend --;
|
|||
|
*bufptr++ = '\"';
|
|||
|
|
|||
|
while (*val && bufptr < bufend)
|
|||
|
{
|
|||
|
if (*val == '\\' || *val == '\"')
|
|||
|
{
|
|||
|
if ((bufptr + 1) >= bufend)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
*bufptr++ = '\\';
|
|||
|
}
|
|||
|
|
|||
|
*bufptr++ = *val++;
|
|||
|
}
|
|||
|
|
|||
|
if (bufptr >= bufend)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
*bufptr++ = '\"';
|
|||
|
*bufptr = '\0';
|
|||
|
bufend ++;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
bufptr += strlen(bufptr);
|
|||
|
}
|
|||
|
|
|||
|
if (bufptr == buffer || (bufend - bufptr) < 2)
|
|||
|
return (NULL);
|
|||
|
|
|||
|
memcpy(bufptr, "}", 2);
|
|||
|
}
|
|||
|
|
|||
|
return (buffer);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'get_points()' - Get a value in points.
|
|||
|
*/
|
|||
|
|
|||
|
static double /* O - Number in points */
|
|||
|
get_points(double number, /* I - Original number */
|
|||
|
const char *uval) /* I - Units */
|
|||
|
{
|
|||
|
if (!strcmp(uval, "mm")) /* Millimeters */
|
|||
|
return (number * 72.0 / 25.4);
|
|||
|
else if (!strcmp(uval, "cm")) /* Centimeters */
|
|||
|
return (number * 72.0 / 2.54);
|
|||
|
else if (!strcmp(uval, "in")) /* Inches */
|
|||
|
return (number * 72.0);
|
|||
|
else if (!strcmp(uval, "ft")) /* Feet */
|
|||
|
return (number * 72.0 * 12.0);
|
|||
|
else if (!strcmp(uval, "m")) /* Meters */
|
|||
|
return (number * 72.0 / 0.0254);
|
|||
|
else /* Points */
|
|||
|
return (number);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* 'get_printer_ppd()' - Get an IPP Everywhere PPD file for the given URI.
|
|||
|
*/
|
|||
|
|
|||
|
static char * /* O - Filename or NULL */
|
|||
|
get_printer_ppd(const char *uri, /* I - Printer URI */
|
|||
|
char *buffer, /* I - Filename buffer */
|
|||
|
size_t bufsize) /* I - Size of filename buffer */
|
|||
|
{
|
|||
|
http_t *http; /* Connection to printer */
|
|||
|
ipp_t *request, /* Get-Printer-Attributes request */
|
|||
|
*response; /* Get-Printer-Attributes response */
|
|||
|
char resolved[1024], /* Resolved URI */
|
|||
|
scheme[32], /* URI scheme */
|
|||
|
userpass[256], /* Username:password */
|
|||
|
host[256], /* Hostname */
|
|||
|
resource[256]; /* Resource path */
|
|||
|
int port; /* Port number */
|
|||
|
static const char * const pattrs[] = /* Printer attributes we need */
|
|||
|
{
|
|||
|
"all",
|
|||
|
"media-col-database"
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
* Connect to the printer...
|
|||
|
*/
|
|||
|
|
|||
|
if (strstr(uri, "._tcp"))
|
|||
|
{
|
|||
|
/*
|
|||
|
* Resolve URI...
|
|||
|
*/
|
|||
|
|
|||
|
if (!_httpResolveURI(uri, resolved, sizeof(resolved), _HTTP_RESOLVE_DEFAULT, NULL, NULL))
|
|||
|
{
|
|||
|
fprintf(stderr, "ERROR: Unable to resolve \"%s\".\n", uri);
|
|||
|
return (NULL);
|
|||
|
}
|
|||
|
|
|||
|
uri = resolved;
|
|||
|
}
|
|||
|
|
|||
|
if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
|
|||
|
{
|
|||
|
fprintf(stderr, "ERROR: Bad printer URI \"%s\".\n", uri);
|
|||
|
return (NULL);
|
|||
|
}
|
|||
|
|
|||
|
http = httpConnect2(host, port, NULL, AF_UNSPEC, !strcmp(scheme, "ipps") ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
|
|||
|
if (!http)
|
|||
|
{
|
|||
|
fprintf(stderr, "ERROR: Unable to connect to \"%s:%d\": %s\n", host, port, cupsLastErrorString());
|
|||
|
return (NULL);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
* Send a Get-Printer-Attributes request...
|
|||
|
*/
|
|||
|
|
|||
|
request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
|
|||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri);
|
|||
|
ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs);
|
|||
|
response = cupsDoRequest(http, request, resource);
|
|||
|
|
|||
|
if (!_ppdCreateFromIPP(buffer, bufsize, response))
|
|||
|
fprintf(stderr, "ERROR: Unable to create PPD file: %s\n", strerror(errno));
|
|||
|
|
|||
|
ippDelete(response);
|
|||
|
httpClose(http);
|
|||
|
|
|||
|
if (buffer[0])
|
|||
|
return (buffer);
|
|||
|
else
|
|||
|
return (NULL);
|
|||
|
}
|