From b3d75f7d37a0a513fe0c28bc1076e8eb6c4574b3 Mon Sep 17 00:00:00 2001 From: kreiserlee Date: Tue, 11 Jun 2024 14:22:41 +0800 Subject: [PATCH] Apply patches on new stream/2.4.7 --- Makedefs.in | 2 +- backend/ipp.c | 4 +- cgi-bin/admin.c | 6 +- conf/Makefile | 5 +- conf/cups-files.conf.in | 4 + conf/mime.convs.in | 3 + conf/mime.types | 3 + configure.ac | 10 + cups-config.in | 7 +- cups/dest.c | 2 +- cups/ppd-cache.c | 1231 +++++++++++++++++++++++++++++++++--- cups/ppd-private.h | 19 +- cups/string-private.h | 2 + cups/string.c | 30 + cups/testhttp.c | 3 +- man/Makefile | 22 +- man/Makefile.l10n | 235 +++++++ man/de/Makefile | 7 + man/fr/Makefile | 7 + man/mantohtml.c | 12 +- man/pt/Makefile | 7 + scheduler/auth.c | 15 +- scheduler/auth.h | 2 - scheduler/client.c | 8 + scheduler/client.h | 2 + scheduler/conf.c | 2 + scheduler/cups-driverd.cxx | 10 - scheduler/cupsd.h | 9 + scheduler/ipp.c | 396 ++++++++---- scheduler/job.c | 83 ++- scheduler/policy.h | 2 - scheduler/printers.c | 10 +- scheduler/printers.h | 2 - test/run-stp-tests.sh | 3 +- 34 files changed, 1887 insertions(+), 278 deletions(-) create mode 100644 man/Makefile.l10n create mode 100644 man/de/Makefile create mode 100644 man/fr/Makefile create mode 100644 man/pt/Makefile diff --git a/Makedefs.in b/Makedefs.in index 07010f0..e44c2c0 100644 --- a/Makedefs.in +++ b/Makedefs.in @@ -23,6 +23,7 @@ CUPS_VERSION = @CUPS_VERSION@ AR = @AR@ AWK = @AWK@ CC = @LIBTOOL_CC@ @CC@ +CC_FOR_BUILD = @CC_FOR_BUILD@ CHMOD = @CHMOD@ CXX = @LIBTOOL_CXX@ @CXX@ DSO = @DSO@ @@ -263,7 +264,6 @@ USBQUIRKS = @USBQUIRKS@ # Rules... # -.SILENT: .SUFFIXES: .a .c .cxx .h .o .c.o: diff --git a/backend/ipp.c b/backend/ipp.c index be1f2c0..e65abe6 100644 --- a/backend/ipp.c +++ b/backend/ipp.c @@ -1889,7 +1889,7 @@ main(int argc, /* I - Number of command-line args */ if (ippContainsString(reasons, "document-format-error")) ipp_status = IPP_STATUS_ERROR_DOCUMENT_FORMAT_ERROR; - else if (ippContainsString(reasons, "document-unprintable")) + else if (ippContainsString(reasons, "document-unprintable-error")) ipp_status = IPP_STATUS_ERROR_DOCUMENT_UNPRINTABLE; ippDelete(response); @@ -2678,7 +2678,7 @@ monitor_printer( new_reasons |= _CUPS_JSR_JOB_RELEASE_WAIT; else if (!strcmp(attr->values[i].string.text, "document-format-error")) new_reasons |= _CUPS_JSR_DOCUMENT_FORMAT_ERROR; - else if (!strcmp(attr->values[i].string.text, "document-unprintable")) + else if (!strcmp(attr->values[i].string.text, "document-unprintable-error")) new_reasons |= _CUPS_JSR_DOCUMENT_UNPRINTABLE; if (!job_canceled && (!strncmp(attr->values[i].string.text, "job-canceled-", 13) || !strcmp(attr->values[i].string.text, "aborted-by-system"))) diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c index 863e885..f81fd71 100644 --- a/cgi-bin/admin.c +++ b/cgi-bin/admin.c @@ -1635,6 +1635,7 @@ do_config_server(http_t *http) /* I - HTTP connection */ int ch; /* Character from file */ char filename[1024]; /* Filename */ const char *server_root; /* Location of config files */ + const char *data_dir; /* Location of data files */ /* @@ -1718,7 +1719,10 @@ do_config_server(http_t *http) /* I - HTTP connection */ * well... */ - strlcat(filename, ".default", sizeof(filename)); + if ((data_dir = getenv("CUPS_DATADIR")) == NULL) + data_dir = CUPS_DATADIR; + + snprintf(filename, sizeof(filename), "%s/cupsd.conf.default",data_dir); if (!stat(filename, &info) && info.st_size < (1024 * 1024) && (cupsd = cupsFileOpen(filename, "r")) != NULL) diff --git a/conf/Makefile b/conf/Makefile index e249e60..42a123f 100644 --- a/conf/Makefile +++ b/conf/Makefile @@ -70,7 +70,7 @@ install-data: else \ $(INSTALL_CONFIG) -g $(CUPS_GROUP) $$file $(SERVERROOT) ; \ fi ; \ - $(INSTALL_CONFIG) -g $(CUPS_GROUP) $$file $(SERVERROOT)/$$file.default; \ + $(INSTALL_CONFIG) -g $(CUPS_GROUP) $$file $(DATADIR)/$$file.default; \ done $(INSTALL_DIR) -m 755 $(DATADIR)/mime for file in $(REPLACE); do \ @@ -118,9 +118,10 @@ install-libs: # uninstall: - for file in $(KEEP) $(REPLACE) cupsd.conf.default; do \ + for file in $(KEEP) $(REPLACE); do \ $(RM) $(SERVERROOT)/$$file; \ done + $(RM) $(DATADIR)/cupsd.conf.default -$(RMDIR) $(SERVERROOT) for file in $(REPLACE); do \ $(RM) $(DATADIR)/mime/$$file; \ diff --git a/conf/cups-files.conf.in b/conf/cups-files.conf.in index 93584a1..b505c40 100644 --- a/conf/cups-files.conf.in +++ b/conf/cups-files.conf.in @@ -29,6 +29,10 @@ SystemGroup @CUPS_SYSTEM_GROUPS@ #ConfigFilePerm 0@CUPS_CONFIG_FILE_PERM@ #LogFilePerm 0@CUPS_LOG_FILE_PERM@ +# Specifies the group name or ID that will be used for log files. +# The default group in Debian is "adm". +LogFileGroup adm + # Location of the file logging all access to the scheduler; may be the name # "syslog". If not an absolute path, the value of ServerRoot is used as the # root directory. Also see the "AccessLogLevel" directive in cupsd.conf. diff --git a/conf/mime.convs.in b/conf/mime.convs.in index 57b459d..e042e01 100644 --- a/conf/mime.convs.in +++ b/conf/mime.convs.in @@ -44,6 +44,9 @@ application/postscript application/vnd.cups-postscript 66 pstops application/vnd.cups-raster image/pwg-raster 100 rastertopwg application/vnd.cups-raster image/urf 100 rastertopwg +# Needed for printing from iOS (AirPrint) clients +image/urf application/pdf 100 - + ######################################################################## # # Raw filter... diff --git a/conf/mime.types b/conf/mime.types index fcd6b6e..ebb0525 100644 --- a/conf/mime.types +++ b/conf/mime.types @@ -108,6 +108,9 @@ image/x-alias pix short(8,8) short(8,24) image/x-bitmap bmp string(0,BM) + !printable(2,14) image/x-icon ico +# Needed for printing from iOS (AirPrint) clients +image/urf urf string(0,UNIRAST<00>) + ######################################################################## # # Text files... diff --git a/configure.ac b/configure.ac index cf8ba03..df8c4a9 100644 --- a/configure.ac +++ b/configure.ac @@ -25,6 +25,16 @@ sinclude(config-scripts/cups-opsys.m4) sinclude(config-scripts/cups-common.m4) sinclude(config-scripts/cups-directories.m4) sinclude(config-scripts/cups-manpages.m4) + +AC_MSG_CHECKING([for build system compiler]) +if test "$cross_compiling" = yes; then + CC_FOR_BUILD=${CC_FOR_BUILD-cc} +else + CC_FOR_BUILD=${CC} +fi +AC_MSG_RESULT(${CC_FOR_BUILD}) +AC_SUBST(CC_FOR_BUILD) + sinclude(config-scripts/cups-sharedlibs.m4) sinclude(config-scripts/cups-libtool.m4) sinclude(config-scripts/cups-compiler.m4) diff --git a/cups-config.in b/cups-config.in index 1f49bb9..89e6fbc 100755 --- a/cups-config.in +++ b/cups-config.in @@ -18,7 +18,7 @@ prefix=@prefix@ exec_prefix=@exec_prefix@ bindir=@bindir@ includedir=@includedir@ -libdir=@libdir@ +libdir=${prefix}/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH) datarootdir=@datadir@ datadir=@datadir@ sysconfdir=@sysconfdir@ @@ -30,7 +30,8 @@ INSTALLSTATIC=@INSTALLSTATIC@ # flags for compiler and linker... CFLAGS="" LDFLAGS="@EXPORT_LDFLAGS@" -LIBS="@LIBGSSAPI@ @DNSSDLIBS@ @EXPORT_TLSLIBS@ @LIBZ@ @LIBS@" +LIBGSSAPI=`[ ! -x /usr/bin/krb5-config ] || /usr/bin/krb5-config --libs` +LIBS="$LIBGSSAPI @DNSSDLIBS@ @EXPORT_SSLLIBS@ @LIBZ@ @LIBS@" # Check for local invocation... selfdir=`dirname $0` @@ -44,7 +45,7 @@ else CFLAGS="$CFLAGS -I$includedir" fi - if test $libdir != /usr/lib -a $libdir != /usr/lib32 -a $libdir != /usr/lib64; then + if test $libdir != /usr/lib -a $libdir != /usr/lib32 -a $libdir != /usr/lib64 -a $libdir != /usr/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH); then LDFLAGS="$LDFLAGS -L$libdir" fi fi diff --git a/cups/dest.c b/cups/dest.c index da775a3..b6b5082 100644 --- a/cups/dest.c +++ b/cups/dest.c @@ -58,7 +58,7 @@ #endif /* __APPLE__ */ #ifdef HAVE_DNSSD -# define _CUPS_DNSSD_GET_DESTS 250 /* Milliseconds for cupsGetDests */ +# define _CUPS_DNSSD_GET_DESTS 1000 /* Milliseconds for cupsGetDests */ # define _CUPS_DNSSD_MAXTIME 50 /* Milliseconds for maximum quantum of time */ #else # define _CUPS_DNSSD_GET_DESTS 0 /* Milliseconds for cupsGetDests */ diff --git a/cups/ppd-cache.c b/cups/ppd-cache.c index 40881cd..6e8d31d 100644 --- a/cups/ppd-cache.c +++ b/cups/ppd-cache.c @@ -504,6 +504,8 @@ _ppdCacheCreateWithFile( _pwg_print_color_mode_t print_color_mode; /* Print color mode for preset */ _pwg_print_quality_t print_quality; /* Print quality for preset */ + _pwg_print_content_optimize_t print_content_optimize; + /* Content optimize for preset */ DEBUG_printf(("_ppdCacheCreateWithFile(filename=\"%s\")", filename)); @@ -929,6 +931,28 @@ _ppdCacheCreateWithFile( cupsParseOptions(valueptr, 0, pc->presets[print_color_mode] + print_quality); } + else if (!_cups_strcasecmp(line, "OptimizePreset")) + { + /* + * Preset print_content_optimize name=value ... + */ + + print_content_optimize = (_pwg_print_content_optimize_t)strtol(value, &valueptr, 10); + + if (print_content_optimize < _PWG_PRINT_CONTENT_OPTIMIZE_AUTO || + print_content_optimize >= _PWG_PRINT_CONTENT_OPTIMIZE_MAX || + valueptr == value || !*valueptr) + { + DEBUG_printf(("ppdCacheCreateWithFile: Bad Optimize Preset on line %d.", + linenum)); + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1); + goto create_error; + } + + pc->num_optimize_presets[print_content_optimize] = + cupsParseOptions(valueptr, 0, + pc->optimize_presets + print_content_optimize); + } else if (!_cups_strcasecmp(line, "SidesOption")) pc->sides_option = strdup(value); else if (!_cups_strcasecmp(line, "Sides1Sided")) @@ -1056,6 +1080,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ *ppd_option; /* Other PPD option */ ppd_choice_t *choice; /* Current InputSlot/MediaType */ pwg_map_t *map; /* Current source/type map */ + int preset_added = 0; /* Preset definition found in PPD? */ ppd_attr_t *ppd_attr; /* Current PPD preset attribute */ int num_options; /* Number of preset options and props */ cups_option_t *options; /* Preset options and properties */ @@ -1511,6 +1536,10 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL) { + /* + * "Classic" Mac OS approach + */ + /* * Copy and convert APPrinterPreset (output-mode + print-quality) data... */ @@ -1611,114 +1640,133 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ _ppdParseOptions(ppd_attr->value, 0, pc->presets[pwg_print_color_mode] + pwg_print_quality, _PPD_PARSE_OPTIONS); + preset_added = 1; } cupsFreeOptions(num_options, options); } while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset", NULL)) != NULL); - } - if (!pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_DRAFT] && - !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_NORMAL] && - !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_HIGH]) - { - /* - * Try adding some common color options to create grayscale presets. These - * are listed in order of popularity... - */ - - const char *color_option = NULL, /* Color control option */ - *gray_choice = NULL; /* Choice to select grayscale */ - - if ((color_model = ppdFindOption(ppd, "ColorModel")) != NULL && - ppdFindChoice(color_model, "Gray")) - { - color_option = "ColorModel"; - gray_choice = "Gray"; - } - else if ((color_model = ppdFindOption(ppd, "HPColorMode")) != NULL && - ppdFindChoice(color_model, "grayscale")) - { - color_option = "HPColorMode"; - gray_choice = "grayscale"; - } - else if ((color_model = ppdFindOption(ppd, "BRMonoColor")) != NULL && - ppdFindChoice(color_model, "Mono")) - { - color_option = "BRMonoColor"; - gray_choice = "Mono"; - } - else if ((color_model = ppdFindOption(ppd, "CNIJSGrayScale")) != NULL && - ppdFindChoice(color_model, "1")) - { - color_option = "CNIJSGrayScale"; - gray_choice = "1"; - } - else if ((color_model = ppdFindOption(ppd, "HPColorAsGray")) != NULL && - ppdFindChoice(color_model, "True")) - { - color_option = "HPColorAsGray"; - gray_choice = "True"; - } - - if (color_option && gray_choice) + if (preset_added && + !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_DRAFT] && + !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_NORMAL] && + !pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][_PWG_PRINT_QUALITY_HIGH]) { /* - * Copy and convert ColorModel (output-mode) data... + * Try adding some common color options to create grayscale presets. These + * are listed in order of popularity... */ - cups_option_t *coption, /* Color option */ - *moption; /* Monochrome option */ + const char *color_option = NULL, /* Color control option */ + *gray_choice = NULL; /* Choice to select grayscale */ - for (pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT; - pwg_print_quality < _PWG_PRINT_QUALITY_MAX; - pwg_print_quality ++) + if ((color_model = ppdFindOption(ppd, "ColorModel")) != NULL && + ppdFindChoice(color_model, "Gray")) { - if (pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][pwg_print_quality]) - { - /* - * Copy the color options... - */ - - num_options = pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR] - [pwg_print_quality]; - options = calloc((size_t)num_options, sizeof(cups_option_t)); - - if (options) - { - for (i = num_options, moption = options, - coption = pc->presets[_PWG_PRINT_COLOR_MODE_COLOR] - [pwg_print_quality]; - i > 0; - i --, moption ++, coption ++) - { - moption->name = _cupsStrRetain(coption->name); - moption->value = _cupsStrRetain(coption->value); - } - - pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] = - num_options; - pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] = - options; - } - } - else if (pwg_print_quality != _PWG_PRINT_QUALITY_NORMAL) - continue; + color_option = "ColorModel"; + gray_choice = "Gray"; + } + else if ((color_model = ppdFindOption(ppd, "HPColorMode")) != NULL && + ppdFindChoice(color_model, "grayscale")) + { + color_option = "HPColorMode"; + gray_choice = "grayscale"; + } + else if ((color_model = ppdFindOption(ppd, "BRMonoColor")) != NULL && + ppdFindChoice(color_model, "Mono")) + { + color_option = "BRMonoColor"; + gray_choice = "Mono"; + } + else if ((color_model = ppdFindOption(ppd, "CNIJSGrayScale")) != NULL && + ppdFindChoice(color_model, "1")) + { + color_option = "CNIJSGrayScale"; + gray_choice = "1"; + } + else if ((color_model = ppdFindOption(ppd, "HPColorAsGray")) != NULL && + ppdFindChoice(color_model, "True")) + { + color_option = "HPColorAsGray"; + gray_choice = "True"; + } + if (color_option && gray_choice) + { /* - * Add the grayscale option to the preset... + * Copy and convert ColorModel (output-mode) data... */ - pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] = - cupsAddOption(color_option, gray_choice, - pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] - [pwg_print_quality], - pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] + + cups_option_t *coption, /* Color option */ + *moption; /* Monochrome option */ + + for (pwg_print_quality = _PWG_PRINT_QUALITY_DRAFT; + pwg_print_quality < _PWG_PRINT_QUALITY_MAX; + pwg_print_quality ++) + { + if (pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][pwg_print_quality]) + { + /* + * Copy the color options... + */ + + num_options = pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR] + [pwg_print_quality]; + options = calloc(sizeof(cups_option_t), (size_t)num_options); + + if (options) + { + for (i = num_options, moption = options, + coption = pc->presets[_PWG_PRINT_COLOR_MODE_COLOR] + [pwg_print_quality]; + i > 0; + i --, moption ++, coption ++) + { + moption->name = _cupsStrRetain(coption->name); + moption->value = _cupsStrRetain(coption->value); + } + + pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] = + num_options; + pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] = + options; + } + } + else if (pwg_print_quality != _PWG_PRINT_QUALITY_NORMAL) + continue; + + /* + * Add the grayscale option to the preset... + */ + + pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME][pwg_print_quality] = + cupsAddOption(color_option, gray_choice, + pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] + [pwg_print_quality], + pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] + pwg_print_quality); + } } } } + if (!preset_added) + { + /* + * Auto-association of PPD file option settings with the IPP job attributes + * print-color-mode, print-quality, and print-content-optimize + * + * This is used to retro-fit PPD files and classic CUPS drivers into + * Printer Applications, which are IPP printers for the clients and so + * should get controlled by standard IPP attributes as far as possible + * + * Note that settings assigned to print-content-optimize are only used + * when printing with "high" print-quality + */ + + _ppdCacheAssignPresets(ppd, pc); + } + /* * Copy and convert Duplex (sides) data... */ @@ -2051,6 +2099,989 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ } +/* + * '_ppdCacheAssignPresets()' - Go through all the options and choices in + * the PPD to find out which influence + * color/bw, print quality, and content + * optimizations to assign them to the prsets + * so that jobs can easily be controlled with + * standard IPP attributes + */ + +void +_ppdCacheAssignPresets(ppd_file_t *ppd, + _ppd_cache_t *pc) +{ + /* properties and scores for each choice of the option under evaluation */ + typedef struct choice_properties_s + { + int sets_mono, /* Does this choice switch to monochrome printing? */ + sets_color, /* ... to color printing? */ + sets_draft, /* ... to draft/lower quality? */ + sets_normal, /* ... to standard/normal quality? */ + sets_high, /* ... to high/better quality? */ + for_photo, /* Does this choice improve photo printing? */ + for_graphics, /* ... graphics printing? */ + for_text, /* ... text printing? */ + for_tg, /* ... text & graphics printing? */ + is_default; /* Is this choice the PPD default? */ + unsigned int res_x,/* Does this choice set resolution (0 if not)? */ + res_y; + } choice_properties_t; + int i, j, k, l; + unsigned int m; /* Ratio for lowering or improving + resolution */ + int pass; /* Passes to go through to find best + choice */ + ppd_group_t *group; /* PPD option group */ + ppd_option_t *option; /* PPD option */ + int is_color; /* Is this PPD for a color printer */ + unsigned int base_res_x = 0, /* Base resolution of the pPD file */ + base_res_y = 0; + cups_page_header2_t header, /* CUPS Raster header to investigate + embedded code in PPD */ + optheader; /* CUPS Raster header to investigate + embedded code in one PPD option */ + int preferred_bits; /* for _cupsRasterExecPS() function + call */ + ppd_attr_t *ppd_attr; /* PPD attribute */ + int res_factor = 1; /* Weights of the scores for the */ + int name_factor = 10; /* print quality */ + int color_factor = 1000; + + /* Do we have a color printer ? */ + is_color = (ppd->color_device ? 1 : 0); + + /* what is the base/default resolution for this PPD? */ + ppdMarkDefaults(ppd); + cupsRasterInterpretPPD(&header, ppd, 0, NULL, NULL); + if (header.HWResolution[0] != 100 || header.HWResolution[1] != 100) + { + base_res_x = header.HWResolution[0]; + base_res_y = header.HWResolution[1]; + } + else if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL) + { + /* Use the PPD-defined default resolution... */ + if (sscanf(ppd_attr->value, "%dx%d", &base_res_x, &base_res_y) == 1) + base_res_y = base_res_x; + } + + /* Go through all options of the PPD file */ + for (i = ppd->num_groups, group = ppd->groups; + i > 0; + i --, group ++) + { + /* Skip the "Installable Options" group */ + if (_cups_strncasecmp(group->name, "Installable", 11) == 0) + continue; + + for (j = group->num_options, option = group->options; + j > 0; + j --, option ++) + { + int sets_color_mode = 0, /* Scores for current choice */ + sets_quality = 0, + sets_optimization = 0; + int best_mono_draft = 0, /* Best score for each preset for this + option */ + best_mono_normal = 0, + best_mono_high = 0, + best_color_draft = 0, + best_color_normal = 0, + best_color_high = 0, + best_photo = 0, + best_graphics = 0, + best_text = 0, + best_tg = 0; + int default_ch = -1, /* Index of default choice */ + best_mono_draft_ch = -1, /* Index of choice with best score */ + best_mono_normal_ch = -1, + best_mono_high_ch = -1, + best_color_draft_ch = -1, + best_color_normal_ch = -1, + best_color_high_ch = -1, + best_photo_ch = -1, + best_graphics_ch = -1, + best_text_ch = -1, + best_tg_ch = -1; + cups_array_t *choice_properties; /* Array of properties of all choices + of this option */ + choice_properties_t *properties; /* Properties of current choice */ + char *o, /* Name of current option */ + *c, /* Name of current choice */ + *p; /* Pointer into string */ + int score; /* Temp variable for score + calculations */ + + o = option->keyword; + + /* Skip options which do not change color mode and quality or + generally do not make sense in presets */ + if (_cups_strcasecmp(o, "PageSize") == 0 || + _cups_strcasecmp(o, "PageRegion") == 0 || + _cups_strcasecmp(o, "InputSlot") == 0 || + _cups_strcasecmp(o, "MediaSource") == 0 || + _cups_strcasecmp(o, "MediaType") == 0 || + _cups_strcasecmp(o, "OutputBin") == 0 || + _cups_strcasecmp(o, "Duplex") == 0 || + _cups_strcasecmp(o, "JCLDuplex") == 0 || + _cups_strcasecmp(o, "EFDuplex") == 0 || + _cups_strcasecmp(o, "EFDuplexing") == 0 || + _cups_strcasecmp(o, "ARDuplex") == 0 || + _cups_strcasecmp(o, "KD03Duplex") == 0 || + _cups_strcasecmp(o, "Collate") == 0) + continue; + + /* Set members options of composite options in Foomatic to stay + controlled by the composite option */ + + /* Composite options in Foomatic are options which set a number + of other options, so each choice of them is the same as a + preset in CUPS. In addition, some PPDs in Foomatic have a + composite option named "PrintoutMode" with 6 choices, exactly + the 6 of the grid of CUPS presets, color/mono in draft, + mediaum, and high quality. The composite options are created + by hand, so they surely do for what they are intended for and + so they are safer as this preset auto-generation + algorithm. Therefore we only let the composite option be set + in our presets and set the member options to leave the + control at the composite option */ + + if (strstr(ppd->nickname, "Foomatic") && + !strncmp(option->choices[0].choice, "From", 4) && + ppdFindOption(ppd, option->choices[0].choice + 4)) + { + for (k = 0; k < 2; k ++) + for (l = 0; l < 3; l ++) + if (cupsGetOption(option->choices[0].choice + 4, + pc->num_presets[k][l], pc->presets[k][l])) + pc->num_presets[k][l] = + cupsAddOption(o, option->choices[0].choice, + pc->num_presets[k][l], &(pc->presets[k][l])); + for (k = 0; k < 5; k ++) + if (cupsGetOption(option->choices[0].choice + 4, + pc->num_optimize_presets[k], + pc->optimize_presets[k])) + pc->num_optimize_presets[k] = + cupsAddOption(o, option->choices[0].choice, + pc->num_optimize_presets[k], + &(pc->optimize_presets[k])); + continue; + } + + /* Array for properties of the choices */ + choice_properties = cupsArrayNew(NULL, NULL); + + /* + * Gather the data for each choice + */ + + for (k = 0; k < option->num_choices; k ++) + { + properties = + (choice_properties_t *)calloc(1, sizeof(choice_properties_t)); + + c = option->choices[k].choice; + + /* Is this the default choice? (preferred for "normal" quality, + used for color if no choice name suggests being color */ + if (strcmp(c, option->defchoice) == 0) + { + properties->is_default = 1; + default_ch = k; + } + + /* + * Color/Gray - print-color-mode + */ + + /* If we have a color device, check whether this option sets mono or + color printing */ + if (is_color) + { + if (_cups_strcasecmp(o, "CNIJSGrayScale") == 0) + { + if (_cups_strcasecmp(c, "1") == 0) + properties->sets_mono = 2; + else + properties->sets_color = 1; + } + else if (_cups_strcasecmp(o, "HPColorAsGray") == 0 || /* HP PostScript */ + _cups_strcasecmp(o, "HPPJLColorAsGray") == 0) /* HP PostScript */ + { + if (_cups_strcasecmp(c, "True") == 0 || + _cups_strcasecmp(c, "yes") == 0) + properties->sets_mono = 2; + else + properties->sets_color = 1; + } + else if (_cups_strcasecmp(o, "ColorModel") == 0 || + _cups_strcasecmp(o, "ColorMode") == 0 || + _cups_strcasecmp(o, "OutputMode") == 0 || + _cups_strcasecmp(o, "PrintoutMode") == 0 || + _cups_strcasecmp(o, "ARCMode") == 0 || /* Sharp */ + _cups_strcasestr(o, "ColorMode") || + _cups_strcasecmp(o, "ColorResType") == 0 || /* Toshiba */ + _cups_strcasestr(o, "MonoColor")) /* Brother */ + { + /* Monochrome/grayscale printing */ + if (_cups_strcasestr(c, "Mono") || + _cups_strcasecmp(c, "Black") == 0 || + ((p = _cups_strcasestr(c, "Black")) && _cups_strcasestr(p, "White")) || + (_cups_strncasecmp(c, "BW", 2) == 0 && !isalpha(c[2]))) + properties->sets_mono = 2; + else if (_cups_strcasestr(c, "Gray") || + _cups_strcasestr(c, "Grey") || + _cups_strcasecmp(c, "BlackOnly") == 0) /* Lexmark */ + properties->sets_mono = 3; + + /* Color printing */ + if (((p = _cups_strcasestr(c, "CMY")) && !_cups_strcasestr(p, "Gray")) || + _cups_strcasecmp(c, "ColorOnly") == 0 || /* Lexmark */ + ((p = _cups_strcasestr(c, "Adobe")) && _cups_strcasestr(p, "RGB"))) + properties->sets_color = 2; + else if (_cups_strcasestr(c, "sRGB")) + properties->sets_color = 4; + else if (_cups_strcasestr(c, "RGB") || + _cups_strcasestr(c, "Color")) + properties->sets_color = 3; + } + + /* This option actually sets color mode */ + if (properties->sets_mono || properties->sets_color) + sets_color_mode = 1; + } + + /* + * Output Quality - print-quality + */ + + /* check whether this option affects print quality or content + optimization */ + + /* Determine influence of the options and choices on the print + quality by their names */ + + /* Vendor-specific option and choice names */ + if (_cups_strcasecmp(o, "ARCPPriority") == 0) /* Sharp */ + { + if (_cups_strcasecmp(c, "Quality") == 0) + properties->sets_high = 10; + else if (_cups_strcasecmp(c, "Speed") == 0) + properties->sets_draft = 10; + } + else if (_cups_strcasecmp(o, "BRJpeg") == 0) /* Brother */ + { + if (_cups_strcasecmp(c, "QualityPrior") == 0) + properties->sets_high = 10; + else if (_cups_strcasecmp(c, "SpeedPrior") == 0) + properties->sets_draft = 10; + } + else if (_cups_strcasecmp(o, "RIPrintMode") == 0) /* Ricoh & OEM */ + { + if (_cups_strcasecmp(c, "1rhit") == 0) + properties->sets_high = 7; + else if (_cups_strcasecmp(c, "6rhit") == 0) + properties->sets_high = 10; + else if (_cups_strcasecmp(c, "3rhit") == 0 || + _cups_strcasecmp(c, "4rhit") == 0 || + _cups_strcasecmp(c, "5rhit") == 0) + properties->sets_draft = 10; + else if (_cups_strcasecmp(c, "0rhit") == 0) + properties->sets_normal = 10; + } + else if (_cups_strcasecmp(o, "EconoMode") == 0 || /* Foomatic */ + _cups_strcasecmp(o, "EconoFast") == 0) /* Foomatic (HP PPA) */ + { + if (_cups_strcasecmp(c, "Off") == 0 || + _cups_strcasecmp(c, "False") == 0) + properties->sets_high = 1; + else if (_cups_strcasecmp(c, "On") == 0 || + _cups_strcasecmp(c, "True") == 0 || + _cups_strcasecmp(c, "Low") == 0) + properties->sets_draft = 10; + else if (_cups_strcasecmp(c, "High") == 0) + properties->sets_draft = 11; + } + else if (_cups_strcasestr(o, "ColorPrecision")) /* Gutenprint */ + { + if (_cups_strcasecmp(c, "best") == 0) + properties->sets_high = 10; + } + /* Generic boolean options which enhance quality if true */ + else if (((p = _cups_strcasestr(o, "slow")) && _cups_strcasestr(p, "dry")) || + ((p = _cups_strcasestr(o, "color")) && _cups_strcasestr(p, "enhance")) || + ((p = _cups_strcasestr(o, "resolution")) && + !_cups_strcasestr(p, "enhance")) || + _cups_strcasecmp(o, "RET") == 0 || + _cups_strcasecmp(o, "Smoothing") == 0 || /* HPLIP */ + ((p = _cups_strcasestr(o, "uni")) && _cups_strcasestr(p, "direction"))) + { + if (_cups_strcasecmp(c, "True") == 0 || + _cups_strcasecmp(c, "On") == 0 || + _cups_strcasecmp(c, "Yes") == 0 || + _cups_strcasecmp(c, "1") == 0 || + _cups_strcasecmp(c, "Medium") == 0) /* Resolution Enhancement/RET (HP)*/ + properties->sets_high = 3; + else if (_cups_strcasecmp(c, "False") == 0 || + _cups_strcasecmp(c, "Off") == 0 || + _cups_strcasecmp(c, "No") == 0 || + _cups_strcasecmp(c, "0") == 0) + properties->sets_draft = 3; + } + /* Generic boolean options which reduce quality if true */ + else if (_cups_strcasestr(o, "draft") || + _cups_strcasestr(o, "economy") || + ((p = _cups_strcasestr(o, "eco")) && _cups_strcasestr(p, "mode")) || + ((p = _cups_strcasestr(o, "toner")) && _cups_strcasestr(p, "sav")) || + ((p = _cups_strcasestr(o, "bi")) && _cups_strcasestr(p, "direction")) || + _cups_strcasecmp(o, "EcoBlack") == 0 || /* Foomatic (Alps) */ + _cups_strcasecmp(o, "bidi") == 0 || + _cups_strcasecmp(o, "bi-di") == 0) + { + if (_cups_strcasecmp(c, "True") == 0 || + _cups_strcasecmp(c, "On") == 0 || + _cups_strcasecmp(c, "Yes") == 0 || + _cups_strcasecmp(c, "1") == 0 || + _cups_strcasecmp(c, "Medium") == 0) /* EconomyMode (Brother) */ + properties->sets_draft = 3; + else if (_cups_strcasecmp(c, "False") == 0 || + _cups_strcasecmp(c, "Off") == 0 || + _cups_strcasecmp(c, "No") == 0 || + _cups_strcasecmp(c, "0") == 0) + properties->sets_high = 3; + } + /* Generic enumerated choice option and choice names */ + else if (_cups_strcasecmp(o, "ColorModel") == 0 || + _cups_strcasecmp(o, "ColorMode") == 0 || + _cups_strcasecmp(o, "OutputMode") == 0 || /* HPLIP hpcups */ + _cups_strcasecmp(o, "PrintoutMode") == 0 || /* Foomatic */ + _cups_strcasecmp(o, "PrintQuality") == 0 || + _cups_strcasecmp(o, "PrintMode") == 0 || + _cups_strcasestr(o, "ColorMode") || + _cups_strcasestr(o, "HalfTone") || /* HPLIP */ + _cups_strcasecmp(o, "ColorResType") == 0 || /* Toshiba */ + _cups_strcasestr(o, "MonoColor") || /* Brother */ + _cups_strcasestr(o, "Quality") || + _cups_strcasestr(o, "Resolution") || + _cups_strcasestr(o, "Precision") || /* ex. stpColorPrecision + in Gutenprint */ + _cups_strcasestr(o, "PrintingDirection")) /* Gutenprint */ + { + /* High quality */ + if (_cups_strcasecmp(c, "Quality") == 0 || + _cups_strcasecmp(c, "5") == 0) + properties->sets_high = 1; + else if (_cups_strcasestr(c, "Photo") || + _cups_strcasestr(c, "Enhance") || + _cups_strcasestr(c, "slow") || + _cups_strncasecmp(c, "ProRes", 6) == 0 || /* HPLIP */ + _cups_strncasecmp(c, "ImageREt", 8) == 0 || /* HPLIP */ + ((p = _cups_strcasestr(c, "low")) && _cups_strcasestr(p, "speed"))) + properties->sets_high = 2; + else if (_cups_strcasestr(c, "fine") || + _cups_strcasestr(c, "deep") || + ((p = _cups_strcasestr(c, "high")) && !_cups_strcasestr(p, "speed")) || + _cups_strcasestr(c, "HQ") || + _cups_strcasecmp(c, "ProRes600") == 0 || /* HPLIP */ + _cups_strcasecmp(c, "ImageREt1200") == 0 || /* HPLIP */ + _cups_strcasecmp(c, "Enhanced") == 0) + properties->sets_high = 3; + else if (_cups_strcasestr(c, "best") || + _cups_strcasecmp(c, "high") == 0 || + _cups_strcasecmp(c, "fine") == 0 || + _cups_strcasecmp(c, "HQ") == 0 || + _cups_strcasecmp(c, "CMYGray") == 0 || /* HPLIP */ + _cups_strcasecmp(c, "ProRes1200") == 0 || /* HPLIP */ + _cups_strcasecmp(c, "ImageREt2400") == 0 || /* HPLIP */ + _cups_strcasestr(c, "unidir")) + properties->sets_high = 4; + else if (_cups_strcasecmp(c, "best") == 0 || + _cups_strcasecmp(c, "ProRes2400") == 0 || /* HPLIP */ + _cups_strcasecmp(c, "monolowdetail") == 0) /* Toshiba */ + properties->sets_high = 5; + + /* Low/Draft quality */ + if (_cups_strcasecmp(c, "monolowdetail") == 0 || /* Toshiba */ + _cups_strcasecmp(c, "3") == 0) + properties->sets_draft = 1; + else if (((p = _cups_strcasestr(c, "fast")) && _cups_strcasestr(p, "draft")) || + ((p = _cups_strcasestr(c, "high")) && _cups_strcasestr(p, "speed")) || + (_cups_strcasestr(c, "speed") && !_cups_strcasestr(c, "low"))) + properties->sets_draft = 2; + else if (_cups_strcasestr(c, "quick") || + (_cups_strcasestr(c, "fast") && + !(_cups_strncasecmp(c, "FastRes", 7) == 0 && isdigit(*(c + 7))))) + /* HPLIP has FastRes600, FastRes1200, ... which are not draft */ + properties->sets_draft = 3; + else if (_cups_strcasecmp(c, "quick") == 0 || + _cups_strcasecmp(c, "fast") == 0 || + _cups_strcasestr(c, "draft") || + (_cups_strcasestr(c, "low") && !_cups_strcasestr(c, "slow")) || + _cups_strcasestr(c, "coarse")) + properties->sets_draft = 4; + else if (_cups_strcasecmp(c, "draft") == 0 || + _cups_strcasecmp(c, "low") == 0 || + _cups_strcasecmp(c, "coarse") == 0 || + _cups_strcasestr(c, "bidir")) + properties->sets_draft = 5; + + /* Use high or low quality but not the extremes */ + if (_cups_strcasestr(c, "ultra") || + _cups_strcasestr(c, "very") || + _cups_strcasestr(c, "super")) + { + if (properties->sets_high > 1) + properties->sets_high --; + if (properties->sets_draft > 1) + properties->sets_draft --; + } + + /* Normal quality */ + if (_cups_strcasestr(c, "automatic") || + _cups_strcasecmp(c, "none") == 0 || + _cups_strcasecmp(c, "4") == 0 || + _cups_strcasecmp(c, "FastRes1200") == 0) /* HPLIP */ + properties->sets_normal = 1; + else if (_cups_strcasestr(c, "normal") || + _cups_strcasestr(c, "standard") || + _cups_strcasestr(c, "default") || + _cups_strcasecmp(c, "FastRes600") == 0) /* HPLIP */ + properties->sets_normal = 2; + else if (_cups_strcasecmp(c, "normal") == 0 || + _cups_strcasecmp(c, "standard") == 0 || + _cups_strcasecmp(c, "default") == 0) + properties->sets_normal = 4; + } + + /* Apply the weight factor for option/choice-name-related scores */ + properties->sets_high *= name_factor; + properties->sets_draft *= name_factor; + properties->sets_normal *= name_factor; + + /* Determine influence of the options and choices on the print + quality by how they change the output resolution compared to + the base/default resolution */ + if (base_res_x && base_res_y) + { + /* First, analyse the code snippet (PostScript, PJL) assigned + to each choice of the option whether it sets resolution */ + if (option->choices[k].code && option->choices[k].code[0]) + { + /* Assume code to be PostScript (also used for CUPS Raster) */ + preferred_bits = 0; + optheader = header; + if (_cupsRasterExecPS(&optheader, &preferred_bits, + option->choices[k].code) == 0) + { + properties->res_x = optheader.HWResolution[0]; + properties->res_y = optheader.HWResolution[1]; + } + else + properties->res_x = properties->res_y = 0; /* invalid */ + if (properties->res_x == 0 || properties->res_y == 0) + { + /* Now try PJL */ + if ((p = strstr(option->choices[k].code, "SET")) && + isspace(*(p + 3)) && (p = strstr(p + 4, "RESOLUTION="))) + { + p += 11; + if (sscanf(p, "%dX%d", + &(properties->res_x), &(properties->res_y)) == 1) + properties->res_y = properties->res_x; + } + } + if (properties->res_x == 100 && properties->res_y == 100) + properties->res_x = properties->res_y = 0; /* Code does not + set resolution */ + } + else + properties->res_x = properties->res_y = 0; /* invalid */ + + /* Then parse the choice name whether it contains a + resolution value (Must have "dpi", as otherwise can be + something else, like a page size */ + if ((properties->res_x == 0 || properties->res_y == 0) && + (p = _cups_strcasestr(c, "dpi")) != NULL) + { + if (p > c) + { + p --; + while (p > c && isspace(*p)) + p --; + if (p > c && isdigit(*p)) + { + char x; + while (p > c && isdigit(*p)) + p --; + if (p > c && (*p == 'x' || *p == 'X')) + p --; + while (p > c && isdigit(*p)) + p --; + while (!isdigit(*p)) + p ++; + if (sscanf(p, "%d%c%d", + &(properties->res_x), &x, &(properties->res_y)) == 2) + properties->res_y = properties->res_x; + } + } + } + + if (properties->res_x != 0 && properties->res_y != 0) + { + /* Choice suggests to set the resolution */ + /* Raising resolution compared to default? */ + m = (properties->res_x * properties->res_y) / + (base_res_x * base_res_y); + /* No or small change -> Normal quality */ + if (m == 1) + properties->sets_normal += res_factor * 4; + /* At least double the pixels -> High quality */ + else if (m == 2) + properties->sets_high += res_factor * 3; + else if (m > 2 && m <= 8) + properties->sets_high += res_factor * 4; + else if (m > 8 && m <= 32) + properties->sets_high += res_factor * 2; + else if (m > 32) + properties->sets_high += res_factor * 1; + else if (m < 1) + { + /* Reducing resolution compared to default? */ + m = (base_res_x * base_res_y) / + (properties->res_x * properties->res_y); + /* No or small change -> Normal quality */ + if (m == 1) + properties->sets_normal += res_factor * 1; + /* At most half the pixels -> Draft quality */ + else if (m == 2) + properties->sets_draft += res_factor * 3; + else if (m > 2 && m < 8) + properties->sets_draft += res_factor * 4; + else if (m >= 8 && m < 32) + properties->sets_draft += res_factor * 2; + else if (m >= 32) + properties->sets_draft += res_factor * 1; + } + } + } + + /* This option actually sets print quality */ + if (properties->sets_draft || properties->sets_high) + sets_quality = 1; + + /* Add the properties of this choice */ + cupsArrayAdd(choice_properties, properties); + } + + /* + * Find the best choice for each field of the color/quality preset + * grid + */ + + for (pass = 0; pass < 3; pass ++) + { + for (k = 0; k < option->num_choices; k ++) + { + properties = cupsArrayIndex(choice_properties, k); + + /* presets[0][0]: Mono/Draft */ + if (best_mono_draft >= 0 && + !properties->sets_color && + (!properties->sets_high || pass > 0)) + { + score = color_factor * properties->sets_mono + + properties->sets_draft; + if (score > best_mono_draft) + { + best_mono_draft = score; + best_mono_draft_ch = k; + } + } + + /* presets[0][1]: Mono/Normal */ + if (best_mono_normal >= 0 && + !properties->sets_color && + (!properties->sets_draft || pass > 1) && + (!properties->sets_high || pass > 0)) + { + score = color_factor * properties->sets_mono + + properties->sets_normal; + if (score > best_mono_normal) + { + best_mono_normal = score; + best_mono_normal_ch = k; + } + } + + /* presets[0][2]: Mono/High */ + if (best_mono_high >= 0 && + !properties->sets_color && + (!properties->sets_draft || pass > 0)) + { + score = color_factor * properties->sets_mono + + properties->sets_high; + if (score > best_mono_high) + { + best_mono_high = score; + best_mono_high_ch = k; + } + } + + /* presets[1][0]: Color/Draft */ + if (best_color_draft >= 0 && + !properties->sets_mono && + (!properties->sets_high || pass > 0)) + { + score = color_factor * properties->sets_color + + properties->sets_draft; + if (score > best_color_draft) + { + best_color_draft = score; + best_color_draft_ch = k; + } + } + + /* presets[1][1]: Color/Normal */ + if (best_color_normal >= 0 && + !properties->sets_mono && + (!properties->sets_draft || pass > 1) && + (!properties->sets_high || pass > 0)) + { + score = color_factor * properties->sets_color + + properties->sets_normal; + if (score > best_color_normal) + { + best_color_normal = score; + best_color_normal_ch = k; + } + } + + /* presets[1][2]: Color/High */ + if (best_color_high >= 0 && + !properties->sets_mono && + (!properties->sets_draft || pass > 0)) + { + score = color_factor * properties->sets_color + + properties->sets_high; + if (score > best_color_high) + { + best_color_high = score; + best_color_high_ch = k; + } + } + } + /* Block next passes for the presets where we are done */ + if (best_mono_draft_ch >= 0) + best_mono_draft = -1; + if (best_mono_normal_ch >= 0) + best_mono_normal = -1; + if (best_mono_high_ch >= 0) + best_mono_high = -1; + if (best_color_draft_ch >= 0) + best_color_draft = -1; + if (best_color_normal_ch >= 0) + best_color_normal = -1; + if (best_color_high_ch >= 0) + best_color_high = -1; + } + + /* + * Content Optimization - print-content-optimize + */ + + for (k = 0; k < option->num_choices; k ++) + { + properties = cupsArrayIndex(choice_properties, k); + c = option->choices[k].choice; + + /* Vendor-specific options */ + if (_cups_strcasecmp(o, "ARCOType") == 0) /* Sharp */ + { + if (_cups_strcasecmp(c, "COTDrawing") == 0) + { + properties->for_text = 3; + properties->for_graphics = 2; + properties->for_tg = 2; + } + else if (_cups_strcasecmp(c, "COTGraphics") == 0) + { + properties->for_graphics = 3; + properties->for_tg = 3; + } + else if (_cups_strcasecmp(c, "COTPhoto") == 0) + properties->for_photo = 3; + } + else if (_cups_strcasecmp(o, "HPRGBEmulation") == 0) /* HP */ + { + if (_cups_strcasecmp(c, "DefaultSRGB") == 0) + properties->for_text = 3; + else if (_cups_strcasecmp(c, "VividSRGB") == 0) + { + properties->for_graphics = 3; + properties->for_tg = 3; + } + else if (_cups_strcasecmp(c, "PhotoSRGB") == 0) + properties->for_photo = 3; + } + else + /* Generic choice names */ + { + if (_cups_strcasestr(c, "photo")) + properties->for_photo = 6; + else if (_cups_strcasecmp(c, "photo") == 0) + properties->for_photo = 7; + + if (_cups_strcasestr(c, "graphic")) + properties->for_graphics = 6; + else if (_cups_strcasecmp(c, "graphic") == 0 || + _cups_strcasecmp(c, "graphics") == 0) + properties->for_graphics = 7; + + if (_cups_strcasestr(c, "text")) + { + if (_cups_strcasestr(c, "graphic")) + properties->for_tg = 7; + else + properties->for_text = 6; + } + else if (_cups_strcasecmp(c, "text") == 0) + properties->for_text = 7; + + if (_cups_strcasestr(c, "presentation")) + { + properties->for_text = 4; + properties->for_graphics = 4; + properties->for_tg = 4; + } + else if (_cups_strcasecmp(c, "presentation") == 0) + { + properties->for_text = 5; + properties->for_graphics = 5; + properties->for_tg = 5; + } + + if (_cups_strcasestr(c, "lineart")) + { + properties->for_graphics = 2; + properties->for_tg = 2; + } + else if (_cups_strcasecmp(c, "lineart") == 0) + { + properties->for_graphics = 3; + properties->for_tg = 3; + } + + if (_cups_strcasestr(c, "drawing")) + { + properties->for_graphics = 4; + properties->for_tg = 4; + } + else if (_cups_strcasecmp(c, "drawing") == 0) + { + properties->for_graphics = 5; + properties->for_tg = 5; + } + + if (_cups_strcasestr(c, "natural")) + properties->for_photo = 2; + else if (_cups_strcasecmp(c, "natural") == 0) + properties->for_photo = 3; + + if (_cups_strcasestr(c, "vivid")) + { + properties->for_text = 2; + properties->for_graphics = 2; + properties->for_tg = 2; + } + else if (_cups_strcasecmp(c, "vivid") == 0) + { + properties->for_text = 3; + properties->for_graphics = 3; + properties->for_tg = 3; + } + } + + /* We apply these optimizations only in high quality mode + therefore we prefer settings for high quality */ + if (properties->sets_high && !properties->sets_draft) + { + if (properties->for_photo) + properties->for_photo += 10; + if (properties->for_graphics) + properties->for_graphics += 10; + if (properties->for_text) + properties->for_text += 10; + if (properties->for_tg) + properties->for_tg += 10; + } + + /* + * Find the best choice for each field of the content optimize presets + */ + + /* Find best choice for each task */ + /* optimize_presets[1]: Photo */ + if (properties->for_photo > best_photo) + { + best_photo = properties->for_photo; + best_photo_ch = k; + } + /* optimize_presets[2]: Graphics */ + if (properties->for_graphics > best_graphics) + { + best_graphics = properties->for_graphics; + best_graphics_ch = k; + } + /* optimize_presets[3]: Text */ + if (properties->for_text > best_text) + { + best_text = properties->for_text; + best_text_ch = k; + } + /* optimize_presets[4]: Text and Graphics */ + if (properties->for_tg > best_tg) + { + best_tg = properties->for_tg; + best_tg_ch = k; + } + + /* This option actually does content optimization */ + if (properties->for_text || properties->for_graphics || + properties->for_tg || properties->for_photo) + sets_optimization = 1; + } + + /* + * Fill in the presets + */ + + if (sets_color_mode || sets_quality) + { + /* presets[0][0]: Mono/Draft */ + if (best_mono_draft_ch < 0) + best_mono_draft_ch = default_ch; + if (best_mono_draft_ch >= 0) + pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] + [_PWG_PRINT_QUALITY_DRAFT] = + cupsAddOption(o, option->choices[best_mono_draft_ch].choice, + pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] + [_PWG_PRINT_QUALITY_DRAFT], + &(pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] + [_PWG_PRINT_QUALITY_DRAFT])); + + /* presets[0][1]: Mono/Normal */ + if (best_mono_normal_ch < 0) + best_mono_normal_ch = default_ch; + if (best_mono_normal_ch >= 0) + pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] + [_PWG_PRINT_QUALITY_NORMAL] = + cupsAddOption(o, option->choices[best_mono_normal_ch].choice, + pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] + [_PWG_PRINT_QUALITY_NORMAL], + &(pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] + [_PWG_PRINT_QUALITY_NORMAL])); + + /* presets[0][2]: Mono/High */ + if (best_mono_high_ch < 0) + best_mono_high_ch = default_ch; + if (best_mono_high_ch >= 0) + pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] + [_PWG_PRINT_QUALITY_HIGH] = + cupsAddOption(o, option->choices[best_mono_high_ch].choice, + pc->num_presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] + [_PWG_PRINT_QUALITY_HIGH], + &(pc->presets[_PWG_PRINT_COLOR_MODE_MONOCHROME] + [_PWG_PRINT_QUALITY_HIGH])); + + /* presets[1][0]: Color/Draft */ + if (best_color_draft_ch < 0) + best_color_draft_ch = default_ch; + if (best_color_draft_ch >= 0) + pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR] + [_PWG_PRINT_QUALITY_DRAFT] = + cupsAddOption(o, option->choices[best_color_draft_ch].choice, + pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR] + [_PWG_PRINT_QUALITY_DRAFT], + &(pc->presets[_PWG_PRINT_COLOR_MODE_COLOR] + [_PWG_PRINT_QUALITY_DRAFT])); + + /* presets[1][1]: Color/Normal */ + if (best_color_normal_ch < 0) + best_color_normal_ch = default_ch; + if (best_color_normal_ch >= 0) + pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR] + [_PWG_PRINT_QUALITY_NORMAL] = + cupsAddOption(o, option->choices[best_color_normal_ch].choice, + pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR] + [_PWG_PRINT_QUALITY_NORMAL], + &(pc->presets[_PWG_PRINT_COLOR_MODE_COLOR] + [_PWG_PRINT_QUALITY_NORMAL])); + + /* presets[1][2]: Color/High */ + if (best_color_high_ch < 0) + best_color_high_ch = default_ch; + if (best_color_high_ch >= 0) + pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR] + [_PWG_PRINT_QUALITY_HIGH] = + cupsAddOption(o, option->choices[best_color_high_ch].choice, + pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR] + [_PWG_PRINT_QUALITY_HIGH], + &(pc->presets[_PWG_PRINT_COLOR_MODE_COLOR] + [_PWG_PRINT_QUALITY_HIGH])); + + } + + if (sets_optimization) + { + + /* optimize_presets[1]: Photo */ + if (best_photo_ch >= 0) + pc->num_optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_PHOTO] = + cupsAddOption + (o, option->choices[best_photo_ch].choice, + pc->num_optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_PHOTO], + &(pc->optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_PHOTO])); + + /* optimize_presets[2]: Graphics */ + if (best_graphics_ch >= 0) + pc->num_optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_GRAPHICS] = + cupsAddOption + (o, option->choices[best_graphics_ch].choice, + pc->num_optimize_presets + [_PWG_PRINT_CONTENT_OPTIMIZE_GRAPHICS], + &(pc->optimize_presets + [_PWG_PRINT_CONTENT_OPTIMIZE_GRAPHICS])); + + /* optimize_presets[1]: Text */ + if (best_text_ch >= 0) + pc->num_optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_TEXT] = + cupsAddOption + (o, option->choices[best_text_ch].choice, + pc->num_optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_TEXT], + &(pc->optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_TEXT])); + + /* optimize_presets[1]: Text and Graphics */ + if (best_tg_ch >= 0) + pc->num_optimize_presets + [_PWG_PRINT_CONTENT_OPTIMIZE_TEXT_AND_GRAPHICS] = + cupsAddOption + (o, option->choices[best_tg_ch].choice, + pc->num_optimize_presets + [_PWG_PRINT_CONTENT_OPTIMIZE_TEXT_AND_GRAPHICS], + &(pc->optimize_presets + [_PWG_PRINT_CONTENT_OPTIMIZE_TEXT_AND_GRAPHICS])); + + } + + for (k = 0; k < option->num_choices; k ++) + free(cupsArrayIndex(choice_properties, k)); + cupsArrayDelete(choice_properties); + } + } +} + /* * '_ppdCacheDestroy()' - Free all memory used for PWG mapping data. */ @@ -2058,7 +3089,7 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd) /* I - PPD file */ void _ppdCacheDestroy(_ppd_cache_t *pc) /* I - PPD cache and mapping data */ { - int i; /* Looping var */ + int i, j; /* Looping vars */ pwg_map_t *map; /* Current map */ pwg_size_t *size; /* Current size */ @@ -2137,6 +3168,15 @@ _ppdCacheDestroy(_ppd_cache_t *pc) /* I - PPD cache and mapping data */ cupsArrayDelete(pc->strings); + for (i = _PWG_PRINT_COLOR_MODE_MONOCHROME; i < _PWG_PRINT_COLOR_MODE_MAX; i ++) + for (j = _PWG_PRINT_QUALITY_DRAFT; j < _PWG_PRINT_QUALITY_MAX; j ++) + if (pc->num_presets[i][j]) + cupsFreeOptions(pc->num_presets[i][j], pc->presets[i][j]); + + for (i = _PWG_PRINT_CONTENT_OPTIMIZE_AUTO; i < _PWG_PRINT_CONTENT_OPTIMIZE_MAX; i ++) + if (pc->num_optimize_presets[i]) + cupsFreeOptions(pc->num_optimize_presets[i], pc->optimize_presets[i]); + free(pc); } @@ -3024,6 +4064,21 @@ _ppdCacheWriteFile( cupsFilePutChar(fp, '\n'); } + /* + * Optimization Presets... + */ + + for (i = _PWG_PRINT_CONTENT_OPTIMIZE_AUTO; i < _PWG_PRINT_CONTENT_OPTIMIZE_MAX; i ++) + if (pc->num_optimize_presets[i]) + { + cupsFilePrintf(fp, "OptimizePreset %d", i); + for (k = pc->num_optimize_presets[i], option = pc->optimize_presets[i]; + k > 0; + k --, option ++) + cupsFilePrintf(fp, " %s=%s", option->name, option->value); + cupsFilePutChar(fp, '\n'); + } + /* * Duplex/sides... */ diff --git a/cups/ppd-private.h b/cups/ppd-private.h index 11324c7..2188b2d 100644 --- a/cups/ppd-private.h +++ b/cups/ppd-private.h @@ -36,7 +36,7 @@ extern "C" { * Constants... */ -# define _PPD_CACHE_VERSION 11 /* Version number in cache file */ +# define _PPD_CACHE_VERSION 12 /* Version number in cache file */ /* @@ -101,6 +101,16 @@ typedef enum _pwg_print_quality_e /**** PWG print-quality values ****/ _PWG_PRINT_QUALITY_MAX } _pwg_print_quality_t; +typedef enum _pwg_print_content_optimize_e /** PWG print-content-optimize **/ +{ + _PWG_PRINT_CONTENT_OPTIMIZE_AUTO = 0, /* print-content-optimize=auto */ + _PWG_PRINT_CONTENT_OPTIMIZE_PHOTO, /* print-content-optimize=photo */ + _PWG_PRINT_CONTENT_OPTIMIZE_GRAPHICS, /* print-content-optimize=graphics */ + _PWG_PRINT_CONTENT_OPTIMIZE_TEXT, /* print-content-optimize=text */ + _PWG_PRINT_CONTENT_OPTIMIZE_TEXT_AND_GRAPHICS, /* ...=text-and-graphics */ + _PWG_PRINT_CONTENT_OPTIMIZE_MAX +} _pwg_print_content_optimize_t; + typedef struct _pwg_finishings_s /**** PWG finishings mapping data ****/ { ipp_finishings_t value; /* finishings value */ @@ -131,6 +141,11 @@ struct _ppd_cache_s /**** PPD cache and PWG conversion data ****/ /* Number of print-color-mode/print-quality options */ cups_option_t *presets[_PWG_PRINT_COLOR_MODE_MAX][_PWG_PRINT_QUALITY_MAX]; /* print-color-mode/print-quality options */ + int num_optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_MAX]; + /* Number of print-content-optimize + options */ + cups_option_t *optimize_presets[_PWG_PRINT_CONTENT_OPTIMIZE_MAX]; + /* print-content-optimize options */ char *sides_option, /* PPD option for sides */ *sides_1sided, /* Choice for one-sided */ *sides_2sided_long, /* Choice for two-sided-long-edge */ @@ -214,6 +229,8 @@ extern const char *_pwgMediaTypeForType(const char *media_type, extern const char *_pwgPageSizeForMedia(pwg_media_t *media, char *name, size_t namesize) _CUPS_PRIVATE; +extern void _ppdCacheAssignPresets(ppd_file_t *ppd, _ppd_cache_t *pc) _CUPS_PRIVATE; + /* * C++ magic... diff --git a/cups/string-private.h b/cups/string-private.h index 335e579..76037e3 100644 --- a/cups/string-private.h +++ b/cups/string-private.h @@ -150,6 +150,8 @@ extern int _cups_strcasecmp(const char *, const char *) _CUPS_PRIVATE; extern int _cups_strncasecmp(const char *, const char *, size_t n) _CUPS_PRIVATE; +extern char *_cups_strcasestr(const char *, const char *) _CUPS_PRIVATE; + # ifndef HAVE_STRLCAT extern size_t _cups_strlcat(char *, const char *, size_t) _CUPS_PRIVATE; # define strlcat _cups_strlcat diff --git a/cups/string.c b/cups/string.c index b4fc120..a479a7c 100644 --- a/cups/string.c +++ b/cups/string.c @@ -671,6 +671,36 @@ _cups_strncasecmp(const char *s, /* I - First string */ return (-1); } +/* + * '_cups_strcasestr()' - Do a case-insensitive search for a sub-string. + */ + +char * /* O - Pointer to found sub-string or + NULL if not found */ +_cups_strcasestr(const char *haystack, /* I - String in which to searh */ + const char *needle) /* I - Sub-string */ +{ + char cn, /* Character in needle */ + ch; /* Character in haystack */ + size_t len; /* Length of needle */ + + if ((cn = *needle++) != 0) + { + cn = _cups_tolower(cn); + len = strlen(needle); + do + { + do + { + if ((ch = *haystack++) == 0) + return (NULL); + } while (_cups_tolower(ch) != cn); + } while (_cups_strncasecmp(haystack, needle, len) != 0); + haystack --; + } + return ((char *)haystack); +} + #ifndef HAVE_STRLCAT /* diff --git a/cups/testhttp.c b/cups/testhttp.c index 66a112e..a4b8eeb 100644 --- a/cups/testhttp.c +++ b/cups/testhttp.c @@ -417,8 +417,7 @@ main(int argc, /* I - Number of command-line arguments */ } else { - failures ++; - puts("FAIL"); + puts("FAIL (Debian Reproducibility; failure allowed, as this is known to fail under reprotest"); } /* diff --git a/man/Makefile b/man/Makefile index 621fe60..7c30dd2 100644 --- a/man/Makefile +++ b/man/Makefile @@ -63,12 +63,18 @@ MAN8 = cupsaccept.8 \ lpmove.8 \ lpc.8 +LANGUAGES=de fr pt # # Make everything... # -all: $(MAN1) $(MAN5) $(MAN7) $(MAN8) +all: $(MAN1) $(MAN5) $(MAN7) $(MAN8) translations + +translations: + # Update the translations and build the translated material + po4a --previous ../debian/manpage-po4a/cups.cfg + for lang in $(LANGUAGES); do $(MAKE) -C $$lang; done # @@ -91,6 +97,12 @@ unittests: clean: $(RM) mantohtml mantohtml.o + $(RM) $(MAN1) $(MAN5) $(MAN7) $(MAN8) + for lang in $(LANGUAGES); do $(MAKE) -C $$lang clean; done + # Make sure the PO files are updated and remove generated + # translations. + po4a --previous --rm-translations ../debian/manpage-po4a/cups.cfg + $(RM) ../debian/manpage-po4a/po/cups.pot # @@ -142,6 +154,7 @@ install-data: all $(RM) $(MANDIR)/man8/$$file; \ $(LN) cupsd-helper.8 $(MANDIR)/man8/$$file; \ done + for lang in $(LANGUAGES); do $(MAKE) -C $$lang install; done # @@ -189,7 +202,7 @@ uninstall: for file in $(MAN8) cupsenable.8 cupsreject.8 cups-deviced.8 cups-driverd.8 cups-exec.8; do \ $(RM) $(MANDIR)/man8/$$file; \ done - -$(RMDIR) $(MANDIR)/man8 + -$(RMDIR) $(AMANDIR)/man$(MAN8DIR) # @@ -222,6 +235,5 @@ html: $(MAN1) $(MAN5) $(MAN7) $(MAN8) mantohtml ./mantohtml $$file >../doc/help/man-`basename $$file .8`.html; \ done -mantohtml: mantohtml.o ../cups/$(LIBCUPSSTATIC) - $(LD_CC) $(ARCHFLAGS) $(ALL_LDFLAGS) -o $@ mantohtml.o $(LINKCUPSSTATIC) - $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ +mantohtml: mantohtml.c + $(CC_FOR_BUILD) -o $@ $< diff --git a/man/Makefile.l10n b/man/Makefile.l10n new file mode 100644 index 0000000..08390f5 --- /dev/null +++ b/man/Makefile.l10n @@ -0,0 +1,235 @@ +# +# Man page makefile for CUPS. +# +# Copyright © 2007-2019 by Apple Inc. +# Copyright © 1993-2006 by Easy Software Products. +# +# Licensed under Apache License v2.0. See the file "LICENSE" for more +# information. +# + +include ../../Makedefs + + +# +# Man pages... +# + +MAN1 = cancel.1 \ + cups.1 \ + cups-config.1 \ + cupstestppd.1 \ + ippeveprinter.1 \ + $(IPPFIND_MAN) \ + ipptool.1 \ + lp.1 \ + lpoptions.1 \ + lpq.1 \ + lprm.1 \ + lpr.1 \ + lpstat.1 \ + ppdc.1 \ + ppdhtml.1 \ + ppdi.1 \ + ppdmerge.1 \ + ppdpo.1 +MAN5 = classes.conf.5 \ + client.conf.5 \ + cups-files.conf.5 \ + cups-snmp.conf.5 \ + cupsd.conf.5 \ + cupsd-logs.5 \ + ipptoolfile.5 \ + mailto.conf.5 \ + mime.convs.5 \ + mime.types.5 \ + ppdcfile.5 \ + printers.conf.5 \ + subscriptions.conf.5 +MAN7 = backend.7 \ + filter.7 \ + ippevepcl.7 \ + notifier.7 +MAN8 = cupsaccept.8 \ + cupsctl.8 \ + cupsfilter.8 \ + cups-lpd.8 \ + cups-snmp.8 \ + cupsd.8 \ + cupsd-helper.8 \ + cupsenable.8 \ + lpadmin.8 \ + lpinfo.8 \ + lpmove.8 \ + lpc.8 + + +# +# Make everything... +# + +# Debian-specific patch: Just assume all files are here. +all: + + +# +# Make library targets... +# + +libs: + + +# +# Make unit tests... +# + +unittests: + + +# +# Clean all config and object files... +# + +clean: + $(RM) mantohtml mantohtml.o + + +# +# Dummy depend target... +# + +depend: + + +# +# Install all targets... +# + +# Debian-specific patch: directory-based language namespace +MANDIR := $(MANDIR)/$(LANGUAGE) + +install: all install-data install-headers install-libs install-exec + + +# +# Install data files... +# + +# Debian-specific patch: skip if doesn't exist +install-data: all + echo Installing man pages in $(MANDIR)/man1... + $(INSTALL_DIR) -m 755 $(MANDIR)/man1 + for file in $(MAN1); do \ + [ ! -r $$file ] || \ + $(INSTALL_MAN) $$file $(MANDIR)/man1; \ + done + echo Installing man pages in $(MANDIR)/man5... + $(INSTALL_DIR) -m 755 $(MANDIR)/man5 + for file in $(MAN5); do \ + [ ! -r $$file ] || \ + $(INSTALL_MAN) $$file $(MANDIR)/man5; \ + done + echo Installing man pages in $(MANDIR)/man7... + $(INSTALL_DIR) -m 755 $(MANDIR)/man7 + for file in $(MAN7); do \ + [ ! -r $$file ] || \ + $(INSTALL_MAN) $$file $(MANDIR)/man7; \ + done + $(RM) $(MANDIR)/man7/ippeveps.7 + $(LN) ippevepcl.7 $(MANDIR)/man7/ippeveps.7 + echo Installing man pages in $(MANDIR)/man8... + $(INSTALL_DIR) -m 755 $(MANDIR)/man8 + for file in $(MAN8); do \ + [ ! -r $$file ] || \ + $(INSTALL_MAN) $$file $(MANDIR)/man8; \ + done + $(RM) $(MANDIR)/man8/cupsdisable.8 + $(LN) cupsenable.8 $(MANDIR)/man8/cupsdisable.8 + $(RM) $(MANDIR)/man8/cupsreject.8 + $(LN) cupsaccept.8 $(MANDIR)/man8/cupsreject.8 + for file in cups-deviced.8 cups-driverd.8 cups-exec.8; do \ + $(RM) $(MANDIR)/man8/$$file; \ + $(LN) cupsd-helper.8 $(MANDIR)/man8/$$file; \ + done + + +# +# Install programs... +# + +install-exec: + + +# +# Install headers... +# + +install-headers: + + +# +# Install libraries... +# + +install-libs: + + +# +# Uninstall files... +# + +uninstall: + echo Uninstalling man pages from $(MANDIR)/man1... + for file in $(MAN1); do \ + $(RM) $(MANDIR)/man1/$$file; \ + done + -$(RMDIR) $(MANDIR)/man1 + echo Uninstalling man pages from $(MANDIR)/man5... + for file in $(MAN5); do \ + $(RM) $(MANDIR)/man5/$$file; \ + done + -$(RMDIR) $(MANDIR)/man5 + echo Uninstalling man pages from $(MANDIR)/man7... + for file in $(MAN7) ippeveps.7; do \ + $(RM) $(MANDIR)/man7/$$file; \ + done + -$(RMDIR) $(MANDIR)/man7 + echo Uninstalling man pages from $(MANDIR)/man8... + for file in $(MAN8) cupsenable.8 cupsreject.8 cups-deviced.8 cups-driverd.8 cups-exec.8; do \ + $(RM) $(MANDIR)/man8/$$file; \ + done + -$(RMDIR) $(MANDIR)/man8 + + +# +# Local programs (not built when cross-compiling...) +# + +local: html + + +# +# Make html versions of man pages... +# + +html: $(MAN1) $(MAN5) $(MAN7) $(MAN8) mantohtml + echo Converting man pages to HTML... + for file in $(MAN1); do \ + echo " $$file..."; \ + ./mantohtml $$file >../doc/help/man-`basename $$file .1`.html; \ + done + for file in $(MAN5); do \ + echo " $$file..."; \ + ./mantohtml $$file >../doc/help/man-`basename $$file .5`.html; \ + done + for file in $(MAN7); do \ + echo " $$file..."; \ + ./mantohtml $$file >../doc/help/man-`basename $$file .7`.html; \ + done + for file in $(MAN8); do \ + echo " $$file..."; \ + ./mantohtml $$file >../doc/help/man-`basename $$file .8`.html; \ + done + +mantohtml: mantohtml.c + $(CC_FOR_BUILD) -o $@ $< diff --git a/man/de/Makefile b/man/de/Makefile new file mode 100644 index 0000000..7c23784 --- /dev/null +++ b/man/de/Makefile @@ -0,0 +1,7 @@ +# +# Man page makefile for the Common UNIX Printing System (CUPS). +# + +LANGUAGE=de + +include ../Makefile.l10n diff --git a/man/fr/Makefile b/man/fr/Makefile new file mode 100644 index 0000000..6a50e93 --- /dev/null +++ b/man/fr/Makefile @@ -0,0 +1,7 @@ +# +# Man page makefile for the Common UNIX Printing System (CUPS). +# + +LANGUAGE=fr + +include ../Makefile.l10n diff --git a/man/mantohtml.c b/man/mantohtml.c index a46b70e..16ac191 100644 --- a/man/mantohtml.c +++ b/man/mantohtml.c @@ -11,8 +11,10 @@ * Include necessary headers. */ -#include -#include +#include +#include +#include +#include #include @@ -811,7 +813,8 @@ main(int argc, /* I - Number of command-line args */ * Anchor for HTML output... */ - strlcpy(anchor, line + 4, sizeof(anchor)); + strncpy(anchor, line + 4, sizeof(anchor) - 1); + anchor[sizeof(anchor) - 1] = '\0'; } else if (strncmp(line, ".\\\"", 3)) { @@ -944,7 +947,8 @@ html_alternate(const char *s, /* I - String */ manfile[1024], // Man page filename manurl[1024]; // Man page URL - strlcpy(name, s, sizeof(name)); + strncpy(name, s, sizeof(name) - 1); + name[sizeof(name) - 1] = '\0'; if ((size_t)(end - s) < sizeof(name)) name[end - s] = '\0'; diff --git a/man/pt/Makefile b/man/pt/Makefile new file mode 100644 index 0000000..e043451 --- /dev/null +++ b/man/pt/Makefile @@ -0,0 +1,7 @@ +# +# Man page makefile for the Common UNIX Printing System (CUPS). +# + +LANGUAGE=pt + +include ../Makefile.l10n diff --git a/scheduler/auth.c b/scheduler/auth.c index 7f6c3f6..6ebd157 100644 --- a/scheduler/auth.c +++ b/scheduler/auth.c @@ -105,7 +105,7 @@ cupsdAddIPMask( cupsd_authmask_t temp; /* New host/domain mask */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddIPMask(masks=%p(%p), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)", masks, *masks, address[0], address[1], address[2], address[3], netmask[0], netmask[1], netmask[2], netmask[3]); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddIPMask(masks=%p(%p), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)", (void *)masks, (void *)*masks, address[0], address[1], address[2], address[3], netmask[0], netmask[1], netmask[2], netmask[3]); temp.type = CUPSD_AUTH_IP; memcpy(temp.mask.ip.address, address, sizeof(temp.mask.ip.address)); @@ -158,7 +158,7 @@ void cupsdAddName(cupsd_location_t *loc, /* I - Location to add to */ char *name) /* I - Name to add */ { - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddName(loc=%p, name=\"%s\")", loc, name); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddName(loc=%p, name=\"%s\")", (void *)loc, name); if (!loc->names) loc->names = cupsArrayNew3(NULL, NULL, NULL, 0, @@ -188,7 +188,7 @@ cupsdAddNameMask(cups_array_t **masks, /* IO - Masks array (created as needed) * *ifptr; /* Pointer to end of name */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddNameMask(masks=%p(%p), name=\"%s\")", masks, *masks, name); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddNameMask(masks=%p(%p), name=\"%s\")", (void *)masks, (void *)*masks, name); if (!_cups_strcasecmp(name, "@LOCAL")) { @@ -274,7 +274,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ con->best = cupsdFindBest(con->uri, httpGetState(con->http)); con->type = CUPSD_AUTH_NONE; - cupsdLogClient(con, CUPSD_LOG_DEBUG2, "con->uri=\"%s\", con->best=%p(%s)", con->uri, con->best, con->best ? con->best->location : ""); + cupsdLogClient(con, CUPSD_LOG_DEBUG2, "con->uri=\"%s\", con->best=%p(%s)", con->uri, (void *)con->best, con->best ? con->best->location : ""); if (con->best && con->best->type != CUPSD_AUTH_NONE) { @@ -1143,7 +1143,7 @@ cupsdCheckGroup( #endif /* HAVE_MBR_UID_TO_UUID */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")", username, user, groupname); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")", username, (void *)user, groupname); /* * Validate input... @@ -1558,7 +1558,7 @@ cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ }; - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: con->uri=\"%s\", con->best=%p(%s)", con->uri, con->best, con->best ? con->best->location ? con->best->location : "(null)" : ""); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: con->uri=\"%s\", con->best=%p(%s)", con->uri, (void *)con->best, con->best ? con->best->location ? con->best->location : "(null)" : ""); if (owner) cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: owner=\"%s\"", owner); @@ -2129,7 +2129,6 @@ check_admin_access(cupsd_client_t *con) // I - Client connection free(snap_name); g_clear_object(&snap); - # endif // CUPS_SNAP done: @@ -2140,6 +2139,8 @@ check_admin_access(cupsd_client_t *con) // I - Client connection return (ret); #else + (void)con; + // No AppArmor/snapd to deal with... return (1); #endif // HAVE_LIBAPPARMOR && HAVE_LIBSNAPDGLIB diff --git a/scheduler/auth.h b/scheduler/auth.h index 14885b0..26459d6 100644 --- a/scheduler/auth.h +++ b/scheduler/auth.h @@ -98,8 +98,6 @@ typedef struct http_encryption_t encryption; /* To encrypt or not to encrypt... */ } cupsd_location_t; -typedef struct cupsd_client_s cupsd_client_t; - /* * Globals... diff --git a/scheduler/client.c b/scheduler/client.c index 327473a..eafb566 100644 --- a/scheduler/client.c +++ b/scheduler/client.c @@ -430,6 +430,14 @@ cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ con->file = -1; } + if (con->bg_pending) + { + /* + * Don't close connection when there is a background thread pending + */ + partial = 1; + } + /* * Close the socket and clear the file from the input set for select()... */ diff --git a/scheduler/client.h b/scheduler/client.h index e12a860..10c4a4a 100644 --- a/scheduler/client.h +++ b/scheduler/client.h @@ -42,6 +42,8 @@ struct cupsd_client_s *query_string; /* QUERY_STRING environment variable */ int file; /* Input/output file */ int file_ready; /* Input ready on file/pipe? */ + int bg_pending; /* Background response pending? */ + cupsd_printer_t *bg_printer; /* Background printer */ int pipe_pid; /* Pipe process ID (or 0 if not a pipe) */ http_status_t pipe_status; /* HTTP status from pipe process */ int sent_header, /* Non-zero if sent HTTP header */ diff --git a/scheduler/conf.c b/scheduler/conf.c index 4fa7eb1..c74745c 100644 --- a/scheduler/conf.c +++ b/scheduler/conf.c @@ -1128,10 +1128,12 @@ cupsdReadConfiguration(void) Group, 1, 1) < 0 || cupsdCheckPermissions(ServerRoot, "ssl", 0700, RunUser, Group, 1, 0) < 0 || + /* Never alter permissions of central conffile cupsdCheckPermissions(ConfigurationFile, NULL, ConfigFilePerm, RunUser, Group, 0, 0) < 0 || cupsdCheckPermissions(CupsFilesFile, NULL, ConfigFilePerm, RunUser, Group, 0, 0) < 0 || + */ cupsdCheckPermissions(ServerRoot, "classes.conf", 0600, RunUser, Group, 0, 0) < 0 || cupsdCheckPermissions(ServerRoot, "printers.conf", 0600, RunUser, diff --git a/scheduler/cups-driverd.cxx b/scheduler/cups-driverd.cxx index ef45e92..eac4756 100644 --- a/scheduler/cups-driverd.cxx +++ b/scheduler/cups-driverd.cxx @@ -241,7 +241,6 @@ add_ppd(const char *filename, /* I - PPD filename */ const char *scheme) /* I - PPD scheme */ { ppd_info_t *ppd; /* PPD */ - char *recommended; /* Foomatic driver string */ /* @@ -279,15 +278,6 @@ add_ppd(const char *filename, /* I - PPD filename */ strlcpy(ppd->record.device_id, device_id, sizeof(ppd->record.device_id)); strlcpy(ppd->record.scheme, scheme, sizeof(ppd->record.scheme)); - /* - * Strip confusing (and often wrong) "recommended" suffix added by - * Foomatic drivers... - */ - - if ((recommended = strstr(ppd->record.make_and_model, - " (recommended)")) != NULL) - *recommended = '\0'; - /* * Add the PPD to the PPD arrays... */ diff --git a/scheduler/cupsd.h b/scheduler/cupsd.h index bc1350e..0703f45 100644 --- a/scheduler/cupsd.h +++ b/scheduler/cupsd.h @@ -99,6 +99,15 @@ extern const char *cups_hstrerror(int); #endif /* _MAIN_C */ +/* + * Base types... + */ + +typedef struct cupsd_client_s cupsd_client_t; +typedef struct cupsd_job_s cupsd_job_t; +typedef struct cupsd_printer_s cupsd_printer_t; + + /* * Other stuff for the scheduler... */ diff --git a/scheduler/ipp.c b/scheduler/ipp.c index 341c5e9..68428db 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -73,7 +73,7 @@ static void copy_subscription_attrs(cupsd_client_t *con, cups_array_t *ra, cups_array_t *exclude); static void create_job(cupsd_client_t *con, ipp_attribute_t *uri); -static void *create_local_bg_thread(cupsd_printer_t *printer); +static void *create_local_bg_thread(cupsd_client_t *con); static void create_local_printer(cupsd_client_t *con); static cups_array_t *create_requested_array(ipp_t *request); static void create_subscriptions(cupsd_client_t *con, ipp_attribute_t *uri); @@ -111,6 +111,7 @@ static void send_document(cupsd_client_t *con, ipp_attribute_t *uri); static void send_http_error(cupsd_client_t *con, http_status_t status, cupsd_printer_t *printer); static void send_ipp_status(cupsd_client_t *con, ipp_status_t status, const char *message, ...) _CUPS_FORMAT(3, 4); +static int send_response(cupsd_client_t *con); static void set_default(cupsd_client_t *con, ipp_attribute_t *uri); static void set_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri); static void set_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri); @@ -143,7 +144,7 @@ cupsdProcessIPPRequest( int valid = 1; /* Valid request? */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest(%p[%d]): operation_id=%04x(%s)", con, con->number, con->request->request.op.operation_id, ippOpString(con->request->request.op.operation_id)); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest(%p[%d]): operation_id=%04x(%s)", (void *)con, con->number, con->request->request.op.operation_id, ippOpString(con->request->request.op.operation_id)); if (LogLevel >= CUPSD_LOG_DEBUG2) { @@ -615,68 +616,13 @@ cupsdProcessIPPRequest( } } - if (con->response) + if (!con->bg_pending && con->response) { /* * Sending data from the scheduler... */ - cupsdLogClient(con, con->response->request.status.status_code >= IPP_STATUS_ERROR_BAD_REQUEST && con->response->request.status.status_code != IPP_STATUS_ERROR_NOT_FOUND ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG, "Returning IPP %s for %s (%s) from %s.", ippErrorString(con->response->request.status.status_code), ippOpString(con->request->request.op.operation_id), uri ? uri->values[0].string.text : "no URI", con->http->hostname); - - httpClearFields(con->http); - -#ifdef CUPSD_USE_CHUNKING - /* - * Because older versions of CUPS (1.1.17 and older) and some IPP - * clients do not implement chunking properly, we cannot use - * chunking by default. This may become the default in future - * CUPS releases, or we might add a configuration directive for - * it. - */ - - if (con->http->version == HTTP_1_1) - { - cupsdLogClient(con, CUPSD_LOG_DEBUG, "Transfer-Encoding: chunked"); - cupsdSetLength(con->http, 0); - } - else -#endif /* CUPSD_USE_CHUNKING */ - { - size_t length; /* Length of response */ - - - length = ippLength(con->response); - - if (con->file >= 0 && !con->pipe_pid) - { - struct stat fileinfo; /* File information */ - - if (!fstat(con->file, &fileinfo)) - length += (size_t)fileinfo.st_size; - } - - cupsdLogClient(con, CUPSD_LOG_DEBUG, "Content-Length: " CUPS_LLFMT, CUPS_LLCAST length); - httpSetLength(con->http, length); - } - - if (cupsdSendHeader(con, HTTP_OK, "application/ipp", CUPSD_AUTH_NONE)) - { - /* - * Tell the caller the response header was sent successfully... - */ - - cupsdAddSelect(httpGetFd(con->http), (cupsd_selfunc_t)cupsdReadClient, (cupsd_selfunc_t)cupsdWriteClient, con); - - return (1); - } - else - { - /* - * Tell the caller the response header could not be sent... - */ - - return (0); - } + return (send_response(con)); } else { @@ -747,7 +693,7 @@ accept_jobs(cupsd_client_t *con, /* I - Client connection */ cupsd_printer_t *printer; /* Printer data */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "accept_jobs(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "accept_jobs(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -832,7 +778,7 @@ add_class(cupsd_client_t *con, /* I - Client connection */ int need_restart_job; /* Need to restart job? */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_class(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_class(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -1142,7 +1088,7 @@ add_file(cupsd_client_t *con, /* I - Connection to client */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_file(con=%p[%d], job=%d, filetype=%s/%s, " - "compression=%d)", con, con ? con->number : -1, job->id, + "compression=%d)", (void *)con, con ? con->number : -1, job->id, filetype->super, filetype->type, compression); /* @@ -1245,8 +1191,8 @@ add_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %p(%s), %p(%s/%s))", - con, con->number, printer, printer->name, - filetype, filetype ? filetype->super : "none", + (void *)con, con->number, (void *)printer, printer->name, + (void *)filetype, filetype ? filetype->super : "none", filetype ? filetype->type : "none"); /* @@ -2226,7 +2172,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ set_port_monitor; /* Did we set the port monitor? */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -2717,8 +2663,21 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ return; } - // Run a background thread to create the PPD... - _cupsThreadCreate((_cups_thread_func_t)create_local_bg_thread, printer); + if (!printer->printer_id) + printer->printer_id = NextPrinterId ++; + + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); + + cupsdSetPrinterAttrs(printer); + + /* Run a background thread to create the PPD... */ + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Creating PPD in background thread."); + + con->bg_pending = 1; + con->bg_printer = printer; + + _cupsThreadCreate((_cups_thread_func_t)create_local_bg_thread, con); + return; } else if (!strcmp(ppd_name, "raw")) { @@ -2883,7 +2842,7 @@ add_printer_state_reasons( { cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_state_reasons(%p[%d], %p[%s])", - con, con->number, p, p->name); + (void *)con, con->number, (void *)p, p->name); if (p->num_reasons == 0) ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, @@ -2909,7 +2868,7 @@ add_queued_job_count( cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_queued_job_count(%p[%d], %p[%s])", - con, con->number, p, p->name); + (void *)con, con->number, (void *)p, p->name); count = cupsdGetPrinterJobCount(p->name); @@ -2999,7 +2958,7 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "authenticate_job(%p[%d], %s)", - con, con->number, uri->values[0].string.text); + (void *)con, con->number, uri->values[0].string.text); /* * Start with "everything is OK" status... @@ -3177,7 +3136,7 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ cupsd_job_t *job; /* Job */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_all_jobs(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_all_jobs(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -3414,7 +3373,7 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ cupsd_jobaction_t purge; /* Purge the job? */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_job(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_job(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -3615,7 +3574,7 @@ cancel_subscription( cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_subscription(con=%p[%d], sub_id=%d)", - con, con->number, sub_id); + (void *)con, con->number, sub_id); /* * Is the subscription ID valid? @@ -3721,7 +3680,7 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "check_quotas(%p[%d], %p[%s])", - con, con->number, p, p->name); + (void *)con, con->number, (void *)p, p->name); /* * Figure out who is printing... @@ -3943,7 +3902,7 @@ close_job(cupsd_client_t *con, /* I - Client connection */ username[256]; /* User name */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "close_job(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "close_job(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -4063,7 +4022,7 @@ copy_attrs(ipp_t *to, /* I - Destination request */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_attrs(to=%p, from=%p, ra=%p, group=%x, quickcopy=%d)", - to, from, ra, group, quickcopy); + (void *)to, (void *)from, (void *)ra, group, quickcopy); if (!to || !from) return; @@ -4147,7 +4106,7 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_banner(con=%p[%d], job=%p[%d], name=\"%s\")", - con, con ? con->number : -1, job, job->id, + (void *)con, con ? con->number : -1, (void *)job, job->id, name ? name : "(null)"); /* @@ -4492,7 +4451,7 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ /* cupsProtocol attribute */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_model(con=%p, from=\"%s\", to=\"%s\")", con, from, to); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_model(con=%p, from=\"%s\", to=\"%s\")", (void *)con, from, to); /* * Run cups-driverd to get the PPD file... @@ -5106,7 +5065,7 @@ copy_subscription_attrs( cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_subscription_attrs(con=%p, sub=%p, ra=%p, exclude=%p)", - con, sub, ra, exclude); + (void *)con, (void *)sub, (void *)ra, (void *)exclude); /* * Copy the subscription attributes to the response using the @@ -5220,7 +5179,7 @@ create_job(cupsd_client_t *con, /* I - Client connection */ }; - cupsdLogMessage(CUPSD_LOG_DEBUG2, "create_job(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "create_job(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -5285,11 +5244,14 @@ create_job(cupsd_client_t *con, /* I - Client connection */ static void * /* O - Exit status */ create_local_bg_thread( - cupsd_printer_t *printer) /* I - Printer */ + cupsd_client_t *con) /* I - Client */ { + cupsd_printer_t *printer = con->bg_printer; + /* Printer */ cups_file_t *from, /* Source file */ *to; /* Destination file */ - char fromppd[1024], /* Source PPD */ + char device_uri[1024], /* Device URI */ + fromppd[1024], /* Source PPD */ toppd[1024], /* Destination PPD */ scheme[32], /* URI scheme */ userpass[256], /* User:pass */ @@ -5301,7 +5263,7 @@ create_local_bg_thread( http_encryption_t encryption; /* Type of encryption to use */ http_t *http; /* Connection to printer */ ipp_t *request, /* Request to printer */ - *response; /* Response from printer */ + *response = NULL; /* Response from printer */ ipp_attribute_t *attr; /* Attribute in response */ ipp_status_t status; /* Status code */ static const char * const pattrs[] = /* Printer attributes we need */ @@ -5315,26 +5277,47 @@ create_local_bg_thread( * Try connecting to the printer... */ - cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Generating PPD file from \"%s\"...", printer->name, printer->device_uri); + _cupsRWLockRead(&printer->lock); + strlcpy(device_uri, printer->device_uri, sizeof(device_uri)); + _cupsRWUnlock(&printer->lock); + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Generating PPD file from \"%s\"...", printer->name, device_uri); - if (strstr(printer->device_uri, "._tcp")) + if (strstr(device_uri, "._tcp")) { - cupsdLogMessage(CUPSD_LOG_DEBUG2, "%s: Resolving mDNS URI \"%s\".", printer->name, printer->device_uri); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "%s: Resolving mDNS URI \"%s\".", printer->name, device_uri); - if (!_httpResolveURI(printer->device_uri, uri, sizeof(uri), _HTTP_RESOLVE_DEFAULT, NULL, NULL)) + if (!_httpResolveURI(device_uri, uri, sizeof(uri), _HTTP_RESOLVE_DEFAULT, NULL, NULL)) { - cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Couldn't resolve mDNS URI \"%s\".", printer->name, printer->device_uri); - return (NULL); + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Couldn't resolve mDNS URI \"%s\".", printer->name, device_uri); + + /* Force printer to timeout and be deleted */ + _cupsRWLockWrite(&printer->lock); + printer->state_time = 0; + _cupsRWUnlock(&printer->lock); + + send_ipp_status(con, IPP_STATUS_ERROR_DEVICE, _("Couldn't resolve mDNS URI \"%s\"."), printer->device_uri); + goto finish_response; } + _cupsRWLockWrite(&printer->lock); cupsdSetString(&printer->device_uri, uri); + _cupsRWUnlock(&printer->lock); + + strlcpy(device_uri, uri, sizeof(device_uri)); } - if (httpSeparateURI(HTTP_URI_CODING_ALL, printer->device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) + if (httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) { - cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Bad device URI \"%s\".", printer->name, printer->device_uri); - return (NULL); + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Bad device URI \"%s\".", printer->name, device_uri); + + /* Force printer to timeout and be deleted */ + _cupsRWLockWrite(&printer->lock); + printer->state_time = 0; + _cupsRWUnlock(&printer->lock); + + send_ipp_status(con, IPP_STATUS_ERROR_DEVICE, _("Bad device URI \"%s\"."), device_uri); + goto finish_response; } if (!strcmp(scheme, "ipps") || port == 443) @@ -5345,7 +5328,14 @@ create_local_bg_thread( if ((http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to connect to %s:%d: %s", printer->name, host, port, cupsLastErrorString()); - return (NULL); + + /* Force printer to timeout and be deleted */ + _cupsRWLockWrite(&printer->lock); + printer->state_time = 0; + _cupsRWUnlock(&printer->lock); + + send_ipp_status(con, IPP_STATUS_ERROR_DEVICE, _("Unable to connect to %s:%d: %s"), host, port, cupsLastErrorString()); + goto finish_response; } /* @@ -5389,6 +5379,7 @@ create_local_bg_thread( * If we did not succeed to obtain the "media-col-database" attribute * try to get it separately */ + if (ippFindAttribute(response, "media-col-database", IPP_TAG_ZERO) == NULL) { @@ -5447,17 +5438,29 @@ create_local_bg_thread( if ((from = cupsFileOpen(fromppd, "r")) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to read generated PPD: %s", printer->name, strerror(errno)); - ippDelete(response); - return (NULL); + + /* Force printer to timeout and be deleted */ + _cupsRWLockWrite(&printer->lock); + printer->state_time = 0; + _cupsRWUnlock(&printer->lock); + + send_ipp_status(con, IPP_STATUS_ERROR_DEVICE, _("Unable to read generated PPD: %s"), strerror(errno)); + goto finish_response; } snprintf(toppd, sizeof(toppd), "%s/ppd/%s.ppd", ServerRoot, printer->name); if ((to = cupsdCreateConfFile(toppd, ConfigFilePerm)) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to create PPD for printer: %s", printer->name, strerror(errno)); - ippDelete(response); cupsFileClose(from); - return (NULL); + + /* Force printer to timeout and be deleted */ + _cupsRWLockWrite(&printer->lock); + printer->state_time = 0; + _cupsRWUnlock(&printer->lock); + + send_ipp_status(con, IPP_STATUS_ERROR_DEVICE, _("Unable to create PPD for printer: %s"), strerror(errno)); + goto finish_response; } while (cupsFileGets(from, line, sizeof(line))) @@ -5466,10 +5469,14 @@ create_local_bg_thread( cupsFileClose(from); if (!cupsdCloseCreatedConfFile(to, toppd)) { + _cupsRWLockWrite(&printer->lock); + printer->config_time = time(NULL); printer->state = IPP_PSTATE_IDLE; printer->accepting = 1; + _cupsRWUnlock(&printer->lock); + cupsdSetPrinterAttrs(printer); cupsdAddEvent(CUPSD_EVENT_PRINTER_CONFIG, printer, NULL, "Printer \"%s\" is now available.", printer->name); @@ -5477,10 +5484,39 @@ create_local_bg_thread( } } else + { cupsdLogMessage(CUPSD_LOG_ERROR, "%s: PPD creation failed: %s", printer->name, cupsLastErrorString()); + /* Force printer to timeout and be deleted */ + _cupsRWLockWrite(&printer->lock); + printer->state_time = 0; + _cupsRWUnlock(&printer->lock); + + send_ipp_status(con, IPP_STATUS_ERROR_DEVICE, _("Unable to create PPD: %s"), cupsLastErrorString()); + goto finish_response; + } + + /* + * Respond to the client... + */ + + send_ipp_status(con, IPP_STATUS_OK, _("Local printer created.")); + + ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", (char)printer->accepting); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", (int)printer->state); + add_printer_state_reasons(con, printer); + + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), httpIsEncrypted(con->http) ? "ipps" : "ipp", NULL, con->clientname, con->clientport, "/printers/%s", printer->name); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, uri); + + finish_response: + ippDelete(response); + send_response(con); + + con->bg_pending = 0; + return (NULL); } @@ -5592,10 +5628,21 @@ create_local_printer( if ((printer = cupsdFindDest(name)) != NULL) { - send_ipp_status(con, IPP_STATUS_ERROR_NOT_POSSIBLE, _("Printer \"%s\" already exists."), name); + printer->state_time = time(NULL); + send_ipp_status(con, IPP_STATUS_OK, _("Printer \"%s\" already exists."), name); goto add_printer_attributes; } + for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers); printer; printer = (cupsd_printer_t *)cupsArrayNext(Printers)) + { + if (printer->device_uri && !strcmp(ptr, printer->device_uri)) + { + printer->state_time = time(NULL); + send_ipp_status(con, IPP_STATUS_OK, _("Printer \"%s\" already exists."), printer->name); + goto add_printer_attributes; + } + } + /* * Create the printer... */ @@ -5682,14 +5729,17 @@ create_local_printer( * Run a background thread to create the PPD... */ - _cupsThreadCreate((_cups_thread_func_t)create_local_bg_thread, printer); + con->bg_pending = 1; + con->bg_printer = printer; + + _cupsThreadCreate((_cups_thread_func_t)create_local_bg_thread, con); + + return; /* * Return printer attributes... */ - send_ipp_status(con, IPP_STATUS_OK, _("Local printer created.")); - add_printer_attributes: ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", (char)printer->accepting); @@ -5795,7 +5845,7 @@ create_subscriptions( * Is the destination valid? */ - cupsdLogMessage(CUPSD_LOG_DEBUG, "create_subscriptions(con=%p(%d), uri=\"%s\")", con, con->number, uri->values[0].string.text); + cupsdLogMessage(CUPSD_LOG_DEBUG, "create_subscriptions(con=%p(%d), uri=\"%s\")", (void *)con, con->number, uri->values[0].string.text); httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, sizeof(scheme), userpass, sizeof(userpass), host, @@ -6143,7 +6193,7 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ int temporary; /* Temporary queue? */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "delete_printer(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "delete_printer(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -6256,7 +6306,7 @@ get_default(cupsd_client_t *con) /* I - Client connection */ cups_array_t *ra; /* Requested attributes array */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_default(%p[%d])", con, con->number); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_default(%p[%d])", (void *)con, con->number); /* * Check policy... @@ -6306,7 +6356,7 @@ get_devices(cupsd_client_t *con) /* I - Client connection */ /* String for included schemes */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_devices(%p[%d])", con, con->number); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_devices(%p[%d])", (void *)con, con->number); /* * Check policy... @@ -6399,7 +6449,7 @@ get_document(cupsd_client_t *con, /* I - Client connection */ format[1024]; /* Format for document */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_document(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_document(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -6546,7 +6596,7 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ *exclude; /* Private attributes array */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_job_attrs(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_job_attrs(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -6677,7 +6727,7 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ cupsd_policy_t *policy; /* Current policy */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs(%p[%d], %s)", con, con->number, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -6988,7 +7038,7 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: job->id=%d, dest=\"%s\", username=\"%s\", " "state_value=%d, attrs=%p", job->id, job->dest, - job->username, job->state_value, job->attrs); + job->username, job->state_value, (void *)job->attrs); if (!job->dest || !job->username) cupsdLoadJob(job); @@ -7067,7 +7117,7 @@ get_notifications(cupsd_client_t *con) /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_notifications(con=%p[%d])", - con, con->number); + (void *)con, con->number); /* * Get subscription attributes... @@ -7200,8 +7250,8 @@ get_ppd(cupsd_client_t *con, /* I - Client connection */ cups_ptype_t dtype; /* Destination type */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppd(%p[%d], %p[%s=%s])", con, - con->number, uri, uri->name, uri->values[0].string.text); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppd(%p[%d], %p[%s=%s])", (void *)con, + con->number, (void *)uri, uri->name, uri->values[0].string.text); if (!strcmp(ippGetName(uri), "ppd-name")) { @@ -7373,7 +7423,7 @@ get_ppds(cupsd_client_t *con) /* I - Client connection */ /* String for included schemes */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppds(%p[%d])", con, con->number); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppds(%p[%d])", (void *)con, con->number); /* * Check policy... @@ -7517,7 +7567,7 @@ get_printer_attrs(cupsd_client_t *con, /* I - Client connection */ cups_array_t *ra; /* Requested attributes array */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_attrs(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_attrs(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -7573,7 +7623,7 @@ get_printer_supported( cupsd_printer_t *printer; /* Printer/class */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_supported(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_supported(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -7643,7 +7693,7 @@ get_printers(cupsd_client_t *con, /* I - Client connection */ int local; /* Local connection? */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printers(%p[%d], %x)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printers(%p[%d], %x)", (void *)con, con->number, type); /* @@ -7804,7 +7854,7 @@ get_subscription_attrs( cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_subscription_attrs(con=%p[%d], sub_id=%d)", - con, con->number, sub_id); + (void *)con, con->number, sub_id); /* * Expire subscriptions as needed... @@ -7891,7 +7941,7 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_subscriptions(con=%p[%d], uri=%s)", - con, con->number, uri->values[0].string.text); + (void *)con, con->number, uri->values[0].string.text); /* * Is the destination valid? @@ -8059,7 +8109,7 @@ hold_job(cupsd_client_t *con, /* I - Client connection */ cupsd_job_t *job; /* Job information */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_job(%p[%d], %s)", con, con->number, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_job(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -8190,7 +8240,7 @@ hold_new_jobs(cupsd_client_t *con, /* I - Connection */ cupsd_printer_t *printer; /* Printer data */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_new_jobs(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_new_jobs(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -8267,7 +8317,7 @@ move_job(cupsd_client_t *con, /* I - Client connection */ *dprinter; /* Destination printer */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "move_job(%p[%d], %s)", con, con->number, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "move_job(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -8596,7 +8646,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ int compression; /* Document compression */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "print_job(%p[%d], %s)", con, con->number, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "print_job(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -9047,7 +9097,7 @@ reject_jobs(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *attr; /* printer-state-message text */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "reject_jobs(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "reject_jobs(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -9129,7 +9179,7 @@ release_held_new_jobs( cupsd_printer_t *printer; /* Printer data */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_held_new_jobs(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_held_new_jobs(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -9202,7 +9252,7 @@ release_job(cupsd_client_t *con, /* I - Client connection */ cupsd_job_t *job; /* Job information */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_job(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_job(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -9339,7 +9389,7 @@ renew_subscription( cupsdLogMessage(CUPSD_LOG_DEBUG2, "renew_subscription(con=%p[%d], sub_id=%d)", - con, con->number, sub_id); + (void *)con, con->number, sub_id); /* * Is the subscription ID valid? @@ -9426,7 +9476,7 @@ restart_job(cupsd_client_t *con, /* I - Client connection */ int port; /* Port portion of URI */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "restart_job(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "restart_job(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -9777,7 +9827,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ int start_job; /* Start the job? */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_document(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_document(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -10288,6 +10338,82 @@ send_ipp_status(cupsd_client_t *con, /* I - Client connection */ } +/* + * 'send_response()' - Send the IPP response. + */ + +static int /* O - 1 on success, 0 on failure */ +send_response(cupsd_client_t *con) /* I - Client */ +{ + ipp_attribute_t *uri; /* Target URI */ + int ret = 0; /* Return value */ + static _cups_mutex_t mutex = _CUPS_MUTEX_INITIALIZER; + /* Mutex for logging/access */ + + + _cupsMutexLock(&mutex); + + if ((uri = ippFindAttribute(con->request, "printer-uri", IPP_TAG_URI)) == NULL) + { + if ((uri = ippFindAttribute(con->request, "job-uri", IPP_TAG_URI)) == NULL) + uri = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME); + } + + cupsdLogClient(con, con->response->request.status.status_code >= IPP_STATUS_ERROR_BAD_REQUEST && con->response->request.status.status_code != IPP_STATUS_ERROR_NOT_FOUND ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG, "Returning IPP %s for %s (%s) from %s.", ippErrorString(con->response->request.status.status_code), ippOpString(con->request->request.op.operation_id), uri ? uri->values[0].string.text : "no URI", con->http->hostname); + + httpClearFields(con->http); + +#ifdef CUPSD_USE_CHUNKING + /* + * Because older versions of CUPS (1.1.17 and older) and some IPP + * clients do not implement chunking properly, we cannot use + * chunking by default. This may become the default in future + * CUPS releases, or we might add a configuration directive for + * it. + */ + + if (con->http->version == HTTP_1_1) + { + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Transfer-Encoding: chunked"); + cupsdSetLength(con->http, 0); + } + else +#endif /* CUPSD_USE_CHUNKING */ + { + size_t length; /* Length of response */ + + + length = ippLength(con->response); + + if (con->file >= 0 && !con->pipe_pid) + { + struct stat fileinfo; /* File information */ + + if (!fstat(con->file, &fileinfo)) + length += (size_t)fileinfo.st_size; + } + + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Content-Length: " CUPS_LLFMT, CUPS_LLCAST length); + httpSetLength(con->http, length); + } + + if (cupsdSendHeader(con, HTTP_STATUS_OK, "application/ipp", CUPSD_AUTH_NONE)) + { + /* + * Tell the caller the response header was sent successfully... + */ + + cupsdAddSelect(httpGetFd(con->http), (cupsd_selfunc_t)cupsdReadClient, (cupsd_selfunc_t)cupsdWriteClient, con); + + ret = 1; + } + + _cupsMutexUnlock(&mutex); + + return (ret); +} + + /* * 'set_default()' - Set the default destination... */ @@ -10302,7 +10428,7 @@ set_default(cupsd_client_t *con, /* I - Client connection */ *oldprinter; /* Old default printer */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_default(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_default(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -10384,7 +10510,7 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ int check_jobs; /* Check jobs? */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_job_attrs(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_job_attrs(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -10764,7 +10890,7 @@ set_printer_attrs(cupsd_client_t *con, /* I - Client connection */ int changed = 0; /* Was anything changed? */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_printer_attrs(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_printer_attrs(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -11110,7 +11236,7 @@ start_printer(cupsd_client_t *con, /* I - Client connection */ cupsd_printer_t *printer; /* Printer data */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_printer(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_printer(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -11192,7 +11318,7 @@ stop_printer(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *attr; /* printer-state-message attribute */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "stop_printer(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "stop_printer(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -11434,7 +11560,7 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ cupsd_printer_t *printer; /* Printer */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "validate_job(%p[%d], %s)", con, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "validate_job(%p[%d], %s)", (void *)con, con->number, uri->values[0].string.text); /* @@ -11627,7 +11753,7 @@ validate_user(cupsd_job_t *job, /* I - Job */ cupsd_printer_t *printer; /* Printer for job */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, userlen=" CUPS_LLFMT ")", job->id, con ? con->number : 0, owner ? owner : "(null)", username, CUPS_LLCAST userlen); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, userlen=" CUPS_LLFMT ")", job->id, con ? con->number : 0, owner ? owner : "(null)", (void *)username, CUPS_LLCAST userlen); /* * Validate input... diff --git a/scheduler/job.c b/scheduler/job.c index 49e4fa3..fae7428 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -3653,9 +3653,13 @@ get_options(cupsd_job_t *job, /* I - Job */ cups_option_t *pwgppds, /* PWG->PPD options */ *pwgppd, /* Current PWG->PPD option */ *preset; /* Current preset option */ - int print_color_mode, + int print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR, /* Output mode (if any) */ - print_quality; /* Print quality (if any) */ + print_quality = _PWG_PRINT_QUALITY_NORMAL, + /* Print quality (if any) */ + print_content_optimize = + _PWG_PRINT_CONTENT_OPTIMIZE_AUTO; + /* Print content type (if any)*/ const char *ppd; /* PPD option choice */ int exact; /* Did we get an exact match? */ static char *options = NULL;/* Full list of options */ @@ -3677,7 +3681,7 @@ get_options(cupsd_job_t *job, /* I - Job */ if (pc && !ippFindAttribute(job->attrs, "com.apple.print.DocumentTicket.PMSpoolFormat", IPP_TAG_ZERO) && !ippFindAttribute(job->attrs, "APPrinterPreset", IPP_TAG_ZERO) && - (ippFindAttribute(job->attrs, "print-color-mode", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "cupsPrintQuality", IPP_TAG_ZERO))) + (ippFindAttribute(job->attrs, "print-color-mode", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "print-content-optimize", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "cupsPrintQuality", IPP_TAG_ZERO))) { /* * Map print-color-mode and print-quality to a preset... @@ -3739,6 +3743,12 @@ get_options(cupsd_job_t *job, /* I - Job */ } } + cupsdLogJob(job, CUPSD_LOG_DEBUG, + "print-color-mode=%s, print-quality=%s", + print_color_mode == _PWG_PRINT_COLOR_MODE_MONOCHROME ? + "gray" : "color", + print_quality == _PWG_PRINT_QUALITY_DRAFT ? "draft" : + (print_quality == _PWG_PRINT_QUALITY_HIGH ? "high" : "normal")); if (pc->num_presets[print_color_mode][print_quality] > 0) { /* @@ -3753,7 +3763,72 @@ get_options(cupsd_job_t *job, /* I - Job */ { if (!ippFindAttribute(job->attrs, preset->name, IPP_TAG_ZERO)) { - cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Adding preset option %s=%s", preset->name, preset->value); + cupsdLogJob(job, CUPSD_LOG_DEBUG, "Adding preset option %s=%s", preset->name, preset->value); + + num_pwgppds = cupsAddOption(preset->name, preset->value, num_pwgppds, &pwgppds); + } + } + } + } + + if (pc && + ippFindAttribute(job->attrs, "print-content-optimize", IPP_TAG_ZERO)) + { + /* + * Map print-content-optimize to a preset... + */ + + if ((attr = ippFindAttribute(job->attrs, "print-content-optimize", + IPP_TAG_KEYWORD)) != NULL) + { + if (!strcmp(attr->values[0].string.text, "auto")) + print_content_optimize = _PWG_PRINT_CONTENT_OPTIMIZE_AUTO; + else if (!strcmp(attr->values[0].string.text, "photo")) + print_content_optimize = _PWG_PRINT_CONTENT_OPTIMIZE_PHOTO; + else if (!strcmp(attr->values[0].string.text, "graphics") || + !strcmp(attr->values[0].string.text, "graphic")) + print_content_optimize = _PWG_PRINT_CONTENT_OPTIMIZE_GRAPHICS; + else if (!strcmp(attr->values[0].string.text, "text")) + print_content_optimize = _PWG_PRINT_CONTENT_OPTIMIZE_TEXT; + else if (!strcmp(attr->values[0].string.text, "text-and-graphics") || + !strcmp(attr->values[0].string.text, "text-and-graphic")) + print_content_optimize = _PWG_PRINT_CONTENT_OPTIMIZE_TEXT_AND_GRAPHICS; + else + print_content_optimize = _PWG_PRINT_CONTENT_OPTIMIZE_AUTO; + } + else + print_content_optimize = _PWG_PRINT_CONTENT_OPTIMIZE_AUTO; + + cupsdLogJob(job, CUPSD_LOG_DEBUG, + "print-content-optimize=%s", + (print_content_optimize == _PWG_PRINT_CONTENT_OPTIMIZE_AUTO ? + "automatic" : + (print_content_optimize == _PWG_PRINT_CONTENT_OPTIMIZE_PHOTO ? + "photo" : + (print_content_optimize == _PWG_PRINT_CONTENT_OPTIMIZE_GRAPHICS ? + "graphics" : + (print_content_optimize == _PWG_PRINT_CONTENT_OPTIMIZE_TEXT ? + "text" : + "text and graphics"))))); + if (pc->num_optimize_presets[print_content_optimize] > 0) + { + /* + * Copy the preset options as long as the corresponding names are not + * already defined in the IPP request and also if it does not change + * the print quality preset (as long as we do not print in high quality) + * ... + */ + + for (i = pc->num_optimize_presets[print_content_optimize], + preset = pc->optimize_presets[print_content_optimize]; + i > 0; + i --, preset ++) + { + if (!ippFindAttribute(job->attrs, preset->name, IPP_TAG_ZERO) && + (print_quality == _PWG_PRINT_QUALITY_HIGH || + cupsGetOption(preset->name, num_pwgppds, pwgppds) == NULL)) + { + cupsdLogJob(job, CUPSD_LOG_DEBUG, "Adding content optimization preset option %s=%s", preset->name, preset->value); num_pwgppds = cupsAddOption(preset->name, preset->value, num_pwgppds, &pwgppds); } diff --git a/scheduler/policy.h b/scheduler/policy.h index 74a7ff4..6a2dd56 100644 --- a/scheduler/policy.h +++ b/scheduler/policy.h @@ -22,8 +22,6 @@ typedef struct *ops; /* Operations */ } cupsd_policy_t; -typedef struct cupsd_printer_s cupsd_printer_t; - /* * Globals... diff --git a/scheduler/printers.c b/scheduler/printers.c index 5f9852e..bf493a3 100644 --- a/scheduler/printers.c +++ b/scheduler/printers.c @@ -620,7 +620,7 @@ cupsdDeletePrinter( cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeletePrinter(p=%p(%s), update=%d)", - p, p->name, update); + (void *)p, p->name, update); /* * Save the current position in the Printers array... @@ -782,11 +782,11 @@ cupsdDeleteTemporaryPrinters(int force) /* I - Force deletion instead of auto? * "cupsdDeleteTemporaryPrinters: Removing unused temporary printers"); /* - * Allow temporary printers to stick around for 60 seconds after the last job + * Allow temporary printers to stick around for 5 minutes after the last job * completes. */ - unused_time = time(NULL) - 60; + unused_time = time(NULL) - 300; for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers)) { @@ -2550,7 +2550,7 @@ cupsdSetPrinterReasons( cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdSetPrinterReasons(p=%p(%s),s=\"%s\"", p, p->name, s); + "cupsdSetPrinterReasons(p=%p(%s),s=\"%s\"", (void *)p, p->name, s); if (s[0] == '-' || s[0] == '+') { @@ -3396,7 +3396,7 @@ add_printer_filter( cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_filter(p=%p(%s), filtertype=%p(%s/%s), " - "filter=\"%s\")", p, p->name, filtertype, filtertype->super, + "filter=\"%s\")", (void *)p, p->name, (void *)filtertype, filtertype->super, filtertype->type, filter); /* diff --git a/scheduler/printers.h b/scheduler/printers.h index 0c7b1af..142aedf 100644 --- a/scheduler/printers.h +++ b/scheduler/printers.h @@ -50,8 +50,6 @@ typedef AvahiStringList *cupsd_txt_t; /* TXT record */ * Printer/class information structure... */ -typedef struct cupsd_job_s cupsd_job_t; - struct cupsd_printer_s { _cups_rwlock_t lock; /* Concurrency lock for background updates */ diff --git a/test/run-stp-tests.sh b/test/run-stp-tests.sh index 39b53c3..21bc308 100755 --- a/test/run-stp-tests.sh +++ b/test/run-stp-tests.sh @@ -19,7 +19,8 @@ argcount=$# if test "x`id -u`" = x0; then echo Please run this as a normal user. Not supported when run as root. - exit 1 + echo "Debian Reproducibility: Skipping allowed, as this is known to break under reprotest. This message MUST NOT be visible in normal Debian buildd logs." + exit 0 fi #