summaryrefslogtreecommitdiff
path: root/scheduler
diff options
context:
space:
mode:
Diffstat (limited to 'scheduler')
-rw-r--r--scheduler/ipp.c206
-rw-r--r--scheduler/job.c4
-rw-r--r--scheduler/printers.c1206
-rw-r--r--scheduler/printers.h6
-rw-r--r--scheduler/select.c2
5 files changed, 866 insertions, 558 deletions
diff --git a/scheduler/ipp.c b/scheduler/ipp.c
index 2b44fba60..048dd959d 100644
--- a/scheduler/ipp.c
+++ b/scheduler/ipp.c
@@ -197,12 +197,15 @@ static void get_subscription_attrs(cupsd_client_t *con, int sub_id);
static void get_subscriptions(cupsd_client_t *con, ipp_attribute_t *uri);
static const char *get_username(cupsd_client_t *con);
static void hold_job(cupsd_client_t *con, ipp_attribute_t *uri);
+static void hold_new_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
static void move_job(cupsd_client_t *con, ipp_attribute_t *uri);
static int ppd_parse_line(const char *line, char *option, int olen,
char *choice, int clen);
static void print_job(cupsd_client_t *con, ipp_attribute_t *uri);
static void read_job_ticket(cupsd_client_t *con);
static void reject_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
+static void release_held_new_jobs(cupsd_client_t *con,
+ ipp_attribute_t *uri);
static void release_job(cupsd_client_t *con, ipp_attribute_t *uri);
static void renew_subscription(cupsd_client_t *con, int sub_id);
static void restart_job(cupsd_client_t *con, ipp_attribute_t *uri);
@@ -564,6 +567,14 @@ cupsdProcessIPPRequest(
set_job_attrs(con, uri);
break;
+ case IPP_HOLD_NEW_JOBS :
+ hold_new_jobs(con, uri);
+ break;
+
+ case IPP_RELEASE_HELD_NEW_JOBS :
+ release_held_new_jobs(con, uri);
+ break;
+
case CUPS_GET_DEFAULT :
get_default(con);
break;
@@ -898,7 +909,7 @@ add_class(cupsd_client_t *con, /* I - Client connection */
{
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 */
@@ -919,8 +930,8 @@ add_class(cupsd_client_t *con, /* I - Client connection */
* 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));
@@ -3570,7 +3581,7 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */
*auth_info; /* auth-info attribute */
int jobid; /* Job ID */
cupsd_job_t *job; /* Current job */
- char method[HTTP_MAX_URI],
+ char scheme[HTTP_MAX_URI],
/* Method portion of URI */
username[HTTP_MAX_URI],
/* Username portion of URI */
@@ -3616,8 +3627,8 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */
* 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,
+ 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, "/jobs/", 6))
@@ -5541,6 +5552,8 @@ copy_printer_attrs(
add_queued_job_count(con, printer);
copy_attrs(con->response, printer->attrs, ra, IPP_TAG_ZERO, 0);
+ if (printer->ppd_attrs)
+ copy_attrs(con->response, printer->ppd_attrs, ra, IPP_TAG_ZERO, 0);
copy_attrs(con->response, CommonData, ra, IPP_TAG_ZERO, IPP_TAG_COPY);
}
@@ -6327,6 +6340,10 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */
printer->name);
unlink(filename);
+ snprintf(filename, sizeof(filename), "%s/%s.ipp", ServerRoot,
+ printer->name);
+ unlink(filename);
+
#ifdef __APPLE__
/*
* Unregister color profiles...
@@ -6497,7 +6514,7 @@ get_document(cupsd_client_t *con, /* I - Client connection */
int jobid; /* Job ID */
int docnum; /* Document number */
cupsd_job_t *job; /* Current job */
- 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 */
@@ -6535,8 +6552,8 @@ get_document(cupsd_client_t *con, /* I - Client connection */
* 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,
+ 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, "/jobs/", 6))
@@ -6640,7 +6657,7 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */
ipp_attribute_t *attr; /* Current attribute */
int jobid; /* Job ID */
cupsd_job_t *job; /* Current job */
- 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 */
@@ -6677,8 +6694,8 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */
* 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,
+ 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, "/jobs/", 6))
@@ -7821,7 +7838,7 @@ hold_job(cupsd_client_t *con, /* I - Client connection */
ipp_attribute_t *attr, /* Current job-hold-until */
*newattr; /* New job-hold-until */
int jobid; /* Job ID */
- 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 */
@@ -7858,8 +7875,8 @@ hold_job(cupsd_client_t *con, /* I - Client connection */
* 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,
+ 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, "/jobs/", 6))
@@ -7955,6 +7972,73 @@ hold_job(cupsd_client_t *con, /* I - Client connection */
/*
+ * 'hold_new_jobs()' - Hold pending/new jobs on a printer or class.
+ */
+
+static void
+hold_new_jobs(cupsd_client_t *con, /* I - Connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ http_status_t status; /* Policy status */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cupsd_printer_t *printer; /* Printer data */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_new_jobs(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class was not found."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+
+ /*
+ * Hold pending/new jobs sent to the printer...
+ */
+
+ printer->holding_new_jobs = 1;
+
+ cupsdSetPrinterReasons(printer, "+hold-new-jobs");
+ cupsdAddPrinterHistory(printer);
+
+ if (dtype & CUPS_PRINTER_CLASS)
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Class \"%s\" now holding pending/new jobs (\"%s\").",
+ printer->name, get_username(con));
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Printer \"%s\" now holding pending/new jobs (\"%s\").",
+ printer->name, get_username(con));
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
* 'move_job()' - Move a job to a new destination.
*/
@@ -8801,6 +8885,74 @@ reject_jobs(cupsd_client_t *con, /* I - Client connection */
/*
+ * 'release_held_new_jobs()' - Release pending/new jobs on a printer or class.
+ */
+
+static void
+release_held_new_jobs(
+ cupsd_client_t *con, /* I - Connection */
+ ipp_attribute_t *uri) /* I - Printer URI */
+{
+ http_status_t status; /* Policy status */
+ cups_ptype_t dtype; /* Destination type (printer/class) */
+ cupsd_printer_t *printer; /* Printer data */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_held_new_jobs(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * Is the destination valid?
+ */
+
+ if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer))
+ {
+ /*
+ * Bad URI...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("The printer or class was not found."));
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, printer);
+ return;
+ }
+
+ /*
+ * Hold pending/new jobs sent to the printer...
+ */
+
+ printer->holding_new_jobs = 0;
+
+ cupsdSetPrinterReasons(printer, "-hold-new-jobs");
+ cupsdAddPrinterHistory(printer);
+
+ if (dtype & CUPS_PRINTER_CLASS)
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Class \"%s\" now printing pending/new jobs (\"%s\").",
+ printer->name, get_username(con));
+ else
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Printer \"%s\" now printing pending/new jobs (\"%s\").",
+ printer->name, get_username(con));
+
+ /*
+ * Everything was ok, so return OK status...
+ */
+
+ con->response->request.status.status_code = IPP_OK;
+}
+
+
+/*
* 'release_job()' - Release a held print job.
*/
@@ -8810,7 +8962,7 @@ release_job(cupsd_client_t *con, /* I - Client connection */
{
ipp_attribute_t *attr; /* Current attribute */
int jobid; /* Job ID */
- 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 */
@@ -8847,8 +8999,8 @@ release_job(cupsd_client_t *con, /* I - Client connection */
* 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,
+ 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, "/jobs/", 6))
@@ -9035,7 +9187,7 @@ restart_job(cupsd_client_t *con, /* I - Client connection */
{
ipp_attribute_t *attr; /* Current attribute */
int jobid; /* Job ID */
- 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 */
@@ -9072,8 +9224,8 @@ restart_job(cupsd_client_t *con, /* I - Client connection */
* 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,
+ 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, "/jobs/", 6))
@@ -9436,7 +9588,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */
cupsd_job_t *job; /* Current job */
char job_uri[HTTP_MAX_URI],
/* Job URI */
- method[HTTP_MAX_URI],
+ scheme[HTTP_MAX_URI],
/* Method portion of URI */
username[HTTP_MAX_URI],
/* Username portion of URI */
@@ -9489,8 +9641,8 @@ send_document(cupsd_client_t *con, /* I - Client connection */
* 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,
+ 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, "/jobs/", 6))
@@ -10016,7 +10168,7 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */
*attr2; /* Job attribute */
int jobid; /* Job ID */
cupsd_job_t *job; /* Current job */
- char method[HTTP_MAX_URI],
+ char scheme[HTTP_MAX_URI],
/* Method portion of URI */
username[HTTP_MAX_URI],
/* Username portion of URI */
@@ -10064,8 +10216,8 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */
* 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,
+ 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, "/jobs/", 6))
diff --git a/scheduler/job.c b/scheduler/job.c
index 927dd949e..af81c235f 100644
--- a/scheduler/job.c
+++ b/scheduler/job.c
@@ -447,7 +447,7 @@ cupsdCheckJobs(void)
cupsdCancelJob(job, 1, IPP_JOB_ABORTED);
}
- else if (printer)
+ else if (printer && !printer->holding_new_jobs)
{
/*
* See if the printer is available or remote and not printing a job;
@@ -473,7 +473,7 @@ cupsdCheckJobs(void)
}
if ((!(printer->type & CUPS_PRINTER_DISCOVERED) && /* Printer is local */
- printer->state == IPP_PRINTER_IDLE) || /* and idle */
+ printer->state == IPP_PRINTER_IDLE) || /* and idle, OR */
((printer->type & CUPS_PRINTER_DISCOVERED) && /* Printer is remote */
!printer->job)) /* and not printing */
{
diff --git a/scheduler/printers.c b/scheduler/printers.c
index 7b5b7b1bf..077776953 100644
--- a/scheduler/printers.c
+++ b/scheduler/printers.c
@@ -68,8 +68,11 @@ static void add_printer_defaults(cupsd_printer_t *p);
static void add_printer_filter(cupsd_printer_t *p, mime_type_t *type,
const char *filter);
static void add_printer_formats(cupsd_printer_t *p);
+static void add_string_array(cups_array_t **a, const char *s);
static int compare_printers(void *first, void *second, void *data);
static void delete_printer_filters(cupsd_printer_t *p);
+static void delete_string_array(cups_array_t **a);
+static void load_ppd(cupsd_printer_t *p);
#ifdef __sgi
static void write_irix_config(cupsd_printer_t *p);
static void write_irix_state(cupsd_printer_t *p);
@@ -313,6 +316,8 @@ cupsdCreateCommonData(void)
IPP_GET_NOTIFICATIONS,
IPP_ENABLE_PRINTER,
IPP_DISABLE_PRINTER,
+ IPP_HOLD_NEW_JOBS,
+ IPP_RELEASE_HELD_NEW_JOBS,
CUPS_GET_DEFAULT,
CUPS_GET_PRINTERS,
CUPS_ADD_PRINTER,
@@ -633,9 +638,9 @@ cupsdDeletePrinter(
cupsd_printer_t *p, /* I - Printer to delete */
int update) /* I - Update printers.conf? */
{
- int i; /* Looping var */
+ int i; /* Looping var */
#ifdef __sgi
- char filename[1024]; /* Interface script filename */
+ char filename[1024]; /* Interface script filename */
#endif /* __sgi */
@@ -767,12 +772,16 @@ cupsdDeletePrinter(
_cupsStrFree(p->reasons[i]);
ippDelete(p->attrs);
+ ippDelete(p->ppd_attrs);
delete_printer_filters(p);
mimeDeleteType(MimeDatabase, p->filetype);
mimeDeleteType(MimeDatabase, p->prefiltertype);
+ delete_string_array(&(p->filters));
+ delete_string_array(&(p->pre_filters));
+
cupsdFreePrinterUsers(p);
cupsdFreeQuotas(p);
@@ -1537,7 +1546,7 @@ cupsdSaveAllPrinters(void)
for (i = 0; i < printer->num_reasons; i ++)
cupsFilePutConf(fp, "Reason", printer->reasons[i]);
- cupsFilePrintf(fp, "Type %d", printer->type);
+ cupsFilePrintf(fp, "Type %d\n", printer->type);
#ifdef HAVE_DNSSD
if (printer->product)
@@ -2039,32 +2048,14 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
int i, /* Looping var */
length; /* Length of browse attributes */
char resource[HTTP_MAX_URI]; /* Resource portion of URI */
- char filename[1024]; /* Name of PPD file */
int num_air; /* Number of auth-info-required values */
const char * const *air; /* auth-info-required values */
- int num_media; /* Number of media options */
cupsd_location_t *auth; /* Pointer to authentication element */
const char *auth_supported; /* Authentication supported */
- ppd_file_t *ppd; /* PPD file data */
- ppd_option_t *input_slot, /* InputSlot options */
- *media_type, /* MediaType options */
- *page_size, /* PageSize options */
- *output_bin, /* OutputBin options */
- *media_quality, /* EFMediaQualityMode options */
- *duplex; /* Duplex options */
- ppd_attr_t *ppdattr; /* PPD attribute */
ipp_t *oldattrs; /* Old printer attributes */
ipp_attribute_t *attr; /* Attribute data */
- ipp_value_t *val; /* Attribute value */
- int num_finishings; /* Number of finishings */
- int finishings[5]; /* finishings-supported values */
cups_option_t *option; /* Current printer option */
- static const char * const sides[3] = /* sides-supported values */
- {
- "one-sided",
- "two-sided-long-edge",
- "two-sided-short-edge"
- };
+ char *filter; /* Current filter */
static const char * const air_userpass[] =
{ /* Basic/Digest authentication */
"username",
@@ -2080,13 +2071,6 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
{ /* No authentication */
"none"
};
- static const char * const standard_commands[] =
- { /* Standard CUPS commands */
- "AutoConfigure",
- "Clean",
- "PrintSelfTestPage",
- "ReportLevels"
- };
DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name,
@@ -2266,11 +2250,10 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
* or class...
*/
- p->type &= ~CUPS_PRINTER_OPTIONS;
-
if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
{
p->raw = 1;
+ p->type &= ~CUPS_PRINTER_OPTIONS;
/*
* Add class-specific attributes...
@@ -2319,507 +2302,26 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
* Assign additional attributes from the PPD file (if any)...
*/
- p->type |= CUPS_PRINTER_BW;
- finishings[0] = IPP_FINISHINGS_NONE;
- num_finishings = 1;
-
- snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
- p->name);
-
- if ((ppd = ppdOpenFile(filename)) != NULL)
- {
- /*
- * Add make/model and other various attributes...
- */
-
- if (ppd->color_device)
- p->type |= CUPS_PRINTER_COLOR;
- if (ppd->variable_sizes)
- p->type |= CUPS_PRINTER_VARIABLE;
- if (!ppd->manual_copies)
- p->type |= CUPS_PRINTER_COPIES;
- if ((ppdattr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL)
- if (ppdattr->value && !strcasecmp(ppdattr->value, "true"))
- p->type |= CUPS_PRINTER_FAX;
-
- ippAddBoolean(p->attrs, IPP_TAG_PRINTER, "color-supported",
- ppd->color_device);
- if (ppd->throughput)
- ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
- "pages-per-minute", ppd->throughput);
-
- if (ppd->nickname)
- {
- /*
- * The NickName can be localized in the character set specified
- * by the LanugageEncoding attribute. However, ppdOpen2() has
- * already converted the ppd->nickname member to UTF-8 for us
- * (the original attribute value is available separately)
- */
-
- cupsdSetString(&p->make_model, ppd->nickname);
- }
- else if (ppd->modelname)
- {
- /*
- * Model name can only contain specific characters...
- */
-
- cupsdSetString(&p->make_model, ppd->modelname);
- }
- else
- cupsdSetString(&p->make_model, "Bad PPD File");
-
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
- "printer-make-and-model", NULL, p->make_model);
-
- /*
- * Add media options from the PPD file...
- */
-
- if ((input_slot = ppdFindOption(ppd, "InputSlot")) != NULL)
- num_media = input_slot->num_choices;
- else
- num_media = 0;
-
- if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
- num_media += media_type->num_choices;
+ load_ppd(p);
- if ((page_size = ppdFindOption(ppd, "PageSize")) != NULL)
- num_media += page_size->num_choices;
-
- if ((media_quality = ppdFindOption(ppd, "EFMediaQualityMode")) != NULL)
- num_media += media_quality->num_choices;
-
- if (num_media == 0)
- {
- cupsdLogMessage(CUPSD_LOG_CRIT,
- "The PPD file for printer %s contains no media "
- "options and is therefore invalid!", p->name);
- }
- else
- {
- attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "media-supported", num_media, NULL, NULL);
- if (attr != NULL)
- {
- val = attr->values;
-
- if (input_slot != NULL)
- for (i = 0; i < input_slot->num_choices; i ++, val ++)
- val->string.text = _cupsStrAlloc(input_slot->choices[i].choice);
-
- if (media_type != NULL)
- for (i = 0; i < media_type->num_choices; i ++, val ++)
- val->string.text = _cupsStrAlloc(media_type->choices[i].choice);
-
- if (media_quality != NULL)
- for (i = 0; i < media_quality->num_choices; i ++, val ++)
- val->string.text = _cupsStrAlloc(media_quality->choices[i].choice);
-
- if (page_size != NULL)
- {
- for (i = 0; i < page_size->num_choices; i ++, val ++)
- val->string.text = _cupsStrAlloc(page_size->choices[i].choice);
-
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "media-default", NULL, page_size->defchoice);
- }
- else if (input_slot != NULL)
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "media-default", NULL, input_slot->defchoice);
- else if (media_type != NULL)
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "media-default", NULL, media_type->defchoice);
- else if (media_quality != NULL)
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "media-default", NULL, media_quality->defchoice);
- else
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "media-default", NULL, "none");
- }
- }
-
- /*
- * Output bin...
- */
-
- if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
- {
- attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "output-bin-supported", output_bin->num_choices,
- NULL, NULL);
-
- if (attr != NULL)
- {
- for (i = 0, val = attr->values;
- i < output_bin->num_choices;
- i ++, val ++)
- val->string.text = _cupsStrAlloc(output_bin->choices[i].choice);
- }
- }
-
- /*
- * Duplexing, etc...
- */
-
- if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
- if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
- if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
- if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL)
- duplex = ppdFindOption(ppd, "JCLDuplex");
-
- if (duplex && duplex->num_choices > 1 &&
- !ppdInstallableConflict(ppd, duplex->keyword, "DuplexTumble"))
- {
- p->type |= CUPS_PRINTER_DUPLEX;
-
- ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "sides-supported", 3, NULL, sides);
-
- if (!strcasecmp(duplex->defchoice, "DuplexTumble"))
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "sides-default", NULL, "two-sided-short-edge");
- else if (!strcasecmp(duplex->defchoice, "DuplexNoTumble"))
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "sides-default", NULL, "two-sided-long-edge");
- else
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "sides-default", NULL, "one-sided");
- }
-
- if (ppdFindOption(ppd, "Collate") != NULL)
- p->type |= CUPS_PRINTER_COLLATE;
-
- if (ppdFindOption(ppd, "StapleLocation") != NULL)
- {
- p->type |= CUPS_PRINTER_STAPLE;
- finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
- }
-
- if (ppdFindOption(ppd, "BindEdge") != NULL)
- {
- p->type |= CUPS_PRINTER_BIND;
- finishings[num_finishings++] = IPP_FINISHINGS_BIND;
- }
-
- for (i = 0; i < ppd->num_sizes; i ++)
- if (ppd->sizes[i].length > 1728)
- p->type |= CUPS_PRINTER_LARGE;
- else if (ppd->sizes[i].length > 1008)
- p->type |= CUPS_PRINTER_MEDIUM;
- else
- p->type |= CUPS_PRINTER_SMALL;
-
- /*
- * Add a filter from application/vnd.cups-raw to printer/name to
- * handle "raw" printing by users.
- */
-
- add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
-
- /*
- * Add any pre-filters in the PPD file...
- */
-
- if ((ppdattr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL)
- {
- p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name);
-
- for (; ppdattr; ppdattr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
- if (ppdattr->value)
- add_printer_filter(p, p->prefiltertype, ppdattr->value);
- }
-
- /*
- * Add any filters in the PPD file...
- */
-
- DEBUG_printf(("ppd->num_filters = %d\n", ppd->num_filters));
- for (i = 0; i < ppd->num_filters; i ++)
- {
- DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i]));
- add_printer_filter(p, p->filetype, ppd->filters[i]);
- }
-
- if (ppd->num_filters == 0)
- {
- /*
- * If there are no filters, add PostScript printing filters.
- */
-
- add_printer_filter(p, p->filetype,
- "application/vnd.cups-command 0 commandtops");
- add_printer_filter(p, p->filetype,
- "application/vnd.cups-postscript 0 -");
-
- p->type |= CUPS_PRINTER_COMMANDS;
- }
- else if (!(p->type & CUPS_PRINTER_COMMANDS))
- {
- /*
- * See if this is a PostScript device without a command filter...
- */
-
- for (i = 0; i < ppd->num_filters; i ++)
- if (!strncasecmp(ppd->filters[i],
- "application/vnd.cups-postscript", 31))
- break;
-
- if (i < ppd->num_filters)
- {
- /*
- * Add the generic PostScript command filter...
- */
-
- add_printer_filter(p, p->filetype,
- "application/vnd.cups-command 0 commandtops");
- p->type |= CUPS_PRINTER_COMMANDS;
- }
- }
-
- if (p->type & CUPS_PRINTER_COMMANDS)
- {
- char *commands, /* Copy of commands */
- *start, /* Start of name */
- *end; /* End of name */
- int count; /* Number of commands */
-
-
- if ((ppdattr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL &&
- ppdattr->value && ppdattr->value[0])
- {
- for (count = 0, start = ppdattr->value; *start; count ++)
- {
- while (isspace(*start & 255))
- start ++;
-
- if (!*start)
- break;
-
- while (*start && !isspace(*start & 255))
- start ++;
- }
- }
- else
- count = 0;
-
- if (count > 0)
- {
- /*
- * Make a copy of the commands string and count how many ...
- */
-
- attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "printer-commands", count, NULL, NULL);
-
- commands = strdup(ppdattr->value);
-
- for (count = 0, start = commands; *start; count ++)
- {
- while (isspace(*start & 255))
- start ++;
-
- if (!*start)
- break;
-
- end = start;
- while (*end && !isspace(*end & 255))
- end ++;
-
- if (*end)
- *end++ = '\0';
-
- attr->values[count].string.text = _cupsStrAlloc(start);
-
- start = end;
- }
-
- free(commands);
- }
- else
- {
- /*
- * Add the standard list of commands...
- */
-
- ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "printer-commands",
- (int)(sizeof(standard_commands) /
- sizeof(standard_commands[0])), NULL,
- standard_commands);
- }
- }
- else
- {
- /*
- * No commands supported...
- */
-
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
- "printer-commands", NULL, "none");
- }
-
- /*
- * Show current and available port monitors for this printer...
- */
-
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
- NULL, p->port_monitor ? p->port_monitor : "none");
-
- for (i = 1, ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
- ppdattr;
- i ++, ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL));
-
- if (ppd->protocols)
- {
- if (strstr(ppd->protocols, "TBCP"))
- i ++;
- else if (strstr(ppd->protocols, "BCP"))
- i ++;
- }
-
- attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
- "port-monitor-supported", i, NULL, NULL);
-
- attr->values[0].string.text = _cupsStrAlloc("none");
-
- for (i = 1, ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
- ppdattr;
- i ++, ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
- attr->values[i].string.text = _cupsStrAlloc(ppdattr->value);
-
- if (ppd->protocols)
- {
- if (strstr(ppd->protocols, "TBCP"))
- attr->values[i].string.text = _cupsStrAlloc("tbcp");
- else if (strstr(ppd->protocols, "BCP"))
- attr->values[i].string.text = _cupsStrAlloc("bcp");
- }
-
-#ifdef HAVE_DNSSD
- cupsdSetString(&p->product, ppd->product);
-#endif /* HAVE_DNSSD */
-
- if (ppdFindAttr(ppd, "APRemoteQueueID", NULL))
- p->type |= CUPS_PRINTER_REMOTE;
-
- /*
- * Close the PPD and set the type...
- */
-
- ppdClose(ppd);
- }
- else if (!access(filename, 0))
- {
- int pline; /* PPD line number */
- ppd_status_t pstatus; /* PPD load status */
-
-
- pstatus = ppdLastError(&pline);
-
- cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded!",
- p->name);
-
- if (pstatus <= PPD_ALLOC_ERROR)
- cupsdLogMessage(CUPSD_LOG_ERROR, "%s", strerror(errno));
- else
- cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d.",
- ppdErrorString(pstatus), pline);
-
- cupsdLogMessage(CUPSD_LOG_INFO,
- "Hint: Run \"cupstestppd %s\" and fix any errors.",
- filename);
-
- /*
- * Add a filter from application/vnd.cups-raw to printer/name to
- * handle "raw" printing by users.
- */
-
- add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
+ /*
+ * Add filters for printer...
+ */
- /*
- * Add a PostScript filter, since this is still possibly PS printer.
- */
+ for (filter = (char *)cupsArrayFirst(p->filters);
+ filter;
+ filter = (char *)cupsArrayNext(p->filters))
+ add_printer_filter(p, p->filetype, filter);
- add_printer_filter(p, p->filetype,
- "application/vnd.cups-postscript 0 -");
- }
- else
+ if (p->pre_filters)
{
- /*
- * If we have an interface script, add a filter entry for it...
- */
-
- snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot,
- p->name);
- if (!access(filename, X_OK))
- {
- /*
- * Yes, we have a System V style interface script; use it!
- */
-
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
- "printer-make-and-model", NULL,
- "Local System V Printer");
-
- snprintf(filename, sizeof(filename), "*/* 0 %s/interfaces/%s",
- ServerRoot, p->name);
- add_printer_filter(p, p->filetype, filename);
- }
- else if (!strncmp(p->device_uri, "ipp://", 6) &&
- (strstr(p->device_uri, "/printers/") != NULL ||
- strstr(p->device_uri, "/classes/") != NULL ||
- (strstr(p->device_uri, "._ipp.") != NULL &&
- !strcmp(p->device_uri + strlen(p->device_uri) - 5,
- "/cups"))))
- {
- /*
- * Tell the client this is really a hard-wired remote printer.
- */
-
- p->type |= CUPS_PRINTER_REMOTE;
-
- /*
- * Point the printer-uri-supported attribute to the
- * remote printer...
- */
-
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
- "printer-uri-supported", NULL, p->device_uri);
-
- /*
- * Then set the make-and-model accordingly...
- */
+ p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name);
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
- "printer-make-and-model", NULL, "Remote Printer");
-
- /*
- * Print all files directly...
- */
-
- p->raw = 1;
- p->remote = 1;
- }
- else
- {
- /*
- * Otherwise we have neither - treat this as a "dumb" printer
- * with no PPD file...
- */
-
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
- "printer-make-and-model", NULL, "Local Raw Printer");
-
- p->raw = 1;
- }
+ for (filter = (char *)cupsArrayFirst(p->pre_filters);
+ filter;
+ filter = (char *)cupsArrayNext(p->pre_filters))
+ add_printer_filter(p, p->prefiltertype, filter);
}
-
- ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
- "finishings-supported", num_finishings, finishings);
- ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
- "finishings-default", IPP_FINISHINGS_NONE);
}
}
@@ -4129,6 +3631,21 @@ add_printer_formats(cupsd_printer_t *p) /* I - Printer */
/*
+ * 'add_string_array()' - Add a string to an array of CUPS strings.
+ */
+
+static void
+add_string_array(cups_array_t **a, /* I - Array */
+ const char *s) /* I - String */
+{
+ if (!*a)
+ *a = cupsArrayNew(NULL, NULL);
+
+ cupsArrayAdd(*a, _cupsStrAlloc(s));
+}
+
+
+/*
* 'compare_printers()' - Compare two printers.
*/
@@ -4179,6 +3696,643 @@ delete_printer_filters(
}
+/*
+ * 'delete_string_array()' - Delete an array of CUPS strings.
+ */
+
+static void
+delete_string_array(cups_array_t **a) /* I - Array */
+{
+ char *ptr; /* Current string */
+
+
+ for (ptr = (char *)cupsArrayFirst(*a);
+ ptr;
+ ptr = (char *)cupsArrayNext(*a))
+ _cupsStrFree(ptr);
+
+ cupsArrayDelete(*a);
+ *a = NULL;
+}
+
+
+/*
+ * 'load_ppd()' - Load a cached PPD file, updating the cache as needed.
+ */
+
+static void
+load_ppd(cupsd_printer_t *p) /* I - Printer */
+{
+ int i; /* Looping var */
+ cups_file_t *cache; /* Cache file */
+ char cache_name[1024]; /* Cache filename */
+ struct stat cache_info; /* Cache file info */
+ ppd_file_t *ppd; /* PPD file */
+ char ppd_name[1024]; /* PPD filename */
+ struct stat ppd_info; /* PPD file info */
+ int num_media; /* Number of media options */
+ ppd_option_t *input_slot, /* InputSlot options */
+ *media_type, /* MediaType options */
+ *page_size, /* PageSize options */
+ *output_bin, /* OutputBin options */
+ *media_quality, /* EFMediaQualityMode options */
+ *duplex; /* Duplex options */
+ ppd_attr_t *ppd_attr; /* PPD attribute */
+ ipp_attribute_t *attr; /* Attribute data */
+ ipp_value_t *val; /* Attribute value */
+ int num_finishings; /* Number of finishings */
+ int finishings[5]; /* finishings-supported values */
+ static const char * const sides[3] = /* sides-supported values */
+ {
+ "one-sided",
+ "two-sided-long-edge",
+ "two-sided-short-edge"
+ };
+ static const char * const standard_commands[] =
+ { /* Standard CUPS commands */
+ "AutoConfigure",
+ "Clean",
+ "PrintSelfTestPage",
+ "ReportLevels"
+ };
+
+
+ /*
+ * Check to see if the cache is up-to-date...
+ */
+
+ snprintf(cache_name, sizeof(cache_name), "%s/%s.ipp", CacheDir, p->name);
+ if (stat(cache_name, &cache_info))
+ cache_info.st_mtime = 0;
+
+ snprintf(ppd_name, sizeof(ppd_name), "%s/ppd/%s.ppd", ServerRoot, p->name);
+ if (stat(ppd_name, &ppd_info))
+ ppd_info.st_mtime = 1;
+
+ ippDelete(p->ppd_attrs);
+ p->ppd_attrs = ippNew();
+
+ if (cache_info.st_mtime >= ppd_info.st_mtime &&
+ (cache = cupsFileOpen(cache_name, "r")) != NULL)
+ {
+ /*
+ * Load cached information and return...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", cache_name);
+
+ if (ippReadIO(cache, (ipp_iocb_t)cupsFileRead, 1, NULL,
+ p->ppd_attrs) == IPP_DATA)
+ {
+ cupsFileClose(cache);
+ return;
+ }
+
+ cupsFileClose(cache);
+ }
+
+ /*
+ * Reload PPD attributes from disk...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", ppd_name);
+
+ delete_string_array(&(p->filters));
+ delete_string_array(&(p->pre_filters));
+
+ p->type &= ~CUPS_PRINTER_OPTIONS;
+ p->type |= CUPS_PRINTER_BW;
+
+ finishings[0] = IPP_FINISHINGS_NONE;
+ num_finishings = 1;
+
+ if ((ppd = ppdOpenFile(ppd_name)) != NULL)
+ {
+ /*
+ * Add make/model and other various attributes...
+ */
+
+ if (ppd->color_device)
+ p->type |= CUPS_PRINTER_COLOR;
+ if (ppd->variable_sizes)
+ p->type |= CUPS_PRINTER_VARIABLE;
+ if (!ppd->manual_copies)
+ p->type |= CUPS_PRINTER_COPIES;
+ if ((ppd_attr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL)
+ if (ppd_attr->value && !strcasecmp(ppd_attr->value, "true"))
+ p->type |= CUPS_PRINTER_FAX;
+
+ ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "color-supported",
+ ppd->color_device);
+ if (ppd->throughput)
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "pages-per-minute", ppd->throughput);
+
+ if (ppd->nickname)
+ {
+ /*
+ * The NickName can be localized in the character set specified
+ * by the LanugageEncoding attribute. However, ppdOpen2() has
+ * already converted the ppd->nickname member to UTF-8 for us
+ * (the original attribute value is available separately)
+ */
+
+ cupsdSetString(&p->make_model, ppd->nickname);
+ }
+ else if (ppd->modelname)
+ {
+ /*
+ * Model name can only contain specific characters...
+ */
+
+ cupsdSetString(&p->make_model, ppd->modelname);
+ }
+ else
+ cupsdSetString(&p->make_model, "Bad PPD File");
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, p->make_model);
+
+ /*
+ * Add media options from the PPD file...
+ */
+
+ if ((input_slot = ppdFindOption(ppd, "InputSlot")) != NULL)
+ num_media = input_slot->num_choices;
+ else
+ num_media = 0;
+
+ if ((media_type = ppdFindOption(ppd, "MediaType")) != NULL)
+ num_media += media_type->num_choices;
+
+ if ((page_size = ppdFindOption(ppd, "PageSize")) != NULL)
+ num_media += page_size->num_choices;
+
+ if ((media_quality = ppdFindOption(ppd, "EFMediaQualityMode")) != NULL)
+ num_media += media_quality->num_choices;
+
+ if (num_media == 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_CRIT,
+ "The PPD file for printer %s contains no media "
+ "options and is therefore invalid!", p->name);
+ }
+ else
+ {
+ attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-supported", num_media, NULL, NULL);
+ if (attr != NULL)
+ {
+ val = attr->values;
+
+ if (input_slot != NULL)
+ for (i = 0; i < input_slot->num_choices; i ++, val ++)
+ val->string.text = _cupsStrAlloc(input_slot->choices[i].choice);
+
+ if (media_type != NULL)
+ for (i = 0; i < media_type->num_choices; i ++, val ++)
+ val->string.text = _cupsStrAlloc(media_type->choices[i].choice);
+
+ if (media_quality != NULL)
+ for (i = 0; i < media_quality->num_choices; i ++, val ++)
+ val->string.text = _cupsStrAlloc(media_quality->choices[i].choice);
+
+ if (page_size != NULL)
+ {
+ for (i = 0; i < page_size->num_choices; i ++, val ++)
+ val->string.text = _cupsStrAlloc(page_size->choices[i].choice);
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-default", NULL, page_size->defchoice);
+ }
+ else if (input_slot != NULL)
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-default", NULL, input_slot->defchoice);
+ else if (media_type != NULL)
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-default", NULL, media_type->defchoice);
+ else if (media_quality != NULL)
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-default", NULL, media_quality->defchoice);
+ else
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "media-default", NULL, "none");
+ }
+ }
+
+ /*
+ * Output bin...
+ */
+
+ if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
+ {
+ attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "output-bin-supported", output_bin->num_choices,
+ NULL, NULL);
+
+ if (attr != NULL)
+ {
+ for (i = 0, val = attr->values;
+ i < output_bin->num_choices;
+ i ++, val ++)
+ val->string.text = _cupsStrAlloc(output_bin->choices[i].choice);
+ }
+ }
+
+ /*
+ * Duplexing, etc...
+ */
+
+ if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
+ if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
+ if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
+ if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL)
+ duplex = ppdFindOption(ppd, "JCLDuplex");
+
+ if (duplex && duplex->num_choices > 1 &&
+ !ppdInstallableConflict(ppd, duplex->keyword, "DuplexTumble"))
+ {
+ p->type |= CUPS_PRINTER_DUPLEX;
+
+ ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "sides-supported", 3, NULL, sides);
+
+ if (!strcasecmp(duplex->defchoice, "DuplexTumble"))
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "sides-default", NULL, "two-sided-short-edge");
+ else if (!strcasecmp(duplex->defchoice, "DuplexNoTumble"))
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "sides-default", NULL, "two-sided-long-edge");
+ else
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "sides-default", NULL, "one-sided");
+ }
+
+ if (ppdFindOption(ppd, "Collate") != NULL)
+ p->type |= CUPS_PRINTER_COLLATE;
+
+ if (ppdFindOption(ppd, "StapleLocation") != NULL)
+ {
+ p->type |= CUPS_PRINTER_STAPLE;
+ finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
+ }
+
+ if (ppdFindOption(ppd, "BindEdge") != NULL)
+ {
+ p->type |= CUPS_PRINTER_BIND;
+ finishings[num_finishings++] = IPP_FINISHINGS_BIND;
+ }
+
+ for (i = 0; i < ppd->num_sizes; i ++)
+ if (ppd->sizes[i].length > 1728)
+ p->type |= CUPS_PRINTER_LARGE;
+ else if (ppd->sizes[i].length > 1008)
+ p->type |= CUPS_PRINTER_MEDIUM;
+ else
+ p->type |= CUPS_PRINTER_SMALL;
+
+ /*
+ * Add a filter from application/vnd.cups-raw to printer/name to
+ * handle "raw" printing by users.
+ */
+
+ add_string_array(&(p->filters), "application/vnd.cups-raw 0 -");
+
+ /*
+ * Add any pre-filters in the PPD file...
+ */
+
+ if ((ppd_attr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL)
+ {
+ for (; ppd_attr; ppd_attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
+ if (ppd_attr->value)
+ add_string_array(&(p->pre_filters), ppd_attr->value);
+ }
+
+ /*
+ * Add any filters in the PPD file...
+ */
+
+ DEBUG_printf(("ppd->num_filters = %d\n", ppd->num_filters));
+ for (i = 0; i < ppd->num_filters; i ++)
+ {
+ DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i]));
+ add_string_array(&(p->filters), ppd->filters[i]);
+ }
+
+ if (ppd->num_filters == 0)
+ {
+ /*
+ * If there are no filters, add PostScript printing filters.
+ */
+
+ add_string_array(&(p->filters),
+ "application/vnd.cups-command 0 commandtops");
+ add_string_array(&(p->filters),
+ "application/vnd.cups-postscript 0 -");
+
+ p->type |= CUPS_PRINTER_COMMANDS;
+ }
+ else if (!(p->type & CUPS_PRINTER_COMMANDS))
+ {
+ /*
+ * See if this is a PostScript device without a command filter...
+ */
+
+ for (i = 0; i < ppd->num_filters; i ++)
+ if (!strncasecmp(ppd->filters[i],
+ "application/vnd.cups-postscript", 31))
+ break;
+
+ if (i < ppd->num_filters)
+ {
+ /*
+ * Add the generic PostScript command filter...
+ */
+
+ add_string_array(&(p->filters),
+ "application/vnd.cups-command 0 commandtops");
+ p->type |= CUPS_PRINTER_COMMANDS;
+ }
+ }
+
+ if (p->type & CUPS_PRINTER_COMMANDS)
+ {
+ char *commands, /* Copy of commands */
+ *start, /* Start of name */
+ *end; /* End of name */
+ int count; /* Number of commands */
+
+
+ if ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL &&
+ ppd_attr->value && ppd_attr->value[0])
+ {
+ for (count = 0, start = ppd_attr->value; *start; count ++)
+ {
+ while (isspace(*start & 255))
+ start ++;
+
+ if (!*start)
+ break;
+
+ while (*start && !isspace(*start & 255))
+ start ++;
+ }
+ }
+ else
+ count = 0;
+
+ if (count > 0)
+ {
+ /*
+ * Make a copy of the commands string and count how many ...
+ */
+
+ attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "printer-commands", count, NULL, NULL);
+
+ commands = strdup(ppd_attr->value);
+
+ for (count = 0, start = commands; *start; count ++)
+ {
+ while (isspace(*start & 255))
+ start ++;
+
+ if (!*start)
+ break;
+
+ end = start;
+ while (*end && !isspace(*end & 255))
+ end ++;
+
+ if (*end)
+ *end++ = '\0';
+
+ attr->values[count].string.text = _cupsStrAlloc(start);
+
+ start = end;
+ }
+
+ free(commands);
+ }
+ else
+ {
+ /*
+ * Add the standard list of commands...
+ */
+
+ ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "printer-commands",
+ (int)(sizeof(standard_commands) /
+ sizeof(standard_commands[0])), NULL,
+ standard_commands);
+ }
+ }
+ else
+ {
+ /*
+ * No commands supported...
+ */
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "printer-commands", NULL, "none");
+ }
+
+ /*
+ * Show current and available port monitors for this printer...
+ */
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor",
+ NULL, p->port_monitor ? p->port_monitor : "none");
+
+ for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
+ ppd_attr;
+ i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL));
+
+ if (ppd->protocols)
+ {
+ if (strstr(ppd->protocols, "TBCP"))
+ i ++;
+ else if (strstr(ppd->protocols, "BCP"))
+ i ++;
+ }
+
+ attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "port-monitor-supported", i, NULL, NULL);
+
+ attr->values[0].string.text = _cupsStrAlloc("none");
+
+ for (i = 1, ppd_attr = ppdFindAttr(ppd, "cupsPortMonitor", NULL);
+ ppd_attr;
+ i ++, ppd_attr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL))
+ attr->values[i].string.text = _cupsStrAlloc(ppd_attr->value);
+
+ if (ppd->protocols)
+ {
+ if (strstr(ppd->protocols, "TBCP"))
+ attr->values[i].string.text = _cupsStrAlloc("tbcp");
+ else if (strstr(ppd->protocols, "BCP"))
+ attr->values[i].string.text = _cupsStrAlloc("bcp");
+ }
+
+#ifdef HAVE_DNSSD
+ cupsdSetString(&p->product, ppd->product);
+#endif /* HAVE_DNSSD */
+
+ if (ppdFindAttr(ppd, "APRemoteQueueID", NULL))
+ p->type |= CUPS_PRINTER_REMOTE;
+
+ /*
+ * Close the PPD and set the type...
+ */
+
+ ppdClose(ppd);
+ }
+ else if (!access(ppd_name, 0))
+ {
+ int pline; /* PPD line number */
+ ppd_status_t pstatus; /* PPD load status */
+
+
+ pstatus = ppdLastError(&pline);
+
+ cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded!",
+ p->name);
+
+ if (pstatus <= PPD_ALLOC_ERROR)
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s", strerror(errno));
+ else
+ cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d.",
+ ppdErrorString(pstatus), pline);
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Hint: Run \"cupstestppd %s\" and fix any errors.",
+ ppd_name);
+
+ /*
+ * Add a filter from application/vnd.cups-raw to printer/name to
+ * handle "raw" printing by users.
+ */
+
+ add_string_array(&(p->filters), "application/vnd.cups-raw 0 -");
+
+ /*
+ * Add a PostScript filter, since this is still possibly PS printer.
+ */
+
+ add_string_array(&(p->filters), "application/vnd.cups-postscript 0 -");
+ }
+ else
+ {
+ /*
+ * If we have an interface script, add a filter entry for it...
+ */
+
+ char interface[1024]; /* Interface script */
+
+
+ snprintf(interface, sizeof(interface), "%s/interfaces/%s", ServerRoot,
+ p->name);
+ if (!access(interface, X_OK))
+ {
+ /*
+ * Yes, we have a System V style interface script; use it!
+ */
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL,
+ "Local System V Printer");
+
+ snprintf(interface, sizeof(interface), "*/* 0 %s/interfaces/%s",
+ ServerRoot, p->name);
+ add_string_array(&(p->filters), interface);
+ }
+ else if (!strncmp(p->device_uri, "ipp://", 6) &&
+ (strstr(p->device_uri, "/printers/") != NULL ||
+ strstr(p->device_uri, "/classes/") != NULL ||
+ (strstr(p->device_uri, "._ipp.") != NULL &&
+ !strcmp(p->device_uri + strlen(p->device_uri) - 5,
+ "/cups"))))
+ {
+ /*
+ * Tell the client this is really a hard-wired remote printer.
+ */
+
+ p->type |= CUPS_PRINTER_REMOTE;
+
+ /*
+ * Point the printer-uri-supported attribute to the
+ * remote printer...
+ */
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
+ "printer-uri-supported", NULL, p->device_uri);
+
+ /*
+ * Then set the make-and-model accordingly...
+ */
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, "Remote Printer");
+
+ /*
+ * Print all files directly...
+ */
+
+ p->raw = 1;
+ p->remote = 1;
+ }
+ else
+ {
+ /*
+ * Otherwise we have neither - treat this as a "dumb" printer
+ * with no PPD file...
+ */
+
+ ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, "Local Raw Printer");
+
+ p->raw = 1;
+ }
+ }
+
+ ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "finishings-supported", num_finishings, finishings);
+ ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+ "finishings-default", IPP_FINISHINGS_NONE);
+
+ if (ppd && (cache = cupsFileOpen(cache_name, "w")) != NULL)
+ {
+ /*
+ * Save cached PPD attributes to disk...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Saving %s...", cache_name);
+
+ p->ppd_attrs->state = IPP_IDLE;
+
+ if (ippWriteIO(cache, (ipp_iocb_t)cupsFileWrite, 1, NULL,
+ p->ppd_attrs) != IPP_DATA)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to save PPD cache file \"%s\" - %s", cache_name,
+ strerror(errno));
+ unlink(cache_name);
+ }
+
+ cupsFileClose(cache);
+ }
+ else if (cache_info.st_mtime)
+ {
+ /*
+ * Remove cache file...
+ */
+
+ unlink(cache_name);
+ }
+}
+
+
#ifdef __sgi
/*
* 'write_irix_config()' - Update the config files used by the IRIX
diff --git a/scheduler/printers.h b/scheduler/printers.h
index abc1b4d0a..0effd8bd9 100644
--- a/scheduler/printers.h
+++ b/scheduler/printers.h
@@ -3,7 +3,7 @@
*
* Printer definitions for the Common UNIX Printing System (CUPS) scheduler.
*
- * Copyright 2007 by Apple Inc.
+ * Copyright 2007-2008 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
@@ -47,6 +47,7 @@ typedef struct cupsd_printer_s
cupsd_policy_t *op_policy_ptr; /* Pointer to operation policy */
int shared; /* Shared? */
int accepting; /* Accepting jobs? */
+ int holding_new_jobs; /* Holding new jobs for printing? */
int in_implicit_class; /* In an implicit class? */
ipp_pstate_t state; /* Printer state */
char state_message[1024]; /* Printer state message */
@@ -67,7 +68,8 @@ typedef struct cupsd_printer_s
*prefiltertype; /* Pseudo-filetype for pre-filters */
cups_array_t *filetypes; /* Supported file types */
void *job; /* Current job in queue */
- ipp_t *attrs; /* Attributes supported by this printer */
+ ipp_t *attrs, /* Attributes supported by this printer */
+ *ppd_attrs; /* Attributes based on the PPD */
int num_printers, /* Number of printers in class */
last_printer; /* Last printer job was sent to */
struct cupsd_printer_s **printers; /* Printers in class */
diff --git a/scheduler/select.c b/scheduler/select.c
index 05512ca71..4e81c4a9e 100644
--- a/scheduler/select.c
+++ b/scheduler/select.c
@@ -638,7 +638,7 @@ cupsdDoSelect(long timeout) /* I - Timeout in seconds */
{
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdDoSelect: pollfds[%d]={fd=%d, revents=%x}",
- pfd - cupsd_pollfds, pfd->fd, pfd->revents);
+ (int)(pfd - cupsd_pollfds), pfd->fd, pfd->revents);
if (!pfd->revents)
continue;