From 1340db2dab0b5ac933dec4796637ca3baa10bb4b Mon Sep 17 00:00:00 2001
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 a89ca293f..2111f79f0 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 337c57e0d..9bd428d9f 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 4757c5d72..fd2b878b5 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 e9d8df1f0..8da2d9616 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 d3c30210a..17f6f89ea 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 3fc1f33b0..c0160e2e9 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 25ddffd9f..cd185c473 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 437f0f5ba..ccc395211 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 c826120f1..47142db2b 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 bd548ff06..45d3bcfb6 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 79765c4b9..f0b180813 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 855c17fbf..4a619ebca 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. */ -- 2.39.5