diff options
62 files changed, 4309 insertions, 2408 deletions
@@ -17,8 +17,8 @@ #ifndef _CUPS_CONFIG_H_ #define _CUPS_CONFIG_H_ -#define CUPS_SVERSION "CUPS v2.2.3" -#define CUPS_MINIMAL "CUPS/2.2.3" +#define CUPS_SVERSION "CUPS v2.2.6" +#define CUPS_MINIMAL "CUPS/2.2.6" #define CUPS_DEFAULT_PRINTOPERATOR_AUTH "@SYSTEM" #define CUPS_DEFAULT_LOG_LEVEL "warn" #define CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS "dnssd" diff --git a/cups/Makefile b/cups/Makefile index 1df7d855..9a220c85 100644 --- a/cups/Makefile +++ b/cups/Makefile @@ -1,7 +1,7 @@ # -# API library Makefile for CUPS. +# Library Makefile for CUPS. # -# Copyright 2007-2016 by Apple Inc. +# Copyright 2007-2017 by Apple Inc. # Copyright 1997-2006 by Easy Software Products, all rights reserved. # # These coded instructions, statements, and computer programs are the @@ -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 \ @@ -344,7 +346,7 @@ libcups.2.dylib: $(LIBOBJS) $(LIBCUPSORDER) libcups.la: $(LIBOBJS) echo Linking $@... - $(CC) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS:.o=.lo) \ + $(LD_CC) $(ARCHFLAGS) $(DSOFLAGS) -o $@ $(LIBOBJS:.o=.lo) \ -rpath $(LIBDIR) -version-info 2:12 $(LIBGSSAPI) $(SSLLIBS) \ $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) @@ -383,7 +385,7 @@ 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) @@ -393,7 +395,7 @@ 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) echo Running array API tests... ./testarray @@ -405,7 +407,7 @@ 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) @@ -415,7 +417,7 @@ 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) @@ -425,7 +427,7 @@ 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) @@ -435,7 +437,7 @@ 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) @@ -445,7 +447,7 @@ 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) @@ -455,19 +457,29 @@ 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) 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) + + +# # 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) echo Running HTTP API tests... ./testhttp @@ -479,7 +491,7 @@ 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) echo Running IPP API tests... ./testipp @@ -491,7 +503,7 @@ 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) echo Running internationalization API tests... ./testi18n @@ -503,10 +515,22 @@ 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) + 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,7 +539,7 @@ 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) echo Running option API tests... ./testoptions @@ -527,7 +551,7 @@ 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) echo Running PPD API tests... ./testppd @@ -539,7 +563,7 @@ 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) echo Running PWG API tests... ./testpwg test.ppd @@ -551,7 +575,7 @@ 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) @@ -561,7 +585,7 @@ 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) @@ -571,56 +595,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 +623,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 +631,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/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/auth.c b/cups/auth.c index 8348a2cc..c051c86b 100644 --- a/cups/auth.c +++ b/cups/auth.c @@ -54,7 +54,7 @@ extern const char *cssmErrorString(int error); # else # define GSS_AUTH_IDENTITY_TYPE_1 1 # define gss_acquire_cred_ex_f __ApplePrivate_gss_acquire_cred_ex_f -typedef struct gss_auth_identity +typedef struct gss_auth_identity /* @private@ */ { uint32_t type; uint32_t flags; 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..8f5c818f 100644 --- a/cups/cups.h +++ b/cups/cups.h @@ -47,10 +47,10 @@ extern "C" { * Constants... */ -# define CUPS_VERSION 2.0203 +# define CUPS_VERSION 2.0206 # define CUPS_VERSION_MAJOR 2 # define CUPS_VERSION_MINOR 2 -# define CUPS_VERSION_PATCH 3 +# define CUPS_VERSION_PATCH 6 # 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,10 @@ extern int cupsSetServerCredentials(const char *path, const char *common_name, /* New in CUPS 2.2/macOS 10.12 */ extern ssize_t cupsHashData(const char *algorithm, const void *data, size_t datalen, unsigned char *hash, size_t hashsize) _CUPS_API_2_2; +/* New in CUPS 2.2.4 */ +extern int cupsAddIntegerOption(const char *name, int value, int num_options, cups_option_t **options) _CUPS_API_2_2_4; +extern int cupsGetIntegerOption(const char *name, int num_options, cups_option_t *options) _CUPS_API_2_2_4; + # ifdef __cplusplus } # endif /* __cplusplus */ diff --git a/cups/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/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..57a8dc95 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 @@ -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) { @@ -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 @@ -338,10 +338,6 @@ cupsDirRead(cups_dir_t *dp) /* I - Directory pointer */ { struct dirent *entry; /* Pointer to entry */ char filename[1024]; /* Full filename */ -# ifdef HAVE_PTHREAD_H - char buffer[sizeof(struct dirent) + 1024]; - /* Directory entry buffer */ -# endif /* HAVE_PTHREAD_H */ DEBUG_printf(("2cupsDirRead(dp=%p)", (void *)dp)); @@ -359,29 +355,8 @@ cupsDirRead(cups_dir_t *dp) /* I - Directory pointer */ for (;;) { -# ifdef HAVE_PTHREAD_H /* - * Read the next entry using the reentrant version of readdir... - */ - - if (readdir_r(dp->dir, (struct dirent *)buffer, &entry)) - { - DEBUG_printf(("3cupsDirRead: readdir_r() failed - %s\n", strerror(errno))); - return (NULL); - } - - if (!entry) - { - DEBUG_puts("3cupsDirRead: readdir_r() returned a NULL pointer!"); - return (NULL); - } - - DEBUG_printf(("4cupsDirRead: readdir_r() returned \"%s\"...", - entry->d_name)); - -# else - /* - * Read the next entry using the original version of readdir... + * Read the next entry... */ if ((entry = readdir(dp->dir)) == NULL) @@ -392,8 +367,6 @@ cupsDirRead(cups_dir_t *dp) /* I - Directory pointer */ DEBUG_printf(("4cupsDirRead: readdir() returned \"%s\"...", entry->d_name)); -# endif /* HAVE_PTHREAD_H */ - /* * Skip "." and ".."... */ diff --git a/cups/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..1f4db798 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-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the diff --git a/cups/file.c b/cups/file.c index a027df40..5d150540 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-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -321,7 +321,6 @@ cupsFileClose(cups_file_t *fp) /* I - CUPS file */ int fd; /* File descriptor */ char mode; /* Open mode */ int status; /* Return status */ - int is_stdio; /* Is a stdio file? */ DEBUG_printf(("cupsFileClose(fp=%p)", (void *)fp)); @@ -410,12 +409,19 @@ cupsFileClose(cups_file_t *fp) /* I - CUPS file */ #endif /* HAVE_LIBZ */ /* + * If this is one of the cupsFileStdin/out/err files, return now and don't + * actually free memory or close (these last the life of the process...) + */ + + if (fp->is_stdio) + return (status); + +/* * Save the file descriptor we used and free memory... */ - fd = fp->fd; - mode = fp->mode; - is_stdio = fp->is_stdio; + fd = fp->fd; + mode = fp->mode; if (fp->printf_buffer) free(fp->printf_buffer); @@ -431,11 +437,8 @@ cupsFileClose(cups_file_t *fp) /* I - CUPS file */ if (httpAddrClose(NULL, fd) < 0) status = -1; } - else if (!is_stdio) - { - if (close(fd) < 0) - status = -1; - } + else if (close(fd) < 0) + status = -1; return (status); } @@ -1384,7 +1387,11 @@ cupsFilePrintf(cups_file_t *fp, /* I - CUPS file */ { memcpy(fp->ptr, fp->printf_buffer, (size_t)bytes); fp->ptr += bytes; - return ((int)bytes); + + if (fp->is_stdio && cupsFileFlush(fp)) + return (-1); + else + return ((int)bytes); } } @@ -1563,7 +1570,11 @@ cupsFilePuts(cups_file_t *fp, /* I - CUPS file */ { memcpy(fp->ptr, s, (size_t)bytes); fp->ptr += bytes; - return ((int)bytes); + + if (fp->is_stdio && cupsFileFlush(fp)) + return (-1); + else + return ((int)bytes); } } @@ -2466,6 +2477,8 @@ cups_fill(cups_file_t *fp) /* I - CUPS file */ * file header... */ + inflateEnd(&fp->stream); + fp->compressed = 0; } else if (status < Z_OK) diff --git a/cups/file.h b/cups/file.h index 177c2e90..42abe208 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-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the diff --git a/cups/http-addr.c b/cups/http-addr.c index 12d13a69..61c86384 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@ */ @@ -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..e5fc940e 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-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -32,7 +32,7 @@ /* * 'httpAddrConnect()' - Connect to any of the addresses in the list. * - * @since CUPS 1.2/macOS 10.5@ + * @since CUPS 1.2/macOS 10.5@ @exclude all@ */ http_addrlist_t * /* O - Connected address or NULL on failure */ @@ -65,7 +65,7 @@ httpAddrConnect2( int flags; /* Socket flags */ #endif /* !WIN32 */ int remaining; /* Remaining timeout */ - int i, /* Looping var */ + int i, j, /* Looping vars */ nfds, /* Number of file descriptors */ fds[100], /* Socket file descriptors */ result; /* Result from select() or poll() */ @@ -323,6 +323,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 +348,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 */ diff --git a/cups/http-private.h b/cups/http-private.h index ec908a66..f71e564b 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-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -172,18 +172,20 @@ 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_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_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_SSL3 2 /* Allow SSL 3.0 */ +# define _HTTP_TLS_ALLOW_DH 4 /* Allow DH/DHE key negotiation */ +# define _HTTP_TLS_DENY_TLS10 16 /* Deny TLS 1.0 */ +# define _HTTP_TLS_DENY_CBC 32 /* Deny CBC cipher suites */ +# define _HTTP_TLS_ONLY_TLS10 64 /* Only use TLS 1.0 */ +# define _HTTP_TLS_SET_DEFAULT 128 /* Setting the default TLS options */ /* diff --git a/cups/http-support.c b/cups/http-support.c index 1ca01b27..76dbb7db 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-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -543,7 +543,7 @@ httpAssembleUUID(const char *server, /* I - Server name */ * This function is deprecated. Use the httpDecode64_2() function instead * which provides buffer length arguments. * - * @deprecated@ + * @deprecated@ @exclude all@ */ char * /* O - Decoded string */ @@ -566,6 +566,10 @@ httpDecode64(char *out, /* I - String to write to */ /* * 'httpDecode64_2()' - Base64-decode a string. * + * The caller must initialize "outlen" to the maximum size of the decoded + * string before calling @code httpDecode64_2@. On return "outlen" contains the + * decoded length of the string. + * * @since CUPS 1.1.21/macOS 10.4@ */ @@ -671,7 +675,7 @@ httpDecode64_2(char *out, /* I - String to write to */ * This function is deprecated. Use the httpEncode64_2() function instead * which provides buffer length arguments. * - * @deprecated@ + * @deprecated@ @exclude all@ */ char * /* O - Encoded string */ @@ -690,7 +694,7 @@ httpEncode64(char *out, /* I - String to write to */ char * /* O - Encoded string */ httpEncode64_2(char *out, /* I - String to write to */ - int outlen, /* I - Size of output string */ + int outlen, /* I - Maximum size of output string */ const char *in, /* I - String to read from */ int inlen) /* I - Size of input string */ { @@ -778,11 +782,11 @@ httpEncode64_2(char *out, /* I - String to write to */ /* * 'httpGetDateString()' - Get a formatted date/time string from a time value. * - * @deprecated@ + * @deprecated@ @exclude all@ */ const char * /* O - Date/time string */ -httpGetDateString(time_t t) /* I - UNIX time */ +httpGetDateString(time_t t) /* I - Time in seconds */ { _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ @@ -798,7 +802,7 @@ httpGetDateString(time_t t) /* I - UNIX time */ */ const char * /* O - Date/time string */ -httpGetDateString2(time_t t, /* I - UNIX time */ +httpGetDateString2(time_t t, /* I - Time in seconds */ char *s, /* I - String buffer */ int slen) /* I - Size of string buffer */ { @@ -819,7 +823,7 @@ httpGetDateString2(time_t t, /* I - UNIX time */ * 'httpGetDateTime()' - Get a time value from a formatted date/time string. */ -time_t /* O - UNIX time */ +time_t /* O - Time in seconds */ httpGetDateTime(const char *s) /* I - Date/time string */ { int i; /* Looping var */ @@ -888,7 +892,7 @@ httpGetDateTime(const char *s) /* I - Date/time string */ * * This function is deprecated; use the httpSeparateURI() function instead. * - * @deprecated@ + * @deprecated@ @exclude all@ */ void @@ -912,7 +916,7 @@ httpSeparate(const char *uri, /* I - Universal Resource Identifier */ * This function is deprecated; use the httpSeparateURI() function instead. * * @since CUPS 1.1.21/macOS 10.4@ - * @deprecated@ + * @deprecated@ @exclude all@ */ void @@ -1419,7 +1423,7 @@ _httpStatus(cups_lang_t *lang, /* I - Language */ * 'httpStatus()' - Return a short string describing a HTTP status code. * * The returned string is localized to the current POSIX locale and is based - * on the status strings defined in RFC 2616. + * on the status strings defined in RFC 7231. */ const char * /* O - Localized status string */ @@ -2310,6 +2314,8 @@ http_resolve_cb( * Note: This function is needed because avahi_simple_poll_iterate is broken * and always uses a timeout of 0 (!) milliseconds. * (Avahi Ticket #364) + * + * @private@ */ static int /* O - Number of file descriptors matching */ diff --git a/cups/http.c b/cups/http.c index 7925513a..61b88c9d 100644 --- a/cups/http.c +++ b/cups/http.c @@ -1,7 +1,7 @@ /* * HTTP routines for CUPS. * - * Copyright 2007-2015 by Apple Inc. + * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by @@ -417,7 +417,7 @@ httpCompareCredentials( * * This function is deprecated - use @link httpConnect2@ instead. * - * @deprecated@ + * @deprecated@ @exclude all@ */ http_t * /* O - New HTTP connection */ @@ -439,7 +439,7 @@ http_t * /* O - New HTTP connection */ httpConnect2( const char *host, /* I - Host to connect to */ int port, /* I - Port number */ - http_addrlist_t *addrlist, /* I - List of addresses or NULL to lookup */ + http_addrlist_t *addrlist, /* I - List of addresses or @code NULL@ to lookup */ int family, /* I - Address family to use or @code AF_UNSPEC@ for any */ http_encryption_t encryption, /* I - Type of encryption to use */ int blocking, /* I - 1 for blocking connection, 0 for non-blocking */ @@ -482,7 +482,7 @@ httpConnect2( * This function is now deprecated. Please use the @link httpConnect2@ function * instead. * - * @deprecated@ + * @deprecated@ @exclude all@ */ http_t * /* O - New HTTP connection */ @@ -609,7 +609,7 @@ httpFieldValue(const char *name) /* I - String name */ /* - * 'httpFlush()' - Flush data from a HTTP connection. + * 'httpFlush()' - Flush data read from a HTTP connection. */ void @@ -679,7 +679,7 @@ httpFlush(http_t *http) /* I - HTTP connection */ /* - * 'httpFlushWrite()' - Flush data in write buffer. + * 'httpFlushWrite()' - Flush data written to a HTTP connection. * * @since CUPS 1.2/macOS 10.5@ */ @@ -751,7 +751,7 @@ httpGet(http_t *http, /* I - HTTP connection */ /* * 'httpGetActivity()' - Get the most recent activity for a connection. * - * The return value is the UNIX time of the last read or write. + * The return value is the time in seconds of the last read or write. * * @since CUPS 2.0/OS 10.10@ */ @@ -766,10 +766,10 @@ httpGetActivity(http_t *http) /* I - HTTP connection */ /* * 'httpGetAuthString()' - Get the current authorization string. * - * The authorization string is set by cupsDoAuthentication() and - * httpSetAuthString(). Use httpGetAuthString() to retrieve the - * string to use with httpSetField() for the HTTP_FIELD_AUTHORIZATION - * value. + * The authorization string is set by @link cupsDoAuthentication@ and + * @link httpSetAuthString@. Use @link httpGetAuthString@ to retrieve the + * string to use with @link httpSetField@ for the + * @code HTTP_FIELD_AUTHORIZATION@ value. * * @since CUPS 1.3/macOS 10.5@ */ @@ -891,7 +891,7 @@ httpGetContentEncoding(http_t *http) /* I - HTTP connection */ * @since CUPS 1.1.19/macOS 10.3@ */ -const char * /* O - Cookie data or NULL */ +const char * /* O - Cookie data or @code NULL@ */ httpGetCookie(http_t *http) /* I - HTTP connection */ { return (http ? http->cookie : NULL); @@ -1006,7 +1006,7 @@ httpGetKeepAlive(http_t *http) /* I - HTTP connection */ * This function is deprecated and will not return lengths larger than * 2^31 - 1; use httpGetLength2() instead. * - * @deprecated@ + * @deprecated@ @exclude all@ */ int /* O - Content length */ @@ -1150,7 +1150,7 @@ httpGetRemaining(http_t *http) /* I - HTTP connection */ * 'httpGets()' - Get a line of text from a HTTP connection. */ -char * /* O - Line or NULL */ +char * /* O - Line or @code NULL@ */ httpGets(char *line, /* I - Line to read into */ int length, /* I - Max length of buffer */ http_t *http) /* I - HTTP connection */ @@ -1346,10 +1346,10 @@ httpGetStatus(http_t *http) /* I - HTTP connection */ /* * 'httpGetSubField()' - Get a sub-field value. * - * @deprecated@ + * @deprecated@ @exclude all@ */ -char * /* O - Value or NULL */ +char * /* O - Value or @code NULL@ */ httpGetSubField(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - Field index */ const char *name, /* I - Name of sub-field */ @@ -1365,7 +1365,7 @@ httpGetSubField(http_t *http, /* I - HTTP connection */ * @since CUPS 1.2/macOS 10.5@ */ -char * /* O - Value or NULL */ +char * /* O - Value or @code NULL@ */ httpGetSubField2(http_t *http, /* I - HTTP connection */ http_field_t field, /* I - Field index */ const char *name, /* I - Name of sub-field */ @@ -1616,7 +1616,7 @@ httpOptions(http_t *http, /* I - HTTP connection */ * * This function copies available data from the given HTTP connection, reading * a buffer as needed. The data is still available for reading using - * @link httpRead@ or @link httpRead2@. + * @link httpRead2@. * * For non-blocking connections the usual timeouts apply. * @@ -1939,7 +1939,7 @@ httpPut(http_t *http, /* I - HTTP connection */ * This function is deprecated. Use the httpRead2() function which can * read more than 2GB of data. * - * @deprecated@ + * @deprecated@ @exclude all@ */ int /* O - Number of bytes read */ @@ -2326,7 +2326,7 @@ httpReadRequest(http_t *http, /* I - HTTP connection */ * This function is deprecated. Please use the @link httpReconnect2@ function * instead. * - * @deprecated@ + * @deprecated@ @exclude all@ */ int /* O - 0 on success, non-zero on failure */ @@ -2467,9 +2467,10 @@ httpReconnect2(http_t *http, /* I - HTTP connection */ * 'httpSetAuthString()' - Set the current authorization string. * * This function just stores a copy of the current authorization string in - * the HTTP connection object. You must still call httpSetField() to set - * HTTP_FIELD_AUTHORIZATION prior to issuing a HTTP request using httpGet(), - * httpHead(), httpOptions(), httpPost, or httpPut(). + * the HTTP connection object. You must still call @link httpSetField@ to set + * @code HTTP_FIELD_AUTHORIZATION@ prior to issuing a HTTP request using + * @link httpGet@, @link httpHead@, @link httpOptions@, @link httpPost@, or + * @link httpPut@. * * @since CUPS 1.3/macOS 10.5@ */ @@ -2820,7 +2821,7 @@ httpSetTimeout( http_t *http, /* I - HTTP connection */ double timeout, /* I - Number of seconds for timeout, must be greater than 0 */ - http_timeout_cb_t cb, /* I - Callback function or NULL */ + http_timeout_cb_t cb, /* I - Callback function or @code NULL@ */ void *user_data) /* I - User data pointer */ { if (!http || timeout <= 0.0) @@ -2864,6 +2865,8 @@ httpShutdown(http_t *http) /* I - HTTP connection */ /* * 'httpTrace()' - Send an TRACE request to the server. + * + * @exclude all@ */ int /* O - Status of call (0 = success) */ @@ -3259,7 +3262,7 @@ httpWait(http_t *http, /* I - HTTP connection */ * This function is deprecated. Use the httpWrite2() function which can * write more than 2GB of data. * - * @deprecated@ + * @deprecated@ @exclude all@ */ int /* O - Number of bytes written */ @@ -3898,7 +3901,7 @@ static http_t * /* O - HTTP connection */ http_create( const char *host, /* I - Hostname */ int port, /* I - Port number */ - http_addrlist_t *addrlist, /* I - Address list or NULL */ + http_addrlist_t *addrlist, /* I - Address list or @code NULL@ */ int family, /* I - Address family or AF_UNSPEC */ http_encryption_t encryption, /* I - Encryption to use */ int blocking, /* I - 1 for blocking mode */ diff --git a/cups/http.h b/cups/http.h index ccbf77ee..c61a79ee 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-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -109,7 +109,7 @@ extern "C" { * Types and structures... */ -typedef enum http_auth_e /**** HTTP authentication types ****/ +typedef enum http_auth_e /**** HTTP authentication types @exclude all@ ****/ { HTTP_AUTH_NONE, /* No authentication in use */ HTTP_AUTH_BASIC, /* Basic authentication in use */ @@ -393,7 +393,7 @@ typedef enum http_uri_coding_e /**** URI en/decode flags ****/ HTTP_URI_CODING_RFC6874 = 16 /* Use RFC 6874 address format */ } http_uri_coding_t; -typedef enum http_version_e /**** HTTP version numbers ****/ +typedef enum http_version_e /**** HTTP version numbers @exclude all@ ****/ { HTTP_VERSION_0_9 = 9, /* HTTP/0.9 */ HTTP_VERSION_1_0 = 100, /* HTTP/1.0 */ @@ -427,6 +427,7 @@ typedef struct http_addrlist_s /**** Socket address list, which is **** used to enumerate all of the **** addresses that are associated **** with a hostname. @since CUPS 1.2/macOS 10.5@ + **** @exclude all@ ****/ { struct http_addrlist_s *next; /* Pointer to next address in list */ @@ -435,7 +436,7 @@ typedef struct http_addrlist_s /**** Socket address list, which is typedef struct _http_s http_t; /**** HTTP connection type ****/ -typedef struct http_credential_s /**** HTTP credential data @since CUPS 1.5/macOS 10.7@ ****/ +typedef struct http_credential_s /**** HTTP credential data @since CUPS 1.5/macOS 10.7@ @exclude all@ ****/ { void *data; /* Pointer to credential data */ size_t datalen; /* Credential length */ diff --git a/cups/ipp-support.c b/cups/ipp-support.c index b49ac0d2..675e5f38 100644 --- a/cups/ipp-support.c +++ b/cups/ipp-support.c @@ -1,7 +1,7 @@ /* * Internet Printing Protocol support functions for CUPS. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -2243,7 +2243,7 @@ ippStateString(ipp_state_t state) /* I - State value */ /* * 'ippTagString()' - Return the tag name corresponding to a tag value. * - * The returned names are defined in RFC 2911 and 3382. + * The returned names are defined in RFC 8011 and the IANA IPP Registry. * * @since CUPS 1.4/macOS 10.6@ */ @@ -2263,7 +2263,7 @@ ippTagString(ipp_tag_t tag) /* I - Tag value */ /* * 'ippTagValue()' - Return the tag value corresponding to a tag name. * - * The tag names are defined in RFC 2911 and 3382. + * The tag names are defined in RFC 8011 and the IANA IPP Registry. * * @since CUPS 1.4/macOS 10.6@ */ @@ -316,7 +316,7 @@ ippAddCollections( /* - * 'ippAddDate()' - Add a date attribute to an IPP message. + * 'ippAddDate()' - Add a dateTime attribute to an IPP message. * * The @code ipp@ parameter refers to an IPP message previously created using * the @link ippNew@, @link ippNewRequest@, or @link ippNewResponse@ functions. @@ -1380,7 +1380,7 @@ ippContainsInteger( * specified string value. * * Returns non-zero when the attribute contains a matching charset, keyword, - * language, mimeMediaType, name, text, URI, or URI scheme value. + * naturalLanguage, mimeMediaType, name, text, uri, or uriScheme value. * * @since CUPS 1.7/macOS 10.9@ */ @@ -1509,6 +1509,16 @@ ippCopyAttribute( dstattr = ippAddSeparator(dst); break; + 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, srcattr->value_tag & ~IPP_TAG_CUPS_CONST, srcattr->name); + break; + case IPP_TAG_INTEGER : case IPP_TAG_ENUM : dstattr = ippAddIntegers(dst, srcattr->group_tag, srcattr->value_tag, @@ -1759,12 +1769,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 +1786,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 +1838,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 +1887,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 +2171,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 +2200,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 +2251,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 +2307,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 +2360,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 +2423,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 +2485,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 +2579,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 +2644,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 +2724,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 +2743,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 +2807,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@ @@ -3706,7 +3727,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 +3769,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 +3810,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 +3818,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 +3827,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 +3875,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 +3902,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 +3987,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 +4105,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 +4185,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 +4293,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@ */ @@ -4334,7 +4355,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 +4393,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 @@ -4715,19 +4736,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 * ------- ----------- @@ -4767,7 +4788,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@ */ @@ -4823,7 +4844,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); } @@ -4831,7 +4852,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); } @@ -4849,7 +4870,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); } @@ -4863,7 +4884,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); } @@ -4877,7 +4898,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); } @@ -4893,7 +4914,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); } @@ -4901,7 +4922,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); } @@ -4909,7 +4930,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); } @@ -4917,7 +4938,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); } @@ -4925,7 +4946,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); } @@ -4933,7 +4954,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); } @@ -4941,7 +4962,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); } @@ -4949,7 +4970,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); } @@ -4957,7 +4978,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); } } @@ -4971,7 +4992,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 == @@ -4986,7 +5007,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 == @@ -5001,7 +5022,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 == @@ -5020,7 +5041,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); @@ -5082,7 +5103,7 @@ ippValidateAttribute( { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad text value \"%s\" - bad UTF-8 " - "sequence (RFC 2911 section 4.1.1)."), attr->name, + "sequence (RFC 8011 section 5.1.2)."), attr->name, attr->values[i].string.text); return (0); } @@ -5091,7 +5112,7 @@ ippValidateAttribute( { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad text value \"%s\" - bad length %d " - "(RFC 2911 section 4.1.1)."), attr->name, + "(RFC 8011 section 5.1.2)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text)); return (0); @@ -5140,7 +5161,7 @@ ippValidateAttribute( { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad name value \"%s\" - bad UTF-8 " - "sequence (RFC 2911 section 4.1.2)."), attr->name, + "sequence (RFC 8011 section 5.1.3)."), attr->name, attr->values[i].string.text); return (0); } @@ -5149,7 +5170,7 @@ ippValidateAttribute( { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad name value \"%s\" - bad length %d " - "(RFC 2911 section 4.1.2)."), attr->name, + "(RFC 8011 section 5.1.3)."), attr->name, attr->values[i].string.text, (int)(ptr - attr->values[i].string.text)); return (0); @@ -5169,7 +5190,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); } @@ -5178,7 +5199,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); @@ -5200,7 +5221,7 @@ ippValidateAttribute( { ipp_set_error(IPP_STATUS_ERROR_BAD_REQUEST, _("\"%s\": Bad URI value \"%s\" - %s " - "(RFC 2911 section 4.1.5)."), attr->name, + "(RFC 8011 section 5.1.6)."), attr->name, attr->values[i].string.text, uri_status_strings[uri_status - HTTP_URI_STATUS_OVERFLOW]); @@ -5211,7 +5232,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)); } @@ -5234,7 +5255,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); } @@ -5243,7 +5264,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); @@ -5263,7 +5284,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); } @@ -5272,7 +5293,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); @@ -5318,7 +5339,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); @@ -5328,7 +5349,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); @@ -5372,7 +5393,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); @@ -5382,7 +5403,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); @@ -5405,8 +5426,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@ */ @@ -6402,6 +6423,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); @@ -6958,6 +6981,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) { /* @@ -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,7 +77,7 @@ extern "C" { * Types and structures... */ -typedef enum ipp_dstate_e /**** Document states ****/ +typedef enum ipp_dstate_e /**** Document states @exclude all@ ****/ { IPP_DOCUMENT_PENDING = 3, /* Document is pending */ IPP_DOCUMENT_PROCESSING = 5, /* Document is processing */ @@ -94,10 +94,10 @@ typedef enum ipp_dstate_e /**** Document states ****/ # endif /* !_CUPS_NO_DEPRECATED */ } ipp_dstate_t; -typedef enum ipp_finishings_e /**** Finishings ****/ +typedef enum ipp_finishings_e /**** Finishings values ****/ { IPP_FINISHINGS_NONE = 3, /* No finishing */ - IPP_FINISHINGS_STAPLE, /* Staple (any location) */ + IPP_FINISHINGS_STAPLE, /* Staple (any location/method) */ IPP_FINISHINGS_PUNCH, /* Punch (any location/count) */ IPP_FINISHINGS_COVER, /* Add cover */ IPP_FINISHINGS_BIND, /* Bind */ @@ -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.c b/cups/language.c index f3a3496b..e6d2d44a 100644 --- a/cups/language.c +++ b/cups/language.c @@ -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/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..925ab805 100644 --- a/cups/ppd-cache.c +++ b/cups/ppd-cache.c @@ -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(); @@ -3581,8 +3601,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,7 +3615,7 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ const char *keyword = ippGetString(attr, i, NULL); /* Keyword for color/bit depth */ - if (!strcmp(keyword, "black_1") || !strcmp(keyword, "bi-level") || !strcmp(keyword, "process-bi-level")) + if (!strcasecmp(keyword, "black_1") || !strcmp(keyword, "bi-level") || !strcmp(keyword, "process-bi-level")) { if (!default_color) cupsFilePrintf(fp, "*OpenUI *ColorModel/%s: PickOne\n" @@ -3606,7 +3626,7 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ 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" @@ -3617,7 +3637,7 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ if (!default_color || !strcmp(default_color, "FastGray")) default_color = "Gray"; } - else if (!strcmp(keyword, "srgb_8") || !strcmp(keyword, "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" @@ -3627,7 +3647,7 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ 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" @@ -3661,7 +3681,36 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ "*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)"))); - if ((attr = ippFindAttribute(response, "pwg-raster-document-sheet-back", IPP_TAG_KEYWORD)) != NULL) + 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; + } + } + } + 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 +3724,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; - } - } - } } /* @@ -3962,42 +3982,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) - { - 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) + 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; @@ -4027,18 +4019,81 @@ _ppdCreateFromIPP(char *buffer, /* I - Filename buffer */ cupsFilePrintf(fp, "*DefaultResolution: %ddpi\n", lowdpi); cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality/%s: PickOne\n" - "*OrderDependency: 10 AnySetup *cupsPrintQuality\n" - "*DefaultcupsPrintQuality: Normal\n", _cupsLangString(lang, _("Print Quality"))); + "*OrderDependency: 10 AnySetup *cupsPrintQuality\n" + "*DefaultcupsPrintQuality: Normal\n", _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/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), lowdpi, lowdpi / 2); 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 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); 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/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("High")), hidpi, hidpi); 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])); + + for (i = 0; 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/%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, resolutions[0], &xres, &yres, NULL, 0); + cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n", _cupsLangString(lang, _("Draft")), xres, yres); + } + pwg_ppdize_resolution(attr, resolutions[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)) + { + pwg_ppdize_resolution(attr, resolutions[count - 1], &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 (is_apple || is_pwg) goto bad_ppd; else 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/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/request.c b/cups/request.c index 39cbe6cc..efbc06eb 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 @@ -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,9 +150,7 @@ 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); @@ -169,9 +166,8 @@ cupsDoIORequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP * Can't send a directory... */ - ippDelete(request); - _cupsSetError(IPP_STATUS_ERROR_NOT_POSSIBLE, strerror(EISDIR), 0); + ippDelete(request); return (NULL); } @@ -186,8 +182,7 @@ cupsDoIORequest(http_t *http, /* I - Connection to server or @code CUPS_HTTP 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... @@ -596,6 +591,7 @@ 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 */ 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 +611,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,6 +680,7 @@ 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); #ifdef HAVE_GSSAPI @@ -996,7 +992,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)) { diff --git a/cups/snmp.c b/cups/snmp.c index fffa2182..7958b93e 100644 --- a/cups/snmp.c +++ b/cups/snmp.c @@ -739,6 +739,10 @@ asn1_debug(const char *prefix, /* I - Prefix string */ _cups_globals_t *cg = _cupsGlobals(); /* Global data */ +#ifdef __clang_analyzer__ /* Suppress bogus clang error */ + memset(string, 0, sizeof(string)); +#endif /* __clang_analyzer__ */ + if (cg->snmp_debug <= 0) return; diff --git a/cups/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/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..c5c20528 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-2017 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -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/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/testipp.c b/cups/testipp.c index 017ee9d6..ea8f9d78 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 @@ -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/thread-private.h b/cups/thread-private.h index ca4ef4cb..79d24386 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 @@ -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..65257aa1 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-2017 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -173,6 +173,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. */ @@ -344,6 +355,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. */ diff --git a/cups/tls-darwin.c b/cups/tls-darwin.c index b6e88b01..92430aca 100644 --- a/cups/tls-darwin.c +++ b/cups/tls-darwin.c @@ -1,7 +1,7 @@ /* * TLS support code for CUPS on macOS. * - * Copyright 2007-2016 by Apple Inc. + * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -21,7 +21,7 @@ #include <spawn.h> -extern char **environ; +extern char **environ; /* @private@ */ /* @@ -1141,7 +1141,8 @@ _httpTLSRead(http_t *http, /* I - HTTP connection */ void _httpTLSSetOptions(int options) /* I - Options */ { - tls_options = options; + if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0) + tls_options = options; } @@ -1227,6 +1228,12 @@ _httpTLSStart(http_t *http) /* I - HTTP connection */ error = SSLSetProtocolVersionMin(http->tls, minProtocol); DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMin(%d), error=%d", minProtocol, (int)error)); + + if (!error && (tls_options & _HTTP_TLS_ONLY_TLS10)) + { + error = SSLSetProtocolVersionMax(http->tls, kTLSProtocol1); + DEBUG_printf(("4_httpTLSStart: SSLSetProtocolVersionMax(kTLSProtocol1), error=%d", (int)error)); + } } # if HAVE_SSLSETENABLEDCIPHERS @@ -1324,7 +1331,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 +1343,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 +1361,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; diff --git a/cups/tls-gnutls.c b/cups/tls-gnutls.c index 7193d794..2dcb7fe3 100644 --- a/cups/tls-gnutls.c +++ b/cups/tls-gnutls.c @@ -1,7 +1,7 @@ /* * TLS support code for CUPS using GNU TLS. * - * Copyright 2007-2016 by Apple Inc. + * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the @@ -397,7 +397,7 @@ httpCredentialsAreValidForName( for (i = 0; i < count; i ++) { rserial_size = sizeof(rserial); - if (!gnutls_x509_crl_get_crt_serial(tls_crl, i, rserial, &rserial_size, NULL) && cserial_size == rserial_size && !memcmp(cserial, rserial, rserial_size)) + if (!gnutls_x509_crl_get_crt_serial(tls_crl, (unsigned)i, rserial, &rserial_size, NULL) && cserial_size == rserial_size && !memcmp(cserial, rserial, rserial_size)) { result = 0; break; @@ -1226,7 +1226,8 @@ _httpTLSSetCredentials(http_t *http) /* I - Connection to server */ void _httpTLSSetOptions(int options) /* I - Options */ { - tls_options = options; + if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0) + tls_options = options; } @@ -1242,7 +1243,7 @@ _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 */ @@ -1508,15 +1509,21 @@ _httpTLSStart(http_t *http) /* I - Connection to server */ 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) - strlcat(priority_string, ":+VERS-TLS-ALL", sizeof(priority_string)); + strlcat(priority_string, ":+VERS-TLS-ALL:+VERS-SSL3.0", sizeof(priority_string)); + else if (tls_options & _HTTP_TLS_ONLY_TLS10) + strlcat(priority_string, ":-VERS-TLS-ALL:-VERS-SSL3.0:+VERS-TLS1.0", sizeof(priority_string)); else strlcat(priority_string, ":+VERS-TLS-ALL:-VERS-SSL3.0", sizeof(priority_string)); - if (!(tls_options & _HTTP_TLS_ALLOW_RC4)) - strlcat(priority_string, ":-ARCFOUR-128", sizeof(priority_string)); + if (tls_options & _HTTP_TLS_ALLOW_RC4) + strlcat(priority_string, ":+ARCFOUR-128", sizeof(priority_string)); + else + 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); diff --git a/cups/tls-sspi.c b/cups/tls-sspi.c index 46f6e790..6eaec4c8 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-2017 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -913,7 +913,8 @@ _httpTLSRead(http_t *http, /* I - HTTP connection */ void _httpTLSSetOptions(int options) /* I - Options */ { - tls_options = options; + if (!(options & _HTTP_TLS_SET_DEFAULT) || tls_options < 0) + tls_options = options; } @@ -1795,7 +1796,7 @@ http_sspi_find_credentials( } #endif /* SP_PROT_TLS1_2_SERVER */ - /* TODO: Support _HTTP_TLS_ALLOW_RC4 and _HTTP_TLS_ALLOW_DH options; right now we'll rely on Windows registry to enable/disable RC4/DH... */ + /* TODO: Support _HTTP_TLS_ALLOW_RC4, _HTTP_TLS_ALLOW_DH, and _HTTP_TLS_DENY_CBC options; right now we'll rely on Windows registry to enable/disable RC4/DH/CBC... */ /* * Create an SSPI credential. diff --git a/cups/tlscheck.c b/cups/tlscheck.c index 32cbcca1..997e7aaf 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 @@ -82,10 +82,18 @@ 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; } + else if (!strcmp(argv[i], "--tls10")) + { + tls_options |= _HTTP_TLS_ONLY_TLS10; + } else if (!strcmp(argv[i], "--rc4")) { tls_options |= _HTTP_TLS_ALLOW_RC4; @@ -729,8 +737,10 @@ 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(" --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..2a004b54 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 @@ -132,6 +132,8 @@ cupsEncryption(void) * thread in a program. Multi-threaded programs that override the setting via * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to * do so in each thread for the same function to be used. + * + * @exclude all@ */ const char * /* O - Password */ @@ -145,7 +147,7 @@ cupsGetPassword(const char *prompt) /* I - Prompt string */ /* - * 'cupsGetPassword2()' - Get a password from the user using the advanced + * 'cupsGetPassword2()' - Get a password from the user using the current * password callback. * * Uses the current password callback function. Returns @code NULL@ if the @@ -153,8 +155,8 @@ cupsGetPassword(const char *prompt) /* I - Prompt string */ * * Note: The current password callback function is tracked separately for each * thread in a program. Multi-threaded programs that override the setting via - * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to - * do so in each thread for the same function to be used. + * the @link cupsSetPasswordCB2@ function need to do so in each thread for the + * same function to be used. * * @since CUPS 1.4/macOS 10.6@ */ @@ -297,6 +299,8 @@ cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */ * Note: The current password callback is tracked separately for each thread * in a program. Multi-threaded programs that override the callback need to do * so in each thread for the same callback to be used. + * + * @exclude all@ */ void @@ -953,7 +957,7 @@ _cupsSetDefaults(void) cg->validate_certs = cc.validate_certs; #ifdef HAVE_SSL - _httpTLSSetOptions(cc.ssl_options); + _httpTLSSetOptions(cc.ssl_options | _HTTP_TLS_SET_DEFAULT); #endif /* HAVE_SSL */ } @@ -1171,7 +1175,7 @@ cups_init_client_conf( * everything...) */ -#ifdef __APPLE__ +#if defined(__APPLE__) && defined(HAVE_SSL) char sval[1024]; /* String value */ int bval; /* Boolean value */ @@ -1192,7 +1196,7 @@ cups_init_client_conf( if (cups_apple_get_boolean(kValidateCertsKey, &bval)) cc->validate_certs = bval; -#endif /* __APPLE__ */ +#endif /* __APPLE__ && HAVE_SSL */ } @@ -1363,6 +1367,8 @@ cups_set_ssl_options( options |= _HTTP_TLS_ALLOW_SSL3; else if (!_cups_strcasecmp(start, "AllowDH")) options |= _HTTP_TLS_ALLOW_DH; + else if (!_cups_strcasecmp(start, "DenyCBC")) + options |= _HTTP_TLS_DENY_CBC; else if (!_cups_strcasecmp(start, "DenyTLS1.0")) options |= _HTTP_TLS_DENY_TLS10; else if (!_cups_strcasecmp(start, "None")) diff --git a/cups/util.c b/cups/util.c index 5db2fc6c..2f5ebdf4 100644 --- a/cups/util.c +++ b/cups/util.c @@ -1,7 +1,7 @@ /* * Printing utilities for CUPS. * - * Copyright 2007-2015 by Apple Inc. + * Copyright 2007-2017 by Apple Inc. * Copyright 1997-2006 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -28,6 +28,19 @@ /* + * Enumeration data and callback... + */ + +typedef struct _cups_createdata_s +{ + const char *name; /* Destination name */ + cups_dest_t *dest; /* Matching destination */ +} _cups_createdata_t; + +static int cups_create_cb(_cups_createdata_t *data, unsigned flags, cups_dest_t *dest); + + +/* * 'cupsCancelJob()' - Cancel a print job on the default server. * * Pass @code CUPS_JOBID_ALL@ to cancel all jobs or @code CUPS_JOBID_CURRENT@ @@ -35,6 +48,8 @@ * * Use the @link cupsLastError@ and @link cupsLastErrorString@ functions to get * the cause of any failure. + * + * @exclude all@ */ int /* O - 1 on success, 0 on failure */ @@ -58,7 +73,7 @@ cupsCancelJob(const char *name, /* I - Name of printer or class */ * Use the @link cupsLastError@ and @link cupsLastErrorString@ functions to get * the cause of any failure. * - * @since CUPS 1.4/macOS 10.6@ + * @since CUPS 1.4/macOS 10.6@ @exclude all@ */ ipp_status_t /* O - IPP status */ @@ -146,7 +161,7 @@ cupsCancelJob2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_ * print, use the @link cupsPrintFile2@ or @link cupsPrintFiles2@ function * instead. * - * @since CUPS 1.4/macOS 10.6@ + * @since CUPS 1.4/macOS 10.6@ @exclude all@ */ int /* O - Job ID or 0 on error */ @@ -157,12 +172,10 @@ cupsCreateJob( int num_options, /* I - Number of options */ cups_option_t *options) /* I - Options */ { - char printer_uri[1024], /* Printer URI */ - resource[1024]; /* Printer resource */ - ipp_t *request, /* Create-Job request */ - *response; /* Create-Job response */ - ipp_attribute_t *attr; /* job-id attribute */ int job_id = 0; /* job-id value */ + ipp_status_t status; /* Create-Job status */ + _cups_createdata_t data; /* Enumeration data */ + cups_dinfo_t *info; /* Destination information */ DEBUG_printf(("cupsCreateJob(http=%p, name=\"%s\", title=\"%s\", num_options=%d, options=%p)", (void *)http, name, title, num_options, (void *)options)); @@ -178,46 +191,47 @@ cupsCreateJob( } /* - * Build a Create-Job request... + * Lookup the destination... */ - if ((request = ippNewRequest(IPP_OP_CREATE_JOB)) == NULL) + data.name = name; + data.dest = NULL; + + cupsEnumDests(0, 1000, NULL, 0, 0, (cups_dest_cb_t)cups_create_cb, &data); + + if (!data.dest) { - _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOMEM), 0); + DEBUG_puts("1cupsCreateJob: Destination not found."); + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(ENOENT), 0); return (0); } - httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), "ipp", - NULL, "localhost", ippPort(), "/printers/%s", name); - snprintf(resource, sizeof(resource), "/printers/%s", name); - - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, printer_uri); - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", - NULL, cupsUser()); - if (title) - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, - title); - cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION); - cupsEncodeOptions2(request, num_options, options, IPP_TAG_JOB); - cupsEncodeOptions2(request, num_options, options, IPP_TAG_SUBSCRIPTION); - /* - * Send the request and get the job-id... + * Query dest information and create the job... */ - response = cupsDoRequest(http, request, resource); + DEBUG_puts("1cupsCreateJob: Querying destination info."); + if ((info = cupsCopyDestInfo(http, data.dest)) == NULL) + { + DEBUG_puts("1cupsCreateJob: Query failed."); + cupsFreeDests(1, data.dest); + return (0); + } - if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL) - job_id = attr->values[0].integer; + status = cupsCreateDestJob(http, data.dest, info, &job_id, title, num_options, options); + DEBUG_printf(("1cupsCreateJob: cupsCreateDestJob returned %04x (%s)", status, ippErrorString(status))); - ippDelete(response); + cupsFreeDestInfo(info); + cupsFreeDests(1, data.dest); /* - * Return it... + * Return the job... */ - return (job_id); + if (status >= IPP_STATUS_REDIRECTION_OTHER_SITE) + return (0); + else + return (job_id); } @@ -226,7 +240,7 @@ cupsCreateJob( * * The document must have been started using @link cupsStartDocument@. * - * @since CUPS 1.4/macOS 10.6@ + * @since CUPS 1.4/macOS 10.6@ @exclude all@ */ ipp_status_t /* O - Status of document submission */ @@ -277,7 +291,7 @@ cupsFreeJobs(int num_jobs, /* I - Number of jobs */ * This function is deprecated and no longer returns a list of printer * classes - use @link cupsGetDests@ instead. * - * @deprecated@ + * @deprecated@ @exclude all@ */ int /* O - Number of classes */ @@ -299,6 +313,8 @@ cupsGetClasses(char ***classes) /* O - Classes */ * Applications should use the @link cupsGetDests@ and @link cupsGetDest@ * functions to get the user-defined default printer, as this function does * not support the lpoptions-defined default printer. + * + * @exclude all@ */ const char * /* O - Default printer or @code NULL@ */ @@ -322,7 +338,7 @@ cupsGetDefault(void) * functions to get the user-defined default printer, as this function does * not support the lpoptions-defined default printer. * - * @since CUPS 1.1.21/macOS 10.4@ + * @since CUPS 1.1.21/macOS 10.4@ @exclude all@ */ const char * /* O - Default printer or @code NULL@ */ @@ -388,6 +404,8 @@ cupsGetDefault2(http_t *http) /* I - Connection to server or @code CUPS_HTTP_DE * of state, while @code CUPS_WHICHJOBS_ACTIVE@ returns jobs that are * pending, processing, or held and @code CUPS_WHICHJOBS_COMPLETED@ returns * jobs that are stopped, canceled, aborted, or completed. + * + * @exclude all@ */ int /* O - Number of jobs */ @@ -683,7 +701,7 @@ cupsGetJobs2(http_t *http, /* I - Connection to server or @code CUPS_HTTP_D * This function is deprecated and no longer returns a list of printers - use * @link cupsGetDests@ instead. * - * @deprecated@ + * @deprecated@ @exclude all@ */ int /* O - Number of printers */ @@ -698,6 +716,8 @@ cupsGetPrinters(char ***printers) /* O - Printers */ /* * 'cupsPrintFile()' - Print a file to a printer or class on the default server. + * + * @exclude all@ */ int /* O - Job ID or 0 on error */ @@ -718,7 +738,7 @@ cupsPrintFile(const char *name, /* I - Destination name */ * 'cupsPrintFile2()' - Print a file to a printer or class on the specified * server. * - * @since CUPS 1.1.21/macOS 10.4@ + * @since CUPS 1.1.21/macOS 10.4@ @exclude all@ */ int /* O - Job ID or 0 on error */ @@ -740,6 +760,8 @@ cupsPrintFile2( /* * 'cupsPrintFiles()' - Print one or more files to a printer or class on the * default server. + * + * @exclude all@ */ int /* O - Job ID or 0 on error */ @@ -766,7 +788,7 @@ cupsPrintFiles( * 'cupsPrintFiles2()' - Print one or more files to a printer or class on the * specified server. * - * @since CUPS 1.1.21/macOS 10.4@ + * @since CUPS 1.1.21/macOS 10.4@ @exclude all@ */ int /* O - Job ID or 0 on error */ @@ -896,7 +918,7 @@ cupsPrintFiles2( * @code CUPS_FORMAT_TEXT@ are provided for the "format" argument, although * any supported MIME type string can be supplied. * - * @since CUPS 1.4/macOS 10.6@ + * @since CUPS 1.4/macOS 10.6@ @exclude all@ */ http_status_t /* O - HTTP status of request */ @@ -951,3 +973,26 @@ cupsStartDocument( return (status); } + + +/* + * 'cups_create_cb()' - Find the destination for printing. + */ + +static int /* O - 0 on match */ +cups_create_cb( + _cups_createdata_t *data, /* I - Data from cupsCreateJob call */ + unsigned flags, /* I - Enumeration flags */ + cups_dest_t *dest) /* I - Destination */ +{ + DEBUG_printf(("2cups_create_cb(data=%p(%s), flags=%08x, dest=%p(%s))", (void *)data, data->name, flags, (void *)dest, dest->name)); + + (void)flags; + + if (dest->instance || strcasecmp(data->name, dest->name)) + return (1); + + cupsCopyDest(dest, 0, &data->dest); + + return (0); +} diff --git a/cups/versioning.h b/cups/versioning.h index 2e92e6ba..5a000c05 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-2017 by Apple Inc. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright @@ -17,11 +17,10 @@ /* * This header defines several constants - _CUPS_DEPRECATED, - * _CUPS_DEPRECATED_MSG, _CUPS_INTERNAL_MSG, _CUPS_API_1_1, _CUPS_API_1_1_19, - * _CUPS_API_1_1_20, _CUPS_API_1_1_21, _CUPS_API_1_2, _CUPS_API_1_3, - * _CUPS_API_1_4, _CUPS_API_1_5, _CUPS_API_1_6, _CUPS_API_1_7, and - * _CUPS_API_2_0 - which add compiler-specific attributes that flag functions - * that are deprecated, added in particular releases, or internal to CUPS. + * _CUPS_DEPRECATED_MSG, _CUPS_INTERNAL_MSG, _CUPS_API_major_minor, and + * _CUPS_API_major_minor_patch - which add compiler-specific attributes that + * flag functions that are deprecated, added in particular releases, or internal + * to CUPS. * * On macOS, the _CUPS_API_* constants are defined based on the values of * the MAC_OS_X_VERSION_MIN_ALLOWED and MAC_OS_X_VERSION_MAX_ALLOWED constants @@ -57,6 +56,9 @@ # ifndef AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER # define AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER __attribute__((unavailable)) # endif /* !AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER */ +# ifndef AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER +# define AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER __attribute__((unavailable)) +# endif /* !AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER */ # define _CUPS_API_1_1_19 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER # define _CUPS_API_1_1_20 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER # define _CUPS_API_1_1_21 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER @@ -68,6 +70,7 @@ # define _CUPS_API_1_7 AVAILABLE_MAC_OS_X_VERSION_10_9_AND_LATER # define _CUPS_API_2_0 AVAILABLE_MAC_OS_X_VERSION_10_10_AND_LATER # define _CUPS_API_2_2 AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER +# define _CUPS_API_2_2_4 AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER # else # define _CUPS_API_1_1_19 # define _CUPS_API_1_1_20 @@ -80,6 +83,7 @@ # define _CUPS_API_1_7 # define _CUPS_API_2_0 # define _CUPS_API_2_2 +# define _CUPS_API_2_2_4 # endif /* __APPLE__ && !_CUPS_SOURCE */ /* diff --git a/filter/Makefile b/filter/Makefile index 7da764d3..02aab14d 100644 --- a/filter/Makefile +++ b/filter/Makefile @@ -1,7 +1,7 @@ # # Filter makefile for CUPS. # -# Copyright 2007-2012 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 @@ -29,6 +29,7 @@ LIBTARGETS = \ libcupsimage.a UNITTARGETS = \ rasterbench \ + testclient \ testraster TARGETS = \ $(LIBTARGETS) \ @@ -38,7 +39,7 @@ IMAGEOBJS = error.o interpret.o raster.o OBJS = $(IMAGEOBJS) \ commandtops.o gziptoany.o common.o pstops.o \ rasterbench.o rastertoepson.o rastertohp.o rastertolabel.o \ - rastertopwg.o testraster.o + rastertopwg.o testclient.o testraster.o # @@ -216,7 +217,7 @@ apihelp: commandtops: commandtops.o ../cups/$(LIBCUPS) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ commandtops.o $(LIBS) + $(LD_CC) $(LDFLAGS) -o $@ commandtops.o $(LIBS) # @@ -225,7 +226,7 @@ commandtops: commandtops.o ../cups/$(LIBCUPS) gziptoany: gziptoany.o ../Makedefs ../cups/$(LIBCUPS) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ gziptoany.o $(LIBZ) $(LIBS) + $(LD_CC) $(LDFLAGS) -o $@ gziptoany.o $(LIBZ) $(LIBS) # @@ -295,7 +296,7 @@ libcupsimage.a: $(IMAGEOBJS) pstops: pstops.o common.o ../cups/$(LIBCUPS) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ pstops.o common.o $(LIBS) + $(LD_CC) $(LDFLAGS) -o $@ pstops.o common.o $(LIBS) # @@ -304,7 +305,7 @@ pstops: pstops.o common.o ../cups/$(LIBCUPS) rastertoepson: rastertoepson.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ rastertoepson.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS) + $(LD_CC) $(LDFLAGS) -o $@ rastertoepson.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS) # @@ -313,7 +314,7 @@ rastertoepson: rastertoepson.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE) rastertohp: rastertohp.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ rastertohp.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS) + $(LD_CC) $(LDFLAGS) -o $@ rastertohp.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS) # @@ -322,7 +323,7 @@ rastertohp: rastertohp.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE) rastertolabel: rastertolabel.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ rastertolabel.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS) + $(LD_CC) $(LDFLAGS) -o $@ rastertolabel.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS) # @@ -331,22 +332,33 @@ rastertolabel: rastertolabel.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE) rastertopwg: rastertopwg.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE) echo Linking $@... - $(CC) $(LDFLAGS) -o $@ rastertopwg.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS) + $(LD_CC) $(LDFLAGS) -o $@ rastertopwg.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS) rastertopwg-static: rastertopwg.o ../cups/$(LIBCUPSSTATIC) libcupsimage.a echo Linking $@... - $(CC) $(LDFLAGS) -o $@ rastertopwg.o libcupsimage.a \ + $(LD_CC) $(LDFLAGS) -o $@ rastertopwg.o libcupsimage.a \ ../cups/$(LIBCUPSSTATIC) $(IMGLIBS) $(DSOLIBS) $(COMMONLIBS) \ $(SSLLIBS) $(DNSSDLIBS) $(LIBGSSAPI) # +# testclient (dependency on static libraries is intentional) +# + +testclient: testclient.o ../cups/$(LIBCUPSSTATIC) libcupsimage.a + echo Linking $@... + $(LD_CC) $(LDFLAGS) -o $@ testclient.o \ + libcupsimage.a ../cups/$(LIBCUPSSTATIC) \ + $(LIBGSSAPI) $(SSLLIBS) $(DNSSDLIBS) $(COMMONLIBS) $(LIBZ) + + +# # testraster # testraster: testraster.o ../cups/$(LIBCUPSSTATIC) libcupsimage.a echo Linking $@... - $(CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testraster.o libcupsimage.a \ + $(LD_CC) $(ARCHFLAGS) $(LDFLAGS) -o $@ testraster.o libcupsimage.a \ ../cups/$(LIBCUPSSTATIC) $(IMGLIBS) $(DSOLIBS) $(COMMONLIBS) \ $(SSLLIBS) $(DNSSDLIBS) $(LIBGSSAPI) echo Running raster API tests... @@ -359,7 +371,7 @@ testraster: testraster.o ../cups/$(LIBCUPSSTATIC) libcupsimage.a rasterbench: rasterbench.o libcupsimage.a echo Linking $@... - $(CC) $(LDFLAGS) -o $@ rasterbench.o libcupsimage.a $(LIBS) + $(LD_CC) $(LDFLAGS) -o $@ rasterbench.o libcupsimage.a $(LIBS) # diff --git a/filter/testclient.c b/filter/testclient.c new file mode 100644 index 00000000..3a9c032c --- /dev/null +++ b/filter/testclient.c @@ -0,0 +1,960 @@ +/* + * Simulated client 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 <stdlib.h> +#include <cups/cups.h> +#include <cups/raster.h> +#include <cups/string-private.h> +#include <cups/thread-private.h> + + +/* + * Local types... + */ + +typedef struct _client_monitor_s +{ + const char *uri, /* Printer URI */ + *hostname, /* Hostname */ + *user, /* Username */ + *resource; /* Resource path */ + int port; /* Port number */ + http_encryption_t encryption; /* Use encryption? */ + ipp_pstate_t printer_state; /* Current printer state */ + char printer_state_reasons[1024]; + /* Current printer-state-reasons */ + int job_id; /* Job ID for submitted job */ + ipp_jstate_t job_state; /* Current job state */ + char job_state_reasons[1024]; + /* Current job-state-reasons */ +} _client_monitor_t; + + +/* + * Local functions... + */ + +static const char *make_raster_file(ipp_t *response, int grayscale, char *tempname, size_t tempsize, const char **format); +static void *monitor_printer(_client_monitor_t *monitor); +static void show_attributes(const char *title, int request, ipp_t *ipp); +static void show_capabilities(ipp_t *response); +static void usage(void); + + +/* + * 'main()' - Main entry. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i; /* Looping var */ + const char *opt, /* Current option */ + *uri = NULL, /* Printer URI */ + *printfile = NULL, + /* Print file */ + *printformat = NULL; + /* Print format */ + int keepfile = 0, /* Keep temp file? */ + grayscale = 0, /* Force grayscale? */ + verbosity = 0; /* Verbosity */ + char tempfile[1024] = "", + /* Temporary file (if any) */ + scheme[32], /* URI scheme */ + userpass[256], /* Username:password */ + hostname[256], /* Hostname */ + resource[256]; /* Resource path */ + int port; /* Port number */ + http_encryption_t encryption; /* Encryption mode */ + _client_monitor_t monitor; /* Monitoring data */ + http_t *http; /* HTTP connection */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* IPP attribute */ + static const char * const pattrs[] = /* Printer attributes we are interested in */ + { + "job-template", + "printer-defaults", + "printer-description", + "media-col-database", + "media-col-ready" + }; + + + /* + * Parse command-line options... + */ + + for (i = 1; i < argc; i ++) + { + if (argv[i][0] == '-') + { + for (opt = argv[i] + 1; *opt; opt ++) + { + switch (*opt) + { + case 'd' : /* -d document-format */ + if (printformat) + { + puts("Document format can only be specified once."); + usage(); + return (1); + } + + i ++; + if (i >= argc) + { + puts("Expected document format after '-d'."); + usage(); + return (1); + } + + printformat = argv[i]; + break; + + case 'f' : /* -f print-file */ + if (printfile) + { + puts("Print file can only be specified once."); + usage(); + return (1); + } + + i ++; + if (i >= argc) + { + puts("Expected print file after '-f'."); + usage(); + return (1); + } + + printfile = argv[i]; + break; + + case 'g' : + grayscale = 1; + break; + + case 'k' : + keepfile = 1; + break; + + case 'v' : + verbosity ++; + break; + + default : + printf("Unknown option '-%c'.\n", *opt); + usage(); + return (1); + } + } + } + else if (uri || (strncmp(argv[i], "ipp://", 6) && strncmp(argv[i], "ipps://", 7))) + { + printf("Unknown command-line argument '%s'.\n", argv[i]); + usage(); + return (1); + } + else + uri = argv[i]; + } + + /* + * Make sure we have everything we need. + */ + + if (!uri) + { + puts("Expected printer URI."); + usage(); + return (1); + } + + /* + * Connect to the printer... + */ + + if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) + { + printf("Bad printer URI '%s'.\n", uri); + return (1); + } + + if (!port) + port = IPP_PORT; + + if (!strcmp(scheme, "https") || !strcmp(scheme, "ipps")) + encryption = HTTP_ENCRYPTION_ALWAYS; + else + encryption = HTTP_ENCRYPTION_IF_REQUESTED; + + if ((http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption, 1, 0, NULL)) == NULL) + { + printf("Unable to connect to '%s' on port %d: %s\n", hostname, port, cupsLastErrorString()); + return (1); + } + + /* + * Query printer status and capabilities... + */ + + request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs); + + response = cupsDoRequest(http, request, resource); + + if (verbosity) + show_capabilities(response); + + /* + * Now figure out what we will be printing... + */ + + if (printfile) + { + /* + * User specified a print file, figure out the format... + */ + + if ((opt = strrchr(printfile, '.')) != NULL) + { + /* + * Guess the format from the extension... + */ + + if (!strcmp(opt, ".jpg")) + printformat = "image/jpeg"; + else if (!strcmp(opt, ".pdf")) + printformat = "application/pdf"; + else if (!strcmp(opt, ".ps")) + printformat = "application/postscript"; + else if (!strcmp(opt, ".pwg")) + printformat = "image/pwg-raster"; + else if (!strcmp(opt, ".urf")) + printformat = "image/urf"; + else + printformat = "application/octet-stream"; + } + else + { + /* + * Tell the printer to auto-detect... + */ + + printformat = "application/octet-stream"; + } + } + else + { + /* + * No file specified, make something to test with... + */ + + if ((printfile = make_raster_file(response, grayscale, tempfile, sizeof(tempfile), &printformat)) == NULL) + return (1); + } + + ippDelete(response); + + /* + * Start monitoring the printer in the background... + */ + + memset(&monitor, 0, sizeof(monitor)); + + monitor.uri = uri; + monitor.hostname = hostname; + monitor.resource = resource; + monitor.port = port; + monitor.encryption = encryption; + + _cupsThreadCreate((_cups_thread_func_t)monitor_printer, &monitor); + + /* + * Create the job and wait for completion... + */ + + request = ippNewRequest(IPP_OP_CREATE_JOB); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); + + if ((opt = strrchr(printfile, '/')) != NULL) + opt ++; + else + opt = printfile; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, opt); + + if (verbosity) + show_attributes("Create-Job request", 1, request); + + response = cupsDoRequest(http, request, resource); + + if (verbosity) + show_attributes("Create-Job response", 0, response); + + if (cupsLastError() >= IPP_STATUS_REDIRECTION_OTHER_SITE) + { + printf("Unable to create print job: %s\n", cupsLastErrorString()); + + monitor.job_state = IPP_JSTATE_ABORTED; + + goto cleanup; + } + + if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL) + { + puts("No job-id returned in Create-Job request."); + + monitor.job_state = IPP_JSTATE_ABORTED; + + goto cleanup; + } + + monitor.job_id = ippGetInteger(attr, 0); + + printf("CREATED JOB %d, sending %s of type %s\n", monitor.job_id, printfile, printformat); + + ippDelete(response); + + request = ippNewRequest(IPP_OP_SEND_DOCUMENT); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", monitor.job_id); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, printformat); + ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); + + if (verbosity) + show_attributes("Send-Document request", 1, request); + + response = cupsDoFileRequest(http, request, resource, printfile); + + if (verbosity) + show_attributes("Send-Document response", 0, response); + + if (cupsLastError() >= IPP_STATUS_REDIRECTION_OTHER_SITE) + { + printf("Unable to print file: %s\n", cupsLastErrorString()); + + monitor.job_state = IPP_JSTATE_ABORTED; + + goto cleanup; + } + + puts("WAITING FOR JOB TO COMPLETE"); + + while (monitor.job_state < IPP_JSTATE_CANCELED) + sleep(1); + + /* + * Cleanup after ourselves... + */ + + cleanup: + + httpClose(http); + + if (tempfile[0] && !keepfile) + unlink(tempfile); + + return (monitor.job_state == IPP_JSTATE_COMPLETED); +} + + +/* + * 'make_raster_file()' - Create a temporary raster file. + */ + +static const char * /* O - Print filename */ +make_raster_file(ipp_t *response, /* I - Printer attributes */ + int grayscale, /* I - Force grayscale? */ + char *tempname, /* I - Temporary filename buffer */ + size_t tempsize, /* I - Size of temp file buffer */ + const char **format) /* O - Print format */ +{ + int i, /* Looping var */ + count; /* Number of values */ + ipp_attribute_t *attr; /* Printer attribute */ + const char *type = NULL; /* Raster type (colorspace + bits) */ + pwg_media_t *media = NULL; /* Media size */ + int xdpi = 0, /* Horizontal resolution */ + ydpi = 0; /* Vertical resolution */ + int fd; /* Temporary file */ + cups_mode_t mode; /* Raster mode */ + cups_raster_t *ras; /* Raster stream */ + cups_page_header2_t header; /* Page header */ + unsigned char *line, /* Line of raster data */ + *lineptr; /* Pointer into line */ + unsigned y, /* Current position on page */ + xcount, ycount, /* Current count for X and Y */ + xrep, yrep, /* Repeat count for X and Y */ + xoff, yoff, /* Offsets for X and Y */ + yend; /* End Y value */ + int temprow, /* Row in template */ + tempcolor; /* Template color */ + const char *template; /* Pointer into template */ + const unsigned char *color; /* Current color */ + static const unsigned char colors[][3] = + { /* Colors for test */ + { 191, 191, 191 }, + { 127, 127, 127 }, + { 63, 63, 63 }, + { 0, 0, 0 }, + { 255, 0, 0 }, + { 255, 127, 0 }, + { 255, 255, 0 }, + { 127, 255, 0 }, + { 0, 255, 0 }, + { 0, 255, 127 }, + { 0, 255, 255 }, + { 0, 127, 255 }, + { 0, 0, 255 }, + { 127, 0, 255 }, + { 255, 0, 255 } + }; + static const char * const templates[] = + { /* Raster template */ + " CCC U U PPPP SSS TTTTT EEEEE SSS TTTTT 000 1 222 333 4 55555 66 77777 888 999 ", + "C C U U P P S S T E S S T 0 0 11 2 2 3 3 4 4 5 6 7 8 8 9 9 ", + "C U U P P S T E S T 0 0 1 2 3 4 4 5 6 7 8 8 9 9 ", + "C U U PPPP SSS ----- T EEEE SSS T 0 0 0 1 22 333 44444 555 6666 7 888 9999 ", + "C U U P S T E S T 0 0 1 2 3 4 5 6 6 7 8 8 9 ", + "C C U U P S S T E S S T 0 0 1 2 3 3 4 5 5 6 6 7 8 8 9 ", + " CCC UUU P SSS T EEEEE SSS T 000 111 22222 333 4 555 666 7 888 99 ", + " " + }; + + + /* + * Figure out the output format... + */ + + if ((attr = ippFindAttribute(response, "document-format-supported", IPP_TAG_MIMETYPE)) == NULL) + { + puts("No supported document formats, aborting."); + return (NULL); + } + + if (*format) + { + if (!ippContainsString(attr, *format)) + { + printf("Printer does not support document-format '%s'.\n", *format); + return (NULL); + } + + if (!strcmp(*format, "image/urf")) + mode = CUPS_RASTER_WRITE_APPLE; + else if (!strcmp(*format, "image/pwg-raster")) + mode = CUPS_RASTER_WRITE_PWG; + else + { + printf("Unable to generate document-format '%s'.\n", *format); + return (NULL); + } + } + else if (ippContainsString(attr, "image/urf")) + { + /* + * Apple Raster format... + */ + + *format = "image/urf"; + mode = CUPS_RASTER_WRITE_APPLE; + } + else if (ippContainsString(attr, "image/pwg-raster")) + { + /* + * PWG Raster format... + */ + + *format = "image/pwg-raster"; + mode = CUPS_RASTER_WRITE_PWG; + } + else + { + /* + * No supported raster format... + */ + + puts("Printer does not support Apple or PWG raster files, aborting."); + return (NULL); + } + + /* + * Figure out the the media, resolution, and color mode... + */ + + if ((attr = ippFindAttribute(response, "media-default", IPP_TAG_KEYWORD)) != NULL) + { + /* + * Use default media... + */ + + media = pwgMediaForPWG(ippGetString(attr, 0, NULL)); + } + else if ((attr = ippFindAttribute(response, "media-ready", IPP_TAG_KEYWORD)) != NULL) + { + /* + * Use ready media... + */ + + if (ippContainsString(attr, "na_letter_8.5x11in")) + media = pwgMediaForPWG("na_letter_8.5x11in"); + else if (ippContainsString(attr, "iso_a4_210x297mm")) + media = pwgMediaForPWG("iso_a4_210x297mm"); + else + media = pwgMediaForPWG(ippGetString(attr, 0, NULL)); + } + else + { + puts("No default or ready media reported by printer, aborting."); + return (NULL); + } + + if (mode == CUPS_RASTER_WRITE_APPLE && (attr = ippFindAttribute(response, "urf-supported", IPP_TAG_KEYWORD)) != NULL) + { + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + const char *val = ippGetString(attr, i, NULL); + + if (!strncmp(val, "RS", 2)) + xdpi = ydpi = atoi(val + 2); + else if (!strncmp(val, "W8", 2) && !type) + type = "sgray_8"; + else if (!strncmp(val, "SRGB24", 6) && !grayscale) + type = "srgb_8"; + } + } + else if (mode == CUPS_RASTER_WRITE_PWG && (attr = ippFindAttribute(response, "pwg-raster-document-resolution-supported", IPP_TAG_RESOLUTION)) != NULL) + { + for (i = 0, count = ippGetCount(attr); i < count; i ++) + { + int tempxdpi, tempydpi; + ipp_res_t tempunits; + + tempxdpi = ippGetResolution(attr, 0, &tempydpi, &tempunits); + + if (i == 0 || tempxdpi < xdpi || tempydpi < ydpi) + { + xdpi = tempxdpi; + ydpi = tempydpi; + } + } + + if ((attr = ippFindAttribute(response, "pwg-raster-document-type-supported", IPP_TAG_KEYWORD)) != NULL) + { + if (!grayscale && ippContainsString(attr, "srgb_8")) + type = "srgb_8"; + else if (ippContainsString(attr, "sgray_8")) + type = "sgray_8"; + } + } + + if (xdpi < 72 || ydpi < 72) + { + puts("No supported raster resolutions, aborting."); + return (NULL); + } + + if (!type) + { + puts("No supported color spaces or bit depths, aborting."); + return (NULL); + } + + /* + * Make the raster context and details... + */ + + if (!cupsRasterInitPWGHeader(&header, media, type, xdpi, ydpi, "one-sided", NULL)) + { + printf("Unable to initialize raster context: %s\n", cupsRasterErrorString()); + return (NULL); + } + + header.cupsInteger[CUPS_RASTER_PWG_TotalPageCount] = 1; + + if (header.cupsWidth > (4 * header.HWResolution[0])) + { + xoff = header.HWResolution[0] / 2; + yoff = header.HWResolution[1] / 2; + } + else + { + xoff = 0; + yoff = 0; + } + + xrep = (header.cupsWidth - 2 * xoff) / 140; + yrep = xrep * header.HWResolution[1] / header.HWResolution[0]; + yend = header.cupsHeight - yoff; + + /* + * Prepare the raster file... + */ + + if ((line = malloc(header.cupsBytesPerLine)) == NULL) + { + printf("Unable to allocate %u bytes for raster output: %s\n", header.cupsBytesPerLine, strerror(errno)); + return (NULL); + } + + if ((fd = cupsTempFd(tempname, (int)tempsize)) < 0) + { + printf("Unable to create temporary print file: %s\n", strerror(errno)); + return (NULL); + } + + if ((ras = cupsRasterOpen(fd, mode)) == NULL) + { + printf("Unable to open raster stream: %s\n", cupsRasterErrorString()); + close(fd); + return (NULL); + } + + /* + * Write a single page consisting of the template dots repeated over the page. + */ + + cupsRasterWriteHeader2(ras, &header); + + memset(line, 0xff, header.cupsBytesPerLine); + + for (y = 0; y < yoff; y ++) + cupsRasterWritePixels(ras, line, header.cupsBytesPerLine); + + for (temprow = 0, tempcolor = 0; y < yend;) + { + template = templates[temprow]; + color = colors[tempcolor]; + + temprow ++; + if (temprow >= (int)(sizeof(templates) / sizeof(templates[0]))) + { + temprow = 0; + tempcolor ++; + if (tempcolor >= (int)(sizeof(colors) / sizeof(colors[0]))) + tempcolor = 0; + else if (tempcolor > 3 && header.cupsColorSpace == CUPS_CSPACE_SW) + tempcolor = 0; + } + + memset(line, 0xff, header.cupsBytesPerLine); + + if (header.cupsColorSpace == CUPS_CSPACE_SW) + { + /* + * Do grayscale output... + */ + + for (lineptr = line + xoff; *template; template ++) + { + if (*template != ' ') + { + for (xcount = xrep; xcount > 0; xcount --) + *lineptr++ = *color; + } + else + { + lineptr += xrep; + } + } + } + else + { + /* + * Do color output... + */ + + for (lineptr = line + 3 * xoff; *template; template ++) + { + if (*template != ' ') + { + for (xcount = xrep; xcount > 0; xcount --, lineptr += 3) + memcpy(lineptr, color, 3); + } + else + { + lineptr += 3 * xrep; + } + } + } + + for (ycount = yrep; ycount > 0 && y < yend; ycount --, y ++) + cupsRasterWritePixels(ras, line, header.cupsBytesPerLine); + } + + memset(line, 0xff, header.cupsBytesPerLine); + + for (y = 0; y < header.cupsHeight; y ++) + cupsRasterWritePixels(ras, line, header.cupsBytesPerLine); + + cupsRasterClose(ras); + + close(fd); + + printf("PRINT FILE: %s\n", tempname); + + return (tempname); +} + + +/* + * 'monitor_printer()' - Monitor the job and printer states. + */ + +static void * /* O - Thread exit code */ +monitor_printer( + _client_monitor_t *monitor) /* I - Monitoring data */ +{ + http_t *http; /* Connection to printer */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* Attribute in response */ + ipp_pstate_t printer_state; /* Printer state */ + char printer_state_reasons[1024]; + /* Printer state reasons */ + ipp_jstate_t job_state; /* Job state */ + char job_state_reasons[1024];/* Printer state reasons */ + static const char * const jattrs[] = /* Job attributes we want */ + { + "job-state", + "job-state-reasons" + }; + static const char * const pattrs[] = /* Printer attributes we want */ + { + "printer-state", + "printer-state-reasons" + }; + + + /* + * Open a connection to the printer... + */ + + http = httpConnect2(monitor->hostname, monitor->port, NULL, AF_UNSPEC, monitor->encryption, 1, 0, NULL); + + /* + * Loop until the job is canceled, aborted, or completed. + */ + + printer_state = (ipp_pstate_t)0; + printer_state_reasons[0] = '\0'; + + job_state = (ipp_jstate_t)0; + job_state_reasons[0] = '\0'; + + while (monitor->job_state < IPP_JSTATE_CANCELED) + { + /* + * Reconnect to the printer as needed... + */ + + if (httpGetFd(http) < 0) + httpReconnect2(http, 30000, NULL); + + if (httpGetFd(http) >= 0) + { + /* + * Connected, so check on the printer state... + */ + + request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, monitor->uri); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs); + + response = cupsDoRequest(http, request, monitor->resource); + + if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) + printer_state = (ipp_pstate_t)ippGetInteger(attr, 0); + + if ((attr = ippFindAttribute(response, "printer-state-reasons", IPP_TAG_KEYWORD)) != NULL) + ippAttributeString(attr, printer_state_reasons, sizeof(printer_state_reasons)); + + if (printer_state != monitor->printer_state || strcmp(printer_state_reasons, monitor->printer_state_reasons)) + { + printf("PRINTER: %s (%s)\n", ippEnumString("printer-state", printer_state), printer_state_reasons); + + monitor->printer_state = printer_state; + strlcpy(monitor->printer_state_reasons, printer_state_reasons, sizeof(monitor->printer_state_reasons)); + } + + ippDelete(response); + + if (monitor->job_id > 0) + { + /* + * Check the status of the job itself... + */ + + request = ippNewRequest(IPP_OP_GET_JOB_ATTRIBUTES); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, monitor->uri); + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", monitor->job_id); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(jattrs) / sizeof(jattrs[0])), NULL, jattrs); + + response = cupsDoRequest(http, request, monitor->resource); + + if ((attr = ippFindAttribute(response, "job-state", IPP_TAG_ENUM)) != NULL) + job_state = (ipp_jstate_t)ippGetInteger(attr, 0); + + if ((attr = ippFindAttribute(response, "job-state-reasons", IPP_TAG_KEYWORD)) != NULL) + ippAttributeString(attr, job_state_reasons, sizeof(job_state_reasons)); + + if (job_state != monitor->job_state || strcmp(job_state_reasons, monitor->job_state_reasons)) + { + printf("JOB %d: %s (%s)\n", monitor->job_id, ippEnumString("job-state", job_state), job_state_reasons); + + monitor->job_state = job_state; + strlcpy(monitor->job_state_reasons, job_state_reasons, sizeof(monitor->job_state_reasons)); + } + + ippDelete(response); + } + } + + if (monitor->job_state < IPP_JSTATE_CANCELED) + { + /* + * Sleep for 5 seconds... + */ + + sleep(5); + } + } + + /* + * Cleanup and return... + */ + + httpClose(http); + + return (NULL); +} + + +/* + * 'show_attributes()' - Show attributes in a request or response. + */ + +static void +show_attributes(const char *title, /* I - Title */ + int request, /* I - 1 for request, 0 for response */ + ipp_t *ipp) /* I - IPP request/response */ +{ + int minor, major = ippGetVersion(ipp, &minor); + /* IPP version number */ + ipp_tag_t group = IPP_TAG_ZERO; + /* Current group tag */ + ipp_attribute_t *attr; /* Current attribute */ + const char *name; /* Attribute name */ + char buffer[1024]; /* Value */ + + + printf("%s:\n", title); + printf(" version=%d.%d\n", major, minor); + printf(" request-id=%d\n", ippGetRequestId(ipp)); + if (!request) + printf(" status-code=%s\n", ippErrorString(ippGetStatusCode(ipp))); + + for (attr = ippFirstAttribute(ipp); attr; attr = ippNextAttribute(ipp)) + { + if (group != ippGetGroupTag(attr)) + { + group = ippGetGroupTag(attr); + if (group) + printf(" %s:\n", ippTagString(group)); + } + + if ((name = ippGetName(attr)) != NULL) + { + ippAttributeString(attr, buffer, sizeof(buffer)); + printf(" %s(%s%s)=%s\n", name, ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr)), buffer); + } + } +} + + +/* + * 'show_capabilities()' - Show printer capabilities. + */ + +static void +show_capabilities(ipp_t *response) /* I - Printer attributes */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* Attribute */ + char buffer[1024]; /* Attribute value buffer */ + static const char * const pattrs[] = /* Attributes we want to show */ + { + "copies-default", + "copies-supported", + "finishings-default", + "finishings-ready", + "finishings-supported", + "media-default", + "media-ready", + "media-supported", + "output-bin-default", + "output-bin-supported", + "print-color-mode-default", + "print-color-mode-supported", + "sides-default", + "sides-supported", + "document-format-default", + "document-format-supported", + "pwg-raster-document-resolution-supported", + "pwg-raster-document-type-supported", + "urf-supported" + }; + + + puts("CAPABILITIES:"); + for (i = 0; i < (int)(sizeof(pattrs) / sizeof(pattrs[0])); i ++) + { + if ((attr = ippFindAttribute(response, pattrs[i], IPP_TAG_ZERO)) != NULL) + { + ippAttributeString(attr, buffer, sizeof(buffer)); + printf(" %s=%s\n", pattrs[i], buffer); + } + } +} + + +/* + * 'usage()' - Show program usage... + */ + +static void +usage(void) +{ + puts("Usage: ./testclient printer-uri [options]"); + puts("Options:"); + puts(" -d document-format Generate the specified format"); + puts(" -f print-file Print the named file"); + puts(" -g Force grayscale printing"); + puts(" -k Keep temporary files"); + puts(" -v Be more verbose"); +} diff --git a/libcups_version b/libcups_version index 0b1f88b8..437a354a 100644 --- a/libcups_version +++ b/libcups_version @@ -1 +1 @@ -v2.2.3 +v2.2.6 |