/*
- * "$Id$"
- *
* IPP routines for the CUPS scheduler.
*
- * Copyright 2007-2015 by Apple Inc.
+ * Copyright 2007-2017 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 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/".
+ * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
*/
/*
cups_array_t *ra,
cups_array_t *exclude);
static void create_job(cupsd_client_t *con, ipp_attribute_t *uri);
+static void create_local_printer(cupsd_client_t *con);
static cups_array_t *create_requested_array(ipp_t *request);
static void create_subscriptions(cupsd_client_t *con, ipp_attribute_t *uri);
static void delete_printer(cupsd_client_t *con, ipp_attribute_t *uri);
static void set_default(cupsd_client_t *con, ipp_attribute_t *uri);
static void set_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
static void set_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
-static void set_printer_defaults(cupsd_client_t *con,
- cupsd_printer_t *printer);
+static int set_printer_defaults(cupsd_client_t *con, cupsd_printer_t *printer);
static void start_printer(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, size_t bufsize);
int sub_id; /* Subscription ID */
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdProcessIPPRequest(%p[%d]): operation_id = %04x",
- con, con->number, con->request->request.op.operation_id);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest(%p[%d]): operation_id=%04x(%s)", con, con->number, con->request->request.op.operation_id, ippOpString(con->request->request.op.operation_id));
+
+ if (LogLevel >= CUPSD_LOG_DEBUG2)
+ {
+ for (group = IPP_TAG_ZERO, attr = ippFirstAttribute(con->request); attr; attr = ippNextAttribute(con->request))
+ {
+ const char *name; /* Attribute name */
+ char value[1024]; /* Attribute value */
+
+ if (group != ippGetGroupTag(attr))
+ {
+ group = ippGetGroupTag(attr);
+ if (group != IPP_TAG_ZERO)
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest: %s", ippTagString(group));
+ }
+
+ if ((name = ippGetName(attr)) == NULL)
+ continue;
+
+ ippAttributeString(attr, value, sizeof(value));
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest: %s %s%s '%s'", name, ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr)), value);
+ }
+ }
/*
* First build an empty response message for this request...
get_notifications(con);
break;
+ case IPP_OP_CUPS_CREATE_LOCAL_PRINTER :
+ create_local_printer(con);
+ break;
+
default :
cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
"%04X %s Operation %04X (%s) not supported",
pclass = cupsdAddClass(resource + 9);
modify = 0;
+
+ pclass->printer_id = NextPrinterId ++;
}
else if ((status = cupsdCheckPolicy(pclass->op_policy_ptr, con,
NULL)) != HTTP_OK)
pclass->accepting ? "Now" : "No longer");
}
- if ((attr = ippFindAttribute(con->request, "printer-is-shared",
- IPP_TAG_BOOLEAN)) != NULL)
+ if ((attr = ippFindAttribute(con->request, "printer-is-shared", IPP_TAG_BOOLEAN)) != NULL)
{
- if (pclass->shared && !attr->values[0].boolean)
+ if (pclass->type & CUPS_PRINTER_REMOTE)
+ {
+ /*
+ * Cannot re-share remote printers.
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Cannot change printer-is-shared for remote queues."));
+ if (!modify)
+ cupsdDeletePrinter(pclass, 0);
+
+ return;
+ }
+
+ if (pclass->shared && !ippGetBoolean(attr, 0))
cupsdDeregisterPrinter(pclass, 1);
cupsdLogMessage(CUPSD_LOG_INFO,
"Setting %s printer-is-shared to %d (was %d.)",
pclass->name, attr->values[0].boolean, pclass->shared);
- pclass->shared = attr->values[0].boolean;
+ pclass->shared = ippGetBoolean(attr, 0);
}
if ((attr = ippFindAttribute(con->request, "printer-state",
send_ipp_status(con, IPP_BAD_REQUEST,
_("Attempt to set %s printer-state to bad value %d."),
pclass->name, attr->values[0].integer);
+ if (!modify)
+ cupsdDeletePrinter(pclass, 0);
+
return;
}
send_ipp_status(con, IPP_NOT_FOUND,
_("The printer or class does not exist."));
+ if (!modify)
+ cupsdDeletePrinter(pclass, 0);
+
return;
}
else if (dtype & CUPS_PRINTER_CLASS)
{
send_ipp_status(con, IPP_BAD_REQUEST,
_("Nested classes are not allowed."));
+ if (!modify)
+ cupsdDeletePrinter(pclass, 0);
+
return;
}
}
}
- set_printer_defaults(con, pclass);
+ if (!set_printer_defaults(con, pclass))
+ {
+ if (!modify)
+ cupsdDeletePrinter(pclass, 0);
+
+ return;
+ }
if ((attr = ippFindAttribute(con->request, "auth-info-required",
IPP_TAG_KEYWORD)) != NULL)
_("Bad job-name value: Wrong type or count."));
if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL)
attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
- return (NULL);
+
+ if (StrictConformance)
+ return (NULL);
+
+ /* Don't use invalid attribute */
+ ippDeleteAttribute(con->request, attr);
+
+ ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled");
}
else if (!ippValidateAttribute(attr))
{
send_ipp_status(con, IPP_ATTRIBUTES, _("Bad job-name value: %s"),
cupsLastErrorString());
+
if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL)
attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
- return (NULL);
+
+ if (StrictConformance)
+ return (NULL);
+
+ /* Don't use invalid attribute */
+ ippDeleteAttribute(con->request, attr);
+
+ ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled");
+ }
+
+ attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME);
+
+ if (attr && !ippValidateAttribute(attr))
+ {
+ send_ipp_status(con, IPP_ATTRIBUTES, _("Bad requesting-user-name value: %s"), cupsLastErrorString());
+
+ if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL)
+ attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP;
+
+ if (StrictConformance)
+ return (NULL);
+
+ /* Don't use invalid attribute */
+ ippDeleteAttribute(con->request, attr);
+
+ attr = ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "requesting-user-name", NULL, "anonymous");
}
if ((job = cupsdAddJob(priority, printer->name)) == NULL)
add_job_uuid(job);
apply_printer_defaults(printer, job);
- attr = ippFindAttribute(job->attrs, "requesting-user-name", IPP_TAG_NAME);
-
if (con->username[0])
{
cupsdSetString(&job->username, con->username);
attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
"job-hold-until", NULL, val);
}
- if (attr && strcmp(attr->values[0].string.text, "no-hold"))
+
+ if (printer->holding_new_jobs)
+ {
+ /*
+ * Hold all new jobs on this printer...
+ */
+
+ if (attr && strcmp(attr->values[0].string.text, "no-hold"))
+ cupsdSetJobHoldUntil(job, ippGetString(attr, 0, NULL), 0);
+ else
+ cupsdSetJobHoldUntil(job, "indefinite", 0);
+
+ job->state->values[0].integer = IPP_JOB_HELD;
+ job->state_value = IPP_JOB_HELD;
+
+ ippSetString(job->attrs, &job->reasons, 0, "job-held-on-create");
+ }
+ else if (attr && strcmp(attr->values[0].string.text, "no-hold"))
{
/*
* Hold job until specified time...
printer = cupsdAddPrinter(resource + 10);
modify = 0;
+
+ printer->printer_id = NextPrinterId ++;
}
else if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
NULL)) != HTTP_OK)
changed_driver = 0;
need_restart_job = 0;
+ if ((attr = ippFindAttribute(con->request, "printer-is-temporary", IPP_TAG_BOOLEAN)) != NULL)
+ printer->temporary = ippGetBoolean(attr, 0);
+
if ((attr = ippFindAttribute(con->request, "printer-location",
IPP_TAG_TEXT)) != NULL)
cupsdSetString(&printer->location, attr->values[0].string.text);
http_uri_status_t uri_status; /* URI separation status */
char old_device_uri[1024];
/* Old device URI */
- static const char * const uri_status_strings[] =
- {
- "URI too large.",
- "Bad arguments to function.",
- "Bad resource path.",
- "Bad port number.",
- "Bad hostname/address.",
- "Bad username/password.",
- "Bad URI scheme.",
- "Bad URI.",
- "OK",
- "Missing URI scheme.",
- "Unknown URI scheme",
- "Missing resource path."
- };
-
need_restart_job = 1;
host, sizeof(host), &port,
resource, sizeof(resource));
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "%s device-uri: %s", printer->name,
- uri_status_strings[uri_status - HTTP_URI_STATUS_OVERFLOW]);
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "%s device-uri: %s", printer->name, httpURIStatusString(uri_status));
if (uri_status < HTTP_URI_OK)
{
send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad device-uri \"%s\"."),
attr->values[0].string.text);
+ if (!modify)
+ cupsdDeletePrinter(printer, 0);
+
return;
}
"To enable, see the FileDevice directive in "
"\"%s/cups-files.conf\"."),
ServerRoot);
+ if (!modify)
+ cupsdDeletePrinter(printer, 0);
+
return;
}
}
send_ipp_status(con, IPP_NOT_POSSIBLE,
_("Bad device-uri scheme \"%s\"."), scheme);
+ if (!modify)
+ cupsdDeletePrinter(printer, 0);
+
return;
}
}
{
send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad port-monitor \"%s\"."),
attr->values[0].string.text);
+ if (!modify)
+ cupsdDeletePrinter(printer, 0);
+
return;
}
printer->accepting ? "Now" : "No longer");
}
- if ((attr = ippFindAttribute(con->request, "printer-is-shared",
- IPP_TAG_BOOLEAN)) != NULL)
+ if ((attr = ippFindAttribute(con->request, "printer-is-shared", IPP_TAG_BOOLEAN)) != NULL)
{
- if (attr->values[0].boolean &&
+ if (ippGetBoolean(attr, 0) &&
printer->num_auth_info_required == 1 &&
!strcmp(printer->auth_info_required[0], "negotiate"))
{
send_ipp_status(con, IPP_BAD_REQUEST,
_("Cannot share a remote Kerberized printer."));
+ if (!modify)
+ cupsdDeletePrinter(printer, 0);
+
return;
}
- if (printer->shared && !attr->values[0].boolean)
+ if (printer->type & CUPS_PRINTER_REMOTE)
+ {
+ /*
+ * Cannot re-share remote printers.
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST, _("Cannot change printer-is-shared for remote queues."));
+ if (!modify)
+ cupsdDeletePrinter(printer, 0);
+
+ return;
+ }
+
+ if (printer->shared && !ippGetBoolean(attr, 0))
cupsdDeregisterPrinter(printer, 1);
cupsdLogMessage(CUPSD_LOG_INFO,
"Setting %s printer-is-shared to %d (was %d.)",
printer->name, attr->values[0].boolean, printer->shared);
- printer->shared = attr->values[0].boolean;
+ printer->shared = ippGetBoolean(attr, 0);
+ if (printer->shared && printer->temporary)
+ printer->temporary = 0;
}
if ((attr = ippFindAttribute(con->request, "printer-state",
{
send_ipp_status(con, IPP_BAD_REQUEST, _("Bad printer-state value %d."),
attr->values[0].integer);
+ if (!modify)
+ cupsdDeletePrinter(printer, 0);
+
return;
}
attr->num_values,
(int)(sizeof(printer->reasons) /
sizeof(printer->reasons[0])));
+ if (!modify)
+ cupsdDeletePrinter(printer, 0);
+
return;
}
"Printer \"%s\" state changed.", printer->name);
}
- set_printer_defaults(con, printer);
+ if (!set_printer_defaults(con, printer))
+ {
+ if (!modify)
+ cupsdDeletePrinter(printer, 0);
+
+ return;
+ }
if ((attr = ippFindAttribute(con->request, "auth-info-required",
IPP_TAG_KEYWORD)) != NULL)
if (strncmp(line, "*PPD-Adobe", 10))
{
send_ipp_status(con, IPP_STATUS_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED, _("Bad PPD file."));
+ if (!modify)
+ cupsdDeletePrinter(printer, 0);
+
return;
}
if (copy_file(srcfile, dstfile, ConfigFilePerm))
{
send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to copy PPD file - %s"), strerror(errno));
+ if (!modify)
+ cupsdDeletePrinter(printer, 0);
+
return;
}
else if (strstr(ppd_name, "../"))
{
send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Invalid ppd-name value."));
+ if (!modify)
+ cupsdDeletePrinter(printer, 0);
+
return;
}
else
if (copy_model(con, ppd_name, dstfile))
{
send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to copy PPD file."));
+ if (!modify)
+ cupsdDeletePrinter(printer, 0);
+
return;
}
char cache_name[1024]; /* Cache filename for printer attrs */
- snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir,
- printer->name);
+ snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, printer->name);
unlink(cache_name);
cupsdSetPrinterReasons(printer, "none");
* Update the printer attributes and return...
*/
+ if (!printer->temporary)
+ {
+ if (!printer->printer_id)
+ printer->printer_id = NextPrinterId ++;
+
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+ }
+
cupsdSetPrinterAttrs(printer);
- cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
if (need_restart_job && printer->job)
{
*option; /* Current option */
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Applying default options...");
+
/*
* Collect all of the default options and add the missing ones to the
* job object...
i --, option ++)
if (!ippFindAttribute(job->attrs, option->name, IPP_TAG_ZERO))
{
- num_options = cupsAddOption(option->name, option->value, num_options,
- &options);
+ if (!strcmp(option->name, "print-quality") && ippFindAttribute(job->attrs, "cupsPrintQuality", IPP_TAG_NAME))
+ continue; /* Don't override cupsPrintQuality */
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Adding default %s=%s", option->name, option->value);
+
+ num_options = cupsAddOption(option->name, option->value, num_options, &options);
}
/*
cupsd_printer_t *printer, /* I - Printer */
cups_array_t *ra) /* I - Requested attributes array */
{
- char printer_uri[HTTP_MAX_URI];
- /* Printer URI */
- char printer_icons[HTTP_MAX_URI];
- /* Printer icons */
- time_t curtime; /* Current time */
- int i; /* Looping var */
+ char uri[HTTP_MAX_URI]; /* URI value */
+ time_t curtime; /* Current time */
+ int i; /* Looping var */
+ int is_encrypted = httpIsEncrypted(con->http);
+ /* Is the connection encrypted? */
/*
curtime = time(NULL);
if (!ra || cupsArrayFind(ra, "marker-change-time"))
- ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
- "marker-change-time", printer->marker_time);
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "marker-change-time", printer->marker_time);
- if (printer->num_printers > 0 &&
- (!ra || cupsArrayFind(ra, "member-uris")))
+ if (printer->num_printers > 0 && (!ra || cupsArrayFind(ra, "member-uris")))
{
ipp_attribute_t *member_uris; /* member-uris attribute */
cupsd_printer_t *p2; /* Printer in class */
ipp_attribute_t *p2_uri; /* printer-uri-supported for class printer */
- if ((member_uris = ippAddStrings(con->response, IPP_TAG_PRINTER,
- IPP_TAG_URI, "member-uris",
- printer->num_printers, NULL,
- NULL)) != NULL)
+ if ((member_uris = ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", printer->num_printers, NULL, NULL)) != NULL)
{
for (i = 0; i < printer->num_printers; i ++)
{
p2 = printer->printers[i];
- if ((p2_uri = ippFindAttribute(p2->attrs, "printer-uri-supported",
- IPP_TAG_URI)) != NULL)
- member_uris->values[i].string.text =
- _cupsStrRetain(p2_uri->values[0].string.text);
+ if ((p2_uri = ippFindAttribute(p2->attrs, "printer-uri-supported", IPP_TAG_URI)) != NULL)
+ {
+ member_uris->values[i].string.text = _cupsStrRetain(p2_uri->values[0].string.text);
+ }
else
{
- httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri,
- sizeof(printer_uri), "ipp", NULL, con->clientname,
- con->clientport,
- (p2->type & CUPS_PRINTER_CLASS) ?
- "/classes/%s" : "/printers/%s", p2->name);
- member_uris->values[i].string.text = _cupsStrAlloc(printer_uri);
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "ipps" : "ipp", NULL, con->clientname, con->clientport, (p2->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : "/printers/%s", p2->name);
+ member_uris->values[i].string.text = _cupsStrAlloc(uri);
}
}
}
}
if (printer->alert && (!ra || cupsArrayFind(ra, "printer-alert")))
- ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_STRING,
- "printer-alert", NULL, printer->alert);
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_STRING, "printer-alert", NULL, printer->alert);
- if (printer->alert_description &&
- (!ra || cupsArrayFind(ra, "printer-alert-description")))
- ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT,
- "printer-alert-description", NULL,
- printer->alert_description);
+ if (printer->alert_description && (!ra || cupsArrayFind(ra, "printer-alert-description")))
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-alert-description", NULL, printer->alert_description);
if (!ra || cupsArrayFind(ra, "printer-config-change-date-time"))
ippAddDate(con->response, IPP_TAG_PRINTER, "printer-config-change-date-time", ippTimeToDate(printer->config_time));
if (!ra || cupsArrayFind(ra, "printer-config-change-time"))
- ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
- "printer-config-change-time", printer->config_time);
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-config-change-time", printer->config_time);
if (!ra || cupsArrayFind(ra, "printer-current-time"))
- ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time",
- ippTimeToDate(curtime));
+ ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time", ippTimeToDate(curtime));
#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
if (!ra || cupsArrayFind(ra, "printer-dns-sd-name"))
{
if (printer->reg_name)
- ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME,
- "printer-dns-sd-name", NULL, printer->reg_name);
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-dns-sd-name", NULL, printer->reg_name);
else
- ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_NOVALUE,
- "printer-dns-sd-name", 0);
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "printer-dns-sd-name", 0);
}
#endif /* HAVE_DNSSD || HAVE_AVAHI */
if (!ra || cupsArrayFind(ra, "printer-error-policy"))
- ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME,
- "printer-error-policy", NULL, printer->error_policy);
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-error-policy", NULL, printer->error_policy);
if (!ra || cupsArrayFind(ra, "printer-error-policy-supported"))
{
static const char * const errors[] =/* printer-error-policy-supported values */
- {
- "abort-job",
- "retry-current-job",
- "retry-job",
- "stop-printer"
- };
+ {
+ "abort-job",
+ "retry-current-job",
+ "retry-job",
+ "stop-printer"
+ };
if (printer->type & CUPS_PRINTER_CLASS)
- ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
- "printer-error-policy-supported", NULL, "retry-current-job");
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, "printer-error-policy-supported", NULL, "retry-current-job");
else
- ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
- "printer-error-policy-supported",
- sizeof(errors) / sizeof(errors[0]), NULL, errors);
+ ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, "printer-error-policy-supported", sizeof(errors) / sizeof(errors[0]), NULL, errors);
}
if (!ra || cupsArrayFind(ra, "printer-icons"))
{
- httpAssembleURIf(HTTP_URI_CODING_ALL, printer_icons, sizeof(printer_icons),
- "http", NULL, con->clientname, con->clientport,
- "/icons/%s.png", printer->name);
- ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-icons",
- NULL, printer_icons);
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-icons=\"%s\"", printer_icons);
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "https" : "http", NULL, con->clientname, con->clientport, "/icons/%s.png", printer->name);
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-icons", NULL, uri);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-icons=\"%s\"", uri);
}
if (!ra || cupsArrayFind(ra, "printer-is-accepting-jobs"))
if (!ra || cupsArrayFind(ra, "printer-is-shared"))
ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-shared", (char)printer->shared);
+ if (!ra || cupsArrayFind(ra, "printer-is-temporary"))
+ ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-temporary", (char)printer->temporary);
+
if (!ra || cupsArrayFind(ra, "printer-more-info"))
{
- httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
- "http", NULL, con->clientname, con->clientport,
- (printer->type & CUPS_PRINTER_CLASS) ?
- "/classes/%s" : "/printers/%s", printer->name);
- ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI,
- "printer-more-info", NULL, printer_uri);
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "https" : "http", NULL, con->clientname, con->clientport, (printer->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : "/printers/%s", printer->name);
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info", NULL, uri);
}
if (!ra || cupsArrayFind(ra, "printer-op-policy"))
- ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME,
- "printer-op-policy", NULL, printer->op_policy);
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-op-policy", NULL, printer->op_policy);
if (!ra || cupsArrayFind(ra, "printer-state"))
- ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
- printer->state);
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", printer->state);
if (!ra || cupsArrayFind(ra, "printer-state-change-date-time"))
ippAddDate(con->response, IPP_TAG_PRINTER, "printer-state-change-date-time", ippTimeToDate(printer->state_time));
if (!ra || cupsArrayFind(ra, "printer-state-change-time"))
- ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
- "printer-state-change-time", printer->state_time);
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-state-change-time", printer->state_time);
if (!ra || cupsArrayFind(ra, "printer-state-message"))
- ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT,
- "printer-state-message", NULL, printer->state_message);
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message", NULL, printer->state_message);
if (!ra || cupsArrayFind(ra, "printer-state-reasons"))
add_printer_state_reasons(con, printer);
+ if (!ra || cupsArrayFind(ra, "printer-strings-uri"))
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "https" : "http", NULL, con->clientname, con->clientport, "/strings/%s.strings", printer->name);
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-strings-uri", NULL, uri);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-strings-uri=\"%s\"", uri);
+ }
+
if (!ra || cupsArrayFind(ra, "printer-type"))
{
cups_ptype_t type; /* printer-type value */
}
if (!ra || cupsArrayFind(ra, "printer-up-time"))
- ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
- "printer-up-time", curtime);
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-up-time", curtime);
if (!ra || cupsArrayFind(ra, "printer-uri-supported"))
{
- httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
- "ipp", NULL, con->clientname, con->clientport,
- (printer->type & CUPS_PRINTER_CLASS) ?
- "/classes/%s" : "/printers/%s", printer->name);
- ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI,
- "printer-uri-supported", NULL, printer_uri);
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-uri-supported=\"%s\"",
- printer_uri);
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "ipps" : "ipp", NULL, con->clientname, con->clientport, (printer->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : "/printers/%s", printer->name);
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, uri);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-uri-supported=\"%s\"", uri);
}
if (!ra || cupsArrayFind(ra, "queued-job-count"))
}
+/*
+ * 'create_local_bg_thread()' - Background thread for creating a local print queue.
+ */
+
+static void * /* O - Exit status */
+create_local_bg_thread(
+ cupsd_printer_t *printer) /* I - Printer */
+{
+ cups_file_t *from, /* Source file */
+ *to; /* Destination file */
+ char fromppd[1024], /* Source PPD */
+ toppd[1024], /* Destination PPD */
+ scheme[32], /* URI scheme */
+ userpass[256], /* User:pass */
+ host[256], /* Hostname */
+ resource[1024], /* Resource path */
+ line[1024]; /* Line from PPD */
+ int port; /* Port number */
+ http_encryption_t encryption; /* Type of encryption to use */
+ http_t *http; /* Connection to printer */
+ ipp_t *request, /* Request to printer */
+ *response; /* Response from printer */
+ ipp_attribute_t *attr; /* Attribute in response */
+
+
+ /*
+ * Try connecting to the printer...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Generating PPD file from \"%s\"...", printer->name, printer->device_uri);
+
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, printer->device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Bad device URI \"%s\".", printer->name, printer->device_uri);
+ return (NULL);
+ }
+
+ if (!strcmp(scheme, "ipps") || port == 443)
+ encryption = HTTP_ENCRYPTION_ALWAYS;
+ else
+ encryption = HTTP_ENCRYPTION_IF_REQUESTED;
+
+ if ((http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to connect to %s:%d: %s", printer->name, host, port, cupsLastErrorString());
+ return (NULL);
+ }
+
+ /*
+ * Query the printer for its capabilities...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Connected to %s:%d, sending Get-Printer-Attributes request...", printer->name, host, port);
+
+ request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer->device_uri);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", NULL, "all");
+
+ response = cupsDoRequest(http, request, resource);
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Get-Printer-Attributes returned %s", printer->name, ippErrorString(cupsLastError()));
+
+ // TODO: Grab printer icon file...
+ httpClose(http);
+
+ /*
+ * Write the PPD for the queue...
+ */
+
+ if (_ppdCreateFromIPP(fromppd, sizeof(fromppd), response))
+ {
+ if ((!printer->info || !*(printer->info)) && (attr = ippFindAttribute(response, "printer-info", IPP_TAG_TEXT)) != NULL)
+ cupsdSetString(&printer->info, ippGetString(attr, 0, NULL));
+
+ if ((!printer->location || !*(printer->location)) && (attr = ippFindAttribute(response, "printer-location", IPP_TAG_TEXT)) != NULL)
+ cupsdSetString(&printer->location, ippGetString(attr, 0, NULL));
+
+ if ((!printer->geo_location || !*(printer->geo_location)) && (attr = ippFindAttribute(response, "printer-geo-location", IPP_TAG_URI)) != NULL)
+ cupsdSetString(&printer->geo_location, ippGetString(attr, 0, NULL));
+
+ if ((from = cupsFileOpen(fromppd, "r")) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to read generated PPD: %s", printer->name, strerror(errno));
+ return (NULL);
+ }
+
+ snprintf(toppd, sizeof(toppd), "%s/ppd/%s.ppd", ServerRoot, printer->name);
+ if ((to = cupsdCreateConfFile(toppd, ConfigFilePerm)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to create PPD for printer: %s", printer->name, strerror(errno));
+ cupsFileClose(from);
+ return (NULL);
+ }
+
+ while (cupsFileGets(from, line, sizeof(line)))
+ cupsFilePrintf(to, "%s\n", line);
+
+ cupsFileClose(from);
+ if (!cupsdCloseCreatedConfFile(to, toppd))
+ {
+ printer->config_time = time(NULL);
+ printer->state = IPP_PSTATE_IDLE;
+ printer->accepting = 1;
+
+ cupsdSetPrinterAttrs(printer);
+
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_CONFIG, printer, NULL, "Printer \"%s\" is now available.", printer->name);
+ cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" is now available.", printer->name);
+ }
+ }
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s: PPD creation failed: %s", printer->name, cupsLastErrorString());
+
+ return (NULL);
+}
+
+
+/*
+ * 'create_local_printer()' - Create a local (temporary) print queue.
+ */
+
+static void
+create_local_printer(
+ cupsd_client_t *con) /* I - Client connection */
+{
+ ipp_attribute_t *device_uri, /* device-uri attribute */
+ *printer_geo_location, /* printer-geo-location attribute */
+ *printer_info, /* printer-info attribute */
+ *printer_location, /* printer-location attribute */
+ *printer_name; /* printer-name attribute */
+ cupsd_printer_t *printer; /* New printer */
+ http_status_t status; /* Policy status */
+ char name[128], /* Sanitized printer name */
+ *nameptr, /* Pointer into name */
+ uri[1024]; /* printer-uri-supported value */
+ const char *ptr; /* Pointer into attribute value */
+
+
+ /*
+ * Require local access to create a local printer...
+ */
+
+ if (!httpAddrLocalhost(httpGetAddress(con->http)))
+ {
+ send_ipp_status(con, IPP_STATUS_ERROR_FORBIDDEN, _("Only local users can create a local printer."));
+ return;
+ }
+
+ /*
+ * Check any other policy limits...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ /*
+ * Grab needed attributes...
+ */
+
+ if ((printer_name = ippFindAttribute(con->request, "printer-name", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(printer_name) != IPP_TAG_PRINTER || ippGetValueTag(printer_name) != IPP_TAG_NAME)
+ {
+ if (!printer_name)
+ send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Missing required attribute \"%s\"."), "printer-name");
+ else if (ippGetGroupTag(printer_name) != IPP_TAG_PRINTER)
+ send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is in the wrong group."), "printer-name");
+ else
+ send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is the wrong value type."), "printer-name");
+
+ return;
+ }
+
+ for (nameptr = name, ptr = ippGetString(printer_name, 0, NULL); *ptr && nameptr < (name + sizeof(name) - 1); ptr ++)
+ {
+ /*
+ * Sanitize the printer name...
+ */
+
+ if (_cups_isalnum(*ptr))
+ *nameptr++ = *ptr;
+ else if (nameptr == name || nameptr[-1] != '_')
+ *nameptr++ = '_';
+ }
+
+ *nameptr = '\0';
+
+ if ((device_uri = ippFindAttribute(con->request, "device-uri", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(device_uri) != IPP_TAG_PRINTER || ippGetValueTag(device_uri) != IPP_TAG_URI)
+ {
+ if (!device_uri)
+ send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Missing required attribute \"%s\"."), "device-uri");
+ else if (ippGetGroupTag(device_uri) != IPP_TAG_PRINTER)
+ send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is in the wrong group."), "device-uri");
+ else
+ send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is the wrong value type."), "device-uri");
+
+ return;
+ }
+
+ printer_geo_location = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI);
+ printer_info = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT);
+ printer_location = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT);
+
+ /*
+ * See if the printer already exists...
+ */
+
+ if ((printer = cupsdFindDest(name)) != NULL)
+ {
+ send_ipp_status(con, IPP_STATUS_ERROR_NOT_POSSIBLE, _("Printer \"%s\" already exists."), name);
+ goto add_printer_attributes;
+ }
+
+ /*
+ * Create the printer...
+ */
+
+ if ((printer = cupsdAddPrinter(name)) == NULL)
+ {
+ send_ipp_status(con, IPP_STATUS_ERROR_INTERNAL, _("Unable to create printer."));
+ return;
+ }
+
+ printer->shared = 0;
+ printer->temporary = 1;
+
+ cupsdSetDeviceURI(printer, ippGetString(device_uri, 0, NULL));
+
+ if (printer_geo_location)
+ cupsdSetString(&printer->geo_location, ippGetString(printer_geo_location, 0, NULL));
+ if (printer_info)
+ cupsdSetString(&printer->info, ippGetString(printer_info, 0, NULL));
+ if (printer_location)
+ cupsdSetString(&printer->location, ippGetString(printer_location, 0, NULL));
+
+ cupsdSetPrinterAttrs(printer);
+
+ /*
+ * Run a background thread to create the PPD...
+ */
+
+ _cupsThreadCreate((_cups_thread_func_t)create_local_bg_thread, printer);
+
+ /*
+ * Return printer attributes...
+ */
+
+ send_ipp_status(con, IPP_STATUS_OK, _("Local printer created."));
+
+ add_printer_attributes:
+
+ ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", (char)printer->accepting);
+ ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", printer->state);
+ add_printer_state_reasons(con, printer);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), httpIsEncrypted(con->http) ? "ipps" : "ipp", NULL, con->clientname, con->clientport, "/printers/%s", printer->name);
+ ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, uri);
+}
+
+
/*
* 'create_requested_array()' - Create an array for the requested-attributes.
*/
cups_ptype_t dtype; /* Destination type (printer/class) */
cupsd_printer_t *printer; /* Printer/class */
char filename[1024]; /* Script/PPD filename */
+ int temporary; /* Temporary queue? */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "delete_printer(%p[%d], %s)", con,
cupsdUnregisterColor(printer);
+ temporary = printer->temporary;
+
if (dtype & CUPS_PRINTER_CLASS)
{
cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" deleted by \"%s\".",
printer->name, get_username(con));
cupsdDeletePrinter(printer, 0);
- cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
+ if (!temporary)
+ cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
}
else
{
cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" deleted by \"%s\".",
printer->name, get_username(con));
- if (cupsdDeletePrinter(printer, 0))
+ if (cupsdDeletePrinter(printer, 0) && !temporary)
cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
- cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+ if (!temporary)
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
}
- cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
+ if (!temporary)
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP);
/*
* Return with no errors...
ipp_jstate_t job_state; /* job-state value */
int first_job_id = 1, /* First job ID */
first_index = 1, /* First index */
- current_index = 0; /* Current index */
- int limit = 0; /* Maximum number of jobs to return */
- int count; /* Number of jobs that match */
- int need_load_job = 0; /* Do we need to load the job? */
+ limit = 0, /* Maximum number of jobs to return */
+ count, /* Number of jobs that match */
+ need_load_job = 0; /* Do we need to load the job? */
const char *job_attr; /* Job attribute requested */
ipp_attribute_t *job_ids; /* job-ids attribute */
cupsd_job_t *job; /* Current job pointer */
}
else
{
- for (count = 0, job = (cupsd_job_t *)cupsArrayFirst(list);
- (limit <= 0 || count < limit) && job;
- job = (cupsd_job_t *)cupsArrayNext(list))
+ if (first_index > 1)
+ job = (cupsd_job_t *)cupsArrayIndex(list, first_index - 1);
+ else
+ job = (cupsd_job_t *)cupsArrayFirst(list);
+
+ for (count = 0; (limit <= 0 || count < limit) && job; job = (cupsd_job_t *)cupsArrayNext(list))
{
/*
* Filter out jobs that don't match...
if (job->id < first_job_id)
continue;
- current_index ++;
- if (current_index < first_index)
- continue;
-
if (need_load_job && !job->attrs)
{
cupsdLoadJob(job);
ipp_attribute_t *attr; /* Current attribute */
int limit; /* Max number of printers to return */
int count; /* Number of printers that match */
+ int printer_id; /* Printer we are interested in */
cupsd_printer_t *printer; /* Current printer pointer */
cups_ptype_t printer_type, /* printer-type attribute */
printer_mask; /* printer-type-mask attribute */
* Support filtering...
*/
+ if ((attr = ippFindAttribute(con->request, "printer-id", IPP_TAG_INTEGER)) != NULL)
+ {
+ if ((printer_id = ippGetInteger(attr, 0)) <= 0)
+ {
+ send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Bad \"printer-id\" value %d."), printer_id);
+ return;
+ }
+ }
+ else
+ printer_id = 0;
+
if ((attr = ippFindAttribute(con->request, "printer-type",
IPP_TAG_ENUM)) != NULL)
printer_type = (cups_ptype_t)attr->values[0].integer;
if (!local && !printer->shared)
continue;
+ if (printer_id && printer->printer_id != printer_id)
+ continue;
+
if ((!type || (printer->type & CUPS_PRINTER_CLASS) == type) &&
(printer->type & printer_mask) == printer_type &&
(!location ||
"get_subscription_attrs(con=%p[%d], sub_id=%d)",
con, con->number, sub_id);
+ /*
+ * Expire subscriptions as needed...
+ */
+
+ cupsdExpireSubscriptions(NULL, NULL);
+
/*
* Is the subscription ID valid?
*/
return;
}
+ /*
+ * Expire subscriptions as needed...
+ */
+
+ cupsdExpireSubscriptions(NULL, NULL);
+
/*
* Copy the subscription attributes to the response using the
* requested-attributes attribute that may be provided by the client.
"Printer \"%s\" now printing pending/new jobs (\"%s\").",
printer->name, get_username(con));
+ cupsdCheckJobs();
+
/*
* Everything was ok, so return OK status...
*/
* 'set_printer_defaults()' - Set printer default options from a request.
*/
-static void
+static int /* O - 1 on success, 0 on failure */
set_printer_defaults(
cupsd_client_t *con, /* I - Client connection */
cupsd_printer_t *printer) /* I - Printer */
send_ipp_status(con, IPP_NOT_POSSIBLE,
_("Unknown printer-op-policy \"%s\"."),
attr->values[0].string.text);
- return;
+ return (0);
}
}
else if (!strcmp(attr->name, "printer-error-policy"))
send_ipp_status(con, IPP_NOT_POSSIBLE,
_("Unknown printer-error-policy \"%s\"."),
attr->values[0].string.text);
- return;
+ return (0);
}
cupsdLogMessage(CUPSD_LOG_DEBUG,
break;
}
}
+
+ return (1);
}
return (cupsdCheckPolicy(printer ? printer->op_policy_ptr : DefaultPolicyPtr,
con, owner) == HTTP_OK);
}
-
-
-/*
- * End of "$Id$".
- */