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

3810 lines
98 KiB

This file contains invisible Unicode characters!

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

/*
* 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);
}