From: msweet
CUPS 1.4 and higher define two new attributes for constraints, cupsUIConstraints and cupsUIResolver. Each cupsUIConstraints attribute points to a cupsUIResolver -attribute which corrects the conflict condition. The same -cupsUIResolver can be used by multiple cupsUIConstraints.
+attribute which specifies alternate options that resolve the conflict condition. +The same cupsUIResolver can be used by multiple +cupsUIConstraints. + +Note: + +When developing PPD files that contain constraints, it is very important + to use the cupstestppd(1) program to + verify that your constraints are accurate and cannot result in unresolvable + option selections.
+ +
Lists two or more options which conflict. The "resolver" string is a (possibly unique) keyword which specifies which options to change when the -constraint exists. When no resolver is provided, a "revert to defaults" -change is assumed - this type of constraint is typically only used for -installable options.
+constraint exists. When no resolver is provided, CUPS first tries the default +choice followed by testing each option choice to resolve the conflict.Examples:
@@ -403,6 +412,15 @@ installable options. *% Specify that 2-sided printing cannot happen on transparencies *cupsUIConstraints transparency: "*Duplex *MediaType Transparency" +*% Specify that envelope printing cannot happen from the paper trays +*cupsUIConstraints envelope: "*PageSize Env10 *InputSlot Tray1" +*cupsUIConstraints envelope: "*PageSize Env10 *InputSlot Tray1" +*cupsUIConstraints envelope: "*PageSize EnvDL *InputSlot Tray2" +*cupsUIConstraints envelope: "*PageSize EnvDL *InputSlot Tray2" + +*% Specify an installable option constraint for the envelope feeder +*cupsUIConstraints: "*InputSlot EnvFeeder *InstalledEnvFeeder" + *% Specify that photo printing cannot happen on plain paper or transparencies at 1200dpi *cupsUIConstraints photo: "*OutputMode Photo *MediaType Plain *Resolution 1200dpi" *cupsUIConstraints photo: "*OutputMode Photo *MediaType Transparency *Resolution 1200dpi" @@ -410,18 +428,29 @@ installable options.*cupsUIResolution resolver: "*Keyword OptionKeyword ..."
+*cupsUIResolution resolver: "*Keyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."
-Specifies one or more options to mark/select to resolve a constraint. The +
Specifies two or more options to mark/select to resolve a constraint. The "resolver" string identifies a particular action to take for one or more cupsUIConstraints. The same action -can be used for multiple constraints.
+can be used for multiple constraints. The option keyword pairs are treated as +an ordered list of option selections to try - only the first N selections will +be used, where N is the minimum number of selections required. Because +cupsResolveConflicts()
+will not change the most recent option selection passed to it, at least two
+options from the constraints must be listed to avoid situations where conflicts
+cannot be resolved.
Examples:
-*% Specify the option to change for the 2-sided transparency constraint
-*cupsUIResolver transparency: "*Duplex None"
+*% Specify the options to change for the 2-sided transparency constraint
+*cupsUIResolver transparency: "*Duplex None *MediaType Plain"
+
+*% Specify the options to change for the envelope printing constraints. Notice
+*% that we try to change the InputSlot to either the envelope feeder or the
+*% manual feed first, then we change the page size...
+*cupsUIResolver envelope: "*InputSlot EnvFeeder *InputSlot ManualFeed *PageSize Letter"
*% Specify the options to change for the photo printing constraints
*cupsUIResolver photo: "*OutputMode Best *Resolution 600dpi"
diff --git a/driver/Dependencies b/driver/Dependencies
index a89ca293f4..2111f79f0e 100644
--- a/driver/Dependencies
+++ b/driver/Dependencies
@@ -11,11 +11,13 @@ commandtopclx.o: ../cups/string.h ../config.h ../data/pcl.h
rastertoescpx.o: driver.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
rastertoescpx.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h
rastertoescpx.o: ../cups/file.h ../cups/language.h ../cups/raster.h
-rastertoescpx.o: ../cups/string.h ../config.h ../data/escp.h
+rastertoescpx.o: ../cups/i18n.h ../cups/transcode.h ../cups/string.h
+rastertoescpx.o: ../config.h ../data/escp.h
rastertopclx.o: driver.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
rastertopclx.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h
rastertopclx.o: ../cups/file.h ../cups/language.h ../cups/raster.h
-rastertopclx.o: pcl-common.h ../cups/string.h ../config.h ../data/pcl.h
+rastertopclx.o: ../cups/i18n.h ../cups/transcode.h ../cups/string.h
+rastertopclx.o: ../config.h pcl-common.h ../data/pcl.h
pcl-common.o: driver.h ../cups/cups.h ../cups/ipp.h ../cups/http.h
pcl-common.o: ../cups/versioning.h ../cups/ppd.h ../cups/array.h
pcl-common.o: ../cups/file.h ../cups/language.h ../cups/raster.h pcl-common.h
diff --git a/man/cupsfilter.man b/man/cupsfilter.man
index 337c57e0d6..9bd428d9f6 100644
--- a/man/cupsfilter.man
+++ b/man/cupsfilter.man
@@ -11,14 +11,14 @@
.\" 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/".
.\"
-.TH cupsfilter 8 "Common UNIX Printing System" "10 September 2008" "Apple Inc."
+.TH cupsfilter 8 "Common UNIX Printing System" "26 February 2009" "Apple Inc."
.SH NAME
cupsfilter \- convert a file to another format using cups filters
.SH SYNOPSIS
.B cupsfilter
[ -c
.I config-file
-] -j
+] [ -e ] -j
.I job-id[,N]
[ -m
.I mime/type
@@ -42,6 +42,10 @@ through CUPS. By default, \fIcupsfilter\fR generates a PDF file.
.br
Uses the named cupsd.conf configuration file.
.TP 5
+-e
+.br
+Use every filter from the PPD file.
+.TP 5
-j job-id[,N]
.br
Converts document N from the specified job. If N is omitted, document 1 is
diff --git a/man/cupstestppd.man b/man/cupstestppd.man
index 4757c5d72e..fd2b878b56 100644
--- a/man/cupstestppd.man
+++ b/man/cupstestppd.man
@@ -12,7 +12,7 @@
.\" 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/".
.\"
-.TH cupstestppd 1 "Common UNIX Printing System" "3 May 2007" "Apple Inc."
+.TH cupstestppd 1 "Common UNIX Printing System" "2 March 2009" "Apple Inc."
.SH NAME
cupstestppd \- test conformance of ppd files
.SH SYNOPSIS
@@ -63,6 +63,10 @@ Report all filter errors as warnings.
.br
Report all profile errors as warnings.
.TP 5
+-W sizes
+.br
+Report all media size errors as warnings.
+.TP 5
-W translations
.br
Report all translation errors as warnings.
diff --git a/scheduler/cupsd.h b/scheduler/cupsd.h
index e9d8df1f07..8da2d96169 100644
--- a/scheduler/cupsd.h
+++ b/scheduler/cupsd.h
@@ -152,8 +152,10 @@ typedef void (*cupsd_selfunc_t)(void *data);
* Globals...
*/
-VAR int TestConfigFile VALUE(0);
+VAR int TestConfigFile VALUE(0),
/* Test the cupsd.conf file? */
+ UseProfiles VALUE(1);
+ /* Use security profiles for child procs? */
VAR int MaxFDs VALUE(0);
/* Maximum number of files */
diff --git a/scheduler/cupsfilter.c b/scheduler/cupsfilter.c
index d3c30210a8..17f6f89ea8 100644
--- a/scheduler/cupsfilter.c
+++ b/scheduler/cupsfilter.c
@@ -86,7 +86,8 @@ static int compare_pids(mime_filter_t *a, mime_filter_t *b);
static char *escape_options(int num_options, cups_option_t *options);
static int exec_filter(const char *filter, char **argv,
char **envp, int infd, int outfd);
-static int exec_filters(cups_array_t *filters, const char *infile,
+static int exec_filters(mime_type_t *srctype,
+ cups_array_t *filters, const char *infile,
const char *outfile, const char *ppdfile,
const char *printer, const char *user,
const char *title, int num_options,
@@ -133,7 +134,8 @@ main(int argc, /* I - Number of command-line args */
const char *ppdfile; /* PPD file */
const char *title, /* Title string */
*user; /* Username */
- int removeppd, /* Remove PPD file */
+ int all_filters, /* Use all filters */
+ removeppd, /* Remove PPD file */
removeinfile; /* Remove input file */
int status; /* Execution status */
@@ -159,6 +161,7 @@ main(int argc, /* I - Number of command-line args */
ppdfile = NULL;
title = NULL;
user = cupsUser();
+ all_filters = 0;
removeppd = 0;
removeinfile = 0;
@@ -213,6 +216,10 @@ main(int argc, /* I - Number of command-line args */
removeinfile = 1;
break;
+ case 'e' : /* Use every filter from the PPD file */
+ all_filters = 1;
+ break;
+
case 'f' : /* Specify input file... */
i ++;
if (i < argc && !infile)
@@ -380,8 +387,16 @@ main(int argc, /* I - Number of command-line args */
return (1);
}
- printer_type = add_printer_filters(command, mime, printer, ppdfile,
- &prefilter_type);
+ if (all_filters)
+ {
+ printer_type = add_printer_filters(command, mime, printer, ppdfile,
+ &prefilter_type);
+ }
+ else
+ {
+ printer_type = mimeType(mime, "application", "vnd.cups-postscript");
+ prefilter_type = NULL;
+ }
/*
* Get the source and destination types...
@@ -429,6 +444,8 @@ main(int argc, /* I - Number of command-line args */
filters = cupsArrayNew(NULL, NULL);
cupsArrayAdd(filters, &GZIPFilter);
+ GZIPFilter.src = src;
+ GZIPFilter.dst = dst;
}
else if ((filters = mimeFilter(mime, src, dst, &cost)) == NULL)
{
@@ -456,7 +473,8 @@ main(int argc, /* I - Number of command-line args */
filter;
filter = (mime_filter_t *)cupsArrayNext(filters))
{
- if ((prefilter = mimeFilterLookup(mime, filter->src, prefilter_type)))
+ if ((prefilter = mimeFilterLookup(mime, filter->src,
+ prefilter_type)) != NULL)
cupsArrayAdd(prefilters, prefilter);
cupsArrayAdd(prefilters, filter);
@@ -470,7 +488,7 @@ main(int argc, /* I - Number of command-line args */
* Do it!
*/
- status = exec_filters(filters, infile, outfile, ppdfile, printer, user,
+ status = exec_filters(src, filters, infile, outfile, ppdfile, printer, user,
title, num_options, options);
/*
@@ -610,6 +628,8 @@ add_printer_filters(
if (ppdattr->value)
add_printer_filter(command, mime, *prefilter_type, ppdattr->value);
}
+ else
+ *prefilter_type = NULL;
return (printer_type);
}
@@ -789,7 +809,8 @@ exec_filter(const char *filter, /* I - Filter to execute */
*/
static int /* O - 0 on success, 1 on error */
-exec_filters(cups_array_t *filters, /* I - Array of filters to run */
+exec_filters(mime_type_t *srctype, /* I - Source type */
+ cups_array_t *filters, /* I - Array of filters to run */
const char *infile, /* I - File to filter */
const char *outfile, /* I - File to create */
const char *ppdfile, /* I - PPD file, if any */
@@ -833,9 +854,8 @@ exec_filters(cups_array_t *filters, /* I - Array of filters to run */
optstr = escape_options(num_options, options);
- filter = cupsArrayFirst(filters);
snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s",
- filter->src->super, filter->src->type);
+ srctype->super, srctype->type);
snprintf(cups_datadir, sizeof(cups_datadir), "CUPS_DATADIR=%s", DataDir);
snprintf(cups_fontpath, sizeof(cups_fontpath), "CUPS_FONTPATH=%s", FontPath);
snprintf(cups_serverbin, sizeof(cups_serverbin), "CUPS_SERVERBIN=%s",
@@ -1285,6 +1305,7 @@ usage(const char *command, /* I - Command name */
"Options:\n"
"\n"
" -c cupsd.conf Set cupsd.conf file to use\n"
+ " -e Use every filter from the PPD file\n"
" -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
" -n copies Set number of copies\n"
" -o name=value Set option(s)\n"
@@ -1296,6 +1317,7 @@ usage(const char *command, /* I - Command name */
"\n"
"Options:\n"
"\n"
+ " -e Use every filter from the PPD file\n"
" -f filename Set file to be converted (otherwise stdin)\n"
" -o filename Set file to be generated (otherwise stdout)\n"
" -i mime/type Set input MIME type (otherwise auto-typed)\n"
diff --git a/scheduler/ipp.c b/scheduler/ipp.c
index 3fc1f33b0c..c0160e2e9e 100644
--- a/scheduler/ipp.c
+++ b/scheduler/ipp.c
@@ -360,7 +360,8 @@ cupsdProcessIPPRequest(
*/
attr = con->request->attrs;
- if (attr && !strcmp(attr->name, "attributes-charset") &&
+ if (attr && attr->name &&
+ !strcmp(attr->name, "attributes-charset") &&
(attr->value_tag & IPP_TAG_MASK) == IPP_TAG_CHARSET)
charset = attr;
else
@@ -369,7 +370,8 @@ cupsdProcessIPPRequest(
if (attr)
attr = attr->next;
- if (attr && !strcmp(attr->name, "attributes-natural-language") &&
+ if (attr && attr->name &&
+ !strcmp(attr->name, "attributes-natural-language") &&
(attr->value_tag & IPP_TAG_MASK) == IPP_TAG_LANGUAGE)
language = attr;
else
diff --git a/scheduler/job.c b/scheduler/job.c
index 25ddffd9fc..cd185c4739 100644
--- a/scheduler/job.c
+++ b/scheduler/job.c
@@ -22,7 +22,6 @@
* cupsdCleanJobs() - Clean out old jobs.
* cupsdContinueJob() - Continue printing with the next file in a job.
* cupsdDeleteJob() - Free all memory used by a job.
- * cupsdFinishJob() - Finish a job.
* cupsdFreeAllJobs() - Free all jobs from memory.
* cupsdFindJob() - Find the specified job.
* cupsdGetPrinterJobCount() - Get the number of pending, processing, or held
@@ -491,7 +490,7 @@ cupsdContinueJob(cupsd_job_t *job) /* I - Job */
FilterLevel -= job->cost;
- filters = NULL;
+ filters = NULL;
if (job->printer->raw)
{
@@ -827,7 +826,7 @@ cupsdContinueJob(cupsd_job_t *job) /* I - Job */
* Just the language code (ll)...
*/
- snprintf(lang, sizeof(lang), "LANG=%s.UTF8",
+ snprintf(lang, sizeof(lang), "LANG=%s.UTF-8",
attr->values[0].string.text);
break;
@@ -836,7 +835,7 @@ cupsdContinueJob(cupsd_job_t *job) /* I - Job */
* Language and country code (ll-cc)...
*/
- snprintf(lang, sizeof(lang), "LANG=%c%c_%c%c.UTF8",
+ snprintf(lang, sizeof(lang), "LANG=%c%c_%c%c.UTF-8",
attr->values[0].string.text[0],
attr->values[0].string.text[1],
toupper(attr->values[0].string.text[3] & 255),
@@ -2481,9 +2480,40 @@ finalize_job(cupsd_job_t *job) /* I - Job */
* Process the exit status...
*/
- printer_state = IPP_PRINTER_IDLE;
- job_state = IPP_JOB_COMPLETED;
- message = "Job completed.";
+ if (job->printer->state == IPP_PRINTER_PROCESSING)
+ printer_state = IPP_PRINTER_IDLE;
+ else
+ printer_state = job->printer->state;
+
+ switch (job_state = job->state_value)
+ {
+ case IPP_JOB_PENDING :
+ message = "Job paused.";
+ break;
+
+ case IPP_JOB_HELD :
+ message = "Job held.";
+ break;
+
+ default :
+ case IPP_JOB_PROCESSING :
+ case IPP_JOB_COMPLETED :
+ job_state = IPP_JOB_COMPLETED;
+ message = "Job completed.";
+ break;
+
+ case IPP_JOB_STOPPED :
+ message = "Job stopped.";
+ break;
+
+ case IPP_JOB_CANCELED :
+ message = "Job canceled.";
+ break;
+
+ case IPP_JOB_ABORTED :
+ message = "Job aborted.";
+ break;
+ }
if (job->status < 0)
{
@@ -2741,8 +2771,8 @@ get_options(cupsd_job_t *job, /* I - Job */
optptr = options;
*optptr = '\0';
- snprintf(title, sizeof(title), "%s-%d", job->printer->name, job->id);
- strcpy(copies, "1");
+ snprintf(title, title_size, "%s-%d", job->printer->name, job->id);
+ strlcpy(copies, "1", copies_size);
for (attr = job->attrs->attrs; attr != NULL; attr = attr->next)
{
@@ -2754,12 +2784,12 @@ get_options(cupsd_job_t *job, /* I - Job */
*/
if (!banner_page)
- sprintf(copies, "%d", attr->values[0].integer);
+ snprintf(copies, copies_size, "%d", attr->values[0].integer);
}
else if (!strcmp(attr->name, "job-name") &&
(attr->value_tag == IPP_TAG_NAME ||
attr->value_tag == IPP_TAG_NAMELANG))
- strlcpy(title, attr->values[0].string.text, sizeof(title));
+ strlcpy(title, attr->values[0].string.text, title_size);
else if (attr->group_tag == IPP_TAG_JOB)
{
/*
@@ -3494,10 +3524,11 @@ start_job(cupsd_job_t *job, /* I - Job ID */
cupsdSetJobState(job, IPP_JOB_PROCESSING, CUPSD_JOB_DEFAULT, NULL);
cupsdSetPrinterState(printer, IPP_PRINTER_PROCESSING, 0);
- job->cost = 0;
- job->progress = 0;
- job->printer = printer;
- printer->job = job;
+ job->cost = 0;
+ job->current_file = 0;
+ job->progress = 0;
+ job->printer = printer;
+ printer->job = job;
/*
* Setup the last exit status and security profiles...
diff --git a/scheduler/main.c b/scheduler/main.c
index 437f0f5ba5..ccc3952114 100644
--- a/scheduler/main.c
+++ b/scheduler/main.c
@@ -145,8 +145,9 @@ main(int argc, /* I - Number of command-line args */
struct stat statbuf; /* Needed for checking lpsched FIFO */
#endif /* __sgi */
#ifdef __APPLE__
- int run_as_child = 0;
+ int run_as_child = 0,
/* Needed for Mac OS X fork/exec */
+ use_sysman = 1; /* Use system management functions? */
#else
time_t netif_time = 0; /* Time since last network update */
#endif /* __APPLE__ */
@@ -188,6 +189,11 @@ main(int argc, /* I - Number of command-line args */
switch (*opt)
{
#ifdef __APPLE__
+ case 'S' : /* Disable system management functions */
+ puts("Warning: -S (disable system management) for internal testing use only!");
+ use_sysman = 0;
+ break;
+
case 'C' : /* Run as child with config file */
run_as_child = 1;
fg = -1;
@@ -270,11 +276,16 @@ main(int argc, /* I - Number of command-line args */
break;
case 'p' : /* Stop immediately for profiling */
- puts("Warning: -p option is for internal testing use only!");
+ puts("Warning: -p (startup profiling) is for internal testing use only!");
stop_scheduler = 1;
fg = 1;
break;
+ case 'P' : /* Disable security profiles */
+ puts("Warning: -P (disable security profiles) is for internal testing use only!");
+ UseProfiles = 0;
+ break;
+
case 't' : /* Test the cupsd.conf file... */
TestConfigFile = 1;
fg = 1;
@@ -630,7 +641,8 @@ main(int argc, /* I - Number of command-line args */
* Start power management framework...
*/
- cupsdStartSystemMonitor();
+ if (use_sysman)
+ cupsdStartSystemMonitor();
#endif /* __APPLE__ */
/*
@@ -1149,7 +1161,8 @@ main(int argc, /* I - Number of command-line args */
* Stop monitoring system event monitoring...
*/
- cupsdStopSystemMonitor();
+ if (use_sysman)
+ cupsdStopSystemMonitor();
#endif /* __APPLE__ */
#ifdef HAVE_GSSAPI
@@ -1742,6 +1755,7 @@ process_children(void)
cupsdContinueJob(job);
}
}
+ break;
}
}
diff --git a/scheduler/printers.c b/scheduler/printers.c
index c826120f19..47142db2bd 100644
--- a/scheduler/printers.c
+++ b/scheduler/printers.c
@@ -2015,7 +2015,7 @@ cupsdSetPrinterAttr(
* Don't allow empty values...
*/
- if (!*value)
+ if (!*value && strcmp(name, "marker-message"))
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Ignoring empty \"%s\" attribute", name);
return;
@@ -2736,10 +2736,6 @@ cupsdSetPrinterReasons(
* Found a match, so remove it...
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdSetPrinterReasons: Removing \"%s\" at index %d",
- reason, i);
-
p->num_reasons --;
_cupsStrFree(p->reasons[i]);
@@ -2779,10 +2775,6 @@ cupsdSetPrinterReasons(
return;
}
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdSetPrinterReasons: Adding \"%s\" at index %d",
- reason, i);
-
p->reasons[i] = _cupsStrAlloc(reason);
p->num_reasons ++;
diff --git a/scheduler/process.c b/scheduler/process.c
index bd548ff06c..45d3bcfb6a 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -83,7 +83,7 @@ cupsdCreateProfile(int job_id) /* I - Job ID or 0 for none */
temp[1024]; /* Quoted TempDir */
- if (RunUser)
+ if (!UseProfiles || RunUser)
{
/*
* Only use sandbox profiles as root...
diff --git a/systemv/Dependencies b/systemv/Dependencies
index 79765c4b9b..f0b1808137 100644
--- a/systemv/Dependencies
+++ b/systemv/Dependencies
@@ -23,8 +23,8 @@ cupstestdsc.o: ../cups/file.h ../cups/i18n.h ../cups/transcode.h
cupstestppd.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h
cupstestppd.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h
cupstestppd.o: ../cups/array.h ../cups/file.h ../cups/language.h
-cupstestppd.o: ../cups/ppd-private.h ../cups/cups.h ../cups/i18n.h
-cupstestppd.o: ../cups/transcode.h ../cups/raster.h
+cupstestppd.o: ../cups/dir.h ../cups/ppd-private.h ../cups/cups.h
+cupstestppd.o: ../cups/i18n.h ../cups/transcode.h ../cups/raster.h
lp.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h
lp.o: ../cups/http.h ../cups/versioning.h ../cups/ppd.h ../cups/array.h
lp.o: ../cups/file.h ../cups/language.h ../cups/i18n.h ../cups/transcode.h
diff --git a/systemv/cupstestppd.c b/systemv/cupstestppd.c
index 855c17fbff..4a619ebcad 100644
--- a/systemv/cupstestppd.c
+++ b/systemv/cupstestppd.c
@@ -3,7 +3,7 @@
*
* PPD test program for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007-2008 by Apple Inc.
+ * Copyright 2007-2009 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
@@ -21,17 +21,19 @@
* main() - Main entry for test program.
* check_basics() - Check for CR LF, mixed line endings, and blank
* lines.
+ * check_constraints() - Check UIConstraints in the PPD file.
* check_case() - Check that there are no duplicate groups, options,
* or choices that differ only by case.
- * check_constraints() - Check UIConstraints in the PPD file.
* check_defaults() - Check default option keywords in the PPD file.
* check_duplex() - Check duplex keywords in the PPD file.
* check_filters() - Check filters in the PPD file.
* check_profiles() - Check ICC color profiles in the PPD file.
+ * check_sizes() - Check media sizes in the PPD file.
* check_translations() - Check translations in the PPD file.
* show_conflicts() - Show option conflicts in a PPD file.
* test_raster() - Test PostScript commands for raster printers.
* usage() - Show program usage...
+ * valid_path() - Check whether a path has the correct capitalization.
* valid_utf8() - Check whether a string contains valid UTF-8 text.
*/
@@ -41,12 +43,13 @@
#include
#include
+#include
#include
#include
#include
#include
#include
-#include
+#include
/*
@@ -62,7 +65,8 @@ enum
WARN_PROFILES = 8,
WARN_TRANSLATIONS = 16,
WARN_DUPLEX = 32,
- WARN_ALL = 63
+ WARN_SIZES = 64,
+ WARN_ALL = 127
};
@@ -93,6 +97,168 @@ enum
};
+/*
+ * Standard Adobe media keywords (must remain sorted)...
+ */
+
+static const char adobe_size_names[][PPD_MAX_NAME] =
+{
+ "10x11",
+ "10x13",
+ "10x14",
+ "12x11",
+ "15x11",
+ "7x9",
+ "8x10",
+ "9x11",
+ "9x12",
+ "A0",
+ "A1",
+ "A10",
+ "A2",
+ "A3",
+ "A3Extra",
+ "A3Rotated",
+ "A4",
+ "A4Extra",
+ "A4Plus",
+ "A4Rotated",
+ "A4Small",
+ "A5",
+ "A5Extra",
+ "A5Rotated",
+ "A6",
+ "A6Rotated",
+ "A7",
+ "A8",
+ "A9",
+ "ARCHA",
+ "ARCHB",
+ "ARCHC",
+ "ARCHD",
+ "ARCHE",
+ "AnsiA",
+ "AnsiB",
+ "AnsiC",
+ "AnsiD",
+ "AnsiE",
+ "B0",
+ "B1",
+ "B1",
+ "B10",
+ "B2",
+ "B3",
+ "B4",
+ "B4Rotated",
+ "B5",
+ "B5Rotated",
+ "B6",
+ "B6Rotated",
+ "B7",
+ "B8",
+ "B9",
+ "C4",
+ "C5",
+ "C6",
+ "DL",
+ "DoublePostcard",
+ "DoublePostcardRotated",
+ "Env10",
+ "Env11",
+ "Env12",
+ "Env14",
+ "Env9",
+ "EnvC0",
+ "EnvC1",
+ "EnvC2",
+ "EnvC3",
+ "EnvC4",
+ "EnvC5",
+ "EnvC6",
+ "EnvC65",
+ "EnvC7",
+ "EnvChou3",
+ "EnvChou3Rotated",
+ "EnvChou4",
+ "EnvChou4Rotated",
+ "EnvDL",
+ "EnvISOB4",
+ "EnvISOB5",
+ "EnvISOB6",
+ "EnvInvite",
+ "EnvItalian",
+ "EnvKaku2",
+ "EnvKaku2Rotated",
+ "EnvKaku3",
+ "EnvKaku3Rotated",
+ "EnvMonarch",
+ "EnvPRC1",
+ "EnvPRC10",
+ "EnvPRC10Rotated",
+ "EnvPRC1Rotated",
+ "EnvPRC2",
+ "EnvPRC2Rotated",
+ "EnvPRC3",
+ "EnvPRC3Rotated",
+ "EnvPRC4",
+ "EnvPRC4Rotated",
+ "EnvPRC5",
+ "EnvPRC5Rotated",
+ "EnvPRC6",
+ "EnvPRC6Rotated",
+ "EnvPRC7",
+ "EnvPRC7Rotated",
+ "EnvPRC8",
+ "EnvPRC8Rotated",
+ "EnvPRC9",
+ "EnvPRC9Rotated",
+ "EnvPersonal",
+ "EnvYou4",
+ "EnvYou4Rotated",
+ "Executive",
+ "FanFoldGerman",
+ "FanFoldGermanLegal",
+ "FanFoldUS",
+ "Folio",
+ "ISOB0",
+ "ISOB1",
+ "ISOB10",
+ "ISOB2",
+ "ISOB3",
+ "ISOB4",
+ "ISOB5",
+ "ISOB5Extra",
+ "ISOB6",
+ "ISOB7",
+ "ISOB8",
+ "ISOB9",
+ "Ledger",
+ "Legal",
+ "LegalExtra",
+ "Letter",
+ "LetterExtra",
+ "LetterPlus",
+ "LetterRotated",
+ "LetterSmall",
+ "Monarch",
+ "Note",
+ "PRC16K",
+ "PRC16KRotated",
+ "PRC32K",
+ "PRC32KBig",
+ "PRC32KBigRotated",
+ "PRC32KRotated",
+ "Postcard",
+ "PostcardRotated",
+ "Quarto",
+ "Statement",
+ "SuperA",
+ "SuperB",
+ "Tabloid",
+ "TabloidExtra"
+};
+
+
/*
* Local functions...
*/
@@ -109,11 +275,14 @@ static int check_filters(ppd_file_t *ppd, const char *root, int errors,
int verbose, int warn);
static int check_profiles(ppd_file_t *ppd, const char *root, int errors,
int verbose, int warn);
-static int check_translations(ppd_file_t *ppd, int errors, int verbose,\
+static int check_sizes(ppd_file_t *ppd, int errors, int verbose, int warn);
+static int check_translations(ppd_file_t *ppd, int errors, int verbose,
int warn);
static void show_conflicts(ppd_file_t *ppd);
static int test_raster(ppd_file_t *ppd, int verbose);
static void usage(void);
+static int valid_path(const char *keyword, const char *path, int errors,
+ int verbose, int warn);
static int valid_utf8(const char *s);
@@ -203,6 +372,8 @@ main(int argc, /* I - Number of command-line args */
warn |= WARN_FILTERS;
else if (!strcmp(argv[i], "profiles"))
warn |= WARN_PROFILES;
+ else if (!strcmp(argv[i], "sizes"))
+ warn |= WARN_SIZES;
else if (!strcmp(argv[i], "translations"))
warn |= WARN_TRANSLATIONS;
else if (!strcmp(argv[i], "all"))
@@ -1088,6 +1259,9 @@ main(int argc, /* I - Number of command-line args */
if (!(warn & WARN_PROFILES))
errors = check_profiles(ppd, root, errors, verbose, 0);
+ if (!(warn & WARN_SIZES))
+ errors = check_sizes(ppd, errors, verbose, 0);
+
if (!(warn & WARN_TRANSLATIONS))
errors = check_translations(ppd, errors, verbose, 0);
@@ -1222,6 +1396,11 @@ main(int argc, /* I - Number of command-line args */
if (warn & WARN_FILTERS)
errors = check_filters(ppd, root, errors, verbose, 1);
+ if (warn & WARN_SIZES)
+ errors = check_sizes(ppd, errors, verbose, 1);
+ else
+ errors = check_sizes(ppd, errors, verbose, 2);
+
if (warn & WARN_TRANSLATIONS)
errors = check_translations(ppd, errors, verbose, 1);
@@ -1384,36 +1563,6 @@ main(int argc, /* I - Number of command-line args */
}
}
-#ifdef __APPLE__
- /*
- * APDialogExtension
- */
-
- for (attr = ppdFindAttr(ppd, "APDialogExtension", NULL);
- attr != NULL;
- attr = ppdFindNextAttr(ppd, "APDialogExtension", NULL))
- {
- if ((!attr->value || access(attr->value, 0)) && verbose >= 0)
- _cupsLangPrintf(stdout, _(" WARN Missing "
- "APDialogExtension file \"%s\"\n"),
- attr->value ? attr->value : "");
- }
-
- /*
- * APPrinterIconPath
- */
-
- for (attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL);
- attr != NULL;
- attr = ppdFindNextAttr(ppd, "APPrinterIconPath", NULL))
- {
- if ((!attr->value || access(attr->value, 0)) && verbose >= 0)
- _cupsLangPrintf(stdout, _(" WARN Missing "
- "APPrinterIconPath file \"%s\"\n"),
- attr->value ? attr->value : "");
- }
-#endif /* __APPLE__ */
-
if (verbose > 0)
{
if (errors)
@@ -1858,6 +2007,24 @@ check_constraints(ppd_file_t *ppd, /* I - PPD file */
}
}
+ /*
+ * Resolvers must list at least two options...
+ */
+
+ if (num_options < 2)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ _cupsLangPrintf(stdout,
+ _(" %s cupsUIResolver %s does not list at least "
+ "two different options!\n"),
+ prefix, constattr->spec);
+
+ if (!warn)
+ errors ++;
+ }
+
/*
* Test the resolver...
*/
@@ -2245,6 +2412,10 @@ check_filters(ppd_file_t *ppd, /* I - PPD file */
prefix = warn ? " WARN " : "**FAIL**";
+ /*
+ * cupsFilter
+ */
+
for (i = 0; i < ppd->num_filters; i ++)
{
if (sscanf(ppd->filters[i], "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type,
@@ -2290,9 +2461,15 @@ check_filters(ppd_file_t *ppd, /* I - PPD file */
if (!warn)
errors ++;
}
+ else
+ errors = valid_path("cupsFilter", pathprog, errors, verbose, warn);
}
}
+ /*
+ * cupsPreFilter
+ */
+
for (attr = ppdFindAttr(ppd, "cupsPreFilter", NULL);
attr;
attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
@@ -2341,8 +2518,110 @@ check_filters(ppd_file_t *ppd, /* I - PPD file */
if (!warn)
errors ++;
}
+ else
+ errors = valid_path("cupsPreFilter", pathprog, errors, verbose, warn);
+ }
+ }
+
+#ifdef __APPLE__
+ /*
+ * APDialogExtension
+ */
+
+ for (attr = ppdFindAttr(ppd, "APDialogExtension", NULL);
+ attr != NULL;
+ attr = ppdFindNextAttr(ppd, "APDialogExtension", NULL))
+ {
+ if (!attr->value || access(attr->value, 0))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing "
+ "APDialogExtension file \"%s\"\n"),
+ prefix, attr->value ? attr->value : "");
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("APDialogExtension", attr->value, errors, verbose,
+ warn);
+ }
+
+ /*
+ * APPrinterIconPath
+ */
+
+ if ((attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL)
+ {
+ if (!attr->value || access(attr->value, 0))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing "
+ "APPrinterIconPath file \"%s\"\n"),
+ prefix, attr->value ? attr->value : "");
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("APPrinterIconPath", attr->value, errors, verbose,
+ warn);
+ }
+
+ /*
+ * APPrinterLowInkTool
+ */
+
+ if ((attr = ppdFindAttr(ppd, "APPrinterLowInkTool", NULL)) != NULL)
+ {
+ if (!attr->value || access(attr->value, 0))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing "
+ "APPrinterLowInkTool file \"%s\"\n"),
+ prefix, attr->value ? attr->value : "");
+
+ if (!warn)
+ errors ++;
+ }
+ else
+ errors = valid_path("APPrinterLowInkTool", attr->value, errors, verbose,
+ warn);
+ }
+
+ /*
+ * APPrinterUtilityPath
+ */
+
+ if ((attr = ppdFindAttr(ppd, "APPrinterUtilityPath", NULL)) != NULL)
+ {
+ if (!attr->value || access(attr->value, 0))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout, _(" %s Missing "
+ "APPrinterUtilityPath file \"%s\"\n"),
+ prefix, attr->value ? attr->value : "");
+
+ if (!warn)
+ errors ++;
}
+ else
+ errors = valid_path("APPrinterUtilityPath", attr->value, errors, verbose,
+ warn);
}
+#endif /* __APPLE__ */
return (errors);
}
@@ -2430,6 +2709,8 @@ check_profiles(ppd_file_t *ppd, /* I - PPD file */
if (!warn)
errors ++;
}
+ else
+ errors = valid_path("cupsICCProfile", filename, errors, verbose, warn);
/*
* Check for hash collisions...
@@ -2475,6 +2756,158 @@ check_profiles(ppd_file_t *ppd, /* I - PPD file */
}
+/*
+ * 'check_sizes()' - Check media sizes in the PPD file.
+ */
+
+static int /* O - Errors found */
+check_sizes(ppd_file_t *ppd, /* I - PPD file */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ int i; /* Looping vars */
+ ppd_size_t *size; /* Current size */
+ int width, /* Custom width */
+ length; /* Custom length */
+ char name[PPD_MAX_NAME], /* Size name without dot suffix */
+ *nameptr; /* Pointer into name */
+ const char *prefix; /* WARN/FAIL prefix */
+ ppd_option_t *page_size, /* PageSize option */
+ *page_region; /* PageRegion option */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ if ((page_size = ppdFindOption(ppd, "PageSize")) == NULL && warn != 2)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Missing REQUIRED PageSize option!\n"
+ " REF: Page 99, section 5.14.\n"),
+ prefix);
+
+ if (!warn)
+ errors ++;
+ }
+
+ if ((page_region = ppdFindOption(ppd, "PageRegion")) == NULL && warn != 2)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Missing REQUIRED PageRegion option!\n"
+ " REF: Page 100, section 5.14.\n"),
+ prefix);
+
+ if (!warn)
+ errors ++;
+ }
+
+ for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
+ {
+ /*
+ * Check that the size name is standard...
+ */
+
+ if (!strcmp(size->name, "Custom"))
+ {
+ /*
+ * Skip custom page size...
+ */
+
+ continue;
+ }
+ else if (warn != 2 && size->name[0] == 'w' &&
+ sscanf(size->name, "w%dh%d", &width, &length) == 2)
+ {
+ /*
+ * Validate device-specific size wNNNhNNN should have proper width and
+ * length...
+ */
+
+ if (fabs(width - size->width) >= 1.0 ||
+ fabs(length - size->length) >= 1.0)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Size \"%s\" has unexpected dimensions "
+ "(%gx%g)!\n"),
+ prefix, size->name, size->width, size->length);
+
+ if (!warn)
+ errors ++;
+ }
+ }
+ else if (warn && verbose >= 0)
+ {
+ /*
+ * Lookup the size name in the standard size table...
+ */
+
+ strlcpy(name, size->name, sizeof(name));
+ if ((nameptr = strchr(name, '.')) != NULL)
+ *nameptr = '\0';
+
+ if (!bsearch(name, adobe_size_names,
+ sizeof(adobe_size_names) /
+ sizeof(adobe_size_names[0]),
+ sizeof(adobe_size_names[0]),
+ (int (*)(const void *, const void *))strcmp))
+ {
+ _cupsLangPrintf(stdout,
+ _(" %s Non-standard size name \"%s\"!\n"
+ " REF: Page 187, section B.2.\n"),
+ prefix, size->name);
+ }
+ }
+
+ /*
+ * Verify that the size is defined for both PageSize and PageRegion...
+ */
+
+ if (warn != 2 && !ppdFindChoice(page_size, size->name))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Size \"%s\" defined for %s but not for "
+ "%s!\n"),
+ prefix, size->name, "PageRegion", "PageSize");
+
+ if (!warn)
+ errors ++;
+ }
+ else if (warn != 2 && !ppdFindChoice(page_region, size->name))
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s Size \"%s\" defined for %s but not for "
+ "%s!\n"),
+ prefix, size->name, "PageSize", "PageRegion");
+
+ if (!warn)
+ errors ++;
+ }
+ }
+
+ return (errors);
+}
+
+
/*
* 'check_translations()' - Check translations in the PPD file.
*/
@@ -2933,7 +3366,7 @@ usage(void)
"\n"
" -R root-directory Set alternate root\n"
" -W {all,none,constraints,defaults,duplex,filters,"
- "translations}\n"
+ "profiles,sizes,translations}\n"
" Issue warnings instead of errors\n"
" -q Run silently\n"
" -r Use 'relaxed' open mode\n"
@@ -2944,6 +3377,89 @@ usage(void)
}
+/*
+ * 'valid_path()' - Check whether a path has the correct capitalization.
+ */
+
+static int /* O - Errors found */
+valid_path(const char *keyword, /* I - Keyword using path */
+ const char *path, /* I - Path to check */
+ int errors, /* I - Errors found */
+ int verbose, /* I - Verbosity level */
+ int warn) /* I - Warnings only? */
+{
+ cups_dir_t *dir; /* Current directory */
+ cups_dentry_t *dentry; /* Current directory entry */
+ char temp[1024], /* Temporary path */
+ *ptr; /* Pointer into temporary path */
+ const char *prefix; /* WARN/FAIL prefix */
+
+
+ prefix = warn ? " WARN " : "**FAIL**";
+
+ /*
+ * Loop over the components of the path, checking that the entry exists with
+ * the same capitalization...
+ */
+
+ strlcpy(temp, path, sizeof(temp));
+
+ while ((ptr = strrchr(temp, '/')) != NULL)
+ {
+ /*
+ * Chop off the trailing component so temp == dirname and ptr == basename.
+ */
+
+ *ptr++ = '\0';
+
+ /*
+ * Try opening the directory containing the base name...
+ */
+
+ if (temp[0])
+ dir = cupsDirOpen(temp);
+ else
+ dir = cupsDirOpen("/");
+
+ if (!dir)
+ dentry = NULL;
+ else
+ {
+ while ((dentry = cupsDirRead(dir)) != NULL)
+ {
+ if (!strcmp(dentry->filename, ptr))
+ break;
+ }
+
+ cupsDirClose(dir);
+ }
+
+ /*
+ * Display an error if the filename doesn't exist with the same
+ * capitalization...
+ */
+
+ if (!dentry)
+ {
+ if (!warn && !errors && !verbose)
+ _cupsLangPuts(stdout, _(" FAIL\n"));
+
+ if (verbose >= 0)
+ _cupsLangPrintf(stdout,
+ _(" %s %s file \"%s\" has the wrong "
+ "capitalization!\n"), prefix, keyword, path);
+
+ if (!warn)
+ errors ++;
+
+ break;
+ }
+ }
+
+ return (errors);
+}
+
+
/*
* 'valid_utf8()' - Check whether a string contains valid UTF-8 text.
*/