From 2e35f8e412fad9a91dcd602a3b94f4c79bbc318d Mon Sep 17 00:00:00 2001 From: Noha Elarief Date: Thu, 18 Jan 2018 10:12:02 -0800 Subject: [PATCH] Moving to 2.2.4 --- Android.mk | 7 +- CHANGES.txt | 374 +++++++--------- CREDITS.txt | 8 +- INSTALL.txt | 271 ++++++------ Makedefs.in | 20 +- Makefile | 4 +- README.txt | 194 +++++---- config.h | 19 +- config.h.in | 11 +- cups/Makefile | 54 +-- cups/adminutil.c | 2 +- cups/adminutil.h | 2 +- cups/api-filter.shtml | 2 +- cups/array-private.h | 2 +- cups/array.c | 2 +- cups/array.h | 2 +- cups/auth.c | 11 +- cups/backchannel.c | 2 +- cups/backend.c | 2 +- cups/backend.h | 2 +- cups/cups-private.h | 9 +- cups/cups.h | 53 +-- cups/debug-private.h | 2 +- cups/debug.c | 2 +- cups/dest-job.c | 36 +- cups/dest-localization.c | 2 +- cups/dest-options.c | 92 +++- cups/dest.c | 845 +++++++++++++++++++++++++----------- cups/dir.c | 33 +- cups/dir.h | 2 +- cups/encode.c | 8 +- cups/file-private.h | 6 +- cups/file.c | 39 +- cups/file.h | 6 +- cups/getdevices.c | 2 +- cups/getputfile.c | 2 +- cups/globals.c | 2 +- cups/hash.c | 2 +- cups/http-addr.c | 26 +- cups/http-addrlist.c | 10 +- cups/http-private.h | 5 +- cups/http-support.c | 30 +- cups/http.c | 60 +-- cups/http.h | 11 +- cups/ipp-private.h | 2 +- cups/ipp-support.c | 102 ++++- cups/ipp.c | 197 +++++---- cups/ipp.h | 280 ++++++------ cups/langprintf.c | 2 +- cups/language-private.h | 11 +- cups/language.c | 132 +++--- cups/language.h | 4 +- cups/libcups2.def | 2 - cups/md5passwd.c | 2 +- cups/notify.c | 2 +- cups/options.c | 61 ++- cups/ppd-attr.c | 2 +- cups/ppd-cache.c | 912 ++++++++++++++++++++++++++------------- cups/ppd-conflicts.c | 2 +- cups/ppd-custom.c | 2 +- cups/ppd-emit.c | 2 +- cups/ppd-localize.c | 6 +- cups/ppd-mark.c | 2 +- cups/ppd-page.c | 2 +- cups/ppd-private.h | 21 +- cups/ppd-util.c | 2 +- cups/ppd.c | 22 +- cups/ppd.h | 2 +- cups/pwg-media.c | 141 +++--- cups/pwg-private.h | 2 +- cups/pwg.h | 8 +- cups/raster-private.h | 2 +- cups/raster.h | 15 +- cups/request.c | 2 +- cups/sidechannel.c | 2 +- cups/sidechannel.h | 2 +- cups/snmp.c | 4 + cups/snprintf.c | 2 +- cups/string-private.h | 2 +- cups/string.c | 20 +- cups/tempfile.c | 2 +- cups/testadmin.c | 2 +- cups/testarray.c | 2 +- cups/testcache.c | 2 +- cups/testconflicts.c | 2 +- cups/testcreds.c | 2 +- cups/testcups.c | 2 +- cups/testdest.c | 9 +- cups/testfile.c | 2 +- cups/testhttp.c | 2 +- cups/testi18n.c | 2 +- cups/testipp.c | 2 +- cups/testlang.c | 2 +- cups/testoptions.c | 2 +- cups/testppd.c | 4 +- cups/testpwg.c | 2 +- cups/testsnmp.c | 2 +- cups/thread-private.h | 2 +- cups/thread.c | 5 +- cups/tls-darwin.c | 50 ++- cups/tls-gnutls.c | 18 +- cups/tls-sspi.c | 5 +- cups/tls.c | 2 +- cups/tlscheck.c | 2 +- cups/transcode.c | 2 +- cups/transcode.h | 2 +- cups/usersys.c | 21 +- cups/util.c | 127 ++++-- cups/versioning.h | 18 +- filter/Makefile | 2 +- filter/api-raster.shtml | 6 +- filter/commandtops.c | 2 +- filter/common.c | 2 +- filter/common.h | 2 +- filter/error.c | 2 +- filter/gziptoany.c | 2 +- filter/interpret.c | 2 +- filter/pstops.c | 2 +- filter/raster.c | 329 ++++++++++++-- filter/rasterbench.c | 2 +- filter/rastertoepson.c | 2 +- filter/rastertohp.c | 2 +- filter/rastertolabel.c | 21 +- filter/rastertopwg.c | 16 +- filter/testraster.c | 38 +- 125 files changed, 3160 insertions(+), 1821 deletions(-) diff --git a/Android.mk b/Android.mk index a67ae40..112b924 100644 --- a/Android.mk +++ b/Android.mk @@ -62,22 +62,23 @@ LOCAL_SRC_FILES:= \ cups/string.c \ cups/tempfile.c \ cups/thread.c \ - cups/tls-gnutls.c \ + cups/tls.c \ cups/transcode.c \ cups/usersys.c \ cups/util.c \ filter/error.c \ filter/raster.c \ + mopria.c \ disabled_src_files:= \ LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/cups \ $(LOCAL_PATH)/../gnutls/include -LOCAL_CFLAGS := -D_PPD_DEPRECATED= +LOCAL_CFLAGS := -D_PPD_DEPRECATED= -Wno-implicit-function-declaration -Wno-empty-body LOCAL_MODULE := lib$(PRIV_LIB_NAME)cups LOCAL_MODULE_TAGS := optional -LOCAL_LDLIBS += -lz -llog +LOCAL_LDLIBS += -lz -llog -Wl,--no-warn-shared-textrel LOCAL_STATIC_LIBRARIES := libgnutls LOCAL_DISABLE_FATAL_LINKER_WARNINGS := true include $(BUILD_SHARED_LIBRARY) \ No newline at end of file diff --git a/CHANGES.txt b/CHANGES.txt index 9bf60a6..24270ba 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,225 +1,183 @@ -CHANGES.txt - 1.6.3 - 2013-07-11 --------------------------------- +CHANGES - 2.2.4 - 2017-06-30 +============================ -CHANGES IN CUPS V1.6.3 +CHANGES IN CUPS V2.2.4 +---------------------- - - The configure script now prefers Clang over GCC. - - Fixed a compile problem on AIX (STR #4307) - - The default IPP version did not always get set before creating a new - IPP request message () - - The lp, lpq, lpr, and lpstat now display an error message advising the - use of the /version=1.1 ServerName option () - - Added documentation about the /version=1.1 option to ServerName in - client.conf () - - httpStatus(HTTP_ERROR) did not return a useful error message - () - - The lp, lpq, lpr, and lpstat commands incorrectly ignored the default - printer set in the lpoptions file () - - Fixed a URI encoding issue for hostnames containing the ` (backquote) - character () - - Added support for RFC 6874's IPv6 link local address format in URIs - () - - The USB backend could crash on libusb-based systems if USB was - disabled in the BIOS () - - Fixed a rounding error in the PWG media size mapping code - () - - Fixed several ipptool test files that used old STATUS names. - - Kerberos credentials could get truncated when printing to a shared - printer. - - Printing using "ipps" URIs was not encrypted. - - Insecure ICC profiles prevented installation of user profiles for a - printer on OS X. - - Added more USB quirks for the libusb-based backend (STR #4311, - ) - - The Russian web interface templates were broken (STR #4310) - - The scheduler no longer tries to do Kerberos authentication over the - loopback interface. - - The IPP backend could fail to pause a job for authentication - (STR #4298) - - Fixed a regression on the handling of auth keys on OS X if the - cups-files.conf was not present or did not contain a SystemAuthKey - value. - - The scheduler incorrectly did a reverse lookup of the server address - when HostNameLookups was turned off (STR #4302) - - The scheduler incorrectly computed the final content type value when - null filters were present. +- The scheduler did not remove old job files (Issue #4987) +- cupsEnumDests did not return early when all printers had been discovered + (Issue #4989) +- The CUPS build system now supports cross-compilation (Issue #4897) +- Added a new CUPS Programming Manual to replace the aging API documentation. +- Added the `cupsAddIntegerOption` and `cupsGetIntegerOption` functions + (Issue #4992) +- The `cupsGetDests` and `cupsCreateJob` functions now support Bonjour printers + (Issue #4993) +- Added a USB quirk rule for Lexmark E260dn printers (Issue #4994) +- Fixed a potential buffer overflow in the `cupstestppd` utility (Issue #4996) +- IPP Everywhere improvements (Issue #4998) +- Fixed the "cancel all jobs" function in the web interface for several + languages (Issue #4999) +- Fixed issues with local queues (Issue #5003, Issue #5008, Issue #5009) +- The `lpstat` command now supports a `-e` option to enumerate local printers + (either previously added or on the network) that can be accessed + (Issue #5005) +- The `lp` and `lpr` commands now support printing to network printers that + haven't yet been added (Issue #5006) +- Fixed a typo in the mime.types file. +- Fixed a bug in the Spanish web interface template (Issue #5016) +- The `cupsEnumDests*` and `cupsGetDest*` functions now report the value of the + "printer-is-temporary" Printer Status attribute (Issue #5028) +- Added Chinese localization (Issue #5029) +- The `cupsCheckDestSupported` function did not support `NULL` values + (Issue #5031) +- Fixed some issues in the RPM spec file (Issue #5032) +- The `cupsConnectDest` function now supports the `CUPS_DEST_FLAGS_DEVICE` flag + for explicitly connecting to the device (printer) associated with the + destination. +- The `SSLOptions` directive in "client.conf" and "cupsd.conf" now supports + `DenyCBC` and `DenyTLS1.0` options (Issue #5037) -CHANGES IN CUPS V1.6.2 +CHANGES IN CUPS V2.2.3 +---------------------- - - Documentation fixes (STR #4229, STR #4239, STR #4234, STR #4248, - STR #4259) - - Security: All file, directory, user, and group settings are now stored - in a separate cups-files.conf configuration file that cannot be set - through the CUPS web interface or APIs (STR #4223) - - Added a Czech localization (STR #4201) - - Added a French localization (STR #4247) - - Added a Russian localization (STR #4228, STR #4285) - - Updated the Catalan localization (STR #4202) - - Local certificate authentication did not guard against an empty - certification file (STR #4293) - - The scheduler did not reject device URIs with spaces. - - Added USB quirk rule for Epson Stylus Photo 750 (STR #4286) - - The IPP backend could crash if the printer disconnects early - (STR #4284) - - cupsGetPPD did not work with statically-configured CUPS shared - queues (STR #4178) - - The scheduler did not support long MIME media types (STR #4270) - - The cupsfilter command did not set the CHARSET environment variable - for the text filters (STR #4273) - - The lp command did not show errors for unknown "--foo" (STR #4261) - - Bad IPP responses could crash ipptool (STR #4262) - - Updated USB quirk rules for Canon and Xerox printers (STR #4217, - STR #4263) - - Added USB blacklisting for printers that require a custom backend - (STR #4218) - - The PPD compiler did not correctly JCL options (STR #4115, STR #4203) - - The ipptool program now supports DEFINE-MATCH and DEFINE-NO-MATCH - predicates for STATUS directives. - - Fixed a problem with local Kerberos authentication (STR #4140) - - Coverity scan: fixed some minor issues (STR #4242) - - The scheduler did not remove color profiles after deleting a printer - (STR #4232, STR #4276) - - The CUPS library did not always detect a timed out connection to the - server which could cause temporary loss of printing from applications - (STR #4187) - - The ipptool program now supports variable substitution in OPERATION - and DELAY directives (STR #4175) - - The IPP backend now stops queues when the server configuration - prevents successful job submission (STR #4125) - - The XML output of ipptool contained empty dictionaries (STR #4136) - - The scheduler did not delete job control backup files (STR #4244) - - cupsGetPPD3 could return a local PPD instead of the correct remote - PPD. - - The scheduler incorrectly advertised auth-info-required for local - queues needing local authentication (STR #4205) - - CUPS 1.6 clients using the ServerName directive in client.conf did not - work with CUPS 1.3.x or older servers (STR #4231, STR #4291) - - The SNMP backend now tries to work around broken printers that use a - newline to separate key/value pairs. - - The IPP backend did not send a cancel request to printers when a job - was canceled and the printer did not support Create-Job. - - Fixed EPM packaging files (STR #4199) - - OpenBSD build fix (STR #4195, STR #4196, STR #4197) - - The scheduler could crash when using Avahi (STR #4183, STR #4192, - STR #4200, STR #4213) - - The IPP backend could get stuck in an endless loop on certain network - errors (STR #4194) - - 32-bit builds failed on Debian (STR #4133) - - The scheduler no longer accepts or sends job description attributes. - - The IPP backend now works around some conformance issues for broken - printers (STR #4190) - - cupsBackendReport() now filters out all control characters from the - reported 1284 device IDs (STR #4124) - - The scheduler no longer allows job-name values that are not valid - network Unicode strings (STR #4072) - - The web interface did not preserve the order of classes, jobs, or - printers (STR #4170) - - The network backends now support disabling of SNMP supply level - queries via the "snmp" URI option (STR #4106) - - The IPP backend did not specify the compression used (STR #4181) - - ipptool did not support octetString values. - - The scheduler did not recognize dnssd: or ipps: URIs as Bonjour shared - queues (STR #4158) - - Applications could not get the PPD file for statically-configured - Bonjour-shared print queues (STR #4159) - - The cupsd.conf file included obsolete browsing directives (STR #4157) - - Fixed a USB backend compatibility issue on systems using libusb - (STR #4155, STR #4191) - - Some Bonjour features were not available on systems with Avahi - (STR #4156) - - CUPS now includes the port number in the Host: header for HTTP - requests. - - Fixed REPEAT-MATCH for STATUS and EXPECT - was incorrectly erroring - out. +- The IPP backend could get into an infinite loop for certain errors, causing a + hung queue () +- The scheduler could pause responding to client requests in order to save state + changes to disk () +- Added support for PPD finishing keywords (Issue #4960, Issue #4961, + Issue #4962) +- The IPP backend did not send a media-col attribute for just the source or type + (Issue #4963) +- IPP Everywhere print queues did not always support all print qualities + supported by the printer (Issue #4953) +- IPP Everywhere print queues did not always support all media types supported + by the printer (Issue #4953) +- The IPP Everywhere PPD generator did not return useful error messages + (Issue #4954) +- The IPP Everywhere finishings support did not work correctly with common UI or + command-line options (Issue #4976) +- Fixed an error handling issue for the network backends (Issue #4979) +- The default cupsd.conf file did not work on systems compiled without Kerberos + support (Issue #4947) +- The "reprint job" option was not available for some canceled jobs + (Issue #4915) +- Updated the job listing in the web interface (Issue #4978) +- Fixed some localization issues on macOS () -CHANGES IN CUPS V1.6.1 +CHANGES IN CUPS V2.2.2 +---------------------- - - Documentation fix (STR #4149) - - RPM packaging fixes (STR #4129, #4145) - - The Japanese and English web interface headers were swapped - (STR #4148) +- Fixed some issues with the Zebra ZPL printer driver (Issue #4898) +- Fixed some issues with IPP Everywhere printer support (Issue #4893, + Issue #4909, Issue #4916, Issue #4921, Issue #4923, Issue #4932, Issue #4933, + Issue #4938) +- The rastertopwg filter could crash with certain input (Issue #4942) +- Optimized connection usage in the IPP backend () +- The scheduler did not detect when an encrypted connection was closed by the + client on Linux (Issue #4901) +- The cups-lpd program did not catch all legacy usage of ISO-8859-1 + (Issue #4899) +- Fixed builds on systems without a working poll() implementation (Issue #4905) +- Added a USB quirk rule for the Kyocera Ecosys P6026cdn (Issue #4900) +- The scheduler no longer creates log files on startup + () +- The ippContainsString function now uses case-insensitive comparisons for + mimeMediaType, name, and text values in conformance with RFC 2911. +- The network backends now log the addresses that were found for a printer + () +- Let's Encrypt certificates did not work when the hostname contained uppercase + letters (Issue #4919) +- Fixed reporting of printed pages in the web interface (Issue #4924) +- Updated systemd config files (Issue #4935) +- Updated documentation (PR #4896) +- Updated localizations (PR #4894, PR #4895, PR #4904, PR #4908, Issue #4946) +- Updated packaging files (Issue #4940) -CHANGES IN CUPS V1.6.0 +CHANGES IN CUPS V2.2.1 +---------------------- - - Document changes (STR #4131) - - Added new Catalan (STR #4107) and Spanish (STR #4137) localizations. +- Added "CreateSelfSignedCerts" directive for cups-files.conf to control whether + the scheduler automatically creates its own self-signed X.509 certificates for + TLS connections (Issue #4876) +- http*Connect did not handle partial failures (Issue #4870) +- Addressed some build warnings on Linux (Issue #4881) +- cupsHashData did not use the correct hashing algorithm + () +- Updated man pages (PR #4885) +- Updated localizations (PR #4877, PR #4886) -CHANGES IN CUPS V1.6rc1 +CHANGES IN CUPS V2.2.0 +---------------------- - - Added a new Japanese localization (STR #4122) - - The SNMP backend no longer exits if it is unable to obtain an IPv6 - socket (STR #4109) - - The LPD backend incorrectly used "localhost" in the control file - instead of the current hostname. +- Normalized the TLS certificate validation code and added additional error + messages to aid troubleshooting. +- The httpConnect functions did not work on Linux when cupsd was not running + (Issue #4870) +- The --no-remote-any option of cupsctl had no effect (Issue #4866) +- http*Connect did not return early when all addresses failed (Issue #4870) -CHANGES IN CUPS V1.6b1 +CHANGES IN CUPS V2.2rc1 +----------------------- - - Documentation updates (STR #3927, STR #3980, STR #4010, STR #4068) - - The scheduler now consolidates all PPD updates from filters at the - end of the job (STR #4075) - - CUPS now supports color management using colord (STR #3808) - - CUPS now supports Bonjour using Avahi (STR #3066) - - The PreserveJobFiles and PreserveJobHistory directives now support - specification of a time interval (STR #3143) - - PPD files can now be archived in (gzip'd) tar files to further reduce - the disk space used by PPD files (STR #3772) - - The network backends now deal with printers that report their levels - in percent but do not specify a maximum capacity of 100 (STR #3551) - - The network backends now report full/almost-full waste bins in - printers along with end-of-life for cleaning pads (STR #4017) - - Added a configure option to set the permissions of the installed - cupsd (STR #3459) - - Added a new WITH-ALL-VALUES directive to ipptool EXPECT predicates - (STR #3949) - - CUPS now supports a User directive in client.conf and the CUPS_USER - environment variable for overriding the default username (STR #3114) - - Now set the PJL USERNAME variable as needed (STR #3100) - - Added support for usernames and passwords longer than 32 characters - (STR #2856) - - Added a new MaxHoldTime directive to automatically cancel jobs that - have been held indefinitely after a specific number of seconds - (STR #2291) - - The LPD backend now uses the originating host name when it is not the - local system (STR #2053) - - CUPS now prefers the suffix "dpcm" when reporting resolution in dots- - per-centimeter (STR #4006) - - The configure script and build system no longer support building of - separate 32-bit and 64-bit libraries. - - The "brightness", "columns", "fitplot", "gamma", "hue", - "natural-scaling", "penwidth", "position", "ppi", "saturation", and - "scaling" options are not longer supported (STR #4010) - - The "page-bottom", "page-left", "page-right", "page-top", - "prettyprint", and "wrap" options have been deprecated (STR #4010) - - The scheduler now reports the standard "number-of-documents" attribute - instead of the CUPS-specific "document-count" attribute in - job objects. - - Added new destination connection and enumeration functions (STR #3924) - - Added new option, localization, and job submission functions that do - not depend on PPD files (STR #3925) - - Added a new MaxJobTime directive for cupsd that specifies the maximum - amount of time allowed for a job to complete before it is canceled. - - The default password callback now supports passwords up to 127 - characters. - - The scheduler now supports a DefaultAuthType of "auto" to - automatically choose between Basic (username/password) and Negotiate - (Kerberos) authentication. - - cupsSideChannelSNMPGet/Walk now support OIDs and values up to 64k in - length. - - CUPS no longer supports automatic remote printers or implicit classes - via the CUPS, LDAP, or SLP protocols (STR #3922, STR #3923) - - The PPD APIs are now deprecated and will be removed in a future - version of CUPS (STR #3927) - - The default IPP version for requests is now 2.0 (STR #3929) - - The IPP APIs no longer expose the ipp_t or ipp_attribute_t structures - and instead provide accessor functions (STR #3928) - - The scheduler will no longer run programs with group write permission. - - The PHP module has been removed (STR #3932) - - The bannertops, commandtoescpx, commandtopclx, imagetops, - imagetoraster, pdftops, rastertoescpx, rastertopclx, and texttops - filters have been removed (STR #3930) - - The serial and parallel backends have been removed (STR 3935) +- Updated the list of supported IPP Everywhere media types. +- The IPP backend did not validate TLS credentials properly. +- The printer-state-message attribute was not cleared after a print job with no + errors (Issue #4851) +- The CUPS-Add-Modify-Class and CUPS-Add-Modify-Printer operations did not + always return an error for failed adds (Issue #4854) +- PPD files with names longer than 127 bytes did not work (Issue #4860) +- Updated localizations (Issue #4846, PR #4858) + + +CHANGES IN CUPS V2.2b2 +---------------------- + +- Added Upstart support (PR #4825) +- CUPS now supports Let's Encrypt certificates on Linux. + + +CHANGES IN CUPS V2.2b1 +---------------------- + +- All CUPS commands now support POSIX options (Issue #4813) +- The scheduler now restarts faster (Issue #4760) +- Improved performance of web interface with large numbers of jobs (Issue #3819) +- Encrypted printing can now be limited to only trusted printers and servers + () +- The scheduler now advertises PWG Raster attributes for IPP Everywhere clients + (Issue #4428) +- The scheduler now logs informational messages for jobs at LogLevel "info" + (Issue #4815) +- The scheduler now uses the getgrouplist function when available (Issue #4611) +- The IPP backend no longer enables compression by default except for certain + raster formats that generally benefit from it () +- The scheduler did not handle out-of-disk situations gracefully (Issue #4742) +- The LPD mini-daemon now detects invalid UTF-8 sequences in job, document, and + user names (Issue #4748) +- The IPP backend now continues on to the next job when the remote server/ + printer puts the job on hold () +- The scheduler did not cancel multi-document jobs immediately + () +- The scheduler did not return non-shared printers to local clients unless they + connected to the domain socket () +- The scheduler now reads the spool directory if one or more job cache entries + point to deleted jobs () +- Added support for disc media sizes () +- The httpAddrConnect and httpConnect* APIs now try connecting to multiple + addresses in parallel () +- The cupsd domain socket is no longer world-accessible on macOS + () +- Interface scripts are no longer supported for security reasons + () +- Added a new cupsHashData API and support for hashed job passwords + () +- Localization fixes (, , + Issue #4041, Issue #4796) +- Documentation changes (Issue #4624, Issue #4781) +- Packaging fixes (PR #4832) diff --git a/CREDITS.txt b/CREDITS.txt index 04cb814..7d5a8b9 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -1,8 +1,8 @@ -CREDITS.txt - 2016-06-21 ------------------------- +CREDITS - 2017-05-01 +==================== -Few projects are completed by one person, and CUPS is no exception. We'd -like to thank the following individuals for their contributions: +Few projects are completed by one person, and CUPS is no exception. We'd like +to thank the following individuals for their contributions: Niklas 'Nille' Åkerström - Swedish localization. Nathaniel Barbour - Lots of testing and feedback. diff --git a/INSTALL.txt b/INSTALL.txt index f498d87..4a2529a 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -1,212 +1,215 @@ -INSTALL - CUPS v2.2.1 - 2016-10-03 ----------------------------------- +INSTALL - CUPS v2.2.4 - 2017-06-30 +================================== This file describes how to compile and install CUPS from source code. For more information on CUPS see the file called "README.txt". A complete change log can be found in "CHANGES.txt". -******************************************************************************* -******************************************************************************* -**** **** -**** USING CUPS REQUIRES ADDITIONAL THIRD-PARTY SUPPORT SOFTWARE AND **** -**** PRINTER DRIVERS. THESE ARE TYPICALLY INCLUDED WITH YOUR OPERATING **** -**** SYSTEM DISTRIBUTION. APPLE DOES NOT ENDORSE OR SUPPORT THIRD-PARTY **** -**** SUPPORT SOFTWARE FOR CUPS. **** -**** **** -******************************************************************************* -******************************************************************************* +> USING CUPS REQUIRES ADDITIONAL THIRD-PARTY SUPPORT SOFTWARE AND PRINTER +> DRIVERS. THESE ARE TYPICALLY INCLUDED WITH YOUR OPERATING SYSTEM +> DISTRIBUTION. APPLE DOES NOT ENDORSE OR SUPPORT THIRD-PARTY SUPPORT SOFTWARE +> FOR CUPS. BEFORE YOU BEGIN +---------------- - You'll need ANSI-compliant C and C++ compilers, plus a make program and - POSIX-compliant shell (/bin/sh). The GNU compiler tools and Bash work well - and we have tested the current CUPS code against several versions of GCC - with excellent results. +You'll need ANSI-compliant C and C++ compilers, plus a make program and POSIX- +compliant shell (/bin/sh). The GNU compiler tools and Bash work well and we +have tested the current CUPS code against several versions of GCC with excellent +results. - The makefiles used by the project should work with most versions of make. - We've tested them with GNU make as well as the make programs shipped by - Compaq, HP, SGI, and Sun. BSD users should use GNU make (gmake) since BSD - make does not support "include". +The makefiles used by the project should work with most versions of make. We've +tested them with GNU make as well as the make programs shipped by Compaq, HP, +SGI, and Sun. BSD users should use GNU make (gmake) since BSD make does not +support "include". - Besides these tools you'll want ZLIB library for compression support, the - GNU TLS library for encryption support on platforms other than iOS, macOS, - or Windows, and either MIT (1.6.3 or higher) or Heimdal Kerberos for - Kerberos support. CUPS will compile and run without these, however you'll - miss out on many of the features provided by CUPS. +Besides these tools you'll want ZLIB library for compression support, the GNU +TLS library for encryption support on platforms other than iOS, macOS, or +Windows, and either MIT (1.6.3 or higher) or Heimdal Kerberos for Kerberos +support. CUPS will compile and run without these, however you'll miss out on +many of the features provided by CUPS. - Also, please note that CUPS does not include print filters to support PDF - or raster printing. You *must* download GPL Ghostscript and/or the Open - Printing CUPS filters package separately to print on operating systems - other than macOS. +On a stock Ubuntu install, the following command will install the required +prerequisites: + + sudo apt-get install autoconf build-essential libavahi-client-dev \ + libgnutls28-dev libkrb5-dev libnss-mdns libpam-dev \ + libsystemd-dev libusb-1.0-0-dev zlib1g-dev + +Also, please note that CUPS does not include print filters to support PDF or +raster printing. You *must* download GPL Ghostscript and/or the Open Printing +CUPS filters package separately to print on operating systems other than macOS. CONFIGURATION +------------- - CUPS uses GNU autoconf, so you should find the usual "configure" script in - the main CUPS source directory. To configure CUPS for your system, type: +CUPS uses GNU autoconf, so you should find the usual "configure" script in the +main CUPS source directory. To configure CUPS for your system, type: - ./configure + ./configure - The default installation will put the CUPS software in the "/etc", "/usr", - and "/var" directories on your system, which will overwrite any existing - printing commands on your system. Use the "--prefix" option to install the - CUPS software in another location: +The default installation will put the CUPS software in the "/etc", "/usr", and +"/var" directories on your system, which will overwrite any existing printing +commands on your system. Use the "--prefix" option to install the CUPS software +in another location: - ./configure --prefix=/some/directory + ./configure --prefix=/some/directory - To see a complete list of configuration options, use the --help option: +To see a complete list of configuration options, use the --help option: - ./configure --help + ./configure --help - If any of the dependent libraries are not installed in a system default - location (typically "/usr/include" and "/usr/lib") you'll need to set the - CFLAGS, CPPFLAGS, CXXFLAGS, DSOFLAGS, and LDFLAGS environment variables - prior to running configure: +If any of the dependent libraries are not installed in a system default location +(typically "/usr/include" and "/usr/lib") you'll need to set the CFLAGS, +CPPFLAGS, CXXFLAGS, DSOFLAGS, and LDFLAGS environment variables prior to running +configure: - setenv CFLAGS "-I/some/directory" - setenv CPPFLAGS "-I/some/directory" - setenv CXXFLAGS "-I/some/directory" - setenv DSOFLAGS "-L/some/directory" - setenv LDFLAGS "-L/some/directory" - ./configure ... + setenv CFLAGS "-I/some/directory" + setenv CPPFLAGS "-I/some/directory" + setenv CXXFLAGS "-I/some/directory" + setenv DSOFLAGS "-L/some/directory" + setenv LDFLAGS "-L/some/directory" + ./configure ... - or: +or: - CFLAGS="-I/some/directory" \ - CPPFLAGS="-I/some/directory" \ - CXXFLAGS="-I/some/directory" \ - DSOFLAGS="-L/some/directory" \ - LDFLAGS="-L/some/directory" \ - ./configure ... + CFLAGS="-I/some/directory" \ + CPPFLAGS="-I/some/directory" \ + CXXFLAGS="-I/some/directory" \ + DSOFLAGS="-L/some/directory" \ + LDFLAGS="-L/some/directory" \ + ./configure ... - The "--enable-debug" option compiles CUPS with debugging information - enabled. Additional debug logging support can be enabled using the - "--enable-debug-printfs" option - these debug messages are enabled using the - CUPS_DEBUG_LOG environment variable at run-time. +The "--enable-debug" option compiles CUPS with debugging information enabled. +Additional debug logging support can be enabled using the +"--enable-debug-printfs" option - these debug messages are enabled using the +CUPS_DEBUG_LOG environment variable at run-time. - CUPS also includes an extensive set of unit tests that can be used to find - and diagnose a variety of common problems - use the "--enable-unit-tests" - configure option to run them at build time. +CUPS also includes an extensive set of unit tests that can be used to find and +diagnose a variety of common problems - use the "--enable-unit-tests" configure +option to run them at build time. - On macOS, use the "--with-archflags" option to build with the correct set of - architectures: +On macOS, use the "--with-archflags" option to build with the correct set of +architectures: - ./configure --with-archflags="-arch i386 -arch x86_64" ... + ./configure --with-archflags="-arch i386 -arch x86_64" ... - Note: Current versions of macOS DO NOT allow installation to - /usr with the default system integrity settings. In addition, - we do not recommend replacing the CUPS supplied with macOS - because not all versions of CUPS are compatible with every - macOS release, and because software updates will replace parts - of your local installation potentially rendering your system - unusable. +> Note: Current versions of macOS DO NOT allow installation to /usr with the +> default system integrity settings. In addition, we do not recommend replacing +> the CUPS supplied with macOS because not all versions of CUPS are compatible +> with every macOS release, and because software updates will replace parts +> of your local installation potentially rendering your system unusable. - Once you have configured things, just type: +Once you have configured things, just type: - make ENTER + make ENTER - or if you have FreeBSD, NetBSD, or OpenBSD type: +or if you have FreeBSD, NetBSD, or OpenBSD type: - gmake ENTER + gmake ENTER - to build the software. +to build the software. TESTING THE SOFTWARE +-------------------- - Aside from the built-in unit tests, CUPS includes an automated test - framework for testing the entire printing system. To run the tests, just - type: +Aside from the built-in unit tests, CUPS includes an automated test framework +for testing the entire printing system. To run the tests, just type: - make check ENTER + make check ENTER - or if you have FreeBSD, NetBSD, or OpenBSD type: +or if you have FreeBSD, NetBSD, or OpenBSD type: - gmake check ENTER + gmake check ENTER - The test framework runs a copy of the CUPS scheduler (cupsd) on port 8631 - in /tmp/cups-$USER and produces a nice HTML report of the results. +The test framework runs a copy of the CUPS scheduler (cupsd) on port 8631 in +/tmp/cups-$USER and produces a nice HTML report of the results. INSTALLING THE SOFTWARE +----------------------- - Once you have built the software you need to install it. The "install" - target provides a quick way to install the software on your local system: +Once you have built the software you need to install it. The "install" target +provides a quick way to install the software on your local system: - make install ENTER + make install ENTER - or for FreeBSD, NetBSD, or OpenBSD: +or for FreeBSD, NetBSD, or OpenBSD: - gmake install ENTER + gmake install ENTER - Use the BUILDROOT variable to install to an alternate root directory: +Use the BUILDROOT variable to install to an alternate root directory: - make BUILDROOT=/some/other/root/directory install ENTER + make BUILDROOT=/some/other/root/directory install ENTER - You can also build binary packages that can be installed on other machines - using the RPM spec file ("packaging/cups.spec") or EPM list file - ("packaging/cups.list"). The latter also supports building of binary RPMs, - so it may be more convenient to use. +You can also build binary packages that can be installed on other machines using +the RPM spec file ("packaging/cups.spec") or EPM list file +("packaging/cups.list"). The latter also supports building of binary RPMs, so +it may be more convenient to use. - You can find the RPM software at: +You can find the RPM software at: - http://www.rpm.org/ + http://www.rpm.org/ - The EPM software is available at: +The EPM software is available at: - http://www.msweet.org/ + https://michaelrsweet.github.io/epm CREATING BINARY DISTRIBUTIONS WITH EPM +-------------------------------------- - The top level makefile supports generation of many types of binary - distributions using EPM. To build a binary distribution type: +The top level makefile supports generation of many types of binary distributions +using EPM. To build a binary distribution type: - make ENTER + make ENTER - or +or - gmake ENTER + gmake ENTER - for FreeBSD, NetBSD, and OpenBSD. The target is one of the - following: +for FreeBSD, NetBSD, and OpenBSD. The target is one of the following: - epm - Builds a script + tarfile package - bsd - Builds a *BSD package - deb - Builds a Debian package - pkg - Builds a Solaris package - rpm - Builds a RPM package - slackware - Build a Slackware package +- "epm": Builds a script + tarfile package +- "bsd": Builds a *BSD package +- "deb": Builds a Debian package +- "pkg": Builds a Solaris package +- "rpm": Builds a RPM package +- "slackware": Build a Slackware package GETTING DEBUG LOGGING FROM CUPS +------------------------------- - When configured with the "--enable-debug-printfs" option, CUPS compiles in - additional debug logging support in the scheduler, CUPS API, and CUPS - Imaging API. The following environment variables are used to enable and - control debug logging: +When configured with the "--enable-debug-printfs" option, CUPS compiles in +additional debug logging support in the scheduler, CUPS API, and CUPS Imaging +API. The following environment variables are used to enable and control debug +logging: - CUPS_DEBUG_FILTER Specifies a POSIX regular expression to control - which messages are logged. - CUPS_DEBUG_LEVEL Specifies a number from 0 to 9 to control the - verbosity of the logging. The default level is 1. - CUPS_DEBUG_LOG Specifies a log file to use. Specify the name "-" - to send the messages to stderr. Prefix a filename - with "+" to append to an existing file. +- `CUPS_DEBUG_FILTER`: Specifies a POSIX regular expression to control which + messages are logged. +- `CUPS_DEBUG_LEVEL`: Specifies a number from 0 to 9 to control the verbosity of + the logging. The default level is 1. +- `CUPS_DEBUG_LOG`: Specifies a log file to use. Specify the name "-" to send + the messages to stderr. Prefix a filename with "+" to append to an existing + file. REPORTING PROBLEMS +------------------ - If you have problems, READ THE DOCUMENTATION FIRST! If the documentation - does not solve your problems, please post a message on the users forum at: +If you have problems, READ THE DOCUMENTATION FIRST! If the documentation does +not solve your problems, please post a message on the users forum at: - http://www.cups.org/ + https://www.cups.org/ - Include your operating system and version, compiler and version, and any - errors or problems you've run into. The "config.log" file and the output - from the configure script and make should also be sent, as it often helps to - determine the cause of your problem. +Include your operating system and version, compiler and version, and any errors +or problems you've run into. The "config.log" file and the output from the +configure script and make should also be sent, as it often helps to determine +the cause of your problem. - If you are running a version of Linux, be sure to provide the Linux - distribution you have, too. +If you are running a version of Linux, be sure to provide the Linux distribution +you have, too. diff --git a/Makedefs.in b/Makedefs.in index 332a127..f958c26 100644 --- a/Makedefs.in +++ b/Makedefs.in @@ -1,14 +1,14 @@ # # Common makefile definitions for CUPS. # -# Copyright 2007-2014 by Apple Inc. +# Copyright 2007-2017 by Apple Inc. # Copyright 1997-2007 by Easy Software Products, all rights reserved. # # 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/". +# missing or damaged, see the license at "http://www.cups.org/". # # @@ -38,14 +38,14 @@ SHELL = /bin/sh # Installation programs... # -INSTALL_BIN = $(LIBTOOL) $(INSTALL) -c -m 555 @INSTALL_STRIP@ +INSTALL_BIN = $(LIBTOOL) $(INSTALL) -c -m @CUPS_EXE_FILE_PERM@ @INSTALL_STRIP@ INSTALL_COMPDATA = $(INSTALL) -c -m 444 @INSTALL_GZIP@ INSTALL_CONFIG = $(INSTALL) -c -m @CUPS_CONFIG_FILE_PERM@ INSTALL_DATA = $(INSTALL) -c -m 444 INSTALL_DIR = $(INSTALL) -d -INSTALL_LIB = $(LIBTOOL) $(INSTALL) -c -m 555 @INSTALL_STRIP@ +INSTALL_LIB = $(LIBTOOL) $(INSTALL) -c -m @CUPS_EXE_FILE_PERM@ @INSTALL_STRIP@ INSTALL_MAN = $(INSTALL) -c -m 444 -INSTALL_SCRIPT = $(INSTALL) -c -m 555 +INSTALL_SCRIPT = $(INSTALL) -c -m @CUPS_EXE_FILE_PERM@ # # Default user, group, and system groups for the scheduler... @@ -72,6 +72,14 @@ LANGUAGES = @LANGUAGES@ INSTALL_LANGUAGES = @INSTALL_LANGUAGES@ UNINSTALL_LANGUAGES = @UNINSTALL_LANGUAGES@ +# +# Cross-compilation support: "local" target is used for any tools that are +# built and run locally. +# + +LOCALTARGET = @LOCALTARGET@ + + # # Libraries... # @@ -141,7 +149,7 @@ IPPFIND_MAN = @IPPFIND_MAN@ LDFLAGS = -L../cgi-bin -L../cups -L../filter -L../ppdc \ -L../scheduler @LDARCHFLAGS@ \ @LDFLAGS@ @RELROFLAGS@ @PIEFLAGS@ $(OPTIM) -LINKCUPS = @LINKCUPS@ $(LIBGSSAPI) $(DNSSDLIBS) $(LIBZ) +LINKCUPS = @LINKCUPS@ $(LIBGSSAPI) $(DNSSDLIBS) $(SSLLIBS) $(LIBZ) LINKCUPSIMAGE = @LINKCUPSIMAGE@ LIBS = $(LINKCUPS) $(COMMONLIBS) ONDEMANDFLAGS = @ONDEMANDFLAGS@ diff --git a/Makefile b/Makefile index 264dc1b..afc90ce 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ # 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/". +# missing or damaged, see the license at "http://www.cups.org/". # include Makedefs @@ -317,7 +317,7 @@ EPMFLAGS = -v --output-dir dist $(EPMARCH) bsd deb epm pkg rpm slackware: epm $(EPMFLAGS) -f $@ cups packaging/cups.list -.PHONEY: dist +.PHONY: dist dist: all $(RM) -r dist $(MAKE) $(MFLAGS) epm diff --git a/README.txt b/README.txt index 9cea07f..97672e9 100644 --- a/README.txt +++ b/README.txt @@ -1,152 +1,160 @@ -README - CUPS v2.2.1 - 2016-10-03 ---------------------------------- +README - CUPS v2.2.4 - 2017-06-30 +================================= -Looking for compile instructions? Read the file "INSTALL.txt" instead... +Looking for compile instructions? Read the file "INSTALL.md" instead... INTRODUCTION +------------ - CUPS is a standards-based, open source printing system developed by Apple - Inc. for macOS® and other UNIX®-like operating systems. CUPS uses the - Internet Printing Protocol ("IPP") and provides System V and Berkeley - command-line interfaces, a web interface, and a C API to manage printers and - print jobs. It supports printing to both local (parallel, serial, USB) and - networked printers, and printers can be shared from one computer to another, - even over the Internet! - Internally, CUPS uses PostScript Printer Description ("PPD") files to - describe printer capabilities and features and a wide variety of generic - and device-specific programs to convert and print many types of files. - Sample drivers are included with CUPS to support many Dymo, EPSON, HP, - Intellitech, OKIDATA, and Zebra printers. Many more drivers are available - online and (in some cases) on the driver CD-ROM that came with your printer. +CUPS is a standards-based, open source printing system developed by Apple Inc. +for macOS® and other UNIX®-like operating systems. CUPS uses the Internet +Printing Protocol ("IPP") and provides System V and Berkeley command-line +interfaces, a web interface, and a C API to manage printers and print jobs. It +supports printing to both local (parallel, serial, USB) and networked printers, +and printers can be shared from one computer to another, even over the Internet! - CUPS is licensed under the GNU General Public License and GNU Library - General Public License versions 2. See the file "LICENSE.txt" for more - information. +Internally, CUPS uses PostScript Printer Description ("PPD") files to describe +printer capabilities and features and a wide variety of generic and device- +specific programs to convert and print many types of files. Sample drivers are +included with CUPS to support many Dymo, EPSON, HP, Intellitech, OKIDATA, and +Zebra printers. Many more drivers are available online and (in some cases) on +the driver CD-ROM that came with your printer. + +CUPS is licensed under the GNU General Public License and GNU Library General +Public License versions 2. See the file "LICENSE.txt" for more information. READING THE DOCUMENTATION +------------------------- - Once you have installed the software you can access the documentation (and - a bunch of other stuff) online at: +Once you have installed the software you can access the documentation (and a +bunch of other stuff) online at: - http://localhost:631/ + http://localhost:631/ - If you're having trouble getting that far, the documentation is located - under the "doc/help" directory. +If you're having trouble getting that far, the documentation is located under +the "doc/help" directory. - Please read the documentation before asking questions. +Please read the documentation before asking questions. GETTING SUPPORT AND OTHER RESOURCES +----------------------------------- - If you have problems, READ THE DOCUMENTATION FIRST! We also provide two - mailing lists which are available at: +If you have problems, READ THE DOCUMENTATION FIRST! We also provide two mailing +lists which are available at: - http://www.cups.org/lists.php + https://lists.cups.org/mailman/listinfo - See the CUPS web site at "http://www.cups.org/" for other resources. +See the CUPS web site at for other resources. SETTING UP PRINTER QUEUES USING YOUR WEB BROWSER +------------------------------------------------ - CUPS includes a web-based administration tool that allows you to manage - printers, classes, and jobs on your server. Open the following URL in your - browser to access the printer administration tools: +CUPS includes a web-based administration tool that allows you to manage +printers, classes, and jobs on your server. Open the following URL in your +browser to access the printer administration tools: - http://localhost:631/admin/ + http://localhost:631/admin/ - DO NOT use the hostname for your machine - it will not work with the default - CUPS configuration. To enable administration access on other addresses, - check the "Allow Remote Administration" box and click on the "Change - Settings" button. +*Do not* use the hostname for your machine - it will not work with the default +CUPS configuration. To enable administration access on other addresses, check +the "Allow Remote Administration" box and click on the "Change Settings" button. - You will be asked for the administration password (root or any other user in - the sys/system/root/admin/lpadmin group on your system) when performing any - administrative function. +You will be asked for the administration password (root or any other user in the +sys/system/root/admin/lpadmin group on your system) when performing any +administrative function. SETTING UP PRINTER QUEUES FROM THE COMMAND-LINE +----------------------------------------------- - CUPS works best with PPD (PostScript Printer Description) files. In a pinch - you can also use System V style printer interface scripts. +CUPS works best with PPD (PostScript Printer Description) files. In a pinch you +can also use System V style printer interface scripts. - CUPS includes several sample PPD files you can use: +CUPS includes several sample PPD files you can use: - Driver PPD Name - ----------------------------- ------------------------------ - Dymo Label Printers drv:///sample.drv/dymo.ppd - Intellitech Intellibar drv:///sample.drv/intelbar.ppd - EPSON 9-pin Series drv:///sample.drv/epson9.ppd - EPSON 24-pin Series drv:///sample.drv/epson24.ppd - Generic PCL Laser Printer drv:///sample.drv/generpcl.ppd - Generic PostScript Printer drv:///sample.drv/generic.ppd - HP DeskJet Series drv:///sample.drv/deskjet.ppd - HP LaserJet Series drv:///sample.drv/laserjet.ppd - OKIDATA 9-Pin Series drv:///sample.drv/okidata9.ppd - OKIDATA 24-Pin Series drv:///sample.drv/okidat24.ppd - Zebra CPCL Label Printer drv:///sample.drv/zebracpl.ppd - Zebra EPL1 Label Printer drv:///sample.drv/zebraep1.ppd - Zebra EPL2 Label Printer drv:///sample.drv/zebraep2.ppd - Zebra ZPL Label Printer drv:///sample.drv/zebra.ppd + Driver PPD Name + ----------------------------- ------------------------------ + Dymo Label Printers drv:///sample.drv/dymo.ppd + Intellitech Intellibar drv:///sample.drv/intelbar.ppd + EPSON 9-pin Series drv:///sample.drv/epson9.ppd + EPSON 24-pin Series drv:///sample.drv/epson24.ppd + Generic PCL Laser Printer drv:///sample.drv/generpcl.ppd + Generic PostScript Printer drv:///sample.drv/generic.ppd + HP DeskJet Series drv:///sample.drv/deskjet.ppd + HP LaserJet Series drv:///sample.drv/laserjet.ppd + OKIDATA 9-Pin Series drv:///sample.drv/okidata9.ppd + OKIDATA 24-Pin Series drv:///sample.drv/okidat24.ppd + Zebra CPCL Label Printer drv:///sample.drv/zebracpl.ppd + Zebra EPL1 Label Printer drv:///sample.drv/zebraep1.ppd + Zebra EPL2 Label Printer drv:///sample.drv/zebraep2.ppd + Zebra ZPL Label Printer drv:///sample.drv/zebra.ppd - Run the "lpinfo -m" command to list the available drivers: +Run the "lpinfo -m" command to list the available drivers: - lpinfo -m + lpinfo -m - Run the "lpinfo -v" command to list the available printers: +Run the "lpinfo -v" command to list the available printers: - lpinfo -v + lpinfo -v - Then use the correct URI to add the printer using the "lpadmin" command: +Then use the correct URI to add the printer using the "lpadmin" command: - lpadmin -p printername -E -v device-uri -m ppd-name + lpadmin -p printername -E -v device-uri -m ppd-name - Network printers typically use "socket" or "lpd" URIs: +Network printers typically use "socket" or "lpd" URIs: - lpadmin -p printername -E -v socket://11.22.33.44 -m ppd-name - lpadmin -p printername -E -v lpd://11.22.33.44/ -m ppd-name + lpadmin -p printername -E -v socket://11.22.33.44 -m ppd-name + lpadmin -p printername -E -v lpd://11.22.33.44/ -m ppd-name - The sample drivers provide basic printing capabilities, but generally do not - exercise the full potential of the printers or CUPS. +The sample drivers provide basic printing capabilities, but generally do not +exercise the full potential of the printers or CUPS. + +CUPS also supports IPP Everywhere printers using the "everywhere" model, for +example: + + lpadmin -p printername -E -v ipp://11.22.33.44/ipp/print -m everywhere PRINTING FILES +-------------- - CUPS provides both the System V "lp" and Berkeley "lpr" commands for - printing: +CUPS provides both the System V "lp" and Berkeley "lpr" commands for printing: - lp filename - lpr filename + lp filename + lpr filename - Both the "lp" and "lpr" commands support printing options for the driver: +Both the "lp" and "lpr" commands support printing options for the driver: - lp -o media=A4 -o resolution=600dpi filename - lpr -o media=A4 -o resolution=600dpi filename + lp -o media=A4 -o resolution=600dpi filename + lpr -o media=A4 -o resolution=600dpi filename - CUPS recognizes many types of images files as well as PDF, PostScript, - and text files, so you can print those files directly rather than through - an application. +CUPS recognizes many types of images files as well as PDF, PostScript, and text +files, so you can print those files directly rather than through an application. - If you have an application that generates output specifically for your - printer then you need to use the "-oraw" or "-l" options: +If you have an application that generates output specifically for your printer +then you need to use the "-oraw" or "-l" options: - lp -o raw filename - lpr -l filename + lp -o raw filename + lpr -l filename - This will prevent the filters from misinterpreting your print file. +This will prevent the filters from misinterpreting your print file. LEGAL STUFF +----------- - CUPS is Copyright 2007-2016 by Apple Inc. CUPS and the CUPS logo are - trademarks of Apple Inc. +CUPS is copyright © 2007-2017 by Apple Inc. CUPS and the CUPS logo are +trademarks of Apple Inc. - The MD5 Digest code is Copyright 1999 Aladdin Enterprises. +The MD5 Digest code is Copyright 1999 Aladdin Enterprises. - CUPS is provided under the terms of version 2 of the GNU General Public - License and GNU Library General Public License. This program is distributed - in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - See the "doc/help/license.html" or "LICENSE.txt" files for more information. +CUPS is provided under the terms of version 2 of the GNU General Public License +and GNU Library General Public License. This program is distributed in the hope +that it will be useful, but WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +"doc/help/license.html" or "LICENSE.txt" files for more information. diff --git a/config.h b/config.h index 8065217..af9d7bd 100644 --- a/config.h +++ b/config.h @@ -4,21 +4,21 @@ * * Configuration file for CUPS. * - * Copyright 2007-2012 by Apple Inc. + * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 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/". + * missing or damaged, see the license at "http://www.cups.org/". */ /* 07/22/2016 Mopria-notice: some config changes were applied directly to this generated file * rather than by running the configure script again. */ -#include +#include #ifndef _CUPS_CONFIG_H_ #define _CUPS_CONFIG_H_ @@ -27,8 +27,8 @@ * Version of software... */ -#define CUPS_SVERSION "CUPS v1.6.3" -#define CUPS_MINIMAL "CUPS/1.6.3" +#define CUPS_SVERSION "CUPS v2.2.3" +#define CUPS_MINIMAL "CUPS/2.2.3" /* @@ -745,15 +745,14 @@ static __inline int _cups_abs(int i) { return (i < 0 ? -i : i); } # endif /* __GNUC__ || __STDC_VERSION__ */ #endif /* !HAVE_ABS && !abs */ -// 11/23/2016 Mopria-notice: as lockf method is not defined in the Android, we defined our own. -#define F_LOCK LOCK_EX -#define F_ULOCK LOCK_UN -#define F_TLOCK ( LOCK_EX | LOCK_NB ) -#define F_TULOCK ( LOCK_UN | LOCK_NB ) +// 11/23/2016 Mopria-notice: lockf not present in Android. static inline int lockf(int fd, int cmd, off_t ignored_len) { return flock(fd, cmd); } +// 08/28/2016 Mopria-notice: pthread_cancel not defined in Android +void pthread_cancel(int thread); + #endif /* !_CUPS_CONFIG_H_ */ /* diff --git a/config.h.in b/config.h.in index 0323eaa..f3b5e4c 100644 --- a/config.h.in +++ b/config.h.in @@ -1,14 +1,14 @@ /* * Configuration file for CUPS. * - * Copyright 2007-2016 by Apple Inc. + * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 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/". + * missing or damaged, see the license at "http://www.cups.org/". */ #ifndef _CUPS_CONFIG_H_ @@ -240,13 +240,6 @@ #undef HAVE_VSYSLOG -/* - * Do we have the ASL functions? - */ - -#undef HAVE_ASL_H - - /* * Do we have the systemd journal functions? */ diff --git a/cups/Makefile b/cups/Makefile index ba9bbed..962bee6 100644 --- a/cups/Makefile +++ b/cups/Makefile @@ -8,7 +8,7 @@ # 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/". +# missing or damaged, see the license at "http://www.cups.org/". # # This file is subject to the Apple OS-Developed Software exception. # @@ -571,56 +571,27 @@ tlscheck: tlscheck.o $(LIBCUPSSTATIC) apihelp: echo Generating CUPS API help files... - mxmldoc --section "Programming" \ - --title "Introduction to CUPS Programming" \ - --css ../doc/cups-printable.css \ - --header api-overview.header --intro api-overview.shtml \ - >../doc/help/api-overview.html + $(RM) cupspm.xml + mxmldoc --section "Programming" --body cupspm.md \ + cupspm.xml \ + auth.c cups.h dest*.c encode.c http.h http*.c ipp.h ipp*.c \ + options.c tls-darwin.c usersys.c util.c \ + --coverimage cupspm.png \ + --epub ../doc/help/cupspm.epub + mxmldoc --section "Programming" --body cupspm.md \ + cupspm.xml > ../doc/help/cupspm.html + $(RM) cupspm.xml mxmldoc --section "Programming" --title "Administration APIs" \ --css ../doc/cups-printable.css \ --header api-admin.header --intro api-admin.shtml \ api-admin.xml \ adminutil.c adminutil.h getdevices.c >../doc/help/api-admin.html - mxmldoc --tokens help/api-admin.html api-admin.xml >../doc/help/api-admin.tokens $(RM) api-admin.xml - mxmldoc --section "Programming" --title "Array API" \ - --css ../doc/cups-printable.css \ - --header api-array.header --intro api-array.shtml \ - api-array.xml \ - array.h array.c >../doc/help/api-array.html - mxmldoc --tokens help/api-array.html api-array.xml >../doc/help/api-array.tokens - $(RM) api-array.xml - mxmldoc --section "Programming" --title "CUPS API" \ - --css ../doc/cups-printable.css \ - --header api-cups.header --intro api-cups.shtml \ - api-cups.xml \ - cups.h pwg.h adminutil.c dest*.c language.c notify.c \ - options.c pwg-media.c tempfile.c usersys.c \ - util.c >../doc/help/api-cups.html - mxmldoc --tokens help/api-cups.html api-cups.xml >../doc/help/api-cups.tokens - $(RM) api-cups.xml - mxmldoc --section "Programming" --title "File and Directory APIs" \ - --css ../doc/cups-printable.css \ - --header api-filedir.header --intro api-filedir.shtml \ - api-filedir.xml \ - file.h file.c dir.h dir.c >../doc/help/api-filedir.html - mxmldoc --tokens api-filedir.xml >../doc/help/api-filedir.tokens - $(RM) api-filedir.xml mxmldoc --section "Programming" --title "PPD API (DEPRECATED)" \ --css ../doc/cups-printable.css \ --header api-ppd.header --intro api-ppd.shtml \ api-ppd.xml ppd.h ppd-*.c >../doc/help/api-ppd.html - mxmldoc --tokens help/api-ppd.html api-ppd.xml >../doc/help/api-ppd.tokens $(RM) api-ppd.xml - mxmldoc --section "Programming" --title "HTTP and IPP APIs" \ - --css ../doc/cups-printable.css \ - --header api-httpipp.header --intro api-httpipp.shtml \ - api-httpipp.xml \ - http.h ipp.h auth.c getdevices.c getputfile.c encode.c \ - http.c http-addr.c http-support.c ipp.c ipp-support.c \ - md5passwd.c request.c >../doc/help/api-httpipp.html - mxmldoc --tokens help/api-httpipp.html api-httpipp.xml >../doc/help/api-httpipp.tokens - $(RM) api-httpipp.xml mxmldoc --section "Programming" \ --title "Filter and Backend Programming" \ --css ../doc/cups-printable.css \ @@ -628,7 +599,6 @@ apihelp: api-filter.xml \ backchannel.c backend.h backend.c sidechannel.c sidechannel.h \ >../doc/help/api-filter.html - mxmldoc --tokens help/api-filter.html api-filter.xml >../doc/help/api-filter.tokens $(RM) api-filter.xml @@ -637,8 +607,6 @@ apihelp: # sloc: - echo "libcupslite: \c" - sloccount $(LITEOBJS:.o=.c) 2>/dev/null | grep "Total Physical" | awk '{print $$9}' echo "libcups: \c" sloccount $(LIBOBJS:.o=.c) 2>/dev/null | grep "Total Physical" | awk '{print $$9}' diff --git a/cups/adminutil.c b/cups/adminutil.c index 1a6d6a7..adb1f7a 100644 --- a/cups/adminutil.c +++ b/cups/adminutil.c @@ -8,7 +8,7 @@ * 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/". + * missing or damaged, see the license at "http://www.cups.org/". * * This file is subject to the Apple OS-Developed Software exception. */ diff --git a/cups/adminutil.h b/cups/adminutil.h index cc119fc..23f7978 100644 --- a/cups/adminutil.h +++ b/cups/adminutil.h @@ -8,7 +8,7 @@ * 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/". + * missing or damaged, see the license at "http://www.cups.org/". * * This file is subject to the Apple OS-Developed Software exception. */ diff --git a/cups/api-filter.shtml b/cups/api-filter.shtml index 1b8f6f3..bd90333 100644 --- a/cups/api-filter.shtml +++ b/cups/api-filter.shtml @@ -94,7 +94,7 @@ being printed.

Filters and backends may also receive SIGPIPE when an upstream or downstream filter/backend exits with a non-zero status. Developers should generally ignore SIGPIPE at the beginning of main() with the following function call:

-#include <signal.h>>
+#include <signal.h>
 
 ...
 
diff --git a/cups/array-private.h b/cups/array-private.h
index c563e25..ff083e4 100644
--- a/cups/array-private.h
+++ b/cups/array-private.h
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/array.c b/cups/array.c
index b8bec27..dee4f5e 100644
--- a/cups/array.c
+++ b/cups/array.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/array.h b/cups/array.h
index c747831..189c6e1 100644
--- a/cups/array.h
+++ b/cups/array.h
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/auth.c b/cups/auth.c
index f9187ff..c051c86 100644
--- a/cups/auth.c
+++ b/cups/auth.c
@@ -1,7 +1,7 @@
 /*
  * Authentication functions for CUPS.
  *
- * Copyright 2007-2014 by Apple Inc.
+ * Copyright 2007-2016 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products.
  *
  * This file contains Kerberos support code, copyright 2006 by
@@ -11,7 +11,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -54,7 +54,7 @@ extern const char *cssmErrorString(int error);
 #    else
 #      define GSS_AUTH_IDENTITY_TYPE_1 1
 #      define gss_acquire_cred_ex_f __ApplePrivate_gss_acquire_cred_ex_f
-typedef struct gss_auth_identity
+typedef struct gss_auth_identity /* @private@ */
 {
   uint32_t type;
   uint32_t flags;
@@ -386,10 +386,7 @@ _cupsSetNegotiateAuthString(
 
     if (data.sem)
     {
-      major_status = gss_acquire_cred_ex_f(NULL, GSS_C_NO_NAME, 0,
-				           GSS_C_INDEFINITE, GSS_KRB5_MECHANISM,
-					   GSS_C_INITIATE, &identity, &data,
-					   cups_gss_acquire);
+      major_status = gss_acquire_cred_ex_f(NULL, GSS_C_NO_NAME, 0, GSS_C_INDEFINITE, GSS_KRB5_MECHANISM, GSS_C_INITIATE, (gss_auth_identity_t)&identity, &data, cups_gss_acquire);
 
       if (major_status == GSS_S_COMPLETE)
       {
diff --git a/cups/backchannel.c b/cups/backchannel.c
index 13a9560..e804d45 100644
--- a/cups/backchannel.c
+++ b/cups/backchannel.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/backend.c b/cups/backend.c
index a21ee38..f164617 100644
--- a/cups/backend.c
+++ b/cups/backend.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/backend.h b/cups/backend.h
index 709fd6e..274bcd4 100644
--- a/cups/backend.h
+++ b/cups/backend.h
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/cups-private.h b/cups/cups-private.h
index 998aeec..6fd66a9 100644
--- a/cups/cups-private.h
+++ b/cups/cups-private.h
@@ -1,14 +1,14 @@
 /*
  * Private definitions for CUPS.
  *
- * Copyright 2007-2015 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -105,7 +105,7 @@ typedef struct _cups_globals_s		/**** CUPS global state data ****/
   int			need_res_init;	/* Need to reinitialize resolver? */
 
   /* ipp.c */
-  ipp_uchar_t		ipp_date[11];	/* RFC-1903 date/time data */
+  ipp_uchar_t		ipp_date[11];	/* RFC-2579 date/time data */
   _cups_buffer_t	*cups_buffers;	/* Buffer list */
 
   /* ipp-support.c */
@@ -124,7 +124,8 @@ typedef struct _cups_globals_s		/**** CUPS global state data ****/
 			*ppd_size_lut,	/* Lookup table for PPD names */
 			*pwg_size_lut;	/* Lookup table for PWG names */
   pwg_media_t		pwg_media;	/* PWG media data for custom size */
-  char			pwg_name[65];	/* PWG media name for custom size */
+  char			pwg_name[65],	/* PWG media name for custom size */
+			ppd_name[41];	/* PPD media name for custom size */
 
   /* request.c */
   http_t		*http;		/* Current server connection */
diff --git a/cups/cups.h b/cups/cups.h
index cef5697..a73cf7a 100644
--- a/cups/cups.h
+++ b/cups/cups.h
@@ -1,14 +1,14 @@
 /*
  * API definitions for CUPS.
  *
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -47,10 +47,10 @@ extern "C" {
  * Constants...
  */
 
-#  define CUPS_VERSION			2.0201
+#  define CUPS_VERSION			2.0204
 #  define CUPS_VERSION_MAJOR		2
 #  define CUPS_VERSION_MINOR		2
-#  define CUPS_VERSION_PATCH		1
+#  define CUPS_VERSION_PATCH		4
 
 #  define CUPS_BC_FD			3
 					/* Back-channel file descriptor for
@@ -78,7 +78,7 @@ extern "C" {
 #  define CUPS_DEST_FLAGS_NONE		0x00
 					/* No flags are set */
 #  define CUPS_DEST_FLAGS_UNCONNECTED	0x01
-					/* There is not connection */
+					/* There is no connection */
 #  define CUPS_DEST_FLAGS_MORE		0x02
 					/* There are more destinations */
 #  define CUPS_DEST_FLAGS_REMOVED	0x04
@@ -92,6 +92,8 @@ extern "C" {
 					/* A connection is being established */
 #  define CUPS_DEST_FLAGS_CANCELED	0x40
 					/* Operation was canceled */
+#  define CUPS_DEST_FLAGS_DEVICE        0x80
+                                        /* For @link cupsConnectDest@: Connect to device */
 
 /* Flags for cupsGetDestMediaByName/Size */
 #  define CUPS_MEDIA_FLAGS_DEFAULT 	0x00
@@ -207,39 +209,37 @@ enum cups_ptype_e			/* Printer type/capability bit
   CUPS_PRINTER_REMOTE = 0x0002,		/* Remote printer or class */
   CUPS_PRINTER_BW = 0x0004,		/* Can do B&W printing */
   CUPS_PRINTER_COLOR = 0x0008,		/* Can do color printing */
-  CUPS_PRINTER_DUPLEX = 0x0010,		/* Can do duplexing */
+  CUPS_PRINTER_DUPLEX = 0x0010,		/* Can do two-sided printing */
   CUPS_PRINTER_STAPLE = 0x0020,		/* Can staple output */
-  CUPS_PRINTER_COPIES = 0x0040,		/* Can do copies */
-  CUPS_PRINTER_COLLATE = 0x0080,	/* Can collage copies */
+  CUPS_PRINTER_COPIES = 0x0040,		/* Can do copies in hardware */
+  CUPS_PRINTER_COLLATE = 0x0080,	/* Can quickly collate copies */
   CUPS_PRINTER_PUNCH = 0x0100,		/* Can punch output */
   CUPS_PRINTER_COVER = 0x0200,		/* Can cover output */
   CUPS_PRINTER_BIND = 0x0400,		/* Can bind output */
   CUPS_PRINTER_SORT = 0x0800,		/* Can sort output */
-  CUPS_PRINTER_SMALL = 0x1000,		/* Can do Letter/Legal/A4 */
-  CUPS_PRINTER_MEDIUM = 0x2000,		/* Can do Tabloid/B/C/A3/A2 */
-  CUPS_PRINTER_LARGE = 0x4000,		/* Can do D/E/A1/A0 */
-  CUPS_PRINTER_VARIABLE = 0x8000,	/* Can do variable sizes */
+  CUPS_PRINTER_SMALL = 0x1000,		/* Can print on Letter/Legal/A4-size media */
+  CUPS_PRINTER_MEDIUM = 0x2000,		/* Can print on Tabloid/B/C/A3/A2-size media */
+  CUPS_PRINTER_LARGE = 0x4000,		/* Can print on D/E/A1/A0-size media */
+  CUPS_PRINTER_VARIABLE = 0x8000,	/* Can print on rolls and custom-size media */
   CUPS_PRINTER_IMPLICIT = 0x10000,	/* Implicit class @private@
 					 * @since Deprecated@ */
   CUPS_PRINTER_DEFAULT = 0x20000,	/* Default printer on network */
   CUPS_PRINTER_FAX = 0x40000,		/* Fax queue */
   CUPS_PRINTER_REJECTING = 0x80000,	/* Printer is rejecting jobs */
   CUPS_PRINTER_DELETE = 0x100000,	/* Delete printer
-					 * @since CUPS 1.2/macOS 10.5@ */
+					 * @deprecated@ @exclude all@ */
   CUPS_PRINTER_NOT_SHARED = 0x200000,	/* Printer is not shared
 					 * @since CUPS 1.2/macOS 10.5@ */
   CUPS_PRINTER_AUTHENTICATED = 0x400000,/* Printer requires authentication
 					 * @since CUPS 1.2/macOS 10.5@ */
   CUPS_PRINTER_COMMANDS = 0x800000,	/* Printer supports maintenance commands
 					 * @since CUPS 1.2/macOS 10.5@ */
-  CUPS_PRINTER_DISCOVERED = 0x1000000,	/* Printer was automatically discovered
-					 * and added @private@
-					 * @since Deprecated@ */
+  CUPS_PRINTER_DISCOVERED = 0x1000000,	/* Printer was discovered @since CUPS 1.2/macOS 10.5@ */
   CUPS_PRINTER_SCANNER = 0x2000000,	/* Scanner-only device
-					 * @since CUPS 1.4/macOS 10.6@ */
+					 * @since CUPS 1.4/macOS 10.6@ @private@ */
   CUPS_PRINTER_MFP = 0x4000000,		/* Printer with scanning capabilities
-					 * @since CUPS 1.4/macOS 10.6@ */
-  CUPS_PRINTER_3D = 0x8000000,		/* Printer with 3D capabilities @since CUPS 2.1@ */
+					 * @since CUPS 1.4/macOS 10.6@ @private@ */
+  CUPS_PRINTER_3D = 0x8000000,		/* Printer with 3D capabilities @exclude all@ @private@ */
   CUPS_PRINTER_OPTIONS = 0x6fffc	/* ~(CLASS | REMOTE | IMPLICIT |
 					 * DEFAULT | FAX | REJECTING | DELETE |
 					 * NOT_SHARED | AUTHENTICATED |
@@ -270,7 +270,7 @@ typedef struct cups_job_s		/**** Job ****/
   int		id;			/* The job ID */
   char		*dest;			/* Printer or class name */
   char		*title;			/* Title/job name */
-  char		*user;			/* User the submitted the job */
+  char		*user;			/* User that submitted the job */
   char		*format;		/* Document format */
   ipp_jstate_t	state;			/* Job state */
   int		size;			/* Size in kilobytes */
@@ -310,11 +310,12 @@ typedef int (*cups_dest_cb_t)(void *user_data, unsigned flags,
 #  ifdef __BLOCKS__
 typedef int (^cups_dest_block_t)(unsigned flags, cups_dest_t *dest);
 			      		/* Destination enumeration block
-					 * @since CUPS 1.6/macOS 10.8@ */
+					 * @since CUPS 1.6/macOS 10.8@
+                                         * @exclude all@ */
 #  endif /* __BLOCKS__ */
 
 typedef const char *(*cups_password_cb_t)(const char *prompt);
-					/* Password callback */
+					/* Password callback @exclude all@ */
 
 typedef const char *(*cups_password_cb2_t)(const char *prompt, http_t *http,
 					   const char *method,
@@ -341,11 +342,11 @@ extern ipp_t		*cupsDoRequest(http_t *http, ipp_t *request,
 			               const char *resource);
 extern http_encryption_t cupsEncryption(void);
 extern void		cupsFreeJobs(int num_jobs, cups_job_t *jobs);
-extern int		cupsGetClasses(char ***classes) _CUPS_DEPRECATED_MSG("Use cupsGetDests instead.");
+extern int		cupsGetClasses(char ***classes) _CUPS_DEPRECATED_MSG("Use cupsEnumDests instead.");
 extern const char	*cupsGetDefault(void);
 extern int		cupsGetJobs(cups_job_t **jobs, const char *name,
 			            int myjobs, int whichjobs);
-extern int		cupsGetPrinters(char ***printers) _CUPS_DEPRECATED_MSG("Use cupsGetDests instead.");
+extern int		cupsGetPrinters(char ***printers) _CUPS_DEPRECATED_MSG("Use cupsEnumDests instead.");
 extern ipp_status_t	cupsLastError(void);
 extern int		cupsPrintFile(const char *name, const char *filename,
 			              const char *title, int num_options,
@@ -601,6 +602,10 @@ extern int		cupsSetServerCredentials(const char *path, const char *common_name,
 /* New in CUPS 2.2/macOS 10.12 */
 extern ssize_t		cupsHashData(const char *algorithm, const void *data, size_t datalen, unsigned char *hash, size_t hashsize) _CUPS_API_2_2;
 
+/* New in CUPS 2.2.4 */
+extern int		cupsAddIntegerOption(const char *name, int value, int num_options, cups_option_t **options) _CUPS_API_2_2_4;
+extern int		cupsGetIntegerOption(const char *name, int num_options, cups_option_t *options) _CUPS_API_2_2_4;
+
 #  ifdef __cplusplus
 }
 #  endif /* __cplusplus */
diff --git a/cups/debug-private.h b/cups/debug-private.h
index 8d9861c..23a0ae1 100644
--- a/cups/debug-private.h
+++ b/cups/debug-private.h
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/debug.c b/cups/debug.c
index a25e4b1..bd244fe 100644
--- a/cups/debug.c
+++ b/cups/debug.c
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/dest-job.c b/cups/dest-job.c
index 146887e..f12b1dc 100644
--- a/cups/dest-job.c
+++ b/cups/dest-job.c
@@ -1,13 +1,13 @@
 /*
  * Destination job support for CUPS.
  *
- * Copyright 2012-2016 by Apple Inc.
+ * Copyright 2012-2017 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -25,13 +25,13 @@
  * The "job_id" is the number returned by cupsCreateDestJob.
  *
  * Returns @code IPP_STATUS_OK@ on success and
- * @code IPP_STATUS_ERRPR_NOT_AUTHORIZED@ or
+ * @code IPP_STATUS_ERROR_NOT_AUTHORIZED@ or
  * @code IPP_STATUS_ERROR_FORBIDDEN@ on failure.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
 
-ipp_status_t
+ipp_status_t                            /* O - Status of cancel operation */
 cupsCancelDestJob(http_t      *http,	/* I - Connection to destination */
                   cups_dest_t *dest,	/* I - Destination */
                   int         job_id)	/* I - Job ID */
@@ -83,6 +83,13 @@ cupsCloseDestJob(
 
   DEBUG_printf(("cupsCloseDestJob(http=%p, dest=%p(%s/%s), info=%p, job_id=%d)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info, job_id));
 
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
@@ -171,6 +178,13 @@ cupsCreateDestJob(
   DEBUG_printf(("cupsCreateDestJob(http=%p, dest=%p(%s/%s), info=%p, "
                 "job_id=%p, title=\"%s\", num_options=%d, options=%p)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info, (void *)job_id, title, num_options, (void *)options));
 
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
@@ -251,6 +265,13 @@ cupsFinishDestDocument(
 {
   DEBUG_printf(("cupsFinishDestDocument(http=%p, dest=%p(%s/%s), info=%p)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info));
 
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
@@ -306,6 +327,13 @@ cupsStartDestDocument(
 
   DEBUG_printf(("cupsStartDestDocument(http=%p, dest=%p(%s/%s), info=%p, job_id=%d, docname=\"%s\", format=\"%s\", num_options=%d, options=%p, last_document=%d)", (void *)http, (void *)dest, dest ? dest->name : NULL, dest ? dest->instance : NULL, (void *)info, job_id, docname, format, num_options, (void *)options, last_document));
 
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
diff --git a/cups/dest-localization.c b/cups/dest-localization.c
index 6358b6d..6d75a97 100644
--- a/cups/dest-localization.c
+++ b/cups/dest-localization.c
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/dest-options.c b/cups/dest-options.c
index fc3fd35..51705a5 100644
--- a/cups/dest-options.c
+++ b/cups/dest-options.c
@@ -1,13 +1,13 @@
 /*
  * Destination option/media support for CUPS.
  *
- * Copyright 2012-2016 by Apple Inc.
+ * Copyright 2012-2017 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -73,7 +73,7 @@ cupsCheckDestSupported(
     cups_dest_t  *dest,			/* I - Destination */
     cups_dinfo_t *dinfo,		/* I - Destination information */
     const char   *option,		/* I - Option */
-    const char   *value)		/* I - Value */
+    const char   *value)		/* I - Value or @code NULL@ */
 {
   int			i;		/* Looping var */
   char			temp[1024];	/* Temporary string */
@@ -85,11 +85,18 @@ cupsCheckDestSupported(
   _ipp_value_t		*attrval;	/* Current attribute value */
 
 
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
 
-  if (!http || !dest || !dinfo || !option || !value)
+  if (!http || !dest || !dinfo || !option)
     return (0);
 
  /*
@@ -107,7 +114,10 @@ cupsCheckDestSupported(
   if (!attr)
     return (0);
 
- /*
+  if (!value)
+    return (1);
+
+/*
   * Compare values...
   */
 
@@ -315,6 +325,13 @@ cupsCopyDestConflicts(
   if (resolved)
     *resolved = NULL;
 
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
@@ -574,6 +591,13 @@ cupsCopyDestInfo(
 
   DEBUG_printf(("cupsCopyDestSupported(http=%p, dest=%p(%s))", (void *)http, (void *)dest, dest ? dest->name : ""));
 
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
@@ -685,6 +709,13 @@ cupsFindDestDefault(
   char	name[IPP_MAX_NAME];		/* Attribute name */
 
 
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
@@ -726,6 +757,13 @@ cupsFindDestReady(
   char	name[IPP_MAX_NAME];		/* Attribute name */
 
 
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
@@ -769,6 +807,13 @@ cupsFindDestSupported(
   char	name[IPP_MAX_NAME];		/* Attribute name */
 
 
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
@@ -791,6 +836,8 @@ cupsFindDestSupported(
 /*
  * 'cupsFreeDestInfo()' - Free destination information obtained using
  *                        @link cupsCopyDestInfo@.
+ *
+ * @since CUPS 1.6/macOS 10.8@
  */
 
 void
@@ -851,6 +898,13 @@ cupsGetDestMediaByIndex(
   pwg_media_t		*pwg;		/* PWG media name for size */
 
 
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
@@ -939,6 +993,13 @@ cupsGetDestMediaByName(
   pwg_media_t		*pwg;		/* PWG media info */
 
 
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
@@ -1007,6 +1068,13 @@ cupsGetDestMediaBySize(
   pwg_media_t		*pwg;		/* PWG media info */
 
 
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
@@ -1058,6 +1126,13 @@ cupsGetDestMediaCount(
     cups_dinfo_t *dinfo,		/* I - Destination information */
     unsigned     flags)			/* I - Media flags */
 {
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
@@ -1103,6 +1178,13 @@ cupsGetDestMediaDefault(
   const char	*media;			/* Default media size */
 
 
+ /*
+  * Get the default connection as needed...
+  */
+
+  if (!http)
+    http = _cupsConnect();
+
  /*
   * Range check input...
   */
diff --git a/cups/dest.c b/cups/dest.c
index cd7529c..fc57ed3 100644
--- a/cups/dest.c
+++ b/cups/dest.c
@@ -1,14 +1,14 @@
 /*
  * User-defined destination (and option) support for CUPS.
  *
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -60,6 +60,10 @@
 #  define kUseLastPrinter	CFSTR("UseLastPrinter")
 #endif /* __APPLE__ */
 
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+#  define _CUPS_DNSSD_MAXTIME	500	/* Milliseconds for maximum quantum of time */
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
+
 
 /*
  * Types...
@@ -85,6 +89,7 @@ typedef struct _cups_dnssd_data_s	/* Enumeration data */
   AvahiSimplePoll	*simple_poll;	/* Polling interface */
   AvahiClient		*client;	/* Client information */
   int			got_data;	/* Did we get data? */
+  int			browsers;	/* How many browsers are running? */
 #  endif /* HAVE_DNSSD */
   cups_dest_cb_t	cb;		/* Callback */
   void			*user_data;	/* User data pointer */
@@ -101,9 +106,9 @@ typedef struct _cups_dnssd_device_s	/* Enumerated device */
 #  else /* HAVE_AVAHI */
   AvahiRecordBrowser	*ref;		/* Browser for query */
 #  endif /* HAVE_DNSSD */
-  char			*domain,	/* Domain name */
-			*fullName,	/* Full name */
-			*regtype;	/* Registration type */
+  char			*fullName,	/* Full name */
+			*regtype,	/* Registration type */
+			*domain;	/* Domain name */
   cups_ptype_t		type;		/* Device registration type */
   cups_dest_t		dest;		/* Destination record */
 } _cups_dnssd_device_t;
@@ -115,6 +120,18 @@ typedef struct _cups_dnssd_resolve_s	/* Data for resolving URI */
 } _cups_dnssd_resolve_t;
 #endif /* HAVE_DNSSD */
 
+typedef struct _cups_getdata_s
+{
+  int         num_dests;                /* Number of destinations */
+  cups_dest_t *dests;                   /* Destinations */
+} _cups_getdata_t;
+
+typedef struct _cups_namedata_s
+{
+  const char  *name;                    /* Named destination */
+  cups_dest_t *dest;                    /* Destination */
+} _cups_namedata_t;
+
 
 /*
  * Local functions...
@@ -208,10 +225,12 @@ static const char	*cups_dnssd_resolve(cups_dest_t *dest, const char *uri,
 static int		cups_dnssd_resolve_cb(void *context);
 static void		cups_dnssd_unquote(char *dst, const char *src,
 			                   size_t dstsize);
+static int		cups_elapsed(struct timeval *t);
 #endif /* HAVE_DNSSD || HAVE_AVAHI */
 static int		cups_find_dest(const char *name, const char *instance,
 				       int num_dests, cups_dest_t *dests, int prev,
 				       int *rdiff);
+static int              cups_get_cb(_cups_getdata_t *data, unsigned flags, cups_dest_t *dest);
 static char		*cups_get_default(const char *filename, char *namebuf,
 					  size_t namesize, const char **instance);
 static int		cups_get_dests(const char *filename, const char *match_name,
@@ -219,6 +238,8 @@ static int		cups_get_dests(const char *filename, const char *match_name,
 				       int num_dests, cups_dest_t **dests);
 static char		*cups_make_string(ipp_attribute_t *attr, char *buffer,
 			                  size_t bufsize);
+static int              cups_name_cb(_cups_namedata_t *data, unsigned flags, cups_dest_t *dest);
+static void		cups_queue_name(char *name, const char *serviceName, size_t namesize);
 
 
 /*
@@ -549,18 +570,24 @@ _cupsAppleSetUseLastPrinter(
 
 
 /*
- * 'cupsConnectDest()' - Connect to the server for a destination.
+ * 'cupsConnectDest()' - Open a conection to the destination.
  *
- * Connect to the destination, returning a new http_t connection object and
- * optionally the resource path to use for the destination.  These calls will
- * block until a connection is made, the timeout expires, the integer pointed
- * to by "cancel" is non-zero, or the callback function (or block) returns 0,
- * The caller is responsible for calling httpClose() on the returned object.
+ * Connect to the destination, returning a new @code http_t@ connection object
+ * and optionally the resource path to use for the destination.  These calls
+ * will block until a connection is made, the timeout expires, the integer
+ * pointed to by "cancel" is non-zero, or the callback function (or block)
+ * returns 0.  The caller is responsible for calling @link httpClose@ on the
+ * returned connection.
+ *
+ * Starting with CUPS 2.2.4, the caller can pass  @code CUPS_DEST_FLAGS_DEVICE@
+ * for the "flags" argument to connect directly to the device associated with
+ * the destination.  Otherwise, the connection is made to the CUPS scheduler
+ * associated with the destination.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
 
-http_t *				/* O - Connection to server or @code NULL@ */
+http_t *				/* O - Connection to destination or @code NULL@ */
 cupsConnectDest(
     cups_dest_t    *dest,		/* I - Destination */
     unsigned       flags,		/* I - Connection flags */
@@ -608,17 +635,24 @@ cupsConnectDest(
   * Grab the printer URI...
   */
 
-  if ((uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options)) == NULL)
+  if (flags & CUPS_DEST_FLAGS_DEVICE)
   {
-    if ((uri = cupsGetOption("resolved-device-uri", dest->num_options, dest->options)) == NULL)
+    if ((uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL)
     {
-      if ((uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL)
-      {
 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
-        if (strstr(uri, "._tcp"))
-          uri = cups_dnssd_resolve(dest, uri, msec, cancel, cb, user_data);
+      if (strstr(uri, "._tcp"))
+        uri = cups_dnssd_resolve(dest, uri, msec, cancel, cb, user_data);
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
+    }
+  }
+  else if ((uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options)) == NULL)
+  {
+    if ((uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL)
+    {
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+      if (strstr(uri, "._tcp"))
+        uri = cups_dnssd_resolve(dest, uri, msec, cancel, cb, user_data);
 #endif /* HAVE_DNSSD || HAVE_AVAHI */
-      }
     }
 
     if (uri)
@@ -725,18 +759,23 @@ cupsConnectDest(
 
 #ifdef __BLOCKS__
 /*
- * 'cupsConnectDestBlock()' - Connect to the server for a destination.
+ * 'cupsConnectDestBlock()' - Open a connection to the destination.
  *
- * Connect to the destination, returning a new http_t connection object and
- * optionally the resource path to use for the destination.  These calls will
- * block until a connection is made, the timeout expires, the integer pointed
- * to by "cancel" is non-zero, or the callback function (or block) returns 0,
- * The caller is responsible for calling httpClose() on the returned object.
+ * Connect to the destination, returning a new @code http_t@ connection object
+ * and optionally the resource path to use for the destination.  These calls
+ * will block until a connection is made, the timeout expires, the integer
+ * pointed to by "cancel" is non-zero, or the block returns 0.  The caller is
+ * responsible for calling @link httpClose@ on the returned connection.
  *
- * @since CUPS 1.6/macOS 10.8@
+ * Starting with CUPS 2.2.4, the caller can pass  @code CUPS_DEST_FLAGS_DEVICE@
+ * for the "flags" argument to connect directly to the device associated with
+ * the destination.  Otherwise, the connection is made to the CUPS scheduler
+ * associated with the destination.
+ *
+ * @since CUPS 1.6/macOS 10.8@ @exclude all@
  */
 
-http_t *				/* O - Connection to server or @code NULL@ */
+http_t *				/* O - Connection to destination or @code NULL@ */
 cupsConnectDestBlock(
     cups_dest_t       *dest,		/* I - Destination */
     unsigned          flags,		/* I - Connection flags */
@@ -762,10 +801,10 @@ cupsConnectDestBlock(
  * @since CUPS 1.6/macOS 10.8@
  */
 
-int
-cupsCopyDest(cups_dest_t *dest,
-             int         num_dests,
-             cups_dest_t **dests)
+int                                     /* O  - New number of destinations */
+cupsCopyDest(cups_dest_t *dest,         /* I  - Destination to copy */
+             int         num_dests,     /* I  - Number of destinations */
+             cups_dest_t **dests)       /* IO - Destination array */
 {
   int		i;			/* Looping var */
   cups_dest_t	*new_dest;		/* New destination pointer */
@@ -907,27 +946,34 @@ _cupsCreateDest(const char *name,	/* I - Printer name */
 /*
  * 'cupsEnumDests()' - Enumerate available destinations with a callback function.
  *
- * Destinations are enumerated from one or more sources. The callback function
- * receives the @code user_data@ pointer, destination name, instance, number of
- * options, and options which can be used as input to the @link cupsAddDest@
- * function.  The function must return 1 to continue enumeration or 0 to stop.
+ * Destinations are enumerated from one or more sources.  The callback function
+ * receives the @code user_data@ pointer and the destination pointer which can
+ * be used as input to the @link cupsCopyDest@ function.  The function must
+ * return 1 to continue enumeration or 0 to stop.
+ *
+ * The @code type@ and @code mask@ arguments allow the caller to filter the
+ * destinations that are enumerated.  Passing 0 for both will enumerate all
+ * printers.  The constant @code CUPS_PRINTER_DISCOVERED@ is used to filter on
+ * destinations that are available but have not yet been added locally.
  *
  * Enumeration happens on the current thread and does not return until all
  * destinations have been enumerated or the callback function returns 0.
  *
+ * Note: The callback function will likely receive multiple updates for the same
+ * destinations - it is up to the caller to suppress any duplicate destinations.
+ *
  * @since CUPS 1.6/macOS 10.8@
  */
 
 int					/* O - 1 on success, 0 on failure */
 cupsEnumDests(
-    unsigned       flags,		/* I - Enumeration flags */
-    int            msec,		/* I - Timeout in milliseconds,
-					 *     -1 for indefinite */
-    int            *cancel,		/* I - Pointer to "cancel" variable */
-    cups_ptype_t   type,		/* I - Printer type bits */
-    cups_ptype_t   mask,		/* I - Mask for printer type bits */
-    cups_dest_cb_t cb,			/* I - Callback function */
-    void           *user_data)		/* I - User data */
+  unsigned       flags,			/* I - Enumeration flags */
+  int            msec,			/* I - Timeout in milliseconds, -1 for indefinite */
+  int            *cancel,		/* I - Pointer to "cancel" variable */
+  cups_ptype_t   type,			/* I - Printer type bits */
+  cups_ptype_t   mask,			/* I - Mask for printer type bits */
+  cups_dest_cb_t cb,			/* I - Callback function */
+  void           *user_data)		/* I - User data */
 {
   int			i,		/* Looping var */
 			num_dests;	/* Number of destinations */
@@ -939,17 +985,19 @@ cupsEnumDests(
 			*user_default;	/* User default printer */
 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   int			count,		/* Number of queries started */
+			completed,	/* Number of completed queries */
 			remaining;	/* Remainder of timeout */
+  struct timeval	curtime;	/* Current time */
   _cups_dnssd_data_t	data;		/* Data for callback */
   _cups_dnssd_device_t	*device;	/* Current device */
 #  ifdef HAVE_DNSSD
   int			nfds,		/* Number of files responded */
 			main_fd;	/* File descriptor for lookups */
-  DNSServiceRef		ipp_ref,	/* IPP browser */
-			local_ipp_ref;	/* Local IPP browser */
+  DNSServiceRef		ipp_ref = NULL,	/* IPP browser */
+			local_ipp_ref = NULL; /* Local IPP browser */
 #    ifdef HAVE_SSL
-  DNSServiceRef		ipps_ref,	/* IPPS browser */
-			local_ipps_ref;	/* Local IPPS browser */
+  DNSServiceRef		ipps_ref = NULL,/* IPPS browser */
+			local_ipps_ref = NULL; /* Local IPPS browser */
 #    endif /* HAVE_SSL */
 #    ifdef HAVE_POLL
   struct pollfd		pfd;		/* Polling data */
@@ -959,13 +1007,14 @@ cupsEnumDests(
 #    endif /* HAVE_POLL */
 #  else /* HAVE_AVAHI */
   int			error;		/* Error value */
-  AvahiServiceBrowser	*ipp_ref;	/* IPP browser */
+  AvahiServiceBrowser	*ipp_ref = NULL;/* IPP browser */
 #    ifdef HAVE_SSL
-  AvahiServiceBrowser	*ipps_ref;	/* IPPS browser */
+  AvahiServiceBrowser	*ipps_ref = NULL; /* IPPS browser */
 #    endif /* HAVE_SSL */
 #  endif /* HAVE_DNSSD */
 #endif /* HAVE_DNSSD || HAVE_AVAHI */
 
+
  /*
   * Range check input...
   */
@@ -976,59 +1025,119 @@ cupsEnumDests(
     return (0);
 
  /*
-  * Get the list of local printers and pass them to the callback function...
+  * Get ready to enumerate...
   */
 
-  num_dests = _cupsGetDests(CUPS_HTTP_DEFAULT, IPP_OP_CUPS_GET_PRINTERS, NULL,
-                            &dests, type, mask | CUPS_PRINTER_3D);
-
-  if ((user_default = _cupsUserDefault(name, sizeof(name))) != NULL)
-    defprinter = name;
-  else if ((defprinter = cupsGetDefault2(CUPS_HTTP_DEFAULT)) != NULL)
-  {
-    strlcpy(name, defprinter, sizeof(name));
-    defprinter = name;
-  }
-
-  if (defprinter)
-  {
-   /*
-    * Separate printer and instance name...
-    */
-
-    if ((instance = strchr(name, '/')) != NULL)
-      *instance++ = '\0';
-
-   /*
-    * Lookup the printer and instance and make it the default...
-    */
-
-    if ((dest = cupsGetDest(name, instance, num_dests, dests)) != NULL)
-      dest->is_default = 1;
-  }
-
-  for (i = num_dests, dest = dests;
-       i > 0 && (!cancel || !*cancel);
-       i --, dest ++)
-    if (!(*cb)(user_data, i > 1 ? CUPS_DEST_FLAGS_MORE : CUPS_DEST_FLAGS_NONE,
-               dest))
-      break;
-
-  cupsFreeDests(num_dests, dests);
-
-  if (i > 0 || msec == 0)
-    return (1);
-
 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
- /*
-  * Get Bonjour-shared printers...
-  */
+  memset(&data, 0, sizeof(data));
 
   data.type      = type;
   data.mask      = mask;
   data.cb        = cb;
   data.user_data = user_data;
   data.devices   = cupsArrayNew3((cups_array_func_t)cups_dnssd_compare_devices, NULL, NULL, 0, NULL, (cups_afree_func_t)cups_dnssd_free_device);
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
+
+  if (!(mask & CUPS_PRINTER_DISCOVERED) || !(type & CUPS_PRINTER_DISCOVERED))
+  {
+   /*
+    * Get the list of local printers and pass them to the callback function...
+    */
+
+    num_dests = _cupsGetDests(CUPS_HTTP_DEFAULT, IPP_OP_CUPS_GET_PRINTERS, NULL,
+                              &dests, type, mask);
+
+    if ((user_default = _cupsUserDefault(name, sizeof(name))) != NULL)
+      defprinter = name;
+    else if ((defprinter = cupsGetDefault2(CUPS_HTTP_DEFAULT)) != NULL)
+    {
+      strlcpy(name, defprinter, sizeof(name));
+      defprinter = name;
+    }
+
+    if (defprinter)
+    {
+     /*
+      * Separate printer and instance name...
+      */
+
+      if ((instance = strchr(name, '/')) != NULL)
+        *instance++ = '\0';
+
+     /*
+      * Lookup the printer and instance and make it the default...
+      */
+
+      if ((dest = cupsGetDest(name, instance, num_dests, dests)) != NULL)
+        dest->is_default = 1;
+    }
+
+    for (i = num_dests, dest = dests;
+         i > 0 && (!cancel || !*cancel);
+         i --, dest ++)
+    {
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+      const char *device_uri;		/* Device URI */
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
+
+      if (!(*cb)(user_data, i > 1 ? CUPS_DEST_FLAGS_MORE : CUPS_DEST_FLAGS_NONE,
+                 dest))
+        break;
+
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+      if (!dest->instance && (device_uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL && !strncmp(device_uri, "dnssd://", 8))
+      {
+       /*
+        * Add existing queue using service name, etc. so we don't list it again...
+        */
+
+        char	scheme[32],		/* URI scheme */
+                userpass[32],           /* Username:password */
+                serviceName[256],       /* Service name (host field) */
+                resource[256],          /* Resource (options) */
+                *regtype,               /* Registration type */
+                *replyDomain;           /* Registration domain */
+        int	port;			/* Port number (not used) */
+
+        if (httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), serviceName, sizeof(serviceName), &port, resource, sizeof(resource)) >= HTTP_URI_STATUS_OK)
+        {
+          if ((regtype = strstr(serviceName, "._ipp")) != NULL)
+          {
+            *regtype++ = '\0';
+
+            if ((replyDomain = strstr(regtype, "._tcp.")) != NULL)
+            {
+              replyDomain[5] = '\0';
+              replyDomain += 6;
+
+              if ((device = cups_dnssd_get_device(&data, serviceName, regtype, replyDomain)) != NULL)
+                device->state = _CUPS_DNSSD_ACTIVE;
+            }
+          }
+        }
+      }
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
+    }
+
+    cupsFreeDests(num_dests, dests);
+
+    if (i > 0 || msec == 0)
+      goto enum_finished;
+  }
+
+ /*
+  * Return early if the caller doesn't want to do discovery...
+  */
+
+  if ((mask & CUPS_PRINTER_DISCOVERED) && !(type & CUPS_PRINTER_DISCOVERED))
+    goto enum_finished;
+
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+ /*
+  * Get Bonjour-shared printers...
+  */
+
+  gettimeofday(&curtime, NULL);
 
 #  ifdef HAVE_DNSSD
   if (DNSServiceCreateConnection(&data.main_ref) != kDNSServiceErr_NoError)
@@ -1079,13 +1188,12 @@ cupsEnumDests(
     return (1);
   }
 
-  ipp_ref  = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC,
-				       AVAHI_PROTO_UNSPEC, "_ipp._tcp", NULL,
-				       0, cups_dnssd_browse_cb, &data);
+  data.browsers = 1;
+  ipp_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_ipp._tcp", NULL, 0, cups_dnssd_browse_cb, &data);
+
 #    ifdef HAVE_SSL
-  ipps_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC,
-			               AVAHI_PROTO_UNSPEC, "_ipps._tcp", NULL,
-			               0, cups_dnssd_browse_cb, &data);
+  data.browsers ++;
+  ipps_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_ipps._tcp", NULL, 0, cups_dnssd_browse_cb, &data);
 #    endif /* HAVE_SSL */
 #  endif /* HAVE_DNSSD */
 
@@ -1100,32 +1208,34 @@ cupsEnumDests(
     * Check for input...
     */
 
+    DEBUG_printf(("1cupsEnumDests: remaining=%d", remaining));
+
+    cups_elapsed(&curtime);
+
 #  ifdef HAVE_DNSSD
 #    ifdef HAVE_POLL
     pfd.fd     = main_fd;
     pfd.events = POLLIN;
 
-    nfds = poll(&pfd, 1, remaining > 250 ? 250 : remaining);
+    nfds = poll(&pfd, 1, remaining > _CUPS_DNSSD_MAXTIME ? _CUPS_DNSSD_MAXTIME : remaining);
 
 #    else
     FD_ZERO(&input);
     FD_SET(main_fd, &input);
 
     timeout.tv_sec  = 0;
-    timeout.tv_usec = remaining > 250 ? 250000 : remaining * 1000;
+    timeout.tv_usec = 1000 * (remaining > _CUPS_DNSSD_MAXTIME ? _CUPS_DNSSD_MAXTIME : remaining);
 
     nfds = select(main_fd + 1, &input, NULL, NULL, &timeout);
 #    endif /* HAVE_POLL */
 
     if (nfds > 0)
       DNSServiceProcessResult(data.main_ref);
-    else if (nfds == 0)
-      remaining -= 250;
 
 #  else /* HAVE_AVAHI */
     data.got_data = 0;
 
-    if ((error = avahi_simple_poll_iterate(data.simple_poll, 250)) > 0)
+    if ((error = avahi_simple_poll_iterate(data.simple_poll, _CUPS_DNSSD_MAXTIME)) > 0)
     {
      /*
       * We've been told to exit the loop.  Perhaps the connection to
@@ -1135,18 +1245,22 @@ cupsEnumDests(
       break;
     }
 
-    if (!data.got_data)
-      remaining -= 250;
+    DEBUG_printf(("1cupsEnumDests: got_data=%d", data.got_data));
 #  endif /* HAVE_DNSSD */
 
+    remaining -= cups_elapsed(&curtime);
+
     for (device = (_cups_dnssd_device_t *)cupsArrayFirst(data.devices),
-             count = 0;
+             count = 0, completed = 0;
          device;
          device = (_cups_dnssd_device_t *)cupsArrayNext(data.devices))
     {
       if (device->ref)
         count ++;
 
+      if (device->state == _CUPS_DNSSD_ACTIVE)
+        completed ++;
+
       if (!device->ref && device->state == _CUPS_DNSSD_NEW)
       {
 	DEBUG_printf(("1cupsEnumDests: Querying '%s'.", device->fullName));
@@ -1173,31 +1287,28 @@ cupsEnumDests(
 	}
 
 #  else /* HAVE_AVAHI */
-	if ((device->ref = avahi_record_browser_new(data.client,
-	                                            AVAHI_IF_UNSPEC,
-						    AVAHI_PROTO_UNSPEC,
-						    device->fullName,
-						    AVAHI_DNS_CLASS_IN,
-						    AVAHI_DNS_TYPE_TXT,
-						    0,
-						    cups_dnssd_query_cb,
-						    &data)) != NULL)
+	if ((device->ref = avahi_record_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, device->fullName, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT, 0, cups_dnssd_query_cb, &data)) != NULL)
         {
+          DEBUG_printf(("1cupsEnumDests: Query ref=%p", device->ref));
 	  count ++;
 	}
 	else
 	{
 	  device->state = _CUPS_DNSSD_ERROR;
 
-	  DEBUG_printf(("1cupsEnumDests: Query failed: %s",
-	                avahi_strerror(avahi_client_errno(data.client))));
+	  DEBUG_printf(("1cupsEnumDests: Query failed: %s", avahi_strerror(avahi_client_errno(data.client))));
 	}
 #  endif /* HAVE_DNSSD */
       }
       else if (device->ref && device->state == _CUPS_DNSSD_PENDING)
       {
+        completed ++;
+
+        DEBUG_printf(("1cupsEnumDests: Query for \"%s\" is complete.", device->fullName));
+
         if ((device->type & mask) == type)
         {
+	  DEBUG_printf(("1cupsEnumDests: Add callback for \"%s\".", device->dest.name));
 	  if (!(*cb)(user_data, CUPS_DEST_FLAGS_NONE, &device->dest))
 	  {
 	    remaining = -1;
@@ -1208,31 +1319,60 @@ cupsEnumDests(
         device->state = _CUPS_DNSSD_ACTIVE;
       }
     }
-  }
 
+#  ifdef HAVE_AVAHI
+    DEBUG_printf(("1cupsEnumDests: remaining=%d, browsers=%d, completed=%d, count=%d, devices count=%d", remaining, data.browsers, completed, count, cupsArrayCount(data.devices)));
+
+    if (data.browsers == 0 && completed == cupsArrayCount(data.devices))
+      break;
+#  else
+    DEBUG_printf(("1cupsEnumDests: remaining=%d, completed=%d, count=%d, devices count=%d", remaining, completed, count, cupsArrayCount(data.devices)));
+
+    if (completed == cupsArrayCount(data.devices))
+      break;
+#  endif /* HAVE_AVAHI */
+  }
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
+
+ /*
+  * Return...
+  */
+
+  enum_finished:
+
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   cupsArrayDelete(data.devices);
 
 #  ifdef HAVE_DNSSD
-  DNSServiceRefDeallocate(ipp_ref);
-  DNSServiceRefDeallocate(local_ipp_ref);
+  if (ipp_ref)
+    DNSServiceRefDeallocate(ipp_ref);
+  if (local_ipp_ref)
+    DNSServiceRefDeallocate(local_ipp_ref);
 
 #    ifdef HAVE_SSL
-  DNSServiceRefDeallocate(ipp_ref);
-  DNSServiceRefDeallocate(local_ipp_ref);
+  if (ipps_ref)
+    DNSServiceRefDeallocate(ipps_ref);
+  if (local_ipps_ref)
+    DNSServiceRefDeallocate(local_ipps_ref);
 #    endif /* HAVE_SSL */
 
-  DNSServiceRefDeallocate(data.main_ref);
+  if (data.main_ref)
+    DNSServiceRefDeallocate(data.main_ref);
 
 #  else /* HAVE_AVAHI */
-  avahi_service_browser_free(ipp_ref);
+  if (ipp_ref)
+    avahi_service_browser_free(ipp_ref);
 #    ifdef HAVE_SSL
-  avahi_service_browser_free(ipps_ref);
+  if (ipps_ref)
+    avahi_service_browser_free(ipps_ref);
 #    endif /* HAVE_SSL */
 
-  avahi_client_free(data.client);
-  avahi_simple_poll_free(data.simple_poll);
+  if (data.client)
+    avahi_client_free(data.client);
+  if (data.simple_poll)
+    avahi_simple_poll_free(data.simple_poll);
 #  endif /* HAVE_DNSSD */
-#endif /* HAVE_DNSSD || HAVE_DNSSD */
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
 
   return (1);
 }
@@ -1242,15 +1382,23 @@ cupsEnumDests(
 /*
  * 'cupsEnumDestsBlock()' - Enumerate available destinations with a block.
  *
- * Destinations are enumerated from one or more sources. The block receives the
- * destination name, instance, number of options, and options which can be used
- * as input to the @link cupsAddDest@ function.  The block must return 1 to
+ * Destinations are enumerated from one or more sources.  The block receives the
+ * @code user_data@ pointer and the destination pointer which can be used as
+ * input to the @link cupsCopyDest@ function.  The block must return 1 to
  * continue enumeration or 0 to stop.
  *
+ * The @code type@ and @code mask@ arguments allow the caller to filter the
+ * destinations that are enumerated.  Passing 0 for both will enumerate all
+ * printers.  The constant @code CUPS_PRINTER_DISCOVERED@ is used to filter on
+ * destinations that are available but have not yet been added locally.
+ *
  * Enumeration happens on the current thread and does not return until all
  * destinations have been enumerated or the block returns 0.
  *
- * @since CUPS 1.6/macOS 10.8@
+ * Note: The block will likely receive multiple updates for the same
+ * destinations - it is up to the caller to suppress any duplicate destinations.
+ *
+ * @since CUPS 1.6/macOS 10.8@ @exclude all@
  */
 
 int					/* O - 1 on success, 0 on failure */
@@ -1298,7 +1446,7 @@ cupsFreeDests(int         num_dests,	/* I - Number of destinations */
 /*
  * 'cupsGetDest()' - Get the named destination from the list.
  *
- * Use the @link cupsGetDests@ or @link cupsGetDests2@ functions to get a
+ * Use the @link cupsEnumDests@ or @link cupsGetDests2@ functions to get a
  * list of supported destinations for the current user.
  */
 
@@ -1363,6 +1511,8 @@ _cupsGetDestResource(
   int		port;			/* Port number */
 
 
+  DEBUG_printf(("_cupsGetDestResource(dest=%p(%s), resource=%p, resourcesize=%d)", (void *)dest, dest->name, (void *)resource, (int)resourcesize));
+
  /*
   * Range check input...
   */
@@ -1380,34 +1530,59 @@ _cupsGetDestResource(
   * Grab the printer URI...
   */
 
-  if ((uri = cupsGetOption("printer-uri-supported", dest->num_options,
-                           dest->options)) == NULL)
+  if ((uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options)) == NULL)
   {
-    if (resource)
-      *resource = '\0';
+    if ((uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL)
+    {
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+      if (strstr(uri, "._tcp"))
+        uri = cups_dnssd_resolve(dest, uri, 5000, NULL, NULL, NULL);
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
+    }
 
-    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
+    if (uri)
+    {
+      DEBUG_printf(("1_cupsGetDestResource: Resolved printer-uri-supported=\"%s\"", uri));
 
-    return (NULL);
-  }
+      uri = _cupsCreateDest(dest->name, cupsGetOption("printer-info", dest->num_options, dest->options), NULL, uri, resource, resourcesize);
+    }
+
+    if (uri)
+    {
+      DEBUG_printf(("1_cupsGetDestResource: Local printer-uri-supported=\"%s\"", uri));
+
+      dest->num_options = cupsAddOption("printer-uri-supported", uri, dest->num_options, &dest->options);
+
+      uri = cupsGetOption("printer-uri-supported", dest->num_options, dest->options);
+    }
+    else
+    {
+      DEBUG_puts("1_cupsGetDestResource: No printer-uri-supported found.");
+
+      if (resource)
+        *resource = '\0';
+
+      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
 
-#ifdef HAVE_DNSSD
-  if (strstr(uri, "._tcp"))
-  {
-    if ((uri = cups_dnssd_resolve(dest, uri, 5000, NULL, NULL, NULL)) == NULL)
       return (NULL);
+    }
   }
-#endif /* HAVE_DNSSD */
-
-  if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
-                      userpass, sizeof(userpass), hostname, sizeof(hostname),
-                      &port, resource, (int)resourcesize) < HTTP_URI_STATUS_OK)
+  else
   {
-    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad printer-uri."), 1);
+    DEBUG_printf(("1_cupsGetDestResource: printer-uri-supported=\"%s\"", uri));
 
-    return (NULL);
+    if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
+                        userpass, sizeof(userpass), hostname, sizeof(hostname),
+                        &port, resource, (int)resourcesize) < HTTP_URI_STATUS_OK)
+    {
+      _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad printer-uri."), 1);
+
+      return (NULL);
+    }
   }
 
+  DEBUG_printf(("1_cupsGetDestResource: resource=\"%s\"", resource));
+
   return (uri);
 }
 
@@ -1434,6 +1609,7 @@ cupsGetDestWithURI(const char *name,	/* I - Desired printer name or @code NULL@
 		hostname[256],		/* Hostname from URI */
 		resource[1024],		/* Resource path from URI */
 		*ptr;			/* Pointer into string */
+  const char	*info;			/* printer-info string */
   int		port;			/* Port number from URI */
 
 
@@ -1455,7 +1631,11 @@ cupsGetDestWithURI(const char *name,	/* I - Desired printer name or @code NULL@
     return (NULL);
   }
 
-  if (!name)
+  if (name)
+  {
+    info = name;
+  }
+  else
   {
    /*
     * Create the name from the URI...
@@ -1467,24 +1647,29 @@ cupsGetDestWithURI(const char *name,	/* I - Desired printer name or @code NULL@
       * Use the service instance name...
       */
 
-      if ((ptr = strchr(hostname, '.')) != NULL)
+      if ((ptr = strstr(hostname, "._")) != NULL)
         *ptr = '\0';
 
-      name = hostname;
+      cups_queue_name(temp, hostname, sizeof(temp));
+      name = temp;
+      info = hostname;
     }
     else if (!strncmp(resource, "/classes/", 9))
     {
       snprintf(temp, sizeof(temp), "%s @ %s", resource + 9, hostname);
-      name = temp;
+      name = resource + 9;
+      info = temp;
     }
     else if (!strncmp(resource, "/printers/", 10))
     {
       snprintf(temp, sizeof(temp), "%s @ %s", resource + 10, hostname);
-      name = temp;
+      name = resource + 10;
+      info = temp;
     }
     else
     {
       name = hostname;
+      info = hostname;
     }
   }
 
@@ -1500,7 +1685,7 @@ cupsGetDestWithURI(const char *name,	/* I - Desired printer name or @code NULL@
 
   dest->name        = _cupsStrAlloc(name);
   dest->num_options = cupsAddOption("device-uri", uri, dest->num_options, &(dest->options));
-  dest->num_options = cupsAddOption("printer-info", name, dest->num_options, &(dest->options));
+  dest->num_options = cupsAddOption("printer-info", info, dest->num_options, &(dest->options));
 
   return (dest);
 }
@@ -1574,6 +1759,7 @@ _cupsGetDests(http_t       *http,	/* I  - Connection to server or
 		  "printer-info",
 		  "printer-is-accepting-jobs",
 		  "printer-is-shared",
+                  "printer-is-temporary",
 		  "printer-location",
 		  "printer-make-and-model",
 		  "printer-mandatory-job-attributes",
@@ -1586,6 +1772,8 @@ _cupsGetDests(http_t       *http,	/* I  - Connection to server or
 		};
 
 
+  DEBUG_printf(("_cupsGetDests(http=%p, op=%x(%s), name=\"%s\", dests=%p, type=%x, mask=%x)", (void *)http, op, ippOpString(op), name, (void *)dests, type, mask));
+
 #ifdef __APPLE__
  /*
   * Get the default paper size...
@@ -1678,7 +1866,8 @@ _cupsGetDests(http_t       *http,	/* I  - Connection to server or
 	    !strcmp(attr->name, "marker-types") ||
 	    !strcmp(attr->name, "printer-commands") ||
 	    !strcmp(attr->name, "printer-info") ||
-	    !strcmp(attr->name, "printer-is-shared") ||
+            !strcmp(attr->name, "printer-is-shared") ||
+            !strcmp(attr->name, "printer-is-temporary") ||
 	    !strcmp(attr->name, "printer-make-and-model") ||
 	    !strcmp(attr->name, "printer-mandatory-job-attributes") ||
 	    !strcmp(attr->name, "printer-state") ||
@@ -1785,15 +1974,23 @@ _cupsGetDests(http_t       *http,	/* I  - Connection to server or
  * 'cupsGetDests()' - Get the list of destinations from the default server.
  *
  * Starting with CUPS 1.2, the returned list of destinations include the
- * printer-info, printer-is-accepting-jobs, printer-is-shared,
- * printer-make-and-model, printer-state, printer-state-change-time,
- * printer-state-reasons, and printer-type attributes as options.  CUPS 1.4
- * adds the marker-change-time, marker-colors, marker-high-levels,
- * marker-levels, marker-low-levels, marker-message, marker-names,
- * marker-types, and printer-commands attributes as well.
+ * "printer-info", "printer-is-accepting-jobs", "printer-is-shared",
+ * "printer-make-and-model", "printer-state", "printer-state-change-time",
+ * "printer-state-reasons", "printer-type", and "printer-uri-supported"
+ * attributes as options.
+ *
+ * CUPS 1.4 adds the "marker-change-time", "marker-colors",
+ * "marker-high-levels", "marker-levels", "marker-low-levels", "marker-message",
+ * "marker-names", "marker-types", and "printer-commands" attributes as options.
+ *
+ * CUPS 2.2 adds accessible IPP printers to the list of destinations that can
+ * be used.  The "printer-uri-supported" option will be present for those IPP
+ * printers that have been recently used.
  *
  * Use the @link cupsFreeDests@ function to free the destination list and
  * the @link cupsGetDest@ function to find a particular destination.
+ *
+ * @exclude all@
  */
 
 int					/* O - Number of destinations */
@@ -1807,12 +2004,18 @@ cupsGetDests(cups_dest_t **dests)	/* O - Destinations */
  * 'cupsGetDests2()' - Get the list of destinations from the specified server.
  *
  * Starting with CUPS 1.2, the returned list of destinations include the
- * printer-info, printer-is-accepting-jobs, printer-is-shared,
- * printer-make-and-model, printer-state, printer-state-change-time,
- * printer-state-reasons, and printer-type attributes as options.  CUPS 1.4
- * adds the marker-change-time, marker-colors, marker-high-levels,
- * marker-levels, marker-low-levels, marker-message, marker-names,
- * marker-types, and printer-commands attributes as well.
+ * "printer-info", "printer-is-accepting-jobs", "printer-is-shared",
+ * "printer-make-and-model", "printer-state", "printer-state-change-time",
+ * "printer-state-reasons", "printer-type", and "printer-uri-supported"
+ * attributes as options.
+ *
+ * CUPS 1.4 adds the "marker-change-time", "marker-colors",
+ * "marker-high-levels", "marker-levels", "marker-low-levels", "marker-message",
+ * "marker-names", "marker-types", and "printer-commands" attributes as options.
+ *
+ * CUPS 2.2 adds accessible IPP printers to the list of destinations that can
+ * be used.  The "printer-uri-supported" option will be present for those IPP
+ * printers that have been recently used.
  *
  * Use the @link cupsFreeDests@ function to free the destination list and
  * the @link cupsGetDest@ function to find a particular destination.
@@ -1824,8 +2027,8 @@ int					/* O - Number of destinations */
 cupsGetDests2(http_t      *http,	/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
               cups_dest_t **dests)	/* O - Destinations */
 {
-  int		num_dests;		/* Number of destinations */
-  cups_dest_t	*dest;			/* Destination pointer */
+  _cups_getdata_t data;                 /* Enumeration data */
+  cups_dest_t   *dest;                  /* Current destination */
   const char	*home;			/* HOME environment variable */
   char		filename[1024];		/* Local ~/.cups/lpoptions file */
   const char	*defprinter;		/* Default printer */
@@ -1851,13 +2054,17 @@ cupsGetDests2(http_t      *http,	/* I - Connection to server or @code CUPS_HTTP_
   * Grab the printers and classes...
   */
 
-  *dests    = (cups_dest_t *)0;
-  num_dests = _cupsGetDests(http, IPP_OP_CUPS_GET_PRINTERS, NULL, dests, 0, CUPS_PRINTER_3D);
+  data.num_dests = 0;
+  data.dests     = NULL;
+
+  cupsEnumDests(0, 1000, NULL, 0, 0, (cups_dest_cb_t)cups_get_cb, &data);
 
   if (cupsLastError() >= IPP_STATUS_REDIRECTION_OTHER_SITE)
   {
-    cupsFreeDests(num_dests, *dests);
+    cupsFreeDests(data.num_dests, data.dests);
+
     *dests = (cups_dest_t *)0;
+
     return (0);
   }
 
@@ -1865,13 +2072,13 @@ cupsGetDests2(http_t      *http,	/* I - Connection to server or @code CUPS_HTTP_
   * Make a copy of the "real" queues for a later sanity check...
   */
 
-  if (num_dests > 0)
+  if (data.num_dests > 0)
   {
-    num_reals = num_dests;
+    num_reals = data.num_dests;
     reals     = calloc((size_t)num_reals, sizeof(cups_dest_t));
 
     if (reals)
-      memcpy(reals, *dests, (size_t)num_reals * sizeof(cups_dest_t));
+      memcpy(reals, data.dests, (size_t)num_reals * sizeof(cups_dest_t));
     else
       num_reals = 0;
   }
@@ -1906,7 +2113,7 @@ cupsGetDests2(http_t      *http,	/* I - Connection to server or @code CUPS_HTTP_
     * Lookup the printer and instance and make it the default...
     */
 
-    if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL)
+    if ((dest = cupsGetDest(name, instance, data.num_dests, data.dests)) != NULL)
       dest->is_default = 1;
   }
   else
@@ -1917,15 +2124,13 @@ cupsGetDests2(http_t      *http,	/* I - Connection to server or @code CUPS_HTTP_
   */
 
   snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
-  num_dests = cups_get_dests(filename, NULL, NULL, user_default != NULL,
-                             num_dests, dests);
+  data.num_dests = cups_get_dests(filename, NULL, NULL, user_default != NULL, data.num_dests, &data.dests);
 
   if ((home = getenv("HOME")) != NULL)
   {
     snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
 
-    num_dests = cups_get_dests(filename, NULL, NULL, user_default != NULL,
-                               num_dests, dests);
+    data.num_dests = cups_get_dests(filename, NULL, NULL, user_default != NULL, data.num_dests, &data.dests);
   }
 
  /*
@@ -1940,7 +2145,7 @@ cupsGetDests2(http_t      *http,	/* I - Connection to server or @code CUPS_HTTP_
     * See if we have a default printer...
     */
 
-    if ((dest = cupsGetDest(NULL, NULL, num_dests, *dests)) != NULL)
+    if ((dest = cupsGetDest(NULL, NULL, data.num_dests, data.dests)) != NULL)
     {
      /*
       * Have a default; see if it is real...
@@ -1953,8 +2158,7 @@ cupsGetDests2(http_t      *http,	/* I - Connection to server or @code CUPS_HTTP_
         * going to an unexpected printer... ()
         */
 
-        num_dests = cupsRemoveDest(dest->name, dest->instance, num_dests,
-                                   dests);
+        data.num_dests = cupsRemoveDest(dest->name, dest->instance, data.num_dests, &data.dests);
       }
     }
 
@@ -1969,10 +2173,12 @@ cupsGetDests2(http_t      *http,	/* I - Connection to server or @code CUPS_HTTP_
   * Return the number of destinations...
   */
 
-  if (num_dests > 0)
+  *dests = data.dests;
+
+  if (data.num_dests > 0)
     _cupsSetError(IPP_STATUS_OK, NULL, 0);
 
-  return (num_dests);
+  return (data.num_dests);
 }
 
 
@@ -1980,10 +2186,10 @@ cupsGetDests2(http_t      *http,	/* I - Connection to server or @code CUPS_HTTP_
  * 'cupsGetNamedDest()' - Get options for the named destination.
  *
  * This function is optimized for retrieving a single destination and should
- * be used instead of @link cupsGetDests@ and @link cupsGetDest@ when you either
- * know the name of the destination or want to print to the default destination.
- * If @code NULL@ is returned, the destination does not exist or there is no
- * default destination.
+ * be used instead of @link cupsGetDests2@ and @link cupsGetDest@ when you
+ * either know the name of the destination or want to print to the default
+ * destination.  If @code NULL@ is returned, the destination does not exist or
+ * there is no default destination.
  *
  * If "http" is @code CUPS_HTTP_DEFAULT@, the connection to the default print
  * server will be used.
@@ -2002,6 +2208,7 @@ cupsGetNamedDest(http_t     *http,	/* I - Connection to server or @code CUPS_HTT
                  const char *name,	/* I - Destination name or @code NULL@ for the default destination */
                  const char *instance)	/* I - Instance name or @code NULL@ */
 {
+  const char    *dest_name;             /* Working destination name */
   cups_dest_t	*dest;			/* Destination */
   char		filename[1024],		/* Path to lpoptions */
 		defname[256];		/* Default printer name */
@@ -2012,16 +2219,20 @@ cupsGetNamedDest(http_t     *http,	/* I - Connection to server or @code CUPS_HTT
   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
 
 
+  DEBUG_printf(("cupsGetNamedDest(http=%p, name=\"%s\", instance=\"%s\")", (void *)http, name, instance));
+
  /*
   * If "name" is NULL, find the default destination...
   */
 
-  if (!name)
+  dest_name = name;
+
+  if (!dest_name)
   {
     set_as_default = 1;
-    name           = _cupsUserDefault(defname, sizeof(defname));
+    dest_name      = _cupsUserDefault(defname, sizeof(defname));
 
-    if (name)
+    if (dest_name)
     {
       char	*ptr;			/* Temporary pointer... */
 
@@ -2041,7 +2252,7 @@ cupsGetNamedDest(http_t     *http,	/* I - Connection to server or @code CUPS_HTT
 
       snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
 
-      name = cups_get_default(filename, defname, sizeof(defname), &instance);
+      dest_name = cups_get_default(filename, defname, sizeof(defname), &instance);
     }
 
     if (!name)
@@ -2050,27 +2261,51 @@ cupsGetNamedDest(http_t     *http,	/* I - Connection to server or @code CUPS_HTT
       * Still not there?  Try the system lpoptions file...
       */
 
-      snprintf(filename, sizeof(filename), "%s/lpoptions",
-	       cg->cups_serverroot);
-      name = cups_get_default(filename, defname, sizeof(defname), &instance);
+      snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
+      dest_name = cups_get_default(filename, defname, sizeof(defname), &instance);
     }
 
-    if (!name)
+    if (!dest_name)
     {
      /*
       * No locally-set default destination, ask the server...
       */
 
       op = IPP_OP_CUPS_GET_DEFAULT;
+
+      DEBUG_puts("1cupsGetNamedDest: Asking server for default printer...");
     }
+    else
+      DEBUG_printf(("1cupsGetNamedDest: Using name=\"%s\"...", name));
   }
 
  /*
   * Get the printer's attributes...
   */
 
-  if (!_cupsGetDests(http, op, name, &dest, 0, CUPS_PRINTER_3D))
-    return (NULL);
+  if (!_cupsGetDests(http, op, dest_name, &dest, 0, 0))
+  {
+    if (name)
+    {
+      _cups_namedata_t  data;           /* Callback data */
+
+      DEBUG_puts("1cupsGetNamedDest: No queue found for printer, looking on network...");
+
+      data.name = name;
+      data.dest = NULL;
+
+      cupsEnumDests(0, 1000, NULL, 0, 0, (cups_dest_cb_t)cups_name_cb, &data);
+
+      if (!data.dest)
+        return (NULL);
+
+      dest = data.dest;
+    }
+    else
+      return (NULL);
+  }
+
+  DEBUG_printf(("1cupsGetNamedDest: Got dest=%p", (void *)dest));
 
   if (instance)
     dest->instance = _cupsStrAlloc(instance);
@@ -2083,13 +2318,13 @@ cupsGetNamedDest(http_t     *http,	/* I - Connection to server or @code CUPS_HTT
   */
 
   snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot);
-  cups_get_dests(filename, name, instance, 1, 1, &dest);
+  cups_get_dests(filename, dest_name, instance, 1, 1, &dest);
 
   if (home)
   {
     snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home);
 
-    cups_get_dests(filename, name, instance, 1, 1, &dest);
+    cups_get_dests(filename, dest_name, instance, 1, 1, &dest);
   }
 
  /*
@@ -2193,6 +2428,8 @@ cupsSetDefaultDest(
  *
  * This function saves the destinations to /etc/cups/lpoptions when run
  * as root and ~/.cups/lpoptions when run as a normal user.
+ *
+ * @exclude all@
  */
 
 void
@@ -2245,7 +2482,7 @@ cupsSetDests2(http_t      *http,	/* I - Connection to server or @code CUPS_HTTP_
   * Get the server destinations...
   */
 
-  num_temps = _cupsGetDests(http, IPP_OP_CUPS_GET_PRINTERS, NULL, &temps, 0, CUPS_PRINTER_3D);
+  num_temps = _cupsGetDests(http, IPP_OP_CUPS_GET_PRINTERS, NULL, &temps, 0, 0);
 
   if (cupsLastError() >= IPP_STATUS_REDIRECTION_OTHER_SITE)
   {
@@ -2839,11 +3076,12 @@ cups_dnssd_browse_cb(
   (void)protocol;
   (void)context;
 
+  DEBUG_printf(("cups_dnssd_browse_cb(..., name=\"%s\", type=\"%s\", domain=\"%s\", ...);", name, type, domain));
+
   switch (event)
   {
     case AVAHI_BROWSER_FAILURE:
-	DEBUG_printf(("cups_dnssd_browse_cb: %s",
-		      avahi_strerror(avahi_client_errno(client))));
+	DEBUG_printf(("cups_dnssd_browse_cb: %s", avahi_strerror(avahi_client_errno(client))));
 	avahi_simple_poll_quit(data->simple_poll);
 	break;
 
@@ -2858,8 +3096,7 @@ cups_dnssd_browse_cb(
 	  * This comes from the local machine so ignore it.
 	  */
 
-	  DEBUG_printf(("cups_dnssd_browse_cb: Ignoring local service \"%s\".",
-	                name));
+	  DEBUG_printf(("cups_dnssd_browse_cb: Ignoring local service \"%s\".", name));
 	}
 	else
 	{
@@ -2871,9 +3108,13 @@ cups_dnssd_browse_cb(
 	}
 	break;
 
-    case AVAHI_BROWSER_REMOVE:
-    case AVAHI_BROWSER_ALL_FOR_NOW:
-    case AVAHI_BROWSER_CACHE_EXHAUSTED:
+    case AVAHI_BROWSER_REMOVE :
+    case AVAHI_BROWSER_CACHE_EXHAUSTED :
+        break;
+
+    case AVAHI_BROWSER_ALL_FOR_NOW :
+        DEBUG_puts("cups_dnssd_browse_cb: ALL_FOR_NOW");
+        data->browsers --;
         break;
   }
 }
@@ -2895,6 +3136,8 @@ cups_dnssd_client_cb(
 
   (void)client;
 
+  DEBUG_printf(("cups_dnssd_client_cb(client=%p, state=%d, context=%p)", client, state, context));
+
  /*
   * If the connection drops, quit.
   */
@@ -2964,8 +3207,9 @@ cups_dnssd_get_device(
 {
   _cups_dnssd_device_t	key,		/* Search key */
 			*device;	/* Device */
-  char			fullName[kDNSServiceMaxDomainName];
+  char			fullName[kDNSServiceMaxDomainName],
 					/* Full name for query */
+			name[128];	/* Queue name */
 
 
   DEBUG_printf(("5cups_dnssd_get_device(data=%p, serviceName=\"%s\", regtype=\"%s\", replyDomain=\"%s\")", (void *)data, serviceName, regtype, replyDomain));
@@ -2974,7 +3218,9 @@ cups_dnssd_get_device(
   * See if this is an existing device...
   */
 
-  key.dest.name = (char *)serviceName;
+  cups_queue_name(name, serviceName, sizeof(name));
+
+  key.dest.name = name;
 
   if ((device = cupsArrayFind(data->devices, &key)) != NULL)
   {
@@ -3035,10 +3281,12 @@ cups_dnssd_get_device(
                   replyDomain));
 
     device            = calloc(sizeof(_cups_dnssd_device_t), 1);
-    device->dest.name = _cupsStrAlloc(serviceName);
+    device->dest.name = _cupsStrAlloc(name);
     device->domain    = _cupsStrAlloc(replyDomain);
     device->regtype   = _cupsStrAlloc(regtype);
 
+    device->dest.num_options = cupsAddOption("printer-info", serviceName, 0, &device->dest.options);
+
     cupsArrayAdd(data->devices, device);
   }
 
@@ -3047,11 +3295,9 @@ cups_dnssd_get_device(
   */
 
 #  ifdef HAVE_DNSSD
-  DNSServiceConstructFullName(fullName, device->dest.name, device->regtype,
-			      device->domain);
+  DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain);
 #  else /* HAVE_AVAHI */
-  avahi_service_name_join(fullName, kDNSServiceMaxDomainName, serviceName,
-                          regtype, replyDomain);
+  avahi_service_name_join(fullName, kDNSServiceMaxDomainName, serviceName, regtype, replyDomain);
 #  endif /* HAVE_DNSSD */
 
   _cupsStrFree(device->fullName);
@@ -3070,6 +3316,8 @@ cups_dnssd_get_device(
 
   if (device->state == _CUPS_DNSSD_ACTIVE)
   {
+    DEBUG_printf(("6cups_dnssd_get_device: Remove callback for \"%s\".", device->dest.name));
+
     (*data->cb)(data->user_data, CUPS_DEST_FLAGS_REMOVED, &device->dest);
     device->state = _CUPS_DNSSD_NEW;
   }
@@ -3128,7 +3376,10 @@ cups_dnssd_local_cb(
   }
 
   if (device->state == _CUPS_DNSSD_ACTIVE)
+  {
+    DEBUG_printf(("6cups_dnssd_local_cb: Remove callback for \"%s\".", device->dest.name));
     (*data->cb)(data->user_data, CUPS_DEST_FLAGS_REMOVED, &device->dest);
+  }
 
   device->state = _CUPS_DNSSD_LOCAL;
 }
@@ -3141,7 +3392,9 @@ cups_dnssd_local_cb(
  *
  * Note: This function is needed because avahi_simple_poll_iterate is broken
  *       and always uses a timeout of 0 (!) milliseconds.
- *       (Avahi Ticket #364)
+ *       (https://github.com/lathiat/avahi/issues/127)
+ *
+ * @private@
  */
 
 static int				/* O - Number of file descriptors matching */
@@ -3156,16 +3409,22 @@ cups_dnssd_poll_cb(
   int			val;		/* Return value */
 
 
+  DEBUG_printf(("cups_dnssd_poll_cb(pollfds=%p, num_pollfds=%d, timeout=%d, context=%p)", pollfds, num_pollfds, timeout, context));
+
   (void)timeout;
 
-  val = poll(pollfds, num_pollfds, 250);
+  val = poll(pollfds, num_pollfds, _CUPS_DNSSD_MAXTIME);
+
+  DEBUG_printf(("cups_dnssd_poll_cb: poll() returned %d", val));
 
   if (val < 0)
   {
     DEBUG_printf(("cups_dnssd_poll_cb: %s", strerror(errno)));
   }
   else if (val > 0)
+  {
     data->got_data = 1;
+  }
 
   return (val);
 }
@@ -3214,7 +3473,8 @@ cups_dnssd_query_cb(
 #  endif /* HAVE_DNSSD */
   _cups_dnssd_data_t	*data = (_cups_dnssd_data_t *)context;
 					/* Enumeration data */
-  char			name[1024],	/* Service name */
+  char			serviceName[256],/* Service name */
+			name[128],	/* Queue name */
 			*ptr;		/* Pointer into string */
   _cups_dnssd_device_t	dkey,		/* Search key */
 			*device;	/* Device */
@@ -3231,11 +3491,7 @@ cups_dnssd_query_cb(
     return;
 
 #  else /* HAVE_AVAHI */
-  DEBUG_printf(("5cups_dnssd_query_cb(browser=%p, interfaceIndex=%d, "
-		"protocol=%d, event=%d, fullName=\"%s\", rrclass=%u, "
-		"rrtype=%u, rdata=%p, rdlen=%u, flags=%x, context=%p)",
-		browser, interfaceIndex, protocol, event, fullName, rrclass,
-		rrtype, rdata, (unsigned)rdlen, flags, context));
+  DEBUG_printf(("cups_dnssd_query_cb(browser=%p, interfaceIndex=%d, protocol=%d, event=%d, fullName=\"%s\", rrclass=%u, rrtype=%u, rdata=%p, rdlen=%u, flags=%x, context=%p)", browser, interfaceIndex, protocol, event, fullName, rrclass, rrtype, rdata, (unsigned)rdlen, flags, context));
 
  /*
   * Only process "add" data...
@@ -3244,8 +3500,7 @@ cups_dnssd_query_cb(
   if (event != AVAHI_BROWSER_NEW)
   {
     if (event == AVAHI_BROWSER_FAILURE)
-      DEBUG_printf(("cups_dnssd_query_cb: %s",
-		    avahi_strerror(avahi_client_errno(client))));
+      DEBUG_printf(("cups_dnssd_query_cb: %s", avahi_strerror(avahi_client_errno(client))));
 
     return;
   }
@@ -3255,14 +3510,16 @@ cups_dnssd_query_cb(
   * Lookup the service in the devices array.
   */
 
-  dkey.dest.name = name;
+  cups_dnssd_unquote(serviceName, fullName, sizeof(serviceName));
 
-  cups_dnssd_unquote(name, fullName, sizeof(name));
-
-  if ((ptr = strstr(name, "._")) != NULL)
+  if ((ptr = strstr(serviceName, "._")) != NULL)
     *ptr = '\0';
 
-  if ((device = cupsArrayFind(data->devices, &dkey)) != NULL)
+  cups_queue_name(name, serviceName, sizeof(name));
+
+  dkey.dest.name = name;
+
+  if ((device = cupsArrayFind(data->devices, &dkey)) != NULL && device->state == _CUPS_DNSSD_NEW)
   {
    /*
     * Found it, pull out the make and model from the TXT record and save it...
@@ -3279,7 +3536,7 @@ cups_dnssd_query_cb(
 			model[256],	/* Model */
 			uriname[1024],	/* Name for URI */
 			uri[1024];	/* Printer URI */
-    cups_ptype_t	type = CUPS_PRINTER_REMOTE | CUPS_PRINTER_BW;
+    cups_ptype_t	type = CUPS_PRINTER_DISCOVERED | CUPS_PRINTER_BW;
 					/* Printer type */
     int			saw_printer_type = 0;
 					/* Did we see a printer-type key? */
@@ -3398,7 +3655,7 @@ cups_dnssd_query_cb(
         */
 
 	saw_printer_type = 1;
-        type             = (cups_ptype_t)strtol(value, NULL, 0);
+        type             = (cups_ptype_t)strtol(value, NULL, 0) | CUPS_PRINTER_DISCOVERED;
       }
       else if (!saw_printer_type)
       {
@@ -3454,8 +3711,6 @@ cups_dnssd_query_cb(
     * Save the printer-xxx values...
     */
 
-    device->dest.num_options = cupsAddOption("printer-info", name, device->dest.num_options, &device->dest.options);
-
     if (make_and_model[0])
     {
       strlcat(make_and_model, " ", sizeof(make_and_model));
@@ -3543,9 +3798,9 @@ cups_dnssd_resolve(
   * Save the resolved URI...
   */
 
-  dest->num_options = cupsAddOption("resolved-device-uri", uri, dest->num_options, &dest->options);
+  dest->num_options = cupsAddOption("device-uri", uri, dest->num_options, &dest->options);
 
-  return (cupsGetOption("resolved-device-uri", dest->num_options, dest->options));
+  return (cupsGetOption("device-uri", dest->num_options, dest->options));
 }
 
 
@@ -3620,6 +3875,29 @@ cups_dnssd_unquote(char       *dst,	/* I - Destination buffer */
 #endif /* HAVE_DNSSD */
 
 
+#if defined(HAVE_AVAHI) || defined(HAVE_DNSSD)
+/*
+ * 'cups_elapsed()' - Return the elapsed time in milliseconds.
+ */
+
+static int				/* O  - Elapsed time in milliseconds */
+cups_elapsed(struct timeval *t)		/* IO - Previous time */
+{
+  int			msecs;		/* Milliseconds */
+  struct timeval	nt;		/* New time */
+
+
+  gettimeofday(&nt, NULL);
+
+  msecs = (int)(1000 * (nt.tv_sec - t->tv_sec) + (nt.tv_usec - t->tv_usec) / 1000);
+
+  *t = nt;
+
+  return (msecs);
+}
+#endif /* HAVE_AVAHI || HAVE_DNSSD */
+
+
 /*
  * 'cups_find_dest()' - Find a destination using a binary search.
  */
@@ -3723,6 +4001,36 @@ cups_find_dest(const char  *name,	/* I - Destination name */
 }
 
 
+/*
+ * 'cups_get_cb()' - Collect enumerated destinations.
+ */
+
+static int                              /* O - 1 to continue, 0 to stop */
+cups_get_cb(_cups_getdata_t *data,      /* I - Data from cupsGetDests */
+            unsigned        flags,      /* I - Enumeration flags */
+            cups_dest_t     *dest)      /* I - Destination */
+{
+  if (flags & CUPS_DEST_FLAGS_REMOVED)
+  {
+   /*
+    * Remove destination from array...
+    */
+
+    data->num_dests = cupsRemoveDest(dest->name, dest->instance, data->num_dests, &data->dests);
+  }
+  else
+  {
+   /*
+    * Add destination to array...
+    */
+
+    data->num_dests = cupsCopyDest(dest, data->num_dests, &data->dests);
+  }
+
+  return (1);
+}
+
+
 /*
  * 'cups_get_default()' - Get the default destination from an lpoptions file.
  */
@@ -4027,3 +4335,58 @@ cups_make_string(
 
   return (buffer);
 }
+
+
+/*
+ * 'cups_name_cb()' - Find an enumerated destination.
+ */
+
+static int                              /* O - 1 to continue, 0 to stop */
+cups_name_cb(_cups_namedata_t *data,    /* I - Data from cupsGetNamedDest */
+             unsigned         flags,    /* I - Enumeration flags */
+             cups_dest_t      *dest)    /* I - Destination */
+{
+  DEBUG_printf(("2cups_name_cb(data=%p(%s), flags=%x, dest=%p(%s)", (void *)data, data->name, flags, (void *)dest, dest->name));
+
+  if (!(flags & CUPS_DEST_FLAGS_REMOVED) && !dest->instance && !strcasecmp(data->name, dest->name))
+  {
+   /*
+    * Copy destination and stop enumeration...
+    */
+
+    cupsCopyDest(dest, 0, &data->dest);
+    return (0);
+  }
+
+  return (1);
+}
+
+
+/*
+ * 'cups_queue_name()' - Create a local queue name based on the service name.
+ */
+
+static void
+cups_queue_name(
+    char       *name,			/* I - Name buffer */
+    const char *serviceName,		/* I - Service name */
+    size_t     namesize)		/* I - Size of name buffer */
+{
+  const char	*ptr;			/* Pointer into serviceName */
+  char		*nameptr;		/* Pointer into name */
+
+
+  for (nameptr = name, ptr = serviceName; *ptr && nameptr < (name + namesize - 1); ptr ++)
+  {
+   /*
+    * Sanitize the printer name...
+    */
+
+    if (_cups_isalnum(*ptr))
+      *nameptr++ = *ptr;
+    else if (nameptr == name || nameptr[-1] != '_')
+      *nameptr++ = '_';
+  }
+
+  *nameptr = '\0';
+}
diff --git a/cups/dir.c b/cups/dir.c
index 074e659..b7cd400 100644
--- a/cups/dir.c
+++ b/cups/dir.c
@@ -3,14 +3,14 @@
  *
  * This set of APIs abstracts enumeration of directory entries.
  *
- * Copyright 2007-2012 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2005 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  */
 
 /*
@@ -338,10 +338,6 @@ cupsDirRead(cups_dir_t *dp)		/* I - Directory pointer */
 {
   struct dirent	*entry;			/* Pointer to entry */
   char		filename[1024];		/* Full filename */
-#  ifdef HAVE_PTHREAD_H
-  char		buffer[sizeof(struct dirent) + 1024];
-					/* Directory entry buffer */
-#  endif /* HAVE_PTHREAD_H */
 
 
   DEBUG_printf(("2cupsDirRead(dp=%p)", (void *)dp));
@@ -359,29 +355,8 @@ cupsDirRead(cups_dir_t *dp)		/* I - Directory pointer */
 
   for (;;)
   {
-#  ifdef HAVE_PTHREAD_H
    /*
-    * Read the next entry using the reentrant version of readdir...
-    */
-
-    if (readdir_r(dp->dir, (struct dirent *)buffer, &entry))
-    {
-      DEBUG_printf(("3cupsDirRead: readdir_r() failed - %s\n", strerror(errno)));
-      return (NULL);
-    }
-
-    if (!entry)
-    {
-      DEBUG_puts("3cupsDirRead: readdir_r() returned a NULL pointer!");
-      return (NULL);
-    }
-
-    DEBUG_printf(("4cupsDirRead: readdir_r() returned \"%s\"...",
-                  entry->d_name));
-
-#  else
-   /*
-    * Read the next entry using the original version of readdir...
+    * Read the next entry...
     */
 
     if ((entry = readdir(dp->dir)) == NULL)
@@ -392,8 +367,6 @@ cupsDirRead(cups_dir_t *dp)		/* I - Directory pointer */
 
     DEBUG_printf(("4cupsDirRead: readdir() returned \"%s\"...", entry->d_name));
 
-#  endif /* HAVE_PTHREAD_H */
-
    /*
     * Skip "." and ".."...
     */
diff --git a/cups/dir.h b/cups/dir.h
index 98a6767..d010544 100644
--- a/cups/dir.h
+++ b/cups/dir.h
@@ -10,7 +10,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  */
 
 #ifndef _CUPS_DIR_H_
diff --git a/cups/encode.c b/cups/encode.c
index d26d86d..94695d0 100644
--- a/cups/encode.c
+++ b/cups/encode.c
@@ -1,14 +1,14 @@
 /*
  * Option encoding routines for CUPS.
  *
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -329,7 +329,7 @@ static int	compare_ipp_options(_ipp_option_t *a, _ipp_option_t *b);
  * 'cupsEncodeOptions()' - Encode printer options into IPP attributes.
  *
  * This function adds operation, job, and then subscription attributes,
- * in that order. Use the cupsEncodeOptions2() function to add attributes
+ * in that order. Use the @link cupsEncodeOptions2@ function to add attributes
  * for a single group.
  */
 
@@ -354,7 +354,7 @@ cupsEncodeOptions(ipp_t         *ipp,		/* I - Request to add to */
  * 'cupsEncodeOptions2()' - Encode printer options into IPP attributes for a group.
  *
  * This function only adds attributes for a single group. Call this
- * function multiple times for each group, or use cupsEncodeOptions()
+ * function multiple times for each group, or use @link cupsEncodeOptions@
  * to add the standard groups.
  *
  * @since CUPS 1.2/macOS 10.5@
diff --git a/cups/file-private.h b/cups/file-private.h
index 6ce11cf..1f4db79 100644
--- a/cups/file-private.h
+++ b/cups/file-private.h
@@ -4,16 +4,16 @@
  * Since stdio files max out at 256 files on many systems, we have to
  * write similar functions without this limit.  At the same time, using
  * our own file functions allows us to provide transparent support of
- * gzip'd print files, PPD files, etc.
+ * different line endings, gzip'd print files, PPD files, etc.
  *
- * Copyright 2007-2014 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/file.c b/cups/file.c
index b81bfe8..8cdf036 100644
--- a/cups/file.c
+++ b/cups/file.c
@@ -4,16 +4,16 @@
  * Since stdio files max out at 256 files on many systems, we have to
  * write similar functions without this limit.  At the same time, using
  * our own file functions allows us to provide transparent support of
- * gzip'd print files, PPD files, etc.
+ * different line endings, gzip'd print files, PPD files, etc.
  *
- * Copyright 2007-2015 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -321,7 +321,6 @@ cupsFileClose(cups_file_t *fp)		/* I - CUPS file */
   int	fd;				/* File descriptor */
   char	mode;				/* Open mode */
   int	status;				/* Return status */
-  int	is_stdio;			/* Is a stdio file? */
 
 
   DEBUG_printf(("cupsFileClose(fp=%p)", (void *)fp));
@@ -410,12 +409,19 @@ cupsFileClose(cups_file_t *fp)		/* I - CUPS file */
 #endif /* HAVE_LIBZ */
 
  /*
+  * If this is one of the cupsFileStdin/out/err files, return now and don't
+  * actually free memory or close (these last the life of the process...)
+  */
+
+  if (fp->is_stdio)
+    return (status);
+
+/*
   * Save the file descriptor we used and free memory...
   */
 
-  fd       = fp->fd;
-  mode     = fp->mode;
-  is_stdio = fp->is_stdio;
+  fd   = fp->fd;
+  mode = fp->mode;
 
   if (fp->printf_buffer)
     free(fp->printf_buffer);
@@ -431,11 +437,8 @@ cupsFileClose(cups_file_t *fp)		/* I - CUPS file */
     if (httpAddrClose(NULL, fd) < 0)
       status = -1;
   }
-  else if (!is_stdio)
-  {
-    if (close(fd) < 0)
-      status = -1;
-  }
+  else if (close(fd) < 0)
+    status = -1;
 
   return (status);
 }
@@ -1384,7 +1387,11 @@ cupsFilePrintf(cups_file_t *fp,		/* I - CUPS file */
   {
     memcpy(fp->ptr, fp->printf_buffer, (size_t)bytes);
     fp->ptr += bytes;
-    return ((int)bytes);
+
+    if (fp->is_stdio && cupsFileFlush(fp))
+      return (-1);
+    else
+      return ((int)bytes);
   }
 }
 
@@ -1563,7 +1570,11 @@ cupsFilePuts(cups_file_t *fp,		/* I - CUPS file */
   {
     memcpy(fp->ptr, s, (size_t)bytes);
     fp->ptr += bytes;
-    return ((int)bytes);
+
+    if (fp->is_stdio && cupsFileFlush(fp))
+      return (-1);
+    else
+      return ((int)bytes);
   }
 }
 
diff --git a/cups/file.h b/cups/file.h
index 8a4289f..42abe20 100644
--- a/cups/file.h
+++ b/cups/file.h
@@ -4,16 +4,16 @@
  * Since stdio files max out at 256 files on many systems, we have to
  * write similar functions without this limit.  At the same time, using
  * our own file functions allows us to provide transparent support of
- * gzip'd print files, PPD files, etc.
+ * different line endings, gzip'd print files, PPD files, etc.
  *
- * Copyright 2007-2014 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/getdevices.c b/cups/getdevices.c
index 13bebd2..0f303ba 100644
--- a/cups/getdevices.c
+++ b/cups/getdevices.c
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/getputfile.c b/cups/getputfile.c
index 76a3093..ae33bc5 100644
--- a/cups/getputfile.c
+++ b/cups/getputfile.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/globals.c b/cups/globals.c
index 276bbcf..8a05c3e 100644
--- a/cups/globals.c
+++ b/cups/globals.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/hash.c b/cups/hash.c
index d52807e..ede5461 100644
--- a/cups/hash.c
+++ b/cups/hash.c
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/http-addr.c b/cups/http-addr.c
index dd61d4a..61c8638 100644
--- a/cups/http-addr.c
+++ b/cups/http-addr.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -58,9 +58,9 @@ httpAddrAny(const http_addr_t *addr)	/* I - Address to check */
  * 'httpAddrClose()' - Close a socket created by @link httpAddrConnect@ or
  *                     @link httpAddrListen@.
  *
- * Pass @code NULL@ for sockets created with @link httpAddrConnect@ and the
- * listen address for sockets created with @link httpAddrListen@. This will
- * ensure that domain sockets are removed when closed.
+ * Pass @code NULL@ for sockets created with @link httpAddrConnect2@ and the
+ * listen address for sockets created with @link httpAddrListen@.  This function
+ * ensures that domain sockets are removed when closed.
  *
  * @since CUPS 2.0/OS 10.10@
  */
@@ -648,6 +648,10 @@ httpAddrString(const http_addr_t *addr,	/* I - Address to convert */
 /*
  * 'httpGetAddress()' - Get the address of the connected peer of a connection.
  *
+ * For connections created with @link httpConnect2@, the address is for the
+ * server.  For connections created with @link httpAccept@, the address is for
+ * the client.
+ *
  * Returns @code NULL@ if the socket is currently unconnected.
  *
  * @since CUPS 2.0/OS 10.10@
@@ -667,7 +671,7 @@ httpGetAddress(http_t *http)		/* I - HTTP connection */
  * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return
  *                         address records for the specified name.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 struct hostent *			/* O - Host entry */
@@ -871,6 +875,18 @@ httpGetHostname(http_t *http,		/* I - HTTP connection or NULL */
       strlcat(s, ".", (size_t)slen);
   }
 
+ /*
+  * Convert the hostname to lowercase as needed...
+  */
+
+  if (s[0] != '/')
+  {
+    char	*ptr;			/* Pointer into string */
+
+    for (ptr = s; *ptr; ptr ++)
+      *ptr = (char)_cups_tolower((int)*ptr);
+  }
+
  /*
   * Return the hostname with as much domain info as we have...
   */
diff --git a/cups/http-addrlist.c b/cups/http-addrlist.c
index e9ef53e..22bd5a7 100644
--- a/cups/http-addrlist.c
+++ b/cups/http-addrlist.c
@@ -1,14 +1,14 @@
 /*
  * HTTP address list routines for CUPS.
  *
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -32,7 +32,7 @@
 /*
  * 'httpAddrConnect()' - Connect to any of the addresses in the list.
  *
- * @since CUPS 1.2/macOS 10.5@
+ * @since CUPS 1.2/macOS 10.5@ @exclude all@
  */
 
 http_addrlist_t *			/* O - Connected address or NULL on failure */
@@ -312,7 +312,7 @@ httpAddrConnect2(
 	DEBUG_printf(("pfds[%d].revents=%x\n", i, pfds[i].revents));
 	if (pfds[i].revents && !(pfds[i].revents & (POLLERR | POLLHUP)))
 #  else
-	if (FD_ISSET(fds[i], &input) && !FD_ISSET(fds[i], &error))
+	if (FD_ISSET(fds[i], &input_set) && !FD_ISSET(fds[i], &error_set))
 #  endif /* HAVE_POLL */
 	{
 	  *sock    = fds[i];
@@ -327,7 +327,7 @@ httpAddrConnect2(
 #  ifdef HAVE_POLL
 	else if (pfds[i].revents & (POLLERR | POLLHUP))
 #  else
-	else if (FD_ISSET(fds[i], &error))
+	else if (FD_ISSET(fds[i], &error_set))
 #  endif /* HAVE_POLL */
         {
          /*
diff --git a/cups/http-private.h b/cups/http-private.h
index ec29707..7c39c04 100644
--- a/cups/http-private.h
+++ b/cups/http-private.h
@@ -1,14 +1,14 @@
 /*
  * Private HTTP definitions for CUPS.
  *
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -184,6 +184,7 @@ extern "C" {
 #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 */
+#define _HTTP_TLS_DENY_CBC	32	/* Deny CBC cipher suites */
 
 
 /*
diff --git a/cups/http-support.c b/cups/http-support.c
index 21776d7..76dbb7d 100644
--- a/cups/http-support.c
+++ b/cups/http-support.c
@@ -1,14 +1,14 @@
 /*
  * HTTP support routines for CUPS.
  *
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -543,7 +543,7 @@ httpAssembleUUID(const char *server,	/* I - Server name */
  * This function is deprecated. Use the httpDecode64_2() function instead
  * which provides buffer length arguments.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 char *					/* O - Decoded string */
@@ -566,6 +566,10 @@ httpDecode64(char       *out,		/* I - String to write to */
 /*
  * 'httpDecode64_2()' - Base64-decode a string.
  *
+ * The caller must initialize "outlen" to the maximum size of the decoded
+ * string before calling @code httpDecode64_2@.  On return "outlen" contains the
+ * decoded length of the string.
+ *
  * @since CUPS 1.1.21/macOS 10.4@
  */
 
@@ -671,7 +675,7 @@ httpDecode64_2(char       *out,		/* I  - String to write to */
  * This function is deprecated. Use the httpEncode64_2() function instead
  * which provides buffer length arguments.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 char *					/* O - Encoded string */
@@ -690,7 +694,7 @@ httpEncode64(char       *out,		/* I - String to write to */
 
 char *					/* O - Encoded string */
 httpEncode64_2(char       *out,		/* I - String to write to */
-	       int        outlen,	/* I - Size of output string */
+	       int        outlen,	/* I - Maximum size of output string */
                const char *in,		/* I - String to read from */
 	       int        inlen)	/* I - Size of input string */
 {
@@ -778,11 +782,11 @@ httpEncode64_2(char       *out,		/* I - String to write to */
 /*
  * 'httpGetDateString()' - Get a formatted date/time string from a time value.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 const char *				/* O - Date/time string */
-httpGetDateString(time_t t)		/* I - UNIX time */
+httpGetDateString(time_t t)		/* I - Time in seconds */
 {
   _cups_globals_t *cg = _cupsGlobals();	/* Pointer to library globals */
 
@@ -798,7 +802,7 @@ httpGetDateString(time_t t)		/* I - UNIX time */
  */
 
 const char *				/* O - Date/time string */
-httpGetDateString2(time_t t,		/* I - UNIX time */
+httpGetDateString2(time_t t,		/* I - Time in seconds */
                    char   *s,		/* I - String buffer */
 		   int    slen)		/* I - Size of string buffer */
 {
@@ -819,7 +823,7 @@ httpGetDateString2(time_t t,		/* I - UNIX time */
  * 'httpGetDateTime()' - Get a time value from a formatted date/time string.
  */
 
-time_t					/* O - UNIX time */
+time_t					/* O - Time in seconds */
 httpGetDateTime(const char *s)		/* I - Date/time string */
 {
   int		i;			/* Looping var */
@@ -888,7 +892,7 @@ httpGetDateTime(const char *s)		/* I - Date/time string */
  *
  * This function is deprecated; use the httpSeparateURI() function instead.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 void
@@ -912,7 +916,7 @@ httpSeparate(const char *uri,		/* I - Universal Resource Identifier */
  * This function is deprecated; use the httpSeparateURI() function instead.
  *
  * @since CUPS 1.1.21/macOS 10.4@
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 void
@@ -1419,7 +1423,7 @@ _httpStatus(cups_lang_t   *lang,	/* I - Language */
  * 'httpStatus()' - Return a short string describing a HTTP status code.
  *
  * The returned string is localized to the current POSIX locale and is based
- * on the status strings defined in RFC 2616.
+ * on the status strings defined in RFC 7231.
  */
 
 const char *				/* O - Localized status string */
@@ -2310,6 +2314,8 @@ http_resolve_cb(
  * Note: This function is needed because avahi_simple_poll_iterate is broken
  *       and always uses a timeout of 0 (!) milliseconds.
  *       (Avahi Ticket #364)
+ *
+ * @private@
  */
 
 static int				/* O - Number of file descriptors matching */
diff --git a/cups/http.c b/cups/http.c
index b3abbe7..61b88c9 100644
--- a/cups/http.c
+++ b/cups/http.c
@@ -1,7 +1,7 @@
 /*
  * HTTP routines for CUPS.
  *
- * Copyright 2007-2015 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * This file contains Kerberos support code, copyright 2006 by
@@ -11,7 +11,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -417,7 +417,7 @@ httpCompareCredentials(
  *
  * This function is deprecated - use @link httpConnect2@ instead.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 http_t *				/* O - New HTTP connection */
@@ -439,7 +439,7 @@ http_t *				/* O - New HTTP connection */
 httpConnect2(
     const char        *host,		/* I - Host to connect to */
     int               port,		/* I - Port number */
-    http_addrlist_t   *addrlist,	/* I - List of addresses or NULL to lookup */
+    http_addrlist_t   *addrlist,	/* I - List of addresses or @code NULL@ to lookup */
     int               family,		/* I - Address family to use or @code AF_UNSPEC@ for any */
     http_encryption_t encryption,	/* I - Type of encryption to use */
     int               blocking,		/* I - 1 for blocking connection, 0 for non-blocking */
@@ -482,7 +482,7 @@ httpConnect2(
  * This function is now deprecated. Please use the @link httpConnect2@ function
  * instead.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 http_t *				/* O - New HTTP connection */
@@ -609,7 +609,7 @@ httpFieldValue(const char *name)	/* I - String name */
 
 
 /*
- * 'httpFlush()' - Flush data from a HTTP connection.
+ * 'httpFlush()' - Flush data read from a HTTP connection.
  */
 
 void
@@ -679,7 +679,7 @@ httpFlush(http_t *http)			/* I - HTTP connection */
 
 
 /*
- * 'httpFlushWrite()' - Flush data in write buffer.
+ * 'httpFlushWrite()' - Flush data written to a HTTP connection.
  *
  * @since CUPS 1.2/macOS 10.5@
  */
@@ -751,7 +751,7 @@ httpGet(http_t     *http,		/* I - HTTP connection */
 /*
  * 'httpGetActivity()' - Get the most recent activity for a connection.
  *
- * The return value is the UNIX time of the last read or write.
+ * The return value is the time in seconds of the last read or write.
  *
  * @since CUPS 2.0/OS 10.10@
  */
@@ -766,10 +766,10 @@ httpGetActivity(http_t *http)		/* I - HTTP connection */
 /*
  * 'httpGetAuthString()' - Get the current authorization string.
  *
- * The authorization string is set by cupsDoAuthentication() and
- * httpSetAuthString().  Use httpGetAuthString() to retrieve the
- * string to use with httpSetField() for the HTTP_FIELD_AUTHORIZATION
- * value.
+ * The authorization string is set by @link cupsDoAuthentication@ and
+ * @link httpSetAuthString@.  Use @link httpGetAuthString@ to retrieve the
+ * string to use with @link httpSetField@ for the
+ * @code HTTP_FIELD_AUTHORIZATION@ value.
  *
  * @since CUPS 1.3/macOS 10.5@
  */
@@ -891,7 +891,7 @@ httpGetContentEncoding(http_t *http)	/* I - HTTP connection */
  * @since CUPS 1.1.19/macOS 10.3@
  */
 
-const char *				/* O - Cookie data or NULL */
+const char *				/* O - Cookie data or @code NULL@ */
 httpGetCookie(http_t *http)		/* I - HTTP connection */
 {
   return (http ? http->cookie : NULL);
@@ -1006,7 +1006,7 @@ httpGetKeepAlive(http_t *http)		/* I - HTTP connection */
  * This function is deprecated and will not return lengths larger than
  * 2^31 - 1; use httpGetLength2() instead.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 int					/* O - Content length */
@@ -1150,7 +1150,7 @@ httpGetRemaining(http_t *http)		/* I - HTTP connection */
  * 'httpGets()' - Get a line of text from a HTTP connection.
  */
 
-char *					/* O - Line or NULL */
+char *					/* O - Line or @code NULL@ */
 httpGets(char   *line,			/* I - Line to read into */
          int    length,			/* I - Max length of buffer */
 	 http_t *http)			/* I - HTTP connection */
@@ -1346,10 +1346,10 @@ httpGetStatus(http_t *http)		/* I - HTTP connection */
 /*
  * 'httpGetSubField()' - Get a sub-field value.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
-char *					/* O - Value or NULL */
+char *					/* O - Value or @code NULL@ */
 httpGetSubField(http_t       *http,	/* I - HTTP connection */
                 http_field_t field,	/* I - Field index */
                 const char   *name,	/* I - Name of sub-field */
@@ -1365,7 +1365,7 @@ httpGetSubField(http_t       *http,	/* I - HTTP connection */
  * @since CUPS 1.2/macOS 10.5@
  */
 
-char *					/* O - Value or NULL */
+char *					/* O - Value or @code NULL@ */
 httpGetSubField2(http_t       *http,	/* I - HTTP connection */
                  http_field_t field,	/* I - Field index */
                  const char   *name,	/* I - Name of sub-field */
@@ -1616,7 +1616,7 @@ httpOptions(http_t     *http,		/* I - HTTP connection */
  *
  * This function copies available data from the given HTTP connection, reading
  * a buffer as needed.  The data is still available for reading using
- * @link httpRead@ or @link httpRead2@.
+ * @link httpRead2@.
  *
  * For non-blocking connections the usual timeouts apply.
  *
@@ -1939,7 +1939,7 @@ httpPut(http_t     *http,		/* I - HTTP connection */
  * This function is deprecated. Use the httpRead2() function which can
  * read more than 2GB of data.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 int					/* O - Number of bytes read */
@@ -2326,7 +2326,7 @@ httpReadRequest(http_t *http,		/* I - HTTP connection */
  * This function is deprecated. Please use the @link httpReconnect2@ function
  * instead.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 int					/* O - 0 on success, non-zero on failure */
@@ -2467,9 +2467,10 @@ httpReconnect2(http_t *http,		/* I - HTTP connection */
  * 'httpSetAuthString()' - Set the current authorization string.
  *
  * This function just stores a copy of the current authorization string in
- * the HTTP connection object.  You must still call httpSetField() to set
- * HTTP_FIELD_AUTHORIZATION prior to issuing a HTTP request using httpGet(),
- * httpHead(), httpOptions(), httpPost, or httpPut().
+ * the HTTP connection object.  You must still call @link httpSetField@ to set
+ * @code HTTP_FIELD_AUTHORIZATION@ prior to issuing a HTTP request using
+ * @link httpGet@, @link httpHead@, @link httpOptions@, @link httpPost@, or
+ * @link httpPut@.
  *
  * @since CUPS 1.3/macOS 10.5@
  */
@@ -2820,7 +2821,7 @@ httpSetTimeout(
     http_t            *http,		/* I - HTTP connection */
     double            timeout,		/* I - Number of seconds for timeout,
                                                must be greater than 0 */
-    http_timeout_cb_t cb,		/* I - Callback function or NULL */
+    http_timeout_cb_t cb,		/* I - Callback function or @code NULL@ */
     void              *user_data)	/* I - User data pointer */
 {
   if (!http || timeout <= 0.0)
@@ -2864,6 +2865,8 @@ httpShutdown(http_t *http)		/* I - HTTP connection */
 
 /*
  * 'httpTrace()' - Send an TRACE request to the server.
+ *
+ * @exclude all@
  */
 
 int					/* O - Status of call (0 = success) */
@@ -3259,7 +3262,7 @@ httpWait(http_t *http,			/* I - HTTP connection */
  * This function is deprecated. Use the httpWrite2() function which can
  * write more than 2GB of data.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 int					/* O - Number of bytes written */
@@ -3667,6 +3670,9 @@ httpWriteResponse(http_t        *http,	/* I - HTTP connection */
       return (0);
     }
 
+    if (http->state == HTTP_STATE_POST_RECV || http->state == HTTP_STATE_GET)
+      http->state ++;
+
 #ifdef HAVE_LIBZ
    /*
     * Then start any content encoding...
@@ -3895,7 +3901,7 @@ static http_t *				/* O - HTTP connection */
 http_create(
     const char        *host,		/* I - Hostname */
     int               port,		/* I - Port number */
-    http_addrlist_t   *addrlist,	/* I - Address list or NULL */
+    http_addrlist_t   *addrlist,	/* I - Address list or @code NULL@ */
     int               family,		/* I - Address family or AF_UNSPEC */
     http_encryption_t encryption,	/* I - Encryption to use */
     int               blocking,		/* I - 1 for blocking mode */
diff --git a/cups/http.h b/cups/http.h
index 00039ee..c61a79e 100644
--- a/cups/http.h
+++ b/cups/http.h
@@ -1,14 +1,14 @@
 /*
  * Hyper-Text Transport Protocol definitions for CUPS.
  *
- * Copyright 2007-2014 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -109,7 +109,7 @@ extern "C" {
  * Types and structures...
  */
 
-typedef enum http_auth_e		/**** HTTP authentication types ****/
+typedef enum http_auth_e		/**** HTTP authentication types @exclude all@ ****/
 {
   HTTP_AUTH_NONE,			/* No authentication in use */
   HTTP_AUTH_BASIC,			/* Basic authentication in use */
@@ -393,7 +393,7 @@ typedef enum http_uri_coding_e		/**** URI en/decode flags ****/
   HTTP_URI_CODING_RFC6874 = 16		/* Use RFC 6874 address format */
 } http_uri_coding_t;
 
-typedef enum http_version_e		/**** HTTP version numbers ****/
+typedef enum http_version_e		/**** HTTP version numbers @exclude all@ ****/
 {
   HTTP_VERSION_0_9 = 9,			/* HTTP/0.9 */
   HTTP_VERSION_1_0 = 100,		/* HTTP/1.0 */
@@ -427,6 +427,7 @@ typedef struct http_addrlist_s		/**** Socket address list, which is
 					 **** used to enumerate all of the
 					 **** addresses that are associated
 					 **** with a hostname. @since CUPS 1.2/macOS 10.5@
+                                         **** @exclude all@
 					 ****/
 {
   struct http_addrlist_s *next;		/* Pointer to next address in list */
@@ -435,7 +436,7 @@ typedef struct http_addrlist_s		/**** Socket address list, which is
 
 typedef struct _http_s http_t;		/**** HTTP connection type ****/
 
-typedef struct http_credential_s	/**** HTTP credential data @since CUPS 1.5/macOS 10.7@ ****/
+typedef struct http_credential_s	/**** HTTP credential data @since CUPS 1.5/macOS 10.7@ @exclude all@ ****/
 {
   void		*data;			/* Pointer to credential data */
   size_t	datalen;		/* Credential length */
diff --git a/cups/ipp-private.h b/cups/ipp-private.h
index 0dbd97e..4b1947c 100644
--- a/cups/ipp-private.h
+++ b/cups/ipp-private.h
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/ipp-support.c b/cups/ipp-support.c
index fc53573..675e5f3 100644
--- a/cups/ipp-support.c
+++ b/cups/ipp-support.c
@@ -1,14 +1,14 @@
 /*
  * Internet Printing Protocol support functions for CUPS.
  *
- * Copyright 2007-2014 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -429,10 +429,10 @@ static const char * const ipp_document_states[] =
 		  "punch-quad-top",	/* Finishings 2.0 */
 		  "punch-quad-right",	/* Finishings 2.0 */
 		  "punch-quad-bottom",	/* Finishings 2.0 */
-		  "86",
-		  "87",
-		  "88",
-		  "89",
+		  "punch-multiple-left",/* Finishings 2.1/Canon */
+		  "punch-multiple-top",	/* Finishings 2.1/Canon */
+		  "punch-multiple-right",/* Finishings 2.1/Canon */
+		  "punch-multiple-bottom",/* Finishings 2.1/Canon */
 		  "fold-accordian",	/* Finishings 2.0 */
 		  "fold-double-gate",	/* Finishings 2.0 */
 		  "fold-gate",		/* Finishings 2.0 */
@@ -443,7 +443,8 @@ static const char * const ipp_document_states[] =
 		  "fold-parallel",	/* Finishings 2.0 */
 		  "fold-poster",	/* Finishings 2.0 */
 		  "fold-right-gate",	/* Finishings 2.0 */
-		  "fold-z"		/* Finishings 2.0 */
+		  "fold-z",		/* Finishings 2.0 */
+                  "fold-engineering-z"	/* Finishings 2.1 */
 		},
 		* const ipp_finishings_vendor[] =
 		{
@@ -896,12 +897,14 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
     "k-octets",
     "k-octets-processed",
     "last-document",
+    "materials-col-actual",		/* IPP 3D */
     "media-actual",
     "media-col-actual",
     "media-input-tray-check-actual",
     "media-sheets",
     "media-sheets-completed",
     "more-info",
+    "multiple-object-handling-actual",	/* IPP 3D */
     "number-up-actual",
     "orientation-requested-actual",
     "output-bin-actual",
@@ -913,12 +916,17 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
     "pages",
     "pages-completed",
     "pages-completed-current-copy",
+    "platform-temperature-actual",	/* IPP 3D */
     "presentation-direction-number-up-actual",
+    "print-accuracy-actual",		/* IPP 3D */
+    "print-base-actual",		/* IPP 3D */
     "print-color-mode-actual",
     "print-content-optimize-actual",
+    "print-objects-actual",		/* IPP 3D */
     "print-quality-actual",
     "print-rendering-intent-actual",
     "print-scaling-actual",		/* IPP Paid Printing */
+    "print-supports-actual",		/* IPP 3D */
     "printer-resolution-actual",
     "printer-up-time",
     "separator-sheets-actual",
@@ -973,6 +981,20 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
     "insert-sheet",
     "insert-sheet-default",
     "insert-sheet-supported",
+    "material-amount-units-supported",	/* IPP 3D */
+    "material-diameter-supported",	/* IPP 3D */
+    "material-purpose-supported",	/* IPP 3D */
+    "material-rate-supported",		/* IPP 3D */
+    "material-rate-units-supported",	/* IPP 3D */
+    "material-shell-thickness-supported",/* IPP 3D */
+    "material-temperature-supported",	/* IPP 3D */
+    "material-type-supported",		/* IPP 3D */
+    "materials-col",			/* IPP 3D */
+    "materials-col-database",		/* IPP 3D */
+    "materials-col-default",		/* IPP 3D */
+    "materials-col-ready",		/* IPP 3D */
+    "materials-col-supported",		/* IPP 3D */
+    "max-materials-col-supported",	/* IPP 3D */
     "max-stitching-locations-supported",
     "media",
     "media-back-coating-supported",
@@ -1005,6 +1027,9 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
     "multiple-document-handling",
     "multiple-document-handling-default",
     "multiple-document-handling-supported",
+    "multiple-object-handling",		/* IPP 3D */
+    "multiple-object-handling-default",	/* IPP 3D */
+    "multiple-object-handling-supported",/* IPP 3D */
     "number-up",
     "number-up-default",
     "number-up-supported",
@@ -1033,15 +1058,27 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
     "pdl-init-file-name-subdirectory-supported",
     "pdl-init-file-name-supported",
     "pdl-init-file-supported",
+    "platform-temperature",		/* IPP 3D */
+    "platform-temperature-default",	/* IPP 3D */
+    "platform-temperature-supported",	/* IPP 3D */
     "presentation-direction-number-up",
     "presentation-direction-number-up-default",
     "presentation-direction-number-up-supported",
+    "print-accuracy",			/* IPP 3D */
+    "print-accuracy-default",		/* IPP 3D */
+    "print-accuracy-supported",		/* IPP 3D */
+    "print-base",			/* IPP 3D */
+    "print-base-default",		/* IPP 3D */
+    "print-base-supported",		/* IPP 3D */
     "print-color-mode",
     "print-color-mode-default",
     "print-color-mode-supported",
     "print-content-optimize",
     "print-content-optimize-default",
     "print-content-optimize-supported",
+    "print-objects",			/* IPP 3D */
+    "print-objects-default",		/* IPP 3D */
+    "print-objects-supported",		/* IPP 3D */
     "print-quality",
     "print-quality-default",
     "print-quality-supported",
@@ -1051,6 +1088,9 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
     "print-scaling",			/* IPP Paid Printing */
     "print-scaling-default",		/* IPP Paid Printing */
     "print-scaling-supported",		/* IPP Paid Printing */
+    "print-supports",			/* IPP 3D */
+    "print-supports-default",		/* IPP 3D */
+    "print-supports-supported",		/* IPP 3D */
     "printer-resolution",
     "printer-resolution-default",
     "printer-resolution-supported",
@@ -1165,10 +1205,12 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
     "job-state-reasons",
     "job-uri",
     "job-uuid",
+    "materials-col-actual",		/* IPP 3D */
     "media-actual",
     "media-col-actual",
     "media-check-input-tray-actual",
     "multiple-document-handling-actual",
+    "multiple-object-handling-actual",	/* IPP 3D */
     "number-of-documents",
     "number-of-intervening-jobs",
     "number-up-actual",
@@ -1180,12 +1222,17 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
     "page-delivery-actual",
     "page-order-received-actual",
     "page-ranges-actual",
+    "platform-temperature-actual",	/* IPP 3D */
     "presentation-direction-number-up-actual",
+    "print-accuracy-actual",		/* IPP 3D */
+    "print-base-actual",		/* IPP 3D */
     "print-color-mode-actual",
     "print-content-optimize-actual",
+    "print-objects-actual",		/* IPP 3D */
     "print-quality-actual",
     "print-rendering-intent-actual",
     "print-scaling-actual",		/* IPP Paid Printing */
+    "print-supports-actual",		/* IPP 3D */
     "printer-resolution-actual",
     "separator-sheets-actual",
     "sheet-collate-actual",
@@ -1207,6 +1254,7 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
   };
   static const char * const job_template[] =
   {					/* job-template group */
+    "accuracy-units-supported",		/* IPP 3D */
     "confirmation-sheet-print",		/* IPP FaxOut */
     "confirmation-sheet-print-default",
     "copies",
@@ -1314,6 +1362,20 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
     "job-sheets-default",
     "job-sheets-supported",
     "logo-uri-schemes-supported",
+    "material-amount-units-supported",	/* IPP 3D */
+    "material-diameter-supported",	/* IPP 3D */
+    "material-purpose-supported",	/* IPP 3D */
+    "material-rate-supported",		/* IPP 3D */
+    "material-rate-units-supported",	/* IPP 3D */
+    "material-shell-thickness-supported",/* IPP 3D */
+    "material-temperature-supported",	/* IPP 3D */
+    "material-type-supported",		/* IPP 3D */
+    "materials-col",			/* IPP 3D */
+    "materials-col-database",		/* IPP 3D */
+    "materials-col-default",		/* IPP 3D */
+    "materials-col-ready",		/* IPP 3D */
+    "materials-col-supported",		/* IPP 3D */
+    "max-materials-col-supported",	/* IPP 3D */
     "max-save-info-supported",
     "max-stitching-locations-supported",
     "media",
@@ -1347,6 +1409,9 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
     "multiple-document-handling",
     "multiple-document-handling-default",
     "multiple-document-handling-supported",
+    "multiple-object-handling",		/* IPP 3D */
+    "multiple-object-handling-default",	/* IPP 3D */
+    "multiple-object-handling-supported",/* IPP 3D */
     "number-of-retries",		/* IPP FaxOut */
     "number-of-retries-default",
     "number-of-retries-supported",
@@ -1384,15 +1449,27 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
     "pdl-init-file-name-subdirectory-supported",
     "pdl-init-file-name-supported",
     "pdl-init-file-supported",
+    "platform-temperature",		/* IPP 3D */
+    "platform-temperature-default",	/* IPP 3D */
+    "platform-temperature-supported",	/* IPP 3D */
     "presentation-direction-number-up",
     "presentation-direction-number-up-default",
     "presentation-direction-number-up-supported",
+    "print-accuracy",			/* IPP 3D */
+    "print-accuracy-default",		/* IPP 3D */
+    "print-accuracy-supported",		/* IPP 3D */
+    "print-base",			/* IPP 3D */
+    "print-base-default",		/* IPP 3D */
+    "print-base-supported",		/* IPP 3D */
     "print-color-mode",
     "print-color-mode-default",
     "print-color-mode-supported",
     "print-content-optimize",
     "print-content-optimize-default",
     "print-content-optimize-supported",
+    "print-objects",			/* IPP 3D */
+    "print-objects-default",		/* IPP 3D */
+    "print-objects-supported",		/* IPP 3D */
     "print-quality",
     "print-quality-default",
     "print-quality-supported",
@@ -1402,6 +1479,9 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
     "print-scaling",			/* IPP Paid Printing */
     "print-scaling-default",		/* IPP Paid Printing */
     "print-scaling-supported",		/* IPP Paid Printing */
+    "print-supports",			/* IPP 3D */
+    "print-supports-default",		/* IPP 3D */
+    "print-supports-supported",		/* IPP 3D */
     "printer-resolution",
     "printer-resolution-default",
     "printer-resolution-supported",
@@ -1532,6 +1612,7 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
     "pages-per-minute",
     "pages-per-minute-color",
     "pdf-k-octets-supported",		/* CUPS extension */
+    "pdf-features-supported",		/* IPP 3D */
     "pdf-versions-supported",		/* CUPS extension */
     "pdl-override-supported",
     "port-monitor",			/* CUPS extension */
@@ -1559,6 +1640,7 @@ ippCreateRequestedArray(ipp_t *request)	/* I - IPP request */
     "printer-get-attributes-supported",
     "printer-icc-profiles",
     "printer-icons",
+    "printer-id",               	/* CUPS extension */
     "printer-info",
     "printer-input-tray",		/* IPP JPS3 */
     "printer-is-accepting-jobs",
@@ -2043,7 +2125,7 @@ ippOpString(ipp_op_t op)		/* I - Operation ID */
   * See if the operation ID is a known value...
   */
 
-  if (op >= IPP_OP_PRINT_JOB && op <= IPP_OP_VALIDATE_DOCUMENT)
+  if (op >= IPP_OP_PRINT_JOB && op < (ipp_op_t)(sizeof(ipp_std_ops) / sizeof(ipp_std_ops[0])))
     return (ipp_std_ops[op]);
   else if (op == IPP_OP_PRIVATE)
     return ("windows-ext");
@@ -2161,7 +2243,7 @@ ippStateString(ipp_state_t state)	/* I - State value */
 /*
  * 'ippTagString()' - Return the tag name corresponding to a tag value.
  *
- * The returned names are defined in RFC 2911 and 3382.
+ * The returned names are defined in RFC 8011 and the IANA IPP Registry.
  *
  * @since CUPS 1.4/macOS 10.6@
  */
@@ -2181,7 +2263,7 @@ ippTagString(ipp_tag_t tag)		/* I - Tag value */
 /*
  * 'ippTagValue()' - Return the tag value corresponding to a tag name.
  *
- * The tag names are defined in RFC 2911 and 3382.
+ * The tag names are defined in RFC 8011 and the IANA IPP Registry.
  *
  * @since CUPS 1.4/macOS 10.6@
  */
diff --git a/cups/ipp.c b/cups/ipp.c
index 1964962..429a05e 100644
--- a/cups/ipp.c
+++ b/cups/ipp.c
@@ -1,14 +1,14 @@
 /*
  * Internet Printing Protocol functions for CUPS.
  *
- * Copyright 2007-2015 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -316,7 +316,7 @@ ippAddCollections(
 
 
 /*
- * 'ippAddDate()' - Add a date attribute to an IPP message.
+ * 'ippAddDate()' - Add a dateTime attribute to an IPP message.
  *
  * The @code ipp@ parameter refers to an IPP message previously created using
  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
@@ -1380,7 +1380,7 @@ ippContainsInteger(
  *                         specified string value.
  *
  * Returns non-zero when the attribute contains a matching charset, keyword,
- * language, mimeMediaType, name, text, URI, or URI scheme value.
+ * naturalLanguage, mimeMediaType, name, text, uri, or uriScheme value.
  *
  * @since CUPS 1.7/macOS 10.9@
  */
@@ -1419,11 +1419,6 @@ ippContainsString(
     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 = attr->num_values, avalue = attr->values;
@@ -1440,6 +1435,25 @@ ippContainsString(
 	  }
         }
 
+    case IPP_TAG_MIMETYPE :
+    case IPP_TAG_NAME :
+    case IPP_TAG_NAMELANG :
+    case IPP_TAG_TEXT :
+    case IPP_TAG_TEXTLANG :
+	for (i = attr->num_values, avalue = attr->values;
+	     i > 0;
+	     i --, avalue ++)
+	{
+	  DEBUG_printf(("1ippContainsString: value[%d]=\"%s\"",
+	                attr->num_values - i, avalue->string.text));
+
+	  if (!_cups_strcasecmp(value, avalue->string.text))
+	  {
+	    DEBUG_puts("1ippContainsString: Returning 1 (match)");
+	    return (1);
+	  }
+        }
+
     default :
         break;
   }
@@ -1745,12 +1759,12 @@ ippCopyAttributes(
 
 
 /*
- * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time
- *                     in seconds.
+ * 'ippDateToTime()' - Convert from RFC 2579 Date/Time format to time in
+ *                     seconds.
  */
 
 time_t					/* O - UNIX time value */
-ippDateToTime(const ipp_uchar_t *date)	/* I - RFC 1903 date info */
+ippDateToTime(const ipp_uchar_t *date)	/* I - RFC 2579 date info */
 {
   struct tm	unixdate;		/* UNIX date/time info */
   time_t	t;			/* Computed time */
@@ -1762,7 +1776,7 @@ ippDateToTime(const ipp_uchar_t *date)	/* I - RFC 1903 date info */
   memset(&unixdate, 0, sizeof(unixdate));
 
  /*
-  * RFC-1903 date/time format is:
+  * RFC-2579 date/time format is:
   *
   *    Byte(s)  Description
   *    -------  -----------
@@ -2138,7 +2152,7 @@ ippFirstAttribute(ipp_t *ipp)		/* I - IPP message */
  * 'ippGetBoolean()' - Get a boolean value for an attribute.
  *
  * The @code element@ parameter specifies which value to get from 0 to
- * @link ippGetCount(attr)@ - 1.
+ * @code ippGetCount(attr)@ - 1.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
@@ -2167,7 +2181,7 @@ ippGetBoolean(ipp_attribute_t *attr,	/* I - IPP attribute */
  * 'ippGetCollection()' - Get a collection value for an attribute.
  *
  * The @code element@ parameter specifies which value to get from 0 to
- * @link ippGetCount(attr)@ - 1.
+ * @code ippGetCount(attr)@ - 1.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
@@ -2218,15 +2232,15 @@ ippGetCount(ipp_attribute_t *attr)	/* I - IPP attribute */
 
 
 /*
- * 'ippGetDate()' - Get a date value for an attribute.
+ * 'ippGetDate()' - Get a dateTime value for an attribute.
  *
  * The @code element@ parameter specifies which value to get from 0 to
- * @link ippGetCount(attr)@ - 1.
+ * @code ippGetCount(attr)@ - 1.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
 
-const ipp_uchar_t *			/* O - Date value or @code NULL@ */
+const ipp_uchar_t *			/* O - dateTime value or @code NULL@ */
 ippGetDate(ipp_attribute_t *attr,	/* I - IPP attribute */
            int             element)	/* I - Value number (0-based) */
 {
@@ -2274,7 +2288,7 @@ ippGetGroupTag(ipp_attribute_t *attr)	/* I - IPP attribute */
  * 'ippGetInteger()' - Get the integer/enum value for an attribute.
  *
  * The @code element@ parameter specifies which value to get from 0 to
- * @link ippGetCount(attr)@ - 1.
+ * @code ippGetCount(attr)@ - 1.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
@@ -2327,7 +2341,7 @@ ippGetName(ipp_attribute_t *attr)	/* I - IPP attribute */
  * 'ippGetOctetString()' - Get an octetString value from an IPP attribute.
  *
  * The @code element@ parameter specifies which value to get from 0 to
- * @link ippGetCount(attr)@ - 1.
+ * @code ippGetCount(attr)@ - 1.
  *
  * @since CUPS 1.7/macOS 10.9@
  */
@@ -2390,7 +2404,7 @@ ippGetOperation(ipp_t *ipp)		/* I - IPP request message */
  * 'ippGetRange()' - Get a rangeOfInteger value from an attribute.
  *
  * The @code element@ parameter specifies which value to get from 0 to
- * @link ippGetCount(attr)@ - 1.
+ * @code ippGetCount(attr)@ - 1.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
@@ -2452,7 +2466,7 @@ ippGetRequestId(ipp_t *ipp)		/* I - IPP message */
  * 'ippGetResolution()' - Get a resolution value for an attribute.
  *
  * The @code element@ parameter specifies which value to get from 0 to
- * @link ippGetCount(attr)@ - 1.
+ * @code ippGetCount(attr)@ - 1.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
@@ -2546,7 +2560,7 @@ ippGetStatusCode(ipp_t *ipp)		/* I - IPP response or event message */
  * 'ippGetString()' - Get the string and optionally the language code for an attribute.
  *
  * The @code element@ parameter specifies which value to get from 0 to
- * @link ippGetCount(attr)@ - 1.
+ * @code ippGetCount(attr)@ - 1.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
@@ -2556,13 +2570,16 @@ ippGetString(ipp_attribute_t *attr,	/* I - IPP attribute */
              int             element,	/* I - Value number (0-based) */
 	     const char      **language)/* O - Language code (@code NULL@ for don't care) */
 {
+  ipp_tag_t	tag;			/* Value tag */
+
+
  /*
   * Range check input...
   */
 
-  if (!attr || element < 0 || element >= attr->num_values ||
-      (attr->value_tag != IPP_TAG_TEXTLANG && attr->value_tag != IPP_TAG_NAMELANG &&
-       (attr->value_tag < IPP_TAG_TEXT || attr->value_tag > IPP_TAG_MIMETYPE)))
+  tag = ippGetValueTag(attr);
+
+  if (!attr || element < 0 || element >= attr->num_values || (tag != IPP_TAG_TEXTLANG && tag != IPP_TAG_NAMELANG && (tag < IPP_TAG_TEXT || tag > IPP_TAG_MIMETYPE)))
     return (NULL);
 
  /*
@@ -2608,7 +2625,7 @@ ippGetValueTag(ipp_attribute_t *attr)	/* I - IPP attribute */
 
 int					/* O - Major version number or 0 on error */
 ippGetVersion(ipp_t *ipp,		/* I - IPP message */
-              int   *minor)		/* O - Minor version number or @code NULL@ */
+              int   *minor)		/* O - Minor version number or @code NULL@ for don't care */
 {
  /*
   * Range check input...
@@ -2705,9 +2722,9 @@ ippNew(void)
 /*
  *  'ippNewRequest()' - Allocate a new IPP request message.
  *
- * The new request message is initialized with the attributes-charset and
- * attributes-natural-language attributes added. The
- * attributes-natural-language value is derived from the current locale.
+ * The new request message is initialized with the "attributes-charset" and
+ * "attributes-natural-language" attributes added. The
+ * "attributes-natural-language" value is derived from the current locale.
  *
  * @since CUPS 1.2/macOS 10.5@
  */
@@ -2769,11 +2786,11 @@ ippNewRequest(ipp_op_t op)		/* I - Operation code */
 /*
  * 'ippNewResponse()' - Allocate a new IPP response message.
  *
- * The new response message is initialized with the same version-number,
- * request-id, attributes-charset, and attributes-natural-language as the
- * provided request message.  If the attributes-charset or
- * attributes-natural-language attributes are missing from the request,
- * "utf-8" and a value derived from the current locale are substituted,
+ * The new response message is initialized with the same "version-number",
+ * "request-id", "attributes-charset", and "attributes-natural-language" as the
+ * provided request message.  If the "attributes-charset" or
+ * "attributes-natural-language" attributes are missing from the request,
+ * 'utf-8' and a value derived from the current locale are substituted,
  * respectively.
  *
  * @since CUPS 1.7/macOS 10.9@
@@ -3689,7 +3706,7 @@ ippReadIO(void       *src,		/* I - Data source */
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
  * The @code element@ parameter specifies which value to set from 0 to
- * @link ippGetCount(attr)@.
+ * @code ippGetCount(attr)@.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
@@ -3731,7 +3748,7 @@ ippSetBoolean(ipp_t           *ipp,	/* I  - IPP message */
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
  * The @code element@ parameter specifies which value to set from 0 to
- * @link ippGetCount(attr)@.
+ * @code ippGetCount(attr)@.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
@@ -3772,7 +3789,7 @@ ippSetCollection(
 
 
 /*
- * 'ippSetDate()' - Set a date value in an attribute.
+ * 'ippSetDate()' - Set a dateTime value in an attribute.
  *
  * The @code ipp@ parameter refers to an IPP message previously created using
  * the @link ippNew@, @link ippNewRequest@, or  @link ippNewResponse@ functions.
@@ -3780,7 +3797,7 @@ ippSetCollection(
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
  * The @code element@ parameter specifies which value to set from 0 to
- * @link ippGetCount(attr)@.
+ * @code ippGetCount(attr)@.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
@@ -3789,7 +3806,7 @@ int					/* O  - 1 on success, 0 on failure */
 ippSetDate(ipp_t             *ipp,	/* I  - IPP message */
            ipp_attribute_t   **attr,	/* IO - IPP attribute */
            int               element,	/* I  - Value number (0-based) */
-           const ipp_uchar_t *datevalue)/* I  - Date value */
+           const ipp_uchar_t *datevalue)/* I  - dateTime value */
 {
   _ipp_value_t	*value;			/* Current value */
 
@@ -3837,7 +3854,7 @@ ippSetGroupTag(
     ipp_tag_t       group_tag)		/* I  - Group tag */
 {
  /*
-  * Range check input - group tag must be 0x01 to 0x0F, per RFC 2911...
+  * Range check input - group tag must be 0x01 to 0x0F, per RFC 8011...
   */
 
   if (!ipp || !attr || !*attr ||
@@ -3864,7 +3881,7 @@ ippSetGroupTag(
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
  * The @code element@ parameter specifies which value to set from 0 to
- * @link ippGetCount(attr)@.
+ * @code ippGetCount(attr)@.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
@@ -3949,7 +3966,7 @@ ippSetName(ipp_t           *ipp,	/* I  - IPP message */
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
  * The @code element@ parameter specifies which value to set from 0 to
- * @link ippGetCount(attr)@.
+ * @code ippGetCount(attr)@.
  *
  * @since CUPS 1.7/macOS 10.9@
  */
@@ -4067,7 +4084,7 @@ ippSetOperation(ipp_t    *ipp,		/* I - IPP request message */
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
  * The @code element@ parameter specifies which value to set from 0 to
- * @link ippGetCount(attr)@.
+ * @code ippGetCount(attr)@.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
@@ -4147,7 +4164,7 @@ ippSetRequestId(ipp_t *ipp,		/* I - IPP message */
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
  * The @code element@ parameter specifies which value to set from 0 to
- * @link ippGetCount(attr)@.
+ * @code ippGetCount(attr)@.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
@@ -4255,7 +4272,7 @@ ippSetStatusCode(ipp_t        *ipp,	/* I - IPP response or event message */
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
  * The @code element@ parameter specifies which value to set from 0 to
- * @link ippGetCount(attr)@.
+ * @code ippGetCount(attr)@.
  *
  * @since CUPS 1.6/macOS 10.8@
  */
@@ -4317,7 +4334,7 @@ ippSetString(ipp_t           *ipp,	/* I  - IPP message */
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
  * The @code element@ parameter specifies which value to set from 0 to
- * @link ippGetCount(attr)@.
+ * @code ippGetCount(attr)@.
  *
  * The @code format@ parameter uses formatting characters compatible with the
  * printf family of standard functions.  Additional arguments follow it as
@@ -4355,7 +4372,7 @@ ippSetStringf(ipp_t           *ipp,	/* I  - IPP message */
  * The @code attr@ parameter may be modified as a result of setting the value.
  *
  * The @code element@ parameter specifies which value to set from 0 to
- * @link ippGetCount(attr)@.
+ * @code ippGetCount(attr)@.
  *
  * The @code format@ parameter uses formatting characters compatible with the
  * printf family of standard functions.  Additional arguments follow it as
@@ -4698,19 +4715,19 @@ ippSetVersion(ipp_t *ipp,		/* I - IPP message */
 
 
 /*
- * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format.
+ * 'ippTimeToDate()' - Convert from time in seconds to RFC 2579 format.
  */
 
-const ipp_uchar_t *			/* O - RFC-1903 date/time data */
-ippTimeToDate(time_t t)			/* I - UNIX time value */
+const ipp_uchar_t *			/* O - RFC-2579 date/time data */
+ippTimeToDate(time_t t)			/* I - Time in seconds */
 {
   struct tm	*unixdate;		/* UNIX unixdate/time info */
   ipp_uchar_t	*date = _cupsGlobals()->ipp_date;
-					/* RFC-1903 date/time data */
+					/* RFC-2579 date/time data */
 
 
  /*
-  * RFC-1903 date/time format is:
+  * RFC-2579 date/time format is:
   *
   *    Byte(s)  Description
   *    -------  -----------
@@ -4750,7 +4767,7 @@ ippTimeToDate(time_t t)			/* I - UNIX time value */
  *
  * This function validates the contents of an attribute based on the name and
  * value tag.  1 is returned if the attribute is valid, 0 otherwise.  On
- * failure, cupsLastErrorString() is set to a human-readable message.
+ * failure, @link cupsLastErrorString@ is set to a human-readable message.
  *
  * @since CUPS 1.7/macOS 10.9@
  */
@@ -4806,7 +4823,7 @@ ippValidateAttribute(
   {
     ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
                   _("\"%s\": Bad attribute name - invalid character "
-		    "(RFC 2911 section 4.1.3)."), attr->name);
+		    "(RFC 8011 section 5.1.4)."), attr->name);
     return (0);
   }
 
@@ -4814,7 +4831,7 @@ ippValidateAttribute(
   {
     ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
                   _("\"%s\": Bad attribute name - bad length %d "
-		    "(RFC 2911 section 4.1.3)."), attr->name,
+		    "(RFC 8011 section 5.1.4)."), attr->name,
 		  (int)(ptr - attr->name));
     return (0);
   }
@@ -4832,7 +4849,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
                           _("\"%s\": Bad boolen value %d "
-			    "(RFC 2911 section 4.1.11)."), attr->name,
+			    "(RFC 8011 section 5.1.21)."), attr->name,
 			  attr->values[i].boolean);
 	    return (0);
 	  }
@@ -4846,7 +4863,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad enum value %d - out of range "
-			    "(RFC 2911 section 4.1.4)."), attr->name,
+			    "(RFC 8011 section 5.1.5)."), attr->name,
 			    attr->values[i].integer);
             return (0);
 	  }
@@ -4860,7 +4877,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad octetString value - bad length %d "
-			    "(RFC 2911 section 4.1.10)."), attr->name,
+			    "(RFC 8011 section 5.1.20)."), attr->name,
 			    attr->values[i].unknown.length);
 	    return (0);
 	  }
@@ -4876,7 +4893,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad dateTime month %u "
-			    "(RFC 2911 section 4.1.14)."), attr->name, date[2]);
+			    "(RFC 8011 section 5.1.15)."), attr->name, date[2]);
 	    return (0);
 	  }
 
@@ -4884,7 +4901,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad dateTime day %u "
-			    "(RFC 2911 section 4.1.14)."), attr->name, date[3]);
+			    "(RFC 8011 section 5.1.15)."), attr->name, date[3]);
 	    return (0);
 	  }
 
@@ -4892,7 +4909,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad dateTime hours %u "
-			    "(RFC 2911 section 4.1.14)."), attr->name, date[4]);
+			    "(RFC 8011 section 5.1.15)."), attr->name, date[4]);
 	    return (0);
 	  }
 
@@ -4900,7 +4917,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad dateTime minutes %u "
-			    "(RFC 2911 section 4.1.14)."), attr->name, date[5]);
+			    "(RFC 8011 section 5.1.15)."), attr->name, date[5]);
 	    return (0);
 	  }
 
@@ -4908,7 +4925,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad dateTime seconds %u "
-			    "(RFC 2911 section 4.1.14)."), attr->name, date[6]);
+			    "(RFC 8011 section 5.1.15)."), attr->name, date[6]);
 	    return (0);
 	  }
 
@@ -4916,7 +4933,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad dateTime deciseconds %u "
-			    "(RFC 2911 section 4.1.14)."), attr->name, date[7]);
+			    "(RFC 8011 section 5.1.15)."), attr->name, date[7]);
 	    return (0);
 	  }
 
@@ -4924,7 +4941,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad dateTime UTC sign '%c' "
-			    "(RFC 2911 section 4.1.14)."), attr->name, date[8]);
+			    "(RFC 8011 section 5.1.15)."), attr->name, date[8]);
 	    return (0);
 	  }
 
@@ -4932,7 +4949,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad dateTime UTC hours %u "
-			    "(RFC 2911 section 4.1.14)."), attr->name, date[9]);
+			    "(RFC 8011 section 5.1.15)."), attr->name, date[9]);
 	    return (0);
 	  }
 
@@ -4940,7 +4957,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad dateTime UTC minutes %u "
-			    "(RFC 2911 section 4.1.14)."), attr->name, date[10]);
+			    "(RFC 8011 section 5.1.15)."), attr->name, date[10]);
 	    return (0);
 	  }
 	}
@@ -4954,7 +4971,7 @@ ippValidateAttribute(
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad resolution value %dx%d%s - cross "
 			    "feed resolution must be positive "
-			    "(RFC 2911 section 4.1.15)."), attr->name,
+			    "(RFC 8011 section 5.1.16)."), attr->name,
 			  attr->values[i].resolution.xres,
 			  attr->values[i].resolution.yres,
 			  attr->values[i].resolution.units ==
@@ -4969,7 +4986,7 @@ ippValidateAttribute(
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad resolution value %dx%d%s - feed "
 			    "resolution must be positive "
-			    "(RFC 2911 section 4.1.15)."), attr->name,
+			    "(RFC 8011 section 5.1.16)."), attr->name,
 			  attr->values[i].resolution.xres,
 			  attr->values[i].resolution.yres,
 			  attr->values[i].resolution.units ==
@@ -4984,7 +5001,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad resolution value %dx%d%s - bad "
-			    "units value (RFC 2911 section 4.1.15)."),
+			    "units value (RFC 8011 section 5.1.16)."),
 			  attr->name, attr->values[i].resolution.xres,
 			  attr->values[i].resolution.yres,
 			  attr->values[i].resolution.units ==
@@ -5003,7 +5020,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad rangeOfInteger value %d-%d - lower "
-			    "greater than upper (RFC 2911 section 4.1.13)."),
+			    "greater than upper (RFC 8011 section 5.1.14)."),
 			  attr->name, attr->values[i].range.lower,
 			  attr->values[i].range.upper);
 	    return (0);
@@ -5065,7 +5082,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad text value \"%s\" - bad UTF-8 "
-			    "sequence (RFC 2911 section 4.1.1)."), attr->name,
+			    "sequence (RFC 8011 section 5.1.2)."), attr->name,
 			  attr->values[i].string.text);
 	    return (0);
 	  }
@@ -5074,7 +5091,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad text value \"%s\" - bad length %d "
-			    "(RFC 2911 section 4.1.1)."), attr->name,
+			    "(RFC 8011 section 5.1.2)."), attr->name,
 			  attr->values[i].string.text,
 			  (int)(ptr - attr->values[i].string.text));
 	    return (0);
@@ -5123,7 +5140,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad name value \"%s\" - bad UTF-8 "
-			    "sequence (RFC 2911 section 4.1.2)."), attr->name,
+			    "sequence (RFC 8011 section 5.1.3)."), attr->name,
 			  attr->values[i].string.text);
 	    return (0);
 	  }
@@ -5132,7 +5149,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad name value \"%s\" - bad length %d "
-			    "(RFC 2911 section 4.1.2)."), attr->name,
+			    "(RFC 8011 section 5.1.3)."), attr->name,
 			  attr->values[i].string.text,
 			  (int)(ptr - attr->values[i].string.text));
 	    return (0);
@@ -5152,7 +5169,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad keyword value \"%s\" - invalid "
-			    "character (RFC 2911 section 4.1.3)."),
+			    "character (RFC 8011 section 5.1.4)."),
 			  attr->name, attr->values[i].string.text);
 	    return (0);
 	  }
@@ -5161,7 +5178,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad keyword value \"%s\" - bad "
-			    "length %d (RFC 2911 section 4.1.3)."),
+			    "length %d (RFC 8011 section 5.1.4)."),
 			  attr->name, attr->values[i].string.text,
 			  (int)(ptr - attr->values[i].string.text));
 	    return (0);
@@ -5183,7 +5200,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad URI value \"%s\" - %s "
-			    "(RFC 2911 section 4.1.5)."), attr->name,
+			    "(RFC 8011 section 5.1.6)."), attr->name,
 			  attr->values[i].string.text,
 			  uri_status_strings[uri_status -
 					     HTTP_URI_STATUS_OVERFLOW]);
@@ -5194,7 +5211,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad URI value \"%s\" - bad length %d "
-			    "(RFC 2911 section 4.1.5)."), attr->name,
+			    "(RFC 8011 section 5.1.6)."), attr->name,
 			  attr->values[i].string.text,
 			  (int)strlen(attr->values[i].string.text));
 	  }
@@ -5217,7 +5234,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad uriScheme value \"%s\" - bad "
-			    "characters (RFC 2911 section 4.1.6)."),
+			    "characters (RFC 8011 section 5.1.7)."),
 			  attr->name, attr->values[i].string.text);
 	    return (0);
 	  }
@@ -5226,7 +5243,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad uriScheme value \"%s\" - bad "
-			    "length %d (RFC 2911 section 4.1.6)."),
+			    "length %d (RFC 8011 section 5.1.7)."),
 			  attr->name, attr->values[i].string.text,
 			  (int)(ptr - attr->values[i].string.text));
 	    return (0);
@@ -5246,7 +5263,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad charset value \"%s\" - bad "
-			    "characters (RFC 2911 section 4.1.7)."),
+			    "characters (RFC 8011 section 5.1.8)."),
 			  attr->name, attr->values[i].string.text);
 	    return (0);
 	  }
@@ -5255,7 +5272,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad charset value \"%s\" - bad "
-			    "length %d (RFC 2911 section 4.1.7)."),
+			    "length %d (RFC 8011 section 5.1.8)."),
 			  attr->name, attr->values[i].string.text,
 			  (int)(ptr - attr->values[i].string.text));
 	    return (0);
@@ -5301,7 +5318,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad naturalLanguage value \"%s\" - bad "
-			    "characters (RFC 2911 section 4.1.8)."),
+			    "characters (RFC 8011 section 5.1.9)."),
 			  attr->name, attr->values[i].string.text);
 	    regfree(&re);
 	    return (0);
@@ -5311,7 +5328,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad naturalLanguage value \"%s\" - bad "
-			    "length %d (RFC 2911 section 4.1.8)."),
+			    "length %d (RFC 8011 section 5.1.9)."),
 			  attr->name, attr->values[i].string.text,
 			  (int)strlen(attr->values[i].string.text));
 	    regfree(&re);
@@ -5355,7 +5372,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad mimeMediaType value \"%s\" - bad "
-			    "characters (RFC 2911 section 4.1.9)."),
+			    "characters (RFC 8011 section 5.1.10)."),
 			  attr->name, attr->values[i].string.text);
 	    regfree(&re);
 	    return (0);
@@ -5365,7 +5382,7 @@ ippValidateAttribute(
 	  {
 	    ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST,
 			  _("\"%s\": Bad mimeMediaType value \"%s\" - bad "
-			    "length %d (RFC 2911 section 4.1.9)."),
+			    "length %d (RFC 8011 section 5.1.10)."),
 			  attr->name, attr->values[i].string.text,
 			  (int)strlen(attr->values[i].string.text));
 	    regfree(&re);
@@ -5388,8 +5405,8 @@ ippValidateAttribute(
  * 'ippValidateAttributes()' - Validate all attributes in an IPP message.
  *
  * This function validates the contents of the IPP message, including each
- * attribute.  Like @link ippValidateAttribute@, cupsLastErrorString() is set
- * to a human-readable message on failure.
+ * attribute.  Like @link ippValidateAttribute@, @link cupsLastErrorString@ is
+ * set to a human-readable message on failure.
  *
  * @since CUPS 1.7/macOS 10.9@
  */
diff --git a/cups/ipp.h b/cups/ipp.h
index 84585a2..2a4f546 100644
--- a/cups/ipp.h
+++ b/cups/ipp.h
@@ -1,14 +1,14 @@
 /*
  * Internet Printing Protocol definitions for CUPS.
  *
- * Copyright 2007-2014 by Apple Inc.
+ * Copyright 2007-2017 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -77,7 +77,7 @@ extern "C" {
  * Types and structures...
  */
 
-typedef enum ipp_dstate_e		/**** Document states ****/
+typedef enum ipp_dstate_e		/**** Document states @exclude all@ ****/
 {
   IPP_DOCUMENT_PENDING = 3,		/* Document is pending */
   IPP_DOCUMENT_PROCESSING = 5,		/* Document is processing */
@@ -94,10 +94,10 @@ typedef enum ipp_dstate_e		/**** Document states ****/
 #  endif /* !_CUPS_NO_DEPRECATED */
 } ipp_dstate_t;
 
-typedef enum ipp_finishings_e		/**** Finishings ****/
+typedef enum ipp_finishings_e		/**** Finishings values ****/
 {
   IPP_FINISHINGS_NONE = 3,		/* No finishing */
-  IPP_FINISHINGS_STAPLE,		/* Staple (any location) */
+  IPP_FINISHINGS_STAPLE,		/* Staple (any location/method) */
   IPP_FINISHINGS_PUNCH,			/* Punch (any location/count) */
   IPP_FINISHINGS_COVER,			/* Add cover */
   IPP_FINISHINGS_BIND,			/* Bind */
@@ -150,6 +150,10 @@ typedef enum ipp_finishings_e		/**** Finishings ****/
   IPP_FINISHINGS_PUNCH_QUAD_TOP,	/* Punch 4 holes top edge */
   IPP_FINISHINGS_PUNCH_QUAD_RIGHT,	/* Punch 4 holes right side */
   IPP_FINISHINGS_PUNCH_QUAD_BOTTOM,	/* Punch 4 holes bottom edge */
+  IPP_FINISHINGS_PUNCH_MULTIPLE_LEFT,	/* Pucnh multiple holes left side */
+  IPP_FINISHINGS_PUNCH_MULTIPLE_TOP,	/* Pucnh multiple holes top edge */
+  IPP_FINISHINGS_PUNCH_MULTIPLE_RIGHT,	/* Pucnh multiple holes right side */
+  IPP_FINISHINGS_PUNCH_MULTIPLE_BOTTOM,	/* Pucnh multiple holes bottom edge */
   IPP_FINISHINGS_FOLD_ACCORDIAN = 90,	/* Accordian-fold the paper vertically into four sections */
   IPP_FINISHINGS_FOLD_DOUBLE_GATE,	/* Fold the top and bottom quarters of the paper towards the midline, then fold in half vertically */
   IPP_FINISHINGS_FOLD_GATE,		/* Fold the top and bottom quarters of the paper towards the midline */
@@ -161,41 +165,42 @@ typedef enum ipp_finishings_e		/**** Finishings ****/
   IPP_FINISHINGS_FOLD_POSTER,		/* Fold the paper in half horizontally and vertically; sometimes also called a cross fold */
   IPP_FINISHINGS_FOLD_RIGHT_GATE,	/* Fold the bottom quarter of the paper towards the midline */
   IPP_FINISHINGS_FOLD_Z,		/* Fold the paper vertically into three sections, forming a Z */
+  IPP_FINISHINGS_FOLD_ENGINEERING_Z,	/* Fold the paper vertically into two small sections and one larger, forming an elongated Z */
 
   /* CUPS extensions for finishings (pre-standard versions of values above) */
   IPP_FINISHINGS_CUPS_PUNCH_TOP_LEFT = 0x40000046,
-					/* Punch 1 hole top left */
-  IPP_FINISHINGS_CUPS_PUNCH_BOTTOM_LEFT,/* Punch 1 hole bottom left */
-  IPP_FINISHINGS_CUPS_PUNCH_TOP_RIGHT,	/* Punch 1 hole top right */
+					/* Punch 1 hole top left @exclude all@ */
+  IPP_FINISHINGS_CUPS_PUNCH_BOTTOM_LEFT,/* Punch 1 hole bottom left @exclude all@ */
+  IPP_FINISHINGS_CUPS_PUNCH_TOP_RIGHT,	/* Punch 1 hole top right @exclude all@ */
   IPP_FINISHINGS_CUPS_PUNCH_BOTTOM_RIGHT,
-					/* Punch 1 hole bottom right */
-  IPP_FINISHINGS_CUPS_PUNCH_DUAL_LEFT,	/* Punch 2 holes left side */
-  IPP_FINISHINGS_CUPS_PUNCH_DUAL_TOP,	/* Punch 2 holes top edge */
-  IPP_FINISHINGS_CUPS_PUNCH_DUAL_RIGHT,	/* Punch 2 holes right side */
-  IPP_FINISHINGS_CUPS_PUNCH_DUAL_BOTTOM,/* Punch 2 holes bottom edge */
-  IPP_FINISHINGS_CUPS_PUNCH_TRIPLE_LEFT,/* Punch 3 holes left side */
-  IPP_FINISHINGS_CUPS_PUNCH_TRIPLE_TOP,	/* Punch 3 holes top edge */
+					/* Punch 1 hole bottom right @exclude all@ */
+  IPP_FINISHINGS_CUPS_PUNCH_DUAL_LEFT,	/* Punch 2 holes left side @exclude all@ */
+  IPP_FINISHINGS_CUPS_PUNCH_DUAL_TOP,	/* Punch 2 holes top edge @exclude all@ */
+  IPP_FINISHINGS_CUPS_PUNCH_DUAL_RIGHT,	/* Punch 2 holes right side @exclude all@ */
+  IPP_FINISHINGS_CUPS_PUNCH_DUAL_BOTTOM,/* Punch 2 holes bottom edge @exclude all@ */
+  IPP_FINISHINGS_CUPS_PUNCH_TRIPLE_LEFT,/* Punch 3 holes left side @exclude all@ */
+  IPP_FINISHINGS_CUPS_PUNCH_TRIPLE_TOP,	/* Punch 3 holes top edge @exclude all@ */
   IPP_FINISHINGS_CUPS_PUNCH_TRIPLE_RIGHT,
-					/* Punch 3 holes right side */
+					/* Punch 3 holes right side @exclude all@ */
   IPP_FINISHINGS_CUPS_PUNCH_TRIPLE_BOTTOM,
-					/* Punch 3 holes bottom edge */
-  IPP_FINISHINGS_CUPS_PUNCH_QUAD_LEFT,	/* Punch 4 holes left side */
-  IPP_FINISHINGS_CUPS_PUNCH_QUAD_TOP,	/* Punch 4 holes top edge */
-  IPP_FINISHINGS_CUPS_PUNCH_QUAD_RIGHT,	/* Punch 4 holes right side */
-  IPP_FINISHINGS_CUPS_PUNCH_QUAD_BOTTOM,/* Punch 4 holes bottom edge */
+					/* Punch 3 holes bottom edge @exclude all@ */
+  IPP_FINISHINGS_CUPS_PUNCH_QUAD_LEFT,	/* Punch 4 holes left side @exclude all@ */
+  IPP_FINISHINGS_CUPS_PUNCH_QUAD_TOP,	/* Punch 4 holes top edge @exclude all@ */
+  IPP_FINISHINGS_CUPS_PUNCH_QUAD_RIGHT,	/* Punch 4 holes right side @exclude all@ */
+  IPP_FINISHINGS_CUPS_PUNCH_QUAD_BOTTOM,/* Punch 4 holes bottom edge @exclude all@ */
 
   IPP_FINISHINGS_CUPS_FOLD_ACCORDIAN = 0x4000005A,
-					/* Accordian-fold the paper vertically into four sections */
-  IPP_FINISHINGS_CUPS_FOLD_DOUBLE_GATE,	/* Fold the top and bottom quarters of the paper towards the midline, then fold in half vertically */
-  IPP_FINISHINGS_CUPS_FOLD_GATE,	/* Fold the top and bottom quarters of the paper towards the midline */
-  IPP_FINISHINGS_CUPS_FOLD_HALF,	/* Fold the paper in half vertically */
-  IPP_FINISHINGS_CUPS_FOLD_HALF_Z,	/* Fold the paper in half horizontally, then Z-fold the paper vertically */
-  IPP_FINISHINGS_CUPS_FOLD_LEFT_GATE,	/* Fold the top quarter of the paper towards the midline */
-  IPP_FINISHINGS_CUPS_FOLD_LETTER,	/* Fold the paper into three sections vertically; sometimes also known as a C fold*/
-  IPP_FINISHINGS_CUPS_FOLD_PARALLEL,	/* Fold the paper in half vertically two times, yielding four sections */
-  IPP_FINISHINGS_CUPS_FOLD_POSTER,	/* Fold the paper in half horizontally and vertically; sometimes also called a cross fold */
-  IPP_FINISHINGS_CUPS_FOLD_RIGHT_GATE,	/* Fold the bottom quarter of the paper towards the midline */
-  IPP_FINISHINGS_CUPS_FOLD_Z		/* Fold the paper vertically into three sections, forming a Z */
+					/* Accordian-fold the paper vertically into four sections @exclude all@ */
+  IPP_FINISHINGS_CUPS_FOLD_DOUBLE_GATE,	/* Fold the top and bottom quarters of the paper towards the midline, then fold in half vertically @exclude all@ */
+  IPP_FINISHINGS_CUPS_FOLD_GATE,	/* Fold the top and bottom quarters of the paper towards the midline @exclude all@ */
+  IPP_FINISHINGS_CUPS_FOLD_HALF,	/* Fold the paper in half vertically @exclude all@ */
+  IPP_FINISHINGS_CUPS_FOLD_HALF_Z,	/* Fold the paper in half horizontally, then Z-fold the paper vertically @exclude all@ */
+  IPP_FINISHINGS_CUPS_FOLD_LEFT_GATE,	/* Fold the top quarter of the paper towards the midline @exclude all@ */
+  IPP_FINISHINGS_CUPS_FOLD_LETTER,	/* Fold the paper into three sections vertically; sometimes also known as a C fold @exclude all@ */
+  IPP_FINISHINGS_CUPS_FOLD_PARALLEL,	/* Fold the paper in half vertically two times, yielding four sections @exclude all@ */
+  IPP_FINISHINGS_CUPS_FOLD_POSTER,	/* Fold the paper in half horizontally and vertically; sometimes also called a cross fold @exclude all@ */
+  IPP_FINISHINGS_CUPS_FOLD_RIGHT_GATE,	/* Fold the bottom quarter of the paper towards the midline @exclude all@ */
+  IPP_FINISHINGS_CUPS_FOLD_Z		/* Fold the paper vertically into three sections, forming a Z @exclude all@ */
 } ipp_finishings_t;
 #  ifndef _CUPS_NO_DEPRECATED
 #    define IPP_FINISHINGS_JOB_OFFSET	IPP_FINISHINGS_JOG_OFFSET
@@ -203,7 +208,7 @@ typedef enum ipp_finishings_e		/**** Finishings ****/
 typedef enum ipp_finishings_e ipp_finish_t;
 #  endif /* !_CUPS_NO_DEPRECATED */
 
-typedef enum ipp_jcollate_e		/**** Job collation types ****/
+typedef enum ipp_jcollate_e		/**** Job collation types @deprecated@ @exclude all@ ****/
 {
   IPP_JCOLLATE_UNCOLLATED_SHEETS = 3,
   IPP_JCOLLATE_COLLATED_DOCUMENTS,
@@ -243,98 +248,98 @@ 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 */
-  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 */
-  IPP_OP_CANCEL_JOB,			/* Cancel a job */
-  IPP_OP_GET_JOB_ATTRIBUTES,		/* Get job attributes */
-  IPP_OP_GET_JOBS,			/* Get a list of jobs */
-  IPP_OP_GET_PRINTER_ATTRIBUTES,	/* Get printer attributes */
-  IPP_OP_HOLD_JOB,			/* Hold a job for printing */
-  IPP_OP_RELEASE_JOB,			/* Release a job for printing */
-  IPP_OP_RESTART_JOB,			/* Reprint a job */
-  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 */
-  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/macOS 10.5@ */
-  IPP_OP_CREATE_JOB_SUBSCRIPTIONS,	/* Create one of more job subscriptions @since CUPS 1.2/macOS 10.5@ */
-  IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES,	/* Get subscription attributes @since CUPS 1.2/macOS 10.5@ */
-  IPP_OP_GET_SUBSCRIPTIONS,		/* Get list of subscriptions @since CUPS 1.2/macOS 10.5@ */
-  IPP_OP_RENEW_SUBSCRIPTION,		/* Renew a printer subscription @since CUPS 1.2/macOS 10.5@ */
-  IPP_OP_CANCEL_SUBSCRIPTION,		/* Cancel a subscription @since CUPS 1.2/macOS 10.5@ */
-  IPP_OP_GET_NOTIFICATIONS,		/* Get notification events @since CUPS 1.2/macOS 10.5@ */
-  IPP_OP_SEND_NOTIFICATIONS,		/* Send notification events @private@ */
-  IPP_OP_GET_RESOURCE_ATTRIBUTES,	/* Get resource attributes @private@ */
-  IPP_OP_GET_RESOURCE_DATA,		/* Get resource data @private@ */
-  IPP_OP_GET_RESOURCES,			/* Get list of resources @private@ */
-  IPP_OP_GET_PRINT_SUPPORT_FILES,	/* Get printer support files @private@ */
-  IPP_OP_ENABLE_PRINTER,		/* Start a printer */
-  IPP_OP_DISABLE_PRINTER,		/* Stop a printer */
+  IPP_OP_PRINT_JOB = 0x0002,		/* Print-Job: Print a single file */
+  IPP_OP_PRINT_URI,			/* Print-URI: Print a single URL @exclude all@ */
+  IPP_OP_VALIDATE_JOB,			/* Validate-Job: Validate job values prior to submission */
+  IPP_OP_CREATE_JOB,			/* Create-Job: Create an empty print job */
+  IPP_OP_SEND_DOCUMENT,			/* Send-Document: Add a file to a job */
+  IPP_OP_SEND_URI,			/* Send-URI: Add a URL to a job @exclude all@ */
+  IPP_OP_CANCEL_JOB,			/* Cancel-Job: Cancel a job */
+  IPP_OP_GET_JOB_ATTRIBUTES,		/* Get-Job-Attribute: Get information about a job */
+  IPP_OP_GET_JOBS,			/* Get-Jobs: Get a list of jobs */
+  IPP_OP_GET_PRINTER_ATTRIBUTES,	/* Get-Printer-Attributes: Get information about a printer */
+  IPP_OP_HOLD_JOB,			/* Hold-Job: Hold a job for printing */
+  IPP_OP_RELEASE_JOB,			/* Release-Job: Release a job for printing */
+  IPP_OP_RESTART_JOB,			/* Restart-Job: Reprint a job @deprecated@ */
+  IPP_OP_PAUSE_PRINTER = 0x0010,	/* Pause-Printer: Stop a printer */
+  IPP_OP_RESUME_PRINTER,		/* Resume-Printer: Start a printer */
+  IPP_OP_PURGE_JOBS,			/* Purge-Jobs: Delete all jobs @deprecated@ @exclude all@ */
+  IPP_OP_SET_PRINTER_ATTRIBUTES,	/* Set-Printer-Attributes: Set printer values */
+  IPP_OP_SET_JOB_ATTRIBUTES,		/* Set-Job-Attributes: Set job values */
+  IPP_OP_GET_PRINTER_SUPPORTED_VALUES,	/* Get-Printer-Supported-Values: Get supported values */
+  IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS,	/* Create-Printer-Subscriptions: Create one or more printer subscriptions @since CUPS 1.2/macOS 10.5@ */
+  IPP_OP_CREATE_JOB_SUBSCRIPTIONS,	/* Create-Job-Subscriptions: Create one of more job subscriptions @since CUPS 1.2/macOS 10.5@ */
+  IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES,	/* Get-Subscription-Attributes: Get subscription information @since CUPS 1.2/macOS 10.5@ */
+  IPP_OP_GET_SUBSCRIPTIONS,		/* Get-Subscriptions: Get list of subscriptions @since CUPS 1.2/macOS 10.5@ */
+  IPP_OP_RENEW_SUBSCRIPTION,		/* Renew-Subscription: Renew a printer subscription @since CUPS 1.2/macOS 10.5@ */
+  IPP_OP_CANCEL_SUBSCRIPTION,		/* Cancel-Subscription: Cancel a subscription @since CUPS 1.2/macOS 10.5@ */
+  IPP_OP_GET_NOTIFICATIONS,		/* Get-Notifications: Get notification events @since CUPS 1.2/macOS 10.5@ */
+  IPP_OP_SEND_NOTIFICATIONS,		/* Send-Notifications: Send notification events @private@ */
+  IPP_OP_GET_RESOURCE_ATTRIBUTES,	/* Get-Resource-Attributes: Get resource information @private@ */
+  IPP_OP_GET_RESOURCE_DATA,		/* Get-Resource-Data: Get resource data @private@ @deprecated@ */
+  IPP_OP_GET_RESOURCES,			/* Get-Resources: Get list of resources @private@ */
+  IPP_OP_GET_PRINT_SUPPORT_FILES,	/* Get-Printer-Support-Files: Get printer support files @private@ */
+  IPP_OP_ENABLE_PRINTER,		/* Enable-Printer: Accept new jobs for a printer */
+  IPP_OP_DISABLE_PRINTER,		/* Disable-Printer: Reject new jobs for a printer */
   IPP_OP_PAUSE_PRINTER_AFTER_CURRENT_JOB,
-					/* 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 */
-  IPP_OP_VALIDATE_DOCUMENT,		/* Validate-Document */
-  IPP_OP_ADD_DOCUMENT_IMAGES,		/* Add-Document-Images */
-  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 */
+					/* Pause-Printer-After-Current-Job: Stop printer after the current job */
+  IPP_OP_HOLD_NEW_JOBS,			/* Hold-New-Jobs: Hold new jobs */
+  IPP_OP_RELEASE_HELD_NEW_JOBS,		/* Release-Held-New-Jobs: Release new jobs that were previously held */
+  IPP_OP_DEACTIVATE_PRINTER,		/* Deactivate-Printer: Stop a printer and do not accept jobs @deprecated@ @exclude all@ */
+  IPP_OP_ACTIVATE_PRINTER,		/* Activate-Printer: Start a printer and accept jobs @deprecated@ @exclude all@ */
+  IPP_OP_RESTART_PRINTER,		/* Restart-Printer: Restart a printer @exclude all@ */
+  IPP_OP_SHUTDOWN_PRINTER,		/* Shutdown-Printer: Turn a printer off @exclude all@ */
+  IPP_OP_STARTUP_PRINTER,		/* Startup-Printer: Turn a printer on @exclude all@ */
+  IPP_OP_REPROCESS_JOB,			/* Reprocess-Job: Reprint a job @deprecated@ @exclude all@*/
+  IPP_OP_CANCEL_CURRENT_JOB,		/* Cancel-Current-Job: Cancel the current job */
+  IPP_OP_SUSPEND_CURRENT_JOB,		/* Suspend-Current-Job: Suspend the current job */
+  IPP_OP_RESUME_JOB,			/* Resume-Job: Resume the current job */
+  IPP_OP_PROMOTE_JOB,			/* Promote-Job: Promote a job to print sooner */
+  IPP_OP_SCHEDULE_JOB_AFTER,		/* Schedule-Job-After: Schedule a job to print after another */
+  IPP_OP_CANCEL_DOCUMENT = 0x0033,	/* Cancel-Document: Cancel a document @exclude all@ */
+  IPP_OP_GET_DOCUMENT_ATTRIBUTES,	/* Get-Document-Attributes: Get document information @exclude all@ */
+  IPP_OP_GET_DOCUMENTS,			/* Get-Documents: Get a list of documents in a job @exclude all@ */
+  IPP_OP_DELETE_DOCUMENT,		/* Delete-Document: Delete a document @deprecated@  @exclude all@ */
+  IPP_OP_SET_DOCUMENT_ATTRIBUTES,	/* Set-Document-Attributes: Set document values @exclude all@ */
+  IPP_OP_CANCEL_JOBS,			/* Cancel-Jobs: Cancel all jobs (administrative) */
+  IPP_OP_CANCEL_MY_JOBS,		/* Cancel-My-Jobs: Cancel a user's jobs */
+  IPP_OP_RESUBMIT_JOB,			/* Resubmit-Job: Copy and reprint a job @exclude all@ */
+  IPP_OP_CLOSE_JOB,			/* Close-Job: Close a job and start printing */
+  IPP_OP_IDENTIFY_PRINTER,		/* Identify-Printer: Make the printer beep, flash, or display a message for identification */
+  IPP_OP_VALIDATE_DOCUMENT,		/* Validate-Document: Validate document values prior to submission @exclude all@ */
+  IPP_OP_ADD_DOCUMENT_IMAGES,		/* Add-Document-Images: Add image(s) from the specified scanner source @exclude all@ */
+  IPP_OP_ACKNOWLEDGE_DOCUMENT,		/* Acknowledge-Document: Acknowledge processing of a document @exclude all@ */
+  IPP_OP_ACKNOWLEDGE_IDENTIFY_PRINTER,	/* Acknowledge-Identify-Printer: Acknowledge action on an Identify-Printer request @exclude all@ */
+  IPP_OP_ACKNOWLEDGE_JOB,		/* Acknowledge-Job: Acknowledge processing of a job @exclude all@ */
+  IPP_OP_FETCH_DOCUMENT,		/* Fetch-Document: Fetch a document for processing @exclude all@ */
+  IPP_OP_FETCH_JOB,			/* Fetch-Job: Fetch a job for processing @exclude all@ */
+  IPP_OP_GET_OUTPUT_DEVICE_ATTRIBUTES,	/* Get-Output-Device-Attributes: Get printer information for a specific output device @exclude all@ */
+  IPP_OP_UPDATE_ACTIVE_JOBS,		/* Update-Active-Jobs: Update the list of active jobs that a proxy has processed @exclude all@ */
+  IPP_OP_DEREGISTER_OUTPUT_DEVICE,	/* Deregister-Output-Device: Remove an output device @exclude all@ */
+  IPP_OP_UPDATE_DOCUMENT_STATUS,	/* Update-Document-Status: Update document values @exclude all@ */
+  IPP_OP_UPDATE_JOB_STATUS,		/* Update-Job-Status: Update job values @exclude all@ */
   IPP_OP_UPDATE_OUTPUT_DEVICE_ATTRIBUTES,
-					/* Update-Output-Device-Attributes */
-  IPP_OP_GET_NEXT_DOCUMENT_DATA,	/* Get-Next-Document-Data */
+					/* Update-Output-Device-Attributes: Update output device values @exclude all@ */
+  IPP_OP_GET_NEXT_DOCUMENT_DATA,	/* Get-Next-Document-Data: Scan more document data @exclude all@ */
 
   IPP_OP_PRIVATE = 0x4000,		/* Reserved @private@ */
-  IPP_OP_CUPS_GET_DEFAULT,		/* Get the default printer */
-  IPP_OP_CUPS_GET_PRINTERS,		/* Get a list of printers and/or classes */
-  IPP_OP_CUPS_ADD_MODIFY_PRINTER,	/* Add or modify a printer */
-  IPP_OP_CUPS_DELETE_PRINTER,		/* Delete a printer */
-  IPP_OP_CUPS_GET_CLASSES,		/* Get a list of classes @deprecated@ */
-  IPP_OP_CUPS_ADD_MODIFY_CLASS,		/* Add or modify a class */
-  IPP_OP_CUPS_DELETE_CLASS,		/* Delete a class */
-  IPP_OP_CUPS_ACCEPT_JOBS,		/* Accept new jobs on a printer */
-  IPP_OP_CUPS_REJECT_JOBS,		/* Reject new jobs on a printer */
-  IPP_OP_CUPS_SET_DEFAULT,		/* Set the default printer */
-  IPP_OP_CUPS_GET_DEVICES,		/* Get a list of supported devices @deprecated@ */
-  IPP_OP_CUPS_GET_PPDS,			/* Get a list of supported drivers @deprecated@ */
-  IPP_OP_CUPS_MOVE_JOB,			/* Move a job to a different printer */
-  IPP_OP_CUPS_AUTHENTICATE_JOB,		/* Authenticate a job @since CUPS 1.2/macOS 10.5@ */
-  IPP_OP_CUPS_GET_PPD,			/* Get a PPD file @deprecated@ */
-  IPP_OP_CUPS_GET_DOCUMENT = 0x4027,	/* Get a document file @since CUPS 1.4/macOS 10.6@ */
-  IPP_OP_CUPS_CREATE_LOCAL_PRINTER	/* Create a local (temporary) printer @since CUPS 2.2 */
+  IPP_OP_CUPS_GET_DEFAULT,		/* CUPS-Get-Default: Get the default printer */
+  IPP_OP_CUPS_GET_PRINTERS,		/* CUPS-Get-Printers: Get a list of printers and/or classes */
+  IPP_OP_CUPS_ADD_MODIFY_PRINTER,	/* CUPS-Add-Modify-Printer: Add or modify a printer */
+  IPP_OP_CUPS_DELETE_PRINTER,		/* CUPS-Delete-Printer: Delete a printer */
+  IPP_OP_CUPS_GET_CLASSES,		/* CUPS-Get-Classes: Get a list of classes @deprecated@ @exclude all@ */
+  IPP_OP_CUPS_ADD_MODIFY_CLASS,		/* CUPS-Add-Modify-Class: Add or modify a class */
+  IPP_OP_CUPS_DELETE_CLASS,		/* CUPS-Delete-Class: Delete a class */
+  IPP_OP_CUPS_ACCEPT_JOBS,		/* CUPS-Accept-Jobs: Accept new jobs on a printer @exclude all@ */
+  IPP_OP_CUPS_REJECT_JOBS,		/* CUPS-Reject-Jobs: Reject new jobs on a printer @exclude all@ */
+  IPP_OP_CUPS_SET_DEFAULT,		/* CUPS-Set-Default: Set the default printer */
+  IPP_OP_CUPS_GET_DEVICES,		/* CUPS-Get-Devices: Get a list of supported devices @deprecated@ */
+  IPP_OP_CUPS_GET_PPDS,			/* CUPS-Get-PPDs: Get a list of supported drivers @deprecated@ */
+  IPP_OP_CUPS_MOVE_JOB,			/* CUPS-Move-Job: Move a job to a different printer */
+  IPP_OP_CUPS_AUTHENTICATE_JOB,		/* CUPS-Authenticate-Job: Authenticate a job @since CUPS 1.2/macOS 10.5@ */
+  IPP_OP_CUPS_GET_PPD,			/* CUPS-Get-PPD: Get a PPD file @deprecated@ */
+  IPP_OP_CUPS_GET_DOCUMENT = 0x4027,	/* CUPS-Get-Document: Get a document file @since CUPS 1.4/macOS 10.6@ */
+  IPP_OP_CUPS_CREATE_LOCAL_PRINTER	/* CUPS-Create-Local-Printer: Create a local (temporary) printer @since CUPS 2.2@ */
 
 #  ifndef _CUPS_NO_DEPRECATED
 #    define IPP_PRINT_JOB			IPP_OP_PRINT_JOB
@@ -359,7 +364,7 @@ typedef enum ipp_op_e			/**** IPP operations ****/
 #    define IPP_CREATE_PRINTER_SUBSCRIPTION	IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS
 #    define IPP_CREATE_JOB_SUBSCRIPTION		IPP_OP_CREATE_JOB_SUBSCRIPTIONS
 #    define IPP_OP_CREATE_PRINTER_SUBSCRIPTION	IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS
-#    define IPP_OP_CREATE_JOB_SUBSCRIPTION		IPP_OP_CREATE_JOB_SUBSCRIPTIONS
+#    define IPP_OP_CREATE_JOB_SUBSCRIPTION	IPP_OP_CREATE_JOB_SUBSCRIPTIONS
 #    define IPP_GET_SUBSCRIPTION_ATTRIBUTES	IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES
 #    define IPP_GET_SUBSCRIPTIONS		IPP_OP_GET_SUBSCRIPTIONS
 #    define IPP_RENEW_SUBSCRIPTION		IPP_OP_RENEW_SUBSCRIPTION
@@ -437,7 +442,7 @@ typedef enum ipp_orient_e		/**** Orientation values ****/
 #  endif /* !_CUPS_NO_DEPRECATED */
 } ipp_orient_t;
 
-typedef enum ipp_pstate_e		/**** Printer states ****/
+typedef enum ipp_pstate_e		/**** Printer state values ****/
 {
   IPP_PSTATE_IDLE = 3,			/* Printer is idle */
   IPP_PSTATE_PROCESSING,		/* Printer is working */
@@ -450,7 +455,7 @@ typedef enum ipp_pstate_e		/**** Printer states ****/
 #  endif /* _CUPS_NO_DEPRECATED */
 } ipp_pstate_t;
 
-typedef enum ipp_quality_e		/**** Qualities ****/
+typedef enum ipp_quality_e		/**** Print quality values ****/
 {
   IPP_QUALITY_DRAFT = 3,		/* Draft quality */
   IPP_QUALITY_NORMAL,			/* Normal quality */
@@ -463,7 +468,7 @@ typedef enum ipp_res_e			/**** Resolution units ****/
   IPP_RES_PER_CM			/* Pixels per centimeter */
 } ipp_res_t;
 
-typedef enum ipp_state_e		/**** IPP states ****/
+typedef enum ipp_state_e		/**** ipp_t state values ****/
 {
   IPP_STATE_ERROR = -1,			/* An error occurred */
   IPP_STATE_IDLE,			/* Nothing is happening/request completed */
@@ -480,7 +485,7 @@ typedef enum ipp_state_e		/**** IPP states ****/
 #  endif /* !_CUPS_NO_DEPRECATED */
 } ipp_state_t;
 
-typedef enum ipp_status_e		/**** IPP status codes ****/
+typedef enum ipp_status_e		/**** IPP status code values ****/
 {
   IPP_STATUS_CUPS_INVALID = -1,		/* Invalid status name for @link ippErrorValue@ */
   IPP_STATUS_OK = 0x0000,		/* successful-ok */
@@ -493,7 +498,7 @@ typedef enum ipp_status_e		/**** IPP status codes ****/
   IPP_STATUS_OK_EVENTS_COMPLETE,	/* successful-ok-events-complete */
   IPP_STATUS_REDIRECTION_OTHER_SITE = 0x0200,
 					/* redirection-other-site @private@ */
-  IPP_STATUS_CUPS_SEE_OTHER = 0x0280,	/* cups-see-other */
+  IPP_STATUS_CUPS_SEE_OTHER = 0x0280,	/* cups-see-other @private@ */
   IPP_STATUS_ERROR_BAD_REQUEST = 0x0400,/* client-error-bad-request */
   IPP_STATUS_ERROR_FORBIDDEN,		/* client-error-forbidden */
   IPP_STATUS_ERROR_NOT_AUTHENTICATED,	/* client-error-not-authenticated */
@@ -569,7 +574,7 @@ typedef enum ipp_status_e		/**** IPP status codes ****/
   IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED = 0x1000,
 					/* cups-authentication-canceled - Authentication canceled by user @since CUPS 1.5/macOS 10.7@ */
   IPP_STATUS_ERROR_CUPS_PKI,		/* cups-pki-error - Error negotiating a secure connection @since CUPS 1.5/macOS 10.7@ */
-  IPP_STATUS_ERROR_CUPS_UPGRADE_REQUIRED/* cups-upgrade-required - TLS upgrade required */
+  IPP_STATUS_ERROR_CUPS_UPGRADE_REQUIRED/* cups-upgrade-required - TLS upgrade required @since CUPS 1.5/macOS 10.7@ */
 
 #  ifndef _CUPS_NO_DEPRECATED
 #    define IPP_OK				IPP_STATUS_OK
@@ -631,7 +636,7 @@ typedef enum ipp_status_e		/**** IPP status codes ****/
 #  endif /* _CUPS_NO_DEPRECATED */
 } ipp_status_t;
 
-typedef enum ipp_tag_e			/**** Format tags for attributes ****/
+typedef enum ipp_tag_e			/**** Value and group tag values for attributes ****/
 {
   IPP_TAG_CUPS_INVALID = -1,		/* Invalid tag name for @link ippTagValue@ */
   IPP_TAG_ZERO = 0x00,			/* Zero tag - used for separators */
@@ -643,7 +648,7 @@ typedef enum ipp_tag_e			/**** Format tags for attributes ****/
   IPP_TAG_SUBSCRIPTION,			/* Subscription group */
   IPP_TAG_EVENT_NOTIFICATION,		/* Event group */
   IPP_TAG_RESOURCE,			/* Resource group @private@ */
-  IPP_TAG_DOCUMENT,			/* Document group */
+  IPP_TAG_DOCUMENT,			/* Document group @exclude all@ */
   IPP_TAG_UNSUPPORTED_VALUE = 0x10,	/* Unsupported value */
   IPP_TAG_DEFAULT,			/* Default value */
   IPP_TAG_UNKNOWN,			/* Unknown value */
@@ -658,10 +663,10 @@ typedef enum ipp_tag_e			/**** Format tags for attributes ****/
   IPP_TAG_DATE,				/* Date/time value */
   IPP_TAG_RESOLUTION,			/* Resolution value */
   IPP_TAG_RANGE,			/* Range value */
-  IPP_TAG_BEGIN_COLLECTION,		/* Beginning of collection value */
+  IPP_TAG_BEGIN_COLLECTION,		/* Beginning of collection value @exclude all@ */
   IPP_TAG_TEXTLANG,			/* Text-with-language value */
   IPP_TAG_NAMELANG,			/* Name-with-language value */
-  IPP_TAG_END_COLLECTION,		/* End of collection value */
+  IPP_TAG_END_COLLECTION,		/* End of collection value @exclude all@ */
   IPP_TAG_TEXT = 0x41,			/* Text value */
   IPP_TAG_NAME,				/* Name value */
   IPP_TAG_RESERVED_STRING,		/* Reserved for future string value @private@ */
@@ -671,8 +676,8 @@ typedef enum ipp_tag_e			/**** Format tags for attributes ****/
   IPP_TAG_CHARSET,			/* Character set value */
   IPP_TAG_LANGUAGE,			/* Language value */
   IPP_TAG_MIMETYPE,			/* MIME media type value */
-  IPP_TAG_MEMBERNAME,			/* Collection member name value */
-  IPP_TAG_EXTENSION = 0x7f,		/* Extension point for 32-bit tags */
+  IPP_TAG_MEMBERNAME,			/* Collection member name value @exclude all@ */
+  IPP_TAG_EXTENSION = 0x7f,		/* Extension point for 32-bit tags @exclude all@ */
   IPP_TAG_CUPS_MASK = 0x7fffffff,	/* Mask for copied attribute values @private@ */
   /* The following expression is used to avoid compiler warnings with +/-0x80000000 */
   IPP_TAG_CUPS_CONST = -0x7fffffff-1	/* Bitflag for copied/const attribute values @private@ */
@@ -683,17 +688,18 @@ typedef enum ipp_tag_e			/**** Format tags for attributes ****/
 #  endif /* !_CUPS_NO_DEPRECATED */
 } ipp_tag_t;
 
-typedef unsigned char ipp_uchar_t;	/**** Unsigned 8-bit integer/character ****/
+typedef unsigned char ipp_uchar_t;	/**** Unsigned 8-bit integer/character @exclude all@ ****/
 typedef struct _ipp_s ipp_t;		/**** IPP request/response data ****/
 typedef struct _ipp_attribute_s ipp_attribute_t;
 					/**** IPP attribute ****/
 
 /**** New in CUPS 1.2/macOS 10.5 ****/
 typedef ssize_t	(*ipp_iocb_t)(void *context, ipp_uchar_t *buffer, size_t bytes);
-					/**** IPP IO Callback Function @since CUPS 1.2/macOS 10.5@ ****/
+					/**** ippReadIO/ippWriteIO callback function @since CUPS 1.2/macOS 10.5@ ****/
 
 /**** New in CUPS 1.6/macOS 10.8 ****/
 typedef int (*ipp_copycb_t)(void *context, ipp_t *dst, ipp_attribute_t *attr);
+                                        /**** ippCopyAttributes callback function @since CUPS 1.6/macOS 10.8 ****/
 
 
 /*
@@ -800,7 +806,7 @@ typedef union _ipp_value_u		/**** Attribute Value ****/
 } _ipp_value_t;
 typedef _ipp_value_t ipp_value_t;	/**** Convenience typedef that will be removed @private@ ****/
 
-struct _ipp_attribute_s			/**** Attribute ****/
+struct _ipp_attribute_s			/**** IPP attribute ****/
 {
   ipp_attribute_t *next;		/* Next attribute in list */
   ipp_tag_t	group_tag,		/* Job/Printer/Operation group tag */
diff --git a/cups/langprintf.c b/cups/langprintf.c
index 40a6688..46b6be5 100644
--- a/cups/langprintf.c
+++ b/cups/langprintf.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/language-private.h b/cups/language-private.h
index a597cd3..49e4b71 100644
--- a/cups/language-private.h
+++ b/cups/language-private.h
@@ -1,14 +1,14 @@
 /*
  * Private localization support for CUPS.
  *
- * Copyright 2007-2010 by Apple Inc.
+ * Copyright 2007-2017 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -22,6 +22,9 @@
 
 #  include 
 #  include 
+#  ifdef __APPLE__
+#    include 
+#  endif /* __APPLE__ */
 
 #  ifdef __cplusplus
 extern "C" {
@@ -51,8 +54,8 @@ typedef struct _cups_message_s		/**** Message catalog entry ****/
  */
 
 #  ifdef __APPLE__
-extern const char	*_cupsAppleLanguage(const char *locale, char *language,
-			                    size_t langsize);
+extern const char	*_cupsAppleLanguage(const char *locale, char *language, size_t langsize);
+extern const char	*_cupsAppleLocale(CFStringRef languageName, char *locale, size_t localesize);
 #  endif /* __APPLE__ */
 extern void		_cupsCharmapFlush(void);
 extern const char	*_cupsEncodingName(cups_encoding_t encoding);
diff --git a/cups/language.c b/cups/language.c
index f1afecc..f3a3496 100644
--- a/cups/language.c
+++ b/cups/language.c
@@ -1,14 +1,14 @@
 /*
  * I18N/language support for CUPS.
  *
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -118,11 +118,13 @@ typedef struct
 } _apple_language_locale_t;
 
 static const _apple_language_locale_t apple_language_locale[] =
-{					/* Locale to language ID LUT */
-  { "en",      "en_US" },
-  { "nb",      "no" },
-  { "zh-Hans", "zh_CN" },
-  { "zh-Hant", "zh_TW" }
+{					/* Language to locale ID LUT */
+  { "en",         "en_US" },
+  { "nb",         "no" },
+  { "nb_NO",      "no" },
+  { "zh-Hans",    "zh_CN" },
+  { "zh-Hant",    "zh_TW" },
+  { "zh-Hant_CN", "zh_TW" }
 };
 #endif /* __APPLE__ */
 
@@ -239,6 +241,75 @@ _cupsAppleLanguage(const char *locale,	/* I - Locale ID */
 
   return (language);
 }
+
+
+/*
+ * '_cupsAppleLocale()' - Get the locale associated with an Apple language ID.
+ */
+
+const char *					/* O - Locale */
+_cupsAppleLocale(CFStringRef languageName,	/* I - Apple language ID */
+                 char        *locale,		/* I - Buffer for locale */
+		 size_t      localesize)	/* I - Size of buffer */
+{
+  int		i;			/* Looping var */
+  CFStringRef	localeName;		/* Locale as a CF string */
+
+
+  localeName = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorDefault, languageName);
+
+  if (localeName)
+  {
+   /*
+    * Copy the locale name and tweak as needed...
+    */
+
+    if (!CFStringGetCString(localeName, locale, (CFIndex)localesize, kCFStringEncodingASCII))
+      *locale = '\0';
+
+    CFRelease(localeName);
+
+   /*
+    * Map new language identifiers to locales...
+    */
+
+    for (i = 0;
+	 i < (int)(sizeof(apple_language_locale) /
+		   sizeof(apple_language_locale[0]));
+	 i ++)
+    {
+      if (!strcmp(locale, apple_language_locale[i].language))
+      {
+	strlcpy(locale, apple_language_locale[i].locale, localesize);
+	break;
+      }
+    }
+  }
+  else
+  {
+   /*
+    * Just try the Apple language name...
+    */
+
+    if (!CFStringGetCString(languageName, locale, (CFIndex)localesize, kCFStringEncodingASCII))
+      *locale = '\0';
+  }
+
+  if (!*locale)
+    return (NULL);
+
+ /*
+  * Convert language subtag into region subtag...
+  */
+
+  if (locale[2] == '-')
+    locale[2] = '_';
+
+  if (!strchr(locale, '.'))
+    strlcat(locale, ".UTF-8", localesize);
+
+  return (locale);
+}
 #endif /* __APPLE__ */
 
 
@@ -1134,13 +1205,11 @@ _cupsMessageNew(void *context)		/* I - User data */
 static const char *			/* O - Locale string */
 appleLangDefault(void)
 {
-  int			i;		/* Looping var */
   CFBundleRef		bundle;		/* Main bundle (if any) */
   CFArrayRef		bundleList;	/* List of localizations in bundle */
   CFPropertyListRef 	localizationList = NULL;
 					/* List of localization data */
   CFStringRef		languageName;	/* Current name */
-  CFStringRef		localeName;	/* Canonical from of name */
   char			*lang;		/* LANG environment variable */
   _cups_globals_t	*cg = _cupsGlobals();
   					/* Pointer to library globals */
@@ -1225,49 +1294,11 @@ appleLangDefault(void)
 	if (languageName &&
 	    CFGetTypeID(languageName) == CFStringGetTypeID())
 	{
-	  localeName = CFLocaleCreateCanonicalLocaleIdentifierFromString(
-			   kCFAllocatorDefault, languageName);
-
-	  if (localeName)
-	  {
-	    CFStringGetCString(localeName, cg->language, sizeof(cg->language),
-			       kCFStringEncodingASCII);
-	    CFRelease(localeName);
-
+	  if (_cupsAppleLocale(languageName, cg->language, sizeof(cg->language)))
 	    DEBUG_printf(("3appleLangDefault: cg->language=\"%s\"",
 			  cg->language));
-
-	   /*
-	    * Map new language identifiers to locales...
-	    */
-
-	    for (i = 0;
-		 i < (int)(sizeof(apple_language_locale) /
-		           sizeof(apple_language_locale[0]));
-		 i ++)
-	    {
-	      if (!strcmp(cg->language, apple_language_locale[i].language))
-	      {
-		DEBUG_printf(("3appleLangDefault: mapping \"%s\" to \"%s\"...",
-			      cg->language, apple_language_locale[i].locale));
-		strlcpy(cg->language, apple_language_locale[i].locale,
-			sizeof(cg->language));
-		break;
-	      }
-	    }
-
-	   /*
-	    * Convert language subtag into region subtag...
-	    */
-
-	    if (cg->language[2] == '-')
-	      cg->language[2] = '_';
-
-	    if (!strchr(cg->language, '.'))
-	      strlcat(cg->language, ".UTF-8", sizeof(cg->language));
-	  }
 	  else
-	    DEBUG_puts("3appleLangDefault: Unable to get localeName.");
+	    DEBUG_puts("3appleLangDefault: Unable to get locale.");
 	}
       }
 
@@ -1371,10 +1402,11 @@ appleMessageLoad(const char *locale)	/* I - Locale ID */
       locale = "Japanese";
     else if (!strncmp(locale, "es", 2))
       locale = "Spanish";
-    else if (!strcmp(locale, "zh_HK"))
+    else if (!strcmp(locale, "zh_HK") || !strncmp(locale, "zh-Hant", 7))
     {
      /*
       * 
+      * 
       *
       * Try zh_TW first, then zh...  Sigh...
       */
diff --git a/cups/language.h b/cups/language.h
index c378e98..c96cbfe 100644
--- a/cups/language.h
+++ b/cups/language.h
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -32,7 +32,7 @@ extern "C" {
  * Types...
  */
 
-typedef enum cups_encoding_e		/**** Language Encodings ****/
+typedef enum cups_encoding_e		/**** Language Encodings @exclude all@ ****/
 {
   CUPS_AUTO_ENCODING = -1,		/* Auto-detect the encoding @private@ */
   CUPS_US_ASCII,			/* US ASCII */
diff --git a/cups/libcups2.def b/cups/libcups2.def
index 51be135..a7be679 100644
--- a/cups/libcups2.def
+++ b/cups/libcups2.def
@@ -118,8 +118,6 @@ _ppdNormalizeMakeAndModel
 _ppdOpen
 _ppdOpenFile
 _ppdParseOptions
-_pwgGenerateSize
-_pwgInitSize
 _pwgInputSlotForSource
 _pwgMediaNearSize
 _pwgMediaTable
diff --git a/cups/md5passwd.c b/cups/md5passwd.c
index 9714aaa..a9817aa 100644
--- a/cups/md5passwd.c
+++ b/cups/md5passwd.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/notify.c b/cups/notify.c
index 5f6e7fd..b58a136 100644
--- a/cups/notify.c
+++ b/cups/notify.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/options.c b/cups/options.c
index a3f57cf..9aa20f8 100644
--- a/cups/options.c
+++ b/cups/options.c
@@ -1,14 +1,14 @@
 /*
  * Option routines for CUPS.
  *
- * Copyright 2007-2014 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -29,6 +29,31 @@ static int	cups_find_option(const char *name, int num_options,
 	                         cups_option_t *option, int prev, int *rdiff);
 
 
+/*
+ * 'cupsAddIntegerOption()' - Add an integer option to an option array.
+ *
+ * New option arrays can be initialized simply by passing 0 for the
+ * "num_options" parameter.
+ *
+ * @since CUPS 2.2.4/macOS 10.13@
+ */
+
+int					/* O  - Number of options */
+cupsAddIntegerOption(
+    const char    *name,		/* I  - Name of option */
+    int           value,		/* I  - Value of option */
+    int           num_options,		/* I  - Number of options */
+    cups_option_t **options)		/* IO - Pointer to options */
+{
+  char	strvalue[32];			/* String value */
+
+
+  snprintf(strvalue, sizeof(strvalue), "%d", value);
+
+  return (cupsAddOption(name, strvalue, num_options, options));
+}
+
+
 /*
  * 'cupsAddOption()' - Add an option to an option array.
  *
@@ -154,6 +179,38 @@ cupsFreeOptions(
 }
 
 
+/*
+ * 'cupsGetIntegerOption()' - Get an integer option value.
+ *
+ * INT_MIN is returned when the option does not exist, is not an integer, or
+ * exceeds the range of values for the "int" type.
+ *
+ * @since CUPS 2.2.4/macOS 10.13@
+ */
+
+int					/* O - Option value or @code INT_MIN@ */
+cupsGetIntegerOption(
+    const char    *name,		/* I - Name of option */
+    int           num_options,		/* I - Number of options */
+    cups_option_t *options)		/* I - Options */
+{
+  const char	*value = cupsGetOption(name, num_options, options);
+					/* String value of option */
+  char		*ptr;			/* Pointer into string value */
+  long		intvalue;		/* Integer value */
+
+
+  if (!value || !*value)
+    return (INT_MIN);
+
+  intvalue = strtol(value, &ptr, 10);
+  if (intvalue < INT_MIN || intvalue > INT_MAX || *ptr)
+    return (INT_MIN);
+
+  return ((int)intvalue);
+}
+
+
 /*
  * 'cupsGetOption()' - Get an option value.
  */
diff --git a/cups/ppd-attr.c b/cups/ppd-attr.c
index 6324e6e..da02637 100644
--- a/cups/ppd-attr.c
+++ b/cups/ppd-attr.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  */
 
 /*
diff --git a/cups/ppd-cache.c b/cups/ppd-cache.c
index 9ce5cfc..7e40214 100644
--- a/cups/ppd-cache.c
+++ b/cups/ppd-cache.c
@@ -1,13 +1,13 @@
 /*
  * PPD cache implementation for CUPS.
  *
- * Copyright 2010-2016 by Apple Inc.
+ * Copyright 2010-2017 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -32,10 +32,10 @@
  * Local functions...
  */
 
+static void	pwg_add_finishing(cups_array_t *finishings, ipp_finishings_t template, const char *name, const char *value);
 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_free_material(_pwg_material_t *m);
 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,
@@ -49,21 +49,20 @@ static void	pwg_unppdize_name(const char *ppd, char *name, size_t namesize,
  * 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					/* 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 */
@@ -198,41 +197,42 @@ _cupsConvertOptions(ipp_t           *request,	/* I - IPP request */
   if ((keyword = cupsGetOption("PageSize", num_options, options)) == NULL)
     keyword = cupsGetOption("media", num_options, options);
 
-  if ((size = _ppdCacheGetSize(pc, keyword)) != NULL)
+  media_source = _ppdCacheGetSource(pc, cupsGetOption("InputSlot", num_options, options));
+  media_type   = _ppdCacheGetType(pc, cupsGetOption("MediaType", num_options, options));
+  size         = _ppdCacheGetSize(pc, keyword);
+
+  if (size || media_source || media_type)
   {
    /*
     * 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));
+    if (size)
+    {
+      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);
+
+      ippAddCollection(media_col, IPP_TAG_ZERO, "media-size", media_size);
+    }
 
     for (i = 0; i < media_col_sup->num_values; i ++)
     {
-      if (!strcmp(media_col_sup->values[i].string.text, "media-left-margin"))
+      if (size && !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"))
+      else if (size && !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"))
+      else if (size && !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"))
+      else if (size && !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)
+      else if (media_source && !strcmp(media_col_sup->values[i].string.text, "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)
+      else if (media_type && !strcmp(media_col_sup->values[i].string.text, "media-type"))
 	ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, "media-type", NULL, media_type);
     }
 
@@ -503,53 +503,6 @@ _ppdCacheCreateWithFile(
       _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad PPD cache file."), 1);
       goto create_error;
     }
-    else if (!_cups_strcasecmp(line, "3D"))
-    {
-      pc->cups_3d = _cupsStrAlloc(value);
-    }
-    else if (!_cups_strcasecmp(line, "LayerOrder"))
-    {
-      pc->cups_layer_order = _cupsStrAlloc(value);
-    }
-    else if (!_cups_strcasecmp(line, "Accuracy"))
-    {
-      sscanf(value, "%d%d%d", pc->cups_accuracy + 0, pc->cups_accuracy + 1, pc->cups_accuracy + 2);
-    }
-    else if (!_cups_strcasecmp(line, "Volume"))
-    {
-      sscanf(value, "%d%d%d", pc->cups_volume + 0, pc->cups_volume + 1, pc->cups_volume + 2);
-    }
-    else if (!_cups_strcasecmp(line, "Material"))
-    {
-     /*
-      * Material key "name" name=value ... name=value
-      */
-
-      if ((valueptr = strchr(value, ' ')) != NULL)
-      {
-	_pwg_material_t	*material = (_pwg_material_t *)calloc(1, sizeof(_pwg_material_t));
-
-        *valueptr++ = '\0';
-
-        material->key = _cupsStrAlloc(value);
-
-        if (*valueptr == '\"')
-	{
-	  value = valueptr + 1;
-	  if ((valueptr = strchr(value, '\"')) != NULL)
-	  {
-	    *valueptr++ = '\0';
-	    material->name = _cupsStrAlloc(value);
-	    material->num_props = cupsParseOptions(valueptr, 0, &material->props);
-	  }
-	}
-
-	if (!pc->materials)
-	  pc->materials = cupsArrayNew3(NULL, NULL, NULL, 0, NULL, (cups_afree_func_t)pwg_free_material);
-
-        cupsArrayAdd(pc->materials, material);
-      }
-    }
     else if (!_cups_strcasecmp(line, "Filter"))
     {
       if (!pc->filters)
@@ -1714,6 +1667,10 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd)	/* I - PPD file */
 
   if ((ppd_attr = ppdFindAttr(ppd, "cupsIPPFinishings", NULL)) != NULL)
   {
+   /*
+    * Have proper vendor mapping of IPP finishings values to PPD options...
+    */
+
     pc->finishings = cupsArrayNew3((cups_array_func_t)pwg_compare_finishings,
                                    NULL, NULL, 0, NULL,
                                    (cups_afree_func_t)pwg_free_finishings);
@@ -1733,6 +1690,114 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd)	/* I - PPD file */
     while ((ppd_attr = ppdFindNextAttr(ppd, "cupsIPPFinishings",
                                        NULL)) != NULL);
   }
+  else
+  {
+   /*
+    * No IPP mapping data, try to map common/standard PPD keywords...
+    */
+
+    ppd_option_t	*ppd_option;	/* PPD option */
+
+    pc->finishings = cupsArrayNew3((cups_array_func_t)pwg_compare_finishings, NULL, NULL, 0, NULL, (cups_afree_func_t)pwg_free_finishings);
+
+    if ((ppd_option = ppdFindOption(ppd, "StapleLocation")) != NULL)
+    {
+     /*
+      * Add staple finishings...
+      */
+
+      if (ppdFindChoice(ppd_option, "SinglePortrait"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_TOP_LEFT, "StapleLocation", "SinglePortrait");
+      if (ppdFindChoice(ppd_option, "UpperLeft")) /* Ricoh extension */
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_TOP_LEFT, "StapleLocation", "UpperLeft");
+      if (ppdFindChoice(ppd_option, "UpperRight")) /* Ricoh extension */
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_TOP_RIGHT, "StapleLocation", "UpperRight");
+      if (ppdFindChoice(ppd_option, "SingleLandscape"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_BOTTOM_LEFT, "StapleLocation", "SingleLandscape");
+      if (ppdFindChoice(ppd_option, "DualLandscape"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_STAPLE_DUAL_LEFT, "StapleLocation", "DualLandscape");
+    }
+
+    if ((ppd_option = ppdFindOption(ppd, "RIPunch")) != NULL)
+    {
+     /*
+      * Add (Ricoh) punch finishings...
+      */
+
+      if (ppdFindChoice(ppd_option, "Left2"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_DUAL_LEFT, "RIPunch", "Left2");
+      if (ppdFindChoice(ppd_option, "Left3"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_TRIPLE_LEFT, "RIPunch", "Left3");
+      if (ppdFindChoice(ppd_option, "Left4"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_QUAD_LEFT, "RIPunch", "Left4");
+      if (ppdFindChoice(ppd_option, "Right2"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_DUAL_RIGHT, "RIPunch", "Right2");
+      if (ppdFindChoice(ppd_option, "Right3"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_TRIPLE_RIGHT, "RIPunch", "Right3");
+      if (ppdFindChoice(ppd_option, "Right4"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_QUAD_RIGHT, "RIPunch", "Right4");
+      if (ppdFindChoice(ppd_option, "Upper2"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_DUAL_TOP, "RIPunch", "Upper2");
+      if (ppdFindChoice(ppd_option, "Upper3"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_TRIPLE_TOP, "RIPunch", "Upper3");
+      if (ppdFindChoice(ppd_option, "Upper4"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_PUNCH_QUAD_TOP, "RIPunch", "Upper4");
+    }
+
+    if ((ppd_option = ppdFindOption(ppd, "BindEdge")) != NULL)
+    {
+     /*
+      * Add bind finishings...
+      */
+
+      if (ppdFindChoice(ppd_option, "Left"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_BIND_LEFT, "BindEdge", "Left");
+      if (ppdFindChoice(ppd_option, "Right"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_BIND_RIGHT, "BindEdge", "Right");
+      if (ppdFindChoice(ppd_option, "Top"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_BIND_TOP, "BindEdge", "Top");
+      if (ppdFindChoice(ppd_option, "Bottom"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_BIND_BOTTOM, "BindEdge", "Bottom");
+    }
+
+    if ((ppd_option = ppdFindOption(ppd, "FoldType")) != NULL)
+    {
+     /*
+      * Add (Adobe) fold finishings...
+      */
+
+      if (ppdFindChoice(ppd_option, "ZFold"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_Z, "FoldType", "ZFold");
+      if (ppdFindChoice(ppd_option, "Saddle"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_HALF, "FoldType", "Saddle");
+      if (ppdFindChoice(ppd_option, "DoubleGate"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_DOUBLE_GATE, "FoldType", "DoubleGate");
+      if (ppdFindChoice(ppd_option, "LeftGate"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_LEFT_GATE, "FoldType", "LeftGate");
+      if (ppdFindChoice(ppd_option, "RightGate"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_RIGHT_GATE, "FoldType", "RightGate");
+      if (ppdFindChoice(ppd_option, "Letter"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_LETTER, "FoldType", "Letter");
+      if (ppdFindChoice(ppd_option, "XFold"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_POSTER, "FoldType", "XFold");
+    }
+
+    if ((ppd_option = ppdFindOption(ppd, "RIFoldType")) != NULL)
+    {
+     /*
+      * Add (Ricoh) fold finishings...
+      */
+
+      if (ppdFindChoice(ppd_option, "OutsideTwoFold"))
+        pwg_add_finishing(pc->finishings, IPP_FINISHINGS_FOLD_LETTER, "RIFoldType", "OutsideTwoFold");
+    }
+
+    if (cupsArrayCount(pc->finishings) == 0)
+    {
+      cupsArrayDelete(pc->finishings);
+      pc->finishings = NULL;
+    }
+  }
 
  /*
   * Max copies...
@@ -1781,42 +1846,6 @@ _ppdCacheCreateWithPPD(ppd_file_t *ppd)	/* I - PPD file */
   if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL)
     cupsArrayAdd(pc->support_files, ppd_attr->value);
 
- /*
-  * 3D stuff...
-  */
-
-  if ((ppd_attr = ppdFindAttr(ppd, "cups3D", NULL)) != NULL)
-    pc->cups_3d = _cupsStrAlloc(ppd_attr->value);
-
-  if ((ppd_attr = ppdFindAttr(ppd, "cupsLayerOrder", NULL)) != NULL)
-    pc->cups_layer_order = _cupsStrAlloc(ppd_attr->value);
-
-  if ((ppd_attr = ppdFindAttr(ppd, "cupsAccuracy", NULL)) != NULL)
-    sscanf(ppd_attr->value, "%d%d%d", pc->cups_accuracy + 0, pc->cups_accuracy + 1, pc->cups_accuracy + 2);
-
-  if ((ppd_attr = ppdFindAttr(ppd, "cupsVolume", NULL)) != NULL)
-    sscanf(ppd_attr->value, "%d%d%d", pc->cups_volume + 0, pc->cups_volume + 1, pc->cups_volume + 2);
-
-  for (ppd_attr = ppdFindAttr(ppd, "cupsMaterial", NULL);
-       ppd_attr;
-       ppd_attr = ppdFindNextAttr(ppd, "cupsMaterial", NULL))
-  {
-   /*
-    * *cupsMaterial key/name: "name=value ... name=value"
-    */
-
-    _pwg_material_t	*material = (_pwg_material_t *)calloc(1, sizeof(_pwg_material_t));
-
-    material->key = _cupsStrAlloc(ppd_attr->name);
-    material->name = _cupsStrAlloc(ppd_attr->text);
-    material->num_props = cupsParseOptions(ppd_attr->value, 0, &material->props);
-
-    if (!pc->materials)
-      pc->materials = cupsArrayNew3(NULL, NULL, NULL, 0, NULL, (cups_afree_func_t)pwg_free_material);
-
-    cupsArrayAdd(pc->materials, material);
-  }
-
  /*
   * Return the cache data...
   */
@@ -1924,11 +1953,6 @@ _ppdCacheDestroy(_ppd_cache_t *pc)	/* I - PPD cache and mapping data */
 
   cupsArrayDelete(pc->support_files);
 
-  _cupsStrFree(pc->cups_3d);
-  _cupsStrFree(pc->cups_layer_order);
-
-  cupsArrayDelete(pc->materials);
-
   free(pc);
 }
 
@@ -2686,7 +2710,6 @@ _ppdCacheWriteFile(
   cups_option_t		*option;	/* Current option */
   const char		*value;		/* Filter/pre-filter value */
   char			newfile[1024];	/* New filename */
-  _pwg_material_t	*m;		/* Material */
 
 
  /*
@@ -2867,32 +2890,6 @@ _ppdCacheWriteFile(
        value = (char *)cupsArrayNext(pc->support_files))
     cupsFilePutConf(fp, "SupportFile", value);
 
- /*
-  * 3D stuff...
-  */
-
-  if (pc->cups_3d)
-    cupsFilePutConf(fp, "3D", pc->cups_3d);
-
-  if (pc->cups_layer_order)
-    cupsFilePutConf(fp, "LayerOrder", pc->cups_layer_order);
-
-  if (pc->cups_accuracy[0] || pc->cups_accuracy[0] || pc->cups_accuracy[2])
-    cupsFilePrintf(fp, "Accuracy %d %d %d\n", pc->cups_accuracy[0], pc->cups_accuracy[1], pc->cups_accuracy[2]);
-
-  if (pc->cups_volume[0] || pc->cups_volume[0] || pc->cups_volume[2])
-    cupsFilePrintf(fp, "Volume %d %d %d\n", pc->cups_volume[0], pc->cups_volume[1], pc->cups_volume[2]);
-
-  for (m = (_pwg_material_t *)cupsArrayFirst(pc->materials);
-       m;
-       m = (_pwg_material_t *)cupsArrayNext(pc->materials))
-  {
-    cupsFilePrintf(fp, "Material %s \"%s\"", m->key, m->name);
-    for (i = 0; i < m->num_props; i ++)
-      cupsFilePrintf(fp, " %s=%s", m->props[i].name, m->props[i].value);
-    cupsFilePuts(fp, "\n");
-  }
-
  /*
   * IPP attributes, if any...
   */
@@ -2925,14 +2922,16 @@ _ppdCacheWriteFile(
  *                         of an IPP printer.
  */
 
-char *					/* O - PPD filename or NULL on error */
+char *					/* O - PPD filename or @code 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 */
+  cups_array_t		*sizes;		/* Media sizes we've added */
   ipp_attribute_t	*attr,		/* xxx-supported */
 			*defattr,	/* xxx-default */
+                        *quality,	/* print-quality-supported */
 			*x_dim, *y_dim;	/* Media dimensions */
   ipp_t			*media_size;	/* Media size collection */
   char			make[256],	/* Make and model */
@@ -2944,7 +2943,10 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
 			bottom,		/* Largest bottom margin */
 			left,		/* Largest left margin */
 			right,		/* Largest right margin */
-			top;		/* Largest top margin */
+			top,		/* Largest top margin */
+			is_apple = 0,	/* Does the printer support Apple raster? */
+			is_pdf = 0,	/* Does the printer support PDF? */
+			is_pwg = 0;	/* Does the printer support PWG Raster? */
   pwg_media_t		*pwg;		/* PWG media size */
   int			xres, yres;	/* Resolution values */
   cups_lang_t		*lang = cupsLangDefault();
@@ -2970,6 +2972,7 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
     { "fold", _("Fold") },
     { "fold-accordian", _("Accordian Fold") },
     { "fold-double-gate", _("Double Gate Fold") },
+    { "fold-engineering-z", _("Engineering Z Fold") },
     { "fold-gate", _("Gate Fold") },
     { "fold-half", _("Half Fold") },
     { "fold-half-z", _("Half Z Fold") },
@@ -2998,6 +3001,10 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
     { "punch-triple-left", _("3-Hole Punch (Portrait)") },
     { "punch-triple-right", _("3-Hole Punch (Reverse Portrait)") },
     { "punch-triple-top", _("3-Hole Punch (Landscape)") },
+    { "punch-multiple-bottom", _("Multi-Hole Punch (Reverse Landscape)") },
+    { "punch-multiple-left", _("Multi-Hole Punch (Portrait)") },
+    { "punch-multiple-right", _("Multi-Hole Punch (Reverse Portrait)") },
+    { "punch-multiple-top", _("Multi-Hole Punch (Landscape)") },
     { "saddle-stitch", _("Saddle Stitch") },
     { "staple", _("Staple") },
     { "staple-bottom-left", _("Single Staple (Reverse Landscape)") },
@@ -3023,15 +3030,27 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
   if (buffer)
     *buffer = '\0';
 
-  if (!buffer || bufsize < 1 || !response)
+  if (!buffer || bufsize < 1)
+  {
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0);
     return (NULL);
+  }
+
+  if (!response)
+  {
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("No IPP attributes."), 1);
+    return (NULL);
+  }
 
  /*
   * Open a temporary file for the PPD...
   */
 
   if ((fp = cupsTempFile2(buffer, (int)bufsize)) == NULL)
+  {
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0);
     return (NULL);
+  }
 
  /*
   * Standard stuff for PPD file...
@@ -3084,20 +3103,31 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
 
   if ((attr = ippFindAttribute(response, "document-format-supported", IPP_TAG_MIMETYPE)) != NULL)
   {
+    is_apple = ippContainsString(attr, "image/urf");
+    is_pdf   = ippContainsString(attr, "application/pdf");
+    is_pwg   = ippContainsString(attr, "image/pwg-raster");
+
     for (i = 0, count = ippGetCount(attr); i < count; i ++)
     {
       const char *format = ippGetString(attr, i, NULL);
 					/* PDL */
 
+     /*
+      * Write cupsFilter2 lines for supported formats...
+      */
+
       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);
+      else if (!_cups_strcasecmp(format, "image/jpeg") || !_cups_strcasecmp(format, "image/png"))
+        cupsFilePrintf(fp, "*cupsFilter2: \"%s %s 0 -\"\n", format, format);
+      else if (!_cups_strcasecmp(format, "image/pwg-raster") || !_cups_strcasecmp(format, "image/urf"))
+        cupsFilePrintf(fp, "*cupsFilter2: \"%s %s 100 -\"\n", format, format);
     }
   }
 
+  if (!is_apple && !is_pdf && !is_pwg)
+    goto bad_ppd;
+
  /*
   * PageSize/PageRegion/ImageableArea/PaperDimension
   */
@@ -3146,35 +3176,54 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
       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));
+      if (x_dim && y_dim && (pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0))) != NULL)
 	strlcpy(ppdname, pwg->ppd, sizeof(ppdname));
-      }
       else
 	strlcpy(ppdname, "Unknown", sizeof(ppdname));
     }
     else
       strlcpy(ppdname, "Unknown", sizeof(ppdname));
   }
+  else if ((pwg = pwgMediaForPWG(ippGetString(ippFindAttribute(response, "media-default", IPP_TAG_ZERO), 0, NULL))) != NULL)
+    strlcpy(ppdname, pwg->ppd, sizeof(ppdname));
+  else
+    strlcpy(ppdname, "Unknown", sizeof(ppdname));
 
-  if ((attr = ippFindAttribute(response, "media-size-supported", IPP_TAG_BEGIN_COLLECTION)) != NULL)
+  if ((attr = ippFindAttribute(response, "media-size-supported", IPP_TAG_BEGIN_COLLECTION)) == NULL)
+    attr = ippFindAttribute(response, "media-supported", IPP_TAG_ZERO);
+  if (attr)
   {
     cupsFilePrintf(fp, "*OpenUI *PageSize: PickOne\n"
 		       "*OrderDependency: 10 AnySetup *PageSize\n"
                        "*DefaultPageSize: %s\n", ppdname);
+
+    sizes = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free);
+
     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 (ippGetValueTag(attr) == IPP_TAG_BEGIN_COLLECTION)
+      {
+	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)
+	pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0));
+      }
+      else
+        pwg = pwgMediaForPWG(ippGetString(attr, i, NULL));
+
+      if (pwg)
       {
         char	twidth[256],		/* Width string */
 		tlength[256];		/* Length string */
 
-        pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0));
+        if (cupsArrayFind(sizes, (void *)pwg->ppd))
+        {
+          cupsFilePrintf(fp, "*%% warning: Duplicate size '%s' reported by printer.\n", pwg->ppd);
+          continue;
+        }
+
+        cupsArrayAdd(sizes, (void *)pwg->ppd);
 
         _cupsStrFormatd(twidth, twidth + sizeof(twidth), pwg->width * 72.0 / 2540.0, loc);
         _cupsStrFormatd(tlength, tlength + sizeof(tlength), pwg->length * 72.0 / 2540.0, loc);
@@ -3184,21 +3233,34 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
     }
     cupsFilePuts(fp, "*CloseUI: *PageSize\n");
 
+    cupsArrayDelete(sizes);
+    sizes = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free);
+
     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 (ippGetValueTag(attr) == IPP_TAG_BEGIN_COLLECTION)
+      {
+	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)
+	pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0));
+      }
+      else
+        pwg = pwgMediaForPWG(ippGetString(attr, i, NULL));
+
+      if (pwg)
       {
         char	twidth[256],		/* Width string */
 		tlength[256];		/* Length string */
 
-        pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0));
+        if (cupsArrayFind(sizes, (void *)pwg->ppd))
+          continue;
+
+        cupsArrayAdd(sizes, (void *)pwg->ppd);
 
         _cupsStrFormatd(twidth, twidth + sizeof(twidth), pwg->width * 72.0 / 2540.0, loc);
         _cupsStrFormatd(tlength, tlength + sizeof(tlength), pwg->length * 72.0 / 2540.0, loc);
@@ -3208,15 +3270,25 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
     }
     cupsFilePuts(fp, "*CloseUI: *PageRegion\n");
 
+    cupsArrayDelete(sizes);
+    sizes = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free);
+
     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 (ippGetValueTag(attr) == IPP_TAG_BEGIN_COLLECTION)
+      {
+	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)
+	pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0));
+      }
+      else
+        pwg = pwgMediaForPWG(ippGetString(attr, i, NULL));
+
+      if (pwg)
       {
         char	tleft[256],		/* Left string */
 		tbottom[256],		/* Bottom string */
@@ -3225,7 +3297,10 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
 		twidth[256],		/* Width string */
 		tlength[256];		/* Length string */
 
-        pwg = pwgMediaForSize(ippGetInteger(x_dim, 0), ippGetInteger(y_dim, 0));
+        if (cupsArrayFind(sizes, (void *)pwg->ppd))
+          continue;
+
+        cupsArrayAdd(sizes, (void *)pwg->ppd);
 
         _cupsStrFormatd(tleft, tleft + sizeof(tleft), left * 72.0 / 2540.0, loc);
         _cupsStrFormatd(tbottom, tbottom + sizeof(tbottom), bottom * 72.0 / 2540.0, loc);
@@ -3238,18 +3313,22 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
         cupsFilePrintf(fp, "*PaperDimension %s: \"%s %s\"\n", pwg->ppd, twidth, tlength);
       }
     }
+
+    cupsArrayDelete(sizes);
   }
+  else
+    goto bad_ppd;
 
  /*
   * InputSlot...
   */
 
-  if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-source", IPP_TAG_KEYWORD)) != NULL)
+  if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-source", IPP_TAG_ZERO)) != 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)
+  if ((attr = ippFindAttribute(response, "media-source-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 1)
   {
     static const char * const sources[][2] =
     {					/* "media-source" strings */
@@ -3326,12 +3405,12 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
   * MediaType...
   */
 
-  if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-type", IPP_TAG_KEYWORD)) != NULL)
+  if ((attr = ippFindAttribute(ippGetCollection(defattr, 0), "media-type", IPP_TAG_ZERO)) != 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)
+  if ((attr = ippFindAttribute(response, "media-type-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 1)
   {
     static const char * const media_types[][2] =
     {					/* "media-type" strings */
@@ -3341,6 +3420,19 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
       { "cardboard", _("Cardboard") },
       { "cardstock", _("Cardstock") },
       { "cd", _("CD") },
+      { "com.hp.advanced-photo", _("Advanced Photo Paper") }, /* HP */
+      { "com.hp.brochure-glossy", _("Glossy Brochure Paper") }, /* HP */
+      { "com.hp.brochure-matte", _("Matte Brochure Paper") }, /* HP */
+      { "com.hp.cover-matte", _("Matte Cover Paper") }, /* HP */
+      { "com.hp.ecosmart-lite", _("Office Recycled Paper") }, /* HP */
+      { "com.hp.everyday-glossy", _("Everyday Glossy Photo Paper") }, /* HP */
+      { "com.hp.everyday-matte", _("Everyday Matte Paper") }, /* HP */
+      { "com.hp.extra-heavy", _("Extra Heavyweight Paper") }, /* HP */
+      { "com.hp.intermediate", _("Multipurpose Paper") }, /* HP */
+      { "com.hp.mid-weight", _("Mid-Weight Paper") }, /* HP */
+      { "com.hp.premium-inkjet", _("Premium Inkjet Paper") }, /* HP */
+      { "com.hp.premium-photo", _("Premium Photo Glossy Paper") }, /* HP */
+      { "com.hp.premium-presentation-matte", _("Premium Presentation Matte Paper") }, /* HP */
       { "continuous", _("Continuous") },
       { "continuous-long", _("Continuous Long") },
       { "continuous-short", _("Continuous Short") },
@@ -3388,6 +3480,10 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
       { "gravure-cylinder", _("Gravure Cylinder") },
       { "image-setter-paper", _("Image Setter Paper") },
       { "imaging-cylinder", _("Imaging Cylinder") },
+      { "jp.co.canon_photo-paper-plus-glossy-ii", _("Photo Paper Plus Glossy II") }, /* Canon */
+      { "jp.co.canon_photo-paper-pro-platinum", _("Photo Paper Pro Platinum") }, /* Canon */
+      { "jp.co.canon-photo-paper-plus-glossy-ii", _("Photo Paper Plus Glossy II") }, /* Canon */
+      { "jp.co.canon-photo-paper-pro-platinum", _("Photo Paper Pro Platinum") }, /* Canon */
       { "labels", _("Labels") },
       { "labels-colored", _("Colored Labels") },
       { "labels-glossy", _("Glossy Labels") },
@@ -3411,8 +3507,9 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
       { "multi-part-form", _("Multi Part Form") },
       { "other", _("Other") },
       { "paper", _("Paper") },
+      { "photo", _("Photo Paper") }, /* HP mis-spelling */
       { "photographic", _("Photo Paper") },
-      { "photographic-archival", _("Photographic Archival") },
+      { "photographic-archival", _("Archival Photo Paper") },
       { "photographic-film", _("Photo Film") },
       { "photographic-glossy", _("Glossy Photo Paper") },
       { "photographic-high-gloss", _("High Gloss Photo Paper") },
@@ -3439,14 +3536,14 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
       { "single-face", _("Single Face") },
       { "single-wall", _("Single Wall Cardboard") },
       { "sleeve", _("Sleeve") },
-      { "stationery", _("Stationery") },
-      { "stationery-archival", _("Stationery Archival") },
+      { "stationery", _("Plain Paper") },
+      { "stationery-archival", _("Archival Paper") },
       { "stationery-coated", _("Coated Paper") },
-      { "stationery-cotton", _("Stationery Cotton") },
+      { "stationery-cotton", _("Cotton Paper") },
       { "stationery-fine", _("Vellum Paper") },
       { "stationery-heavyweight", _("Heavyweight Paper") },
-      { "stationery-heavyweight-coated", _("Stationery Heavyweight Coated") },
-      { "stationery-inkjet", _("Stationery Inkjet Paper") },
+      { "stationery-heavyweight-coated", _("Heavyweight Coated Paper") },
+      { "stationery-inkjet", _("Inkjet Paper") },
       { "stationery-letterhead", _("Letterhead") },
       { "stationery-lightweight", _("Lightweight Paper") },
       { "stationery-preprinted", _("Preprinted Paper") },
@@ -3462,14 +3559,20 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
     cupsFilePrintf(fp, "*OpenUI *MediaType: PickOne\n"
                        "*OrderDependency: 10 AnySetup *MediaType\n"
                        "*DefaultMediaType: %s\n", ppdname);
-    for (i = 0; i < (int)(sizeof(media_types) / sizeof(media_types[0])); i ++)
+    for (i = 0; i < count; i ++)
     {
-      if (!ippContainsString(attr, media_types[i][0]))
-        continue;
+      const char *keyword = ippGetString(attr, i, NULL);
 
-      pwg_ppdize_name(media_types[i][0], ppdname, sizeof(ppdname));
+      pwg_ppdize_name(keyword, ppdname, sizeof(ppdname));
 
-      cupsFilePrintf(fp, "*MediaType %s/%s: \"<>setpagedevice\"\n", ppdname, _cupsLangString(lang, media_types[i][1]), ppdname);
+      for (j = 0; j < (int)(sizeof(media_types) / sizeof(media_types[0])); j ++)
+        if (!strcmp(keyword, media_types[j][0]))
+          break;
+
+      if (j < (int)(sizeof(media_types) / sizeof(media_types[0])))
+        cupsFilePrintf(fp, "*MediaType %s/%s: \"<>setpagedevice\"\n", ppdname, _cupsLangString(lang, media_types[j][1]), ppdname);
+      else
+        cupsFilePrintf(fp, "*MediaType %s/%s: \"<>setpagedevice\"\n", ppdname, keyword, ppdname);
     }
     cupsFilePuts(fp, "*CloseUI: *MediaType\n");
   }
@@ -3479,7 +3582,9 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
   */
 
   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 = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) == NULL)
+      if ((attr = ippFindAttribute(response, "print-color-mode-supported", IPP_TAG_KEYWORD)) == NULL)
+        attr = ippFindAttribute(response, "output-mode-supported", IPP_TAG_KEYWORD);
 
   if (attr)
   {
@@ -3490,7 +3595,7 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
       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 (!strcasecmp(keyword, "black_1") || !strcmp(keyword, "bi-level") || !strcmp(keyword, "process-bi-level"))
       {
         if (!default_color)
 	  cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n"
@@ -3501,7 +3606,7 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
         if (!default_color)
 	  default_color = "FastGray";
       }
-      else if (!strcmp(keyword, "sgray_8") || !strcmp(keyword, "monochrome") || !strcmp(keyword, "process-monochrome"))
+      else if (!strcasecmp(keyword, "sgray_8") || !strcmp(keyword, "W8") || !strcmp(keyword, "monochrome") || !strcmp(keyword, "process-monochrome"))
       {
         if (!default_color)
 	  cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n"
@@ -3512,7 +3617,7 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
         if (!default_color || !strcmp(default_color, "FastGray"))
 	  default_color = "Gray";
       }
-      else if (!strcmp(keyword, "srgb_8") || !strcmp(keyword, "color"))
+      else if (!strcasecmp(keyword, "srgb_8") || !strcmp(keyword, "SRGB24") || !strcmp(keyword, "color"))
       {
         if (!default_color)
 	  cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n"
@@ -3522,6 +3627,17 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
 
 	default_color = "RGB";
       }
+      else if (!strcasecmp(keyword, "adobe-rgb_16") || !strcmp(keyword, "ADOBERGB48"))
+      {
+        if (!default_color)
+	  cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n"
+			     "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang, _("Color Mode")));
+
+        cupsFilePrintf(fp, "*ColorModel AdobeRGB/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Deep Color")));
+
+        if (!default_color)
+	  default_color = "AdobeRGB";
+      }
     }
 
     if (default_color)
@@ -3591,95 +3707,261 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
   }
 
  /*
-  * Finishing options...
+  * Output bin...
   */
 
-  if ((attr = ippFindAttribute(response, "finishings-col-database", IPP_TAG_BEGIN_COLLECTION)) != NULL)
+  if ((attr = ippFindAttribute(response, "output-bin-default", IPP_TAG_ZERO)) != NULL)
+    pwg_ppdize_name(ippGetString(attr, 0, NULL), ppdname, sizeof(ppdname));
+  else
+    strlcpy(ppdname, "Unknown", sizeof(ppdname));
+
+  if ((attr = ippFindAttribute(response, "output-bin-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 1)
+  {
+    static const char * const output_bins[][2] =
+    {					/* "output-bin" strings */
+      { "auto", _("Automatic") },
+      { "bottom", _("Bottom Tray") },
+      { "center", _("Center Tray") },
+      { "face-down", _("Face Down") },
+      { "face-up", _("Face Up") },
+      { "large-capacity", _("Large Capacity Tray") },
+      { "left", _("Left Tray") },
+      { "mailbox-1", _("Mailbox 1") },
+      { "mailbox-2", _("Mailbox 2") },
+      { "mailbox-3", _("Mailbox 3") },
+      { "mailbox-4", _("Mailbox 4") },
+      { "mailbox-5", _("Mailbox 5") },
+      { "mailbox-6", _("Mailbox 6") },
+      { "mailbox-7", _("Mailbox 7") },
+      { "mailbox-8", _("Mailbox 8") },
+      { "mailbox-9", _("Mailbox 9") },
+      { "mailbox-10", _("Mailbox 10") },
+      { "middle", _("Middle") },
+      { "my-mailbox", _("My Mailbox") },
+      { "rear", _("Rear Tray") },
+      { "right", _("Right Tray") },
+      { "side", _("Side Tray") },
+      { "stacker-1", _("Stacker 1") },
+      { "stacker-2", _("Stacker 2") },
+      { "stacker-3", _("Stacker 3") },
+      { "stacker-4", _("Stacker 4") },
+      { "stacker-5", _("Stacker 5") },
+      { "stacker-6", _("Stacker 6") },
+      { "stacker-7", _("Stacker 7") },
+      { "stacker-8", _("Stacker 8") },
+      { "stacker-9", _("Stacker 9") },
+      { "stacker-10", _("Stacker 10") },
+      { "top", _("Top Tray") },
+      { "tray-1", _("Tray 1") },
+      { "tray-2", _("Tray 2") },
+      { "tray-3", _("Tray 3") },
+      { "tray-4", _("Tray 4") },
+      { "tray-5", _("Tray 5") },
+      { "tray-6", _("Tray 6") },
+      { "tray-7", _("Tray 7") },
+      { "tray-8", _("Tray 8") },
+      { "tray-9", _("Tray 9") },
+      { "tray-10", _("Tray 10") }
+    };
+
+    cupsFilePrintf(fp, "*OpenUI *OutputBin: PickOne\n"
+                       "*OrderDependency: 10 AnySetup *OutputBin\n"
+                       "*DefaultOutputBin: %s\n", ppdname);
+    for (i = 0; i < (int)(sizeof(output_bins) / sizeof(output_bins[0])); i ++)
+    {
+      if (!ippContainsString(attr, output_bins[i][0]))
+        continue;
+
+      pwg_ppdize_name(output_bins[i][0], ppdname, sizeof(ppdname));
+
+      cupsFilePrintf(fp, "*OutputBin %s/%s: \"\"\n", ppdname, _cupsLangString(lang, output_bins[i][1]));
+    }
+    cupsFilePuts(fp, "*CloseUI: *OutputBin\n");
+  }
+
+ /*
+  * Finishing options...
+  *
+  * Eventually need to re-add support for finishings-col-database, however
+  * it is difficult to map arbitrary finishing-template values to PPD options
+  * and have the right constraints apply (e.g. stapling vs. folding vs.
+  * punching, etc.)
+  */
+
+  if ((attr = ippFindAttribute(response, "finishings-supported", IPP_TAG_ENUM)) != NULL)
   {
-    ipp_t		*col;		/* Collection value */
-    ipp_attribute_t	*template;	/* "finishing-template" member */
     const char		*name;		/* String name */
-    int			value;		/* Enum value, if any */
+    int			value;		/* Enum value */
     cups_array_t	*names;		/* Names we've added */
 
     count = ippGetCount(attr);
     names = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, (cups_acopy_func_t)strdup, (cups_afree_func_t)free);
 
-    cupsFilePrintf(fp, "*OpenUI *cupsFinishingTemplate/%s: PickMany\n"
-		       "*OrderDependency: 10 AnySetup *cupsFinishingTemplate\n"
-		       "*DefaultcupsFinishingTemplate: none\n"
-		       "*cupsFinishingTemplate none/%s: \"\"\n"
-		       "*cupsIPPFinishings 3/none: \"*cupsFinishingTemplate none\"\n", _cupsLangString(lang, _("Finishing")), _cupsLangString(lang, _("No Finishing")));
+   /*
+    * Staple/Bind/Stitch
+    */
 
     for (i = 0; i < count; i ++)
     {
-      col      = ippGetCollection(attr, i);
-      template = ippFindAttribute(col, "finishing-template", IPP_TAG_ZERO);
+      value = ippGetInteger(attr, i);
+      name  = ippEnumString("finishings", value);
 
-      if ((name = ippGetString(template, 0, NULL)) == NULL || !strcmp(name, "none"))
-        continue;
+      if (!strncmp(name, "staple-", 7) || !strncmp(name, "bind-", 5) || !strncmp(name, "edge-stitch-", 12) || !strcmp(name, "saddle-stitch"))
+        break;
+    }
 
-      if (cupsArrayFind(names, (char *)name))
-        continue;			/* Already did this finishing template */
+    if (i < count)
+    {
+      cupsFilePrintf(fp, "*OpenUI *StapleLocation/%s: PickOne\n", _cupsLangString(lang, _("Staple")));
+      cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *StapleLocation\n");
+      cupsFilePuts(fp, "*DefaultStapleLocation: None\n");
+      cupsFilePrintf(fp, "*StapleLocation None/%s: \"\"\n", _cupsLangString(lang, _("None")));
 
-      cupsArrayAdd(names, (char *)name);
-
-      for (j = 0; j < (int)(sizeof(finishings) / sizeof(finishings[0])); j ++)
+      for (; i < count; i ++)
       {
-        if (!strcmp(finishings[j][0], name))
-	{
-          cupsFilePrintf(fp, "*cupsFinishingTemplate %s/%s: \"\"\n", name, _cupsLangString(lang, finishings[j][1]));
+        value = ippGetInteger(attr, i);
+        name  = ippEnumString("finishings", value);
 
-	  value = ippEnumValue("finishings", name);
+        if (strncmp(name, "staple-", 7) && strncmp(name, "bind-", 5) && strncmp(name, "edge-stitch-", 12) && strcmp(name, "saddle-stitch"))
+          continue;
 
-	  if (value)
-	    cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*cupsFinishingTemplate %s\"\n", value, name, name);
-          break;
-	}
+        if (cupsArrayFind(names, (char *)name))
+          continue;			/* Already did this finishing template */
+
+        cupsArrayAdd(names, (char *)name);
+
+        for (j = 0; j < (int)(sizeof(finishings) / sizeof(finishings[0])); j ++)
+        {
+          if (!strcmp(finishings[j][0], name))
+          {
+            cupsFilePrintf(fp, "*StapleLocation %s/%s: \"\"\n", name, _cupsLangString(lang, finishings[j][1]));
+            cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*StapleLocation %s\"\n", value, name, name);
+            break;
+          }
+        }
       }
+
+      cupsFilePuts(fp, "*CloseUI: *StapleLocation\n");
+    }
+
+   /*
+    * Fold
+    */
+
+    for (i = 0; i < count; i ++)
+    {
+      value = ippGetInteger(attr, i);
+      name  = ippEnumString("finishings", value);
+
+      if (!strncmp(name, "fold-", 5))
+        break;
+    }
+
+    if (i < count)
+    {
+      cupsFilePrintf(fp, "*OpenUI *FoldType/%s: PickOne\n", _cupsLangString(lang, _("Fold")));
+      cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *FoldType\n");
+      cupsFilePuts(fp, "*DefaultFoldType: None\n");
+      cupsFilePrintf(fp, "*FoldType None/%s: \"\"\n", _cupsLangString(lang, _("None")));
+
+      for (; i < count; i ++)
+      {
+        value = ippGetInteger(attr, i);
+        name  = ippEnumString("finishings", value);
+
+        if (strncmp(name, "fold-", 5))
+          continue;
+
+        if (cupsArrayFind(names, (char *)name))
+          continue;			/* Already did this finishing template */
+
+        cupsArrayAdd(names, (char *)name);
+
+        for (j = 0; j < (int)(sizeof(finishings) / sizeof(finishings[0])); j ++)
+        {
+          if (!strcmp(finishings[j][0], name))
+          {
+            cupsFilePrintf(fp, "*FoldType %s/%s: \"\"\n", name, _cupsLangString(lang, finishings[j][1]));
+            cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*FoldType %s\"\n", value, name, name);
+            break;
+          }
+        }
+      }
+
+      cupsFilePuts(fp, "*CloseUI: *FoldType\n");
+    }
+
+   /*
+    * Punch
+    */
+
+    for (i = 0; i < count; i ++)
+    {
+      value = ippGetInteger(attr, i);
+      name  = ippEnumString("finishings", value);
+
+      if (!strncmp(name, "punch-", 6))
+        break;
+    }
+
+    if (i < count)
+    {
+      cupsFilePrintf(fp, "*OpenUI *PunchMedia/%s: PickOne\n", _cupsLangString(lang, _("Punch")));
+      cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *PunchMedia\n");
+      cupsFilePuts(fp, "*DefaultPunchMedia: None\n");
+      cupsFilePrintf(fp, "*PunchMedia None/%s: \"\"\n", _cupsLangString(lang, _("None")));
+
+      for (i = 0; i < count; i ++)
+      {
+        value = ippGetInteger(attr, i);
+        name  = ippEnumString("finishings", value);
+
+        if (strncmp(name, "punch-", 6))
+          continue;
+
+        if (cupsArrayFind(names, (char *)name))
+          continue;			/* Already did this finishing template */
+
+        cupsArrayAdd(names, (char *)name);
+
+        for (j = 0; j < (int)(sizeof(finishings) / sizeof(finishings[0])); j ++)
+        {
+          if (!strcmp(finishings[j][0], name))
+          {
+            cupsFilePrintf(fp, "*PunchMedia %s/%s: \"\"\n", name, _cupsLangString(lang, finishings[j][1]));
+            cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*PunchMedia %s\"\n", value, name, name);
+            break;
+          }
+        }
+      }
+
+      cupsFilePuts(fp, "*CloseUI: *PunchMedia\n");
+    }
+
+   /*
+    * Booklet
+    */
+
+    if (ippContainsInteger(attr, IPP_FINISHINGS_BOOKLET_MAKER))
+    {
+      cupsFilePrintf(fp, "*OpenUI *Booklet/%s: Boolean\n", _cupsLangString(lang, _("Booklet")));
+      cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *Booklet\n");
+      cupsFilePuts(fp, "*DefaultBooklet: False\n");
+      cupsFilePuts(fp, "*Booklet False: \"\"\n");
+      cupsFilePuts(fp, "*Booklet True: \"\"\n");
+      cupsFilePrintf(fp, "*cupsIPPFinishings %d/booklet-maker: \"*Booklet True\"\n", IPP_FINISHINGS_BOOKLET_MAKER);
+      cupsFilePuts(fp, "*CloseUI: *Booklet\n");
     }
 
     cupsArrayDelete(names);
-
-    cupsFilePuts(fp, "*CloseUI: *cupsFinishingTemplate\n");
-  }
-  else if ((attr = ippFindAttribute(response, "finishings-supported", IPP_TAG_ENUM)) != NULL && (count = ippGetCount(attr)) > 1 )
-  {
-    const char		*name;		/* String name */
-    int			value;		/* Enum value, if any */
-
-    count = ippGetCount(attr);
-
-    cupsFilePrintf(fp, "*OpenUI *cupsFinishingTemplate/%s: PickMany\n"
-		       "*OrderDependency: 10 AnySetup *cupsFinishingTemplate\n"
-		       "*DefaultcupsFinishingTemplate: none\n"
-		       "*cupsFinishingTemplate none/%s: \"\"\n"
-		       "*cupsIPPFinishings 3/none: \"*cupsFinishingTemplate none\"\n", _cupsLangString(lang, _("Finishing")), _cupsLangString(lang, _("No Finishing")));
-
-    for (i = 0; i < count; i ++)
-    {
-      if ((value = ippGetInteger(attr, i)) == 3)
-        continue;
-
-      name = ippEnumString("finishings", value);
-      for (j = 0; j < (int)(sizeof(finishings) / sizeof(finishings[0])); j ++)
-      {
-        if (!strcmp(finishings[j][0], name))
-	{
-          cupsFilePrintf(fp, "*cupsFinishingTemplate %s/%s: \"\"\n", name, _cupsLangString(lang, finishings[j][1]));
-	  cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*cupsFinishingTemplate %s\"\n", value, name, name);
-          break;
-	}
-      }
-    }
-
-    cupsFilePuts(fp, "*CloseUI: *cupsFinishingTemplate\n");
   }
 
  /*
   * cupsPrintQuality and DefaultResolution...
   */
 
+  quality = ippFindAttribute(response, "print-quality-supported", IPP_TAG_ENUM);
+
   if ((attr = ippFindAttribute(response, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL)
   {
     count = ippGetCount(attr);
@@ -3690,16 +3972,19 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
     cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality/%s: PickOne\n"
 		       "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
 		       "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang, _("Print Quality")));
-    if (count > 2)
+    if (count > 2 || ippContainsInteger(quality, IPP_QUALITY_DRAFT))
     {
       pwg_ppdize_resolution(attr, 0, &xres, &yres, NULL, 0);
       cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), xres, yres);
     }
     pwg_ppdize_resolution(attr, count / 2, &xres, &yres, NULL, 0);
     cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Normal")), xres, yres);
-    if (count > 1)
+    if (count > 1 || ippContainsInteger(quality, IPP_QUALITY_HIGH))
     {
-      pwg_ppdize_resolution(attr, count - 1, &xres, &yres, NULL, 0);
+      if (count > 1)
+        pwg_ppdize_resolution(attr, count - 1, &xres, &yres, NULL, 0);
+      else
+        pwg_ppdize_resolution(attr, 0, &xres, &yres, NULL, 0);
       cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("High")), xres, yres);
     }
 
@@ -3731,7 +4016,7 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
       * Invalid "urf-supported" value...
       */
 
-      cupsFilePuts(fp, "*DefaultResolution: 300dpi\n");
+      goto bad_ppd;
     }
     else
     {
@@ -3746,19 +4031,40 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
 			 "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang, _("Print Quality")));
       if ((lowdpi & 1) == 0)
 	cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), lowdpi, lowdpi / 2);
+      else if (ippContainsInteger(quality, IPP_QUALITY_DRAFT))
+	cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), lowdpi, lowdpi);
       cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Normal")), lowdpi, lowdpi);
-      if (hidpi > lowdpi)
+      if (hidpi > lowdpi || ippContainsInteger(quality, IPP_QUALITY_HIGH))
 	cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("High")), 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 if (is_apple || is_pwg)
+    goto bad_ppd;
   else
-    cupsFilePuts(fp, "*DefaultResolution: 300dpi\n");
+  {
+    if ((attr = ippFindAttribute(response, "printer-resolution-default", IPP_TAG_RESOLUTION)) != NULL)
+    {
+      pwg_ppdize_resolution(attr, 0, &xres, &yres, ppdname, sizeof(ppdname));
+    }
+    else
+    {
+      xres = yres = 300;
+      strlcpy(ppdname, "300dpi", sizeof(ppdname));
+    }
+
+    cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname);
+
+    cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality/%s: PickOne\n"
+                       "*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
+                       "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang, _("Print Quality")));
+    if (ippContainsInteger(quality, IPP_QUALITY_DRAFT))
+      cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), xres, yres);
+    cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("Normal")), xres, yres);
+    if (ippContainsInteger(quality, IPP_QUALITY_HIGH))
+      cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<>setpagedevice\"\n", _cupsLangString(lang, _("High")), xres, yres);
+    cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n");
+  }
 
  /*
   * Close up and return...
@@ -3767,6 +4073,20 @@ _ppdCreateFromIPP(char   *buffer,	/* I - Filename buffer */
   cupsFileClose(fp);
 
   return (buffer);
+
+ /*
+  * If we get here then there was a problem creating the PPD...
+  */
+
+  bad_ppd:
+
+  cupsFileClose(fp);
+  unlink(buffer);
+  *buffer = '\0';
+
+  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Printer does not support required IPP attributes or document formats."), 1);
+
+  return (NULL);
 }
 
 
@@ -3925,11 +4245,35 @@ _pwgPageSizeForMedia(
 }
 
 
+/*
+ * 'pwg_add_finishing()' - Add a finishings value.
+ */
+
+static void
+pwg_add_finishing(
+    cups_array_t     *finishings,	/* I - Finishings array */
+    ipp_finishings_t template,		/* I - Finishing template */
+    const char       *name,		/* I - PPD option */
+    const char       *value)		/* I - PPD choice */
+{
+  _pwg_finishings_t	*f;		/* New finishings value */
+
+
+  if ((f = (_pwg_finishings_t *)calloc(1, sizeof(_pwg_finishings_t))) != NULL)
+  {
+    f->value       = template;
+    f->num_options = cupsAddOption(name, value, 0, &f->options);
+
+    cupsArrayAdd(finishings, f);
+  }
+}
+
+
 /*
  * 'pwg_compare_finishings()' - Compare two finishings values.
  */
 
-static int				/* O- Result of comparison */
+static int				/* O - Result of comparison */
 pwg_compare_finishings(
     _pwg_finishings_t *a,		/* I - First finishings value */
     _pwg_finishings_t *b)		/* I - Second finishings value */
@@ -3951,22 +4295,6 @@ pwg_free_finishings(
 }
 
 
-/*
- * 'pwg_free_material()' - Free a material value.
- */
-
-static void
-pwg_free_material(_pwg_material_t *m)	/* I - Material value */
-{
-  _cupsStrFree(m->key);
-  _cupsStrFree(m->name);
-
-  cupsFreeOptions(m->num_props, m->props);
-
-  free(m);
-}
-
-
 /*
  * 'pwg_ppdize_name()' - Convert an IPP keyword to a PPD keyword.
  */
@@ -3980,11 +4308,17 @@ pwg_ppdize_name(const char *ipp,	/* I - IPP keyword */
 	*end;				/* End of name buffer */
 
 
+  if (!ipp)
+  {
+    *name = '\0';
+    return;
+  }
+
   *name = (char)toupper(*ipp++);
 
   for (ptr = name + 1, end = name + namesize - 1; *ipp && ptr < end;)
   {
-    if (*ipp == '-' && _cups_isalpha(ipp[1]))
+    if (*ipp == '-' && _cups_isalnum(ipp[1]))
     {
       ipp ++;
       *ptr++ = (char)toupper(*ipp++ & 255);
diff --git a/cups/ppd-conflicts.c b/cups/ppd-conflicts.c
index 68e03b4..8f875a5 100644
--- a/cups/ppd-conflicts.c
+++ b/cups/ppd-conflicts.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * PostScript is a trademark of Adobe Systems, Inc.
  *
diff --git a/cups/ppd-custom.c b/cups/ppd-custom.c
index 6e4d3bd..b7070fa 100644
--- a/cups/ppd-custom.c
+++ b/cups/ppd-custom.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * PostScript is a trademark of Adobe Systems, Inc.
  *
diff --git a/cups/ppd-emit.c b/cups/ppd-emit.c
index 0b4f1c9..36e5bca 100644
--- a/cups/ppd-emit.c
+++ b/cups/ppd-emit.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * PostScript is a trademark of Adobe Systems, Inc.
  *
diff --git a/cups/ppd-localize.c b/cups/ppd-localize.c
index db93170..ed75bf8 100644
--- a/cups/ppd-localize.c
+++ b/cups/ppd-localize.c
@@ -1,14 +1,14 @@
 /*
  * PPD localization routines for CUPS.
  *
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * PostScript is a trademark of Adobe Systems, Inc.
  *
@@ -665,7 +665,7 @@ _ppdLocalizedAttr(ppd_file_t *ppd,	/* I - PPD file */
    /*
     * 
     *
-    * Hong Kong locale needs special handling...  Sigh...
+    * Multiple locales need special handling...  Sigh...
     */
 
     if (!strcmp(ll_CC, "zh_HK"))
diff --git a/cups/ppd-mark.c b/cups/ppd-mark.c
index 08bc993..9fdaf0b 100644
--- a/cups/ppd-mark.c
+++ b/cups/ppd-mark.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * PostScript is a trademark of Adobe Systems, Inc.
  *
diff --git a/cups/ppd-page.c b/cups/ppd-page.c
index f18e68d..ccbf052 100644
--- a/cups/ppd-page.c
+++ b/cups/ppd-page.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * PostScript is a trademark of Adobe Systems, Inc.
  *
diff --git a/cups/ppd-private.h b/cups/ppd-private.h
index 83f048e..b199bbd 100644
--- a/cups/ppd-private.h
+++ b/cups/ppd-private.h
@@ -1,14 +1,14 @@
 /*
  * Private PPD definitions for CUPS.
  *
- * Copyright 2007-2015 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * PostScript is a trademark of Adobe Systems, Inc.
  *
@@ -47,7 +47,7 @@ extern "C" {
  * Constants...
  */
 
-#  define _PPD_CACHE_VERSION	7	/* Version number in cache file */
+#  define _PPD_CACHE_VERSION	8	/* Version number in cache file */
 
 
 /*
@@ -100,7 +100,7 @@ typedef enum _pwg_print_color_mode_e	/**** PWG print-color-mode indices ****/
 {
   _PWG_PRINT_COLOR_MODE_MONOCHROME = 0,	/* print-color-mode=monochrome */
   _PWG_PRINT_COLOR_MODE_COLOR,		/* print-color-mode=color */
-  /* Other proposed values are not supported by CUPS yet. */
+  /* Other values are not supported by CUPS yet. */
   _PWG_PRINT_COLOR_MODE_MAX
 } _pwg_print_color_mode_t;
 
@@ -119,14 +119,6 @@ typedef struct _pwg_finishings_s	/**** PWG finishings mapping data ****/
   cups_option_t		*options;	/* Options to apply */
 } _pwg_finishings_t;
 
-typedef struct _pwg_material_s		/**** PWG material mapping data ****/
-{
-  char		*key,			/* material-key value */
-		*name;			/* material-name value */
-  int		num_props;		/* Number of properties */
-  cups_option_t	*props;			/* Material properties */
-} _pwg_material_t;
-
 struct _ppd_cache_s			/**** PPD cache and PWG conversion data ****/
 {
   int		num_bins;		/* Number of output bins */
@@ -166,11 +158,6 @@ struct _ppd_cache_s			/**** PPD cache and PWG conversion data ****/
   cups_array_t	*mandatory;		/* cupsMandatory value */
   char		*charge_info_uri;	/* cupsChargeInfoURI value */
   cups_array_t	*support_files;		/* Support files - ICC profiles, etc. */
-  char		*cups_3d,		/* cups3D value */
-		*cups_layer_order;	/* cupsLayerOrder value */
-  int		cups_accuracy[3];	/* cupsAccuracy value - x, y, and z in nanometers */
-  int		cups_volume[3];		/* cupsVolume value - x, y, and z in millimeters */
-  cups_array_t	*materials;		/* cupsMaterial values */
 };
 
 
diff --git a/cups/ppd-util.c b/cups/ppd-util.c
index af5bd20..d0194c8 100644
--- a/cups/ppd-util.c
+++ b/cups/ppd-util.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/ppd.c b/cups/ppd.c
index 44a22c5..5bd839d 100644
--- a/cups/ppd.c
+++ b/cups/ppd.c
@@ -1,14 +1,14 @@
 /*
  * PPD file routines for CUPS.
  *
- * Copyright 2007-2015 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * PostScript is a trademark of Adobe Systems, Inc.
  *
@@ -579,12 +579,28 @@ _ppdOpen(
 
    /*
     * 
+    * 
     *
     * Need to use a different base language for some locales...
     */
 
     if (!strcmp(lang->language, "zh_HK"))
-      strlcpy(ll, "zh_TW.", sizeof(ll));
+    {					/* Traditional Chinese + variants */
+      strlcpy(ll_CC, "zh_TW.", sizeof(ll_CC));
+      strlcpy(ll, "zh_", sizeof(ll));
+    }
+    else if (!strncmp(lang->language, "zh", 2))
+      strlcpy(ll, "zh_", sizeof(ll));	/* Any Chinese variant */
+    else if (!strncmp(lang->language, "jp", 2))
+    {					/* Any Japanese variant */
+      strlcpy(ll_CC, "ja", sizeof(ll_CC));
+      strlcpy(ll, "jp", sizeof(ll));
+    }
+    else if (!strncmp(lang->language, "nb", 2) || !strncmp(lang->language, "no", 2))
+    {					/* Any Norwegian variant */
+      strlcpy(ll_CC, "nb", sizeof(ll_CC));
+      strlcpy(ll, "no", sizeof(ll));
+    }
     else
       snprintf(ll, sizeof(ll), "%2.2s.", lang->language);
 
diff --git a/cups/ppd.h b/cups/ppd.h
index eb9ab38..fb33c08 100644
--- a/cups/ppd.h
+++ b/cups/ppd.h
@@ -12,7 +12,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * PostScript is a trademark of Adobe Systems, Inc.
  *
diff --git a/cups/pwg-media.c b/cups/pwg-media.c
index 6a20687..73356fd 100644
--- a/cups/pwg-media.c
+++ b/cups/pwg-media.c
@@ -1,13 +1,13 @@
 /*
  * PWG media name API implementation for CUPS.
  *
- * Copyright 2009-2016 by Apple Inc.
+ * Copyright 2009-2017 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -37,8 +37,7 @@ static int	pwg_compare_pwg(pwg_media_t *a, pwg_media_t *b);
 static int	pwg_compare_ppd(pwg_media_t *a, pwg_media_t *b);
 static char	*pwg_format_inches(char *buf, size_t bufsize, int val);
 static char	*pwg_format_millimeters(char *buf, size_t bufsize, int val);
-static int	pwg_scan_measurement(const char *buf, char **bufptr, int numer,
-		                     int denom);
+static int	pwg_scan_measurement(const char *buf, char **bufptr, int numer, int denom);
 
 
 /*
@@ -61,7 +60,7 @@ static pwg_media_t const cups_pwg_media[] =
   _PWG_MEDIA_IN("na_index-5x8_5x8in", NULL, "5x8", 5, 8),
   _PWG_MEDIA_IN("na_number-14_5x11.5in", NULL, "Env14", 5, 11.5),
   _PWG_MEDIA_IN("na_invoice_5.5x8.5in", "invoice", "Statement", 5.5, 8.5),
-  _PWG_MEDIA_IN("na_index-4x6-ext_6x8in", NULL, NULL, 6, 8),
+  _PWG_MEDIA_IN("na_index-4x6-ext_6x8in", NULL, "6x8", 6, 8),
   _PWG_MEDIA_IN("na_6x9_6x9in", "na-6x9-envelope", "6x9", 6, 9),
   _PWG_MEDIA_IN("na_c5_6.5x9.5in", NULL, "6.5x9.5", 6.5, 9.5),
   _PWG_MEDIA_IN("na_7x9_7x9in", "na-7x9-envelope", "7x9", 7, 9),
@@ -86,7 +85,7 @@ static pwg_media_t const cups_pwg_media[] =
   _PWG_MEDIA_IN("na_10x15_10x15in", "na-10x15-envelope", "10x15", 10, 15),
   _PWG_MEDIA_IN("na_11x12_11x12in", NULL, "11x12", 11, 12),
   _PWG_MEDIA_IN("na_edp_11x14in", NULL, "11x14", 11, 14),
-  _PWG_MEDIA_IN("na_fanfold-us_11x14.875in", NULL, NULL, 11, 14.875),
+  _PWG_MEDIA_IN("na_fanfold-us_11x14.875in", NULL, "11x14.875", 11, 14.875),
   _PWG_MEDIA_IN("na_11x15_11x15in", NULL, "11x15", 11, 15),
   _PWG_MEDIA_IN("na_ledger_11x17in", "tabloid", "Tabloid", 11, 17),
   _PWG_MEDIA_IN("na_eur-edp_12x14in", NULL, NULL, 12, 14),
@@ -98,8 +97,8 @@ static pwg_media_t const cups_pwg_media[] =
   _PWG_MEDIA_IN("na_arch-c_18x24in", "arch-c", "ARCHC", 18, 24),
   _PWG_MEDIA_IN("na_d_22x34in", "d", "AnsiD", 22, 34),
   _PWG_MEDIA_IN("na_arch-d_24x36in", "arch-d", "ARCHD", 24, 36),
-  _PWG_MEDIA_IN("asme_f_28x40in", "f", NULL, 28, 40),
-  _PWG_MEDIA_IN("na_wide-format_30x42in", NULL, NULL, 30, 42),
+  _PWG_MEDIA_IN("asme_f_28x40in", "f", "28x40", 28, 40),
+  _PWG_MEDIA_IN("na_wide-format_30x42in", NULL, "30x42", 30, 42),
   _PWG_MEDIA_IN("na_e_34x44in", "e", "AnsiE", 34, 44),
   _PWG_MEDIA_IN("na_arch-e_36x48in", "arch-e", "ARCHE", 36, 48),
   _PWG_MEDIA_IN("na_f_44x68in", NULL, "AnsiF", 44, 68),
@@ -116,35 +115,35 @@ static pwg_media_t const cups_pwg_media[] =
   _PWG_MEDIA_MM("iso_a4-tab_225x297mm", NULL, "A4Tab", 225, 297),
   _PWG_MEDIA_MM("iso_a4-extra_235.5x322.3mm", NULL, "A4Extra", 235.5, 322.3),
   _PWG_MEDIA_MM("iso_a3_297x420mm", "iso-a3", "A3", 297, 420),
-  _PWG_MEDIA_MM("iso_a4x3_297x630mm", "iso-a4x3", NULL, 297, 630),
-  _PWG_MEDIA_MM("iso_a4x4_297x841mm", "iso-a4x4", NULL, 297, 841),
-  _PWG_MEDIA_MM("iso_a4x5_297x1051mm", "iso-a4x5", NULL, 297, 1051),
-  _PWG_MEDIA_MM("iso_a4x6_297x1261mm", "iso-a4x6", NULL, 297, 1261),
-  _PWG_MEDIA_MM("iso_a4x7_297x1471mm", "iso-a4x7", NULL, 297, 1471),
-  _PWG_MEDIA_MM("iso_a4x8_297x1682mm", "iso-a4x8", NULL, 297, 1682),
-  _PWG_MEDIA_MM("iso_a4x9_297x1892mm", "iso-a4x9", NULL, 297, 1892),
+  _PWG_MEDIA_MM("iso_a4x3_297x630mm", "iso-a4x3", "A4x3", 297, 630),
+  _PWG_MEDIA_MM("iso_a4x4_297x841mm", "iso-a4x4", "A4x4", 297, 841),
+  _PWG_MEDIA_MM("iso_a4x5_297x1051mm", "iso-a4x5", "A4x5", 297, 1051),
+  _PWG_MEDIA_MM("iso_a4x6_297x1261mm", "iso-a4x6", "A4x6", 297, 1261),
+  _PWG_MEDIA_MM("iso_a4x7_297x1471mm", "iso-a4x7", "A4x7", 297, 1471),
+  _PWG_MEDIA_MM("iso_a4x8_297x1682mm", "iso-a4x8", "A4x8", 297, 1682),
+  _PWG_MEDIA_MM("iso_a4x9_297x1892mm", "iso-a4x9", "A4x9", 297, 1892),
   _PWG_MEDIA_MM("iso_a3-extra_322x445mm", "iso-a3-extra", "A3Extra", 322, 445),
   _PWG_MEDIA_MM("iso_a2_420x594mm", "iso-a2", "A2", 420, 594),
-  _PWG_MEDIA_MM("iso_a3x3_420x891mm", "iso-a3x3", NULL, 420, 891),
-  _PWG_MEDIA_MM("iso_a3x4_420x1189mm", "iso-a3x4", NULL, 420, 1189),
-  _PWG_MEDIA_MM("iso_a3x5_420x1486mm", "iso-a3x5", NULL, 420, 1486),
-  _PWG_MEDIA_MM("iso_a3x6_420x1783mm", "iso-a3x6", NULL, 420, 1783),
-  _PWG_MEDIA_MM("iso_a3x7_420x2080mm", "iso-a3x7", NULL, 420, 2080),
+  _PWG_MEDIA_MM("iso_a3x3_420x891mm", "iso-a3x3", "A3x3", 420, 891),
+  _PWG_MEDIA_MM("iso_a3x4_420x1189mm", "iso-a3x4", "A3x4", 420, 1189),
+  _PWG_MEDIA_MM("iso_a3x5_420x1486mm", "iso-a3x5", "A3x6", 420, 1486),
+  _PWG_MEDIA_MM("iso_a3x6_420x1783mm", "iso-a3x6", "A3x6", 420, 1783),
+  _PWG_MEDIA_MM("iso_a3x7_420x2080mm", "iso-a3x7", "A3x7", 420, 2080),
   _PWG_MEDIA_MM("iso_a1_594x841mm", "iso-a1", "A1", 594, 841),
-  _PWG_MEDIA_MM("iso_a2x3_594x1261mm", "iso-a2x3", NULL, 594, 1261),
-  _PWG_MEDIA_MM("iso_a2x4_594x1682mm", "iso-a2x4", NULL, 594, 1682),
-  _PWG_MEDIA_MM("iso_a2x5_594x2102mm", "iso-a2x5", NULL, 594, 2102),
+  _PWG_MEDIA_MM("iso_a2x3_594x1261mm", "iso-a2x3", "A2x3", 594, 1261),
+  _PWG_MEDIA_MM("iso_a2x4_594x1682mm", "iso-a2x4", "A2x4", 594, 1682),
+  _PWG_MEDIA_MM("iso_a2x5_594x2102mm", "iso-a2x5", "A2x5", 594, 2102),
   _PWG_MEDIA_MM("iso_a0_841x1189mm", "iso-a0", "A0", 841, 1189),
-  _PWG_MEDIA_MM("iso_a1x3_841x1783mm", "iso-a1x3", NULL, 841, 1783),
-  _PWG_MEDIA_MM("iso_a1x4_841x2378mm", "iso-a1x4", NULL, 841, 2378),
-  _PWG_MEDIA_MM("iso_2a0_1189x1682mm", NULL, NULL, 1189, 1682),
-  _PWG_MEDIA_MM("iso_a0x3_1189x2523mm", NULL, NULL, 1189, 2523),
+  _PWG_MEDIA_MM("iso_a1x3_841x1783mm", "iso-a1x3", "A1x3", 841, 1783),
+  _PWG_MEDIA_MM("iso_a1x4_841x2378mm", "iso-a1x4", "A1x4", 841, 2378),
+  _PWG_MEDIA_MM("iso_2a0_1189x1682mm", NULL, "1189x1682mm", 1189, 1682),
+  _PWG_MEDIA_MM("iso_a0x3_1189x2523mm", NULL, "A0x3", 1189, 2523),
   _PWG_MEDIA_MM("iso_b10_31x44mm", "iso-b10", "ISOB10", 31, 44),
   _PWG_MEDIA_MM("iso_b9_44x62mm", "iso-b9", "ISOB9", 44, 62),
   _PWG_MEDIA_MM("iso_b8_62x88mm", "iso-b8", "ISOB8", 62, 88),
   _PWG_MEDIA_MM("iso_b7_88x125mm", "iso-b7", "ISOB7", 88, 125),
   _PWG_MEDIA_MM("iso_b6_125x176mm", "iso-b6", "ISOB6", 125, 176),
-  _PWG_MEDIA_MM("iso_b6c4_125x324mm", NULL, NULL, 125, 324),
+  _PWG_MEDIA_MM("iso_b6c4_125x324mm", NULL, "125x324mm", 125, 324),
   _PWG_MEDIA_MM("iso_b5_176x250mm", "iso-b5", "ISOB5", 176, 250),
   _PWG_MEDIA_MM("iso_b5-extra_201x276mm", NULL, "ISOB5Extra", 201, 276),
   _PWG_MEDIA_MM("iso_b4_250x353mm", "iso-b4", "ISOB4", 250, 353),
@@ -152,11 +151,11 @@ static pwg_media_t const cups_pwg_media[] =
   _PWG_MEDIA_MM("iso_b2_500x707mm", "iso-b2", "ISOB2", 500, 707),
   _PWG_MEDIA_MM("iso_b1_707x1000mm", "iso-b1", "ISOB1", 707, 1000),
   _PWG_MEDIA_MM("iso_b0_1000x1414mm", "iso-b0", "ISOB0", 1000, 1414),
-  _PWG_MEDIA_MM("iso_c10_28x40mm", "iso-c10", NULL, 28, 40),
-  _PWG_MEDIA_MM("iso_c9_40x57mm", "iso-c9", NULL, 40, 57),
-  _PWG_MEDIA_MM("iso_c8_57x81mm", "iso-c8", NULL, 57, 81),
+  _PWG_MEDIA_MM("iso_c10_28x40mm", "iso-c10", "EnvC10", 28, 40),
+  _PWG_MEDIA_MM("iso_c9_40x57mm", "iso-c9", "EnvC9", 40, 57),
+  _PWG_MEDIA_MM("iso_c8_57x81mm", "iso-c8", "EnvC8", 57, 81),
   _PWG_MEDIA_MM("iso_c7_81x114mm", "iso-c7", "EnvC7", 81, 114),
-  _PWG_MEDIA_MM("iso_c7c6_81x162mm", NULL, NULL, 81, 162),
+  _PWG_MEDIA_MM("iso_c7c6_81x162mm", NULL, "EnvC76", 81, 162),
   _PWG_MEDIA_MM("iso_c6_114x162mm", "iso-c6", "EnvC6", 114, 162),
   _PWG_MEDIA_MM("iso_c6c5_114x229mm", NULL, "EnvC65", 114, 229),
   _PWG_MEDIA_MM("iso_c5_162x229mm", "iso-c5", "EnvC5", 162, 229),
@@ -166,16 +165,16 @@ static pwg_media_t const cups_pwg_media[] =
   _PWG_MEDIA_MM("iso_c1_648x917mm", "iso-c1", "EnvC1", 648, 917),
   _PWG_MEDIA_MM("iso_c0_917x1297mm", "iso-c0", "EnvC0", 917, 1297),
   _PWG_MEDIA_MM("iso_dl_110x220mm", "iso-designated", "EnvDL", 110, 220),
-  _PWG_MEDIA_MM("iso_ra4_215x305mm", "iso-ra4", NULL, 215, 305),
-  _PWG_MEDIA_MM("iso_sra4_225x320mm", "iso-sra4", NULL, 225, 320),
-  _PWG_MEDIA_MM("iso_ra3_305x430mm", "iso-ra3", NULL, 305, 430),
-  _PWG_MEDIA_MM("iso_sra3_320x450mm", "iso-sra3", NULL, 320, 450),
-  _PWG_MEDIA_MM("iso_ra2_430x610mm", "iso-ra2", NULL, 430, 610),
-  _PWG_MEDIA_MM("iso_sra2_450x640mm", "iso-sra2", NULL, 450, 640),
-  _PWG_MEDIA_MM("iso_ra1_610x860mm", "iso-ra1", NULL, 610, 860),
-  _PWG_MEDIA_MM("iso_sra1_640x900mm", "iso-sra1", NULL, 640, 900),
-  _PWG_MEDIA_MM("iso_ra0_860x1220mm", "iso-ra0", NULL, 860, 1220),
-  _PWG_MEDIA_MM("iso_sra0_900x1280mm", "iso-sra0", NULL, 900, 1280),
+  _PWG_MEDIA_MM("iso_ra4_215x305mm", "iso-ra4", "RA4", 215, 305),
+  _PWG_MEDIA_MM("iso_sra4_225x320mm", "iso-sra4", "SRA4", 225, 320),
+  _PWG_MEDIA_MM("iso_ra3_305x430mm", "iso-ra3", "RA3", 305, 430),
+  _PWG_MEDIA_MM("iso_sra3_320x450mm", "iso-sra3", "SRA3", 320, 450),
+  _PWG_MEDIA_MM("iso_ra2_430x610mm", "iso-ra2", "RA2", 430, 610),
+  _PWG_MEDIA_MM("iso_sra2_450x640mm", "iso-sra2", "SRA2", 450, 640),
+  _PWG_MEDIA_MM("iso_ra1_610x860mm", "iso-ra1", "RA1", 610, 860),
+  _PWG_MEDIA_MM("iso_sra1_640x900mm", "iso-sra1", "SRA1", 640, 900),
+  _PWG_MEDIA_MM("iso_ra0_860x1220mm", "iso-ra0", "RA0", 860, 1220),
+  _PWG_MEDIA_MM("iso_sra0_900x1280mm", "iso-sra0", "SRA0", 900, 1280),
 
   /* Japanese Standard Sheet Media Sizes */
   _PWG_MEDIA_MM("jis_b10_32x45mm", "jis-b10", "B10", 32, 45),
@@ -189,7 +188,7 @@ static pwg_media_t const cups_pwg_media[] =
   _PWG_MEDIA_MM("jis_b2_515x728mm", "jis-b2", "B2", 515, 728),
   _PWG_MEDIA_MM("jis_b1_728x1030mm", "jis-b1", "B1", 728, 1030),
   _PWG_MEDIA_MM("jis_b0_1030x1456mm", "jis-b0", "B0", 1030, 1456),
-  _PWG_MEDIA_MM("jis_exec_216x330mm", NULL, NULL, 216, 330),
+  _PWG_MEDIA_MM("jis_exec_216x330mm", NULL, "216x330mm", 216, 330),
   _PWG_MEDIA_MM("jpn_kaku2_240x332mm", NULL, "EnvKaku2", 240, 332),
   _PWG_MEDIA_MM("jpn_kaku3_216x277mm", NULL, "EnvKaku3", 216, 277),
   _PWG_MEDIA_MM("jpn_kaku4_197x267mm", NULL, "EnvKaku4", 197, 267),
@@ -204,7 +203,7 @@ static pwg_media_t const cups_pwg_media[] =
   _PWG_MEDIA_MM("jpn_chou3_120x235mm", NULL, "EnvChou3", 120, 235),
   _PWG_MEDIA_MM("jpn_chou40_90x225mm", NULL, "EnvChou40", 90, 225),
   _PWG_MEDIA_MM("jpn_oufuku_148x200mm", NULL, "DoublePostcardRotated", 148, 200),
-  _PWG_MEDIA_MM("jpn_kahu_240x322.1mm", NULL, NULL, 240, 322.1),
+  _PWG_MEDIA_MM("jpn_kahu_240x322.1mm", NULL, "240x322mm", 240, 322.1),
 
   /* Chinese Standard Sheet Media Sizes */
   _PWG_MEDIA_MM("prc_32k_97x151mm", NULL, "PRC32K", 97, 151),
@@ -215,9 +214,9 @@ static pwg_media_t const cups_pwg_media[] =
   _PWG_MEDIA_MM("prc_6_120x320mm", NULL, NULL, 120, 320),
   _PWG_MEDIA_MM("prc_16k_146x215mm", NULL, "PRC16K", 146, 215),
   _PWG_MEDIA_MM("prc_7_160x230mm", NULL, "EnvPRC7", 160, 230),
-  _PWG_MEDIA_MM("om_juuro-ku-kai_198x275mm", NULL, NULL, 198, 275),
-  _PWG_MEDIA_MM("om_pa-kai_267x389mm", NULL, NULL, 267, 389),
-  _PWG_MEDIA_MM("om_dai-pa-kai_275x395mm", NULL, NULL, 275, 395),
+  _PWG_MEDIA_MM("om_juuro-ku-kai_198x275mm", NULL, "198x275mm", 198, 275),
+  _PWG_MEDIA_MM("om_pa-kai_267x389mm", NULL, "267x389mm", 267, 389),
+  _PWG_MEDIA_MM("om_dai-pa-kai_275x395mm", NULL, "275x395mm", 275, 395),
 
   /* Chinese Standard Sheet Media Inch Sizes */
   _PWG_MEDIA_IN("roc_16k_7.75x10.75in", NULL, "roc16k", 7.75, 10.75),
@@ -227,16 +226,16 @@ static pwg_media_t const cups_pwg_media[] =
   _PWG_MEDIA_IN("oe_photo-l_3.5x5in", NULL, "3.5x5", 3.5, 5),
 
   /* Other Metric Standard Sheet Media Sizes */
-  _PWG_MEDIA_MM("om_small-photo_100x150mm", NULL, "om_small-photo", 100, 150),
+  _PWG_MEDIA_MM("om_small-photo_100x150mm", NULL, "100x150mm", 100, 150),
   _PWG_MEDIA_MM("om_italian_110x230mm", NULL, "EnvItalian", 110, 230),
-  _PWG_MEDIA_MM("om_large-photo_200x300", NULL, "om_large-photo", 200, 300),
+  _PWG_MEDIA_MM("om_large-photo_200x300", NULL, "200x300mm", 200, 300),
   _PWG_MEDIA_MM("om_folio_210x330mm", "folio", "Folio", 210, 330),
   _PWG_MEDIA_MM("om_folio-sp_215x315mm", NULL, "FolioSP", 215, 315),
   _PWG_MEDIA_MM("om_invite_220x220mm", NULL, "EnvInvite", 220, 220),
-  _PWG_MEDIA_MM("om_small-photo_100x200mm", NULL, "om_wide-photo", 100, 200),
+  _PWG_MEDIA_MM("om_small-photo_100x200mm", NULL, "100x200mm", 100, 200),
 
   /* Disc Sizes */
-  _PWG_MEDIA_MM("disc_standard_40x118mm", NULL, NULL, 118, 118)
+  _PWG_MEDIA_MM("disc_standard_40x118mm", NULL, "Disc", 118, 118)
 };
 
 
@@ -378,11 +377,6 @@ pwgFormatSizeName(char       *keyword,	/* I - Keyword buffer */
   return (1);
 }
 
-/* For macOS 10.8 and earlier... */
-void _pwgGenerateSize(char *keyword, size_t keysize, const char *prefix,
-		      const char *name, int width, int length)
-{ pwgFormatSizeName(keyword, keysize, prefix, name, width, length, NULL); }
-
 
 /*
  * 'pwgInitSize()' - Initialize a pwg_size_t structure using IPP Job Template
@@ -560,10 +554,6 @@ pwgInitSize(pwg_size_t *size,		/* I - Size to initialize */
   return (1);
 }
 
-/* For macOS 10.8 and earlier */
-int _pwgInitSize(pwg_size_t *size, ipp_t *job, int *margins_set)
-{ return (pwgInitSize(size, job, margins_set)); }
-
 
 /*
  * 'pwgMediaForLegacy()' - Find a PWG media size by ISO/IPP legacy name.
@@ -771,6 +761,8 @@ pwgMediaForPPD(const char *ppd)		/* I - PPD size name */
 	*     [oe|om]_WIDTHxHEIGHTuu_WIDTHxHEIGHTuu
 	*/
 
+        char	wstr[32], lstr[32];	/* Width and length as strings */
+
 	size         = &(cg->pwg_media);
 	size->width  = w;
 	size->length = l;
@@ -779,6 +771,12 @@ pwgMediaForPPD(const char *ppd)		/* I - PPD size name */
 	pwgFormatSizeName(cg->pwg_name, sizeof(cg->pwg_name),
 	                  custom ? "custom" : NULL, custom ? ppd + 7 : NULL,
 	                  size->width, size->length, NULL);
+
+        if ((w % 635) == 0 && (l % 635) == 0)
+          snprintf(cg->ppd_name, sizeof(cg->ppd_name), "%sx%s", pwg_format_inches(wstr, sizeof(wstr), w), pwg_format_inches(lstr, sizeof(lstr), l));
+        else
+          snprintf(cg->ppd_name, sizeof(cg->ppd_name), "%sx%smm", pwg_format_millimeters(wstr, sizeof(wstr), w), pwg_format_millimeters(lstr, sizeof(lstr), l));
+        size->ppd = cg->ppd_name;
       }
     }
   }
@@ -869,6 +867,8 @@ pwgMediaForPWG(const char *pwg)		/* I - PWG size name */
 
       if (ptr)
       {
+        char	wstr[32], lstr[32];	/* Width and length strings */
+
         if (!strncmp(pwg, "disc_", 5))
           w = l;			/* Make the media size OUTERxOUTER */
 
@@ -878,6 +878,12 @@ pwgMediaForPWG(const char *pwg)		/* I - PWG size name */
 
         strlcpy(cg->pwg_name, pwg, sizeof(cg->pwg_name));
 	size->pwg = cg->pwg_name;
+
+        if (numer == 100)
+          snprintf(cg->ppd_name, sizeof(cg->ppd_name), "%sx%smm", pwg_format_millimeters(wstr, sizeof(wstr), w), pwg_format_millimeters(lstr, sizeof(lstr), l));
+        else
+          snprintf(cg->ppd_name, sizeof(cg->ppd_name), "%sx%s", pwg_format_inches(wstr, sizeof(wstr), w), pwg_format_inches(lstr, sizeof(lstr), l));
+        size->ppd = cg->ppd_name;
       }
     }
   }
@@ -927,6 +933,7 @@ _pwgMediaNearSize(int width,	        /* I - Width in hundredths of millimeters *
   int		dw, dl,			/* Difference in width and length */
 		best_dw = 999,		/* Best difference in width and length */
 		best_dl = 999;
+  char		wstr[32], lstr[32];	/* Width and length as strings */
   _cups_globals_t *cg = _cupsGlobals();	/* Global data */
 
 
@@ -979,6 +986,12 @@ _pwgMediaNearSize(int width,	        /* I - Width in hundredths of millimeters *
   cg->pwg_media.width  = width;
   cg->pwg_media.length = length;
 
+  if ((width % 635) == 0 && (length % 635) == 0)
+    snprintf(cg->ppd_name, sizeof(cg->ppd_name), "%sx%s", pwg_format_inches(wstr, sizeof(wstr), width), pwg_format_inches(lstr, sizeof(lstr), length));
+  else
+    snprintf(cg->ppd_name, sizeof(cg->ppd_name), "%sx%smm", pwg_format_millimeters(wstr, sizeof(wstr), width), pwg_format_millimeters(lstr, sizeof(lstr), length));
+  cg->pwg_media.ppd = cg->ppd_name;
+
   return (&(cg->pwg_media));
 }
 
@@ -1038,8 +1051,8 @@ pwg_compare_pwg(pwg_media_t *a,	/* I - First size */
 
 static char *				/* O - String */
 pwg_format_inches(char   *buf,		/* I - Buffer */
-                 size_t bufsize,	/* I - Size of buffer */
-                 int    val)		/* I - Value in hundredths of millimeters */
+                  size_t bufsize,	/* I - Size of buffer */
+                  int    val)		/* I - Value in hundredths of millimeters */
 {
   int	thousandths,			/* Thousandths of inches */
 	integer,			/* Integer portion */
@@ -1079,8 +1092,8 @@ pwg_format_inches(char   *buf,		/* I - Buffer */
 
 static char *				/* O - String */
 pwg_format_millimeters(char   *buf,	/* I - Buffer */
-                      size_t bufsize,	/* I - Size of buffer */
-                      int    val)	/* I - Value in hundredths of millimeters */
+                       size_t bufsize,	/* I - Size of buffer */
+                       int    val)	/* I - Value in hundredths of millimeters */
 {
   int	integer,			/* Integer portion */
 	fraction;			/* Fractional portion */
diff --git a/cups/pwg-private.h b/cups/pwg-private.h
index 25fb667..e771590 100644
--- a/cups/pwg-private.h
+++ b/cups/pwg-private.h
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/pwg.h b/cups/pwg.h
index f663246..4204050 100644
--- a/cups/pwg.h
+++ b/cups/pwg.h
@@ -1,13 +1,13 @@
 /*
  * PWG media API definitions for CUPS.
  *
- * Copyright 2009-2013 by Apple Inc.
+ * Copyright 2009-2017 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -39,7 +39,7 @@ extern "C" {
  * Types and structures...
  */
 
-typedef struct pwg_map_s		/**** Map element - PPD to/from PWG */
+typedef struct pwg_map_s		/**** Map element - PPD to/from PWG @exclude all@ */
 {
   char		*pwg,			/* PWG media keyword */
 		*ppd;			/* PPD option keyword */
@@ -54,7 +54,7 @@ typedef struct pwg_media_s		/**** Common media size data ****/
 		length;			/* Length in 2540ths */
 } pwg_media_t;
 
-typedef struct pwg_size_s		/**** Size element - PPD to/from PWG */
+typedef struct pwg_size_s		/**** Size element - PPD to/from PWG @exclude all@ */
 {
   pwg_map_t	map;			/* Map element */
   int		width,			/* Width in 2540ths */
diff --git a/cups/raster-private.h b/cups/raster-private.h
index 7656b27..3813581 100644
--- a/cups/raster-private.h
+++ b/cups/raster-private.h
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/raster.h b/cups/raster.h
index 43a9d15..4067b3c 100644
--- a/cups/raster.h
+++ b/cups/raster.h
@@ -10,7 +10,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -52,6 +52,9 @@ extern "C" {
 #  define CUPS_RASTER_SYNCv2	0x52615332	/* RaS2 */
 #  define CUPS_RASTER_REVSYNCv2	0x32536152	/* 2SaR */
 
+#  define CUPS_RASTER_SYNCapple	0x554E4952	/* UNIR */
+#  define CUPS_RASTER_REVSYNCapple 0x52494E55	/* RINU */
+
 #  define CUPS_RASTER_SYNC_PWG	CUPS_RASTER_SYNCv2
 
 /*
@@ -75,6 +78,13 @@ extern "C" {
 
 #  define CUPS_RASTER_HAVE_PWGRASTER 1
 
+/*
+ * The following definition can be used to determine if Apple Raster is
+ * supported (beta).
+ */
+
+#  define CUPS_RASTER_HAVE_APPLERASTER 1
+
 /*
  * The following PWG 5102.4 definitions specify indices into the
  * cupsInteger[] array in the raster header.
@@ -202,7 +212,8 @@ enum cups_mode_e			/**** cupsRasterOpen modes ****/
   CUPS_RASTER_READ = 0,			/* Open stream for reading */
   CUPS_RASTER_WRITE = 1,		/* Open stream for writing */
   CUPS_RASTER_WRITE_COMPRESSED = 2,	/* Open stream for compressed writing @since CUPS 1.3/macOS 10.5@ */
-  CUPS_RASTER_WRITE_PWG = 3		/* Open stream for compressed writing in PWG mode @since CUPS 1.5/macOS 10.7@ */
+  CUPS_RASTER_WRITE_PWG = 3,		/* Open stream for compressed writing in PWG Raster mode @since CUPS 1.5/macOS 10.7@ */
+  CUPS_RASTER_WRITE_APPLE = 4		/* Open stream for compressed writing in AppleRaster mode (beta) @private@ */
 };
 
 typedef enum cups_mode_e cups_mode_t;	/**** cupsRasterOpen modes ****/
diff --git a/cups/request.c b/cups/request.c
index 8de44f7..39cbe6c 100644
--- a/cups/request.c
+++ b/cups/request.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/sidechannel.c b/cups/sidechannel.c
index 8070ea7..a4cd960 100644
--- a/cups/sidechannel.c
+++ b/cups/sidechannel.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/sidechannel.h b/cups/sidechannel.h
index 3de4542..a82408f 100644
--- a/cups/sidechannel.h
+++ b/cups/sidechannel.h
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/snmp.c b/cups/snmp.c
index fffa218..7958b93 100644
--- a/cups/snmp.c
+++ b/cups/snmp.c
@@ -739,6 +739,10 @@ asn1_debug(const char    *prefix,	/* I - Prefix string */
   _cups_globals_t *cg = _cupsGlobals();	/* Global data */
 
 
+#ifdef __clang_analyzer__ /* Suppress bogus clang error */
+  memset(string, 0, sizeof(string));
+#endif /* __clang_analyzer__ */
+
   if (cg->snmp_debug <= 0)
     return;
 
diff --git a/cups/snprintf.c b/cups/snprintf.c
index d586ce9..c5d8908 100644
--- a/cups/snprintf.c
+++ b/cups/snprintf.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/string-private.h b/cups/string-private.h
index 8b1140b..e8448d1 100644
--- a/cups/string-private.h
+++ b/cups/string-private.h
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/string.c b/cups/string.c
index 0a531b1..0d4ed0f 100644
--- a/cups/string.c
+++ b/cups/string.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -231,15 +231,12 @@ _cupsStrFormatd(char         *buf,	/* I - String */
   * Next, find the decimal point...
   */
 
-/* 07/22/2016 Mopria-notice: this causes "struct lconv has no member named 'decimal_point'"
-compilation error in Android so commenting out
-   if (loc && loc->decimal_point)
+  if (loc && loc->decimal_point)
   {
     dec    = loc->decimal_point;
     declen = (int)strlen(dec);
   }
   else
-  */
   {
     dec    = ".";
     declen = 1;
@@ -448,16 +445,12 @@ _cupsStrScand(const char   *buf,	/* I - Pointer to number */
 
     buf ++;
 
-/*    07/22/2016 Mopria-notice: this causes "struct lconv has no member named 'decimal_point'"
-      compilation error in Android so commenting out
     if (loc && loc->decimal_point)
     {
       strlcpy(tempptr, loc->decimal_point, sizeof(temp) - (size_t)(tempptr - temp));
       tempptr += strlen(tempptr);
     }
-    else
-    */
-    if (tempptr < (temp + sizeof(temp) - 1))
+    else if (tempptr < (temp + sizeof(temp) - 1))
       *tempptr++ = '.';
     else
     {
@@ -702,10 +695,11 @@ _cups_strlcat(char       *dst,		/* O - Destination string */
   */
 
   dstlen = strlen(dst);
-  size   -= dstlen + 1;
 
-  if (!size)
-    return (dstlen);		/* No room, return immediately... */
+  if (size < (dstlen + 1))
+    return (dstlen);		        /* No room, return immediately... */
+
+  size -= dstlen + 1;
 
  /*
   * Figure out how much room is needed...
diff --git a/cups/tempfile.c b/cups/tempfile.c
index d96ee7d..da705a9 100644
--- a/cups/tempfile.c
+++ b/cups/tempfile.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testadmin.c b/cups/testadmin.c
index f15c808..69b5efb 100644
--- a/cups/testadmin.c
+++ b/cups/testadmin.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testarray.c b/cups/testarray.c
index 5ae7315..6164ffc 100644
--- a/cups/testarray.c
+++ b/cups/testarray.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testcache.c b/cups/testcache.c
index 9025a0d..e7816a3 100644
--- a/cups/testcache.c
+++ b/cups/testcache.c
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testconflicts.c b/cups/testconflicts.c
index d07b088..973c5a0 100644
--- a/cups/testconflicts.c
+++ b/cups/testconflicts.c
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testcreds.c b/cups/testcreds.c
index 8e3c878..bc17a20 100644
--- a/cups/testcreds.c
+++ b/cups/testcreds.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testcups.c b/cups/testcups.c
index b6bf78f..aa58766 100644
--- a/cups/testcups.c
+++ b/cups/testcups.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testdest.c b/cups/testdest.c
index de6f1da..4e2cbed 100644
--- a/cups/testdest.c
+++ b/cups/testdest.c
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -218,9 +218,9 @@ enum_cb(void        *user_data,		/* I - User data (unused) */
   (void)flags;
 
   if (dest->instance)
-    printf("%s/%s:\n", dest->name, dest->instance);
+    printf("%s%s/%s:\n", (flags & CUPS_DEST_FLAGS_REMOVED) ? "REMOVE " : "", dest->name, dest->instance);
   else
-    printf("%s:\n", dest->name);
+    printf("%s%s:\n", (flags & CUPS_DEST_FLAGS_REMOVED) ? "REMOVE " : "", dest->name);
 
   for (i = 0; i < dest->num_options; i ++)
     printf("    %s=\"%s\"\n", dest->options[i].name, dest->options[i].value);
@@ -594,7 +594,8 @@ show_supported(http_t       *http,	/* I - Connection to destination */
   }
   else if (!value)
   {
-    puts(option);
+    printf("%s (%s)\n", option, cupsCheckDestSupported(http, dest, dinfo, option, NULL) ? "supported" : "not-supported");
+
     if ((attr = cupsFindDestSupported(http, dest, dinfo, option)) != NULL)
     {
       count = ippGetCount(attr);
diff --git a/cups/testfile.c b/cups/testfile.c
index dae50fa..b2ec8cd 100644
--- a/cups/testfile.c
+++ b/cups/testfile.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testhttp.c b/cups/testhttp.c
index 20c6625..376d71f 100644
--- a/cups/testhttp.c
+++ b/cups/testhttp.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testi18n.c b/cups/testi18n.c
index a88f1e1..beaf236 100644
--- a/cups/testi18n.c
+++ b/cups/testi18n.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testipp.c b/cups/testipp.c
index 150abe0..017ee9d 100644
--- a/cups/testipp.c
+++ b/cups/testipp.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testlang.c b/cups/testlang.c
index 6f0691e..6aa49ab 100644
--- a/cups/testlang.c
+++ b/cups/testlang.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testoptions.c b/cups/testoptions.c
index 44a3c71..f5ce2e2 100644
--- a/cups/testoptions.c
+++ b/cups/testoptions.c
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testppd.c b/cups/testppd.c
index 6d5065c..e1b5156 100644
--- a/cups/testppd.c
+++ b/cups/testppd.c
@@ -1,14 +1,14 @@
 /*
  * PPD test program for CUPS.
  *
- * Copyright 2007-2015 by Apple Inc.
+ * Copyright 2007-2017 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testpwg.c b/cups/testpwg.c
index 05aba45..d2332c2 100644
--- a/cups/testpwg.c
+++ b/cups/testpwg.c
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/testsnmp.c b/cups/testsnmp.c
index 3ab48af..4026a28 100644
--- a/cups/testsnmp.c
+++ b/cups/testsnmp.c
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/thread-private.h b/cups/thread-private.h
index 64897a3..ca4ef4c 100644
--- a/cups/thread-private.h
+++ b/cups/thread-private.h
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/thread.c b/cups/thread.c
index 8c022f6..77b4442 100644
--- a/cups/thread.c
+++ b/cups/thread.c
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -150,8 +150,7 @@ _cupsRWUnlock(_cups_rwlock_t *rwlock)	/* I - Reader/writer lock */
 void
 _cupsThreadCancel(_cups_thread_t thread)/* I - Thread ID */
 {
-  // Mopria-notice: pthread_cancel is not defined in the Android, commenting out.
-  // pthread_cancel(thread);
+  pthread_cancel(thread);
 }
 
 
diff --git a/cups/tls-darwin.c b/cups/tls-darwin.c
index 383a20e..78d6de2 100644
--- a/cups/tls-darwin.c
+++ b/cups/tls-darwin.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -21,7 +21,7 @@
 
 #include 
 
-extern char **environ;
+extern char **environ; /* @private@ */
 
 
 /*
@@ -41,6 +41,8 @@ static int		tls_auto_create = 0;
 static char		*tls_common_name = NULL;
 					/* Default common name */
 #ifdef HAVE_SECKEYCHAINOPEN
+static int		tls_cups_keychain = 0;
+					/* Opened the CUPS keychain? */
 static SecKeychainRef	tls_keychain = NULL;
 					/* Server cert keychain */
 #else
@@ -1322,7 +1324,6 @@ _httpTLSStart(http_t *http)		/* I - HTTP connection */
           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 :
@@ -1335,6 +1336,14 @@ _httpTLSStart(http_t *http)		/* I - HTTP connection */
           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_PSK_WITH_AES_128_CBC_SHA256 :
+          case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 :
+	      if (tls_options & _HTTP_TLS_DENY_CBC)
+	      {
+	        DEBUG_printf(("4_httpTLSStart: Excluding CBC cipher suite %d", supported[i]));
+	        break;
+	      }
+
 //          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 :
@@ -1345,15 +1354,28 @@ _httpTLSStart(http_t *http)		/* I - HTTP connection */
           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 */
+          case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA :
+          case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 :
+          case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 :
+          case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 :
+          case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 :
+          case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 :
+          case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 :
+          case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 :
+          case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 :
+              if (tls_options & _HTTP_TLS_DENY_CBC)
+	      {
+	        DEBUG_printf(("4_httpTLSStart: Excluding CBC cipher suite %d", supported[i]));
+	        break;
+	      }
+
+          /* Anything else we'll assume is "secure" */
           default :
 	      enabled[num_enabled ++] = supported[i];
 	      break;
@@ -1747,6 +1769,7 @@ http_cdsa_copy_server(
   CFMutableDictionaryRef query = NULL;	/* Query qualifiers */
   CFArrayRef		list = NULL;	/* Keychain list */
   SecKeychainRef	syschain = NULL;/* System keychain */
+  SecKeychainStatus	status = 0;	/* Keychain status */
 
 
   DEBUG_printf(("3http_cdsa_copy_server(common_name=\"%s\")", common_name));
@@ -1769,6 +1792,11 @@ http_cdsa_copy_server(
 
   _cupsMutexLock(&tls_mutex);
 
+  err = SecKeychainGetStatus(tls_keychain, &status);
+
+  if (err == noErr && !(status & kSecUnlockStateStatus) && tls_cups_keychain)
+    SecKeychainUnlock(tls_keychain, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, TRUE);
+
   CFDictionaryAddValue(query, kSecClass, kSecClassIdentity);
   CFDictionaryAddValue(query, kSecMatchPolicy, policy);
   CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue);
@@ -1901,9 +1929,15 @@ http_cdsa_open_keychain(
   */
 
   if (!path)
+  {
     path = http_cdsa_default_path(filename, filesize);
+    tls_cups_keychain = 1;
+  }
   else
+  {
     strlcpy(filename, path, filesize);
+    tls_cups_keychain = 0;
+  }
 
  /*
   * Save the interaction setting and disable while we open the keychain...
@@ -1912,7 +1946,7 @@ http_cdsa_open_keychain(
   SecKeychainGetUserInteractionAllowed(&interaction);
   SecKeychainSetUserInteractionAllowed(FALSE);
 
-  if (access(path, R_OK))
+  if (access(path, R_OK) && tls_cups_keychain)
   {
    /*
     * Create a new keychain at the given path...
@@ -1931,7 +1965,7 @@ http_cdsa_open_keychain(
     if (err == noErr)
       err = SecKeychainGetStatus(keychain, &status);
 
-    if (err == noErr && !(status & kSecUnlockStateStatus))
+    if (err == noErr && !(status & kSecUnlockStateStatus) && tls_cups_keychain)
       err = SecKeychainUnlock(keychain, _CUPS_CDSA_PASSLEN, _CUPS_CDSA_PASSWORD, TRUE);
   }
 
diff --git a/cups/tls-gnutls.c b/cups/tls-gnutls.c
index ddae3b9..48bc11a 100644
--- a/cups/tls-gnutls.c
+++ b/cups/tls-gnutls.c
@@ -1,14 +1,14 @@
 /*
  * TLS support code for CUPS using GNU TLS.
  *
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2017 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -18,17 +18,10 @@
 /*
  * Include necessary headers...
  */
-// 11/23/2016 Mopria-notice: Included necessary headers as per above comment.
-#include "cups-private.h"
-#include "http.h"
-#include "thread-private.h"
-#include 
-#include 
 
 #include 
 
 
-
 /*
  * Local globals...
  */
@@ -404,7 +397,7 @@ httpCredentialsAreValidForName(
         for (i = 0; i < count; i ++)
 	{
 	  rserial_size = sizeof(rserial);
-          if (!gnutls_x509_crl_get_crt_serial(tls_crl, i, rserial, &rserial_size, NULL) && cserial_size == rserial_size && !memcmp(cserial, rserial, rserial_size))
+          if (!gnutls_x509_crl_get_crt_serial(tls_crl, (unsigned)i, rserial, &rserial_size, NULL) && cserial_size == rserial_size && !memcmp(cserial, rserial, rserial_size))
 	  {
 	    result = 0;
 	    break;
@@ -1525,6 +1518,9 @@ _httpTLSStart(http_t *http)		/* I - Connection to server */
   if (!(tls_options & _HTTP_TLS_ALLOW_DH))
     strlcat(priority_string, ":!ANON-DH", sizeof(priority_string));
 
+  if (!(tls_options & _HTTP_TLS_DENY_CBC))
+    strlcat(priority_string, ":!CBC", sizeof(priority_string));
+
 #ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT
   gnutls_priority_set_direct(http->tls, priority_string, NULL);
 
@@ -1589,7 +1585,7 @@ _httpTLSStop(http_t *http)		/* I - Connection to server */
 
   if (http->tls_credentials)
   {
-    // gnutls_certificate_free_credentials(*(http->tls_credentials));
+    gnutls_certificate_free_credentials(*(http->tls_credentials));
     free(http->tls_credentials);
     http->tls_credentials = NULL;
   }
diff --git a/cups/tls-sspi.c b/cups/tls-sspi.c
index 2c84c71..77b883b 100644
--- a/cups/tls-sspi.c
+++ b/cups/tls-sspi.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -20,7 +20,6 @@
  */
 
 #include "debug-private.h"
-// #include "http-private.h"
 
 
 /*
@@ -1796,7 +1795,7 @@ http_sspi_find_credentials(
   }
 #endif /* SP_PROT_TLS1_2_SERVER */
 
-  /* 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... */
+  /* TODO: Support _HTTP_TLS_ALLOW_RC4, _HTTP_TLS_ALLOW_DH, and _HTTP_TLS_DENY_CBC options; right now we'll rely on Windows registry to enable/disable RC4/DH/CBC... */
 
  /*
   * Create an SSPI credential.
diff --git a/cups/tls.c b/cups/tls.c
index c1db80d..36d484c 100644
--- a/cups/tls.c
+++ b/cups/tls.c
@@ -11,7 +11,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/tlscheck.c b/cups/tlscheck.c
index 9197261..32cbcca 100644
--- a/cups/tlscheck.c
+++ b/cups/tlscheck.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/transcode.c b/cups/transcode.c
index 2aa1a8b..6f73a42 100644
--- a/cups/transcode.c
+++ b/cups/transcode.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/transcode.h b/cups/transcode.h
index 20d13db..cd12cb5 100644
--- a/cups/transcode.h
+++ b/cups/transcode.h
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/cups/usersys.c b/cups/usersys.c
index b1a2a82..ff5cb30 100644
--- a/cups/usersys.c
+++ b/cups/usersys.c
@@ -1,14 +1,14 @@
 /*
  * User, system, and password routines for CUPS.
  *
- * Copyright 2007-2015 by Apple Inc.
+ * Copyright 2007-2017 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -132,6 +132,8 @@ cupsEncryption(void)
  * thread in a program. Multi-threaded programs that override the setting via
  * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
  * do so in each thread for the same function to be used.
+ *
+ * @exclude all@
  */
 
 const char *				/* O - Password */
@@ -145,7 +147,7 @@ cupsGetPassword(const char *prompt)	/* I - Prompt string */
 
 
 /*
- * 'cupsGetPassword2()' - Get a password from the user using the advanced
+ * 'cupsGetPassword2()' - Get a password from the user using the current
  *                        password callback.
  *
  * Uses the current password callback function. Returns @code NULL@ if the
@@ -153,8 +155,8 @@ cupsGetPassword(const char *prompt)	/* I - Prompt string */
  *
  * Note: The current password callback function is tracked separately for each
  * thread in a program. Multi-threaded programs that override the setting via
- * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
- * do so in each thread for the same function to be used.
+ * the @link cupsSetPasswordCB2@ function need to do so in each thread for the
+ * same function to be used.
  *
  * @since CUPS 1.4/macOS 10.6@
  */
@@ -297,6 +299,8 @@ cupsSetEncryption(http_encryption_t e)	/* I - New encryption preference */
  * Note: The current password callback is tracked separately for each thread
  * in a program. Multi-threaded programs that override the callback need to do
  * so in each thread for the same callback to be used.
+ *
+ * @exclude all@
  */
 
 void
@@ -1363,6 +1367,8 @@ cups_set_ssl_options(
       options |= _HTTP_TLS_ALLOW_SSL3;
     else if (!_cups_strcasecmp(start, "AllowDH"))
       options |= _HTTP_TLS_ALLOW_DH;
+    else if (!_cups_strcasecmp(start, "DenyCBC"))
+      options |= _HTTP_TLS_DENY_CBC;
     else if (!_cups_strcasecmp(start, "DenyTLS1.0"))
       options |= _HTTP_TLS_DENY_TLS10;
     else if (!_cups_strcasecmp(start, "None"))
@@ -1387,8 +1393,3 @@ cups_set_user(
 {
   strlcpy(cc->user, value, sizeof(cc->user));
 }
-
-// 07/22/2016 Mopria-notice: localeconv is not defined in Android so need to define for cross compilation
-struct lconv *localeconv(void) {
-    return NULL;
-}
\ No newline at end of file
diff --git a/cups/util.c b/cups/util.c
index abfb8d4..2f5ebdf 100644
--- a/cups/util.c
+++ b/cups/util.c
@@ -1,14 +1,14 @@
 /*
  * Printing utilities for CUPS.
  *
- * Copyright 2007-2015 by Apple Inc.
+ * Copyright 2007-2017 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -27,6 +27,19 @@
 #endif /* WIN32 || __EMX__ */
 
 
+/*
+ * Enumeration data and callback...
+ */
+
+typedef struct _cups_createdata_s
+{
+  const char  *name;                    /* Destination name */
+  cups_dest_t *dest;                    /* Matching destination */
+} _cups_createdata_t;
+
+static int  cups_create_cb(_cups_createdata_t *data, unsigned flags, cups_dest_t *dest);
+
+
 /*
  * 'cupsCancelJob()' - Cancel a print job on the default server.
  *
@@ -35,6 +48,8 @@
  *
  * Use the @link cupsLastError@ and @link cupsLastErrorString@ functions to get
  * the cause of any failure.
+ *
+ * @exclude all@
  */
 
 int					/* O - 1 on success, 0 on failure */
@@ -58,7 +73,7 @@ cupsCancelJob(const char *name,		/* I - Name of printer or class */
  * Use the @link cupsLastError@ and @link cupsLastErrorString@ functions to get
  * the cause of any failure.
  *
- * @since CUPS 1.4/macOS 10.6@
+ * @since CUPS 1.4/macOS 10.6@ @exclude all@
  */
 
 ipp_status_t				/* O - IPP status */
@@ -146,7 +161,7 @@ cupsCancelJob2(http_t     *http,	/* I - Connection to server or @code CUPS_HTTP_
  * print, use the @link cupsPrintFile2@ or @link cupsPrintFiles2@ function
  * instead.
  *
- * @since CUPS 1.4/macOS 10.6@
+ * @since CUPS 1.4/macOS 10.6@ @exclude all@
  */
 
 int					/* O - Job ID or 0 on error */
@@ -157,12 +172,10 @@ cupsCreateJob(
     int           num_options,		/* I - Number of options */
     cups_option_t *options)		/* I - Options */
 {
-  char		printer_uri[1024],	/* Printer URI */
-		resource[1024];		/* Printer resource */
-  ipp_t		*request,		/* Create-Job request */
-		*response;		/* Create-Job response */
-  ipp_attribute_t *attr;		/* job-id attribute */
   int		job_id = 0;		/* job-id value */
+  ipp_status_t  status;                 /* Create-Job status */
+  _cups_createdata_t data;              /* Enumeration data */
+  cups_dinfo_t  *info;                  /* Destination information */
 
 
   DEBUG_printf(("cupsCreateJob(http=%p, name=\"%s\", title=\"%s\", num_options=%d, options=%p)", (void *)http, name, title, num_options, (void *)options));
@@ -178,46 +191,47 @@ cupsCreateJob(
   }
 
  /*
-  * Build a Create-Job request...
+  * Lookup the destination...
   */
 
-  if ((request = ippNewRequest(IPP_OP_CREATE_JOB)) == NULL)
+  data.name = name;
+  data.dest = NULL;
+
+  cupsEnumDests(0, 1000, NULL, 0, 0, (cups_dest_cb_t)cups_create_cb, &data);
+
+  if (!data.dest)
   {
-    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0);
+    DEBUG_puts("1cupsCreateJob: Destination not found.");
+    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0);
     return (0);
   }
 
-  httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), "ipp",
-                   NULL, "localhost", ippPort(), "/printers/%s", name);
-  snprintf(resource, sizeof(resource), "/printers/%s", name);
-
-  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
-               NULL, printer_uri);
-  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
-               NULL, cupsUser());
-  if (title)
-    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
-                 title);
-  cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION);
-  cupsEncodeOptions2(request, num_options, options, IPP_TAG_JOB);
-  cupsEncodeOptions2(request, num_options, options, IPP_TAG_SUBSCRIPTION);
-
  /*
-  * Send the request and get the job-id...
+  * Query dest information and create the job...
   */
 
-  response = cupsDoRequest(http, request, resource);
+  DEBUG_puts("1cupsCreateJob: Querying destination info.");
+  if ((info = cupsCopyDestInfo(http, data.dest)) == NULL)
+  {
+    DEBUG_puts("1cupsCreateJob: Query failed.");
+    cupsFreeDests(1, data.dest);
+    return (0);
+  }
 
-  if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL)
-    job_id = attr->values[0].integer;
+  status = cupsCreateDestJob(http, data.dest, info, &job_id, title, num_options, options);
+  DEBUG_printf(("1cupsCreateJob: cupsCreateDestJob returned %04x (%s)", status, ippErrorString(status)));
 
-  ippDelete(response);
+  cupsFreeDestInfo(info);
+  cupsFreeDests(1, data.dest);
 
  /*
-  * Return it...
+  * Return the job...
   */
 
-  return (job_id);
+  if (status >= IPP_STATUS_REDIRECTION_OTHER_SITE)
+    return (0);
+  else
+    return (job_id);
 }
 
 
@@ -226,7 +240,7 @@ cupsCreateJob(
  *
  * The document must have been started using @link cupsStartDocument@.
  *
- * @since CUPS 1.4/macOS 10.6@
+ * @since CUPS 1.4/macOS 10.6@ @exclude all@
  */
 
 ipp_status_t				/* O - Status of document submission */
@@ -277,7 +291,7 @@ cupsFreeJobs(int        num_jobs,	/* I - Number of jobs */
  * This function is deprecated and no longer returns a list of printer
  * classes - use @link cupsGetDests@ instead.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 int					/* O - Number of classes */
@@ -299,6 +313,8 @@ cupsGetClasses(char ***classes)		/* O - Classes */
  * Applications should use the @link cupsGetDests@ and @link cupsGetDest@
  * functions to get the user-defined default printer, as this function does
  * not support the lpoptions-defined default printer.
+ *
+ * @exclude all@
  */
 
 const char *				/* O - Default printer or @code NULL@ */
@@ -322,7 +338,7 @@ cupsGetDefault(void)
  * functions to get the user-defined default printer, as this function does
  * not support the lpoptions-defined default printer.
  *
- * @since CUPS 1.1.21/macOS 10.4@
+ * @since CUPS 1.1.21/macOS 10.4@ @exclude all@
  */
 
 const char *				/* O - Default printer or @code NULL@ */
@@ -388,6 +404,8 @@ cupsGetDefault2(http_t *http)		/* I - Connection to server or @code CUPS_HTTP_DE
  * of state, while @code CUPS_WHICHJOBS_ACTIVE@ returns jobs that are
  * pending, processing, or held and @code CUPS_WHICHJOBS_COMPLETED@ returns
  * jobs that are stopped, canceled, aborted, or completed.
+ *
+ * @exclude all@
  */
 
 int					/* O - Number of jobs */
@@ -683,7 +701,7 @@ cupsGetJobs2(http_t     *http,		/* I - Connection to server or @code CUPS_HTTP_D
  * This function is deprecated and no longer returns a list of printers - use
  * @link cupsGetDests@ instead.
  *
- * @deprecated@
+ * @deprecated@ @exclude all@
  */
 
 int					/* O - Number of printers */
@@ -698,6 +716,8 @@ cupsGetPrinters(char ***printers)	/* O - Printers */
 
 /*
  * 'cupsPrintFile()' - Print a file to a printer or class on the default server.
+ *
+ * @exclude all@
  */
 
 int					/* O - Job ID or 0 on error */
@@ -718,7 +738,7 @@ cupsPrintFile(const char    *name,	/* I - Destination name */
  * 'cupsPrintFile2()' - Print a file to a printer or class on the specified
  *                      server.
  *
- * @since CUPS 1.1.21/macOS 10.4@
+ * @since CUPS 1.1.21/macOS 10.4@ @exclude all@
  */
 
 int					/* O - Job ID or 0 on error */
@@ -740,6 +760,8 @@ cupsPrintFile2(
 /*
  * 'cupsPrintFiles()' - Print one or more files to a printer or class on the
  *                      default server.
+ *
+ * @exclude all@
  */
 
 int					/* O - Job ID or 0 on error */
@@ -766,7 +788,7 @@ cupsPrintFiles(
  * 'cupsPrintFiles2()' - Print one or more files to a printer or class on the
  *                       specified server.
  *
- * @since CUPS 1.1.21/macOS 10.4@
+ * @since CUPS 1.1.21/macOS 10.4@ @exclude all@
  */
 
 int					/* O - Job ID or 0 on error */
@@ -896,7 +918,7 @@ cupsPrintFiles2(
  * @code CUPS_FORMAT_TEXT@ are provided for the "format" argument, although
  * any supported MIME type string can be supplied.
  *
- * @since CUPS 1.4/macOS 10.6@
+ * @since CUPS 1.4/macOS 10.6@ @exclude all@
  */
 
 http_status_t				/* O - HTTP status of request */
@@ -951,3 +973,26 @@ cupsStartDocument(
 
   return (status);
 }
+
+
+/*
+ * 'cups_create_cb()' - Find the destination for printing.
+ */
+
+static int                              /* O - 0 on match */
+cups_create_cb(
+    _cups_createdata_t *data,           /* I - Data from cupsCreateJob call */
+    unsigned           flags,           /* I - Enumeration flags */
+    cups_dest_t        *dest)           /* I - Destination */
+{
+  DEBUG_printf(("2cups_create_cb(data=%p(%s), flags=%08x, dest=%p(%s))", (void *)data, data->name, flags, (void *)dest, dest->name));
+
+  (void)flags;
+
+  if (dest->instance || strcasecmp(data->name, dest->name))
+    return (1);
+
+  cupsCopyDest(dest, 0, &data->dest);
+
+  return (0);
+}
diff --git a/cups/versioning.h b/cups/versioning.h
index ed68f82..5a000c0 100644
--- a/cups/versioning.h
+++ b/cups/versioning.h
@@ -1,13 +1,13 @@
 /*
  * API versioning definitions for CUPS.
  *
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2017 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -17,11 +17,10 @@
 
 /*
  * This header defines several constants - _CUPS_DEPRECATED,
- * _CUPS_DEPRECATED_MSG, _CUPS_INTERNAL_MSG, _CUPS_API_1_1, _CUPS_API_1_1_19,
- * _CUPS_API_1_1_20, _CUPS_API_1_1_21, _CUPS_API_1_2, _CUPS_API_1_3,
- * _CUPS_API_1_4, _CUPS_API_1_5, _CUPS_API_1_6, _CUPS_API_1_7, and
- * _CUPS_API_2_0 - which add compiler-specific attributes that flag functions
- * that are deprecated, added in particular releases, or internal to CUPS.
+ * _CUPS_DEPRECATED_MSG, _CUPS_INTERNAL_MSG, _CUPS_API_major_minor, and
+ * _CUPS_API_major_minor_patch - which add compiler-specific attributes that
+ * flag functions that are deprecated, added in particular releases, or internal
+ * to CUPS.
  *
  * On macOS, the _CUPS_API_* constants are defined based on the values of
  * the MAC_OS_X_VERSION_MIN_ALLOWED and MAC_OS_X_VERSION_MAX_ALLOWED constants
@@ -57,6 +56,9 @@
 #    ifndef AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER
 #      define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER __attribute__((unavailable))
 #    endif /* !AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER */
+#    ifndef AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER
+#      define AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER __attribute__((unavailable))
+#    endif /* !AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER */
 #    define _CUPS_API_1_1_19 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
 #    define _CUPS_API_1_1_20 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
 #    define _CUPS_API_1_1_21 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
@@ -68,6 +70,7 @@
 #    define _CUPS_API_1_7 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER
 #    define _CUPS_API_2_0 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER
 #    define _CUPS_API_2_2 AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER
+#    define _CUPS_API_2_2_4 AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER
 #  else
 #    define _CUPS_API_1_1_19
 #    define _CUPS_API_1_1_20
@@ -80,6 +83,7 @@
 #    define _CUPS_API_1_7
 #    define _CUPS_API_2_0
 #    define _CUPS_API_2_2
+#    define _CUPS_API_2_2_4
 #  endif /* __APPLE__ && !_CUPS_SOURCE */
 
 /*
diff --git a/filter/Makefile b/filter/Makefile
index 152bc90..7da764d 100644
--- a/filter/Makefile
+++ b/filter/Makefile
@@ -8,7 +8,7 @@
 # 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/".
+# missing or damaged, see the license at "http://www.cups.org/".
 #
 # This file is subject to the Apple OS-Developed Software exception.
 #
diff --git a/filter/api-raster.shtml b/filter/api-raster.shtml
index 35996f6..6d458a2 100644
--- a/filter/api-raster.shtml
+++ b/filter/api-raster.shtml
@@ -34,7 +34,7 @@ function. For example, to read raster data from the standard input, open
 file descriptor 0:

-#include <cups/raster.h>>
+#include <cups/raster.h>
 
 cups_raster_t *ras = cupsRasterOpen(0, CUPS_RASTER_READ);
 
@@ -61,7 +61,7 @@ hardware resolution, and so forth used for the page.

function:

-#include <cups/raster.h>>
+#include <cups/raster.h>
 
 cups_raster_t *ras = cupsRasterOpen(0, CUPS_RASTER_READ);
 cups_page_header2_t header;
@@ -84,7 +84,7 @@ function. A for loop is normally used to read the page one line
 at a time:

-#include <cups/raster.h>>
+#include <cups/raster.h>
 
 cups_raster_t *ras = cupsRasterOpen(0, CUPS_RASTER_READ);
 cups_page_header2_t header;
diff --git a/filter/commandtops.c b/filter/commandtops.c
index 65dcd35..07979e0 100644
--- a/filter/commandtops.c
+++ b/filter/commandtops.c
@@ -7,7 +7,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  */
 
 /*
diff --git a/filter/common.c b/filter/common.c
index bed4a53..86b5f8e 100644
--- a/filter/common.c
+++ b/filter/common.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/filter/common.h b/filter/common.h
index 0dcb289..e72b27f 100644
--- a/filter/common.h
+++ b/filter/common.h
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/filter/error.c b/filter/error.c
index dfbb5c9..3c552cb 100644
--- a/filter/error.c
+++ b/filter/error.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/filter/gziptoany.c b/filter/gziptoany.c
index b3f5dff..0eae85e 100644
--- a/filter/gziptoany.c
+++ b/filter/gziptoany.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/filter/interpret.c b/filter/interpret.c
index f811d1a..031b1d5 100644
--- a/filter/interpret.c
+++ b/filter/interpret.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/filter/pstops.c b/filter/pstops.c
index e9b4438..072356e 100644
--- a/filter/pstops.c
+++ b/filter/pstops.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/filter/raster.c b/filter/raster.c
index dee8eec..bacf5ba 100644
--- a/filter/raster.c
+++ b/filter/raster.c
@@ -10,7 +10,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -36,7 +36,8 @@ struct _cups_raster_s			/**** Raster stream data ****/
   cups_raster_iocb_t	iocb;		/* IO callback */
   cups_mode_t		mode;		/* Read/write mode */
   cups_page_header2_t	header;		/* Raster header for current page */
-  unsigned		count,		/* Current row run-length count */
+  unsigned		rowheight,	/* Row height in lines */
+			count,		/* Current row run-length count */
 			remaining,	/* Remaining rows in page image */
 			bpp;		/* Bytes per pixel/color */
   unsigned char		*pixels,	/* Pixels for current row */
@@ -51,6 +52,7 @@ struct _cups_raster_s			/**** Raster stream data ****/
 #ifdef DEBUG
   size_t		iocount;	/* Number of bytes read/written */
 #endif /* DEBUG */
+  unsigned		apple_page_count;/* Apple raster page count */
 };
 
 
@@ -418,7 +420,9 @@ cupsRasterOpenIO(
         r->sync != CUPS_RASTER_SYNCv1 &&
         r->sync != CUPS_RASTER_REVSYNCv1 &&
         r->sync != CUPS_RASTER_SYNCv2 &&
-        r->sync != CUPS_RASTER_REVSYNCv2)
+        r->sync != CUPS_RASTER_REVSYNCv2 &&
+        r->sync != CUPS_RASTER_SYNCapple &&
+        r->sync != CUPS_RASTER_REVSYNCapple)
     {
       _cupsRasterAddError("Unknown raster format %08x!\n", r->sync);
       free(r);
@@ -426,14 +430,33 @@ cupsRasterOpenIO(
     }
 
     if (r->sync == CUPS_RASTER_SYNCv2 ||
-        r->sync == CUPS_RASTER_REVSYNCv2)
+        r->sync == CUPS_RASTER_REVSYNCv2 ||
+        r->sync == CUPS_RASTER_SYNCapple ||
+        r->sync == CUPS_RASTER_REVSYNCapple)
       r->compressed = 1;
 
     if (r->sync == CUPS_RASTER_REVSYNC ||
         r->sync == CUPS_RASTER_REVSYNCv1 ||
-        r->sync == CUPS_RASTER_REVSYNCv2)
+        r->sync == CUPS_RASTER_REVSYNCv2 ||
+        r->sync == CUPS_RASTER_REVSYNCapple)
       r->swapped = 1;
 
+    if (r->sync == CUPS_RASTER_SYNCapple ||
+        r->sync == CUPS_RASTER_REVSYNCapple)
+    {
+      unsigned char	header[8];	/* File header */
+
+      if (cups_raster_io(r, (unsigned char *)header, sizeof(header)) !=
+	      sizeof(header))
+      {
+	_cupsRasterAddError("Unable to read header from raster stream: %s\n",
+			    strerror(errno));
+	free(r);
+	return (NULL);
+      }
+
+    }
+
     DEBUG_printf(("1cupsRasterOpenIO: r->swapped=%d, r->sync=%08x\n", r->swapped, r->sync));
   }
   else
@@ -459,6 +482,13 @@ cupsRasterOpenIO(
           r->sync       = htonl(CUPS_RASTER_SYNC_PWG);
           r->swapped    = r->sync != CUPS_RASTER_SYNC_PWG;
 	  break;
+
+      case CUPS_RASTER_WRITE_APPLE :
+          r->compressed     = 1;
+          r->sync           = htonl(CUPS_RASTER_SYNCapple);
+          r->swapped        = r->sync != CUPS_RASTER_SYNCapple;
+          r->apple_page_count = 0xffffffffU;
+	  break;
     }
 
     if (cups_raster_io(r, (unsigned char *)&(r->sync), sizeof(r->sync)) < (ssize_t)sizeof(r->sync))
@@ -662,7 +692,31 @@ cupsRasterReadPixels(cups_raster_t *r,	/* I - Raster stream */
 	  return (0);
 	}
 
-	if (byte & 128)
+        if (byte == 128)
+        {
+         /*
+          * Clear to end of line...
+          */
+
+          switch (r->header.cupsColorSpace)
+          {
+            case CUPS_CSPACE_W :
+            case CUPS_CSPACE_RGB :
+            case CUPS_CSPACE_SW :
+            case CUPS_CSPACE_SRGB :
+            case CUPS_CSPACE_RGBW :
+            case CUPS_CSPACE_ADOBERGB :
+                memset(temp, 0xff, (size_t)bytes);
+                break;
+            default :
+                memset(temp, 0x00, (size_t)bytes);
+                break;
+          }
+
+          temp += bytes;
+          bytes = 0;
+        }
+	else if (byte & 128)
 	{
 	 /*
 	  * Copy N literal pixels...
@@ -891,6 +945,60 @@ cupsRasterWriteHeader(
 
     return (cups_raster_io(r, (unsigned char *)&fh, sizeof(fh)) == sizeof(fh));
   }
+  else if (r->mode == CUPS_RASTER_WRITE_APPLE)
+  {
+   /*
+    * Raw raster data is always network byte order with most of the page header
+    * zeroed.
+    */
+
+    unsigned char appleheader[32];	/* Raw page header */
+
+    if (r->apple_page_count == 0xffffffffU)
+    {
+     /*
+      * Write raw page count from raster page header...
+      */
+
+      r->apple_page_count = r->header.cupsInteger[0];
+
+      appleheader[0] = 'A';
+      appleheader[1] = 'S';
+      appleheader[2] = 'T';
+      appleheader[3] = 0;
+      appleheader[4] = (unsigned char)(r->apple_page_count >> 24);
+      appleheader[5] = (unsigned char)(r->apple_page_count >> 16);
+      appleheader[6] = (unsigned char)(r->apple_page_count >> 8);
+      appleheader[7] = (unsigned char)(r->apple_page_count);
+
+      if (cups_raster_io(r, appleheader, 8) != 8)
+        return (0);
+    }
+
+    memset(appleheader, 0, sizeof(appleheader));
+
+    appleheader[0]  = (unsigned char)r->header.cupsBitsPerPixel;
+    appleheader[1]  = r->header.cupsColorSpace == CUPS_CSPACE_SRGB ? 1 :
+                        r->header.cupsColorSpace == CUPS_CSPACE_RGBW ? 2 :
+                        r->header.cupsColorSpace == CUPS_CSPACE_ADOBERGB ? 3 :
+                        r->header.cupsColorSpace == CUPS_CSPACE_W ? 4 :
+                        r->header.cupsColorSpace == CUPS_CSPACE_RGB ? 5 :
+                        r->header.cupsColorSpace == CUPS_CSPACE_CMYK ? 6 : 0;
+    appleheader[12] = (unsigned char)(r->header.cupsWidth >> 24);
+    appleheader[13] = (unsigned char)(r->header.cupsWidth >> 16);
+    appleheader[14] = (unsigned char)(r->header.cupsWidth >> 8);
+    appleheader[15] = (unsigned char)(r->header.cupsWidth);
+    appleheader[16] = (unsigned char)(r->header.cupsHeight >> 24);
+    appleheader[17] = (unsigned char)(r->header.cupsHeight >> 16);
+    appleheader[18] = (unsigned char)(r->header.cupsHeight >> 8);
+    appleheader[19] = (unsigned char)(r->header.cupsHeight);
+    appleheader[20] = (unsigned char)(r->header.HWResolution[0] >> 24);
+    appleheader[21] = (unsigned char)(r->header.HWResolution[0] >> 16);
+    appleheader[22] = (unsigned char)(r->header.HWResolution[0] >> 8);
+    appleheader[23] = (unsigned char)(r->header.HWResolution[0]);
+
+    return (cups_raster_io(r, appleheader, sizeof(appleheader)) == sizeof(appleheader));
+  }
   else
     return (cups_raster_io(r, (unsigned char *)&(r->header), sizeof(r->header))
 		== sizeof(r->header));
@@ -901,7 +1009,7 @@ cupsRasterWriteHeader(
  * 'cupsRasterWriteHeader2()' - Write a raster page header from a version 2
  *                              page header structure.
  *
- * The page header can be initialized using @link cupsRasterInterpretPPD@.
+ * The page header can be initialized using @link cupsRasterInitPWGHeader@.
  *
  * @since CUPS 1.2/macOS 10.5@
  */
@@ -924,6 +1032,16 @@ cupsRasterWriteHeader2(
   if (!cups_raster_update(r))
     return (0);
 
+  if (r->mode == CUPS_RASTER_WRITE_APPLE)
+  {
+    r->rowheight = h->HWResolution[0] / h->HWResolution[1];
+
+    if (h->HWResolution[0] != (r->rowheight * h->HWResolution[1]))
+      return (0);
+  }
+  else
+    r->rowheight = 1;
+
  /*
   * Write the raster header...
   */
@@ -985,6 +1103,62 @@ cupsRasterWriteHeader2(
 
     return (cups_raster_io(r, (unsigned char *)&fh, sizeof(fh)) == sizeof(fh));
   }
+  else if (r->mode == CUPS_RASTER_WRITE_APPLE)
+  {
+   /*
+    * Raw raster data is always network byte order with most of the page header
+    * zeroed.
+    */
+
+    unsigned char appleheader[32];	/* Raw page header */
+    unsigned height = r->header.cupsHeight * r->rowheight;
+					/* Computed page height */
+
+    if (r->apple_page_count == 0xffffffffU)
+    {
+     /*
+      * Write raw page count from raster page header...
+      */
+
+      r->apple_page_count = r->header.cupsInteger[0];
+
+      appleheader[0] = 'A';
+      appleheader[1] = 'S';
+      appleheader[2] = 'T';
+      appleheader[3] = 0;
+      appleheader[4] = (unsigned char)(r->apple_page_count >> 24);
+      appleheader[5] = (unsigned char)(r->apple_page_count >> 16);
+      appleheader[6] = (unsigned char)(r->apple_page_count >> 8);
+      appleheader[7] = (unsigned char)(r->apple_page_count);
+
+      if (cups_raster_io(r, appleheader, 8) != 8)
+        return (0);
+    }
+
+    memset(appleheader, 0, sizeof(appleheader));
+
+    appleheader[0]  = (unsigned char)r->header.cupsBitsPerPixel;
+    appleheader[1]  = r->header.cupsColorSpace == CUPS_CSPACE_SRGB ? 1 :
+                        r->header.cupsColorSpace == CUPS_CSPACE_RGBW ? 2 :
+                        r->header.cupsColorSpace == CUPS_CSPACE_ADOBERGB ? 3 :
+                        r->header.cupsColorSpace == CUPS_CSPACE_W ? 4 :
+                        r->header.cupsColorSpace == CUPS_CSPACE_RGB ? 5 :
+                        r->header.cupsColorSpace == CUPS_CSPACE_CMYK ? 6 : 0;
+    appleheader[12] = (unsigned char)(r->header.cupsWidth >> 24);
+    appleheader[13] = (unsigned char)(r->header.cupsWidth >> 16);
+    appleheader[14] = (unsigned char)(r->header.cupsWidth >> 8);
+    appleheader[15] = (unsigned char)(r->header.cupsWidth);
+    appleheader[16] = (unsigned char)(height >> 24);
+    appleheader[17] = (unsigned char)(height >> 16);
+    appleheader[18] = (unsigned char)(height >> 8);
+    appleheader[19] = (unsigned char)(height);
+    appleheader[20] = (unsigned char)(r->header.HWResolution[0] >> 24);
+    appleheader[21] = (unsigned char)(r->header.HWResolution[0] >> 16);
+    appleheader[22] = (unsigned char)(r->header.HWResolution[0] >> 8);
+    appleheader[23] = (unsigned char)(r->header.HWResolution[0]);
+
+    return (cups_raster_io(r, appleheader, sizeof(appleheader)) == sizeof(appleheader));
+  }
   else
     return (cups_raster_io(r, (unsigned char *)&(r->header), sizeof(r->header))
 		== sizeof(r->header));
@@ -1116,7 +1290,7 @@ cupsRasterWritePixels(cups_raster_t *r,	/* I - Raster stream */
           * Increase the repeat count...
 	  */
 
-	  r->count ++;
+	  r->count += r->rowheight;
 	  r->pcurrent = r->pixels;
 
 	 /*
@@ -1132,7 +1306,7 @@ cupsRasterWritePixels(cups_raster_t *r,	/* I - Raster stream */
 	    else
 	      return (len);
 	  }
-	  else if (r->count == 256)
+	  else if (r->count > (256 - r->rowheight))
 	  {
 	    if (cups_raster_write(r, r->pixels) <= 0)
 	      return (0);
@@ -1161,7 +1335,7 @@ cupsRasterWritePixels(cups_raster_t *r,	/* I - Raster stream */
         * Increase the repeat count...
 	*/
 
-	r->count ++;
+	r->count += r->rowheight;
 	r->pcurrent = r->pixels;
 
        /*
@@ -1201,53 +1375,118 @@ cups_raster_read_header(
 
   DEBUG_printf(("4cups_raster_read_header: r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount));
 
- /*
-  * Get the length of the raster header...
-  */
-
-  if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1)
-    len = sizeof(cups_page_header_t);
-  else
-    len = sizeof(cups_page_header2_t);
-
-  DEBUG_printf(("4cups_raster_read_header: len=%d", (int)len));
+  memset(&(r->header), 0, sizeof(r->header));
 
  /*
   * Read the header...
   */
 
-  memset(&(r->header), 0, sizeof(r->header));
-
-  if (cups_raster_read(r, (unsigned char *)&(r->header), len) < (ssize_t)len)
+  switch (r->sync)
   {
-    DEBUG_printf(("4cups_raster_read_header: EOF, r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount));
-    return (0);
-  }
+    default :
+       /*
+	* Get the length of the raster header...
+	*/
 
- /*
-  * Swap bytes as needed...
-  */
+	if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1)
+	  len = sizeof(cups_page_header_t);
+	else
+	  len = sizeof(cups_page_header2_t);
 
-  if (r->swapped)
-  {
-    unsigned	*s,			/* Current word */
-		temp;			/* Temporary copy */
+	DEBUG_printf(("4cups_raster_read_header: len=%d", (int)len));
+
+       /*
+        * Read it...
+        */
+
+	if (cups_raster_read(r, (unsigned char *)&(r->header), len) < (ssize_t)len)
+	{
+	  DEBUG_printf(("4cups_raster_read_header: EOF, r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount));
+	  return (0);
+	}
+
+       /*
+	* Swap bytes as needed...
+	*/
+
+	if (r->swapped)
+	{
+	  unsigned	*s,		/* Current word */
+			temp;		/* Temporary copy */
 
 
-    DEBUG_puts("4cups_raster_read_header: Swapping header bytes.");
+	  DEBUG_puts("4cups_raster_read_header: Swapping header bytes.");
 
-    for (len = 81, s = &(r->header.AdvanceDistance);
-	 len > 0;
-	 len --, s ++)
-    {
-      temp = *s;
-      *s   = ((temp & 0xff) << 24) |
-             ((temp & 0xff00) << 8) |
-             ((temp & 0xff0000) >> 8) |
-             ((temp & 0xff000000) >> 24);
+	  for (len = 81, s = &(r->header.AdvanceDistance);
+	       len > 0;
+	       len --, s ++)
+	  {
+	    temp = *s;
+	    *s   = ((temp & 0xff) << 24) |
+		   ((temp & 0xff00) << 8) |
+		   ((temp & 0xff0000) >> 8) |
+		   ((temp & 0xff000000) >> 24);
 
-      DEBUG_printf(("4cups_raster_read_header: %08x => %08x", temp, *s));
-    }
+	    DEBUG_printf(("4cups_raster_read_header: %08x => %08x", temp, *s));
+	  }
+	}
+        break;
+
+    case CUPS_RASTER_SYNCapple :
+    case CUPS_RASTER_REVSYNCapple :
+        {
+          unsigned char	appleheader[32];	/* Raw header */
+          static const unsigned rawcspace[] =
+          {
+            CUPS_CSPACE_SW,
+            CUPS_CSPACE_SRGB,
+            CUPS_CSPACE_RGBW,
+            CUPS_CSPACE_ADOBERGB,
+            CUPS_CSPACE_W,
+            CUPS_CSPACE_RGB,
+            CUPS_CSPACE_CMYK
+          };
+          static const unsigned rawnumcolors[] =
+          {
+            1,
+            3,
+            4,
+            3,
+            1,
+            3,
+            4
+          };
+
+	  if (cups_raster_read(r, appleheader, sizeof(appleheader)) < (ssize_t)sizeof(appleheader))
+	  {
+	    DEBUG_printf(("4cups_raster_read_header: EOF, r->iocount=" CUPS_LLFMT, CUPS_LLCAST r->iocount));
+	    return (0);
+	  }
+
+	  strlcpy(r->header.MediaClass, "PwgRaster", sizeof(r->header.MediaClass));
+					      /* PwgRaster */
+          r->header.cupsBitsPerPixel = appleheader[0];
+          r->header.cupsColorSpace   = appleheader[1] >= (sizeof(rawcspace) / sizeof(rawcspace[0])) ? CUPS_CSPACE_DEVICE1 : rawcspace[appleheader[1]];
+          r->header.cupsNumColors    = appleheader[1] >= (sizeof(rawnumcolors) / sizeof(rawnumcolors[0])) ? 1 : rawnumcolors[appleheader[1]];
+          r->header.cupsBitsPerColor = r->header.cupsBitsPerPixel / r->header.cupsNumColors;
+          r->header.cupsWidth        = ((((((unsigned)appleheader[12] << 8) | (unsigned)appleheader[13]) << 8) | (unsigned)appleheader[14]) << 8) | (unsigned)appleheader[15];
+          r->header.cupsHeight       = ((((((unsigned)appleheader[16] << 8) | (unsigned)appleheader[17]) << 8) | (unsigned)appleheader[18]) << 8) | (unsigned)appleheader[19];
+          r->header.cupsBytesPerLine = r->header.cupsWidth * r->header.cupsBitsPerPixel / 8;
+          r->header.cupsColorOrder   = CUPS_ORDER_CHUNKED;
+          r->header.HWResolution[0]  = r->header.HWResolution[1] = ((((((unsigned)appleheader[20] << 8) | (unsigned)appleheader[21]) << 8) | (unsigned)appleheader[22]) << 8) | (unsigned)appleheader[23];
+
+          if (r->header.HWResolution[0] > 0)
+          {
+	    r->header.PageSize[0]     = (unsigned)(r->header.cupsWidth * 72 / r->header.HWResolution[0]);
+	    r->header.PageSize[1]     = (unsigned)(r->header.cupsHeight * 72 / r->header.HWResolution[1]);
+	    r->header.cupsPageSize[0] = (float)(r->header.cupsWidth * 72.0 / r->header.HWResolution[0]);
+	    r->header.cupsPageSize[1] = (float)(r->header.cupsHeight * 72.0 / r->header.HWResolution[1]);
+          }
+
+          r->header.cupsInteger[0] = r->apple_page_count;
+          r->header.cupsInteger[7] = 0xffffff;
+        }
+        break;
   }
 
  /*
diff --git a/filter/rasterbench.c b/filter/rasterbench.c
index 010fd9d..8746f31 100644
--- a/filter/rasterbench.c
+++ b/filter/rasterbench.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/filter/rastertoepson.c b/filter/rastertoepson.c
index 74dc61c..4efe669 100644
--- a/filter/rastertoepson.c
+++ b/filter/rastertoepson.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/filter/rastertohp.c b/filter/rastertohp.c
index 2994b80..eb11c8c 100644
--- a/filter/rastertohp.c
+++ b/filter/rastertohp.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
diff --git a/filter/rastertolabel.c b/filter/rastertolabel.c
index a082831..4e49181 100644
--- a/filter/rastertolabel.c
+++ b/filter/rastertolabel.c
@@ -1,14 +1,14 @@
 /*
  * Label printer filter for CUPS.
  *
- * Copyright 2007-2015 by Apple Inc.
+ * Copyright 2007-2016 by Apple Inc.
  * Copyright 2001-2007 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -438,7 +438,7 @@ StartPage(ppd_file_t         *ppd,	/* I - PPD file */
  */
 
 void
-EndPage(ppd_file_t *ppd,		/* I - PPD file */
+EndPage(ppd_file_t          *ppd,	/* I - PPD file */
         cups_page_header2_t *header)	/* I - Page header */
 {
   int		val;			/* Option value */
@@ -495,6 +495,19 @@ EndPage(ppd_file_t *ppd,		/* I - PPD file */
 
         puts("^XA");
 
+       /*
+        * Rotate 180 degrees so that the top of the label/page is at the
+	* leading edge...
+	*/
+
+	puts("^POI");
+
+       /*
+        * Set print width...
+	*/
+
+        printf("^PW%u\n", header->cupsWidth);
+
        /*
         * Set print rate...
 	*/
@@ -605,8 +618,8 @@ EndPage(ppd_file_t *ppd,		/* I - PPD file */
         * End the label and eject...
 	*/
 
-        puts("^IDR:CUPS.GRF^FS");
 	puts("^XZ");
+        puts("^IDR:CUPS.GRF^FS");
 
        /*
         * Cut the label as needed...
diff --git a/filter/rastertopwg.c b/filter/rastertopwg.c
index f478ac5..5413df0 100644
--- a/filter/rastertopwg.c
+++ b/filter/rastertopwg.c
@@ -1,13 +1,13 @@
 /*
  * CUPS raster to PWG raster format filter for CUPS.
  *
- * Copyright 2011, 2014-2016 Apple Inc.
+ * Copyright 2011, 2014-2017 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -31,6 +31,8 @@ int					/* O - Exit status */
 main(int  argc,				/* I - Number of command-line args */
      char *argv[])			/* I - Command-line arguments */
 {
+  const char		*final_content_type;
+					/* FINAL_CONTENT_TYPE env var */
   int			fd;		/* Raster file */
   cups_raster_t		*inras,		/* Input raster stream */
 			*outras;	/* Output raster stream */
@@ -48,7 +50,7 @@ main(int  argc,				/* I - Number of command-line args */
 			lineoffset;	/* Offset into line */
   unsigned char		white;		/* White pixel */
   ppd_file_t		*ppd;		/* PPD file */
-  ppd_attr_t		*back;		/* cupsBackSize attribute */
+  ppd_attr_t		*back;		/* cupsBackSide attribute */
   _ppd_cache_t		*cache;		/* PPD cache */
   pwg_size_t		*pwg_size;	/* PWG media size */
   pwg_media_t		*pwg_media;	/* PWG media name */
@@ -73,8 +75,11 @@ main(int  argc,				/* I - Number of command-line args */
   else
     fd = 0;
 
+  if ((final_content_type = getenv("FINAL_CONTENT_TYPE")) == NULL)
+    final_content_type = "image/pwg-raster";
+
   inras  = cupsRasterOpen(fd, CUPS_RASTER_READ);
-  outras = cupsRasterOpen(1, CUPS_RASTER_WRITE_PWG);
+  outras = cupsRasterOpen(1, !strcmp(final_content_type, "image/pwg-raster") ? CUPS_RASTER_WRITE_PWG : CUPS_RASTER_WRITE_APPLE);
 
   ppd   = ppdOpenFile(getenv("PPD"));
   back  = ppdFindAttr(ppd, "cupsBackSide", NULL);
@@ -430,6 +435,9 @@ main(int  argc,				/* I - Number of command-line args */
     if (linesize < inheader.cupsBytesPerLine)
       linesize = inheader.cupsBytesPerLine;
 
+    if ((lineoffset + inheader.cupsBytesPerLine) > linesize)
+      lineoffset = linesize - inheader.cupsBytesPerLine;
+
     line = malloc(linesize);
 
     memset(line, white, linesize);
diff --git a/filter/testraster.c b/filter/testraster.c
index 9c3f765..d5d63de 100644
--- a/filter/testraster.c
+++ b/filter/testraster.c
@@ -8,7 +8,7 @@
  * 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/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  *
  * This file is subject to the Apple OS-Developed Software exception.
  */
@@ -208,6 +208,7 @@ main(int  argc,				/* I - Number of command-line args */
     errors += do_raster_tests(CUPS_RASTER_WRITE);
     errors += do_raster_tests(CUPS_RASTER_WRITE_COMPRESSED);
     errors += do_raster_tests(CUPS_RASTER_WRITE_PWG);
+    errors += do_raster_tests(CUPS_RASTER_WRITE_APPLE);
   }
   else
   {
@@ -526,8 +527,9 @@ do_raster_tests(cups_mode_t mode)	/* O - Write mode */
 
   printf("cupsRasterOpen(%s): ",
          mode == CUPS_RASTER_WRITE ? "CUPS_RASTER_WRITE" :
-	     mode == CUPS_RASTER_WRITE ? "CUPS_RASTER_WRITE_COMPRESSED" :
-	                                 "CUPS_RASTER_WRITE_PWG");
+	     mode == CUPS_RASTER_WRITE_COMPRESSED ? "CUPS_RASTER_WRITE_COMPRESSED" :
+	     mode == CUPS_RASTER_WRITE_PWG ? "CUPS_RASTER_WRITE_PWG" :
+				             "CUPS_RASTER_WRITE_APPLE");
   fflush(stdout);
 
   if ((fp = fopen("test.raster", "wb")) == NULL)
@@ -551,18 +553,24 @@ do_raster_tests(cups_mode_t mode)	/* O - Write mode */
     header.cupsWidth        = 256;
     header.cupsHeight       = 256;
     header.cupsBytesPerLine = 256;
+    header.HWResolution[0]  = 64;
+    header.HWResolution[1]  = 64;
+    header.PageSize[0]      = 288;
+    header.PageSize[1]      = 288;
+    header.cupsPageSize[0]  = 288.0f;
+    header.cupsPageSize[1]  = 288.0f;
 
     if (page & 1)
     {
-      header.cupsBytesPerLine *= 2;
+      header.cupsBytesPerLine *= 4;
       header.cupsColorSpace = CUPS_CSPACE_CMYK;
       header.cupsColorOrder = CUPS_ORDER_CHUNKED;
       header.cupsNumColors  = 4;
     }
     else
     {
-      header.cupsColorSpace = CUPS_CSPACE_K;
-      header.cupsColorOrder = CUPS_ORDER_BANDED;
+      header.cupsColorSpace = CUPS_CSPACE_W;
+      header.cupsColorOrder = CUPS_ORDER_CHUNKED;
       header.cupsNumColors  = 1;
     }
 
@@ -677,8 +685,18 @@ do_raster_tests(cups_mode_t mode)	/* O - Write mode */
     expected.cupsWidth        = 256;
     expected.cupsHeight       = 256;
     expected.cupsBytesPerLine = 256;
+    expected.HWResolution[0]  = 64;
+    expected.HWResolution[1]  = 64;
+    expected.PageSize[0]      = 288;
+    expected.PageSize[1]      = 288;
 
-    if (mode == CUPS_RASTER_WRITE_PWG)
+    if (mode != CUPS_RASTER_WRITE_PWG)
+    {
+      expected.cupsPageSize[0] = 288.0f;
+      expected.cupsPageSize[1] = 288.0f;
+    }
+
+    if (mode >= CUPS_RASTER_WRITE_PWG)
     {
       strlcpy(expected.MediaClass, "PwgRaster", sizeof(expected.MediaClass));
       expected.cupsInteger[7] = 0xffffff;
@@ -686,15 +704,15 @@ do_raster_tests(cups_mode_t mode)	/* O - Write mode */
 
     if (page & 1)
     {
-      expected.cupsBytesPerLine *= 2;
+      expected.cupsBytesPerLine *= 4;
       expected.cupsColorSpace = CUPS_CSPACE_CMYK;
       expected.cupsColorOrder = CUPS_ORDER_CHUNKED;
       expected.cupsNumColors  = 4;
     }
     else
     {
-      expected.cupsColorSpace = CUPS_CSPACE_K;
-      expected.cupsColorOrder = CUPS_ORDER_BANDED;
+      expected.cupsColorSpace = CUPS_CSPACE_W;
+      expected.cupsColorOrder = CUPS_ORDER_CHUNKED;
       expected.cupsNumColors  = 1;
     }