/*
- * "$Id: ipp.c 6433 2007-04-02 21:50:50Z mike $"
+ * "$Id: ipp.c 7014 2007-10-10 21:57:43Z mike $"
*
* IPP routines for the Common UNIX Printing System (CUPS) scheduler.
*
+ * Copyright 2007 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* This file contains Kerberos support code, copyright 2006 by
* Jelmer Vernooij.
*
* These coded instructions, statements, and computer programs are the
- * property of Easy Software Products and are protected by Federal
- * copyright law. Distribution and use rights are outlined in the file
- * "LICENSE.txt" which should have been included with this file. If this
- * file is missing or damaged please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
* Contents:
*
- * cupsdProcessIPPRequest() - Process an incoming IPP request...
+ * cupsdProcessIPPRequest() - Process an incoming IPP request.
+ * cupsdTimeoutJob() - Timeout a job waiting on job files.
* accept_jobs() - Accept print jobs to a printer.
* add_class() - Add a class to the system.
* add_file() - Add a file to a job.
* get_default() - Get the default destination.
* get_devices() - Get the list of available devices on the
* local system.
+ * get_document() - Get a copy of a job file.
* get_job_attrs() - Get job attributes.
* get_jobs() - Get a list of jobs for the specified printer.
* get_notifications() - Get events for a subscription.
+ * get_ppd() - Get a named PPD from the local system.
* get_ppds() - Get the list of PPD files on the local
* system.
* get_printer_attrs() - Get printer attributes.
* start_printer() - Start a printer.
* stop_printer() - Stop a printer.
* url_encode_attr() - URL-encode a string attribute.
+ * url_encode_string() - URL-encode a string.
* user_allowed() - See if a user is allowed to print to a queue.
* validate_job() - Validate printer options and destination.
* validate_name() - Make sure the printer name only contains
#include "cupsd.h"
-#ifdef HAVE_KRB5_H
-# include <krb5.h>
-#endif /* HAVE_KRB5_H */
-
#ifdef HAVE_LIBPAPER
# include <paper.h>
#endif /* HAVE_LIBPAPER */
static void delete_printer(cupsd_client_t *con, ipp_attribute_t *uri);
static void get_default(cupsd_client_t *con);
static void get_devices(cupsd_client_t *con);
+static void get_document(cupsd_client_t *con, ipp_attribute_t *uri);
static void get_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
static void get_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
static void get_notifications(cupsd_client_t *con);
+static void get_ppd(cupsd_client_t *con, ipp_attribute_t *uri);
static void get_ppds(cupsd_client_t *con);
static void get_printers(cupsd_client_t *con, int type);
static void get_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
static void stop_printer(cupsd_client_t *con, ipp_attribute_t *uri);
static void url_encode_attr(ipp_attribute_t *attr, char *buffer,
int bufsize);
+static char *url_encode_string(const char *s, char *buffer, int bufsize);
static int user_allowed(cupsd_printer_t *p, const char *username);
static void validate_job(cupsd_client_t *con, ipp_attribute_t *uri);
static int validate_name(const char *name);
/*
- * 'cupsdProcessIPPRequest()' - Process an incoming IPP request...
+ * 'cupsdProcessIPPRequest()' - Process an incoming IPP request.
*/
int /* O - 1 on success, 0 on failure */
con->response = ippNew();
- con->response->request.status.version[0] = con->request->request.op.version[0];
- con->response->request.status.version[1] = con->request->request.op.version[1];
- con->response->request.status.request_id = con->request->request.op.request_id;
+ con->response->request.status.version[0] =
+ con->request->request.op.version[0];
+ con->response->request.status.version[1] =
+ con->request->request.op.version[1];
+ con->response->request.status.request_id =
+ con->request->request.op.request_id;
/*
* Then validate the request header and required attributes...
else if ((attr = ippFindAttribute(con->request, "job-uri",
IPP_TAG_URI)) != NULL)
uri = attr;
+ else if (con->request->request.op.operation_id == CUPS_GET_PPD)
+ uri = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME);
else
uri = NULL;
if (charset)
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
- "attributes-charset", NULL, charset->values[0].string.text);
+ "attributes-charset", NULL,
+ charset->values[0].string.text);
else
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
"attributes-charset", NULL, DefaultCharset);
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, DefaultLanguage);
- if (!charset || !language ||
- (!uri &&
- con->request->request.op.operation_id != CUPS_GET_DEFAULT &&
- con->request->request.op.operation_id != CUPS_GET_PRINTERS &&
- con->request->request.op.operation_id != CUPS_GET_CLASSES &&
- con->request->request.op.operation_id != CUPS_GET_DEVICES &&
- con->request->request.op.operation_id != CUPS_GET_PPDS))
+ if (charset &&
+ strcasecmp(charset->values[0].string.text, "us-ascii") &&
+ strcasecmp(charset->values[0].string.text, "utf-8"))
+ {
+ /*
+ * Bad character set...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unsupported character set \"%s\"!",
+ charset->values[0].string.text);
+ cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
+ "%04X %s Unsupported attributes-charset value \"%s\"",
+ IPP_CHARSET, con->http.hostname,
+ charset->values[0].string.text);
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Unsupported character set \"%s\"!"),
+ charset->values[0].string.text);
+ }
+ else if (!charset || !language ||
+ (!uri &&
+ con->request->request.op.operation_id != CUPS_GET_DEFAULT &&
+ con->request->request.op.operation_id != CUPS_GET_PRINTERS &&
+ con->request->request.op.operation_id != CUPS_GET_CLASSES &&
+ con->request->request.op.operation_id != CUPS_GET_DEVICES &&
+ con->request->request.op.operation_id != CUPS_GET_PPDS))
{
/*
* Return an error, since attributes-charset,
if (!uri)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
- "Missing printer-uri or job-uri attribute!");
+ "Missing printer-uri, job-uri, or ppd-name "
+ "attribute!");
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
- "%04X %s Missing printer-uri or job-uri attribute",
- IPP_BAD_REQUEST, con->http.hostname);
+ "%04X %s Missing printer-uri, job-uri, or ppd-name "
+ "attribute", IPP_BAD_REQUEST, con->http.hostname);
}
cupsdLogMessage(CUPSD_LOG_DEBUG, "Request attributes follow...");
get_devices(con);
break;
+ case CUPS_GET_DOCUMENT :
+ get_document(con, uri);
+ break;
+
+ case CUPS_GET_PPD :
+ get_ppd(con, uri);
+ break;
+
case CUPS_GET_PPDS :
get_ppds(con);
break;
send_ipp_status(con, IPP_OPERATION_NOT_SUPPORTED,
_("%s not supported!"),
- ippOpString(con->request->request.op.operation_id));
+ ippOpString(
+ con->request->request.op.operation_id));
break;
}
}
length = ippLength(con->response);
+ if (con->file >= 0 && !con->pipe_pid)
+ {
+ struct stat fileinfo; /* File information */
+
+
+ if (!fstat(con->file, &fileinfo))
+ length += fileinfo.st_size;
+ }
+
if (httpPrintf(HTTP(con), "Content-Length: " CUPS_LLFMT "\r\n\r\n",
CUPS_LLCAST length) < 0)
return (0);
con->http.data_encoding = HTTP_ENCODE_LENGTH;
con->http.data_remaining = length;
+
+ if (con->http.data_remaining <= INT_MAX)
+ con->http._data_remaining = con->http.data_remaining;
+ else
+ con->http._data_remaining = INT_MAX;
}
cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient,
}
+/*
+ * 'cupsdTimeoutJob()' - Timeout a job waiting on job files.
+ */
+
+void
+cupsdTimeoutJob(cupsd_job_t *job) /* I - Job to timeout */
+{
+ cupsd_printer_t *printer; /* Destination printer or class */
+ ipp_attribute_t *attr; /* job-sheets attribute */
+ int kbytes; /* Kilobytes in banner */
+
+
+ job->pending_timeout = 0;
+
+ /*
+ * See if we need to add the ending sheet...
+ */
+
+ printer = cupsdFindDest(job->dest);
+ attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
+
+ if (printer &&
+ !(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) &&
+ attr && attr->num_values > 1)
+ {
+ /*
+ * Yes...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Adding end banner page \"%s\".",
+ job->id, attr->values[1].string.text);
+
+ kbytes = copy_banner(NULL, job, attr->values[1].string.text);
+
+ cupsdUpdateQuota(printer, job->username, 0, kbytes);
+ }
+}
+
+
/*
* 'accept_jobs()' - Accept print jobs to a printer.
*/
ipp_attribute_t *uri) /* I - Printer or class URI */
{
http_status_t status; /* Policy status */
- cups_ptype_t dtype; /* Destination type (printer or class) */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
cupsd_printer_t *printer; /* Printer data */
{
cupsdSaveAllPrinters();
- cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" now accepting jobs (\"%s\").",
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Printer \"%s\" now accepting jobs (\"%s\").",
printer->name, get_username(con));
}
return;
}
- /*
- * Check policy...
- */
-
- if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
- {
- send_http_error(con, status, NULL);
- return;
- }
-
/*
* See if the class already exists; if not, create a new class...
*/
*/
if ((pclass = cupsdFindPrinter(resource + 9)) != NULL &&
- !(pclass->type & CUPS_PRINTER_REMOTE))
+ !(pclass->type & CUPS_PRINTER_DISCOVERED))
{
/*
* Yes, return an error...
}
/*
- * No, add the pclass...
+ * No, check the default policy and then add the class...
*/
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
pclass = cupsdAddClass(resource + 9);
modify = 0;
}
else if (pclass->type & CUPS_PRINTER_IMPLICIT)
{
/*
- * Rename the implicit class to "AnyClass" or remove it...
+ * Check the default policy, then rename the implicit class to "AnyClass"
+ * or remove it...
*/
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
if (ImplicitAnyClasses)
{
snprintf(newname, sizeof(newname), "Any%s", resource + 9);
pclass = cupsdAddClass(resource + 9);
modify = 0;
}
- else if (pclass->type & CUPS_PRINTER_REMOTE)
+ else if (pclass->type & CUPS_PRINTER_DISCOVERED)
{
/*
- * Rename the remote class to "Class"...
+ * Check the default policy, then rename the remote class to "Class"...
*/
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
snprintf(newname, sizeof(newname), "%s@%s", resource + 9, pclass->hostname);
cupsdRenamePrinter(pclass, newname);
pclass = cupsdAddClass(resource + 9);
modify = 0;
}
+ else if ((status = cupsdCheckPolicy(pclass->op_policy_ptr, con,
+ NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, pclass);
+ return;
+ }
else
modify = 1;
if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs",
IPP_TAG_BOOLEAN)) != NULL)
{
- cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
- pclass->name, attr->values[0].boolean, pclass->accepting);
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Setting %s printer-is-accepting-jobs to %d (was %d.)",
+ pclass->name, attr->values[0].boolean, pclass->accepting);
pclass->accepting = attr->values[0].boolean;
cupsdAddPrinterHistory(pclass);
return;
}
- cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-state to %d (was %d.)", pclass->name,
- attr->values[0].integer, pclass->state);
+ cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-state to %d (was %d.)",
+ pclass->name, attr->values[0].integer, pclass->state);
if (attr->values[0].integer == IPP_PRINTER_STOPPED)
cupsdStopPrinter(pclass, 0);
set_printer_defaults(con, pclass);
+ if ((attr = ippFindAttribute(con->request, "auth-info-required",
+ IPP_TAG_KEYWORD)) != NULL)
+ cupsdSetAuthInfoRequired(pclass, NULL, attr);
+
/*
* Update the printer class attributes and return...
*/
cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "add_file(con=%p[%d], job=%d, filetype=%s/%s, compression=%d)",
- con, con->http.fd, job->id, filetype->super, filetype->type,
- compression);
+ "add_file(con=%p[%d], job=%d, filetype=%s/%s, "
+ "compression=%d)", con, con ? con->http.fd : -1, job->id,
+ filetype->super, filetype->type, compression);
/*
* Add the file to the job...
{
cupsdCancelJob(job, 1, IPP_JOB_ABORTED);
- send_ipp_status(con, IPP_INTERNAL_ERROR,
- _("Unable to allocate memory for file types!"));
+ if (con)
+ send_ipp_status(con, IPP_INTERNAL_ERROR,
+ _("Unable to allocate memory for file types!"));
+
return (-1);
}
cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %p(%s), %p(%s/%s))",
con, con->http.fd, printer, printer->name,
- filetype, filetype->super, filetype->type);
+ filetype, filetype ? filetype->super : "none",
+ filetype ? filetype->type : "none");
/*
* Check remote printing to non-shared printer...
return (NULL);
}
- if (!check_quotas(con, printer))
+ if ((i = check_quotas(con, printer)) < 0)
{
send_ipp_status(con, IPP_NOT_POSSIBLE, _("Quota limit reached."));
return (NULL);
}
+ else if (i == 0)
+ {
+ send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Not allowed to print."));
+ return (NULL);
+ }
/*
* Create the job and set things up...
if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)))
{
cupsdLogMessage(CUPSD_LOG_INFO,
- "Adding start banner page \"%s\" to job %d.",
- attr->values[0].string.text, job->id);
+ "[Job %d] Adding start banner page \"%s\".",
+ job->id, attr->values[0].string.text);
kbytes = copy_banner(con, job, attr->values[0].string.text);
{
http_status_t status; /* Policy status */
int i; /* Looping var */
- char method[HTTP_MAX_URI], /* Method portion of URI */
+ char scheme[HTTP_MAX_URI], /* Method portion of URI */
username[HTTP_MAX_URI], /* Username portion of URI */
host[HTTP_MAX_URI], /* Host portion of URI */
resource[HTTP_MAX_URI]; /* Resource portion of URI */
int modify; /* Non-zero if we are modifying */
char newname[IPP_MAX_NAME]; /* New printer name */
int need_restart_job; /* Need to restart job? */
+ int set_device_uri, /* Did we set the device URI? */
+ set_port_monitor; /* Did we set the port monitor? */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer(%p[%d], %s)", con,
* Do we have a valid URI?
*/
- httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
- sizeof(method), username, sizeof(username), host,
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
sizeof(host), &port, resource, sizeof(resource));
if (strncmp(resource, "/printers/", 10) || strlen(resource) == 10)
return;
}
- /*
- * Check policy...
- */
-
- if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
- {
- send_http_error(con, status, NULL);
- return;
- }
-
/*
* See if the printer already exists; if not, create a new printer...
*/
*/
if ((printer = cupsdFindClass(resource + 10)) != NULL &&
- !(printer->type & CUPS_PRINTER_REMOTE))
+ !(printer->type & CUPS_PRINTER_DISCOVERED))
{
/*
* Yes, return an error...
}
/*
- * No, add the printer...
+ * No, check the default policy then add the printer...
*/
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
printer = cupsdAddPrinter(resource + 10);
modify = 0;
}
else if (printer->type & CUPS_PRINTER_IMPLICIT)
{
/*
- * Rename the implicit printer to "AnyPrinter" or delete it...
+ * Check the default policy, then rename the implicit printer to
+ * "AnyPrinter" or delete it...
*/
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
if (ImplicitAnyClasses)
{
snprintf(newname, sizeof(newname), "Any%s", resource + 10);
printer = cupsdAddPrinter(resource + 10);
modify = 0;
}
- else if (printer->type & CUPS_PRINTER_REMOTE)
+ else if (printer->type & CUPS_PRINTER_DISCOVERED)
{
/*
- * Rename the remote printer to "Printer@server"...
+ * Check the default policy, then rename the remote printer to
+ * "Printer@server"...
*/
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
snprintf(newname, sizeof(newname), "%s@%s", resource + 10,
printer->hostname);
cupsdRenamePrinter(printer, newname);
printer = cupsdAddPrinter(resource + 10);
modify = 0;
}
+ else if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
+ NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
else
modify = 1;
IPP_TAG_TEXT)) != NULL)
cupsdSetString(&printer->info, attr->values[0].string.text);
+ set_device_uri = 0;
+
if ((attr = ippFindAttribute(con->request, "device-uri",
IPP_TAG_URI)) != NULL)
{
* Do we have a valid device URI?
*/
+ http_uri_status_t uri_status; /* URI separation status */
+
+
need_restart_job = 1;
- httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, method,
- sizeof(method), username, sizeof(username), host,
- sizeof(host), &port, resource, sizeof(resource));
+ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL,
+ attr->values[0].string.text,
+ scheme, sizeof(scheme),
+ username, sizeof(username),
+ host, sizeof(host), &port,
+ resource, sizeof(resource));
+
+ if (uri_status < HTTP_URI_OK)
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad device-uri \"%s\"!"),
+ attr->values[0].string.text);
+ cupsdLogMessage(CUPSD_LOG_DEBUG,
+ "add_printer: httpSeparateURI returned %d", uri_status);
+ return;
+ }
- if (!strcmp(method, "file"))
+ if (!strcmp(scheme, "file"))
{
/*
* See if the administrator has enabled file devices...
* See if the backend exists and is executable...
*/
- snprintf(srcfile, sizeof(srcfile), "%s/backend/%s", ServerBin, method);
+ snprintf(srcfile, sizeof(srcfile), "%s/backend/%s", ServerBin, scheme);
if (access(srcfile, X_OK))
{
/*
sizeof(resource)));
cupsdSetString(&printer->device_uri, attr->values[0].string.text);
+ set_device_uri = 1;
}
+ set_port_monitor = 0;
+
if ((attr = ippFindAttribute(con->request, "port-monitor",
- IPP_TAG_KEYWORD)) != NULL)
+ IPP_TAG_NAME)) != NULL)
{
ipp_attribute_t *supported; /* port-monitor-supported attribute */
need_restart_job = 1;
supported = ippFindAttribute(printer->attrs, "port-monitor-supported",
- IPP_TAG_KEYWORD);
+ IPP_TAG_NAME);
for (i = 0; i < supported->num_values; i ++)
if (!strcmp(supported->values[i].string.text,
attr->values[0].string.text))
cupsdLogMessage(CUPSD_LOG_INFO,
"Setting %s port-monitor to \"%s\" (was \"%s\".)",
printer->name, attr->values[0].string.text,
- printer->port_monitor);
+ printer->port_monitor ? printer->port_monitor : "none");
if (strcmp(attr->values[0].string.text, "none"))
cupsdSetString(&printer->port_monitor, attr->values[0].string.text);
else
cupsdClearString(&printer->port_monitor);
+
+ set_port_monitor = 1;
}
if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs",
return;
}
- cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-state to %d (was %d.)", printer->name,
- attr->values[0].integer, printer->state);
+ cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-state to %d (was %d.)",
+ printer->name, attr->values[0].integer, printer->state);
if (attr->values[0].integer == IPP_PRINTER_STOPPED)
cupsdStopPrinter(printer, 0);
set_printer_defaults(con, printer);
+ if ((attr = ippFindAttribute(con->request, "auth-info-required",
+ IPP_TAG_KEYWORD)) != NULL)
+ cupsdSetAuthInfoRequired(printer, NULL, attr);
+
/*
* See if we have all required attributes...
*/
}
}
+ /*
+ * If we set the device URI but not the port monitor, check which port
+ * monitor to use by default...
+ */
+
+ if (set_device_uri && !set_port_monitor)
+ {
+ ppd_file_t *ppd; /* PPD file */
+ ppd_attr_t *ppdattr; /* cupsPortMonitor attribute */
+
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, printer->device_uri, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ snprintf(srcfile, sizeof(srcfile), "%s/ppd/%s.ppd", ServerRoot,
+ printer->name);
+ if ((ppd = ppdOpenFile(srcfile)) != NULL)
+ {
+ for (ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
+ ppdattr;
+ ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
+ if (!strcmp(scheme, ppdattr->spec))
+ {
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Setting %s port-monitor to \"%s\" (was \"%s\".)",
+ printer->name, ppdattr->value,
+ printer->port_monitor ? printer->port_monitor
+ : "none");
+
+ if (strcmp(ppdattr->value, "none"))
+ cupsdSetString(&printer->port_monitor, ppdattr->value);
+ else
+ cupsdClearString(&printer->port_monitor);
+
+ break;
+ }
+
+ ppdClose(ppd);
+ }
+ }
+
/*
* Update the printer attributes and return...
*/
if (!con->username[0] && !auth_info)
{
- send_ipp_status(con, IPP_NOT_AUTHORIZED,
- _("No authentication information provided!"));
+ cupsd_printer_t *printer; /* Job destination */
+
+
+ /*
+ * No auth data. If we need to authenticate via Kerberos, send a
+ * HTTP auth challenge, otherwise just return an IPP error...
+ */
+
+ printer = cupsdFindDest(job->dest);
+
+ if (printer && printer->num_auth_info_required > 0 &&
+ !strcmp(printer->auth_info_required[0], "negotiate"))
+ send_http_error(con, HTTP_UNAUTHORIZED, printer);
+ else
+ send_ipp_status(con, IPP_NOT_AUTHORIZED,
+ _("No authentication information provided!"));
return;
}
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED, NULL);
+ send_http_error(con, HTTP_UNAUTHORIZED, cupsdFindDest(job->dest));
return;
}
cupsdReleaseJob(job);
- cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was authenticated by \"%s\".", jobid,
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Authenticated by \"%s\".", jobid,
con->username);
}
resource[HTTP_MAX_URI]; /* Resource portion of URI */
int port; /* Port portion of URI */
cupsd_job_t *job; /* Job information */
- cups_ptype_t dtype; /* Destination type (printer or class) */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
cupsd_printer_t *printer; /* Printer data */
+ int purge; /* Purge the job? */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_job(%p[%d], %s)", con,
jobid = job->id;
else
{
- send_ipp_status(con, IPP_NOT_POSSIBLE, _("No active jobs on %s!"),
- printer->name);
- return;
+ for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
+ job;
+ job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
+ if (job->state_value == IPP_JOB_STOPPED &&
+ !strcasecmp(job->dest, printer->name))
+ break;
+
+ if (job)
+ jobid = job->id;
+ else
+ {
+ send_ipp_status(con, IPP_NOT_POSSIBLE, _("No active jobs on %s!"),
+ printer->name);
+ return;
+ }
}
}
}
jobid = atoi(resource + 6);
}
+ /*
+ * Look for the "purge-job" attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "purge-job",
+ IPP_TAG_BOOLEAN)) != NULL)
+ purge = attr->values[0].boolean;
+ else
+ purge = 0;
+
/*
* See if the job exists...
*/
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED, NULL);
+ send_http_error(con, HTTP_UNAUTHORIZED, cupsdFindDest(job->dest));
return;
}
* we can't cancel...
*/
- if (job->state_value >= IPP_JOB_CANCELED)
+ if (job->state_value >= IPP_JOB_CANCELED && !purge)
{
switch (job->state_value)
{
* Cancel the job and return...
*/
- cupsdCancelJob(job, 0, IPP_JOB_CANCELED);
+ cupsdCancelJob(job, purge, IPP_JOB_CANCELED);
cupsdCheckJobs();
- cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was canceled by \"%s\".", jobid,
- username);
+ if (purge)
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Purged by \"%s\".", jobid,
+ username);
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Canceled by \"%s\".", jobid,
+ username);
con->response->request.status.status_code = IPP_OK;
}
*/
#ifdef __APPLE__
- if (AppleQuotas)
+ if (AppleQuotas && (q = cupsdFindQuota(p, username)) != NULL)
{
/*
* TODO: Define these special page count values as constants!
"quota limit exceeded.",
username, p->name, p->info);
q->page_count = 2; /* force quota exceeded failure */
- return (0);
+ return (-1);
}
else if (q->page_count == -2) /* quota disabled for user */
{
"printing disabled for user.",
username, p->name, p->info);
q->page_count = 2; /* force quota exceeded failure */
- return (0);
+ return (-1);
}
else if (q->page_count == -1) /* quota access error */
{
"unable to determine quota limit.",
username, p->name, p->info);
q->page_count = 2; /* force quota exceeded failure */
- return (0);
+ return (-1);
}
else if (q->page_count < 0) /* user not found or other error */
{
"user disabled / missing quota.",
username, p->name, p->info);
q->page_count = 2; /* force quota exceeded failure */
- return (0);
+ return (-1);
}
else /* page within user limits */
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to allocate quota data for user \"%s\"!",
username);
- return (0);
+ return (-1);
}
if ((q->k_count >= p->k_limit && p->k_limit) ||
{
cupsdLogMessage(CUPSD_LOG_INFO, "User \"%s\" is over the quota limit...",
username);
- return (0);
+ return (-1);
}
}
else
{
for (i = 0; i < attr->num_values; i ++)
- toattr->values[i].string.text = _cupsStrAlloc(attr->values[i].string.text);
+ toattr->values[i].string.text =
+ _cupsStrAlloc(attr->values[i].string.text);
}
break;
toattr->values[i].string.charset =
toattr->values[0].string.charset;
- toattr->values[i].string.text = _cupsStrAlloc(attr->values[i].string.text);
+ toattr->values[i].string.text =
+ _cupsStrAlloc(attr->values[i].string.text);
}
}
break;
cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_banner(%p[%d], %p[%d], %s)",
- con, con->http.fd, job, job->id, name ? name : "(null)");
+ con, con ? con->http.fd : -1, job, job->id,
+ name ? name : "(null)");
/*
* Find the banner; return if not found or "none"...
{
fd_set input; /* select() input set */
struct timeval timeout; /* select() timeout */
- int maxfd; /* Maximum file descriptor for select() */
+ int maxfd; /* Max file descriptor for select() */
char tempfile[1024]; /* Temporary PPD file */
int tempfd; /* Temporary PPD file descriptor */
int temppid; /* Process ID of cups-driverd */
con->servername, con->serverport, "/jobs/%d",
job->id);
+ if (!ra || cupsArrayFind(ra, "document-count"))
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "document-count", job->num_files);
+
if (!ra || cupsArrayFind(ra, "job-more-info"))
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
"job-more-info", NULL, job_uri);
if ((job = add_job(con, printer, NULL)) == NULL)
return;
+ job->pending_timeout = 1;
+
/*
* Save and log the job...
*/
cupsdSaveJob(job);
- cupsdLogMessage(CUPSD_LOG_INFO, "Job %d created on \"%s\" by \"%s\".",
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Queued on \"%s\" by \"%s\".",
job->id, job->dest, job->username);
}
http_status_t status; /* Policy status */
int i; /* Looping var */
ipp_attribute_t *attr; /* Current attribute */
- cups_ptype_t dtype; /* Destination type (printer or class) */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
char scheme[HTTP_MAX_URI],
/* Scheme portion of URI */
userpass[HTTP_MAX_URI],
cupsd_job_t *job; /* Job */
int jobid; /* Job ID */
cupsd_subscription_t *sub; /* Subscription object */
- const char *username, /* requesting-user-name or authenticated username */
+ const char *username, /* requesting-user-name or
+ authenticated username */
*recipient, /* notify-recipient-uri */
*pullmethod; /* notify-pull-method */
ipp_attribute_t *user_data; /* notify-user-data */
if (access(notifier, X_OK))
{
send_ipp_status(con, IPP_NOT_POSSIBLE,
- _("notify-recipient-uri URI \"%s\" uses unknown scheme!"),
- recipient);
+ _("notify-recipient-uri URI \"%s\" uses unknown "
+ "scheme!"), recipient);
ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM,
"notify-status-code", IPP_URI_SCHEME);
return;
ipp_attribute_t *uri) /* I - URI of printer or class */
{
http_status_t status; /* Policy status */
- cups_ptype_t dtype; /* Destination type (printer or class) */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
cupsd_printer_t *printer; /* Printer/class */
char filename[1024]; /* Script/PPD filename */
/*
- * 'get_job_attrs()' - Get job attributes.
+ * 'get_document()' - Get a copy of a job file.
*/
static void
-get_job_attrs(cupsd_client_t *con, /* I - Client connection */
- ipp_attribute_t *uri) /* I - Job URI */
+get_document(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job URI */
{
http_status_t status; /* Policy status */
ipp_attribute_t *attr; /* Current attribute */
int jobid; /* Job ID */
+ int docnum; /* Document number */
cupsd_job_t *job; /* Current job */
char method[HTTP_MAX_URI], /* Method portion of URI */
username[HTTP_MAX_URI], /* Username portion of URI */
host[HTTP_MAX_URI], /* Host portion of URI */
resource[HTTP_MAX_URI]; /* Resource portion of URI */
int port; /* Port portion of URI */
- cups_array_t *ra; /* Requested attributes array */
+ char filename[1024], /* Filename for document */
+ format[1024]; /* Format for document */
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_job_attrs(%p[%d], %s)", con,
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_document(%p[%d], %s)", con,
con->http.fd, uri->values[0].string.text);
/*
}
/*
- * Copy attributes...
+ * Get the document number...
*/
+ if ((attr = ippFindAttribute(con->request, "document-number",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Missing document-number attribute!"));
+ return;
+ }
+
+ if ((docnum = attr->values[0].integer) < 1 || docnum > job->num_files ||
+ attr->num_values > 1)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND, _("Document %d not found in job %d."),
+ docnum, jobid);
+ return;
+ }
+
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, jobid,
+ docnum);
+ if ((con->file = open(filename, O_RDONLY)) == -1)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to open document %d in job %d - %s", docnum, jobid,
+ strerror(errno));
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("Unable to open document %d in job %d!"), docnum, jobid);
+ return;
+ }
+
+ fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+
cupsdLoadJob(job);
- ra = create_requested_array(con->request);
- copy_job_attrs(con, job, ra);
- cupsArrayDelete(ra);
+ snprintf(format, sizeof(format), "%s/%s", job->filetypes[docnum - 1]->super,
+ job->filetypes[docnum - 1]->type);
- con->response->request.status.status_code = IPP_OK;
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format",
+ NULL, format);
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "document-number",
+ docnum);
+ if ((attr = ippFindAttribute(job->attrs, "document-name",
+ IPP_TAG_NAME)) != NULL)
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "document-name",
+ NULL, attr->values[0].string.text);
}
/*
- * 'get_jobs()' - Get a list of jobs for the specified printer.
+ * 'get_job_attrs()' - Get job attributes.
*/
static void
-get_jobs(cupsd_client_t *con, /* I - Client connection */
- ipp_attribute_t *uri) /* I - Printer URI */
+get_job_attrs(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job URI */
{
http_status_t status; /* Policy status */
ipp_attribute_t *attr; /* Current attribute */
- const char *dest; /* Destination */
- cups_ptype_t dtype; /* Destination type (printer or class) */
- cups_ptype_t dmask; /* Destination type mask */
- char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
+ int jobid; /* Job ID */
+ cupsd_job_t *job; /* Current job */
+ char method[HTTP_MAX_URI], /* Method portion of URI */
username[HTTP_MAX_URI], /* Username portion of URI */
host[HTTP_MAX_URI], /* Host portion of URI */
resource[HTTP_MAX_URI]; /* Resource portion of URI */
int port; /* Port portion of URI */
- int completed; /* Completed jobs? */
- int first_job_id; /* First job ID */
- int limit; /* Maximum number of jobs to return */
- int count; /* Number of jobs that match */
- cupsd_job_t *job; /* Current job pointer */
- cupsd_printer_t *printer; /* Printer */
- cups_array_t *list; /* Which job list... */
cups_array_t *ra; /* Requested attributes array */
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs(%p[%d], %s)", con, con->http.fd,
- uri->values[0].string.text);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_job_attrs(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
/*
- * Is the destination valid?
+ * See if we have a job URI or a printer URI...
*/
- httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
- sizeof(scheme), username, sizeof(username), host,
- sizeof(host), &port, resource, sizeof(resource));
-
- if (!strcmp(resource, "/") ||
- (!strncmp(resource, "/jobs", 5) && strlen(resource) <= 6))
+ if (!strcmp(uri->name, "printer-uri"))
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Got a printer-uri attribute but no job-id!"));
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
+ sizeof(method), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (strncmp(resource, "/jobs/", 6))
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Bad job-uri attribute \"%s\"!"),
+ uri->values[0].string.text);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = cupsdFindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid);
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ /*
+ * Copy attributes...
+ */
+
+ cupsdLoadJob(job);
+
+ ra = create_requested_array(con->request);
+ copy_job_attrs(con, job, ra);
+ cupsArrayDelete(ra);
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
+ * 'get_jobs()' - Get a list of jobs for the specified printer.
+ */
+
+static void
+get_jobs(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ http_status_t status; /* Policy status */
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *dest; /* Destination */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cups_ptype_t dmask; /* Destination type mask */
+ char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ int completed; /* Completed jobs? */
+ int first_job_id; /* First job ID */
+ int limit; /* Maximum number of jobs to return */
+ int count; /* Number of jobs that match */
+ cupsd_job_t *job; /* Current job pointer */
+ cupsd_printer_t *printer; /* Printer */
+ cups_array_t *list; /* Which job list... */
+ cups_array_t *ra; /* Requested attributes array */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs(%p[%d], %s)", con, con->http.fd,
+ uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme,
+ sizeof(scheme), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (!strcmp(resource, "/") ||
+ (!strncmp(resource, "/jobs", 5) && strlen(resource) <= 6))
{
dest = NULL;
dtype = (cups_ptype_t)0;
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: job->id = %d", job->id);
+ if (!job->dest || !job->username)
+ cupsdLoadJob(job);
+
+ if (!job->dest || !job->username)
+ continue;
+
if ((dest && strcmp(job->dest, dest)) &&
(!job->printer || !dest || strcmp(job->printer->name, dest)))
continue;
}
+/*
+ * 'get_ppd()' - Get a named PPD from the local system.
+ */
+
+static void
+get_ppd(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Printer URI or PPD name */
+{
+ http_status_t status; /* Policy status */
+ cupsd_printer_t *dest; /* Destination */
+ cups_ptype_t dtype; /* Destination type */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppd(%p[%d], %p[%s=%s])", con,
+ con->http.fd, uri, uri->name, uri->values[0].string.text);
+
+ if (!strcmp(uri->name, "ppd-name"))
+ {
+ /*
+ * Return a PPD file from cups-driverd...
+ */
+
+ char command[1024], /* cups-driverd command */
+ options[1024], /* Options to pass to command */
+ ppd_name[1024]; /* ppd-name */
+
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ /*
+ * Run cups-driverd command with the given options...
+ */
+
+ snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin);
+ url_encode_string(uri->values[0].string.text, ppd_name, sizeof(ppd_name));
+ snprintf(options, sizeof(options), "get+%d+%s",
+ con->request->request.op.request_id, ppd_name);
+
+ if (cupsdSendCommand(con, command, options, 0))
+ {
+ /*
+ * Command started successfully, don't send an IPP response here...
+ */
+
+ ippDelete(con->response);
+ con->response = NULL;
+ }
+ else
+ {
+ /*
+ * Command failed, return "internal error" so the user knows something
+ * went wrong...
+ */
+
+ send_ipp_status(con, IPP_INTERNAL_ERROR,
+ _("cups-driverd failed to execute."));
+ }
+ }
+ else if (!strcmp(uri->name, "printer-uri") &&
+ cupsdValidateDest(uri->values[0].string.text, &dtype, &dest))
+ {
+ int i; /* Looping var */
+ char filename[1024]; /* PPD filename */
+
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(dest->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, dest);
+ return;
+ }
+
+ /*
+ * See if we need the PPD for a class or remote printer...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
+ dest->name);
+
+ if ((dtype & CUPS_PRINTER_REMOTE) && access(filename, 0))
+ {
+ con->response->request.status.status_code = CUPS_SEE_OTHER;
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, dest->uri);
+ return;
+ }
+ else if (dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ {
+ for (i = 0; i < dest->num_printers; i ++)
+ if (!(dest->printers[i]->type &
+ (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)))
+ {
+ snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
+ dest->printers[i]->name);
+
+ if (!access(filename, 0))
+ break;
+ }
+
+ if (i < dest->num_printers)
+ dest = dest->printers[i];
+ else
+ {
+ con->response->request.status.status_code = CUPS_SEE_OTHER;
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, dest->printers[0]->uri);
+ return;
+ }
+ }
+
+ /*
+ * Found the printer with the PPD file, now see if there is one...
+ */
+
+ if ((con->file = open(filename, O_RDONLY)) < 0)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The PPD file \"%s\" could not be opened: %s"),
+ uri->values[0].string.text, strerror(errno));
+ return;
+ }
+
+ fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+
+ con->pipe_pid = 0;
+
+ con->response->request.status.status_code = IPP_OK;
+ }
+ else
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The PPD file \"%s\" could not be found."),
+ uri->values[0].string.text);
+}
+
+
/*
* 'get_ppds()' - Get the list of PPD files on the local system.
*/
{
http_status_t status; /* Policy status */
ipp_attribute_t *limit, /* Limit attribute */
+ *device, /* ppd-device-id attribute */
+ *language, /* ppd-natural-language attribute */
*make, /* ppd-make attribute */
+ *model, /* ppd-make-and-model attribute */
+ *model_number, /* ppd-model-number attribute */
+ *product, /* ppd-product attribute */
+ *psversion, /* ppd-psverion attribute */
+ *type, /* ppd-type attribute */
*requested; /* requested-attributes attribute */
- char command[1024], /* cups-deviced command */
+ char command[1024], /* cups-driverd command */
options[1024], /* Options to pass to command */
- requested_str[256],
+ device_str[256],/* Escaped ppd-device-id string */
+ language_str[256],
+ /* Escaped ppd-natural-language */
+ make_str[256], /* Escaped ppd-make string */
+ model_str[256], /* Escaped ppd-make-and-model string */
+ model_number_str[256],
+ /* ppd-model-number string */
+ product_str[256],
+ /* Escaped ppd-product string */
+ psversion_str[256],
+ /* Escaped ppd-psversion string */
+ type_str[256], /* Escaped ppd-type string */
+ requested_str[256];
/* String for requested attributes */
- make_str[256]; /* Escaped ppd-make string */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppds(%p[%d])", con, con->http.fd);
* Run cups-driverd command with the given options...
*/
- limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
- make = ippFindAttribute(con->request, "ppd-make", IPP_TAG_TEXT);
- requested = ippFindAttribute(con->request, "requested-attributes",
- IPP_TAG_KEYWORD);
+ limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
+ device = ippFindAttribute(con->request, "ppd-device-id", IPP_TAG_TEXT);
+ language = ippFindAttribute(con->request, "ppd-natural-language",
+ IPP_TAG_LANGUAGE);
+ make = ippFindAttribute(con->request, "ppd-make", IPP_TAG_TEXT);
+ model = ippFindAttribute(con->request, "ppd-make-and-model",
+ IPP_TAG_TEXT);
+ model_number = ippFindAttribute(con->request, "ppd-model-number",
+ IPP_TAG_INTEGER);
+ product = ippFindAttribute(con->request, "ppd-product", IPP_TAG_TEXT);
+ psversion = ippFindAttribute(con->request, "ppd-psversion", IPP_TAG_TEXT);
+ type = ippFindAttribute(con->request, "ppd-type", IPP_TAG_KEYWORD);
+ requested = ippFindAttribute(con->request, "requested-attributes",
+ IPP_TAG_KEYWORD);
if (requested)
url_encode_attr(requested, requested_str, sizeof(requested_str));
else
strlcpy(requested_str, "requested-attributes=all", sizeof(requested_str));
+ if (device)
+ url_encode_attr(device, device_str, sizeof(device_str));
+ else
+ device_str[0] = '\0';
+
+ if (language)
+ url_encode_attr(language, language_str, sizeof(language_str));
+ else
+ language_str[0] = '\0';
+
if (make)
url_encode_attr(make, make_str, sizeof(make_str));
else
make_str[0] = '\0';
+ if (model)
+ url_encode_attr(model, model_str, sizeof(model_str));
+ else
+ model_str[0] = '\0';
+
+ if (model_number)
+ snprintf(model_number_str, sizeof(model_number_str), "ppd-model-number=%d",
+ model_number->values[0].integer);
+ else
+ model_number_str[0] = '\0';
+
+ if (product)
+ url_encode_attr(product, product_str, sizeof(product_str));
+ else
+ product_str[0] = '\0';
+
+ if (psversion)
+ url_encode_attr(psversion, psversion_str, sizeof(psversion_str));
+ else
+ psversion_str[0] = '\0';
+
+ if (type)
+ url_encode_attr(type, type_str, sizeof(type_str));
+ else
+ type_str[0] = '\0';
+
snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin);
- snprintf(options, sizeof(options), "list+%d+%d+%s%s%s",
+ snprintf(options, sizeof(options),
+ "list+%d+%d+%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
con->request->request.op.request_id,
limit ? limit->values[0].integer : 0,
- requested_str, make ? "%20" : "", make_str);
+ requested_str,
+ device ? "%20" : "", device_str,
+ language ? "%20" : "", language_str,
+ make ? "%20" : "", make_str,
+ model ? "%20" : "", model_str,
+ model_number ? "%20" : "", model_number_str,
+ product ? "%20" : "", product_str,
+ psversion ? "%20" : "", psversion_str,
+ type ? "%20" : "", type_str);
if (cupsdSendCommand(con, command, options, 0))
{
ipp_attribute_t *uri) /* I - Printer URI */
{
http_status_t status; /* Policy status */
- cups_ptype_t dtype; /* Destination type (printer or class) */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
cupsd_printer_t *printer; /* Printer/class */
cups_array_t *ra; /* Requested attributes array */
{
http_status_t status; /* Policy status */
ipp_attribute_t *attr; /* Current attribute */
- int limit; /* Maximum number of printers to return */
+ int limit; /* Max number of printers to return */
int count; /* Number of printers that match */
cupsd_printer_t *printer; /* Current printer pointer */
int printer_type, /* printer-type attribute */
cupsd_subscription_t *sub; /* Subscription */
cups_array_t *ra; /* Requested attributes array */
ipp_attribute_t *attr; /* Attribute */
- cups_ptype_t dtype; /* Destination type (printer or class) */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
char scheme[HTTP_MAX_URI],
/* Scheme portion of URI */
username[HTTP_MAX_URI],
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED, NULL);
+ send_http_error(con, HTTP_UNAUTHORIZED, cupsdFindDest(job->dest));
return;
}
"Job job-hold-until value changed by user.");
}
- cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was held by \"%s\".", jobid,
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Held by \"%s\".", jobid,
username);
con->response->request.status.status_code = IPP_OK;
cupsd_job_t *job; /* Current job */
const char *src; /* Source printer/class */
cups_ptype_t stype, /* Source type (printer or class) */
- dtype; /* Destination type (printer or class) */
+ dtype; /* Destination type (printer/class) */
char scheme[HTTP_MAX_URI], /* Scheme portion of URI */
username[HTTP_MAX_URI], /* Username portion of URI */
host[HTTP_MAX_URI], /* Host portion of URI */
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED, NULL);
+ send_http_error(con, HTTP_UNAUTHORIZED, cupsdFindDest(job->dest));
return;
}
return;
}
- cupsdLogMessage(CUPSD_LOG_DEBUG, "print_job: request file type is %s/%s.",
- filetype->super, filetype->type);
-
/*
* Read any embedded job ticket info from PS files...
*/
if ((job = add_job(con, printer, filetype)) == NULL)
return;
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Adding job file of type %s/%s.",
+ job->id, filetype->super, filetype->type);
+
/*
* Update quota data...
*/
* See if we need to add the ending sheet...
*/
- attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
-
- if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) &&
- attr && attr->num_values > 1)
- {
- /*
- * Yes...
- */
-
- cupsdLogMessage(CUPSD_LOG_INFO, "Adding end banner page \"%s\" to job %d.",
- attr->values[1].string.text, job->id);
-
- kbytes = copy_banner(con, job, attr->values[1].string.text);
-
- cupsdUpdateQuota(printer, job->username, 0, kbytes);
- }
+ cupsdTimeoutJob(job);
/*
* Log and save the job...
*/
- cupsdLogMessage(CUPSD_LOG_INFO, "Job %d queued on \"%s\" by \"%s\".", job->id,
- job->dest, job->username);
- cupsdLogMessage(CUPSD_LOG_DEBUG, "Job %d hold_until = %d", job->id,
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Queued on \"%s\" by \"%s\".",
+ job->id, job->dest, job->username);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] hold_until = %d", job->id,
(int)job->hold_until);
cupsdSaveJob(job);
ipp_attribute_t *uri) /* I - Printer or class URI */
{
http_status_t status; /* Policy status */
- cups_ptype_t dtype; /* Destination type (printer or class) */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
cupsd_printer_t *printer; /* Printer data */
ipp_attribute_t *attr; /* printer-state-message text */
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED, NULL);
+ send_http_error(con, HTTP_UNAUTHORIZED, cupsdFindDest(job->dest));
return;
}
cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job,
"Job released by user.");
- cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was released by \"%s\".", jobid,
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Released by \"%s\".", jobid,
username);
con->response->request.status.status_code = IPP_OK;
cupsdSaveAllSubscriptions();
con->response->request.status.status_code = IPP_OK;
+
+ ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+ "notify-lease-duration", sub->lease);
}
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED, NULL);
+ send_http_error(con, HTTP_UNAUTHORIZED, cupsdFindDest(job->dest));
return;
}
cupsdRestartJob(job);
- cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was restarted by \"%s\".", jobid,
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Restarted by \"%s\".", jobid,
username);
con->response->request.status.status_code = IPP_OK;
cupsd_job_t *job, /* I - Job */
ipp_attribute_t *auth_info) /* I - auth-info attribute, if any */
{
- int i; /* Looping var */
- char filename[1024]; /* Job authentication filename */
- cups_file_t *fp; /* Job authentication file */
- char line[2048]; /* Line for file */
+ int i; /* Looping var */
+ char filename[1024]; /* Job authentication filename */
+ cups_file_t *fp; /* Job authentication file */
+ char line[2048]; /* Line for file */
+ cupsd_printer_t *dest; /* Destination printer/class */
/*
if (RunUser)
return;
+ if ((dest = cupsdFindDest(job->dest)) == NULL)
+ return;
+
/*
* Create the authentication file and change permissions...
*/
fchown(cupsFileNumber(fp), 0, 0);
fchmod(cupsFileNumber(fp), 0400);
- if (auth_info)
+ if (auth_info && auth_info->num_values == dest->num_auth_info_required)
{
/*
- * Write 1 to 4 auth values...
+ * Write 1 to 3 auth values...
*/
+ cupsdClearString(&job->auth_username);
+ cupsdClearString(&job->auth_domain);
+ cupsdClearString(&job->auth_password);
+
for (i = 0; i < auth_info->num_values; i ++)
{
httpEncode64_2(line, sizeof(line), auth_info->values[i].string.text,
strlen(auth_info->values[i].string.text));
cupsFilePrintf(fp, "%s\n", line);
+
+ if (!strcmp(dest->auth_info_required[i], "username"))
+ cupsdSetStringf(&job->auth_username, "AUTH_USERNAME=%s",
+ auth_info->values[i].string.text);
+ else if (!strcmp(dest->auth_info_required[i], "domain"))
+ cupsdSetStringf(&job->auth_domain, "AUTH_DOMAIN=%s",
+ auth_info->values[i].string.text);
+ else if (!strcmp(dest->auth_info_required[i], "password"))
+ cupsdSetStringf(&job->auth_password, "AUTH_PASSWORD=%s",
+ auth_info->values[i].string.text);
}
}
- else
+ else if (con->username[0])
{
/*
* Write the authenticated username...
httpEncode64_2(line, sizeof(line), con->username, strlen(con->username));
cupsFilePrintf(fp, "%s\n", line);
+ cupsdSetStringf(&job->auth_username, "AUTH_USERNAME=%s", con->username);
+ cupsdClearString(&job->auth_domain);
+
/*
* Write the authenticated password...
*/
httpEncode64_2(line, sizeof(line), con->password, strlen(con->password));
cupsFilePrintf(fp, "%s\n", line);
+
+ cupsdSetStringf(&job->auth_password, "AUTH_PASSWORD=%s", con->password);
}
/*
cupsFileClose(fp);
#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5_H)
- save_krb5_creds(con, job);
+ if (con->gss_have_creds)
+ save_krb5_creds(con, job);
+ else if (job->ccname)
+ cupsdClearString(&(job->ccname));
#endif /* HAVE_GSSAPI && HAVE_KRB5_H */
}
save_krb5_creds(cupsd_client_t *con, /* I - Client connection */
cupsd_job_t *job) /* I - Job */
{
- krb5_context krb_context; /* Kerberos context */
- krb5_ccache ccache; /* Credentials cache */
- OM_uint32 major_status, /* Major status code */
- minor_status; /* Minor status code */
-
+# if !defined(HAVE_KRB5_CC_NEW_UNIQUE) && !defined(HAVE_HEIMDAL)
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Sorry, your version of Kerberos does not support delegated "
+ "credentials!");
+ return;
-# ifdef __APPLE__
- /*
- * If the weak-linked GSSAPI/Kerberos library is not present, don't try
- * to use it...
- */
+# else
+ krb5_error_code error; /* Kerberos error code */
+ OM_uint32 major_status, /* Major status code */
+ minor_status; /* Minor status code */
+ krb5_principal principal; /* Kerberos principal */
- if (krb5_init_context == NULL)
- {
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "save_krb5_creds: GSSAPI/Kerberos framework is not "
- "present");
- return;
- }
-# endif /* __APPLE__ */
+# ifdef __APPLE__
/*
- * Setup a cached context for the job filters to use...
+ * If the weak-linked GSSAPI/Kerberos library is not present, don't try
+ * to use it...
*/
- if (krb5_init_context(&krb_context))
+ if (krb5_init_context == NULL)
+ return;
+# endif /* __APPLE__ */
+
+ /*
+ * We MUST create a file-based cache because memory-based caches are
+ * only valid for the current process/address space.
+ *
+ * Due to various bugs/features in different versions of Kerberos, we
+ * need either the krb5_cc_new_unique() function or Heimdal's version
+ * of krb5_cc_gen_new() to create a new FILE: credential cache that
+ * can be passed to the backend. These functions create a temporary
+ * file (typically in /tmp) containing the cached credentials, which
+ * are removed when we have successfully printed a job.
+ */
+
+# ifdef HAVE_KRB5_CC_NEW_UNIQUE
+ if ((error = krb5_cc_new_unique(KerberosContext, "FILE", NULL,
+ &(job->ccache))) != 0)
+# else /* HAVE_HEIMDAL */
+ if ((error = krb5_cc_gen_new(KerberosContext, &krb5_fcc_ops,
+ &(job->ccache))) != 0)
+# endif /* HAVE_KRB5_CC_NEW_UNIQUE */
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to create new credentials cache (%d/%s)",
+ error, strerror(errno));
+ job->ccache = NULL;
+ return;
+ }
+
+ if ((error = krb5_parse_name(KerberosContext, con->username, &principal)) != 0)
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize Kerberos context");
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to parse kerberos username (%d/%s)",
+ error, strerror(errno));
+ krb5_cc_destroy(KerberosContext, job->ccache);
+ job->ccache = NULL;
return;
}
-# ifdef HAVE_HEIMDAL
- if (krb5_cc_gen_new(krb_context, &krb5_fcc_ops, &ccache))
-# else
- if (krb5_cc_gen_new(krb_context, &ccache))
-# endif /* HAVE_HEIMDAL */
+ if ((error = krb5_cc_initialize(KerberosContext, job->ccache, principal)))
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create new credentials");
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to initialize credentials cache (%d/%s)", error,
+ strerror(errno));
+ krb5_cc_destroy(KerberosContext, job->ccache);
+ krb5_free_principal(KerberosContext, principal);
+ job->ccache = NULL;
return;
}
+ krb5_free_principal(KerberosContext, principal);
+
+ /*
+ * Copy the user's credentials to the new cache file...
+ */
+
major_status = gss_krb5_copy_ccache(&minor_status, con->gss_delegated_cred,
- ccache);
+ job->ccache);
if (GSS_ERROR(major_status))
{
cupsdLogGSSMessage(CUPSD_LOG_ERROR, major_status, minor_status,
"Unable to import client credentials cache");
- krb5_cc_destroy(krb_context, ccache);
+ krb5_cc_destroy(KerberosContext, job->ccache);
+ job->ccache = NULL;
return;
}
+ /*
+ * Add the KRB5CCNAME environment variable to the job so that the
+ * backend can use the credentials when printing.
+ */
+
cupsdSetStringf(&(job->ccname), "KRB5CCNAME=FILE:%s",
- krb5_cc_get_name(krb_context, ccache));
- krb5_cc_close(krb_context, ccache);
+ krb5_cc_get_name(KerberosContext, job->ccache));
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "[Job %d] save_krb5_creds: %s", job->id,
+ job->ccname);
+# endif /* HAVE_KRB5_CC_NEW_UNIQUE || HAVE_HEIMDAL */
}
#endif /* HAVE_GSSAPI && HAVE_KRB5_H */
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED, NULL);
+ send_http_error(con, HTTP_UNAUTHORIZED, cupsdFindDest(job->dest));
return;
}
* Grab format from client...
*/
- if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2)
+ if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]",
+ super, type) != 2)
{
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"!"),
format->values[0].string.text);
* See if we need to add the ending sheet...
*/
- if (printer &&
- !(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) &&
- (attr = ippFindAttribute(job->attrs, "job-sheets",
- IPP_TAG_ZERO)) != NULL &&
- attr->num_values > 1)
- {
- /*
- * Yes...
- */
-
- cupsdLogMessage(CUPSD_LOG_INFO,
- "Adding end banner page \"%s\" to job %d.",
- attr->values[1].string.text, job->id);
-
- kbytes = copy_banner(con, job, attr->values[1].string.text);
-
- cupsdUpdateQuota(printer, job->username, 0, kbytes);
- }
+ cupsdTimeoutJob(job);
if (job->state_value == IPP_JOB_STOPPED)
{
printer && printer->num_auth_info_required > 0 &&
!strcmp(printer->auth_info_required[0], "negotiate"))
cupsdSendError(con, status, AUTH_NEGOTIATE);
+ else if (printer)
+ {
+ char resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ cupsd_location_t *auth; /* Pointer to authentication element */
+
+
+ if (printer->type & CUPS_PRINTER_CLASS)
+ snprintf(resource, sizeof(resource), "/classes/%s", printer->name);
+ else
+ snprintf(resource, sizeof(resource), "/printers/%s", printer->name);
+
+ if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL ||
+ auth->type == AUTH_NONE)
+ auth = cupsdFindPolicyOp(printer->op_policy_ptr, IPP_PRINT_JOB);
+
+ cupsdSendError(con, status, auth ? auth->type : AUTH_NONE);
+ }
else
cupsdSendError(con, status, AUTH_NONE);
char formatted[1024]; /* Formatted errror message */
- if (message)
- {
- va_start(ap, message);
- vsnprintf(formatted, sizeof(formatted),
- _cupsLangString(con->language, message), ap);
- va_end(ap);
+ va_start(ap, message);
+ vsnprintf(formatted, sizeof(formatted),
+ _cupsLangString(con->language, message), ap);
+ va_end(ap);
- cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s: %s",
- ippOpString(con->request->request.op.operation_id),
- ippErrorString(status), formatted);
- }
- else
- cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s",
- ippOpString(con->request->request.op.operation_id),
- ippErrorString(status));
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s: %s",
+ ippOpString(con->request->request.op.operation_id),
+ ippErrorString(status), formatted);
con->response->request.status.status_code = status;
ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, DefaultLanguage);
- if (message)
- ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_TEXT,
- "status-message", NULL, formatted);
+ ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_TEXT,
+ "status-message", NULL, formatted);
}
ipp_attribute_t *uri) /* I - Printer URI */
{
http_status_t status; /* Policy status */
- cups_ptype_t dtype; /* Destination type (printer or class) */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
cupsd_printer_t *printer; /* Printer */
if (!validate_user(job, con, job->username, username, sizeof(username)))
{
- send_http_error(con, HTTP_UNAUTHORIZED, NULL);
+ send_http_error(con, HTTP_UNAUTHORIZED, cupsdFindDest(job->dest));
return;
}
else if (con->response->request.status.status_code == IPP_OK)
{
job->state->values[0].integer = attr->values[0].integer;
- job->state_value = (ipp_jstate_t)attr->values[0].integer;
+ job->state_value = (ipp_jstate_t)attr->values[0].integer;
event |= CUPSD_EVENT_JOB_STATE;
}
ipp_attribute_t *uri) /* I - Printer URI */
{
http_status_t status; /* Policy status */
- cups_ptype_t dtype; /* Destination type (printer or class) */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
cupsd_printer_t *printer; /* Printer data */
ipp_attribute_t *uri) /* I - Printer URI */
{
http_status_t status; /* Policy status */
- cups_ptype_t dtype; /* Destination type (printer or class) */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
cupsd_printer_t *printer; /* Printer data */
ipp_attribute_t *attr; /* printer-state-message attribute */
{
int i; /* Looping var */
char *bufptr, /* Pointer into buffer */
- *bufend, /* End of buffer */
- *valptr; /* Pointer into value */
+ *bufend; /* End of buffer */
strlcpy(buffer, attr->name, bufsize);
*bufptr++ = '\'';
- for (valptr = attr->values[i].string.text;
- *valptr && bufptr < bufend;
- valptr ++)
- if (*valptr == ' ')
- {
- if (bufptr >= (bufend - 2))
- break;
-
- *bufptr++ = '%';
- *bufptr++ = '2';
- *bufptr++ = '0';
- }
- else if (*valptr == '\'' || *valptr == '\\')
- {
- *bufptr++ = '\\';
- *bufptr++ = *valptr;
- }
- else
- *bufptr++ = *valptr;
+ bufptr = url_encode_string(attr->values[i].string.text,
+ bufptr, bufend - bufptr + 1);
if (bufptr >= bufend)
break;
}
+/*
+ * 'url_encode_string()' - URL-encode a string.
+ */
+
+static char * /* O - End of string */
+url_encode_string(const char *s, /* I - String */
+ char *buffer, /* I - String buffer */
+ int bufsize) /* I - Size of buffer */
+{
+ char *bufptr, /* Pointer into buffer */
+ *bufend; /* End of buffer */
+ static const char *hex = "0123456789ABCDEF";
+ /* Hex digits */
+
+
+ bufptr = buffer;
+ bufend = buffer + bufsize - 1;
+
+ while (*s && bufptr < bufend)
+ {
+ if (*s == ' ' || *s == '%')
+ {
+ if (bufptr >= (bufend - 2))
+ break;
+
+ *bufptr++ = '%';
+ *bufptr++ = hex[(*s >> 4) & 15];
+ *bufptr++ = hex[*s & 15];
+
+ s ++;
+ }
+ else if (*s == '\'' || *s == '\\')
+ {
+ if (bufptr >= (bufend - 1))
+ break;
+
+ *bufptr++ = '\\';
+ *bufptr++ = *s++;
+ }
+ else
+ *bufptr++ = *s++;
+ }
+
+ *bufptr = '\0';
+
+ return (bufptr);
+}
+
+
/*
* 'user_allowed()' - See if a user is allowed to print to a queue.
*/
http_status_t status; /* Policy status */
ipp_attribute_t *attr; /* Current attribute */
ipp_attribute_t *format; /* Document-format attribute */
- cups_ptype_t dtype; /* Destination type (printer or class) */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
char super[MIME_MAX_SUPER],
/* Supertype of file */
type[MIME_MAX_TYPE];
if ((format = ippFindAttribute(con->request, "document-format",
IPP_TAG_MIMETYPE)) != NULL)
{
- if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, type) != 2)
+ if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]",
+ super, type) != 2)
{
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"!"),
format->values[0].string.text);
* 'validate_name()' - Make sure the printer name only contains valid chars.
*/
-static int /* O - 0 if name is no good, 1 if name is good */
+static int /* O - 0 if name is no good, 1 if good */
validate_name(const char *name) /* I - Name to check */
{
const char *ptr; /* Pointer into name */
/*
- * End of "$Id: ipp.c 6433 2007-04-02 21:50:50Z mike $".
+ * End of "$Id: ipp.c 7014 2007-10-10 21:57:43Z mike $".
*/