diff options
Diffstat (limited to 'cups')
86 files changed, 5550 insertions, 3688 deletions
diff --git a/cups/Makefile b/cups/Makefile index 1df7d855..f83c937c 100644 --- a/cups/Makefile +++ b/cups/Makefile @@ -1,8 +1,8 @@ # -# API library Makefile for CUPS. +# Library Makefile for CUPS. # -# Copyright 2007-2016 by Apple Inc. -# Copyright 1997-2006 by Easy Software Products, all rights reserved. +# Copyright © 2007-2018 by Apple Inc. +# Copyright © 1997-2006 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 @@ -89,6 +89,7 @@ TESTOBJS = \ testcups.o \ testdest.o \ testfile.o \ + testgetdests.o \ testhttp.o \ testi18n.o \ testipp.o \ @@ -158,6 +159,7 @@ UNITTARGETS = \ testcups \ testdest \ testfile \ + testgetdests \ testhttp \ testi18n \ testipp \ @@ -310,8 +312,9 @@ uninstall: libcups.so.2: $(LIBOBJS) echo Linking $@... - $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS) $(LIBGSSAPI) \ + $(DSO) $(ARCHFLAGS) $(LDFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS) $(LIBGSSAPI) \ $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ $(RM) `basename $@ .2` $(LN) $@ `basename $@ .2` @@ -327,13 +330,14 @@ libcups.2.dylib: $(LIBOBJS) $(LIBCUPSORDER) grep -v -E -e '^(_cupsConnect|_cupsCharset|_cupsEncodingName|_cupsSetDefaults|_cupsSetHTTPError|_cupsUserDefault)$$' | \ sort >t.exp echo Linking $@... - $(DSO) $(ARCHFLAGS) $(DSOFLAGS) -o $@ \ + $(DSO) $(ARCHFLAGS) $(LDFLAGS) $(DSOFLAGS) -o $@ \ -install_name $(libdir)/$@ \ - -current_version 2.12.0 \ + -current_version 2.13.0 \ -compatibility_version 2.0.0 \ -exported_symbols_list t.exp \ $(LIBOBJS) $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) \ $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ $(RM) libcups.dylib t.exp $(LN) $@ libcups.dylib @@ -344,8 +348,8 @@ libcups.2.dylib: $(LIBOBJS) $(LIBCUPSORDER) libcups.la: $(LIBOBJS) echo Linking $@... - $(CC) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS:.o=.lo) \ - -rpath $(LIBDIR) -version-info 2:12 $(LIBGSSAPI) $(SSLLIBS) \ + $(LD_CC) $(ARCHFLAGS) $(LDFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS:.o=.lo) \ + -rpath $(LIBDIR) -version-info 2:13 $(LIBGSSAPI) $(SSLLIBS) \ $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) @@ -367,12 +371,12 @@ libcups.a: $(LIBOBJS) libcups2.def: $(LIBOBJS) Makefile echo Generating $@... echo "LIBRARY libcups2" >libcups2.def - echo "VERSION 2.12" >>libcups2.def + echo "VERSION 2.13" >>libcups2.def echo "EXPORTS" >>libcups2.def (nm $(LIBOBJS) 2>/dev/null | grep "T _" | awk '{print $$3}'; \ echo __cups_strcpy; echo __cups_strlcat; echo __cups_strlcpy) | \ grep -v -E \ - -e 'cups_debug|Apple|BackChannel|Backend|FileCheck|Filter|GSSService|SetNegotiate|SideChannel' \ + -e 'cups_debug|Apple|BackChannel|Backend|FileCheck|Filter|GSSService|SetNegotiate|SideChannel|SNMP' \ -e 'Block$$' | \ sed -e '1,$$s/^_//' | sort >>libcups2.def @@ -383,8 +387,9 @@ libcups2.def: $(LIBOBJS) Makefile testadmin: testadmin.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ testadmin.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(LDFLAGS) -o $@ testadmin.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ # @@ -393,8 +398,9 @@ testadmin: testadmin.o $(LIBCUPSSTATIC) testarray: testarray.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testarray.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testarray.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ echo Running array API tests... ./testarray @@ -405,8 +411,9 @@ testarray: testarray.o $(LIBCUPSSTATIC) testcache: testcache.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ testcache.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(LDFLAGS) -o $@ testcache.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ # @@ -415,8 +422,9 @@ testcache: testcache.o $(LIBCUPSSTATIC) testconflicts: testconflicts.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ testconflicts.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(LDFLAGS) -o $@ testconflicts.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ # @@ -425,8 +433,9 @@ testconflicts: testconflicts.o $(LIBCUPSSTATIC) testcreds: testcreds.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testcreds.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testcreds.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ # @@ -435,8 +444,9 @@ testcreds: testcreds.o $(LIBCUPSSTATIC) testcups: testcups.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ testcups.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(LDFLAGS) -o $@ testcups.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ # @@ -445,8 +455,9 @@ testcups: testcups.o $(LIBCUPSSTATIC) testdest: testdest.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ testdest.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(LDFLAGS) -o $@ testdest.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ # @@ -455,20 +466,33 @@ testdest: testdest.o $(LIBCUPSSTATIC) testfile: testfile.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testfile.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testfile.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ echo Running file API tests... ./testfile # +# testgetdests (dependency on static CUPS library is intentional) +# + +testgetdests: testgetdests.o $(LIBCUPSSTATIC) + echo Linking $@... + $(LD_CC) $(LDFLAGS) -o $@ testgetdests.o $(LIBCUPSSTATIC) \ + $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ + + +# # testhttp (dependency on static CUPS library is intentional) # testhttp: testhttp.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testhttp.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testhttp.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ echo Running HTTP API tests... ./testhttp @@ -479,8 +503,9 @@ testhttp: testhttp.o $(LIBCUPSSTATIC) testipp: testipp.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testipp.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testipp.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ echo Running IPP API tests... ./testipp @@ -491,8 +516,9 @@ testipp: testipp.o $(LIBCUPSSTATIC) testi18n: testi18n.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testi18n.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testi18n.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ echo Running internationalization API tests... ./testi18n @@ -503,10 +529,23 @@ testi18n: testi18n.o $(LIBCUPSSTATIC) testlang: testlang.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testlang.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testlang.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ + echo Creating locale directory structure... + $(RM) -r locale + $(MKDIR) locale/en + echo 'msgid "No"' > locale/en/cups_en.po + echo 'msgstr "No"' >> locale/en/cups_en.po + echo 'msgid "Yes"' >> locale/en/cups_en.po + echo 'msgstr "Yes"' >> locale/en/cups_en.po + for po in ../locale/cups_*.po; do \ + lang=`basename $$po .po | sed -e '1,$$s/^cups_//'`; \ + $(MKDIR) locale/$$lang; \ + $(LN) ../../$$po locale/$$lang; \ + done echo Running language API tests... - ./testlang + LOCALEDIR=locale ./testlang # @@ -515,8 +554,9 @@ testlang: testlang.o $(LIBCUPSSTATIC) testoptions: testoptions.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testoptions.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testoptions.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ echo Running option API tests... ./testoptions @@ -527,8 +567,9 @@ testoptions: testoptions.o $(LIBCUPSSTATIC) testppd: testppd.o $(LIBCUPSSTATIC) test.ppd test2.ppd echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testppd.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testppd.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ echo Running PPD API tests... ./testppd @@ -539,8 +580,9 @@ testppd: testppd.o $(LIBCUPSSTATIC) test.ppd test2.ppd testpwg: testpwg.o $(LIBCUPSSTATIC) test.ppd echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testpwg.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testpwg.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ echo Running PWG API tests... ./testpwg test.ppd @@ -551,8 +593,9 @@ testpwg: testpwg.o $(LIBCUPSSTATIC) test.ppd testsnmp: testsnmp.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ testsnmp.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(LDFLAGS) -o $@ testsnmp.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ # @@ -561,8 +604,9 @@ testsnmp: testsnmp.o $(LIBCUPSSTATIC) tlscheck: tlscheck.o $(LIBCUPSSTATIC) echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ tlscheck.o $(LIBCUPSSTATIC) \ + $(LD_CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ tlscheck.o $(LIBCUPSSTATIC) \ $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + $(CODE_SIGN) -s "$(CODE_SIGN_IDENTITY)" $@ # @@ -571,56 +615,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 +643,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 +651,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 adb1f7ae..375b9054 100644 --- a/cups/adminutil.c +++ b/cups/adminutil.c @@ -22,11 +22,11 @@ #include "adminutil.h" #include <fcntl.h> #include <sys/stat.h> -#ifdef WIN32 +#ifdef _WIN32 #else # include <unistd.h> # include <sys/wait.h> -#endif /* WIN32 */ +#endif /* _WIN32 */ /* @@ -2087,7 +2087,7 @@ do_samba_command(const char *command, /* I - Command to run */ const char *authfile, /* I - Samba authentication file */ FILE *logfile) /* I - Optional log file */ { -#ifdef WIN32 +#ifdef _WIN32 return (1); /* Always fail on Windows... */ #else @@ -2154,7 +2154,7 @@ do_samba_command(const char *command, /* I - Command to run */ return (WEXITSTATUS(status)); else return (-WTERMSIG(status)); -#endif /* WIN32 */ +#endif /* _WIN32 */ } @@ -2172,9 +2172,9 @@ get_cupsd_conf( int *remote) /* O - Remote file? */ { int fd; /* Temporary file descriptor */ -#ifndef WIN32 +#ifndef _WIN32 struct stat info; /* cupsd.conf file information */ -#endif /* WIN32 */ +#endif /* _WIN32 */ http_status_t status; /* Status of getting cupsd.conf */ char host[HTTP_MAX_HOST]; /* Hostname for connection */ @@ -2191,7 +2191,7 @@ get_cupsd_conf( snprintf(name, namesize, "%s/cupsd.conf", cg->cups_serverroot); *remote = 0; -#ifndef WIN32 +#ifndef _WIN32 if (!_cups_strcasecmp(host, "localhost") && !access(name, R_OK)) { /* @@ -2218,7 +2218,7 @@ get_cupsd_conf( status = HTTP_STATUS_OK; } else -#endif /* !WIN32 */ +#endif /* !_WIN32 */ { /* * Read cupsd.conf via a HTTP GET request... diff --git a/cups/api-array.header b/cups/api-array.header deleted file mode 100644 index 557833e5..00000000 --- a/cups/api-array.header +++ /dev/null @@ -1,32 +0,0 @@ -<!-- - Array API header for CUPS. - - Copyright 2008-2011 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/". ---> - -<h1 class='title'>Array API</h1> - -<div class='summary'><table summary='General Information'> -<thead> -<tr> - <th>Header</th> - <th>cups/array.h</th> -</tr> -</thead> -<tbody> -<tr> - <th>Library</th> - <td>-lcups</td> -</tr> -<tr> - <th>See Also</th> - <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a></td> -</tr> -</tbody> -</table></div> diff --git a/cups/api-array.shtml b/cups/api-array.shtml deleted file mode 100644 index 374ef5bf..00000000 --- a/cups/api-array.shtml +++ /dev/null @@ -1,194 +0,0 @@ -<!-- - Array API introduction for CUPS. - - Copyright 2007-2011 by Apple Inc. - Copyright 1997-2006 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/". ---> - -<h2 class='title'><a name='OVERVIEW'>Overview</a></h2> - -<p>The CUPS array API provides a high-performance generic array container. -The contents of the array container can be sorted and the container itself is -designed for optimal speed and memory usage under a wide variety of conditions. -Sorted arrays use a binary search algorithm from the last found or inserted -element to quickly find matching elements in the array. Arrays created with the -optional hash function can often find elements with a single lookup. The -<a href='#cups_array_t'><code>cups_array_t</code></a> type is used when -referring to a CUPS array.</p> - -<p>The CUPS scheduler (<tt>cupsd</tt>) and many of the CUPS API -functions use the array API to efficiently manage large lists of -data.</p> - -<h3><a name='MANAGING_ARRAYS'>Managing Arrays</a></h3> - -<p>Arrays are created using either the -<a href='#cupsArrayNew'><code>cupsArrayNew</code></a>, -<a href='#cupsArrayNew2'><code>cupsArrayNew2</code></a>, or -<a href='#cupsArrayNew2'><code>cupsArrayNew3</code></a> functions. The -first function creates a new array with the specified callback function -and user data pointer:</p> - -<pre class='example'> -#include <cups/array.h> - -static int compare_func(void *first, void *second, void *user_data); - -void *user_data; -<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>(compare_func, user_data); -</pre> - -<p>The comparison function (type -<a href="#cups_arrayfunc_t"><code>cups_arrayfunc_t</code></a>) is called -whenever an element is added to the array and can be <code>NULL</code> to -create an unsorted array. The function returns -1 if the first element should -come before the second, 0 if the first and second elements should have the same -ordering, and 1 if the first element should come after the second.</p> - -<p>The "user_data" pointer is passed to your comparison function. Pass -<code>NULL</code> if you do not need to associate the elements in your array -with additional information.</p> - -<p>The <a href='#cupsArrayNew2'><code>cupsArrayNew2</code></a> function adds -two more arguments to support hashed lookups, which can potentially provide -instantaneous ("O(1)") lookups in your array:</p> - -<pre class='example'> -#include <cups/array.h> - -#define HASH_SIZE 512 /* Size of hash table */ - -static int compare_func(void *first, void *second, void *user_data); -static int hash_func(void *element, void *user_data); - -void *user_data; -<a href='#cups_array_t'>cups_array_t</a> *hash_array = <a href='#cupsArrayNew2'>cupsArrayNew2</a>(compare_func, user_data, hash_func, HASH_SIZE); -</pre> - -<p>The hash function (type -<a href="#cups_ahash_func_t"><code>cups_ahash_func_t</code></a>) should return a -number from 0 to (hash_size-1) that (hopefully) uniquely identifies the -element and is called whenever you look up an element in the array with -<a href='#cupsArrayFind'><code>cupsArrayFind</code></a>. The hash size is -only limited by available memory, but generally should not be larger than -16384 to realize any performance improvement.</p> - -<p>The <a href='#cupsArrayNew3'><code>cupsArrayNew3</code></a> function adds -copy and free callbacks to support basic memory management of elements:</p> - -<pre class='example'> -#include <cups/array.h> - -#define HASH_SIZE 512 /* Size of hash table */ - -static int compare_func(void *first, void *second, void *user_data); -static void *copy_func(void *element, void *user_data); -static void free_func(void *element, void *user_data); -static int hash_func(void *element, void *user_data); - -void *user_data; -<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew3'>cupsArrayNew3</a>(compare_func, user_data, NULL, 0, copy_func, free_func); - -<a href='#cups_array_t'>cups_array_t</a> *hash_array = <a href='#cupsArrayNew3'>cupsArrayNew3</a>(compare_func, user_data, hash_func, HASH_SIZE, copy_func, free_func); -</pre> - -<p>Once you have created the array, you add elements using the -<a href='#cupsArrayAdd'><code>cupsArrayAdd</code></a> -<a href='#cupsArrayInsert'><code>cupsArrayInsert</code></a> functions. -The first function adds an element to the array, adding the new element -after any elements that have the same order, while the second inserts the -element before others with the same order. For unsorted arrays, -<a href='#cupsArrayAdd'><code>cupsArrayAdd</code></a> appends the element to -the end of the array while -<a href='#cupsArrayInsert'><code>cupsArrayInsert</code></a> inserts the -element at the beginning of the array. For example, the following code -creates a sorted array of character strings:</p> - -<pre class='example'> -#include <cups/array.h> - -/* Use strcmp() to compare strings - it will ignore the user_data pointer */ -<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>((<a href='#cups_array_func_t'>cups_array_func_t</a>)strcmp, NULL); - -/* Add four strings to the array */ -<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "One Fish"); -<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Two Fish"); -<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Red Fish"); -<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Blue Fish"); -</pre> - -<p>Elements are removed using the -<a href='#cupsArrayRemove'><code>cupsArrayRemove</code></a> function, for -example:</p> - -<pre class='example'> -#include <cups/array.h> - -/* Use strcmp() to compare strings - it will ignore the user_data pointer */ -<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>((<a href='#cups_array_func_t'>cups_array_func_t</a>)strcmp, NULL); - -/* Add four strings to the array */ -<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "One Fish"); -<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Two Fish"); -<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Red Fish"); -<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Blue Fish"); - -/* Remove "Red Fish" */ -<a href='#cupsArrayRemove'>cupsArrayRemove</a>(array, "Red Fish"); -</pre> - -<p>Finally, you free the memory used by the array using the -<a href='#cupsArrayDelete'><code>cupsArrayDelete</code></a> function. All -of the memory for the array and hash table (if any) is freed, however <em>CUPS -does not free the elements unless you provide copy and free functions</em>.</p> - -<h3><a name='FINDING_AND_ENUMERATING'>Finding and Enumerating Elements</a></h3> - -<p>CUPS provides several functions to find and enumerate elements in an -array. Each one sets or updates a "current index" into the array, such that -future lookups will start where the last one left off:</p> - -<dl> - <dt><a href='#cupsArrayFind'><code>cupsArrayFind</code></a></dt> - <dd>Returns the first matching element.</dd> - <dt><a href='#cupsArrayFirst'><code>cupsArrayFirst</code></a></dt> - <dd>Returns the first element in the array.</dd> - <dt><a href='#cupsArrayIndex'><code>cupsArrayIndex</code></a></dt> - <dd>Returns the Nth element in the array, starting at 0.</dd> - <dt><a href='#cupsArrayLast'><code>cupsArrayLast</code></a></dt> - <dd>Returns the last element in the array.</dd> - <dt><a href='#cupsArrayNext'><code>cupsArrayNext</code></a></dt> - <dd>Returns the next element in the array.</dd> - <dt><a href='#cupsArrayPrev'><code>cupsArrayPrev</code></a></dt> - <dd>Returns the previous element in the array.</dd> -</dl> - -<p>Each of these functions returns <code>NULL</code> when there is no -corresponding element. For example, a simple <code>for</code> loop using the -<a href='#cupsArrayFirst'><code>cupsArrayFirst</code></a> and -<a href='#cupsArrayNext'><code>cupsArrayNext</code></a> functions will -enumerate all of the strings in our previous example:</p> - -<pre class='example'> -#include <cups/array.h> - -/* Use strcmp() to compare strings - it will ignore the user_data pointer */ -<a href='#cups_array_t'>cups_array_t</a> *array = <a href='#cupsArrayNew'>cupsArrayNew</a>((<a href='#cups_array_func_t'>cups_array_func_t</a>)strcmp, NULL); - -/* Add four strings to the array */ -<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "One Fish"); -<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Two Fish"); -<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Red Fish"); -<a href='#cupsArrayAdd'>cupsArrayAdd</a>(array, "Blue Fish"); - -/* Show all of the strings in the array */ -char *s; -for (s = (char *)<a href='#cupsArrayFirst'>cupsArrayFirst</a>(array); s != NULL; s = (char *)<a href='#cupsArrayNext'>cupsArrayNext</a>(array)) - puts(s); -</pre> diff --git a/cups/api-cups.header b/cups/api-cups.header deleted file mode 100644 index 23b3794d..00000000 --- a/cups/api-cups.header +++ /dev/null @@ -1,38 +0,0 @@ -<!-- - CUPS API header for CUPS. - - Copyright 2008-2011 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/". ---> - -<h1 class='title'>CUPS API</h1> - -<div class='summary'><table summary='General Information'> -<thead> -<tr> - <th>Header</th> - <th>cups/cups.h</th> -</tr> -</thead> -<tbody> -<tr> - <th>Library</th> - <td>-lcups</td> -</tr> -<tr> - <th>See Also</th> - <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a><br> - Programming: <a href='api-array.html' target='_top'>Array API</a><br> - Programming: <a href='api-filedir.html' target='_top'>File and Directory APIs</a><br> - Programming: <a href='api-filter.html' target='_top'>Filter and Backend Programming</a><br> - Programming: <a href='api-httpipp.html' target='_top'>HTTP and IPP APIs</a><br> - Programming: <a href='api-ppd.html' target='_top'>PPD API</a><br> - Programming: <a href='api-raster.html' target='_top'>Raster API</a></td> -</tr> -</tbody> -</table></div> diff --git a/cups/api-cups.shtml b/cups/api-cups.shtml deleted file mode 100644 index 918efe77..00000000 --- a/cups/api-cups.shtml +++ /dev/null @@ -1,441 +0,0 @@ -<!-- - API introduction for CUPS. - - Copyright 2007-2013 by Apple Inc. - Copyright 1997-2006 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/". ---> - -<h2 class='title'><a name='OVERVIEW'>Overview</a></h2> - -<p>The CUPS API provides the convenience functions needed to support -applications, filters, printer drivers, and backends that need to interface -with the CUPS scheduler.</p> - -<h3><a name='CLIENTS_AND_SERVERS'>Clients and Servers</a></h3> - -<p>CUPS is based on the Internet Printing Protocol ("IPP"), which allows -clients (applications) to communicate with a server (the scheduler) to get a -list of printers, send print jobs, and so forth. You identify which server -you want to communicate with using a pointer to the opaque structure -<code>http_t</code>. All of the examples in this document use the -<code>CUPS_HTTP_DEFAULT</code> constant, referring to the default connection -to the scheduler. The <a href='api-httpipp.html' target='_top'>HTTP and IPP -APIs</a> document provides more information on server connections.</p> - -<h3><a name='PRINTERS_AND_CLASSES'>Printers and Classes</a></h3> - -<p>Printers and classes (collections of printers) are accessed through -the <a href="#cups_dest_t"><code>cups_dest_t</code></a> structure which -includes the name (<code>name</code>), instance (<code>instance</code> - -a way of selecting certain saved options/settings), and the options and -attributes associated with that destination (<code>num_options</code> and -<code>options</code>). Destinations are created using the -<a href="#cupsGetDests"><code>cupsGetDests</code></a> function and freed -using the <a href='#cupsFreeDests'><code>cupsFreeDests</code></a> function. -The <a href='#cupsGetDest'><code>cupsGetDest</code></a> function finds a -specific destination for printing:</p> - -<pre class='example'> -#include <cups/cups.h> - -<a href='#cups_dest_t'>cups_dest_t</a> *dests; -int num_dests = <a href='#cupsGetDests'>cupsGetDests</a>(&dests); -<a href='#cups_dest_t'>cups_dest_t</a> *dest = <a href='#cupsGetDest'>cupsGetDest</a>("name", NULL, num_dests, dests); - -/* do something with dest */ - -<a href='#cupsFreeDests'>cupsFreeDests</a>(num_dests, dests); -</pre> - -<p>Passing <code>NULL</code> to -<a href='#cupsGetDest'><code>cupsGetDest</code></a> for the destination name -will return the default destination. Similarly, passing a <code>NULL</code> -instance will return the default instance for that destination.</p> - -<div class='table'><table summary='Table 1: Printer Attributes' width='80%'> -<caption>Table 1: <a name='TABLE1'>Printer Attributes</a></caption> -<thead> -<tr> - <th>Attribute Name</th> - <th>Description</th> -</tr> -</thead> -<tbody> -<tr> - <td>"auth-info-required"</td> - <td>The type of authentication required for printing to this - destination: "none", "username,password", "domain,username,password", - or "negotiate" (Kerberos)</td> -</tr> -<tr> - <td>"printer-info"</td> - <td>The human-readable description of the destination such as "My - Laser Printer".</td> -</tr> -<tr> - <td>"printer-is-accepting-jobs"</td> - <td>"true" if the destination is accepting new jobs, "false" if - not.</td> -</tr> -<tr> - <td>"printer-is-shared"</td> - <td>"true" if the destination is being shared with other computers, - "false" if not.</td> -</tr> -<tr> - <td>"printer-location"</td> - <td>The human-readable location of the destination such as "Lab 4".</td> -</tr> -<tr> - <td>"printer-make-and-model"</td> - <td>The human-readable make and model of the destination such as "HP - LaserJet 4000 Series".</td> -</tr> -<tr> - <td>"printer-state"</td> - <td>"3" if the destination is idle, "4" if the destination is printing - a job, and "5" if the destination is stopped.</td> -</tr> -<tr> - <td>"printer-state-change-time"</td> - <td>The UNIX time when the destination entered the current state.</td> -</tr> -<tr> - <td>"printer-state-reasons"</td> - <td>Additional comma-delimited state keywords for the destination - such as "media-tray-empty-error" and "toner-low-warning".</td> -</tr> -<tr> - <td>"printer-type"</td> - <td>The <a href='#cups_printer_t'><code>cups_printer_t</code></a> - value associated with the destination.</td> -</tr> -</tbody> -</table></div> - -<h3><a name='OPTIONS'>Options</a></h3> - -<p>Options are stored in arrays of -<a href='#cups_option_t'><code>cups_option_t</code></a> structures. Each -option has a name (<code>name</code>) and value (<code>value</code>) -associated with it. The <a href='#cups_dest_t'><code>cups_dest_t</code></a> -<code>num_options</code> and <code>options</code> members contain the -default options for a particular destination, along with several informational -attributes about the destination as shown in <a href='#TABLE1'>Table 1</a>. -The <a href='#cupsGetOption'><code>cupsGetOption</code></a> function gets -the value for the named option. For example, the following code lists the -available destinations and their human-readable descriptions:</p> - -<pre class='example'> -#include <cups/cups.h> - -<a href='#cups_dest_t'>cups_dest_t</a> *dests; -int num_dests = <a href='#cupsGetDests'>cupsGetDests</a>(&dests); -<a href='#cups_dest_t'>cups_dest_t</a> *dest; -int i; -const char *value; - -for (i = num_dests, dest = dests; i > 0; i --, dest ++) - if (dest->instance == NULL) - { - value = <a href='#cupsGetOption'>cupsGetOption</a>("printer-info", dest->num_options, dest->options); - printf("%s (%s)\n", dest->name, value ? value : "no description"); - } - -<a href='#cupsFreeDests'>cupsFreeDests</a>(num_dests, dests); -</pre> - -<p>You can create your own option arrays using the -<a href='#cupsAddOption'><code>cupsAddOption</code></a> function, which -adds a single named option to an array:</p> - -<pre class='example'> -#include <cups/cups.h> - -int num_options = 0; -<a href='#cups_option_t'>cups_option_t</a> *options = NULL; - -/* The returned num_options value is updated as needed */ -num_options = <a href='#cupsAddOption'>cupsAddOption</a>("first", "value", num_options, &options); - -/* This adds a second option value */ -num_options = <a href='#cupsAddOption'>cupsAddOption</a>("second", "value", num_options, &options); - -/* This replaces the first option we added */ -num_options = <a href='#cupsAddOption'>cupsAddOption</a>("first", "new value", num_options, &options); -</pre> - -<p>Use a <code>for</code> loop to copy the options from a destination:</p> - -<pre class='example'> -#include <cups/cups.h> - -int i; -int num_options = 0; -<a href='#cups_option_t'>cups_option_t</a> *options = NULL; -<a href='#cups_dest_t'>cups_dest_t</a> *dest; - -for (i = 0; i < dest->num_options; i ++) - num_options = <a href='#cupsAddOption'>cupsAddOption</a>(dest->options[i].name, dest->options[i].value, - num_options, &options); -</pre> - -<p>Use the <a href='#cupsFreeOptions'><code>cupsFreeOptions</code></a> -function to free the options array when you are done using it:</p> - -<pre class='example'> -<a href='#cupsFreeOptions'>cupsFreeOptions</a>(num_options, options); -</pre> - -<h3><a name='PRINT_JOBS'>Print Jobs</a></h3> - -<p>Print jobs are identified by a locally-unique job ID number from 1 to -2<sup>31</sup>-1 and have options and one or more files for printing to a -single destination. The <a href='#cupsPrintFile'><code>cupsPrintFile</code></a> -function creates a new job with one file. The following code prints the CUPS -test page file:</p> - -<pre class='example'> -#include <cups/cups.h> - -<a href='#cups_dest_t'>cups_dest_t</a> *dest; -int num_options; -<a href='#cups_option_t'>cups_option_t</a> *options; -int job_id; - -/* Print a single file */ -job_id = <a href='#cupsPrintFile'>cupsPrintFile</a>(dest->name, "/usr/share/cups/data/testprint.ps", - "Test Print", num_options, options); -</pre> - -<p>The <a href='#cupsPrintFiles'><code>cupsPrintFiles</code></a> function -creates a job with multiple files. The files are provided in a -<code>char *</code> array:</p> - -<pre class='example'> -#include <cups/cups.h> - -<a href='#cups_dest_t'>cups_dest_t</a> *dest; -int num_options; -<a href='#cups_option_t'>cups_option_t</a> *options; -int job_id; -char *files[3] = { "file1.pdf", "file2.pdf", "file3.pdf" }; - -/* Print three files */ -job_id = <a href='#cupsPrintFiles'>cupsPrintFiles</a>(dest->name, 3, files, "Test Print", num_options, options); -</pre> - -<p>Finally, the <a href='#cupsCreateJob'><code>cupsCreateJob</code></a> -function creates a new job with no files in it. Files are added using the -<a href='#cupsStartDocument'><code>cupsStartDocument</code></a>, -<a href='api-httpipp.html#cupsWriteRequestData'><code>cupsWriteRequestData</code></a>, -and <a href='#cupsFinishDocument'><code>cupsFinishDocument</code></a> functions. -The following example creates a job with 10 text files for printing:</p> - -<pre class='example'> -#include <cups/cups.h> - -<a href='#cups_dest_t'>cups_dest_t</a> *dest; -int num_options; -<a href='#cups_option_t'>cups_option_t</a> *options; -int job_id; -int i; -char buffer[1024]; - -/* Create the job */ -job_id = <a href='#cupsCreateJob'>cupsCreateJob</a>(CUPS_HTTP_DEFAULT, dest->name, "10 Text Files", - num_options, options); - -/* If the job is created, add 10 files */ -if (job_id > 0) -{ - for (i = 1; i <= 10; i ++) - { - snprintf(buffer, sizeof(buffer), "file%d.txt", i); - - <a href='#cupsStartDocument'>cupsStartDocument</a>(CUPS_HTTP_DEFAULT, dest->name, job_id, buffer, - CUPS_FORMAT_TEXT, i == 10); - - snprintf(buffer, sizeof(buffer), - "File %d\n" - "\n" - "One fish,\n" - "Two fish,\n - "Red fish,\n - "Blue fish\n", i); - - /* cupsWriteRequestData can be called as many times as needed */ - <a href='#cupsWriteRequestData'>cupsWriteRequestData</a>(CUPS_HTTP_DEFAULT, buffer, strlen(buffer)); - - <a href='#cupsFinishDocument'>cupsFinishDocument</a>(CUPS_HTTP_DEFAULT, dest->name); - } -} -</pre> - -<p>Once you have created a job, you can monitor its status using the -<a href='#cupsGetJobs'><code>cupsGetJobs</code></a> function, which returns -an array of <a href='#cups_job_t'><code>cups_job_t</code></a> structures. -Each contains the job ID (<code>id</code>), destination name -(<code>dest</code>), title (<code>title</code>), and other information -associated with the job. The job array is freed using the -<a href='#cupsFreeJobs'><code>cupsFreeJobs</code></a> function. The following -example monitors a specific job ID, showing the current job state once every -5 seconds until the job is completed:</p> - -<pre class='example'> -#include <cups/cups.h> - -<a href='#cups_dest_t'>cups_dest_t</a> *dest; -int job_id; -int num_jobs; -<a href='#cups_job_t'>cups_job_t</a> *jobs; -int i; -ipp_jstate_t job_state = IPP_JOB_PENDING; - -while (job_state < IPP_JOB_STOPPED) -{ - /* Get my jobs (1) with any state (-1) */ - num_jobs = <a href='#cupsGetJobs'>cupsGetJobs</a>(&jobs, dest->name, 1, -1); - - /* Loop to find my job */ - job_state = IPP_JOB_COMPLETED; - - for (i = 0; i < num_jobs; i ++) - if (jobs[i].id == job_id) - { - job_state = jobs[i].state; - break; - } - - /* Free the job array */ - <a href='#cupsFreeJobs'>cupsFreeJobs</a>(num_jobs, jobs); - - /* Show the current state */ - switch (job_state) - { - case IPP_JOB_PENDING : - printf("Job %d is pending.\n", job_id); - break; - case IPP_JOB_HELD : - printf("Job %d is held.\n", job_id); - break; - case IPP_JOB_PROCESSING : - printf("Job %d is processing.\n", job_id); - break; - case IPP_JOB_STOPPED : - printf("Job %d is stopped.\n", job_id); - break; - case IPP_JOB_CANCELED : - printf("Job %d is canceled.\n", job_id); - break; - case IPP_JOB_ABORTED : - printf("Job %d is aborted.\n", job_id); - break; - case IPP_JOB_COMPLETED : - printf("Job %d is completed.\n", job_id); - break; - } - - /* Sleep if the job is not finished */ - if (job_state < IPP_JOB_STOPPED) - sleep(5); -} -</pre> - -<p>To cancel a job, use the -<a href='#cupsCancelJob'><code>cupsCancelJob</code></a> function with the -job ID:</p> - -<pre class='example'> -#include <cups/cups.h> - -<a href='#cups_dest_t'>cups_dest_t</a> *dest; -int job_id; - -<a href='#cupsCancelJob'>cupsCancelJob</a>(dest->name, job_id); -</pre> - -<h3><a name='ERROR_HANDLING'>Error Handling</a></h3> - -<p>If any of the CUPS API printing functions returns an error, the reason for -that error can be found by calling the -<a href='#cupsLastError'><code>cupsLastError</code></a> and -<a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> functions. -<a href='#cupsLastError'><code>cupsLastError</code></a> returns the last IPP -error code -(<a href='api-httpipp.html#ipp_status_t'><code>ipp_status_t</code></a>) -that was encountered, while -<a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> returns -a (localized) human-readable string that can be shown to the user. For example, -if any of the job creation functions returns a job ID of 0, you can use -<a href='#cupsLastErrorString'><code>cupsLastErrorString</code></a> to show -the reason why the job could not be created:</p> - -<pre class='example'> -#include <cups/cups.h> - -int job_id; - -if (job_id == 0) - puts(cupsLastErrorString()); -</pre> - -<h3><a name='PASSWORDS_AND_AUTHENTICATION'>Passwords and Authentication</a></h3> - -<p>CUPS supports authentication of any request, including submission of print -jobs. The default mechanism for getting the username and password is to use the -login user and a password from the console.</p> - -<p>To support other types of applications, in particular Graphical User -Interfaces ("GUIs"), the CUPS API provides functions to set the default -username and to register a callback function that returns a password string.</p> - -<p>The <a href="#cupsSetPasswordCB"><code>cupsSetPasswordCB</code></a> -function is used to set a password callback in your program. Only one -function can be used at any time.</p> - -<p>The <a href="#cupsSetUser"><code>cupsSetUser</code></a> function sets the -current username for authentication. This function can be called by your -password callback function to change the current username as needed.</p> - -<p>The following example shows a simple password callback that gets a -username and password from the user:</p> - -<pre class='example'> -#include <cups/cups.h> - -const char * -my_password_cb(const char *prompt) -{ - char user[65]; - - - puts(prompt); - - /* Get a username from the user */ - printf("Username: "); - if (fgets(user, sizeof(user), stdin) == NULL) - return (NULL); - - /* Strip the newline from the string and set the user */ - user[strlen(user) - 1] = '\0'; - - <a href='#cupsSetUser'>cupsSetUser</a>(user); - - /* Use getpass() to ask for the password... */ - return (getpass("Password: ")); -} - -<a href='#cupsSetPasswordCB'>cupsSetPasswordCB</a>(my_password_cb); -</pre> - -<p>Similarly, a GUI could display the prompt string in a window with input -fields for the username and password. The username should default to the -string returned by the <a href="#cupsUser"><code>cupsUser</code></a> -function.</p> diff --git a/cups/api-filedir.header b/cups/api-filedir.header deleted file mode 100644 index 87744eed..00000000 --- a/cups/api-filedir.header +++ /dev/null @@ -1,34 +0,0 @@ -<!-- - File and Directory API header for CUPS. - - Copyright 2008-2011 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/". ---> - -<h1 class='title'>File and Directory APIs</h1> - -<div class='summary'><table summary='General Information'> -<thead> -<tr> - <th>Headers</th> - <th>cups/file.h<br> - cups/dir.h</th> -</tr> -</thead> -<tbody> -<tr> - <th>Library</th> - <td>-lcups</td> -</tr> -<tr> - <th>See Also</th> - <td>Programming: <a href='api-overview.html' target='_top'>Introduction to CUPS Programming</a><br> - Programming: <a href='api-cups.html' target='_top'>CUPS API</a></td> -</tr> -</tbody> -</table></div> diff --git a/cups/api-filedir.shtml b/cups/api-filedir.shtml deleted file mode 100644 index 8fdbee64..00000000 --- a/cups/api-filedir.shtml +++ /dev/null @@ -1,29 +0,0 @@ -<!-- - File and directory API introduction for CUPS. - - Copyright 2007-2011 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/". ---> - -<h2 class='title'><a name="OVERVIEW">Overview</a></h2> - -<p>The CUPS file and directory APIs provide portable interfaces -for manipulating files and listing files and directories. Unlike -stdio <code>FILE</code> streams, the <code>cupsFile</code> functions -allow you to open more than 256 files at any given time. They -also manage the platform-specific details of locking, large file -support, line endings (CR, LF, or CR LF), and reading and writing -files using Flate ("gzip") compression. Finally, you can also -connect, read from, and write to network connections using the -<code>cupsFile</code> functions.</p> - -<p>The <code>cupsDir</code> functions manage the platform-specific -details of directory access/listing and provide a convenient way -to get both a list of files and the information (permissions, -size, timestamp, etc.) for each of those files.</p> diff --git a/cups/api-httpipp.header b/cups/api-httpipp.header deleted file mode 100644 index cbede8f6..00000000 --- a/cups/api-httpipp.header +++ /dev/null @@ -1,37 +0,0 @@ -<!-- - HTTP and IPP API header for CUPS. - - Copyright 2007-2016 by Apple Inc. - Copyright 1997-2006 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/". ---> - -<h1 class='title'>HTTP and IPP APIs</h1> - -<div class='summary'><table summary='General Information'> -<thead> -<tr> - <th>Headers</th> - <th>cups/cups.h<br> - cups/http.h<br> - cups/ipp.h</th> -</tr> -</thead> -<tbody> -<tr> - <th>Library</th> - <td>-lcups</td> -</tr> -<tr> - <th>See Also</th> - <td>Programming: <a href='api-overview.html'>Introduction to CUPS Programming</a><br> - Programming: <a href='api-cups.html'>CUPS API</a><br> - References: <a href='spec-ipp.html'>CUPS Implementation of IPP</a></td> -</tr> -</tbody> -</table></div> diff --git a/cups/api-httpipp.shtml b/cups/api-httpipp.shtml deleted file mode 100644 index 33bf5ad3..00000000 --- a/cups/api-httpipp.shtml +++ /dev/null @@ -1,315 +0,0 @@ -<!-- - HTTP and IPP API introduction for CUPS. - - Copyright 2007-2012 by Apple Inc. - Copyright 1997-2006 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/". ---> - -<h2 class='title'><a name='OVERVIEW'>Overview</a></h2> - -<p>The CUPS HTTP and IPP APIs provide low-level access to the HTTP and IPP -protocols and CUPS scheduler. They are typically used by monitoring and -administration programs to perform specific functions not supported by the -high-level CUPS API functions.</p> - -<p>The HTTP APIs use an opaque structure called -<a href='#http_t'><code>http_t</code></a> to manage connections to -a particular HTTP or IPP server. The -<a href='#httpConnectEncrypt'><code>httpConnectEncrypt</code></a> function is -used to create an instance of this structure for a particular server. -The constant <code>CUPS_HTTP_DEFAULT</code> can be used with all of the -<code>cups</code> functions to refer to the default CUPS server - the functions -create a per-thread <a href='#http_t'><code>http_t</code></a> as needed.</p> - -<p>The IPP APIs use two opaque structures for requests (messages sent to the CUPS scheduler) and responses (messages sent back to your application from the scheduler). The <a href='#ipp_t'><code>ipp_t</code></a> type holds a complete request or response and is allocated using the <a href='#ippNew'><code>ippNew</code></a> or <a href='#ippNewRequest'><code>ippNewRequest</code></a> functions and freed using the <a href='#ippDelete'><code>ippDelete</code></a> function.</p> - -<p>The second opaque structure is called <a href='#ipp_attribute_t'><code>ipp_attribute_t</code></a> and holds a single IPP attribute which consists of a group tag (<a href='#ippGetGroupTag'><code>ippGetGroupTag</code></a>), a value type tag (<a href='#ippGetValueTag'><code>ippGetValueTag</code></a>), the attribute name (<a href='#ippGetName'><code>ippGetName</code></a>), and 1 or more values (<a href='#ippGetCount'><code>ippGetCount</code></a>, <a href='#ippGetBoolean'><code>ippGetBoolean</code></a>, <a href='#ippGetCollection'><code>ippGetCollection</code></a>, <a href='#ippGetDate'><code>ippGetDate</code></a>, <a href='#ippGetInteger'><code>ippGetInteger</code></a>, <a href='#ippGetRange'><code>ippGetRange</code></a>, <a href='#ippGetResolution'><code>ippGetResolution</code></a>, and <a href='#ippGetString'><code>ippGetString</code></a>). Attributes are added to an <a href='#ipp_t'><code>ipp_t</code></a> pointer using one of the <code>ippAdd</code> functions. For example, use <a href='#ippAddString'><code>ippAddString</code></a> to add the "printer-uri" and "requesting-user-name" string attributes to a request:</p> - -<pre class='example'> -<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(IPP_GET_JOBS); - -<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, "ipp://localhost/printers/"); -<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", - NULL, cupsUser()); -</pre> - -<p>Once you have created an IPP request, use the <code>cups</code> functions to send the request to and read the response from the server. For example, the <a href='#cupsDoRequest'><code>cupsDoRequest</code></a> function can be used for simple query operations that do not involve files:</p> - -<pre class='example'> -#include <cups/cups.h> - - -<a href='#ipp_t'>ipp_t</a> *<a name='get_jobs'>get_jobs</a>(void) -{ - <a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(IPP_GET_JOBS); - - <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, "ipp://localhost/printers/"); - <a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", - NULL, cupsUser()); - - return (<a href='#cupsDoRequest'>cupsDoRequest</a>(CUPS_HTTP_DEFAULT, request, "/")); -} -</pre> - -<p>The <a href='#cupsDoRequest'><code>cupsDoRequest</code></a> function frees the request and returns an IPP response or <code>NULL</code> pointer if the request could not be sent to the server. Once you have a response from the server, you can either use the <a href='#ippFindAttribute'><code>ippFindAttribute</code></a> and <a href='#ippFindNextAttribute'><code>ippFindNextAttribute</code></a> functions to find specific attributes, for example:</p> - -<pre class='example'> -<a href='#ipp_t'>ipp_t</a> *response; -<a href='#ipp_attribute_t'>ipp_attribute_t</a> *attr; - -attr = <a href='#ippFindAttribute'>ippFindAttribute</a>(response, "printer-state", IPP_TAG_ENUM); -</pre> - -<p>You can also walk the list of attributes with a simple <code>for</code> loop like this:</p> - -<pre class='example'> -<a href='#ipp_t'>ipp_t</a> *response; -<a href='#ipp_attribute_t'>ipp_attribute_t</a> *attr; - -for (attr = <a href='#ippFirstAttribute'>ippFirstAttribute</a>(response); attr != NULL; attr = <a href='#ippNextAttribute'>ippNextAttribute</a>(response)) - if (ippGetName(attr) == NULL) - puts("--SEPARATOR--"); - else - puts(ippGetName(attr)); -</pre> - -<p>The <code>for</code> loop approach is normally used when collecting attributes for multiple objects (jobs, printers, etc.) in a response. Attributes with <code>NULL</code> names indicate a separator between the attributes of each object. For example, the following code will list the jobs returned from our previous <a href='#get_jobs'><code>get_jobs</code></a> example code:</p> - -<pre class='example'> -<a href='#ipp_t'>ipp_t</a> *response = <a href='#get_jobs'>get_jobs</a>(); - -if (response != NULL) -{ - <a href='#ipp_attribute_t'>ipp_attribute_t</a> *attr; - const char *attrname; - int job_id = 0; - const char *job_name = NULL; - const char *job_originating_user_name = NULL; - - puts("Job ID Owner Title"); - puts("------ ---------------- ---------------------------------"); - - for (attr = <a href='#ippFirstAttribute'>ippFirstAttribute</a>(response); attr != NULL; attr = <a href='#ippNextAttribute'>ippNextAttribute</a>(response)) - { - /* Attributes without names are separators between jobs */ - attrname = ippGetName(attr); - if (attrname == NULL) - { - if (job_id > 0) - { - if (job_name == NULL) - job_name = "(withheld)"; - - if (job_originating_user_name == NULL) - job_originating_user_name = "(withheld)"; - - printf("%5d %-16s %s\n", job_id, job_originating_user_name, job_name); - } - - job_id = 0; - job_name = NULL; - job_originating_user_name = NULL; - continue; - } - else if (!strcmp(attrname, "job-id") && ippGetValueTag(attr) == IPP_TAG_INTEGER) - job_id = ippGetInteger(attr, 0); - else if (!strcmp(attrname, "job-name") && ippGetValueTag(attr) == IPP_TAG_NAME) - job_name = ippGetString(attr, 0, NULL); - else if (!strcmp(attrname, "job-originating-user-name") && - ippGetValueTag(attr) == IPP_TAG_NAME) - job_originating_user_name = ippGetString(attr, 0, NULL); - } - - if (job_id > 0) - { - if (job_name == NULL) - job_name = "(withheld)"; - - if (job_originating_user_name == NULL) - job_originating_user_name = "(withheld)"; - - printf("%5d %-16s %s\n", job_id, job_originating_user_name, job_name); - } -} -</pre> - -<h3><a name='CREATING_URI_STRINGS'>Creating URI Strings</a></h3> - -<p>To ensure proper encoding, the -<a href='#httpAssembleURIf'><code>httpAssembleURIf</code></a> function must be -used to format a "printer-uri" string for all printer-based requests:</p> - -<pre class='example'> -const char *name = "Foo"; -char uri[1024]; -<a href='#ipp_t'>ipp_t</a> *request; - -<a href='#httpAssembleURIf'>httpAssembleURIf</a>(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, cupsServer(), - ippPort(), "/printers/%s", name); -<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); -</pre> - -<h3><a name='SENDING_REQUESTS_WITH_FILES'>Sending Requests with Files</a></h3> - -<p>The <a href='#cupsDoFileRequest'><code>cupsDoFileRequest</code></a> and -<a href='#cupsDoIORequest'><code>cupsDoIORequest</code></a> functions are -used for requests involving files. The -<a href='#cupsDoFileRequest'><code>cupsDoFileRequest</code></a> function -attaches the named file to a request and is typically used when sending a print -file or changing a printer's PPD file:</p> - -<pre class='example'> -const char *filename = "/usr/share/cups/data/testprint.ps"; -const char *name = "Foo"; -char uri[1024]; -char resource[1024]; -<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(IPP_PRINT_JOB); -<a href='#ipp_t'>ipp_t</a> *response; - -/* Use httpAssembleURIf for the printer-uri string */ -<a href='#httpAssembleURIf'>httpAssembleURIf</a>(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, cupsServer(), - ippPort(), "/printers/%s", name); -<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); -<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", - NULL, cupsUser()); -<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", - NULL, "testprint.ps"); - -/* Use snprintf for the resource path */ -snprintf(resource, sizeof(resource), "/printers/%s", name); - -response = <a href='#cupsDoFileRequest'>cupsDoFileRequest</a>(CUPS_HTTP_DEFAULT, request, resource, filename); -</pre> - -<p>The <a href='#cupsDoIORequest'><code>cupsDoIORequest</code></a> function -optionally attaches a file to the request and optionally saves a file in the -response from the server. It is used when using a pipe for the request -attachment or when using a request that returns a file, currently only -<code>CUPS_GET_DOCUMENT</code> and <code>CUPS_GET_PPD</code>. For example, -the following code will download the PPD file for the sample HP LaserJet -printer driver:</p> - -<pre class='example'> -char tempfile[1024]; -int tempfd; -<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(CUPS_GET_PPD); -<a href='#ipp_t'>ipp_t</a> *response; - -<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", - NULL, "laserjet.ppd"); - -tempfd = cupsTempFd(tempfile, sizeof(tempfile)); - -response = <a href='#cupsDoIORequest'>cupsDoIORequest</a>(CUPS_HTTP_DEFAULT, request, "/", -1, tempfd); -</pre> - -<p>The example passes <code>-1</code> for the input file descriptor to specify -that no file is to be attached to the request. The PPD file attached to the -response is written to the temporary file descriptor we created using the -<code>cupsTempFd</code> function.</p> - -<h3><a name='ASYNCHRONOUS_REQUEST_PROCESSING'>Asynchronous Request Processing</a></h3> - -<p>The <a href='#cupsSendRequest'><code>cupsSendRequest</code></a> and -<a href='#cupsGetResponse'><code>cupsGetResponse</code></a> support -asynchronous communications with the server. Unlike the other request -functions, the IPP request is not automatically freed, so remember to -free your request with the <a href='#ippDelete'><code>ippDelete</code></a> -function.</p> - -<p>File data is attached to the request using the -<a href='#cupsWriteRequestData'><code>cupsWriteRequestData</code></a> -function, while file data returned from the server is read using the -<a href='#cupsReadResponseData'><code>cupsReadResponseData</code></a> -function. We can rewrite the previous <code>CUPS_GET_PPD</code> example -to use the asynchronous functions quite easily:</p> - -<pre class='example'> -char tempfile[1024]; -int tempfd; -<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(CUPS_GET_PPD); -<a href='#ipp_t'>ipp_t</a> *response; - -<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", - NULL, "laserjet.ppd"); - -tempfd = cupsTempFd(tempfile, sizeof(tempfile)); - -if (<a href='#cupsSendRequest'>cupsSendRequest</a>(CUPS_HTTP_DEFAULT, request, "/") == HTTP_CONTINUE) -{ - response = <a href='#cupsGetResponse'>cupsGetResponse</a>(CUPS_HTTP_DEFAULT, "/"); - - if (response != NULL) - { - ssize_t bytes; - char buffer[8192]; - - while ((bytes = <a href='#cupsReadResponseData'>cupsReadResponseData</a>(CUPS_HTTP_DEFAULT, buffer, sizeof(buffer))) > 0) - write(tempfd, buffer, bytes); - } -} - -/* Free the request! */ -<a href='#ippDelete'>ippDelete</a>(request); -</pre> - -<p>The <a href='#cupsSendRequest'><code>cupsSendRequest</code></a> function -returns the initial HTTP request status, typically either -<code>HTTP_CONTINUE</code> or <code>HTTP_UNAUTHORIZED</code>. The latter status -is returned when the request requires authentication of some sort. The -<a href='#cupsDoAuthentication'><code>cupsDoAuthentication</code></a> function -must be called when your see <code>HTTP_UNAUTHORIZED</code> and the request -re-sent. We can add authentication support to our example code by using a -<code>do ... while</code> loop:</p> - -<pre class='example'> -char tempfile[1024]; -int tempfd; -<a href='#ipp_t'>ipp_t</a> *request = <a href='#ippNewRequest'>ippNewRequest</a>(CUPS_GET_PPD); -<a href='#ipp_t'>ipp_t</a> *response; -http_status_t status; - -<a href='#ippAddString'>ippAddString</a>(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", - NULL, "laserjet.ppd"); - -tempfd = cupsTempFd(tempfile, sizeof(tempfile)); - -/* Loop for authentication */ -do -{ - status = <a href='#cupsSendRequest'>cupsSendRequest</a>(CUPS_HTTP_DEFAULT, request, "/"); - - if (status == HTTP_UNAUTHORIZED) - { - /* Try to authenticate, break out of the loop if that fails */ - if (<a href='#cupsDoAuthentication'>cupsDoAuthentication</a>(CUPS_HTTP_DEFAULT, "POST", "/")) - break; - } -} -while (status != HTTP_CONTINUE && status != HTTP_UNAUTHORIZED); - -if (status == HTTP_CONTINUE) -{ - response = <a href='#cupsGetResponse'>cupsGetResponse</a>(CUPS_HTTP_DEFAULT, "/"); - - if (response != NULL) - { - ssize_t bytes; - char buffer[8192]; - - while ((bytes = <a href='#cupsReadResponseData'>cupsReadResponseData</a>(CUPS_HTTP_DEFAULT, buffer, sizeof(buffer))) > 0) - write(tempfd, buffer, bytes); - } -} - -/* Free the request! */ -<a href='#ippDelete'>ippDelete</a>(request); -</pre> diff --git a/cups/api-ppd.shtml b/cups/api-ppd.shtml index 50c48500..49409462 100644 --- a/cups/api-ppd.shtml +++ b/cups/api-ppd.shtml @@ -1,7 +1,7 @@ <!-- PPD API introduction for CUPS. - Copyright 2007-2012 by Apple Inc. + Copyright 2007-2018 by Apple Inc. Copyright 1997-2006 by Easy Software Products, all rights reserved. These coded instructions, statements, and computer programs are the @@ -13,7 +13,7 @@ <h2 class='title'><a name='OVERVIEW'>Overview</a></h2> -<blockquote>The PPD API is deprecated starting in CUPS 1.6/macOS 10.8. Please use the new Job Ticket APIs in the <a href="api-cups.html">CUPS API</a> documentation. These functions will be removed in a future release of CUPS.</blockquote> +<blockquote>The PPD API is deprecated starting in CUPS 1.6/macOS 10.8. Please use the new Job Ticket APIs in the <a href="cupspm.html">CUPS API</a> documentation. These functions will be removed in a future release of CUPS.</blockquote> <p>The CUPS PPD API provides read-only access the data in PostScript Printer Description ("PPD") files which are used for all printers with a driver. With diff --git a/cups/auth.c b/cups/auth.c index 8348a2cc..a1f50423 100644 --- a/cups/auth.c +++ b/cups/auth.c @@ -1,8 +1,8 @@ /* * Authentication functions for CUPS. * - * Copyright 2007-2016 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products. + * Copyright © 2007-2018 by Apple Inc. + * Copyright © 1997-2007 by Easy Software Products. * * This file contains Kerberos support code, copyright 2006 by * Jelmer Vernooij. @@ -23,11 +23,11 @@ #include "cups-private.h" #include <fcntl.h> #include <sys/stat.h> -#if defined(WIN32) || defined(__EMX__) +#if defined(_WIN32) || defined(__EMX__) # include <io.h> #else # include <unistd.h> -#endif /* WIN32 || __EMX__ */ +#endif /* _WIN32 || __EMX__ */ #if HAVE_AUTHORIZATION_H # include <Security/Authorization.h> @@ -47,6 +47,10 @@ extern const char *cssmErrorString(int error); * Local functions... */ +static const char *cups_auth_find(const char *www_authenticate, const char *scheme); +static const char *cups_auth_param(const char *scheme, const char *name, char *value, size_t valsize); +static const char *cups_auth_scheme(const char *www_authenticate, char *scheme, size_t schemesize); + #ifdef HAVE_GSSAPI # ifdef HAVE_GSS_ACQUIRE_CRED_EX_F # ifdef HAVE_GSS_GSSAPI_SPI_H @@ -54,7 +58,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; @@ -112,10 +116,10 @@ cupsDoAuthentication( const char *resource) /* I - Resource path */ { const char *password, /* Password string */ - *www_auth; /* WWW-Authenticate header */ - char prompt[1024], /* Prompt for user */ - realm[HTTP_MAX_VALUE], /* realm="xyz" string */ - nonce[HTTP_MAX_VALUE]; /* nonce="xyz" string */ + *www_auth, /* WWW-Authenticate header */ + *schemedata; /* Scheme-specific data */ + char scheme[256], /* Scheme name */ + prompt[1024]; /* Prompt for user */ int localauth; /* Local authentication result */ _cups_globals_t *cg; /* Global data */ @@ -163,122 +167,129 @@ cupsDoAuthentication( } /* - * Nope, see if we should retry the current username:password... + * Nope, loop through the authentication schemes to find the first we support. */ - www_auth = http->fields[HTTP_FIELD_WWW_AUTHENTICATE]; + www_auth = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE); - if ((http->digest_tries > 1 || !http->userpass[0]) && - (!_cups_strncasecmp(www_auth, "Basic", 5) || - !_cups_strncasecmp(www_auth, "Digest", 6))) + for (schemedata = cups_auth_scheme(www_auth, scheme, sizeof(scheme)); schemedata; schemedata = cups_auth_scheme(schemedata + strlen(scheme), scheme, sizeof(scheme))) { /* - * Nope - get a new password from the user... + * Check the scheme name... */ - char default_username[HTTP_MAX_VALUE]; - /* Default username */ +#ifdef HAVE_GSSAPI + if (!_cups_strcasecmp(scheme, "Negotiate")) + { + /* + * Kerberos authentication... + */ - cg = _cupsGlobals(); + if (_cupsSetNegotiateAuthString(http, method, resource)) + { + http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; + return (-1); + } - if (!cg->lang_default) - cg->lang_default = cupsLangDefault(); + break; + } + else +#endif /* HAVE_GSSAPI */ + if (_cups_strcasecmp(scheme, "Basic") && _cups_strcasecmp(scheme, "Digest")) + continue; /* Not supported (yet) */ - if (httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "username", - default_username)) - cupsSetUser(default_username); + /* + * See if we should retry the current username:password... + */ - snprintf(prompt, sizeof(prompt), - _cupsLangString(cg->lang_default, _("Password for %s on %s? ")), - cupsUser(), - http->hostname[0] == '/' ? "localhost" : http->hostname); + if ((http->digest_tries > 1 || !http->userpass[0]) && (!_cups_strcasecmp(scheme, "Basic") || (!_cups_strcasecmp(scheme, "Digest")))) + { + /* + * Nope - get a new password from the user... + */ - http->digest_tries = _cups_strncasecmp(www_auth, "Digest", 6) != 0; - http->userpass[0] = '\0'; + char default_username[HTTP_MAX_VALUE]; + /* Default username */ - if ((password = cupsGetPassword2(prompt, http, method, resource)) == NULL) - { - http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; - return (-1); - } + cg = _cupsGlobals(); - snprintf(http->userpass, sizeof(http->userpass), "%s:%s", cupsUser(), - password); - } - else if (http->status == HTTP_STATUS_UNAUTHORIZED) - http->digest_tries ++; + if (!cg->lang_default) + cg->lang_default = cupsLangDefault(); - if (http->status == HTTP_STATUS_UNAUTHORIZED && http->digest_tries >= 3) - { - DEBUG_printf(("1cupsDoAuthentication: Too many authentication tries (%d)", - http->digest_tries)); + if (cups_auth_param(schemedata, "username", default_username, sizeof(default_username))) + cupsSetUser(default_username); - http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; - return (-1); - } + snprintf(prompt, sizeof(prompt), _cupsLangString(cg->lang_default, _("Password for %s on %s? ")), cupsUser(), http->hostname[0] == '/' ? "localhost" : http->hostname); - /* - * Got a password; encode it for the server... - */ + http->digest_tries = _cups_strncasecmp(scheme, "Digest", 6) != 0; + http->userpass[0] = '\0'; -#ifdef HAVE_GSSAPI - if (!_cups_strncasecmp(www_auth, "Negotiate", 9)) - { - /* - * Kerberos authentication... - */ + if ((password = cupsGetPassword2(prompt, http, method, resource)) == NULL) + { + http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; + return (-1); + } - if (_cupsSetNegotiateAuthString(http, method, resource)) + snprintf(http->userpass, sizeof(http->userpass), "%s:%s", cupsUser(), password); + } + else if (http->status == HTTP_STATUS_UNAUTHORIZED) + http->digest_tries ++; + + if (http->status == HTTP_STATUS_UNAUTHORIZED && http->digest_tries >= 3) { + DEBUG_printf(("1cupsDoAuthentication: Too many authentication tries (%d)", http->digest_tries)); + http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; return (-1); } - } - else -#endif /* HAVE_GSSAPI */ - if (!_cups_strncasecmp(www_auth, "Basic", 5)) - { + /* - * Basic authentication... + * Got a password; encode it for the server... */ - char encode[256]; /* Base64 buffer */ + if (!_cups_strcasecmp(scheme, "Basic")) + { + /* + * Basic authentication... + */ + char encode[256]; /* Base64 buffer */ - httpEncode64_2(encode, sizeof(encode), http->userpass, - (int)strlen(http->userpass)); - httpSetAuthString(http, "Basic", encode); - } - else if (!_cups_strncasecmp(www_auth, "Digest", 6)) - { - /* - * Digest authentication... - */ + httpEncode64_2(encode, sizeof(encode), http->userpass, (int)strlen(http->userpass)); + httpSetAuthString(http, "Basic", encode); + break; + } + else if (!_cups_strcasecmp(scheme, "Digest")) + { + /* + * Digest authentication... + */ - char encode[33], /* MD5 buffer */ - digest[1024]; /* Digest auth data */ + char nonce[HTTP_MAX_VALUE]; /* nonce="xyz" string */ - httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm); - httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce); + cups_auth_param(schemedata, "algorithm", http->algorithm, sizeof(http->algorithm)); + cups_auth_param(schemedata, "opaque", http->opaque, sizeof(http->opaque)); + cups_auth_param(schemedata, "nonce", nonce, sizeof(nonce)); + cups_auth_param(schemedata, "realm", http->realm, sizeof(http->realm)); - httpMD5(cupsUser(), realm, strchr(http->userpass, ':') + 1, encode); - httpMD5Final(nonce, method, resource, encode); - snprintf(digest, sizeof(digest), - "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", " - "response=\"%s\"", cupsUser(), realm, nonce, resource, encode); - httpSetAuthString(http, "Digest", digest); + if (_httpSetDigestAuthString(http, nonce, method, resource)) + break; + } + } + + if (http->authstring) + { + DEBUG_printf(("1cupsDoAuthentication: authstring=\"%s\"", http->authstring)); + + return (0); } else { - DEBUG_printf(("1cupsDoAuthentication: Unknown auth type: \"%s\"", - www_auth)); + DEBUG_printf(("1cupsDoAuthentication: Unknown auth type: \"%s\"", www_auth)); http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; + return (-1); } - - DEBUG_printf(("1cupsDoAuthentication: authstring=\"%s\"", http->authstring)); - - return (0); } @@ -336,7 +347,7 @@ _cupsSetNegotiateAuthString( GSS_C_NO_BUFFER, &http->gssmech, &output_token, NULL, NULL); -#ifdef HAVE_GSS_ACQUIRE_CRED_EX_F +# ifdef HAVE_GSS_ACQUIRE_CRED_EX_F if (major_status == GSS_S_NO_CRED) { /* @@ -412,7 +423,7 @@ _cupsSetNegotiateAuthString( } } } -#endif /* HAVE_GSS_ACQUIRED_CRED_EX_F */ +# endif /* HAVE_GSS_ACQUIRED_CRED_EX_F */ if (GSS_ERROR(major_status)) { @@ -422,11 +433,11 @@ _cupsSetNegotiateAuthString( return (-1); } -#ifdef DEBUG +# ifdef DEBUG else if (major_status == GSS_S_CONTINUE_NEEDED) cups_gss_printf(major_status, minor_status, "_cupsSetNegotiateAuthString: Continuation needed!"); -#endif /* DEBUG */ +# endif /* DEBUG */ if (output_token.length > 0 && output_token.length <= 65536) { @@ -464,8 +475,259 @@ _cupsSetNegotiateAuthString( return (0); } +#endif /* HAVE_GSSAPI */ + + +/* + * 'cups_auth_find()' - Find the named WWW-Authenticate scheme. + * + * The "www_authenticate" parameter points to the current position in the header. + * + * Returns @code NULL@ if the auth scheme is not present. + */ + +static const char * /* O - Start of matching scheme or @code NULL@ if not found */ +cups_auth_find(const char *www_authenticate, /* I - Pointer into WWW-Authenticate header */ + const char *scheme) /* I - Authentication scheme */ +{ + size_t schemelen = strlen(scheme); /* Length of scheme */ + + + DEBUG_printf(("8cups_auth_find(www_authenticate=\"%s\", scheme=\"%s\"(%d))", www_authenticate, scheme, (int)schemelen)); + + while (*www_authenticate) + { + /* + * Skip leading whitespace and commas... + */ + + DEBUG_printf(("9cups_auth_find: Before whitespace: \"%s\"", www_authenticate)); + while (isspace(*www_authenticate & 255) || *www_authenticate == ',') + www_authenticate ++; + DEBUG_printf(("9cups_auth_find: After whitespace: \"%s\"", www_authenticate)); + + /* + * See if this is "Scheme" followed by whitespace or the end of the string. + */ + + if (!strncmp(www_authenticate, scheme, schemelen) && (isspace(www_authenticate[schemelen] & 255) || www_authenticate[schemelen] == ',' || !www_authenticate[schemelen])) + { + /* + * Yes, this is the start of the scheme-specific information... + */ + + DEBUG_printf(("9cups_auth_find: Returning \"%s\".", www_authenticate)); + + return (www_authenticate); + } + + /* + * Skip the scheme name or param="value" string... + */ + + while (!isspace(*www_authenticate & 255) && *www_authenticate) + { + if (*www_authenticate == '\"') + { + /* + * Skip quoted value... + */ + + www_authenticate ++; + while (*www_authenticate && *www_authenticate != '\"') + www_authenticate ++; + + DEBUG_printf(("9cups_auth_find: After quoted: \"%s\"", www_authenticate)); + } + + www_authenticate ++; + } + + DEBUG_printf(("9cups_auth_find: After skip: \"%s\"", www_authenticate)); + } + + DEBUG_puts("9cups_auth_find: Returning NULL."); + + return (NULL); +} +/* + * 'cups_auth_param()' - Copy the value for the named authentication parameter, + * if present. + */ + +static const char * /* O - Parameter value or @code NULL@ if not present */ +cups_auth_param(const char *scheme, /* I - Pointer to auth data */ + const char *name, /* I - Name of parameter */ + char *value, /* I - Value buffer */ + size_t valsize) /* I - Size of value buffer */ +{ + char *valptr = value, /* Pointer into value buffer */ + *valend = value + valsize - 1; /* Pointer to end of buffer */ + size_t namelen = strlen(name); /* Name length */ + int param; /* Is this a parameter? */ + + + DEBUG_printf(("8cups_auth_param(scheme=\"%s\", name=\"%s\", value=%p, valsize=%d)", scheme, name, (void *)value, (int)valsize)); + + while (!isspace(*scheme & 255) && *scheme) + scheme ++; + + while (*scheme) + { + while (isspace(*scheme & 255) || *scheme == ',') + scheme ++; + + if (!strncmp(scheme, name, namelen) && scheme[namelen] == '=') + { + /* + * Found the parameter, copy the value... + */ + + scheme += namelen + 1; + if (*scheme == '\"') + { + scheme ++; + + while (*scheme && *scheme != '\"') + { + if (valptr < valend) + *valptr++ = *scheme; + + scheme ++; + } + } + else + { + while (*scheme && strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~+/=", *scheme)) + { + if (valptr < valend) + *valptr++ = *scheme; + + scheme ++; + } + } + + *valptr = '\0'; + + DEBUG_printf(("9cups_auth_param: Returning \"%s\".", value)); + + return (value); + } + + /* + * Skip the param=value string... + */ + + param = 0; + + while (!isspace(*scheme & 255) && *scheme) + { + if (*scheme == '=') + param = 1; + else if (*scheme == '\"') + { + /* + * Skip quoted value... + */ + + scheme ++; + while (*scheme && *scheme != '\"') + scheme ++; + } + + scheme ++; + } + + /* + * If this wasn't a parameter, we are at the end of this scheme's + * parameters... + */ + + if (!param) + break; + } + + *value = '\0'; + + DEBUG_puts("9cups_auth_param: Returning NULL."); + + return (NULL); +} + + +/* + * 'cups_auth_scheme()' - Get the (next) WWW-Authenticate scheme. + * + * The "www_authenticate" parameter points to the current position in the header. + * + * Returns @code NULL@ if there are no (more) auth schemes present. + */ + +static const char * /* O - Start of scheme or @code NULL@ if not found */ +cups_auth_scheme(const char *www_authenticate, /* I - Pointer into WWW-Authenticate header */ + char *scheme, /* I - Scheme name buffer */ + size_t schemesize) /* I - Size of buffer */ +{ + const char *start; /* Start of scheme data */ + char *sptr = scheme, /* Pointer into scheme buffer */ + *send = scheme + schemesize - 1;/* End of scheme buffer */ + int param; /* Is this a parameter? */ + + + DEBUG_printf(("8cups_auth_scheme(www_authenticate=\"%s\", scheme=%p, schemesize=%d)", www_authenticate, (void *)scheme, (int)schemesize)); + + while (*www_authenticate) + { + /* + * Skip leading whitespace and commas... + */ + + while (isspace(*www_authenticate & 255) || *www_authenticate == ',') + www_authenticate ++; + + /* + * Parse the scheme name or param="value" string... + */ + + for (sptr = scheme, start = www_authenticate, param = 0; *www_authenticate && *www_authenticate != ',' && !isspace(*www_authenticate & 255); www_authenticate ++) + { + if (*www_authenticate == '=') + param = 1; + else if (!param && sptr < send) + *sptr++ = *www_authenticate; + else if (*www_authenticate == '\"') + { + /* + * Skip quoted value... + */ + + www_authenticate ++; + while (*www_authenticate && *www_authenticate != '\"') + www_authenticate ++; + } + } + + if (sptr > scheme && !param) + { + *sptr = '\0'; + + DEBUG_printf(("9cups_auth_scheme: Returning \"%s\".", start)); + + return (start); + } + } + + *scheme = '\0'; + + DEBUG_puts("9cups_auth_scheme: Returning NULL."); + + return (NULL); +} + + +#ifdef HAVE_GSSAPI # ifdef HAVE_GSS_ACQUIRE_CRED_EX_F /* * 'cups_gss_acquire()' - Kerberos credentials callback. @@ -639,9 +901,9 @@ static int /* O - 0 if available */ /* -1 error */ cups_local_auth(http_t *http) /* I - HTTP connection to server */ { -#if defined(WIN32) || defined(__EMX__) +#if defined(_WIN32) || defined(__EMX__) /* - * Currently WIN32 and OS-2 do not support the CUPS server... + * Currently _WIN32 and OS-2 do not support the CUPS server... */ return (1); @@ -650,6 +912,8 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ FILE *fp; /* Certificate file */ char trc[16], /* Try Root Certificate parameter */ filename[1024]; /* Certificate filename */ + const char *www_auth, /* WWW-Authenticate header */ + *schemedata; /* Data for the named auth scheme */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ # if defined(HAVE_AUTHORIZATION_H) OSStatus status; /* Status */ @@ -668,13 +932,14 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ * See if we are accessing localhost... */ - if (!httpAddrLocalhost(http->hostaddr) && - _cups_strcasecmp(http->hostname, "localhost") != 0) + if (!httpAddrLocalhost(http->hostaddr) && _cups_strcasecmp(http->hostname, "localhost") != 0) { DEBUG_puts("8cups_local_auth: Not a local connection!"); return (1); } + www_auth = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE); + # if defined(HAVE_AUTHORIZATION_H) /* * Delete any previous authorization reference... @@ -686,12 +951,9 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ http->auth_ref = NULL; } - if (!getenv("GATEWAY_INTERFACE") && - httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey", - auth_key, sizeof(auth_key))) + if (!getenv("GATEWAY_INTERFACE") && (schemedata = cups_auth_find(www_auth, "AuthRef")) != NULL && cups_auth_param(schemedata, "key", auth_key, sizeof(auth_key))) { - status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, - kAuthorizationFlagDefaults, &http->auth_ref); + status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &http->auth_ref); if (status != errAuthorizationSuccess) { DEBUG_printf(("8cups_local_auth: AuthorizationCreate() returned %d (%s)", @@ -745,6 +1007,11 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ } # endif /* HAVE_AUTHORIZATION_H */ +# ifdef HAVE_GSSAPI + if (cups_auth_find(www_auth, "Negotiate")) + return (1); +# endif /* HAVE_GSSAPI */ + # if defined(SO_PEERCRED) && defined(AF_LOCAL) /* * See if we can authenticate using the peer credentials provided over a @@ -752,16 +1019,9 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ * information... */ - if ( -# ifdef HAVE_GSSAPI - _cups_strncasecmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9) && -# endif /* HAVE_GSSAPI */ -# ifdef HAVE_AUTHORIZATION_H - !httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey", - auth_key, sizeof(auth_key)) && -# endif /* HAVE_AUTHORIZATION_H */ - http->hostaddr->addr.sa_family == AF_LOCAL && - !getenv("GATEWAY_INTERFACE")) /* Not via CGI programs... */ + if (http->hostaddr->addr.sa_family == AF_LOCAL && + !getenv("GATEWAY_INTERFACE") && /* Not via CGI programs... */ + cups_auth_find(www_auth, "PeerCred")) { /* * Verify that the current cupsUser() matches the current UID... @@ -784,6 +1044,9 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ } # endif /* SO_PEERCRED && AF_LOCAL */ + if ((schemedata = cups_auth_find(www_auth, "Local")) == NULL) + return (1); + /* * Try opening a certificate file for this PID. If that fails, * try the root certificate... @@ -797,33 +1060,9 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ * No certificate for this PID; see if we can get the root certificate... */ - DEBUG_printf(("9cups_local_auth: Unable to open file %s: %s", - filename, strerror(errno))); + DEBUG_printf(("9cups_local_auth: Unable to open file \"%s\": %s", filename, strerror(errno))); -# ifdef HAVE_GSSAPI - if (!_cups_strncasecmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Negotiate", 9)) - { - /* - * Kerberos required, don't try the root certificate... - */ - - return (1); - } -# endif /* HAVE_GSSAPI */ - -# ifdef HAVE_AUTHORIZATION_H - if (httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey", - auth_key, sizeof(auth_key))) - { - /* - * Don't use the root certificate as a replacement for an authkey... - */ - - return (1); - } -# endif /* HAVE_AUTHORIZATION_H */ - if (!httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "trc", trc, - sizeof(trc))) + if (!cups_auth_param(schemedata, "trc", trc, sizeof(trc))) { /* * Scheduler doesn't want us to use the root certificate... @@ -833,7 +1072,8 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ } snprintf(filename, sizeof(filename), "%s/certs/0", cg->cups_statedir); - fp = fopen(filename, "r"); + if ((fp = fopen(filename, "r")) == NULL) + DEBUG_printf(("9cups_local_auth: Unable to open file \"%s\": %s", filename, strerror(errno))); } if (fp) @@ -864,5 +1104,5 @@ cups_local_auth(http_t *http) /* I - HTTP connection to server */ } return (1); -#endif /* WIN32 || __EMX__ */ +#endif /* _WIN32 || __EMX__ */ } diff --git a/cups/backchannel.c b/cups/backchannel.c index e804d45b..bca04dc3 100644 --- a/cups/backchannel.c +++ b/cups/backchannel.c @@ -19,12 +19,12 @@ #include "cups.h" #include <errno.h> -#ifdef WIN32 +#ifdef _WIN32 # include <io.h> # include <fcntl.h> #else # include <sys/time.h> -#endif /* WIN32 */ +#endif /* _WIN32 */ /* @@ -77,11 +77,11 @@ cupsBackChannelRead(char *buffer, /* I - Buffer to read into */ * Read bytes from the pipe... */ -#ifdef WIN32 +#ifdef _WIN32 return ((ssize_t)_read(3, buffer, (unsigned)bytes)); #else return (read(3, buffer, bytes)); -#endif /* WIN32 */ +#endif /* _WIN32 */ } @@ -139,11 +139,11 @@ cupsBackChannelWrite( * Write bytes to the pipe... */ -#ifdef WIN32 +#ifdef _WIN32 count = (ssize_t)_write(3, buffer, (unsigned)(bytes - total)); #else count = write(3, buffer, bytes - total); -#endif /* WIN32 */ +#endif /* _WIN32 */ if (count < 0) { diff --git a/cups/cups-private.h b/cups/cups-private.h index 264fd01c..6fd66a9c 100644 --- a/cups/cups-private.h +++ b/cups/cups-private.h @@ -1,7 +1,7 @@ /* * 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 @@ -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 */ diff --git a/cups/cups.h b/cups/cups.h index 3205dd82..cf3be127 100644 --- a/cups/cups.h +++ b/cups/cups.h @@ -1,7 +1,7 @@ /* * API definitions for CUPS. * - * Copyright 2007-2017 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -21,12 +21,12 @@ */ # include <sys/types.h> -# if defined(WIN32) && !defined(__CUPS_SSIZE_T_DEFINED) +# if defined(_WIN32) && !defined(__CUPS_SSIZE_T_DEFINED) # define __CUPS_SSIZE_T_DEFINED # include <stddef.h> /* Windows does not support the ssize_t type, so map it to long... */ typedef long ssize_t; /* @private@ */ -# endif /* WIN32 && !__CUPS_SSIZE_T_DEFINED */ +# endif /* _WIN32 && !__CUPS_SSIZE_T_DEFINED */ # include "file.h" # include "ipp.h" @@ -47,10 +47,10 @@ extern "C" { * Constants... */ -# define CUPS_VERSION 2.0203 +# define CUPS_VERSION 2.0209 # define CUPS_VERSION_MAJOR 2 # define CUPS_VERSION_MINOR 2 -# define CUPS_VERSION_PATCH 3 +# define CUPS_VERSION_PATCH 9 # 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,38 +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@ */ + 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 @private@ */ + * @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 | @@ -269,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 */ @@ -309,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, @@ -340,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, @@ -600,6 +602,13 @@ 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; + +/* New in CUPS 2.2.7 */ +extern const char *cupsHashString(const unsigned char *hash, size_t hashsize, char *buffer, size_t bufsize) _CUPS_API_2_2_7; + # ifdef __cplusplus } # endif /* __cplusplus */ diff --git a/cups/cupspm-icon.png b/cups/cupspm-icon.png new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/cups/cupspm-icon.png diff --git a/cups/cupspm.md b/cups/cupspm.md new file mode 100644 index 00000000..cb381ac2 --- /dev/null +++ b/cups/cupspm.md @@ -0,0 +1,994 @@ +--- +title: CUPS Programming Manual +author: Michael R Sweet +copyright: Copyright © 2007-2017 by Apple Inc. All Rights Reserved. +version: 2.2.5 +... + +> Please [file issues on Github](https://github.com/apple/cups/issues) to +> provide feedback on this document. + + +# Introduction + +CUPS provides the "cups" library to talk to the different parts of CUPS and with +Internet Printing Protocol (IPP) printers. The "cups" library functions are +accessed by including the `<cups/cups.h>` header. + +CUPS is based on the Internet Printing Protocol ("IPP"), which allows clients +(applications) to communicate with a server (the scheduler, printers, etc.) to +get a list of destinations, send print jobs, and so forth. You identify which +server you want to communicate with using a pointer to the opaque structure +`http_t`. The `CUPS_HTTP_DEFAULT` constant can be used when you want to talk to +the CUPS scheduler. + + +## Guidelines + +When writing software that uses the "cups" library: + +- Do not use undocumented or deprecated APIs, +- Do not rely on pre-configured printers, +- Do not assume that printers support specific features or formats, and +- Do not rely on implementation details (PPDs, etc.) + +CUPS is designed to insulate users and developers from the implementation +details of printers and file formats. The goal is to allow an application to +supply a print file in a standard format with the user intent ("print four +copies, two-sided on A4 media, and staple each copy") and have the printing +system manage the printer communication and format conversion needed. + +Similarly, printer and job management applications can use standard query +operations to obtain the status information in a common, generic form and use +standard management operations to control the state of those printers and jobs. + + +## Terms Used in This Document + +A *Destination* is a printer or print queue that accepts print jobs. A +*Print Job* is one or more documents that are processed by a destination +using options supplied when creating the job. A *Document* is a file (JPEG +image, PDF file, etc.) suitable for printing. An *Option* controls some aspect +of printing, such as the media used. *Media* is the sheets or roll that is +printed on. An *Attribute* is an option encoded for an Internet Printing +Protocol (IPP) request. + + +## Compiling Programs That Use the CUPS API + +The CUPS libraries can be used from any C, C++, or Objective C program. +The method of compiling against the libraries varies depending on the +operating system and installation of CUPS. The following sections show how +to compile a simple program (shown below) in two common environments. + +The following simple program lists the available destinations: + + #include <stdio.h> + #include <cups/cups.h> + + int print_dest(void *user_data, unsigned flags, cups_dest_t *dest) + { + if (dest->instance) + printf("%s/%s\n", dest->name, dest->instance); + else + puts(dest->name); + + return (1); + } + + int main(void) + { + cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, 0, 0, print_dest, NULL); + + return (0); + } + + +### Compiling with Xcode + +In Xcode, choose *New Project...* from the *File* menu (or press SHIFT+CMD+N), +then select the *Command Line Tool* under the macOS Application project type. +Click *Next* and enter a name for the project, for example "firstcups". Click +*Next* and choose a project directory. The click *Next* to create the project. + +In the project window, click on the *Build Phases* group and expand the +*Link Binary with Libraries* section. Click *+*, type "libcups" to show the +library, and then double-click on `libcups.tbd`. + +Finally, click on the `main.c` file in the sidebar and copy the example program +to the file. Build and run (CMD+R) to see the list of destinations. + + +### Compiling with GCC + +From the command-line, create a file called `sample.c` using your favorite +editor, copy the example to this file, and save. Then run the following command +to compile it with GCC and run it: + + gcc -o simple `cups-config --cflags` simple.c `cups-config --libs` + ./simple + +The `cups-config` command provides the compiler flags (`cups-config --cflags`) +and libraries (`cups-config --libs`) needed for the local system. + + +# Working with Destinations + +Destinations, which in CUPS represent individual printers or classes +(collections or pools) of printers, are represented by the `cups_dest_t` +structure which includes the name \(`name`), instance \(`instance`, saved +options/settings), whether the destination is the default for the user +\(`is_default`), and the options and basic information associated with that +destination \(`num_options` and `options`). + +Historically destinations have been manually maintained by the administrator of +a system or network, but CUPS also supports dynamic discovery of destinations on +the current network. + + +## Finding Available Destinations + +The `cupsEnumDests` function finds all of the available destinations: + + int + cupsEnumDests(unsigned flags, int msec, int *cancel, + cups_ptype_t type, cups_ptype_t mask, + cups_dest_cb_t cb, void *user_data) + +The `flags` argument specifies enumeration options, which at present must be +`CUPS_DEST_FLAGS_NONE`. + +The `msec` argument specifies the maximum amount of time that should be used for +enumeration in milliseconds - interactive applications should keep this value to +5000 or less when run on the main thread. + +The `cancel` argument points to an integer variable that, when set to a non-zero +value, will cause enumeration to stop as soon as possible. It can be `NULL` if +not needed. + +The `type` and `mask` arguments are bitfields that allow the caller to filter +the destinations based on categories and/or capabilities. The destination's +"printer-type" value is masked by the `mask` value and compared to the `type` +value when filtering. For example, to only enumerate destinations that are +hosted on the local system, pass `CUPS_PRINTER_LOCAL` for the `type` argument +and `CUPS_PRINTER_DISCOVERED` for the `mask` argument. The following constants +can be used for filtering: + +- `CUPS_PRINTER_CLASS`: A collection of destinations. +- `CUPS_PRINTER_FAX`: A facsimile device. +- `CUPS_PRINTER_LOCAL`: A local printer or class. This constant has the value 0 + (no bits set) and is only used for the `type` argument and is paired with the + `CUPS_PRINTER_REMOTE` or `CUPS_PRINTER_DISCOVERED` constant passed in the + `mask` argument. +- `CUPS_PRINTER_REMOTE`: A remote (shared) printer or class. +- `CUPS_PRINTER_DISCOVERED`: An available network printer or class. +- `CUPS_PRINTER_BW`: Can do B&W printing. +- `CUPS_PRINTER_COLOR`: Can do color printing. +- `CUPS_PRINTER_DUPLEX`: Can do two-sided printing. +- `CUPS_PRINTER_STAPLE`: Can staple output. +- `CUPS_PRINTER_COLLATE`: Can quickly collate copies. +- `CUPS_PRINTER_PUNCH`: Can punch output. +- `CUPS_PRINTER_COVER`: Can cover output. +- `CUPS_PRINTER_BIND`: Can bind output. +- `CUPS_PRINTER_SORT`: Can sort output (mailboxes, etc.) +- `CUPS_PRINTER_SMALL`: Can print on Letter/Legal/A4-size media. +- `CUPS_PRINTER_MEDIUM`: Can print on Tabloid/B/C/A3/A2-size media. +- `CUPS_PRINTER_LARGE`: Can print on D/E/A1/A0-size media. +- `CUPS_PRINTER_VARIABLE`: Can print on rolls and custom-size media. + +The `cb` argument specifies a function to call for every destination that is +found: + + typedef int (*cups_dest_cb_t)(void *user_data, + unsigned flags, + cups_dest_t *dest); + +The callback function receives a copy of the `user_data` argument along with a +bitfield \(`flags`) and the destination that was found. The `flags` argument +can have any of the following constant (bit) values set: + +- `CUPS_DEST_FLAGS_MORE`: There are more destinations coming. +- `CUPS_DEST_FLAGS_REMOVED`: The destination has gone away and should be removed + from the list of destinations a user can select. +- `CUPS_DEST_FLAGS_ERROR`: An error occurred. The reason for the error can be + found by calling the `cupsLastError` and/or `cupsLastErrorString` functions. + +The callback function returns 0 to stop enumeration or 1 to continue. + +> Note that the callback function will likely be called multiple times for the +> same destination, so it is up to the caller to suppress any duplicate +> destinations. + +The following example shows how to use `cupsEnumDests` to get a filtered array +of destinations: + + typedef struct + { + int num_dests; + cups_dest_t *dests; + } my_user_data_t; + + int + my_dest_cb(my_user_data_t *user_data, unsigned flags, + cups_dest_t *dest) + { + if (flags & CUPS_DEST_FLAGS_REMOVED) + { + /* + * Remove destination from array... + */ + + user_data->num_dests = + cupsRemoveDest(dest->name, dest->instance, + user_data->num_dests, + &(user_data->dests)); + } + else + { + /* + * Add destination to array... + */ + + user_data->num_dests = + cupsCopyDest(dest, user_data->num_dests, + &(user_data->dests)); + } + + return (1); + } + + int + my_get_dests(cups_ptype_t type, cups_ptype_t mask, + cups_dest_t **dests) + { + my_user_data_t user_data = { 0, NULL }; + + if (!cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, type, + mask, (cups_dest_cb_t)my_dest_cb, + &user_data)) + { + /* + * An error occurred, free all of the destinations and + * return... + */ + + cupsFreeDests(user_data.num_dests, user_dasta.dests); + + *dests = NULL; + + return (0); + } + + /* + * Return the destination array... + */ + + *dests = user_data.dests; + + return (user_data.num_dests); + } + + +## Basic Destination Information + +The `num_options` and `options` members of the `cups_dest_t` structure provide +basic attributes about the destination in addition to the user default options +and values for that destination. The following names are predefined for various +destination attributes: + +- "auth-info-required": The type of authentication required for printing to this + destination: "none", "username,password", "domain,username,password", or + "negotiate" (Kerberos). +- "printer-info": The human-readable description of the destination such as "My + Laser Printer". +- "printer-is-accepting-jobs": "true" if the destination is accepting new jobs, + "false" otherwise. +- "printer-is-shared": "true" if the destination is being shared with other + computers, "false" otherwise. +- "printer-location": The human-readable location of the destination such as + "Lab 4". +- "printer-make-and-model": The human-readable make and model of the destination + such as "ExampleCorp LaserPrinter 4000 Series". +- "printer-state": "3" if the destination is idle, "4" if the destination is + printing a job, and "5" if the destination is stopped. +- "printer-state-change-time": The UNIX time when the destination entered the + current state. +- "printer-state-reasons": Additional comma-delimited state keywords for the + destination such as "media-tray-empty-error" and "toner-low-warning". +- "printer-type": The `cups_ptype_t` value associated with the destination. +- "printer-uri-supported": The URI associated with the destination; if not set, + this destination was discovered but is not yet setup as a local printer. + +Use the `cupsGetOption` function to retrieve the value. For example, the +following code gets the make and model of a destination: + + const char *model = cupsGetOption("printer-make-and-model", + dest->num_options, + dest->options); + + +## Detailed Destination Information + +Once a destination has been chosen, the `cupsCopyDestInfo` function can be used +to gather detailed information about the destination: + + cups_dinfo_t * + cupsCopyDestInfo(http_t *http, cups_dest_t *dest); + +The `http` argument specifies a connection to the CUPS scheduler and is +typically the constant `CUPS_HTTP_DEFAULT`. The `dest` argument specifies the +destination to query. + +The `cups_dinfo_t` structure that is returned contains a snapshot of the +supported options and their supported, ready, and default values. It also can +report constraints between different options and values, and recommend changes +to resolve those constraints. + + +### Getting Supported Options and Values + +The `cupsCheckDestSupported` function can be used to test whether a particular +option or option and value is supported: + + int + cupsCheckDestSupported(http_t *http, cups_dest_t *dest, + cups_dinfo_t *info, + const char *option, + const char *value); + +The `option` argument specifies the name of the option to check. The following +constants can be used to check the various standard options: + +- `CUPS_COPIES`: Controls the number of copies that are produced. +- `CUPS_FINISHINGS`: A comma-delimited list of integer constants that control + the finishing processes that are applied to the job, including stapling, + punching, and folding. +- `CUPS_MEDIA`: Controls the media size that is used, typically one of the + following: `CUPS_MEDIA_3X5`, `CUPS_MEDIA_4X6`, `CUPS_MEDIA_5X7`, + `CUPS_MEDIA_8X10`, `CUPS_MEDIA_A3`, `CUPS_MEDIA_A4`, `CUPS_MEDIA_A5`, + `CUPS_MEDIA_A6`, `CUPS_MEDIA_ENV10`, `CUPS_MEDIA_ENVDL`, `CUPS_MEDIA_LEGAL`, + `CUPS_MEDIA_LETTER`, `CUPS_MEDIA_PHOTO_L`, `CUPS_MEDIA_SUPERBA3`, or + `CUPS_MEDIA_TABLOID`. +- `CUPS_MEDIA_SOURCE`: Controls where the media is pulled from, typically either + `CUPS_MEDIA_SOURCE_AUTO` or `CUPS_MEDIA_SOURCE_MANUAL`. +- `CUPS_MEDIA_TYPE`: Controls the type of media that is used, typically one of + the following: `CUPS_MEDIA_TYPE_AUTO`, `CUPS_MEDIA_TYPE_ENVELOPE`, + `CUPS_MEDIA_TYPE_LABELS`, `CUPS_MEDIA_TYPE_LETTERHEAD`, + `CUPS_MEDIA_TYPE_PHOTO`, `CUPS_MEDIA_TYPE_PHOTO_GLOSSY`, + `CUPS_MEDIA_TYPE_PHOTO_MATTE`, `CUPS_MEDIA_TYPE_PLAIN`, or + `CUPS_MEDIA_TYPE_TRANSPARENCY`. +- `CUPS_NUMBER_UP`: Controls the number of document pages that are placed on + each media side. +- `CUPS_ORIENTATION`: Controls the orientation of document pages placed on the + media: `CUPS_ORIENTATION_PORTRAIT` or `CUPS_ORIENTATION_LANDSCAPE`. +- `CUPS_PRINT_COLOR_MODE`: Controls whether the output is in color + \(`CUPS_PRINT_COLOR_MODE_COLOR`), grayscale + \(`CUPS_PRINT_COLOR_MODE_MONOCHROME`), or either + \(`CUPS_PRINT_COLOR_MODE_AUTO`). +- `CUPS_PRINT_QUALITY`: Controls the generate quality of the output: + `CUPS_PRINT_QUALITY_DRAFT`, `CUPS_PRINT_QUALITY_NORMAL`, or + `CUPS_PRINT_QUALITY_HIGH`. +- `CUPS_SIDES`: Controls whether prints are placed on one or both sides of the + media: `CUPS_SIDES_ONE_SIDED`, `CUPS_SIDES_TWO_SIDED_PORTRAIT`, or + `CUPS_SIDES_TWO_SIDED_LANDSCAPE`. + +If the `value` argument is `NULL`, the `cupsCheckDestSupported` function returns +whether the option is supported by the destination. Otherwise, the function +returns whether the specified value of the option is supported. + +The `cupsFindDestSupported` function returns the IPP attribute containing the +supported values for a given option: + + ipp_attribute_t * + cupsFindDestSupported(http_t *http, cups_dest_t *dest, + cups_dinfo_t *dinfo, + const char *option); + +For example, the following code prints the supported finishing processes for a +destination, if any, to the standard output: + + cups_dinfo_t *info = cupsCopyDestInfo(CUPS_HTTP_DEFAULT, + dest); + + if (cupsCheckDestSupported(CUPS_HTTP_DEFAULT, dest, info, + CUPS_FINISHINGS, NULL)) + { + ipp_attribute_t *finishings = + cupsFindDestSupported(CUPS_HTTP_DEFAULT, dest, info, + CUPS_FINISHINGS); + int i, count = ippGetCount(finishings); + + puts("finishings supported:"); + for (i = 0; i < count; i ++) + printf(" %d\n", ippGetInteger(finishings, i)); + } + else + puts("finishings not supported."); + +The "job-creation-attributes" option can be queried to get a list of supported +options. For example, the following code prints the list of supported options +to the standard output: + + ipp_attribute_t *attrs = + cupsFindDestSupported(CUPS_HTTP_DEFAULT, dest, info, + "job-creation-attributes"); + int i, count = ippGetCount(attrs); + + for (i = 0; i < count; i ++) + puts(ippGetString(attrs, i, NULL)); + + +### Getting Default Values + +There are two sets of default values - user defaults that are available via the +`num_options` and `options` members of the `cups_dest_t` structure, and +destination defaults that available via the `cups_dinfo_t` structure and the +`cupsFindDestDefault` function which returns the IPP attribute containing the +default value(s) for a given option: + + ipp_attribute_t * + cupsFindDestDefault(http_t *http, cups_dest_t *dest, + cups_dinfo_t *dinfo, + const char *option); + +The user defaults from `cupsGetOption` should always take preference over the +destination defaults. For example, the following code prints the default +finishings value(s) to the standard output: + + const char *def_value = + cupsGetOption(CUPS_FINISHINGS, dest->num_options, + dest->options); + ipp_attribute_t *def_attr = + cupsFindDestDefault(CUPS_HTTP_DEFAULT, dest, info, + CUPS_FINISHINGS); + + if (def_value != NULL) + { + printf("Default finishings: %s\n", def_value); + } + else + { + int i, count = ippGetCount(def_attr); + + printf("Default finishings: %d", + ippGetInteger(def_attr, 0)); + for (i = 1; i < count; i ++) + printf(",%d", ippGetInteger(def_attr, i)); + putchar('\n'); + } + + +### Getting Ready (Loaded) Values + +The finishings and media options also support queries for the ready, or loaded, +values. For example, a printer may have punch and staple finishers installed +but be out of staples - the supported values will list both punch and staple +finishing processes but the ready values will only list the punch processes. +Similarly, a printer may support hundreds of different sizes of media but only +have a single size loaded at any given time - the ready values are limited to +the media that is actually in the printer. + +The `cupsFindDestReady` function finds the IPP attribute containing the ready +values for a given option: + + ipp_attribute_t * + cupsFindDestReady(http_t *http, cups_dest_t *dest, + cups_dinfo_t *dinfo, const char *option); + +For example, the following code lists the ready finishing processes: + + ipp_attribute_t *ready_finishings = + cupsFindDestReady(CUPS_HTTP_DEFAULT, dest, info, + CUPS_FINISHINGS); + + if (ready_finishings != NULL) + { + int i, count = ippGetCount(ready_finishings); + + puts("finishings ready:"); + for (i = 0; i < count; i ++) + printf(" %d\n", ippGetInteger(ready_finishings, i)); + } + else + puts("no finishings are ready."); + + +### Media Size Options + +CUPS provides functions for querying the dimensions and margins for each of the +supported media size options. The `cups_size_t` structure is used to describe a +media size: + + typedef struct cups_size_s + { + char media[128]; + int width, length; + int bottom, left, right, top; + } cups_size_t; + +The `width` and `length` members specify the dimensions of the media in +hundredths of millimeters (1/2540th of an inch). The `bottom`, `left`, `right`, +and `top` members specify the margins of the printable area, also in hundredths +of millimeters. + +The `cupsGetDestMediaByName` and `cupsGetDestMediaBySize` functions lookup the +media size information using a standard media size name or dimensions in +hundredths of millimeters: + + int + cupsGetDestMediaByName(http_t *http, cups_dest_t *dest, + cups_dinfo_t *dinfo, + const char *media, + unsigned flags, cups_size_t *size); + + int + cupsGetDestMediaBySize(http_t *http, cups_dest_t *dest, + cups_dinfo_t *dinfo, + int width, int length, + unsigned flags, cups_size_t *size); + +The `media`, `width`, and `length` arguments specify the size to lookup. The +`flags` argument specifies a bitfield controlling various lookup options: + +- `CUPS_MEDIA_FLAGS_DEFAULT`: Find the closest size supported by the printer. +- `CUPS_MEDIA_FLAGS_BORDERLESS`: Find a borderless size. +- `CUPS_MEDIA_FLAGS_DUPLEX`: Find a size compatible with two-sided printing. +- `CUPS_MEDIA_FLAGS_EXACT`: Find an exact match for the size. +- `CUPS_MEDIA_FLAGS_READY`: If the printer supports media sensing or + configuration of the media in each tray/source, find the size amongst the + "ready" media. + +If a matching size is found for the destination, the size information is stored +in the structure pointed to by the `size` argument and 1 is returned. Otherwise +0 is returned. + +For example, the following code prints the margins for two-sided printing on US +Letter media: + + cups_size_t size; + + if (cupsGetDestMediaByName(CUPS_HTTP_DEFAULT, dest, info, + CUPS_MEDIA_LETTER, + CUPS_MEDIA_FLAGS_DUPLEX, &size)) + { + puts("Margins for duplex US Letter:"); + printf(" Bottom: %.2fin\n", size.bottom / 2540.0); + printf(" Left: %.2fin\n", size.left / 2540.0); + printf(" Right: %.2fin\n", size.right / 2540.0); + printf(" Top: %.2fin\n", size.top / 2540.0); + } + else + puts("Margins for duplex US Letter are not available."); + +You can also enumerate all of the sizes that match a given `flags` value using +the `cupsGetDestMediaByIndex` and `cupsGetDestMediaCount` functions: + + int + cupsGetDestMediaByIndex(http_t *http, cups_dest_t *dest, + cups_dinfo_t *dinfo, int n, + unsigned flags, cups_size_t *size); + + int + cupsGetDestMediaCount(http_t *http, cups_dest_t *dest, + cups_dinfo_t *dinfo, unsigned flags); + +For example, the following code prints the list of ready media and corresponding +margins: + + cups_size_t size; + int i; + int count = cupsGetDestMediaCount(CUPS_HTTP_DEFAULT, + dest, info, + CUPS_MEDIA_FLAGS_READY); + + for (i = 0; i < count; i ++) + { + if (cupsGetDestMediaByIndex(CUPS_HTTP_DEFAULT, dest, info, + i, CUPS_MEDIA_FLAGS_READY, + &size)) + { + printf("%s:\n", size.name); + printf(" Width: %.2fin\n", size.width / 2540.0); + printf(" Length: %.2fin\n", size.length / 2540.0); + printf(" Bottom: %.2fin\n", size.bottom / 2540.0); + printf(" Left: %.2fin\n", size.left / 2540.0); + printf(" Right: %.2fin\n", size.right / 2540.0); + printf(" Top: %.2fin\n", size.top / 2540.0); + } + } + +Finally, the `cupsGetDestMediaDefault` function returns the default media size: + + int + cupsGetDestMediaDefault(http_t *http, cups_dest_t *dest, + cups_dinfo_t *dinfo, unsigned flags, + cups_size_t *size); + + +### Localizing Options and Values + +CUPS provides three functions to get localized, human-readable strings in the +user's current locale for options and values: `cupsLocalizeDestMedia`, +`cupsLocalizeDestOption`, and `cupsLocalizeDestValue`: + + const char * + cupsLocalizeDestMedia(http_t *http, cups_dest_t *dest, + cups_dinfo_t *info, unsigned flags, + cups_size_t *size); + + const char * + cupsLocalizeDestOption(http_t *http, cups_dest_t *dest, + cups_dinfo_t *info, + const char *option); + + const char * + cupsLocalizeDestValue(http_t *http, cups_dest_t *dest, + cups_dinfo_t *info, + const char *option, const char *value); + + +## Submitting a Print Job + +Once you are ready to submit a print job, you create a job using the +`cupsCreateDestJob` function: + + ipp_status_t + cupsCreateDestJob(http_t *http, cups_dest_t *dest, + cups_dinfo_t *info, int *job_id, + const char *title, int num_options, + cups_option_t *options); + +The `title` argument specifies a name for the print job such as "My Document". +The `num_options` and `options` arguments specify the options for the print +job which are allocated using the `cupsAddOption` function. + +When successful, the job's numeric identifier is stored in the integer pointed +to by the `job_id` argument and `IPP_STATUS_OK` is returned. Otherwise, an IPP +error status is returned. + +For example, the following code creates a new job that will print 42 copies of a +two-sided US Letter document: + + int job_id = 0; + int num_options = 0; + cups_option_t *options = NULL; + + num_options = cupsAddOption(CUPS_COPIES, "42", + num_options, &options); + num_options = cupsAddOption(CUPS_MEDIA, CUPS_MEDIA_LETTER, + num_options, &options); + num_options = cupsAddOption(CUPS_SIDES, + CUPS_SIDES_TWO_SIDED_PORTRAIT, + num_options, &options); + + if (cupsCreateDestJob(CUPS_HTTP_DEFAULT, dest, info, + &job_id, "My Document", num_options, + options) == IPP_STATUS_OK) + printf("Created job: %d\n", job_id); + else + printf("Unable to create job: %s\n", + cupsLastErrorString()); + +Once the job is created, you submit documents for the job using the +`cupsStartDestDocument`, `cupsWriteRequestData`, and `cupsFinishDestDocument` +functions: + + http_status_t + cupsStartDestDocument(http_t *http, cups_dest_t *dest, + cups_dinfo_t *info, int job_id, + const char *docname, + const char *format, + int num_options, + cups_option_t *options, + int last_document); + + http_status_t + cupsWriteRequestData(http_t *http, const char *buffer, + size_t length); + + ipp_status_t + cupsFinishDestDocument(http_t *http, cups_dest_t *dest, + cups_dinfo_t *info); + +The `docname` argument specifies the name of the document, typically the +original filename. The `format` argument specifies the MIME media type of the +document, including the following constants: + +- `CUPS_FORMAT_JPEG`: "image/jpeg" +- `CUPS_FORMAT_PDF`: "application/pdf" +- `CUPS_FORMAT_POSTSCRIPT`: "application/postscript" +- `CUPS_FORMAT_TEXT`: "text/plain" + +The `num_options` and `options` arguments specify per-document print options, +which at present must be 0 and `NULL`. The `last_document` argument specifies +whether this is the last document in the job. + +For example, the following code submits a PDF file to the job that was just +created: + + FILE *fp = fopen("filename.pdf", "rb"); + size_t bytes; + char buffer[65536]; + + if (cupsStartDestDocument(CUPS_HTTP_DEFAULT, dest, info, + job_id, "filename.pdf", 0, NULL, + 1) == HTTP_STATUS_CONTINUE) + { + while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) + if (cupsWriteRequestData(CUPS_HTTP_DEFAULT, buffer, + bytes) != HTTP_STATUS_CONTINUE) + break; + + if (cupsFinishDestDocument(CUPS_HTTP_DEFAULT, dest, + info) == IPP_STATUS_OK) + puts("Document send succeeded."); + else + printf("Document send failed: %s\n", + cupsLastErrorString()); + } + + fclose(fp); + + +# Sending IPP Requests + +CUPS provides a rich API for sending IPP requests to the scheduler or printers, +typically from management or utility applications whose primary purpose is not +to send print jobs. + + +## Connecting to the Scheduler or Printer + +The connection to the scheduler or printer is represented by the HTTP connection +type `http_t`. The `cupsConnectDest` function connects to the scheduler or +printer associated with the destination: + + http_t * + cupsConnectDest(cups_dest_t *dest, unsigned flags, int msec, + int *cancel, char *resource, + size_t resourcesize, cups_dest_cb_t cb, + void *user_data); + +The `dest` argument specifies the destination to connect to. + +The `flags` argument specifies whether you want to connect to the scheduler +(`CUPS_DEST_FLAGS_NONE`) or device/printer (`CUPS_DEST_FLAGS_DEVICE`) associated +with the destination. + +The `msec` argument specifies how long you are willing to wait for the +connection to be established in milliseconds. Specify a value of `-1` to wait +indefinitely. + +The `cancel` argument specifies the address of an integer variable that can be +set to a non-zero value to cancel the connection. Specify a value of `NULL` +to not provide a cancel variable. + +The `resource` and `resourcesize` arguments specify the address and size of a +character string array to hold the path to use when sending an IPP request. + +The `cb` and `user_data` arguments specify a destination callback function that +returns 1 to continue connecting or 0 to stop. The destination callback work +the same way as the one used for the `cupsEnumDests` function. + +On success, a HTTP connection is returned that can be used to send IPP requests +and get IPP responses. + +For example, the following code connects to the printer associated with a +destination with a 30 second timeout: + + char resource[256]; + http_t *http = cupsConnectDest(dest, CUPS_DEST_FLAGS_DEVICE, + 30000, NULL, resource, + sizeof(resource), NULL, NULL); + + +## Creating an IPP Request + +IPP requests are represented by the IPP message type `ipp_t` and each IPP +attribute in the request is representing using the type `ipp_attribute_t`. Each +IPP request includes an operation code (`IPP_OP_CREATE_JOB`, +`IPP_OP_GET_PRINTER_ATTRIBUTES`, etc.) and a 32-bit integer identifier. + +The `ippNewRequest` function creates a new IPP request: + + ipp_t * + ippNewRequest(ipp_op_t op); + +The `op` argument specifies the IPP operation code for the request. For +example, the following code creates an IPP Get-Printer-Attributes request: + + ipp_t *request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); + +The request identifier is automatically set to a unique value for the current +process. + +Each IPP request starts with two IPP attributes, "attributes-charset" and +"attributes-natural-language", followed by IPP attribute(s) that specify the +target of the operation. The `ippNewRequest` automatically adds the correct +"attributes-charset" and "attributes-natural-language" attributes, but you must +add the target attribute(s). For example, the following code adds the +"printer-uri" attribute to the IPP Get-Printer-Attributes request to specify +which printer is being queried: + + const char *printer_uri = cupsGetOption("device-uri", + dest->num_options, + dest->options); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, printer_uri); + +> Note: If we wanted to query the scheduler instead of the device, we would look +> up the "printer-uri-supported" option instead of the "device-uri" value. + +The `ippAddString` function adds the "printer-uri" attribute the the IPP +request. The `IPP_TAG_OPERATION` argument specifies that the attribute is part +of the operation. The `IPP_TAG_URI` argument specifies that the value is a +Universal Resource Identifier (URI) string. The `NULL` argument specifies there +is no language (English, French, Japanese, etc.) associated with the string, and +the `printer_uri` argument specifies the string value. + +The IPP Get-Printer-Attributes request also supports an IPP attribute called +"requested-attributes" that lists the attributes and values you are interested +in. For example, the following code requests the printer state attributes: + + static const char * const requested_attributes[] = + { + "printer-state", + "printer-state-message", + "printer-state-reasons" + }; + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", 3, NULL, + requested_attributes); + +The `ippAddStrings` function adds an attribute with one or more strings, in this +case three. The `IPP_TAG_KEYWORD` argument specifies that the strings are +keyword values, which are used for attribute names. All strings use the same +language (`NULL`), and the attribute will contain the three strings in the +array `requested_attributes`. + +CUPS provides many functions to adding attributes of different types: + +- `ippAddBoolean` adds a boolean (`IPP_TAG_BOOLEAN`) attribute with one value. +- `ippAddInteger` adds an enum (`IPP_TAG_ENUM`) or integer (`IPP_TAG_INTEGER`) + attribute with one value. +- `ippAddIntegers` adds an enum or integer attribute with one or more values. +- `ippAddOctetString` adds an octetString attribute with one value. +- `ippAddOutOfBand` adds a admin-defined (`IPP_TAG_ADMINDEFINE`), default + (`IPP_TAG_DEFAULT`), delete-attribute (`IPP_TAG_DELETEATTR`), no-value + (`IPP_TAG_NOVALUE`), not-settable (`IPP_TAG_NOTSETTABLE`), unknown + (`IPP_TAG_UNKNOWN`), or unsupported (`IPP_TAG_UNSUPPORTED_VALUE`) out-of-band + attribute. +- `ippAddRange` adds a rangeOfInteger attribute with one range. +- `ippAddRanges` adds a rangeOfInteger attribute with one or more ranges. +- `ippAddResolution` adds a resolution attribute with one resolution. +- `ippAddResolutions` adds a resolution attribute with one or more resolutions. +- `ippAddString` adds a charset (`IPP_TAG_CHARSET`), keyword (`IPP_TAG_KEYWORD`), + mimeMediaType (`IPP_TAG_MIMETYPE`), name (`IPP_TAG_NAME` and + `IPP_TAG_NAMELANG`), naturalLanguage (`IPP_TAG_NATURAL_LANGUAGE`), text + (`IPP_TAG_TEXT` and `IPP_TAG_TEXTLANG`), uri (`IPP_TAG_URI`), or uriScheme + (`IPP_TAG_URISCHEME`) attribute with one value. +- `ippAddStrings` adds a charset, keyword, mimeMediaType, name, naturalLanguage, + text, uri, or uriScheme attribute with one or more values. + + +## Sending the IPP Request + +Once you have created the IPP request, you can send it using the +`cupsDoRequest` function. For example, the following code sends the IPP +Get-Printer-Attributes request to the destination and saves the response: + + ipp_t *response = cupsDoRequest(http, request, resource); + +For requests like Send-Document that include a file, the `cupsDoFileRequest` +function should be used: + + ipp_t *response = cupsDoFileRequest(http, request, resource, + filename); + +Both `cupsDoRequest` and `cupsDoFileRequest` free the IPP request. If a valid +IPP response is received, it is stored in a new IPP message (`ipp_t`) and +returned to the caller. Otherwise `NULL` is returned. + +The status from the most recent request can be queried using the `cupsLastError` +function, for example: + + if (cupsLastError() >= IPP_STATUS_ERROR_BAD_REQUEST) + { + /* request failed */ + } + +A human-readable error message is also available using the `cupsLastErrorString` +function: + + if (cupsLastError() >= IPP_STATUS_ERROR_BAD_REQUEST) + { + /* request failed */ + printf("Request failed: %s\n", cupsLastErrorString()); + } + + +## Processing the IPP Response + +Each response to an IPP request is also an IPP message (`ipp_t`) with its own +IPP attributes (`ipp_attribute_t`) that includes a status code (`IPP_STATUS_OK`, +`IPP_STATUS_ERROR_BAD_REQUEST`, etc.) and the corresponding 32-bit integer +identifier from the request. + +For example, the following code finds the printer state attributes and prints +their values: + + ipp_attribute_t *attr; + + if ((attr = ippFindAttribute(response, "printer-state", + IPP_TAG_ENUM)) != NULL) + { + printf("printer-state=%s\n", + ippEnumString("printer-state", ippGetInteger(attr, 0))); + } + else + puts("printer-state=unknown"); + + if ((attr = ippFindAttribute(response, "printer-state-message", + IPP_TAG_TEXT)) != NULL) + { + printf("printer-state-message=\"%s\"\n", + ippGetString(attr, 0, NULL))); + } + + if ((attr = ippFindAttribute(response, "printer-state-reasons", + IPP_TAG_KEYWORD)) != NULL) + { + int i, count = ippGetCount(attr); + + puts("printer-state-reasons="); + for (i = 0; i < count; i ++) + printf(" %s\n", ippGetString(attr, i, NULL))); + } + +The `ippGetCount` function returns the number of values in an attribute. + +The `ippGetInteger` and `ippGetString` functions return a single integer or +string value from an attribute. + +The `ippEnumString` function converts a enum value to its keyword (string) +equivalent. + +Once you are done using the IPP response message, free it using the `ippDelete` +function: + + ippDelete(response); + + +## Authentication + +CUPS normally handles authentication through the console. GUI applications +should set a password callback using the `cupsSetPasswordCB2` function: + + void + cupsSetPasswordCB2(cups_password_cb2_t cb, void *user_data); + +The password callback will be called when needed and is responsible for setting +the current user name using `cupsSetUser` and returning a string: + + const char * + cups_password_cb2(const char *prompt, http_t *http, + const char *method, const char *resource, + void *user_data); + +The `prompt` argument is a string from CUPS that should be displayed to the +user. + +The `http` argument is the connection hosting the request that is being +authenticated. The password callback can call the `httpGetField` and +`httpGetSubField` functions to look for additional details concerning the +authentication challenge. + +The `method` argument specifies the HTTP method used for the request and is +typically "POST". + +The `resource` argument specifies the path used for the request. + +The `user_data` argument provides the user data pointer from the +`cupsSetPasswordCB2` call. diff --git a/cups/cupspm.opacity b/cups/cupspm.opacity new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/cups/cupspm.opacity diff --git a/cups/cupspm.png b/cups/cupspm.png new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/cups/cupspm.png diff --git a/cups/debug-private.h b/cups/debug-private.h index 23a0ae17..dc9fe4eb 100644 --- a/cups/debug-private.h +++ b/cups/debug-private.h @@ -1,7 +1,7 @@ /* * Private debugging macros for CUPS. * - * Copyright 2007-2012 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2005 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -67,20 +67,10 @@ extern "C" { */ # ifdef DEBUG -# ifdef WIN32 -# ifdef LIBCUPS2_EXPORTS -# define DLLExport __declspec(dllexport) -# else -# define DLLExport -# endif /* LIBCUPS2_EXPORTS */ -# else -# define DLLExport -# endif /* WIN32 */ # define DEBUG_puts(x) _cups_debug_puts(x) # define DEBUG_printf(x) _cups_debug_printf x # define DEBUG_set(logfile,level,filter) _cups_debug_set(logfile,level,filter,1) # else -# define DLLExport # define DEBUG_puts(x) # define DEBUG_printf(x) # define DEBUG_set(logfile,level,filter) @@ -93,16 +83,13 @@ extern "C" { extern int _cups_debug_fd; extern int _cups_debug_level; -extern void DLLExport _cups_debug_printf(const char *format, ...) - __attribute__ ((__format__ (__printf__, 1, 2))); -extern void DLLExport _cups_debug_puts(const char *s); -extern void DLLExport _cups_debug_set(const char *logfile, - const char *level, const char *filter, - int force); -# ifdef WIN32 -extern int _cups_gettimeofday(struct timeval *tv, void *tz); +extern void _cups_debug_printf(const char *format, ...) _CUPS_FORMAT(1, 2); +extern void _cups_debug_puts(const char *s); +extern void _cups_debug_set(const char *logfile, const char *level, const char *filter, int force) _CUPS_PRIVATE; +# ifdef _WIN32 +extern int _cups_gettimeofday(struct timeval *tv, void *tz) _CUPS_PRIVATE; # define gettimeofday(a,b) _cups_gettimeofday(a, b) -# endif /* WIN32 */ +# endif /* _WIN32 */ # ifdef __cplusplus } diff --git a/cups/debug.c b/cups/debug.c index bd244fe7..b68f5edb 100644 --- a/cups/debug.c +++ b/cups/debug.c @@ -18,7 +18,7 @@ #include "cups-private.h" #include "thread-private.h" -#ifdef WIN32 +#ifdef _WIN32 # include <sys/timeb.h> # include <time.h> # include <io.h> @@ -36,7 +36,7 @@ _cups_gettimeofday(struct timeval *tv, /* I - Timeval struct */ #else # include <sys/time.h> # include <unistd.h> -#endif /* WIN32 */ +#endif /* _WIN32 */ #include <regex.h> #include <fcntl.h> @@ -83,7 +83,7 @@ debug_thread_id(void) * '_cups_debug_printf()' - Write a formatted line to the log. */ -void DLLExport +void _cups_debug_printf(const char *format, /* I - Printf-style format string */ ...) /* I - Additional arguments as needed */ { @@ -168,7 +168,7 @@ _cups_debug_printf(const char *format, /* I - Printf-style format string */ * '_cups_debug_puts()' - Write a single line to the log. */ -void DLLExport +void _cups_debug_puts(const char *s) /* I - String to output */ { struct timeval curtime; /* Current time */ @@ -248,7 +248,7 @@ _cups_debug_puts(const char *s) /* I - String to output */ * '_cups_debug_set()' - Enable or disable debug logging. */ -void DLLExport +void _cups_debug_set(const char *logfile, /* I - Log file or NULL */ const char *level, /* I - Log level or NULL */ const char *filter, /* I - Filter string or NULL */ diff --git a/cups/dest-job.c b/cups/dest-job.c index b0d89b6e..f12b1dc5 100644 --- a/cups/dest-job.c +++ b/cups/dest-job.c @@ -1,7 +1,7 @@ /* * 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 @@ -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 */ @@ -84,6 +84,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... */ @@ -172,6 +179,13 @@ cupsCreateDestJob( "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... */ @@ -252,6 +266,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... */ @@ -307,6 +328,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 6d75a972..fceaad29 100644 --- a/cups/dest-localization.c +++ b/cups/dest-localization.c @@ -60,12 +60,15 @@ cupsLocalizeDestMedia( *ltype; /* Localized media type */ + DEBUG_printf(("cupsLocalizeDestMedia(http=%p, dest=%p, dinfo=%p, flags=%x, size=%p(\"%s\"))", (void *)http, (void *)dest, (void *)dinfo, flags, (void *)size, size ? size->media : "(null)")); + /* * Range check input... */ if (!http || !dest || !dinfo || !size) { + DEBUG_puts("1cupsLocalizeDestMedia: Returning NULL."); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(EINVAL), 0); return (NULL); } @@ -79,13 +82,24 @@ cupsLocalizeDestMedia( key.id = size->media; if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, &key)) != NULL) + { + DEBUG_printf(("1cupsLocalizeDestMedia: Returning \"%s\".", match->str)); return (match->str); + } /* * If not, get the localized size, source, and type strings... */ lang = cupsLangDefault(); + + snprintf(temp, sizeof(temp), "media.%s", size->media); + if ((lsize = _cupsLangString(lang, temp)) != NULL && strcmp(lsize, temp)) + { + DEBUG_printf(("1cupsLocalizeDestMedia: Returning standard localization \"%s\".", lsize)); + return (lsize); + } + pwg = pwgMediaForSize(size->width, size->length); if (pwg->ppd) @@ -101,7 +115,7 @@ cupsLocalizeDestMedia( * Use inches since the size is a multiple of 1/4 inch. */ - snprintf(temp, sizeof(temp), _cupsLangString(lang, _("%g x %g")), size->width / 2540.0, size->length / 2540.0); + snprintf(temp, sizeof(temp), _cupsLangString(lang, _("%g x %g \"")), size->width / 2540.0, size->length / 2540.0); } else { @@ -189,6 +203,8 @@ cupsLocalizeDestMedia( cupsArrayAdd(dinfo->localizations, match); + DEBUG_printf(("1cupsLocalizeDestMedia: Returning \"%s\".", match->str)); + return (match->str); } @@ -212,7 +228,10 @@ cupsLocalizeDestOption( { _cups_message_t key, /* Search key */ *match; /* Matching entry */ + const char *localized; /* Localized string */ + + DEBUG_printf(("cupsLocalizeDestOption(http=%p, dest=%p, dinfo=%p, option=\"%s\")", (void *)http, (void *)dest, (void *)dinfo, option)); if (!http || !dest || !dinfo) return (option); @@ -220,13 +239,12 @@ cupsLocalizeDestOption( if (!dinfo->localizations) cups_create_localizations(http, dinfo); - if (cupsArrayCount(dinfo->localizations) == 0) - return (option); - key.id = (char *)option; if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, &key)) != NULL) return (match->str); + else if ((localized = _cupsLangString(cupsLangDefault(), option)) != NULL) + return (localized); else return (option); } @@ -253,22 +271,40 @@ cupsLocalizeDestValue( _cups_message_t key, /* Search key */ *match; /* Matching entry */ char pair[256]; /* option.value pair */ + const char *localized; /* Localized string */ + DEBUG_printf(("cupsLocalizeDestValue(http=%p, dest=%p, dinfo=%p, option=\"%s\", value=\"%s\")", (void *)http, (void *)dest, (void *)dinfo, option, value)); + if (!http || !dest || !dinfo) return (value); + if (!strcmp(option, "media")) + { + pwg_media_t *media = pwgMediaForPWG(value); + cups_size_t size; + + strlcpy(size.media, value, sizeof(size.media)); + size.width = media ? media->width : 0; + size.length = media ? media->length : 0; + size.left = 0; + size.right = 0; + size.bottom = 0; + size.top = 0; + + return (cupsLocalizeDestMedia(http, dest, dinfo, CUPS_MEDIA_FLAGS_DEFAULT, &size)); + } + if (!dinfo->localizations) cups_create_localizations(http, dinfo); - if (cupsArrayCount(dinfo->localizations) == 0) - return (value); - snprintf(pair, sizeof(pair), "%s.%s", option, value); key.id = pair; if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations, &key)) != NULL) return (match->str); + else if ((localized = _cupsLangString(cupsLangDefault(), pair)) != NULL && strcmp(localized, pair)) + return (localized); else return (value); } diff --git a/cups/dest-options.c b/cups/dest-options.c index bf9020ba..51705a50 100644 --- a/cups/dest-options.c +++ b/cups/dest-options.c @@ -1,7 +1,7 @@ /* * 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 @@ -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 */ @@ -86,10 +86,17 @@ cupsCheckDestSupported( /* + * 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... */ @@ -316,6 +326,13 @@ cupsCopyDestConflicts( *resolved = NULL; /* + * Get the default connection as needed... + */ + + if (!http) + http = _cupsConnect(); + + /* * Range check input... */ @@ -575,6 +592,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... */ @@ -686,6 +710,13 @@ cupsFindDestDefault( /* + * Get the default connection as needed... + */ + + if (!http) + http = _cupsConnect(); + + /* * Range check input... */ @@ -727,6 +758,13 @@ cupsFindDestReady( /* + * Get the default connection as needed... + */ + + if (!http) + http = _cupsConnect(); + + /* * Range check input... */ @@ -770,6 +808,13 @@ cupsFindDestSupported( /* + * 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 @@ -852,6 +899,13 @@ cupsGetDestMediaByIndex( /* + * Get the default connection as needed... + */ + + if (!http) + http = _cupsConnect(); + + /* * Range check input... */ @@ -940,6 +994,13 @@ cupsGetDestMediaByName( /* + * Get the default connection as needed... + */ + + if (!http) + http = _cupsConnect(); + + /* * Range check input... */ @@ -1008,6 +1069,13 @@ cupsGetDestMediaBySize( /* + * Get the default connection as needed... + */ + + if (!http) + http = _cupsConnect(); + + /* * Range check input... */ @@ -1059,6 +1127,13 @@ cupsGetDestMediaCount( unsigned flags) /* I - Media flags */ { /* + * Get the default connection as needed... + */ + + if (!http) + http = _cupsConnect(); + + /* * Range check input... */ @@ -1104,6 +1179,13 @@ cupsGetDestMediaDefault( /* + * Get the default connection as needed... + */ + + if (!http) + http = _cupsConnect(); + + /* * Range check input... */ diff --git a/cups/dest.c b/cups/dest.c index b06a9ee1..7ef85a1b 100644 --- a/cups/dest.c +++ b/cups/dest.c @@ -1,7 +1,7 @@ /* * 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 @@ -60,6 +60,13 @@ # define kUseLastPrinter CFSTR("UseLastPrinter") #endif /* __APPLE__ */ +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) +# define _CUPS_DNSSD_GET_DESTS 250 /* Milliseconds for cupsGetDests */ +# define _CUPS_DNSSD_MAXTIME 50 /* Milliseconds for maximum quantum of time */ +#else +# define _CUPS_DNSSD_GET_DESTS 0 /* Milliseconds for cupsGetDests */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ + /* * Types... @@ -85,6 +92,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 +109,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 +123,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 +228,13 @@ 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_enum_dests(http_t *http, unsigned flags, int msec, int *cancel, cups_ptype_t type, cups_ptype_t mask, cups_dest_cb_t cb, void *user_data); 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 +242,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 +574,24 @@ _cupsAppleSetUseLastPrinter( /* - * 'cupsConnectDest()' - Connect to the server for a destination. + * 'cupsConnectDest()' - Open a conection to the destination. + * + * 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. * - * 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. + * 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 +639,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 +763,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 +805,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,334 +950,36 @@ _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 */ - cups_dest_t *dests = NULL, /* Destinations */ - *dest; /* Current destination */ - const char *defprinter; /* Default printer */ - char name[1024], /* Copy of printer name */ - *instance, /* Pointer to instance name */ - *user_default; /* User default printer */ -#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) - int count, /* Number of queries started */ - remaining; /* Remainder of timeout */ - _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 */ -# ifdef HAVE_SSL - DNSServiceRef ipps_ref, /* IPPS browser */ - local_ipps_ref; /* Local IPPS browser */ -# endif /* HAVE_SSL */ -# ifdef HAVE_POLL - struct pollfd pfd; /* Polling data */ -# else - fd_set input; /* Input set for select() */ - struct timeval timeout; /* Timeout for select() */ -# endif /* HAVE_POLL */ -# else /* HAVE_AVAHI */ - int error; /* Error value */ - AvahiServiceBrowser *ipp_ref; /* IPP browser */ -# ifdef HAVE_SSL - AvahiServiceBrowser *ipps_ref; /* IPPS browser */ -# endif /* HAVE_SSL */ -# endif /* HAVE_DNSSD */ -#endif /* HAVE_DNSSD || HAVE_AVAHI */ - - /* - * Range check input... - */ - - (void)flags; - - if (!cb) - return (0); - - /* - * 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 | 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... - */ - - 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); - -# ifdef HAVE_DNSSD - if (DNSServiceCreateConnection(&data.main_ref) != kDNSServiceErr_NoError) - return (0); - - main_fd = DNSServiceRefSockFD(data.main_ref); - - ipp_ref = data.main_ref; - DNSServiceBrowse(&ipp_ref, kDNSServiceFlagsShareConnection, 0, - "_ipp._tcp", NULL, - (DNSServiceBrowseReply)cups_dnssd_browse_cb, &data); - - local_ipp_ref = data.main_ref; - DNSServiceBrowse(&local_ipp_ref, kDNSServiceFlagsShareConnection, - kDNSServiceInterfaceIndexLocalOnly, - "_ipp._tcp", NULL, - (DNSServiceBrowseReply)cups_dnssd_local_cb, &data); - -# ifdef HAVE_SSL - ipps_ref = data.main_ref; - DNSServiceBrowse(&ipps_ref, kDNSServiceFlagsShareConnection, 0, - "_ipps._tcp", NULL, - (DNSServiceBrowseReply)cups_dnssd_browse_cb, &data); - - local_ipps_ref = data.main_ref; - DNSServiceBrowse(&local_ipps_ref, kDNSServiceFlagsShareConnection, - kDNSServiceInterfaceIndexLocalOnly, - "_ipps._tcp", NULL, - (DNSServiceBrowseReply)cups_dnssd_local_cb, &data); -# endif /* HAVE_SSL */ - -# else /* HAVE_AVAHI */ - if ((data.simple_poll = avahi_simple_poll_new()) == NULL) - { - DEBUG_puts("cupsEnumDests: Unable to create Avahi simple poll object."); - return (1); - } - - avahi_simple_poll_set_func(data.simple_poll, cups_dnssd_poll_cb, &data); - - data.client = avahi_client_new(avahi_simple_poll_get(data.simple_poll), - 0, cups_dnssd_client_cb, &data, - &error); - if (!data.client) - { - DEBUG_puts("cupsEnumDests: Unable to create Avahi client."); - avahi_simple_poll_free(data.simple_poll); - 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); -# 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); -# endif /* HAVE_SSL */ -# endif /* HAVE_DNSSD */ - - if (msec < 0) - remaining = INT_MAX; - else - remaining = msec; - - while (remaining > 0 && (!cancel || !*cancel)) - { - /* - * Check for input... - */ - -# ifdef HAVE_DNSSD -# ifdef HAVE_POLL - pfd.fd = main_fd; - pfd.events = POLLIN; - - nfds = poll(&pfd, 1, remaining > 250 ? 250 : remaining); - -# else - FD_ZERO(&input); - FD_SET(main_fd, &input); - - timeout.tv_sec = 0; - timeout.tv_usec = remaining > 250 ? 250000 : remaining * 1000; - - 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) - { - /* - * We've been told to exit the loop. Perhaps the connection to - * Avahi failed. - */ - - break; - } - - if (!data.got_data) - remaining -= 250; -# endif /* HAVE_DNSSD */ - - for (device = (_cups_dnssd_device_t *)cupsArrayFirst(data.devices), - count = 0; - device; - device = (_cups_dnssd_device_t *)cupsArrayNext(data.devices)) - { - if (device->ref) - count ++; - - if (!device->ref && device->state == _CUPS_DNSSD_NEW) - { - DEBUG_printf(("1cupsEnumDests: Querying '%s'.", device->fullName)); - -# ifdef HAVE_DNSSD - device->ref = data.main_ref; - - if (DNSServiceQueryRecord(&(device->ref), - kDNSServiceFlagsShareConnection, - 0, device->fullName, - kDNSServiceType_TXT, - kDNSServiceClass_IN, - (DNSServiceQueryRecordReply)cups_dnssd_query_cb, - &data) == kDNSServiceErr_NoError) - { - count ++; - } - else - { - device->ref = 0; - device->state = _CUPS_DNSSD_ERROR; - - DEBUG_puts("1cupsEnumDests: Query failed."); - } - -# 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) - { - count ++; - } - else - { - device->state = _CUPS_DNSSD_ERROR; - - 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) - { - if ((device->type & mask) == type) - { - if (!(*cb)(user_data, CUPS_DEST_FLAGS_NONE, &device->dest)) - { - remaining = -1; - break; - } - } - - device->state = _CUPS_DNSSD_ACTIVE; - } - } - } - - cupsArrayDelete(data.devices); - -# ifdef HAVE_DNSSD - DNSServiceRefDeallocate(ipp_ref); - DNSServiceRefDeallocate(local_ipp_ref); - -# ifdef HAVE_SSL - DNSServiceRefDeallocate(ipp_ref); - DNSServiceRefDeallocate(local_ipp_ref); -# endif /* HAVE_SSL */ - - DNSServiceRefDeallocate(data.main_ref); - -# else /* HAVE_AVAHI */ - avahi_service_browser_free(ipp_ref); -# ifdef HAVE_SSL - avahi_service_browser_free(ipps_ref); -# endif /* HAVE_SSL */ - - avahi_client_free(data.client); - avahi_simple_poll_free(data.simple_poll); -# endif /* HAVE_DNSSD */ -#endif /* HAVE_DNSSD || HAVE_DNSSD */ - - return (1); + return (cups_enum_dests(CUPS_HTTP_DEFAULT, flags, msec, cancel, type, mask, cb, user_data)); } @@ -1242,15 +987,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 +1051,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 +1116,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 +1135,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 +1214,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 +1236,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 +1252,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 +1290,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 +1364,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,12 +1377,15 @@ _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... */ appleGetPaperSize(media_default, sizeof(media_default)); + DEBUG_printf(("1_cupsGetDests: Default media is '%s'.", media_default)); #endif /* __APPLE__ */ /* @@ -1678,7 +1472,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") || @@ -1699,7 +1494,7 @@ _cupsGetDests(http_t *http, /* I - Connection to server or num_options, &options); } #ifdef __APPLE__ - else if (!strcmp(attr->name, "media-supported")) + else if (!strcmp(attr->name, "media-supported") && media_default[0]) { /* * See if we can set a default media size... @@ -1710,8 +1505,8 @@ _cupsGetDests(http_t *http, /* I - Connection to server or for (i = 0; i < attr->num_values; i ++) if (!_cups_strcasecmp(media_default, attr->values[i].string.text)) { - num_options = cupsAddOption("media", media_default, num_options, - &options); + DEBUG_printf(("1_cupsGetDests: Setting media to '%s'.", media_default)); + num_options = cupsAddOption("media", media_default, num_options, &options); break; } } @@ -1720,7 +1515,8 @@ _cupsGetDests(http_t *http, /* I - Connection to server or attr->value_tag == IPP_TAG_NAME) printer_name = attr->values[0].string.text; else if (strncmp(attr->name, "notify-", 7) && - (attr->value_tag == IPP_TAG_BOOLEAN || + strncmp(attr->name, "print-quality-", 14) && + (attr->value_tag == IPP_TAG_BOOLEAN || attr->value_tag == IPP_TAG_ENUM || attr->value_tag == IPP_TAG_INTEGER || attr->value_tag == IPP_TAG_KEYWORD || @@ -1735,12 +1531,8 @@ _cupsGetDests(http_t *http, /* I - Connection to server or strlcpy(optname, attr->name, sizeof(optname)); optname[ptr - attr->name] = '\0'; - if (_cups_strcasecmp(optname, "media") || - !cupsGetOption("media", num_options, options)) - num_options = cupsAddOption(optname, - cups_make_string(attr, value, - sizeof(value)), - num_options, &options); + if (_cups_strcasecmp(optname, "media") || !cupsGetOption("media", num_options, options)) + num_options = cupsAddOption(optname, cups_make_string(attr, value, sizeof(value)), num_options, &options); } } @@ -1785,15 +1577,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 +1607,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 +1630,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 */ @@ -1837,41 +1643,70 @@ cupsGetDests2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ - /* + DEBUG_printf(("cupsGetDests2(http=%p, dests=%p)", (void *)http, (void *)dests)); + +/* * Range check the input... */ if (!dests) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad NULL dests pointer"), 1); + DEBUG_puts("1cupsGetDests2: NULL dests pointer, returning 0."); return (0); } /* + * Connect to the server as needed... + */ + + if (!http) + { + if ((http = _cupsConnect()) == NULL) + { + *dests = NULL; + + return (0); + } + } + + /* * 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; - if (cupsLastError() >= IPP_STATUS_REDIRECTION_OTHER_SITE) + if (!httpAddrLocalhost(httpGetAddress(http))) { - cupsFreeDests(num_dests, *dests); - *dests = (cups_dest_t *)0; - return (0); + /* + * When talking to a remote cupsd, just enumerate printers on the remote + * cupsd. + */ + + cups_enum_dests(http, 0, _CUPS_DNSSD_GET_DESTS, NULL, 0, CUPS_PRINTER_DISCOVERED, (cups_dest_cb_t)cups_get_cb, &data); + } + else + { + /* + * When talking to a local cupsd, enumerate both local printers and ones we + * can find on the network... + */ + + cups_enum_dests(http, 0, _CUPS_DNSSD_GET_DESTS, NULL, 0, 0, (cups_dest_cb_t)cups_get_cb, &data); } /* * 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 +1741,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 +1752,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 +1773,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 +1786,7 @@ cupsGetDests2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_ * going to an unexpected printer... (<rdar://problem/14216472>) */ - 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 +1801,14 @@ 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); + DEBUG_printf(("1cupsGetDests2: Returning %d destinations.", data.num_dests)); + + return (data.num_dests); } @@ -1980,10 +1816,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 +1838,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 +1849,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,36 +1882,60 @@ 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) + if (!dest_name) { /* * 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 +1948,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 +2058,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 @@ -2223,9 +2090,9 @@ cupsSetDests2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_ cups_option_t *option; /* Current option */ _ipp_option_t *match; /* Matching attribute for option */ FILE *fp; /* File pointer */ -#ifndef WIN32 +#ifndef _WIN32 const char *home; /* HOME environment variable */ -#endif /* WIN32 */ +#endif /* _WIN32 */ char filename[1024]; /* lpoptions file */ int num_temps; /* Number of temporary destinations */ cups_dest_t *temps = NULL, /* Temporary destinations */ @@ -2245,7 +2112,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) { @@ -2259,7 +2126,7 @@ cupsSetDests2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_ snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot); -#ifndef WIN32 +#ifndef _WIN32 if (getuid()) { /* @@ -2285,7 +2152,7 @@ cupsSetDests2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_ snprintf(filename, sizeof(filename), "%s/.cups/lpoptions", home); } } -#endif /* !WIN32 */ +#endif /* !_WIN32 */ /* * Try to open the file... @@ -2297,7 +2164,7 @@ cupsSetDests2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_ return (-1); } -#ifndef WIN32 +#ifndef _WIN32 /* * Set the permissions to 0644 when saving to the /etc/cups/lpoptions * file... @@ -2305,7 +2172,7 @@ cupsSetDests2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_ if (!getuid()) fchmod(fileno(fp), 0644); -#endif /* !WIN32 */ +#endif /* !_WIN32 */ /* * Write each printer; each line looks like: @@ -2839,11 +2706,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 +2726,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 +2738,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 +2766,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 +2837,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 +2848,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 +2911,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 +2925,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 +2946,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 +3006,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 +3022,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 +3039,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 +3103,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 +3121,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 +3130,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 +3140,16 @@ cups_dnssd_query_cb( * Lookup the service in the devices array. */ - dkey.dest.name = name; - - cups_dnssd_unquote(name, fullName, sizeof(name)); + cups_dnssd_unquote(serviceName, fullName, sizeof(serviceName)); - 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 +3166,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 +3285,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 +3341,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 +3428,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 +3505,476 @@ 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_enum_dests()' - Enumerate destinations from a specific server. + */ + +static int /* O - 1 on success, 0 on failure */ +cups_enum_dests( + http_t *http, /* I - Connection to scheduler */ + 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 */ + cups_dest_t *dests = NULL, /* Destinations */ + *dest; /* Current destination */ + const char *defprinter; /* Default printer */ + char name[1024], /* Copy of printer name */ + *instance, /* Pointer to instance name */ + *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 = NULL, /* IPP browser */ + local_ipp_ref = NULL; /* Local IPP browser */ +# ifdef HAVE_SSL + DNSServiceRef ipps_ref = NULL, /* IPPS browser */ + local_ipps_ref = NULL; /* Local IPPS browser */ +# endif /* HAVE_SSL */ +# ifdef HAVE_POLL + struct pollfd pfd; /* Polling data */ +# else + fd_set input; /* Input set for select() */ + struct timeval timeout; /* Timeout for select() */ +# endif /* HAVE_POLL */ +# else /* HAVE_AVAHI */ + int error; /* Error value */ + AvahiServiceBrowser *ipp_ref = NULL; /* IPP browser */ +# ifdef HAVE_SSL + AvahiServiceBrowser *ipps_ref = NULL; /* IPPS browser */ +# endif /* HAVE_SSL */ +# endif /* HAVE_DNSSD */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ + + + DEBUG_printf(("cups_enum_dests(flags=%x, msec=%d, cancel=%p, type=%x, mask=%x, cb=%p, user_data=%p)", flags, msec, (void *)cancel, type, mask, (void *)cb, (void *)user_data)); + + /* + * Range check input... + */ + + (void)flags; + + if (!cb) + { + DEBUG_puts("1cups_enum_dests: No callback, returning 0."); + return (0); + } + + /* + * Get ready to enumerate... + */ + +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) + 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(http, IPP_OP_CUPS_GET_PRINTERS, NULL, &dests, type, mask); + + if ((user_default = _cupsUserDefault(name, sizeof(name))) != NULL) + defprinter = name; + else if ((defprinter = cupsGetDefault2(http)) != 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) + { + DEBUG_puts("1cups_enum_dests: Unable to create service browser, returning 0."); + return (0); + } + + main_fd = DNSServiceRefSockFD(data.main_ref); + + ipp_ref = data.main_ref; + if (DNSServiceBrowse(&ipp_ref, kDNSServiceFlagsShareConnection, 0, "_ipp._tcp", NULL, (DNSServiceBrowseReply)cups_dnssd_browse_cb, &data) != kDNSServiceErr_NoError) + { + DEBUG_puts("1cups_enum_dests: Unable to create IPP browser, returning 0."); + DNSServiceRefDeallocate(data.main_ref); + return (0); + } + + local_ipp_ref = data.main_ref; + if (DNSServiceBrowse(&local_ipp_ref, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexLocalOnly, "_ipp._tcp", NULL, (DNSServiceBrowseReply)cups_dnssd_local_cb, &data) != kDNSServiceErr_NoError) + { + DEBUG_puts("1cups_enum_dests: Unable to create local IPP browser, returning 0."); + DNSServiceRefDeallocate(data.main_ref); + return (0); + } + +# ifdef HAVE_SSL + ipps_ref = data.main_ref; + if (DNSServiceBrowse(&ipps_ref, kDNSServiceFlagsShareConnection, 0, "_ipps._tcp", NULL, (DNSServiceBrowseReply)cups_dnssd_browse_cb, &data) != kDNSServiceErr_NoError) + { + DEBUG_puts("1cups_enum_dests: Unable to create IPPS browser, returning 0."); + DNSServiceRefDeallocate(data.main_ref); + return (0); + } + + local_ipps_ref = data.main_ref; + if (DNSServiceBrowse(&local_ipps_ref, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexLocalOnly, "_ipps._tcp", NULL, (DNSServiceBrowseReply)cups_dnssd_local_cb, &data) != kDNSServiceErr_NoError) + { + DEBUG_puts("1cups_enum_dests: Unable to create local IPPS browser, returning 0."); + DNSServiceRefDeallocate(data.main_ref); + return (0); + } +# endif /* HAVE_SSL */ + +# else /* HAVE_AVAHI */ + if ((data.simple_poll = avahi_simple_poll_new()) == NULL) + { + DEBUG_puts("1cups_enum_dests: Unable to create Avahi poll, returning 0."); + return (0); + } + + avahi_simple_poll_set_func(data.simple_poll, cups_dnssd_poll_cb, &data); + + data.client = avahi_client_new(avahi_simple_poll_get(data.simple_poll), + 0, cups_dnssd_client_cb, &data, + &error); + if (!data.client) + { + DEBUG_puts("1cups_enum_dests: Unable to create Avahi client, returning 0."); + avahi_simple_poll_free(data.simple_poll); + return (0); + } + + data.browsers = 1; + if ((ipp_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_ipp._tcp", NULL, 0, cups_dnssd_browse_cb, &data)) == NULL) + { + DEBUG_puts("1cups_enum_dests: Unable to create Avahi IPP browser, returning 0."); + + avahi_client_free(data.client); + avahi_simple_poll_free(data.simple_poll); + return (0); + } + +# ifdef HAVE_SSL + data.browsers ++; + if ((ipps_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_ipps._tcp", NULL, 0, cups_dnssd_browse_cb, &data)) == NULL) + { + DEBUG_puts("1cups_enum_dests: Unable to create Avahi IPPS browser, returning 0."); + + avahi_service_browser_free(ipp_ref); + avahi_client_free(data.client); + avahi_simple_poll_free(data.simple_poll); + return (0); + } +# endif /* HAVE_SSL */ +# endif /* HAVE_DNSSD */ + + if (msec < 0) + remaining = INT_MAX; + else + remaining = msec; + + while (remaining > 0 && (!cancel || !*cancel)) + { + /* + * Check for input... + */ + + DEBUG_printf(("1cups_enum_dests: remaining=%d", remaining)); + + cups_elapsed(&curtime); + +# ifdef HAVE_DNSSD +# ifdef HAVE_POLL + pfd.fd = main_fd; + pfd.events = POLLIN; + + 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 = 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 && errno != EINTR && errno != EAGAIN) + break; + +# else /* HAVE_AVAHI */ + data.got_data = 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 + * Avahi failed. + */ + + break; + } + + DEBUG_printf(("1cups_enum_dests: got_data=%d", data.got_data)); +# endif /* HAVE_DNSSD */ + + remaining -= cups_elapsed(&curtime); + + for (device = (_cups_dnssd_device_t *)cupsArrayFirst(data.devices), + 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(("1cups_enum_dests: Querying '%s'.", device->fullName)); + +# ifdef HAVE_DNSSD + device->ref = data.main_ref; + + if (DNSServiceQueryRecord(&(device->ref), kDNSServiceFlagsShareConnection, 0, device->fullName, kDNSServiceType_TXT, kDNSServiceClass_IN, (DNSServiceQueryRecordReply)cups_dnssd_query_cb, &data) == kDNSServiceErr_NoError) + { + count ++; + } + else + { + device->ref = 0; + device->state = _CUPS_DNSSD_ERROR; + + DEBUG_puts("1cups_enum_dests: Query failed."); + } + +# 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) + { + DEBUG_printf(("1cups_enum_dests: Query ref=%p", device->ref)); + count ++; + } + else + { + device->state = _CUPS_DNSSD_ERROR; + + DEBUG_printf(("1cups_enum_dests: 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(("1cups_enum_dests: Query for \"%s\" is complete.", device->fullName)); + + if ((device->type & mask) == type) + { + DEBUG_printf(("1cups_enum_dests: Add callback for \"%s\".", device->dest.name)); + if (!(*cb)(user_data, CUPS_DEST_FLAGS_NONE, &device->dest)) + { + remaining = -1; + break; + } + } + + device->state = _CUPS_DNSSD_ACTIVE; + } + } + +# ifdef HAVE_AVAHI + DEBUG_printf(("1cups_enum_dests: 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(("1cups_enum_dests: 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 + if (ipp_ref) + DNSServiceRefDeallocate(ipp_ref); + if (local_ipp_ref) + DNSServiceRefDeallocate(local_ipp_ref); + +# ifdef HAVE_SSL + if (ipps_ref) + DNSServiceRefDeallocate(ipps_ref); + if (local_ipps_ref) + DNSServiceRefDeallocate(local_ipps_ref); +# endif /* HAVE_SSL */ + + if (data.main_ref) + DNSServiceRefDeallocate(data.main_ref); + +# else /* HAVE_AVAHI */ + if (ipp_ref) + avahi_service_browser_free(ipp_ref); +# ifdef HAVE_SSL + if (ipps_ref) + avahi_service_browser_free(ipps_ref); +# endif /* HAVE_SSL */ + + 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_AVAHI */ + + DEBUG_puts("1cups_enum_dests: Returning 1."); + + return (1); +} + + /* * 'cups_find_dest()' - Find a destination using a binary search. */ @@ -3724,6 +4079,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 +4412,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'; +} @@ -3,7 +3,7 @@ * * 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 @@ -26,7 +26,7 @@ * Windows implementation... */ -#ifdef WIN32 +#ifdef _WIN32 # include <windows.h> /* @@ -145,7 +145,7 @@ cupsDirOpen(const char *directory) /* I - Directory name */ cups_dentry_t * /* O - Directory entry or @code NULL@ if there are no more */ cupsDirRead(cups_dir_t *dp) /* I - Directory pointer */ { - WIN32_FIND_DATA entry; /* Directory entry data */ + WIN32_FIND_DATAA entry; /* Directory entry data */ /* @@ -165,11 +165,11 @@ cupsDirRead(cups_dir_t *dp) /* I - Directory pointer */ * No, find the first file... */ - dp->dir = FindFirstFile(dp->directory, &entry); + dp->dir = FindFirstFileA(dp->directory, &entry); if (dp->dir == INVALID_HANDLE_VALUE) return (NULL); } - else if (!FindNextFile(dp->dir, &entry)) + else if (!FindNextFileA(dp->dir, &entry)) return (NULL); /* @@ -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 ".."... */ @@ -449,4 +422,4 @@ cupsDirRewind(cups_dir_t *dp) /* I - Directory pointer */ rewinddir(dp->dir); } -#endif /* WIN32 */ +#endif /* _WIN32 */ diff --git a/cups/encode.c b/cups/encode.c index e60aec0d..94695d08 100644 --- a/cups/encode.c +++ b/cups/encode.c @@ -1,7 +1,7 @@ /* * 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 @@ -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 b8ca431f..6789283e 100644 --- a/cups/file-private.h +++ b/cups/file-private.h @@ -4,9 +4,9 @@ * 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-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -31,13 +31,10 @@ # include <stdarg.h> # include <fcntl.h> -# ifdef HAVE_LIBZ -# include <zlib.h> -# endif /* HAVE_LIBZ */ -# ifdef WIN32 +# ifdef _WIN32 # include <io.h> # include <sys/locking.h> -# endif /* WIN32 */ +# endif /* _WIN32 */ /* @@ -88,30 +85,6 @@ typedef enum /**** _cupsFileCheck file type values ****/ typedef void (*_cups_fc_func_t)(void *context, _cups_fc_result_t result, const char *message); -struct _cups_file_s /**** CUPS file structure... ****/ - -{ - int fd; /* File descriptor */ - char mode, /* Mode ('r' or 'w') */ - compressed, /* Compression used? */ - is_stdio, /* stdin/out/err? */ - eof, /* End of file? */ - buf[4096], /* Buffer */ - *ptr, /* Pointer into buffer */ - *end; /* End of buffer data */ - off_t pos, /* Position in file */ - bufpos; /* File position for start of buffer */ - -#ifdef HAVE_LIBZ - z_stream stream; /* (De)compression stream */ - Bytef cbuf[4096]; /* (De)compression buffer */ - uLong crc; /* (De)compression CRC */ -#endif /* HAVE_LIBZ */ - - char *printf_buffer; /* cupsFilePrintf buffer */ - size_t printf_size; /* Size of cupsFilePrintf buffer */ -}; - /* * Prototypes... @@ -125,6 +98,7 @@ extern _cups_fc_result_t _cupsFileCheck(const char *filename, extern void _cupsFileCheckFilter(void *context, _cups_fc_result_t result, const char *message); +extern int _cupsFilePeekAhead(cups_file_t *fp, int ch); # ifdef __cplusplus } diff --git a/cups/file.c b/cups/file.c index a027df40..5c9ddf8f 100644 --- a/cups/file.c +++ b/cups/file.c @@ -4,9 +4,9 @@ * 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-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -26,6 +26,39 @@ #include <sys/stat.h> #include <sys/types.h> +# ifdef HAVE_LIBZ +# include <zlib.h> +# endif /* HAVE_LIBZ */ + + +/* + * Internal structures... + */ + +struct _cups_file_s /**** CUPS file structure... ****/ + +{ + int fd; /* File descriptor */ + char mode, /* Mode ('r' or 'w') */ + compressed, /* Compression used? */ + is_stdio, /* stdin/out/err? */ + eof, /* End of file? */ + buf[4096], /* Buffer */ + *ptr, /* Pointer into buffer */ + *end; /* End of buffer data */ + off_t pos, /* Position in file */ + bufpos; /* File position for start of buffer */ + +#ifdef HAVE_LIBZ + z_stream stream; /* (De)compression stream */ + Bytef cbuf[4096]; /* (De)compression buffer */ + uLong crc; /* (De)compression CRC */ +#endif /* HAVE_LIBZ */ + + char *printf_buffer; /* cupsFilePrintf buffer */ + size_t printf_size; /* Size of cupsFilePrintf buffer */ +}; + /* * Local functions... @@ -40,7 +73,7 @@ static ssize_t cups_read(cups_file_t *fp, char *buf, size_t bytes); static ssize_t cups_write(cups_file_t *fp, const char *buf, size_t bytes); -#ifndef WIN32 +#ifndef _WIN32 /* * '_cupsFileCheck()' - Check the permissions of the given filename. */ @@ -306,7 +339,7 @@ _cupsFileCheckFilter( fprintf(stderr, "%s: %s\n", prefix, message); } -#endif /* !WIN32 */ +#endif /* !_WIN32 */ /* @@ -321,7 +354,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 +442,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 +470,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); } @@ -523,22 +559,22 @@ cupsFileFind(const char *filename, /* I - File to find */ while (*path) { -#ifdef WIN32 +#ifdef _WIN32 if (*path == ';' || (*path == ':' && ((bufptr - buffer) > 1 || !isalpha(buffer[0] & 255)))) #else if (*path == ';' || *path == ':') -#endif /* WIN32 */ +#endif /* _WIN32 */ { if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend) *bufptr++ = '/'; strlcpy(bufptr, filename, (size_t)(bufend - bufptr)); -#ifdef WIN32 +#ifdef _WIN32 if (!access(buffer, 0)) #else if (!access(buffer, executable ? X_OK : 0)) -#endif /* WIN32 */ +#endif /* _WIN32 */ { DEBUG_printf(("1cupsFileFind: Returning \"%s\"", buffer)); return (buffer); @@ -989,11 +1025,11 @@ cupsFileLock(cups_file_t *fp, /* I - CUPS file */ * Try the lock... */ -#ifdef WIN32 +#ifdef _WIN32 return (_locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0)); #else return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0)); -#endif /* WIN32 */ +#endif /* _WIN32 */ } @@ -1081,11 +1117,11 @@ cupsFileOpen(const char *filename, /* I - Name of file */ } if (fd >= 0) -#ifdef WIN32 +#ifdef _WIN32 _chsize(fd, 0); #else ftruncate(fd, 0); -#endif /* WIN32 */ +#endif /* _WIN32 */ break; case 's' : /* Read/write socket */ @@ -1252,15 +1288,27 @@ cupsFileOpenFd(int fd, /* I - File descriptor */ * Don't pass this file to child processes... */ -#ifndef WIN32 +#ifndef _WIN32 fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC); -#endif /* !WIN32 */ +#endif /* !_WIN32 */ return (fp); } /* + * '_cupsFilePeekAhead()' - See if the requested character is buffered up. + */ + +int /* O - 1 if present, 0 otherwise */ +_cupsFilePeekAhead(cups_file_t *fp, /* I - CUPS file */ + int ch) /* I - Character */ +{ + return (fp && fp->ptr && memchr(fp->ptr, ch, (size_t)(fp->end - fp->ptr))); +} + + +/* * 'cupsFilePeekChar()' - Peek at the next character from a file. * * @since CUPS 1.2/macOS 10.5@ @@ -1384,7 +1432,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 +1615,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); } } @@ -2008,11 +2064,11 @@ cupsFileUnlock(cups_file_t *fp) /* I - CUPS file */ * Unlock... */ -#ifdef WIN32 +#ifdef _WIN32 return (_locking(fp->fd, _LK_UNLCK, 0)); #else return (lockf(fp->fd, F_ULOCK, 0)); -#endif /* WIN32 */ +#endif /* _WIN32 */ } @@ -2466,6 +2522,8 @@ cups_fill(cups_file_t *fp) /* I - CUPS file */ * file header... */ + inflateEnd(&fp->stream); + fp->compressed = 0; } else if (status < Z_OK) @@ -2540,9 +2598,9 @@ cups_open(const char *filename, /* I - Filename */ { int fd; /* File descriptor */ struct stat fileinfo; /* File information */ -#ifndef WIN32 +#ifndef _WIN32 struct stat linkinfo; /* Link information */ -#endif /* !WIN32 */ +#endif /* !_WIN32 */ /* @@ -2570,18 +2628,18 @@ cups_open(const char *filename, /* I - Filename */ return (-1); } -#ifdef WIN32 +#ifdef _WIN32 if (fileinfo.st_mode & _S_IFDIR) #else if (S_ISDIR(fileinfo.st_mode)) -#endif /* WIN32 */ +#endif /* _WIN32 */ { close(fd); errno = EISDIR; return (-1); } -#ifndef WIN32 +#ifndef _WIN32 /* * Then use lstat to determine whether the filename is a symlink... */ @@ -2609,7 +2667,7 @@ cups_open(const char *filename, /* I - Filename */ errno = EPERM; return (-1); } -#endif /* !WIN32 */ +#endif /* !_WIN32 */ return (fd); } @@ -2635,7 +2693,7 @@ cups_read(cups_file_t *fp, /* I - CUPS file */ for (;;) { -#ifdef WIN32 +#ifdef _WIN32 if (fp->mode == 's') total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0); else @@ -2645,7 +2703,7 @@ cups_read(cups_file_t *fp, /* I - CUPS file */ total = recv(fp->fd, buf, bytes, 0); else total = read(fp->fd, buf, bytes); -#endif /* WIN32 */ +#endif /* _WIN32 */ DEBUG_printf(("9cups_read: total=" CUPS_LLFMT, CUPS_LLCAST total)); @@ -2692,7 +2750,7 @@ cups_write(cups_file_t *fp, /* I - CUPS file */ total = 0; while (bytes > 0) { -#ifdef WIN32 +#ifdef _WIN32 if (fp->mode == 's') count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0); else @@ -2702,7 +2760,7 @@ cups_write(cups_file_t *fp, /* I - CUPS file */ count = send(fp->fd, buf, bytes, 0); else count = write(fp->fd, buf, bytes); -#endif /* WIN32 */ +#endif /* _WIN32 */ DEBUG_printf(("9cups_write: count=" CUPS_LLFMT, CUPS_LLCAST count)); diff --git a/cups/file.h b/cups/file.h index 177c2e90..0d3a2e5d 100644 --- a/cups/file.h +++ b/cups/file.h @@ -4,9 +4,9 @@ * 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-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -29,11 +29,11 @@ # include "versioning.h" # include <stddef.h> # include <sys/types.h> -# if defined(WIN32) && !defined(__CUPS_SSIZE_T_DEFINED) +# if defined(_WIN32) && !defined(__CUPS_SSIZE_T_DEFINED) # define __CUPS_SSIZE_T_DEFINED /* Windows does not support the ssize_t type, so map it to off_t... */ typedef off_t ssize_t; /* @private@ */ -# endif /* WIN32 && !__CUPS_SSIZE_T_DEFINED */ +# endif /* _WIN32 && !__CUPS_SSIZE_T_DEFINED */ /* @@ -85,9 +85,7 @@ extern cups_file_t *cupsFileOpen(const char *filename, const char *mode) _CUPS_API_1_2; extern cups_file_t *cupsFileOpenFd(int fd, const char *mode) _CUPS_API_1_2; extern int cupsFilePeekChar(cups_file_t *fp) _CUPS_API_1_2; -extern int cupsFilePrintf(cups_file_t *fp, const char *format, ...) - __attribute__((__format__ (__printf__, 2, 3))) - _CUPS_API_1_2; +extern int cupsFilePrintf(cups_file_t *fp, const char *format, ...) _CUPS_FORMAT(2, 3) _CUPS_API_1_2; extern int cupsFilePutChar(cups_file_t *fp, int c) _CUPS_API_1_2; extern ssize_t cupsFilePutConf(cups_file_t *fp, const char *directive, const char *value) _CUPS_API_1_4; diff --git a/cups/getputfile.c b/cups/getputfile.c index ae33bc59..7749ae0a 100644 --- a/cups/getputfile.c +++ b/cups/getputfile.c @@ -1,7 +1,7 @@ /* * Get/put file functions for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -20,11 +20,11 @@ #include "cups-private.h" #include <fcntl.h> #include <sys/stat.h> -#if defined(WIN32) || defined(__EMX__) +#if defined(_WIN32) || defined(__EMX__) # include <io.h> #else # include <unistd.h> -#endif /* WIN32 || __EMX__ */ +#endif /* _WIN32 || __EMX__ */ /* @@ -45,6 +45,8 @@ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA http_status_t status; /* HTTP status from server */ char if_modified_since[HTTP_MAX_VALUE]; /* If-Modified-Since header */ + int new_auth = 0; /* Using new auth information? */ + int digest; /* Are we using Digest authentication? */ /* @@ -85,9 +87,33 @@ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA } httpClearFields(http); - httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); httpSetField(http, HTTP_FIELD_IF_MODIFIED_SINCE, if_modified_since); + digest = http->authstring && !strncmp(http->authstring, "Digest ", 7); + + if (digest && !new_auth) + { + /* + * Update the Digest authentication string... + */ + + _httpSetDigestAuthString(http, http->nextnonce, "GET", resource); + } + +#ifdef HAVE_GSSAPI + if (http->authstring && !strncmp(http->authstring, "Negotiate", 9) && !new_auth) + { + /* + * Do not use cached Kerberos credentials since they will look like a + * "replay" attack... + */ + + _cupsSetNegotiateAuthString(http, "GET", resource); + } +#endif /* HAVE_GSSAPI */ + + httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); + if (httpGet(http, resource)) { if (httpReconnect2(http, 30000, NULL)) @@ -102,6 +128,8 @@ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA } } + new_auth = 0; + while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); if (status == HTTP_STATUS_UNAUTHORIZED) @@ -116,6 +144,8 @@ cupsGetFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA * See if we can do authentication... */ + new_auth = 1; + if (cupsDoAuthentication(http, "GET", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; @@ -267,6 +297,8 @@ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA int retries; /* Number of retries */ char buffer[8192]; /* Buffer for file */ http_status_t status; /* HTTP status from server */ + int new_auth = 0; /* Using new auth information? */ + int digest; /* Are we using Digest authentication? */ /* @@ -309,10 +341,34 @@ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA http->authstring)); httpClearFields(http); - httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked"); httpSetExpect(http, HTTP_STATUS_CONTINUE); + digest = http->authstring && !strncmp(http->authstring, "Digest ", 7); + + if (digest && !new_auth) + { + /* + * Update the Digest authentication string... + */ + + _httpSetDigestAuthString(http, http->nextnonce, "PUT", resource); + } + +#ifdef HAVE_GSSAPI + if (http->authstring && !strncmp(http->authstring, "Negotiate", 9) && !new_auth) + { + /* + * Do not use cached Kerberos credentials since they will look like a + * "replay" attack... + */ + + _cupsSetNegotiateAuthString(http, "PUT", resource); + } +#endif /* HAVE_GSSAPI */ + + httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); + if (httpPut(http, resource)) { if (httpReconnect2(http, 30000, NULL)) @@ -383,6 +439,8 @@ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA DEBUG_printf(("2cupsPutFd: status=%d", status)); + new_auth = 0; + if (status == HTTP_STATUS_UNAUTHORIZED) { /* @@ -395,6 +453,8 @@ cupsPutFd(http_t *http, /* I - Connection to server or @code CUPS_HTTP_DEFA * See if we can do authentication... */ + new_auth = 1; + if (cupsDoAuthentication(http, "PUT", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; diff --git a/cups/globals.c b/cups/globals.c index 8a05c3eb..28c993be 100644 --- a/cups/globals.c +++ b/cups/globals.c @@ -34,23 +34,23 @@ static _cups_threadkey_t cups_globals_key = _CUPS_THREADKEY_INITIALIZER; static pthread_once_t cups_globals_key_once = PTHREAD_ONCE_INIT; /* One-time initialization object */ #endif /* HAVE_PTHREAD_H */ -#if defined(HAVE_PTHREAD_H) || defined(WIN32) +#if defined(HAVE_PTHREAD_H) || defined(_WIN32) static _cups_mutex_t cups_global_mutex = _CUPS_MUTEX_INITIALIZER; /* Global critical section */ -#endif /* HAVE_PTHREAD_H || WIN32 */ +#endif /* HAVE_PTHREAD_H || _WIN32 */ /* * Local functions... */ -#ifdef WIN32 +#ifdef _WIN32 static void cups_fix_path(char *path); -#endif /* WIN32 */ +#endif /* _WIN32 */ static _cups_globals_t *cups_globals_alloc(void); -#if defined(HAVE_PTHREAD_H) || defined(WIN32) +#if defined(HAVE_PTHREAD_H) || defined(_WIN32) static void cups_globals_free(_cups_globals_t *g); -#endif /* HAVE_PTHREAD_H || WIN32 */ +#endif /* HAVE_PTHREAD_H || _WIN32 */ #ifdef HAVE_PTHREAD_H static void cups_globals_init(void); #endif /* HAVE_PTHREAD_H */ @@ -65,7 +65,7 @@ _cupsGlobalLock(void) { #ifdef HAVE_PTHREAD_H pthread_mutex_lock(&cups_global_mutex); -#elif defined(WIN32) +#elif defined(_WIN32) EnterCriticalSection(&cups_global_mutex.m_criticalSection); #endif /* HAVE_PTHREAD_H */ } @@ -120,13 +120,13 @@ _cupsGlobalUnlock(void) { #ifdef HAVE_PTHREAD_H pthread_mutex_unlock(&cups_global_mutex); -#elif defined(WIN32) +#elif defined(_WIN32) LeaveCriticalSection(&cups_global_mutex.m_criticalSection); #endif /* HAVE_PTHREAD_H */ } -#ifdef WIN32 +#ifdef _WIN32 /* * 'DllMain()' - Main entry for library. */ @@ -170,7 +170,7 @@ DllMain(HINSTANCE hinst, /* I - DLL module handle */ return (TRUE); } -#endif /* WIN32 */ +#endif /* _WIN32 */ /* @@ -182,13 +182,13 @@ cups_globals_alloc(void) { _cups_globals_t *cg = malloc(sizeof(_cups_globals_t)); /* Pointer to global data */ -#ifdef WIN32 +#ifdef _WIN32 HKEY key; /* Registry key */ DWORD size; /* Size of string */ static char installdir[1024] = "", /* Install directory */ confdir[1024] = "", /* Server root directory */ localedir[1024] = ""; /* Locale directory */ -#endif /* WIN32 */ +#endif /* _WIN32 */ if (!cg) @@ -219,7 +219,7 @@ cups_globals_alloc(void) * Then set directories as appropriate... */ -#ifdef WIN32 +#ifdef _WIN32 if (!installdir[0]) { /* @@ -315,7 +315,7 @@ cups_globals_alloc(void) if ((cg->localedir = getenv("LOCALEDIR")) == NULL) cg->localedir = CUPS_LOCALEDIR; } -#endif /* WIN32 */ +#endif /* _WIN32 */ return (cg); } @@ -325,7 +325,7 @@ cups_globals_alloc(void) * 'cups_globals_free()' - Free global data. */ -#if defined(HAVE_PTHREAD_H) || defined(WIN32) +#if defined(HAVE_PTHREAD_H) || defined(_WIN32) static void cups_globals_free(_cups_globals_t *cg) /* I - Pointer to global data */ { @@ -360,7 +360,7 @@ cups_globals_free(_cups_globals_t *cg) /* I - Pointer to global data */ free(cg); } -#endif /* HAVE_PTHREAD_H || WIN32 */ +#endif /* HAVE_PTHREAD_H || _WIN32 */ #ifdef HAVE_PTHREAD_H diff --git a/cups/hash.c b/cups/hash.c index ede54616..50dc5fb3 100644 --- a/cups/hash.c +++ b/cups/hash.c @@ -1,7 +1,7 @@ /* * Hashing function for CUPS. * - * Copyright 2015-2016 by Apple Inc. + * Copyright © 2015-2018 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -21,6 +21,8 @@ # include <CommonCrypto/CommonDigest.h> #elif defined(HAVE_GNUTLS) # include <gnutls/crypto.h> +#else +# include "md5-private.h" #endif /* __APPLE__ */ @@ -53,7 +55,24 @@ cupsHashData(const char *algorithm, /* I - Algorithm name */ } #ifdef __APPLE__ - if (!strcmp(algorithm, "sha")) + if (!strcmp(algorithm, "md5")) + { + /* + * MD5 (deprecated but widely used...) + */ + + CC_MD5_CTX ctx; /* MD5 context */ + + if (hashsize < CC_MD5_DIGEST_LENGTH) + goto too_small; + + CC_MD5_Init(&ctx); + CC_MD5_Update(&ctx, data, (CC_LONG)datalen); + CC_MD5_Final(hash, &ctx); + + return (CC_MD5_DIGEST_LENGTH); + } + else if (!strcmp(algorithm, "sha")) { /* * SHA-1... @@ -171,7 +190,9 @@ cupsHashData(const char *algorithm, /* I - Algorithm name */ unsigned char temp[64]; /* Temporary hash buffer */ size_t tempsize = 0; /* Truncate to this size? */ - if (!strcmp(algorithm, "sha")) + if (!strcmp(algorithm, "md5")) + alg = GNUTLS_DIG_MD5; + else if (!strcmp(algorithm, "sha")) alg = GNUTLS_DIG_SHA1; else if (!strcmp(algorithm, "sha2-224")) alg = GNUTLS_DIG_SHA224; @@ -219,10 +240,20 @@ cupsHashData(const char *algorithm, /* I - Algorithm name */ #else /* - * No hash support without CommonCrypto or GNU TLS... + * No hash support beyond MD5 without CommonCrypto or GNU TLS... */ - if (hashsize < 64) + if (!strcmp(algorithm, "md5")) + { + _cups_md5_state_t state; /* MD5 state info */ + + _cupsMD5Init(&state); + _cupsMD5Append(&state, data, datalen); + _cupsMD5Finish(&state, hash); + + return (16); + } + else if (hashsize < 64) goto too_small; #endif /* __APPLE__ */ @@ -243,3 +274,53 @@ cupsHashData(const char *algorithm, /* I - Algorithm name */ _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Hash buffer too small."), 1); return (-1); } + + +/* + * 'cupsHashString()' - Format a hash value as a hexadecimal string. + * + * The passed buffer must be at least 2 * hashsize + 1 characters in length. + * + * @since CUPS 2.2.7@ + */ + +const char * /* O - Formatted string */ +cupsHashString( + const unsigned char *hash, /* I - Hash */ + size_t hashsize, /* I - Size of hash */ + char *buffer, /* I - String buffer */ + size_t bufsize) /* I - Size of string buffer */ +{ + char *bufptr = buffer; /* Pointer into buffer */ + static const char *hex = "0123456789abcdef"; + /* Hex characters (lowercase!) */ + + + /* + * Range check input... + */ + + if (!hash || hashsize < 1 || !buffer || bufsize < (2 * hashsize + 1)) + { + if (buffer) + *buffer = '\0'; + return (NULL); + } + + /* + * Loop until we've converted the whole hash... + */ + + while (hashsize > 0) + { + *bufptr++ = hex[*hash >> 4]; + *bufptr++ = hex[*hash & 15]; + + hash ++; + hashsize --; + } + + *bufptr = '\0'; + + return (buffer); +} diff --git a/cups/http-addr.c b/cups/http-addr.c index 12d13a69..f8b8131c 100644 --- a/cups/http-addr.c +++ b/cups/http-addr.c @@ -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@ */ @@ -69,11 +69,11 @@ int /* O - 0 on success, -1 on failure */ httpAddrClose(http_addr_t *addr, /* I - Listen address or @code NULL@ */ int fd) /* I - Socket file descriptor */ { -#ifdef WIN32 +#ifdef _WIN32 if (closesocket(fd)) #else if (close(fd)) -#endif /* WIN32 */ +#endif /* _WIN32 */ return (-1); #ifdef AF_LOCAL @@ -258,9 +258,9 @@ httpAddrListen(http_addr_t *addr, /* I - Address to bind to */ * Close on exec... */ -#ifndef WIN32 +#ifndef _WIN32 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); -#endif /* !WIN32 */ +#endif /* !_WIN32 */ #ifdef SO_NOSIGPIPE /* @@ -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 */ diff --git a/cups/http-addrlist.c b/cups/http-addrlist.c index 723bf029..d9a96c4e 100644 --- a/cups/http-addrlist.c +++ b/cups/http-addrlist.c @@ -1,7 +1,7 @@ /* * HTTP address list routines for CUPS. * - * Copyright 2007-2016 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -24,15 +24,15 @@ #ifdef HAVE_POLL # include <poll.h> #endif /* HAVE_POLL */ -#ifndef WIN32 +#ifndef _WIN32 # include <fcntl.h> -#endif /* WIN32 */ +#endif /* _WIN32 */ /* * '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 */ @@ -61,14 +61,14 @@ httpAddrConnect2( int *cancel) /* I - Pointer to "cancel" variable */ { int val; /* Socket option value */ -#ifndef WIN32 - int flags; /* Socket flags */ -#endif /* !WIN32 */ - int remaining; /* Remaining timeout */ - int i, /* Looping var */ - nfds, /* Number of file descriptors */ - fds[100], /* Socket file descriptors */ +#ifndef _WIN32 + int i, j, /* Looping vars */ + flags, /* Socket flags */ result; /* Result from select() or poll() */ +#endif /* !_WIN32 */ + int remaining; /* Remaining timeout */ + int nfds, /* Number of file descriptors */ + fds[100]; /* Socket file descriptors */ http_addrlist_t *addrs[100]; /* Addresses */ #ifndef HAVE_POLL int max_fd = -1; /* Highest file descriptor */ @@ -84,8 +84,10 @@ httpAddrConnect2( # endif /* HAVE_POLL */ #endif /* O_NONBLOCK */ #ifdef DEBUG +# ifndef _WIN32 socklen_t len; /* Length of value */ http_addr_t peer; /* Peer address */ +# endif /* !_WIN32 */ char temp[256]; /* Temporary address string */ #endif /* DEBUG */ @@ -213,11 +215,11 @@ httpAddrConnect2( return (addrlist); } -#ifdef WIN32 +#ifdef _WIN32 if (WSAGetLastError() != WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK) #else if (errno != EINPROGRESS && errno != EWOULDBLOCK) -#endif /* WIN32 */ +#endif /* _WIN32 */ { DEBUG_printf(("1httpAddrConnect2: Unable to connect to %s:%d: %s", httpAddrString(&(addrlist->addr), temp, sizeof(temp)), httpAddrPort(&(addrlist->addr)), strerror(errno))); httpAddrClose(NULL, fds[nfds]); @@ -225,9 +227,9 @@ httpAddrConnect2( continue; } -#ifndef WIN32 +#ifndef _WIN32 fcntl(fds[nfds], F_SETFL, flags); -#endif /* !WIN32 */ +#endif /* !_WIN32 */ #ifndef HAVE_POLL if (fds[nfds] > max_fd) @@ -296,11 +298,11 @@ httpAddrConnect2( DEBUG_printf(("1httpAddrConnect2: select() returned %d (%d)", result, errno)); # endif /* HAVE_POLL */ } -# ifdef WIN32 +# ifdef _WIN32 while (result < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)); # else while (result < 0 && (errno == EINTR || errno == EAGAIN)); -# endif /* WIN32 */ +# endif /* _WIN32 */ if (result > 0) { @@ -323,6 +325,8 @@ httpAddrConnect2( if (!getpeername(fds[i], (struct sockaddr *)&peer, &len)) DEBUG_printf(("1httpAddrConnect2: Connected to %s:%d...", httpAddrString(&peer, temp, sizeof(temp)), httpAddrPort(&peer))); # endif /* DEBUG */ + + break; } # ifdef HAVE_POLL else if (pfds[i].revents & (POLLERR | POLLHUP)) @@ -346,7 +350,20 @@ httpAddrConnect2( } if (connaddr) + { + /* + * Connected on one address, close all of the other sockets we have so + * far and return... + */ + + for (j = 0; j < i; j ++) + httpAddrClose(NULL, fds[j]); + + for (j ++; j < nfds; j ++) + httpAddrClose(NULL, fds[j]); + return (connaddr); + } } #endif /* O_NONBLOCK */ @@ -362,11 +379,11 @@ httpAddrConnect2( httpAddrClose(NULL, fds[nfds]); } -#ifdef WIN32 +#ifdef _WIN32 _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, "Connection failed", 0); #else _cupsSetError(IPP_STATUS_ERROR_SERVICE_UNAVAILABLE, strerror(errno), 0); -#endif /* WIN32 */ +#endif /* _WIN32 */ return (NULL); } @@ -603,6 +620,7 @@ httpAddrGetList(const char *hostname, /* I - Hostname, IP address, or NULL for p if (!temp) { httpAddrFreeList(first); + freeaddrinfo(results); _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); return (NULL); } @@ -833,11 +851,11 @@ httpAddrGetList(const char *hostname, /* I - Hostname, IP address, or NULL for p temp->addr.ipv6.sin6_family = AF_INET6; temp->addr.ipv6.sin6_port = htons(portnum); -# ifdef WIN32 +# ifdef _WIN32 temp->addr.ipv6.sin6_addr.u.Byte[15] = 1; # else temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1); -# endif /* WIN32 */ +# endif /* _WIN32 */ if (!first) first = temp; diff --git a/cups/http-private.h b/cups/http-private.h index ec908a66..32cb9ea5 100644 --- a/cups/http-private.h +++ b/cups/http-private.h @@ -1,7 +1,7 @@ /* * Private HTTP definitions for CUPS. * - * Copyright 2007-2016 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -30,7 +30,7 @@ # endif /* __sun */ # include <limits.h> -# ifdef WIN32 +# ifdef _WIN32 # include <io.h> # include <winsock2.h> # define CUPS_SOCAST (const char *) @@ -39,7 +39,7 @@ # include <fcntl.h> # include <sys/socket.h> # define CUPS_SOCAST -# endif /* WIN32 */ +# endif /* _WIN32 */ # ifdef HAVE_GSSAPI # ifdef HAVE_GSS_GSSAPI_H @@ -68,7 +68,6 @@ typedef int socklen_t; # endif /* __APPLE__ && !_SOCKLEN_T */ # include <cups/http.h> -# include "md5-private.h" # include "ipp-private.h" # ifdef HAVE_GNUTLS @@ -141,7 +140,7 @@ extern SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator, SecCertificate # include <sspi.h> # endif /* HAVE_GNUTLS */ -# ifndef WIN32 +# ifndef _WIN32 # include <net/if.h> # include <resolv.h> # ifdef HAVE_GETIFADDRS @@ -152,11 +151,7 @@ extern SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator, SecCertificate # include <sys/sockio.h> # endif /* HAVE_SYS_SOCKIO_H */ # endif /* HAVE_GETIFADDRS */ -# endif /* !WIN32 */ - -# ifdef HAVE_LIBZ -# include <zlib.h> -# endif /* HAVE_LIBZ */ +# endif /* !_WIN32 */ /* @@ -172,18 +167,24 @@ extern "C" { * Constants... */ +# define _HTTP_MAX_SBUFFER 65536 /* Size of (de)compression buffer */ +# define _HTTP_RESOLVE_DEFAULT 0 /* Just resolve with default options */ +# define _HTTP_RESOLVE_STDERR 1 /* Log resolve progress to stderr */ +# define _HTTP_RESOLVE_FQDN 2 /* Resolve to a FQDN */ +# define _HTTP_RESOLVE_FAXOUT 4 /* Resolve FaxOut service? */ -#define _HTTP_MAX_SBUFFER 65536 /* Size of (de)compression buffer */ -#define _HTTP_RESOLVE_DEFAULT 0 /* Just resolve with default options */ -#define _HTTP_RESOLVE_STDERR 1 /* Log resolve progress to stderr */ -#define _HTTP_RESOLVE_FQDN 2 /* Resolve to a FQDN */ -#define _HTTP_RESOLVE_FAXOUT 4 /* Resolve FaxOut service? */ +# define _HTTP_TLS_NONE 0 /* No TLS options */ +# define _HTTP_TLS_ALLOW_RC4 1 /* Allow RC4 cipher suites */ +# define _HTTP_TLS_ALLOW_DH 2 /* Allow DH/DHE key negotiation */ +# define _HTTP_TLS_DENY_CBC 4 /* Deny CBC cipher suites */ +# define _HTTP_TLS_SET_DEFAULT 128 /* Setting the default TLS options */ -#define _HTTP_TLS_NONE 0 /* No TLS options */ -#define _HTTP_TLS_ALLOW_RC4 1 /* Allow RC4 cipher suites */ -#define _HTTP_TLS_ALLOW_SSL3 2 /* Allow SSL 3.0 */ -#define _HTTP_TLS_ALLOW_DH 4 /* Allow DH/DHE key negotiation */ -#define _HTTP_TLS_DENY_TLS10 16 /* Deny TLS 1.0 */ +# define _HTTP_TLS_SSL3 0 /* Min/max version is SSL/3.0 */ +# define _HTTP_TLS_1_0 1 /* Min/max version is TLS/1.0 */ +# define _HTTP_TLS_1_1 2 /* Min/max version is TLS/1.1 */ +# define _HTTP_TLS_1_2 3 /* Min/max version is TLS/1.2 */ +# define _HTTP_TLS_1_3 4 /* Min/max version is TLS/1.3 */ +# define _HTTP_TLS_MAX 5 /* Highest known TLS version */ /* @@ -295,10 +296,10 @@ struct _http_s /**** HTTP connection structure ****/ char buffer[HTTP_MAX_BUFFER]; /* Buffer for incoming data */ int _auth_type; /* Authentication in use (deprecated) */ - _cups_md5_state_t md5_state; /* MD5 state */ + unsigned char _md5_state[88]; /* MD5 state (deprecated) */ char nonce[HTTP_MAX_VALUE]; /* Nonce value */ - int nonce_count; /* Nonce count */ + unsigned nonce_count; /* Nonce count */ http_tls_t tls; /* TLS state information */ http_encryption_t encryption; /* Encryption requirements */ @@ -359,9 +360,20 @@ struct _http_s /**** HTTP connection structure ****/ /* Default field values */ # ifdef HAVE_LIBZ _http_coding_t coding; /* _HTTP_CODING_xxx */ - z_stream stream; /* (De)compression stream */ - Bytef *sbuffer; /* (De)compression buffer */ + void *stream; /* (De)compression stream */ + unsigned char *sbuffer; /* (De)compression buffer */ # endif /* HAVE_LIBZ */ + + /**** New in CUPS 2.2.9 ****/ + char *authentication_info, + /* Authentication-Info header */ + algorithm[65], /* Algorithm from WWW-Authenticate */ + nextnonce[HTTP_MAX_VALUE], + /* Next nonce value from Authentication-Info */ + opaque[HTTP_MAX_VALUE], + /* Opaque value from WWW-Authenticate */ + realm[HTTP_MAX_VALUE]; + /* Realm from WWW-Authenticate */ }; # endif /* !_HTTP_NO_PRIVATE */ @@ -380,7 +392,7 @@ extern const char *_cups_hstrerror(int error); * Some OS's don't have getifaddrs() and freeifaddrs()... */ -# if !defined(WIN32) && !defined(HAVE_GETIFADDRS) +# if !defined(_WIN32) && !defined(HAVE_GETIFADDRS) # ifdef ifa_dstaddr # undef ifa_dstaddr # endif /* ifa_dstaddr */ @@ -415,7 +427,7 @@ extern int _cups_getifaddrs(struct ifaddrs **addrs); # define getifaddrs _cups_getifaddrs extern void _cups_freeifaddrs(struct ifaddrs *addrs); # define freeifaddrs _cups_freeifaddrs -# endif /* !WIN32 && !HAVE_GETIFADDRS */ +# endif /* !_WIN32 && !HAVE_GETIFADDRS */ /* @@ -435,12 +447,13 @@ extern const char *_httpResolveURI(const char *uri, char *resolved_uri, size_t resolved_size, int options, int (*cb)(void *context), void *context); +extern int _httpSetDigestAuthString(http_t *http, const char *nonce, const char *method, const char *resource); extern const char *_httpStatus(cups_lang_t *lang, http_status_t status); extern void _httpTLSInitialize(void); extern size_t _httpTLSPending(http_t *http); extern int _httpTLSRead(http_t *http, char *buf, int len); extern int _httpTLSSetCredentials(http_t *http); -extern void _httpTLSSetOptions(int options); +extern void _httpTLSSetOptions(int options, int min_version, int max_version); extern int _httpTLSStart(http_t *http); extern void _httpTLSStop(http_t *http); extern int _httpTLSWrite(http_t *http, const char *buf, int len); diff --git a/cups/http-support.c b/cups/http-support.c index 1ca01b27..767fbf68 100644 --- a/cups/http-support.c +++ b/cups/http-support.c @@ -1,7 +1,7 @@ /* * HTTP support routines for CUPS. * - * Copyright 2007-2016 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -20,13 +20,13 @@ #include "cups-private.h" #ifdef HAVE_DNSSD # include <dns_sd.h> -# ifdef WIN32 +# ifdef _WIN32 # include <io.h> # elif defined(HAVE_POLL) # include <poll.h> # else # include <sys/select.h> -# endif /* WIN32 */ +# endif /* _WIN32 */ #elif defined(HAVE_AVAHI) # include <avahi-client/client.h> # include <avahi-client/lookup.h> @@ -502,7 +502,6 @@ httpAssembleUUID(const char *server, /* I - Server name */ size_t bufsize) /* I - Size of buffer */ { char data[1024]; /* Source string for MD5 */ - _cups_md5_state_t md5state; /* MD5 state */ unsigned char md5sum[16]; /* MD5 digest/sum */ @@ -517,9 +516,7 @@ httpAssembleUUID(const char *server, /* I - Server name */ port, name ? name : server, number, (unsigned)CUPS_RAND() & 0xffff, (unsigned)CUPS_RAND() & 0xffff); - _cupsMD5Init(&md5state); - _cupsMD5Append(&md5state, (unsigned char *)data, (int)strlen(data)); - _cupsMD5Finish(&md5state, md5sum); + cupsHashData("md5", (unsigned char *)data, strlen(data), md5sum, sizeof(md5sum)); /* * Generate the UUID from the MD5... @@ -543,7 +540,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 +563,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 +672,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 +691,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 +779,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 +799,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 +820,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 +889,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 +913,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 @@ -1031,7 +1032,7 @@ httpSeparateURI( *ptr = '\0'; - if (*uri != ':') + if (*uri != ':' || *scheme == '.' || !*scheme) { *scheme = '\0'; return (HTTP_URI_STATUS_BAD_SCHEME); @@ -1302,6 +1303,152 @@ httpSeparateURI( /* + * '_httpSetDigestAuthString()' - Calculate a Digest authentication response + * using the appropriate RFC 2068/2617/7616 + * algorithm. + */ + +int /* O - 1 on success, 0 on failure */ +_httpSetDigestAuthString( + http_t *http, /* I - HTTP connection */ + const char *nonce, /* I - Nonce value */ + const char *method, /* I - HTTP method */ + const char *resource) /* I - HTTP resource path */ +{ + char kd[65], /* Final MD5/SHA-256 digest */ + ha1[65], /* Hash of username:realm:password */ + ha2[65], /* Hash of method:request-uri */ + username[HTTP_MAX_VALUE], + /* username:password */ + *password, /* Pointer to password */ + temp[1024], /* Temporary string */ + digest[1024]; /* Digest auth data */ + unsigned char hash[32]; /* Hash buffer */ + size_t hashsize; /* Size of hash */ + + + DEBUG_printf(("2_httpSetDigestAuthString(http=%p, nonce=\"%s\", method=\"%s\", resource=\"%s\")", http, nonce, method, resource)); + + if (nonce && *nonce && strcmp(nonce, http->nonce)) + { + strlcpy(http->nonce, nonce, sizeof(http->nonce)); + + if (nonce == http->nextnonce) + http->nextnonce[0] = '\0'; + + http->nonce_count = 1; + } + else + http->nonce_count ++; + + strlcpy(username, http->userpass, sizeof(username)); + if ((password = strchr(username, ':')) != NULL) + *password++ = '\0'; + else + return (0); + + if (http->algorithm[0]) + { + /* + * Follow RFC 2617/7616... + */ + + int i; /* Looping var */ + char cnonce[65]; /* cnonce value */ + const char *hashalg; /* Hashing algorithm */ + + for (i = 0; i < 64; i ++) + cnonce[i] = "0123456789ABCDEF"[CUPS_RAND() & 15]; + cnonce[64] = '\0'; + + if (!_cups_strcasecmp(http->algorithm, "MD5")) + { + /* + * RFC 2617 Digest with MD5 + */ + + hashalg = "md5"; + } + else if (!_cups_strcasecmp(http->algorithm, "SHA-256")) + { + /* + * RFC 7616 Digest with SHA-256 + */ + + hashalg = "sha2-256"; + } + else + { + /* + * Some other algorithm we don't support, skip this one... + */ + + return (0); + } + + /* + * Calculate digest value... + */ + + /* H(A1) = H(username:realm:password) */ + snprintf(temp, sizeof(temp), "%s:%s:%s", username, http->realm, password); + hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, ha1, sizeof(ha1)); + + /* H(A2) = H(method:uri) */ + snprintf(temp, sizeof(temp), "%s:%s", method, resource); + hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, ha2, sizeof(ha2)); + + /* KD = H(H(A1):nonce:nc:cnonce:qop:H(A2)) */ + snprintf(temp, sizeof(temp), "%s:%s:%08x:%s:%s:%s", ha1, http->nonce, http->nonce_count, cnonce, "auth", ha2); + hashsize = (size_t)cupsHashData(hashalg, (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, kd, sizeof(kd)); + + /* + * Pass the RFC 2617/7616 WWW-Authenticate header... + */ + + if (http->opaque[0]) + snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", algorithm=%s, qop=auth, opaque=\"%s\", cnonce=\"%s\", nc=%08x, uri=\"%s\", response=\"%s\"", cupsUser(), http->realm, http->nonce, http->algorithm, http->opaque, cnonce, http->nonce_count, resource, kd); + else + snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", algorithm=%s, qop=auth, cnonce=\"%s\", nc=%08x, uri=\"%s\", response=\"%s\"", username, http->realm, http->nonce, http->algorithm, cnonce, http->nonce_count, resource, kd); + } + else + { + /* + * Use old RFC 2069 Digest method... + */ + + /* H(A1) = H(username:realm:password) */ + snprintf(temp, sizeof(temp), "%s:%s:%s", username, http->realm, password); + hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, ha1, sizeof(ha1)); + + /* H(A2) = H(method:uri) */ + snprintf(temp, sizeof(temp), "%s:%s", method, resource); + hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, ha2, sizeof(ha2)); + + /* KD = H(H(A1):nonce:H(A2)) */ + snprintf(temp, sizeof(temp), "%s:%s:%s", ha1, http->nonce, ha2); + hashsize = (size_t)cupsHashData("md5", (unsigned char *)temp, strlen(temp), hash, sizeof(hash)); + cupsHashString(hash, hashsize, kd, sizeof(kd)); + + /* + * Pass the old RFC 2069 WWW-Authenticate header... + */ + + snprintf(digest, sizeof(digest), "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"", username, http->realm, http->nonce, resource, kd); + } + + httpSetAuthString(http, "Digest", digest); + + return (1); +} + + +/* * 'httpStateString()' - Return the string describing a HTTP state value. * * @since CUPS 2.0/OS 10.10@ @@ -1356,6 +1503,9 @@ _httpStatus(cups_lang_t *lang, /* I - Language */ case HTTP_STATUS_MOVED_PERMANENTLY : s = _("Moved Permanently"); break; + case HTTP_STATUS_FOUND : + s = _("Found"); + break; case HTTP_STATUS_SEE_OTHER : s = _("See Other"); break; @@ -1419,7 +1569,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 */ @@ -1618,9 +1768,6 @@ _httpResolveURI( _http_uribuf_t uribuf; /* URI buffer */ int offline = 0; /* offline-report state set? */ # ifdef HAVE_DNSSD -# ifdef WIN32 -# pragma comment(lib, "dnssd.lib") -# endif /* WIN32 */ DNSServiceRef ref, /* DNS-SD master service reference */ domainref = NULL,/* DNS-SD service reference for domain */ ippref = NULL, /* DNS-SD service reference for network IPP */ @@ -1749,11 +1896,11 @@ _httpResolveURI( FD_ZERO(&input_set); FD_SET(DNSServiceRefSockFD(ref), &input_set); -# ifdef WIN32 +# ifdef _WIN32 stimeout.tv_sec = (long)timeout; # else stimeout.tv_sec = timeout; -# endif /* WIN32 */ +# endif /* _WIN32 */ stimeout.tv_usec = 0; fds = select(DNSServiceRefSockFD(ref)+1, &input_set, NULL, NULL, @@ -2310,6 +2457,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 7925513a..5c14ef68 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-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by @@ -23,22 +23,26 @@ #include "cups-private.h" #include <fcntl.h> #include <math.h> -#ifdef WIN32 +#ifdef _WIN32 # include <tchar.h> #else # include <signal.h> # include <sys/time.h> # include <sys/resource.h> -#endif /* WIN32 */ +#endif /* _WIN32 */ #ifdef HAVE_POLL # include <poll.h> #endif /* HAVE_POLL */ +# ifdef HAVE_LIBZ +# include <zlib.h> +# endif /* HAVE_LIBZ */ /* * Local functions... */ +static void http_add_field(http_t *http, http_field_t field, const char *value, int append); #ifdef HAVE_LIBZ static void http_content_coding_finish(http_t *http); static void http_content_coding_start(http_t *http, @@ -105,7 +109,8 @@ static const char * const http_fields[] = "WWW-Authenticate", "Accept-Encoding", "Allow", - "Server" + "Server", + "Authentication-Info" }; @@ -325,6 +330,12 @@ httpClearFields(http_t *http) /* I - HTTP connection */ http->server = NULL; } + if (http->authentication_info) + { + _cupsStrFree(http->authentication_info); + http->authentication_info = NULL; + } + http->expect = (http_status_t)0; } } @@ -417,7 +428,7 @@ httpCompareCredentials( * * This function is deprecated - use @link httpConnect2@ instead. * - * @deprecated@ + * @deprecated@ @exclude all@ */ http_t * /* O - New HTTP connection */ @@ -439,7 +450,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 +493,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 +620,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 +690,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 +762,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 +777,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 +902,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); @@ -969,11 +980,14 @@ httpGetField(http_t *http, /* I - HTTP connection */ case HTTP_FIELD_SERVER : return (http->server); + case HTTP_FIELD_AUTHENTICATION_INFO : + return (http->authentication_info); + case HTTP_FIELD_AUTHORIZATION : if (http->field_authorization) { /* - * Special case for WWW-Authenticate: as its contents can be + * Special case for Authorization: as its contents can be * longer than HTTP_MAX_VALUE... */ @@ -1006,7 +1020,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 +1164,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 */ @@ -1183,11 +1197,11 @@ httpGets(char *line, /* I - Line to read into */ * Pre-load the buffer as needed... */ -#ifdef WIN32 +#ifdef _WIN32 WSASetLastError(0); #else errno = 0; -#endif /* WIN32 */ +#endif /* _WIN32 */ while (http->used == 0) { @@ -1201,11 +1215,11 @@ httpGets(char *line, /* I - Line to read into */ continue; DEBUG_puts("3httpGets: Timed out!"); -#ifdef WIN32 +#ifdef _WIN32 http->error = WSAETIMEDOUT; #else http->error = ETIMEDOUT; -#endif /* WIN32 */ +#endif /* _WIN32 */ return (NULL); } @@ -1219,7 +1233,7 @@ httpGets(char *line, /* I - Line to read into */ * Nope, can't get a line this time... */ -#ifdef WIN32 +#ifdef _WIN32 DEBUG_printf(("3httpGets: recv() error %d!", WSAGetLastError())); if (WSAGetLastError() == WSAEINTR) @@ -1256,7 +1270,7 @@ httpGets(char *line, /* I - Line to read into */ http->error = errno; continue; } -#endif /* WIN32 */ +#endif /* _WIN32 */ return (NULL); } @@ -1346,10 +1360,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 +1379,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 */ @@ -1523,9 +1537,9 @@ void httpInitialize(void) { static int initialized = 0; /* Have we been called before? */ -#ifdef WIN32 +#ifdef _WIN32 WSADATA winsockdata; /* WinSock data */ -#endif /* WIN32 */ +#endif /* _WIN32 */ _cupsGlobalLock(); @@ -1535,7 +1549,7 @@ httpInitialize(void) return; } -#ifdef WIN32 +#ifdef _WIN32 WSAStartup(MAKEWORD(2,2), &winsockdata); #elif !defined(SO_NOSIGPIPE) @@ -1557,7 +1571,7 @@ httpInitialize(void) # else signal(SIGPIPE, SIG_IGN); # endif /* !SO_NOSIGPIPE */ -#endif /* WIN32 */ +#endif /* _WIN32 */ # ifdef HAVE_SSL _httpTLSInitialize(); @@ -1616,7 +1630,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. * @@ -1713,7 +1727,7 @@ httpPeek(http_t *http, /* I - HTTP connection */ #ifdef HAVE_LIBZ if (http->used == 0 && (http->coding == _HTTP_CODING_IDENTITY || - (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in == 0))) + (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in == 0))) #else if (http->used == 0) #endif /* HAVE_LIBZ */ @@ -1762,16 +1776,16 @@ httpPeek(http_t *http, /* I - HTTP connection */ int zerr; /* Decompressor error */ z_stream stream; /* Copy of decompressor stream */ - if (http->used > 0 && http->stream.avail_in < HTTP_MAX_BUFFER) + if (http->used > 0 && ((z_stream *)http->stream)->avail_in < HTTP_MAX_BUFFER) { - size_t buflen = buflen = HTTP_MAX_BUFFER - http->stream.avail_in; + size_t buflen = buflen = HTTP_MAX_BUFFER - ((z_stream *)http->stream)->avail_in; /* Number of bytes to copy */ - if (http->stream.avail_in > 0 && - http->stream.next_in > http->sbuffer) - memmove(http->sbuffer, http->stream.next_in, http->stream.avail_in); + if (((z_stream *)http->stream)->avail_in > 0 && + ((z_stream *)http->stream)->next_in > http->sbuffer) + memmove(http->sbuffer, ((z_stream *)http->stream)->next_in, ((z_stream *)http->stream)->avail_in); - http->stream.next_in = http->sbuffer; + ((z_stream *)http->stream)->next_in = http->sbuffer; if (buflen > (size_t)http->data_remaining) buflen = (size_t)http->data_remaining; @@ -1782,8 +1796,8 @@ httpPeek(http_t *http, /* I - HTTP connection */ DEBUG_printf(("1httpPeek: Copying %d more bytes of data into " "decompression buffer.", (int)buflen)); - memcpy(http->sbuffer + http->stream.avail_in, http->buffer, buflen); - http->stream.avail_in += buflen; + memcpy(http->sbuffer + ((z_stream *)http->stream)->avail_in, http->buffer, buflen); + ((z_stream *)http->stream)->avail_in += buflen; http->used -= (int)buflen; http->data_remaining -= (off_t)buflen; @@ -1792,9 +1806,9 @@ httpPeek(http_t *http, /* I - HTTP connection */ } DEBUG_printf(("2httpPeek: length=%d, avail_in=%d", (int)length, - (int)http->stream.avail_in)); + (int)((z_stream *)http->stream)->avail_in)); - if (inflateCopy(&stream, &(http->stream)) != Z_OK) + if (inflateCopy(&stream, (z_stream *)http->stream) != Z_OK) { DEBUG_puts("2httpPeek: Unable to copy decompressor stream."); http->error = ENOMEM; @@ -1811,14 +1825,14 @@ httpPeek(http_t *http, /* I - HTTP connection */ { DEBUG_printf(("2httpPeek: zerr=%d", zerr)); #ifdef DEBUG - http_debug_hex("2httpPeek", (char *)http->sbuffer, (int)http->stream.avail_in); + http_debug_hex("2httpPeek", (char *)http->sbuffer, (int)((z_stream *)http->stream)->avail_in); #endif /* DEBUG */ http->error = EIO; return (-1); } - bytes = (ssize_t)(length - http->stream.avail_out); + bytes = (ssize_t)(length - ((z_stream *)http->stream)->avail_out); # else DEBUG_puts("2httpPeek: No inflateCopy on this platform, httpPeek does not " @@ -1845,7 +1859,7 @@ httpPeek(http_t *http, /* I - HTTP connection */ if (bytes < 0) { -#ifdef WIN32 +#ifdef _WIN32 if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK) bytes = 0; else @@ -1855,7 +1869,7 @@ httpPeek(http_t *http, /* I - HTTP connection */ bytes = 0; else http->error = errno; -#endif /* WIN32 */ +#endif /* _WIN32 */ } else if (bytes == 0) { @@ -1939,7 +1953,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 */ @@ -1985,31 +1999,31 @@ httpRead2(http_t *http, /* I - HTTP connection */ { do { - if (http->stream.avail_in > 0) + if (((z_stream *)http->stream)->avail_in > 0) { int zerr; /* Decompressor error */ DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d", - (int)http->stream.avail_in, (int)length)); + (int)((z_stream *)http->stream)->avail_in, (int)length)); - http->stream.next_out = (Bytef *)buffer; - http->stream.avail_out = (uInt)length; + ((z_stream *)http->stream)->next_out = (Bytef *)buffer; + ((z_stream *)http->stream)->avail_out = (uInt)length; - if ((zerr = inflate(&(http->stream), Z_SYNC_FLUSH)) < Z_OK) + if ((zerr = inflate((z_stream *)http->stream, Z_SYNC_FLUSH)) < Z_OK) { DEBUG_printf(("2httpRead2: zerr=%d", zerr)); #ifdef DEBUG - http_debug_hex("2httpRead2", (char *)http->sbuffer, (int)http->stream.avail_in); + http_debug_hex("2httpRead2", (char *)http->sbuffer, (int)((z_stream *)http->stream)->avail_in); #endif /* DEBUG */ http->error = EIO; return (-1); } - bytes = (ssize_t)(length - http->stream.avail_out); + bytes = (ssize_t)(length - ((z_stream *)http->stream)->avail_out); DEBUG_printf(("2httpRead2: avail_in=%d, avail_out=%d, bytes=%d", - http->stream.avail_in, http->stream.avail_out, + ((z_stream *)http->stream)->avail_in, ((z_stream *)http->stream)->avail_out, (int)bytes)); } else @@ -2017,16 +2031,16 @@ httpRead2(http_t *http, /* I - HTTP connection */ if (bytes == 0) { - ssize_t buflen = HTTP_MAX_BUFFER - (ssize_t)http->stream.avail_in; + ssize_t buflen = HTTP_MAX_BUFFER - (ssize_t)((z_stream *)http->stream)->avail_in; /* Additional bytes for buffer */ if (buflen > 0) { - if (http->stream.avail_in > 0 && - http->stream.next_in > http->sbuffer) - memmove(http->sbuffer, http->stream.next_in, http->stream.avail_in); + if (((z_stream *)http->stream)->avail_in > 0 && + ((z_stream *)http->stream)->next_in > http->sbuffer) + memmove(http->sbuffer, ((z_stream *)http->stream)->next_in, ((z_stream *)http->stream)->avail_in); - http->stream.next_in = http->sbuffer; + ((z_stream *)http->stream)->next_in = http->sbuffer; DEBUG_printf(("1httpRead2: Reading up to %d more bytes of data into " "decompression buffer.", (int)buflen)); @@ -2036,10 +2050,10 @@ httpRead2(http_t *http, /* I - HTTP connection */ if (buflen > http->data_remaining) buflen = (ssize_t)http->data_remaining; - bytes = http_read_buffered(http, (char *)http->sbuffer + http->stream.avail_in, (size_t)buflen); + bytes = http_read_buffered(http, (char *)http->sbuffer + ((z_stream *)http->stream)->avail_in, (size_t)buflen); } else if (http->data_encoding == HTTP_ENCODING_CHUNKED) - bytes = http_read_chunk(http, (char *)http->sbuffer + http->stream.avail_in, (size_t)buflen); + bytes = http_read_chunk(http, (char *)http->sbuffer + ((z_stream *)http->stream)->avail_in, (size_t)buflen); else bytes = 0; @@ -2052,7 +2066,7 @@ httpRead2(http_t *http, /* I - HTTP connection */ "decompression buffer.", CUPS_LLCAST bytes)); http->data_remaining -= bytes; - http->stream.avail_in += (uInt)bytes; + ((z_stream *)http->stream)->avail_in += (uInt)bytes; if (http->data_remaining <= 0 && http->data_encoding == HTTP_ENCODING_CHUNKED) @@ -2131,7 +2145,7 @@ httpRead2(http_t *http, /* I - HTTP connection */ if ( #ifdef HAVE_LIBZ (http->coding == _HTTP_CODING_IDENTITY || - (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in == 0)) && + (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in == 0)) && #endif /* HAVE_LIBZ */ ((http->data_remaining <= 0 && http->data_encoding == HTTP_ENCODING_LENGTH) || @@ -2326,7 +2340,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 */ @@ -2416,11 +2430,11 @@ httpReconnect2(http_t *http, /* I - HTTP connection */ * Unable to connect... */ -#ifdef WIN32 +#ifdef _WIN32 http->error = WSAGetLastError(); #else http->error = errno; -#endif /* WIN32 */ +#endif /* _WIN32 */ http->status = HTTP_STATUS_ERROR; DEBUG_printf(("1httpReconnect2: httpAddrConnect failed: %s", @@ -2467,9 +2481,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@ */ @@ -2658,105 +2673,7 @@ httpSetField(http_t *http, /* I - HTTP connection */ value == NULL) return; - switch (field) - { - case HTTP_FIELD_ACCEPT_ENCODING : - if (http->accept_encoding) - _cupsStrFree(http->accept_encoding); - - http->accept_encoding = _cupsStrAlloc(value); - break; - - case HTTP_FIELD_ALLOW : - if (http->allow) - _cupsStrFree(http->allow); - - http->allow = _cupsStrAlloc(value); - break; - - case HTTP_FIELD_SERVER : - if (http->server) - _cupsStrFree(http->server); - - http->server = _cupsStrAlloc(value); - break; - - case HTTP_FIELD_WWW_AUTHENTICATE : - /* CUPS STR #4503 - don't override WWW-Authenticate for unknown auth schemes */ - if (http->fields[HTTP_FIELD_WWW_AUTHENTICATE][0] && - _cups_strncasecmp(value, "Basic ", 6) && - _cups_strncasecmp(value, "Digest ", 7) && - _cups_strncasecmp(value, "Negotiate ", 10)) - { - DEBUG_printf(("1httpSetField: Ignoring unknown auth scheme in \"%s\".", value)); - return; - } - - /* Fall through to copy */ - - default : - strlcpy(http->fields[field], value, HTTP_MAX_VALUE); - break; - } - - if (field == HTTP_FIELD_AUTHORIZATION) - { - /* - * Special case for Authorization: as its contents can be - * longer than HTTP_MAX_VALUE - */ - - if (http->field_authorization) - free(http->field_authorization); - - http->field_authorization = strdup(value); - } - else if (field == HTTP_FIELD_HOST) - { - /* - * Special-case for Host: as we don't want a trailing "." on the hostname and - * need to bracket IPv6 numeric addresses. - */ - - char *ptr = strchr(value, ':'); - - if (value[0] != '[' && ptr && strchr(ptr + 1, ':')) - { - /* - * Bracket IPv6 numeric addresses... - * - * This is slightly inefficient (basically copying twice), but is an edge - * case and not worth optimizing... - */ - - snprintf(http->fields[HTTP_FIELD_HOST], - sizeof(http->fields[HTTP_FIELD_HOST]), "[%s]", value); - } - else - { - /* - * Check for a trailing dot on the hostname... - */ - - ptr = http->fields[HTTP_FIELD_HOST]; - - if (*ptr) - { - ptr += strlen(ptr) - 1; - - if (*ptr == '.') - *ptr = '\0'; - } - } - } -#ifdef HAVE_LIBZ - else if (field == HTTP_FIELD_CONTENT_ENCODING && - http->data_encoding != HTTP_ENCODING_FIELDS) - { - DEBUG_puts("1httpSetField: Calling http_content_coding_start."); - http_content_coding_start(http, value); - } -#endif /* HAVE_LIBZ */ + http_add_field(http, field, value, 0); } @@ -2820,7 +2737,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) @@ -2854,16 +2771,18 @@ httpShutdown(http_t *http) /* I - HTTP connection */ _httpTLSStop(http); #endif /* HAVE_SSL */ -#ifdef WIN32 +#ifdef _WIN32 shutdown(http->fd, SD_RECEIVE); /* Microsoft-ism... */ #else shutdown(http->fd, SHUT_RD); -#endif /* WIN32 */ +#endif /* _WIN32 */ } /* * 'httpTrace()' - Send an TRACE request to the server. + * + * @exclude all@ */ int /* O - Status of call (0 = success) */ @@ -3032,7 +2951,12 @@ _httpUpdate(http_t *http, /* I - HTTP connection */ httpSetCookie(http, value); } else if ((field = httpFieldValue(line)) != HTTP_FIELD_UNKNOWN) - httpSetField(http, field, value); + { + http_add_field(http, field, value, 1); + + if (field == HTTP_FIELD_AUTHENTICATION_INFO) + httpGetSubField2(http, HTTP_FIELD_AUTHENTICATION_INFO, "nextnonce", http->nextnonce, (int)sizeof(http->nextnonce)); + } #ifdef DEBUG else DEBUG_printf(("1_httpUpdate: unknown field %s seen!", line)); @@ -3185,12 +3109,12 @@ _httpWait(http_t *http, /* I - HTTP connection */ DEBUG_printf(("6_httpWait: select() returned %d...", nfds)); } -# ifdef WIN32 +# ifdef _WIN32 while (nfds < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)); # else while (nfds < 0 && (errno == EINTR || errno == EAGAIN)); -# endif /* WIN32 */ +# endif /* _WIN32 */ #endif /* HAVE_POLL */ DEBUG_printf(("5_httpWait: returning with nfds=%d, errno=%d...", nfds, @@ -3226,7 +3150,7 @@ httpWait(http_t *http, /* I - HTTP connection */ } #ifdef HAVE_LIBZ - if (http->coding >= _HTTP_CODING_GUNZIP && http->stream.avail_in > 0) + if (http->coding >= _HTTP_CODING_GUNZIP && ((z_stream *)http->stream)->avail_in > 0) { DEBUG_puts("3httpWait: Returning 1 since there is buffered data ready."); return (1); @@ -3259,7 +3183,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 */ @@ -3322,17 +3246,17 @@ httpWrite2(http_t *http, /* I - HTTP connection */ size_t slen; /* Bytes to write */ ssize_t sret; /* Bytes written */ - http->stream.next_in = (Bytef *)buffer; - http->stream.avail_in = (uInt)length; + ((z_stream *)http->stream)->next_in = (Bytef *)buffer; + ((z_stream *)http->stream)->avail_in = (uInt)length; - while (deflate(&(http->stream), Z_NO_FLUSH) == Z_OK) + while (deflate((z_stream *)http->stream, Z_NO_FLUSH) == Z_OK) { - DEBUG_printf(("1httpWrite2: avail_out=%d", http->stream.avail_out)); + DEBUG_printf(("1httpWrite2: avail_out=%d", ((z_stream *)http->stream)->avail_out)); - if (http->stream.avail_out > 0) + if (((z_stream *)http->stream)->avail_out > 0) continue; - slen = _HTTP_MAX_SBUFFER - http->stream.avail_out; + slen = _HTTP_MAX_SBUFFER - ((z_stream *)http->stream)->avail_out; DEBUG_printf(("1httpWrite2: Writing intermediate chunk, len=%d", (int)slen)); @@ -3349,8 +3273,8 @@ httpWrite2(http_t *http, /* I - HTTP connection */ return (-1); } - http->stream.next_out = (Bytef *)http->sbuffer; - http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER; + ((z_stream *)http->stream)->next_out = (Bytef *)http->sbuffer; + ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER; } bytes = (ssize_t)length; @@ -3686,6 +3610,125 @@ httpWriteResponse(http_t *http, /* I - HTTP connection */ } +/* + * 'http_add_field()' - Add a value for a HTTP field, appending if needed. + */ + +static void +http_add_field(http_t *http, /* I - HTTP connection */ + http_field_t field, /* I - HTTP field */ + const char *value, /* I - Value string */ + int append) /* I - Append value? */ +{ + char newvalue[1024]; /* New value string */ + const char *oldvalue; /* Old field value */ + + + + /* + * Optionally append the new value to the existing one... + */ + + if (append && field != HTTP_FIELD_ACCEPT_ENCODING && field != HTTP_FIELD_ACCEPT_LANGUAGE && field != HTTP_FIELD_ACCEPT_RANGES && field != HTTP_FIELD_ALLOW && field != HTTP_FIELD_LINK && field != HTTP_FIELD_TRANSFER_ENCODING && field != HTTP_FIELD_UPGRADE && field != HTTP_FIELD_WWW_AUTHENTICATE) + append = 0; + + if (field == HTTP_FIELD_HOST) + { + /* + * Special-case for Host: as we don't want a trailing "." on the hostname and + * need to bracket IPv6 numeric addresses. + */ + + char *ptr = strchr(value, ':'); + + if (value[0] != '[' && ptr && strchr(ptr + 1, ':')) + { + /* + * Bracket IPv6 numeric addresses... + */ + + snprintf(newvalue, sizeof(newvalue), "[%s]", value); + value = newvalue; + } + else if (*value && value[strlen(value) - 1] == '.') + { + /* + * Strip the trailing dot on the hostname... + */ + + strlcpy(newvalue, value, sizeof(newvalue)); + newvalue[strlen(newvalue) - 1] = '\0'; + value = newvalue; + } + } + else if (append && *value && (oldvalue = httpGetField(http, field)) != NULL && *oldvalue) + { + snprintf(newvalue, sizeof(newvalue), "%s, %s", oldvalue, value); + value = newvalue; + } + + /* + * Save the new value... + */ + + switch (field) + { + case HTTP_FIELD_ACCEPT_ENCODING : + if (http->accept_encoding) + _cupsStrFree(http->accept_encoding); + + http->accept_encoding = _cupsStrAlloc(value); + break; + + case HTTP_FIELD_ALLOW : + if (http->allow) + _cupsStrFree(http->allow); + + http->allow = _cupsStrAlloc(value); + break; + + case HTTP_FIELD_SERVER : + if (http->server) + _cupsStrFree(http->server); + + http->server = _cupsStrAlloc(value); + break; + + case HTTP_FIELD_AUTHENTICATION_INFO : + if (http->authentication_info) + _cupsStrFree(http->authentication_info); + + http->authentication_info = _cupsStrAlloc(value); + break; + + default : + strlcpy(http->fields[field], value, HTTP_MAX_VALUE); + break; + } + + if (field == HTTP_FIELD_AUTHORIZATION) + { + /* + * Special case for Authorization: as its contents can be + * longer than HTTP_MAX_VALUE + */ + + if (http->field_authorization) + free(http->field_authorization); + + http->field_authorization = strdup(value); + } +#ifdef HAVE_LIBZ + else if (field == HTTP_FIELD_CONTENT_ENCODING && + http->data_encoding != HTTP_ENCODING_FIELDS) + { + DEBUG_puts("1http_add_field: Calling http_content_coding_start."); + http_content_coding_start(http, value); + } +#endif /* HAVE_LIBZ */ +} + + #ifdef HAVE_LIBZ /* * 'http_content_coding_finish()' - Finish doing any content encoding. @@ -3707,13 +3750,13 @@ http_content_coding_finish( { case _HTTP_CODING_DEFLATE : case _HTTP_CODING_GZIP : - http->stream.next_in = dummy; - http->stream.avail_in = 0; + ((z_stream *)http->stream)->next_in = dummy; + ((z_stream *)http->stream)->avail_in = 0; do { - zerr = deflate(&(http->stream), Z_FINISH); - bytes = _HTTP_MAX_SBUFFER - http->stream.avail_out; + zerr = deflate((z_stream *)http->stream, Z_FINISH); + bytes = _HTTP_MAX_SBUFFER - ((z_stream *)http->stream)->avail_out; if (bytes > 0) { @@ -3725,15 +3768,18 @@ http_content_coding_finish( http_write(http, (char *)http->sbuffer, bytes); } - http->stream.next_out = (Bytef *)http->sbuffer; - http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER; + ((z_stream *)http->stream)->next_out = (Bytef *)http->sbuffer; + ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER; } while (zerr == Z_OK); - deflateEnd(&(http->stream)); + deflateEnd((z_stream *)http->stream); free(http->sbuffer); + free(http->stream); + http->sbuffer = NULL; + http->stream = NULL; if (http->wused) httpFlushWrite(http); @@ -3741,9 +3787,13 @@ http_content_coding_finish( case _HTTP_CODING_INFLATE : case _HTTP_CODING_GUNZIP : - inflateEnd(&(http->stream)); + inflateEnd((z_stream *)http->stream); + free(http->sbuffer); + free(http->stream); + http->sbuffer = NULL; + http->stream = NULL; break; default : @@ -3813,8 +3863,6 @@ http_content_coding_start( return; } - memset(&(http->stream), 0, sizeof(http->stream)); - switch (coding) { case _HTTP_CODING_DEFLATE : @@ -3835,18 +3883,30 @@ http_content_coding_start( * documentation. */ - if ((zerr = deflateInit2(&(http->stream), Z_DEFAULT_COMPRESSION, - Z_DEFLATED, - coding == _HTTP_CODING_DEFLATE ? -11 : 27, 7, - Z_DEFAULT_STRATEGY)) < Z_OK) + if ((http->stream = calloc(1, sizeof(z_stream))) == NULL) + { + free(http->sbuffer); + + http->sbuffer = NULL; + http->status = HTTP_STATUS_ERROR; + http->error = errno; + return; + } + + if ((zerr = deflateInit2((z_stream *)http->stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, coding == _HTTP_CODING_DEFLATE ? -11 : 27, 7, Z_DEFAULT_STRATEGY)) < Z_OK) { - http->status = HTTP_STATUS_ERROR; - http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL; + free(http->sbuffer); + free(http->stream); + + http->sbuffer = NULL; + http->stream = NULL; + http->status = HTTP_STATUS_ERROR; + http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL; return; } - http->stream.next_out = (Bytef *)http->sbuffer; - http->stream.avail_out = (uInt)_HTTP_MAX_SBUFFER; + ((z_stream *)http->stream)->next_out = (Bytef *)http->sbuffer; + ((z_stream *)http->stream)->avail_out = (uInt)_HTTP_MAX_SBUFFER; break; case _HTTP_CODING_INFLATE : @@ -3863,19 +3923,30 @@ http_content_coding_start( * -15 is raw inflate, 31 is gunzip, per ZLIB documentation. */ - if ((zerr = inflateInit2(&(http->stream), - coding == _HTTP_CODING_INFLATE ? -15 : 31)) - < Z_OK) + if ((http->stream = calloc(1, sizeof(z_stream))) == NULL) + { + free(http->sbuffer); + + http->sbuffer = NULL; + http->status = HTTP_STATUS_ERROR; + http->error = errno; + return; + } + + if ((zerr = inflateInit2((z_stream *)http->stream, coding == _HTTP_CODING_INFLATE ? -15 : 31)) < Z_OK) { free(http->sbuffer); + free(http->stream); + http->sbuffer = NULL; + http->stream = NULL; http->status = HTTP_STATUS_ERROR; http->error = zerr == Z_MEM_ERROR ? ENOMEM : EINVAL; return; } - http->stream.avail_in = 0; - http->stream.next_in = http->sbuffer; + ((z_stream *)http->stream)->avail_in = 0; + ((z_stream *)http->stream)->next_in = http->sbuffer; break; default : @@ -3898,7 +3969,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 */ @@ -3941,7 +4012,7 @@ http_create( if ((http = calloc(sizeof(http_t), 1)) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); - httpAddrFreeList(addrlist); + httpAddrFreeList(myaddrlist); return (NULL); } @@ -4053,7 +4124,7 @@ http_read(http_t *http, /* I - HTTP connection */ DEBUG_printf(("http_read(http=%p, buffer=%p, length=" CUPS_LLFMT ")", (void *)http, (void *)buffer, CUPS_LLCAST length)); - if (!http->blocking) + if (!http->blocking || http->timeout_value > 0.0) { while (!httpWait(http, http->wait_value)) { @@ -4078,7 +4149,7 @@ http_read(http_t *http, /* I - HTTP connection */ if (bytes < 0) { -#ifdef WIN32 +#ifdef _WIN32 if (WSAGetLastError() != WSAEINTR) { http->error = WSAGetLastError(); @@ -4114,7 +4185,7 @@ http_read(http_t *http, /* I - HTTP connection */ http->error = errno; return (-1); } -#endif /* WIN32 */ +#endif /* _WIN32 */ } } while (bytes < 0); @@ -4128,7 +4199,7 @@ http_read(http_t *http, /* I - HTTP connection */ if (bytes < 0) { -#ifdef WIN32 +#ifdef _WIN32 if (WSAGetLastError() == WSAEINTR) bytes = 0; else @@ -4138,7 +4209,7 @@ http_read(http_t *http, /* I - HTTP connection */ bytes = 0; else http->error = errno; -#endif /* WIN32 */ +#endif /* _WIN32 */ } else if (bytes == 0) { @@ -4502,7 +4573,7 @@ static void http_set_timeout(int fd, /* I - File descriptor */ double timeout) /* I - Timeout in seconds */ { -#ifdef WIN32 +#ifdef _WIN32 DWORD tv = (DWORD)(timeout * 1000); /* Timeout in milliseconds */ @@ -4517,7 +4588,7 @@ http_set_timeout(int fd, /* I - File descriptor */ setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CUPS_SOCAST &tv, sizeof(tv)); setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, CUPS_SOCAST &tv, sizeof(tv)); -#endif /* WIN32 */ +#endif /* _WIN32 */ } @@ -4648,7 +4719,7 @@ http_write(http_t *http, /* I - HTTP connection */ { DEBUG_printf(("3http_write: About to write %d bytes.", (int)length)); - if (http->timeout_cb) + if (http->timeout_value > 0.0) { #ifdef HAVE_POLL struct pollfd pfd; /* Polled file descriptor */ @@ -4679,12 +4750,12 @@ http_write(http_t *http, /* I - HTTP connection */ nfds = select(http->fd + 1, NULL, &output_set, NULL, &timeout); } -# ifdef WIN32 +# ifdef _WIN32 while (nfds < 0 && (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)); # else while (nfds < 0 && (errno == EINTR || errno == EAGAIN)); -# endif /* WIN32 */ +# endif /* _WIN32 */ #endif /* HAVE_POLL */ if (nfds < 0) @@ -4692,13 +4763,13 @@ http_write(http_t *http, /* I - HTTP connection */ http->error = errno; return (-1); } - else if (nfds == 0 && !(*http->timeout_cb)(http, http->timeout_data)) + else if (nfds == 0 && (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data))) { -#ifdef WIN32 +#ifdef _WIN32 http->error = WSAEWOULDBLOCK; #else http->error = EWOULDBLOCK; -#endif /* WIN32 */ +#endif /* _WIN32 */ return (-1); } } @@ -4717,7 +4788,7 @@ http_write(http_t *http, /* I - HTTP connection */ if (bytes < 0) { -#ifdef WIN32 +#ifdef _WIN32 if (WSAGetLastError() == WSAEINTR) continue; else if (WSAGetLastError() == WSAEWOULDBLOCK) @@ -4751,7 +4822,7 @@ http_write(http_t *http, /* I - HTTP connection */ http->error = errno; continue; } -#endif /* WIN32 */ +#endif /* _WIN32 */ DEBUG_printf(("3http_write: error writing data (%s).", strerror(http->error))); diff --git a/cups/http.h b/cups/http.h index ccbf77ee..e94adae3 100644 --- a/cups/http.h +++ b/cups/http.h @@ -1,7 +1,7 @@ /* * Hyper-Text Transport Protocol definitions for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -25,7 +25,7 @@ # include <string.h> # include <time.h> # include <sys/types.h> -# ifdef WIN32 +# ifdef _WIN32 # ifndef __CUPS_SSIZE_T_DEFINED # define __CUPS_SSIZE_T_DEFINED /* Windows does not support the ssize_t type, so map it to off_t... */ @@ -54,7 +54,7 @@ typedef off_t ssize_t; /* @private@ */ # if defined(LOCAL_PEERCRED) && !defined(SO_PEERCRED) # define SO_PEERCRED LOCAL_PEERCRED # endif /* LOCAL_PEERCRED && !SO_PEERCRED */ -# endif /* WIN32 */ +# endif /* _WIN32 */ /* @@ -85,7 +85,7 @@ extern "C" { # define s6_addr32 _S6_un._S6_u32 # elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)|| defined(__DragonFly__) # define s6_addr32 __u6_addr.__u6_addr32 -# elif defined(WIN32) +# elif defined(_WIN32) /* * Windows only defines byte and 16-bit word members of the union and * requires special casing of all raw address code... @@ -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 */ @@ -181,6 +181,7 @@ typedef enum http_field_e /**** HTTP field names ****/ HTTP_FIELD_ACCEPT_ENCODING, /* Accepting-Encoding field @since CUPS 1.7/macOS 10.9@ */ HTTP_FIELD_ALLOW, /* Allow field @since CUPS 1.7/macOS 10.9@ */ HTTP_FIELD_SERVER, /* Server field @since CUPS 1.7/macOS 10.9@ */ + HTTP_FIELD_AUTHENTICATION_INFO, /* Authentication-Info field (@since CUPS 2.2.9) */ HTTP_FIELD_MAX /* Maximum field index */ } http_field_t; @@ -248,10 +249,11 @@ typedef enum http_status_e /**** HTTP status codes ****/ HTTP_STATUS_MULTIPLE_CHOICES = 300, /* Multiple files match request */ HTTP_STATUS_MOVED_PERMANENTLY, /* Document has moved permanently */ - HTTP_STATUS_MOVED_TEMPORARILY, /* Document has moved temporarily */ - HTTP_STATUS_SEE_OTHER, /* See this other link... */ + HTTP_STATUS_FOUND, /* Document was found at a different URI */ + HTTP_STATUS_SEE_OTHER, /* See this other link */ HTTP_STATUS_NOT_MODIFIED, /* File not modified */ HTTP_STATUS_USE_PROXY, /* Must use a proxy to access this URI */ + HTTP_STATUS_TEMPORARY_REDIRECT = 307, /* Temporary redirection */ HTTP_STATUS_BAD_REQUEST = 400, /* Bad request */ HTTP_STATUS_UNAUTHORIZED, /* Unauthorized to access host */ @@ -285,6 +287,8 @@ typedef enum http_status_e /**** HTTP status codes ****/ HTTP_STATUS_CUPS_PKI_ERROR, /* Error negotiating a secure connection @since CUPS 1.5/macOS 10.7@ */ HTTP_STATUS_CUPS_WEBIF_DISABLED /* Web interface is disabled @private@ */ +# define HTTP_STATUS_MOVED_TEMPORARILY HTTP_STATUS_FOUND /* Renamed in RFC 7231 */ + # ifndef _CUPS_NO_DEPRECATED /* Old names for this enumeration */ # define HTTP_ERROR HTTP_STATUS_ERROR @@ -393,7 +397,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 +431,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 +440,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 */ @@ -475,8 +480,7 @@ extern int httpHead(http_t *http, const char *uri); extern void httpInitialize(void); extern int httpOptions(http_t *http, const char *uri); extern int httpPost(http_t *http, const char *uri); -extern int httpPrintf(http_t *http, const char *format, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); +extern int httpPrintf(http_t *http, const char *format, ...) _CUPS_FORMAT(2, 3); extern int httpPut(http_t *http, const char *uri); extern int httpRead(http_t *http, char *buffer, int length) _CUPS_DEPRECATED_MSG("Use httpRead2 instead."); extern int httpReconnect(http_t *http) _CUPS_DEPRECATED_1_6_MSG("Use httpReconnect2 instead."); diff --git a/cups/ipp-support.c b/cups/ipp-support.c index b49ac0d2..d1ad65c8 100644 --- a/cups/ipp-support.c +++ b/cups/ipp-support.c @@ -1,8 +1,8 @@ /* * Internet Printing Protocol support functions for CUPS. * - * Copyright 2007-2014 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Copyright © 2007-2018 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 @@ -960,9 +960,12 @@ ippCreateRequestedArray(ipp_t *request) /* I - IPP request */ "feed-orientation-supported", "finishings", "finishings-col", + "finishings-col-database", "finishings-col-default", + "finishings-col-ready", "finishings-col-supported", "finishings-default", + "finishings-ready", "finishings-supported", "font-name-requested", "font-name-requested-default", @@ -1001,6 +1004,7 @@ ippCreateRequestedArray(ipp_t *request) /* I - IPP request */ "media-bottom-margin-supported", "media-col", "media-col-default", + "media-col-ready", "media-col-supported", "media-color-supported", "media-default", @@ -1015,6 +1019,7 @@ ippCreateRequestedArray(ipp_t *request) /* I - IPP request */ "media-left-margin-supported", "media-order-count-supported", "media-pre-printed-supported", + "media-ready", "media-recycled-supported", "media-right-margin-supported", "media-size-supported", @@ -1277,9 +1282,12 @@ ippCreateRequestedArray(ipp_t *request) /* I - IPP request */ "feed-orientation-supported", "finishings", "finishings-col", + "finishings-col-database", "finishings-col-default", + "finishings-col-ready", "finishings-col-supported", "finishings-default", + "finishings-ready", "finishings-supported", "font-name-requested", "font-name-requested-default", @@ -1383,6 +1391,7 @@ ippCreateRequestedArray(ipp_t *request) /* I - IPP request */ "media-bottom-margin-supported", "media-col", "media-col-default", + "media-col-ready", "media-col-supported", "media-color-supported", "media-default", @@ -1397,6 +1406,7 @@ ippCreateRequestedArray(ipp_t *request) /* I - IPP request */ "media-left-margin-supported", "media-order-count-supported", "media-pre-printed-supported", + "media-ready", "media-recycled-supported", "media-right-margin-supported", "media-size-supported", @@ -1582,10 +1592,12 @@ ippCreateRequestedArray(ipp_t *request) /* I - IPP request */ "job-page-limit", /* CUPS extension */ "job-password-encryption-supported", "job-password-supported", + "job-presets-supported", /* IPP Presets */ "job-quota-period", /* CUPS extension */ "job-resolvers-supported", "job-settable-attributes-supported", "job-spooling-supported", + "job-triggers-supported", /* IPP Presets */ "jpeg-k-octets-supported", /* CUPS extension */ "jpeg-x-dimension-supported", /* CUPS extension */ "jpeg-y-dimension-supported", /* CUPS extension */ @@ -1599,8 +1611,6 @@ ippCreateRequestedArray(ipp_t *request) /* I - IPP request */ "marker-message", /* CUPS extension */ "marker-names", /* CUPS extension */ "marker-types", /* CUPS extension */ - "media-col-ready", - "media-ready", "member-names", /* CUPS extension */ "member-uris", /* CUPS extension */ "multiple-destination-uris-supported",/* IPP FaxOut */ @@ -1623,6 +1633,8 @@ ippCreateRequestedArray(ipp_t *request) /* I - IPP request */ "printer-charge-info", "printer-charge-info-uri", "printer-commands", /* CUPS extension */ + "printer-config-change-date-time", + "printer-config-change-time", "printer-current-time", "printer-detailed-status-messages", "printer-device-id", @@ -2243,7 +2255,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@ */ @@ -2263,7 +2275,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@ */ @@ -1,8 +1,8 @@ /* * Internet Printing Protocol functions for CUPS. * - * Copyright 2007-2017 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Copyright © 2007-2018 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 @@ -19,9 +19,9 @@ #include "cups-private.h" #include <regex.h> -#ifdef WIN32 +#ifdef _WIN32 # include <io.h> -#endif /* WIN32 */ +#endif /* _WIN32 */ /* @@ -33,12 +33,8 @@ static ipp_attribute_t *ipp_add_attr(ipp_t *ipp, const char *name, int num_values); static void ipp_free_values(ipp_attribute_t *attr, int element, int count); -static char *ipp_get_code(const char *locale, char *buffer, - size_t bufsize) - __attribute__((nonnull(1,2))); -static char *ipp_lang_code(const char *locale, char *buffer, - size_t bufsize) - __attribute__((nonnull(1,2))); +static char *ipp_get_code(const char *locale, char *buffer, size_t bufsize) _CUPS_NONNULL((1, 2)); +static char *ipp_lang_code(const char *locale, char *buffer, size_t bufsize) _CUPS_NONNULL((1, 2)); static size_t ipp_length(ipp_t *ipp, int collection); static ssize_t ipp_read_http(http_t *http, ipp_uchar_t *buffer, size_t length); @@ -316,7 +312,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 +1376,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@ */ @@ -1483,6 +1479,7 @@ ippCopyAttribute( int quickcopy) /* I - 1 for a referenced copy, 0 for normal */ { int i; /* Looping var */ + ipp_tag_t srctag; /* Source value tag */ ipp_attribute_t *dstattr; /* Destination attribute */ _ipp_value_t *srcval, /* Source value */ *dstval; /* Destination value */ @@ -1501,144 +1498,86 @@ ippCopyAttribute( * Copy it... */ - quickcopy = quickcopy ? IPP_TAG_CUPS_CONST : 0; + quickcopy = (quickcopy && (srcattr->value_tag & IPP_TAG_CUPS_CONST)) ? IPP_TAG_CUPS_CONST : 0; + srctag = srcattr->value_tag & IPP_TAG_CUPS_MASK; - switch (srcattr->value_tag & ~IPP_TAG_CUPS_CONST) + switch (srctag) { case IPP_TAG_ZERO : dstattr = ippAddSeparator(dst); break; - case IPP_TAG_INTEGER : - case IPP_TAG_ENUM : - dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag, - srcattr->name, srcattr->num_values, NULL); - if (!dstattr) - break; - - for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; - i > 0; - i --, srcval ++, dstval ++) - dstval->integer = srcval->integer; + case IPP_TAG_UNSUPPORTED_VALUE : + case IPP_TAG_DEFAULT : + case IPP_TAG_UNKNOWN : + case IPP_TAG_NOVALUE : + case IPP_TAG_NOTSETTABLE : + case IPP_TAG_DELETEATTR : + case IPP_TAG_ADMINDEFINE : + dstattr = ippAddOutOfBand(dst, srcattr->group_tag, srctag, srcattr->name); break; + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : case IPP_TAG_BOOLEAN : - dstattr = ippAddBooleans(dst, srcattr->group_tag, srcattr->name, - srcattr->num_values, NULL); - if (!dstattr) - break; - - for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; - i > 0; - i --, srcval ++, dstval ++) - dstval->boolean = srcval->boolean; + case IPP_TAG_DATE : + case IPP_TAG_RESOLUTION : + case IPP_TAG_RANGE : + if ((dstattr = ipp_add_attr(dst, srcattr->name, srcattr->group_tag, srctag, srcattr->num_values)) != NULL) + memcpy(dstattr->values, srcattr->values, (size_t)srcattr->num_values * sizeof(_ipp_value_t)); break; case IPP_TAG_TEXT : case IPP_TAG_NAME : + case IPP_TAG_RESERVED_STRING : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : case IPP_TAG_MIMETYPE : - dstattr = ippAddStrings(dst, srcattr->group_tag, - (ipp_tag_t)(srcattr->value_tag | quickcopy), - srcattr->name, srcattr->num_values, NULL, NULL); - if (!dstattr) + if ((dstattr = ippAddStrings(dst, srcattr->group_tag, (ipp_tag_t)(srctag | quickcopy), srcattr->name, srcattr->num_values, NULL, NULL)) == NULL) break; if (quickcopy) { - for (i = srcattr->num_values, srcval = srcattr->values, - dstval = dstattr->values; - i > 0; - i --, srcval ++, dstval ++) - dstval->string.text = srcval->string.text; + /* + * Can safely quick-copy these string values... + */ + + memcpy(dstattr->values, srcattr->values, (size_t)srcattr->num_values * sizeof(_ipp_value_t)); } - else if (srcattr->value_tag & IPP_TAG_CUPS_CONST) - { - for (i = srcattr->num_values, srcval = srcattr->values, - dstval = dstattr->values; - i > 0; - i --, srcval ++, dstval ++) - dstval->string.text = _cupsStrAlloc(srcval->string.text); - } else { - for (i = srcattr->num_values, srcval = srcattr->values, - dstval = dstattr->values; - i > 0; - i --, srcval ++, dstval ++) - dstval->string.text = _cupsStrRetain(srcval->string.text); - } - break; - - case IPP_TAG_DATE : - if (srcattr->num_values != 1) - return (NULL); - - dstattr = ippAddDate(dst, srcattr->group_tag, srcattr->name, - srcattr->values[0].date); - break; - - case IPP_TAG_RESOLUTION : - dstattr = ippAddResolutions(dst, srcattr->group_tag, srcattr->name, - srcattr->num_values, IPP_RES_PER_INCH, - NULL, NULL); - if (!dstattr) - break; - - for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; - i > 0; - i --, srcval ++, dstval ++) - { - dstval->resolution.xres = srcval->resolution.xres; - dstval->resolution.yres = srcval->resolution.yres; - dstval->resolution.units = srcval->resolution.units; - } - break; - - case IPP_TAG_RANGE : - dstattr = ippAddRanges(dst, srcattr->group_tag, srcattr->name, - srcattr->num_values, NULL, NULL); - if (!dstattr) - break; + /* + * Otherwise do a normal reference counted copy... + */ - for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; - i > 0; - i --, srcval ++, dstval ++) - { - dstval->range.lower = srcval->range.lower; - dstval->range.upper = srcval->range.upper; + for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) + dstval->string.text = _cupsStrAlloc(srcval->string.text); } break; case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : - dstattr = ippAddStrings(dst, srcattr->group_tag, - (ipp_tag_t)(srcattr->value_tag | quickcopy), - srcattr->name, srcattr->num_values, NULL, NULL); - if (!dstattr) + if ((dstattr = ippAddStrings(dst, srcattr->group_tag, (ipp_tag_t)(srctag | quickcopy), srcattr->name, srcattr->num_values, NULL, NULL)) == NULL) break; if (quickcopy) { - for (i = srcattr->num_values, srcval = srcattr->values, - dstval = dstattr->values; - i > 0; - i --, srcval ++, dstval ++) - { - dstval->string.language = srcval->string.language; - dstval->string.text = srcval->string.text; - } + /* + * Can safely quick-copy these string values... + */ + + memcpy(dstattr->values, srcattr->values, (size_t)srcattr->num_values * sizeof(_ipp_value_t)); } else if (srcattr->value_tag & IPP_TAG_CUPS_CONST) { - for (i = srcattr->num_values, srcval = srcattr->values, - dstval = dstattr->values; - i > 0; - i --, srcval ++, dstval ++) + /* + * Otherwise do a normal reference counted copy... + */ + + for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) { if (srcval == srcattr->values) dstval->string.language = _cupsStrAlloc(srcval->string.language); @@ -1648,32 +1587,13 @@ ippCopyAttribute( dstval->string.text = _cupsStrAlloc(srcval->string.text); } } - else - { - for (i = srcattr->num_values, srcval = srcattr->values, - dstval = dstattr->values; - i > 0; - i --, srcval ++, dstval ++) - { - if (srcval == srcattr->values) - dstval->string.language = _cupsStrRetain(srcval->string.language); - else - dstval->string.language = dstattr->values[0].string.language; - - dstval->string.text = _cupsStrRetain(srcval->string.text); - } - } break; case IPP_TAG_BEGIN_COLLECTION : - dstattr = ippAddCollections(dst, srcattr->group_tag, srcattr->name, - srcattr->num_values, NULL); - if (!dstattr) + if ((dstattr = ippAddCollections(dst, srcattr->group_tag, srcattr->name, srcattr->num_values, NULL)) == NULL) break; - for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; - i > 0; - i --, srcval ++, dstval ++) + for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) { dstval->collection = srcval->collection; srcval->collection->use ++; @@ -1682,15 +1602,10 @@ ippCopyAttribute( case IPP_TAG_STRING : default : - /* TODO: Implement quick copy for unknown/octetString values */ - dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag, - srcattr->name, srcattr->num_values, NULL); - if (!dstattr) + if ((dstattr = ipp_add_attr(dst, srcattr->name, srcattr->group_tag, srctag, srcattr->num_values)) == NULL) break; - for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; - i > 0; - i --, srcval ++, dstval ++) + for (i = srcattr->num_values, srcval = srcattr->values, dstval = dstattr->values; i > 0; i --, srcval ++, dstval ++) { dstval->unknown.length = srcval->unknown.length; @@ -1759,12 +1674,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 */ @@ -1776,7 +1691,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 * ------- ----------- @@ -1828,12 +1743,19 @@ ippDelete(ipp_t *ipp) /* I - IPP message */ ipp->use --; if (ipp->use > 0) + { + DEBUG_printf(("4debug_retain: %p IPP message (use=%d)", (void *)ipp, ipp->use)); return; + } + + DEBUG_printf(("4debug_free: %p IPP message", (void *)ipp)); for (attr = ipp->attrs; attr != NULL; attr = next) { next = attr->next; + DEBUG_printf(("4debug_free: %p %s %s%s (%d values)", (void *)attr, attr->name, attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag), attr->num_values)); + ipp_free_values(attr, 0, attr->num_values); if (attr->name) @@ -1870,6 +1792,8 @@ ippDeleteAttribute( if (!attr) return; + DEBUG_printf(("4debug_free: %p %s %s%s (%d values)", (void *)attr, attr->name, attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag), attr->num_values)); + /* * Find the attribute in the list... */ @@ -2152,7 +2076,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@ */ @@ -2181,7 +2105,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@ */ @@ -2232,15 +2156,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) */ { @@ -2288,7 +2212,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@ */ @@ -2341,7 +2265,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@ */ @@ -2404,7 +2328,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@ */ @@ -2466,7 +2390,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@ */ @@ -2560,7 +2484,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@ */ @@ -2625,7 +2549,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,6 +2629,8 @@ ippNew(void) * Set default version - usually 2.0... */ + DEBUG_printf(("4debug_alloc: %p IPP message", (void *)temp)); + if (cg->server_version == 0) _cupsSetDefaults(); @@ -2722,9 +2648,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@ */ @@ -2786,11 +2712,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@ @@ -3068,6 +2994,13 @@ ippReadIO(void *src, /* I - Data source */ ipp->state = IPP_STATE_DATA; break; } + else if (tag == IPP_TAG_ZERO || (tag == IPP_TAG_OPERATION && ipp->curtag != IPP_TAG_ZERO)) + { + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Invalid group tag."), 1); + DEBUG_printf(("1ippReadIO: bad tag 0x%02x.", tag)); + _cupsBufferRelease((char *)buffer); + return (IPP_STATE_ERROR); + } else if (tag < IPP_TAG_UNSUPPORTED_VALUE) { /* @@ -3365,7 +3298,10 @@ ippReadIO(void *src, /* I - Data source */ value->boolean = (char)buffer[0]; break; - case IPP_TAG_NOVALUE : + case IPP_TAG_UNSUPPORTED_VALUE : + case IPP_TAG_DEFAULT : + case IPP_TAG_UNKNOWN : + case IPP_TAG_NOVALUE : case IPP_TAG_NOTSETTABLE : case IPP_TAG_DELETEATTR : case IPP_TAG_ADMINDEFINE : @@ -3385,6 +3321,7 @@ ippReadIO(void *src, /* I - Data source */ case IPP_TAG_TEXT : case IPP_TAG_NAME : + case IPP_TAG_RESERVED_STRING : case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : @@ -3706,7 +3643,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@ */ @@ -3748,7 +3685,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@ */ @@ -3789,7 +3726,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. @@ -3797,7 +3734,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@ */ @@ -3806,7 +3743,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 */ @@ -3854,7 +3791,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 || @@ -3881,7 +3818,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@ */ @@ -3966,7 +3903,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@ */ @@ -4084,7 +4021,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@ */ @@ -4164,7 +4101,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@ */ @@ -4272,7 +4209,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@ */ @@ -4285,17 +4222,21 @@ ippSetString(ipp_t *ipp, /* I - IPP message */ { char *temp; /* Temporary string */ _ipp_value_t *value; /* Current value */ + ipp_tag_t value_tag; /* Value tag */ /* * Range check input... */ + if (attr && *attr) + value_tag = (*attr)->value_tag & IPP_TAG_CUPS_MASK; + else + value_tag = IPP_TAG_ZERO; + if (!ipp || !attr || !*attr || - ((*attr)->value_tag != IPP_TAG_TEXTLANG && - (*attr)->value_tag != IPP_TAG_NAMELANG && - ((*attr)->value_tag < IPP_TAG_TEXT || - (*attr)->value_tag > IPP_TAG_MIMETYPE)) || + (value_tag < IPP_TAG_TEXT && value_tag != IPP_TAG_TEXTLANG && + value_tag != IPP_TAG_NAMELANG) || value_tag > IPP_TAG_MIMETYPE || element < 0 || element > (*attr)->num_values || !strvalue) return (0); @@ -4334,7 +4275,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 @@ -4372,7 +4313,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 @@ -4710,19 +4651,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 * ------- ----------- @@ -4762,7 +4703,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@ */ @@ -4782,21 +4723,6 @@ ippValidateAttribute( ipp_attribute_t *colattr; /* Collection attribute */ regex_t re; /* Regular expression */ ipp_uchar_t *date; /* Current date value */ - static const char * const uri_status_strings[] = - { /* URI status strings */ - "URI too large", - "Bad arguments to function", - "Bad resource in URI", - "Bad port number in URI", - "Bad hostname/address in URI", - "Bad username in URI", - "Bad scheme in URI", - "Bad/empty URI", - "OK", - "Missing scheme in URI", - "Unknown scheme in URI", - "Missing resource in URI" - }; /* @@ -4818,7 +4744,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); } @@ -4826,7 +4752,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); } @@ -4844,7 +4770,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); } @@ -4858,7 +4784,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); } @@ -4872,7 +4798,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); } @@ -4888,7 +4814,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); } @@ -4896,7 +4822,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); } @@ -4904,7 +4830,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); } @@ -4912,7 +4838,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); } @@ -4920,7 +4846,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); } @@ -4928,7 +4854,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); } @@ -4936,7 +4862,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); } @@ -4944,7 +4870,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); } @@ -4952,7 +4878,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); } } @@ -4966,7 +4892,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 == @@ -4981,7 +4907,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 == @@ -4996,7 +4922,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 == @@ -5015,7 +4941,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); @@ -5071,22 +4997,29 @@ ippValidateAttribute( } else if (*ptr & 0x80) break; + else if ((*ptr < ' ' && *ptr != '\n' && *ptr != '\r' && *ptr != '\t') || *ptr == 0x7f) + break; } - if (*ptr) - { - 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, - attr->values[i].string.text); - return (0); - } + if (*ptr) + { + if (*ptr < ' ' || *ptr == 0x7f) + { + ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad text value \"%s\" - bad control character (PWG 5100.14 section 8.3)."), attr->name, attr->values[i].string.text); + return (0); + } + else + { + ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad text value \"%s\" - bad UTF-8 sequence (RFC 8011 section 5.1.2)."), attr->name, attr->values[i].string.text); + return (0); + } + } if ((ptr - attr->values[i].string.text) > (IPP_MAX_TEXT - 1)) { 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); @@ -5129,22 +5062,29 @@ ippValidateAttribute( } else if (*ptr & 0x80) break; + else if (*ptr < ' ' || *ptr == 0x7f) + break; } if (*ptr) { - 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, - attr->values[i].string.text); - return (0); - } + if (*ptr < ' ' || *ptr == 0x7f) + { + ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad name value \"%s\" - bad control character (PWG 5100.14 section 8.1)."), attr->name, attr->values[i].string.text); + return (0); + } + else + { + ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad name value \"%s\" - bad UTF-8 sequence (RFC 8011 section 5.1.3)."), attr->name, attr->values[i].string.text); + return (0); + } + } if ((ptr - attr->values[i].string.text) > (IPP_MAX_NAME - 1)) { 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); @@ -5164,7 +5104,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); } @@ -5173,7 +5113,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); @@ -5193,12 +5133,7 @@ ippValidateAttribute( if (uri_status < HTTP_URI_STATUS_OK) { - ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, - _("\"%s\": Bad URI value \"%s\" - %s " - "(RFC 2911 section 4.1.5)."), attr->name, - attr->values[i].string.text, - uri_status_strings[uri_status - - HTTP_URI_STATUS_OVERFLOW]); + ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad URI value \"%s\" - %s (RFC 8011 section 5.1.6)."), attr->name, attr->values[i].string.text, httpURIStatusString(uri_status)); return (0); } @@ -5206,7 +5141,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)); } @@ -5229,7 +5164,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); } @@ -5238,7 +5173,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); @@ -5258,7 +5193,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); } @@ -5267,7 +5202,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); @@ -5313,7 +5248,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); @@ -5323,7 +5258,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); @@ -5367,7 +5302,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); @@ -5377,7 +5312,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); @@ -5400,8 +5335,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@ */ @@ -6397,6 +6332,8 @@ ipp_add_attr(ipp_t *ipp, /* I - IPP message */ * Initialize attribute... */ + DEBUG_printf(("4debug_alloc: %p %s %s%s (%d values)", (void *)attr, name, num_values > 1 ? "1setOf " : "", ippTagString(value_tag), num_values)); + if (name) attr->name = _cupsStrAlloc(name); @@ -6474,6 +6411,7 @@ ipp_free_values(ipp_attribute_t *attr, /* I - Attribute to free values from */ } break; + case IPP_TAG_UNSUPPORTED_VALUE : case IPP_TAG_DEFAULT : case IPP_TAG_UNKNOWN : case IPP_TAG_NOVALUE : @@ -6815,14 +6753,14 @@ ipp_read_http(http_t *http, /* I - Client connection */ if ((bytes = httpRead2(http, (char *)buffer, length - (size_t)tbytes)) < 0) { -#ifdef WIN32 +#ifdef _WIN32 break; #else if (errno != EAGAIN && errno != EINTR) break; bytes = 0; -#endif /* WIN32 */ +#endif /* _WIN32 */ } else if (bytes == 0) break; @@ -6850,11 +6788,11 @@ ipp_read_file(int *fd, /* I - File descriptor */ ipp_uchar_t *buffer, /* O - Read buffer */ size_t length) /* I - Number of bytes to read */ { -#ifdef WIN32 +#ifdef _WIN32 return ((ssize_t)read(*fd, buffer, (unsigned)length)); #else return (read(*fd, buffer, length)); -#endif /* WIN32 */ +#endif /* _WIN32 */ } @@ -6953,6 +6891,9 @@ ipp_set_value(ipp_t *ipp, /* IO - IPP message */ * Reset pointers in the list... */ + DEBUG_printf(("4debug_free: %p %s", (void *)*attr, temp->name)); + DEBUG_printf(("4debug_alloc: %p %s %s%s (%d)", (void *)temp, temp->name, temp->num_values > 1 ? "1setOf " : "", ippTagString(temp->value_tag), temp->num_values)); + if (ipp->current == *attr && ipp->prev) { /* @@ -7019,9 +6960,9 @@ ipp_write_file(int *fd, /* I - File descriptor */ ipp_uchar_t *buffer, /* I - Data to write */ size_t length) /* I - Number of bytes to write */ { -#ifdef WIN32 +#ifdef _WIN32 return ((ssize_t)write(*fd, buffer, (unsigned)length)); #else return (write(*fd, buffer, length)); -#endif /* WIN32 */ +#endif /* _WIN32 */ } @@ -1,7 +1,7 @@ /* * 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 @@ -77,13 +77,13 @@ 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 */ - IPP_DOCUMENT_CANCELED = 7, /* Document is canceled */ - IPP_DOCUMENT_ABORTED, /* Document is aborted */ - IPP_DOCUMENT_COMPLETED /* Document is completed */ + IPP_DSTATE_PENDING = 3, /* Document is pending */ + IPP_DSTATE_PROCESSING = 5, /* Document is processing */ + IPP_DSTATE_CANCELED = 7, /* Document is canceled */ + IPP_DSTATE_ABORTED, /* Document is aborted */ + IPP_DSTATE_COMPLETED /* Document is completed */ # ifndef _CUPS_NO_DEPRECATED # define IPP_DOCUMENT_PENDING IPP_DSTATE_PENDING @@ -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 */ @@ -169,38 +169,38 @@ typedef enum ipp_finishings_e /**** Finishings ****/ /* 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 @@ -208,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, @@ -248,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 @@ -364,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 @@ -442,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 */ @@ -455,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 */ @@ -468,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 */ @@ -485,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 */ @@ -498,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 */ @@ -574,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 @@ -636,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 */ @@ -648,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 */ @@ -663,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@ */ @@ -676,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@ */ @@ -688,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 ****/ /* @@ -805,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/language-private.h b/cups/language-private.h index 49e4b713..f447ef92 100644 --- a/cups/language-private.h +++ b/cups/language-private.h @@ -1,7 +1,7 @@ /* * Private localization support for CUPS. * - * Copyright 2007-2017 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -20,6 +20,7 @@ * Include necessary headers... */ +# include "config.h" # include <stdio.h> # include <cups/transcode.h> # ifdef __APPLE__ @@ -59,16 +60,11 @@ extern const char *_cupsAppleLocale(CFStringRef languageName, char *locale, size # endif /* __APPLE__ */ extern void _cupsCharmapFlush(void); extern const char *_cupsEncodingName(cups_encoding_t encoding); -extern void _cupsLangPrintError(const char *prefix, - const char *message); -extern int _cupsLangPrintFilter(FILE *fp, const char *prefix, - const char *message, ...) - __attribute__ ((__format__ (__printf__, 3, 4))); -extern int _cupsLangPrintf(FILE *fp, const char *message, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); +extern void _cupsLangPrintError(const char *prefix, const char *message); +extern int _cupsLangPrintFilter(FILE *fp, const char *prefix, const char *message, ...) _CUPS_FORMAT(3, 4); +extern int _cupsLangPrintf(FILE *fp, const char *message, ...) _CUPS_FORMAT(2, 3); extern int _cupsLangPuts(FILE *fp, const char *message); -extern const char *_cupsLangString(cups_lang_t *lang, - const char *message); +extern const char *_cupsLangString(cups_lang_t *lang, const char *message); extern void _cupsMessageFree(cups_array_t *a); extern cups_array_t *_cupsMessageLoad(const char *filename, int unquote); extern const char *_cupsMessageLookup(cups_array_t *a, const char *m); diff --git a/cups/language.c b/cups/language.c index f3a3496b..61280c0f 100644 --- a/cups/language.c +++ b/cups/language.c @@ -21,11 +21,11 @@ #ifdef HAVE_LANGINFO_H # include <langinfo.h> #endif /* HAVE_LANGINFO_H */ -#ifdef WIN32 +#ifdef _WIN32 # include <io.h> #else # include <unistd.h> -#endif /* WIN32 */ +#endif /* _WIN32 */ #ifdef HAVE_COREFOUNDATION_H # include <CoreFoundation/CoreFoundation.h> #endif /* HAVE_COREFOUNDATION_H */ @@ -123,7 +123,9 @@ static const _apple_language_locale_t apple_language_locale[] = { "nb", "no" }, { "nb_NO", "no" }, { "zh-Hans", "zh_CN" }, + { "zh_HANS", "zh_CN" }, { "zh-Hant", "zh_TW" }, + { "zh_HANT", "zh_TW" }, { "zh-Hant_CN", "zh_TW" } }; #endif /* __APPLE__ */ @@ -254,7 +256,15 @@ _cupsAppleLocale(CFStringRef languageName, /* I - Apple language ID */ { int i; /* Looping var */ CFStringRef localeName; /* Locale as a CF string */ +#ifdef DEBUG + char temp[1024]; /* Temporary string */ + + if (!CFStringGetCString(languageName, temp, (CFIndex)sizeof(temp), kCFStringEncodingASCII)) + temp[0] = '\0'; + + DEBUG_printf(("_cupsAppleLocale(languageName=%p(%s), locale=%p, localsize=%d)", (void *)languageName, temp, (void *)locale, (int)localesize)); +#endif /* DEBUG */ localeName = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorDefault, languageName); @@ -267,6 +277,8 @@ _cupsAppleLocale(CFStringRef languageName, /* I - Apple language ID */ if (!CFStringGetCString(localeName, locale, (CFIndex)localesize, kCFStringEncodingASCII)) *locale = '\0'; + DEBUG_printf(("_cupsAppleLocale: locale=\"%s\"", locale)); + CFRelease(localeName); /* @@ -278,8 +290,12 @@ _cupsAppleLocale(CFStringRef languageName, /* I - Apple language ID */ sizeof(apple_language_locale[0])); i ++) { - if (!strcmp(locale, apple_language_locale[i].language)) + size_t len = strlen(apple_language_locale[i].language); + + if (!strcmp(locale, apple_language_locale[i].language) || + (!strncmp(locale, apple_language_locale[i].language, len) && (locale[len] == '_' || locale[len] == '-'))) { + DEBUG_printf(("_cupsAppleLocale: Updating locale to \"%s\".", apple_language_locale[i].locale)); strlcpy(locale, apple_language_locale[i].locale, localesize); break; } @@ -296,7 +312,10 @@ _cupsAppleLocale(CFStringRef languageName, /* I - Apple language ID */ } if (!*locale) + { + DEBUG_puts("_cupsAppleLocale: Returning NULL."); return (NULL); + } /* * Convert language subtag into region subtag... @@ -304,10 +323,14 @@ _cupsAppleLocale(CFStringRef languageName, /* I - Apple language ID */ if (locale[2] == '-') locale[2] = '_'; + else if (locale[3] == '-') + locale[3] = '_'; if (!strchr(locale, '.')) strlcat(locale, ".UTF-8", localesize); + DEBUG_printf(("_cupsAppleLocale: Returning \"%s\".", locale)); + return (locale); } #endif /* __APPLE__ */ @@ -669,6 +692,15 @@ cupsLangGet(const char *language) /* I - Language or locale */ *ptr++ = (char)toupper(*language & 255); *ptr = '\0'; + + /* + * Map Chinese region codes to legacy country codes. + */ + + if (!strcmp(language, "zh") && !strcmp(country, "HANS")) + strlcpy(country, "CN", sizeof(country)); + if (!strcmp(language, "zh") && !strcmp(country, "HANT")) + strlcpy(country, "TW", sizeof(country)); } if (*language == '.' && !charset[0]) @@ -688,7 +720,7 @@ cupsLangGet(const char *language) /* I - Language or locale */ * Force a POSIX locale for an invalid language name... */ - if (strlen(langname) != 2) + if (strlen(langname) != 2 && strlen(langname) != 3) { strlcpy(langname, "C", sizeof(langname)); country[0] = '\0'; @@ -828,6 +860,9 @@ _cupsLangString(cups_lang_t *lang, /* I - Language */ { const char *s; /* Localized message */ + + DEBUG_printf(("_cupsLangString(lang=%p, message=\"%s\")", (void *)lang, message)); + /* * Range check input... */ @@ -1126,6 +1161,8 @@ _cupsMessageLookup(cups_array_t *a, /* I - Message array */ *match; /* Matching message */ + DEBUG_printf(("_cupsMessageLookup(a=%p, m=\"%s\")", (void *)a, m)); + /* * Lookup the message string; if it doesn't exist in the catalog, * then return the message that was passed to us... @@ -1336,11 +1373,13 @@ appleMessageLoad(const char *locale) /* I - Locale ID */ { char filename[1024], /* Path to cups.strings file */ applelang[256], /* Apple language ID */ - baselang[3]; /* Base language */ + baselang[4]; /* Base language */ CFURLRef url; /* URL to cups.strings file */ CFReadStreamRef stream = NULL; /* File stream */ CFPropertyListRef plist = NULL; /* Localization file */ #ifdef DEBUG + const char *cups_strings = getenv("CUPS_STRINGS"); + /* Test strings file */ CFErrorRef error = NULL; /* Error when opening file */ #endif /* DEBUG */ @@ -1351,6 +1390,15 @@ appleMessageLoad(const char *locale) /* I - Locale ID */ * Load the cups.strings file... */ +#ifdef DEBUG + if (cups_strings) + { + DEBUG_puts("1appleMessageLoad: Using debug CUPS_STRINGS file."); + strlcpy(filename, cups_strings, sizeof(filename)); + } + else +#endif /* DEBUG */ + snprintf(filename, sizeof(filename), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", _cupsAppleLanguage(locale, applelang, sizeof(applelang))); @@ -1363,6 +1411,7 @@ appleMessageLoad(const char *locale) /* I - Locale ID */ * Try with original locale string... */ + DEBUG_printf(("1appleMessageLoad: \"%s\": %s", filename, strerror(errno))); snprintf(filename, sizeof(filename), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", locale); } @@ -1374,18 +1423,23 @@ appleMessageLoad(const char *locale) /* I - Locale ID */ * Try with just the language code... */ + DEBUG_printf(("1appleMessageLoad: \"%s\": %s", filename, strerror(errno))); + strlcpy(baselang, locale, sizeof(baselang)); + if (baselang[3] == '-' || baselang[3] == '_') + baselang[3] = '\0'; + snprintf(filename, sizeof(filename), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", baselang); } - DEBUG_printf(("1appleMessageLoad: filename=\"%s\"", filename)); - if (access(filename, 0)) { /* * Try alternate lproj directory names... */ + DEBUG_printf(("1appleMessageLoad: \"%s\": %s", filename, strerror(errno))); + if (!strncmp(locale, "en", 2)) locale = "English"; else if (!strncmp(locale, "nb", 2)) @@ -1402,7 +1456,7 @@ appleMessageLoad(const char *locale) /* I - Locale ID */ locale = "Japanese"; else if (!strncmp(locale, "es", 2)) locale = "Spanish"; - else if (!strcmp(locale, "zh_HK") || !strncmp(locale, "zh-Hant", 7)) + else if (!strcmp(locale, "zh_HK") || !strncasecmp(locale, "zh-Hant", 7) || !strncasecmp(locale, "zh_Hant", 7)) { /* * <rdar://problem/22130168> @@ -1423,14 +1477,18 @@ appleMessageLoad(const char *locale) /* I - Locale ID */ */ strlcpy(baselang, locale, sizeof(baselang)); + if (baselang[2] == '-' || baselang[2] == '_') + baselang[2] = '\0'; + locale = baselang; } snprintf(filename, sizeof(filename), CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", locale); - DEBUG_printf(("1appleMessageLoad: alternate filename=\"%s\"", filename)); } + DEBUG_printf(("1appleMessageLoad: filename=\"%s\"", filename)); + url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)filename, (CFIndex)strlen(filename), false); diff --git a/cups/language.h b/cups/language.h index 0a3da779..c96cbfe9 100644 --- a/cups/language.h +++ b/cups/language.h @@ -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 a7be679f..fa4aaa3b 100644 --- a/cups/libcups2.def +++ b/cups/libcups2.def @@ -1,5 +1,5 @@ LIBRARY libcups2 -VERSION 2.12 +VERSION 2.13 EXPORTS _cupsArrayAddStrings _cupsArrayNewStrings @@ -13,6 +13,7 @@ _cupsConnect _cupsConvertOptions _cupsCreateDest _cupsEncodingName +_cupsFilePeekAhead _cupsGet1284Values _cupsGetDestResource _cupsGetDests @@ -24,9 +25,6 @@ _cupsLangPrintError _cupsLangPrintf _cupsLangPuts _cupsLangString -_cupsMD5Append -_cupsMD5Finish -_cupsMD5Init _cupsMessageFree _cupsMessageLoad _cupsMessageLookup @@ -39,18 +37,6 @@ _cupsRWInit _cupsRWLockRead _cupsRWLockWrite _cupsRWUnlock -_cupsSNMPClose -_cupsSNMPCopyOID -_cupsSNMPDefaultCommunity -_cupsSNMPIsOID -_cupsSNMPIsOIDPrefixed -_cupsSNMPOIDToString -_cupsSNMPOpen -_cupsSNMPRead -_cupsSNMPSetDebug -_cupsSNMPStringToOID -_cupsSNMPWalk -_cupsSNMPWrite _cupsSetDefaults _cupsSetError _cupsSetHTTPError @@ -65,6 +51,7 @@ _cupsStrScand _cupsStrStatistics _cupsThreadCancel _cupsThreadCreate +_cupsThreadDetach _cupsThreadWait _cupsUserDefault _cups_safe_vsnprintf @@ -81,6 +68,7 @@ _httpDisconnect _httpEncodeURI _httpFreeCredentials _httpResolveURI +_httpSetDigestAuthString _httpStatus _httpTLSInitialize _httpTLSPending @@ -124,6 +112,7 @@ _pwgMediaTable _pwgMediaTypeForType _pwgPageSizeForMedia cupsAddDest +cupsAddIntegerOption cupsAddOption cupsAdminCreateWindowsPPD cupsAdminExportSamba @@ -227,6 +216,7 @@ cupsGetDests2 cupsGetDevices cupsGetFd cupsGetFile +cupsGetIntegerOption cupsGetJobs cupsGetJobs2 cupsGetNamedDest @@ -240,6 +230,7 @@ cupsGetPrinters cupsGetResponse cupsGetServerPPD cupsHashData +cupsHashString cupsLangDefault cupsLangEncoding cupsLangFlush @@ -1,7 +1,7 @@ /* * Private MD5 implementation for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2017 by Apple Inc. * Copyright 2005 by Easy Software Products * Copyright (C) 1999 Aladdin Enterprises. All rights reserved. * @@ -43,70 +43,71 @@ #include "md5-private.h" #include "string-private.h" -#define T1 0xd76aa478 -#define T2 0xe8c7b756 -#define T3 0x242070db -#define T4 0xc1bdceee -#define T5 0xf57c0faf -#define T6 0x4787c62a -#define T7 0xa8304613 -#define T8 0xfd469501 -#define T9 0x698098d8 -#define T10 0x8b44f7af -#define T11 0xffff5bb1 -#define T12 0x895cd7be -#define T13 0x6b901122 -#define T14 0xfd987193 -#define T15 0xa679438e -#define T16 0x49b40821 -#define T17 0xf61e2562 -#define T18 0xc040b340 -#define T19 0x265e5a51 -#define T20 0xe9b6c7aa -#define T21 0xd62f105d -#define T22 0x02441453 -#define T23 0xd8a1e681 -#define T24 0xe7d3fbc8 -#define T25 0x21e1cde6 -#define T26 0xc33707d6 -#define T27 0xf4d50d87 -#define T28 0x455a14ed -#define T29 0xa9e3e905 -#define T30 0xfcefa3f8 -#define T31 0x676f02d9 -#define T32 0x8d2a4c8a -#define T33 0xfffa3942 -#define T34 0x8771f681 -#define T35 0x6d9d6122 -#define T36 0xfde5380c -#define T37 0xa4beea44 -#define T38 0x4bdecfa9 -#define T39 0xf6bb4b60 -#define T40 0xbebfbc70 -#define T41 0x289b7ec6 -#define T42 0xeaa127fa -#define T43 0xd4ef3085 -#define T44 0x04881d05 -#define T45 0xd9d4d039 -#define T46 0xe6db99e5 -#define T47 0x1fa27cf8 -#define T48 0xc4ac5665 -#define T49 0xf4292244 -#define T50 0x432aff97 -#define T51 0xab9423a7 -#define T52 0xfc93a039 -#define T53 0x655b59c3 -#define T54 0x8f0ccc92 -#define T55 0xffeff47d -#define T56 0x85845dd1 -#define T57 0x6fa87e4f -#define T58 0xfe2ce6e0 -#define T59 0xa3014314 -#define T60 0x4e0811a1 -#define T61 0xf7537e82 -#define T62 0xbd3af235 -#define T63 0x2ad7d2bb -#define T64 0xeb86d391 +#if !defined(__APPLE__) && !defined(HAVE_GNUTLS) +# define T1 0xd76aa478 +# define T2 0xe8c7b756 +# define T3 0x242070db +# define T4 0xc1bdceee +# define T5 0xf57c0faf +# define T6 0x4787c62a +# define T7 0xa8304613 +# define T8 0xfd469501 +# define T9 0x698098d8 +# define T10 0x8b44f7af +# define T11 0xffff5bb1 +# define T12 0x895cd7be +# define T13 0x6b901122 +# define T14 0xfd987193 +# define T15 0xa679438e +# define T16 0x49b40821 +# define T17 0xf61e2562 +# define T18 0xc040b340 +# define T19 0x265e5a51 +# define T20 0xe9b6c7aa +# define T21 0xd62f105d +# define T22 0x02441453 +# define T23 0xd8a1e681 +# define T24 0xe7d3fbc8 +# define T25 0x21e1cde6 +# define T26 0xc33707d6 +# define T27 0xf4d50d87 +# define T28 0x455a14ed +# define T29 0xa9e3e905 +# define T30 0xfcefa3f8 +# define T31 0x676f02d9 +# define T32 0x8d2a4c8a +# define T33 0xfffa3942 +# define T34 0x8771f681 +# define T35 0x6d9d6122 +# define T36 0xfde5380c +# define T37 0xa4beea44 +# define T38 0x4bdecfa9 +# define T39 0xf6bb4b60 +# define T40 0xbebfbc70 +# define T41 0x289b7ec6 +# define T42 0xeaa127fa +# define T43 0xd4ef3085 +# define T44 0x04881d05 +# define T45 0xd9d4d039 +# define T46 0xe6db99e5 +# define T47 0x1fa27cf8 +# define T48 0xc4ac5665 +# define T49 0xf4292244 +# define T50 0x432aff97 +# define T51 0xab9423a7 +# define T52 0xfc93a039 +# define T53 0x655b59c3 +# define T54 0x8f0ccc92 +# define T55 0xffeff47d +# define T56 0x85845dd1 +# define T57 0x6fa87e4f +# define T58 0xfe2ce6e0 +# define T59 0xa3014314 +# define T60 0x4e0811a1 +# define T61 0xf7537e82 +# define T62 0xbd3af235 +# define T63 0x2ad7d2bb +# define T64 0xeb86d391 static void _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/) @@ -116,10 +117,10 @@ _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/) c = pms->abcd[2], d = pms->abcd[3]; unsigned int t; -#ifndef ARCH_IS_BIG_ENDIAN -# define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */ -#endif -#if ARCH_IS_BIG_ENDIAN +# ifndef ARCH_IS_BIG_ENDIAN +# define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */ +# endif +# if ARCH_IS_BIG_ENDIAN /* * On big-endian machines, we must arrange the bytes in the right @@ -133,7 +134,7 @@ _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/) X[i] = (unsigned)xp[0] + ((unsigned)xp[1] << 8) + ((unsigned)xp[2] << 16) + ((unsigned)xp[3] << 24); -#else /* !ARCH_IS_BIG_ENDIAN */ +# else /* !ARCH_IS_BIG_ENDIAN */ /* * On little-endian machines, we can process properly aligned data @@ -150,15 +151,15 @@ _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/) memcpy(xbuf, data, 64); X = xbuf; } -#endif +# endif -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) +# define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ +# define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +# define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ @@ -178,13 +179,13 @@ _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/) SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); -#undef SET +# undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ +# define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +# define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ @@ -204,13 +205,13 @@ _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/) SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); -#undef SET +# undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ +# define H(x, y, z) ((x) ^ (y) ^ (z)) +# define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ @@ -230,13 +231,13 @@ _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/) SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); -#undef SET +# undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ +# define I(x, y, z) ((y) ^ ((x) | ~(z))) +# define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ @@ -256,7 +257,7 @@ _cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/) SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); -#undef SET +# undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block @@ -337,3 +338,4 @@ _cupsMD5Finish(_cups_md5_state_t *pms, unsigned char digest[16]) for (i = 0; i < 16; ++i) digest[i] = (unsigned char)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } +#endif /* !__APPLE__ && !HAVE_GNUTLS */ diff --git a/cups/md5passwd.c b/cups/md5passwd.c index a9817aaa..49add7d7 100644 --- a/cups/md5passwd.c +++ b/cups/md5passwd.c @@ -1,7 +1,7 @@ /* - * MD5 password support for CUPS. + * MD5 password support for CUPS (deprecated). * - * Copyright 2007-2010 by Apple Inc. + * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2005 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -17,12 +17,15 @@ * Include necessary headers... */ +#include <cups/cups.h> #include "http-private.h" #include "string-private.h" /* * 'httpMD5()' - Compute the MD5 sum of the username:group:password. + * + * @deprecated@ */ char * /* O - MD5 sum */ @@ -31,7 +34,6 @@ httpMD5(const char *username, /* I - User name */ const char *passwd, /* I - Password string */ char md5[33]) /* O - MD5 string */ { - _cups_md5_state_t state; /* MD5 state info */ unsigned char sum[16]; /* Sum data */ char line[256]; /* Line to sum */ @@ -41,15 +43,13 @@ httpMD5(const char *username, /* I - User name */ */ snprintf(line, sizeof(line), "%s:%s:%s", username, realm, passwd); - _cupsMD5Init(&state); - _cupsMD5Append(&state, (unsigned char *)line, (int)strlen(line)); - _cupsMD5Finish(&state, sum); + cupsHashData("md5", (unsigned char *)line, strlen(line), sum, sizeof(sum)); /* * Return the sum... */ - return (httpMD5String(sum, md5)); + return ((char *)cupsHashString(sum, sizeof(sum), md5, 33)); } @@ -57,6 +57,8 @@ httpMD5(const char *username, /* I - User name */ * 'httpMD5Final()' - Combine the MD5 sum of the username, group, and password * with the server-supplied nonce value, method, and * request-uri. + * + * @deprecated@ */ char * /* O - New sum */ @@ -65,7 +67,6 @@ httpMD5Final(const char *nonce, /* I - Server nonce value */ const char *resource, /* I - Resource path */ char md5[33]) /* IO - MD5 sum */ { - _cups_md5_state_t state; /* MD5 state info */ unsigned char sum[16]; /* Sum data */ char line[1024]; /* Line of data */ char a2[33]; /* Hash of method and resource */ @@ -76,10 +77,8 @@ httpMD5Final(const char *nonce, /* I - Server nonce value */ */ snprintf(line, sizeof(line), "%s:%s", method, resource); - _cupsMD5Init(&state); - _cupsMD5Append(&state, (unsigned char *)line, (int)strlen(line)); - _cupsMD5Finish(&state, sum); - httpMD5String(sum, a2); + cupsHashData("md5", (unsigned char *)line, strlen(line), sum, sizeof(sum)); + cupsHashString(sum, sizeof(sum), a2, sizeof(a2)); /* * Then combine A1 (MD5 of username, realm, and password) with the nonce @@ -88,17 +87,16 @@ httpMD5Final(const char *nonce, /* I - Server nonce value */ */ snprintf(line, sizeof(line), "%s:%s:%s", md5, nonce, a2); + cupsHashData("md5", (unsigned char *)line, strlen(line), sum, sizeof(sum)); - _cupsMD5Init(&state); - _cupsMD5Append(&state, (unsigned char *)line, (int)strlen(line)); - _cupsMD5Finish(&state, sum); - - return (httpMD5String(sum, md5)); + return ((char *)cupsHashString(sum, sizeof(sum), md5, 33)); } /* * 'httpMD5String()' - Convert an MD5 sum to a character string. + * + * @deprecated@ */ char * /* O - MD5 sum in hex */ @@ -106,23 +104,5 @@ httpMD5String(const unsigned char *sum, /* I - MD5 sum data */ char md5[33]) /* O - MD5 sum in hex */ { - int i; /* Looping var */ - char *md5ptr; /* Pointer into MD5 string */ - static const char hex[] = "0123456789abcdef"; - /* Hex digits */ - - - /* - * Convert the MD5 sum to hexadecimal... - */ - - for (i = 16, md5ptr = md5; i > 0; i --, sum ++) - { - *md5ptr++ = hex[*sum >> 4]; - *md5ptr++ = hex[*sum & 15]; - } - - *md5ptr = '\0'; - - return (md5); + return ((char *)cupsHashString(sum, 16, md5, 33)); } diff --git a/cups/options.c b/cups/options.c index aa709928..db14bec7 100644 --- a/cups/options.c +++ b/cups/options.c @@ -1,7 +1,7 @@ /* * 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 @@ -30,6 +30,31 @@ static int cups_find_option(const char *name, int num_options, /* + * '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. * * New option arrays can be initialized simply by passing 0 for the @@ -55,6 +80,11 @@ cupsAddOption(const char *name, /* I - Name of option */ return (num_options); } + if (!_cups_strcasecmp(name, "cupsPrintQuality")) + num_options = cupsRemoveOption("print-quality", num_options, options); + else if (!_cups_strcasecmp(name, "print-quality")) + num_options = cupsRemoveOption("cupsPrintQuality", num_options, options); + /* * Look for an existing option with the same name... */ @@ -155,6 +185,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-cache.c b/cups/ppd-cache.c index e7123410..9ed946e6 100644 --- a/cups/ppd-cache.c +++ b/cups/ppd-cache.c @@ -1,7 +1,7 @@ /* * PPD cache implementation for CUPS. * - * Copyright 2010-2017 by Apple Inc. + * Copyright © 2010-2018 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -78,6 +78,8 @@ _cupsConvertOptions( int num_finishings = 0, /* Number of finishing values */ finishings[10]; /* Finishing enum values */ ppd_choice_t *choice; /* Marked choice */ + int finishings_copies = copies; + /* Number of copies for finishings */ /* @@ -366,13 +368,13 @@ _cupsConvertOptions( { ippAddIntegers(request, IPP_TAG_JOB, IPP_TAG_ENUM, "finishings", num_finishings, finishings); - if (copies > 1 && (keyword = cupsGetOption("job-impressions", num_options, options)) != NULL) + if (copies != finishings_copies && (keyword = cupsGetOption("job-impressions", num_options, options)) != NULL) { /* * Send job-pages-per-set attribute to apply finishings correctly... */ - ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", atoi(keyword) / copies); + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-pages-per-set", atoi(keyword) / finishings_copies); } } @@ -2084,11 +2086,16 @@ _ppdCacheGetFinishingValues( DEBUG_printf(("_ppdCacheGetFinishingValues(pc=%p, num_options=%d, options=%p, max_values=%d, values=%p)", pc, num_options, options, max_values, values)); - if (!pc || !pc->finishings || num_options < 1 || max_values < 1 || !values) + if (!pc || max_values < 1 || !values) { DEBUG_puts("_ppdCacheGetFinishingValues: Bad arguments, returning 0."); return (0); } + else if (!pc->finishings) + { + DEBUG_puts("_ppdCacheGetFinishingValues: No finishings support, returning 0."); + return (0); + } /* * Go through the finishings options and see what is set... @@ -2114,7 +2121,7 @@ _ppdCacheGetFinishingValues( if (i == 0) { - DEBUG_printf(("_ppdCacheGetFinishingValues: Adding %d.", f->value)); + DEBUG_printf(("_ppdCacheGetFinishingValues: Adding %d (%s)", f->value, ippEnumString("finishings", f->value))); values[num_values ++] = f->value; @@ -2123,6 +2130,17 @@ _ppdCacheGetFinishingValues( } } + if (num_values == 0) + { + /* + * Always have at least "finishings" = 'none'... + */ + + DEBUG_puts("_ppdCacheGetFinishingValues: Adding 3 (none)."); + values[0] = IPP_FINISHINGS_NONE; + num_values ++; + } + DEBUG_printf(("_ppdCacheGetFinishingValues: Returning %d.", num_values)); return (num_values); @@ -2949,6 +2967,8 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ is_pwg = 0; /* Does the printer support PWG Raster? */ pwg_media_t *pwg; /* PWG media size */ int xres, yres; /* Resolution values */ + int resolutions[1000]; + /* Array of resolution indices */ cups_lang_t *lang = cupsLangDefault(); /* Localization info */ struct lconv *loc = localeconv(); @@ -3085,8 +3105,8 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ cupsFilePrintf(fp, "*Manufacturer: \"%s\"\n", make); cupsFilePrintf(fp, "*ModelName: \"%s\"\n", model); cupsFilePrintf(fp, "*Product: \"(%s)\"\n", model); - cupsFilePrintf(fp, "*NickName: \"%s\"\n", model); - cupsFilePrintf(fp, "*ShortNickName: \"%s\"\n", model); + cupsFilePrintf(fp, "*NickName: \"%s - IPP Everywhere\"\n", model); + cupsFilePrintf(fp, "*ShortNickName: \"%s - IPP Everywhere\"\n", model); if ((attr = ippFindAttribute(response, "color-supported", IPP_TAG_BOOLEAN)) != NULL && ippGetBoolean(attr, 0)) cupsFilePuts(fp, "*ColorDevice: True\n"); @@ -3098,6 +3118,41 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ cupsFilePuts(fp, "*cupsLanguages: \"en\"\n"); /* + * Password/PIN printing... + */ + + if ((attr = ippFindAttribute(response, "job-password-supported", IPP_TAG_INTEGER)) != NULL) + { + char pattern[33]; /* Password pattern */ + int maxlen = ippGetInteger(attr, 0); + /* Maximum length */ + const char *repertoire = ippGetString(ippFindAttribute(response, "job-password-repertoire-configured", IPP_TAG_KEYWORD), 0, NULL); + /* Type of password */ + + if (maxlen > (int)(sizeof(pattern) - 1)) + maxlen = (int)sizeof(pattern) - 1; + + if (!repertoire || !strcmp(repertoire, "iana_us-ascii_digits")) + memset(pattern, '1', (size_t)maxlen); + else if (!strcmp(repertoire, "iana_us-ascii_letters")) + memset(pattern, 'A', (size_t)maxlen); + else if (!strcmp(repertoire, "iana_us-ascii_complex")) + memset(pattern, 'C', (size_t)maxlen); + else if (!strcmp(repertoire, "iana_us-ascii_any")) + memset(pattern, '.', (size_t)maxlen); + else if (!strcmp(repertoire, "iana_utf-8_digits")) + memset(pattern, 'N', (size_t)maxlen); + else if (!strcmp(repertoire, "iana_utf-8_letters")) + memset(pattern, 'U', (size_t)maxlen); + else + memset(pattern, '*', (size_t)maxlen); + + pattern[maxlen] = '\0'; + + cupsFilePrintf(fp, "*cupsPassword: \"%s\"\n", pattern); + } + + /* * Filters... */ @@ -3105,24 +3160,28 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ { is_apple = ippContainsString(attr, "image/urf"); is_pdf = ippContainsString(attr, "application/pdf"); - is_pwg = ippContainsString(attr, "image/pwg-raster"); + is_pwg = ippContainsString(attr, "image/pwg-raster") && !is_apple; - for (i = 0, count = ippGetCount(attr); i < count; i ++) + if (ippContainsString(attr, "image/jpeg")) + cupsFilePuts(fp, "*cupsFilter2: \"image/jpeg image/jpeg 0 -\"\n"); + if (ippContainsString(attr, "image/png")) + cupsFilePuts(fp, "*cupsFilter2: \"image/png image/png 0 -\"\n"); + if (is_pdf) { - const char *format = ippGetString(attr, i, NULL); - /* PDL */ - /* - * Write cupsFilter2 lines for supported formats... + * Don't locally filter PDF content when printing to a CUPS shared + * printer, otherwise the options will be applied twice... */ - if (!_cups_strcasecmp(format, "application/pdf")) + if (ippContainsString(attr, "application/vnd.cups-pdf")) + cupsFilePuts(fp, "*cupsFilter2: \"application/pdf application/pdf 0 -\"\n"); + else cupsFilePuts(fp, "*cupsFilter2: \"application/vnd.cups-pdf application/pdf 10 -\"\n"); - 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) + cupsFilePuts(fp, "*cupsFilter2: \"image/urf image/urf 100 -\"\n"); + if (is_pwg) + cupsFilePuts(fp, "*cupsFilter2: \"image/pwg-raster image/pwg-raster 100 -\"\n"); } if (!is_apple && !is_pdf && !is_pwg) @@ -3394,7 +3453,8 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ for (j = 0; j < (int)(sizeof(sources) / sizeof(sources[0])); j ++) if (!strcmp(sources[j][0], ppdname)) { - cupsFilePrintf(fp, "*InputSlot %s/%s: \"<</MediaPosition %d>>setpagedevice\"\n", ppdname, _cupsLangString(lang, sources[j][1]), j); + cupsFilePrintf(fp, "*InputSlot %s: \"<</MediaPosition %d>>setpagedevice\"\n", ppdname, j); + cupsFilePrintf(fp, "*%s.InputSlot %s/%s: \"\"\n", lang->language, ppdname, _cupsLangString(lang, sources[j][1])); break; } } @@ -3570,9 +3630,14 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ break; if (j < (int)(sizeof(media_types) / sizeof(media_types[0]))) - cupsFilePrintf(fp, "*MediaType %s/%s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, _cupsLangString(lang, media_types[j][1]), ppdname); + { + cupsFilePrintf(fp, "*MediaType %s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, ppdname); + cupsFilePrintf(fp, "*%s.MediaType %s/%s: \"\"\n", lang->language, ppdname, _cupsLangString(lang, media_types[j][1])); + } else + { cupsFilePrintf(fp, "*MediaType %s/%s: \"<</MediaType(%s)>>setpagedevice\"\n", ppdname, keyword, ppdname); + } } cupsFilePuts(fp, "*CloseUI: *MediaType\n"); } @@ -3581,8 +3646,8 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ * ColorModel... */ - if ((attr = ippFindAttribute(response, "pwg-raster-document-type-supported", IPP_TAG_KEYWORD)) == NULL) - if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) == NULL) + if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) == NULL) + if ((attr = ippFindAttribute(response, "pwg-raster-document-type-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); @@ -3595,45 +3660,49 @@ _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" - "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang, _("Color Mode"))); + cupsFilePrintf(fp, "*OpenUI *ColorModel: PickOne\n" + "*OrderDependency: 10 AnySetup *ColorModel\n" + "*%s.Translation ColorModel/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Color Mode"))); - cupsFilePrintf(fp, "*ColorModel FastGray/%s: \"<</cupsColorSpace 3/cupsBitsPerColor 1/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", _cupsLangString(lang, _("Fast Grayscale"))); + cupsFilePrintf(fp, "*ColorModel FastGray: \"<</cupsColorSpace 3/cupsBitsPerColor 1/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n*%s.ColorModel FastGray/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Fast Grayscale"))); if (!default_color) default_color = "FastGray"; } - else if (!strcmp(keyword, "sgray_8") || !strcmp(keyword, "W8") || !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" - "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang, _("Color Mode"))); + cupsFilePrintf(fp, "*OpenUI *ColorModel: PickOne\n" + "*OrderDependency: 10 AnySetup *ColorModel\n" + "*%s.Translation ColorModel/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Color Mode"))); - cupsFilePrintf(fp, "*ColorModel Gray/%s: \"<</cupsColorSpace 18/cupsBitsPerColor 8/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", _cupsLangString(lang, _("Grayscale"))); + cupsFilePrintf(fp, "*ColorModel Gray: \"<</cupsColorSpace 18/cupsBitsPerColor 8/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n*%s.ColorModel Gray/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Grayscale"))); if (!default_color || !strcmp(default_color, "FastGray")) default_color = "Gray"; } - else if (!strcmp(keyword, "srgb_8") || !strcmp(keyword, "SRGB24") || !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" - "*OrderDependency: 10 AnySetup *ColorModel\n", _cupsLangString(lang, _("Color Mode"))); + cupsFilePrintf(fp, "*OpenUI *ColorModel: PickOne\n" + "*OrderDependency: 10 AnySetup *ColorModel\n" + "*%s.Translation ColorModel/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Color Mode"))); - cupsFilePrintf(fp, "*ColorModel RGB/%s: \"<</cupsColorSpace 19/cupsBitsPerColor 8/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", _cupsLangString(lang, _("Color"))); + cupsFilePrintf(fp, "*ColorModel RGB: \"<</cupsColorSpace 19/cupsBitsPerColor 8/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n*%s.ColorModel RGB/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Color"))); default_color = "RGB"; } - else if (!strcmp(keyword, "adobe-rgb_16") || !strcmp(keyword, "ADOBERGB48")) + 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, "*OpenUI *ColorModel: PickOne\n" + "*OrderDependency: 10 AnySetup *ColorModel\n" + "*%s.Translation ColorModel/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Color Mode"))); - cupsFilePrintf(fp, "*ColorModel AdobeRGB/%s: \"<</cupsColorSpace 20/cupsBitsPerColor 16/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n", _cupsLangString(lang, _("Deep Color"))); + cupsFilePrintf(fp, "*ColorModel AdobeRGB: \"<</cupsColorSpace 20/cupsBitsPerColor 16/cupsColorOrder 0/cupsCompression 0>>setpagedevice\"\n*%s.ColorModel AdobeRGB/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Deep Color"))); if (!default_color) default_color = "AdobeRGB"; @@ -3653,15 +3722,48 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if ((attr = ippFindAttribute(response, "sides-supported", IPP_TAG_KEYWORD)) != NULL && ippContainsString(attr, "two-sided-long-edge")) { - cupsFilePrintf(fp, "*OpenUI *Duplex/%s: PickOne\n" + cupsFilePrintf(fp, "*OpenUI *Duplex: PickOne\n" "*OrderDependency: 10 AnySetup *Duplex\n" + "*%s.Translation Duplex/%s: \"\"\n" "*DefaultDuplex: None\n" - "*Duplex None/%s: \"<</Duplex false>>setpagedevice\"\n" - "*Duplex DuplexNoTumble/%s: \"<</Duplex true/Tumble false>>setpagedevice\"\n" - "*Duplex DuplexTumble/%s: \"<</Duplex true/Tumble true>>setpagedevice\"\n" - "*CloseUI: *Duplex\n", _cupsLangString(lang, _("2-Sided Printing")), _cupsLangString(lang, _("Off (1-Sided)")), _cupsLangString(lang, _("Long-Edge (Portrait)")), _cupsLangString(lang, _("Short-Edge (Landscape)"))); + "*Duplex None: \"<</Duplex false>>setpagedevice\"\n" + "*%s.Duplex None/%s: \"\"\n" + "*Duplex DuplexNoTumble: \"<</Duplex true/Tumble false>>setpagedevice\"\n" + "*%s.Duplex DuplexNoTumble/%s: \"\"\n" + "*Duplex DuplexTumble: \"<</Duplex true/Tumble true>>setpagedevice\"\n" + "*%s.Duplex DuplexTumble/%s: \"\"\n" + "*CloseUI: *Duplex\n", lang->language, _cupsLangString(lang, _("2-Sided Printing")), lang->language, _cupsLangString(lang, _("Off (1-Sided)")), lang->language, _cupsLangString(lang, _("Long-Edge (Portrait)")), lang->language, _cupsLangString(lang, _("Short-Edge (Landscape)"))); + + if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL) + { + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + const char *dm = ippGetString(attr, i, NULL); + /* DM value */ - if ((attr = ippFindAttribute(response, "pwg-raster-document-sheet-back", IPP_TAG_KEYWORD)) != NULL) + if (!_cups_strcasecmp(dm, "DM1")) + { + cupsFilePuts(fp, "*cupsBackSide: Normal\n"); + break; + } + else if (!_cups_strcasecmp(dm, "DM2")) + { + cupsFilePuts(fp, "*cupsBackSide: Flipped\n"); + break; + } + else if (!_cups_strcasecmp(dm, "DM3")) + { + cupsFilePuts(fp, "*cupsBackSide: Rotated\n"); + break; + } + else if (!_cups_strcasecmp(dm, "DM4")) + { + cupsFilePuts(fp, "*cupsBackSide: ManualTumble\n"); + break; + } + } + } + else if ((attr = ippFindAttribute(response, "pwg-raster-document-sheet-back", IPP_TAG_KEYWORD)) != NULL) { const char *keyword = ippGetString(attr, 0, NULL); /* Keyword value */ @@ -3675,35 +3777,6 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ else cupsFilePuts(fp, "*cupsBackSide: Rotated\n"); } - else if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL) - { - for (i = 0, count = ippGetCount(attr); i < count; i ++) - { - const char *dm = ippGetString(attr, i, NULL); - /* DM value */ - - if (!_cups_strcasecmp(dm, "DM1")) - { - cupsFilePuts(fp, "*cupsBackSide: Normal\n"); - break; - } - else if (!_cups_strcasecmp(dm, "DM2")) - { - cupsFilePuts(fp, "*cupsBackSide: Flipped\n"); - break; - } - else if (!_cups_strcasecmp(dm, "DM3")) - { - cupsFilePuts(fp, "*cupsBackSide: Rotated\n"); - break; - } - else if (!_cups_strcasecmp(dm, "DM4")) - { - cupsFilePuts(fp, "*cupsBackSide: ManualTumble\n"); - break; - } - } - } } /* @@ -3717,6 +3790,12 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if ((attr = ippFindAttribute(response, "output-bin-supported", IPP_TAG_ZERO)) != NULL && (count = ippGetCount(attr)) > 1) { + ipp_attribute_t *trays = ippFindAttribute(response, "printer-output-tray", IPP_TAG_STRING); + /* printer-output-tray attribute, if any */ + const char *tray_ptr; /* printer-output-tray value */ + int tray_len; /* Len of printer-output-tray value */ + char tray[IPP_MAX_OCTETSTRING]; + /* printer-output-tray string value */ static const char * const output_bins[][2] = { /* "output-bin" strings */ { "auto", _("Automatic") }, @@ -3767,6 +3846,11 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ cupsFilePrintf(fp, "*OpenUI *OutputBin: PickOne\n" "*OrderDependency: 10 AnySetup *OutputBin\n" "*DefaultOutputBin: %s\n", ppdname); + if (!strcmp(ppdname, "FaceUp")) + cupsFilePuts(fp, "*DefaultOutputOrder: Reverse\n"); + else + cupsFilePuts(fp, "*DefaultOutputOrder: Normal\n"); + for (i = 0; i < (int)(sizeof(output_bins) / sizeof(output_bins[0])); i ++) { if (!ippContainsString(attr, output_bins[i][0])) @@ -3774,7 +3858,26 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ pwg_ppdize_name(output_bins[i][0], ppdname, sizeof(ppdname)); - cupsFilePrintf(fp, "*OutputBin %s/%s: \"\"\n", ppdname, _cupsLangString(lang, output_bins[i][1])); + cupsFilePrintf(fp, "*OutputBin %s: \"\"\n", ppdname); + cupsFilePrintf(fp, "*%s.OutputBin %s/%s: \"\"\n", lang->language, ppdname, _cupsLangString(lang, output_bins[i][1])); + + if ((tray_ptr = ippGetOctetString(trays, i, &tray_len)) != NULL) + { + if (tray_len >= (int)sizeof(tray)) + tray_len = (int)sizeof(tray) - 1; + + memcpy(tray, tray_ptr, (size_t)tray_len); + tray[tray_len] = '\0'; + + if (strstr(tray, "stackingorder=lastToFirst;")) + cupsFilePrintf(fp, "*PageStackOrder %s: Reverse\n", ppdname); + else + cupsFilePrintf(fp, "*PageStackOrder %s: Normal\n", ppdname); + } + else if (!strcmp(ppdname, "FaceUp")) + cupsFilePrintf(fp, "*PageStackOrder %s: Reverse\n", ppdname); + else + cupsFilePrintf(fp, "*PageStackOrder %s: Normal\n", ppdname); } cupsFilePuts(fp, "*CloseUI: *OutputBin\n"); } @@ -3812,10 +3915,12 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if (i < count) { - cupsFilePrintf(fp, "*OpenUI *StapleLocation/%s: PickOne\n", _cupsLangString(lang, _("Staple"))); + cupsFilePuts(fp, "*OpenUI *StapleLocation: PickOne\n"); cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *StapleLocation\n"); + cupsFilePrintf(fp, "*%s.Translation StapleLocation/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Staple"))); cupsFilePuts(fp, "*DefaultStapleLocation: None\n"); - cupsFilePrintf(fp, "*StapleLocation None/%s: \"\"\n", _cupsLangString(lang, _("None"))); + cupsFilePuts(fp, "*StapleLocation None: \"\"\n"); + cupsFilePrintf(fp, "*%s.StapleLocation None/%s: \"\"\n", lang->language, _cupsLangString(lang, _("None"))); for (; i < count; i ++) { @@ -3834,7 +3939,8 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ { if (!strcmp(finishings[j][0], name)) { - cupsFilePrintf(fp, "*StapleLocation %s/%s: \"\"\n", name, _cupsLangString(lang, finishings[j][1])); + cupsFilePrintf(fp, "*StapleLocation %s: \"\"\n", name); + cupsFilePrintf(fp, "*%s.StapleLocation %s/%s: \"\"\n", lang->language, name, _cupsLangString(lang, finishings[j][1])); cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*StapleLocation %s\"\n", value, name, name); break; } @@ -3859,10 +3965,12 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if (i < count) { - cupsFilePrintf(fp, "*OpenUI *FoldType/%s: PickOne\n", _cupsLangString(lang, _("Fold"))); + cupsFilePuts(fp, "*OpenUI *FoldType: PickOne\n"); cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *FoldType\n"); + cupsFilePrintf(fp, "*%s.Translation FoldType/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Fold"))); cupsFilePuts(fp, "*DefaultFoldType: None\n"); - cupsFilePrintf(fp, "*FoldType None/%s: \"\"\n", _cupsLangString(lang, _("None"))); + cupsFilePuts(fp, "*FoldType None: \"\"\n"); + cupsFilePrintf(fp, "*%s.FoldType None/%s: \"\"\n", lang->language, _cupsLangString(lang, _("None"))); for (; i < count; i ++) { @@ -3881,7 +3989,8 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ { if (!strcmp(finishings[j][0], name)) { - cupsFilePrintf(fp, "*FoldType %s/%s: \"\"\n", name, _cupsLangString(lang, finishings[j][1])); + cupsFilePrintf(fp, "*FoldType %s: \"\"\n", name); + cupsFilePrintf(fp, "*%s.FoldType %s/%s: \"\"\n", lang->language, name, _cupsLangString(lang, finishings[j][1])); cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*FoldType %s\"\n", value, name, name); break; } @@ -3906,10 +4015,12 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if (i < count) { - cupsFilePrintf(fp, "*OpenUI *PunchMedia/%s: PickOne\n", _cupsLangString(lang, _("Punch"))); + cupsFilePuts(fp, "*OpenUI *PunchMedia: PickOne\n"); cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *PunchMedia\n"); + cupsFilePrintf(fp, "*%s.Translation PunchMedia/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Punch"))); cupsFilePuts(fp, "*DefaultPunchMedia: None\n"); - cupsFilePrintf(fp, "*PunchMedia None/%s: \"\"\n", _cupsLangString(lang, _("None"))); + cupsFilePuts(fp, "*PunchMedia None: \"\"\n"); + cupsFilePrintf(fp, "*%s.PunchMedia None/%s: \"\"\n", lang->language, _cupsLangString(lang, _("None"))); for (i = 0; i < count; i ++) { @@ -3928,7 +4039,8 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ { if (!strcmp(finishings[j][0], name)) { - cupsFilePrintf(fp, "*PunchMedia %s/%s: \"\"\n", name, _cupsLangString(lang, finishings[j][1])); + cupsFilePrintf(fp, "*PunchMedia %s: \"\"\n", name); + cupsFilePrintf(fp, "*%s.PunchMedia %s/%s: \"\"\n", lang->language, name, _cupsLangString(lang, finishings[j][1])); cupsFilePrintf(fp, "*cupsIPPFinishings %d/%s: \"*PunchMedia %s\"\n", value, name, name); break; } @@ -3944,8 +4056,9 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if (ippContainsInteger(attr, IPP_FINISHINGS_BOOKLET_MAKER)) { - cupsFilePrintf(fp, "*OpenUI *Booklet/%s: Boolean\n", _cupsLangString(lang, _("Booklet"))); + cupsFilePuts(fp, "*OpenUI *Booklet: Boolean\n"); cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *Booklet\n"); + cupsFilePrintf(fp, "*%s.Translation Booklet/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Booklet"))); cupsFilePuts(fp, "*DefaultBooklet: False\n"); cupsFilePuts(fp, "*Booklet False: \"\"\n"); cupsFilePuts(fp, "*Booklet True: \"\"\n"); @@ -3962,42 +4075,14 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ quality = ippFindAttribute(response, "print-quality-supported", IPP_TAG_ENUM); - if ((attr = ippFindAttribute(response, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL) + if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL) { - count = ippGetCount(attr); - - pwg_ppdize_resolution(attr, count / 2, &xres, &yres, ppdname, 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 (count > 2 || ippContainsInteger(quality, IPP_QUALITY_DRAFT)) - { - pwg_ppdize_resolution(attr, 0, &xres, &yres, NULL, 0); - cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), xres, yres); - } - pwg_ppdize_resolution(attr, count / 2, &xres, &yres, NULL, 0); - cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Normal")), xres, yres); - if (count > 1 || ippContainsInteger(quality, IPP_QUALITY_HIGH)) - { - 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: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("High")), xres, yres); - } - - cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n"); - } - else if ((attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL) - { - int lowdpi = 0, hidpi = 0; /* Lower and higher resolution */ + int lowdpi = 0, hidpi = 0; /* Lower and higher resolution */ for (i = 0, count = ippGetCount(attr); i < count; i ++) { const char *rs = ippGetString(attr, i, NULL); - /* RS value */ + /* RS value */ if (_cups_strncasecmp(rs, "RS", 2)) continue; @@ -4026,19 +4111,92 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ cupsFilePrintf(fp, "*DefaultResolution: %ddpi\n", lowdpi); - cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality/%s: PickOne\n" + cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality: PickOne\n" "*OrderDependency: 10 AnySetup *cupsPrintQuality\n" - "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang, _("Print Quality"))); + "*%s.Translation cupsPrintQuality/%s: \"\"\n" + "*DefaultcupsPrintQuality: Normal\n", lang->language, _cupsLangString(lang, _("Print Quality"))); if ((lowdpi & 1) == 0) - cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), lowdpi, lowdpi / 2); + cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<</HWResolution[%d %d]>>setpagedevice\"\n*%s.cupsPrintQuality Draft/%s: \"\"\n", lowdpi, lowdpi / 2, lang->language, _cupsLangString(lang, _("Draft"))); else if (ippContainsInteger(quality, IPP_QUALITY_DRAFT)) - cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), lowdpi, lowdpi); - cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Normal")), lowdpi, lowdpi); + cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<</HWResolution[%d %d]>>setpagedevice\"\n*%s.cupsPrintQuality Draft/%s: \"\"\n", lowdpi, lowdpi, lang->language, _cupsLangString(lang, _("Draft"))); + + cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<</HWResolution[%d %d]>>setpagedevice\"\n*%s.cupsPrintQuality Normal/%s: \"\"\n", lowdpi, lowdpi, lang->language, _cupsLangString(lang, _("Normal"))); + if (hidpi > lowdpi || ippContainsInteger(quality, IPP_QUALITY_HIGH)) - cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("High")), hidpi, hidpi); + cupsFilePrintf(fp, "*cupsPrintQuality High: \"<</HWResolution[%d %d]>>setpagedevice\"\n*%s.cupsPrintQuality High/%s: \"\"\n", hidpi, hidpi, lang->language, _cupsLangString(lang, _("High"))); cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n"); } } + else if ((attr = ippFindAttribute(response, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL) + { + /* + * Make a sorted list of resolutions. + */ + + count = ippGetCount(attr); + if (count > (int)(sizeof(resolutions) / sizeof(resolutions[0]))) + count = (int)(sizeof(resolutions) / sizeof(resolutions[0])); + + resolutions[0] = 0; /* Not in loop to silence Clang static analyzer... */ + for (i = 1; i < count; i ++) + resolutions[i] = i; + + for (i = 0; i < (count - 1); i ++) + { + for (j = i + 1; j < count; j ++) + { + int ix, iy, /* First X and Y resolution */ + jx, jy, /* Second X and Y resolution */ + temp; /* Swap variable */ + ipp_res_t units; /* Resolution units */ + + ix = ippGetResolution(attr, resolutions[i], &iy, &units); + jx = ippGetResolution(attr, resolutions[j], &jy, &units); + + if (ix > jx || (ix == jx && iy > jy)) + { + /* + * Swap these two resolutions... + */ + + temp = resolutions[i]; + resolutions[i] = resolutions[j]; + resolutions[j] = temp; + } + } + } + + /* + * Generate print quality options... + */ + + pwg_ppdize_resolution(attr, resolutions[count / 2], &xres, &yres, ppdname, sizeof(ppdname)); + cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname); + + cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality: PickOne\n" + "*OrderDependency: 10 AnySetup *cupsPrintQuality\n" + "*%s.Translation cupsPrintQuality/%s: \"\"\n" + "*DefaultcupsPrintQuality: Normal\n", lang->language, _cupsLangString(lang, _("Print Quality"))); + if (count > 2 || ippContainsInteger(quality, IPP_QUALITY_DRAFT)) + { + pwg_ppdize_resolution(attr, resolutions[0], &xres, &yres, NULL, 0); + cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<</HWResolution[%d %d]>>setpagedevice\"\n", xres, yres); + cupsFilePrintf(fp, "*%s.cupsPrintQuality Draft/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Draft"))); + } + + pwg_ppdize_resolution(attr, resolutions[count / 2], &xres, &yres, NULL, 0); + cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<</HWResolution[%d %d]>>setpagedevice\"\n", xres, yres); + cupsFilePrintf(fp, "*%s.cupsPrintQuality Normal/%s: \"\"\n", lang->language, _cupsLangString(lang, _("Normal"))); + + if (count > 1 || ippContainsInteger(quality, IPP_QUALITY_HIGH)) + { + pwg_ppdize_resolution(attr, resolutions[count - 1], &xres, &yres, NULL, 0); + cupsFilePrintf(fp, "*cupsPrintQuality High: \"<</HWResolution[%d %d]>>setpagedevice\"\n", xres, yres); + cupsFilePrintf(fp, "*%s.cupsPrintQuality High/%s: \"\"\n", lang->language, _cupsLangString(lang, _("High"))); + } + + cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n"); + } else if (is_apple || is_pwg) goto bad_ppd; else @@ -4055,14 +4213,17 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ cupsFilePrintf(fp, "*DefaultResolution: %s\n", ppdname); - cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality/%s: PickOne\n" + cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality: PickOne\n" "*OrderDependency: 10 AnySetup *cupsPrintQuality\n" - "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang, _("Print Quality"))); + "*%s.Translation cupsPrintQuality/%s: \"\"\n" + "*DefaultcupsPrintQuality: Normal\n", lang->language, _cupsLangString(lang, _("Print Quality"))); if (ippContainsInteger(quality, IPP_QUALITY_DRAFT)) - cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), xres, yres); - cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Normal")), xres, yres); + cupsFilePrintf(fp, "*cupsPrintQuality Draft: \"<</HWResolution[%d %d]>>setpagedevice\"\n*%s.cupsPrintQuality Draft/%s: \"\"\n", xres, yres, lang->language, _cupsLangString(lang, _("Draft"))); + + cupsFilePrintf(fp, "*cupsPrintQuality Normal: \"<</HWResolution[%d %d]>>setpagedevice\"\n*%s.cupsPrintQuality Normal/%s: \"\"\n", xres, yres, lang->language, _cupsLangString(lang, _("Normal"))); + if (ippContainsInteger(quality, IPP_QUALITY_HIGH)) - cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("High")), xres, yres); + cupsFilePrintf(fp, "*cupsPrintQuality High: \"<</HWResolution[%d %d]>>setpagedevice\"\n*%s.cupsPrintQuality High/%s: \"\"\n", xres, yres, lang->language, _cupsLangString(lang, _("High"))); cupsFilePuts(fp, "*CloseUI: *cupsPrintQuality\n"); } diff --git a/cups/ppd-conflicts.c b/cups/ppd-conflicts.c index 8f875a57..24330ecb 100644 --- a/cups/ppd-conflicts.c +++ b/cups/ppd-conflicts.c @@ -1,7 +1,7 @@ /* * Option conflict management routines for CUPS. * - * Copyright 2007-2015 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -29,7 +29,6 @@ enum { - _PPD_NORMAL_CONSTRAINTS, _PPD_OPTION_CONSTRAINTS, _PPD_INSTALLABLE_CONSTRAINTS, _PPD_ALL_CONSTRAINTS @@ -998,7 +997,7 @@ ppd_test_constraints( if (!consts->installable && which == _PPD_INSTALLABLE_CONSTRAINTS) continue; /* Skip non-installable option constraint */ - if (which == _PPD_OPTION_CONSTRAINTS && option) + if ((which == _PPD_OPTION_CONSTRAINTS || which == _PPD_INSTALLABLE_CONSTRAINTS) && option) { /* * Skip constraints that do not involve the current option... diff --git a/cups/ppd-emit.c b/cups/ppd-emit.c index 36e5bcaf..4b153aca 100644 --- a/cups/ppd-emit.c +++ b/cups/ppd-emit.c @@ -21,11 +21,11 @@ #include "cups-private.h" #include "ppd.h" -#if defined(WIN32) || defined(__EMX__) +#if defined(_WIN32) || defined(__EMX__) # include <io.h> #else # include <unistd.h> -#endif /* WIN32 || __EMX__ */ +#endif /* _WIN32 || __EMX__ */ /* @@ -328,11 +328,11 @@ ppdEmitFd(ppd_file_t *ppd, /* I - PPD file record */ while (buflength > 0) { -#ifdef WIN32 +#ifdef _WIN32 if ((bytes = (ssize_t)write(fd, bufptr, (unsigned)buflength)) < 0) #else if ((bytes = write(fd, bufptr, buflength)) < 0) -#endif /* WIN32 */ +#endif /* _WIN32 */ { if (errno == EAGAIN || errno == EINTR) continue; diff --git a/cups/ppd-localize.c b/cups/ppd-localize.c index ed75bf86..9537ef5b 100644 --- a/cups/ppd-localize.c +++ b/cups/ppd-localize.c @@ -1,7 +1,7 @@ /* * PPD localization routines for CUPS. * - * Copyright 2007-2017 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -277,7 +277,7 @@ ppdLocalizeIPPReason( if (!locattr) { - if (lang && (!scheme || !strcmp(scheme, "text"))) + if (lang && (!scheme || !strcmp(scheme, "text")) && strcmp(reason, "none")) { /* * Try to localize a standard printer-state-reason keyword... diff --git a/cups/ppd-mark.c b/cups/ppd-mark.c index 9fdaf0bd..464c09a9 100644 --- a/cups/ppd-mark.c +++ b/cups/ppd-mark.c @@ -1,7 +1,7 @@ /* * Option marking 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 @@ -253,6 +253,7 @@ cupsMarkOptions( */ for (i = num_options, optptr = options; i > 0; i --, optptr ++) + { if (!_cups_strcasecmp(optptr->name, "media") || !_cups_strcasecmp(optptr->name, "output-bin") || !_cups_strcasecmp(optptr->name, "output-mode") || @@ -341,6 +342,19 @@ cupsMarkOptions( ppd_mark_option(ppd, "MirrorPrint", optptr->value); else ppd_mark_option(ppd, optptr->name, optptr->value); + } + + if (print_quality) + { + int pq = atoi(print_quality); /* print-quaity value */ + + if (pq == IPP_QUALITY_DRAFT) + ppd_mark_option(ppd, "cupsPrintQuality", "Draft"); + else if (pq == IPP_QUALITY_HIGH) + ppd_mark_option(ppd, "cupsPrintQuality", "High"); + else + ppd_mark_option(ppd, "cupsPrintQuality", "Normal"); + } ppd_debug_marked(ppd, "After..."); diff --git a/cups/ppd-util.c b/cups/ppd-util.c index d0194c80..0974bae9 100644 --- a/cups/ppd-util.c +++ b/cups/ppd-util.c @@ -1,8 +1,8 @@ /* * PPD utilities for CUPS. * - * Copyright 2007-2015 by Apple Inc. - * Copyright 1997-2006 by Easy Software Products. + * Copyright © 2007-2018 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 @@ -21,11 +21,11 @@ #include "ppd-private.h" #include <fcntl.h> #include <sys/stat.h> -#if defined(WIN32) || defined(__EMX__) +#if defined(_WIN32) || defined(__EMX__) # include <io.h> #else # include <unistd.h> -#endif /* WIN32 || __EMX__ */ +#endif /* _WIN32 || __EMX__ */ /* @@ -171,7 +171,7 @@ cupsGetPPD3(http_t *http, /* I - HTTP connection or @code CUPS_HTTP_DEFAUL return (HTTP_STATUS_NOT_ACCEPTABLE); } -#ifndef WIN32 +#ifndef _WIN32 /* * See if the PPD file is available locally... */ @@ -216,6 +216,27 @@ cupsGetPPD3(http_t *http, /* I - HTTP connection or @code CUPS_HTTP_DEFAUL const char *tmpdir; /* TMPDIR environment variable */ struct timeval curtime; /* Current time */ +#ifdef __APPLE__ + /* + * On macOS and iOS, the TMPDIR environment variable is not always the + * best location to place temporary files due to sandboxing. Instead, + * the confstr function should be called to get the proper per-user, + * per-process TMPDIR value. + */ + + char tmppath[1024]; /* Temporary directory */ + + if ((tmpdir = getenv("TMPDIR")) != NULL && access(tmpdir, W_OK)) + tmpdir = NULL; + + if (!tmpdir) + { + if (confstr(_CS_DARWIN_USER_TEMP_DIR, tmppath, sizeof(tmppath))) + tmpdir = tmppath; + else + tmpdir = "/private/tmp"; /* This should never happen */ + } +#else /* * Previously we put root temporary files in the default CUPS temporary * directory under /var/spool/cups. However, since the scheduler cleans @@ -224,11 +245,8 @@ cupsGetPPD3(http_t *http, /* I - HTTP connection or @code CUPS_HTTP_DEFAUL */ if ((tmpdir = getenv("TMPDIR")) == NULL) -# ifdef __APPLE__ - tmpdir = "/private/tmp"; /* /tmp is a symlink to /private/tmp */ -# else - tmpdir = "/tmp"; -# endif /* __APPLE__ */ + tmpdir = "/tmp"; +#endif /* __APPLE__ */ /* * Make the temporary name using the specified directory... @@ -280,7 +298,7 @@ cupsGetPPD3(http_t *http, /* I - HTTP connection or @code CUPS_HTTP_DEFAUL } } } -#endif /* !WIN32 */ +#endif /* !_WIN32 */ /* * Try finding a printer URI for this printer... @@ -511,23 +529,16 @@ cups_get_printer_uri( int depth) /* I - Depth of query */ { int i; /* Looping var */ - int http_port; /* Port number */ - http_t *http2; /* Alternate HTTP connection */ ipp_t *request, /* IPP request */ *response; /* IPP response */ ipp_attribute_t *attr; /* Current attribute */ char uri[HTTP_MAX_URI], /* printer-uri attribute */ scheme[HTTP_MAX_URI], /* Scheme name */ - username[HTTP_MAX_URI], /* Username:password */ - classname[255], /* Temporary class name */ - http_hostname[HTTP_MAX_HOST]; - /* Hostname associated with connection */ + username[HTTP_MAX_URI]; /* Username:password */ static const char * const requested_attrs[] = { /* Requested attributes */ - "device-uri", "member-uris", - "printer-uri-supported", - "printer-type" + "printer-uri-supported" }; @@ -550,15 +561,6 @@ cups_get_printer_uri( DEBUG_printf(("5cups_get_printer_uri: printer-uri=\"%s\"", uri)); /* - * Get the hostname and port number we are connected to... - */ - - httpGetHostname(http, http_hostname, sizeof(http_hostname)); - http_port = httpAddrPort(http->hostaddr); - - DEBUG_printf(("5cups_get_printer_uri: http_hostname=\"%s\"", http_hostname)); - - /* * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following * attributes: * @@ -582,31 +584,7 @@ cups_get_printer_uri( if ((response = cupsDoRequest(http, request, resource)) != NULL) { - const char *device_uri = NULL; /* device-uri value */ - - if ((attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI)) != NULL) - { - device_uri = attr->values[0].string.text; - DEBUG_printf(("5cups_get_printer_uri: device-uri=\"%s\"", device_uri)); - } - - if (device_uri && - (((!strncmp(device_uri, "ipp://", 6) || !strncmp(device_uri, "ipps://", 7)) && - (strstr(device_uri, "/printers/") != NULL || strstr(device_uri, "/classes/") != NULL)) || - ((strstr(device_uri, "._ipp.") != NULL || strstr(device_uri, "._ipps.") != NULL) && - !strcmp(device_uri + strlen(device_uri) - 5, "/cups")))) - { - /* - * Statically-configured shared printer. - */ - - httpSeparateURI(HTTP_URI_CODING_ALL, _httpResolveURI(device_uri, uri, sizeof(uri), _HTTP_RESOLVE_DEFAULT, NULL, NULL), scheme, sizeof(scheme), username, sizeof(username), host, hostsize, port, resource, resourcesize); - ippDelete(response); - - DEBUG_printf(("5cups_get_printer_uri: Resolved to host=\"%s\", port=%d, resource=\"%s\"", host, *port, resource)); - return (1); - } - else if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL) + if ((attr = ippFindAttribute(response, "member-uris", IPP_TAG_URI)) != NULL) { /* * Get the first actual printer name in the class... @@ -631,55 +609,6 @@ cups_get_printer_uri( return (1); } } - - /* - * No printers in this class - try recursively looking for a printer, - * but not more than 3 levels deep... - */ - - if (depth < 3) - { - for (i = 0; i < attr->num_values; i ++) - { - httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[i].string.text, - scheme, sizeof(scheme), username, sizeof(username), - host, hostsize, port, resource, resourcesize); - if (!strncmp(resource, "/classes/", 9)) - { - /* - * Found a class! Connect to the right server... - */ - - if (!_cups_strcasecmp(http_hostname, host) && *port == http_port) - http2 = http; - else if ((http2 = httpConnect2(host, *port, NULL, AF_UNSPEC, cupsEncryption(), 1, 30000, NULL)) == NULL) - { - DEBUG_puts("8cups_get_printer_uri: Unable to connect to server"); - - continue; - } - - /* - * Look up printers on that server... - */ - - strlcpy(classname, resource + 9, sizeof(classname)); - - cups_get_printer_uri(http2, classname, host, hostsize, port, - resource, resourcesize, depth + 1); - - /* - * Close the connection as needed... - */ - - if (http2 != http) - httpClose(http2); - - if (*host) - return (1); - } - } - } } else if ((attr = ippFindAttribute(response, "printer-uri-supported", IPP_TAG_URI)) != NULL) { @@ -1,7 +1,7 @@ /* * PPD file routines for CUPS. * - * Copyright 2007-2017 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -94,9 +94,9 @@ static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name, cups_encoding_t encoding); static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name); static _ppd_globals_t *ppd_globals_alloc(void); -#if defined(HAVE_PTHREAD_H) || defined(WIN32) +#if defined(HAVE_PTHREAD_H) || defined(_WIN32) static void ppd_globals_free(_ppd_globals_t *g); -#endif /* HAVE_PTHREAD_H || WIN32 */ +#endif /* HAVE_PTHREAD_H || _WIN32 */ #ifdef HAVE_PTHREAD_H static void ppd_globals_init(void); #endif /* HAVE_PTHREAD_H */ @@ -333,7 +333,9 @@ ppdErrorString(ppd_status_t status) /* I - PPD status */ _("Bad custom parameter"), _("Missing option keyword"), _("Bad value string"), - _("Missing CloseGroup") + _("Missing CloseGroup"), + _("Bad CloseUI/JCLCloseUI"), + _("Missing CloseUI/JCLCloseUI") }; @@ -1542,8 +1544,29 @@ _ppdOpen( choice->code = _cupsStrRetain(custom_attr->value); } } - else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI")) + else if (!strcmp(keyword, "CloseUI")) { + if ((!option || option->section == PPD_ORDER_JCL) && pg->ppd_conform == PPD_CONFORM_STRICT) + { + pg->ppd_status = PPD_BAD_CLOSE_UI; + + goto error; + } + + option = NULL; + + _cupsStrFree(string); + string = NULL; + } + else if (!strcmp(keyword, "JCLCloseUI")) + { + if ((!option || option->section != PPD_ORDER_JCL) && pg->ppd_conform == PPD_CONFORM_STRICT) + { + pg->ppd_status = PPD_BAD_CLOSE_UI; + + goto error; + } + option = NULL; _cupsStrFree(string); @@ -2007,6 +2030,16 @@ _ppdOpen( } /* + * Check for a missing CloseUI/JCLCloseUI... + */ + + if (option && pg->ppd_conform == PPD_CONFORM_STRICT) + { + pg->ppd_status = PPD_MISSING_CLOSE_UI; + goto error; + } + + /* * Check for a missing CloseGroup... */ @@ -2804,13 +2837,13 @@ ppd_globals_alloc(void) * 'ppd_globals_free()' - Free global data. */ -#if defined(HAVE_PTHREAD_H) || defined(WIN32) +#if defined(HAVE_PTHREAD_H) || defined(_WIN32) static void ppd_globals_free(_ppd_globals_t *pg) /* I - Pointer to global data */ { free(pg); } -#endif /* HAVE_PTHREAD_H || WIN32 */ +#endif /* HAVE_PTHREAD_H || _WIN32 */ #ifdef HAVE_PTHREAD_H @@ -132,6 +132,8 @@ typedef enum ppd_status_e /**** Status Codes @since CUPS 1.1.19/macOS 10.3@ *** PPD_MISSING_OPTION_KEYWORD, /* Missing option keyword */ PPD_BAD_VALUE, /* Bad value string */ PPD_MISSING_CLOSE_GROUP, /* Missing CloseGroup */ + PPD_BAD_CLOSE_UI, /* Bad CloseUI/JCLCloseUI */ + PPD_MISSING_CLOSE_UI, /* Missing CloseUI/JCLCloseUI */ PPD_MAX_STATUS /* @private@ */ } ppd_status_t; diff --git a/cups/pwg-media.c b/cups/pwg-media.c index 73356fd7..62455ea6 100644 --- a/cups/pwg-media.c +++ b/cups/pwg-media.c @@ -189,6 +189,7 @@ static pwg_media_t const cups_pwg_media[] = _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, "216x330mm", 216, 330), + _PWG_MEDIA_MM("jpn_kaku1_270x382mm", NULL, "EnvKaku1", 270, 382), _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), @@ -1,7 +1,7 @@ /* * 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 @@ -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 38135815..94dd951c 100644 --- a/cups/raster-private.h +++ b/cups/raster-private.h @@ -1,7 +1,7 @@ /* * Private image library definitions for CUPS. * - * Copyright 2007-2015 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1993-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -24,13 +24,13 @@ # include <cups/cups.h> # include <cups/debug-private.h> # include <cups/string-private.h> -# ifdef WIN32 +# ifdef _WIN32 # include <io.h> # include <winsock2.h> /* for htonl() definition */ # else # include <unistd.h> # include <fcntl.h> -# endif /* WIN32 */ +# endif /* _WIN32 */ /* @@ -49,12 +49,8 @@ * Prototypes... */ -extern int _cupsRasterExecPS(cups_page_header2_t *h, - int *preferred_bits, - const char *code) - __attribute__((nonnull(3))); -extern void _cupsRasterAddError(const char *f, ...) - __attribute__((__format__(__printf__, 1, 2))); +extern int _cupsRasterExecPS(cups_page_header2_t *h, int *preferred_bits, const char *code) _CUPS_NONNULL((3)); +extern void _cupsRasterAddError(const char *f, ...) _CUPS_FORMAT(1,2); extern void _cupsRasterClearError(void); #endif /* !_CUPS_RASTER_PRIVATE_H_ */ diff --git a/cups/request.c b/cups/request.c index 39cbe6cc..a4e4b905 100644 --- a/cups/request.c +++ b/cups/request.c @@ -1,7 +1,7 @@ /* * IPP utilities 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 @@ -20,11 +20,11 @@ #include "cups-private.h" #include <fcntl.h> #include <sys/stat.h> -#if defined(WIN32) || defined(__EMX__) +#if defined(_WIN32) || defined(__EMX__) # include <io.h> #else # include <unistd.h> -#endif /* WIN32 || __EMX__ */ +#endif /* _WIN32 || __EMX__ */ #ifndef O_BINARY # define O_BINARY 0 #endif /* O_BINARY */ @@ -131,13 +131,12 @@ cupsDoIORequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP * Get the default connection as needed... */ - if (!http) - if ((http = _cupsConnect()) == NULL) - { - ippDelete(request); + if (!http && (http = _cupsConnect()) == NULL) + { + ippDelete(request); - return (NULL); - } + return (NULL); + } /* * See if we have a file to send... @@ -151,43 +150,39 @@ cupsDoIORequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP * Can't get file information! */ - _cupsSetError(errno == EBADF ? IPP_STATUS_ERROR_NOT_FOUND : IPP_STATUS_ERROR_NOT_AUTHORIZED, - NULL, 0); - + _cupsSetError(errno == EBADF ? IPP_STATUS_ERROR_NOT_FOUND : IPP_STATUS_ERROR_NOT_AUTHORIZED, NULL, 0); ippDelete(request); return (NULL); } -#ifdef WIN32 +#ifdef _WIN32 if (fileinfo.st_mode & _S_IFDIR) #else if (S_ISDIR(fileinfo.st_mode)) -#endif /* WIN32 */ +#endif /* _WIN32 */ { /* * Can't send a directory... */ - ippDelete(request); - _cupsSetError(IPP_STATUS_ERROR_NOT_POSSIBLE, strerror(EISDIR), 0); + ippDelete(request); return (NULL); } -#ifndef WIN32 +#ifndef _WIN32 if (!S_ISREG(fileinfo.st_mode)) length = 0; /* Chunk when piping */ else -#endif /* !WIN32 */ +#endif /* !_WIN32 */ length = ippLength(request) + (size_t)fileinfo.st_size; } else length = ippLength(request); - DEBUG_printf(("2cupsDoIORequest: Request length=%ld, total length=%ld", - (long)ippLength(request), (long)length)); + DEBUG_printf(("2cupsDoIORequest: Request length=%ld, total length=%ld", (long)ippLength(request), (long)length)); /* * Clear any "Local" authentication data since it is probably stale... @@ -220,9 +215,9 @@ cupsDoIORequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP * Send the file with the request... */ -#ifndef WIN32 +#ifndef _WIN32 if (S_ISREG(fileinfo.st_mode)) -#endif /* WIN32 */ +#endif /* _WIN32 */ lseek(infile, 0, SEEK_SET); while ((bytes = read(infile, buffer, sizeof(buffer))) > 0) @@ -596,6 +591,8 @@ cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP int got_status; /* Did we get the status? */ ipp_state_t state; /* State of IPP processing */ http_status_t expect; /* Expect: header to use */ + char date[256]; /* Date: header value */ + int digest; /* Are we using Digest authentication? */ DEBUG_printf(("cupsSendRequest(http=%p, request=%p(%s), resource=\"%s\", length=" CUPS_LLFMT ")", (void *)http, (void *)request, request ? ippOpString(request->request.op.operation_id) : "?", resource, CUPS_LLCAST length)); @@ -615,9 +612,8 @@ cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP * Get the default connection as needed... */ - if (!http) - if ((http = _cupsConnect()) == NULL) - return (HTTP_STATUS_SERVICE_UNAVAILABLE); + if (!http && (http = _cupsConnect()) == NULL) + return (HTTP_STATUS_SERVICE_UNAVAILABLE); /* * If the prior request was not flushed out, do so now... @@ -685,8 +681,20 @@ cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP httpClearFields(http); httpSetExpect(http, expect); httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp"); + httpSetField(http, HTTP_FIELD_DATE, httpGetDateString2(time(NULL), date, (int)sizeof(date))); httpSetLength(http, length); + digest = http->authstring && !strncmp(http->authstring, "Digest ", 7); + + if (digest) + { + /* + * Update the Digest authentication string... + */ + + _httpSetDigestAuthString(http, http->nextnonce, "POST", resource); + } + #ifdef HAVE_GSSAPI if (http->authstring && !strncmp(http->authstring, "Negotiate", 9)) { @@ -771,9 +779,9 @@ cupsSendRequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP * Wait up to 1 second to get the 100-continue response as needed... */ - if (!got_status) + if (!got_status || (digest && status == HTTP_STATUS_CONTINUE)) { - if (expect == HTTP_STATUS_CONTINUE) + if (expect == HTTP_STATUS_CONTINUE || digest) { DEBUG_puts("2cupsSendRequest: Waiting for 100-continue..."); @@ -996,7 +1004,11 @@ _cupsConnect(void) */ if (strcmp(cg->http->hostname, cg->server) || +#ifdef AF_LOCAL + (httpAddrFamily(cg->http->hostaddr) != AF_LOCAL && cg->ipp_port != httpAddrPort(cg->http->hostaddr)) || +#else cg->ipp_port != httpAddrPort(cg->http->hostaddr) || +#endif /* AF_LOCAL */ (cg->http->encryption != cg->encryption && cg->http->encryption == HTTP_ENCRYPTION_NEVER)) { @@ -1016,13 +1028,13 @@ _cupsConnect(void) char ch; /* Connection check byte */ ssize_t n; /* Number of bytes */ -#ifdef WIN32 +#ifdef _WIN32 if ((n = recv(cg->http->fd, &ch, 1, MSG_PEEK)) == 0 || (n < 0 && WSAGetLastError() != WSAEWOULDBLOCK)) #else if ((n = recv(cg->http->fd, &ch, 1, MSG_PEEK | MSG_DONTWAIT)) == 0 || (n < 0 && errno != EWOULDBLOCK)) -#endif /* WIN32 */ +#endif /* _WIN32 */ { /* * Nope, close the connection... diff --git a/cups/sidechannel.c b/cups/sidechannel.c index a4cd960a..f2dbabd6 100644 --- a/cups/sidechannel.c +++ b/cups/sidechannel.c @@ -19,15 +19,15 @@ #include "sidechannel.h" #include "cups-private.h" -#ifdef WIN32 +#ifdef _WIN32 # include <io.h> #else # include <unistd.h> -#endif /* WIN32 */ -#ifndef WIN32 +#endif /* _WIN32 */ +#ifndef _WIN32 # include <sys/select.h> # include <sys/time.h> -#endif /* !WIN32 */ +#endif /* !_WIN32 */ #ifdef HAVE_POLL # include <poll.h> #endif /* HAVE_POLL */ diff --git a/cups/snmp.c b/cups/snmp.c index fffa2182..8437528d 100644 --- a/cups/snmp.c +++ b/cups/snmp.c @@ -395,11 +395,11 @@ _cupsSNMPRead(int fd, /* I - SNMP socket file descriptor */ ready = select(fd + 1, &input_set, NULL, NULL, &stimeout); } -# ifdef WIN32 +# ifdef _WIN32 while (ready < 0 && WSAGetLastError() == WSAEINTR); # else while (ready < 0 && (errno == EINTR || errno == EAGAIN)); -# endif /* WIN32 */ +# endif /* _WIN32 */ #endif /* HAVE_POLL */ /* @@ -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/string-private.h b/cups/string-private.h index e8448d17..ced24923 100644 --- a/cups/string-private.h +++ b/cups/string-private.h @@ -1,7 +1,7 @@ /* * Private string definitions for CUPS. * - * Copyright 2007-2015 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -42,12 +42,12 @@ # include <bstring.h> # endif /* HAVE_BSTRING_H */ -# if defined(WIN32) && !defined(__CUPS_SSIZE_T_DEFINED) +# if defined(_WIN32) && !defined(__CUPS_SSIZE_T_DEFINED) # define __CUPS_SSIZE_T_DEFINED # include <stddef.h> /* Windows does not support the ssize_t type, so map it to long... */ typedef long ssize_t; /* @private@ */ -# endif /* WIN32 && !__CUPS_SSIZE_T_DEFINED */ +# endif /* _WIN32 && !__CUPS_SSIZE_T_DEFINED */ /* @@ -175,8 +175,7 @@ extern size_t _cups_strlcpy(char *, const char *, size_t); # endif /* !HAVE_STRLCPY */ # ifndef HAVE_SNPRINTF -extern int _cups_snprintf(char *, size_t, const char *, ...) - __attribute__ ((__format__ (__printf__, 3, 4))); +extern int _cups_snprintf(char *, size_t, const char *, ...) _CUPS_FORMAT(3, 4); # define snprintf _cups_snprintf # endif /* !HAVE_SNPRINTF */ diff --git a/cups/string.c b/cups/string.c index 39a787f0..0d4ed0f5 100644 --- a/cups/string.c +++ b/cups/string.c @@ -695,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 da705a94..7b341e13 100644 --- a/cups/tempfile.c +++ b/cups/tempfile.c @@ -1,8 +1,8 @@ /* * Temp file utilities for CUPS. * - * Copyright 2007-2014 by Apple Inc. - * Copyright 1997-2006 by Easy Software Products. + * Copyright © 2007-2018 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 @@ -21,11 +21,11 @@ #include <stdlib.h> #include <fcntl.h> #include <sys/stat.h> -#if defined(WIN32) || defined(__EMX__) +#if defined(_WIN32) || defined(__EMX__) # include <io.h> #else # include <unistd.h> -#endif /* WIN32 || __EMX__ */ +#endif /* _WIN32 || __EMX__ */ /* @@ -42,24 +42,46 @@ cupsTempFd(char *filename, /* I - Pointer to buffer */ int fd; /* File descriptor for temp file */ int tries; /* Number of tries */ const char *tmpdir; /* TMPDIR environment var */ -#ifdef WIN32 - char tmppath[1024]; /* Windows temporary directory */ +#if defined(__APPLE__) || defined(_WIN32) + char tmppath[1024]; /* Temporary directory */ +#endif /* __APPLE__ || _WIN32 */ +#ifdef _WIN32 DWORD curtime; /* Current time */ #else struct timeval curtime; /* Current time */ -#endif /* WIN32 */ +#endif /* _WIN32 */ /* * See if TMPDIR is defined... */ -#ifdef WIN32 +#ifdef _WIN32 if ((tmpdir = getenv("TEMP")) == NULL) { GetTempPath(sizeof(tmppath), tmppath); tmpdir = tmppath; } + +#elif defined(__APPLE__) + /* + * On macOS and iOS, the TMPDIR environment variable is not always the best + * location to place temporary files due to sandboxing. Instead, the confstr + * function should be called to get the proper per-user, per-process TMPDIR + * value. + */ + + if ((tmpdir = getenv("TMPDIR")) != NULL && access(tmpdir, W_OK)) + tmpdir = NULL; + + if (!tmpdir) + { + if (confstr(_CS_DARWIN_USER_TEMP_DIR, tmppath, sizeof(tmppath))) + tmpdir = tmppath; + else + tmpdir = "/private/tmp"; /* This should never happen */ + } + #else /* * Previously we put root temporary files in the default CUPS temporary @@ -69,12 +91,8 @@ cupsTempFd(char *filename, /* I - Pointer to buffer */ */ if ((tmpdir = getenv("TMPDIR")) == NULL) -# if defined(__APPLE__) && !TARGET_OS_IOS - tmpdir = "/private/tmp"; /* /tmp is a symlink to /private/tmp */ -# else tmpdir = "/tmp"; -# endif /* __APPLE__ && !TARGET_OS_IOS */ -#endif /* WIN32 */ +#endif /* _WIN32 */ /* * Make the temporary name using the specified directory... @@ -84,7 +102,7 @@ cupsTempFd(char *filename, /* I - Pointer to buffer */ do { -#ifdef WIN32 +#ifdef _WIN32 /* * Get the current time of day... */ @@ -108,21 +126,21 @@ cupsTempFd(char *filename, /* I - Pointer to buffer */ */ snprintf(filename, (size_t)len - 1, "%s/%05x%08x", tmpdir, (unsigned)getpid(), (unsigned)(curtime.tv_sec + curtime.tv_usec + tries)); -#endif /* WIN32 */ +#endif /* _WIN32 */ /* * Open the file in "exclusive" mode, making sure that we don't * stomp on an existing file or someone's symlink crack... */ -#ifdef WIN32 +#ifdef _WIN32 fd = open(filename, _O_CREAT | _O_RDWR | _O_TRUNC | _O_BINARY, _S_IREAD | _S_IWRITE); #elif defined(O_NOFOLLOW) fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); #else fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600); -#endif /* WIN32 */ +#endif /* _WIN32 */ if (fd < 0 && errno != EEXIST) break; diff --git a/cups/testarray.c b/cups/testarray.c index 6164ffc6..892e3250 100644 --- a/cups/testarray.c +++ b/cups/testarray.c @@ -494,7 +494,7 @@ main(void) * 'get_seconds()' - Get the current time in seconds... */ -#ifdef WIN32 +#ifdef _WIN32 # include <windows.h> @@ -515,7 +515,7 @@ get_seconds(void) gettimeofday(&curtime, NULL); return (curtime.tv_sec + 0.000001 * curtime.tv_usec); } -#endif /* WIN32 */ +#endif /* _WIN32 */ /* diff --git a/cups/testcups.c b/cups/testcups.c index aa587661..f4931c50 100644 --- a/cups/testcups.c +++ b/cups/testcups.c @@ -1,7 +1,7 @@ /* * CUPS API test program for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2017 by Apple Inc. * Copyright 2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -47,7 +47,9 @@ main(int argc, /* I - Number of command-line arguments */ cups_dest_t *dests, /* Destinations */ *dest, /* Current destination */ *named_dest; /* Current named destination */ - const char *ppdfile; /* PPD file */ + const char *dest_name, /* Destination name */ + *dval, /* Destination value */ + *ppdfile; /* PPD file */ ppd_file_t *ppd; /* PPD file data */ int num_jobs; /* Number of jobs for queue */ cups_job_t *jobs; /* Jobs for queue */ @@ -360,11 +362,19 @@ main(int argc, /* I - Number of command-line arguments */ * cupsGetDest(printer) */ - printf("cupsGetDest(\"%s\"): ", dests[num_dests / 2].name); + for (i = 0, dest_name = NULL; i < num_dests; i ++) + { + if ((dval = cupsGetOption("printer-is-temporary", dests[i].num_options, dest[i].options)) != NULL && !strcmp(dval, "false")) + { + dest_name = dests[i].name; + break; + } + } + + printf("cupsGetDest(\"%s\"): ", dest_name ? dest_name : "(null)"); fflush(stdout); - if ((dest = cupsGetDest(dests[num_dests / 2].name, NULL, num_dests, - dests)) == NULL) + if ((dest = cupsGetDest(dest_name, NULL, num_dests, dests)) == NULL) { puts("FAIL"); return (1); @@ -380,8 +390,7 @@ main(int argc, /* I - Number of command-line arguments */ dest->instance ? dest->instance : "(null)"); fflush(stdout); - if ((named_dest = cupsGetNamedDest(NULL, dest->name, - dest->instance)) == NULL || + if ((named_dest = cupsGetNamedDest(NULL, dest->name, dest->instance)) == NULL || !dests_equal(dest, named_dest)) { if (named_dest) @@ -408,7 +417,7 @@ main(int argc, /* I - Number of command-line arguments */ fputs("cupsPrintFile: ", stdout); fflush(stdout); - if (cupsPrintFile(dest->name, "../data/testprint", "Test Page", + if (cupsPrintFile(dest->name, "../test/testfile.pdf", "Test Page", dest->num_options, dest->options) <= 0) { printf("FAIL (%s)\n", cupsLastErrorString()); @@ -421,7 +430,7 @@ main(int argc, /* I - Number of command-line arguments */ * cupsGetPPD(printer) */ - fputs("cupsGetPPD(): ", stdout); + fputs("cupsGetPPD: ", stdout); fflush(stdout); if ((ppdfile = cupsGetPPD(dest->name)) == NULL) @@ -436,7 +445,7 @@ main(int argc, /* I - Number of command-line arguments */ * ppdOpenFile() */ - fputs("ppdOpenFile(): ", stdout); + fputs("ppdOpenFile: ", stdout); fflush(stdout); if ((ppd = ppdOpenFile(ppdfile)) == NULL) @@ -550,33 +559,39 @@ show_diffs(cups_dest_t *a, /* I - First destination */ { int i; /* Looping var */ cups_option_t *aoption; /* Current option */ + cups_option_t *boption; /* Current option */ const char *bval; /* Option value */ if (!a || !b) return; - puts(" Item cupsGetDest cupsGetNamedDest"); - puts(" -------------------- -------------------- --------------------"); + puts(" Item cupsGetDest cupsGetNamedDest"); + puts(" -------------------- ------------------------ ------------------------"); if (_cups_strcasecmp(a->name, b->name)) - printf(" name %-20.20s %-20.20s\n", a->name, b->name); + printf(" name %-24.24s %-24.24s\n", a->name, b->name); if ((a->instance && !b->instance) || (!a->instance && b->instance) || (a->instance && _cups_strcasecmp(a->instance, b->instance))) - printf(" instance %-20.20s %-20.20s\n", + printf(" instance %-24.24s %-24.24s\n", a->instance ? a->instance : "(null)", b->instance ? b->instance : "(null)"); if (a->num_options != b->num_options) - printf(" num_options %-20d %-20d\n", a->num_options, + printf(" num_options %-24d %-24d\n", a->num_options, b->num_options); for (i = a->num_options, aoption = a->options; i > 0; i --, aoption ++) if ((bval = cupsGetOption(aoption->name, b->num_options, b->options)) == NULL || strcmp(aoption->value, bval)) - printf(" %-20.20s %-20.20s %-20.20s\n", aoption->name, + printf(" %-20.20s %-24.24s %-24.24s\n", aoption->name, aoption->value, bval ? bval : "(null)"); + + for (i = b->num_options, boption = b->options; i > 0; i --, boption ++) + if (!cupsGetOption(boption->name, a->num_options, a->options)) + printf(" %-20.20s %-24.24s %-24.24s\n", boption->name, + boption->value, "(null)"); } diff --git a/cups/testdest.c b/cups/testdest.c index 945e3e11..9eab8d2e 100644 --- a/cups/testdest.c +++ b/cups/testdest.c @@ -1,7 +1,7 @@ /* * CUPS destination API test program for CUPS. * - * Copyright 2012-2016 by Apple Inc. + * Copyright 2012-2018 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -32,7 +32,7 @@ static void show_conflicts(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, static void show_default(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option); static void show_media(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, unsigned flags, const char *name); static void show_supported(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option, const char *value); -static void usage(const char *arg) __attribute__((noreturn)); +static void usage(const char *arg) _CUPS_NORETURN; /* @@ -105,6 +105,14 @@ main(int argc, /* I - Number of command-line arguments */ } else if (!strncmp(argv[1], "ipp://", 6) || !strncmp(argv[1], "ipps://", 7)) dest = cupsGetDestWithURI(NULL, argv[1]); + else if (!strcmp(argv[1], "default")) + { + dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, NULL, NULL); + if (dest && dest->instance) + printf("default is \"%s/%s\".\n", dest->name, dest->instance); + else + printf("default is \"%s\".\n", dest->name); + } else dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, argv[1], NULL); @@ -218,9 +226,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); @@ -463,10 +471,37 @@ show_default(http_t *http, /* I - Connection to destination */ cups_dinfo_t *dinfo, /* I - Destination information */ const char *option) /* I - Option */ { - (void)http; - (void)dest; - (void)dinfo; - (void)option; + if (!strcmp(option, "media")) + { + /* + * Show default media option... + */ + + cups_size_t size; /* Media size information */ + + if (cupsGetDestMediaDefault(http, dest, dinfo, CUPS_MEDIA_FLAGS_DEFAULT, &size)) + printf("%s (%.2fx%.2fmm, margins=[%.2f %.2f %.2f %.2f])\n", size.media, size.width * 0.01, size.length * 0.01, size.left * 0.01, size.bottom * 0.01, size.right * 0.01, size.top * 0.01); + else + puts("FAILED"); + } + else + { + /* + * Show default other option... + */ + + ipp_attribute_t *defattr; /* Default attribute */ + + if ((defattr = cupsFindDestDefault(http, dest, dinfo, option)) != NULL) + { + char value[1024]; /* Value of default attribute */ + + ippAttributeString(defattr, value, sizeof(value)); + puts(value); + } + else + puts("FAILED"); + } } @@ -594,7 +629,8 @@ show_supported(http_t *http, /* I - Connection to destination */ } else if (!value) { - puts(option); + printf("%s (%s - %s)\n", option, cupsLocalizeDestOption(http, dest, dinfo, option), cupsCheckDestSupported(http, dest, dinfo, option, NULL) ? "supported" : "not-supported"); + if ((attr = cupsFindDestSupported(http, dest, dinfo, option)) != NULL) { count = ippGetCount(attr); @@ -608,7 +644,13 @@ show_supported(http_t *http, /* I - Connection to destination */ case IPP_TAG_ENUM : for (i = 0; i < count; i ++) - printf(" %s\n", ippEnumString(option, ippGetInteger(attr, i))); + { + int val = ippGetInteger(attr, i); + char valstr[256]; + + snprintf(valstr, sizeof(valstr), "%d", val); + printf(" %s (%s)\n", ippEnumString(option, ippGetInteger(attr, i)), cupsLocalizeDestValue(http, dest, dinfo, option, valstr)); + } break; case IPP_TAG_RANGE : @@ -634,11 +676,15 @@ show_supported(http_t *http, /* I - Connection to destination */ } break; + case IPP_TAG_KEYWORD : + for (i = 0; i < count; i ++) + printf(" %s (%s)\n", ippGetString(attr, i, NULL), cupsLocalizeDestValue(http, dest, dinfo, option, ippGetString(attr, i, NULL))); + break; + case IPP_TAG_TEXTLANG : case IPP_TAG_NAMELANG : case IPP_TAG_TEXT : case IPP_TAG_NAME : - case IPP_TAG_KEYWORD : case IPP_TAG_URI : case IPP_TAG_URISCHEME : case IPP_TAG_CHARSET : diff --git a/cups/testfile.c b/cups/testfile.c index b2ec8cd5..1473a4a0 100644 --- a/cups/testfile.c +++ b/cups/testfile.c @@ -1,7 +1,7 @@ /* * File test program for CUPS. * - * Copyright 2007-2015 by Apple Inc. + * Copyright 2007-2018 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -22,14 +22,11 @@ #include "file.h" #include <stdlib.h> #include <time.h> -#ifdef HAVE_LIBZ -# include <zlib.h> -#endif /* HAVE_LIBZ */ -#ifdef WIN32 +#ifdef _WIN32 # include <io.h> #else # include <unistd.h> -#endif /* WIN32 */ +#endif /* _WIN32 */ #include <fcntl.h> @@ -53,10 +50,10 @@ main(int argc, /* I - Number of command-line arguments */ int status; /* Exit status */ char filename[1024]; /* Filename buffer */ cups_file_t *fp; /* File pointer */ -#ifndef WIN32 +#ifndef _WIN32 int fds[2]; /* Open file descriptors */ cups_file_t *fdfile; /* File opened with cupsFileOpenFd() */ -#endif /* !WIN32 */ +#endif /* !_WIN32 */ int count; /* Number of lines in file */ @@ -84,7 +81,7 @@ main(int argc, /* I - Number of command-line arguments */ status += random_tests(); -#ifndef WIN32 +#ifndef _WIN32 /* * Test fdopen and close without reading... */ @@ -118,7 +115,7 @@ main(int argc, /* I - Number of command-line arguments */ puts("PASS"); } -#endif /* !WIN32 */ +#endif /* !_WIN32 */ /* * Count lines in psglyphs, rewind, then count again. @@ -174,13 +171,13 @@ main(int argc, /* I - Number of command-line arguments */ */ fputs("\ncupsFileFind: ", stdout); -#ifdef WIN32 +#ifdef _WIN32 if (cupsFileFind("notepad.exe", "C:/WINDOWS", 1, filename, sizeof(filename)) && cupsFileFind("notepad.exe", "C:/WINDOWS;C:/WINDOWS/SYSTEM32", 1, filename, sizeof(filename))) #else if (cupsFileFind("cat", "/bin", 1, filename, sizeof(filename)) && cupsFileFind("cat", "/bin:/usr/bin", 1, filename, sizeof(filename))) -#endif /* WIN32 */ +#endif /* _WIN32 */ printf("PASS (%s)\n", filename); else { diff --git a/cups/testgetdests.c b/cups/testgetdests.c new file mode 100644 index 00000000..459998f9 --- /dev/null +++ b/cups/testgetdests.c @@ -0,0 +1,51 @@ +/* + * CUPS cupsGetDests API test program for CUPS. + * + * Copyright 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 + * missing or damaged, see the license at "http://www.cups.org/". + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +/* + * Include necessary headers... + */ + +#include <stdio.h> +#include "cups.h" +#include <sys/time.h> + + +/* + * 'main()' - Loop calling cupsGetDests. + */ + +int /* O - Exit status */ +main(void) +{ + int num_dests; /* Number of destinations */ + cups_dest_t *dests; /* Destinations */ + struct timeval start, end; /* Start and stop time */ + double secs; /* Total seconds to run cupsGetDests */ + + + for (;;) + { + gettimeofday(&start, NULL); + num_dests = cupsGetDests(&dests); + gettimeofday(&end, NULL); + secs = end.tv_sec - start.tv_sec + 0.000001 * (end.tv_usec - start.tv_usec); + + printf("Found %d printers in %.3f seconds...\n", num_dests, secs); + + cupsFreeDests(num_dests, dests); + sleep(1); + } + + return (0); +} diff --git a/cups/testhttp.c b/cups/testhttp.c index 376d71f6..7d8ec06d 100644 --- a/cups/testhttp.c +++ b/cups/testhttp.c @@ -1,8 +1,8 @@ /* * HTTP test program for CUPS. * - * Copyright 2007-2014 by Apple Inc. - * Copyright 1997-2006 by Easy Software Products. + * Copyright © 2007-2018 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 @@ -120,6 +120,9 @@ static uri_test_t uri_tests[] = /* URI test data */ { HTTP_URI_STATUS_OK, "ipp://%22%23%2F%3A%3C%3E%3F%40%5B%5C%5D%5E%60%7B%7C%7D/", "ipp", "", "\"#/:<>?@[\\]^`{|}", "/", 631, 0, HTTP_URI_CODING_MOST }, + { HTTP_URI_STATUS_UNKNOWN_SCHEME, "smb://server/Some%20Printer", + "smb", "", "server", "/Some Printer", 0, 0, + HTTP_URI_CODING_ALL }, /* Missing scheme */ { HTTP_URI_STATUS_MISSING_SCHEME, "/path/to/file/index.html", @@ -148,6 +151,9 @@ static uri_test_t uri_tests[] = /* URI test data */ HTTP_URI_CODING_MOST }, /* Bad scheme */ + { HTTP_URI_STATUS_BAD_SCHEME, "://server/ipp", + "", "", "", "", 0, 0, + HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_BAD_SCHEME, "bad_scheme://server/resource", "", "", "", "", 0, 0, HTTP_URI_CODING_MOST }, @@ -180,6 +186,9 @@ static uri_test_t uri_tests[] = /* URI test data */ HTTP_URI_CODING_MOST }, /* Bad resource */ + { HTTP_URI_STATUS_BAD_RESOURCE, "mailto:\r\nbla", + "mailto", "", "", "", 0, 0, + HTTP_URI_CODING_MOST }, { HTTP_URI_STATUS_BAD_RESOURCE, "http://server/index.html%", "http", "", "server", "", 80, 0, HTTP_URI_CODING_MOST }, @@ -332,6 +341,40 @@ main(int argc, /* I - Number of command-line arguments */ if (!j) puts("PASS"); +#if 0 + /* + * _httpDigest() + */ + + fputs("_httpDigest(MD5): ", stdout); + if (!_httpDigest(buffer, sizeof(buffer), "MD5", "Mufasa", "http-auth@example.org", "Circle of Life", "7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", 1, "f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ", "auth", "GET", "/dir/index.html")) + { + failures ++; + puts("FAIL (unable to calculate hash)"); + } + else if (strcmp(buffer, "8ca523f5e9506fed4657c9700eebdbec")) + { + failures ++; + printf("FAIL (got \"%s\", expected \"8ca523f5e9506fed4657c9700eebdbec\")\n", buffer); + } + else + puts("PASS"); + + fputs("_httpDigest(SHA-256): ", stdout); + if (!_httpDigest(buffer, sizeof(buffer), "SHA-256", "Mufasa", "http-auth@example.org", "Circle of Life", "7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v", 1, "f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ", "auth", "GET", "/dir/index.html")) + { + failures ++; + puts("FAIL (unable to calculate hash)"); + } + else if (strcmp(buffer, "753927fa0e85d155564e2e272a28d1802ca10daf4496794697cf8db5856cb6c1")) + { + failures ++; + printf("FAIL (got \"%s\", expected \"753927fa0e85d155564e2e272a28d1802ca10daf4496794697cf8db5856cb6c1\")\n", buffer); + } + else + puts("PASS"); +#endif /* 0 */ + /* * httpGetHostname() */ @@ -590,6 +633,8 @@ main(int argc, /* I - Number of command-line arguments */ for (i = 1; i < argc; i ++) { + int new_auth; + if (!strcmp(argv[i], "-o")) { i ++; @@ -673,6 +718,8 @@ main(int argc, /* I - Number of command-line arguments */ printf("Checking file \"%s\"...\n", resource); + new_auth = 0; + do { if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) @@ -685,9 +732,13 @@ main(int argc, /* I - Number of command-line arguments */ } } + if (http->authstring && !strncmp(http->authstring, "Digest ", 7) && !new_auth) + _httpSetDigestAuthString(http, http->nextnonce, "HEAD", resource); + httpClearFields(http); httpSetField(http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString(http)); httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); + if (httpHead(http, resource)) { if (httpReconnect2(http, 30000, NULL)) @@ -704,6 +755,8 @@ main(int argc, /* I - Number of command-line arguments */ while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); + new_auth = 0; + if (status == HTTP_STATUS_UNAUTHORIZED) { /* @@ -716,7 +769,9 @@ main(int argc, /* I - Number of command-line arguments */ * See if we can do authentication... */ - if (cupsDoAuthentication(http, "GET", resource)) + new_auth = 1; + + if (cupsDoAuthentication(http, "HEAD", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; break; @@ -764,6 +819,8 @@ main(int argc, /* I - Number of command-line arguments */ printf("Requesting file \"%s\" (Accept-Encoding: %s)...\n", resource, encoding ? encoding : "identity"); + new_auth = 0; + do { if (!_cups_strcasecmp(httpGetField(http, HTTP_FIELD_CONNECTION), "close")) @@ -776,6 +833,9 @@ main(int argc, /* I - Number of command-line arguments */ } } + if (http->authstring && !strncmp(http->authstring, "Digest ", 7) && !new_auth) + _httpSetDigestAuthString(http, http->nextnonce, "GET", resource); + httpClearFields(http); httpSetField(http, HTTP_FIELD_AUTHORIZATION, httpGetAuthString(http)); httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); @@ -797,6 +857,8 @@ main(int argc, /* I - Number of command-line arguments */ while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE); + new_auth = 0; + if (status == HTTP_STATUS_UNAUTHORIZED) { /* @@ -809,6 +871,8 @@ main(int argc, /* I - Number of command-line arguments */ * See if we can do authentication... */ + new_auth = 1; + if (cupsDoAuthentication(http, "GET", resource)) { status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED; diff --git a/cups/testipp.c b/cups/testipp.c index 017ee9d6..2ef2496e 100644 --- a/cups/testipp.c +++ b/cups/testipp.c @@ -1,7 +1,7 @@ /* * IPP test program for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2005 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -20,12 +20,12 @@ #include "file.h" #include "string-private.h" #include "ipp-private.h" -#ifdef WIN32 +#ifdef _WIN32 # include <io.h> #else # include <unistd.h> # include <fcntl.h> -#endif /* WIN32 */ +#endif /* _WIN32 */ /* @@ -810,88 +810,9 @@ void print_attributes(ipp_t *ipp, /* I - IPP request */ int indent) /* I - Indentation */ { - int i; /* Looping var */ ipp_tag_t group; /* Current group */ ipp_attribute_t *attr; /* Current attribute */ - _ipp_value_t *val; /* Current value */ - static const char * const tags[] = /* Value/group tag strings */ - { - "reserved-00", - "operation-attributes-tag", - "job-attributes-tag", - "end-of-attributes-tag", - "printer-attributes-tag", - "unsupported-attributes-tag", - "subscription-attributes-tag", - "event-attributes-tag", - "reserved-08", - "reserved-09", - "reserved-0A", - "reserved-0B", - "reserved-0C", - "reserved-0D", - "reserved-0E", - "reserved-0F", - "unsupported", - "default", - "unknown", - "no-value", - "reserved-14", - "not-settable", - "delete-attr", - "admin-define", - "reserved-18", - "reserved-19", - "reserved-1A", - "reserved-1B", - "reserved-1C", - "reserved-1D", - "reserved-1E", - "reserved-1F", - "reserved-20", - "integer", - "boolean", - "enum", - "reserved-24", - "reserved-25", - "reserved-26", - "reserved-27", - "reserved-28", - "reserved-29", - "reserved-2a", - "reserved-2b", - "reserved-2c", - "reserved-2d", - "reserved-2e", - "reserved-2f", - "octetString", - "dateTime", - "resolution", - "rangeOfInteger", - "begCollection", - "textWithLanguage", - "nameWithLanguage", - "endCollection", - "reserved-38", - "reserved-39", - "reserved-3a", - "reserved-3b", - "reserved-3c", - "reserved-3d", - "reserved-3e", - "reserved-3f", - "reserved-40", - "textWithoutLanguage", - "nameWithoutLanguage", - "reserved-43", - "keyword", - "uri", - "uriScheme", - "charset", - "naturalLanguage", - "mimeMediaType", - "memberName" - }; + char buffer[2048]; /* Value string */ for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next) @@ -907,83 +828,12 @@ print_attributes(ipp_t *ipp, /* I - IPP request */ { group = attr->group_tag; - printf("\n%*s%s:\n\n", indent - 4, "", tags[group]); + printf("\n%*s%s:\n\n", indent - 4, "", ippTagString(group)); } - printf("%*s%s (", indent, "", attr->name ? attr->name : "(null)"); - if (attr->num_values > 1) - printf("1setOf "); - printf("%s):", tags[attr->value_tag]); + ippAttributeString(attr, buffer, sizeof(buffer)); - switch (attr->value_tag) - { - case IPP_TAG_ENUM : - case IPP_TAG_INTEGER : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - printf(" %d", val->integer); - putchar('\n'); - break; - - case IPP_TAG_BOOLEAN : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - printf(" %s", val->boolean ? "true" : "false"); - putchar('\n'); - break; - - case IPP_TAG_RANGE : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - printf(" %d-%d", val->range.lower, val->range.upper); - putchar('\n'); - break; - - case IPP_TAG_DATE : - { - char vstring[256]; /* Formatted time */ - - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - printf(" (%s)", _cupsStrDate(vstring, sizeof(vstring), ippDateToTime(val->date))); - } - putchar('\n'); - break; - - case IPP_TAG_RESOLUTION : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - printf(" %dx%d%s", val->resolution.xres, val->resolution.yres, - val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpcm"); - putchar('\n'); - break; - - case IPP_TAG_STRING : - case IPP_TAG_TEXTLANG : - case IPP_TAG_NAMELANG : - case IPP_TAG_TEXT : - case IPP_TAG_NAME : - case IPP_TAG_KEYWORD : - case IPP_TAG_URI : - case IPP_TAG_URISCHEME : - case IPP_TAG_CHARSET : - case IPP_TAG_LANGUAGE : - case IPP_TAG_MIMETYPE : - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - printf(" \"%s\"", val->string.text); - putchar('\n'); - break; - - case IPP_TAG_BEGIN_COLLECTION : - putchar('\n'); - - for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) - { - if (i) - putchar('\n'); - print_attributes(val->collection, indent + 4); - } - break; - - default : - printf("UNKNOWN (%d values)\n", attr->num_values); - break; - } + printf("%*s%s (%s%s): %s\n", indent, "", attr->name ? attr->name : "(null)", attr->num_values > 1 ? "1setOf " : "", ippTagString(attr->value_tag), buffer); } } diff --git a/cups/testlang.c b/cups/testlang.c index 6aa49ab4..3f140d9b 100644 --- a/cups/testlang.c +++ b/cups/testlang.c @@ -1,7 +1,7 @@ /* * Localization 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 @@ -19,6 +19,16 @@ #include "cups-private.h" #include "ppd-private.h" +#ifdef __APPLE__ +# include <CoreFoundation/CoreFoundation.h> +#endif /* __APPLE__ */ + + +/* + * Local functions... + */ + +static int test_string(cups_lang_t *language, const char *msgid); /* @@ -71,8 +81,9 @@ main(int argc, /* I - Number of command-line arguments */ printf("Language = \"%s\"\n", language->language); printf("Encoding = \"%s\"\n", _cupsEncodingName(language->encoding)); - printf("No = \"%s\"\n", _cupsLangString(language, "No")); - printf("Yes = \"%s\"\n", _cupsLangString(language, "Yes")); + + errors += test_string(language, "No"); + errors += test_string(language, "Yes"); if (language != language2) { @@ -138,9 +149,141 @@ main(int argc, /* I - Number of command-line arguments */ } } + printf("media-empty: %s\n", ppdLocalizeIPPReason(ppd, "media-empty", NULL, buffer, sizeof(buffer))); + ppdClose(ppd); } } +#ifdef __APPLE__ + else + { + /* + * Test all possible language IDs for compatibility with _cupsAppleLocale... + */ + + CFIndex j, /* Looping var */ + num_locales; /* Number of locales */ + CFArrayRef locales; /* Locales */ + CFStringRef locale_id, /* Current locale ID */ + language_id; /* Current language ID */ + char locale_str[256], /* Locale ID C string */ + language_str[256], /* Language ID C string */ + *bufptr; /* Pointer to ".UTF-8" in POSIX locale */ + size_t buflen; /* Length of POSIX locale */ +# if TEST_COUNTRY_CODES + CFIndex k, /* Looping var */ + num_country_codes; /* Number of country codes */ + CFArrayRef country_codes; /* Country codes */ + CFStringRef country_code, /* Current country code */ + temp_id; /* Temporary language ID */ + char country_str[256]; /* Country code C string */ +# endif /* TEST_COUNTRY_CODES */ + + locales = CFLocaleCopyAvailableLocaleIdentifiers(); + num_locales = CFArrayGetCount(locales); + +# if TEST_COUNTRY_CODES + country_codes = CFLocaleCopyISOCountryCodes(); + num_country_codes = CFArrayGetCount(country_codes); +# endif /* TEST_COUNTRY_CODES */ + + printf("%d locales are available:\n", (int)num_locales); + + for (j = 0; j < num_locales; j ++) + { + locale_id = CFArrayGetValueAtIndex(locales, j); + language_id = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorDefault, locale_id); + + if (!locale_id || !CFStringGetCString(locale_id, locale_str, (CFIndex)sizeof(locale_str), kCFStringEncodingASCII)) + { + printf("%d: FAIL (unable to get locale ID string)\n", (int)j + 1); + errors ++; + continue; + } + + if (!language_id || !CFStringGetCString(language_id, language_str, (CFIndex)sizeof(language_str), kCFStringEncodingASCII)) + { + printf("%d %s: FAIL (unable to get language ID string)\n", (int)j + 1, locale_str); + errors ++; + continue; + } + + if (!_cupsAppleLocale(language_id, buffer, sizeof(buffer))) + { + printf("%d %s(%s): FAIL (unable to convert language ID string to POSIX locale)\n", (int)j + 1, locale_str, language_str); + errors ++; + continue; + } + + if ((bufptr = strstr(buffer, ".UTF-8")) != NULL) + buflen = (size_t)(bufptr - buffer); + else + buflen = strlen(buffer); + + if ((language = cupsLangGet(buffer)) == NULL) + { + printf("%d %s(%s): FAIL (unable to load POSIX locale \"%s\")\n", (int)j + 1, locale_str, language_str, buffer); + errors ++; + continue; + } + + if (strncasecmp(language->language, buffer, buflen)) + { + printf("%d %s(%s): FAIL (unable to load POSIX locale \"%s\", got \"%s\")\n", (int)j + 1, locale_str, language_str, buffer, language->language); + errors ++; + continue; + } + + printf("%d %s(%s): PASS (POSIX locale is \"%s\")\n", (int)j + 1, locale_str, language_str, buffer); + } + + CFRelease(locales); + +# if TEST_COUNTRY_CODES + CFRelease(country_codes); +# endif /* TEST_COUNTRY_CODES */ + } +#endif /* __APPLE__ */ + + if (errors == 0) + puts("ALL TESTS PASSED"); return (errors > 0); } + + +/* + * 'test_string()' - Test the localization of a string. + */ + +static int /* O - 1 on failure, 0 on success */ +test_string(cups_lang_t *language, /* I - Language */ + const char *msgid) /* I - Message */ +{ + const char *msgstr; /* Localized string */ + + + /* + * Get the localized string and then see if we got what we expected. + * + * For the POSIX locale, the string pointers should be the same. + * For any other locale, the string pointers should be different. + */ + + msgstr = _cupsLangString(language, msgid); + if (strcmp(language->language, "C") && msgid == msgstr) + { + printf("%-8s = \"%s\" (FAIL - no message catalog loaded)\n", msgid, msgstr); + return (1); + } + else if (!strcmp(language->language, "C") && msgid != msgstr) + { + printf("%-8s = \"%s\" (FAIL - POSIX locale is localized)\n", msgid, msgstr); + return (1); + } + + printf("%-8s = \"%s\" (PASS)\n", msgid, msgstr); + + return (0); +} + diff --git a/cups/testppd.c b/cups/testppd.c index e1b51564..a127a794 100644 --- a/cups/testppd.c +++ b/cups/testppd.c @@ -21,12 +21,12 @@ #include "cups-private.h" #include "ppd-private.h" #include <sys/stat.h> -#ifdef WIN32 +#ifdef _WIN32 # include <io.h> #else # include <unistd.h> # include <fcntl.h> -#endif /* WIN32 */ +#endif /* _WIN32 */ #include <math.h> @@ -876,6 +876,13 @@ main(int argc, /* I - Number of command-line arguments */ host[256], /* Hostname */ resource[256]; /* Resource path */ int port; /* Port number */ + static const char * const pattrs[] =/* Requested printer attributes */ + { + "job-template", + "printer-defaults", + "printer-description", + "media-col-database" + }; if (httpSeparateURI(HTTP_URI_CODING_ALL, argv[1], scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) { @@ -892,6 +899,7 @@ main(int argc, /* I - Number of command-line arguments */ request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, argv[1]); + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), NULL, pattrs); response = cupsDoRequest(http, request, resource); if (_ppdCreateFromIPP(buffer, sizeof(buffer), response)) diff --git a/cups/testsnmp.c b/cups/testsnmp.c index 4026a28b..9e168ab7 100644 --- a/cups/testsnmp.c +++ b/cups/testsnmp.c @@ -1,7 +1,7 @@ /* * SNMP test program for CUPS. * - * Copyright 2008-2014 by Apple Inc. + * Copyright 2008-2018 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -27,7 +27,7 @@ static void print_packet(cups_snmp_t *packet, void *data); static int show_oid(int fd, const char *community, http_addr_t *addr, const char *s, int walk); -static void usage(void) __attribute__((noreturn)); +static void usage(void) _CUPS_NORETURN; /* diff --git a/cups/thread-private.h b/cups/thread-private.h index ca4ef4cb..ae8163d1 100644 --- a/cups/thread-private.h +++ b/cups/thread-private.h @@ -1,7 +1,7 @@ /* * Private threading definitions 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 @@ -46,7 +46,7 @@ typedef pthread_key_t _cups_threadkey_t; # define _cupsThreadGetData(k) pthread_getspecific(k) # define _cupsThreadSetData(k,p) pthread_setspecific(k,p) -# elif defined(WIN32) /* Windows threading */ +# elif defined(_WIN32) /* Windows threading */ # include <winsock2.h> # include <windows.h> typedef void *(__stdcall *_cups_thread_func_t)(void *arg); @@ -99,6 +99,7 @@ extern void _cupsRWLockWrite(_cups_rwlock_t *rwlock); extern void _cupsRWUnlock(_cups_rwlock_t *rwlock); extern void _cupsThreadCancel(_cups_thread_t thread); extern _cups_thread_t _cupsThreadCreate(_cups_thread_func_t func, void *arg); +extern void _cupsThreadDetach(_cups_thread_t thread); extern void *_cupsThreadWait(_cups_thread_t thread); # ifdef __cplusplus diff --git a/cups/thread.c b/cups/thread.c index 77b44426..7ffc2ec0 100644 --- a/cups/thread.c +++ b/cups/thread.c @@ -1,7 +1,7 @@ /* * Threading primitives for CUPS. * - * Copyright 2009-2016 by Apple Inc. + * Copyright © 2009-2018 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -56,8 +56,16 @@ _cupsCondWait(_cups_cond_t *cond, /* I - Condition */ { struct timespec abstime; /* Timeout */ - abstime.tv_sec = (long)timeout; - abstime.tv_nsec = (long)(1000000000 * (timeout - (long)timeout)); + clock_gettime(CLOCK_REALTIME, &abstime); + + abstime.tv_sec += (long)timeout; + abstime.tv_nsec += (long)(1000000000 * (timeout - (long)timeout)); + + while (abstime.tv_nsec >= 1000000000) + { + abstime.tv_nsec -= 1000000000; + abstime.tv_sec ++; + }; pthread_cond_timedwait(cond, mutex, &abstime); } @@ -173,6 +181,17 @@ _cupsThreadCreate( /* + * '_cupsThreadDetach()' - Tell the OS that the thread is running independently. + */ + +void +_cupsThreadDetach(_cups_thread_t thread)/* I - Thread ID */ +{ + pthread_detach(thread); +} + + +/* * '_cupsThreadWait()' - Wait for a thread to exit. */ @@ -189,7 +208,7 @@ _cupsThreadWait(_cups_thread_t thread) /* I - Thread ID */ } -#elif defined(WIN32) +#elif defined(_WIN32) # include <process.h> @@ -344,6 +363,18 @@ _cupsThreadCreate( /* + * '_cupsThreadDetach()' - Tell the OS that the thread is running independently. + */ + +void +_cupsThreadDetach(_cups_thread_t thread)/* I - Thread ID */ +{ + // TODO: Implement me + (void)thread; +} + + +/* * '_cupsThreadWait()' - Wait for a thread to exit. */ @@ -490,8 +521,7 @@ _cupsThreadCreate( _cups_thread_func_t func, /* I - Entry point */ void *arg) /* I - Entry point context */ { - fputs("DEBUG: CUPS was compiled without threading support, no thread " - "created.\n", stderr); + fputs("DEBUG: CUPS was compiled without threading support, no thread created.\n", stderr); (void)func; (void)arg; @@ -501,6 +531,17 @@ _cupsThreadCreate( /* + * '_cupsThreadDetach()' - Tell the OS that the thread is running independently. + */ + +void +_cupsThreadDetach(_cups_thread_t thread)/* I - Thread ID */ +{ + (void)thread; +} + + +/* * '_cupsThreadWait()' - Wait for a thread to exit. */ diff --git a/cups/tls-darwin.c b/cups/tls-darwin.c index b6e88b01..c4f0ccb2 100644 --- a/cups/tls-darwin.c +++ b/cups/tls-darwin.c @@ -1,8 +1,8 @@ /* * TLS support code for CUPS on macOS. * - * Copyright 2007-2016 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Copyright © 2007-2018 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 @@ -21,7 +21,7 @@ #include <spawn.h> -extern char **environ; +extern char **environ; /* @private@ */ /* @@ -53,7 +53,9 @@ static char *tls_keypath = NULL; /* Server cert keychain path */ static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER; /* Mutex for keychain/certs */ -static int tls_options = -1;/* Options for TLS connections */ +static int tls_options = -1,/* Options for TLS connections */ + tls_min_version = _HTTP_TLS_1_0, + tls_max_version = _HTTP_TLS_MAX; /* @@ -807,7 +809,6 @@ httpCredentialsString( CFStringRef cf_name; /* CF common name string */ char name[256]; /* Common name associated with cert */ time_t expiration; /* Expiration date of cert */ - _cups_md5_state_t md5_state; /* MD5 state */ unsigned char md5_digest[16]; /* MD5 result */ if ((cf_name = SecCertificateCopySubjectSummary(secCert)) != NULL) @@ -820,9 +821,7 @@ httpCredentialsString( expiration = (time_t)(SecCertificateNotValidAfter(secCert) + kCFAbsoluteTimeIntervalSince1970); - _cupsMD5Init(&md5_state); - _cupsMD5Append(&md5_state, first->data, (int)first->datalen); - _cupsMD5Finish(&md5_state, md5_digest); + cupsHashData("md5", first->data, first->datalen, md5_digest, sizeof(md5_digest)); snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", name, httpGetDateString(expiration), md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]); @@ -1139,9 +1138,16 @@ _httpTLSRead(http_t *http, /* I - HTTP connection */ */ void -_httpTLSSetOptions(int options) /* I - Options */ +_httpTLSSetOptions(int options, /* I - Options */ + int min_version, /* I - Minimum TLS version */ + int max_version) /* I - Maximum TLS version */ { - tls_options = options; + if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0) + { + tls_options = options; + tls_min_version = min_version; + tls_max_version = max_version; + } } @@ -1173,7 +1179,7 @@ _httpTLSStart(http_t *http) /* I - HTTP connection */ { DEBUG_puts("4_httpTLSStart: Setting defaults."); _cupsSetDefaults(); - DEBUG_printf(("4_httpTLSStart: tls_options=%x", tls_options)); + DEBUG_printf(("4_httpTLSStart: tls_options=%x, tls_min_version=%d, tls_max_version=%d", tls_options, tls_min_version, tls_max_version)); } #ifdef HAVE_SECKEYCHAINOPEN @@ -1216,17 +1222,26 @@ _httpTLSStart(http_t *http) /* I - HTTP connection */ if (!error) { - SSLProtocol minProtocol; - - if (tls_options & _HTTP_TLS_DENY_TLS10) - minProtocol = kTLSProtocol11; - else if (tls_options & _HTTP_TLS_ALLOW_SSL3) - minProtocol = kSSLProtocol3; - else - minProtocol = kTLSProtocol1; + static const SSLProtocol protocols[] = /* Min/max protocol versions */ + { + kSSLProtocol3, + kTLSProtocol1, + kTLSProtocol11, + kTLSProtocol12, + kTLSProtocol13 + }; + + if (tls_min_version < _HTTP_TLS_MAX) + { + error = SSLSetProtocolVersionMin(http->tls, protocols[tls_min_version]); + DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", protocols[tls_min_version], (int)error)); + } - error = SSLSetProtocolVersionMin(http->tls, minProtocol); - DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", minProtocol, (int)error)); + if (!error && tls_max_version < _HTTP_TLS_MAX) + { + error = SSLSetProtocolVersionMax(http->tls, protocols[tls_max_version]); + DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMax(%d), error=%d", protocols[tls_max_version], (int)error)); + } } # if HAVE_SSLSETENABLEDCIPHERS @@ -1324,7 +1339,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 : @@ -1337,6 +1351,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 : @@ -1347,15 +1369,31 @@ _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 : + case TLS_RSA_WITH_3DES_EDE_CBC_SHA : + case TLS_RSA_WITH_AES_128_CBC_SHA : + case TLS_RSA_WITH_AES_256_CBC_SHA : + 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; @@ -1502,7 +1540,28 @@ _httpTLSStart(http_t *http) /* I - HTTP connection */ if (!error) { - int done = 0; /* Are we done yet? */ + int done = 0; /* Are we done yet? */ + double old_timeout; /* Old timeout value */ + http_timeout_cb_t old_cb; /* Old timeout callback */ + void *old_data; /* Old timeout data */ + + /* + * Enforce a minimum timeout of 10 seconds for the TLS handshake... + */ + + old_timeout = http->timeout_value; + old_cb = http->timeout_cb; + old_data = http->timeout_data; + + if (!old_cb || old_timeout < 10.0) + { + DEBUG_puts("4_httpTLSStart: Setting timeout to 10 seconds."); + httpSetTimeout(http, 10.0, NULL, NULL); + } + + /* + * Do the TLS handshake... + */ while (!error && !done) { @@ -1623,6 +1682,12 @@ _httpTLSStart(http_t *http) /* I - HTTP connection */ break; } } + + /* + * Restore the previous timeout settings... + */ + + httpSetTimeout(http, old_timeout, old_cb, old_data); } if (error) @@ -1834,7 +1899,9 @@ http_cdsa_copy_server( DEBUG_printf(("4http_cdsa_copy_server: Returning %p.", (void *)certificates)); return (certificates); + #else + (void)common_name; if (!tls_selfsigned) return (NULL); @@ -2055,7 +2122,7 @@ http_cdsa_read( http = (http_t *)connection; - if (!http->blocking) + if (!http->blocking || http->timeout_value > 0.0) { /* * Make sure we have data before we read... diff --git a/cups/tls-gnutls.c b/cups/tls-gnutls.c index 7193d794..606b45af 100644 --- a/cups/tls-gnutls.c +++ b/cups/tls-gnutls.c @@ -1,8 +1,8 @@ /* * TLS support code for CUPS using GNU TLS. * - * Copyright 2007-2016 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * Copyright © 2007-2018 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 @@ -35,7 +35,9 @@ static char *tls_keypath = NULL; /* Server cert keychain path */ static _cups_mutex_t tls_mutex = _CUPS_MUTEX_INITIALIZER; /* Mutex for keychain/certs */ -static int tls_options = -1;/* Options for TLS connections */ +static int tls_options = -1,/* Options for TLS connections */ + tls_min_version = _HTTP_TLS_1_0, + tls_max_version = _HTTP_TLS_MAX; /* @@ -397,7 +399,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; @@ -646,7 +648,6 @@ httpCredentialsString( char name[256]; /* Common name associated with cert */ size_t namelen; /* Length of name */ time_t expiration; /* Expiration date of cert */ - _cups_md5_state_t md5_state; /* MD5 state */ unsigned char md5_digest[16]; /* MD5 result */ namelen = sizeof(name) - 1; @@ -657,9 +658,7 @@ httpCredentialsString( expiration = gnutls_x509_crt_get_expiration_time(cert); - _cupsMD5Init(&md5_state); - _cupsMD5Append(&md5_state, first->data, (int)first->datalen); - _cupsMD5Finish(&md5_state, md5_digest); + cupsHashData("md5", first->data, first->datalen, md5_digest, sizeof(md5_digest)); snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", name, httpGetDateString(expiration), md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]); @@ -1094,7 +1093,7 @@ http_gnutls_read( http = (http_t *)ptr; - if (!http->blocking) + if (!http->blocking || http->timeout_value > 0.0) { /* * Make sure we have data before we read... @@ -1224,9 +1223,16 @@ _httpTLSSetCredentials(http_t *http) /* I - Connection to server */ */ void -_httpTLSSetOptions(int options) /* I - Options */ +_httpTLSSetOptions(int options, /* I - Options */ + int min_version, /* I - Minimum TLS version */ + int max_version) /* I - Maximum TLS version */ { - tls_options = options; + if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0) + { + tls_options = options; + tls_min_version = min_version; + tls_max_version = max_version; + } } @@ -1242,8 +1248,21 @@ _httpTLSStart(http_t *http) /* I - Connection to server */ int status; /* Status of handshake */ gnutls_certificate_credentials_t *credentials; /* TLS credentials */ - char priority_string[1024]; + char priority_string[2048]; /* Priority string */ + int version; /* Current version */ + double old_timeout; /* Old timeout value */ + http_timeout_cb_t old_cb; /* Old timeout callback */ + void *old_data; /* Old timeout data */ + static const char * const versions[] =/* SSL/TLS versions */ + { + "VERS-SSL3.0", + "VERS-TLS1.0", + "VERS-TLS1.1", + "VERS-TLS1.2", + "VERS-TLS1.3", + "VERS-TLS-ALL" + }; DEBUG_printf(("3_httpTLSStart(http=%p)", http)); @@ -1505,18 +1524,50 @@ _httpTLSStart(http_t *http) /* I - Connection to server */ strlcpy(priority_string, "NORMAL", sizeof(priority_string)); - if (tls_options & _HTTP_TLS_DENY_TLS10) - strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-TLS1.0:-VERS-SSL3.0", sizeof(priority_string)); - else if (tls_options & _HTTP_TLS_ALLOW_SSL3) + if (tls_max_version < _HTTP_TLS_MAX) + { + /* + * Require specific TLS versions... + */ + + strlcat(priority_string, ":-VERS-TLS-ALL", sizeof(priority_string)); + for (version = tls_min_version; version <= tls_max_version; version ++) + { + strlcat(priority_string, ":+", sizeof(priority_string)); + strlcat(priority_string, versions[version], sizeof(priority_string)); + } + } + else if (tls_min_version == _HTTP_TLS_SSL3) + { + /* + * Allow all versions of TLS and SSL/3.0... + */ + + strlcat(priority_string, ":+VERS-TLS-ALL:+VERS-SSL3.0", sizeof(priority_string)); + } + else + { + /* + * Require a minimum version... + */ + strlcat(priority_string, ":+VERS-TLS-ALL", sizeof(priority_string)); + for (version = 0; version < tls_min_version; version ++) + { + strlcat(priority_string, ":-", sizeof(priority_string)); + strlcat(priority_string, versions[version], sizeof(priority_string)); + } + } + + if (tls_options & _HTTP_TLS_ALLOW_RC4) + strlcat(priority_string, ":+ARCFOUR-128", sizeof(priority_string)); else - strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-SSL3.0", sizeof(priority_string)); + strlcat(priority_string, ":!ARCFOUR-128", sizeof(priority_string)); - if (!(tls_options & _HTTP_TLS_ALLOW_RC4)) - strlcat(priority_string, ":-ARCFOUR-128", sizeof(priority_string)); + strlcat(priority_string, ":!ANON-DH", sizeof(priority_string)); - 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, ":!AES-128-CBC:!AES-256-CBC:!CAMELLIA-128-CBC:!CAMELLIA-256-CBC:!3DES-CBC", sizeof(priority_string)); #ifdef HAVE_GNUTLS_PRIORITY_SET_DIRECT gnutls_priority_set_direct(http->tls, priority_string, NULL); @@ -1536,6 +1587,24 @@ _httpTLSStart(http_t *http) /* I - Connection to server */ #endif /* HAVE_GNUTLS_TRANSPORT_SET_PULL_TIMEOUT_FUNCTION */ gnutls_transport_set_push_function(http->tls, http_gnutls_write); + /* + * Enforce a minimum timeout of 10 seconds for the TLS handshake... + */ + + old_timeout = http->timeout_value; + old_cb = http->timeout_cb; + old_data = http->timeout_data; + + if (!old_cb || old_timeout < 10.0) + { + DEBUG_puts("4_httpTLSStart: Setting timeout to 10 seconds."); + httpSetTimeout(http, 10.0, NULL, NULL); + } + + /* + * Do the TLS handshake... + */ + while ((status = gnutls_handshake(http->tls)) != GNUTLS_E_SUCCESS) { DEBUG_printf(("5_httpStartTLS: gnutls_handshake returned %d (%s)", @@ -1553,10 +1622,18 @@ _httpTLSStart(http_t *http) /* I - Connection to server */ free(credentials); http->tls = NULL; + httpSetTimeout(http, old_timeout, old_cb, old_data); + return (-1); } } + /* + * Restore the previous timeout settings... + */ + + httpSetTimeout(http, old_timeout, old_cb, old_data); + http->tls_credentials = credentials; return (0); diff --git a/cups/tls-sspi.c b/cups/tls-sspi.c index 46f6e790..ea3fb007 100644 --- a/cups/tls-sspi.c +++ b/cups/tls-sspi.c @@ -2,7 +2,7 @@ * TLS support for CUPS on Windows using the Security Support Provider * Interface (SSPI). * - * Copyright 2010-2015 by Apple Inc. + * Copyright 2010-2018 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -52,7 +52,9 @@ * Local globals... */ -static int tls_options = -1;/* Options for TLS connections */ +static int tls_options = -1,/* Options for TLS connections */ + tls_min_version = _HTTP_TLS_1_0, + tls_max_version = _HTTP_TLS_MAX; /* @@ -351,7 +353,6 @@ httpCredentialsString( SYSTEMTIME systime; /* System time */ struct tm tm; /* UNIX date/time */ time_t expiration; /* Expiration date of cert */ - _cups_md5_state_t md5_state; /* MD5 state */ unsigned char md5_digest[16]; /* MD5 result */ FileTimeToSystemTime(&(cert->pCertInfo->NotAfter), &systime); @@ -378,9 +379,7 @@ httpCredentialsString( else strlcpy(cert_name, "unknown", sizeof(cert_name)); - _cupsMD5Init(&md5_state); - _cupsMD5Append(&md5_state, first->data, (int)first->datalen); - _cupsMD5Finish(&md5_state, md5_digest); + cupsHashData("md5", first->data, first->datalen, md5_digest, sizeof(md5_digest)); snprintf(buffer, bufsize, "%s / %s / %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", cert_name, httpGetDateString(expiration), md5_digest[0], md5_digest[1], md5_digest[2], md5_digest[3], md5_digest[4], md5_digest[5], md5_digest[6], md5_digest[7], md5_digest[8], md5_digest[9], md5_digest[10], md5_digest[11], md5_digest[12], md5_digest[13], md5_digest[14], md5_digest[15]); @@ -911,9 +910,16 @@ _httpTLSRead(http_t *http, /* I - HTTP connection */ */ void -_httpTLSSetOptions(int options) /* I - Options */ +_httpTLSSetOptions(int options, /* I - Options */ + int min_version, /* I - Minimum TLS version */ + int max_version) /* I - Maximum TLS version */ { - tls_options = options; + if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0) + { + tls_options = options; + tls_min_version = min_version; + tls_max_version = max_version; + } } @@ -1761,41 +1767,45 @@ http_sspi_find_credentials( #ifdef SP_PROT_TLS1_2_SERVER if (http->mode == _HTTP_MODE_SERVER) { - if (tls_options & _HTTP_TLS_DENY_TLS10) - SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER; - else if (tls_options & _HTTP_TLS_ALLOW_SSL3) + if (tls_min_version == _HTTP_TLS_SSL3) SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER | SP_PROT_SSL3_SERVER; - else + else if (tls_min_version == _HTTP_TLS_1_0) SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_0_SERVER; + else if (tls_min_version == _HTTP_TLS_1_1) + SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER | SP_PROT_TLS1_1_SERVER; + else + SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_SERVER; } else { - if (tls_options & _HTTP_TLS_DENY_TLS10) - SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT; - else if (tls_options & _HTTP_TLS_ALLOW_SSL3) + if (tls_min_version == _HTTP_TLS_SSL3) SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT | SP_PROT_SSL3_CLIENT; - else + else if (tls_min_version == _HTTP_TLS_1_0) SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_0_CLIENT; + else if (tls_min_version == _HTTP_TLS_1_1) + SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT | SP_PROT_TLS1_1_CLIENT; + else + SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT; } #else if (http->mode == _HTTP_MODE_SERVER) { - if (tls_options & _HTTP_TLS_ALLOW_SSL3) + if (tls_min_version == _HTTP_TLS_SSL3) SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER | SP_PROT_SSL3_SERVER; else SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_SERVER; } else { - if (tls_options & _HTTP_TLS_ALLOW_SSL3) + if (tls_min_version == _HTTP_TLS_SSL3) SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT | SP_PROT_SSL3_CLIENT; else SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT; } #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. @@ -23,20 +23,20 @@ #include "cups-private.h" #include <fcntl.h> #include <math.h> -#ifdef WIN32 +#ifdef _WIN32 # include <tchar.h> #else # include <signal.h> # include <sys/time.h> # include <sys/resource.h> -#endif /* WIN32 */ +#endif /* _WIN32 */ #ifdef HAVE_POLL # include <poll.h> #endif /* HAVE_POLL */ /* - * Local functions... + * Include platform-specific TLS code... */ #ifdef HAVE_SSL diff --git a/cups/tlscheck.c b/cups/tlscheck.c index 32cbcca1..d16bf1e4 100644 --- a/cups/tlscheck.c +++ b/cups/tlscheck.c @@ -1,7 +1,7 @@ /* * TLS check 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 @@ -54,6 +54,8 @@ main(int argc, /* I - Number of command-line arguments */ int af = AF_UNSPEC, /* Address family */ tls_options = _HTTP_TLS_NONE, /* TLS options */ + tls_min_version = _HTTP_TLS_1_0, + tls_max_version = _HTTP_TLS_MAX, verbose = 0; /* Verbosity */ ipp_t *request, /* IPP Get-Printer-Attributes request */ *response; /* IPP Get-Printer-Attributes response */ @@ -82,9 +84,33 @@ main(int argc, /* I - Number of command-line arguments */ { tls_options |= _HTTP_TLS_ALLOW_DH; } + else if (!strcmp(argv[i], "--no-cbc")) + { + tls_options |= _HTTP_TLS_DENY_CBC; + } else if (!strcmp(argv[i], "--no-tls10")) { - tls_options |= _HTTP_TLS_DENY_TLS10; + tls_min_version = _HTTP_TLS_1_1; + } + else if (!strcmp(argv[i], "--tls10")) + { + tls_min_version = _HTTP_TLS_1_0; + tls_max_version = _HTTP_TLS_1_0; + } + else if (!strcmp(argv[i], "--tls11")) + { + tls_min_version = _HTTP_TLS_1_1; + tls_max_version = _HTTP_TLS_1_1; + } + else if (!strcmp(argv[i], "--tls12")) + { + tls_min_version = _HTTP_TLS_1_2; + tls_max_version = _HTTP_TLS_1_2; + } + else if (!strcmp(argv[i], "--tls13")) + { + tls_min_version = _HTTP_TLS_1_3; + tls_max_version = _HTTP_TLS_1_3; } else if (!strcmp(argv[i], "--rc4")) { @@ -140,7 +166,7 @@ main(int argc, /* I - Number of command-line arguments */ if (!port) port = 631; - _httpTLSSetOptions(tls_options); + _httpTLSSetOptions(tls_options, tls_min_version, tls_max_version); http = httpConnect2(server, port, NULL, af, HTTP_ENCRYPTION_ALWAYS, 1, 30000, NULL); if (!http) @@ -729,8 +755,13 @@ usage(void) puts(""); puts("Options:"); puts(" --dh Allow DH/DHE key exchange"); + puts(" --no-cbc Disable CBC cipher suites"); puts(" --no-tls10 Disable TLS/1.0"); puts(" --rc4 Allow RC4 encryption"); + puts(" --tls10 Only use TLS/1.0"); + puts(" --tls11 Only use TLS/1.1"); + puts(" --tls12 Only use TLS/1.2"); + puts(" --tls13 Only use TLS/1.3"); puts(" --verbose Be verbose"); puts(" -4 Connect using IPv4 addresses only"); puts(" -6 Connect using IPv6 addresses only"); diff --git a/cups/usersys.c b/cups/usersys.c index 333d21e0..781f27bb 100644 --- a/cups/usersys.c +++ b/cups/usersys.c @@ -1,7 +1,7 @@ /* * 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 @@ -20,13 +20,13 @@ #include "cups-private.h" #include <stdlib.h> #include <sys/stat.h> -#ifdef WIN32 +#ifdef _WIN32 # include <windows.h> #else # include <pwd.h> # include <termios.h> # include <sys/utsname.h> -#endif /* WIN32 */ +#endif /* _WIN32 */ /* @@ -54,7 +54,9 @@ typedef struct _cups_client_conf_s /**** client.conf config data ****/ { #ifdef HAVE_SSL - int ssl_options; /* SSLOptions values */ + int ssl_options, /* SSLOptions values */ + ssl_min_version,/* Minimum SSL/TLS version */ + ssl_max_version;/* Maximum SSL/TLS version */ #endif /* HAVE_SSL */ int trust_first, /* Trust on first use? */ any_root, /* Allow any (e.g., self-signed) root */ @@ -132,6 +134,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 +149,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 +157,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 +301,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 @@ -484,12 +490,12 @@ cupsSetUserAgent(const char *user_agent)/* I - User-Agent string or @code NULL@ { _cups_globals_t *cg = _cupsGlobals(); /* Thread globals */ -#ifdef WIN32 +#ifdef _WIN32 SYSTEM_INFO sysinfo; /* System information */ OSVERSIONINFO version; /* OS version info */ #else struct utsname name; /* uname info */ -#endif /* WIN32 */ +#endif /* _WIN32 */ if (user_agent) @@ -498,7 +504,7 @@ cupsSetUserAgent(const char *user_agent)/* I - User-Agent string or @code NULL@ return; } -#ifdef WIN32 +#ifdef _WIN32 version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&version); GetNativeSystemInfo(&sysinfo); @@ -522,7 +528,7 @@ cupsSetUserAgent(const char *user_agent)/* I - User-Agent string or @code NULL@ snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (%s %s; %s) IPP/2.0", name.sysname, name.release, name.machine); -#endif /* WIN32 */ +#endif /* _WIN32 */ } @@ -574,7 +580,7 @@ cupsUserAgent(void) const char * /* O - Password or @code NULL@ if none */ _cupsGetPassword(const char *prompt) /* I - Prompt string */ { -#ifdef WIN32 +#ifdef _WIN32 HANDLE tty; /* Console handle */ DWORD mode; /* Console mode */ char passch, /* Current key press */ @@ -840,7 +846,7 @@ _cupsGetPassword(const char *prompt) /* I - Prompt string */ memset(cg->password, 0, sizeof(cg->password)); return (NULL); } -#endif /* WIN32 */ +#endif /* _WIN32 */ } @@ -899,7 +905,7 @@ _cupsSetDefaults(void) # ifdef HAVE_GETEUID if ((geteuid() == getuid() || !getuid()) && getegid() == getgid() && (home = getenv("HOME")) != NULL) -# elif !defined(WIN32) +# elif !defined(_WIN32) if (getuid() && (home = getenv("HOME")) != NULL) # else if ((home = getenv("HOME")) != NULL) @@ -953,7 +959,7 @@ _cupsSetDefaults(void) cg->validate_certs = cc.validate_certs; #ifdef HAVE_SSL - _httpTLSSetOptions(cc.ssl_options); + _httpTLSSetOptions(cc.ssl_options | _HTTP_TLS_SET_DEFAULT, cc.ssl_min_version, cc.ssl_max_version); #endif /* HAVE_SSL */ } @@ -1095,7 +1101,7 @@ cups_finalize_client_conf( if (!cc->user[0]) { -#ifdef WIN32 +#ifdef _WIN32 /* * Get the current user name from the OS... */ @@ -1131,7 +1137,7 @@ cups_finalize_client_conf( if (pw) strlcpy(cc->user, pw->pw_name, sizeof(cc->user)); else -#endif /* WIN32 */ +#endif /* _WIN32 */ { /* * Use the default "unknown" user name... @@ -1160,18 +1166,22 @@ cups_init_client_conf( memset(cc, 0, sizeof(_cups_client_conf_t)); - cc->encryption = (http_encryption_t)-1; - cc->trust_first = -1; - cc->any_root = -1; - cc->expired_certs = -1; - cc->validate_certs = -1; +#ifdef HAVE_SSL + cc->ssl_min_version = _HTTP_TLS_1_0; + cc->ssl_max_version = _HTTP_TLS_MAX; +#endif /* HAVE_SSL */ + cc->encryption = (http_encryption_t)-1; + cc->trust_first = -1; + cc->any_root = -1; + cc->expired_certs = -1; + cc->validate_certs = -1; /* * Load settings from the org.cups.PrintingPrefs plist (which trump * everything...) */ -#ifdef __APPLE__ +#if defined(__APPLE__) && defined(HAVE_SSL) char sval[1024]; /* String value */ int bval; /* Boolean value */ @@ -1192,7 +1202,7 @@ cups_init_client_conf( if (cups_apple_get_boolean(kValidateCertsKey, &bval)) cc->validate_certs = bval; -#endif /* __APPLE__ */ +#endif /* __APPLE__ && HAVE_SSL */ } @@ -1332,7 +1342,9 @@ cups_set_ssl_options( * SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyTLS1.0] [None] */ - int options = _HTTP_TLS_NONE; /* SSL/TLS options */ + int options = _HTTP_TLS_NONE, /* SSL/TLS options */ + min_version = _HTTP_TLS_1_0, /* Minimum SSL/TLS version */ + max_version = _HTTP_TLS_MAX; /* Maximum SSL/TLS version */ char temp[256], /* Copy of value */ *start, /* Start of option */ *end; /* End of option */ @@ -1360,18 +1372,38 @@ cups_set_ssl_options( if (!_cups_strcasecmp(start, "AllowRC4")) options |= _HTTP_TLS_ALLOW_RC4; else if (!_cups_strcasecmp(start, "AllowSSL3")) - options |= _HTTP_TLS_ALLOW_SSL3; + min_version = _HTTP_TLS_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; + min_version = _HTTP_TLS_1_1; + else if (!_cups_strcasecmp(start, "MaxTLS1.0")) + max_version = _HTTP_TLS_1_0; + else if (!_cups_strcasecmp(start, "MaxTLS1.1")) + max_version = _HTTP_TLS_1_1; + else if (!_cups_strcasecmp(start, "MaxTLS1.2")) + max_version = _HTTP_TLS_1_2; + else if (!_cups_strcasecmp(start, "MaxTLS1.3")) + max_version = _HTTP_TLS_1_3; + else if (!_cups_strcasecmp(start, "MinTLS1.0")) + min_version = _HTTP_TLS_1_0; + else if (!_cups_strcasecmp(start, "MinTLS1.1")) + min_version = _HTTP_TLS_1_1; + else if (!_cups_strcasecmp(start, "MinTLS1.2")) + min_version = _HTTP_TLS_1_2; + else if (!_cups_strcasecmp(start, "MinTLS1.3")) + min_version = _HTTP_TLS_1_3; else if (!_cups_strcasecmp(start, "None")) options = _HTTP_TLS_NONE; } - cc->ssl_options = options; + cc->ssl_options = options; + cc->ssl_max_version = max_version; + cc->ssl_min_version = min_version; - DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x", (void *)cc, value, options)); + DEBUG_printf(("4cups_set_ssl_options(cc=%p, value=\"%s\") options=%x, min_version=%d, max_version=%d", (void *)cc, value, options, min_version, max_version)); } #endif /* HAVE_SSL */ diff --git a/cups/util.c b/cups/util.c index 5db2fc6c..ef1709c5 100644 --- a/cups/util.c +++ b/cups/util.c @@ -1,8 +1,8 @@ /* * Printing utilities for CUPS. * - * Copyright 2007-2015 by Apple Inc. - * Copyright 1997-2006 by Easy Software Products. + * Copyright © 2007-2018 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 @@ -20,11 +20,11 @@ #include "cups-private.h" #include <fcntl.h> #include <sys/stat.h> -#if defined(WIN32) || defined(__EMX__) +#if defined(_WIN32) || defined(__EMX__) # include <io.h> #else # include <unistd.h> -#endif /* WIN32 || __EMX__ */ +#endif /* _WIN32 || __EMX__ */ /* @@ -35,6 +35,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 +60,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 +148,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 +159,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_dest_t *dest; /* Destination */ + 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 +178,42 @@ cupsCreateJob( } /* - * Build a Create-Job request... + * Lookup the destination... */ - if ((request = ippNewRequest(IPP_OP_CREATE_JOB)) == NULL) + if ((dest = cupsGetNamedDest(http, name, NULL)) == NULL) { - _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, dest)) == NULL) + { + DEBUG_puts("1cupsCreateJob: Query failed."); + cupsFreeDests(1, dest); + return (0); + } - if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL) - job_id = attr->values[0].integer; + status = cupsCreateDestJob(http, dest, info, &job_id, title, num_options, options); + DEBUG_printf(("1cupsCreateJob: cupsCreateDestJob returned %04x (%s)", status, ippErrorString(status))); - ippDelete(response); + cupsFreeDestInfo(info); + cupsFreeDests(1, dest); /* - * Return it... + * Return the job... */ - return (job_id); + if (status >= IPP_STATUS_REDIRECTION_OTHER_SITE) + return (0); + else + return (job_id); } @@ -226,7 +222,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 +273,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 +295,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 +320,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 +386,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 +683,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 +698,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 +720,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 +742,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 +770,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 +900,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 +955,4 @@ cupsStartDocument( return (status); } + diff --git a/cups/versioning.h b/cups/versioning.h index 2e92e6ba..620396f7 100644 --- a/cups/versioning.h +++ b/cups/versioning.h @@ -1,7 +1,7 @@ /* * API versioning definitions for CUPS. * - * Copyright 2007-2016 by Apple Inc. + * Copyright © 2007-2018 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -16,79 +16,41 @@ # define _CUPS_VERSIONING_H_ /* - * 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. + * This header defines several macros that add compiler-specific attributes for + * functions: * - * 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 - * provided by the compiler. + * - _CUPS_API_major_minor[_patch]: Specifies when an API became available by + * CUPS version. + * - _CUPS_DEPRECATED: Function is deprecated with no replacement. + * - _CUPS_DEPRECATED_MSG("message"): Function is deprecated and has a + * replacement. + * - _CUPS_FORMAT(format-index, additional-args-index): Function has a + * printf-style format argument followed by zero or more additional + * arguments. Indices start at 1. + * - _CUPS_INTERNAL: Function is internal with no replacement API. + * - _CUPS_INTERNAL_MSG("msg"): Function is internal - use specified API + * instead. + * - _CUPS_NONNULL((arg list)): Specifies the comma-separated argument indices + * are assumed non-NULL. Indices start at 1. + * - _CUPS_NORETURN: Specifies the function does not return. + * - _CUPS_PRIVATE: Specifies the function is private to CUPS. + * - _CUPS_PUBLIC: Specifies the function is public API. */ -# if defined(__APPLE__) && !defined(_CUPS_SOURCE) && !TARGET_OS_IOS -# include <AvailabilityMacros.h> -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER */ -# ifndef AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER -# define AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER __attribute__((unavailable)) -# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER */ -# 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 */ -# 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 -# define _CUPS_API_1_2 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER -# define _CUPS_API_1_3 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER -# define _CUPS_API_1_4 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER -# define _CUPS_API_1_5 AVAILABLE_MAC_OS_X_VERSION_10_7_AND_LATER -# define _CUPS_API_1_6 AVAILABLE_MAC_OS_X_VERSION_10_8_AND_LATER -# 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 -# else -# define _CUPS_API_1_1_19 -# define _CUPS_API_1_1_20 -# define _CUPS_API_1_1_21 -# define _CUPS_API_1_2 -# define _CUPS_API_1_3 -# define _CUPS_API_1_4 -# define _CUPS_API_1_5 -# define _CUPS_API_1_6 -# define _CUPS_API_1_7 -# define _CUPS_API_2_0 -# define _CUPS_API_2_2 -# endif /* __APPLE__ && !_CUPS_SOURCE */ - /* - * With GCC and Clang we can mark old APIs as "deprecated" or "unavailable" with - * messages so you get warnings/errors are compile-time... + * Determine which compiler is being used and what annotation features are + * available... */ +# ifdef __APPLE__ +# include <os/availability.h> +# endif /* __APPLE__ */ + # ifdef __has_extension /* Clang */ # define _CUPS_HAS_DEPRECATED +# define _CUPS_HAS_FORMAT +# define _CUPS_HAS_NORETURN +# define _CUPS_HAS_VISIBILITY # if __has_extension(attribute_deprecated_with_message) # define _CUPS_HAS_DEPRECATED_WITH_MESSAGE # endif @@ -98,6 +60,9 @@ # elif defined(__GNUC__) /* GCC and compatible */ # if __GNUC__ >= 3 /* GCC 3.0 or higher */ # define _CUPS_HAS_DEPRECATED +# define _CUPS_HAS_FORMAT +# define _CUPS_HAS_NORETURN +# define _CUPS_HAS_VISIBILITY # endif /* __GNUC__ >= 3 */ # if __GNUC__ >= 5 /* GCC 5.x */ # define _CUPS_HAS_DEPRECATED_WITH_MESSAGE @@ -105,61 +70,197 @@ /* GCC 4.5 or higher */ # define _CUPS_HAS_DEPRECATED_WITH_MESSAGE # endif /* __GNUC__ >= 5 */ +# elif defined(_WIN32) +# define __attribute__(...) # endif /* __has_extension */ + +/* + * Define _CUPS_INTERNAL, _CUPS_PRIVATE, and _CUPS_PUBLIC visibilty macros for + * internal/private/public functions... + */ + +# ifdef _CUPS_HAS_VISIBILITY +# define _CUPS_INTERNAL __attribute__ ((visibility("hidden"))) +# define _CUPS_PRIVATE __attribute__ ((visibility("default"))) +# define _CUPS_PUBLIC __attribute__ ((visibility("default"))) +# else +# define _CUPS_INTERNAL +# define _CUPS_PRIVATE +# define _CUPS_PUBLIC +# endif /* _CUPS_HAS_VISIBILITY */ + + +/* + * Define _CUPS_API_major_minor[_patch] availability macros for CUPS. + * + * Note: Using any of the _CUPS_API macros automatically adds _CUPS_PUBLIC. + */ + +# if defined(__APPLE__) && !defined(_CUPS_SOURCE) && !TARGET_OS_IOS +/* + * On Apple operating systems, the _CUPS_API_* constants are defined using the + * API_ macros in <os/availability.h>. + * + * On iOS, we don't actually have libcups available directly, but the supplied + * libcups_static target in the Xcode project supports building on iOS 11.0 and + * later. + */ +# define _CUPS_API_1_1_19 API_AVAILABLE(macos(10.3), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_1_20 API_AVAILABLE(macos(10.4), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_1_21 API_AVAILABLE(macos(10.4), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_2 API_AVAILABLE(macos(10.5), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_3 API_AVAILABLE(macos(10.5), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_4 API_AVAILABLE(macos(10.6), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_5 API_AVAILABLE(macos(10.7), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_6 API_AVAILABLE(macos(10.8), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_1_7 API_AVAILABLE(macos(10.9), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_2_0 API_AVAILABLE(macos(10.10), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_2_2 API_AVAILABLE(macos(10.12), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_2_2_4 API_AVAILABLE(macos(10.13), ios(11.0)) _CUPS_PUBLIC +# define _CUPS_API_2_2_7 API_AVAILABLE(macos(10.14), ios(11.0)) _CUPS_PUBLIC +# else +# define _CUPS_API_1_1_19 _CUPS_PUBLIC +# define _CUPS_API_1_1_20 _CUPS_PUBLIC +# define _CUPS_API_1_1_21 _CUPS_PUBLIC +# define _CUPS_API_1_2 _CUPS_PUBLIC +# define _CUPS_API_1_3 _CUPS_PUBLIC +# define _CUPS_API_1_4 _CUPS_PUBLIC +# define _CUPS_API_1_5 _CUPS_PUBLIC +# define _CUPS_API_1_6 _CUPS_PUBLIC +# define _CUPS_API_1_7 _CUPS_PUBLIC +# define _CUPS_API_2_0 _CUPS_PUBLIC +# define _CUPS_API_2_2 _CUPS_PUBLIC +# define _CUPS_API_2_2_4 _CUPS_PUBLIC +# define _CUPS_API_2_2_7 _CUPS_PUBLIC +# endif /* __APPLE__ && !_CUPS_SOURCE */ + + +/* + * Define _CUPS_DEPRECATED and _CUPS_INTERNAL macros to mark old APIs as + * "deprecated" or "unavailable" with messages so you get warnings/errors are + * compile-time... + * + * Note: Using any of the _CUPS_DEPRECATED macros automatically adds + * _CUPS_PUBLIC. + */ + # if !defined(_CUPS_HAS_DEPRECATED) || (defined(_CUPS_SOURCE) && !defined(_CUPS_NO_DEPRECATED)) /* * Don't mark functions deprecated if the compiler doesn't support it * or we are building CUPS source that doesn't care. */ -# define _CUPS_DEPRECATED -# define _CUPS_DEPRECATED_MSG(m) -# define _CUPS_DEPRECATED_1_6_MSG(m) -# define _CUPS_DEPRECATED_1_7_MSG(m) -# define _CUPS_INTERNAL_MSG(m) +# define _CUPS_DEPRECATED _CUPS_PUBLIC +# define _CUPS_DEPRECATED_MSG(m) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_2_MSG(m) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_6_MSG(m) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_7_MSG(m) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_2_2_MSG(m) _CUPS_PUBLIC +# elif defined(__APPLE__) && defined(_CUPS_NO_DEPRECATED) + /* + * Compiler supports the unavailable attribute, so use it when the code + * wants to exclude the use of deprecated API. + */ +# define _CUPS_DEPRECATED __attribute__ ((unavailable)) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((unavailable(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_2_MSG(m) API_DEPRECATED(m, macos(10.2,10.5)) API_UNAVAILABLE(ios) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_6_MSG(m) API_DEPRECATED(m, macos(10.2,10.8)) API_UNAVAILABLE(ios) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_7_MSG(m) API_DEPRECATED(m, macos(10.2,10.9)) API_UNAVAILABLE(ios) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_2_2_MSG(m) API_DEPRECATED(m, macos(10.2,10.12)) API_UNAVAILABLE(ios) _CUPS_PUBLIC + +# elif defined(__APPLE__) + /* + * Just mark things as deprecated... + */ +# define _CUPS_DEPRECATED __attribute__ ((deprecated)) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((deprecated(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_2_MSG(m) API_DEPRECATED(m, macos(10.2,10.5)) API_UNAVAILABLE(ios) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_6_MSG(m) API_DEPRECATED(m, macos(10.2,10.8)) API_UNAVAILABLE(ios) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_7_MSG(m) API_DEPRECATED(m, macos(10.2,10.9)) API_UNAVAILABLE(ios) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_2_2_MSG(m) API_DEPRECATED(m, macos(10.2,10.12)) API_UNAVAILABLE(ios) _CUPS_PUBLIC + # elif defined(_CUPS_HAS_UNAVAILABLE_WITH_MESSAGE) && defined(_CUPS_NO_DEPRECATED) /* * Compiler supports the unavailable attribute, so use it when the code * wants to exclude the use of deprecated API. */ -# define _CUPS_DEPRECATED __attribute__ ((unavailable)) -# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((unavailable(m))) -# define _CUPS_DEPRECATED_1_6_MSG(m) __attribute__ ((unavailable(m))) -# define _CUPS_DEPRECATED_1_7_MSG(m) __attribute__ ((unavailable(m))) -# define _CUPS_INTERNAL_MSG(m) __attribute__ ((unavailable(m))) +# define _CUPS_DEPRECATED __attribute__ ((unavailable)) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((unavailable(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_2_MSG(m) __attribute__ ((unavailable(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_6_MSG(m) __attribute__ ((unavailable(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_7_MSG(m) __attribute__ ((unavailable(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_2_2_MSG(m) __attribute__ ((unavailable(m))) _CUPS_PUBLIC # else /* * Compiler supports the deprecated attribute, so use it. */ -# define _CUPS_DEPRECATED __attribute__ ((deprecated)) +# define _CUPS_DEPRECATED __attribute__ ((deprecated)) _CUPS_PUBLIC # ifdef _CUPS_HAS_DEPRECATED_WITH_MESSAGE -# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((deprecated(m))) +# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((deprecated(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_2_MSG(m) __attribute__ ((deprecated(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_6_MSG(m) __attribute__ ((deprecated(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_7_MSG(m) __attribute__ ((deprecated(m))) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_2_2_MSG(m) __attribute__ ((deprecated(m))) _CUPS_PUBLIC # else -# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((deprecated)) +# define _CUPS_DEPRECATED_MSG(m) __attribute__ ((deprecated)) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_2_MSG(m) __attribute__ ((deprecated)) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_6_MSG(m) __attribute__ ((deprecated)) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_1_7_MSG(m) __attribute__ ((deprecated)) _CUPS_PUBLIC +# define _CUPS_DEPRECATED_2_2_MSG(m) __attribute__ ((deprecated)) _CUPS_PUBLIC # endif /* _CUPS_HAS_DEPRECATED_WITH_MESSAGE */ -# if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8 -# define _CUPS_DEPRECATED_1_6_MSG(m) _CUPS_DEPRECATED_MSG(m) -# else -# define _CUPS_DEPRECATED_1_6_MSG(m) -# endif /* MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_8 */ -# if defined(MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9 -# define _CUPS_DEPRECATED_1_7_MSG(m) _CUPS_DEPRECATED_MSG(m) -# else -# define _CUPS_DEPRECATED_1_7_MSG(m) -# endif /* MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_9 */ -# ifdef _CUPS_SOURCE -# define _CUPS_INTERNAL_MSG(m) -# elif defined(_CUPS_HAS_UNAVAILABLE_WITH_MESSAGE) -# define _CUPS_INTERNAL_MSG(m) __attribute__ ((unavailable(m))) -# elif defined(_CUPS_HAS_DEPRECATED_WITH_MESSAGE) -# define _CUPS_INTERNAL_MSG(m) __attribute__ ((deprecated(m))) -# else -# define _CUPS_INTERNAL_MSG(m) __attribute__ ((deprecated)) -# endif /* _CUPS_SOURCE */ # endif /* !_CUPS_HAS_DEPRECATED || (_CUPS_SOURCE && !_CUPS_NO_DEPRECATED) */ -# ifndef __GNUC__ -# define __attribute__(x) -# endif /* !__GNUC__ */ + +/* + * Define _CUPS_FORMAT macro for printf-style functions... + */ + +# ifdef _CUPS_HAS_FORMAT +# define _CUPS_FORMAT(a,b) __attribute__ ((__format__(__printf__, a,b))) +# else +# define _CUPS_FORMAT(a,b) +# endif /* _CUPS_HAS_FORMAT */ + + +/* + * Define _CUPS_INTERNAL_MSG macro for private APIs that have (historical) + * public visibility. + * + * Note: Using the _CUPS_INTERNAL_MSG macro automatically adds _CUPS_PUBLIC. + */ + +# ifdef _CUPS_SOURCE +# define _CUPS_INTERNAL_MSG(m) _CUPS_PUBLIC +# elif defined(_CUPS_HAS_UNAVAILABLE_WITH_MESSAGE) +# define _CUPS_INTERNAL_MSG(m) __attribute__ ((unavailable(m))) _CUPS_PUBLIC +# elif defined(_CUPS_HAS_DEPRECATED_WITH_MESSAGE) +# define _CUPS_INTERNAL_MSG(m) __attribute__ ((deprecated(m))) _CUPS_PUBLIC +# else +# define _CUPS_INTERNAL_MSG(m) __attribute__ ((deprecated)) _CUPS_PUBLIC +# endif /* _CUPS_SOURCE */ + + +/* + * Define _CUPS_NONNULL macro for functions that don't expect non-null + * arguments... + */ + +# ifdef _CUPS_HAS_NONNULL +# define _CUPS_NONNULL(...) __attribute__ ((nonnull(__VA_ARGS__))) +# else +# define _CUPS_NONNULL(...) +# endif /* _CUPS_HAS_FORMAT */ + + +/* + * Define _CUPS_NORETURN macro for functions that don't return. + */ + +# ifdef _CUPS_HAS_NORETURN +# define _CUPS_NORETURN __attribute__ ((noreturn)) +# else +# define _CUPS_NORETURN +# endif /* _CUPS_HAS_NORETURN */ + #endif /* !_CUPS_VERSIONING_H_ */ |