From c8d724e6bb16ec1edfe0e13b8a5ed04cf8c417a7 Mon Sep 17 00:00:00 2001 From: Michael Sweet Date: Tue, 15 Mar 2016 10:43:16 -0400 Subject: [PATCH] Import CUPS v2.1b1 --- CHANGES-2.0.txt | 201 + CHANGES.txt | 251 +- INSTALL.txt | 2 +- Makedefs.in | 4 +- Makefile | 4 +- README.txt | 2 +- backend/dnssd.c | 4 +- backend/ipp.c | 373 +- backend/snmp-supplies.c | 4 +- backend/usb-darwin.c | 151 +- backend/usb-libusb.c | 4 +- cgi-bin/Makefile | 4 +- cgi-bin/admin.c | 101 +- cgi-bin/help-index.c | 8 +- cgi-bin/ipp-var.c | 7 +- cgi-bin/template.c | 4 +- cgi-bin/var.c | 35 +- conf/Makefile | 8 +- config-scripts/cups-common.m4 | 7 +- config-scripts/cups-compiler.m4 | 13 +- config-scripts/cups-defaults.m4 | 6 +- config-scripts/cups-network.m4 | 4 +- config-scripts/cups-ssl.m4 | 10 +- config-scripts/cups-startup.m4 | 13 +- config.h.in | 27 +- configure | 300 +- configure.ac | 5 +- cups/Makefile | 20 +- cups/auth.c | 6 +- cups/cups-private.h | 6 +- cups/cups.h | 29 +- cups/debug.c | 4 +- cups/dest.c | 4 +- cups/encode.c | 10 +- cups/file.c | 4 +- cups/globals.c | 4 +- cups/http-private.h | 8 +- cups/http.c | 4 +- cups/ipp-support.c | 22 +- cups/ipp.c | 4 +- cups/ipp.h | 67 +- cups/language.c | 4 +- cups/mark.c | 12 +- cups/ppd-cache.c | 953 +++- cups/ppd-private.h | 10 +- cups/test.ppd | 15 +- cups/testfile.c | 4 +- cups/testhttp.c | 5 +- cups/testppd.c | 57 +- cups/tls-darwin.c | 85 +- cups/tls-gnutls.c | 49 +- cups/tls-sspi.c | 25 +- cups/tlscheck.c | 739 +++ cups/transcode.c | 4 +- cups/usersys.c | 53 +- cups/util.c | 4 +- cups/versioning.h | 4 +- data/Makefile | 29 +- data/classified | 6 - data/confidential | 6 - data/secret | 6 - data/standard | 6 - data/testprint.in | 7 - data/topsecret | 6 - data/unclassified | 6 - doc/help/api-array.html | 2 +- doc/help/api-cgi.html | 2 +- doc/help/api-cups.html | 2 +- doc/help/api-filedir.html | 2 +- doc/help/api-filter.html | 2 +- doc/help/api-httpipp.html | 76 +- doc/help/api-mime.html | 2 +- doc/help/api-overview.html | 2 +- doc/help/api-ppd.html | 2 +- doc/help/api-ppdc.html | 2 +- doc/help/api-raster.html | 2 +- doc/help/man-client.conf.html | 8 +- doc/help/man-cups-files.conf.html | 9 +- doc/help/man-cupsd.conf.html | 5 +- doc/help/man-ipptool.html | 2 +- doc/help/man-ipptoolfile.html | 8 +- doc/help/man-lpadmin.html | 10 +- doc/help/postscript-driver.html | 2 +- doc/help/ppd-compiler.html | 2 +- doc/help/raster-driver.html | 2 +- doc/help/spec-cmp.html | 2 +- doc/help/spec-ppd.html | 2 +- filter/Makefile | 10 +- filter/error.c | 21 +- filter/gziptoany.c | 4 +- filter/interpret.c | 101 +- filter/pstops.c | 4 +- filter/raster.c | 131 +- filter/rastertoepson.c | 4 +- filter/rastertohp.c | 4 +- filter/rastertopwg.c | 4 +- locale/Makefile | 4 +- locale/cups.pot | 1334 ++--- locale/cups.strings | 9 +- locale/cups_ca.po | 31 +- locale/cups_cs.po | 31 +- locale/cups_de.po | 77 +- locale/cups_es.po | 1837 +------ locale/cups_fr.po | 31 +- locale/cups_it.po | 40 +- locale/cups_ja.po | 1878 +------ locale/cups_ru.po | 364 +- man/Makefile | 8 +- man/client.conf.man.in | 16 +- man/cups-files.conf.man.in | 17 +- man/cupsd.conf.man.in | 13 +- man/ipptool.man | 10 +- man/ipptoolfile.man | 17 +- man/lpadmin.man | 18 +- man/mantohtml.c | 4 +- packaging/cups.spec | 10 +- packaging/cups.spec.in | 6 +- ppdc/Makefile | 4 +- ppdc/ppdhtml.cxx | 4 +- ppdc/ppdpo.cxx | 4 +- ppdc/sample.drv | 6 +- scheduler/Makefile | 12 +- scheduler/auth.c | 4 +- scheduler/client.c | 11 +- scheduler/colorman.c | 8 +- scheduler/conf.c | 167 +- scheduler/conf.h | 8 +- scheduler/cups-driverd.cxx | 12 +- scheduler/cups-lpd.c | 21 +- scheduler/cupsfilter.c | 4 +- scheduler/dirsvc.c | 4 +- scheduler/env.c | 4 +- scheduler/ipp.c | 189 +- scheduler/job.c | 127 +- scheduler/job.h | 9 +- scheduler/log.c | 349 +- scheduler/main.c | 31 +- scheduler/org.cups.cups-lpd.plist.in | 6 +- scheduler/org.cups.cupsd.plist | 14 +- scheduler/printers.c | 171 +- scheduler/printers.h | 12 +- scheduler/process.c | 4 +- scheduler/server.c | 13 +- scheduler/sysman.c | 7 +- scheduler/testlpd.c | 10 +- scheduler/type.c | 4 +- systemv/cancel.c | 4 +- systemv/cupstestppd.c | 72 +- systemv/lpadmin.c | 225 +- templates/de/help-trailer.tmpl | 0 templates/ru/help-trailer.tmpl | 0 test/5.1-lpadmin.sh | 4 +- test/5.4-lpstat.sh | 4 +- test/Dependencies | 12 +- test/Makefile | 48 +- test/ipp-1.1.test | 4 +- test/ippfind.c | 10 +- test/ippinfra.c | 7125 ++++++++++++++++++++++++++ test/ippinfra.man | 103 + test/ippproxy.c | 29 + test/ippproxy.man | 59 + test/ippserver.c | 27 +- test/ipptool.c | 526 +- test/run-stp-tests.sh | 42 +- test/str-header.html | 21 +- vcnet/config.h | 10 +- xcode/CUPS.xcodeproj/project.pbxproj | 431 +- xcode/config.h | 35 +- 168 files changed, 13716 insertions(+), 6319 deletions(-) create mode 100644 CHANGES-2.0.txt create mode 100644 cups/tlscheck.c delete mode 100644 data/classified delete mode 100644 data/confidential delete mode 100644 data/secret delete mode 100644 data/standard delete mode 100644 data/testprint.in delete mode 100644 data/topsecret delete mode 100644 data/unclassified create mode 100644 templates/de/help-trailer.tmpl create mode 100644 templates/ru/help-trailer.tmpl create mode 100644 test/ippinfra.c create mode 100644 test/ippinfra.man create mode 100644 test/ippproxy.c create mode 100644 test/ippproxy.man diff --git a/CHANGES-2.0.txt b/CHANGES-2.0.txt new file mode 100644 index 0000000000..81c8dcf54f --- /dev/null +++ b/CHANGES-2.0.txt @@ -0,0 +1,201 @@ +CHANGES-2.0.txt +--------------- + +CHANGES IN CUPS V2.0.3 + + - Security: Fixed CERT VU #810572 exploiting the dynamic linker + (STR #4609) + - Security: The scheduler could hang with malformed gzip data + (STR #4602) + - Restored missing generic printer icon file (STR #4587) + - Fixed logging of configuration errors to show up as errors (STR #4582) + - Fixed potential buffer overflows in raster code and filters + (STR #4598, STR #4599, STR #4600, STR #4601) + - Fixed a gzip processing bug (#4602) + - Fixed inside (STR #4575) + - Fixed lpadmin when both -m and -o are used (STR #4578) + - The web interface always showed support for 2-sided printing + (STR #4595) + - cupsRasterReadHeader did not fully validate the raster header + (STR #4596) + - The rastertopwg filter did not check for truncated input (STR #4597) + - The cups-lpd mini-daemon did not check for request parameters + (STR #4603) + - The scheduler could get caught in a busy loop (STR #4605) + - The sample Epson driver could crash (STR #4616) + - The IPP backend now correctly monitors jobs + () + - The ppdhtml and ppdpo utilities crashed when the -D option was used + before a driver information file (STR #4627) + - ippfind incorrectly substituted "=port" for service_port. + - The IPP/1.1 test file did not handle the initial print job + completing early (STR #4576) + - Fixed a memory leak in cupsConnectDest (STR #4634) + - PWG Raster Format output contained invalid ImageBox values + () + - Added Russian translation (STR #4577) + - Added German translation (STR #4635) + + +CHANGES IN CUPS V2.0.2 + + - Security: cupsRasterReadPixels buffer overflow with invalid page + header and compressed raster data (STR #4551) + - Command-line programs were not localized on Mac OS X + () + - The scheduler incorrectly cleared the MakeModel string in the + printers.conf file after a restart () + - CUPS did not compile with older versions of GNU TLS (STR #4527) + - CUPS did not compile without Avahi or mDNSResponder (STR #4523) + - ippLength() did not return the correct length for IPP_TAG_CONST + string values. + - The scheduler incorrectly aborted jobs after a job was restarted + () + - The cups-files.conf file contained the old ServerCertificate/Key + directives instead of ServerKeychain. + - Fixed builds when no SSL/TLS library is available, or when explicitly + disabled (STR #4531) + - Fixed an OpenBSD charset transcoding issue. + - Fixed USB printing on OpenBSD (STR #4525) + - The --without-xinetd configure option did not work (STR #4542) + - Backends needing to load OS X kernel extensions did not work + () + - Mapping of PPD keywords to IPP keywords did not work if the PPD + keyword was already an IPP keyword () + - cupsGetPPD* sent bad requests (STR #4567) + - ippserver used the wrong temporary directory on Windows (STR #4547) + - ippserver did not handle Bonjour registrations properly (STR #4548) + - The scheduler could crash during shutdown if Avahi was shutdown + first (STR #4550) + - Added a USB quirk rule for Intermec printers (STR #4553) + - The scheduler did not always log which configuration file had the + error (STR #4559) + - The ippfind and ipptool programs now correctly match hostnames with + trailing dots (STR #4563) + - The ipptool timeout option did not work (STR #4515) + - Fixed several issues with client.conf, CUPS_SERVER, and the "-h" + option of most commands (STR #4528) + - Another change for OpenBSD (STR #4526) + - Added Japanese localization (STR #4524) + - Documentation changes (STR #4569) + + +CHANGES IN CUPS V2.0.1 + + - Security: SSLv3 is now disabled by default to protect against the + POODLE attack (STR #4476) + - Printer sharing did not work when systemd was being used (STR #4497) + - cupsGetPPD* would return a symlink to the PPD in /etc/cups/ppd even if + it was not readable by the user (STR #4500) + - The web interface now protects against frame "click-jacking" attacks + (STR #4492) + - Fixed a crash in ippAttributeString () + - Fixed a crash in the scheduler on Linux/*BSD if colord was not running + (STR #4496) + - Fixed a random crash in the scheduler when not using systemd + (STR #4484) + - Added systemd support for cups-lpd (STR #4493) + - The scheduler did not honor the FatalErrors directive for mis- + configured Group and SystemGroup values (STR #4495) + - The network backends no longer report waste-receptacle conditions when + using SNMP (STR #4499) + - The IPP backend did not work with some configurations of Windows + (STR #4503) + - RPMs did not build (STR #4490) + - Added a USB quirk rule for the Brother HL-1250 (STR #4519) + - Fixed compiles on unsupported platforms (STR #4510) + - "cancel -a" did not cancel all jobs on all destinations (STR #4513) + - The web interface did not work on OpenBSD (STR #4496) + + +CHANGES IN CUPS V2.0.0 + + - The scheduler did not preserve listener sockets from launchd or + systemd after a restart () + - Added some USB quirk rules for the libusb-based USB backend + (STR #4482) + - Spanish localization update (STR #4487) + - Updated documentation for 2.0.0 release. + + +CHANGES IN CUPS V2.0rc1 + + - Documentation updates (STR #4464) + - The scheduler now monitors the AC power status on OS X, allowing for + "sleep printing" when sharing printers () + - The scheduler incorrectly called launch_activate_socket multiple times + on OS X () + - The ippserver test program now passes the IPP Everywhere self- + certification tests (STR #4101) + - Relaxed the new OS X filter sandbox slightly (STR #4471, + ) + - Dropped the old Epson Stylus Color/Photo sample drivers since they + don't work with any current printers and there are free alternatives + that produce much better output () + - Log and configuration files that are not world-readable are again + accessible via the web interface (STR #4461) + - PPD files are now created using the permissions specified by the + ConfigFilePerm directive. + - Fixed RPM build issues (STR #4459) + - Fixed the spinner image and restart page when reconfiguring the + scheduler through the web interface (STR #4475) + + +CHANGES IN CUPS V2.0b1 + + - Added a "--list-filters" option to the cupsfilter command (STR #4325) + - Added systemd support (STR #3917) + - Added support for re-sending a job as a raster file if a higher-level + format such as PDF fails () + - Added support for regular expression matching in the MIME type rules + () + - Added support for TLS certificate validation and policy enforcement + (STR #1616) + - Added support for simultaneous XML and test output from ipptool. + - Added support for PAUSE directive in ipptool test files. + - Added support for auto-typing of TIFF files by ipptool (STR #4418) + - The scheduler now returns completed jobs in the correct newest-to- + oldest order (STR #4396) + - The configure script now supports target-specific tools for pkg-config + and others (STR #4423) + - The ipptool program now supports EXPECT statements for collection + member attributes () + - The ipptool program now supports collection attributes with multiple + values () + - The sample drivers now include all of the installed localizations by + default () + - Adopted Linux man page conventions and updated all man pages + (STR #4372, STR #4329) + - The scheduler now supports the "first-index" operation attribute for + the Get-Jobs operation (STR #2913) + - Changed the default AccessLogLevel and PageLogFormat to disable the + access_log and page_log files by default () + - cupsRasterInterpretPPD now supports the Orientation header in order to + support long-edge feed raster printers () + - The scheduler now allows run-as-root backends to have group read and + execute permissions (STR #2935) + - The ippFindAttribute and ippFindNextAttribute functions now support + hierarchical searches (STR #4395) + - Dropped OpenSSL support in favor of GNU TLS. + - Dropped "dark wake" support on OS X, which was preventing portables + from going to sleep when there was a stuck job. We now use a variation + of the CUPS 1.4 sleep support to do a cleaner sleep + () + - Dropped support for AIX, HP-UX, and OSF/1 (aka Digital UNIX) + - Dropped lppasswd and support for Digest authentication in in the + scheduler (STR #4321) + - The cupsGetClasses, cupsGetPrinters, and cupsTempFile functions are no + longer supported. + - The scheduler now caches more job history data and limits the number + of completed jobs returned by Get-Jobs as needed in order to prevent a + denial-of-service on busy servers (STR #2913) + - The filter/backend sandbox on OS X now defaults to a more strict + whitelist () + - Increased the default idle exit timeout to 60 seconds on OS X + () + - Printer classes were not accessible on OS X + () + - The scheduler now uses to close the default printer + definition in printers.conf (STR #4153) + - Canceling all jobs in the web interface now just cancels the jobs + (STR #1914) diff --git a/CHANGES.txt b/CHANGES.txt index f2a44dc3b1..113637de41 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,215 +1,42 @@ -CHANGES.txt - 2.0.4 - 2015-07-31 +CHANGES.txt - 2.1b1 - 2015-06-03 -------------------------------- -CHANGES IN CUPS V2.0.4 +CHANGES IN CUPS V2.1b1 + + - Improved speed of ppdMarkDefaults for complex/large PPDs + () + - The IPP backend now stops sending print data if the printer indicates + the job has been aborted or canceled () + - The IPP backend now sends the job-pages-per-set attribute when + printing multiple copy jobs with finishings + () + - The IPP backend now updates the cupsMandatory values when the printer + configuration changes () + - No longer install banner files since third-party banner filters now + supply their own (STR #4518) + - Added support for EXPECT-ALL directive in ipptool test files + (STR #4469) + - Added support for WITH-VALUE-FROM predicate in ipptool test files + (STR #4470) + - The scheduler no longer listens on the loopback interface unless the + web interface or printer sharing are enabled + () + - Added a PPD generator for IPP Everywhere printers (STR #4258) + - Now install "default" versions of more configuration files + () + - The cupstestppd program did not handle "maxsize(nnn)" entries in + cupsFilter/cupsFilter2 values () + - The scheduler now checks the return value of rename() calls + (STR #4589) + - The scheduler now validates ErrorPolicy values in config files + (STR #4591) + - Long cookies caused the web interface to stop working (STR #4619) + - Added SSLOptions values to allow Diffie-Hellman key exchange and + disable TLS/1.0 support. + - Updated the scheduler to support more IPP Everywhere attributes + (STR #4630) + - The scheduler now supports advanced ASL and journald logging when + "syslog" output is configured (STR #4474) + - The scheduler now supports logging to stderr when running in the + foreground (STR #4505) - - Fixed a bug in cupsRasterWritePixels (STR #4650) - - Fixed redirection in the web interface (STR #4538) - - The IPP backend did not respond to side-channel requests (STR #4645) - - The scheduler did not start all pending jobs at once (STR #4646) - - The web search incorrectly searched time-at-xxx values (STR #4652) - - Fixed an RPM spec file issue (STR #4657) - - The scheduler incorrectly started jobs while canceling multiple jobs - (STR #4648) - - Fixed processing of server overrides without port numbers (STR #4675) - - Documentation changes (STR #4651, STR #4674) - - -CHANGES IN CUPS V2.0.3 - - - Security: Fixed CERT VU #810572 exploiting the dynamic linker - (STR #4609) - - Security: The scheduler could hang with malformed gzip data - (STR #4602) - - Restored missing generic printer icon file (STR #4587) - - Fixed logging of configuration errors to show up as errors (STR #4582) - - Fixed potential buffer overflows in raster code and filters - (STR #4598, STR #4599, STR #4600, STR #4601) - - Fixed a gzip processing bug (#4602) - - Fixed inside (STR #4575) - - Fixed lpadmin when both -m and -o are used (STR #4578) - - The web interface always showed support for 2-sided printing - (STR #4595) - - cupsRasterReadHeader did not fully validate the raster header - (STR #4596) - - The rastertopwg filter did not check for truncated input (STR #4597) - - The cups-lpd mini-daemon did not check for request parameters - (STR #4603) - - The scheduler could get caught in a busy loop (STR #4605) - - The sample Epson driver could crash (STR #4616) - - The IPP backend now correctly monitors jobs - () - - The ppdhtml and ppdpo utilities crashed when the -D option was used - before a driver information file (STR #4627) - - ippfind incorrectly substituted "=port" for service_port. - - The IPP/1.1 test file did not handle the initial print job - completing early (STR #4576) - - Fixed a memory leak in cupsConnectDest (STR #4634) - - PWG Raster Format output contained invalid ImageBox values - () - - Added Russian translation (STR #4577) - - Added German translation (STR #4635) - - -CHANGES IN CUPS V2.0.2 - - - Security: cupsRasterReadPixels buffer overflow with invalid page - header and compressed raster data (STR #4551) - - Command-line programs were not localized on Mac OS X - () - - The scheduler incorrectly cleared the MakeModel string in the - printers.conf file after a restart () - - CUPS did not compile with older versions of GNU TLS (STR #4527) - - CUPS did not compile without Avahi or mDNSResponder (STR #4523) - - ippLength() did not return the correct length for IPP_TAG_CONST - string values. - - The scheduler incorrectly aborted jobs after a job was restarted - () - - The cups-files.conf file contained the old ServerCertificate/Key - directives instead of ServerKeychain. - - Fixed builds when no SSL/TLS library is available, or when explicitly - disabled (STR #4531) - - Fixed an OpenBSD charset transcoding issue. - - Fixed USB printing on OpenBSD (STR #4525) - - The --without-xinetd configure option did not work (STR #4542) - - Backends needing to load OS X kernel extensions did not work - () - - Mapping of PPD keywords to IPP keywords did not work if the PPD - keyword was already an IPP keyword () - - cupsGetPPD* sent bad requests (STR #4567) - - ippserver used the wrong temporary directory on Windows (STR #4547) - - ippserver did not handle Bonjour registrations properly (STR #4548) - - The scheduler could crash during shutdown if Avahi was shutdown - first (STR #4550) - - Added a USB quirk rule for Intermec printers (STR #4553) - - The scheduler did not always log which configuration file had the - error (STR #4559) - - The ippfind and ipptool programs now correctly match hostnames with - trailing dots (STR #4563) - - The ipptool timeout option did not work (STR #4515) - - Fixed several issues with client.conf, CUPS_SERVER, and the "-h" - option of most commands (STR #4528) - - Another change for OpenBSD (STR #4526) - - Added Japanese localization (STR #4524) - - Documentation changes (STR #4569) - - -CHANGES IN CUPS V2.0.1 - - - Security: SSLv3 is now disabled by default to protect against the - POODLE attack (STR #4476) - - Printer sharing did not work when systemd was being used (STR #4497) - - cupsGetPPD* would return a symlink to the PPD in /etc/cups/ppd even if - it was not readable by the user (STR #4500) - - The web interface now protects against frame "click-jacking" attacks - (STR #4492) - - Fixed a crash in ippAttributeString () - - Fixed a crash in the scheduler on Linux/*BSD if colord was not running - (STR #4496) - - Fixed a random crash in the scheduler when not using systemd - (STR #4484) - - Added systemd support for cups-lpd (STR #4493) - - The scheduler did not honor the FatalErrors directive for mis- - configured Group and SystemGroup values (STR #4495) - - The network backends no longer report waste-receptacle conditions when - using SNMP (STR #4499) - - The IPP backend did not work with some configurations of Windows - (STR #4503) - - RPMs did not build (STR #4490) - - Added a USB quirk rule for the Brother HL-1250 (STR #4519) - - Fixed compiles on unsupported platforms (STR #4510) - - "cancel -a" did not cancel all jobs on all destinations (STR #4513) - - The web interface did not work on OpenBSD (STR #4496) - - -CHANGES IN CUPS V2.0.0 - - - The scheduler did not preserve listener sockets from launchd or - systemd after a restart () - - Added some USB quirk rules for the libusb-based USB backend - (STR #4482) - - Spanish localization update (STR #4487) - - Updated documentation for 2.0.0 release. - - -CHANGES IN CUPS V2.0rc1 - - - Documentation updates (STR #4464) - - The scheduler now monitors the AC power status on OS X, allowing for - "sleep printing" when sharing printers () - - The scheduler incorrectly called launch_activate_socket multiple times - on OS X () - - The ippserver test program now passes the IPP Everywhere self- - certification tests (STR #4101) - - Relaxed the new OS X filter sandbox slightly (STR #4471, - ) - - Dropped the old Epson Stylus Color/Photo sample drivers since they - don't work with any current printers and there are free alternatives - that produce much better output () - - Log and configuration files that are not world-readable are again - accessible via the web interface (STR #4461) - - PPD files are now created using the permissions specified by the - ConfigFilePerm directive. - - Fixed RPM build issues (STR #4459) - - Fixed the spinner image and restart page when reconfiguring the - scheduler through the web interface (STR #4475) - - -CHANGES IN CUPS V2.0b1 - - - Added a "--list-filters" option to the cupsfilter command (STR #4325) - - Added systemd support (STR #3917) - - Added support for re-sending a job as a raster file if a higher-level - format such as PDF fails () - - Added support for regular expression matching in the MIME type rules - () - - Added support for TLS certificate validation and policy enforcement - (STR #1616) - - Added support for simultaneous XML and test output from ipptool. - - Added support for PAUSE directive in ipptool test files. - - Added support for auto-typing of TIFF files by ipptool (STR #4418) - - The scheduler now returns completed jobs in the correct newest-to- - oldest order (STR #4396) - - The configure script now supports target-specific tools for pkg-config - and others (STR #4423) - - The ipptool program now supports EXPECT statements for collection - member attributes () - - The ipptool program now supports collection attributes with multiple - values () - - The sample drivers now include all of the installed localizations by - default () - - Adopted Linux man page conventions and updated all man pages - (STR #4372, STR #4329) - - The scheduler now supports the "first-index" operation attribute for - the Get-Jobs operation (STR #2913) - - Changed the default AccessLogLevel and PageLogFormat to disable the - access_log and page_log files by default () - - cupsRasterInterpretPPD now supports the Orientation header in order to - support long-edge feed raster printers () - - The scheduler now allows run-as-root backends to have group read and - execute permissions (STR #2935) - - The ippFindAttribute and ippFindNextAttribute functions now support - hierarchical searches (STR #4395) - - Dropped OpenSSL support in favor of GNU TLS. - - Dropped "dark wake" support on OS X, which was preventing portables - from going to sleep when there was a stuck job. We now use a variation - of the CUPS 1.4 sleep support to do a cleaner sleep - () - - Dropped support for AIX, HP-UX, and OSF/1 (aka Digital UNIX) - - Dropped lppasswd and support for Digest authentication in in the - scheduler (STR #4321) - - The cupsGetClasses, cupsGetPrinters, and cupsTempFile functions are no - longer supported. - - The scheduler now caches more job history data and limits the number - of completed jobs returned by Get-Jobs as needed in order to prevent a - denial-of-service on busy servers (STR #2913) - - The filter/backend sandbox on OS X now defaults to a more strict - whitelist () - - Increased the default idle exit timeout to 60 seconds on OS X - () - - Printer classes were not accessible on OS X - () - - The scheduler now uses to close the default printer - definition in printers.conf (STR #4153) - - Canceling all jobs in the web interface now just cancels the jobs - (STR #1914) diff --git a/INSTALL.txt b/INSTALL.txt index bd8c28aafb..0608c3547a 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -1,4 +1,4 @@ -INSTALL - CUPS v2.0.4 - 2015-07-31 +INSTALL - CUPS v2.1b1 - 2015-06-08 ---------------------------------- This file describes how to compile and install CUPS from source code. For more diff --git a/Makedefs.in b/Makedefs.in index f9c275f3c4..3afef0a332 100644 --- a/Makedefs.in +++ b/Makedefs.in @@ -1,5 +1,5 @@ # -# "$Id: Makedefs.in 11716 2014-03-21 14:50:24Z msweet $" +# "$Id: Makedefs.in 12519 2015-02-17 13:10:19Z msweet $" # # Common makefile definitions for CUPS. # @@ -264,5 +264,5 @@ USBQUIRKS = @USBQUIRKS@ # -# End of "$Id: Makedefs.in 11716 2014-03-21 14:50:24Z msweet $" +# End of "$Id: Makedefs.in 12519 2015-02-17 13:10:19Z msweet $" # diff --git a/Makefile b/Makefile index f5aa07c062..94ce714e81 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # -# "$Id: Makefile 12415 2015-01-21 00:03:08Z msweet $" +# "$Id: Makefile 12414 2015-01-21 00:02:04Z msweet $" # # Top-level Makefile for CUPS. # @@ -348,5 +348,5 @@ dist: all # -# End of "$Id: Makefile 12415 2015-01-21 00:03:08Z msweet $". +# End of "$Id: Makefile 12414 2015-01-21 00:02:04Z msweet $". # diff --git a/README.txt b/README.txt index 8e4e64197d..a6db7bfb94 100644 --- a/README.txt +++ b/README.txt @@ -1,4 +1,4 @@ -README - CUPS v2.0.4 - 2015-07-31 +README - CUPS v2.1b1 - 2015-06-08 --------------------------------- Looking for compile instructions? Read the file "INSTALL.txt" instead... diff --git a/backend/dnssd.c b/backend/dnssd.c index 83f450959d..e76431b0b1 100644 --- a/backend/dnssd.c +++ b/backend/dnssd.c @@ -1,5 +1,5 @@ /* - * "$Id: dnssd.c 12660 2015-05-22 19:09:57Z msweet $" + * "$Id: dnssd.c 12659 2015-05-22 19:06:41Z msweet $" * * DNS-SD discovery backend for CUPS. * @@ -1330,5 +1330,5 @@ unquote(char *dst, /* I - Destination buffer */ /* - * End of "$Id: dnssd.c 12660 2015-05-22 19:09:57Z msweet $". + * End of "$Id: dnssd.c 12659 2015-05-22 19:06:41Z msweet $". */ diff --git a/backend/ipp.c b/backend/ipp.c index 50dd73ea44..96957eaaf0 100644 --- a/backend/ipp.c +++ b/backend/ipp.c @@ -1,9 +1,9 @@ /* - * "$Id: ipp.c 12759 2015-06-24 20:06:30Z msweet $" + * "$Id: ipp.c 12676 2015-05-28 01:19:14Z msweet $" * * IPP backend for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2015 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -122,6 +122,7 @@ static const char * const pattrs[] = /* Printer attributes we want */ "printer-alert", "printer-alert-description", "printer-is-accepting-jobs", + "printer-mandatory-job-attributes", "printer-state", "printer-state-message", "printer-state-reasons" @@ -145,6 +146,8 @@ static cups_option_t *attr_cache = NULL; static cups_array_t *state_reasons; /* Array of printe-state-reasons keywords */ static char tmpfilename[1024] = ""; /* Temporary spool file name */ +static char mandatory_attrs[1024] = ""; + /* cupsMandatory value */ /* @@ -1295,11 +1298,16 @@ main(int argc, /* I - Number of command-line args */ * Load the PPD file and generate PWG attribute mapping information... */ + ppd_attr_t *mandatory; /* cupsMandatory value */ + ppd = ppdOpenFile(getenv("PPD")); pc = _ppdCacheCreateWithPPD(ppd); ppdMarkDefaults(ppd); cupsMarkOptions(ppd, num_options, options); + + if ((mandatory = ppdFindAttr(ppd, "cupsMandatory", NULL)) != NULL) + strlcpy(mandatory_attrs, mandatory->value, sizeof(mandatory_attrs)); } } else @@ -1459,6 +1467,7 @@ main(int argc, /* I - Number of command-line args */ ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_AUTHORIZATION_FAILED) goto cleanup; else if (ipp_status == IPP_STATUS_ERROR_FORBIDDEN || + ipp_status == IPP_STATUS_ERROR_NOT_AUTHORIZED || ipp_status == IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED) { const char *www_auth = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE); @@ -1562,7 +1571,6 @@ main(int argc, /* I - Number of command-line args */ FD_ZERO(&input); FD_SET(fd, &input); FD_SET(snmp_fd, &input); - FD_SET(CUPS_SC_FD, &input); while (select(fd > snmp_fd ? fd + 1 : snmp_fd + 1, &input, NULL, NULL, NULL) <= 0 && !job_canceled); @@ -2018,12 +2026,8 @@ main(int argc, /* I - Number of command-line args */ remote_job_states[job_state->values[0].integer - IPP_JOB_PENDING]); - if ((job_sheets = ippFindAttribute(response, - "job-media-sheets-completed", - IPP_TAG_INTEGER)) == NULL) - job_sheets = ippFindAttribute(response, - "job-impressions-completed", - IPP_TAG_INTEGER); + if ((job_sheets = ippFindAttribute(response, "job-impressions-completed", IPP_TAG_INTEGER)) == NULL) + job_sheets = ippFindAttribute(response, "job-media-sheets-completed", IPP_TAG_INTEGER); if (job_sheets) fprintf(stderr, "PAGE: total %d\n", @@ -2460,6 +2464,8 @@ monitor_printer( new_reasons |= _CUPS_JSR_JOB_PASSWORD_WAIT; else if (!strcmp(attr->values[i].string.text, "job-release-wait")) new_reasons |= _CUPS_JSR_JOB_RELEASE_WAIT; + else if (!strncmp(attr->values[i].string.text, "job-canceled-", 13) || !strcmp(attr->values[i].string.text, "aborted-by-system")) + job_canceled = 1; } if (new_reasons != monitor->job_reasons) @@ -2560,19 +2566,10 @@ new_request( ipp_attribute_t *print_color_mode_sup) /* I - Printer supports print-color-mode */ { - int i; /* Looping var */ ipp_t *request; /* Request data */ const char *keyword; /* PWG keyword */ - _pwg_size_t *size; /* PWG media size */ - ipp_t *media_col, /* media-col value */ - *media_size; /* media-size value */ - const char *media_source, /* media-source value */ - *media_type, /* media-type value */ - *collate_str, /* multiple-document-handling value */ - *mandatory; /* Mandatory attributes */ ipp_tag_t group; /* Current group */ ipp_attribute_t *attr; /* Current attribute */ - const char *color_attr_name; /* Supported color attribute */ char buffer[1024]; /* Value buffer */ @@ -2592,36 +2589,31 @@ new_request( * Add standard attributes... */ - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, uri); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); fprintf(stderr, "DEBUG: printer-uri=\"%s\"\n", uri); if (user && *user) { - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, - "requesting-user-name", NULL, user); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, user); fprintf(stderr, "DEBUG: requesting-user-name=\"%s\"\n", user); } if (title && *title) { - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, - title); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, title); fprintf(stderr, "DEBUG: job-name=\"%s\"\n", title); } if (format && op != IPP_CREATE_JOB) { - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, - "document-format", NULL, format); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, format); fprintf(stderr, "DEBUG: document-format=\"%s\"\n", format); } #ifdef HAVE_LIBZ if (compression && op != IPP_OP_CREATE_JOB && op != IPP_OP_VALIDATE_JOB) { - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, - "compression", NULL, compression); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "compression", NULL, compression); fprintf(stderr, "DEBUG: compression=\"%s\"\n", compression); } #endif /* HAVE_LIBZ */ @@ -2634,313 +2626,13 @@ new_request( { if (pc) { - int num_finishings = 0, /* Number of finishing values */ - finishings[10]; /* Finishing enum values */ - ppd_choice_t *choice; /* Marked choice */ - /* * Send standard IPP attributes... */ fputs("DEBUG: Adding standard IPP operation/job attributes.\n", stderr); - if (pc->password && - (keyword = cupsGetOption("job-password", num_options, - options)) != NULL) - { - ippAddOctetString(request, IPP_TAG_OPERATION, "job-password", keyword, (int)strlen(keyword)); - - if ((keyword = cupsGetOption("job-password-encryption", num_options, - options)) == NULL) - keyword = "none"; - - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, - "job-password-encryption", NULL, keyword); - } - - if (pc->account_id) - { - if ((keyword = cupsGetOption("job-account-id", num_options, - options)) == NULL) - keyword = cupsGetOption("job-billing", num_options, options); - - if (keyword) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_NAME, "job-account-id", - NULL, keyword); - } - - if (pc->accounting_user_id) - { - if ((keyword = cupsGetOption("job-accounting-user-id", num_options, - options)) == NULL) - keyword = user; - - if (keyword) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_NAME, - "job-accounting-user-id", NULL, keyword); - } - - for (mandatory = (char *)cupsArrayFirst(pc->mandatory); - mandatory; - mandatory = (char *)cupsArrayNext(pc->mandatory)) - { - if (strcmp(mandatory, "copies") && - strcmp(mandatory, "destination-uris") && - strcmp(mandatory, "finishings") && - strcmp(mandatory, "job-account-id") && - strcmp(mandatory, "job-accounting-user-id") && - strcmp(mandatory, "job-password") && - strcmp(mandatory, "job-password-encryption") && - strcmp(mandatory, "media") && - strncmp(mandatory, "media-col", 9) && - strcmp(mandatory, "multiple-document-handling") && - strcmp(mandatory, "output-bin") && - strcmp(mandatory, "print-color-mode") && - strcmp(mandatory, "print-quality") && - strcmp(mandatory, "sides") && - (keyword = cupsGetOption(mandatory, num_options, options)) != NULL) - { - _ipp_option_t *opt = _ippFindOption(mandatory); - /* Option type */ - ipp_tag_t value_tag = opt ? opt->value_tag : IPP_TAG_NAME; - /* Value type */ - - switch (value_tag) - { - case IPP_TAG_INTEGER : - case IPP_TAG_ENUM : - ippAddInteger(request, IPP_TAG_JOB, value_tag, mandatory, - atoi(keyword)); - break; - case IPP_TAG_BOOLEAN : - ippAddBoolean(request, IPP_TAG_JOB, mandatory, - !_cups_strcasecmp(keyword, "true")); - break; - case IPP_TAG_RANGE : - { - int lower, upper; /* Range */ - - if (sscanf(keyword, "%d-%d", &lower, &upper) != 2) - lower = upper = atoi(keyword); - - ippAddRange(request, IPP_TAG_JOB, mandatory, lower, upper); - } - break; - case IPP_TAG_STRING : - ippAddOctetString(request, IPP_TAG_JOB, mandatory, keyword, (int)strlen(keyword)); - break; - default : - if (!strcmp(mandatory, "print-color-mode") && !strcmp(keyword, "monochrome")) - { - if (ippContainsString(print_color_mode_sup, "auto-monochrome")) - keyword = "auto-monochrome"; - else if (ippContainsString(print_color_mode_sup, "process-monochrome") && !ippContainsString(print_color_mode_sup, "monochrome")) - keyword = "process-monochrome"; - } - - ippAddString(request, IPP_TAG_JOB, value_tag, mandatory, - NULL, keyword); - break; - } - } - } - - if ((keyword = cupsGetOption("PageSize", num_options, options)) == NULL) - keyword = cupsGetOption("media", num_options, options); - - if ((size = _ppdCacheGetSize(pc, keyword)) != NULL) - { - /* - * Add a media-col value... - */ - - media_size = ippNew(); - ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, - "x-dimension", size->width); - ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, - "y-dimension", size->length); - - media_col = ippNew(); - ippAddCollection(media_col, IPP_TAG_ZERO, "media-size", media_size); - - media_source = _ppdCacheGetSource(pc, cupsGetOption("InputSlot", - num_options, - options)); - media_type = _ppdCacheGetType(pc, cupsGetOption("MediaType", - num_options, - options)); - - for (i = 0; i < media_col_sup->num_values; i ++) - { - if (!strcmp(media_col_sup->values[i].string.text, - "media-left-margin")) - ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, - "media-left-margin", size->left); - else if (!strcmp(media_col_sup->values[i].string.text, - "media-bottom-margin")) - ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, - "media-bottom-margin", size->bottom); - else if (!strcmp(media_col_sup->values[i].string.text, - "media-right-margin")) - ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, - "media-right-margin", size->right); - else if (!strcmp(media_col_sup->values[i].string.text, - "media-top-margin")) - ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, - "media-top-margin", size->top); - else if (!strcmp(media_col_sup->values[i].string.text, - "media-source") && media_source) - ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, - "media-source", NULL, media_source); - else if (!strcmp(media_col_sup->values[i].string.text, - "media-type") && media_type) - ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, - "media-type", NULL, media_type); - } - - ippAddCollection(request, IPP_TAG_JOB, "media-col", media_col); - } - - if ((keyword = cupsGetOption("output-bin", num_options, - options)) == NULL) - { - if ((choice = ppdFindMarkedChoice(ppd, "OutputBin")) != NULL) - keyword = _ppdCacheGetBin(pc, choice->choice); - } - - if (keyword) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-bin", - NULL, keyword); - - color_attr_name = print_color_mode_sup ? "print-color-mode" : "output-mode"; - - if ((keyword = cupsGetOption("print-color-mode", num_options, - options)) == NULL) - { - if ((choice = ppdFindMarkedChoice(ppd, "ColorModel")) != NULL) - { - if (!_cups_strcasecmp(choice->choice, "Gray")) - keyword = "monochrome"; - else - keyword = "color"; - } - } - - if (keyword && !strcmp(keyword, "monochrome")) - { - if (ippContainsString(print_color_mode_sup, "auto-monochrome")) - keyword = "auto-monochrome"; - else if (ippContainsString(print_color_mode_sup, "process-monochrome") && !ippContainsString(print_color_mode_sup, "monochrome")) - keyword = "process-monochrome"; - } - - if (keyword) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, color_attr_name, - NULL, keyword); - - if ((keyword = cupsGetOption("print-quality", num_options, - options)) != NULL) - ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", - atoi(keyword)); - else if ((choice = ppdFindMarkedChoice(ppd, "cupsPrintQuality")) != NULL) - { - if (!_cups_strcasecmp(choice->choice, "draft")) - ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", - IPP_QUALITY_DRAFT); - else if (!_cups_strcasecmp(choice->choice, "normal")) - ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", - IPP_QUALITY_NORMAL); - else if (!_cups_strcasecmp(choice->choice, "high")) - ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", - IPP_QUALITY_HIGH); - } - - if ((keyword = cupsGetOption("sides", num_options, options)) != NULL) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", - NULL, keyword); - else if (pc->sides_option && - (choice = ppdFindMarkedChoice(ppd, pc->sides_option)) != NULL) - { - if (!_cups_strcasecmp(choice->choice, pc->sides_1sided)) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", - NULL, "one-sided"); - else if (!_cups_strcasecmp(choice->choice, pc->sides_2sided_long)) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", - NULL, "two-sided-long-edge"); - if (!_cups_strcasecmp(choice->choice, pc->sides_2sided_short)) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", - NULL, "two-sided-short-edge"); - } - - if ((keyword = cupsGetOption("multiple-document-handling", - num_options, options)) != NULL) - { - if (strstr(keyword, "uncollated")) - keyword = "false"; - else - keyword = "true"; - } - else if ((keyword = cupsGetOption("collate", num_options, - options)) == NULL) - keyword = "true"; - - if (format) - { - if (!_cups_strcasecmp(format, "image/gif") || - !_cups_strcasecmp(format, "image/jp2") || - !_cups_strcasecmp(format, "image/jpeg") || - !_cups_strcasecmp(format, "image/png") || - !_cups_strcasecmp(format, "image/tiff") || - !_cups_strncasecmp(format, "image/x-", 8)) - { - /* - * Collation makes no sense for single page image formats... - */ - - keyword = "false"; - } - else if (!_cups_strncasecmp(format, "image/", 6) || - !_cups_strcasecmp(format, "application/vnd.cups-raster")) - { - /* - * Multi-page image formats will have copies applied by the upstream - * filters... - */ - - copies = 1; - } - } - - if (doc_handling_sup) - { - if (!_cups_strcasecmp(keyword, "true")) - collate_str = "separate-documents-collated-copies"; - else - collate_str = "separate-documents-uncollated-copies"; - - for (i = 0; i < doc_handling_sup->num_values; i ++) - if (!strcmp(doc_handling_sup->values[i].string.text, collate_str)) - { - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "multiple-document-handling", NULL, collate_str); - break; - } - - if (i >= doc_handling_sup->num_values) - copies = 1; - } - - /* - * Map finishing options... - */ - - num_finishings = _ppdCacheGetFinishingValues(pc, num_options, options, - (int)(sizeof(finishings) / - sizeof(finishings[0])), - finishings); - if (num_finishings > 0) - ippAddIntegers(request, IPP_TAG_JOB, IPP_TAG_ENUM, "finishings", - num_finishings, finishings); + copies = _cupsConvertOptions(request, ppd, pc, media_col_sup, doc_handling_sup, print_color_mode_sup, user, format, copies, num_options, options); /* * Map FaxOut options... @@ -3222,6 +2914,7 @@ report_printer_state(ipp_t *ipp) /* I - IPP response */ { ipp_attribute_t *pa, /* printer-alert */ *pam, /* printer-alert-message */ + *pmja, /* printer-mandatory-job-attributes */ *psm, /* printer-state-message */ *reasons, /* printer-state-reasons */ *marker; /* marker-* attributes */ @@ -3242,6 +2935,26 @@ report_printer_state(ipp_t *ipp) /* I - IPP response */ IPP_TAG_TEXT)) != NULL) report_attr(pam); + if ((pmja = ippFindAttribute(ipp, "printer-mandatory-job-attributes", IPP_TAG_KEYWORD)) != NULL) + { + int i, /* Looping var */ + count = ippGetCount(pmja); /* Number of values */ + + for (i = 0, valptr = value; i < count; i ++, valptr += strlen(valptr)) + { + if (i) + snprintf(valptr, sizeof(value) - (size_t)(valptr - value), " %s", ippGetString(pmja, i, NULL)); + else + strlcpy(value, ippGetString(pmja, i, NULL), sizeof(value)); + } + + if (strcmp(value, mandatory_attrs)) + { + strlcpy(mandatory_attrs, value, sizeof(mandatory_attrs)); + fprintf(stderr, "PPD: cupsMandatory=\"%s\"\n", value); + } + } + if ((psm = ippFindAttribute(ipp, "printer-state-message", IPP_TAG_TEXT)) != NULL) { @@ -3770,5 +3483,5 @@ update_reasons(ipp_attribute_t *attr, /* I - printer-state-reasons or NULL */ } /* - * End of "$Id: ipp.c 12759 2015-06-24 20:06:30Z msweet $". + * End of "$Id: ipp.c 12676 2015-05-28 01:19:14Z msweet $". */ diff --git a/backend/snmp-supplies.c b/backend/snmp-supplies.c index 93d0ff114f..38ef28e93a 100644 --- a/backend/snmp-supplies.c +++ b/backend/snmp-supplies.c @@ -1,5 +1,5 @@ /* - * "$Id: snmp-supplies.c 12228 2014-10-21 13:42:05Z msweet $" + * "$Id: snmp-supplies.c 12227 2014-10-21 13:42:04Z msweet $" * * SNMP supplies functions for CUPS. * @@ -1098,5 +1098,5 @@ utf16_to_utf8( /* - * End of "$Id: snmp-supplies.c 12228 2014-10-21 13:42:05Z msweet $". + * End of "$Id: snmp-supplies.c 12227 2014-10-21 13:42:04Z msweet $". */ diff --git a/backend/usb-darwin.c b/backend/usb-darwin.c index cc85f885f2..d9dbde3353 100644 --- a/backend/usb-darwin.c +++ b/backend/usb-darwin.c @@ -1,5 +1,5 @@ /* - * "$Id: usb-darwin.c 12529 2015-02-23 18:57:57Z msweet $" + * "$Id: usb-darwin.c 12672 2015-05-28 00:10:27Z msweet $" * * Copyright 2005-2014 Apple Inc. All rights reserved. * @@ -302,8 +302,8 @@ static void parse_pserror (char *sockBuffer, int len); static IOUSBInterfaceInterface220 **usb_interface220_for_service(io_service_t usbClass); static IOUSBDeviceInterface **usb_device_interface_for_device(io_service_t usbDevice); -static CFStringRef printer_interface_deviceid(IOUSBInterfaceInterface220 **printer, UInt8 alternateSetting); -static CFStringRef printer_interface_indexed_description(IOUSBInterfaceInterface220 ** printer, UInt8 index, UInt16 language); +static CFStringRef copy_printer_interface_deviceid(IOUSBInterfaceInterface220 **printer, UInt8 alternateSetting); +static CFStringRef copy_printer_interface_indexed_description(IOUSBInterfaceInterface220 ** printer, UInt8 index, UInt16 language); static CFStringRef deviceIDCopyManufacturer(CFStringRef deviceID); static CFStringRef deviceIDCopyModel(CFStringRef deviceID); static CFStringRef deviceIDCopySerialNumber(CFStringRef deviceID); @@ -1099,17 +1099,17 @@ sidechannel_thread(void *reference) static void iterate_printers(iterator_callback_t callBack, void *userdata) { Iterating = 1; - + mach_port_t masterPort = 0x0; kern_return_t kr = IOMasterPort (bootstrap_port, &masterPort); - + if (kr == kIOReturnSuccess && masterPort != 0x0) { iterator_reference_t reference = { callBack, userdata, true }; - + IONotificationPortRef addNotification = IONotificationPortCreate(masterPort); io_iterator_t addIterator = IO_OBJECT_NULL; - + kr = IOServiceAddMatchingNotification(addNotification, kIOFirstMatchNotification, IOServiceMatching(kIOUSBDeviceClassName), &device_added, &reference, &addIterator); if (kr == kIOReturnSuccess && addIterator != IO_OBJECT_NULL) @@ -1124,7 +1124,7 @@ static void iterate_printers(iterator_callback_t callBack, void *userdata) } mach_port_deallocate(mach_task_self(), masterPort); } - + Iterating = 0; } @@ -1138,7 +1138,7 @@ static void device_added(void *userdata, io_iterator_t iterator) { iterator_reference_t *reference = userdata; io_service_t device; - + while (reference->keepRunning && (device = IOIteratorNext(iterator)) != 0x0) { UInt32 locationID = 0; @@ -1175,7 +1175,7 @@ static void device_added(void *userdata, io_iterator_t iterator) if (IsPrintingInterface(intfClass, intfSubclass, intfProtocol)) { - CFStringRef deviceIDString = printer_interface_deviceid(intf220, 0); + CFStringRef deviceIDString = copy_printer_interface_deviceid(intf220, 0); if (deviceIDString != NULL) { reference->keepRunning = reference->callback(userdata, intf, deviceIDString, locationID, intfNumber, 0); @@ -1183,7 +1183,7 @@ static void device_added(void *userdata, io_iterator_t iterator) } } - IOUSBInterfaceDescriptor *intfDesc = nil; + IOUSBInterfaceDescriptor *intfDesc = NULL; while (reference->keepRunning && (intfDesc = (IOUSBInterfaceDescriptor *)(*intf220)->FindNextAssociatedDescriptor(intf220, intfDesc, kUSBInterfaceDesc))) { intfClass = intfDesc->bInterfaceClass; @@ -1192,7 +1192,7 @@ static void device_added(void *userdata, io_iterator_t iterator) if ((IsPrintingInterface(intfClass, intfSubclass, intfProtocol))) { - CFStringRef deviceIDString = printer_interface_deviceid(intf220, intfDesc->bAlternateSetting); + CFStringRef deviceIDString = copy_printer_interface_deviceid(intf220, intfDesc->bAlternateSetting); if (deviceIDString != NULL) { reference->keepRunning = reference->callback(userdata, intf, deviceIDString, locationID, intfNumber, intfDesc->bAlternateSetting); @@ -1202,6 +1202,7 @@ static void device_added(void *userdata, io_iterator_t iterator) } (*intf220)->Release(intf220); } + IOObjectRelease(intf); } device_added_done: @@ -1210,12 +1211,12 @@ static void device_added(void *userdata, io_iterator_t iterator) IOObjectRelease(device); } - + /* One last call to the call back now that we are not longer have printers left to iterate... */ if (reference->keepRunning && reference->callback) reference->keepRunning = reference->callback(reference->userdata, IO_OBJECT_NULL, NULL, 0, 0, 0); - + if (!reference->keepRunning) CFRunLoopStop(CFRunLoopGetCurrent()); } @@ -1226,42 +1227,47 @@ static void device_added(void *userdata, io_iterator_t iterator) static Boolean list_device_cb(void *refcon, io_service_t obj, CFStringRef deviceIDString, UInt32 deviceLocation, UInt8 interfaceNum, UInt8 alternateSetting) { + (void)refcon; (void)interfaceNum; (void)alternateSetting; if (obj != IO_OBJECT_NULL) { - CFStringRef make = NULL; - CFStringRef model = NULL; - CFStringRef serial = NULL; - + CFStringRef make = deviceIDCopyManufacturer(deviceIDString); + CFStringRef model = deviceIDCopyModel(deviceIDString); + CFStringRef serial = deviceIDCopySerialNumber(deviceIDString); + char uristr[1024], makestr[1024], modelstr[1024], serialstr[1024]; char optionsstr[1024], idstr[1024], make_modelstr[1024]; - + CFStringGetCString(deviceIDString, idstr, sizeof(idstr), kCFStringEncodingUTF8); backendGetMakeModel(idstr, make_modelstr, sizeof(make_modelstr)); - + modelstr[0] = '/'; - + if (make == NULL || !CFStringGetCString(make, makestr, sizeof(makestr), kCFStringEncodingUTF8)) strlcpy(makestr, "Unknown", sizeof(makestr)); - + if (model == NULL || !CFStringGetCString(model, &modelstr[1], sizeof(modelstr)-1, kCFStringEncodingUTF8)) strlcpy(modelstr + 1, "Printer", sizeof(modelstr) - 1); - + optionsstr[0] = '\0'; if (serial != NULL && CFStringGetCString(serial, serialstr, sizeof(serialstr), kCFStringEncodingUTF8)) snprintf(optionsstr, sizeof(optionsstr), "?serial=%s", serialstr); else if (deviceLocation != 0) snprintf(optionsstr, sizeof(optionsstr), "?location=%x", (unsigned)deviceLocation); - + httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr); strlcat(uristr, optionsstr, sizeof(uristr)); - + cupsBackendReport("direct", uristr, make_modelstr, make_modelstr, idstr, NULL); - } + if (make != NULL) CFRelease(make); + if (model != NULL) CFRelease(model); + if (serial != NULL) CFRelease(serial); + } + return obj != IO_OBJECT_NULL; } @@ -1271,13 +1277,13 @@ static Boolean list_device_cb(void *refcon, io_service_t obj, CFStringRef device static Boolean find_device_cb(void *refcon, io_service_t obj, CFStringRef deviceIDString, UInt32 deviceLocation, UInt8 interfaceNum, UInt8 alternateSetting) { Boolean keepLooking = true; - + if (obj != IO_OBJECT_NULL) { CFStringRef make = deviceIDCopyManufacturer(deviceIDString); CFStringRef model = deviceIDCopyModel(deviceIDString); CFStringRef serial = deviceIDCopySerialNumber(deviceIDString); - + if (make && CFStringCompare(make, g.make, kCFCompareCaseInsensitive) == kCFCompareEqualTo) { if (model && CFStringCompare(model, g.model, kCFCompareCaseInsensitive) == kCFCompareEqualTo) @@ -1288,6 +1294,7 @@ static Boolean find_device_cb(void *refcon, io_service_t obj, CFStringRef device { IOObjectRetain(obj); g.printer_obj = obj; + g.location = deviceLocation; g.alternateSetting = alternateSetting; keepLooking = false; } @@ -1296,20 +1303,20 @@ static Boolean find_device_cb(void *refcon, io_service_t obj, CFStringRef device { if (g.printer_obj != 0) IOObjectRelease(g.printer_obj); - + g.alternateSetting = alternateSetting; g.printer_obj = obj; IOObjectRetain(obj); - + if (g.location == 0 || g.location == deviceLocation) keepLooking = false; } - + if ( !keepLooking ) g.interfaceNum = interfaceNum; } } - + if (make) CFRelease(make); if (model) CFRelease(model); if (serial) CFRelease(serial); @@ -1328,7 +1335,7 @@ static Boolean find_device_cb(void *refcon, io_service_t obj, CFStringRef device } } } - + if (!keepLooking && g.status_timer != NULL) { fputs("STATE: -offline-report\n", stderr); @@ -1337,14 +1344,14 @@ static Boolean find_device_cb(void *refcon, io_service_t obj, CFStringRef device CFRelease(g.status_timer); g.status_timer = NULL; } - + return keepLooking; } static CFStringRef deviceIDCopySerialNumber(CFStringRef deviceID) { CFStringRef serialKeys[] = { CFSTR("SN:"), CFSTR("SERN:"), NULL }; - + return copy_value_for_key(deviceID, serialKeys); } @@ -1554,7 +1561,7 @@ static IOUSBDeviceInterface **usb_device_interface_for_device(io_service_t usbDe } -static CFStringRef printer_interface_deviceid(IOUSBInterfaceInterface220 **printer, UInt8 alternateSetting) +static CFStringRef copy_printer_interface_deviceid(IOUSBInterfaceInterface220 **printer, UInt8 alternateSetting) { // I have tried to make this function as neat as I can, but the possibility of needing to resend // a request to get the entire string makes it hideous... @@ -1568,8 +1575,8 @@ static CFStringRef printer_interface_deviceid(IOUSBInterfaceInterface220 **print #define kDefaultNoDataTimeout 5000L #define pack_device_id_wIndex(intf, alt) ((UInt16)((((UInt16)(intf)) << 8) | ((UInt8)(alt)))) - if (printer == nil) - return nil; + if (printer == NULL) + return NULL; IOReturn err = kIOReturnError; @@ -1591,15 +1598,15 @@ static CFStringRef printer_interface_deviceid(IOUSBInterfaceInterface220 **print request.pData = NULL; } - IOReturn err = kIOReturnError; + IOReturn berr = kIOReturnError; char *buffer = malloc(size); if (buffer == NULL) return kIOReturnNoMemory; request.wLength = HostToUSBWord(size); request.pData = buffer; - err = (*printer)->ControlRequestTO(printer, (UInt8)0, &request); - return err; + berr = (*printer)->ControlRequestTO(printer, (UInt8)0, &request); + return berr; }; /* This request takes the 0 based configuration index. IOKit returns a 1 based configuration index */ @@ -1639,7 +1646,7 @@ static CFStringRef printer_interface_deviceid(IOUSBInterfaceInterface220 **print } CFStringRef manufacturer = deviceIDCopyManufacturer(ret); - CFStringRef model = deviceIDCopyManufacturer(ret); + CFStringRef model = deviceIDCopyModel(ret); CFStringRef serial = deviceIDCopySerialNumber(ret); if (manufacturer == NULL || serial == NULL || model == NULL) @@ -1664,22 +1671,22 @@ static CFStringRef printer_interface_deviceid(IOUSBInterfaceInterface220 **print CFMutableStringRef extras = CFStringCreateMutable(NULL, 0); if (manufacturer == NULL) { - manufacturer = printer_interface_indexed_description(printer, desc.iManufacturer, kUSBLanguageEnglish); - if (CFStringGetLength(manufacturer) > 0) + manufacturer = copy_printer_interface_indexed_description(printer, desc.iManufacturer, kUSBLanguageEnglish); + if (manufacturer && CFStringGetLength(manufacturer) > 0) CFStringAppendFormat(extras, NULL, CFSTR("MFG:%@;"), manufacturer); } if (model == NULL) { - model = printer_interface_indexed_description(printer, desc.iProduct, kUSBLanguageEnglish); - if (CFStringGetLength(model) > 0) - CFStringAppendFormat(extras, NULL, CFSTR("MDL:%@;"), manufacturer); + model = copy_printer_interface_indexed_description(printer, desc.iProduct, kUSBLanguageEnglish); + if (model && CFStringGetLength(model) > 0) + CFStringAppendFormat(extras, NULL, CFSTR("MDL:%@;"), model); } if (serial == NULL && desc.iSerialNumber != 0) { - serial = printer_interface_indexed_description(printer, desc.iSerialNumber, kUSBLanguageEnglish); - if (CFStringGetLength(serial) > 0) + serial = copy_printer_interface_indexed_description(printer, desc.iSerialNumber, kUSBLanguageEnglish); + if (serial && CFStringGetLength(serial) > 0) CFStringAppendFormat(extras, NULL, CFSTR("SERN:%@;"), serial); } @@ -1697,14 +1704,8 @@ static CFStringRef printer_interface_deviceid(IOUSBInterfaceInterface220 **print } } - if (manufacturer != NULL) - CFRelease(manufacturer); - if (model != NULL) - CFRelease(model); - if (serial != NULL) - CFRelease(serial); - - + if (ret != NULL) + { /* Remove special characters from the serial number */ CFRange range = (serial != NULL ? CFStringFind(serial, CFSTR("+"), 0) : CFRangeMake(0, 0)); if (range.length == 1) @@ -1717,11 +1718,27 @@ static CFStringRef printer_interface_deviceid(IOUSBInterfaceInterface220 **print ret = deviceIDString; CFStringFindAndReplace(deviceIDString, CFSTR("+"), CFSTR(""), range, 0); } + } + + if (manufacturer != NULL) + CFRelease(manufacturer); + + if (model != NULL) + CFRelease(model); + + if (serial != NULL) + CFRelease(serial); - return (CFStringGetLength(ret) > 0 ? ret : nil); + if (ret != NULL && CFStringGetLength(ret) == 0) + { + CFRelease(ret); + return NULL; + } + + return ret; } -static CFStringRef printer_interface_indexed_description(IOUSBInterfaceInterface220 ** printer, UInt8 index, UInt16 language) +static CFStringRef copy_printer_interface_indexed_description(IOUSBInterfaceInterface220 ** printer, UInt8 index, UInt16 language) { IOReturn err; UInt8 description[256]; // Max possible descriptor length @@ -1759,7 +1776,7 @@ static CFStringRef printer_interface_indexed_description(IOUSBInterfaceInterface err = (*printer)->ControlRequestTO(printer, 0, &request); if (err != kIOReturnSuccess && err != kIOReturnUnderrun) - return nil; + return NULL; } unsigned int length = description[0]; @@ -1775,17 +1792,17 @@ static CFStringRef printer_interface_indexed_description(IOUSBInterfaceInterface request.wIndex = language; bzero(description, length); - request.wLength = length; + request.wLength = (UInt16)length; request.pData = &description; request.completionTimeout = 0; request.noDataTimeout = 60L; err = (*printer)->ControlRequestTO(printer, 0, &request); if (err != kIOReturnSuccess) - return nil; + return NULL; if (description[1] != kUSBStringDesc) - return nil; + return NULL; if ((description[0] & 1) != 0) description[0] &= 0xfe; @@ -1799,7 +1816,7 @@ static CFStringRef printer_interface_indexed_description(IOUSBInterfaceInterface if (length > maxLength - 1) length = maxLength -1; - for (int i = 0; i < length; i++) + for (unsigned i = 0; i < length; i++) buffer[i] = (char) description[2*i+2]; buffer[length] = 0; @@ -2446,7 +2463,7 @@ static void get_device_id(cups_sc_status_t *status, IOUSBInterfaceInterface220 **intf220 = usb_interface220_for_service(g.printer_obj); if (intf220) { - deviceIDString = printer_interface_deviceid(intf220, g.alternateSetting); + deviceIDString = copy_printer_interface_deviceid(intf220, g.alternateSetting); (*intf220)->Release(intf220); } } @@ -2458,7 +2475,7 @@ static void get_device_id(cups_sc_status_t *status, *datalen = (int)strlen(data); else *datalen = 0; - + CFRelease(deviceIDString); } else @@ -2497,5 +2514,5 @@ log_usb_class_driver(int is_64bit) /* I - Is the USB class driver 64-bit? */ /* - * End of "$Id: usb-darwin.c 12529 2015-02-23 18:57:57Z msweet $". + * End of "$Id: usb-darwin.c 12672 2015-05-28 00:10:27Z msweet $". */ diff --git a/backend/usb-libusb.c b/backend/usb-libusb.c index bab2bc5885..4d13a2a933 100644 --- a/backend/usb-libusb.c +++ b/backend/usb-libusb.c @@ -1,5 +1,5 @@ /* - * "$Id: usb-libusb.c 12349 2014-12-09 22:10:52Z msweet $" + * "$Id: usb-libusb.c 12348 2014-12-09 22:10:45Z msweet $" * * LIBUSB interface code for CUPS. * @@ -2004,6 +2004,6 @@ soft_reset_printer( /* - * End of "$Id: usb-libusb.c 12349 2014-12-09 22:10:52Z msweet $". + * End of "$Id: usb-libusb.c 12348 2014-12-09 22:10:45Z msweet $". */ diff --git a/cgi-bin/Makefile b/cgi-bin/Makefile index 342a8a53df..898fb7bf50 100644 --- a/cgi-bin/Makefile +++ b/cgi-bin/Makefile @@ -1,5 +1,5 @@ # -# "$Id: Makefile 11777 2014-03-28 19:18:10Z msweet $" +# "$Id: Makefile 12519 2015-02-17 13:10:19Z msweet $" # # CGI makefile for CUPS. # @@ -353,5 +353,5 @@ include Dependencies # -# End of "$Id: Makefile 11777 2014-03-28 19:18:10Z msweet $". +# End of "$Id: Makefile 12519 2015-02-17 13:10:19Z msweet $". # diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c index 9de2424c3c..29ae5c8daa 100644 --- a/cgi-bin/admin.c +++ b/cgi-bin/admin.c @@ -1,9 +1,9 @@ /* - * "$Id: admin.c 12123 2014-08-28 14:24:45Z msweet $" + * "$Id: admin.c 12516 2015-02-12 20:18:11Z msweet $" * * Administration CGI for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2015 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -18,6 +18,8 @@ */ #include "cgi-private.h" +#include +#include #include #include #include @@ -38,12 +40,7 @@ static int current_device = 0; /* Current device shown */ * Local functions... */ -static void choose_device_cb(const char *device_class, - const char *device_id, const char *device_info, - const char *device_make_and_model, - const char *device_uri, - const char *device_location, - const char *title); +static void choose_device_cb(const char *device_class, const char *device_id, const char *device_info, const char *device_make_and_model, const char *device_uri, const char *device_location, const char *title); static void do_add_rss_subscription(http_t *http); static void do_am_class(http_t *http, int modify); static void do_am_printer(http_t *http, int modify); @@ -61,6 +58,7 @@ static void do_set_sharing(http_t *http); static char *get_option_value(ppd_file_t *ppd, const char *name, char *buffer, size_t bufsize); static double get_points(double number, const char *uval); +static char *get_printer_ppd(const char *uri, char *buffer, size_t bufsize); /* @@ -832,7 +830,8 @@ do_am_printer(http_t *http, /* I - HTTP connection */ const cgi_file_t *file; /* Uploaded file, if any */ const char *var; /* CGI variable */ char uri[HTTP_MAX_URI], /* Device or printer URI */ - *uriptr; /* Pointer into URI */ + *uriptr, /* Pointer into URI */ + evefile[1024] = ""; /* IPP Everywhere PPD file */ int maxrate; /* Maximum baud rate */ char baudrate[255]; /* Baud rate string */ const char *name, /* Pointer to class name */ @@ -1331,7 +1330,9 @@ do_am_printer(http_t *http, /* I - HTTP connection */ if (!file) { var = cgiGetVariable("PPD_NAME"); - if (strcmp(var, "__no_change__")) + if (!strcmp(var, "everywhere")) + get_printer_ppd(cgiGetVariable("DEVICE_URI"), evefile, sizeof(evefile)); + else if (strcmp(var, "__no_change__")) ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", NULL, var); } @@ -1384,6 +1385,11 @@ do_am_printer(http_t *http, /* I - HTTP connection */ if (file) ippDelete(cupsDoFileRequest(http, request, "/admin/", file->tempfile)); + else if (evefile[0]) + { + ippDelete(cupsDoFileRequest(http, request, "/admin/", evefile)); + unlink(evefile); + } else ippDelete(cupsDoRequest(http, request, "/admin/")); @@ -4198,5 +4204,78 @@ get_points(double number, /* I - Original number */ /* - * End of "$Id: admin.c 12123 2014-08-28 14:24:45Z msweet $". + * 'get_printer_ppd()' - Get an IPP Everywhere PPD file for the given URI. + */ + +static char * /* O - Filename or NULL */ +get_printer_ppd(const char *uri, /* I - Printer URI */ + char *buffer, /* I - Filename buffer */ + size_t bufsize) /* I - Size of filename buffer */ +{ + http_t *http; /* Connection to printer */ + ipp_t *request, /* Get-Printer-Attributes request */ + *response; /* Get-Printer-Attributes response */ + char resolved[1024], /* Resolved URI */ + scheme[32], /* URI scheme */ + userpass[256], /* Username:password */ + host[256], /* Hostname */ + resource[256]; /* Resource path */ + int port; /* Port number */ + + + /* + * Connect to the printer... + */ + + if (strstr(uri, "._tcp")) + { + /* + * Resolve URI... + */ + + if (!_httpResolveURI(uri, resolved, sizeof(resolved), _HTTP_RESOLVE_DEFAULT, NULL, NULL)) + { + fprintf(stderr, "ERROR: Unable to resolve \"%s\".\n", uri); + return (NULL); + } + + uri = resolved; + } + + if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) + { + fprintf(stderr, "ERROR: Bad printer URI \"%s\".\n", uri); + return (NULL); + } + + http = httpConnect2(host, port, NULL, AF_UNSPEC, !strcmp(scheme, "ipps") ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL); + if (!http) + { + fprintf(stderr, "ERROR: Unable to connect to \"%s:%d\": %s\n", host, port, cupsLastErrorString()); + return (NULL); + } + + /* + * Send a Get-Printer-Attributes request... + */ + + request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); + response = cupsDoRequest(http, request, resource); + + if (!_ppdCreateFromIPP(buffer, bufsize, response)) + fprintf(stderr, "ERROR: Unable to create PPD file: %s\n", strerror(errno)); + + ippDelete(response); + httpClose(http); + + if (buffer[0]) + return (buffer); + else + return (NULL); +} + + +/* + * End of "$Id: admin.c 12516 2015-02-12 20:18:11Z msweet $". */ diff --git a/cgi-bin/help-index.c b/cgi-bin/help-index.c index cda5e966c7..d467cb6b03 100644 --- a/cgi-bin/help-index.c +++ b/cgi-bin/help-index.c @@ -1,9 +1,9 @@ /* - * "$Id: help-index.c 12344 2014-12-09 21:36:11Z msweet $" + * "$Id: help-index.c 12644 2015-05-19 21:22:35Z msweet $" * * Online help index routines for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2015 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -1220,7 +1220,7 @@ help_new_node(const char *filename, /* I - Filename */ n->filename = strdup(filename); n->anchor = anchor ? strdup(anchor) : NULL; - n->section = (section && *section) ? strdup(section) : NULL; + n->section = *section ? strdup(section) : NULL; n->text = strdup(text); n->mtime = mtime; n->offset = offset; @@ -1306,5 +1306,5 @@ help_sort_words(help_word_t *w1, /* I - Second word */ /* - * End of "$Id: help-index.c 12344 2014-12-09 21:36:11Z msweet $". + * End of "$Id: help-index.c 12644 2015-05-19 21:22:35Z msweet $". */ diff --git a/cgi-bin/ipp-var.c b/cgi-bin/ipp-var.c index 98300537c4..f99ee41d80 100644 --- a/cgi-bin/ipp-var.c +++ b/cgi-bin/ipp-var.c @@ -1,5 +1,5 @@ /* - * "$Id: ipp-var.c 12769 2015-06-30 16:13:48Z msweet $" + * "$Id: ipp-var.c 12700 2015-06-08 18:32:35Z msweet $" * * CGI <-> IPP variable routines for CUPS. * @@ -222,9 +222,6 @@ cgiGetIPPObjects(ipp_t *response, /* I - IPP response */ break; case IPP_TAG_INTEGER : - if (!strncmp(ippGetName(attr), "time-at-", 8)) - break; /* Ignore time-at-xxx */ - for (i = 0; !add && i < attr->num_values; i ++) { char buf[255]; /* Number buffer */ @@ -1550,5 +1547,5 @@ cgiText(const char *message) /* I - Message */ /* - * End of "$Id: ipp-var.c 12769 2015-06-30 16:13:48Z msweet $". + * End of "$Id: ipp-var.c 12700 2015-06-08 18:32:35Z msweet $". */ diff --git a/cgi-bin/template.c b/cgi-bin/template.c index fefc489ff9..426e635e6e 100644 --- a/cgi-bin/template.c +++ b/cgi-bin/template.c @@ -1,5 +1,5 @@ /* - * "$Id: template.c 12701 2015-06-08 18:33:44Z msweet $" + * "$Id: template.c 12700 2015-06-08 18:32:35Z msweet $" * * CGI template function. * @@ -686,5 +686,5 @@ cgi_puturi(const char *s, /* I - String to output */ /* - * End of "$Id: template.c 12701 2015-06-08 18:33:44Z msweet $". + * End of "$Id: template.c 12700 2015-06-08 18:32:35Z msweet $". */ diff --git a/cgi-bin/var.c b/cgi-bin/var.c index dc06cbc4c5..017de1eeb3 100644 --- a/cgi-bin/var.c +++ b/cgi-bin/var.c @@ -1,9 +1,9 @@ /* - * "$Id: var.c 12034 2014-07-16 19:37:34Z msweet $" + * "$Id: var.c 12621 2015-05-06 21:32:18Z msweet $" * * CGI form variable and array functions for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2015 by Apple Inc. * Copyright 1997-2005 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -626,6 +626,8 @@ cgi_initialize_cookies(void) while (*cookie) { + int skip = 0; /* Skip this cookie? */ + /* * Skip leading whitespace... */ @@ -641,9 +643,14 @@ cgi_initialize_cookies(void) for (ptr = name; *cookie && *cookie != '=';) if (ptr < (name + sizeof(name) - 1)) + { *ptr++ = *cookie++; + } else - break; + { + skip = 1; + cookie ++; + } if (*cookie != '=') break; @@ -659,26 +666,38 @@ cgi_initialize_cookies(void) { for (cookie ++, ptr = value; *cookie && *cookie != '\"';) if (ptr < (value + sizeof(value) - 1)) + { *ptr++ = *cookie++; + } else - break; + { + skip = 1; + cookie ++; + } if (*cookie == '\"') cookie ++; + else + skip = 1; } else { for (ptr = value; *cookie && *cookie != ';';) if (ptr < (value + sizeof(value) - 1)) + { *ptr++ = *cookie++; + } else - break; + { + skip = 1; + cookie ++; + } } if (*cookie == ';') cookie ++; else if (*cookie) - break; + skip = 1; *ptr = '\0'; @@ -687,7 +706,7 @@ cgi_initialize_cookies(void) * "$"... */ - if (name[0] != '$') + if (name[0] != '$' && !skip) num_cookies = cupsAddOption(name, value, num_cookies, &cookies); } } @@ -1278,5 +1297,5 @@ cgi_unlink_file(void) /* - * End of "$Id: var.c 12034 2014-07-16 19:37:34Z msweet $". + * End of "$Id: var.c 12621 2015-05-06 21:32:18Z msweet $". */ diff --git a/conf/Makefile b/conf/Makefile index f4d63f8d4c..933d7d909d 100644 --- a/conf/Makefile +++ b/conf/Makefile @@ -1,9 +1,9 @@ # -# "$Id: Makefile 10996 2013-05-29 11:51:34Z msweet $" +# "$Id: Makefile 12533 2015-02-27 12:30:26Z msweet $" # # Configuration file makefile for CUPS. # -# Copyright 2007-2012 by Apple Inc. +# Copyright 2007-2015 by Apple Inc. # Copyright 1993-2006 by Easy Software Products. # # These coded instructions, statements, and computer programs are the @@ -76,8 +76,8 @@ install-data: else \ $(INSTALL_CONFIG) -g $(CUPS_GROUP) $$file $(SERVERROOT) ; \ fi ; \ + $(INSTALL_CONFIG) -g $(CUPS_GROUP) $$file $(SERVERROOT)/$$file.default; \ done - $(INSTALL_CONFIG) -g $(CUPS_GROUP) cupsd.conf $(SERVERROOT)/cupsd.conf.default $(INSTALL_DIR) -m 755 $(DATADIR)/mime for file in $(REPLACE); do \ if test -r $(DATADIR)/mime/$$file ; then \ @@ -139,5 +139,5 @@ uninstall: # -# End of "$Id: Makefile 10996 2013-05-29 11:51:34Z msweet $". +# End of "$Id: Makefile 12533 2015-02-27 12:30:26Z msweet $". # diff --git a/config-scripts/cups-common.m4 b/config-scripts/cups-common.m4 index 929267da67..f1a9263c22 100644 --- a/config-scripts/cups-common.m4 +++ b/config-scripts/cups-common.m4 @@ -1,5 +1,5 @@ dnl -dnl "$Id: cups-common.m4 12336 2014-12-09 21:19:52Z msweet $" +dnl "$Id: cups-common.m4 12697 2015-06-08 17:42:16Z msweet $" dnl dnl Common configuration stuff for CUPS. dnl @@ -20,7 +20,7 @@ dnl Set the name of the config header file... AC_CONFIG_HEADER(config.h) dnl Version number information... -CUPS_VERSION=2.0.4 +CUPS_VERSION=2.1b1 CUPS_REVISION= #if test -z "$CUPS_REVISION" -a -d .svn; then # CUPS_REVISION="-r`svnversion . | awk -F: '{print $NF}' | sed -e '1,$s/[[a-zA-Z]]*//g'`" @@ -137,6 +137,7 @@ AC_CHECK_HEADER(bstring.h,AC_DEFINE(HAVE_BSTRING_H)) AC_CHECK_HEADER(sys/ioctl.h,AC_DEFINE(HAVE_SYS_IOCTL_H)) AC_CHECK_HEADER(sys/param.h,AC_DEFINE(HAVE_SYS_PARAM_H)) AC_CHECK_HEADER(sys/ucred.h,AC_DEFINE(HAVE_SYS_UCRED_H)) +AC_CHECK_HEADER(asl.h,AC_DEFINE(HAVE_ASL_H)) dnl Checks for iconv.h and iconv_open AC_CHECK_HEADER(iconv.h, @@ -465,5 +466,5 @@ esac AC_SUBST(BUILDDIRS) dnl -dnl End of "$Id: cups-common.m4 12336 2014-12-09 21:19:52Z msweet $". +dnl End of "$Id: cups-common.m4 12697 2015-06-08 17:42:16Z msweet $". dnl diff --git a/config-scripts/cups-compiler.m4 b/config-scripts/cups-compiler.m4 index aa18e9525a..ca3bae8e07 100644 --- a/config-scripts/cups-compiler.m4 +++ b/config-scripts/cups-compiler.m4 @@ -1,5 +1,5 @@ dnl -dnl "$Id: cups-compiler.m4 12743 2015-06-23 14:49:09Z msweet $" +dnl "$Id: cups-compiler.m4 12122 2014-08-28 12:55:52Z msweet $" dnl dnl Compiler stuff for CUPS. dnl @@ -156,15 +156,6 @@ if test -n "$GCC"; then # Add useful warning options for tracking down problems... OPTIM="-Wall -Wno-format-y2k -Wunused $OPTIM" - AC_MSG_CHECKING(whether compiler supports -Wno-unused-result) - OLDCFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror -Wno-unused-result" - AC_TRY_COMPILE(,, - [OPTIM="$OPTIM -Wno-unused-result" - AC_MSG_RESULT(yes)], - AC_MSG_RESULT(no)) - CFLAGS="$OLDCFLAGS" - AC_MSG_CHECKING(whether compiler supports -Wsign-conversion) OLDCFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror -Wsign-conversion" @@ -246,5 +237,5 @@ case $uname in esac dnl -dnl End of "$Id: cups-compiler.m4 12743 2015-06-23 14:49:09Z msweet $". +dnl End of "$Id: cups-compiler.m4 12122 2014-08-28 12:55:52Z msweet $". dnl diff --git a/config-scripts/cups-defaults.m4 b/config-scripts/cups-defaults.m4 index cf268ded28..3db1e91212 100644 --- a/config-scripts/cups-defaults.m4 +++ b/config-scripts/cups-defaults.m4 @@ -1,9 +1,9 @@ dnl -dnl "$Id: cups-defaults.m4 11789 2014-04-02 16:52:53Z msweet $" +dnl "$Id: cups-defaults.m4 12350 2014-12-09 22:18:21Z msweet $" dnl dnl Default cupsd configuration settings for CUPS. dnl -dnl Copyright 2007-2012 by Apple Inc. +dnl Copyright 2007-2014 by Apple Inc. dnl Copyright 2006-2007 by Easy Software Products, all rights reserved. dnl dnl These coded instructions, statements, and computer programs are the @@ -409,5 +409,5 @@ AC_SUBST(CUPS_WEBIF) AC_DEFINE_UNQUOTED(CUPS_DEFAULT_WEBIF, $CUPS_DEFAULT_WEBIF) dnl -dnl End of "$Id: cups-defaults.m4 11789 2014-04-02 16:52:53Z msweet $". +dnl End of "$Id: cups-defaults.m4 12350 2014-12-09 22:18:21Z msweet $". dnl diff --git a/config-scripts/cups-network.m4 b/config-scripts/cups-network.m4 index a2df1d53b0..e5b3405cc0 100644 --- a/config-scripts/cups-network.m4 +++ b/config-scripts/cups-network.m4 @@ -1,5 +1,5 @@ dnl -dnl "$Id: cups-network.m4 12325 2014-12-09 20:28:51Z msweet $" +dnl "$Id: cups-network.m4 12324 2014-12-09 20:28:39Z msweet $" dnl dnl Networking stuff for CUPS. dnl @@ -72,5 +72,5 @@ AC_SUBST(CUPS_DEFAULT_DOMAINSOCKET) AC_SUBST(CUPS_LISTEN_DOMAINSOCKET) dnl -dnl End of "$Id: cups-network.m4 12325 2014-12-09 20:28:51Z msweet $". +dnl End of "$Id: cups-network.m4 12324 2014-12-09 20:28:39Z msweet $". dnl diff --git a/config-scripts/cups-ssl.m4 b/config-scripts/cups-ssl.m4 index fdd3c56e93..df0bd45e8d 100644 --- a/config-scripts/cups-ssl.m4 +++ b/config-scripts/cups-ssl.m4 @@ -1,9 +1,9 @@ dnl -dnl "$Id: cups-ssl.m4 12290 2014-12-05 17:25:55Z msweet $" +dnl "$Id: cups-ssl.m4 12645 2015-05-20 01:20:52Z msweet $" dnl dnl TLS stuff for CUPS. dnl -dnl Copyright 2007-2014 by Apple Inc. +dnl Copyright 2007-2015 by Apple Inc. dnl Copyright 1997-2007 by Easy Software Products, all rights reserved. dnl dnl These coded instructions, statements, and computer programs are the @@ -53,6 +53,10 @@ if test x$enable_ssl != xno; then AC_DEFINE(HAVE_CSSMERRORSTRING) AC_DEFINE(HAVE_SECKEYCHAINOPEN)]) + + if test $uversion -ge 150; then + AC_DEFINE(HAVE_SSLSETENABLEDCIPHERS) + fi fi fi @@ -104,5 +108,5 @@ EXPORT_SSLLIBS="$SSLLIBS" AC_SUBST(EXPORT_SSLLIBS) dnl -dnl End of "$Id: cups-ssl.m4 12290 2014-12-05 17:25:55Z msweet $". +dnl End of "$Id: cups-ssl.m4 12645 2015-05-20 01:20:52Z msweet $". dnl diff --git a/config-scripts/cups-startup.m4 b/config-scripts/cups-startup.m4 index 0053aa7902..e82ad5193a 100644 --- a/config-scripts/cups-startup.m4 +++ b/config-scripts/cups-startup.m4 @@ -1,5 +1,5 @@ dnl -dnl "$Id: cups-startup.m4 12351 2014-12-09 22:18:45Z msweet $" +dnl "$Id: cups-startup.m4 12691 2015-06-04 18:00:31Z msweet $" dnl dnl Launch-on-demand/startup stuff for CUPS. dnl @@ -68,6 +68,15 @@ if test x$enable_systemd != xno; then else AC_MSG_RESULT(no) fi + AC_MSG_CHECKING(for libsystemd-journal) + if $PKGCONFIG --exists libsystemd-journal; then + AC_MSG_RESULT(yes) + ONDEMANDFLAGS="$ONDEMANDFLAGS `$PKGCONFIG --cflags libsystemd-journal`" + ONDEMANDLIBS="$ONDEMANDLIBS `$PKGCONFIG --libs libsystemd-journal`" + AC_CHECK_HEADER(systemd/sd-journal.h,AC_DEFINE(HAVE_SYSTEMD_SD_JOURNAL_H)) + else + AC_MSG_RESULT(no) + fi fi fi @@ -172,5 +181,5 @@ fi dnl -dnl End of "$Id: cups-startup.m4 12351 2014-12-09 22:18:45Z msweet $". +dnl End of "$Id: cups-startup.m4 12691 2015-06-04 18:00:31Z msweet $". dnl diff --git a/config.h.in b/config.h.in index 802e259259..15607eeca9 100644 --- a/config.h.in +++ b/config.h.in @@ -1,9 +1,9 @@ /* - * "$Id: config.h.in 12329 2014-12-09 20:50:51Z msweet $" + * "$Id: config.h.in 12687 2015-06-03 17:19:04Z msweet $" * * Configuration file for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2015 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -242,6 +242,20 @@ #undef HAVE_VSYSLOG +/* + * Do we have the ASL functions? + */ + +#undef HAVE_ASL_H + + +/* + * Do we have the systemd journal functions? + */ + +#undef HAVE_SYSTEMD_SD_JOURNAL_H + + /* * Do we have the (v)snprintf() functions? */ @@ -348,6 +362,13 @@ #undef HAVE_SECKEYCHAINOPEN +/* + * Do we have (a working) SSLSetEnabledCiphers function? + */ + +#undef HAVE_SSLSETENABLEDCIPHERS + + /* * Do we have libpaper? */ @@ -719,5 +740,5 @@ static __inline int _cups_abs(int i) { return (i < 0 ? -i : i); } #endif /* !_CUPS_CONFIG_H_ */ /* - * End of "$Id: config.h.in 12329 2014-12-09 20:50:51Z msweet $". + * End of "$Id: config.h.in 12687 2015-06-03 17:19:04Z msweet $". */ diff --git a/configure b/configure index 6836c7db16..7d86119fe9 100755 --- a/configure +++ b/configure @@ -1,9 +1,11 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69. +# Generated by GNU Autoconf 2.68. # # -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. # # # This configure script is free software; the Free Software Foundation @@ -132,31 +134,6 @@ export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH -# Use a proper internal environment variable to ensure we don't fall - # into an infinite loop, continuously re-executing ourselves. - if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then - _as_can_reexec=no; export _as_can_reexec; - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 - fi - # We don't want this to propagate to other subprocesses. - { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh @@ -190,8 +167,7 @@ if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi -test x\$exitcode = x0 || exit 1 -test -x / || exit 1" +test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && @@ -236,25 +212,21 @@ IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : - export CONFIG_SHELL - # We cannot yet assume a decent shell, so we have to provide a -# neutralization value for shells without unset; and this also -# works around shells that cannot unset nonexistent variables. -# Preserve -v and -x to the replacement shell. -BASH_ENV=/dev/null -ENV=/dev/null -(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV -case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; -esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} -# Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -exit 255 + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + # Preserve -v and -x to the replacement shell. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; + esac + exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : @@ -356,14 +328,6 @@ $as_echo X"$as_dir" | } # as_fn_mkdir_p - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take @@ -485,10 +449,6 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - # If we had to re-execute with $CONFIG_SHELL, we're ensured to have - # already done that, so ensure we don't try to do so again and fall - # in an infinite loop. This has already happened in practice. - _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). @@ -523,16 +483,16 @@ if (echo >conf$$.file) 2>/dev/null; then # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. + # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' + as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -pR' + as_ln_s='cp -p' fi else - as_ln_s='cp -pR' + as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null @@ -544,8 +504,28 @@ else as_mkdir_p=false fi -as_test_x='test -x' -as_executable_p=as_fn_executable_p +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -1378,6 +1358,8 @@ target=$target_alias if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi @@ -1701,9 +1683,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure -generated by GNU Autoconf 2.69 +generated by GNU Autoconf 2.68 -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1854,7 +1836,7 @@ $as_echo "$ac_try_echo"; } >&5 test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || - test -x conftest$ac_exeext + $as_test_x conftest$ac_exeext }; then : ac_retval=0 else @@ -2161,7 +2143,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2537,7 +2519,7 @@ esac ac_config_headers="$ac_config_headers config.h" -CUPS_VERSION=2.0.4 +CUPS_VERSION=2.1b1 CUPS_REVISION= #if test -z "$CUPS_REVISION" -a -d .svn; then # CUPS_REVISION="-r`svnversion . | awk -F: '{print $NF}' | sed -e '1,$s/[[a-zA-Z]]*//g'`" @@ -2586,7 +2568,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2634,7 +2616,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2678,7 +2660,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3122,7 +3104,8 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include -struct stat; +#include +#include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); @@ -3372,7 +3355,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3416,7 +3399,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3618,7 +3601,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3658,7 +3641,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3711,7 +3694,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_AR="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3751,7 +3734,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_CHMOD="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3791,7 +3774,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_GZIP="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3831,7 +3814,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_LD="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3871,7 +3854,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_LN="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3911,7 +3894,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_MV="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3951,7 +3934,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_RM="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3991,7 +3974,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_RMDIR="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -4031,7 +4014,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_SED="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -4071,7 +4054,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_XDGOPEN="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -4147,7 +4130,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -4190,7 +4173,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ac_pt_PKGCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -4600,7 +4583,7 @@ do for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in @@ -4666,7 +4649,7 @@ do for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in @@ -4927,6 +4910,13 @@ if test "x$ac_cv_header_sys_ucred_h" = xyes; then : fi +ac_fn_c_check_header_mongrel "$LINENO" "asl.h" "ac_cv_header_asl_h" "$ac_includes_default" +if test "x$ac_cv_header_asl_h" = xyes; then : + $as_echo "#define HAVE_ASL_H 1" >>confdefs.h + +fi + + ac_fn_c_check_header_mongrel "$LINENO" "iconv.h" "ac_cv_header_iconv_h" "$ac_includes_default" if test "x$ac_cv_header_iconv_h" = xyes; then : @@ -6786,32 +6776,6 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Add useful warning options for tracking down problems... OPTIM="-Wall -Wno-format-y2k -Wunused $OPTIM" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -Wno-unused-result" >&5 -$as_echo_n "checking whether compiler supports -Wno-unused-result... " >&6; } - OLDCFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror -Wno-unused-result" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - OPTIM="$OPTIM -Wno-unused-result" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS="$OLDCFLAGS" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiler supports -Wsign-conversion" >&5 $as_echo_n "checking whether compiler supports -Wsign-conversion... " >&6; } OLDCFLAGS="$CFLAGS" @@ -7624,7 +7588,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_KRB5CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -7667,7 +7631,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ac_pt_KRB5CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -8193,6 +8157,11 @@ fi fi + + if test $uversion -ge 150; then + $as_echo "#define HAVE_SSLSETENABLEDCIPHERS 1" >>confdefs.h + + fi fi fi @@ -8216,7 +8185,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_LIBGNUTLSCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -8259,7 +8228,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ac_pt_LIBGNUTLSCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -8314,7 +8283,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_LIBGCRYPTCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -8357,7 +8326,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ac_pt_LIBGCRYPTCONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -8918,8 +8887,6 @@ _ACEOF esac rm -rf conftest* fi - - fi @@ -9183,6 +9150,24 @@ $as_echo "yes" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libsystemd-journal" >&5 +$as_echo_n "checking for libsystemd-journal... " >&6; } + if $PKGCONFIG --exists libsystemd-journal; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ONDEMANDFLAGS="$ONDEMANDFLAGS `$PKGCONFIG --cflags libsystemd-journal`" + ONDEMANDLIBS="$ONDEMANDLIBS `$PKGCONFIG --libs libsystemd-journal`" + ac_fn_c_check_header_mongrel "$LINENO" "systemd/sd-journal.h" "ac_cv_header_systemd_sd_journal_h" "$ac_includes_default" +if test "x$ac_cv_header_systemd_sd_journal_h" = xyes; then : + $as_echo "#define HAVE_SYSTEMD_SD_JOURNAL_H 1" >>confdefs.h + +fi + + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi fi fi @@ -9917,7 +9902,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_JAVA="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -9980,7 +9965,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -10043,7 +10028,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PHPCGI="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -10084,7 +10069,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PHP="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -10152,7 +10137,7 @@ do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -10212,7 +10197,7 @@ fi -ac_config_files="$ac_config_files Makedefs conf/cups-files.conf conf/cupsd.conf conf/mime.convs conf/pam.std conf/snmp.conf cups-config data/testprint desktop/cups.desktop doc/index.html man/client.conf.man man/cups-files.conf.man man/cups-lpd.man man/cups-snmp.man man/cupsaddsmb.man man/cupsd.conf.man man/cupsd.man man/lpoptions.man scheduler/cups-lpd.xinetd scheduler/cups.sh scheduler/cups.xml scheduler/org.cups.cups-lpd.plist scheduler/org.cups.cups-lpdAT.service scheduler/org.cups.cupsd.path scheduler/org.cups.cupsd.service scheduler/org.cups.cupsd.socket templates/header.tmpl packaging/cups.list $LANGFILES" +ac_config_files="$ac_config_files Makedefs conf/cups-files.conf conf/cupsd.conf conf/mime.convs conf/pam.std conf/snmp.conf cups-config desktop/cups.desktop doc/index.html man/client.conf.man man/cups-files.conf.man man/cups-lpd.man man/cups-snmp.man man/cupsaddsmb.man man/cupsd.conf.man man/cupsd.man man/lpoptions.man scheduler/cups-lpd.xinetd scheduler/cups.sh scheduler/cups.xml scheduler/org.cups.cups-lpd.plist scheduler/org.cups.cups-lpdAT.service scheduler/org.cups.cupsd.path scheduler/org.cups.cupsd.service scheduler/org.cups.cupsd.socket templates/header.tmpl packaging/cups.list $LANGFILES" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -10621,16 +10606,16 @@ if (echo >conf$$.file) 2>/dev/null; then # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. + # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -pR' + as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -pR' + as_ln_s='cp -p' fi else - as_ln_s='cp -pR' + as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null @@ -10690,16 +10675,28 @@ else as_mkdir_p=false fi - -# as_fn_executable_p FILE -# ----------------------- -# Test if FILE is an executable regular file. -as_fn_executable_p () -{ - test -f "$1" && test -x "$1" -} # as_fn_executable_p -as_test_x='test -x' -as_executable_p=as_fn_executable_p +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -10721,7 +10718,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by $as_me, which was -generated by GNU Autoconf 2.69. Invocation command line was +generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -10783,10 +10780,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status -configured by $0, generated by GNU Autoconf 2.69, +configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -10875,7 +10872,7 @@ fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then - set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' @@ -10912,7 +10909,6 @@ do "conf/pam.std") CONFIG_FILES="$CONFIG_FILES conf/pam.std" ;; "conf/snmp.conf") CONFIG_FILES="$CONFIG_FILES conf/snmp.conf" ;; "cups-config") CONFIG_FILES="$CONFIG_FILES cups-config" ;; - "data/testprint") CONFIG_FILES="$CONFIG_FILES data/testprint" ;; "desktop/cups.desktop") CONFIG_FILES="$CONFIG_FILES desktop/cups.desktop" ;; "doc/index.html") CONFIG_FILES="$CONFIG_FILES doc/index.html" ;; "man/client.conf.man") CONFIG_FILES="$CONFIG_FILES man/client.conf.man" ;; diff --git a/configure.ac b/configure.ac index 26b7b713e3..1e3fb72af0 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ dnl -dnl "$Id: configure.ac 12222 2014-10-21 11:55:01Z msweet $" +dnl "$Id: configure.ac 12278 2014-12-01 13:53:56Z msweet $" dnl dnl Configuration script for CUPS. dnl @@ -66,7 +66,6 @@ AC_OUTPUT(Makedefs conf/pam.std conf/snmp.conf cups-config - data/testprint desktop/cups.desktop doc/index.html man/client.conf.man @@ -92,5 +91,5 @@ AC_OUTPUT(Makedefs chmod +x cups-config dnl -dnl End of "$Id: configure.ac 12222 2014-10-21 11:55:01Z msweet $". +dnl End of "$Id: configure.ac 12278 2014-12-01 13:53:56Z msweet $". dnl diff --git a/cups/Makefile b/cups/Makefile index 00b9b2b80a..ed44fab588 100644 --- a/cups/Makefile +++ b/cups/Makefile @@ -1,5 +1,5 @@ # -# "$Id: Makefile 12032 2014-07-15 20:37:32Z msweet $" +# "$Id: Makefile 12635 2015-05-19 02:12:22Z msweet $" # # API library Makefile for CUPS. # @@ -94,7 +94,8 @@ TESTOBJS = \ testlang.o \ testppd.o \ testpwg.o \ - testsnmp.o + testsnmp.o \ + tlscheck.o OBJS = \ $(LIBOBJS) \ $(TESTOBJS) @@ -161,7 +162,8 @@ UNITTARGETS = \ testoptions \ testppd \ testpwg \ - testsnmp + testsnmp \ + tlscheck TARGETS = \ $(LIBTARGETS) @@ -539,6 +541,16 @@ testsnmp: testsnmp.o $(LIBCUPSSTATIC) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) +# +# tlscheck (dependency on static CUPS library is intentional) +# + +tlscheck: tlscheck.o $(LIBCUPSSTATIC) + echo Linking $@... + $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ tlscheck.o $(LIBCUPSSTATIC) \ + $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + + # # Automatic API help files... # @@ -665,5 +677,5 @@ tls.o: tls-darwin.c tls-gnutls.c tls-sspi.c # -# End of "$Id: Makefile 12032 2014-07-15 20:37:32Z msweet $". +# End of "$Id: Makefile 12635 2015-05-19 02:12:22Z msweet $". # diff --git a/cups/auth.c b/cups/auth.c index 4b4c936adb..52a9db3480 100644 --- a/cups/auth.c +++ b/cups/auth.c @@ -1,5 +1,5 @@ /* - * "$Id: auth.c 12230 2014-10-21 13:55:24Z msweet $" + * "$Id: auth.c 12619 2015-05-06 21:00:19Z msweet $" * * Authentication functions for CUPS. * @@ -311,7 +311,7 @@ _cupsSetNegotiateAuthString( * to use it... */ - if (gss_init_sec_context == NULL) + if (&gss_init_sec_context == NULL) { DEBUG_puts("1_cupsSetNegotiateAuthString: Weak-linked GSSAPI/Kerberos " "framework is not present"); @@ -876,5 +876,5 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ /* - * End of "$Id: auth.c 12230 2014-10-21 13:55:24Z msweet $". + * End of "$Id: auth.c 12619 2015-05-06 21:00:19Z msweet $". */ diff --git a/cups/cups-private.h b/cups/cups-private.h index 90420a220d..da8a3963bd 100644 --- a/cups/cups-private.h +++ b/cups/cups-private.h @@ -1,9 +1,9 @@ /* - * "$Id: cups-private.h 11851 2014-05-07 23:55:35Z msweet $" + * "$Id: cups-private.h 12441 2015-01-29 14:42:32Z msweet $" * * Private definitions for CUPS. * - * Copyright 2007-2013 by Apple Inc. + * Copyright 2007-2015 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -281,5 +281,5 @@ extern char *_cupsUserDefault(char *name, size_t namesize); #endif /* !_CUPS_CUPS_PRIVATE_H_ */ /* - * End of "$Id: cups-private.h 11851 2014-05-07 23:55:35Z msweet $". + * End of "$Id: cups-private.h 12441 2015-01-29 14:42:32Z msweet $". */ diff --git a/cups/cups.h b/cups/cups.h index 969919015e..4faf82cdc7 100644 --- a/cups/cups.h +++ b/cups/cups.h @@ -1,9 +1,9 @@ /* - * "$Id: cups.h 12761 2015-06-24 20:10:19Z msweet $" + * "$Id: cups.h 12722 2015-06-08 22:00:19Z msweet $" * * API definitions for CUPS. * - * Copyright 2007-2015 by Apple Inc. + * Copyright 2007-2014 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -35,6 +35,15 @@ typedef off_t ssize_t; /* @private@ */ # include "language.h" # include "pwg.h" +/* + * Define _PPD_DEPRECATED to silence the warnings about PPD functions being + * deprecated... + */ + +# ifndef _PPD_DEPRECATED +# define _PPD_DEPRECATED _CUPS_DEPRECATED_1_6_MSG("Use cupsCopyDestInfo and friends instead.") +# endif /* !_PPD_DEPRECATED */ + /* * C++ magic... @@ -49,10 +58,10 @@ extern "C" { * Constants... */ -# define CUPS_VERSION 2.0004 +# define CUPS_VERSION 2.0100 # define CUPS_VERSION_MAJOR 2 -# define CUPS_VERSION_MINOR 0 -# define CUPS_VERSION_PATCH 4 +# define CUPS_VERSION_MINOR 1 +# define CUPS_VERSION_PATCH 0 # define CUPS_BC_FD 3 /* Back-channel file descriptor for @@ -354,8 +363,7 @@ extern int cupsGetClasses(char ***classes) _CUPS_DEPRECATED_MSG("Use cupsGetDes extern const char *cupsGetDefault(void); extern int cupsGetJobs(cups_job_t **jobs, const char *name, int myjobs, int whichjobs); -extern const char *cupsGetPPD(const char *name) - _CUPS_DEPRECATED_1_6_MSG("Use cupsCopyDestInfo instead."); +extern const char *cupsGetPPD(const char *name) _PPD_DEPRECATED; extern int cupsGetPrinters(char ***printers) _CUPS_DEPRECATED_MSG("Use cupsGetDests instead."); extern ipp_status_t cupsLastError(void); extern int cupsPrintFile(const char *name, const char *filename, @@ -413,8 +421,7 @@ extern int cupsGetDests2(http_t *http, cups_dest_t **dests) extern int cupsGetJobs2(http_t *http, cups_job_t **jobs, const char *name, int myjobs, int whichjobs) _CUPS_API_1_1_21; -extern const char *cupsGetPPD2(http_t *http, const char *name) - _CUPS_DEPRECATED_1_6_MSG("Use cupsCopyDestInfo instead."); +extern const char *cupsGetPPD2(http_t *http, const char *name) _PPD_DEPRECATED; extern int cupsPrintFile2(http_t *http, const char *name, const char *filename, const char *title, int num_options, @@ -479,7 +486,7 @@ extern const char *cupsGetPassword2(const char *prompt, http_t *http, const char *resource) _CUPS_API_1_4; extern http_status_t cupsGetPPD3(http_t *http, const char *name, time_t *modtime, char *buffer, - size_t bufsize) _CUPS_API_1_4; + size_t bufsize) _PPD_DEPRECATED; extern ipp_t *cupsGetResponse(http_t *http, const char *resource) _CUPS_API_1_4; extern ssize_t cupsReadResponseData(http_t *http, char *buffer, @@ -628,5 +635,5 @@ extern int cupsSetServerCredentials(const char *path, const char *common_name, #endif /* !_CUPS_CUPS_H_ */ /* - * End of "$Id: cups.h 12761 2015-06-24 20:10:19Z msweet $". + * End of "$Id: cups.h 12722 2015-06-08 22:00:19Z msweet $". */ diff --git a/cups/debug.c b/cups/debug.c index 5514f773b9..feae91d117 100644 --- a/cups/debug.c +++ b/cups/debug.c @@ -1,5 +1,5 @@ /* - * "$Id: debug.c 12328 2014-12-09 20:38:47Z msweet $" + * "$Id: debug.c 12327 2014-12-09 20:38:39Z msweet $" * * Debugging functions for CUPS. * @@ -643,5 +643,5 @@ _cups_debug_set(const char *logfile, /* I - Log file or NULL */ /* - * End of "$Id: debug.c 12328 2014-12-09 20:38:47Z msweet $". + * End of "$Id: debug.c 12327 2014-12-09 20:38:39Z msweet $". */ diff --git a/cups/dest.c b/cups/dest.c index 384105ffbe..dcbdfb9e2e 100644 --- a/cups/dest.c +++ b/cups/dest.c @@ -1,5 +1,5 @@ /* - * "$Id: dest.c 12665 2015-05-25 15:08:55Z msweet $" + * "$Id: dest.c 12722 2015-06-08 22:00:19Z msweet $" * * User-defined destination (and option) support for CUPS. * @@ -3943,5 +3943,5 @@ cups_make_string( /* - * End of "$Id: dest.c 12665 2015-05-25 15:08:55Z msweet $". + * End of "$Id: dest.c 12722 2015-06-08 22:00:19Z msweet $". */ diff --git a/cups/encode.c b/cups/encode.c index 5847f5684a..b43c4a3fc4 100644 --- a/cups/encode.c +++ b/cups/encode.c @@ -1,9 +1,9 @@ /* - * "$Id: encode.c 11733 2014-03-25 18:01:41Z msweet $" + * "$Id: encode.c 12668 2015-05-27 19:30:32Z msweet $" * * Option encoding routines for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2015 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -117,6 +117,9 @@ static const _ipp_option_t ipp_options[] = { 0, "copies", IPP_TAG_INTEGER, IPP_TAG_JOB, IPP_TAG_DOCUMENT }, { 0, "copies-default", IPP_TAG_INTEGER, IPP_TAG_PRINTER }, + { 0, "date-time-at-completed",IPP_TAG_DATE, IPP_TAG_ZERO }, /* never send as option */ + { 0, "date-time-at-creation", IPP_TAG_DATE, IPP_TAG_ZERO }, /* never send as option */ + { 0, "date-time-at-processing",IPP_TAG_DATE, IPP_TAG_ZERO }, /* never send as option */ { 0, "device-uri", IPP_TAG_URI, IPP_TAG_PRINTER }, { 1, "document-copies", IPP_TAG_RANGE, IPP_TAG_JOB, IPP_TAG_DOCUMENT, @@ -274,6 +277,7 @@ static const _ipp_option_t ipp_options[] = { 0, "print-quality-default", IPP_TAG_ENUM, IPP_TAG_PRINTER }, { 1, "printer-commands", IPP_TAG_KEYWORD, IPP_TAG_PRINTER }, { 0, "printer-error-policy", IPP_TAG_NAME, IPP_TAG_PRINTER }, + { 0, "printer-geo-location", IPP_TAG_URI, IPP_TAG_PRINTER }, { 0, "printer-info", IPP_TAG_TEXT, IPP_TAG_PRINTER }, { 0, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, { 0, "printer-is-shared", IPP_TAG_BOOLEAN, IPP_TAG_PRINTER }, @@ -849,5 +853,5 @@ compare_ipp_options(_ipp_option_t *a, /* I - First option */ /* - * End of "$Id: encode.c 11733 2014-03-25 18:01:41Z msweet $". + * End of "$Id: encode.c 12668 2015-05-27 19:30:32Z msweet $". */ diff --git a/cups/file.c b/cups/file.c index 6c6b8492e9..a69f0f95ac 100644 --- a/cups/file.c +++ b/cups/file.c @@ -1,5 +1,5 @@ /* - * "$Id: file.c 12642 2015-05-19 15:04:47Z msweet $" + * "$Id: file.c 12641 2015-05-19 15:04:39Z msweet $" * * File functions for CUPS. * @@ -2752,5 +2752,5 @@ cups_write(cups_file_t *fp, /* I - CUPS file */ /* - * End of "$Id: file.c 12642 2015-05-19 15:04:47Z msweet $". + * End of "$Id: file.c 12641 2015-05-19 15:04:39Z msweet $". */ diff --git a/cups/globals.c b/cups/globals.c index c48c321440..4b041f4712 100644 --- a/cups/globals.c +++ b/cups/globals.c @@ -1,5 +1,5 @@ /* - * "$Id: globals.c 12481 2015-02-03 12:45:14Z msweet $" + * "$Id: globals.c 12480 2015-02-03 12:36:34Z msweet $" * * Global variable access routines for CUPS. * @@ -394,5 +394,5 @@ cups_globals_init(void) /* - * End of "$Id: globals.c 12481 2015-02-03 12:45:14Z msweet $". + * End of "$Id: globals.c 12480 2015-02-03 12:36:34Z msweet $". */ diff --git a/cups/http-private.h b/cups/http-private.h index 3a8c18c025..3393e87f85 100644 --- a/cups/http-private.h +++ b/cups/http-private.h @@ -1,5 +1,5 @@ /* - * "$Id: http-private.h 12419 2015-01-22 15:51:20Z msweet $" + * "$Id: http-private.h 12645 2015-05-20 01:20:52Z msweet $" * * Private HTTP definitions for CUPS. * @@ -126,6 +126,7 @@ extern CFAbsoluteTime SecCertificateNotValidAfter(SecCertificateRef certificate) # ifndef WIN32 # include +# include # ifdef HAVE_GETIFADDRS # include # else @@ -161,8 +162,11 @@ extern "C" { #define _HTTP_RESOLVE_FQDN 2 /* Resolve to a FQDN */ #define _HTTP_RESOLVE_FAXOUT 4 /* Resolve FaxOut service? */ +#define _HTTP_TLS_NONE 0 /* No TLS options */ #define _HTTP_TLS_ALLOW_RC4 1 /* Allow RC4 cipher suites */ #define _HTTP_TLS_ALLOW_SSL3 2 /* Allow SSL 3.0 */ +#define _HTTP_TLS_ALLOW_DH 4 /* Allow DH/DHE key negotiation */ +#define _HTTP_TLS_DENY_TLS10 16 /* Deny TLS 1.0 */ /* @@ -438,5 +442,5 @@ extern int _httpWait(http_t *http, int msec, int usessl); #endif /* !_CUPS_HTTP_PRIVATE_H_ */ /* - * End of "$Id: http-private.h 12419 2015-01-22 15:51:20Z msweet $". + * End of "$Id: http-private.h 12645 2015-05-20 01:20:52Z msweet $". */ diff --git a/cups/http.c b/cups/http.c index 6c8f5797ef..98188a4b56 100644 --- a/cups/http.c +++ b/cups/http.c @@ -1,5 +1,5 @@ /* - * "$Id: http.c 12334 2014-12-09 21:01:55Z msweet $" + * "$Id: http.c 12333 2014-12-09 21:01:46Z msweet $" * * HTTP routines for CUPS. * @@ -4850,5 +4850,5 @@ http_write_chunk(http_t *http, /* I - HTTP connection */ /* - * End of "$Id: http.c 12334 2014-12-09 21:01:55Z msweet $". + * End of "$Id: http.c 12333 2014-12-09 21:01:46Z msweet $". */ diff --git a/cups/ipp-support.c b/cups/ipp-support.c index 88e4065f9c..6a5d940671 100644 --- a/cups/ipp-support.c +++ b/cups/ipp-support.c @@ -1,5 +1,5 @@ /* - * "$Id: ipp-support.c 12194 2014-10-02 18:44:36Z msweet $" + * "$Id: ipp-support.c 12666 2015-05-25 19:38:09Z msweet $" * * Internet Printing Protocol support functions for CUPS. * @@ -195,7 +195,7 @@ static const char * const ipp_std_ops[] = "Suspend-Current-Job", "Resume-Job", - /* 0x0030 - 0x003e */ + /* 0x0030 - 0x003f */ "Promote-Job", "Schedule-Job-After", "0x0032", @@ -210,7 +210,21 @@ static const char * const ipp_std_ops[] = "Close-Job", "Identify-Printer", "Validate-Document", - "Send-Hardcopy-Document" + "Send-Hardcopy-Document", + "Acknowledge-Document", + + /* 0x0040 - 0x004a */ + "Acknowledge-Identify-Printer", + "Acknowledge-Job", + "Fetch-Document", + "Fetch-Job", + "Get-Output-Device-Attributes", + "Update-Active-Jobs", + "Deregister-Output-Device", + "Update-Document-Status", + "Update-Job-Status", + "Update-Output-Device-Attributes", + "Get-Next-Document-Data" }, * const ipp_cups_ops[] = { @@ -2271,5 +2285,5 @@ ipp_col_string(ipp_t *col, /* I - Collection attribute */ /* - * End of "$Id: ipp-support.c 12194 2014-10-02 18:44:36Z msweet $". + * End of "$Id: ipp-support.c 12666 2015-05-25 19:38:09Z msweet $". */ diff --git a/cups/ipp.c b/cups/ipp.c index 6ef17ecd76..5e7b730622 100644 --- a/cups/ipp.c +++ b/cups/ipp.c @@ -1,5 +1,5 @@ /* - * "$Id: ipp.c 12469 2015-02-01 04:51:08Z msweet $" + * "$Id: ipp.c 12468 2015-02-01 04:50:43Z msweet $" * * Internet Printing Protocol functions for CUPS. * @@ -7062,5 +7062,5 @@ ipp_write_file(int *fd, /* I - File descriptor */ /* - * End of "$Id: ipp.c 12469 2015-02-01 04:51:08Z msweet $". + * End of "$Id: ipp.c 12468 2015-02-01 04:50:43Z msweet $". */ diff --git a/cups/ipp.h b/cups/ipp.h index c56e7abe8f..9fccd11ca0 100644 --- a/cups/ipp.h +++ b/cups/ipp.h @@ -1,5 +1,5 @@ /* - * "$Id: ipp.h 11806 2014-04-09 16:12:27Z msweet $" + * "$Id: ipp.h 12666 2015-05-25 19:38:09Z msweet $" * * Internet Printing Protocol definitions for CUPS. * @@ -246,11 +246,11 @@ typedef enum ipp_op_e /**** IPP operations ****/ IPP_OP_CUPS_INVALID = -1, /* Invalid operation name for @link ippOpValue@ */ IPP_OP_CUPS_NONE = 0, /* No operation @private@ */ IPP_OP_PRINT_JOB = 0x0002, /* Print a single file */ - IPP_OP_PRINT_URI, /* Print a single URL @private@ */ + IPP_OP_PRINT_URI, /* Print a single URL */ IPP_OP_VALIDATE_JOB, /* Validate job options */ IPP_OP_CREATE_JOB, /* Create an empty print job */ IPP_OP_SEND_DOCUMENT, /* Add a file to a job */ - IPP_OP_SEND_URI, /* Add a URL to a job @private@ */ + IPP_OP_SEND_URI, /* Add a URL to a job */ IPP_OP_CANCEL_JOB, /* Cancel a job */ IPP_OP_GET_JOB_ATTRIBUTES, /* Get job attributes */ IPP_OP_GET_JOBS, /* Get a list of jobs */ @@ -261,7 +261,7 @@ typedef enum ipp_op_e /**** IPP operations ****/ IPP_OP_PAUSE_PRINTER = 0x0010, /* Stop a printer */ IPP_OP_RESUME_PRINTER, /* Start a printer */ IPP_OP_PURGE_JOBS, /* Cancel all jobs */ - IPP_OP_SET_PRINTER_ATTRIBUTES, /* Set printer attributes @private@ */ + IPP_OP_SET_PRINTER_ATTRIBUTES, /* Set printer attributes */ IPP_OP_SET_JOB_ATTRIBUTES, /* Set job attributes */ IPP_OP_GET_PRINTER_SUPPORTED_VALUES, /* Get supported attribute values */ IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS, /* Create one or more printer subscriptions @since CUPS 1.2/OS X 10.5@ */ @@ -279,32 +279,45 @@ typedef enum ipp_op_e /**** IPP operations ****/ IPP_OP_ENABLE_PRINTER, /* Start a printer */ IPP_OP_DISABLE_PRINTER, /* Stop a printer */ IPP_OP_PAUSE_PRINTER_AFTER_CURRENT_JOB, - /* Stop printer after the current job @private@ */ - IPP_OP_HOLD_NEW_JOBS, /* Hold new jobs @private@ */ - IPP_OP_RELEASE_HELD_NEW_JOBS, /* Release new jobs @private@ */ - IPP_OP_DEACTIVATE_PRINTER, /* Stop a printer @private@ */ - IPP_OP_ACTIVATE_PRINTER, /* Start a printer @private@ */ - IPP_OP_RESTART_PRINTER, /* Restart a printer @private@ */ - IPP_OP_SHUTDOWN_PRINTER, /* Turn a printer off @private@ */ - IPP_OP_STARTUP_PRINTER, /* Turn a printer on @private@ */ - IPP_OP_REPROCESS_JOB, /* Reprint a job @private@ */ - IPP_OP_CANCEL_CURRENT_JOB, /* Cancel the current job @private@ */ - IPP_OP_SUSPEND_CURRENT_JOB, /* Suspend the current job @private@ */ - IPP_OP_RESUME_JOB, /* Resume the current job @private@ */ - IPP_OP_PROMOTE_JOB, /* Promote a job to print sooner @private@ */ - IPP_OP_SCHEDULE_JOB_AFTER, /* Schedule a job to print after another @private@ */ - IPP_OP_CANCEL_DOCUMENT = 0x0033, /* Cancel-Document @private@ */ - IPP_OP_GET_DOCUMENT_ATTRIBUTES, /* Get-Document-Attributes @private@ */ - IPP_OP_GET_DOCUMENTS, /* Get-Documents @private@ */ - IPP_OP_DELETE_DOCUMENT, /* Delete-Document @private@ */ - IPP_OP_SET_DOCUMENT_ATTRIBUTES, /* Set-Document-Attributes @private@ */ + /* Stop printer after the current job */ + IPP_OP_HOLD_NEW_JOBS, /* Hold new jobs */ + IPP_OP_RELEASE_HELD_NEW_JOBS, /* Release new jobs */ + IPP_OP_DEACTIVATE_PRINTER, /* Stop a printer */ + IPP_OP_ACTIVATE_PRINTER, /* Start a printer */ + IPP_OP_RESTART_PRINTER, /* Restart a printer */ + IPP_OP_SHUTDOWN_PRINTER, /* Turn a printer off */ + IPP_OP_STARTUP_PRINTER, /* Turn a printer on */ + IPP_OP_REPROCESS_JOB, /* Reprint a job */ + IPP_OP_CANCEL_CURRENT_JOB, /* Cancel the current job */ + IPP_OP_SUSPEND_CURRENT_JOB, /* Suspend the current job */ + IPP_OP_RESUME_JOB, /* Resume the current job */ + IPP_OP_PROMOTE_JOB, /* Promote a job to print sooner */ + IPP_OP_SCHEDULE_JOB_AFTER, /* Schedule a job to print after another */ + IPP_OP_CANCEL_DOCUMENT = 0x0033, /* Cancel-Document */ + IPP_OP_GET_DOCUMENT_ATTRIBUTES, /* Get-Document-Attributes */ + IPP_OP_GET_DOCUMENTS, /* Get-Documents */ + IPP_OP_DELETE_DOCUMENT, /* Delete-Document */ + IPP_OP_SET_DOCUMENT_ATTRIBUTES, /* Set-Document-Attributes */ IPP_OP_CANCEL_JOBS, /* Cancel-Jobs */ IPP_OP_CANCEL_MY_JOBS, /* Cancel-My-Jobs */ IPP_OP_RESUBMIT_JOB, /* Resubmit-Job */ IPP_OP_CLOSE_JOB, /* Close-Job */ - IPP_OP_IDENTIFY_PRINTER, /* Identify-Printer @private@ */ - IPP_OP_VALIDATE_DOCUMENT, /* Validate-Document @private@ */ - IPP_OP_SEND_HARDCOPY_DOCUMENT, /* Send-Hardcopy-Document @private@ */ + IPP_OP_IDENTIFY_PRINTER, /* Identify-Printer */ + IPP_OP_VALIDATE_DOCUMENT, /* Validate-Document */ + IPP_OP_SEND_HARDCOPY_DOCUMENT, /* Send-Hardcopy-Document */ + IPP_OP_ACKNOWLEDGE_DOCUMENT, /* Acknowledge-Document */ + IPP_OP_ACKNOWLEDGE_IDENTIFY_PRINTER, /* Acknowledge-Identify-Printer */ + IPP_OP_ACKNOWLEDGE_JOB, /* Acknowledge-Job */ + IPP_OP_FETCH_DOCUMENT, /* Fetch-Document */ + IPP_OP_FETCH_JOB, /* Fetch-Job */ + IPP_OP_GET_OUTPUT_DEVICE_ATTRIBUTES, /* Get-Output-Device-Attributes */ + IPP_OP_UPDATE_ACTIVE_JOBS, /* Update-Active-Jobs */ + IPP_OP_DEREGISTER_OUTPUT_DEVICE, /* Deregister-Output-Device */ + IPP_OP_UPDATE_DOCUMENT_STATUS, /* Update-Document-Status */ + IPP_OP_UPDATE_JOB_STATUS, /* Update-Job-Status */ + IPP_OP_UPDATE_OUTPUT_DEVICE_ATTRIBUTES, + /* Update-Output-Device-Attributes */ + IPP_OP_GET_NEXT_DOCUMENT_DATA, /* Get-Next-Document-Data */ IPP_OP_PRIVATE = 0x4000, /* Reserved @private@ */ IPP_OP_CUPS_GET_DEFAULT, /* Get the default printer */ @@ -1021,5 +1034,5 @@ extern const char *ippStateString(ipp_state_t state) _CUPS_API_2_0; #endif /* !_CUPS_IPP_H_ */ /* - * End of "$Id: ipp.h 11806 2014-04-09 16:12:27Z msweet $". + * End of "$Id: ipp.h 12666 2015-05-25 19:38:09Z msweet $". */ diff --git a/cups/language.c b/cups/language.c index 7888af0989..0adf73ad6a 100644 --- a/cups/language.c +++ b/cups/language.c @@ -1,5 +1,5 @@ /* - * "$Id: language.c 12266 2014-11-19 16:05:28Z msweet $" + * "$Id: language.c 12262 2014-11-19 15:18:33Z msweet $" * * I18N/language support for CUPS. * @@ -1588,5 +1588,5 @@ cups_unquote(char *d, /* O - Unquoted string */ /* - * End of "$Id: language.c 12266 2014-11-19 16:05:28Z msweet $". + * End of "$Id: language.c 12262 2014-11-19 15:18:33Z msweet $". */ diff --git a/cups/mark.c b/cups/mark.c index 9580c0da7c..0c27628e55 100644 --- a/cups/mark.c +++ b/cups/mark.c @@ -1,5 +1,5 @@ /* - * "$Id: mark.c 11558 2014-02-06 18:33:34Z msweet $" + * "$Id: mark.c 12258 2014-11-19 12:38:44Z msweet $" * * Option marking routines for CUPS. * @@ -514,6 +514,12 @@ ppdMarkDefaults(ppd_file_t *ppd) /* I - PPD file record */ for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++) ppd_defaults(ppd, g); + + /* + * Finally, tag any conflicts (API compatibility) once at the end. + */ + + ppdConflicts(ppd); } @@ -710,7 +716,7 @@ ppd_defaults(ppd_file_t *ppd, /* I - PPD file */ for (i = g->num_options, o = g->options; i > 0; i --, o ++) if (_cups_strcasecmp(o->keyword, "PageRegion") != 0) - ppdMarkOption(ppd, o->keyword, o->defchoice); + ppd_mark_option(ppd, o->keyword, o->defchoice); for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++) ppd_defaults(ppd, sg); @@ -1078,5 +1084,5 @@ ppd_mark_option(ppd_file_t *ppd, /* I - PPD file */ /* - * End of "$Id: mark.c 11558 2014-02-06 18:33:34Z msweet $". + * End of "$Id: mark.c 12258 2014-11-19 12:38:44Z msweet $". */ diff --git a/cups/ppd-cache.c b/cups/ppd-cache.c index 851cb0bea1..5a5af77de3 100644 --- a/cups/ppd-cache.c +++ b/cups/ppd-cache.c @@ -1,5 +1,5 @@ /* - * "$Id: ppd-cache.c 12434 2015-01-28 16:29:06Z msweet $" + * "$Id: ppd-cache.c 12722 2015-06-08 22:00:19Z msweet $" * * PPD cache implementation for CUPS. * @@ -37,10 +37,326 @@ static int pwg_compare_finishings(_pwg_finishings_t *a, _pwg_finishings_t *b); static void pwg_free_finishings(_pwg_finishings_t *f); static void pwg_ppdize_name(const char *ipp, char *name, size_t namesize); +static void pwg_ppdize_resolution(ipp_attribute_t *attr, int element, int *xres, int *yres, char *name, size_t namesize); static void pwg_unppdize_name(const char *ppd, char *name, size_t namesize, const char *dashchars); +/* + * '_cupsConvertOptions()' - Convert printer options to standard IPP attributes. + * + * This functions converts PPD and CUPS-specific options to their standard IPP + * attributes and values and adds them to the specified IPP request. + */ + +int /* O - New number of copies */ +_cupsConvertOptions(ipp_t *request, /* I - IPP request */ + ppd_file_t *ppd, /* I - PPD file */ + _ppd_cache_t *pc, /* I - PPD cache info */ + ipp_attribute_t *media_col_sup, + /* I - media-col-supported values */ + ipp_attribute_t *doc_handling_sup, + /* I - multiple-document-handling-supported values */ + ipp_attribute_t *print_color_mode_sup, + /* I - Printer supports print-color-mode */ + const char *user, /* I - User info */ + const char *format, /* I - document-format value */ + int copies, /* I - Number of copies */ + int num_options, /* I - Number of options */ + cups_option_t *options) /* I - Options */ +{ + int i; /* Looping var */ + const char *keyword; /* PWG keyword */ + pwg_size_t *size; /* PWG media size */ + ipp_t *media_col, /* media-col value */ + *media_size; /* media-size value */ + const char *media_source, /* media-source value */ + *media_type, /* media-type value */ + *collate_str, /* multiple-document-handling value */ + *color_attr_name, /* Supported color attribute */ + *mandatory; /* Mandatory attributes */ + int num_finishings = 0, /* Number of finishing values */ + finishings[10]; /* Finishing enum values */ + ppd_choice_t *choice; /* Marked choice */ + + + /* + * Send standard IPP attributes... + */ + + if (pc->password && (keyword = cupsGetOption("job-password", num_options, options)) != NULL) + { + ippAddOctetString(request, IPP_TAG_OPERATION, "job-password", keyword, (int)strlen(keyword)); + + if ((keyword = cupsGetOption("job-password-encryption", num_options, options)) == NULL) + keyword = "none"; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "job-password-encryption", NULL, keyword); + } + + if (pc->account_id) + { + if ((keyword = cupsGetOption("job-account-id", num_options, options)) == NULL) + keyword = cupsGetOption("job-billing", num_options, options); + + if (keyword) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_NAME, "job-account-id", NULL, keyword); + } + + if (pc->accounting_user_id) + { + if ((keyword = cupsGetOption("job-accounting-user-id", num_options, options)) == NULL) + keyword = user; + + if (keyword) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_NAME, "job-accounting-user-id", NULL, keyword); + } + + for (mandatory = (const char *)cupsArrayFirst(pc->mandatory); mandatory; mandatory = (const char *)cupsArrayNext(pc->mandatory)) + { + if (strcmp(mandatory, "copies") && + strcmp(mandatory, "destination-uris") && + strcmp(mandatory, "finishings") && + strcmp(mandatory, "job-account-id") && + strcmp(mandatory, "job-accounting-user-id") && + strcmp(mandatory, "job-password") && + strcmp(mandatory, "job-password-encryption") && + strcmp(mandatory, "media") && + strncmp(mandatory, "media-col", 9) && + strcmp(mandatory, "multiple-document-handling") && + strcmp(mandatory, "output-bin") && + strcmp(mandatory, "print-color-mode") && + strcmp(mandatory, "print-quality") && + strcmp(mandatory, "sides") && + (keyword = cupsGetOption(mandatory, num_options, options)) != NULL) + { + _ipp_option_t *opt = _ippFindOption(mandatory); + /* Option type */ + ipp_tag_t value_tag = opt ? opt->value_tag : IPP_TAG_NAME; + /* Value type */ + + switch (value_tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + ippAddInteger(request, IPP_TAG_JOB, value_tag, mandatory, atoi(keyword)); + break; + case IPP_TAG_BOOLEAN : + ippAddBoolean(request, IPP_TAG_JOB, mandatory, !_cups_strcasecmp(keyword, "true")); + break; + case IPP_TAG_RANGE : + { + int lower, upper; /* Range */ + + if (sscanf(keyword, "%d-%d", &lower, &upper) != 2) + lower = upper = atoi(keyword); + + ippAddRange(request, IPP_TAG_JOB, mandatory, lower, upper); + } + break; + case IPP_TAG_STRING : + ippAddOctetString(request, IPP_TAG_JOB, mandatory, keyword, (int)strlen(keyword)); + break; + default : + if (!strcmp(mandatory, "print-color-mode") && !strcmp(keyword, "monochrome")) + { + if (ippContainsString(print_color_mode_sup, "auto-monochrome")) + keyword = "auto-monochrome"; + else if (ippContainsString(print_color_mode_sup, "process-monochrome") && !ippContainsString(print_color_mode_sup, "monochrome")) + keyword = "process-monochrome"; + } + + ippAddString(request, IPP_TAG_JOB, value_tag, mandatory, NULL, keyword); + break; + } + } + } + + if ((keyword = cupsGetOption("PageSize", num_options, options)) == NULL) + keyword = cupsGetOption("media", num_options, options); + + if ((size = _ppdCacheGetSize(pc, keyword)) != NULL) + { + /* + * Add a media-col value... + */ + + media_size = ippNew(); + ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, + "x-dimension", size->width); + ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, + "y-dimension", size->length); + + media_col = ippNew(); + ippAddCollection(media_col, IPP_TAG_ZERO, "media-size", media_size); + + media_source = _ppdCacheGetSource(pc, cupsGetOption("InputSlot", + num_options, + options)); + media_type = _ppdCacheGetType(pc, cupsGetOption("MediaType", + num_options, + options)); + + for (i = 0; i < media_col_sup->num_values; i ++) + { + if (!strcmp(media_col_sup->values[i].string.text, "media-left-margin")) + ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-left-margin", size->left); + else if (!strcmp(media_col_sup->values[i].string.text, "media-bottom-margin")) + ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-bottom-margin", size->bottom); + else if (!strcmp(media_col_sup->values[i].string.text, "media-right-margin")) + ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-right-margin", size->right); + else if (!strcmp(media_col_sup->values[i].string.text, "media-top-margin")) + ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, "media-top-margin", size->top); + else if (!strcmp(media_col_sup->values[i].string.text, "media-source") && media_source) + ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, "media-source", NULL, media_source); + else if (!strcmp(media_col_sup->values[i].string.text, "media-type") && media_type) + ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, "media-type", NULL, media_type); + } + + ippAddCollection(request, IPP_TAG_JOB, "media-col", media_col); + } + + if ((keyword = cupsGetOption("output-bin", num_options, options)) == NULL) + { + if ((choice = ppdFindMarkedChoice(ppd, "OutputBin")) != NULL) + keyword = _ppdCacheGetBin(pc, choice->choice); + } + + if (keyword) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-bin", NULL, keyword); + + color_attr_name = print_color_mode_sup ? "print-color-mode" : "output-mode"; + + if ((keyword = cupsGetOption("print-color-mode", num_options, options)) == NULL) + { + if ((choice = ppdFindMarkedChoice(ppd, "ColorModel")) != NULL) + { + if (!_cups_strcasecmp(choice->choice, "Gray")) + keyword = "monochrome"; + else + keyword = "color"; + } + } + + if (keyword && !strcmp(keyword, "monochrome")) + { + if (ippContainsString(print_color_mode_sup, "auto-monochrome")) + keyword = "auto-monochrome"; + else if (ippContainsString(print_color_mode_sup, "process-monochrome") && !ippContainsString(print_color_mode_sup, "monochrome")) + keyword = "process-monochrome"; + } + + if (keyword) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, color_attr_name, NULL, keyword); + + if ((keyword = cupsGetOption("print-quality", num_options, options)) != NULL) + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", atoi(keyword)); + else if ((choice = ppdFindMarkedChoice(ppd, "cupsPrintQuality")) != NULL) + { + if (!_cups_strcasecmp(choice->choice, "draft")) + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", IPP_QUALITY_DRAFT); + else if (!_cups_strcasecmp(choice->choice, "normal")) + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", IPP_QUALITY_NORMAL); + else if (!_cups_strcasecmp(choice->choice, "high")) + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", IPP_QUALITY_HIGH); + } + + if ((keyword = cupsGetOption("sides", num_options, options)) != NULL) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, keyword); + else if (pc->sides_option && (choice = ppdFindMarkedChoice(ppd, pc->sides_option)) != NULL) + { + if (!_cups_strcasecmp(choice->choice, pc->sides_1sided)) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, "one-sided"); + else if (!_cups_strcasecmp(choice->choice, pc->sides_2sided_long)) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, "two-sided-long-edge"); + if (!_cups_strcasecmp(choice->choice, pc->sides_2sided_short)) + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", NULL, "two-sided-short-edge"); + } + + /* + * Copies... + */ + + if ((keyword = cupsGetOption("multiple-document-handling", num_options, options)) != NULL) + { + if (strstr(keyword, "uncollated")) + keyword = "false"; + else + keyword = "true"; + } + else if ((keyword = cupsGetOption("collate", num_options, options)) == NULL) + keyword = "true"; + + if (format) + { + if (!_cups_strcasecmp(format, "image/gif") || + !_cups_strcasecmp(format, "image/jp2") || + !_cups_strcasecmp(format, "image/jpeg") || + !_cups_strcasecmp(format, "image/png") || + !_cups_strcasecmp(format, "image/tiff") || + !_cups_strncasecmp(format, "image/x-", 8)) + { + /* + * Collation makes no sense for single page image formats... + */ + + keyword = "false"; + } + else if (!_cups_strncasecmp(format, "image/", 6) || + !_cups_strcasecmp(format, "application/vnd.cups-raster")) + { + /* + * Multi-page image formats will have copies applied by the upstream + * filters... + */ + + copies = 1; + } + } + + if (doc_handling_sup) + { + if (!_cups_strcasecmp(keyword, "true")) + collate_str = "separate-documents-collated-copies"; + else + collate_str = "separate-documents-uncollated-copies"; + + for (i = 0; i < doc_handling_sup->num_values; i ++) + { + if (!strcmp(doc_handling_sup->values[i].string.text, collate_str)) + { + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "multiple-document-handling", NULL, collate_str); + break; + } + } + + if (i >= doc_handling_sup->num_values) + copies = 1; + } + + /* + * Map finishing options... + */ + + num_finishings = _ppdCacheGetFinishingValues(pc, num_options, options, (int)(sizeof(finishings) / sizeof(finishings[0])), finishings); + if (num_finishings > 0) + { + ippAddIntegers(request, IPP_TAG_JOB, IPP_TAG_ENUM, "finishings", num_finishings, finishings); + + if (copies > 1 && (keyword = cupsGetOption("job-impressions", num_options, options)) != NULL) + { + /* + * Send job-pages-per-set attribute to apply finishings correctly... + */ + + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", atoi(keyword) / copies); + } + } + + return (copies); +} + + /* * '_ppdCacheCreateWithFile()' - Create PPD cache and mapping data from a * written file. @@ -2466,6 +2782,604 @@ _ppdCacheWriteFile( } +/* + * '_ppdCreateFromIPP()' - Create a PPD file describing the capabilities + * of an IPP printer. + */ + +char * /* O - PPD filename or NULL on error */ +_ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ + size_t bufsize, /* I - Size of filename buffer */ + ipp_t *response) /* I - Get-Printer-Attributes response */ +{ + cups_file_t *fp; /* PPD file */ + ipp_attribute_t *attr, /* xxx-supported */ + *defattr, /* xxx-default */ + *x_dim, *y_dim; /* Media dimensions */ + ipp_t *media_size; /* Media size collection */ + char make[256], /* Make and model */ + *model, /* Model name */ + ppdname[PPD_MAX_NAME]; + /* PPD keyword */ + int i, j, /* Looping vars */ + count, /* Number of values */ + bottom, /* Largest bottom margin */ + left, /* Largest left margin */ + right, /* Largest right margin */ + top; /* Largest top margin */ + pwg_media_t *pwg; /* PWG media size */ + int xres, yres; /* Resolution values */ + struct lconv *loc = localeconv(); + /* Locale data */ + + + /* + * Range check input... + */ + + if (buffer) + *buffer = '\0'; + + if (!buffer || bufsize < 1 || !response) + return (NULL); + + /* + * Open a temporary file for the PPD... + */ + + if ((fp = cupsTempFile2(buffer, (int)bufsize)) == NULL) + return (NULL); + + /* + * Standard stuff for PPD file... + */ + + cupsFilePuts(fp, "*PPD-Adobe: \"4.3\"\n"); + cupsFilePuts(fp, "*FormatVersion: \"4.3\"\n"); + cupsFilePrintf(fp, "*FileVersion: \"%d.%d\"\n", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR); + cupsFilePuts(fp, "*LanguageVersion: English\n"); + cupsFilePuts(fp, "*LanguageEncoding: ISOLatin1\n"); + cupsFilePuts(fp, "*PSVersion: \"(3010.000) 0\"\n"); + cupsFilePuts(fp, "*LanguageLevel: \"3\"\n"); + cupsFilePuts(fp, "*FileSystem: False\n"); + cupsFilePuts(fp, "*PCFileName: \"ippeve.ppd\"\n"); + + if ((attr = ippFindAttribute(response, "printer-make-and-model", IPP_TAG_TEXT)) != NULL) + strlcpy(make, ippGetString(attr, 0, NULL), sizeof(make)); + else + strlcpy(make, "Unknown Printer", sizeof(make)); + + if (!_cups_strncasecmp(make, "Hewlett Packard ", 16) || + !_cups_strncasecmp(make, "Hewlett-Packard ", 16)) + { + model = make + 16; + strlcpy(make, "HP", sizeof(make)); + } + else if ((model = strchr(make, ' ')) != NULL) + *model++ = '\0'; + else + model = make; + + cupsFilePrintf(fp, "*Manufacturer: \"%s\"\n", make); + cupsFilePrintf(fp, "*ModelName: \"%s\"\n", model); + cupsFilePrintf(fp, "*Product: \"(%s)\"\n", model); + cupsFilePrintf(fp, "*NickName: \"%s\"\n", model); + cupsFilePrintf(fp, "*ShortNickName: \"%s\"\n", model); + + if ((attr = ippFindAttribute(response, "color-supported", IPP_TAG_BOOLEAN)) != NULL && ippGetBoolean(attr, 0)) + cupsFilePuts(fp, "*ColorDevice: True\n"); + else + cupsFilePuts(fp, "*ColorDevice: False\n"); + + cupsFilePrintf(fp, "*cupsVersion: %d.%d\n", CUPS_VERSION_MAJOR, CUPS_VERSION_MINOR); + cupsFilePuts(fp, "*cupsSNMPSupplies: False\n"); + cupsFilePuts(fp, "*cupsLanguages: \"en\"\n"); + + /* + * Filters... + */ + + if ((attr = ippFindAttribute(response, "document-format-supported", IPP_TAG_MIMETYPE)) != NULL) + { + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + const char *format = ippGetString(attr, i, NULL); + /* PDL */ + + if (!_cups_strcasecmp(format, "application/pdf")) + cupsFilePuts(fp, "*cupsFilter2: \"application/vnd.cups-pdf application/pdf 10 -\"\n"); + else if (!_cups_strcasecmp(format, "application/postscript")) + cupsFilePuts(fp, "*cupsFilter2: \"application/vnd.cups-postscript application/postscript 10 -\"\n"); + else if (_cups_strcasecmp(format, "application/octet-stream") && _cups_strcasecmp(format, "application/vnd.hp-pcl") && _cups_strcasecmp(format, "text/plain")) + cupsFilePrintf(fp, "*cupsFilter2: \"%s %s 10 -\"\n", format, format); + } + } + + /* + * PageSize/PageRegion/ImageableArea/PaperDimension + */ + + if ((attr = ippFindAttribute(response, "media-bottom-margin-supported", IPP_TAG_INTEGER)) != NULL) + { + for (i = 1, bottom = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++) + if (ippGetInteger(attr, i) > bottom) + bottom = ippGetInteger(attr, i); + } + else + bottom = 1270; + + if ((attr = ippFindAttribute(response, "media-left-margin-supported", IPP_TAG_INTEGER)) != NULL) + { + for (i = 1, left = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++) + if (ippGetInteger(attr, i) > left) + left = ippGetInteger(attr, i); + } + else + left = 635; + + if ((attr = ippFindAttribute(response, "media-right-margin-supported", IPP_TAG_INTEGER)) != NULL) + { + for (i = 1, right = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++) + if (ippGetInteger(attr, i) > right) + right = ippGetInteger(attr, i); + } + else + right = 635; + + if ((attr = ippFindAttribute(response, "media-top-margin-supported", IPP_TAG_INTEGER)) != NULL) + { + for (i = 1, top = ippGetInteger(attr, 0), count = ippGetCount(attr); i < count; i ++) + if (ippGetInteger(attr, i) > top) + top = ippGetInteger(attr, i); + } + else + top = 1270; + + if ((defattr = ippFindAttribute(response, "media-col-default", IPP_TAG_BEGIN_COLLECTION)) != NULL) + { + if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-size", IPP_TAG_BEGIN_COLLECTION)) != NULL) + { + media_size = ippGetCollection(attr, 0); + x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER); + y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER); + + if (x_dim && y_dim) + { + pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); + strlcpy(ppdname, pwg->ppd, sizeof(ppdname)); + } + else + strlcpy(ppdname, "Unknown", sizeof(ppdname)); + } + else + strlcpy(ppdname, "Unknown", sizeof(ppdname)); + } + + if ((attr = ippFindAttribute(response, "media-size-supported", IPP_TAG_BEGIN_COLLECTION)) != NULL) + { + cupsFilePrintf(fp, "*OpenUI *PageSize: PickOne\n" + "*OrderDependency: 10 AnySetup *PageSize\n" + "*DefaultPageSize: %s\n", ppdname); + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + media_size = ippGetCollection(attr, i); + x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER); + y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER); + + if (x_dim && y_dim) + { + char twidth[256], /* Width string */ + tlength[256]; /* Length string */ + + pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); + + _cupsStrFormatd(twidth, twidth + sizeof(twidth), pwg->width * 72.0 / 2540.0, loc); + _cupsStrFormatd(tlength, tlength + sizeof(tlength), pwg->length * 72.0 / 2540.0, loc); + + cupsFilePrintf(fp, "*PageSize %s: \"<>setpagedevice\"\n", pwg->ppd, twidth, tlength); + } + } + cupsFilePuts(fp, "*CloseUI: *PageSize\n"); + + cupsFilePrintf(fp, "*OpenUI *PageRegion: PickOne\n" + "*OrderDependency: 10 AnySetup *PageRegion\n" + "*DefaultPageRegion: %s\n", ppdname); + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + media_size = ippGetCollection(attr, i); + x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER); + y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER); + + if (x_dim && y_dim) + { + char twidth[256], /* Width string */ + tlength[256]; /* Length string */ + + pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); + + _cupsStrFormatd(twidth, twidth + sizeof(twidth), pwg->width * 72.0 / 2540.0, loc); + _cupsStrFormatd(tlength, tlength + sizeof(tlength), pwg->length * 72.0 / 2540.0, loc); + + cupsFilePrintf(fp, "*PageRegion %s: \"<>setpagedevice\"\n", pwg->ppd, twidth, tlength); + } + } + cupsFilePuts(fp, "*CloseUI: *PageRegion\n"); + + cupsFilePrintf(fp, "*DefaultImageableArea: %s\n" + "*DefaultPaperDimension: %s\n", ppdname, ppdname); + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + media_size = ippGetCollection(attr, i); + x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER); + y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER); + + if (x_dim && y_dim) + { + char tleft[256], /* Left string */ + tbottom[256], /* Bottom string */ + tright[256], /* Right string */ + ttop[256], /* Top string */ + twidth[256], /* Width string */ + tlength[256]; /* Length string */ + + pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0)); + + _cupsStrFormatd(tleft, tleft + sizeof(tleft), left * 72.0 / 2540.0, loc); + _cupsStrFormatd(tbottom, tbottom + sizeof(tbottom), bottom * 72.0 / 2540.0, loc); + _cupsStrFormatd(tright, tright + sizeof(tright), (pwg->width - right) * 72.0 / 2540.0, loc); + _cupsStrFormatd(ttop, ttop + sizeof(ttop), (pwg->length - top) * 72.0 / 2540.0, loc); + _cupsStrFormatd(twidth, twidth + sizeof(twidth), pwg->width * 72.0 / 2540.0, loc); + _cupsStrFormatd(tlength, tlength + sizeof(tlength), pwg->length * 72.0 / 2540.0, loc); + + cupsFilePrintf(fp, "*ImageableArea %s: \"%s %s %s %s\"\n", pwg->ppd, tleft, tbottom, tright, ttop); + cupsFilePrintf(fp, "*PaperDimension %s: \"%s %s\"\n", pwg->ppd, twidth, tlength); + } + } + } + + /* + * InputSlot... + */ + + if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-source", IPP_TAG_KEYWORD)) != NULL) + pwg_ppdize_name(ippGetString(attr, 0, NULL), ppdname, sizeof(ppdname)); + else + strlcpy(ppdname, "Unknown", sizeof(ppdname)); + + if ((attr = ippFindAttribute(response, "media-source-supported", IPP_TAG_KEYWORD)) != NULL && (count = ippGetCount(attr)) > 1) + { + static const char * const sources[][2] = + { + { "Auto", "Automatic" }, + { "Main", "Main" }, + { "Alternate", "Alternate" }, + { "LargeCapacity", "Large Capacity" }, + { "Manual", "Manual" }, + { "Envelope", "Envelope" }, + { "Disc", "Disc" }, + { "Photo", "Photo" }, + { "Hagaki", "Hagaki" }, + { "MainRoll", "Main Roll" }, + { "AlternateRoll", "Alternate Roll" }, + { "Top", "Top" }, + { "Middle", "Middle" }, + { "Bottom", "Bottom" }, + { "Side", "Side" }, + { "Left", "Left" }, + { "Right", "Right" }, + { "Center", "Center" }, + { "Rear", "Rear" }, + { "ByPassTray", "Multipurpose" }, + { "Tray1", "Tray 1" }, + { "Tray2", "Tray 2" }, + { "Tray3", "Tray 3" }, + { "Tray4", "Tray 4" }, + { "Tray5", "Tray 5" }, + { "Tray6", "Tray 6" }, + { "Tray7", "Tray 7" }, + { "Tray8", "Tray 8" }, + { "Tray9", "Tray 9" }, + { "Tray10", "Tray 10" }, + { "Tray11", "Tray 11" }, + { "Tray12", "Tray 12" }, + { "Tray13", "Tray 13" }, + { "Tray14", "Tray 14" }, + { "Tray15", "Tray 15" }, + { "Tray16", "Tray 16" }, + { "Tray17", "Tray 17" }, + { "Tray18", "Tray 18" }, + { "Tray19", "Tray 19" }, + { "Tray20", "Tray 20" }, + { "Roll1", "Roll 1" }, + { "Roll2", "Roll 2" }, + { "Roll3", "Roll 3" }, + { "Roll4", "Roll 4" }, + { "Roll5", "Roll 5" }, + { "Roll6", "Roll 6" }, + { "Roll7", "Roll 7" }, + { "Roll8", "Roll 8" }, + { "Roll9", "Roll 9" }, + { "Roll10", "Roll 10" } + }; + + cupsFilePrintf(fp, "*OpenUI *InputSlot: PickOne\n" + "*OrderDependency: 10 AnySetup *InputSlot\n" + "*DefaultInputSlot: %s\n", ppdname); + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + pwg_ppdize_name(ippGetString(attr, i, NULL), ppdname, sizeof(ppdname)); + + for (j = 0; j < (int)(sizeof(sources) / sizeof(sources[0])); j ++) + if (!strcmp(sources[j][0], ppdname)) + { + cupsFilePrintf(fp, "*InputSlot %s/%s: \"<>setpagedevice\"\n", ppdname, sources[j][1], j); + break; + } + } + cupsFilePuts(fp, "*CloseUI: *InputSlot\n"); + } + + /* + * MediaType... + */ + + if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-type", IPP_TAG_KEYWORD)) != NULL) + pwg_ppdize_name(ippGetString(attr, 0, NULL), ppdname, sizeof(ppdname)); + else + strlcpy(ppdname, "Unknown", sizeof(ppdname)); + + if ((attr = ippFindAttribute(response, "media-type-supported", IPP_TAG_KEYWORD)) != NULL && (count = ippGetCount(attr)) > 1) + { + static const char * const types[][2] = + { /* Media type strings (far from complete) */ + { "Auto", "Automatic" }, + { "Cardstock", "Cardstock" }, + { "Disc", "CD/DVD/Bluray" }, + { "Envelope", "Envelope" }, + { "Labels", "Label" }, + { "Other", "Other" }, + { "Photographic", "Photo" }, + { "PhotographicGlossy", "Glossy Photo" }, + { "PhotographicHighGloss", "High-Gloss Photo" }, + { "PhotographicMatte", "Matte Photo" }, + { "PhotographicSatin", "Satin Photo" }, + { "PhotographicSemiGloss", "Semi-Gloss Photo" }, + { "Stationery", "Plain Paper" }, + { "StationeryLetterhead", "Letterhead" }, + { "Transparency", "Transparency" } + }; + + cupsFilePrintf(fp, "*OpenUI *MediaType: PickOne\n" + "*OrderDependency: 10 AnySetup *MediaType\n" + "*DefaultMediaType: %s\n", ppdname); + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + pwg_ppdize_name(ippGetString(attr, i, NULL), ppdname, sizeof(ppdname)); + + for (j = 0; j < (int)(sizeof(types) / sizeof(types[0])); j ++) + if (!strcmp(types[j][0], ppdname)) + { + cupsFilePrintf(fp, "*MediaType %s/%s: \"<>setpagedevice\"\n", ppdname, types[j][1], ppdname); + break; + } + + if (j >= (int)(sizeof(types) / sizeof(types[0]))) + cupsFilePrintf(fp, "*MediaType %s: \"<>setpagedevice\"\n", ppdname, ppdname); + + } + cupsFilePuts(fp, "*CloseUI: *MediaType\n"); + } + + /* + * ColorModel... + */ + + if ((attr = ippFindAttribute(response, "pwg-raster-document-type-supported", IPP_TAG_KEYWORD)) == NULL) + attr = ippFindAttribute(response, "print-color-mode-supported", IPP_TAG_KEYWORD); + + if (attr) + { + const char *default_color = NULL; /* Default */ + + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + const char *keyword = ippGetString(attr, i, NULL); + /* Keyword for color/bit depth */ + + if (!strcmp(keyword, "black_1") || !strcmp(keyword, "bi-level") || !strcmp(keyword, "process-bi-level")) + { + if (!default_color) + cupsFilePuts(fp, "*OpenUI *ColorModel/Color Mode: PickOne\n" + "*OrderDependency: 10 AnySetup *ColorModel\n"); + + cupsFilePuts(fp, "*ColorModel FastGray/Fast Grayscale: \"<>setpagedevice\"\n"); + + if (!default_color) + default_color = "FastGray"; + } + else if (!strcmp(keyword, "sgray_8") || !strcmp(keyword, "monochrome") || !strcmp(keyword, "process-monochrome")) + { + if (!default_color) + cupsFilePuts(fp, "*OpenUI *ColorModel/Color Mode: PickOne\n" + "*OrderDependency: 10 AnySetup *ColorModel\n"); + + cupsFilePuts(fp, "*ColorModel Gray/Grayscale: \"<>setpagedevice\"\n"); + + if (!default_color || !strcmp(default_color, "FastGray")) + default_color = "Gray"; + } + else if (!strcmp(keyword, "srgb_8") || !strcmp(keyword, "color")) + { + if (!default_color) + cupsFilePuts(fp, "*OpenUI *ColorModel/Color Mode: PickOne\n" + "*OrderDependency: 10 AnySetup *ColorModel\n"); + + cupsFilePuts(fp, "*ColorModel RGB/Color: \"<>setpagedevice\"\n"); + + default_color = "RGB"; + } + } + + if (default_color) + { + cupsFilePrintf(fp, "*DefaultColorModel: %s\n", default_color); + cupsFilePuts(fp, "*CloseUI: *ColorModel\n"); + } + } + + /* + * Duplex... + */ + + if ((attr = ippFindAttribute(response, "sides-supported", IPP_TAG_KEYWORD)) != NULL && ippContainsString(attr, "two-sided-long-edge")) + { + cupsFilePuts(fp, "*OpenUI *Duplex/2-Sided Printing: PickOne\n" + "*OrderDependency: 10 AnySetup *Duplex\n" + "*DefaultDuplex: None\n" + "*Duplex None/Off (1-Sided): \"<>setpagedevice\"\n" + "*Duplex DuplexNoTumble/Long-Edge (Portrait): \"<>setpagedevice\"\n" + "*Duplex DuplexTumble/Short-Edge (Landscape): \"<>setpagedevice\"\n" + "*CloseUI: *Duplex\n"); + + if ((attr = ippFindAttribute(response, "pwg-raster-document-sheet-back", IPP_TAG_KEYWORD)) != NULL) + { + const char *keyword = ippGetString(attr, 0, NULL); + /* Keyword value */ + + if (!strcmp(keyword, "flipped")) + cupsFilePuts(fp, "*cupsBackSide: Flipped\n"); + else if (!strcmp(keyword, "manual-tumble")) + cupsFilePuts(fp, "*cupsBackSide: ManualTumble\n"); + else if (!strcmp(keyword, "normal")) + cupsFilePuts(fp, "*cupsBackSide: Normal\n"); + else + cupsFilePuts(fp, "*cupsBackSide: Rotated\n"); + } + else if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL) + { + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + const char *dm = ippGetString(attr, i, NULL); + /* DM value */ + + if (!_cups_strcasecmp(dm, "DM1")) + { + cupsFilePuts(fp, "*cupsBackSide: Normal\n"); + break; + } + else if (!_cups_strcasecmp(dm, "DM2")) + { + cupsFilePuts(fp, "*cupsBackSide: Flipped\n"); + break; + } + else if (!_cups_strcasecmp(dm, "DM3")) + { + cupsFilePuts(fp, "*cupsBackSide: Rotated\n"); + break; + } + else if (!_cups_strcasecmp(dm, "DM4")) + { + cupsFilePuts(fp, "*cupsBackSide: ManualTumble\n"); + break; + } + } + } + } + + /* + * cupsPrintQuality and DefaultResolution... + */ + + if ((attr = ippFindAttribute(response, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL) + { + count = ippGetCount(attr); + + pwg_ppdize_resolution(attr, count / 2, &xres, &yres, ppdname, sizeof(ppdname)); + cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname); + + cupsFilePuts(fp, "*OpenUI *cupsPrintQuality/Print Quality: PickOne\n" + "*OrderDependency: 10 AnySetup *cupsPrintQuality\n" + "*DefaultcupsPrintQuality: Normal\n"); + if (count > 2) + { + pwg_ppdize_resolution(attr, 0, &xres, &yres, NULL, 0); + cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<>setpagedevice\"\n", xres, yres); + } + pwg_ppdize_resolution(attr, count / 2, &xres, &yres, NULL, 0); + cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<>setpagedevice\"\n", xres, yres); + if (count > 1) + { + pwg_ppdize_resolution(attr, count - 1, &xres, &yres, NULL, 0); + cupsFilePrintf(fp, "*cupsPrintQuality High: \"<>setpagedevice\"\n", xres, yres); + } + + cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n"); + } + else if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL) + { + int lowdpi = 0, hidpi = 0; /* Lower and higher resolution */ + + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + const char *rs = ippGetString(attr, i, NULL); + /* RS value */ + + if (_cups_strncasecmp(rs, "RS", 2)) + continue; + + lowdpi = atoi(rs + 2); + if ((rs = strrchr(rs, '-')) != NULL) + hidpi = atoi(rs + 1); + else + hidpi = lowdpi; + break; + } + + if (lowdpi == 0) + { + /* + * Invalid "urf-supported" value... + */ + + cupsFilePuts(fp, "*DefaultResolution: 300dpi\n"); + } + else + { + /* + * Generate print qualities based on low and high DPIs... + */ + + cupsFilePrintf(fp, "*DefaultResolution: %ddpi\n", lowdpi); + + cupsFilePuts(fp, "*OpenUI *cupsPrintQuality/Print Quality: PickOne\n" + "*OrderDependency: 10 AnySetup *cupsPrintQuality\n" + "*DefaultcupsPrintQuality: Normal\n"); + if ((lowdpi & 1) == 0) + cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<>setpagedevice\"\n", lowdpi, lowdpi / 2); + cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<>setpagedevice\"\n", lowdpi, lowdpi); + if (hidpi > lowdpi) + cupsFilePrintf(fp, "*cupsPrintQuality High: \"<>setpagedevice\"\n", hidpi, hidpi); + cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n"); + } + } + else if ((attr = ippFindAttribute(response, "printer-resolution-default", IPP_TAG_RESOLUTION)) != NULL) + { + pwg_ppdize_resolution(attr, 0, &xres, &yres, ppdname, sizeof(ppdname)); + cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname); + } + else + cupsFilePuts(fp, "*DefaultResolution: 300dpi\n"); + + /* + * Close up and return... + */ + + cupsFileClose(fp); + + return (buffer); +} + + /* * '_pwgInputSlotForSource()' - Get the InputSlot name for the given PWG * media-source. @@ -2677,6 +3591,41 @@ pwg_ppdize_name(const char *ipp, /* I - IPP keyword */ } + +/* + * 'pwg_ppdize_resolution()' - Convert PWG resolution values to PPD values. + */ + +static void +pwg_ppdize_resolution( + ipp_attribute_t *attr, /* I - Attribute to convert */ + int element, /* I - Element to convert */ + int *xres, /* O - X resolution in DPI */ + int *yres, /* O - Y resolution in DPI */ + char *name, /* I - Name buffer */ + size_t namesize) /* I - Size of name buffer */ +{ + ipp_res_t units; /* Units for resolution */ + + + *xres = ippGetResolution(attr, element, yres, &units); + + if (units == IPP_RES_PER_CM) + { + *xres = (int)(*xres * 2.54); + *yres = (int)(*yres * 2.54); + } + + if (name && namesize > 4) + { + if (*xres == *yres) + snprintf(name, namesize, "%ddpi", *xres); + else + snprintf(name, namesize, "%dx%ddpi", *xres, *yres); + } +} + + /* * 'pwg_unppdize_name()' - Convert a PPD keyword to a lowercase IPP keyword. */ @@ -2731,5 +3680,5 @@ pwg_unppdize_name(const char *ppd, /* I - PPD keyword */ /* - * End of "$Id: ppd-cache.c 12434 2015-01-28 16:29:06Z msweet $". + * End of "$Id: ppd-cache.c 12722 2015-06-08 22:00:19Z msweet $". */ diff --git a/cups/ppd-private.h b/cups/ppd-private.h index c1376d2cb9..f6f63294f6 100644 --- a/cups/ppd-private.h +++ b/cups/ppd-private.h @@ -1,9 +1,9 @@ /* - * "$Id: ppd-private.h 11558 2014-02-06 18:33:34Z msweet $" + * "$Id: ppd-private.h 12722 2015-06-08 22:00:19Z msweet $" * * Private PPD definitions for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2015 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -49,7 +49,7 @@ extern "C" { * Constants... */ -# define _PPD_CACHE_VERSION 6 /* Version number in cache file */ +# define _PPD_CACHE_VERSION 7 /* Version number in cache file */ /* @@ -155,6 +155,7 @@ struct _ppd_cache_s /**** PPD cache and PWG conversion data ****/ * Prototypes... */ +extern int _cupsConvertOptions(ipp_t *request, ppd_file_t *ppd, _ppd_cache_t *pc, ipp_attribute_t *media_col_sup, ipp_attribute_t *doc_handling_sup, ipp_attribute_t *print_color_mode_sup, const char *user, const char *format, int copies, int num_options, cups_option_t *options); extern _ppd_cache_t *_ppdCacheCreateWithFile(const char *filename, ipp_t **attrs); extern _ppd_cache_t *_ppdCacheCreateWithPPD(ppd_file_t *ppd); @@ -187,6 +188,7 @@ extern const char *_ppdCacheGetType(_ppd_cache_t *pc, const char *media_type); extern int _ppdCacheWriteFile(_ppd_cache_t *pc, const char *filename, ipp_t *attrs); +extern char *_ppdCreateFromIPP(char *buffer, size_t bufsize, ipp_t *response); extern void _ppdFreeLanguages(cups_array_t *languages); extern cups_encoding_t _ppdGetEncoding(const char *name); extern cups_array_t *_ppdGetLanguages(ppd_file_t *ppd); @@ -221,5 +223,5 @@ extern const char *_pwgPageSizeForMedia(pwg_media_t *media, #endif /* !_CUPS_PPD_PRIVATE_H_ */ /* - * End of "$Id: ppd-private.h 11558 2014-02-06 18:33:34Z msweet $". + * End of "$Id: ppd-private.h 12722 2015-06-08 22:00:19Z msweet $". */ diff --git a/cups/test.ppd b/cups/test.ppd index fc453a6499..1f64fe55ef 100644 --- a/cups/test.ppd +++ b/cups/test.ppd @@ -14,7 +14,7 @@ *% *% Copyright 2007-2010 by Apple Inc. *% Copyright 2002-2006 by Easy Software Products. -*% +*% *% These coded instructions, statements, and computer programs are the *% property of Apple Inc. and are protected by Federal copyright *% law. Distribution and use rights are outlined in the file "LICENSE.txt" @@ -22,7 +22,7 @@ *% file is missing or damaged, see the license at "http://www.cups.org/". *FormatVersion: "4.3" *FileVersion: "1.3" -*LanguageVersion: English +*LanguageVersion: English *LanguageEncoding: ISOLatin1 *PCFileName: "TEST.PPD" *Manufacturer: "ESP" @@ -104,7 +104,7 @@ *fr_CA.PageRegion A4/French Canadian A4: "" *fr_CA.PageRegion Env10/French Canadian #10 Envelope: "" -*DefaultImageableArea: Letter +*DefaultImageableArea: Letter *ImageableArea Letter: "18 36 594 756" *ImageableArea Letter.Banner: "18 0 594 792" *ImageableArea Letter.Fullbleed: "0 0 612 792" @@ -145,6 +145,15 @@ *MediaType Transparency/Transparency Film: "MediaType=Transparency" *CloseUI: *MediaType +*OpenUI *OutputBin/Output Tray: PickOne +*OrderDependency: 25 AnySetup *OutputBin +*DefaultOutputBin: Tray1 +*OutputBin Auto/Automatic Tray: "OutputBin=Auto" +*OutputBin Tray1/Tray 1: "OutputBin=Tray1" +*OutputBin Tray2/Tray 2: "OutputBin=Tray2" +*OutputBin MainTray/Main Tray: "OutputBin=MainTray" +*CloseUI: *OutputBin + *OpenUI *Duplex/2-Sided Printing: PickOne *OrderDependency: 10 DocumentSetup *Duplex *DefaultDuplex: None diff --git a/cups/testfile.c b/cups/testfile.c index 16e52c3e69..61db0807bc 100644 --- a/cups/testfile.c +++ b/cups/testfile.c @@ -1,5 +1,5 @@ /* - * "$Id: testfile.c 12578 2015-03-30 19:07:29Z msweet $" + * "$Id: testfile.c 12577 2015-03-30 19:07:17Z msweet $" * * File test program for CUPS. * @@ -825,5 +825,5 @@ read_write_tests(int compression) /* I - Use compression? */ /* - * End of "$Id: testfile.c 12578 2015-03-30 19:07:29Z msweet $". + * End of "$Id: testfile.c 12577 2015-03-30 19:07:17Z msweet $". */ diff --git a/cups/testhttp.c b/cups/testhttp.c index cd8cb5e374..cb5345ff3d 100644 --- a/cups/testhttp.c +++ b/cups/testhttp.c @@ -1,5 +1,5 @@ /* - * "$Id: testhttp.c 12028 2014-07-15 14:01:27Z msweet $" + * "$Id: testhttp.c 12678 2015-05-28 19:09:48Z msweet $" * * HTTP test program for CUPS. * @@ -645,7 +645,6 @@ main(int argc, /* I - Number of command-line arguments */ if (lcreds && cupsArrayCount(creds) == cupsArrayCount(lcreds)) { - int i; http_credential_t *cred, *lcred; for (i = 1, cred = (http_credential_t *)cupsArrayFirst(creds), lcred = (http_credential_t *)cupsArrayFirst(lcreds); @@ -890,5 +889,5 @@ main(int argc, /* I - Number of command-line arguments */ /* - * End of "$Id: testhttp.c 12028 2014-07-15 14:01:27Z msweet $". + * End of "$Id: testhttp.c 12678 2015-05-28 19:09:48Z msweet $". */ diff --git a/cups/testppd.c b/cups/testppd.c index d858106181..dbd896e3fe 100644 --- a/cups/testppd.c +++ b/cups/testppd.c @@ -1,9 +1,9 @@ /* - * "$Id: testppd.c 12604 2015-05-06 01:43:05Z msweet $" + * "$Id: testppd.c 12603 2015-05-06 01:42:51Z msweet $" * * PPD test program for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2015 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -51,6 +51,11 @@ static const char *default_code = "%%EndFeature\n" "} stopped cleartomark\n" "[{\n" + "%%BeginFeature: *OutputBin Tray1\n" + "OutputBin=Tray1\n" + "%%EndFeature\n" + "} stopped cleartomark\n" + "[{\n" "%%BeginFeature: *MediaType Plain\n" "MediaType=Plain\n" "%%EndFeature\n" @@ -80,6 +85,11 @@ static const char *custom_code = "%%EndFeature\n" "} stopped cleartomark\n" "[{\n" + "%%BeginFeature: *OutputBin Tray1\n" + "OutputBin=Tray1\n" + "%%EndFeature\n" + "} stopped cleartomark\n" + "[{\n" "%%BeginFeature: *IntOption None\n" "%%EndFeature\n" "} stopped cleartomark\n" @@ -853,6 +863,47 @@ main(int argc, /* I - Number of command-line arguments */ status ++; } } + else if (!strncmp(argv[1], "ipp://", 6) || !strncmp(argv[1], "ipps://", 7)) + { + /* + * ipp://... or ipps://... + */ + + http_t *http; /* Connection to printer */ + ipp_t *request, /* Get-Printer-Attributes request */ + *response; /* Get-Printer-Attributes response */ + char scheme[32], /* URI scheme */ + userpass[256], /* Username:password */ + host[256], /* Hostname */ + resource[256]; /* Resource path */ + int port; /* Port number */ + + if (httpSeparateURI(HTTP_URI_CODING_ALL, argv[1], scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) + { + printf("Bad URI \"%s\".\n", argv[1]); + return (1); + } + + http = httpConnect2(host, port, NULL, AF_UNSPEC, !strcmp(scheme, "ipps") ? HTTP_ENCRYPTION_ALWAYS : HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL); + if (!http) + { + printf("Unable to connect to \"%s:%d\": %s\n", host, port, cupsLastErrorString()); + return (1); + } + + request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, argv[1]); + response = cupsDoRequest(http, request, resource); + + if (_ppdCreateFromIPP(buffer, sizeof(buffer), response)) + printf("Created PPD: %s\n", buffer); + else + puts("Unable to create PPD."); + + ippDelete(response); + httpClose(http); + return (0); + } else { const char *filename; /* PPD filename */ @@ -1119,5 +1170,5 @@ main(int argc, /* I - Number of command-line arguments */ /* - * End of "$Id: testppd.c 12604 2015-05-06 01:43:05Z msweet $". + * End of "$Id: testppd.c 12603 2015-05-06 01:42:51Z msweet $". */ diff --git a/cups/tls-darwin.c b/cups/tls-darwin.c index 02a44045da..377919ddaf 100644 --- a/cups/tls-darwin.c +++ b/cups/tls-darwin.c @@ -1,5 +1,5 @@ /* - * "$Id: tls-darwin.c 12481 2015-02-03 12:45:14Z msweet $" + * "$Id: tls-darwin.c 12675 2015-05-28 01:14:32Z msweet $" * * TLS support code for CUPS on OS X. * @@ -26,14 +26,6 @@ extern char **environ; -/* - * Test define - set to 1 to use SSLSetEnabledCiphers. Currently disabled (0) - * because of . - */ - -#define USE_SET_ENABLED_CIPHERS 0 - - /* * Local globals... */ @@ -49,8 +41,8 @@ static char *tls_keypath = NULL; /* Server cert keychain path */ static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER; /* Mutex for keychain/certs */ -static int tls_options = 0;/* Options for TLS connections */ #endif /* HAVE_SECKEYCHAINOPEN */ +static int tls_options = -1;/* Options for TLS connections */ /* @@ -1017,7 +1009,14 @@ _httpTLSStart(http_t *http) /* I - HTTP connection */ http_credential_t *credential; /* Credential data */ - DEBUG_printf(("7_httpTLSStart(http=%p)", http)); + DEBUG_printf(("3_httpTLSStart(http=%p)", http)); + + if (tls_options < 0) + { + DEBUG_puts("4_httpTLSStart: Setting defaults."); + _cupsSetDefaults(); + DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options)); + } #ifdef HAVE_SECKEYCHAINOPEN if (http->mode == _HTTP_MODE_SERVER && !tls_keychain) @@ -1061,11 +1060,20 @@ _httpTLSStart(http_t *http) /* I - HTTP connection */ if (!error) { - error = SSLSetProtocolVersionMin(http->tls, (tls_options & _HTTP_TLS_ALLOW_SSL3) ? kSSLProtocol3 : kTLSProtocol1); - DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin, error=%d", (int)error)); + SSLProtocol minProtocol; + + if (tls_options & _HTTP_TLS_DENY_TLS10) + minProtocol = kTLSProtocol11; + else if (tls_options & _HTTP_TLS_ALLOW_SSL3) + minProtocol = kSSLProtocol3; + else + minProtocol = kTLSProtocol1; + + error = SSLSetProtocolVersionMin(http->tls, minProtocol); + DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", minProtocol, (int)error)); } -# if USE_SET_ENABLED_CIPHERS +# if HAVE_SSLSETENABLEDCIPHERS if (!error) { SSLCipherSuite supported[100]; /* Supported cipher suites */ @@ -1130,6 +1138,7 @@ _httpTLSStart(http_t *http) /* I - HTTP connection */ case TLS_RSA_PSK_WITH_NULL_SHA256 : case TLS_RSA_PSK_WITH_NULL_SHA384 : case SSL_RSA_WITH_DES_CBC_MD5 : + DEBUG_printf(("4_httpTLSStart: Excluding insecure cipher suite %d", supported[i])); break; /* RC4 cipher suites that should only be used as a last resort */ @@ -1144,8 +1153,52 @@ _httpTLSStart(http_t *http) /* I - HTTP connection */ case TLS_RSA_PSK_WITH_RC4_128_SHA : if (tls_options & _HTTP_TLS_ALLOW_RC4) enabled[num_enabled ++] = supported[i]; + else + DEBUG_printf(("4_httpTLSStart: Excluding RC4 cipher suite %d", supported[i])); break; + /* DH/DHE cipher suites that are problematic with parameters < 1024 bits */ + case TLS_DH_DSS_WITH_AES_128_CBC_SHA : + case TLS_DH_RSA_WITH_AES_128_CBC_SHA : + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA : + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA : + case TLS_DH_DSS_WITH_AES_256_CBC_SHA : + case TLS_DH_RSA_WITH_AES_256_CBC_SHA : + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA : + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA : + case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA : + case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA : +// case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA : + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA : + case TLS_DH_DSS_WITH_AES_128_CBC_SHA256 : + case TLS_DH_RSA_WITH_AES_128_CBC_SHA256 : + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 : + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 : + case TLS_DH_DSS_WITH_AES_256_CBC_SHA256 : + case TLS_DH_RSA_WITH_AES_256_CBC_SHA256 : + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 : + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 : + case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA : + case TLS_DHE_PSK_WITH_AES_128_CBC_SHA : + case TLS_DHE_PSK_WITH_AES_256_CBC_SHA : +// case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 : +// case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 : + case TLS_DH_RSA_WITH_AES_128_GCM_SHA256 : + case TLS_DH_RSA_WITH_AES_256_GCM_SHA384 : +// case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 : +// case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 : + case TLS_DH_DSS_WITH_AES_128_GCM_SHA256 : + case TLS_DH_DSS_WITH_AES_256_GCM_SHA384 : + case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 : + case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 : + case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 : + case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 : + if (tls_options & _HTTP_TLS_ALLOW_DH) + enabled[num_enabled ++] = supported[i]; + else + DEBUG_printf(("4_httpTLSStart: Excluding DH/DHE cipher suite %d", supported[i])); + break; + /* Anything else we'll assume is secure */ default : enabled[num_enabled ++] = supported[i]; @@ -1157,7 +1210,7 @@ _httpTLSStart(http_t *http) /* I - HTTP connection */ error = SSLSetEnabledCiphers(http->tls, enabled, num_enabled); } } -#endif /* USE_SET_ENABLED_CIPHERS */ +#endif /* HAVE_SSLSETENABLEDCIPHERS */ if (!error && http->mode == _HTTP_MODE_CLIENT) { @@ -1782,5 +1835,5 @@ http_cdsa_write( /* - * End of "$Id: tls-darwin.c 12481 2015-02-03 12:45:14Z msweet $". + * End of "$Id: tls-darwin.c 12675 2015-05-28 01:14:32Z msweet $". */ diff --git a/cups/tls-gnutls.c b/cups/tls-gnutls.c index 00ff2234c5..3da05e2815 100644 --- a/cups/tls-gnutls.c +++ b/cups/tls-gnutls.c @@ -1,5 +1,5 @@ /* - * "$Id: tls-gnutls.c 12481 2015-02-03 12:45:14Z msweet $" + * "$Id: tls-gnutls.c 12670 2015-05-27 19:48:05Z msweet $" * * TLS support code for CUPS using GNU TLS. * @@ -36,7 +36,7 @@ static char *tls_keypath = NULL; /* Server cert keychain path */ static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER; /* Mutex for keychain/certs */ -static int tls_options = 0;/* Options for TLS connections */ +static int tls_options = -1;/* Options for TLS connections */ /* @@ -1028,9 +1028,18 @@ _httpTLSStart(http_t *http) /* I - Connection to server */ int status; /* Status of handshake */ gnutls_certificate_credentials_t *credentials; /* TLS credentials */ + char priority_string[1024]; + /* Priority string */ - DEBUG_printf(("7_httpTLSStart(http=%p)", http)); + DEBUG_printf(("3_httpTLSStart(http=%p)", http)); + + if (tls_options < 0) + { + DEBUG_puts("4_httpTLSStart: Setting defaults."); + _cupsSetDefaults(); + DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options)); + } if (http->mode == _HTTP_MODE_SERVER && !tls_keypath) { @@ -1199,28 +1208,28 @@ _httpTLSStart(http_t *http) /* I - Connection to server */ return (-1); } -#ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT - if (!tls_options) - gnutls_priority_set_direct(http->tls, "NORMAL:-ARCFOUR-128:+VERS-TLS-ALL:-VERS-SSL3.0", NULL); - else if ((tls_options & _HTTP_TLS_ALLOW_SSL3) && (tls_options & _HTTP_TLS_ALLOW_RC4)) - gnutls_priority_set_direct(http->tls, "NORMAL", NULL); + strlcpy(priority_string, "NORMAL", sizeof(priority_string)); + + if (tls_options & _HTTP_TLS_DENY_TLS10) + strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-TLS1.0:-VERS-SSL3.0", sizeof(priority_string)); else if (tls_options & _HTTP_TLS_ALLOW_SSL3) - gnutls_priority_set_direct(http->tls, "NORMAL:-ARCFOUR-128:+VERS-TLS-ALL", NULL); + strlcat(priority_string, ":+VERS-TLS-ALL", sizeof(priority_string)); else - gnutls_priority_set_direct(http->tls, "NORMAL:+VERS-TLS-ALL:-VERS-SSL3.0", NULL); + strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-SSL3.0", sizeof(priority_string)); + + if (!(tls_options & _HTTP_TLS_ALLOW_RC4)) + strlcat(priority_string, ":-ARCFOUR-128", sizeof(priority_string)); + + if (!(tls_options & _HTTP_TLS_ALLOW_DH)) + strlcat(priority_string, ":!ANON-DH", sizeof(priority_string)); + +#ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT + gnutls_priority_set_direct(http->tls, priority_string, NULL); #else gnutls_priority_t priority; /* Priority */ - if (!tls_options) - gnutls_priority_init(&priority, "NORMAL:-ARCFOUR-128:+VERS-TLS-ALL:-VERS-SSL3.0", NULL); - else if ((tls_options & _HTTP_TLS_ALLOW_SSL3) && (tls_options & _HTTP_TLS_ALLOW_RC4)) - gnutls_priority_init(&priority, "NORMAL", NULL); - else if (tls_options & _HTTP_TLS_ALLOW_SSL3) - gnutls_priority_init(&priority, "NORMAL:-ARCFOUR-128:+VERS-TLS-ALL", NULL); - else - gnutls_priority_init(&priority, "NORMAL:+VERS-TLS-ALL:-VERS-SSL3.0", NULL); - + gnutls_priority_init(&priority, priority_string, NULL); gnutls_priority_set(http->tls, priority); gnutls_priority_deinit(priority); #endif /* HAVE_GNUTLS_PRIORITY_SET_DIRECT */ @@ -1332,5 +1341,5 @@ _httpTLSWrite(http_t *http, /* I - Connection to server */ /* - * End of "$Id: tls-gnutls.c 12481 2015-02-03 12:45:14Z msweet $". + * End of "$Id: tls-gnutls.c 12670 2015-05-27 19:48:05Z msweet $". */ diff --git a/cups/tls-sspi.c b/cups/tls-sspi.c index 28596befe4..aa8994d34d 100644 --- a/cups/tls-sspi.c +++ b/cups/tls-sspi.c @@ -1,5 +1,5 @@ /* - * "$Id: tls-sspi.c 12481 2015-02-03 12:45:14Z msweet $" + * "$Id: tls-sspi.c 12647 2015-05-20 18:37:52Z msweet $" * * TLS support for CUPS on Windows using the Security Support Provider * Interface (SSPI). @@ -54,7 +54,7 @@ * Local globals... */ -static int tls_options = 0;/* Options for TLS connections */ +static int tls_options = -1;/* Options for TLS connections */ /* @@ -930,7 +930,14 @@ _httpTLSStart(http_t *http) /* I - HTTP connection */ *hostptr; /* Pointer into hostname */ - DEBUG_printf(("7_httpTLSStart(http=%p)", http)); + DEBUG_printf(("3_httpTLSStart(http=%p)", http)); + + if (tls_options < 0) + { + DEBUG_puts("4_httpTLSStart: Setting defaults."); + _cupsSetDefaults(); + DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options)); + } if ((http->tls = http_sspi_alloc()) == NULL) return (-1); @@ -1756,14 +1763,18 @@ http_sspi_find_credentials( #ifdef SP_PROT_TLS1_2_SERVER if (http->mode == _HTTP_MODE_SERVER) { - if (tls_options & _HTTP_TLS_ALLOW_SSL3) + if (tls_options & _HTTP_TLS_DENY_TLS10) + SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER; + else if (tls_options & _HTTP_TLS_ALLOW_SSL3) SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER | SP_PROT_SSL3_SERVER; else SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER; } else { - if (tls_options & _HTTP_TLS_ALLOW_SSL3) + if (tls_options & _HTTP_TLS_DENY_TLS10) + SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT; + else if (tls_options & _HTTP_TLS_ALLOW_SSL3) SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_SSL3_CLIENT; else SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT; @@ -1786,7 +1797,7 @@ http_sspi_find_credentials( } #endif /* SP_PROT_TLS1_2_SERVER */ - /* TODO: Support _HTTP_TLS_ALLOW_RC4 option; right now we'll rely on Windows registry to enable/disable RC4... */ + /* TODO: Support _HTTP_TLS_ALLOW_RC4 and _HTTP_TLS_ALLOW_DH options; right now we'll rely on Windows registry to enable/disable RC4/DH... */ /* * Create an SSPI credential. @@ -2416,5 +2427,5 @@ http_sspi_verify( /* - * End of "$Id: tls-sspi.c 12481 2015-02-03 12:45:14Z msweet $". + * End of "$Id: tls-sspi.c 12647 2015-05-20 18:37:52Z msweet $". */ diff --git a/cups/tlscheck.c b/cups/tlscheck.c new file mode 100644 index 0000000000..56cc1de533 --- /dev/null +++ b/cups/tlscheck.c @@ -0,0 +1,739 @@ +/* + * "$Id: tlscheck.c 12688 2015-06-03 17:31:30Z msweet $" + * + * TLS check program for CUPS. + * + * Copyright 2007-2015 by Apple Inc. + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Apple Inc. and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "LICENSE.txt" + * which should have been included with this file. If this file is + * file is missing or damaged, see the license at "http://www.cups.org/". + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +/* + * Include necessary headers... + */ + +#include "cups-private.h" + + +#ifndef HAVE_SSL +int main(void) { puts("Sorry, no TLS support compiled in."); return (1); } +#else + +/* + * Local functions... + */ + +static void usage(void); + + +/* + * 'main()' - Main entry. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i; /* Looping var */ + http_t *http; /* HTTP connection */ + const char *server = NULL; /* Hostname from command-line */ + int port = 0; /* Port number */ + const char *cipherName = "UNKNOWN";/* Cipher suite name */ + int dhBits = 0; /* Diffie-Hellman bits */ + int tlsVersion = 0; /* TLS version number */ + char uri[1024], /* Printer URI */ + scheme[32], /* URI scheme */ + host[256], /* Hostname */ + userpass[256], /* Username/password */ + resource[256]; /* Resource path */ + int tls_options = _HTTP_TLS_NONE, + /* TLS options */ + verbose = 0; /* Verbosity */ + ipp_t *request, /* IPP Get-Printer-Attributes request */ + *response; /* IPP Get-Printer-Attributes response */ + ipp_attribute_t *attr; /* Current attribute */ + const char *name; /* Attribute name */ + char value[1024]; /* Attribute (string) value */ + static const char * const pattrs[] = /* Requested attributes */ + { + "color-supported", + "compression-supported", + "document-format-supported", + "pages-per-minute", + "printer-location", + "printer-make-and-model", + "printer-state", + "printer-state-reasons", + "sides-supported", + "uri-authentication-supported", + "uri-security-supported" + }; + + + for (i = 1; i < argc; i ++) + { + if (!strcmp(argv[i], "--dh")) + { + tls_options |= _HTTP_TLS_ALLOW_DH; + } + else if (!strcmp(argv[i], "--no-tls10")) + { + tls_options |= _HTTP_TLS_DENY_TLS10; + } + else if (!strcmp(argv[i], "--rc4")) + { + tls_options |= _HTTP_TLS_ALLOW_RC4; + } + else if (!strcmp(argv[i], "--verbose") || !strcmp(argv[i], "-v")) + { + verbose = 1; + } + else if (argv[i][0] == '-') + { + printf("tlscheck: Unknown option '%s'.\n", argv[i]); + usage(); + } + else if (!server) + { + if (!strncmp(argv[i], "ipps://", 7)) + { + httpSeparateURI(HTTP_URI_CODING_ALL, argv[i], scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)); + server = host; + } + else + { + server = argv[i]; + strlcpy(resource, "/ipp/print", sizeof(resource)); + } + } + else if (!port && (argv[i][0] == '=' || isdigit(argv[i][0] & 255))) + { + if (argv[i][0] == '=') + port = atoi(argv[i] + 1); + else + port = atoi(argv[i]); + } + else + { + printf("tlscheck: Unexpected argument '%s'.\n", argv[i]); + usage(); + } + } + + if (!server) + usage(); + + if (!port) + port = 631; + + _httpTLSSetOptions(tls_options); + + http = httpConnect2(server, port, NULL, AF_UNSPEC, HTTP_ENCRYPTION_ALWAYS, 1, 30000, NULL); + if (!http) + { + printf("%s: ERROR (%s)\n", server, cupsLastErrorString()); + return (1); + } + +#ifdef __APPLE__ + SSLProtocol protocol; + SSLCipherSuite cipher; + char unknownCipherName[256]; + int paramsNeeded = 0; + const void *params; + size_t paramsLen; + OSStatus err; + + if ((err = SSLGetNegotiatedProtocolVersion(http->tls, &protocol)) != noErr) + { + printf("%s: ERROR (No protocol version - %d)\n", server, (int)err); + httpClose(http); + return (1); + } + + switch (protocol) + { + default : + tlsVersion = 0; + break; + case kSSLProtocol3 : + tlsVersion = 30; + break; + case kTLSProtocol1 : + tlsVersion = 10; + break; + case kTLSProtocol11 : + tlsVersion = 11; + break; + case kTLSProtocol12 : + tlsVersion = 12; + break; + } + + if ((err = SSLGetNegotiatedCipher(http->tls, &cipher)) != noErr) + { + printf("%s: ERROR (No cipher suite - %d)\n", server, (int)err); + httpClose(http); + return (1); + } + + switch (cipher) + { + case TLS_NULL_WITH_NULL_NULL: + cipherName = "TLS_NULL_WITH_NULL_NULL"; + break; + case TLS_RSA_WITH_NULL_MD5: + cipherName = "TLS_RSA_WITH_NULL_MD5"; + break; + case TLS_RSA_WITH_NULL_SHA: + cipherName = "TLS_RSA_WITH_NULL_SHA"; + break; + case TLS_RSA_WITH_RC4_128_MD5: + cipherName = "TLS_RSA_WITH_RC4_128_MD5"; + break; + case TLS_RSA_WITH_RC4_128_SHA: + cipherName = "TLS_RSA_WITH_RC4_128_SHA"; + break; + case TLS_RSA_WITH_3DES_EDE_CBC_SHA: + cipherName = "TLS_RSA_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_RSA_WITH_NULL_SHA256: + cipherName = "TLS_RSA_WITH_NULL_SHA256"; + break; + case TLS_RSA_WITH_AES_128_CBC_SHA256: + cipherName = "TLS_RSA_WITH_AES_128_CBC_SHA256"; + break; + case TLS_RSA_WITH_AES_256_CBC_SHA256: + cipherName = "TLS_RSA_WITH_AES_256_CBC_SHA256"; + break; + case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: + cipherName = "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: + cipherName = "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: + cipherName = "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: + cipherName = "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DH_DSS_WITH_AES_128_CBC_SHA256: + cipherName = "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_DH_RSA_WITH_AES_128_CBC_SHA256: + cipherName = "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: + cipherName = "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: + cipherName = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_DH_DSS_WITH_AES_256_CBC_SHA256: + cipherName = "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_DH_RSA_WITH_AES_256_CBC_SHA256: + cipherName = "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: + cipherName = "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: + cipherName = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_DH_anon_WITH_RC4_128_MD5: + cipherName = "TLS_DH_anon_WITH_RC4_128_MD5"; + paramsNeeded = 1; + break; + case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA: + cipherName = "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DH_anon_WITH_AES_128_CBC_SHA256: + cipherName = "TLS_DH_anon_WITH_AES_128_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_DH_anon_WITH_AES_256_CBC_SHA256: + cipherName = "TLS_DH_anon_WITH_AES_256_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_PSK_WITH_RC4_128_SHA: + cipherName = "TLS_PSK_WITH_RC4_128_SHA"; + break; + case TLS_PSK_WITH_3DES_EDE_CBC_SHA: + cipherName = "TLS_PSK_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_PSK_WITH_AES_128_CBC_SHA: + cipherName = "TLS_PSK_WITH_AES_128_CBC_SHA"; + break; + case TLS_PSK_WITH_AES_256_CBC_SHA: + cipherName = "TLS_PSK_WITH_AES_256_CBC_SHA"; + break; + case TLS_DHE_PSK_WITH_RC4_128_SHA: + cipherName = "TLS_DHE_PSK_WITH_RC4_128_SHA"; + paramsNeeded = 1; + break; + case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: + cipherName = "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DHE_PSK_WITH_AES_128_CBC_SHA: + cipherName = "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DHE_PSK_WITH_AES_256_CBC_SHA: + cipherName = "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_RSA_PSK_WITH_RC4_128_SHA: + cipherName = "TLS_RSA_PSK_WITH_RC4_128_SHA"; + break; + case TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: + cipherName = "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"; + break; + case TLS_RSA_PSK_WITH_AES_128_CBC_SHA: + cipherName = "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"; + break; + case TLS_RSA_PSK_WITH_AES_256_CBC_SHA: + cipherName = "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"; + break; + case TLS_PSK_WITH_NULL_SHA: + cipherName = "TLS_PSK_WITH_NULL_SHA"; + break; + case TLS_DHE_PSK_WITH_NULL_SHA: + cipherName = "TLS_DHE_PSK_WITH_NULL_SHA"; + paramsNeeded = 1; + break; + case TLS_RSA_PSK_WITH_NULL_SHA: + cipherName = "TLS_RSA_PSK_WITH_NULL_SHA"; + break; + case TLS_RSA_WITH_AES_128_GCM_SHA256: + cipherName = "TLS_RSA_WITH_AES_128_GCM_SHA256"; + break; + case TLS_RSA_WITH_AES_256_GCM_SHA384: + cipherName = "TLS_RSA_WITH_AES_256_GCM_SHA384"; + break; + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: + cipherName = "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"; + paramsNeeded = 1; + break; + case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: + cipherName = "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"; + paramsNeeded = 1; + break; + case TLS_DH_RSA_WITH_AES_128_GCM_SHA256: + cipherName = "TLS_DH_RSA_WITH_AES_128_GCM_SHA256"; + paramsNeeded = 1; + break; + case TLS_DH_RSA_WITH_AES_256_GCM_SHA384: + cipherName = "TLS_DH_RSA_WITH_AES_256_GCM_SHA384"; + paramsNeeded = 1; + break; + case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: + cipherName = "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"; + paramsNeeded = 1; + break; + case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: + cipherName = "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"; + paramsNeeded = 1; + break; + case TLS_DH_DSS_WITH_AES_128_GCM_SHA256: + cipherName = "TLS_DH_DSS_WITH_AES_128_GCM_SHA256"; + paramsNeeded = 1; + break; + case TLS_DH_DSS_WITH_AES_256_GCM_SHA384: + cipherName = "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"; + paramsNeeded = 1; + break; + case TLS_DH_anon_WITH_AES_128_GCM_SHA256: + cipherName = "TLS_DH_anon_WITH_AES_128_GCM_SHA256"; + paramsNeeded = 1; + break; + case TLS_DH_anon_WITH_AES_256_GCM_SHA384: + cipherName = "TLS_DH_anon_WITH_AES_256_GCM_SHA384"; + paramsNeeded = 1; + break; + case TLS_PSK_WITH_AES_128_GCM_SHA256: + cipherName = "TLS_PSK_WITH_AES_128_GCM_SHA256"; + break; + case TLS_PSK_WITH_AES_256_GCM_SHA384: + cipherName = "TLS_PSK_WITH_AES_256_GCM_SHA384"; + break; + case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256: + cipherName = "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256"; + paramsNeeded = 1; + break; + case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384: + cipherName = "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384"; + paramsNeeded = 1; + break; + case TLS_RSA_PSK_WITH_AES_128_GCM_SHA256: + cipherName = "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"; + break; + case TLS_RSA_PSK_WITH_AES_256_GCM_SHA384: + cipherName = "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384"; + break; + case TLS_PSK_WITH_AES_128_CBC_SHA256: + cipherName = "TLS_PSK_WITH_AES_128_CBC_SHA256"; + break; + case TLS_PSK_WITH_AES_256_CBC_SHA384: + cipherName = "TLS_PSK_WITH_AES_256_CBC_SHA384"; + break; + case TLS_PSK_WITH_NULL_SHA256: + cipherName = "TLS_PSK_WITH_NULL_SHA256"; + break; + case TLS_PSK_WITH_NULL_SHA384: + cipherName = "TLS_PSK_WITH_NULL_SHA384"; + break; + case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256: + cipherName = "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384: + cipherName = "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384"; + paramsNeeded = 1; + break; + case TLS_DHE_PSK_WITH_NULL_SHA256: + cipherName = "TLS_DHE_PSK_WITH_NULL_SHA256"; + paramsNeeded = 1; + break; + case TLS_DHE_PSK_WITH_NULL_SHA384: + cipherName = "TLS_DHE_PSK_WITH_NULL_SHA384"; + paramsNeeded = 1; + break; + case TLS_RSA_PSK_WITH_AES_128_CBC_SHA256: + cipherName = "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"; + break; + case TLS_RSA_PSK_WITH_AES_256_CBC_SHA384: + cipherName = "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"; + break; + case TLS_RSA_PSK_WITH_NULL_SHA256: + cipherName = "TLS_RSA_PSK_WITH_NULL_SHA256"; + break; + case TLS_RSA_PSK_WITH_NULL_SHA384: + cipherName = "TLS_RSA_PSK_WITH_NULL_SHA384"; + break; + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: + cipherName = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: + cipherName = "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"; + paramsNeeded = 1; + break; + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: + cipherName = "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: + cipherName = "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384"; + paramsNeeded = 1; + break; + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: + cipherName = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: + cipherName = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"; + paramsNeeded = 1; + break; + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: + cipherName = "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"; + paramsNeeded = 1; + break; + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: + cipherName = "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384"; + paramsNeeded = 1; + break; + case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: + cipherName = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"; + paramsNeeded = 1; + break; + case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: + cipherName = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"; + paramsNeeded = 1; + break; + case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: + cipherName = "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"; + paramsNeeded = 1; + break; + case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: + cipherName = "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"; + paramsNeeded = 1; + break; + case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: + cipherName = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"; + paramsNeeded = 1; + break; + case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: + cipherName = "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"; + paramsNeeded = 1; + break; + case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: + cipherName = "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"; + paramsNeeded = 1; + break; + case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: + cipherName = "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"; + paramsNeeded = 1; + break; + case TLS_RSA_WITH_AES_128_CBC_SHA: + cipherName = "TLS_RSA_WITH_AES_128_CBC_SHA"; + break; + case TLS_DH_DSS_WITH_AES_128_CBC_SHA: + cipherName = "TLS_DH_DSS_WITH_AES_128_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DH_RSA_WITH_AES_128_CBC_SHA: + cipherName = "TLS_DH_RSA_WITH_AES_128_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: + cipherName = "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: + cipherName = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DH_anon_WITH_AES_128_CBC_SHA: + cipherName = "TLS_DH_anon_WITH_AES_128_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_RSA_WITH_AES_256_CBC_SHA: + cipherName = "TLS_RSA_WITH_AES_256_CBC_SHA"; + break; + case TLS_DH_DSS_WITH_AES_256_CBC_SHA: + cipherName = "TLS_DH_DSS_WITH_AES_256_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DH_RSA_WITH_AES_256_CBC_SHA: + cipherName = "TLS_DH_RSA_WITH_AES_256_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: + cipherName = "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: + cipherName = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_DH_anon_WITH_AES_256_CBC_SHA: + cipherName = "TLS_DH_anon_WITH_AES_256_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_ECDSA_WITH_NULL_SHA: + cipherName = "TLS_ECDH_ECDSA_WITH_NULL_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_ECDSA_WITH_RC4_128_SHA: + cipherName = "TLS_ECDH_ECDSA_WITH_RC4_128_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: + cipherName = "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: + cipherName = "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: + cipherName = "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDHE_ECDSA_WITH_NULL_SHA: + cipherName = "TLS_ECDHE_ECDSA_WITH_NULL_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: + cipherName = "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: + cipherName = "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: + cipherName = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: + cipherName = "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_RSA_WITH_NULL_SHA: + cipherName = "TLS_ECDH_RSA_WITH_NULL_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_RSA_WITH_RC4_128_SHA: + cipherName = "TLS_ECDH_RSA_WITH_RC4_128_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: + cipherName = "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: + cipherName = "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: + cipherName = "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDHE_RSA_WITH_NULL_SHA: + cipherName = "TLS_ECDHE_RSA_WITH_NULL_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDHE_RSA_WITH_RC4_128_SHA: + cipherName = "TLS_ECDHE_RSA_WITH_RC4_128_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: + cipherName = "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: + cipherName = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: + cipherName = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_anon_WITH_NULL_SHA: + cipherName = "TLS_ECDH_anon_WITH_NULL_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_anon_WITH_RC4_128_SHA: + cipherName = "TLS_ECDH_anon_WITH_RC4_128_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA: + cipherName = "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: + cipherName = "TLS_ECDH_anon_WITH_AES_128_CBC_SHA"; + paramsNeeded = 1; + break; + case TLS_ECDH_anon_WITH_AES_256_CBC_SHA: + cipherName = "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"; + paramsNeeded = 1; + break; + default : + snprintf(unknownCipherName, sizeof(unknownCipherName), "UNKNOWN_%04X", cipher); + cipherName = unknownCipherName; + break; + } + + if (cipher == TLS_RSA_WITH_RC4_128_MD5 || + cipher == TLS_RSA_WITH_RC4_128_SHA) + { + printf("%s: ERROR (Printers MUST NOT negotiate RC4 cipher suites.)\n", server); + httpClose(http); + return (1); + } + + if ((err = SSLGetDiffieHellmanParams(http->tls, ¶ms, ¶msLen)) != noErr && paramsNeeded) + { + printf("%s: ERROR (Unable to get Diffie-Hellman parameters - %d)\n", server, (int)err); + httpClose(http); + return (1); + } + + if (paramsLen < 128 && paramsLen != 0) + { + printf("%s: ERROR (Diffie-Hellman parameters MUST be at least 2048 bits, but Printer uses only %d bits/%d bytes)\n", server, (int)paramsLen * 8, (int)paramsLen); + httpClose(http); + return (1); + } + + dhBits = (int)paramsLen * 8; +#endif /* __APPLE__ */ + + if (dhBits > 0) + printf("%s: OK (TLS: %d.%d, %s, %d DH bits)\n", server, tlsVersion / 10, tlsVersion % 10, cipherName, dhBits); + else + printf("%s: OK (TLS: %d.%d, %s)\n", server, tlsVersion / 10, tlsVersion % 10, cipherName); + + if (verbose) + { + httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipps", NULL, host, port, resource); + request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs); + + response = cupsDoRequest(http, request, resource); + + for (attr = ippFirstAttribute(response); attr; attr = ippNextAttribute(response)) + { + if (ippGetGroupTag(attr) != IPP_TAG_PRINTER) + continue; + + if ((name = ippGetName(attr)) == NULL) + continue; + + ippAttributeString(attr, value, sizeof(value)); + printf(" %s=%s\n", name, value); + } + + ippDelete(response); + } + + httpClose(http); + + return (0); +} + + +/* + * 'usage()' - Show program usage. + */ + +static void +usage(void) +{ + puts("Usage: ./tlscheck [options] server [port]"); + puts(" ./tlscheck [options] ipps://server[:port]/path"); + puts(""); + puts("Options:"); + puts(" --dh Allow DH/DHE key exchange"); + puts(" --no-tls10 Disable TLS/1.0"); + puts(" --rc4 Allow RC4 encryption"); + puts(" --verbose Be verbose"); + puts(" -v Be verbose"); + puts(""); + puts("The default port is 631."); + + exit(1); +} +#endif /* !HAVE_SSL */ + + +/* + * End of "$Id: tlscheck.c 12688 2015-06-03 17:31:30Z msweet $". + */ diff --git a/cups/transcode.c b/cups/transcode.c index f1b26459cf..81b596fe0f 100644 --- a/cups/transcode.c +++ b/cups/transcode.c @@ -1,5 +1,5 @@ /* - * "$Id: transcode.c 12332 2014-12-09 20:58:45Z msweet $" + * "$Id: transcode.c 12330 2014-12-09 20:57:28Z msweet $" * * Transcoding support for CUPS. * @@ -716,5 +716,5 @@ cupsUTF32ToUTF8( /* - * End of "$Id: transcode.c 12332 2014-12-09 20:58:45Z msweet $" + * End of "$Id: transcode.c 12330 2014-12-09 20:57:28Z msweet $" */ diff --git a/cups/usersys.c b/cups/usersys.c index a042171041..da78be3688 100644 --- a/cups/usersys.c +++ b/cups/usersys.c @@ -1,5 +1,5 @@ /* - * "$Id: usersys.c 12813 2015-07-30 15:00:40Z msweet $" + * "$Id: usersys.c 12647 2015-05-20 18:37:52Z msweet $" * * User, system, and password routines for CUPS. * @@ -68,7 +68,6 @@ typedef struct _cups_client_conf_s /**** client.conf config data ****/ static void cups_finalize_client_conf(_cups_client_conf_t *cc); static void cups_init_client_conf(_cups_client_conf_t *cc); static void cups_read_client_conf(cups_file_t *fp, _cups_client_conf_t *cc); -static void cups_set_default_ipp_port(_cups_globals_t *cg); static void cups_set_encryption(_cups_client_conf_t *cc, const char *value); #ifdef HAVE_GSSAPI static void cups_set_gss_service_name(_cups_client_conf_t *cc, const char *value); @@ -383,9 +382,6 @@ cupsSetServer(const char *server) /* I - Server name */ cg->ipp_port = atoi(port); } - if (!cg->ipp_port) - cups_set_default_ipp_port(cg); - if (cg->server[0] == '/') strlcpy(cg->servername, "localhost", sizeof(cg->servername)); else @@ -396,7 +392,6 @@ cupsSetServer(const char *server) /* I - Server name */ cg->server[0] = '\0'; cg->servername[0] = '\0'; cg->server_version = 20; - cg->ipp_port = 0; } if (cg->http) @@ -913,7 +908,17 @@ _cupsSetDefaults(void) cupsSetServer(cc.server_name); if (!cg->ipp_port) - cups_set_default_ipp_port(cg); + { + const char *ipp_port; /* IPP_PORT environment variable */ + + if ((ipp_port = getenv("IPP_PORT")) != NULL) + { + if ((cg->ipp_port = atoi(ipp_port)) <= 0) + cg->ipp_port = CUPS_DEFAULT_IPP_PORT; + } + else + cg->ipp_port = CUPS_DEFAULT_IPP_PORT; + } if (!cg->user[0]) strlcpy(cg->user, cc.user, sizeof(cg->user)); @@ -1145,26 +1150,6 @@ cups_read_client_conf( } -/* - * 'cups_set_default_ipp_port()' - Set the default IPP port value. - */ - -static void -cups_set_default_ipp_port( - _cups_globals_t *cg) /* I - Global data */ -{ - const char *ipp_port; /* IPP_PORT environment variable */ - - - if ((ipp_port = getenv("IPP_PORT")) != NULL) - { - if ((cg->ipp_port = atoi(ipp_port)) <= 0) - cg->ipp_port = CUPS_DEFAULT_IPP_PORT; - } - else - cg->ipp_port = CUPS_DEFAULT_IPP_PORT; -} - /* * 'cups_set_encryption()' - Set the Encryption value. */ @@ -1224,10 +1209,10 @@ cups_set_ssl_options( const char *value) /* I - Value */ { /* - * SSLOptions [AllowRC4] [AllowSSL3] [None] + * SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyTLS1.0] [None] */ - int options = 0; /* SSL/TLS options */ + int options = _HTTP_TLS_NONE; /* SSL/TLS options */ char temp[256], /* Copy of value */ *start, /* Start of option */ *end; /* End of option */ @@ -1256,11 +1241,17 @@ cups_set_ssl_options( options |= _HTTP_TLS_ALLOW_RC4; else if (!_cups_strcasecmp(start, "AllowSSL3")) options |= _HTTP_TLS_ALLOW_SSL3; + else if (!_cups_strcasecmp(start, "AllowDH")) + options |= _HTTP_TLS_ALLOW_DH; + else if (!_cups_strcasecmp(start, "DenyTLS1.0")) + options |= _HTTP_TLS_DENY_TLS10; else if (!_cups_strcasecmp(start, "None")) - options = 0; + options = _HTTP_TLS_NONE; } cc->ssl_options = options; + + DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x", cc, value, options)); } #endif /* HAVE_SSL */ @@ -1279,5 +1270,5 @@ cups_set_user( /* - * End of "$Id: usersys.c 12813 2015-07-30 15:00:40Z msweet $". + * End of "$Id: usersys.c 12647 2015-05-20 18:37:52Z msweet $". */ diff --git a/cups/util.c b/cups/util.c index 3ccc21c147..10ce821a0f 100644 --- a/cups/util.c +++ b/cups/util.c @@ -1,5 +1,5 @@ /* - * "$Id: util.c 12449 2015-01-29 20:32:16Z msweet $" + * "$Id: util.c 12448 2015-01-29 20:32:07Z msweet $" * * Printing utilities for CUPS. * @@ -1655,5 +1655,5 @@ cups_get_printer_uri( /* - * End of "$Id: util.c 12449 2015-01-29 20:32:16Z msweet $". + * End of "$Id: util.c 12448 2015-01-29 20:32:07Z msweet $". */ diff --git a/cups/versioning.h b/cups/versioning.h index 79ac89176e..1e661df348 100644 --- a/cups/versioning.h +++ b/cups/versioning.h @@ -1,5 +1,5 @@ /* - * "$Id: versioning.h 12419 2015-01-22 15:51:20Z msweet $" + * "$Id: versioning.h 12418 2015-01-22 15:49:23Z msweet $" * * API versioning definitions for CUPS. * @@ -162,5 +162,5 @@ #endif /* !_CUPS_VERSIONING_H_ */ /* - * End of "$Id: versioning.h 12419 2015-01-22 15:51:20Z msweet $". + * End of "$Id: versioning.h 12418 2015-01-22 15:49:23Z msweet $". */ diff --git a/data/Makefile b/data/Makefile index 7753b7dbee..484dc26159 100644 --- a/data/Makefile +++ b/data/Makefile @@ -1,9 +1,9 @@ # -# "$Id: Makefile 10996 2013-05-29 11:51:34Z msweet $" +# "$Id: Makefile 12278 2014-12-01 13:53:56Z msweet $" # # Datafile makefile for CUPS. # -# Copyright 2007-2011 by Apple Inc. +# Copyright 2007-2014 by Apple Inc. # Copyright 1993-2006 by Easy Software Products. # # These coded instructions, statements, and computer programs are the @@ -19,17 +19,6 @@ include ../Makedefs # Data files... # -BANNERS = \ - classified \ - confidential \ - secret \ - standard \ - topsecret \ - unclassified - -DATAFILES = \ - testprint - PPDCFILES = \ epson.h \ font.defs \ @@ -87,13 +76,7 @@ install: all install-data install-headers install-libs install-exec install-data: $(INSTALL_DIR) -m 755 $(DATADIR)/banners - for file in $(BANNERS); do \ - $(INSTALL_DATA) $$file $(DATADIR)/banners; \ - done $(INSTALL_DIR) -m 755 $(DATADIR)/data - for file in $(DATAFILES); do \ - $(INSTALL_DATA) $$file $(DATADIR)/data; \ - done $(INSTALL_DIR) -m 755 $(DATADIR)/model $(INSTALL_DIR) -m 755 $(DATADIR)/ppdc for file in $(PPDCFILES); do \ @@ -128,12 +111,6 @@ install-libs: # uninstall: - for file in $(BANNERS); do \ - $(RM) $(DATADIR)/banners/$$file; \ - done - for file in $(DATAFILES); do \ - $(RM) $(DATADIR)/data/$$file; \ - done for file in $(PPDCFILES); do \ $(RM) $(DATADIR)/ppdc/$$file; \ done @@ -146,5 +123,5 @@ uninstall: # -# End of "$Id: Makefile 10996 2013-05-29 11:51:34Z msweet $". +# End of "$Id: Makefile 12278 2014-12-01 13:53:56Z msweet $". # diff --git a/data/classified b/data/classified deleted file mode 100644 index ca01a13b7d..0000000000 --- a/data/classified +++ /dev/null @@ -1,6 +0,0 @@ -#CUPS-BANNER -Show job-id job-name job-originating-user-name job-originating-host-name job-billing -Header Classified -Footer Classified -Image images/cups.png - diff --git a/data/confidential b/data/confidential deleted file mode 100644 index f1f0d854db..0000000000 --- a/data/confidential +++ /dev/null @@ -1,6 +0,0 @@ -#CUPS-BANNER -Show job-id job-name job-originating-user-name job-originating-host-name job-billing -Header Confidential -Footer Confidential -Image images/cups.png - diff --git a/data/secret b/data/secret deleted file mode 100644 index 66a0e8a919..0000000000 --- a/data/secret +++ /dev/null @@ -1,6 +0,0 @@ -#CUPS-BANNER -Show job-id job-name job-originating-user-name job-originating-host-name job-billing -Header Secret -Footer Secret -Image images/cups.png - diff --git a/data/standard b/data/standard deleted file mode 100644 index 31c68a08ed..0000000000 --- a/data/standard +++ /dev/null @@ -1,6 +0,0 @@ -#CUPS-BANNER -Show job-id job-name job-originating-user-name job-originating-host-name job-billing -Header Cover Page -Footer Cover Page -Image images/cups.png - diff --git a/data/testprint.in b/data/testprint.in deleted file mode 100644 index 8cee3ab4f9..0000000000 --- a/data/testprint.in +++ /dev/null @@ -1,7 +0,0 @@ -#CUPS-BANNER -Show printer-name printer-info printer-location printer-make-and-model printer-driver-name printer-driver-version paper-size imageable-area -Header Printer Test Page -Footer Printer Test Page -Notice CUPS @CUPS_VERSION@. -Image images/cups.png -Image images/color-wheel.png diff --git a/data/topsecret b/data/topsecret deleted file mode 100644 index d2b87fabb9..0000000000 --- a/data/topsecret +++ /dev/null @@ -1,6 +0,0 @@ -#CUPS-BANNER -Show job-id job-name job-originating-user-name job-originating-host-name job-billing -Header Top Secret -Footer Top Secret -Image images/cups.png - diff --git a/data/unclassified b/data/unclassified deleted file mode 100644 index 2d1a7d0f97..0000000000 --- a/data/unclassified +++ /dev/null @@ -1,6 +0,0 @@ -#CUPS-BANNER -Show job-id job-name job-originating-user-name job-originating-host-name job-billing -Header Unclassified -Footer Unclassified -Image images/cups.png - diff --git a/doc/help/api-array.html b/doc/help/api-array.html index 220c0f1cb0..cd93e87fb2 100644 --- a/doc/help/api-array.html +++ b/doc/help/api-array.html @@ -5,7 +5,7 @@ Array API - + \n" + "\n" + "\n" + "" + "" + "" + "" + "
StatusSuppliesMedia
\n" + "
\n", title, !strcmp(client->uri, "/") ? " sel" : "", !strcmp(client->uri, "/supplies") ? " sel" : "", !strcmp(client->uri, "/media") ? " sel" : ""); +} + + +/* + * 'html_printf()' - Send formatted text to the client, quoting as needed. + */ + +static void +html_printf(_ipp_client_t *client, /* I - Client */ + const char *format, /* I - Printf-style format string */ + ...) /* I - Additional arguments as needed */ +{ + va_list ap; /* Pointer to arguments */ + const char *start; /* Start of string */ + char size, /* Size character (h, l, L) */ + type; /* Format type character */ + int width, /* Width of field */ + prec; /* Number of characters of precision */ + char tformat[100], /* Temporary format string for sprintf() */ + *tptr, /* Pointer into temporary format */ + temp[1024]; /* Buffer for formatted numbers */ + char *s; /* Pointer to string */ + + + /* + * Loop through the format string, formatting as needed... + */ + + va_start(ap, format); + start = format; + + while (*format) + { + if (*format == '%') + { + if (format > start) + httpWrite2(client->http, start, (size_t)(format - start)); + + tptr = tformat; + *tptr++ = *format++; + + if (*format == '%') + { + httpWrite2(client->http, "%", 1); + format ++; + start = format; + continue; + } + else if (strchr(" -+#\'", *format)) + *tptr++ = *format++; + + if (*format == '*') + { + /* + * Get width from argument... + */ + + format ++; + width = va_arg(ap, int); + + snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", width); + tptr += strlen(tptr); + } + else + { + width = 0; + + while (isdigit(*format & 255)) + { + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + width = width * 10 + *format++ - '0'; + } + } + + if (*format == '.') + { + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + format ++; + + if (*format == '*') + { + /* + * Get precision from argument... + */ + + format ++; + prec = va_arg(ap, int); + + snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", prec); + tptr += strlen(tptr); + } + else + { + prec = 0; + + while (isdigit(*format & 255)) + { + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + prec = prec * 10 + *format++ - '0'; + } + } + } + + if (*format == 'l' && format[1] == 'l') + { + size = 'L'; + + if (tptr < (tformat + sizeof(tformat) - 2)) + { + *tptr++ = 'l'; + *tptr++ = 'l'; + } + + format += 2; + } + else if (*format == 'h' || *format == 'l' || *format == 'L') + { + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + size = *format++; + } + else + size = 0; + + + if (!*format) + { + start = format; + break; + } + + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + type = *format++; + *tptr = '\0'; + start = format; + + switch (type) + { + case 'E' : /* Floating point formats */ + case 'G' : + case 'e' : + case 'f' : + case 'g' : + if ((size_t)(width + 2) > sizeof(temp)) + break; + + sprintf(temp, tformat, va_arg(ap, double)); + + httpWrite2(client->http, temp, strlen(temp)); + break; + + case 'B' : /* Integer formats */ + case 'X' : + case 'b' : + case 'd' : + case 'i' : + case 'o' : + case 'u' : + case 'x' : + if ((size_t)(width + 2) > sizeof(temp)) + break; + +# ifdef HAVE_LONG_LONG + if (size == 'L') + sprintf(temp, tformat, va_arg(ap, long long)); + else +# endif /* HAVE_LONG_LONG */ + if (size == 'l') + sprintf(temp, tformat, va_arg(ap, long)); + else + sprintf(temp, tformat, va_arg(ap, int)); + + httpWrite2(client->http, temp, strlen(temp)); + break; + + case 'p' : /* Pointer value */ + if ((size_t)(width + 2) > sizeof(temp)) + break; + + sprintf(temp, tformat, va_arg(ap, void *)); + + httpWrite2(client->http, temp, strlen(temp)); + break; + + case 'c' : /* Character or character array */ + if (width <= 1) + { + temp[0] = (char)va_arg(ap, int); + temp[1] = '\0'; + html_escape(client, temp, 1); + } + else + html_escape(client, va_arg(ap, char *), (size_t)width); + break; + + case 's' : /* String */ + if ((s = va_arg(ap, char *)) == NULL) + s = "(null)"; + + html_escape(client, s, strlen(s)); + break; + } + } + else + format ++; + } + + if (format > start) + httpWrite2(client->http, start, (size_t)(format - start)); + + va_end(ap); +} + + +/* + * 'ipp_acknowledge_document()' - Acknowledge receipt of a document. + */ + +static void +ipp_acknowledge_document( + _ipp_client_t *client) /* I - Client */ +{ + _ipp_device_t *device; /* Device */ + _ipp_job_t *job; /* Job */ + ipp_attribute_t *attr; /* Attribute */ + + + if ((device = find_device(client)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Device was not found."); + return; + } + + if ((job = find_job(client, 0)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job was not found."); + return; + } + + if (!job->dev_uuid || strcmp(job->dev_uuid, device->uuid)) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job not assigned to device."); + return; + } + + if ((attr = ippFindAttribute(client->request, "document-number", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(attr) != IPP_TAG_OPERATION || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetCount(attr) != 1 || ippGetInteger(attr, 0) != 1) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, attr ? "Bad document-number attribute." : "Missing document-number attribute."); + return; + } + + respond_ipp(client, IPP_STATUS_OK, NULL); +} + + +/* + * 'ipp_acknowledge_identify_printer()' - Acknowledge an identify command. + */ + +static void +ipp_acknowledge_identify_printer( + _ipp_client_t *client) /* I - Client */ +{ + // TODO: Implement this! + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Need to implement this."); +} + + +/* + * 'ipp_acknowledge_job()' - Acknowledge receipt of a job. + */ + +static void +ipp_acknowledge_job( + _ipp_client_t *client) /* I - Client */ +{ + _ipp_device_t *device; /* Device */ + _ipp_job_t *job; /* Job */ + + + if ((device = find_device(client)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Device was not found."); + return; + } + + if ((job = find_job(client, 0)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job was not found."); + return; + } + + if (job->dev_uuid && strcmp(job->dev_uuid, device->uuid)) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_AUTHORIZED, "Job not assigned to device."); + return; + } + + if (!(job->state_reasons & _IPP_JREASON_JOB_FETCHABLE)) + { + respond_ipp(client, _IPP_STATUS_ERROR_NOT_FETCHABLE, "Job not fetchable."); + return; + } + + if (!job->dev_uuid) + job->dev_uuid = strdup(device->uuid); + + job->state_reasons &= (_ipp_jreason_t)~_IPP_JREASON_JOB_FETCHABLE; + + add_event(client->printer, job, _IPP_EVENT_JOB_STATE_CHANGED, "Job acknowledged."); + + respond_ipp(client, IPP_STATUS_OK, NULL); +} + + +/* + * 'ipp_cancel_job()' - Cancel a job. + */ + +static void +ipp_cancel_job(_ipp_client_t *client) /* I - Client */ +{ + _ipp_job_t *job; /* Job information */ + + + /* + * Get the job... + */ + + if ((job = find_job(client, 0)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); + return; + } + + /* + * See if the job is already completed, canceled, or aborted; if so, + * we can't cancel... + */ + + switch (job->state) + { + case IPP_JSTATE_CANCELED : + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, + "Job #%d is already canceled - can\'t cancel.", job->id); + break; + + case IPP_JSTATE_ABORTED : + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, + "Job #%d is already aborted - can\'t cancel.", job->id); + break; + + case IPP_JSTATE_COMPLETED : + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, + "Job #%d is already completed - can\'t cancel.", job->id); + break; + + default : + /* + * Cancel the job... + */ + + _cupsRWLockWrite(&(client->printer->rwlock)); + + if (job->state == IPP_JSTATE_PROCESSING || + (job->state == IPP_JSTATE_HELD && job->fd >= 0)) + job->cancel = 1; + else + { + job->state = IPP_JSTATE_CANCELED; + job->completed = time(NULL); + } + + _cupsRWUnlock(&(client->printer->rwlock)); + + add_event(client->printer, job, _IPP_EVENT_JOB_COMPLETED, NULL); + + respond_ipp(client, IPP_STATUS_OK, NULL); + break; + } +} + + +/* + * 'ipp_cancel_my_jobs()' - Cancel a user's jobs. + */ + +static void +ipp_cancel_my_jobs( + _ipp_client_t *client) /* I - Client */ +{ + // TODO: Implement this! + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Need to implement this."); +} + + +/* + * 'ipp_cancel_subscription()' - Cancel a subscription. + */ + +static void +ipp_cancel_subscription( + _ipp_client_t *client) /* I - Client */ +{ + _ipp_subscription_t *sub; /* Subscription */ + + + if ((sub = find_subscription(client, 0)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Subscription was not found."); + return; + } + + _cupsRWLockWrite(&client->printer->rwlock); + cupsArrayRemove(client->printer->subscriptions, sub); + delete_subscription(sub); + _cupsRWUnlock(&client->printer->rwlock); + respond_ipp(client, IPP_STATUS_OK, NULL); +} + + +/* + * 'ipp_close_job()' - Close an open job. + */ + +static void +ipp_close_job(_ipp_client_t *client) /* I - Client */ +{ + _ipp_job_t *job; /* Job information */ + + + /* + * Get the job... + */ + + if ((job = find_job(client, 0)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); + return; + } + + /* + * See if the job is already completed, canceled, or aborted; if so, + * we can't cancel... + */ + + switch (job->state) + { + case IPP_JSTATE_CANCELED : + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, + "Job #%d is canceled - can\'t close.", job->id); + break; + + case IPP_JSTATE_ABORTED : + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, + "Job #%d is aborted - can\'t close.", job->id); + break; + + case IPP_JSTATE_COMPLETED : + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, + "Job #%d is completed - can\'t close.", job->id); + break; + + case IPP_JSTATE_PROCESSING : + case IPP_JSTATE_STOPPED : + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, + "Job #%d is already closed.", job->id); + break; + + default : + respond_ipp(client, IPP_STATUS_OK, NULL); + break; + } +} + + +/* + * 'ipp_create_job()' - Create a job object. + */ + +static void +ipp_create_job(_ipp_client_t *client) /* I - Client */ +{ + _ipp_job_t *job; /* New job */ + cups_array_t *ra; /* Attributes to send in response */ + + + /* + * Validate print job attributes... + */ + + if (!valid_job_attributes(client)) + { + httpFlush(client->http); + return; + } + + /* + * Do we have a file to print? + */ + + if (httpGetState(client->http) == HTTP_STATE_POST_RECV) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, + "Unexpected document data following request."); + return; + } + + /* + * Create the job... + */ + + if ((job = create_job(client)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_TOO_MANY_JOBS, "Too many jobs are queued."); + return; + } + + /* + * Return the job info... + */ + + respond_ipp(client, IPP_STATUS_OK, NULL); + + ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); + cupsArrayAdd(ra, "job-id"); + cupsArrayAdd(ra, "job-state"); + cupsArrayAdd(ra, "job-state-message"); + cupsArrayAdd(ra, "job-state-reasons"); + cupsArrayAdd(ra, "job-uri"); + + copy_job_attributes(client, job, ra); + cupsArrayDelete(ra); + + /* + * Add any subscriptions... + */ + + client->job = job; + ipp_create_xxx_subscriptions(client); +} + + +/* + * 'ipp_create_xxx_subscriptions()' - Create job and printer subscriptions. + */ + +static void +ipp_create_xxx_subscriptions( + _ipp_client_t *client) +{ + _ipp_subscription_t *sub; /* Subscription */ + ipp_attribute_t *attr; /* Subscription attribute */ + const char *username; /* requesting-user-name or + authenticated username */ + int num_subs = 0, /* Number of subscriptions */ + ok_subs = 0; /* Number of good subscriptions */ + + + /* + * For the Create-xxx-Subscriptions operations, queue up a successful-ok + * response... + */ + + if (ippGetOperation(client->request) == IPP_OP_CREATE_JOB_SUBSCRIPTIONS || ippGetOperation(client->request) == IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS) + respond_ipp(client, IPP_STATUS_OK, NULL); + + /* + * Get the authenticated user name, if any... + */ + + if (client->username[0]) + username = client->username; + else if ((attr = ippFindAttribute(client->request, "requesting-user-name", IPP_TAG_NAME)) != NULL && ippGetGroupTag(attr) == IPP_TAG_OPERATION && ippGetCount(attr) == 1) + username = ippGetString(attr, 0, NULL); + else + username = "guest"; + + /* + * Skip past the initial attributes to the first subscription group. + */ + + attr = ippFirstAttribute(client->request); + while (attr && ippGetGroupTag(attr) != IPP_TAG_SUBSCRIPTION) + attr = ippNextAttribute(client->request); + + while (attr) + { + _ipp_job_t *job = NULL; /* Job */ + const char *attrname, /* Attribute name */ + *pullmethod = NULL; + /* notify-pull-method */ + ipp_attribute_t *notify_attributes = NULL, + /* notify-attributes */ + *notify_events = NULL, + /* notify-events */ + *notify_user_data = NULL; + /* notify-user-data */ + int interval = 0, /* notify-time-interval */ + lease = _IPP_NOTIFY_LEASE_DURATION_DEFAULT; + /* notify-lease-duration */ + ipp_status_t status = IPP_STATUS_OK; + /* notify-status-code */ + + num_subs ++; + + while (attr) + { + if ((attrname = ippGetName(attr)) == NULL) + break; + + if (!strcmp(attrname, "notify-recipient-uri")) + { + /* + * Push notifications not supported. + */ + + status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; + ippCopyAttribute(client->response, attr, 0); + } + else if (!strcmp(attrname, "notify-pull-method")) + { + pullmethod = ippGetString(attr, 0, NULL); + + if (ippGetValueTag(attr) != IPP_TAG_KEYWORD || ippGetCount(attr) != 1 || !pullmethod || strcmp(pullmethod, "ippget")) + { + ippCopyAttribute(client->response, attr, 0); + pullmethod = NULL; + status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; + } + } + else if (!strcmp(attrname, "notify-attributes")) + { + if (ippGetValueTag(attr) != IPP_TAG_KEYWORD) + { + status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; + ippCopyAttribute(client->response, attr, 0); + } + + notify_attributes = attr; + } + else if (!strcmp(attrname, "notify-charset")) + { + if (ippGetValueTag(attr) != IPP_TAG_CHARSET || ippGetCount(attr) != 1 || + (strcmp(ippGetString(attr, 0, NULL), "us-ascii") && strcmp(ippGetString(attr, 0, NULL), "utf-8"))) + { + status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; + ippCopyAttribute(client->response, attr, 0); + } + } + else if (!strcmp(attrname, "notify-natural-language")) + { + if (ippGetValueTag(attr) != IPP_TAG_LANGUAGE || ippGetCount(attr) != 1 || strcmp(ippGetString(attr, 0, NULL), "en")) + { + status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; + ippCopyAttribute(client->response, attr, 0); + } + } + else if (!strcmp(attrname, "notify-user-data")) + { + int datalen; /* Length of data */ + + if (ippGetValueTag(attr) != IPP_TAG_STRING || ippGetCount(attr) != 1 || !ippGetOctetString(attr, 0, &datalen) || datalen > 63) + { + status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; + ippCopyAttribute(client->response, attr, 0); + } + else + notify_user_data = attr; + } + else if (!strcmp(attrname, "notify-events")) + { + if (ippGetValueTag(attr) != IPP_TAG_KEYWORD) + { + status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; + ippCopyAttribute(client->response, attr, 0); + } + else + notify_events = attr; + } + else if (!strcmp(attrname, "notify-lease-duration")) + { + if (ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetCount(attr) != 1 || ippGetInteger(attr, 0) < 0) + { + status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; + ippCopyAttribute(client->response, attr, 0); + } + else + lease = ippGetInteger(attr, 0); + } + else if (!strcmp(attrname, "notify-time-interval")) + { + if (ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetCount(attr) != 1 || ippGetInteger(attr, 0) < 0) + { + status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; + ippCopyAttribute(client->response, attr, 0); + } + else + interval = ippGetInteger(attr, 0); + } + else if (!strcmp(attrname, "notify-job-id")) + { + if (ippGetOperation(client->request) != IPP_OP_CREATE_JOB_SUBSCRIPTIONS || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetInteger(attr, 0) < 1) + { + status = IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES; + ippCopyAttribute(client->response, attr, 0); + } + else if ((job = find_job(client, ippGetInteger(attr, 0))) == NULL) + { + status = IPP_STATUS_ERROR_NOT_FOUND; + ippCopyAttribute(client->response, attr, 0); + } + } + + attr = ippNextAttribute(client->request); + } + + if (status) + { + ippAddInteger(client->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", status); + } + else if (!pullmethod) + { + ippAddInteger(client->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_STATUS_ERROR_BAD_REQUEST); + } + else + { + switch (ippGetOperation(client->request)) + { + case IPP_OP_PRINT_JOB : + case IPP_OP_PRINT_URI : + case IPP_OP_CREATE_JOB : + job = client->job; + break; + + default : + break; + } + + if ((sub = create_subscription(client->printer, job, interval, lease, username, notify_events, notify_attributes, notify_user_data)) == NULL) + { + ippAddInteger(client->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-subscription-id", sub->id); + ok_subs ++; + } + else + ippAddInteger(client->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_STATUS_ERROR_INTERNAL); + } + } + + if (ok_subs == 0) + ippSetStatusCode(client->response, IPP_STATUS_ERROR_IGNORED_ALL_SUBSCRIPTIONS); + else if (ok_subs != num_subs) + ippSetStatusCode(client->response, IPP_STATUS_OK_IGNORED_SUBSCRIPTIONS); +} + + +/* + * 'ipp_deregister_output_device()' - Unregister an output device. + */ + +static void +ipp_deregister_output_device( + _ipp_client_t *client) /* I - Client */ +{ + _ipp_device_t *device; /* Device */ + + + /* + * Find the device... + */ + + if ((device = find_device(client)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Output device not found."); + return; + } + + /* + * Remove the device from the printer... + */ + + _cupsRWLockWrite(&client->printer->rwlock); + + cupsArrayRemove(client->printer->devices, device); + + update_device_attributes_no_lock(client->printer); + update_device_state_no_lock(client->printer); + + _cupsRWUnlock(&client->printer->rwlock); + + /* + * Delete the device... + */ + + delete_device(device); + + respond_ipp(client, IPP_STATUS_OK, NULL); +} + + +/* + * 'ipp_fetch_document()' - Download a document. + */ + +static void +ipp_fetch_document( + _ipp_client_t *client) /* I - Client */ +{ + _ipp_device_t *device; /* Device */ + _ipp_job_t *job; /* Job */ + ipp_attribute_t *attr; /* Attribute */ + int compression; /* compression */ + char filename[1024]; /* Job filename */ + const char *format; /* document-format */ + + + if ((device = find_device(client)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Device was not found."); + return; + } + + if ((job = find_job(client, 0)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job was not found."); + return; + } + + if (!job->dev_uuid || strcmp(job->dev_uuid, device->uuid)) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job not assigned to device."); + return; + } + + if ((attr = ippFindAttribute(client->request, "document-number", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(attr) != IPP_TAG_OPERATION || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetCount(attr) != 1 || ippGetInteger(attr, 0) != 1) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, attr ? "Bad document-number attribute." : "Missing document-number attribute."); + return; + } + + if ((attr = ippFindAttribute(client->request, "compression-accepted", IPP_TAG_KEYWORD)) != NULL) + compression = !strcmp(ippGetString(attr, 0, NULL), "gzip"); + else + compression = 0; + + if ((attr = ippFindAttribute(client->request, "document-format-accepted", IPP_TAG_MIMETYPE)) != NULL) + { + int i, /* Looping var */ + count = ippGetCount(attr); /* Number of values */ + + + for (i = 0; i < count; i ++) + { + format = ippGetString(attr, i, NULL); + + create_job_filename(client->printer, job, NULL, filename, sizeof(filename)); + + if (!access(filename, R_OK)) + break; + } + + if (i >= count) + { + respond_ipp(client, _IPP_STATUS_ERROR_NOT_FETCHABLE, "Document not available in requested format."); + return; + } + } + else if ((attr = ippFindAttribute(job->attrs, "document-format", IPP_TAG_MIMETYPE)) != NULL) + format = ippGetString(attr, 0, NULL); + else + { + respond_ipp(client, _IPP_STATUS_ERROR_NOT_FETCHABLE, "Document format unknown."); + return; + } + + respond_ipp(client, IPP_STATUS_OK, NULL); + ippAddString(client->response, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, format); + ippAddString(client->response, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "compression", NULL, compression ? "gzip" : "none"); + + client->fetch_file = open(filename, O_RDONLY); +} + + +/* + * 'ipp_fetch_job()' - Download a job. + */ + +static void +ipp_fetch_job(_ipp_client_t *client) /* I - Client */ +{ + _ipp_device_t *device; /* Device */ + _ipp_job_t *job; /* Job */ + + + if ((device = find_device(client)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Device was not found."); + return; + } + + if ((job = find_job(client, 0)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job was not found."); + return; + } + + if (job->dev_uuid && strcmp(job->dev_uuid, device->uuid)) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job not assigned to device."); + return; + } + + if (!(job->state_reasons & _IPP_JREASON_JOB_FETCHABLE)) + { + respond_ipp(client, _IPP_STATUS_ERROR_NOT_FETCHABLE, "Job not fetchable."); + return; + } + + respond_ipp(client, IPP_STATUS_OK, NULL); + copy_attributes(client->response, job->attrs, NULL, IPP_TAG_JOB, 0); +} + + +/* + * 'ipp_get_document_attributes()' - Get the attributes for a document object. + * + * Note: This implementation only supports single document jobs so we + * synthesize the information for a single document from the job. + */ + +static void +ipp_get_document_attributes( + _ipp_client_t *client) /* I - Client */ +{ + // TODO: Implement this! + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Need to implement this."); +} + + +/* + * 'ipp_get_documents()' - Get the list of documents in a job. + * + * Note: This implementation only supports single document jobs so we + * synthesize the information for a single document from the job. + */ + +static void +ipp_get_documents(_ipp_client_t *client)/* I - Client */ +{ + // TODO: Implement this! + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Need to implement this."); +} + + +/* + * 'ipp_get_job_attributes()' - Get the attributes for a job object. + */ + +static void +ipp_get_job_attributes( + _ipp_client_t *client) /* I - Client */ +{ + _ipp_job_t *job; /* Job */ + cups_array_t *ra; /* requested-attributes */ + + + if ((job = find_job(client, 0)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job not found."); + return; + } + + respond_ipp(client, IPP_STATUS_OK, NULL); + + ra = ippCreateRequestedArray(client->request); + copy_job_attributes(client, job, ra); + cupsArrayDelete(ra); +} + + +/* + * 'ipp_get_jobs()' - Get a list of job objects. + */ + +static void +ipp_get_jobs(_ipp_client_t *client) /* I - Client */ +{ + ipp_attribute_t *attr; /* Current attribute */ + const char *which_jobs = NULL; + /* which-jobs values */ + int job_comparison; /* Job comparison */ + ipp_jstate_t job_state; /* job-state value */ + int first_job_id, /* First job ID */ + limit, /* Maximum number of jobs to return */ + count; /* Number of jobs that match */ + const char *username; /* Username */ + _ipp_job_t *job; /* Current job pointer */ + cups_array_t *ra; /* Requested attributes array */ + + + /* + * See if the "which-jobs" attribute have been specified... + */ + + if ((attr = ippFindAttribute(client->request, "which-jobs", + IPP_TAG_KEYWORD)) != NULL) + { + which_jobs = ippGetString(attr, 0, NULL); + fprintf(stderr, "%s Get-Jobs which-jobs=%s", client->hostname, which_jobs); + } + + if (!which_jobs || !strcmp(which_jobs, "not-completed")) + { + job_comparison = -1; + job_state = IPP_JSTATE_STOPPED; + } + else if (!strcmp(which_jobs, "completed")) + { + job_comparison = 1; + job_state = IPP_JSTATE_CANCELED; + } + else if (!strcmp(which_jobs, "aborted")) + { + job_comparison = 0; + job_state = IPP_JSTATE_ABORTED; + } + else if (!strcmp(which_jobs, "all")) + { + job_comparison = 1; + job_state = IPP_JSTATE_PENDING; + } + else if (!strcmp(which_jobs, "canceled")) + { + job_comparison = 0; + job_state = IPP_JSTATE_CANCELED; + } + else if (!strcmp(which_jobs, "pending")) + { + job_comparison = 0; + job_state = IPP_JSTATE_PENDING; + } + else if (!strcmp(which_jobs, "pending-held")) + { + job_comparison = 0; + job_state = IPP_JSTATE_HELD; + } + else if (!strcmp(which_jobs, "processing")) + { + job_comparison = 0; + job_state = IPP_JSTATE_PROCESSING; + } + else if (!strcmp(which_jobs, "processing-stopped")) + { + job_comparison = 0; + job_state = IPP_JSTATE_STOPPED; + } + else + { + respond_ipp(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, + "The which-jobs value \"%s\" is not supported.", which_jobs); + ippAddString(client->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, + "which-jobs", NULL, which_jobs); + return; + } + + /* + * See if they want to limit the number of jobs reported... + */ + + if ((attr = ippFindAttribute(client->request, "limit", + IPP_TAG_INTEGER)) != NULL) + { + limit = ippGetInteger(attr, 0); + + fprintf(stderr, "%s Get-Jobs limit=%d", client->hostname, limit); + } + else + limit = 0; + + if ((attr = ippFindAttribute(client->request, "first-job-id", + IPP_TAG_INTEGER)) != NULL) + { + first_job_id = ippGetInteger(attr, 0); + + fprintf(stderr, "%s Get-Jobs first-job-id=%d", client->hostname, + first_job_id); + } + else + first_job_id = 1; + + /* + * See if we only want to see jobs for a specific user... + */ + + username = NULL; + + if ((attr = ippFindAttribute(client->request, "my-jobs", + IPP_TAG_BOOLEAN)) != NULL) + { + int my_jobs = ippGetBoolean(attr, 0); + + fprintf(stderr, "%s Get-Jobs my-jobs=%s\n", client->hostname, + my_jobs ? "true" : "false"); + + if (my_jobs) + { + if ((attr = ippFindAttribute(client->request, "requesting-user-name", + IPP_TAG_NAME)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, + "Need requesting-user-name with my-jobs."); + return; + } + + username = ippGetString(attr, 0, NULL); + + fprintf(stderr, "%s Get-Jobs requesting-user-name=\"%s\"\n", + client->hostname, username); + } + } + + /* + * OK, build a list of jobs for this printer... + */ + + ra = ippCreateRequestedArray(client->request); + + respond_ipp(client, IPP_STATUS_OK, NULL); + + _cupsRWLockRead(&(client->printer->rwlock)); + + for (count = 0, job = (_ipp_job_t *)cupsArrayFirst(client->printer->jobs); + (limit <= 0 || count < limit) && job; + job = (_ipp_job_t *)cupsArrayNext(client->printer->jobs)) + { + /* + * Filter out jobs that don't match... + */ + + if ((job_comparison < 0 && job->state > job_state) || + (job_comparison == 0 && job->state != job_state) || + (job_comparison > 0 && job->state < job_state) || + job->id < first_job_id || + (username && job->username && + strcasecmp(username, job->username))) + continue; + + if (count > 0) + ippAddSeparator(client->response); + + count ++; + copy_job_attributes(client, job, ra); + } + + cupsArrayDelete(ra); + + _cupsRWUnlock(&(client->printer->rwlock)); +} + + +/* + * 'ipp_get_notifications()' - Get notification events for one or more subscriptions. + */ + +static void +ipp_get_notifications( + _ipp_client_t *client) /* I - Client */ +{ + ipp_attribute_t *sub_ids, /* notify-subscription-ids */ + *seq_nums, /* notify-sequence-numbers */ + *notify_wait; /* Wait for events? */ + int i, /* Looping vars */ + count, /* Number of IDs */ + first = 1, /* First event? */ + seq_num; /* Sequence number */ + _ipp_subscription_t *sub; /* Current subscription */ + ipp_t *event; /* Current event */ + + + if ((sub_ids = ippFindAttribute(client->request, "notify-subscription-ids", IPP_TAG_INTEGER)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing notify-subscription-ids attribute."); + return; + } + + count = ippGetCount(sub_ids); + seq_nums = ippFindAttribute(client->request, "notify-sequence-numbers", IPP_TAG_INTEGER); + notify_wait = ippFindAttribute(client->request, "notify-wait", IPP_TAG_BOOLEAN); + + if (seq_nums && count != ippGetCount(seq_nums)) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "The notify-subscription-ids and notify-sequence-numbers attributes are different lengths."); + return; + } + + respond_ipp(client, IPP_STATUS_OK, NULL); + ippAddInteger(client->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "notify-get-interval", 30); + + for (i = 0; i < count; i ++) + { + if ((sub = find_subscription(client, ippGetInteger(sub_ids, i))) == NULL) + continue; + + seq_num = ippGetInteger(seq_nums, i); + if (seq_num < sub->first_sequence) + seq_num = sub->first_sequence; + + if (seq_num > sub->last_sequence) + continue; + + for (event = (ipp_t *)cupsArrayIndex(sub->events, seq_num - sub->first_sequence); + event; + event = (ipp_t *)cupsArrayNext(sub->events)) + { + if (first) + first = 0; + else + ippAddSeparator(client->response); + + ippCopyAttributes(client->response, event, 0, NULL, NULL); + } + } +} + + +/* + * 'ipp_get_output_device_attributes()' - Get attributes for an output device. + */ + +static void +ipp_get_output_device_attributes( + _ipp_client_t *client) /* I - Client */ +{ + // TODO: Implement this! + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Need to implement this."); +} + + +/* + * 'ipp_get_printer_attributes()' - Get the attributes for a printer object. + */ + +static void +ipp_get_printer_attributes( + _ipp_client_t *client) /* I - Client */ +{ + cups_array_t *ra; /* Requested attributes array */ + _ipp_printer_t *printer; /* Printer */ + + + /* + * Send the attributes... + */ + + ra = ippCreateRequestedArray(client->request); + printer = client->printer; + + respond_ipp(client, IPP_STATUS_OK, NULL); + + _cupsRWLockRead(&(printer->rwlock)); + + copy_attributes(client->response, printer->attrs, ra, IPP_TAG_ZERO, + IPP_TAG_CUPS_CONST); + copy_attributes(client->response, printer->dev_attrs, ra, IPP_TAG_ZERO, IPP_TAG_ZERO); + + if (!ra || cupsArrayFind(ra, "printer-config-change-date-time")) + ippAddDate(client->response, IPP_TAG_PRINTER, "printer-config-change-date-time", ippTimeToDate(printer->config_time)); + + if (!ra || cupsArrayFind(ra, "printer-config-change-time")) + ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-config-change-time", (int)(printer->config_time - printer->start_time)); + + if (!ra || cupsArrayFind(ra, "printer-current-time")) + ippAddDate(client->response, IPP_TAG_PRINTER, "printer-current-time", ippTimeToDate(time(NULL))); + + + if (!ra || cupsArrayFind(ra, "printer-state")) + ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, + "printer-state", printer->state > printer->dev_state ? printer->state : printer->dev_state); + + if (!ra || cupsArrayFind(ra, "printer-state-change-date-time")) + ippAddDate(client->response, IPP_TAG_PRINTER, "printer-state-change-date-time", ippTimeToDate(printer->state_time)); + + if (!ra || cupsArrayFind(ra, "printer-state-change-time")) + ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-state-change-time", (int)(printer->state_time - printer->start_time)); + + if (!ra || cupsArrayFind(ra, "printer-state-message")) + { + static const char * const messages[] = { "Idle.", "Printing.", "Stopped." }; + + if (printer->state > printer->dev_state) + ippAddString(client->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-state-message", NULL, messages[printer->state - IPP_PSTATE_IDLE]); + else + ippAddString(client->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-state-message", NULL, messages[printer->dev_state - IPP_PSTATE_IDLE]); + } + + if (!ra || cupsArrayFind(ra, "printer-state-reasons")) + copy_printer_state_reasons(client->response, IPP_TAG_PRINTER, printer); + + if (!ra || cupsArrayFind(ra, "printer-up-time")) + ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-up-time", (int)(time(NULL) - printer->start_time)); + + if (!ra || cupsArrayFind(ra, "queued-job-count")) + ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "queued-job-count", cupsArrayCount(printer->active_jobs)); + + _cupsRWUnlock(&(printer->rwlock)); + + cupsArrayDelete(ra); +} + + +/* + * 'ipp_get_printer_supported_values()' - Return the supported values for + * the infrastructure printer. + */ + +static void +ipp_get_printer_supported_values( + _ipp_client_t *client) /* I - Client */ +{ + cups_array_t *ra = ippCreateRequestedArray(client->request); + /* Requested attributes */ + + + respond_ipp(client, IPP_STATUS_OK, NULL); + + copy_attributes(client->response, client->printer->attrs, ra, IPP_TAG_PRINTER, 1); + + cupsArrayDelete(ra); +} + + +/* + * 'ipp_get_subscription_attributes()' - Get attributes for a subscription. + */ + +static void +ipp_get_subscription_attributes( + _ipp_client_t *client) /* I - Client */ +{ + _ipp_subscription_t *sub; /* Subscription */ + cups_array_t *ra = ippCreateRequestedArray(client->request); + /* Requested attributes */ + + + if ((sub = find_subscription(client, 0)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Subscription was not found."); + } + else + { + respond_ipp(client, IPP_STATUS_OK, NULL); + copy_subscription_attributes(client, sub, ra); + } + + cupsArrayDelete(ra); +} + + +/* + * 'ipp_get_subscriptions()' - Get attributes for all subscriptions. + */ + +static void +ipp_get_subscriptions( + _ipp_client_t *client) /* I - Client */ +{ + _ipp_subscription_t *sub; /* Current subscription */ + cups_array_t *ra = ippCreateRequestedArray(client->request); + /* Requested attributes */ + int first = 1; /* First time? */ + + + respond_ipp(client, IPP_STATUS_OK, NULL); + _cupsRWLockRead(&client->printer->rwlock); + for (sub = (_ipp_subscription_t *)cupsArrayFirst(client->printer->subscriptions); + sub; + sub = (_ipp_subscription_t *)cupsArrayNext(client->printer->subscriptions)) + { + if (first) + first = 0; + else + ippAddSeparator(client->response); + + copy_subscription_attributes(client, sub, ra); + } + + cupsArrayDelete(ra); +} + + +/* + * 'ipp_identify_printer()' - Beep or display a message. + */ + +static void +ipp_identify_printer( + _ipp_client_t *client) /* I - Client */ +{ + /* TODO: Do something */ + + respond_ipp(client, IPP_STATUS_OK, NULL); +} + + +/* + * 'ipp_print_job()' - Create a job object with an attached document. + */ + +static void +ipp_print_job(_ipp_client_t *client) /* I - Client */ +{ + _ipp_job_t *job; /* New job */ + char filename[1024], /* Filename buffer */ + buffer[4096]; /* Copy buffer */ + ssize_t bytes; /* Bytes read */ + cups_array_t *ra; /* Attributes to send in response */ + + + /* + * Validate print job attributes... + */ + + if (!valid_job_attributes(client)) + { + httpFlush(client->http); + return; + } + + /* + * Do we have a file to print? + */ + + if (httpGetState(client->http) == HTTP_STATE_POST_SEND) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "No file in request."); + return; + } + + /* + * Print the job... + */ + + if ((job = create_job(client)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_BUSY, + "Currently printing another job."); + return; + } + + /* + * Create a file for the request data... + */ + + create_job_filename(client->printer, job, NULL, filename, sizeof(filename)); + + if (Verbosity) + fprintf(stderr, "Creating job file \"%s\", format \"%s\".\n", filename, job->format); + + if ((job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) + { + job->state = IPP_JSTATE_ABORTED; + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to create print file: %s", strerror(errno)); + return; + } + + while ((bytes = httpRead2(client->http, buffer, sizeof(buffer))) > 0) + { + if (write(job->fd, buffer, (size_t)bytes) < bytes) + { + int error = errno; /* Write error */ + + job->state = IPP_JSTATE_ABORTED; + + close(job->fd); + job->fd = -1; + + unlink(filename); + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to write print file: %s", strerror(error)); + return; + } + } + + if (bytes < 0) + { + /* + * Got an error while reading the print data, so abort this job. + */ + + job->state = IPP_JSTATE_ABORTED; + + close(job->fd); + job->fd = -1; + + unlink(filename); + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to read print file."); + return; + } + + if (close(job->fd)) + { + int error = errno; /* Write error */ + + job->state = IPP_JSTATE_ABORTED; + job->fd = -1; + + unlink(filename); + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to write print file: %s", strerror(error)); + return; + } + + job->fd = -1; + job->filename = strdup(filename); + job->state = IPP_JSTATE_PENDING; + + /* + * Process the job, if possible... + */ + + check_jobs(client->printer); + + /* + * Return the job info... + */ + + respond_ipp(client, IPP_STATUS_OK, NULL); + + ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); + cupsArrayAdd(ra, "job-id"); + cupsArrayAdd(ra, "job-state"); + cupsArrayAdd(ra, "job-state-message"); + cupsArrayAdd(ra, "job-state-reasons"); + cupsArrayAdd(ra, "job-uri"); + + copy_job_attributes(client, job, ra); + cupsArrayDelete(ra); + + /* + * Process any pending subscriptions... + */ + + client->job = job; + ipp_create_xxx_subscriptions(client); +} + + +/* + * 'ipp_print_uri()' - Create a job object with a referenced document. + */ + +static void +ipp_print_uri(_ipp_client_t *client) /* I - Client */ +{ + _ipp_job_t *job; /* New job */ + ipp_attribute_t *uri; /* document-uri */ + char scheme[256], /* URI scheme */ + userpass[256], /* Username and password info */ + hostname[256], /* Hostname */ + resource[1024]; /* Resource path */ + int port; /* Port number */ + http_uri_status_t uri_status; /* URI decode status */ + http_encryption_t encryption; /* Encryption to use, if any */ + http_t *http; /* Connection for http/https URIs */ + http_status_t status; /* Access status for http/https URIs */ + int infile; /* Input file for local file URIs */ + char filename[1024], /* Filename buffer */ + buffer[4096]; /* Copy buffer */ + ssize_t bytes; /* Bytes read */ + cups_array_t *ra; /* Attributes to send in response */ + static const char * const uri_status_strings[] = + { /* URI decode errors */ + "URI too large.", + "Bad arguments to function.", + "Bad resource in URI.", + "Bad port number in URI.", + "Bad hostname in URI.", + "Bad username in URI.", + "Bad scheme in URI.", + "Bad/empty URI." + }; + + + /* + * Validate print job attributes... + */ + + if (!valid_job_attributes(client)) + { + httpFlush(client->http); + return; + } + + /* + * Do we have a file to print? + */ + + if (httpGetState(client->http) == HTTP_STATE_POST_RECV) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, + "Unexpected document data following request."); + return; + } + + /* + * Do we have a document URI? + */ + + if ((uri = ippFindAttribute(client->request, "document-uri", + IPP_TAG_URI)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing document-uri."); + return; + } + + if (ippGetCount(uri) != 1) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, + "Too many document-uri values."); + return; + } + + uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL), + scheme, sizeof(scheme), userpass, + sizeof(userpass), hostname, sizeof(hostname), + &port, resource, sizeof(resource)); + if (uri_status < HTTP_URI_STATUS_OK) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad document-uri: %s", + uri_status_strings[uri_status - HTTP_URI_STATUS_OVERFLOW]); + return; + } + + if (strcmp(scheme, "file") && +#ifdef HAVE_SSL + strcmp(scheme, "https") && +#endif /* HAVE_SSL */ + strcmp(scheme, "http")) + { + respond_ipp(client, IPP_STATUS_ERROR_URI_SCHEME, + "URI scheme \"%s\" not supported.", scheme); + return; + } + + if (!strcmp(scheme, "file") && access(resource, R_OK)) + { + respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, + "Unable to access URI: %s", strerror(errno)); + return; + } + + /* + * Print the job... + */ + + if ((job = create_job(client)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_BUSY, + "Currently printing another job."); + return; + } + + /* + * Create a file for the request data... + */ + + if (!strcasecmp(job->format, "image/jpeg")) + snprintf(filename, sizeof(filename), "%s/%d.jpg", + client->printer->directory, job->id); + else if (!strcasecmp(job->format, "image/png")) + snprintf(filename, sizeof(filename), "%s/%d.png", + client->printer->directory, job->id); + else if (!strcasecmp(job->format, "application/pdf")) + snprintf(filename, sizeof(filename), "%s/%d.pdf", + client->printer->directory, job->id); + else if (!strcasecmp(job->format, "application/postscript")) + snprintf(filename, sizeof(filename), "%s/%d.ps", + client->printer->directory, job->id); + else + snprintf(filename, sizeof(filename), "%s/%d.prn", + client->printer->directory, job->id); + + if ((job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) + { + job->state = IPP_JSTATE_ABORTED; + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to create print file: %s", strerror(errno)); + return; + } + + if (!strcmp(scheme, "file")) + { + if ((infile = open(resource, O_RDONLY)) < 0) + { + respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, + "Unable to access URI: %s", strerror(errno)); + return; + } + + do + { + if ((bytes = read(infile, buffer, sizeof(buffer))) < 0 && + (errno == EAGAIN || errno == EINTR)) + bytes = 1; + else if (bytes > 0 && write(job->fd, buffer, (size_t)bytes) < bytes) + { + int error = errno; /* Write error */ + + job->state = IPP_JSTATE_ABORTED; + + close(job->fd); + job->fd = -1; + + unlink(filename); + close(infile); + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to write print file: %s", strerror(error)); + return; + } + } + while (bytes > 0); + + close(infile); + } + else + { +#ifdef HAVE_SSL + if (port == 443 || !strcmp(scheme, "https")) + encryption = HTTP_ENCRYPTION_ALWAYS; + else +#endif /* HAVE_SSL */ + encryption = HTTP_ENCRYPTION_IF_REQUESTED; + + if ((http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, + 1, 30000, NULL)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, + "Unable to connect to %s: %s", hostname, + cupsLastErrorString()); + job->state = IPP_JSTATE_ABORTED; + + close(job->fd); + job->fd = -1; + + unlink(filename); + return; + } + + httpClearFields(http); + httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); + if (httpGet(http, resource)) + { + respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, + "Unable to GET URI: %s", strerror(errno)); + + job->state = IPP_JSTATE_ABORTED; + + close(job->fd); + job->fd = -1; + + unlink(filename); + httpClose(http); + return; + } + + while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); + + if (status != HTTP_STATUS_OK) + { + respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, + "Unable to GET URI: %s", httpStatus(status)); + + job->state = IPP_JSTATE_ABORTED; + + close(job->fd); + job->fd = -1; + + unlink(filename); + httpClose(http); + return; + } + + while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) + { + if (write(job->fd, buffer, (size_t)bytes) < bytes) + { + int error = errno; /* Write error */ + + job->state = IPP_JSTATE_ABORTED; + + close(job->fd); + job->fd = -1; + + unlink(filename); + httpClose(http); + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to write print file: %s", strerror(error)); + return; + } + } + + httpClose(http); + } + + if (close(job->fd)) + { + int error = errno; /* Write error */ + + job->state = IPP_JSTATE_ABORTED; + job->fd = -1; + + unlink(filename); + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to write print file: %s", strerror(error)); + return; + } + + job->fd = -1; + job->filename = strdup(filename); + job->state = IPP_JSTATE_PENDING; + + /* TODO: Do something different here - only process if the printer is idle */ + /* + * Process the job... + */ + + check_jobs(client->printer); + + /* + * Return the job info... + */ + + respond_ipp(client, IPP_STATUS_OK, NULL); + + ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); + cupsArrayAdd(ra, "job-id"); + cupsArrayAdd(ra, "job-state"); + cupsArrayAdd(ra, "job-state-reasons"); + cupsArrayAdd(ra, "job-uri"); + + copy_job_attributes(client, job, ra); + cupsArrayDelete(ra); + + /* + * Process any pending subscriptions... + */ + + client->job = job; + ipp_create_xxx_subscriptions(client); +} + + +/* + * 'ipp_renew_subscription()' - Renew a subscription. + */ + +static void +ipp_renew_subscription( + _ipp_client_t *client) /* I - Client */ +{ + _ipp_subscription_t *sub; /* Subscription */ + ipp_attribute_t *attr; /* notify-lease-duration */ + int lease; /* Lease duration in seconds */ + + + if ((sub = find_subscription(client, 0)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Subscription was not found."); + return; + } + + if (sub->job) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Per-job subscriptions cannot be renewed."); + return; + } + + if ((attr = ippFindAttribute(client->request, "notify-lease-duration", IPP_TAG_ZERO)) != NULL) + { + if (ippGetGroupTag(attr) != IPP_TAG_SUBSCRIPTION || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetCount(attr) != 1 || ippGetInteger(attr, 0) < 0) + { + respond_ipp(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, "Bad notify-lease-duration."); + return; + } + + lease = ippGetInteger(attr, 0); + } + else + lease = _IPP_NOTIFY_LEASE_DURATION_DEFAULT; + + sub->lease = lease; + + if (lease) + sub->expire = time(NULL) + sub->lease; + else + sub->expire = INT_MAX; + + respond_ipp(client, IPP_STATUS_OK, NULL); +} + + +/* + * 'ipp_send_document()' - Add an attached document to a job object created with + * Create-Job. + */ + +static void +ipp_send_document(_ipp_client_t *client)/* I - Client */ +{ + _ipp_job_t *job; /* Job information */ + char filename[1024], /* Filename buffer */ + buffer[4096]; /* Copy buffer */ + ssize_t bytes; /* Bytes read */ + ipp_attribute_t *attr; /* Current attribute */ + cups_array_t *ra; /* Attributes to send in response */ + + + /* + * Get the job... + */ + + if ((job = find_job(client, 0)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); + httpFlush(client->http); + return; + } + + /* + * See if we already have a document for this job or the job has already + * in a non-pending state... + */ + + if (job->state > IPP_JSTATE_HELD) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, + "Job is not in a pending state."); + httpFlush(client->http); + return; + } + else if (job->filename || job->fd >= 0) + { + respond_ipp(client, IPP_STATUS_ERROR_MULTIPLE_JOBS_NOT_SUPPORTED, + "Multiple document jobs are not supported."); + httpFlush(client->http); + return; + } + + if ((attr = ippFindAttribute(client->request, "last-document", + IPP_TAG_ZERO)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, + "Missing required last-document attribute."); + httpFlush(client->http); + return; + } + else if (ippGetValueTag(attr) != IPP_TAG_BOOLEAN || ippGetCount(attr) != 1 || + !ippGetBoolean(attr, 0)) + { + respond_unsupported(client, attr); + httpFlush(client->http); + return; + } + + /* + * Validate document attributes... + */ + + if (!valid_doc_attributes(client)) + { + httpFlush(client->http); + return; + } + + copy_attributes(job->attrs, client->request, NULL, IPP_TAG_JOB, 0); + + /* + * Get the document format for the job... + */ + + _cupsRWLockWrite(&(client->printer->rwlock)); + + if ((attr = ippFindAttribute(job->attrs, "document-format-detected", IPP_TAG_MIMETYPE)) != NULL) + job->format = ippGetString(attr, 0, NULL); + else if ((attr = ippFindAttribute(job->attrs, "document-format-supplied", IPP_TAG_MIMETYPE)) != NULL) + job->format = ippGetString(attr, 0, NULL); + else + job->format = "application/octet-stream"; + + /* + * Create a file for the request data... + */ + + create_job_filename(client->printer, job, NULL, filename, sizeof(filename)); + + if (Verbosity) + fprintf(stderr, "Creating job file \"%s\", format \"%s\".\n", filename, job->format); + + job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); + + _cupsRWUnlock(&(client->printer->rwlock)); + + if (job->fd < 0) + { + job->state = IPP_JSTATE_ABORTED; + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to create print file: %s", strerror(errno)); + return; + } + + while ((bytes = httpRead2(client->http, buffer, sizeof(buffer))) > 0) + { + if (write(job->fd, buffer, (size_t)bytes) < bytes) + { + int error = errno; /* Write error */ + + job->state = IPP_JSTATE_ABORTED; + + close(job->fd); + job->fd = -1; + + unlink(filename); + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to write print file: %s", strerror(error)); + return; + } + } + + if (bytes < 0) + { + /* + * Got an error while reading the print data, so abort this job. + */ + + job->state = IPP_JSTATE_ABORTED; + + close(job->fd); + job->fd = -1; + + unlink(filename); + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to read print file."); + return; + } + + if (close(job->fd)) + { + int error = errno; /* Write error */ + + job->state = IPP_JSTATE_ABORTED; + job->fd = -1; + + unlink(filename); + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to write print file: %s", strerror(error)); + return; + } + + _cupsRWLockWrite(&(client->printer->rwlock)); + + job->fd = -1; + job->filename = strdup(filename); + job->state = IPP_JSTATE_PENDING; + + _cupsRWUnlock(&(client->printer->rwlock)); + + /* + * Process the job, if possible... + */ + + check_jobs(client->printer); + + /* + * Return the job info... + */ + + respond_ipp(client, IPP_STATUS_OK, NULL); + + ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); + cupsArrayAdd(ra, "job-id"); + cupsArrayAdd(ra, "job-state"); + cupsArrayAdd(ra, "job-state-reasons"); + cupsArrayAdd(ra, "job-uri"); + + copy_job_attributes(client, job, ra); + cupsArrayDelete(ra); +} + + +/* + * 'ipp_send_uri()' - Add a referenced document to a job object created with + * Create-Job. + */ + +static void +ipp_send_uri(_ipp_client_t *client) /* I - Client */ +{ + _ipp_job_t *job; /* Job information */ + ipp_attribute_t *uri; /* document-uri */ + char scheme[256], /* URI scheme */ + userpass[256], /* Username and password info */ + hostname[256], /* Hostname */ + resource[1024]; /* Resource path */ + int port; /* Port number */ + http_uri_status_t uri_status; /* URI decode status */ + http_encryption_t encryption; /* Encryption to use, if any */ + http_t *http; /* Connection for http/https URIs */ + http_status_t status; /* Access status for http/https URIs */ + int infile; /* Input file for local file URIs */ + char filename[1024], /* Filename buffer */ + buffer[4096]; /* Copy buffer */ + ssize_t bytes; /* Bytes read */ + ipp_attribute_t *attr; /* Current attribute */ + cups_array_t *ra; /* Attributes to send in response */ + static const char * const uri_status_strings[] = + { /* URI decode errors */ + "URI too large.", + "Bad arguments to function.", + "Bad resource in URI.", + "Bad port number in URI.", + "Bad hostname in URI.", + "Bad username in URI.", + "Bad scheme in URI.", + "Bad/empty URI." + }; + + + /* + * Get the job... + */ + + if ((job = find_job(client, 0)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist."); + httpFlush(client->http); + return; + } + + /* + * See if we already have a document for this job or the job has already + * in a non-pending state... + */ + + if (job->state > IPP_JSTATE_HELD) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, + "Job is not in a pending state."); + httpFlush(client->http); + return; + } + else if (job->filename || job->fd >= 0) + { + respond_ipp(client, IPP_STATUS_ERROR_MULTIPLE_JOBS_NOT_SUPPORTED, + "Multiple document jobs are not supported."); + httpFlush(client->http); + return; + } + + if ((attr = ippFindAttribute(client->request, "last-document", + IPP_TAG_ZERO)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, + "Missing required last-document attribute."); + httpFlush(client->http); + return; + } + else if (ippGetValueTag(attr) != IPP_TAG_BOOLEAN || ippGetCount(attr) != 1 || + !ippGetBoolean(attr, 0)) + { + respond_unsupported(client, attr); + httpFlush(client->http); + return; + } + + /* + * Validate document attributes... + */ + + if (!valid_doc_attributes(client)) + { + httpFlush(client->http); + return; + } + + /* + * Do we have a file to print? + */ + + if (httpGetState(client->http) == HTTP_STATE_POST_RECV) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, + "Unexpected document data following request."); + return; + } + + /* + * Do we have a document URI? + */ + + if ((uri = ippFindAttribute(client->request, "document-uri", + IPP_TAG_URI)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Missing document-uri."); + return; + } + + if (ippGetCount(uri) != 1) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, + "Too many document-uri values."); + return; + } + + uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL), + scheme, sizeof(scheme), userpass, + sizeof(userpass), hostname, sizeof(hostname), + &port, resource, sizeof(resource)); + if (uri_status < HTTP_URI_STATUS_OK) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad document-uri: %s", + uri_status_strings[uri_status - HTTP_URI_STATUS_OVERFLOW]); + return; + } + + if (strcmp(scheme, "file") && +#ifdef HAVE_SSL + strcmp(scheme, "https") && +#endif /* HAVE_SSL */ + strcmp(scheme, "http")) + { + respond_ipp(client, IPP_STATUS_ERROR_URI_SCHEME, + "URI scheme \"%s\" not supported.", scheme); + return; + } + + if (!strcmp(scheme, "file") && access(resource, R_OK)) + { + respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, + "Unable to access URI: %s", strerror(errno)); + return; + } + + /* + * Get the document format for the job... + */ + + _cupsRWLockWrite(&(client->printer->rwlock)); + + if ((attr = ippFindAttribute(job->attrs, "document-format", + IPP_TAG_MIMETYPE)) != NULL) + job->format = ippGetString(attr, 0, NULL); + else + job->format = "application/octet-stream"; + + /* + * Create a file for the request data... + */ + + if (!strcasecmp(job->format, "image/jpeg")) + snprintf(filename, sizeof(filename), "%s/%d.jpg", + client->printer->directory, job->id); + else if (!strcasecmp(job->format, "image/png")) + snprintf(filename, sizeof(filename), "%s/%d.png", + client->printer->directory, job->id); + else if (!strcasecmp(job->format, "application/pdf")) + snprintf(filename, sizeof(filename), "%s/%d.pdf", + client->printer->directory, job->id); + else if (!strcasecmp(job->format, "application/postscript")) + snprintf(filename, sizeof(filename), "%s/%d.ps", + client->printer->directory, job->id); + else + snprintf(filename, sizeof(filename), "%s/%d.prn", + client->printer->directory, job->id); + + job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); + + _cupsRWUnlock(&(client->printer->rwlock)); + + if (job->fd < 0) + { + job->state = IPP_JSTATE_ABORTED; + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to create print file: %s", strerror(errno)); + return; + } + + if (!strcmp(scheme, "file")) + { + if ((infile = open(resource, O_RDONLY)) < 0) + { + respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, + "Unable to access URI: %s", strerror(errno)); + return; + } + + do + { + if ((bytes = read(infile, buffer, sizeof(buffer))) < 0 && + (errno == EAGAIN || errno == EINTR)) + bytes = 1; + else if (bytes > 0 && write(job->fd, buffer, (size_t)bytes) < bytes) + { + int error = errno; /* Write error */ + + job->state = IPP_JSTATE_ABORTED; + + close(job->fd); + job->fd = -1; + + unlink(filename); + close(infile); + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to write print file: %s", strerror(error)); + return; + } + } + while (bytes > 0); + + close(infile); + } + else + { +#ifdef HAVE_SSL + if (port == 443 || !strcmp(scheme, "https")) + encryption = HTTP_ENCRYPTION_ALWAYS; + else +#endif /* HAVE_SSL */ + encryption = HTTP_ENCRYPTION_IF_REQUESTED; + + if ((http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, + 1, 30000, NULL)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, + "Unable to connect to %s: %s", hostname, + cupsLastErrorString()); + job->state = IPP_JSTATE_ABORTED; + + close(job->fd); + job->fd = -1; + + unlink(filename); + return; + } + + httpClearFields(http); + httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); + if (httpGet(http, resource)) + { + respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, + "Unable to GET URI: %s", strerror(errno)); + + job->state = IPP_JSTATE_ABORTED; + + close(job->fd); + job->fd = -1; + + unlink(filename); + httpClose(http); + return; + } + + while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); + + if (status != HTTP_STATUS_OK) + { + respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, + "Unable to GET URI: %s", httpStatus(status)); + + job->state = IPP_JSTATE_ABORTED; + + close(job->fd); + job->fd = -1; + + unlink(filename); + httpClose(http); + return; + } + + while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) + { + if (write(job->fd, buffer, (size_t)bytes) < bytes) + { + int error = errno; /* Write error */ + + job->state = IPP_JSTATE_ABORTED; + + close(job->fd); + job->fd = -1; + + unlink(filename); + httpClose(http); + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to write print file: %s", strerror(error)); + return; + } + } + + httpClose(http); + } + + if (close(job->fd)) + { + int error = errno; /* Write error */ + + job->state = IPP_JSTATE_ABORTED; + job->fd = -1; + + unlink(filename); + + respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, + "Unable to write print file: %s", strerror(error)); + return; + } + + _cupsRWLockWrite(&(client->printer->rwlock)); + + job->fd = -1; + job->filename = strdup(filename); + job->state = IPP_JSTATE_PENDING; + + _cupsRWUnlock(&(client->printer->rwlock)); + + /* + * Process the job, if possible... + */ + + check_jobs(client->printer); + + /* + * Return the job info... + */ + + respond_ipp(client, IPP_STATUS_OK, NULL); + + ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); + cupsArrayAdd(ra, "job-id"); + cupsArrayAdd(ra, "job-state"); + cupsArrayAdd(ra, "job-state-reasons"); + cupsArrayAdd(ra, "job-uri"); + + copy_job_attributes(client, job, ra); + cupsArrayDelete(ra); +} + + +/* + * 'ipp_update_active_jobs()' - Update the list of active jobs. + */ + +static void +ipp_update_active_jobs( + _ipp_client_t *client) /* I - Client */ +{ + _ipp_device_t *device; /* Output device */ + _ipp_job_t *job; /* Job */ + ipp_attribute_t *job_ids, /* job-ids */ + *job_states; /* output-device-job-states */ + int i, /* Looping var */ + count, /* Number of values */ + num_different = 0, + /* Number of jobs with different states */ + different[1000],/* Jobs with different states */ + num_unsupported = 0, + /* Number of unsupported job-ids */ + unsupported[1000]; + /* Unsupported job-ids */ + ipp_jstate_t states[1000]; /* Different job state values */ + + + /* + * Process the job-ids and output-device-job-states values... + */ + + if ((device = find_device(client)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Device was not found."); + return; + } + + if ((job_ids = ippFindAttribute(client->request, "job-ids", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(job_ids) != IPP_TAG_OPERATION || ippGetValueTag(job_ids) != IPP_TAG_INTEGER) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, job_ids ? "Bad job-ids attribute." : "Missing required job-ids attribute."); + return; + } + + if ((job_states = ippFindAttribute(client->request, "output-device-job-states", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(job_states) != IPP_TAG_OPERATION || ippGetValueTag(job_states) != IPP_TAG_ENUM) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, job_ids ? "Bad output-device-job-states attribute." : "Missing required output-device-job-states attribute."); + return; + } + + count = ippGetCount(job_ids); + if (count != ippGetCount(job_states)) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "The job-ids and output-device-job-states attributes do not have the same number of values."); + return; + } + + for (i = 0; i < count; i ++) + { + if ((job = find_job(client, ippGetInteger(job_ids, i))) == NULL || !job->dev_uuid || strcmp(job->dev_uuid, device->uuid)) + { + if (num_unsupported < 1000) + unsupported[num_unsupported ++] = ippGetInteger(job_ids, i); + } + else + { + ipp_jstate_t state = (ipp_jstate_t)ippGetInteger(job_states, i); + + if (job->state >= IPP_JSTATE_STOPPED && state != job->state) + { + if (num_different < 1000) + { + different[num_different] = job->id; + states[num_different ++] = job->state; + } + } + else + job->dev_state = state; + } + } + + /* + * Then look for jobs assigned to the device but not listed... + */ + + for (job = (_ipp_job_t *)cupsArrayFirst(client->printer->jobs); + job && num_different < 1000; + job = (_ipp_job_t *)cupsArrayNext(client->printer->jobs)) + { + if (job->dev_uuid && !strcmp(job->dev_uuid, device->uuid) && !ippContainsInteger(job_ids, job->id)) + { + different[num_different] = job->id; + states[num_different ++] = job->state; + } + } + + respond_ipp(client, IPP_STATUS_OK, NULL); + + if (num_different > 0) + { + ippAddIntegers(client->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-ids", num_different, different); + ippAddIntegers(client->response, IPP_TAG_OPERATION, IPP_TAG_ENUM, "output-device-job-states", num_different, (int *)states); + } + + if (num_unsupported > 0) + { + ippAddIntegers(client->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER, "job-ids", num_unsupported, unsupported); + } +} + + +/* + * 'ipp_update_document_status()' - Update the state of a document. + */ + +static void +ipp_update_document_status( + _ipp_client_t *client) /* I - Client */ +{ + _ipp_device_t *device; /* Device */ + _ipp_job_t *job; /* Job */ + ipp_attribute_t *attr; /* Attribute */ + + + if ((device = find_device(client)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Device was not found."); + return; + } + + if ((job = find_job(client, 0)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job was not found."); + return; + } + + if (!job->dev_uuid || strcmp(job->dev_uuid, device->uuid)) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job not assigned to device."); + return; + } + + if ((attr = ippFindAttribute(client->request, "document-number", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(attr) != IPP_TAG_OPERATION || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetCount(attr) != 1 || ippGetInteger(attr, 0) != 1) + { + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, attr ? "Bad document-number attribute." : "Missing document-number attribute."); + return; + } + + if ((attr = ippFindAttribute(client->request, "impressions-completed", IPP_TAG_INTEGER)) != NULL) + { + job->impcompleted = ippGetInteger(attr, 0); + add_event(client->printer, job, _IPP_EVENT_JOB_PROGRESS, NULL); + } + + respond_ipp(client, IPP_STATUS_OK, NULL); +} + + +/* + * 'ipp_update_job_status()' - Update the state of a job. + */ + +static void +ipp_update_job_status( + _ipp_client_t *client) /* I - Client */ +{ + _ipp_device_t *device; /* Device */ + _ipp_job_t *job; /* Job */ + ipp_attribute_t *attr; /* Attribute */ + _ipp_event_t events = _IPP_EVENT_NONE; + /* Event(s) */ + + + if ((device = find_device(client)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Device was not found."); + return; + } + + if ((job = find_job(client, 0)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job was not found."); + return; + } + + if (!job->dev_uuid || strcmp(job->dev_uuid, device->uuid)) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Job not assigned to device."); + return; + } + + if ((attr = ippFindAttribute(client->request, "job-impressions-completed", IPP_TAG_INTEGER)) != NULL) + { + job->impcompleted = ippGetInteger(attr, 0); + events |= _IPP_EVENT_JOB_PROGRESS; + } + + if ((attr = ippFindAttribute(client->request, "output-device-job-state", IPP_TAG_ENUM)) != NULL) + { + job->dev_state = (ipp_jstate_t)ippGetInteger(attr, 0); + events |= _IPP_EVENT_JOB_STATE_CHANGED; + } + + if ((attr = ippFindAttribute(client->request, "output-device-job-state-reasons", IPP_TAG_KEYWORD)) != NULL) + { + job->dev_state_reasons = get_job_state_reasons_bits(attr); + events |= _IPP_EVENT_JOB_STATE_CHANGED; + } + + if (events) + add_event(client->printer, job, events, NULL); + + respond_ipp(client, IPP_STATUS_OK, NULL); +} + + +/* + * 'ipp_update_output_device_attributes()' - Update the values for an output device. + */ + +static void +ipp_update_output_device_attributes( + _ipp_client_t *client) /* I - Client */ +{ + _ipp_device_t *device; /* Device */ + ipp_attribute_t *attr, /* Current attribute */ + *dev_attr; /* Device attribute */ + _ipp_event_t events = _IPP_EVENT_NONE; + /* Config/state changed? */ + + + if ((device = find_device(client)) == NULL) + { + if ((device = create_device(client)) == NULL) + { + respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE, "Unable to add output device."); + return; + } + } + + _cupsRWLockWrite(&device->rwlock); + + attr = ippFirstAttribute(client->request); + while (attr && ippGetGroupTag(attr) != IPP_TAG_PRINTER) + attr = ippNextAttribute(client->request); + + for (; attr; attr = ippNextAttribute(client->request)) + { + const char *attrname = ippGetName(attr), + /* Attribute name */ + *dotptr; /* Pointer to dot in name */ + + /* + * Skip attributes we don't care about... + */ + + if (!attrname) + continue; + + if (strncmp(attrname, "copies", 6) && strncmp(attrname, "document-format", 15) && strncmp(attrname, "finishings", 10) && strncmp(attrname, "media", 5) && strncmp(attrname, "print-", 6) && strncmp(attrname, "sides", 5) && strncmp(attrname, "printer-alert", 13) && strncmp(attrname, "printer-input", 13) && strncmp(attrname, "printer-output", 14) && strncmp(attrname, "printer-resolution", 18) && strncmp(attrname, "pwg-raster", 10) && strncmp(attrname, "urf-", 4)) + continue; + + if (strncmp(attrname, "printer-alert", 13) || strncmp(attrname, "printer-state", 13)) + events |= _IPP_EVENT_PRINTER_CONFIG_CHANGED; + else + events |= _IPP_EVENT_PRINTER_STATE_CHANGED; + + if (!strcmp(attrname, "media-col-ready") || !strcmp(attrname, "media-ready")) + events |= _IPP_EVENT_PRINTER_MEDIA_CHANGED; + + if (!strcmp(attrname, "finishings-col-ready") || !strcmp(attrname, "finishings-ready")) + events |= _IPP_EVENT_PRINTER_FINISHINGS_CHANGED; + + if ((dotptr = strrchr(attrname, '.')) != NULL && isdigit(dotptr[1] & 255)) + { +#if 0 + /* + * Sparse representation: name.NNN or name.NNN-NNN + */ + + char temp[256], /* Temporary name string */ + *tempptr; /* Pointer into temporary string */ + int low, high; /* Low and high numbers in range */ + + low = (int)strtol(dotptr + 1, (char **)&dotptr, 10); + if (dotptr && *dotptr == '-') + high = (int)strtol(dotptr + 1, NULL, 10); + else + high = low; + + strlcpy(temp, attrname, sizeof(temp)); + if ((tempptr = strrchr(temp, '.')) != NULL) + *tempptr = '\0'; + + if ((dev_attr = ippFindAttribute(device->attrs, temp, IPP_TAG_ZERO)) != NULL) + { + } + else +#endif /* 0 */ + respond_unsupported(client, attr); + } + else + { + /* + * Regular representation - replace or delete current attribute, + * if any... + */ + + if ((dev_attr = ippFindAttribute(device->attrs, attrname, IPP_TAG_ZERO)) != NULL) + ippDeleteAttribute(device->attrs, dev_attr); + + if (ippGetValueTag(attr) != IPP_TAG_DELETEATTR) + ippCopyAttribute(device->attrs, attr, 0); + } + } + + _cupsRWUnlock(&device->rwlock); + + if (events) + { + _cupsRWLockWrite(&client->printer->rwlock); + if (events & _IPP_EVENT_PRINTER_CONFIG_CHANGED) + update_device_attributes_no_lock(client->printer); + if (events & _IPP_EVENT_PRINTER_STATE_CHANGED) + update_device_state_no_lock(client->printer); + _cupsRWUnlock(&client->printer->rwlock); + + add_event(client->printer, NULL, events, NULL); + } +} + + +/* + * 'ipp_validate_document()' - Validate document creation attributes. + */ + +static void +ipp_validate_document( + _ipp_client_t *client) /* I - Client */ +{ + if (valid_doc_attributes(client)) + respond_ipp(client, IPP_STATUS_OK, NULL); +} + + +/* + * 'ipp_validate_job()' - Validate job creation attributes. + */ + +static void +ipp_validate_job(_ipp_client_t *client) /* I - Client */ +{ + if (valid_job_attributes(client)) + respond_ipp(client, IPP_STATUS_OK, NULL); +} + + +#if 0 +/* + * 'parse_options()' - Parse URL options into CUPS options. + * + * The client->options string is destroyed by this function. + */ + +static int /* O - Number of options */ +parse_options(_ipp_client_t *client, /* I - Client */ + cups_option_t **options) /* O - Options */ +{ + char *name, /* Name */ + *value, /* Value */ + *next; /* Next name=value pair */ + int num_options = 0; /* Number of options */ + + + *options = NULL; + + for (name = client->options; name && *name; name = next) + { + if ((value = strchr(name, '=')) == NULL) + break; + + *value++ = '\0'; + if ((next = strchr(value, '&')) != NULL) + *next++ = '\0'; + + num_options = cupsAddOption(name, value, num_options, options); + } + + return (num_options); +} +#endif /* 0 */ + + +/* + * 'process_client()' - Process client requests on a thread. + */ + +static void * /* O - Exit status */ +process_client(_ipp_client_t *client) /* I - Client */ +{ + /* + * Loop until we are out of requests or timeout (30 seconds)... + */ + +#ifdef HAVE_SSL + int first_time = 1; /* First time request? */ +#endif /* HAVE_SSL */ + + while (httpWait(client->http, 30000)) + { +#ifdef HAVE_SSL + if (first_time) + { + /* + * See if we need to negotiate a TLS connection... + */ + + char buf[1]; /* First byte from client */ + + if (recv(httpGetFd(client->http), buf, 1, MSG_PEEK) == 1 && (!buf[0] || !strchr("DGHOPT", buf[0]))) + { + fprintf(stderr, "%s Starting HTTPS session.\n", client->hostname); + + if (httpEncryption(client->http, HTTP_ENCRYPTION_ALWAYS)) + { + fprintf(stderr, "%s Unable to encrypt connection: %s\n", client->hostname, cupsLastErrorString()); + break; + } + + fprintf(stderr, "%s Connection now encrypted.\n", client->hostname); + } + + first_time = 0; + } +#endif /* HAVE_SSL */ + + if (!process_http(client)) + break; + } + + /* + * Close the conection to the client and return... + */ + + delete_client(client); + + return (NULL); +} + + +/* + * 'process_http()' - Process a HTTP request. + */ + +int /* O - 1 on success, 0 on failure */ +process_http(_ipp_client_t *client) /* I - Client connection */ +{ + char uri[1024]; /* URI */ + http_state_t http_state; /* HTTP state */ + http_status_t http_status; /* HTTP status */ + ipp_state_t ipp_state; /* State of IPP transfer */ + char scheme[32], /* Method/scheme */ + userpass[128], /* Username:password */ + hostname[HTTP_MAX_HOST]; + /* Hostname */ + int port; /* Port number */ + const char *encoding; /* Content-Encoding value */ + static const char * const http_states[] = + { /* Strings for logging HTTP method */ + "WAITING", + "OPTIONS", + "GET", + "GET_SEND", + "HEAD", + "POST", + "POST_RECV", + "POST_SEND", + "PUT", + "PUT_RECV", + "DELETE", + "TRACE", + "CONNECT", + "STATUS", + "UNKNOWN_METHOD", + "UNKNOWN_VERSION" + }; + + + /* + * Clear state variables... + */ + + ippDelete(client->request); + ippDelete(client->response); + + client->request = NULL; + client->response = NULL; + client->operation = HTTP_STATE_WAITING; + + /* + * Read a request from the connection... + */ + + while ((http_state = httpReadRequest(client->http, uri, + sizeof(uri))) == HTTP_STATE_WAITING) + usleep(1); + + /* + * Parse the request line... + */ + + if (http_state == HTTP_STATE_ERROR) + { + if (httpError(client->http) == EPIPE) + fprintf(stderr, "%s Client closed connection.\n", client->hostname); + else + fprintf(stderr, "%s Bad request line (%s).\n", client->hostname, + strerror(httpError(client->http))); + + return (0); + } + else if (http_state == HTTP_STATE_UNKNOWN_METHOD) + { + fprintf(stderr, "%s Bad/unknown operation.\n", client->hostname); + respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); + return (0); + } + else if (http_state == HTTP_STATE_UNKNOWN_VERSION) + { + fprintf(stderr, "%s Bad HTTP version.\n", client->hostname); + respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); + return (0); + } + + fprintf(stderr, "%s %s %s\n", client->hostname, http_states[http_state], + uri); + + /* + * Separate the URI into its components... + */ + + if (httpSeparateURI(HTTP_URI_CODING_MOST, uri, scheme, sizeof(scheme), + userpass, sizeof(userpass), + hostname, sizeof(hostname), &port, + client->uri, sizeof(client->uri)) < HTTP_URI_STATUS_OK && + (http_state != HTTP_STATE_OPTIONS || strcmp(uri, "*"))) + { + fprintf(stderr, "%s Bad URI \"%s\".\n", client->hostname, uri); + respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); + return (0); + } + + if ((client->options = strchr(client->uri, '?')) != NULL) + *(client->options)++ = '\0'; + + /* + * Process the request... + */ + + client->start = time(NULL); + client->operation = httpGetState(client->http); + + /* + * Parse incoming parameters until the status changes... + */ + + while ((http_status = httpUpdate(client->http)) == HTTP_STATUS_CONTINUE); + + if (http_status != HTTP_STATUS_OK) + { + respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); + return (0); + } + + if (!httpGetField(client->http, HTTP_FIELD_HOST)[0] && + httpGetVersion(client->http) >= HTTP_VERSION_1_1) + { + /* + * HTTP/1.1 and higher require the "Host:" field... + */ + + respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); + return (0); + } + + /* + * Handle HTTP Upgrade... + */ + + if (!strcasecmp(httpGetField(client->http, HTTP_FIELD_CONNECTION), + "Upgrade")) + { +#ifdef HAVE_SSL + if (strstr(httpGetField(client->http, HTTP_FIELD_UPGRADE), "TLS/") != NULL && !httpIsEncrypted(client->http)) + { + if (!respond_http(client, HTTP_STATUS_SWITCHING_PROTOCOLS, NULL, NULL, 0)) + return (0); + + fprintf(stderr, "%s Upgrading to encrypted connection.\n", client->hostname); + + if (httpEncryption(client->http, HTTP_ENCRYPTION_REQUIRED)) + { + fprintf(stderr, "%s Unable to encrypt connection: %s\n", client->hostname, cupsLastErrorString()); + return (0); + } + + fprintf(stderr, "%s Connection now encrypted.\n", client->hostname); + } + else +#endif /* HAVE_SSL */ + + if (!respond_http(client, HTTP_STATUS_NOT_IMPLEMENTED, NULL, NULL, 0)) + return (0); + } + + /* + * Handle HTTP Expect... + */ + + if (httpGetExpect(client->http) && + (client->operation == HTTP_STATE_POST || + client->operation == HTTP_STATE_PUT)) + { + if (httpGetExpect(client->http) == HTTP_STATUS_CONTINUE) + { + /* + * Send 100-continue header... + */ + + if (!respond_http(client, HTTP_STATUS_CONTINUE, NULL, NULL, 0)) + return (0); + } + else + { + /* + * Send 417-expectation-failed header... + */ + + if (!respond_http(client, HTTP_STATUS_EXPECTATION_FAILED, NULL, NULL, 0)) + return (0); + } + } + + /* + * Handle new transfers... + */ + + encoding = httpGetContentEncoding(client->http); + + switch (client->operation) + { + case HTTP_STATE_OPTIONS : + /* + * Do OPTIONS command... + */ + + return (respond_http(client, HTTP_STATUS_OK, NULL, NULL, 0)); + + case HTTP_STATE_HEAD : +#if 0 /* TODO: Work out icon support */ + if (!strcmp(client->uri, "/icon.png")) + return (respond_http(client, HTTP_STATUS_OK, NULL, "image/png", 0)); + else +#endif /* 0 */ + if (!strcmp(client->uri, "/") || !strcmp(client->uri, "/media") || !strcmp(client->uri, "/supplies")) + return (respond_http(client, HTTP_STATUS_OK, NULL, "text/html", 0)); + else + return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0)); + + case HTTP_STATE_GET : +#if 0 /* TODO: Work out icon support */ + if (!strcmp(client->uri, "/icon.png")) + { + /* + * Send PNG icon file. + */ + + int fd; /* Icon file */ + struct stat fileinfo; /* Icon file information */ + char buffer[4096]; /* Copy buffer */ + ssize_t bytes; /* Bytes */ + + fprintf(stderr, "Icon file is \"%s\".\n", client->printer->icon); + + if (!stat(client->printer->icon, &fileinfo) && + (fd = open(client->printer->icon, O_RDONLY)) >= 0) + { + if (!respond_http(client, HTTP_STATUS_OK, NULL, "image/png", + (size_t)fileinfo.st_size)) + { + close(fd); + return (0); + } + + while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) + httpWrite2(client->http, buffer, (size_t)bytes); + + httpFlushWrite(client->http); + + close(fd); + } + else + return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0)); + } + else +#endif /* 0 */ + if (!strcmp(client->uri, "/")) + { + /* + * Show web status page... + */ + + _ipp_job_t *job; /* Current job */ + int i; /* Looping var */ + _ipp_preason_t reason; /* Current reason */ + static const char * const reasons[] = + { /* Reason strings */ + "Other", + "Cover Open", + "Input Tray Missing", + "Marker Supply Empty", + "Marker Supply Low", + "Marker Waste Almost Full", + "Marker Waste Full", + "Media Empty", + "Media Jam", + "Media Low", + "Media Needed", + "Moving to Paused", + "Paused", + "Spool Area Full", + "Toner Empty", + "Toner Low" + }; + + if (!respond_http(client, HTTP_STATUS_OK, encoding, "text/html", 0)) + return (0); + + html_header(client, client->printer->name); + html_printf(client, + "

ippserver (" CUPS_SVERSION ")

\n" + "

%s, %d job(s).", client->printer->state == IPP_PSTATE_IDLE ? "Idle" : client->printer->state == IPP_PSTATE_PROCESSING ? "Printing" : "Stopped", cupsArrayCount(client->printer->jobs)); + for (i = 0, reason = 1; i < (int)(sizeof(reasons) / sizeof(reasons[0])); i ++, reason <<= 1) + if (client->printer->state_reasons & reason) + html_printf(client, "\n
    %s", reasons[i]); + html_printf(client, "

\n"); + + if (cupsArrayCount(client->printer->jobs) > 0) + { + _cupsRWLockRead(&(client->printer->rwlock)); + + html_printf(client, "\n"); + for (job = (_ipp_job_t *)cupsArrayFirst(client->printer->jobs); job; job = (_ipp_job_t *)cupsArrayNext(client->printer->jobs)) + { + char when[256], /* When job queued/started/finished */ + hhmmss[64]; /* Time HH:MM:SS */ + + switch (job->state) + { + case IPP_JSTATE_PENDING : + case IPP_JSTATE_HELD : + snprintf(when, sizeof(when), "Queued at %s", time_string(job->created, hhmmss, sizeof(hhmmss))); + break; + case IPP_JSTATE_PROCESSING : + case IPP_JSTATE_STOPPED : + snprintf(when, sizeof(when), "Started at %s", time_string(job->processing, hhmmss, sizeof(hhmmss))); + break; + case IPP_JSTATE_ABORTED : + snprintf(when, sizeof(when), "Aborted at %s", time_string(job->completed, hhmmss, sizeof(hhmmss))); + break; + case IPP_JSTATE_CANCELED : + snprintf(when, sizeof(when), "Canceled at %s", time_string(job->completed, hhmmss, sizeof(hhmmss))); + break; + case IPP_JSTATE_COMPLETED : + snprintf(when, sizeof(when), "Completed at %s", time_string(job->completed, hhmmss, sizeof(hhmmss))); + break; + } + + html_printf(client, "\n", job->id, job->name, job->username, when); + } + html_printf(client, "
Job #NameOwnerWhen
%d%s%s%s
\n"); + + _cupsRWUnlock(&(client->printer->rwlock)); + } + html_footer(client); + + return (1); + } +#if 0 /* TODO: Pull media and supply info from device attrs */ + else if (!strcmp(client->uri, "/media")) + { + /* + * Show web media page... + */ + + int i, /* Looping var */ + num_options; /* Number of form options */ + cups_option_t *options; /* Form options */ + static const char * const sizes[] = + { /* Size strings */ + "ISO A4", + "ISO A5", + "ISO A6", + "DL Envelope", + "US Legal", + "US Letter", + "#10 Envelope", + "3x5 Photo", + "3.5x5 Photo", + "4x6 Photo", + "5x7 Photo" + }; + static const char * const types[] = + /* Type strings */ + { + "Auto", + "Cardstock", + "Envelope", + "Labels", + "Other", + "Glossy Photo", + "High-Gloss Photo", + "Matte Photo", + "Satin Photo", + "Semi-Gloss Photo", + "Plain", + "Letterhead", + "Transparency" + }; + static const int sheets[] = /* Number of sheets */ + { + 250, + 100, + 25, + 5, + 0 + }; + + if (!respond_http(client, HTTP_STATUS_OK, encoding, "text/html", 0)) + return (0); + + html_header(client, client->printer->name); + + if ((num_options = parse_options(client, &options)) > 0) + { + /* + * WARNING: A real printer/server implementation MUST NOT implement + * media updates via a GET request - GET requests are supposed to be + * idempotent (without side-effects) and we obviously are not + * authenticating access here. This form is provided solely to + * enable testing and development! + */ + + const char *val; /* Form value */ + + if ((val = cupsGetOption("main_size", num_options, options)) != NULL) + client->printer->main_size = atoi(val); + if ((val = cupsGetOption("main_type", num_options, options)) != NULL) + client->printer->main_type = atoi(val); + if ((val = cupsGetOption("main_level", num_options, options)) != NULL) + client->printer->main_level = atoi(val); + + if ((val = cupsGetOption("envelope_size", num_options, options)) != NULL) + client->printer->envelope_size = atoi(val); + if ((val = cupsGetOption("envelope_level", num_options, options)) != NULL) + client->printer->envelope_level = atoi(val); + + if ((val = cupsGetOption("photo_size", num_options, options)) != NULL) + client->printer->photo_size = atoi(val); + if ((val = cupsGetOption("photo_type", num_options, options)) != NULL) + client->printer->photo_type = atoi(val); + if ((val = cupsGetOption("photo_level", num_options, options)) != NULL) + client->printer->photo_level = atoi(val); + + if ((client->printer->main_level < 100 && client->printer->main_level > 0) || (client->printer->envelope_level < 25 && client->printer->envelope_level > 0) || (client->printer->photo_level < 25 && client->printer->photo_level > 0)) + client->printer->state_reasons |= _IPP_PREASON_MEDIA_LOW; + else + client->printer->state_reasons &= (_ipp_preason_t)~_IPP_PREASON_MEDIA_LOW; + + if ((client->printer->main_level == 0 && client->printer->main_size > _IPP_MEDIA_SIZE_NONE) || (client->printer->envelope_level == 0 && client->printer->envelope_size > _IPP_MEDIA_SIZE_NONE) || (client->printer->photo_level == 0 && client->printer->photo_size > _IPP_MEDIA_SIZE_NONE)) + { + client->printer->state_reasons |= _IPP_PREASON_MEDIA_EMPTY; + if (client->printer->active_job) + client->printer->state_reasons |= _IPP_PREASON_MEDIA_NEEDED; + } + else + client->printer->state_reasons &= (_ipp_preason_t)~(_IPP_PREASON_MEDIA_EMPTY | _IPP_PREASON_MEDIA_NEEDED); + + html_printf(client, "
Media updated.
\n"); + } + + html_printf(client, "
\n"); + + html_printf(client, "\n"); + html_printf(client, "\n"); + + html_printf(client, + "\n"); + + html_printf(client, + "\n"); + + html_printf(client, "
Main Tray:
Envelope Feeder:
Photo Tray:
\n"); + html_footer(client); + + return (1); + } + else if (!strcmp(client->uri, "/supplies")) + { + /* + * Show web supplies page... + */ + + int i, j, /* Looping vars */ + num_options; /* Number of form options */ + cups_option_t *options; /* Form options */ + static const int levels[] = { 0, 5, 10, 25, 50, 75, 90, 95, 100 }; + + if (!respond_http(client, HTTP_STATUS_OK, encoding, "text/html", 0)) + return (0); + + html_header(client, client->printer->name); + + if ((num_options = parse_options(client, &options)) > 0) + { + /* + * WARNING: A real printer/server implementation MUST NOT implement + * supply updates via a GET request - GET requests are supposed to be + * idempotent (without side-effects) and we obviously are not + * authenticating access here. This form is provided solely to + * enable testing and development! + */ + + char name[64]; /* Form field */ + const char *val; /* Form value */ + + client->printer->state_reasons &= (_ipp_preason_t)~(_IPP_PREASON_MARKER_SUPPLY_EMPTY | _IPP_PREASON_MARKER_SUPPLY_LOW | _IPP_PREASON_MARKER_WASTE_ALMOST_FULL | _IPP_PREASON_MARKER_WASTE_FULL | _IPP_PREASON_TONER_EMPTY | _IPP_PREASON_TONER_LOW); + + for (i = 0; i < (int)(sizeof(printer_supplies) / sizeof(printer_supplies[0])); i ++) + { + snprintf(name, sizeof(name), "supply_%d", i); + if ((val = cupsGetOption(name, num_options, options)) != NULL) + { + int level = client->printer->supplies[i] = atoi(val); + /* New level */ + + if (i < 4) + { + if (level == 0) + client->printer->state_reasons |= _IPP_PREASON_TONER_EMPTY; + else if (level < 10) + client->printer->state_reasons |= _IPP_PREASON_TONER_LOW; + } + else + { + if (level == 100) + client->printer->state_reasons |= _IPP_PREASON_MARKER_WASTE_FULL; + else if (level > 90) + client->printer->state_reasons |= _IPP_PREASON_MARKER_WASTE_ALMOST_FULL; + } + } + } + + html_printf(client, "
Supplies updated.
\n"); + } + + html_printf(client, "
\n"); + + html_printf(client, "\n"); + for (i = 0; i < (int)(sizeof(printer_supplies) / sizeof(printer_supplies[0])); i ++) + { + html_printf(client, "\n"); + } + html_printf(client, "\n
%s:
\n
\n"); + html_footer(client); + + return (1); + } +#endif /* 0 */ + else + return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0)); + break; + + case HTTP_STATE_POST : + if (strcmp(httpGetField(client->http, HTTP_FIELD_CONTENT_TYPE), + "application/ipp")) + { + /* + * Not an IPP request... + */ + + return (respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0)); + } + + /* + * Read the IPP request... + */ + + client->request = ippNew(); + + while ((ipp_state = ippRead(client->http, + client->request)) != IPP_STATE_DATA) + { + if (ipp_state == IPP_STATE_ERROR) + { + fprintf(stderr, "%s IPP read error (%s).\n", client->hostname, + cupsLastErrorString()); + respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0); + return (0); + } + } + + /* + * Now that we have the IPP request, process the request... + */ + + return (process_ipp(client)); + + default : + break; /* Anti-compiler-warning-code */ + } + + return (1); +} + + +/* + * 'process_ipp()' - Process an IPP request. + */ + +static int /* O - 1 on success, 0 on error */ +process_ipp(_ipp_client_t *client) /* I - Client */ +{ + ipp_tag_t group; /* Current group tag */ + ipp_attribute_t *attr; /* Current attribute */ + ipp_attribute_t *charset; /* Character set attribute */ + ipp_attribute_t *language; /* Language attribute */ + ipp_attribute_t *uri; /* Printer URI attribute */ + int major, minor; /* Version number */ + const char *name; /* Name of attribute */ + + + debug_attributes("Request", client->request, 1); + + /* + * First build an empty response message for this request... + */ + + client->operation_id = ippGetOperation(client->request); + client->response = ippNewResponse(client->request); + + /* + * Then validate the request header and required attributes... + */ + + major = ippGetVersion(client->request, &minor); + + if (major < 1 || major > 2) + { + /* + * Return an error, since we only support IPP 1.x and 2.x. + */ + + respond_ipp(client, IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, + "Bad request version number %d.%d.", major, minor); + } + else if (ippGetRequestId(client->request) <= 0) + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad request-id %d.", + ippGetRequestId(client->request)); + else if (!ippFirstAttribute(client->request)) + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, + "No attributes in request."); + else + { + /* + * Make sure that the attributes are provided in the correct order and + * don't repeat groups... + */ + + for (attr = ippFirstAttribute(client->request), + group = ippGetGroupTag(attr); + attr; + attr = ippNextAttribute(client->request)) + { + if (ippGetGroupTag(attr) < group && ippGetGroupTag(attr) != IPP_TAG_ZERO) + { + /* + * Out of order; return an error... + */ + + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, + "Attribute groups are out of order (%x < %x).", + ippGetGroupTag(attr), group); + break; + } + else + group = ippGetGroupTag(attr); + } + + if (!attr) + { + /* + * Then make sure that the first three attributes are: + * + * attributes-charset + * attributes-natural-language + * printer-uri/job-uri + */ + + attr = ippFirstAttribute(client->request); + name = ippGetName(attr); + if (attr && name && !strcmp(name, "attributes-charset") && + ippGetValueTag(attr) == IPP_TAG_CHARSET) + charset = attr; + else + charset = NULL; + + attr = ippNextAttribute(client->request); + name = ippGetName(attr); + + if (attr && name && !strcmp(name, "attributes-natural-language") && + ippGetValueTag(attr) == IPP_TAG_LANGUAGE) + language = attr; + else + language = NULL; + + if ((attr = ippFindAttribute(client->request, "printer-uri", + IPP_TAG_URI)) != NULL) + uri = attr; + else if ((attr = ippFindAttribute(client->request, "job-uri", + IPP_TAG_URI)) != NULL) + uri = attr; + else + uri = NULL; + + if (charset && + strcasecmp(ippGetString(charset, 0, NULL), "us-ascii") && + strcasecmp(ippGetString(charset, 0, NULL), "utf-8")) + { + /* + * Bad character set... + */ + + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, + "Unsupported character set \"%s\".", + ippGetString(charset, 0, NULL)); + } + else if (!charset || !language || !uri) + { + /* + * Return an error, since attributes-charset, + * attributes-natural-language, and printer-uri/job-uri are required + * for all operations. + */ + + respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, + "Missing required attributes."); + } + else + { + char scheme[32], /* URI scheme */ + userpass[32], /* Username/password in URI */ + host[256], /* Host name in URI */ + resource[256]; /* Resource path in URI */ + int port; /* Port number in URI */ + + name = ippGetName(uri); + + if (httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL), + scheme, sizeof(scheme), + userpass, sizeof(userpass), + host, sizeof(host), &port, + resource, sizeof(resource)) < HTTP_URI_STATUS_OK) + respond_ipp(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, + "Bad %s value '%s'.", name, ippGetString(uri, 0, NULL)); + else if ((!strcmp(name, "job-uri") && strncmp(resource, "/ipp/print/", 11)) || + (!strcmp(name, "printer-uri") && strcmp(resource, "/ipp/print"))) + respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "%s %s not found.", + name, ippGetString(uri, 0, NULL)); + else + { + /* + * Try processing the operation... + */ + + switch ((int)ippGetOperation(client->request)) + { + case IPP_OP_PRINT_JOB : + ipp_print_job(client); + break; + + case IPP_OP_PRINT_URI : + ipp_print_uri(client); + break; + + case IPP_OP_VALIDATE_JOB : + ipp_validate_job(client); + break; + + case IPP_OP_CREATE_JOB : + ipp_create_job(client); + break; + + case IPP_OP_SEND_DOCUMENT : + ipp_send_document(client); + break; + + case IPP_OP_SEND_URI : + ipp_send_uri(client); + break; + + case IPP_OP_CANCEL_JOB : + ipp_cancel_job(client); + break; + + case IPP_OP_CANCEL_MY_JOBS : + ipp_cancel_my_jobs(client); + break; + + case IPP_OP_GET_JOB_ATTRIBUTES : + ipp_get_job_attributes(client); + break; + + case IPP_OP_GET_JOBS : + ipp_get_jobs(client); + break; + + case IPP_OP_GET_PRINTER_ATTRIBUTES : + ipp_get_printer_attributes(client); + break; + + case IPP_OP_GET_PRINTER_SUPPORTED_VALUES : + ipp_get_printer_supported_values(client); + break; + + case IPP_OP_CLOSE_JOB : + ipp_close_job(client); + break; + + case IPP_OP_IDENTIFY_PRINTER : + ipp_identify_printer(client); + break; + + case IPP_OP_CANCEL_SUBSCRIPTION : + ipp_cancel_subscription(client); + break; + + case IPP_OP_CREATE_JOB_SUBSCRIPTIONS : + case IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS : + ipp_create_xxx_subscriptions(client); + break; + + case IPP_OP_GET_NOTIFICATIONS : + ipp_get_notifications(client); + break; + + case IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES : + ipp_get_subscription_attributes(client); + break; + + case IPP_OP_GET_SUBSCRIPTIONS : + ipp_get_subscriptions(client); + break; + + case IPP_OP_RENEW_SUBSCRIPTION : + ipp_renew_subscription(client); + break; + + case IPP_OP_GET_DOCUMENT_ATTRIBUTES : + ipp_get_document_attributes(client); + break; + + case IPP_OP_GET_DOCUMENTS : + ipp_get_documents(client); + break; + + case IPP_OP_VALIDATE_DOCUMENT : + ipp_validate_document(client); + break; + + case _IPP_OP_ACKNOWLEDGE_DOCUMENT : + ipp_acknowledge_document(client); + break; + + case _IPP_OP_ACKNOWLEDGE_IDENTIFY_PRINTER : + ipp_acknowledge_identify_printer(client); + break; + + case _IPP_OP_ACKNOWLEDGE_JOB : + ipp_acknowledge_job(client); + break; + + case _IPP_OP_FETCH_DOCUMENT : + ipp_fetch_document(client); + break; + + case _IPP_OP_FETCH_JOB : + ipp_fetch_job(client); + break; + + case _IPP_OP_GET_OUTPUT_DEVICE_ATTRIBUTES : + ipp_get_output_device_attributes(client); + break; + + case _IPP_OP_UPDATE_ACTIVE_JOBS : + ipp_update_active_jobs(client); + break; + + case _IPP_OP_UPDATE_DOCUMENT_STATUS : + ipp_update_document_status(client); + break; + + case _IPP_OP_UPDATE_JOB_STATUS : + ipp_update_job_status(client); + break; + + case _IPP_OP_UPDATE_OUTPUT_DEVICE_ATTRIBUTES : + ipp_update_output_device_attributes(client); + break; + + case _IPP_OP_DEREGISTER_OUTPUT_DEVICE : + ipp_deregister_output_device(client); + break; + + default : + respond_ipp(client, IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED, + "Operation not supported."); + break; + } + } + } + } + } + + /* + * Send the HTTP header and return... + */ + + if (httpGetState(client->http) != HTTP_STATE_POST_SEND) + httpFlush(client->http); /* Flush trailing (junk) data */ + + return (respond_http(client, HTTP_STATUS_OK, NULL, "application/ipp", + client->fetch_file >= 0 ? 0 : ippLength(client->response))); +} + + +/* + * 'process_job()' - Process a print job. + */ + +static void * /* O - Thread exit status */ +process_job(_ipp_job_t *job) /* I - Job */ +{ + job->state = IPP_JSTATE_PROCESSING; + job->printer->state = IPP_PSTATE_PROCESSING; + job->processing = time(NULL); + job->printer->processing_job = job; + + add_event(job->printer, job, _IPP_EVENT_JOB_STATE_CHANGED, "Job processing."); + + /* + * TODO: Perform any preprocessing needed... + */ + + // job->state_reasons |= _IPP_JREASON_JOB_TRANSFORMING; + // job->state_reasons &= ~_IPP_JREASON_JOB_TRANSFORMING; + + /* + * Set the state to processing-stopped, fetchable, then send a + * notification. + */ + + job->state = IPP_JSTATE_STOPPED; + job->state_reasons |= _IPP_JREASON_JOB_FETCHABLE; + + add_event(job->printer, job, _IPP_EVENT_JOB_STATE_CHANGED, "Job fetchable."); + + return (NULL); +} + + +/* + * 'respond_http()' - Send a HTTP response. + */ + +int /* O - 1 on success, 0 on failure */ +respond_http( + _ipp_client_t *client, /* I - Client */ + http_status_t code, /* I - HTTP status of response */ + const char *content_encoding, /* I - Content-Encoding of response */ + const char *type, /* I - MIME media type of response */ + size_t length) /* I - Length of response */ +{ + char message[1024]; /* Text message */ + + + fprintf(stderr, "%s %s\n", client->hostname, httpStatus(code)); + + if (code == HTTP_STATUS_CONTINUE) + { + /* + * 100-continue doesn't send any headers... + */ + + return (httpWriteResponse(client->http, HTTP_STATUS_CONTINUE) == 0); + } + + /* + * Format an error message... + */ + + if (!type && !length && code != HTTP_STATUS_OK && code != HTTP_STATUS_SWITCHING_PROTOCOLS) + { + snprintf(message, sizeof(message), "%d - %s\n", code, httpStatus(code)); + + type = "text/plain"; + length = strlen(message); + } + else + message[0] = '\0'; + + /* + * Send the HTTP response header... + */ + + httpClearFields(client->http); + + if (code == HTTP_STATUS_METHOD_NOT_ALLOWED || + client->operation == HTTP_STATE_OPTIONS) + httpSetField(client->http, HTTP_FIELD_ALLOW, "GET, HEAD, OPTIONS, POST"); + + if (type) + { + if (!strcmp(type, "text/html")) + httpSetField(client->http, HTTP_FIELD_CONTENT_TYPE, + "text/html; charset=utf-8"); + else + httpSetField(client->http, HTTP_FIELD_CONTENT_TYPE, type); + + if (content_encoding) + httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, content_encoding); + } + + httpSetLength(client->http, length); + + if (httpWriteResponse(client->http, code) < 0) + return (0); + + /* + * Send the response data... + */ + + if (message[0]) + { + /* + * Send a plain text message. + */ + + if (httpPrintf(client->http, "%s", message) < 0) + return (0); + + if (httpWrite2(client->http, "", 0) < 0) + return (0); + } + else if (client->response) + { + /* + * Send an IPP response... + */ + + debug_attributes("Response", client->response, 2); + + ippSetState(client->response, IPP_STATE_IDLE); + + if (ippWrite(client->http, client->response) != IPP_STATE_DATA) + return (0); + + if (client->fetch_file >= 0) + { + ssize_t bytes; /* Bytes read */ + char buffer[32768]; /* Buffer */ + + if (client->fetch_compression) + httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, "gzip"); + + while ((bytes = read(client->fetch_file, buffer, sizeof(buffer))) > 0) + httpWrite2(client->http, buffer, (size_t)bytes); + + httpWrite2(client->http, "", 0); + close(client->fetch_file); + client->fetch_file = -1; + } + } + + return (1); +} + + +/* + * 'respond_ipp()' - Send an IPP response. + */ + +static void +respond_ipp(_ipp_client_t *client, /* I - Client */ + ipp_status_t status, /* I - status-code */ + const char *message, /* I - printf-style status-message */ + ...) /* I - Additional args as needed */ +{ + const char *formatted = NULL; /* Formatted message */ + + + ippSetStatusCode(client->response, status); + + if (message) + { + va_list ap; /* Pointer to additional args */ + ipp_attribute_t *attr; /* New status-message attribute */ + + va_start(ap, message); + if ((attr = ippFindAttribute(client->response, "status-message", + IPP_TAG_TEXT)) != NULL) + ippSetStringfv(client->response, &attr, 0, message, ap); + else + attr = ippAddStringfv(client->response, IPP_TAG_OPERATION, IPP_TAG_TEXT, + "status-message", NULL, message, ap); + va_end(ap); + + formatted = ippGetString(attr, 0, NULL); + } + + if (formatted) + fprintf(stderr, "%s %s %s (%s)\n", client->hostname, + ippOpString(client->operation_id), ippErrorString(status), + formatted); + else + fprintf(stderr, "%s %s %s\n", client->hostname, + ippOpString(client->operation_id), ippErrorString(status)); +} + + +/* + * 'respond_unsupported()' - Respond with an unsupported attribute. + */ + +static void +respond_unsupported( + _ipp_client_t *client, /* I - Client */ + ipp_attribute_t *attr) /* I - Atribute */ +{ + ipp_attribute_t *temp; /* Copy of attribute */ + + + respond_ipp(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, + "Unsupported %s %s%s value.", ippGetName(attr), + ippGetCount(attr) > 1 ? "1setOf " : "", + ippTagString(ippGetValueTag(attr))); + + temp = ippCopyAttribute(client->response, attr, 0); + ippSetGroupTag(client->response, &temp, IPP_TAG_UNSUPPORTED_GROUP); +} + + +/* + * 'run_printer()' - Run the printer service. + */ + +static void +run_printer(_ipp_printer_t *printer) /* I - Printer */ +{ + int num_fds; /* Number of file descriptors */ + struct pollfd polldata[3]; /* poll() data */ + int timeout; /* Timeout for poll() */ + _ipp_client_t *client; /* New client */ + + + /* + * Setup poll() data for the Bonjour service socket and IPv4/6 listeners... + */ + + polldata[0].fd = printer->ipv4; + polldata[0].events = POLLIN; + + polldata[1].fd = printer->ipv6; + polldata[1].events = POLLIN; + + num_fds = 2; + + /* + * Loop until we are killed or have a hard error... + */ + + for (;;) + { + if (cupsArrayCount(printer->jobs)) + timeout = 10; + else + timeout = -1; + + if (poll(polldata, (nfds_t)num_fds, timeout) < 0 && errno != EINTR) + { + perror("poll() failed"); + break; + } + + if (polldata[0].revents & POLLIN) + { + if ((client = create_client(printer, printer->ipv4)) != NULL) + { + if (!_cupsThreadCreate((_cups_thread_func_t)process_client, client)) + { + perror("Unable to create client thread"); + delete_client(client); + } + } + } + + if (polldata[1].revents & POLLIN) + { + if ((client = create_client(printer, printer->ipv6)) != NULL) + { + if (!_cupsThreadCreate((_cups_thread_func_t)process_client, client)) + { + perror("Unable to create client thread"); + delete_client(client); + } + } + } + + /* + * Clean out old jobs... + */ + + clean_jobs(printer); + } +} + + +/* + * 'time_string()' - Return the local time in hours, minutes, and seconds. + */ + +static char * +time_string(time_t tv, /* I - Time value */ + char *buffer, /* I - Buffer */ + size_t bufsize) /* I - Size of buffer */ +{ + struct tm *curtime = localtime(&tv); + /* Local time */ + + strftime(buffer, bufsize, "%X", curtime); + return (buffer); +} + + +/* + * 'update_device_attributes_no_lock()' - Update the composite device attributes. + * + * Note: Caller MUST lock the printer object for writing before using. + */ + +static void +update_device_attributes_no_lock( + _ipp_printer_t *printer) /* I - Printer */ +{ + _ipp_device_t *device; /* Current device */ + ipp_t *dev_attrs; /* Device attributes */ + + + /* TODO: Support multiple output devices, icons, etc... */ + device = (_ipp_device_t *)cupsArrayFirst(printer->devices); + dev_attrs = ippNew(); + + if (device) + copy_attributes(dev_attrs, device->attrs, NULL, IPP_TAG_PRINTER, 0); + + ippDelete(printer->dev_attrs); + printer->dev_attrs = dev_attrs; + + printer->config_time = time(NULL); +} + + +/* + * 'update_device_status_no_lock()' - Update the composite device state. + * + * Note: Caller MUST lock the printer object for writing before using. + */ + +static void +update_device_state_no_lock( + _ipp_printer_t *printer) /* I - Printer */ +{ + _ipp_device_t *device; /* Current device */ + ipp_attribute_t *attr; /* Current attribute */ + + + /* TODO: Support multiple output devices, icons, etc... */ + device = (_ipp_device_t *)cupsArrayFirst(printer->devices); + + if ((attr = ippFindAttribute(device->attrs, "printer-state", IPP_TAG_ENUM)) != NULL) + printer->dev_state = (ipp_pstate_t)ippGetInteger(attr, 0); + else + printer->dev_state = IPP_PSTATE_STOPPED; + + if ((attr = ippFindAttribute(device->attrs, "printer-state-reasons", IPP_TAG_KEYWORD)) != NULL) + printer->dev_reasons = get_printer_state_reasons_bits(attr); + else + printer->dev_reasons = _IPP_PREASON_PAUSED; + + printer->state_time = time(NULL); +} + + +/* + * 'usage()' - Show program usage. + */ + +static void +usage(int status) /* O - Exit status */ +{ + if (!status) + { + puts(CUPS_SVERSION " - Copyright 2010-2014 by Apple Inc. All rights reserved."); + puts(""); + } + + puts("Usage: ippinfra [options] \"name\""); + puts(""); + puts("Options:"); + printf("-d spool-directory Spool directory " + "(default=/tmp/ippserver.%d)\n", (int)getpid()); + puts("-h Show program help"); + puts("-k Keep job spool files"); + puts("-n hostname Hostname for printer"); + puts("-p port Port number (default=auto)"); + puts("-u user:pass Set proxy username and password"); + puts("-v[vvv] Be (very) verbose"); + + exit(status); +} + + +/* + * 'valid_doc_attributes()' - Determine whether the document attributes are + * valid. + * + * When one or more document attributes are invalid, this function adds a + * suitable response and attributes to the unsupported group. + */ + +static int /* O - 1 if valid, 0 if not */ +valid_doc_attributes( + _ipp_client_t *client) /* I - Client */ +{ + int valid = 1; /* Valid attributes? */ + ipp_op_t op = ippGetOperation(client->request); + /* IPP operation */ + const char *op_name = ippOpString(op); + /* IPP operation name */ + ipp_attribute_t *attr, /* Current attribute */ + *supported; /* xxx-supported attribute */ + const char *compression = NULL, + /* compression value */ + *format = NULL; /* document-format value */ + + + /* + * Check operation attributes... + */ + + if ((attr = ippFindAttribute(client->request, "compression", IPP_TAG_ZERO)) != NULL) + { + /* + * If compression is specified, only accept a supported value in a Print-Job + * or Send-Document request... + */ + + compression = ippGetString(attr, 0, NULL); + supported = ippFindAttribute(client->printer->attrs, + "compression-supported", IPP_TAG_KEYWORD); + + if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD || + ippGetGroupTag(attr) != IPP_TAG_OPERATION || + (op != IPP_OP_PRINT_JOB && op != IPP_OP_SEND_DOCUMENT && + op != IPP_OP_VALIDATE_JOB) || + !ippContainsString(supported, compression)) + { + respond_unsupported(client, attr); + valid = 0; + } + else + { + fprintf(stderr, "%s %s compression=\"%s\"\n", client->hostname, op_name, compression); + + ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "compression-supplied", NULL, compression); + + if (strcmp(compression, "none")) + { + if (Verbosity) + fprintf(stderr, "Receiving job file with \"%s\" compression.\n", compression); + httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, compression); + } + } + } + + /* + * Is it a format we support? + */ + + if ((attr = ippFindAttribute(client->request, "document-format", IPP_TAG_ZERO)) != NULL) + { + if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_MIMETYPE || + ippGetGroupTag(attr) != IPP_TAG_OPERATION) + { + respond_unsupported(client, attr); + valid = 0; + } + else + { + format = ippGetString(attr, 0, NULL); + + fprintf(stderr, "%s %s document-format=\"%s\"\n", + client->hostname, op_name, format); + + ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-supplied", NULL, format); + } + } + else + { + format = ippGetString(ippFindAttribute(client->printer->attrs, "document-format-default", IPP_TAG_MIMETYPE), 0, NULL); + if (!format) + format = "application/octet-stream"; /* Should never happen */ + + attr = ippAddString(client->request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, format); + } + + if (!strcmp(format, "application/octet-stream") && (ippGetOperation(client->request) == IPP_OP_PRINT_JOB || ippGetOperation(client->request) == IPP_OP_SEND_DOCUMENT)) + { + /* + * Auto-type the file using the first 8 bytes of the file... + */ + + unsigned char header[8]; /* First 8 bytes of file */ + + memset(header, 0, sizeof(header)); + httpPeek(client->http, (char *)header, sizeof(header)); + + if (!memcmp(header, "%PDF", 4)) + format = "application/pdf"; + else if (!memcmp(header, "%!", 2)) + format = "application/postscript"; + else if (!memcmp(header, "\377\330\377", 3) && header[3] >= 0xe0 && header[3] <= 0xef) + format = "image/jpeg"; + else if (!memcmp(header, "\211PNG", 4)) + format = "image/png"; + else if (!memcmp(header, "RAS2", 4)) + format = "image/pwg-raster"; + else if (!memcmp(header, "UNIRAST", 8)) + format = "image/urf"; + else + format = NULL; + + if (format) + { + fprintf(stderr, "%s %s Auto-typed document-format=\"%s\"\n", + client->hostname, op_name, format); + + ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-detected", NULL, format); + } + } + + if (op != IPP_OP_CREATE_JOB && (supported = ippFindAttribute(client->printer->attrs, "document-format-supported", IPP_TAG_MIMETYPE)) != NULL && !ippContainsString(supported, format)) + { + respond_unsupported(client, attr); + valid = 0; + } + + /* + * document-name + */ + + if ((attr = ippFindAttribute(client->request, "document-name", IPP_TAG_NAME)) != NULL) + ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_NAME, "document-name-supplied", NULL, ippGetString(attr, 0, NULL)); + + return (valid); +} + + +/* + * 'valid_job_attributes()' - Determine whether the job attributes are valid. + * + * When one or more job attributes are invalid, this function adds a suitable + * response and attributes to the unsupported group. + */ + +static int /* O - 1 if valid, 0 if not */ +valid_job_attributes( + _ipp_client_t *client) /* I - Client */ +{ + int i, /* Looping var */ + valid = 1; /* Valid attributes? */ + ipp_attribute_t *attr, /* Current attribute */ + *supported; /* xxx-supported attribute */ + + + /* + * Check operation attributes... + */ + + valid = valid_doc_attributes(client); + + /* + * Check the various job template attributes... + */ + + if ((attr = ippFindAttribute(client->request, "copies", IPP_TAG_ZERO)) != NULL) + { + if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_INTEGER || + ippGetInteger(attr, 0) < 1 || ippGetInteger(attr, 0) > 999) + { + respond_unsupported(client, attr); + valid = 0; + } + } + + if ((attr = ippFindAttribute(client->request, "ipp-attribute-fidelity", IPP_TAG_ZERO)) != NULL) + { + if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_BOOLEAN) + { + respond_unsupported(client, attr); + valid = 0; + } + } + + if ((attr = ippFindAttribute(client->request, "job-hold-until", IPP_TAG_ZERO)) != NULL) + { + if (ippGetCount(attr) != 1 || + (ippGetValueTag(attr) != IPP_TAG_NAME && + ippGetValueTag(attr) != IPP_TAG_NAMELANG && + ippGetValueTag(attr) != IPP_TAG_KEYWORD) || + strcmp(ippGetString(attr, 0, NULL), "no-hold")) + { + respond_unsupported(client, attr); + valid = 0; + } + } + + if ((attr = ippFindAttribute(client->request, "job-impressions", IPP_TAG_ZERO)) != NULL) + { + if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_INTEGER || ippGetInteger(attr, 0) < 0) + { + respond_unsupported(client, attr); + valid = 0; + } + } + + if ((attr = ippFindAttribute(client->request, "job-name", IPP_TAG_ZERO)) != NULL) + { + if (ippGetCount(attr) != 1 || + (ippGetValueTag(attr) != IPP_TAG_NAME && + ippGetValueTag(attr) != IPP_TAG_NAMELANG)) + { + respond_unsupported(client, attr); + valid = 0; + } + + ippSetGroupTag(client->request, &attr, IPP_TAG_JOB); + } + else + ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled"); + + if ((attr = ippFindAttribute(client->request, "job-priority", IPP_TAG_ZERO)) != NULL) + { + if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_INTEGER || + ippGetInteger(attr, 0) < 1 || ippGetInteger(attr, 0) > 100) + { + respond_unsupported(client, attr); + valid = 0; + } + } + + if ((attr = ippFindAttribute(client->request, "job-sheets", IPP_TAG_ZERO)) != NULL) + { + if (ippGetCount(attr) != 1 || + (ippGetValueTag(attr) != IPP_TAG_NAME && + ippGetValueTag(attr) != IPP_TAG_NAMELANG && + ippGetValueTag(attr) != IPP_TAG_KEYWORD) || + strcmp(ippGetString(attr, 0, NULL), "none")) + { + respond_unsupported(client, attr); + valid = 0; + } + } + + if ((attr = ippFindAttribute(client->request, "media", IPP_TAG_ZERO)) != NULL) + { + if (ippGetCount(attr) != 1 || + (ippGetValueTag(attr) != IPP_TAG_NAME && + ippGetValueTag(attr) != IPP_TAG_NAMELANG && + ippGetValueTag(attr) != IPP_TAG_KEYWORD)) + { + respond_unsupported(client, attr); + valid = 0; + } + else + { +#if 0 /* TODO: Validate media */ + for (i = 0; + i < (int)(sizeof(media_supported) / sizeof(media_supported[0])); + i ++) + if (!strcmp(ippGetString(attr, 0, NULL), media_supported[i])) + break; + + if (i >= (int)(sizeof(media_supported) / sizeof(media_supported[0]))) + { + respond_unsupported(client, attr); + valid = 0; + } +#endif /* 0 */ + } + } + + if ((attr = ippFindAttribute(client->request, "media-col", IPP_TAG_ZERO)) != NULL) + { + if (ippGetCount(attr) != 1 || + ippGetValueTag(attr) != IPP_TAG_BEGIN_COLLECTION) + { + respond_unsupported(client, attr); + valid = 0; + } + /* TODO: check for valid media-col */ + } + + if ((attr = ippFindAttribute(client->request, "multiple-document-handling", IPP_TAG_ZERO)) != NULL) + { + if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD || + (strcmp(ippGetString(attr, 0, NULL), + "separate-documents-uncollated-copies") && + strcmp(ippGetString(attr, 0, NULL), + "separate-documents-collated-copies"))) + { + respond_unsupported(client, attr); + valid = 0; + } + } + + if ((attr = ippFindAttribute(client->request, "orientation-requested", IPP_TAG_ZERO)) != NULL) + { + if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_ENUM || + ippGetInteger(attr, 0) < IPP_ORIENT_PORTRAIT || + ippGetInteger(attr, 0) > IPP_ORIENT_REVERSE_PORTRAIT) + { + respond_unsupported(client, attr); + valid = 0; + } + } + + if ((attr = ippFindAttribute(client->request, "page-ranges", IPP_TAG_ZERO)) != NULL) + { + if (ippGetValueTag(attr) != IPP_TAG_RANGE) + { + respond_unsupported(client, attr); + valid = 0; + } + } + + if ((attr = ippFindAttribute(client->request, "print-quality", IPP_TAG_ZERO)) != NULL) + { + if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_ENUM || + ippGetInteger(attr, 0) < IPP_QUALITY_DRAFT || + ippGetInteger(attr, 0) > IPP_QUALITY_HIGH) + { + respond_unsupported(client, attr); + valid = 0; + } + } + + if ((attr = ippFindAttribute(client->request, "printer-resolution", IPP_TAG_ZERO)) != NULL) + { + supported = ippFindAttribute(client->printer->dev_attrs, "printer-resolution-supported", IPP_TAG_RESOLUTION); + + if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_RESOLUTION || + !supported) + { + respond_unsupported(client, attr); + valid = 0; + } + else + { + int count, /* Number of supported values */ + xdpi, /* Horizontal resolution for job template attribute */ + ydpi, /* Vertical resolution for job template attribute */ + sydpi; /* Vertical resolution for supported value */ + ipp_res_t units, /* Units for job template attribute */ + sunits; /* Units for supported value */ + + xdpi = ippGetResolution(attr, 0, &ydpi, &units); + count = ippGetCount(supported); + + for (i = 0; i < count; i ++) + { + if (xdpi == ippGetResolution(supported, i, &sydpi, &sunits) && ydpi == sydpi && units == sunits) + break; + } + + if (i >= count) + { + respond_unsupported(client, attr); + valid = 0; + } + } + } + + if ((attr = ippFindAttribute(client->request, "sides", IPP_TAG_ZERO)) != NULL) + { + const char *sides = ippGetString(attr, 0, NULL); + /* "sides" value... */ + + if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD) + { + respond_unsupported(client, attr); + valid = 0; + } + else if ((supported = ippFindAttribute(client->printer->dev_attrs, "sides-supported", IPP_TAG_KEYWORD)) != NULL) + { + if (!ippContainsString(supported, sides)) + { + respond_unsupported(client, attr); + valid = 0; + } + } + else if (strcmp(sides, "one-sided")) + { + respond_unsupported(client, attr); + valid = 0; + } + } + + return (valid); +} + + +/* + * End of "$Id: ippinfra.c 12237 2014-11-03 13:07:32Z msweet $". + */ diff --git a/test/ippinfra.man b/test/ippinfra.man new file mode 100644 index 0000000000..46ac84e404 --- /dev/null +++ b/test/ippinfra.man @@ -0,0 +1,103 @@ +.\" +.\" "$Id$" +.\" +.\" ippinfra man page for CUPS. +.\" +.\" Copyright 2014 by Apple Inc. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Apple Inc. and are protected by Federal copyright +.\" law. Distribution and use rights are outlined in the file "LICENSE.txt" +.\" which should have been included with this file. If this file is +.\" file is missing or damaged, see the license at "http://www.cups.org/". +.\" +.TH ippinfra 1 "CUPS" "16 September 2014" "Apple Inc." +.SH NAME +ippinfra \- a simple ipp infrastructure server +.SH SYNOPSIS +.B ippinfra +[ +.B \-d +.I spool-directory +] [ +.B \-h +] [ +.B \-k +] [ +.B \-n +.I hostname +] [ +.B \-p +.I port +] [ +.B \-u +.I username:password +] [ +.B \-v[vvv] +] +.I service-name +.SH DESCRIPTION +.B ippinfra +is a simple Internet Printing Protocol (IPP) infrastructure server conforming to the IPP Shared Infrastructure Extensions (INFRA) specification. It can be used as a very basic infrastructure server between standard IPP clients and IPP proxies conforming to the INFRA specification. +.SH OPTIONS +The following options are recognized by +.B ippinfra: +.TP 5 +\fB\-d \fIspool-directory\fR +Specifies the directory that will hold the print files. +The default is a directory under the user's current temporary directory. +.TP 5 +.B \-h +Shows program help. +.TP 5 +.B \-k +Keeps the print documents in the spool directory rather than deleting them. +.TP 5 +\fB\-n \fIhostname\fR +Specifies the hostname that is reported by the server. +The default is the name returned by the +.BR hostname (1) +command. +.TP 5 +\fB\-p \fIport\fR +Specifies the port number to listen on. +The default is a user-specific number from 8000 to 8999. +.TP 5 +\fB\-u \fIusername:password\fR +Specifies the username and password for the IPP proxy. +The default is "test:test123". +.TP 5 +.B \-v[vvv] +Be (very) verbose when logging activity to the standard output. +.SH EXIT STATUS +The +.B ippinfra +program returns 1 if it is unable to process the command-line arguments. +Otherwise +.B ippinfra +will run continuously until terminated. +.SH CONFORMING TO +The +.B ippinfra +program is unique to CUPS and conforms to the IPP Shared Infrastructure Extensions (INFRA) specification as an Infrastructure Printer. +.SH EXAMPLES +Run +.B ippinfra +with a service name of My Cool Printer: +.nf + + ippinfra "My Cool Printer" +.fi +.LP +Specify a proxy username of "foo" and password of "bar": +.nf + + ippinfra \-u foo:bar "My Cool Printer" +.fi +.SH SEE ALSO +PWG Internet Printing Protocol Workgroup (http://www.pwg.org/ipp) +.SH COPYRIGHT +Copyright \[co] 2007-2014 by Apple Inc. +.\" +.\" End of "$Id$". +.\" diff --git a/test/ippproxy.c b/test/ippproxy.c new file mode 100644 index 0000000000..e8dd2c19e8 --- /dev/null +++ b/test/ippproxy.c @@ -0,0 +1,29 @@ +/* + * "$Id: ippproxy.c 12191 2014-10-01 19:00:21Z msweet $" + * + * CUPS Cloud Proxy for HP PCL and IPP Everywhere printers. + * + * Copyright 2014 by Apple Inc. + */ + +#include + + +/* + * 'main()' - Main entry for cupsproxy. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + (void)argc; + (void)argv; + + return (0); +} + + +/* + * End of "$Id: ippproxy.c 12191 2014-10-01 19:00:21Z msweet $". + */ diff --git a/test/ippproxy.man b/test/ippproxy.man new file mode 100644 index 0000000000..1d46c9afe7 --- /dev/null +++ b/test/ippproxy.man @@ -0,0 +1,59 @@ +.\" +.\" "$Id$" +.\" +.\" ippproxy man page for CUPS. +.\" +.\" Copyright 2014 by Apple Inc. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Apple Inc. and are protected by Federal copyright +.\" law. Distribution and use rights are outlined in the file "LICENSE.txt" +.\" which should have been included with this file. If this file is +.\" file is missing or damaged, see the license at "http://www.cups.org/". +.\" +.TH ippproxy 1 "CUPS" "16 September 2014" "Apple Inc." +.SH NAME +ippproxy \- a simple ipp proxy client +.SH SYNOPSIS +.B ippproxy +[ +.B \-v[vvv] +] +.I infrastructure-printer-uri +.I local-printer-uri +.SH DESCRIPTION +.B ippproxy +is a simple IPP proxy client conforming to the IPP Shared Infrastructure Extensions (INFRA) specification. It can be used to proxy access to a local IPP printer through an Infrastructure Printer such as +.BR ippinfra (1). +.SH OPTIONS +The following options are recognized by +.B ippproxy: +.TP 5 +.B \-v[vvv] +Be (very) verbose when logging activity to the standard output. +.SH EXIT STATUS +The +.B ippproxy +program returns 1 if it is unable to process the command-line arguments or connect to either the infrastructure or local printers. +Otherwise +.B ippproxy +will run continuously until terminated. +.SH CONFORMING TO +The +.B ippproxy +program is unique to CUPS and conforms to the IPP Shared Infrastructure Extensions (INFRA) specification. +.SH EXAMPLE +Run +.B ippproxy +with an infrastructure URI of "ipps://host.example.com/ipp/print" and a local URI of "ipp://10.0.1.2/ipp/print": +.nf + + ippproxy ipps://host.example.com/ipp/print ipp://10.0.1.2/ipp/print +.fi +.SH SEE ALSO +PWG Internet Printing Protocol Workgroup (http://www.pwg.org/ipp) +.SH COPYRIGHT +Copyright \[co] 2007-2014 by Apple Inc. +.\" +.\" End of "$Id$". +.\" diff --git a/test/ippserver.c b/test/ippserver.c index 22c2dd51c0..03c8cfb2a4 100644 --- a/test/ippserver.c +++ b/test/ippserver.c @@ -1,5 +1,5 @@ /* - * "$Id: ippserver.c 12486 2015-02-04 13:13:21Z msweet $" + * "$Id: ippserver.c 12598 2015-05-05 18:57:57Z msweet $" * * Sample IPP Everywhere server for CUPS. * @@ -1371,16 +1371,15 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default) static const int pwg_raster_document_resolution_supported[] = { 150, - 300, - 600 + 300 }; static const char * const pwg_raster_document_type_supported[] = { - "black-1", - "cmyk-8", - "sgray-8", - "srgb-8", - "srgb-16" + "black_1", + "cmyk_8", + "sgray_8", + "srgb_8", + "srgb_16" }; static const char * const reference_uri_schemes_supported[] = { /* reference-uri-schemes-supported */ @@ -1402,7 +1401,7 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default) "CP1", "IS1-5-7", "MT1-2-3-4-5-6-8-9-10-11-12-13", - "RS600", + "RS300", "SRGB24", "V1.4", "W8", @@ -1992,6 +1991,7 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default) { static const char * const names[] = { + "job-account-id", "job-accounting-user-id", "job-password" }; @@ -4812,7 +4812,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */ if (client->printer->state_reasons & reason) html_printf(client, "\n
    %s", reasons[i]); html_printf(client, "

\n"); - + if (cupsArrayCount(client->printer->jobs) > 0) { _cupsRWLockRead(&(client->printer->rwlock)); @@ -5603,6 +5603,11 @@ register_printer( # ifdef HAVE_SSL TXTRecordSetValue(&ipp_txt, "TLS", 3, "1.2"); # endif /* HAVE_SSL */ + if (strstr(formats, "image/urf")) + TXTRecordSetValue(&ipp_txt, "URF", 66, "CP1,IS1-5-7,MT1-2-3-4-5-6-8-9-10-11-12-13,RS300,SRGB24,V1.4,W8,DM1"); + + TXTRecordSetValue(&ipp_txt, "txtvers", 1, "1"); + TXTRecordSetValue(&ipp_txt, "qtotal", 1, "1"); /* * Register the _printer._tcp (LPD) service type with a port number of 0 to @@ -6489,5 +6494,5 @@ valid_job_attributes( /* - * End of "$Id: ippserver.c 12486 2015-02-04 13:13:21Z msweet $". + * End of "$Id: ippserver.c 12598 2015-05-05 18:57:57Z msweet $". */ diff --git a/test/ipptool.c b/test/ipptool.c index b1f784359b..bbb865abb1 100644 --- a/test/ipptool.c +++ b/test/ipptool.c @@ -1,5 +1,5 @@ /* - * "$Id: ipptool.c 12465 2015-02-01 02:47:23Z msweet $" + * "$Id: ipptool.c 12644 2015-05-19 21:22:35Z msweet $" * * ipptool command for CUPS. * @@ -70,13 +70,15 @@ typedef enum _cups_with_e /**** WITH flags ****/ typedef struct _cups_expect_s /**** Expected attribute info ****/ { int optional, /* Optional attribute? */ - not_expect; /* Don't expect attribute? */ + not_expect, /* Don't expect attribute? */ + expect_all; /* Expect all attributes to match/not match */ char *name, /* Attribute name */ *of_type, /* Type name */ *same_count_as, /* Parallel attribute name */ *if_defined, /* Only required if variable defined */ *if_not_defined, /* Only required if variable is not defined */ *with_value, /* Attribute must include this value */ + *with_value_from, /* Attribute must have one of the values in this attribute */ *define_match, /* Variable to define on match */ *define_no_match, /* Variable to define on no-match */ *define_value; /* Variable to define with value */ @@ -189,6 +191,7 @@ static int validate_attr(FILE *outfile, cups_array_t *errors, ipp_attribute_t *a static int with_value(FILE *outfile, cups_array_t *errors, char *value, int flags, ipp_attribute_t *attr, char *matchbuf, size_t matchlen); +static int with_value_from(cups_array_t *errors, ipp_attribute_t *fromattr, ipp_attribute_t *attr, char *matchbuf, size_t matchlen); /* @@ -1258,7 +1261,8 @@ do_tests(FILE *outfile, /* I - Output file */ _cups_strcasecmp(token, "WITH-HOSTNAME") && _cups_strcasecmp(token, "WITH-RESOURCE") && _cups_strcasecmp(token, "WITH-SCHEME") && - _cups_strcasecmp(token, "WITH-VALUE")) + _cups_strcasecmp(token, "WITH-VALUE") && + _cups_strcasecmp(token, "WITH-VALUE-FROM")) last_expect = NULL; if (_cups_strcasecmp(token, "DEFINE-MATCH") && @@ -1993,12 +1997,14 @@ do_tests(FILE *outfile, /* I - Output file */ last_status->repeat_match = 0; last_status->repeat_no_match = 0; } - else if (!_cups_strcasecmp(token, "EXPECT")) + else if (!_cups_strcasecmp(token, "EXPECT") || !_cups_strcasecmp(token, "EXPECT-ALL")) { /* * Expected attributes... */ + int expect_all = !_cups_strcasecmp(token, "EXPECT-ALL"); + if (num_expects >= (int)(sizeof(expects) / sizeof(expects[0]))) { print_fatal_error(outfile, "Too many EXPECT's on line %d.", linenum); @@ -2018,6 +2024,7 @@ do_tests(FILE *outfile, /* I - Output file */ memset(last_expect, 0, sizeof(_cups_expect_t)); last_expect->repeat_limit = 1000; + last_expect->expect_all = expect_all; if (token[0] == '!') { @@ -2369,6 +2376,34 @@ do_tests(FILE *outfile, /* I - Output file */ goto test_exit; } } + else if (!_cups_strcasecmp(token, "WITH-VALUE-FROM")) + { + if (!get_token(fp, temp, sizeof(temp), &linenum)) + { + print_fatal_error(outfile, "Missing %s value on line %d.", token, linenum); + pass = 0; + goto test_exit; + } + + if (last_expect) + { + /* + * Expand any variables in the value and then save it. + */ + + expand_variables(vars, token, temp, sizeof(token)); + + last_expect->with_value_from = strdup(token); + last_expect->with_flags = _CUPS_WITH_LITERAL; + } + else + { + print_fatal_error(outfile, "%s without a preceding EXPECT on line %d.", token, + linenum); + pass = 0; + goto test_exit; + } + } else if (!_cups_strcasecmp(token, "DISPLAY")) { /* @@ -2938,192 +2973,210 @@ do_tests(FILE *outfile, /* I - Output file */ get_variable(vars, expect->if_not_defined)) continue; - found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO); + found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO); - if ((found && expect->not_expect) || - (!found && !(expect->not_expect || expect->optional)) || - (found && !expect_matches(expect, found->value_tag)) || - (found && expect->in_group && - found->group_tag != expect->in_group)) - { - if (expect->define_no_match) - set_variable(outfile, vars, expect->define_no_match, "1"); - else if (!expect->define_match && !expect->define_value) + do + { + if ((found && expect->not_expect) || + (!found && !(expect->not_expect || expect->optional)) || + (found && !expect_matches(expect, found->value_tag)) || + (found && expect->in_group && + found->group_tag != expect->in_group)) { - if (found && expect->not_expect) - add_stringf(errors, "NOT EXPECTED: %s", expect->name); - else if (!found && !(expect->not_expect || expect->optional)) - add_stringf(errors, "EXPECTED: %s", expect->name); - else if (found) + if (expect->define_no_match) + set_variable(outfile, vars, expect->define_no_match, "1"); + else if (!expect->define_match && !expect->define_value) { - if (!expect_matches(expect, found->value_tag)) - add_stringf(errors, "EXPECTED: %s OF-TYPE %s (got %s)", - expect->name, expect->of_type, - ippTagString(found->value_tag)); - - if (expect->in_group && found->group_tag != expect->in_group) - add_stringf(errors, "EXPECTED: %s IN-GROUP %s (got %s).", - expect->name, ippTagString(expect->in_group), - ippTagString(found->group_tag)); - } - } + if (found && expect->not_expect) + add_stringf(errors, "NOT EXPECTED: %s", expect->name); + else if (!found && !(expect->not_expect || expect->optional)) + add_stringf(errors, "EXPECTED: %s", expect->name); + else if (found) + { + if (!expect_matches(expect, found->value_tag)) + add_stringf(errors, "EXPECTED: %s OF-TYPE %s (got %s)", + expect->name, expect->of_type, + ippTagString(found->value_tag)); + + if (expect->in_group && found->group_tag != expect->in_group) + add_stringf(errors, "EXPECTED: %s IN-GROUP %s (got %s).", + expect->name, ippTagString(expect->in_group), + ippTagString(found->group_tag)); + } + } - if (expect->repeat_no_match && - repeat_count < expect->repeat_limit) - repeat_test = 1; + if (expect->repeat_no_match && + repeat_count < expect->repeat_limit) + repeat_test = 1; - continue; - } + break; + } - if (found) - ippAttributeString(found, buffer, sizeof(buffer)); + if (found) + ippAttributeString(found, buffer, sizeof(buffer)); - if (found && - !with_value(outfile, NULL, expect->with_value, expect->with_flags, found, - buffer, sizeof(buffer))) - { - if (expect->define_no_match) - set_variable(outfile, vars, expect->define_no_match, "1"); - else if (!expect->define_match && !expect->define_value && - !expect->repeat_match && !expect->repeat_no_match) + if (found && expect->with_value_from && !with_value_from(NULL, ippFindAttribute(response, expect->with_value_from, IPP_TAG_ZERO), found, buffer, sizeof(buffer))) { - if (expect->with_flags & _CUPS_WITH_REGEX) - add_stringf(errors, "EXPECTED: %s %s /%s/", - expect->name, - (expect->with_flags & _CUPS_WITH_ALL) ? - "WITH-ALL-VALUES" : "WITH-VALUE", - expect->with_value); - else - add_stringf(errors, "EXPECTED: %s %s \"%s\"", - expect->name, - (expect->with_flags & _CUPS_WITH_ALL) ? - "WITH-ALL-VALUES" : "WITH-VALUE", - expect->with_value); - - with_value(outfile, errors, expect->with_value, expect->with_flags, found, - buffer, sizeof(buffer)); - } + if (expect->define_no_match) + set_variable(outfile, vars, expect->define_no_match, "1"); + else if (!expect->define_match && !expect->define_value && !expect->repeat_match && !expect->repeat_no_match) + { + add_stringf(errors, "EXPECTED: %s WITH-VALUES-FROM %s", expect->name, expect->with_value_from); - if (expect->repeat_no_match && - repeat_count < expect->repeat_limit) - repeat_test = 1; + with_value_from(errors, ippFindAttribute(response, expect->with_value_from, IPP_TAG_ZERO), found, buffer, sizeof(buffer)); + } - continue; - } + if (expect->repeat_no_match && repeat_count < expect->repeat_limit) + repeat_test = 1; - if (found && expect->count > 0 && - found->num_values != expect->count) - { - if (expect->define_no_match) - set_variable(outfile, vars, expect->define_no_match, "1"); - else if (!expect->define_match && !expect->define_value) - { - add_stringf(errors, "EXPECTED: %s COUNT %d (got %d)", expect->name, - expect->count, found->num_values); + break; } + else if (found && !with_value(outfile, NULL, expect->with_value, expect->with_flags, found, buffer, sizeof(buffer))) + { + if (expect->define_no_match) + set_variable(outfile, vars, expect->define_no_match, "1"); + else if (!expect->define_match && !expect->define_value && + !expect->repeat_match && !expect->repeat_no_match) + { + if (expect->with_flags & _CUPS_WITH_REGEX) + add_stringf(errors, "EXPECTED: %s %s /%s/", + expect->name, + (expect->with_flags & _CUPS_WITH_ALL) ? + "WITH-ALL-VALUES" : "WITH-VALUE", + expect->with_value); + else + add_stringf(errors, "EXPECTED: %s %s \"%s\"", + expect->name, + (expect->with_flags & _CUPS_WITH_ALL) ? + "WITH-ALL-VALUES" : "WITH-VALUE", + expect->with_value); + + with_value(outfile, errors, expect->with_value, expect->with_flags, found, + buffer, sizeof(buffer)); + } - if (expect->repeat_no_match && - repeat_count < expect->repeat_limit) - repeat_test = 1; - - continue; - } + if (expect->repeat_no_match && + repeat_count < expect->repeat_limit) + repeat_test = 1; - if (found && expect->same_count_as) - { - attrptr = ippFindAttribute(response, expect->same_count_as, - IPP_TAG_ZERO); + break; + } - if (!attrptr || attrptr->num_values != found->num_values) + if (found && expect->count > 0 && + found->num_values != expect->count) { if (expect->define_no_match) set_variable(outfile, vars, expect->define_no_match, "1"); else if (!expect->define_match && !expect->define_value) { - if (!attrptr) - add_stringf(errors, - "EXPECTED: %s (%d values) SAME-COUNT-AS %s " - "(not returned)", expect->name, - found->num_values, expect->same_count_as); - else if (attrptr->num_values != found->num_values) - add_stringf(errors, - "EXPECTED: %s (%d values) SAME-COUNT-AS %s " - "(%d values)", expect->name, found->num_values, - expect->same_count_as, attrptr->num_values); + add_stringf(errors, "EXPECTED: %s COUNT %d (got %d)", expect->name, + expect->count, found->num_values); } if (expect->repeat_no_match && - repeat_count < expect->repeat_limit) + repeat_count < expect->repeat_limit) repeat_test = 1; - continue; + break; } - } - if (found && expect->define_match) - set_variable(outfile, vars, expect->define_match, "1"); - - if (found && expect->define_value) - { - if (!expect->with_value) + if (found && expect->same_count_as) { - int last = ippGetCount(found) - 1; - /* Last element in attribute */ + attrptr = ippFindAttribute(response, expect->same_count_as, + IPP_TAG_ZERO); - switch (ippGetValueTag(found)) + if (!attrptr || attrptr->num_values != found->num_values) { - case IPP_TAG_ENUM : - case IPP_TAG_INTEGER : - snprintf(buffer, sizeof(buffer), "%d", ippGetInteger(found, last)); - break; - - case IPP_TAG_BOOLEAN : - if (ippGetBoolean(found, last)) - strlcpy(buffer, "true", sizeof(buffer)); - else - strlcpy(buffer, "false", sizeof(buffer)); - break; + if (expect->define_no_match) + set_variable(outfile, vars, expect->define_no_match, "1"); + else if (!expect->define_match && !expect->define_value) + { + if (!attrptr) + add_stringf(errors, + "EXPECTED: %s (%d values) SAME-COUNT-AS %s " + "(not returned)", expect->name, + found->num_values, expect->same_count_as); + else if (attrptr->num_values != found->num_values) + add_stringf(errors, + "EXPECTED: %s (%d values) SAME-COUNT-AS %s " + "(%d values)", expect->name, found->num_values, + expect->same_count_as, attrptr->num_values); + } - case IPP_TAG_RESOLUTION : - { - int xres, /* Horizontal resolution */ - yres; /* Vertical resolution */ - ipp_res_t units; /* Resolution units */ + if (expect->repeat_no_match && + repeat_count < expect->repeat_limit) + repeat_test = 1; - xres = ippGetResolution(found, last, &yres, &units); + break; + } + } - if (xres == yres) - snprintf(buffer, sizeof(buffer), "%d%s", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); - else - snprintf(buffer, sizeof(buffer), "%dx%d%s", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); - } - break; + if (found && expect->define_match) + set_variable(outfile, vars, expect->define_match, "1"); - case IPP_TAG_CHARSET : - case IPP_TAG_KEYWORD : - case IPP_TAG_LANGUAGE : - case IPP_TAG_MIMETYPE : - case IPP_TAG_NAME : - case IPP_TAG_NAMELANG : - case IPP_TAG_TEXT : - case IPP_TAG_TEXTLANG : - case IPP_TAG_URI : - case IPP_TAG_URISCHEME : - strlcpy(buffer, ippGetString(found, last, NULL), sizeof(buffer)); - break; + if (found && expect->define_value) + { + if (!expect->with_value) + { + int last = ippGetCount(found) - 1; + /* Last element in attribute */ - default : - ippAttributeString(found, buffer, sizeof(buffer)); - break; + switch (ippGetValueTag(found)) + { + case IPP_TAG_ENUM : + case IPP_TAG_INTEGER : + snprintf(buffer, sizeof(buffer), "%d", ippGetInteger(found, last)); + break; + + case IPP_TAG_BOOLEAN : + if (ippGetBoolean(found, last)) + strlcpy(buffer, "true", sizeof(buffer)); + else + strlcpy(buffer, "false", sizeof(buffer)); + break; + + case IPP_TAG_RESOLUTION : + { + int xres, /* Horizontal resolution */ + yres; /* Vertical resolution */ + ipp_res_t units; /* Resolution units */ + + xres = ippGetResolution(found, last, &yres, &units); + + if (xres == yres) + snprintf(buffer, sizeof(buffer), "%d%s", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); + else + snprintf(buffer, sizeof(buffer), "%dx%d%s", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); + } + break; + + case IPP_TAG_CHARSET : + case IPP_TAG_KEYWORD : + case IPP_TAG_LANGUAGE : + case IPP_TAG_MIMETYPE : + case IPP_TAG_NAME : + case IPP_TAG_NAMELANG : + case IPP_TAG_TEXT : + case IPP_TAG_TEXTLANG : + case IPP_TAG_URI : + case IPP_TAG_URISCHEME : + strlcpy(buffer, ippGetString(found, last, NULL), sizeof(buffer)); + break; + + default : + ippAttributeString(found, buffer, sizeof(buffer)); + break; + } } - } - set_variable(outfile, vars, expect->define_value, buffer); - } + set_variable(outfile, vars, expect->define_value, buffer); + } - if (found && expect->repeat_match && - repeat_count < expect->repeat_limit) - repeat_test = 1; + if (found && expect->repeat_match && + repeat_count < expect->repeat_limit) + repeat_test = 1; + } + while (expect->expect_all && (found = ippFindNextAttribute(response, expect->name, IPP_TAG_ZERO)) != NULL); } } @@ -3463,7 +3516,7 @@ expand_variables(_cups_vars_t *vars, /* I - Variables */ value = getenv(temp); src += tempptr - temp + 5; } - else if (vars) + else { if (src[1] == '{') { @@ -3510,11 +3563,6 @@ expand_variables(_cups_vars_t *vars, /* I - Variables */ src += tempptr - temp + 1; } - else - { - value = "$"; - src ++; - } if (value) { @@ -5870,5 +5918,165 @@ with_value(FILE *outfile, /* I - Output file */ /* - * End of "$Id: ipptool.c 12465 2015-02-01 02:47:23Z msweet $". + * 'with_value_from()' - Test a WITH-VALUE-FROM predicate. + */ + +static int /* O - 1 on match, 0 on non-match */ +with_value_from( + cups_array_t *errors, /* I - Errors array */ + ipp_attribute_t *fromattr, /* I - "From" attribute */ + ipp_attribute_t *attr, /* I - Attribute to compare */ + char *matchbuf, /* I - Buffer to hold matching value */ + size_t matchlen) /* I - Length of match buffer */ +{ + int i, j, /* Looping vars */ + count = ippGetCount(attr), /* Number of attribute values */ + match = 1; /* Match? */ + + + *matchbuf = '\0'; + + /* + * Compare the from value(s) to the attribute value(s)... + */ + + switch (ippGetValueTag(attr)) + { + case IPP_TAG_INTEGER : + if (ippGetValueTag(fromattr) != IPP_TAG_INTEGER && ippGetValueTag(fromattr) != IPP_TAG_RANGE) + goto wrong_value_tag; + + for (i = 0; i < count; i ++) + { + int value = ippGetInteger(attr, i); + /* Current integer value */ + + if (ippContainsInteger(fromattr, value)) + { + if (!matchbuf[0]) + snprintf(matchbuf, matchlen, "%d", value); + } + else + { + add_stringf(errors, "GOT: %s=%d", ippGetName(attr), value); + match = 0; + } + } + break; + + case IPP_TAG_ENUM : + if (ippGetValueTag(fromattr) != IPP_TAG_ENUM) + goto wrong_value_tag; + + for (i = 0; i < count; i ++) + { + int value = ippGetInteger(attr, i); + /* Current integer value */ + + if (ippContainsInteger(fromattr, value)) + { + if (!matchbuf[0]) + snprintf(matchbuf, matchlen, "%d", value); + } + else + { + add_stringf(errors, "GOT: %s=%d", ippGetName(attr), value); + match = 0; + } + } + break; + + case IPP_TAG_RESOLUTION : + if (ippGetValueTag(fromattr) != IPP_TAG_RESOLUTION) + goto wrong_value_tag; + + for (i = 0; i < count; i ++) + { + int xres, yres; + ipp_res_t units; + int fromcount = ippGetCount(fromattr); + int fromxres, fromyres; + ipp_res_t fromunits; + + xres = ippGetResolution(attr, i, &yres, &units); + + for (j = 0; j < fromcount; j ++) + { + fromxres = ippGetResolution(fromattr, j, &fromyres, &fromunits); + if (fromxres == xres && fromyres == yres && fromunits == units) + break; + } + + if (j < fromcount) + { + if (!matchbuf[0]) + { + if (xres == yres) + snprintf(matchbuf, matchlen, "%d%s", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); + else + snprintf(matchbuf, matchlen, "%dx%d%s", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); + } + } + else + { + if (xres == yres) + add_stringf(errors, "GOT: %s=%d%s", ippGetName(attr), xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); + else + add_stringf(errors, "GOT: %s=%dx%d%s", ippGetName(attr), xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); + + match = 0; + } + } + break; + + case IPP_TAG_NOVALUE : + case IPP_TAG_UNKNOWN : + return (1); + + case IPP_TAG_CHARSET : + case IPP_TAG_KEYWORD : + case IPP_TAG_LANGUAGE : + case IPP_TAG_MIMETYPE : + case IPP_TAG_NAME : + case IPP_TAG_NAMELANG : + case IPP_TAG_TEXT : + case IPP_TAG_TEXTLANG : + case IPP_TAG_URI : + case IPP_TAG_URISCHEME : + for (i = 0; i < count; i ++) + { + const char *value = ippGetString(attr, i, NULL); + /* Current string value */ + + if (ippContainsString(fromattr, value)) + { + if (!matchbuf[0]) + strlcpy(matchbuf, value, matchlen); + } + else + { + add_stringf(errors, "GOT: %s='%s'", ippGetName(attr), value); + match = 0; + } + } + break; + + default : + match = 0; + break; + } + + return (match); + + /* value tag mismatch between fromattr and attr */ + wrong_value_tag : + + add_stringf(errors, "GOT: %s OF-TYPE %s", ippGetName(attr), ippTagString(ippGetValueTag(attr))); + + return (0); +} + + +/* + * End of "$Id: ipptool.c 12644 2015-05-19 21:22:35Z msweet $". */ diff --git a/test/run-stp-tests.sh b/test/run-stp-tests.sh index 0f02ba2496..88560dac1b 100755 --- a/test/run-stp-tests.sh +++ b/test/run-stp-tests.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# "$Id: run-stp-tests.sh 12658 2015-05-22 17:53:45Z msweet $" +# "$Id: run-stp-tests.sh 12696 2015-06-08 15:05:11Z msweet $" # # Perform the complete set of IPP compliance tests specified in the # CUPS Software Test Plan. @@ -722,9 +722,9 @@ date=`date "+%Y-%m-%d"` if test -d $root/.svn; then rev=`svn info . | grep Revision: | awk '{print $2}'` - strfile=$BASE/cups-str-2.0-r$rev-$user.html + strfile=$BASE/cups-str-2.1-r$rev-$user.html else - strfile=$BASE/cups-str-2.0-$date-$user.html + strfile=$BASE/cups-str-2.1-$date-$user.html fi rm -f $strfile @@ -737,7 +737,7 @@ cat str-header.html >$strfile echo "" echo "Running IPP compliance tests..." -echo "

1 - IPP Compliance Tests

" >>$strfile +echo "

1 - IPP Compliance Tests

" >>$strfile echo "

This section provides the results to the IPP compliance tests" >>$strfile echo "outlined in the CUPS Software Test Plan. These tests were run on" >>$strfile echo `date "+%Y-%m-%d"` by $user on `hostname`. >>$strfile @@ -775,7 +775,7 @@ echo "" >>$strfile echo "" echo "Running command tests..." -echo "

2 - Command Tests

" >>$strfile +echo "

2 - Command Tests

" >>$strfile echo "

This section provides the results to the command tests" >>$strfile echo "outlined in the CUPS Software Test Plan. These tests were run on" >>$strfile echo $date by $user on `hostname`. >>$strfile @@ -840,12 +840,8 @@ echo "" >>$strfile # kill $cupsd - -# -# Append the log files for post-mortim... -# - -echo "

3 - Log Files

" >>$strfile +wait $cupsd +cupsdstatus=$? # # Verify counts... @@ -853,7 +849,16 @@ echo "

3 - Log Files

" >>$strfile echo "Test Summary" echo "" -echo "

Summary

" >>$strfile +echo "

3 - Test Summary

" >>$strfile + +if test $cupsdstatus != 0; then + echo "FAIL: cupsd failed with exit status $cupsdstatus." + echo "

FAIL: cupsd failed with exit status $cupsdstatus.

" >>$strfile + fail=`expr $fail + 1` +else + echo "PASS: cupsd exited with no errors." + echo "

PASS: cupsd exited with no errors.

" >>$strfile +fi # Job control files count=`ls -1 $BASE/spool | wc -l` @@ -1052,18 +1057,23 @@ else echo "

PASS: $count debug2 messages.

" >>$strfile fi +# # Log files... -echo "

access_log

" >>$strfile +# + +echo "

4 - Log Files

" >>$strfile + +echo "

access_log

" >>$strfile echo "
" >>$strfile
 sed -e '1,$s/&/&/g' -e '1,$s/>$strfile
 echo "
" >>$strfile -echo "

error_log

" >>$strfile +echo "

error_log

" >>$strfile echo "
" >>$strfile
 $GREP -v '^d' $BASE/log/error_log | sed -e '1,$s/&/&/g' -e '1,$s/>$strfile
 echo "
" >>$strfile -echo "

page_log

" >>$strfile +echo "

page_log

" >>$strfile echo "
" >>$strfile
 sed -e '1,$s/&/&/g' -e '1,$s/>$strfile
 echo "
" >>$strfile @@ -1103,5 +1113,5 @@ if test $fail != 0; then fi # -# End of "$Id: run-stp-tests.sh 12658 2015-05-22 17:53:45Z msweet $" +# End of "$Id: run-stp-tests.sh 12696 2015-06-08 15:05:11Z msweet $" # diff --git a/test/str-header.html b/test/str-header.html index 4dafd6806b..d13205af63 100644 --- a/test/str-header.html +++ b/test/str-header.html @@ -1,10 +1,10 @@ - - + + - CUPS 2.0 Software Test Report + CUPS 2.1 Software Test Report