]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Merge changes from CUPS 1.5svn-r9352.
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Sat, 6 Nov 2010 05:13:04 +0000 (05:13 +0000)
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Sat, 6 Nov 2010 05:13:04 +0000 (05:13 +0000)
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@2848 a1ca3aef-8c08-0410-bb20-df032aa958be

88 files changed:
CHANGES.txt
IPPTOOL.txt
conf/cupsd.conf.in
cups/api-array.shtml
cups/array.c
cups/array.h
cups/http-addrlist.c
cups/http-private.h
cups/http.c
cups/libcups2.def
cups/pwg-ppd.c
cups/request.c
cups/usersys.c
doc/cups-printable.css
doc/cups.css
doc/help/api-array.html
doc/help/api-cgi.html
doc/help/api-cups.html
doc/help/api-driver.html
doc/help/api-filedir.html
doc/help/api-filter.html
doc/help/api-httpipp.html
doc/help/api-mime.html
doc/help/api-overview.html
doc/help/api-ppd.html
doc/help/api-ppdc.html
doc/help/api-raster.html
doc/help/postscript-driver.html
doc/help/ppd-compiler.html
doc/help/raster-driver.html
doc/help/ref-cupsd-conf.html.in
doc/help/spec-ppd.html
filter/Makefile
filter/api-raster.header
filter/postscript-driver.header
filter/ppd-compiler.header
filter/raster-driver.header
filter/spec-ppd.header [new file with mode: 0644]
filter/spec-ppd.shtml [new file with mode: 0644]
man/cupsd.conf.man.in
man/ipptool.man
scheduler/auth.c
scheduler/auth.h
scheduler/banners.c
scheduler/banners.h
scheduler/cert.c
scheduler/cert.h
scheduler/classes.c
scheduler/classes.h
scheduler/client.c
scheduler/client.h
scheduler/conf.c
scheduler/conf.h
scheduler/cups-deviced.c
scheduler/cupsd.h
scheduler/cupsfilter.c
scheduler/dirsvc.c
scheduler/dirsvc.h
scheduler/env.c
scheduler/ipp.c
scheduler/job.c
scheduler/job.h
scheduler/listen.c
scheduler/log.c
scheduler/main.c
scheduler/mime.h
scheduler/network.h
scheduler/policy.c
scheduler/policy.h
scheduler/printers.c
scheduler/printers.h
scheduler/quotas.c
scheduler/removefile.c
scheduler/select.c
scheduler/statbuf.c
scheduler/statbuf.h
scheduler/subscriptions.c
scheduler/subscriptions.h
scheduler/sysman.c
scheduler/sysman.h
scheduler/util.c
scheduler/util.h
test/4.4-subscription-ops.test
test/get-printer-attributes.test
test/ipp-1.1.test
test/ipptool.c
test/print-job-media-col.test
test/run-stp-tests.sh

index 067dc958ed1165cf71b79b5d999fe7f1813418cd..008b91b3726a5ecc9580a556ade78c2a694c2795 100644 (file)
@@ -1,8 +1,12 @@
-CHANGES.txt - 2010-06-16
+CHANGES.txt - 2010-11-05
 ------------------------
 
 CHANGES IN CUPS V1.5b1
 
+       - The scheduler now provides privacy controls for jobs and subscriptions
+         (STR #2969)
+       - Added new cupsArrayNew3 API which offers memory management of array
+         elements.
        - Added several new color spaces to the CUPS raster format (STR #3419)
        - The Validate-Job operation now uses the same policy as Print-Job by
          default. 
index c968220173b0526c217e879903a205c98643beef..c13da01ae7cdcc675c97fbdc521b77e38adfd947 100644 (file)
@@ -1,24 +1,23 @@
-IPPTOOL.txt - 2010-04-07
+IPPTOOL.txt - 2010-10-17
 ------------------------
 
 
 INTRODUCTION
 
-    Starting with CUPS 1.5, CUPS now installs a user program called
-    ipptool that can be used to send arbitrary IPP requests to a CUPS
-    server or IPP printer. This tool started life as part of the CUPS
-    automated test suite and has grown to support complex conformance
-    tests and a simple way to query printer, job, and subscription
-    attributes.
+    Starting with CUPS 1.5, CUPS now installs a user program called ipptool that
+    can be used to send arbitrary IPP requests to a CUPS server or IPP printer.
+    This tool started life as part of the CUPS automated test suite and has
+    grown to support complex conformance tests and a simple way to query
+    printer, job, and subscription attributes.
 
 
 BASIC USAGE
 
-    The ipptool command requires a printer URI and one or more "test"
-    files that describe the operations, attributes to display, and
-    expected status and attribute values. Several standard files are
-    included with CUPS, for example to show a list of pending print jobs
-    on a CUPS printer called "myprinter" you'd run:
+    The ipptool command requires a printer URI and one or more "test" files that
+    describe the operations, attributes to display, and expected status and
+    attribute values. Several standard files are included with CUPS, for example
+    to show a list of pending print jobs on a CUPS printer called "myprinter"
+    you'd run:
 
         ipptool ipp://localhost/printers/myprinter get-jobs.test
 
@@ -31,8 +30,8 @@ BASIC USAGE
        74     pending-held testfile.jpg msweet
        75     pending-held testfile.txt msweet
 
-    To get output suitable for import into a spreadsheet, use the "-c"
-    (CSV) option:
+    To get output suitable for import into a spreadsheet, use the "-c" (CSV)
+    option:
 
         ipptool -c ipp://localhost/printers/myprinter get-jobs.test
 
@@ -47,9 +46,8 @@ BASIC USAGE
 
 CONFORMANCE TESTS
 
-    We provide basic IPP conformance tests for IPP/1.1, IPP/2.0, and
-    IPP/2.1. For a given printer URI, the following commands perform
-    tests at each level:
+    We provide basic IPP conformance tests for IPP/1.1, IPP/2.0, and IPP/2.1.
+    For a given printer URI, the following commands perform tests at each level:
 
         ipptool -t printer-uri ipp-1.1.test
         ipptool -t -V 2.0 printer-uri ipp-2.0.test
@@ -58,8 +56,8 @@ CONFORMANCE TESTS
 
 READING THE DOCUMENTATION
 
-    The command usage is described in the ipptest(1) man page, while the
-    file format is described in the ipptestfile(5) man page.
+    The command usage is described in the ipptest(1) man page, while the file
+    format is described in the ipptestfile(5) man page.
 
 
 GETTING SUPPORT AND OTHER RESOURCES
index a7143b7dc94e4023648ae8f65a58f840be1dc0a5..1a2037cfaefdddba2b94da9856e7c418df0e5258 100644 (file)
@@ -45,6 +45,12 @@ DefaultAuthType Basic
 
 # Set the default printer/job policies...
 <Policy default>
+  # Job/subscription privacy...
+  JobPrivateAccess default
+  JobPrivateValues default
+  SubscriptionPrivateAccess default
+  SubscriptionPrivateAccess default
+
   # Job-related operations must be done by the owner or an administrator...
   <Limit Create-Job Print-Job Print-URI Validate-Job>
     Order deny,allow
@@ -63,14 +69,14 @@ DefaultAuthType Basic
   </Limit>
 
   # All printer operations require a printer operator to authenticate...
-  <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After CUPS-Accept-Jobs CUPS-Reject-Jobs>
+  <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
     AuthType Default
     Require user @CUPS_DEFAULT_PRINTOPERATOR_AUTH@
     Order deny,allow
   </Limit>
 
   # Only the owner or an administrator can cancel or authenticate a job...
-  <Limit Cancel-Job Cancel-Jobs CUPS-Authenticate-Job>
+  <Limit Cancel-Job CUPS-Authenticate-Job>
     Require user @OWNER @CUPS_DEFAULT_PRINTOPERATOR_AUTH@
     Order deny,allow
   </Limit>
@@ -82,6 +88,12 @@ DefaultAuthType Basic
 
 # Set the authenticated printer/job policies...
 <Policy authenticated>
+  # Job/subscription privacy...
+  JobPrivateAccess default
+  JobPrivateValues default
+  SubscriptionPrivateAccess default
+  SubscriptionPrivateAccess default
+
   # Job-related operations must be done by the owner or an administrator...
   <Limit Create-Job Print-Job Print-URI Validate-Job>
     AuthType Default
@@ -102,14 +114,14 @@ DefaultAuthType Basic
   </Limit>
 
   # All printer operations require a printer operator to authenticate...
-  <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After CUPS-Accept-Jobs CUPS-Reject-Jobs>
+  <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs CUPS-Reject-Jobs>
     AuthType Default
     Require user @CUPS_DEFAULT_PRINTOPERATOR_AUTH@
     Order deny,allow
   </Limit>
 
   # Only the owner or an administrator can cancel or authenticate a job...
-  <Limit Cancel-Job Cancel-Jobs CUPS-Authenticate-Job>
+  <Limit Cancel-Job CUPS-Authenticate-Job>
     AuthType Default
     Require user @OWNER @CUPS_DEFAULT_PRINTOPERATOR_AUTH@
     Order deny,allow
index bacf48307c44d7d4c6944b0a6705867bf783d312..0872d51e7ed65ea709767ccb7282defee29d7b9a 100644 (file)
@@ -31,8 +31,9 @@ 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> or
-<a href='#cupsArrayNew2'><code>cupsArrayNew2</code></a> functions. 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>
 
@@ -69,7 +70,7 @@ 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> *array = <a href='#cupsArrayNew2'>cupsArrayNew2</a>(compare_func, user_data, hash_func, HASH_SIZE);
+<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
@@ -80,6 +81,25 @@ element and is called whenever you look up an element in the array with
 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 &lt;cups/array.h&gt;
+
+#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.
@@ -128,8 +148,7 @@ example:</p>
 <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</em> - if necessary, you must allocate and free the
-elements yourself.</p>
+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>
 
index 5b9a8ce375513a000b8205b8e38fd6fc4adb7188..5448472b3812a1562673087f974f9d37fa32d4db 100644 (file)
  *   cupsArrayInsert()    - Insert an element in the array.
  *   cupsArrayLast()      - Get the last element in the array.
  *   cupsArrayNew()       - Create a new array.
+ *   cupsArrayNew2()      - Create a new array with hash.
+ *   cupsArrayNew3()      - Create a new array with hash and/or free function.
  *   cupsArrayNext()      - Get the next element in the array.
  *   cupsArrayPrev()      - Get the previous element in the array.
  *   cupsArrayRemove()    - Remove an element from the array.
- *   cupsArrayRestore()   - Reset the current element to the last cupsArraySave.
- *   cupsArraySave()      - Mark the current element for a later
- *                          cupsArrayRestore.
+ *   cupsArrayRestore()   - Reset the current element to the last @link
+ *                          cupsArraySave@.
+ *   cupsArraySave()      - Mark the current element for a later @link
+ *                          cupsArrayRestore@.
  *   cupsArrayUserData()  - Return the user data for an array.
  *   cups_array_add()     - Insert or append an element to the array...
  *   cups_array_find()    - Find an element in the array...
@@ -84,6 +87,8 @@ struct _cups_array_s                  /**** CUPS array structure ****/
   cups_ahash_func_t    hashfunc;       /* Hash function */
   int                  hashsize,       /* Size of hash */
                        *hash;          /* Hash array */
+  cups_acopy_func_t    copyfunc;       /* Copy function */
+  cups_afree_func_t    freefunc;       /* Free function */
 };
 
 
@@ -149,6 +154,19 @@ cupsArrayClear(cups_array_t *a)            /* I - Array */
   if (!a)
     return;
 
+ /*
+  * Free the existing elements as needed..
+  */
+
+  if (a->freefunc)
+  {
+    int                i;                      /* Looping var */
+    void       **e;                    /* Current element */
+
+    for (i = a->num_elements, e = a->elements; i > 0; i --, e ++)
+      (a->freefunc)(*e, a->data);
+  }
+
  /*
   * Set the number of elements to 0; we don't actually free the memory
   * here - that is done in cupsArrayDelete()...
@@ -236,8 +254,21 @@ cupsArrayDelete(cups_array_t *a)   /* I - Array */
     return;
 
  /*
-  * Free the array of element pointers - the caller is responsible
-  * for freeing the elements themselves...
+  * Free the elements if we have a free function (otherwise the caller is
+  * responsible for doing the dirty work...)
+  */
+
+  if (a->freefunc)
+  {
+    int                i;                      /* Looping var */
+    void       **e;                    /* Current element */
+
+    for (i = a->num_elements, e = a->elements; i > 0; i --, e ++)
+      (a->freefunc)(*e, a->data);
+  }
+
+ /*
+  * Free the array of element pointers...
   */
 
   if (a->alloc_elements)
@@ -303,7 +334,26 @@ cupsArrayDup(cups_array_t *a)              /* I - Array */
     * Copy the element pointers...
     */
 
-    memcpy(da->elements, a->elements, a->num_elements * sizeof(void *));
+    if (a->copyfunc)
+    {
+     /*
+      * Use the copy function to make a copy of each element...
+      */
+
+      int      i;                      /* Looping var */
+
+      for (i = 0; i < a->num_elements; i ++)
+       da->elements[i] = (a->copyfunc)(a->elements[i], a->data);
+    }
+    else
+    {
+     /*
+      * Just copy raw pointers...
+      */
+
+      memcpy(da->elements, a->elements, a->num_elements * sizeof(void *));
+    }
+
     da->num_elements   = a->num_elements;
     da->alloc_elements = a->num_elements;
   }
@@ -566,7 +616,7 @@ cups_array_t *                              /* O - Array */
 cupsArrayNew(cups_array_func_t f,      /* I - Comparison function or @code NULL@ for an unsorted array */
              void              *d)     /* I - User data pointer or @code NULL@ */
 {
-  return (cupsArrayNew2(f, d, 0, 0));
+  return (cupsArrayNew3(f, d, 0, 0, 0, 0));
 }
 
 
@@ -589,6 +639,38 @@ cupsArrayNew2(cups_array_func_t  f,        /* I - Comparison function or @code NULL@ fo
               void               *d,   /* I - User data or @code NULL@ */
               cups_ahash_func_t  h,    /* I - Hash function or @code NULL@ for unhashed lookups */
              int                hsize) /* I - Hash size (>= 0) */
+{
+  return (cupsArrayNew3(f, d, h, hsize, 0, 0));
+}
+
+
+/*
+ * 'cupsArrayNew3()' - Create a new array with hash and/or free function.
+ *
+ * The comparison function ("f") is used to create a sorted array. The function
+ * receives pointers to two elements and the user data pointer ("d") - the user
+ * data pointer argument can safely be omitted when not required so functions
+ * like @code strcmp@ can be used for sorted string arrays.
+ *
+ * The hash function ("h") is used to implement cached lookups with the
+ * specified hash size ("hsize").
+ *
+ * The copy function ("cf") is used to automatically copy/retain elements when
+ * added or the array is copied.
+ *
+ * The free function ("cf") is used to automatically free/release elements when
+ * removed or the array is deleted.
+ *
+ * @since CUPS 1.5@
+ */
+
+cups_array_t *                         /* O - Array */
+cupsArrayNew3(cups_array_func_t  f,    /* I - Comparison function or @code NULL@ for an unsorted array */
+              void               *d,   /* I - User data or @code NULL@ */
+              cups_ahash_func_t  h,    /* I - Hash function or @code NULL@ for unhashed lookups */
+             int                hsize, /* I - Hash size (>= 0) */
+             cups_acopy_func_t  cf,    /* I - Copy function */
+             cups_afree_func_t  ff)    /* I - Free function */
 {
   cups_array_t *a;                     /* Array  */
 
@@ -623,6 +705,9 @@ cupsArrayNew2(cups_array_func_t  f, /* I - Comparison function or @code NULL@ fo
     memset(a->hash, -1, hsize * sizeof(int));
   }
 
+  a->copyfunc = cf;
+  a->freefunc = ff;
+
   return (a);
 }
 
@@ -738,6 +823,9 @@ cupsArrayRemove(cups_array_t *a,    /* I - Array */
 
   a->num_elements --;
 
+  if (a->freefunc)
+    (a->freefunc)(a->elements[current], a->data);
+
   if (current < a->num_elements)
     memmove(a->elements + current, a->elements + current + 1,
             (a->num_elements - current) * sizeof(void *));
@@ -985,7 +1073,17 @@ cups_array_add(cups_array_t *a,           /* I - Array */
     DEBUG_printf(("9cups_array_add: append element at %d...", current));
 #endif /* DEBUG */
 
-  a->elements[current] = e;
+  if (a->copyfunc)
+  {
+    if ((a->elements[current] = (a->copyfunc)(e, a->data)) == NULL)
+    {
+      DEBUG_puts("8cups_array_add: Copy function returned NULL, returning 0");
+      return (0);
+    }
+  }
+  else
+    a->elements[current] = e;
+
   a->num_elements ++;
   a->insert = current;
 
index 029e2e996050ce2e66648f796e7d40429d35156f..466a2721fc48ad9bbc1fd65f1d9533a0f6e13bca 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: array.h 7266 2008-01-29 02:15:29Z mike $"
  *
- *   Sorted array definitions for the Common UNIX Printing System (CUPS).
+ *   Sorted array definitions for CUPS.
  *
- *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -45,6 +45,10 @@ typedef int (*cups_array_func_t)(void *first, void *second, void *data);
                                        /**** Array comparison function ****/
 typedef int (*cups_ahash_func_t)(void *element, void *data);
                                        /**** Array hash function ****/
+typedef void *(*cups_acopy_func_t)(void *element, void *data);
+                                       /**** Array element copy function ****/
+typedef void (*cups_afree_func_t)(void *element, void *data);
+                                       /**** Array element free function ****/
 
 
 /*
@@ -67,6 +71,10 @@ extern void          *cupsArrayLast(cups_array_t *a) _CUPS_API_1_2;
 extern cups_array_t    *cupsArrayNew(cups_array_func_t f, void *d) _CUPS_API_1_2;
 extern cups_array_t    *cupsArrayNew2(cups_array_func_t f, void *d,
                                       cups_ahash_func_t h, int hsize) _CUPS_API_1_3;
+extern cups_array_t    *cupsArrayNew3(cups_array_func_t f, void *d,
+                                      cups_ahash_func_t h, int hsize,
+                                      cups_acopy_func_t cf,
+                                      cups_afree_func_t ff) _CUPS_API_1_5;
 extern void            *cupsArrayNext(cups_array_t *a) _CUPS_API_1_2;
 extern void            *cupsArrayPrev(cups_array_t *a) _CUPS_API_1_2;
 extern int             cupsArrayRemove(cups_array_t *a, void *e) _CUPS_API_1_2;
index 14406427dde3cfd2fa6986271d3ec6045bc03f06..7c11d1b1a8e905168f4a20046b50a40fe35e0f7f 100644 (file)
@@ -40,9 +40,12 @@ httpAddrConnect(
     http_addrlist_t *addrlist,         /* I - List of potential addresses */
     int             *sock)             /* O - Socket */
 {
-  int  val;                            /* Socket option value */
+  int                  val;            /* Socket option value */
+#ifdef __APPLE__
+  struct timeval       timeout;        /* Socket timeout value */
+#endif /* __APPLE__ */
 #ifdef DEBUG
-  char temp[256];                      /* Temporary address string */
+  char                 temp[256];      /* Temporary address string */
 #endif /* DEBUG */
 
 
@@ -108,8 +111,9 @@ httpAddrConnect(
     * we block...
     */
 
-    val = 30;
-    setsockopt(*sock, SOL_SOCKET, SO_RCVTIMEO, &val, sizeof(val));
+    timeout.tv_sec  = 30;
+    timeout.tv_usec = 0;
+    setsockopt(*sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
 #endif /* __APPLE__ */
 
    /*
index 0700530bdf84775c9f90031caf99ef4a5850bbd4..483592f51331c906dce51db29174d80735cc1155 100644 (file)
@@ -169,6 +169,8 @@ typedef void *http_tls_t;
 #  endif /* HAVE_LIBSSL */
 
 
+typedef int (*_http_timeout_cb_t)(http_t *http, void *user_data);
+
 struct _http_s                         /**** HTTP connection structure. ****/
 {
   int                  fd;             /* File descriptor for this socket */
@@ -224,11 +226,14 @@ struct _http_s                            /**** HTTP connection structure. ****/
   gss_name_t           gssname;        /* Authentication server name @since CUPS 1.3@ */
 #  endif /* HAVE_GSSAPI */
 #  ifdef HAVE_AUTHORIZATION_H
-  AuthorizationRef     auth_ref;       /* Authorization ref */
+  AuthorizationRef     auth_ref;       /* Authorization ref @since CUPS 1.3@ */
 #  endif /* HAVE_AUTHORIZATION_H */
   /**** New in CUPS 1.5 ****/
   http_tls_credentials_t tls_credentials;
-                                       /* TLS credentials */
+                                       /* TLS credentials @since CUPS 1.5@ */
+  _http_timeout_cb_t   timeout_cb;     /* Timeout callback @since CUPS 1.5@ */
+  void                 *timeout_data;  /* User data pointer @since CUPS 1.5@ */
+  struct timeval       timeout_value;  /* Timeout in seconds */
 };
 
 
@@ -314,6 +319,8 @@ extern void         _httpFreeCredentials(http_tls_credentials_t credentials);
 extern ssize_t         _httpPeek(http_t *http, char *buffer, size_t length);
 extern const char      *_httpResolveURI(const char *uri, char *resolved_uri,
                                         size_t resolved_size, int log);
+extern void            _httpSetTimeout(http_t *http, double timeout,
+                                       _http_timeout_cb_t cb, void *user_data);
 extern int             _httpWait(http_t *http, int msec, int usessl);
 
 
index defa388594edc3ec11287089cb70379c8a0e246f..06ceb021239afd65411bb8f0486bc6777fc4ecd5 100644 (file)
@@ -80,6 +80,8 @@
  *   httpSetExpect()           - Set the Expect: header in a request.
  *   httpSetField()            - Set the value of an HTTP header.
  *   httpSetLength()           - Set the content-length and content-encoding.
+ *   _httpSetTimeout()         - Set read/write timeouts and an optional
+ *                               callback.
  *   httpTrace()               - Send an TRACE request to the server.
  *   httpUpdate()              - Update the current HTTP state for incoming
  *                               data.
@@ -1347,8 +1349,15 @@ httpGets(char   *line,                   /* I - Line to read into */
 #ifdef WIN32
         DEBUG_printf(("3httpGets: recv() error %d!", WSAGetLastError()));
 
-        if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)
+        if (WSAGetLastError() == WSAEINTR)
          continue;
+       else if (WSAGetLastError() == WSAEWOULDBLOCK)
+       {
+         if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+           continue;
+
+         http->error = WSAGetLastError();
+       }
        else if (WSAGetLastError() != http->error)
        {
          http->error = WSAGetLastError();
@@ -1358,8 +1367,17 @@ httpGets(char   *line,                   /* I - Line to read into */
 #else
         DEBUG_printf(("3httpGets: recv() error %d!", errno));
 
-        if (errno == EINTR || errno == EAGAIN)
+        if (errno == EINTR)
          continue;
+       else if (errno == EWOULDBLOCK || errno == EAGAIN)
+       {
+         if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+           continue;
+         else if (!http->timeout_cb && errno == EAGAIN)
+           continue;
+
+         http->error = errno;
+       }
        else if (errno != http->error)
        {
          http->error = errno;
@@ -1925,13 +1943,34 @@ httpRead2(http_t *http,                 /* I - Connection to server */
     else if (bytes < 0)
     {
 #ifdef WIN32
-      if (WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK)
+      if (WSAGetLastError() != WSAEINTR)
       {
         http->error = WSAGetLastError();
         return (-1);
       }
+      else if (WSAGetLastError() == WSAEWOULDBLOCK)
+      {
+        if (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data))
+       {
+         http->error = WSAEWOULDBLOCK;
+         return (-1);
+       }
+      }
 #else
-      if (errno != EINTR && errno != EAGAIN)
+      if (errno == EWOULDBLOCK || errno == EAGAIN)
+      {
+        if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data))
+       {
+         http->error = errno;
+         return (-1);
+       }
+       else if (!http->timeout_cb && errno != EAGAIN)
+       {
+         http->error = errno;
+         return (-1);
+       }
+      }
+      else if (errno != EINTR)
       {
         http->error = errno;
         return (-1);
@@ -1979,13 +2018,29 @@ httpRead2(http_t *http,                 /* I - Connection to server */
                   CUPS_LLCAST length));
 
 #ifdef WIN32
-    while ((bytes = (ssize_t) recv(http->fd, buffer, (int)length, 0)) < 0)
-      if (WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK)
+    while ((bytes = (ssize_t)recv(http->fd, buffer, (int)length, 0)) < 0)
+    {
+      if (WSAGetLastError() == WSAEWOULDBLOCK)
+      {
+        if (!http->timeout_cb || !(*http->timeout_cb)(http, http->timeout_data))
+         break;
+      }
+      else if (WSAGetLastError() != WSAEINTR)
         break;
+    }
 #else
     while ((bytes = recv(http->fd, buffer, length, 0)) < 0)
-      if (errno != EINTR && errno != EAGAIN)
+    {
+      if (errno == EWOULDBLOCK || errno == EAGAIN)
+      {
+        if (http->timeout_cb && !(*http->timeout_cb)(http, http->timeout_data))
+         break;
+        else if (!http->timeout_cb && errno != EAGAIN)
+         break;
+      }
+      else if (errno != EINTR)
         break;
+    }
 #endif /* WIN32 */
 
     DEBUG_printf(("2httpRead2: read " CUPS_LLFMT " bytes from socket...",
@@ -2004,12 +2059,12 @@ httpRead2(http_t *http,                 /* I - Connection to server */
   else if (bytes < 0)
   {
 #ifdef WIN32
-    if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)
+    if (WSAGetLastError() == WSAEINTR)
       bytes = 0;
     else
       http->error = WSAGetLastError();
 #else
-    if (errno == EINTR || errno == EAGAIN)
+    if (errno == EINTR || (errno == EAGAIN && !http->timeout_cb))
       bytes = 0;
     else
       http->error = errno;
@@ -2216,6 +2271,14 @@ httpReconnect(http_t *http)              /* I - Connection to server */
 
   DEBUG_printf(("2httpReconnect: New socket=%d", http->fd));
 
+  if (http->timeout_value.tv_sec > 0)
+  {
+    setsockopt(http->fd, SOL_SOCKET, SO_RCVTIMEO, &(http->timeout_value),
+               sizeof(http->timeout_value));
+    setsockopt(http->fd, SOL_SOCKET, SO_SNDTIMEO, &(http->timeout_value),
+               sizeof(http->timeout_value));
+  }
+
   http->hostaddr = &(addr->addr);
   http->error    = 0;
   http->status   = HTTP_CONTINUE;
@@ -2470,6 +2533,39 @@ httpSetLength(http_t *http,              /* I - Connection to server */
 }
 
 
+/*
+ * '_httpSetTimeout()' - Set read/write timeouts and an optional callback.
+ *
+ * The optional timeout callback receives both the HTTP connection and a user
+ * data pointer and must return 1 to continue or 0 to error out.
+ */
+
+void
+_httpSetTimeout(
+    http_t             *http,          /* I - Connection to server */
+    double             timeout,                /* I - Number of seconds for timeout,
+                                               must be greater than 0 */
+    _http_timeout_cb_t cb,             /* I - Callback function or NULL */
+    void               *user_data)     /* I - User data pointer */
+{
+  if (!http || timeout <= 0.0)
+    return;
+
+  http->timeout_cb            = cb;
+  http->timeout_data          = user_data;
+  http->timeout_value.tv_sec  = (int)timeout;
+  http->timeout_value.tv_usec = (int)(timeout * 1000000) % 1000000;
+
+  if (http->fd >= 0)
+  {
+    setsockopt(http->fd, SOL_SOCKET, SO_RCVTIMEO, &(http->timeout_value),
+               sizeof(http->timeout_value));
+    setsockopt(http->fd, SOL_SOCKET, SO_SNDTIMEO, &(http->timeout_value),
+               sizeof(http->timeout_value));
+  }
+}
+
+
 /*
  * 'httpTrace()' - Send an TRACE request to the server.
  */
@@ -4175,16 +4271,34 @@ http_write(http_t     *http,            /* I - Connection to server */
     if (bytes < 0)
     {
 #ifdef WIN32
-      if (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEWOULDBLOCK)
+      if (WSAGetLastError() == WSAEINTR)
         continue;
-      else if (WSAGetLastError() != http->error && WSAGetLastError() != WSAECONNRESET)
+      else if (WSAGetLastError() == WSAEWOULDBLOCK)
+      {
+        if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+          continue;
+
+        http->error = WSAGetLastError();
+      }
+      else if (WSAGetLastError() != http->error &&
+               WSAGetLastError() != WSAECONNRESET)
       {
         http->error = WSAGetLastError();
        continue;
       }
+
 #else
-      if (errno == EINTR || errno == EAGAIN)
+      if (errno == EINTR)
         continue;
+      else if (errno == EWOULDBLOCK || errno == EAGAIN)
+      {
+       if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data))
+          continue;
+        else if (!http->timeout_cb && errno == EAGAIN)
+         continue;
+
+        http->error = errno;
+      }
       else if (errno != http->error && errno != ECONNRESET)
       {
         http->error = errno;
index a34c70032013420afc845d89e2afa33dc71d9697..798c82f65980b0540506c73ee04c7975c015c531 100644 (file)
@@ -24,6 +24,7 @@ _cups_strcpy
 _cups_strlcat\r
 _cups_strlcpy\r
 _httpResolveURI\r
+_httpSetTimeout\r
 _ippAddAttr\r
 _ippAttrString\r
 _ippFindOption\r
index 5307019c7b9c44c7dade9b75bbc558b8b0d7c947..1bfd26d9e7fb3e9245b1d43f5770a2a3d707c85a 100644 (file)
@@ -95,7 +95,8 @@ _pwgCreateWithPPD(ppd_file_t *ppd)    /* I - PPD file */
   int                  similar;        /* Are the old and new size similar? */
   _pwg_size_t           *old_size;     /* Current old size */
   int                  old_imageable,  /* Old imageable length in 2540ths */
-                       old_borderless; /* Old borderless state */
+                       old_borderless, /* Old borderless state */
+                       old_known_pwg;  /* Old PWG name is well-known */
   int                  new_width,      /* New width in 2540ths */
                        new_length,     /* New length in 2540ths */
                        new_left,       /* New left margin in 2540ths */
@@ -103,7 +104,8 @@ _pwgCreateWithPPD(ppd_file_t *ppd)  /* I - PPD file */
                        new_right,      /* New right margin in 2540ths */
                        new_top,        /* New top margin in 2540ths */
                        new_imageable,  /* New imageable length in 2540ths */
-                       new_borderless; /* New borderless state */
+                       new_borderless, /* New borderless state */
+                       new_known_pwg;  /* New PWG name is well-known */
   _pwg_size_t           *new_size;     /* New size to add, if any */
 
 
@@ -178,7 +180,8 @@ _pwgCreateWithPPD(ppd_file_t *ppd)  /* I - PPD file */
       * Standard name and no conflicts, use it!
       */
 
-      pwg_name = pwg_media->pwg;
+      pwg_name      = pwg_media->pwg;
+      new_known_pwg = 1;
     }
     else
     {
@@ -188,7 +191,8 @@ _pwgCreateWithPPD(ppd_file_t *ppd)  /* I - PPD file */
       *     pp_lowerppd_WIDTHxHEIGHTuu
       */
 
-      pwg_name = pwg_keyword;
+      pwg_name      = pwg_keyword;
+      new_known_pwg = 0;
 
       pwg_unppdize_name(ppd_size->name, ppd_name, sizeof(ppd_name));
       _pwgGenerateSize(pwg_keyword, sizeof(pwg_keyword), NULL, ppd_name,
@@ -208,8 +212,8 @@ _pwgCreateWithPPD(ppd_file_t *ppd)  /* I - PPD file */
     new_right      = _PWG_FROMPTS(ppd_size->width - ppd_size->right);
     new_top        = _PWG_FROMPTS(ppd_size->length - ppd_size->top);
     new_imageable  = new_length - new_top - new_bottom;
-    new_borderless = (new_bottom == 0 && new_top == 0) ||
-                     (new_left == 0 && new_right == 0);
+    new_borderless = new_bottom == 0 && new_top == 0 &&
+                     new_left == 0 && new_right == 0;
 
     for (k = pwg->num_sizes, similar = 0, old_size = pwg->sizes, new_size = NULL;
          k > 0 && !similar;
@@ -218,16 +222,20 @@ _pwgCreateWithPPD(ppd_file_t *ppd)        /* I - PPD file */
       old_imageable  = old_size->length - old_size->top - old_size->bottom;
       old_borderless = old_size->left == 0 && old_size->bottom == 0 &&
                       old_size->right == 0 && old_size->top == 0;
-
+      old_known_pwg  = strncmp(old_size->map.pwg, "oe_", 3) &&
+                      strncmp(old_size->map.pwg, "om_", 3);
+               
       similar = old_borderless == new_borderless &&
                 _PWG_EQUIVALENT(old_size->width, new_width) &&
                _PWG_EQUIVALENT(old_size->length, new_length);
 
-      if (similar && new_imageable > old_imageable)
+      if (similar && 
+          (new_known_pwg || (!old_known_pwg && new_imageable > old_imageable)))
       {
        /*
-       * The new paper has a larger imageable area so it will replace
-       * the older paper.
+       * The new paper has a larger imageable area so it could replace
+       * the older paper.  Regardless of the imageable area, we always
+       * prefer the size with a well-known PWG name.
        */
 
        new_size = old_size;
index 8b7a329415dbab186a2824a30fade7c07ca09271..df2c0137cfe2f9a15438cd6a94915c6a53b8d053 100644 (file)
@@ -803,6 +803,7 @@ cupsWriteRequestData(
     if ((http = cg->http) == NULL)
     {
       _cupsSetError(IPP_INTERNAL_ERROR, _("No active connection"), 1);
+      DEBUG_puts("1cupsWriteRequestData: Returning HTTP_ERROR.");
       return (HTTP_ERROR);
     }
   }
@@ -814,7 +815,11 @@ cupsWriteRequestData(
   wused = http->wused;
 
   if (httpWrite2(http, buffer, length) < 0)
+  {
+    DEBUG_puts("1cupsWriteRequestData: Returning HTTP_ERROR.");
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(http->error), 0);
     return (HTTP_ERROR);
+  }
 
  /*
   * Finally, check if we have any pending data from the server...
@@ -833,12 +838,17 @@ cupsWriteRequestData(
       http_status_t    status;         /* Status from httpUpdate */
 
       if ((status = httpUpdate(http)) >= HTTP_BAD_REQUEST)
+      {
+        _cupsSetHTTPError(status);
         httpFlush(http);
+      }
 
+      DEBUG_printf(("1cupsWriteRequestData: Returning %d.\n", status));
       return (status);
     }
   }
 
+  DEBUG_puts("1cupsWriteRequestData: Returning HTTP_CONTINUE.");
   return (HTTP_CONTINUE);
 }
 
@@ -1004,6 +1014,10 @@ _cupsSetHTTPError(http_status_t status)  /* I - HTTP status code */
        _cupsSetError(IPP_PKI_ERROR, httpStatus(status), 0);
         break;
 
+    case HTTP_ERROR :
+       _cupsSetError(IPP_INTERNAL_ERROR, httpStatus(status), 0);
+        break;
+
     default :
        DEBUG_printf(("4_cupsSetHTTPError: HTTP error %d mapped to "
                      "IPP_SERVICE_UNAVAILABLE!", status));
index abee546c3b236ea54503103a5cbf3097b2978e99..20a38db2d9dc58e7264bb72ae25fe56a715a8901 100644 (file)
@@ -539,91 +539,45 @@ _cupsSetDefaults(void)
   cups_expiredcerts = getenv("CUPS_EXPIREDCERTS");
 
  /*
-  * Then, if needed, the .cups/client.conf or .cupsrc file in the home
-  * directory...
+  * Then, if needed, read the ~/.cups/client.conf or /etc/cups/client.conf
+  * files to get the default values...
   */
 
-  if ((cg->encryption == (http_encryption_t)-1 || !cg->server[0] ||
-       !cg->ipp_port) && (home = getenv("HOME")) != NULL)
-  {
-   /*
-    * Look for ~/.cups/client.conf...
-    */
-
-    snprintf(filename, sizeof(filename), "%s/.cups/client.conf", home);
-    if ((fp = cupsFileOpen(filename, "r")) != NULL)
-    {
-      cups_read_client_conf(fp, cg, cups_encryption, cups_server,
-                           cups_anyroot, cups_expiredroot,
-                           cups_expiredcerts);
-
-      cupsFileClose(fp);
-    }
-  }
-
   if (cg->encryption == (http_encryption_t)-1 || !cg->server[0] ||
       !cg->ipp_port)
   {
-   /*
-    * Look for CUPS_SERVERROOT/client.conf...
-    */
-
-    snprintf(filename, sizeof(filename), "%s/client.conf", cg->cups_serverroot);
-    if ((fp = cupsFileOpen(filename, "r")) != NULL)
+    if ((home = getenv("HOME")) != NULL)
     {
-      cups_read_client_conf(fp, cg, cups_encryption, cups_server,
-                           cups_anyroot, cups_expiredroot,
-                           cups_expiredcerts);
-      cupsFileClose(fp);
-    }
-  }
-
- /*
-  * If we still have things that aren't set, use the compiled in defaults...
-  */
+     /*
+      * Look for ~/.cups/client.conf...
+      */
 
-  if (cg->encryption == (http_encryption_t)-1)
-    cg->encryption = HTTP_ENCRYPT_IF_REQUESTED;
+      snprintf(filename, sizeof(filename), "%s/.cups/client.conf", home);
+      fp = cupsFileOpen(filename, "r");
+    }
+    else
+      fp = NULL;
 
-  if (!cg->server[0])
-  {
-    if (!cups_server)
+    if (!fp)
     {
-#ifdef CUPS_DEFAULT_DOMAINSOCKET
      /*
-      * If we are compiled with domain socket support, only use the
-      * domain socket if it exists and has the right permissions...
+      * Look for CUPS_SERVERROOT/client.conf...
       */
 
-      struct stat      sockinfo;       /* Domain socket information */
-
-      if (!stat(CUPS_DEFAULT_DOMAINSOCKET, &sockinfo) &&
-         (sockinfo.st_mode & S_IRWXO) == S_IRWXO)
-       cups_server = CUPS_DEFAULT_DOMAINSOCKET;
-      else
-#endif /* CUPS_DEFAULT_DOMAINSOCKET */
-      cups_server = "localhost";
+      snprintf(filename, sizeof(filename), "%s/client.conf",
+               cg->cups_serverroot);
+      fp = cupsFileOpen(filename, "r");
     }
 
-    cupsSetServer(cups_server);
-  }
-
-  if (!cg->ipp_port)
-  {
-    const char         *ipp_port;      /* IPP_PORT environment variable */
-    struct servent     *service;       /* Port number info */
-
+   /*
+    * Read the configuration file and apply any environment variables; both
+    * functions handle NULL cups_file_t pointers...
+    */
 
-    if ((ipp_port = getenv("IPP_PORT")) != NULL)
-    {
-      if ((cg->ipp_port = atoi(ipp_port)) <= 0)
-        cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
-    }
-    else if ((service = getservbyname("ipp", NULL)) == NULL ||
-             service->s_port <= 0)
-      cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
-    else
-      cg->ipp_port = ntohs(service->s_port);
+    cups_read_client_conf(fp, cg, cups_encryption, cups_server,
+                         cups_anyroot, cups_expiredroot,
+                         cups_expiredcerts);
+    cupsFileClose(fp);
   }
 }
 
@@ -738,6 +692,44 @@ cups_read_client_conf(
       cg->ipp_port = atoi(value);
   }
 
+  if (!cg->server[0])
+  {
+#ifdef CUPS_DEFAULT_DOMAINSOCKET
+   /*
+    * If we are compiled with domain socket support, only use the
+    * domain socket if it exists and has the right permissions...
+    */
+
+    struct stat        sockinfo;               /* Domain socket information */
+
+    if (!stat(CUPS_DEFAULT_DOMAINSOCKET, &sockinfo) &&
+       (sockinfo.st_mode & S_IRWXO) == S_IRWXO)
+      cups_server = CUPS_DEFAULT_DOMAINSOCKET;
+    else
+#endif /* CUPS_DEFAULT_DOMAINSOCKET */
+      cups_server = "localhost";
+
+    cupsSetServer(cups_server);
+  }
+
+  if (!cg->ipp_port)
+  {
+    const char         *ipp_port;      /* IPP_PORT environment variable */
+    struct servent     *service;       /* Port number info */
+
+
+    if ((ipp_port = getenv("IPP_PORT")) != NULL)
+    {
+      if ((cg->ipp_port = atoi(ipp_port)) <= 0)
+        cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
+    }
+    else if ((service = getservbyname("ipp", NULL)) == NULL ||
+             service->s_port <= 0)
+      cg->ipp_port = CUPS_DEFAULT_IPP_PORT;
+    else
+      cg->ipp_port = ntohs(service->s_port);
+  }
+
   if (cups_anyroot)
     cg->any_root = !strcasecmp(cups_anyroot, "yes") ||
                   !strcasecmp(cups_anyroot, "on")  ||
index cc11262fde403f4e599c95d9857f65879792768d..42ea2bee15c2918ca0a145015673741266f826da 100644 (file)
@@ -16,7 +16,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
index 8ec40856fe46c76c132dbbdcc772fd9b4d8ddae4..4d76d63327ba94bd69a111ae0ca2b1eeed68846d 100644 (file)
@@ -19,8 +19,11 @@ PRE {
 }
 
 PRE.command {
+  background: #f0f0f0;
+  border: dotted thin #7f7f7f;
   color: #7f0000;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.example {
index fec426de9b885b119bc68af96bf4ae8c3b82e3ed..2b47b3e13a1dc766d184abae3e51f91dfd994eff 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
@@ -394,6 +396,7 @@ div.contents ul.subcontents li {
 <li><a href="#cupsArrayLast" title="Get the last element in the array.">cupsArrayLast</a></li>
 <li><a href="#cupsArrayNew" title="Create a new array.">cupsArrayNew</a></li>
 <li><a href="#cupsArrayNew2" title="Create a new array with hash.">cupsArrayNew2</a></li>
+<li><a href="#cupsArrayNew3" title="Create a new array with hash and/or free function.">cupsArrayNew3</a></li>
 <li><a href="#cupsArrayNext" title="Get the next element in the array.">cupsArrayNext</a></li>
 <li><a href="#cupsArrayPrev" title="Get the previous element in the array.">cupsArrayPrev</a></li>
 <li><a href="#cupsArrayRemove" title="Remove an element from the array.">cupsArrayRemove</a></li>
@@ -402,6 +405,8 @@ div.contents ul.subcontents li {
 <li><a href="#cupsArrayUserData" title="Return the user data for an array.">cupsArrayUserData</a></li>
 </ul></li>
 <li><a href="#TYPES">Data Types</a><ul class="code">
+       <li><a href="#cups_acopy_func_t" title="Array element copy function">cups_acopy_func_t</a></li>
+       <li><a href="#cups_afree_func_t" title="Array element free function">cups_afree_func_t</a></li>
        <li><a href="#cups_ahash_func_t" title="Array hash function">cups_ahash_func_t</a></li>
        <li><a href="#cups_array_func_t" title="Array comparison function">cups_array_func_t</a></li>
        <li><a href="#cups_array_t" title="CUPS array type">cups_array_t</a></li>
@@ -439,8 +444,9 @@ 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> or
-<a href='#cupsArrayNew2'><code>cupsArrayNew2</code></a> functions. 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>
 
@@ -477,7 +483,7 @@ 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> *array = <a href='#cupsArrayNew2'>cupsArrayNew2</a>(compare_func, user_data, hash_func, HASH_SIZE);
+<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
@@ -488,6 +494,25 @@ element and is called whenever you look up an element in the array with
 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 &lt;cups/array.h&gt;
+
+#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.
@@ -536,8 +561,7 @@ example:</p>
 <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</em> - if necessary, you must allocate and free the
-elements yourself.</p>
+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>
 
@@ -848,6 +872,50 @@ like <code>strcmp</code> can be used for sorted string arrays.<br>
 The hash function (&quot;h&quot;) is used to implement cached lookups with the
 specified hash size (&quot;hsize&quot;).
 
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5&nbsp;</span><a name="cupsArrayNew3">cupsArrayNew3</a></h3>
+<p class="description">Create a new array with hash and/or free function.</p>
+<p class="code">
+<a href="#cups_array_t">cups_array_t</a> *cupsArrayNew3 (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_array_func_t">cups_array_func_t</a> f,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *d,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_ahash_func_t">cups_ahash_func_t</a> h,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int hsize,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_acopy_func_t">cups_acopy_func_t</a> cf,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_afree_func_t">cups_afree_func_t</a> ff<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>f</dt>
+<dd class="description">Comparison function or <code>NULL</code> for an unsorted array</dd>
+<dt>d</dt>
+<dd class="description">User data or <code>NULL</code></dd>
+<dt>h</dt>
+<dd class="description">Hash function or <code>NULL</code> for unhashed lookups</dd>
+<dt>hsize</dt>
+<dd class="description">Hash size (&gt;= 0)</dd>
+<dt>cf</dt>
+<dd class="description">Copy function</dd>
+<dt>ff</dt>
+<dd class="description">Free function</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Array</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">The comparison function (&quot;f&quot;) is used to create a sorted array. The function
+receives pointers to two elements and the user data pointer (&quot;d&quot;) - the user
+data pointer argument can safely be omitted when not required so functions
+like <code>strcmp</code> can be used for sorted string arrays.<br>
+<br>
+The hash function (&quot;h&quot;) is used to implement cached lookups with the
+specified hash size (&quot;hsize&quot;).<br>
+<br>
+The copy function (&quot;cf&quot;) is used to automatically copy/retain elements when
+added or the array is copied.<br>
+<br>
+The free function (&quot;cf&quot;) is used to automatically free/release elements when
+removed or the array is deleted.
+
 </p>
 <h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsArrayNext">cupsArrayNext</a></h3>
 <p class="description">Get the next element in the array.</p>
@@ -963,6 +1031,16 @@ void *cupsArrayUserData (<br>
 <h4 class="returnvalue">Return Value</h4>
 <p class="description">User data</p>
 <h2 class="title"><a name="TYPES">Data Types</a></h2>
+<h3 class="typedef"><a name="cups_acopy_func_t">cups_acopy_func_t</a></h3>
+<p class="description">Array element copy function</p>
+<p class="code">
+typedef void *(*cups_acopy_func_t)(void *element, void *data);
+</p>
+<h3 class="typedef"><a name="cups_afree_func_t">cups_afree_func_t</a></h3>
+<p class="description">Array element free function</p>
+<p class="code">
+typedef void (*cups_afree_func_t)(void *element, void *data);
+</p>
 <h3 class="typedef"><a name="cups_ahash_func_t">cups_ahash_func_t</a></h3>
 <p class="description">Array hash function</p>
 <p class="code">
index bdcd5c21f6ca24ef3a262f0bdd0311cc8535425a..a1b75197fa7ae1188f2b83db8e19083571278d4f 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
index d53d09f0f253f57a7ab9c08aa52b295254655f6b..796248bba01fef03eb4f8a230fe59090414c523b 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
@@ -428,8 +430,6 @@ for the given language.">cupsLangEncoding</a></li>
 <li><a href="#cupsLangFlush" title="Flush all language data out of the cache.">cupsLangFlush</a></li>
 <li><a href="#cupsLangFree" title="Free language data.">cupsLangFree</a></li>
 <li><a href="#cupsLangGet" title="Get a language.">cupsLangGet</a></li>
-<li><a href="#cupsLastError" title="Return the last IPP status code.">cupsLastError</a></li>
-<li><a href="#cupsLastErrorString" title="Return the last IPP status-message.">cupsLastErrorString</a></li>
 <li><a href="#cupsNotifySubject" title="Return the subject for the given notification message.">cupsNotifySubject</a></li>
 <li><a href="#cupsNotifyText" title="Return the text for the given notification message.">cupsNotifyText</a></li>
 <li><a href="#cupsParseOptions" title="Parse options from a command-line argument.">cupsParseOptions</a></li>
@@ -443,6 +443,9 @@ specified server.">cupsPrintFiles2</a></li>
 <li><a href="#cupsRemoveDest" title="Remove a destination from the destination list.">cupsRemoveDest</a></li>
 <li><a href="#cupsRemoveOption" title="Remove an option from an option array.">cupsRemoveOption</a></li>
 <li><a href="#cupsServer" title="Return the hostname/address of the current server.">cupsServer</a></li>
+<li><a href="#cupsSetClientCertCB" title="Set the client certificate callback.">cupsSetClientCertCB</a></li>
+<li><a href="#cupsSetCredentials" title="Set the default credentials to be used for SSL/TLS
+connections.">cupsSetCredentials</a></li>
 <li><a href="#cupsSetDefaultDest" title="Set the default destination.">cupsSetDefaultDest</a></li>
 <li><a href="#cupsSetDests" title="Save the list of destinations for the default server.">cupsSetDests</a></li>
 <li><a href="#cupsSetDests2" title="Save the list of destinations for the specified server.">cupsSetDests2</a></li>
@@ -450,6 +453,7 @@ specified server.">cupsPrintFiles2</a></li>
 <li><a href="#cupsSetPasswordCB" title="Set the password callback for CUPS.">cupsSetPasswordCB</a></li>
 <li><a href="#cupsSetPasswordCB2" title="Set the advanced password callback for CUPS.">cupsSetPasswordCB2</a></li>
 <li><a href="#cupsSetServer" title="Set the default server name and port.">cupsSetServer</a></li>
+<li><a href="#cupsSetServerCertCB" title="Set the server certificate callback.">cupsSetServerCertCB</a></li>
 <li><a href="#cupsSetUser" title="Set the default user name.">cupsSetUser</a></li>
 <li><a href="#cupsStartDocument" title="Add a document to a job created with cupsCreateJob().">cupsStartDocument</a></li>
 <li><a href="#cupsTempFd" title="Creates a temporary file.">cupsTempFd</a></li>
@@ -458,6 +462,7 @@ specified server.">cupsPrintFiles2</a></li>
 <li><a href="#cupsUser" title="Return the current user's name.">cupsUser</a></li>
 </ul></li>
 <li><a href="#TYPES">Data Types</a><ul class="code">
+       <li><a href="#cups_client_cert_cb_t" title="Client credentials callback ">cups_client_cert_cb_t</a></li>
        <li><a href="#cups_dest_t" title="Destination">cups_dest_t</a></li>
        <li><a href="#cups_device_cb_t" title="Device callback ">cups_device_cb_t</a></li>
        <li><a href="#cups_job_t" title="Job">cups_job_t</a></li>
@@ -465,6 +470,7 @@ specified server.">cupsPrintFiles2</a></li>
        <li><a href="#cups_password_cb2_t" title="New password callback ">cups_password_cb2_t</a></li>
        <li><a href="#cups_password_cb_t" title="Password callback">cups_password_cb_t</a></li>
        <li><a href="#cups_ptype_t" title="Printer type/capability bits">cups_ptype_t</a></li>
+       <li><a href="#cups_server_cert_cb_t" title="Server credentials callback ">cups_server_cert_cb_t</a></li>
 </ul></li>
 <li><a href="#STRUCTURES">Structures</a><ul class="code">
        <li><a href="#cups_dest_s" title="Destination">cups_dest_s</a></li>
@@ -1716,18 +1722,6 @@ cups_lang_t *cupsLangGet (<br>
 </dl>
 <h4 class="returnvalue">Return Value</h4>
 <p class="description">Language data</p>
-<h3 class="function"><a name="cupsLastError">cupsLastError</a></h3>
-<p class="description">Return the last IPP status code.</p>
-<p class="code">
-ipp_status_t cupsLastError (void);</p>
-<h4 class="returnvalue">Return Value</h4>
-<p class="description">IPP status code from last request</p>
-<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsLastErrorString">cupsLastErrorString</a></h3>
-<p class="description">Return the last IPP status-message.</p>
-<p class="code">
-const char *cupsLastErrorString (void);</p>
-<h4 class="returnvalue">Return Value</h4>
-<p class="description">status-message text from last request</p>
 <h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsNotifySubject">cupsNotifySubject</a></h3>
 <p class="description">Return the subject for the given notification message.</p>
 <p class="code">
@@ -1975,6 +1969,48 @@ Note: The current server is tracked separately for each thread in a program.
 Multi-threaded programs that override the server via the
 <a href="#cupsSetServer"><code>cupsSetServer</code></a> function need to do so in each thread for the same
 server to be used.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5&nbsp;</span><a name="cupsSetClientCertCB">cupsSetClientCertCB</a></h3>
+<p class="description">Set the client certificate callback.</p>
+<p class="code">
+void cupsSetClientCertCB (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_client_cert_cb_t">cups_client_cert_cb_t</a> cb,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *user_data<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cb</dt>
+<dd class="description">Callback function</dd>
+<dt>user_data</dt>
+<dd class="description">User data pointer</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Pass <code>NULL</code> to restore the default callback.<br>
+<br>
+Note: The current certificate 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.
+
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5&nbsp;</span><a name="cupsSetCredentials">cupsSetCredentials</a></h3>
+<p class="description">Set the default credentials to be used for SSL/TLS
+connections.</p>
+<p class="code">
+int cupsSetCredentials (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_array_t *credentials<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>credentials</dt>
+<dd class="description">Array of credentials</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of call (0 = success)</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Note: The default credentials are tracked separately for each thread in a
+program. Multi-threaded programs that override the setting need to do so in
+each thread for the same setting to be used.
+
+</p>
 <h3 class="function"><span class="info">&nbsp;CUPS 1.3/Mac OS X 10.5&nbsp;</span><a name="cupsSetDefaultDest">cupsSetDefaultDest</a></h3>
 <p class="description">Set the default destination.</p>
 <p class="code">
@@ -2122,6 +2158,28 @@ default server name and port.<br>
 Note: The current server is tracked separately for each thread in a program.
 Multi-threaded programs that override the server need to do so in each
 thread for the same server to be used.</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5&nbsp;</span><a name="cupsSetServerCertCB">cupsSetServerCertCB</a></h3>
+<p class="description">Set the server certificate callback.</p>
+<p class="code">
+void cupsSetServerCertCB (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#cups_server_cert_cb_t">cups_server_cert_cb_t</a> cb,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *user_data<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>cb</dt>
+<dd class="description">Callback function</dd>
+<dt>user_data</dt>
+<dd class="description">User data pointer</dd>
+</dl>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Pass <code>NULL</code> to restore the default callback.<br>
+<br>
+Note: The current credentials 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.
+
+</p>
 <h3 class="function"><a name="cupsSetUser">cupsSetUser</a></h3>
 <p class="description">Set the default user name.</p>
 <p class="code">
@@ -2251,6 +2309,11 @@ program. Multi-threaded programs that override the user name with the
 <a href="#cupsSetUser"><code>cupsSetUser</code></a> function need to do so in each thread for the same user
 name to be used.</p>
 <h2 class="title"><a name="TYPES">Data Types</a></h2>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.5&nbsp;</span><a name="cups_client_cert_cb_t">cups_client_cert_cb_t</a></h3>
+<p class="description">Client credentials callback </p>
+<p class="code">
+typedef int (*cups_client_cert_cb_t)(http_t *http, void *tls, cups_array_t *distinguished_names, void *user_data);
+</p>
 <h3 class="typedef"><a name="cups_dest_t">cups_dest_t</a></h3>
 <p class="description">Destination</p>
 <p class="code">
@@ -2286,6 +2349,11 @@ typedef const char *(*cups_password_cb_t)(const char *prompt);
 <p class="code">
 typedef unsigned cups_ptype_t;
 </p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.5&nbsp;</span><a name="cups_server_cert_cb_t">cups_server_cert_cb_t</a></h3>
+<p class="description">Server credentials callback </p>
+<p class="code">
+typedef int (*cups_server_cert_cb_t)(http_t *http, void *tls, cups_array_t *certs, void *user_data);
+</p>
 <h2 class="title"><a name="STRUCTURES">Structures</a></h2>
 <h3 class="struct"><a name="cups_dest_s">cups_dest_s</a></h3>
 <p class="description">Destination</p>
index 4f221310bdf60edd609aa8e9f21a646ee4a1b87a..2f456ea0c2c7a9585191820d185c2e5e92a3025a 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
index 7f4dd9473b774772c889c7cba149b7021b4c81ba..d798578345eccb07184ba7a26dcc6bf87a5a1282 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
index 568aa07b87700cba77d9b20b7faf56b49aa3a059..48ed8dcb48056ee4c04f49dade80fa87fbfa7d01 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
@@ -375,7 +377,7 @@ div.contents ul.subcontents li {
        Programming: <a href='api-raster.html' target='_top'>Raster API</a><br>
        Programming: <a href='postscript-driver.html' target='_top'>Developing PostScript Printer Drivers</a><br>
        Programming: <a href='raster-driver.html' target='_top'>Developing Raster Printer Drivers</a><br>
-       Specifications: <a href='spec-design' target='_top'>CUPS Design Description</a></td>
+       Specifications: <a href='spec-design.html' target='_top'>CUPS Design Description</a></td>
 </tr>
 </tbody>
 </table></div>
index 6753a8d923e9ff6a96785a75398231e75f670a5c..98878ddaba3b310a0d6c22dd53fa69d5279914f4 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
@@ -393,11 +395,14 @@ div.contents ul.subcontents li {
 <li><a href="#cupsGetFd" title="Get a file from the server.">cupsGetFd</a></li>
 <li><a href="#cupsGetFile" title="Get a file from the server.">cupsGetFile</a></li>
 <li><a href="#cupsGetResponse" title="Get a response to an IPP request.">cupsGetResponse</a></li>
+<li><a href="#cupsLastError" title="Return the last IPP status code.">cupsLastError</a></li>
+<li><a href="#cupsLastErrorString" title="Return the last IPP status-message.">cupsLastErrorString</a></li>
 <li><a href="#cupsPutFd" title="Put a file on the server.">cupsPutFd</a></li>
 <li><a href="#cupsPutFile" title="Put a file on the server.">cupsPutFile</a></li>
 <li><a href="#cupsReadResponseData" title="Read additional data after the IPP response.">cupsReadResponseData</a></li>
 <li><a href="#cupsSendRequest" title="Send an IPP request.">cupsSendRequest</a></li>
 <li><a href="#cupsWriteRequestData" title="Write additional data after an IPP request.">cupsWriteRequestData</a></li>
+<li><a href="#httpAddCredential" title="Allocates and adds a single credential to an array.">httpAddCredential</a></li>
 <li><a href="#httpAddrAny" title="Check for the &quot;any&quot; address.">httpAddrAny</a></li>
 <li><a href="#httpAddrEqual" title="Compare two addresses.">httpAddrEqual</a></li>
 <li><a href="#httpAddrLength" title="Return the length of the address in bytes.">httpAddrLength</a></li>
@@ -412,9 +417,11 @@ components with a formatted resource.">httpAssembleURIf</a></li>
 <li><a href="#httpCheck" title="Check to see if there is a pending response from the server.">httpCheck</a></li>
 <li><a href="#httpClearCookie" title="Clear the cookie value(s).">httpClearCookie</a></li>
 <li><a href="#httpClearFields" title="Clear HTTP request fields.">httpClearFields</a></li>
-<li><a href="#httpClose" title="Close an HTTP connection...">httpClose</a></li>
+<li><a href="#httpClose" title="Close an HTTP connection.">httpClose</a></li>
 <li><a href="#httpConnect" title="Connect to a HTTP server.">httpConnect</a></li>
 <li><a href="#httpConnectEncrypt" title="Connect to a HTTP server using encryption.">httpConnectEncrypt</a></li>
+<li><a href="#httpCopyCredentials" title="Copy the credentials associated with an encrypted
+connection.">httpCopyCredentials</a></li>
 <li><a href="#httpDecode64" title="Base64-decode a string.">httpDecode64</a></li>
 <li><a href="#httpDecode64_2" title="Base64-decode a string.">httpDecode64_2</a></li>
 <li><a href="#httpDelete" title="Send a DELETE request to the server.">httpDelete</a></li>
@@ -424,6 +431,7 @@ components with a formatted resource.">httpAssembleURIf</a></li>
 <li><a href="#httpError" title="Get the last error on a connection.">httpError</a></li>
 <li><a href="#httpFlush" title="Flush data from a HTTP connection.">httpFlush</a></li>
 <li><a href="#httpFlushWrite" title="Flush data in write buffer.">httpFlushWrite</a></li>
+<li><a href="#httpFreeCredentials" title="Free an array of credentials.">httpFreeCredentials</a></li>
 <li><a href="#httpGet" title="Send a GET request to the server.">httpGet</a></li>
 <li><a href="#httpGetAuthString" title="Get the current authorization string.">httpGetAuthString</a></li>
 <li><a href="#httpGetBlocking" title="Get the blocking/non-block state of a connection.">httpGetBlocking</a></li>
@@ -465,7 +473,9 @@ components.">httpSeparate2</a></li>
 <li><a href="#httpSeparateURI" title="Separate a Universal Resource Identifier into its
 components.">httpSeparateURI</a></li>
 <li><a href="#httpSetAuthString" title="Set the current authorization string.">httpSetAuthString</a></li>
-<li><a href="#httpSetCookie" title="Set the cookie value(s)...">httpSetCookie</a></li>
+<li><a href="#httpSetCookie" title="Set the cookie value(s).">httpSetCookie</a></li>
+<li><a href="#httpSetCredentials" title="Set the credentials associated with an encrypted
+connection.">httpSetCredentials</a></li>
 <li><a href="#httpSetExpect" title="Set the Expect: header in a request.">httpSetExpect</a></li>
 <li><a href="#httpSetField" title="Set the value of an HTTP header.">httpSetField</a></li>
 <li><a href="#httpSetLength" title="Set the content-length and content-encoding.">httpSetLength</a></li>
@@ -525,6 +535,7 @@ used to enumerate all of the
 addresses that are associated
 with a hostname. ">http_addrlist_t</a></li>
        <li><a href="#http_auth_t" title="HTTP authentication types">http_auth_t</a></li>
+       <li><a href="#http_credential_t" title="Credential data ">http_credential_t</a></li>
        <li><a href="#http_encoding_t" title="HTTP transfer encoding values">http_encoding_t</a></li>
        <li><a href="#http_encryption_t" title="HTTP encryption values">http_encryption_t</a></li>
        <li><a href="#http_field_t" title="HTTP field names">http_field_t</a></li>
@@ -557,6 +568,7 @@ are server-oriented...">http_state_t</a></li>
 used to enumerate all of the
 addresses that are associated
 with a hostname. ">http_addrlist_s</a></li>
+       <li><a href="#http_credential_s" title="Credential data ">http_credential_s</a></li>
        <li><a href="#ipp_attribute_s" title="Attribute">ipp_attribute_s</a></li>
        <li><a href="#ipp_s" title="IPP Request/Response/Notification">ipp_s</a></li>
 </ul></li>
@@ -1172,6 +1184,18 @@ cupsSendDocument() or cupsSendRequest(). For requests that return
 additional data, use httpRead() after getting a successful response.
 
 </p>
+<h3 class="function"><a name="cupsLastError">cupsLastError</a></h3>
+<p class="description">Return the last IPP status code.</p>
+<p class="code">
+ipp_status_t cupsLastError (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">IPP status code from last request</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="cupsLastErrorString">cupsLastErrorString</a></h3>
+<p class="description">Return the last IPP status-message.</p>
+<p class="code">
+const char *cupsLastErrorString (void);</p>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">status-message text from last request</p>
 <h3 class="function"><span class="info">&nbsp;CUPS 1.1.20/Mac OS X 10.4&nbsp;</span><a name="cupsPutFd">cupsPutFd</a></h3>
 <p class="description">Put a file on the server.</p>
 <p class="code">
@@ -1269,7 +1293,7 @@ files for CUPS_GET_PPD and CUPS_GET_DOCUMENT requests, respectively.
 <h4 class="discussion">Discussion</h4>
 <p class="discussion">Use httpWrite() to write any additional data (document, PPD file, etc.)
 for the request, cupsGetResponse() to get the IPP response, and httpRead()
-to read any additional data following the response. Only one request can be 
+to read any additional data following the response. Only one request can be
 sent/queued at a time.<br>
 <br>
 Unlike cupsDoFileRequest(), cupsDoIORequest(), and cupsDoRequest(), the
@@ -1299,6 +1323,29 @@ request is not freed.
 <p class="discussion">This function is used after <a href="#cupsSendRequest"><code>cupsSendRequest</code></a> to provide a PPD and
 after <a href="#cupsStartDocument"><code>cupsStartDocument</code></a> to provide a document file.
 
+</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5&nbsp;</span><a name="httpAddCredential">httpAddCredential</a></h3>
+<p class="description">Allocates and adds a single credential to an array.</p>
+<p class="code">
+int httpAddCredential (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_array_t *credentials,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;const void *data,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t datalen<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>credentials</dt>
+<dd class="description">Credentials array</dd>
+<dt>data</dt>
+<dd class="description">PEM-encoded X.509 data</dd>
+<dt>datalen</dt>
+<dd class="description">Length of data</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">0 on success, -1 on error</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">Use <code>cupsArrayNew(NULL, NULL)</code> to create a credentials array.
+
 </p>
 <h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpAddrAny">httpAddrAny</a></h3>
 <p class="description">Check for the &quot;any&quot; address.</p>
@@ -1531,7 +1578,7 @@ void httpClearFields (<br>
 <dd class="description">Connection to server</dd>
 </dl>
 <h3 class="function"><a name="httpClose">httpClose</a></h3>
-<p class="description">Close an HTTP connection...</p>
+<p class="description">Close an HTTP connection.</p>
 <p class="code">
 void httpClose (<br>
 &nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http<br>
@@ -1580,6 +1627,23 @@ void httpClose (<br>
 </dl>
 <h4 class="returnvalue">Return Value</h4>
 <p class="description">New HTTP connection</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5&nbsp;</span><a name="httpCopyCredentials">httpCopyCredentials</a></h3>
+<p class="description">Copy the credentials associated with an encrypted
+connection.</p>
+<p class="code">
+int httpCopyCredentials (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_array_t **credentials<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>credentials</dt>
+<dd class="description">Array of credentials</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of call (0 = success)</p>
 <h3 class="function"><span class="info">&nbsp;DEPRECATED&nbsp;</span><a name="httpDecode64">httpDecode64</a></h3>
 <p class="description">Base64-decode a string.</p>
 <p class="code">
@@ -1732,6 +1796,17 @@ int httpFlushWrite (<br>
 </dl>
 <h4 class="returnvalue">Return Value</h4>
 <p class="description">Bytes written or -1 on error</p>
+<h3 class="function"><a name="httpFreeCredentials">httpFreeCredentials</a></h3>
+<p class="description">Free an array of credentials.</p>
+<p class="code">
+void httpFreeCredentials (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_array_t *credentials<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>credentials</dt>
+<dd class="description">Array of credentials</dd>
+</dl>
 <h3 class="function"><a name="httpGet">httpGet</a></h3>
 <p class="description">Send a GET request to the server.</p>
 <p class="code">
@@ -2356,7 +2431,7 @@ httpHead(), httpOptions(), httpPost, or httpPut().
 
 </p>
 <h3 class="function"><span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span><a name="httpSetCookie">httpSetCookie</a></h3>
-<p class="description">Set the cookie value(s)...</p>
+<p class="description">Set the cookie value(s).</p>
 <p class="code">
 void httpSetCookie (<br>
 &nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
@@ -2369,6 +2444,23 @@ void httpSetCookie (<br>
 <dt>cookie</dt>
 <dd class="description">Cookie string</dd>
 </dl>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.5&nbsp;</span><a name="httpSetCredentials">httpSetCredentials</a></h3>
+<p class="description">Set the credentials associated with an encrypted
+connection.</p>
+<p class="code">
+int httpSetCredentials (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#http_t">http_t</a> *http,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;cups_array_t *credentials<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>http</dt>
+<dd class="description">Connection to server</dd>
+<dt>credentials</dt>
+<dd class="description">Array of credentials</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">Status of call (0 = success)</p>
 <h3 class="function"><span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span><a name="httpSetExpect">httpSetExpect</a></h3>
 <p class="description">Set the Expect: header in a request.</p>
 <p class="code">
@@ -3267,6 +3359,11 @@ typedef struct <a href="#http_addrlist_s">http_addrlist_s</a> / http_addrlist_t;
 <p class="code">
 typedef enum <a href="#http_auth_e">http_auth_e</a> http_auth_t;
 </p>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.5&nbsp;</span><a name="http_credential_t">http_credential_t</a></h3>
+<p class="description">Credential data </p>
+<p class="code">
+typedef struct <a href="#http_credential_s">http_credential_s</a> http_credential_t;
+</p>
 <h3 class="typedef"><a name="http_encoding_t">http_encoding_t</a></h3>
 <p class="description">HTTP transfer encoding values</p>
 <p class="code">
@@ -3308,7 +3405,7 @@ typedef struct _http_s http_t;
 <p class="code">
 typedef enum <a href="#http_uri_coding_e">http_uri_coding_e</a> http_uri_coding_t;
 </p>
-<h3 class="typedef"><span class="info">&nbsp;CUPS1.2&nbsp;</span><a name="http_uri_status_t">http_uri_status_t</a></h3>
+<h3 class="typedef"><span class="info">&nbsp;CUPS 1.2&nbsp;</span><a name="http_uri_status_t">http_uri_status_t</a></h3>
 <p class="description">URI separation status </p>
 <p class="code">
 typedef enum <a href="#http_uri_status_e">http_uri_status_e</a> http_uri_status_t;
@@ -3410,6 +3507,19 @@ with a hostname. </p>
 <dt>next </dt>
 <dd class="description">Pointer to next address in list</dd>
 </dl>
+<h3 class="struct"><span class="info">&nbsp;CUPS 1.5&nbsp;</span><a name="http_credential_s">http_credential_s</a></h3>
+<p class="description">Credential data </p>
+<p class="code">struct http_credential_s {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void *data;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;size_t datalen;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>data </dt>
+<dd class="description">Pointer to credential data</dd>
+<dt>datalen </dt>
+<dd class="description">Credential length</dd>
+</dl>
 <h3 class="struct"><a name="ipp_attribute_s">ipp_attribute_s</a></h3>
 <p class="description">Attribute</p>
 <p class="code">struct ipp_attribute_s {<br>
@@ -3460,8 +3570,8 @@ with a hostname. </p>
 <dd class="description">Request header</dd>
 <dt>state </dt>
 <dd class="description">State of request</dd>
-<dt>use </dt>
-<dd class="description">Use count</dd>
+<dt>use <span class="info">&nbsp;CUPS 1.4.4/Mac OS X 10.6.?&nbsp;</span></dt>
+<dd class="description">Use count </dd>
 </dl>
 <h2 class="title"><a name="UNIONS">Unions</a></h2>
 <h3 class="union"><a name="ipp_request_u">ipp_request_u</a></h3>
@@ -3646,8 +3756,8 @@ are server-oriented...</p>
 <dl>
 <dt>HTTP_ACCEPTED </dt>
 <dd class="description">DELETE command was successful</dd>
-<dt>HTTP_AUTHORIZATION_CANCELED </dt>
-<dd class="description">User cancelled authorization</dd>
+<dt>HTTP_AUTHORIZATION_CANCELED <span class="info">&nbsp;CUPS 1.4&nbsp;</span></dt>
+<dd class="description">User canceled authorization </dd>
 <dt>HTTP_BAD_GATEWAY </dt>
 <dd class="description">Bad gateway</dd>
 <dt>HTTP_BAD_REQUEST </dt>
@@ -3698,6 +3808,8 @@ are server-oriented...</p>
 <dd class="description">Only a partial file was recieved/sent</dd>
 <dt>HTTP_PAYMENT_REQUIRED </dt>
 <dd class="description">Payment required</dd>
+<dt>HTTP_PKI_ERROR <span class="info">&nbsp;CUPS 1.5&nbsp;</span></dt>
+<dd class="description">Error negotiating a secure connection </dd>
 <dt>HTTP_PRECONDITION </dt>
 <dd class="description">Precondition failed</dd>
 <dt>HTTP_PROXY_AUTHENTICATION </dt>
@@ -3748,7 +3860,7 @@ are server-oriented...</p>
 <dt>HTTP_URI_CODING_USERNAME </dt>
 <dd class="description">En/decode the username portion</dd>
 </dl>
-<h3 class="enumeration"><span class="info">&nbsp;CUPS1.2&nbsp;</span><a name="http_uri_status_e">http_uri_status_e</a></h3>
+<h3 class="enumeration"><span class="info">&nbsp;CUPS 1.2&nbsp;</span><a name="http_uri_status_e">http_uri_status_e</a></h3>
 <p class="description">URI separation status </p>
 <h4 class="constants">Constants</h4>
 <dl>
@@ -4032,6 +4144,8 @@ are server-oriented...</p>
 <dd class="description">client-error-attributes-or-values-not-supported</dd>
 <dt>IPP_ATTRIBUTES_NOT_SETTABLE </dt>
 <dd class="description">client-error-attributes-not-settable</dd>
+<dt>IPP_AUTHENTICATION_CANCELED <span class="info">&nbsp;CUPS 1.5&nbsp;</span></dt>
+<dd class="description">Authentication canceled by user </dd>
 <dt>IPP_BAD_REQUEST </dt>
 <dd class="description">client-error-bad-request</dd>
 <dt>IPP_CHARSET </dt>
@@ -4092,6 +4206,8 @@ are server-oriented...</p>
 <dd class="description">successful-ok-too-many-events</dd>
 <dt>IPP_OPERATION_NOT_SUPPORTED </dt>
 <dd class="description">server-error-operation-not-supported</dd>
+<dt>IPP_PKI_ERROR <span class="info">&nbsp;CUPS 1.5&nbsp;</span></dt>
+<dd class="description">Error negotiating a secure connection </dd>
 <dt>IPP_PRINTER_BUSY </dt>
 <dd class="description">server-error-busy</dd>
 <dt>IPP_PRINTER_IS_DEACTIVATED </dt>
@@ -4110,6 +4226,8 @@ are server-oriented...</p>
 <dd class="description">client-error-timeout</dd>
 <dt>IPP_TOO_MANY_SUBSCRIPTIONS </dt>
 <dd class="description">client-error-too-many-subscriptions</dd>
+<dt>IPP_UPGRADE_REQUIRED </dt>
+<dd class="description">TLS upgrade required</dd>
 <dt>IPP_URI_SCHEME </dt>
 <dd class="description">client-error-uri-scheme-not-supported</dd>
 <dt>IPP_VERSION_NOT_SUPPORTED </dt>
index 7b428490e3a8f65a7384225033d7e94d046edd2c..e904ddbd5ae163d24d9f7346226e0831d3c0ebaf 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
index a5eb498a23e43bdc90b55d98ae769e6670d4733a..bdd3f612bc64a214a2c98a18a60dfdab94a50719 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
index 6ac61beece0b928f2f1190b32799d720fc12bda1..c6d6077caa2631f424052f0c4fd02bd611ec13ae 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
@@ -1805,7 +1807,6 @@ typedef enum <a href="#ppd_ui_e">ppd_ui_e</a> ppd_ui_t;
 &nbsp;&nbsp;&nbsp;&nbsp;char *product;<br>
 &nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_profile_t">ppd_profile_t</a> *profiles;<br>
 &nbsp;&nbsp;&nbsp;&nbsp;char *protocols;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;void *pwg;<br>
 &nbsp;&nbsp;&nbsp;&nbsp;char *shortnickname;<br>
 &nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_size_t">ppd_size_t</a> *sizes;<br>
 &nbsp;&nbsp;&nbsp;&nbsp;int throughput;<br>
@@ -1888,8 +1889,6 @@ typedef enum <a href="#ppd_ui_e">ppd_ui_e</a> ppd_ui_t;
 <dd class="description">sRGB color profiles </dd>
 <dt>protocols <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
 <dd class="description">Protocols (BCP, TBCP) string </dd>
-<dt>pwg </dt>
-<dd class="description">PWG to/from PPD mappings</dd>
 <dt>shortnickname </dt>
 <dd class="description">Short version of nickname</dd>
 <dt>sizes </dt>
index d8bef72bb42496d390b512ce3c85842d30e3302b..e02f71d051c07860ff00b237e6a04c723d9b05bd 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
index 93c816b8805aba708ead167fd07be2336e8831ab..3d7875cdca9485cc50a36e5ece7f9bd1c26b7aba 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
@@ -340,9 +342,9 @@ div.contents ul.subcontents li {
 <!--
   "$Id$"
 
-  Raster API header for the Common UNIX Printing System (CUPS).
+  Raster API documentation for CUPS.
 
-  Copyright 2008-2009 by Apple Inc.
+  Copyright 2008-2010 by Apple Inc.
 
   These coded instructions, statements, and computer programs are the
   property of Apple Inc. and are protected by Federal copyright
@@ -1186,20 +1188,52 @@ factor not applied) </dd>
 <p class="description">cupsColorSpace attribute values</p>
 <h4 class="constants">Constants</h4>
 <dl>
+<dt>CUPS_CSPACE_ADOBERGB <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">Red, green, blue (Adobe RGB) </dd>
 <dt>CUPS_CSPACE_CIELab <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
 <dd class="description">CIE Lab </dd>
 <dt>CUPS_CSPACE_CIEXYZ <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
 <dd class="description">CIE XYZ </dd>
 <dt>CUPS_CSPACE_CMY </dt>
-<dd class="description">Cyan, magenta, yellow</dd>
+<dd class="description">Cyan, magenta, yellow (DeviceCMY)</dd>
 <dt>CUPS_CSPACE_CMYK </dt>
-<dd class="description">Cyan, magenta, yellow, black</dd>
-<dt>CUPS_CSPACE_GMCK </dt>
-<dd class="description">Gold, magenta, yellow, black</dd>
-<dt>CUPS_CSPACE_GMCS </dt>
-<dd class="description">Gold, magenta, yellow, silver</dd>
-<dt>CUPS_CSPACE_GOLD </dt>
-<dd class="description">Gold foil</dd>
+<dd class="description">Cyan, magenta, yellow, black (DeviceCMYK)</dd>
+<dt>CUPS_CSPACE_DEVICE1 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 1 color </dd>
+<dt>CUPS_CSPACE_DEVICE2 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 2 colors </dd>
+<dt>CUPS_CSPACE_DEVICE3 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 3 colors </dd>
+<dt>CUPS_CSPACE_DEVICE4 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 4 colors </dd>
+<dt>CUPS_CSPACE_DEVICE5 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 5 colors </dd>
+<dt>CUPS_CSPACE_DEVICE6 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 6 colors </dd>
+<dt>CUPS_CSPACE_DEVICE7 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 7 colors </dd>
+<dt>CUPS_CSPACE_DEVICE8 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 8 colors </dd>
+<dt>CUPS_CSPACE_DEVICE9 <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 9 colors </dd>
+<dt>CUPS_CSPACE_DEVICEA <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 10 colors </dd>
+<dt>CUPS_CSPACE_DEVICEB <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 11 colors </dd>
+<dt>CUPS_CSPACE_DEVICEC <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 12 colors </dd>
+<dt>CUPS_CSPACE_DEVICED <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 13 colors </dd>
+<dt>CUPS_CSPACE_DEVICEE <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 14 colors </dd>
+<dt>CUPS_CSPACE_DEVICEF <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">DeviceN, 15 colors </dd>
+<dt>CUPS_CSPACE_GMCK <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Gold, magenta, yellow, black </dd>
+<dt>CUPS_CSPACE_GMCS <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Gold, magenta, yellow, silver </dd>
+<dt>CUPS_CSPACE_GOLD <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Gold foil </dd>
 <dt>CUPS_CSPACE_ICC1 <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
 <dd class="description">ICC-based, 1 color </dd>
 <dt>CUPS_CSPACE_ICC2 <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
@@ -1231,28 +1265,31 @@ factor not applied) </dd>
 <dt>CUPS_CSPACE_ICCF <span class="info">&nbsp;CUPS 1.1.19/Mac OS X 10.3&nbsp;</span></dt>
 <dd class="description">ICC-based, 15 colors </dd>
 <dt>CUPS_CSPACE_K </dt>
-<dd class="description">Black</dd>
-<dt>CUPS_CSPACE_KCMY </dt>
-<dd class="description">Black, cyan, magenta, yellow</dd>
-<dt>CUPS_CSPACE_KCMYcm </dt>
-<dd class="description">Black, cyan, magenta, yellow, *
-light-cyan, light-magenta</dd>
+<dd class="description">Black (DeviceK)</dd>
+<dt>CUPS_CSPACE_KCMY <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Black, cyan, magenta, yellow </dd>
+<dt>CUPS_CSPACE_KCMYcm <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Black, cyan, magenta, yellow, light-cyan, light-magenta </dd>
 <dt>CUPS_CSPACE_RGB </dt>
-<dd class="description">Red, green, blue</dd>
+<dd class="description">Red, green, blue (DeviceRGB, sRGB by default)</dd>
 <dt>CUPS_CSPACE_RGBA </dt>
-<dd class="description">Red, green, blue, alpha</dd>
+<dd class="description">Red, green, blue, alpha (DeviceRGB, sRGB by default)</dd>
 <dt>CUPS_CSPACE_RGBW <span class="info">&nbsp;CUPS 1.2/Mac OS X 10.5&nbsp;</span></dt>
-<dd class="description">Red, green, blue, white </dd>
-<dt>CUPS_CSPACE_SILVER </dt>
-<dd class="description">Silver foil</dd>
+<dd class="description">Red, green, blue, white (DeviceRGB, sRGB by default) </dd>
+<dt>CUPS_CSPACE_SILVER <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Silver foil </dd>
+<dt>CUPS_CSPACE_SRGB <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">Red, green, blue (sRGB) </dd>
+<dt>CUPS_CSPACE_SW <span class="info">&nbsp;CUPS 1.4.5&nbsp;</span></dt>
+<dd class="description">Luminance (gamma 2.2) </dd>
 <dt>CUPS_CSPACE_W </dt>
-<dd class="description">Luminance</dd>
-<dt>CUPS_CSPACE_WHITE </dt>
-<dd class="description">White ink (as black)</dd>
-<dt>CUPS_CSPACE_YMC </dt>
-<dd class="description">Yellow, magenta, cyan</dd>
-<dt>CUPS_CSPACE_YMCK </dt>
-<dd class="description">Yellow, magenta, cyan, black</dd>
+<dd class="description">Luminance (DeviceGray, gamma 2.2 by default)</dd>
+<dt>CUPS_CSPACE_WHITE <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">White ink (as black) </dd>
+<dt>CUPS_CSPACE_YMC <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Yellow, magenta, cyan </dd>
+<dt>CUPS_CSPACE_YMCK <span class="info">&nbsp;DEPRECATED&nbsp;</span></dt>
+<dd class="description">Yellow, magenta, cyan, black </dd>
 </dl>
 <h3 class="enumeration"><a name="cups_cut_e">cups_cut_e</a></h3>
 <p class="description">CutMedia attribute values</p>
index 40a7db7aaab270d3500ce03ccc875e6d0ecd79ca..b74dc0364f6bbe9c92bd931a6017083c45002c3c 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
@@ -337,6 +339,21 @@ div.contents ul.subcontents li {
 </head>
 <body>
 <div class='body'>
+<!--
+  "$Id$"
+
+  PostScript printer driver documentation for CUPS.
+
+  Copyright 2007-2010 by Apple Inc.
+  Copyright 1997-2007 by Easy Software Products.
+
+  These coded instructions, statements, and computer programs are the
+  property of Apple Inc. and are protected by Federal copyright
+  law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+  which should have been included with this file.  If this file is
+  file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
 <h1 class='title'>Developing PostScript Printer Drivers</h1>
 
 <p>This document describes how to develop printer drivers for PostScript printers. Topics include: <a href='#BASICS'>printer driver basics</a>, <a href='#CREATE'>creating new PPD files</a>, <a href='#IMPORT'>importing existing PPD files</a>, <a href='#FILTERS'>using custom filters</a>, <a href='#COLOR'>implementing color management</a>, and <a href='#MACOSX'>adding Mac OS X features</a>.</p>
index c00d4dbdd6b0d8d62f504e62449a447810fc6950..9a40ca88e6b84e93919865595089adc3cef21cbb 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
@@ -337,6 +339,21 @@ div.contents ul.subcontents li {
 </head>
 <body>
 <div class='body'>
+<!--
+  "$Id$"
+
+  PPD compiler documentation for CUPS.
+
+  Copyright 2007-2010 by Apple Inc.
+  Copyright 1997-2007 by Easy Software Products.
+
+  These coded instructions, statements, and computer programs are the
+  property of Apple Inc. and are protected by Federal copyright
+  law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+  which should have been included with this file.  If this file is
+  file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
 <h1 class='title'>Introduction to the PPD Compiler</h1>
 
 <P>This document describes how to use the CUPS PostScript Printer Description
index fc85337c4a40683563becae218b1068565b9ec4a..40346a66acad8b031653370fb62672ffc206cfd3 100644 (file)
@@ -24,7 +24,9 @@ PRE {
 }
 
 PRE.command {
+  border: dotted thin #7f7f7f;
   margin-left: 36pt;
+  padding: 10px;
 }
 
 P.compact {
@@ -337,6 +339,21 @@ div.contents ul.subcontents li {
 </head>
 <body>
 <div class='body'>
+<!--
+  "$Id$"
+
+  Raster printer driver documentation for CUPS.
+
+  Copyright 2007-2010 by Apple Inc.
+  Copyright 1997-2007 by Easy Software Products.
+
+  These coded instructions, statements, and computer programs are the
+  property of Apple Inc. and are protected by Federal copyright
+  law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+  which should have been included with this file.  If this file is
+  file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
 <h1 class='title'>Developing Raster Printer Drivers</h1>
 
 <p>This document describes how to develop printer drivers for raster printers. Topics include: <a href='#BASICS'>printer driver basics</a>, <a href='#CREATE'>creating new PPD files</a>, <a href='#FILTERS'>using filters</a>, <a href='#COLOR'>implementing color management</a>, and <a href='#MACOSX'>adding Mac OS X features</a>.</p>
index a35ca4af6783b7fdbda3e04db3f7565771be76f7..d3610cb84f503a1bc0465e6bde73cec0a745e8fa 100644 (file)
@@ -1479,6 +1479,48 @@ the file is assumed to be relative to the <A
 HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory.</P>
 
 
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.5</SPAN><A NAME="JobPrivateAccess">JobPrivateAccess</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+JobPrivateAccess all
+JobPrivateAccess default
+JobPrivateAccess {user|@group|@ACL|@OWNER|@SYSTEM}+
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>JobPrivateAccess</CODE> directive specifies the access list for a
+job's private values. The "default" access list is "@OWNER @SYSTEM". "@ACL" maps
+to the printer's requesting-user-name-allowed or requesting-user-name-denied
+values.</P>
+
+<P>The <CODE>JobPrivateAccess</CODE> directive must appear inside a <A
+HREF="#Policy"><CODE>Policy</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.5</SPAN><A NAME="JobPrivateValues">JobPrivateValues</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+JobPrivateValues all
+JobPrivateValues default
+JobPrivateValues none
+JobPrivateValues attribute-name-1 [ ... attribute-name-N ]
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>JobPrivateValues</CODE> directive specifies the list of job values
+to make private. The "default" values are "job-name",
+"job-originating-host-name", and "job-originating-user-name".</P>
+
+<P>The <CODE>JobPrivateValues</CODE> directive must appear inside a <A
+HREF="#Policy"><CODE>Policy</CODE></A> section.</P>
+
+
 <H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2/Mac OS X 10.5</SPAN><A NAME="JobRetryInterval">JobRetryInterval</A></H2>
 
 <H3>Examples</H3>
@@ -2985,6 +3027,49 @@ on for secure connections. Multiple <CODE>SSLPort</CODE> lines
 can be specified to listen on multiple ports.</P>
 
 
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.5</SPAN><A NAME="SubscriptionPrivateAccess">SubscriptionPrivateAccess</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+SubscriptionPrivateAccess all
+SubscriptionPrivateAccess default
+SubscriptionPrivateAccess {user|@group|@ACL|@OWNER|@SYSTEM}+
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>SubscriptionPrivateAccess</CODE> directive specifies the access list for a
+subscription's private values. The "default" access list is "@OWNER @SYSTEM".
+"@ACL" maps to the printer's requesting-user-name-allowed or
+requesting-user-name-denied values.</P>
+
+<P>The <CODE>SubscriptionPrivateAccess</CODE> directive must appear inside a <A
+HREF="#Policy"><CODE>Policy</CODE></A> section.</P>
+
+
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.5</SPAN><A NAME="SubscriptionPrivateValues">SubscriptionPrivateValues</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+SubscriptionPrivateValues all
+SubscriptionPrivateValues default
+SubscriptionPrivateValues none
+SubscriptionPrivateValues attribute-name-1 [ ... attribute-name-N ]
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>SubscriptionPrivateValues</CODE> directive specifies the list of
+subscription values to make private. The "default" values are "notify-events",
+"notify-pull-method", "notify-recipient-uri", "notify-subscriber-user-name", and
+"notify-user-data".</P>
+
+<P>The <CODE>SubscriptionPrivateValues</CODE> directive must appear inside a <A
+HREF="#Policy"><CODE>Policy</CODE></A> section.</P>
+
+
 <H2 CLASS="title"><A NAME="SystemGroup">SystemGroup</A></H2>
 
 <H3>Examples</H3>
index 3c81a763c08230621ca27a34aa502f9b1d75453a..1343d71f2fe82c1f8c889e0e4bd1c4e99d320993 100644 (file)
 <html>
 <!-- SECTION: Specifications -->
 <head>
-       <title>CUPS PPD Extensions</title>
-       <meta name='keywords' content='Programming, PostScript Printer Description'>
-       <link rel='stylesheet' type='text/css' href='../cups-printable.css'>
+<title>CUPS PPD Extensions</title>
+<meta name="keywords" content="Specifications">
+<meta name="creator" content="Mini-XML v2.6">
+<style type="text/css"><!--
+BODY {
+  font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+H1, H2, H3, H4, H5, H6, P, TD, TH {
+  font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+KBD {
+  font-family: monaco, courier, monospace;
+  font-weight: bold;
+}
+
+PRE {
+  font-family: monaco, courier, monospace;
+}
+
+PRE.command {
+  border: dotted thin #7f7f7f;
+  margin-left: 36pt;
+  padding: 10px;
+}
+
+P.compact {
+  margin: 0;
+}
+
+P.example {
+  font-style: italic;
+  margin-left: 36pt;
+}
+  
+PRE.example {
+  background: #eeeeee;
+  border: dotted thin #999999;
+  margin-left: 36pt;
+  padding: 10pt;
+}
+
+PRE.command EM, PRE.example EM {
+  font-family: lucida grande, geneva, helvetica, arial, sans-serif;
+}
+
+P.command {
+  font-family: monaco, courier, monospace;
+  margin-left: 36pt;
+}
+
+P.formula {
+  font-style: italic;
+  margin-left: 36pt;
+}
+
+BLOCKQUOTE {
+  background: #eeeeee;
+  border: solid thin #999999;
+  padding: 10pt;
+}
+
+A IMG {
+  border: none;
+}
+
+A:link:hover IMG {
+  background: #f0f0f0;
+  border-radius: 10px;
+  -moz-border-radius: 10px;
+}
+
+A:link, A:visited {
+  font-weight: normal;
+  text-decoration: none;
+}
+
+A:link:hover, A:visited:hover, A:active {
+  text-decoration: underline;
+}
+
+SUB, SUP {
+  font-size: 50%;
+}
+
+TR.data, TD.data, TR.data TD {
+  margin-top: 10pt;
+  padding: 5pt;
+  border-bottom: solid 1pt #999999;
+}
+
+TR.data TH {
+  border-bottom: solid 1pt #999999;
+  padding-top: 10pt;
+  padding-left: 5pt;
+  text-align: left;
+}
+
+DIV.table TABLE {
+  border: solid thin #999999;
+  border-collapse: collapse;
+  border-spacing: 0;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+DIV.table CAPTION {
+  caption-side: top;
+  font-size: 120%;
+  font-style: italic;
+  font-weight: bold;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+DIV.table TABLE TD {
+  border: solid thin #cccccc;
+  padding-top: 5pt;
+}
+
+DIV.table TABLE TH {
+  background: #cccccc;
+  border: none;
+  border-bottom: solid thin #999999;
+}
+
+DIV.figure TABLE {
+  margin-left: auto;
+  margin-right: auto;
+}
+
+DIV.figure CAPTION {
+  caption-side: bottom;
+  font-size: 120%;
+  font-style: italic;
+  font-weight: bold;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+TH.label {
+  text-align: right;
+  vertical-align: top;
+}
+
+TH.sublabel {
+  text-align: right;
+  font-weight: normal;
+}
+
+HR {
+  border: solid thin;
+}
+
+SPAN.info {
+  background: black;
+  border: thin solid black;
+  color: white;
+  font-size: 80%;
+  font-style: italic;
+  font-weight: bold;
+  white-space: nowrap;
+}
+
+H2 SPAN.info, H3 SPAN.info, H4 SPAN.info {
+  float: right;
+  font-size: 100%;
+}
+
+H1.title {
+}
+
+H2.title, H3.title {
+  border-bottom: solid 2pt #000000;
+}
+
+DIV.indent, TABLE.indent {
+  margin-top: 2em;
+  margin-left: auto;
+  margin-right: auto;
+  width: 90%;
+}
+
+TABLE.indent {
+  border-collapse: collapse;
+}
+
+TABLE.indent TD, TABLE.indent TH {
+  padding: 0;
+}
+
+TABLE.list {
+  border-collapse: collapse;
+  margin-left: auto;
+  margin-right: auto;
+  width: 90%;
+}
+
+TABLE.list TH {
+  background: white;
+  border-bottom: solid thin #cccccc;
+  color: #444444;
+  padding-top: 10pt;
+  padding-left: 5pt;
+  text-align: left;
+  vertical-align: bottom;
+  white-space: nowrap;
+}
+
+TABLE.list TH A {
+  color: #4444cc;
+}
+
+TABLE.list TD {
+  border-bottom: solid thin #eeeeee;
+  padding-top: 5pt;
+  padding-left: 5pt;
+}
+
+TABLE.list TR:nth-child(even) {
+  background: #f8f8f8;
+}
+
+TABLE.list TR:nth-child(odd) {
+  background: #f4f4f4;
+}
+
+DT {
+  margin-left: 36pt;
+  margin-top: 12pt;
+}
+
+DD {
+  margin-left: 54pt;
+}
+
+DL.category DT {
+  font-weight: bold;
+}
+
+P.summary {
+  margin-left: 36pt;
+  font-family: monaco, courier, monospace;
+}
+
+DIV.summary TABLE {
+  border: solid thin #999999;
+  border-collapse: collapse;
+  border-spacing: 0;
+  margin: 10px;
+}
+
+DIV.summary TABLE TD, DIV.summary TABLE TH {
+  border: solid thin #999999;
+  padding: 5px;
+  text-align: left;
+  vertical-align: top;
+}
+
+DIV.summary TABLE THEAD TH {
+  background: #eeeeee;
+}
+
+/* API documentation styles... */
+div.body h1 {
+  margin: 0;
+}
+div.body h2 {
+  margin-top: 1.5em;
+}
+div.body h3, div.body h4, div.body h5 {
+  margin-bottom: 0.5em;
+  margin-top: 1.5em;
+}
+.class, .enumeration, .function, .struct, .typedef, .union {
+  border-bottom: solid thin #999999;
+  margin-bottom: 0;
+  margin-top: 2em;
+}
+.description {
+  margin-top: 0.5em;
+}
+code, p.code, pre, ul.code li {
+  font-family: monaco, courier, monospace;
+  font-size: 90%;
+}
+ul.code, ul.contents, ul.subcontents {
+  list-style-type: none;
+  margin: 0;
+  padding-left: 0;
+}
+ul.code li {
+  margin: 0;
+}
+ul.contents > li {
+  margin-top: 1em;
+}
+ul.contents li ul.code, ul.contents li ul.subcontents {
+  padding-left: 2em;
+}
+div.body dl {
+  margin-left: 0;
+  margin-top: 0;
+}
+div.body dt {
+  font-style: italic;
+  margin-left: 0;
+  margin-top: 0;
+}
+div.body dd {
+  margin-bottom: 0.5em;
+}
+
+/* This is just for the HTML files generated with the framedhelp target */
+div.contents {
+  background: #e8e8e8;
+  border: solid thin black;
+  padding: 10px;
+}
+div.contents h1 {
+  font-size: 110%;
+}
+div.contents h2 {
+  font-size: 100%;
+}
+div.contents ul.contents {
+  font-size: 80%;
+}
+div.contents ul.subcontents li {
+  margin-left: 1em;
+  text-indent: -1em;
+}
+--></style>
 </head>
 <body>
+<div class='body'>
 <!--
-  "$Id: spec-ppd.html 7937 2008-09-11 16:16:41Z mike $"
+  "$Id: spec-ppd.html 9345 2010-10-26 23:46:51Z mike $"
 
-  CUPS PPD extensions specification for CUPS.
+  PPD extension documentation for CUPS.
 
   Copyright 2007-2010 by Apple Inc.
   Copyright 1997-2007 by Easy Software Products.
 
 <H1 CLASS="title">CUPS PPD Extensions</H1>
 
-<h2 class='title'><a name='INTRODUCTION'>Introduction</a></h2>
-
-<p>This specification describes the attributes and extensions
-that CUPS adds to <a
-href="http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf">
-Adobe TechNote #5003: PostScript Printer Description File Format
-Specification Version 4.3</a>. PostScript Printer Description
-("PPD") files describe the capabilities of each printer and are
-used by CUPS to support printer-specific features and intelligent
-filtering.</p>
+<p>This specification describes the attributes and extensions that CUPS adds to <a href="http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf" target="_blank">Adobe TechNote #5003: PostScript Printer Description File Format Specification Version 4.3</a>. PostScript Printer Description ("PPD") files describe the capabilities of each printer and are used by CUPS to support printer-specific features and intelligent filtering.</p>
 
+<div class='summary'><table summary='General Information'>
+<tbody>
+<tr>
+       <th>See Also</th>
+       <td>Programming: <a href='postscript-driver.html'>Developing PostScript Printer Drivers</a><br>
+       Programming: <a href='raster-driver.html'>Developing Raster Printer Drivers</a><br>
+       Programming: <a href='api-filter.html'>Filter and Backend Programming</a><br>
+       Programming: <a href='ppd-compiler.html'>Introduction to the PPD Compiler</a><br>
+       Programming: <a href='api-raster.html'>Raster API</a><br>
+       References: <a href='ref-ppdcfile.html'>PPD Compiler Driver Information File Reference</a></td>
+</tr>
+</tbody>
+</table></div>
+<h2 class="title">Contents</h2>
+<ul class="contents">
+<ul class="subcontents">
+<li><a href="#SYNTAX">PPD File Syntax</a></li>
+<li><a href="#AUTOCONFIG">Auto-Configuration</a><ul class="subcontents">
+<li><a href="#APAutoSetupTool">APAutoSetupTool</a></li>
+<li><a href="#QUERYKEYWORD">?MainKeyword</a></li>
+<li><a href="#OID">OIDMainKeyword</a></li>
+</ul></li>
+<li><a href="#PROFILES">Color Profiles</a><ul class="subcontents">
+<li><a href="#cupsColorProfile">cupsColorProfile</a></li>
+<li><a href="#cupsICCProfile">cupsICCProfile</a></li>
+<li><a href="#APCustom">Custom Color Matching Support</a></li>
+</ul></li>
+<li><a href="#CONSTRAINTS">Constraints</a><ul class="subcontents">
+<li><a href="#cupsUIConstraints">cupsUIConstraints</a></li>
+<li><a href="#cupsUIResolver">cupsUIResolver</a></li>
+</ul></li>
+<li><a href="#I18N">Globalized PPD Support</a></li>
+<li><a href="#OPTIONS">CUPS 1.3/Mac OS X 10.6Custom Options</a></li>
+<li><a href="#RASTERPS">Writing PostScript Option Commands for Raster Drivers</a></li>
+<li><a href="#MEDIA">Media Keywords</a><ul class="subcontents">
+<li><a href="#cupsMediaQualifier2">cupsMediaQualifier2</a></li>
+<li><a href="#cupsMediaQualifier3">cupsMediaQualifier3</a></li>
+<li><a href="#cupsMinSize">cupsMinSize</a></li>
+<li><a href="#cupsMaxSize">cupsMaxSize</a></li>
+</ul></li>
+<li><a href="#ATTRIBUTES">General Attributes</a><ul class="subcontents">
+<li><a href="#cupsBackSide">cupsBackSide</a></li>
+<li><a href="#cupsCommands">cupsCommands</a></li>
+<li><a href="#cupsEvenDuplex">cupsEvenDuplex</a></li>
+<li><a href="#cupsFax">cupsFax</a></li>
+<li><a href="#cupsFilter">cupsFilter</a></li>
+<li><a href="#cupsFlipDuplex">cupsFlipDuplex</a></li>
+<li><a href="#cupsIPPFinishings">cupsIPPFinishings</a></li>
+<li><a href="#cupsIPPReason">cupsIPPReason</a></li>
+<li><a href="#cupsLanguages">cupsLanguages</a></li>
+<li><a href="#cupsManualCopies">cupsManualCopies</a></li>
+<li><a href="#cupsMarkerName">cupsMarkerName</a></li>
+<li><a href="#cupsMarkerNotice">cupsMarkerNotice</a></li>
+<li><a href="#cupsModelNumber">cupsModelNumber</a></li>
+<li><a href="#cupsPJLCharset">cupsPJLCharset</a></li>
+<li><a href="#cupsPJLDisplay">cupsPJLDisplay</a></li>
+<li><a href="#cupsPortMonitor">cupsPortMonitor</a></li>
+<li><a href="#cupsPreFilter">cupsPreFilter</a></li>
+<li><a href="#cupsPrintQuality">cupsPrintQuality</a></li>
+<li><a href="#cupsSNMPSupplies">cupsSNMPSupplies</a></li>
+<li><a href="#cupsVersion">cupsVersion</a></li>
+</ul></li>
+<li><a href="#MACOSX">Mac OS X Attributes</a><ul class="subcontents">
+<li><a href="#APDialogExtension">APDialogExtension</a></li>
+<li><a href="#APDuplexRequiresFlippedMargin">APDuplexRequiresFlippedMargin</a></li>
+<li><a href="#APHelpBook">APHelpBook</a></li>
+<li><a href="#APICADriver">APICADriver</a></li>
+<li><a href="#APPrinterIconPath">APPrinterIconPath</a></li>
+<li><a href="#APPrinterLowInkTool">APPrinterLowInkTool</a></li>
+<li><a href="#APPrinterPreset">APPrinterPreset</a></li>
+<li><a href="#APPrinterUtilityPath">APPrinterUtilityPath</a></li>
+<li><a href="#APScannerOnly">APScannerOnly</a></li>
+<li><a href="#APScanAppBundleID">APScanAppBundleID</a></li>
+</ul></li>
+<li><a href="#HISTORY">Change History</a></li>
 <h2 class='title'><a name='SYNTAX'>PPD File Syntax</a></h2>
 
-<p>The PPD format is text-based and uses lines of up to 255
-characters terminated by a carriage return, linefeed, or
-combination of carriage return and line feed. The following ABNF
-definition [RFC4234] defines the general format of lines in a PPD
-file:</p>
+<p>The PPD format is text-based and uses lines of up to 255 characters terminated by a carriage return, linefeed, or combination of carriage return and line feed. The following ABNF definition [<a href="http://tools.ietf.org/html/rfc5234" target="_blank">RFC5234</a>] defines the general format of lines in a PPD file:</p>
 
 <pre class='command'>
 PPD-FILE = HEADER +(DATA / COMMENT / LINE-END)
@@ -69,21 +463,21 @@ LINE-END = CR / LF / CR LF
 
 <h2 class='title'><a name='AUTOCONFIG'>Auto-Configuration</a></h2>
 
-<p>CUPS supports several methods of auto-configuration via PPD attributes.
-<em>Currently these methods are only implemented on Mac OS X.</em></p>
+<p>CUPS supports several methods of auto-configuration via PPD keywords.</p>
 
-<h3><span class='info'>Mac OS X 10.5</span><a name='APAutoSetupTool'>APAutoSetupTool</a></h3>
+<h3><span class='info'>Deprecated</span><a name='APAutoSetupTool'>APAutoSetupTool</a></h3>
 
 <p class='summary'>*APAutoSetupTool: "/LibraryPrinters/vendor/filename"</p>
 
-<p>This attribute defines a program that sets the default option choices. It
-is run when a printer is added from the printer browser instead of the
-normal PostScript query and SNMP OID attribute lookups.</p>
+<p>This deprecated keyword defines a program that sets the default option choices. It is run when a printer is added from the <var>Add Printer</var> window or the <var>Nearby Printers</var> list in the <var>Print</var> dialog.</p>
 
-<p>The program is provided with two arguments: the printer's device URI and
-the PPD file to be used for the printer. The program must write an updated
-PPD file to stdout.</p>
+<p>The program is provided with two arguments: the printer's device URI and the PPD file to be used for the printer. The program must write an updated PPD file to stdout.</p>
+
+<blockquote><b>Note:</b>
 
+<p>This keyword is deprecated. New printer drivers SHOULD provide a CUPS command filter and support the "AutoConfigure" command. Alternately, drivers MAY use the <a href="#OID">SNMP OID</a> keywords to configure network printers or <a href="#QUERYKEYWORD">PostScript query keywords</a> to configure PostScript printers.</p>
+
+</blockquote>
 <p>Examples:</p>
 
 <pre class='command'>
@@ -91,20 +485,16 @@ PPD file to stdout.</p>
 *APAutoSetupTool: "/Library/Printers/vendor/Tools/autosetuptool"
 </pre>
 
-<h3><span class='info'>Mac OS X 10.2</span><a name='QUERYKEYWORD'>?MainKeyword</a></h3>
+<h3><span class='info'>Mac OS X 10.2/CUPS 1.4</span><a name='QUERYKEYWORD'>?MainKeyword</a></h3>
 
 <p class='summary'>*?<i>MainKeyword</i>: "<br>
   PostScript query code that writes a message using the = operator...<br>
 "<br>
 *End</p>
 
-<p>The <tt>?<i>MainKeyword</i></tt> attribute defines PostScript code that
-determines the currently selected/enabled option keyword (choice) for the
-main keyword (option). It is typically used when communicating with USB,
-serial, Appletalk, and AppSocket (port 9100) printers.</p>
+<p>The <tt>?<i>MainKeyword</i></tt> keyword defines PostScript code that determines the currently selected/enabled option keyword (choice) for the main keyword (option). It is typically used when communicating with USB, serial, Appletalk, and AppSocket (port 9100) printers.</p>
 
-<p>The PostScript code typically sends its response back using the <tt>=</tt>
-operator.</p>
+<p>The PostScript code typically sends its response back using the <tt>=</tt> operator.</p>
 
 <p>Example:</p>
 
@@ -124,20 +514,14 @@ operator.</p>
 *CloseUI: OptionDuplex
 </pre>
 
-<h3><span class='info'>Mac OS X 10.4</span><a name='OID'>OIDMainKeyword</a></h3>
+<h3><span class='info'>Mac OS X 10.4/CUPS 1.5</span><a name='OID'>OIDMainKeyword</a></h3>
 
 <p class='summary'>*?OID<i>MainKeyword</i>: ".n.n.n..."<br>
 *OID<i>MainKeyword</i> <i>OptionKeyword1</i>: "value"<br>
 ...<br>
 *OID<i>MainKeyword</i> <i>OptionKeywordN</i>: "value"</p>
 
-<p>The <tt>OID<i>MainKeyword</i></tt> attribute is used to define
-SNMP OIDs that map to installable options. The first (query) line
-defines the OID to lookup on the network device. The second and
-subsequent attributes define a mapping from OID value to option
-keyword. Since SNMP is an IP-based network protocol, this method
-is typically only used to configure AppSocket, IPP, and LPD network
-printers.</p>
+<p>The <tt>OID<i>MainKeyword</i></tt> keyword is used to define SNMP OIDs that map to installable options. The first (query) line defines the OID to lookup on the network device. The second and subsequent keywords define a mapping from OID value to option keyword. Since SNMP is an IP-based network protocol, this method is typically only used to configure AppSocket, IPP, and LPD network printers.</p>
 
 <p>Examples:</p>
 
@@ -153,32 +537,21 @@ printers.</p>
 
 <h2 class='title'><a name='PROFILES'>Color Profiles</a></h2>
 
-<p>CUPS supports three types of color profiles. The first type is
-based on sRGB and is used by the standard CUPS raster filters and
-GPL Ghostscript. The second type is based on ICC profiles and is
-used by the Quartz-based filters on MacOS X. The final type is
-based on well-known colorspaces such as sRGB and Adobe RGB.</p>
+<p>CUPS supports three types of color profiles. The first type is based on sRGB and is used by the standard CUPS raster filters and GPL Ghostscript. The second type is based on ICC profiles and is used by the Quartz-based filters on MacOS X. The final type is based on well-known colorspaces such as sRGB and Adobe RGB.</p>
 
 <blockquote><b>Note:</b>
 
-<p>At this time, none of the CUPS raster filters support ICC profiles. This
-will be addressed as time and resources permit.</p>
+<p>At this time, none of the CUPS raster filters support ICC profiles. This will be addressed as time and resources permit.</p>
 
 </blockquote>
 
 <h3><span class='info'>Deprecated</span><a name='cupsColorProfile'>cupsColorProfile</a></h3>
 
-<p class='summary'>*cupsColorProfile Resolution/MediaType: "density
-gamma m00 m01 m02 m10 m11 m12 m20 m21 m22"</p>
+<p class='summary'>*cupsColorProfile Resolution/MediaType: "density gamma m00 m01 m02 m10 m11 m12 m20 m21 m22"</p>
 
-<p>This string attribute specifies an sRGB-based color profile
-consisting of gamma and density controls and a 3x3 CMY color
-transform matrix. <em>This attribute is not supported on Mac OS X.</em></p>
+<p>This string keyword specifies an sRGB-based color profile consisting of gamma and density controls and a 3x3 CMY color transform matrix. <em>This keyword is not supported on Mac OS X.</em></p>
 
-<p>The <i>Resolution</i> and <i>MediaType</i> values may be "-"
-to act as a wildcard. Otherwise they must match one of the
-<tt>Resolution</tt> or <tt>MediaType</tt> attributes defined in
-the PPD file.</p>
+<p>The <i>Resolution</i> and <i>MediaType</i> values may be "-" to act as a wildcard. Otherwise they must match one of the <tt>Resolution</tt> or <tt>MediaType</tt> option keywords defined in the PPD file.</p>
 
 <p>The <i>density</i> and <i>gamma</i> values define gamma and
 density adjustment function such that:</p>
@@ -187,9 +560,7 @@ density adjustment function such that:</p>
 f(x) = density * x <sup style='font-size: 100%'>gamma</sup>
 </pre>
 
-<p>The <i>m00</i> through <i>m22</i> values define a 3x3
-transformation matrix for the CMY color values. The density
-function is applied <i>after</i> the CMY transformation:</p>
+<p>The <i>m00</i> through <i>m22</i> values define a 3x3 transformation matrix for the CMY color values. The density function is applied <i>after</i> the CMY transformation:</p>
 
 <pre class='command'>
 | m00 m01 m02 |
@@ -211,23 +582,13 @@ function is applied <i>after</i> the CMY transformation:</p>
 </pre>
 
 
-<h3><span class='info'>Mac OS X 10.3/CUPS 1.2/Mac OS X 10.5</span><a name='cupsICCProfile'>cupsICCProfile</a></h3>
+<h3><span class='info'>Mac OS X 10.3/CUPS 1.2</span><a name='cupsICCProfile'>cupsICCProfile</a></h3>
 
-<p class='summary'>*cupsICCProfile
-ColorModel.MediaType.Resolution/Description: "filename"</p>
+<p class='summary'>*cupsICCProfile ColorModel.MediaType.Resolution/Description: "filename"</p>
 
-<p>This attribute specifies an ICC color profile that is
-used to convert the document colors to the device
-colorspace. The <tt>ColorModel</tt>, <tt>MediaType</tt>, and
-<tt>Resolution</tt> keywords specify a selector for color
-profiles. If omitted, the color profile will match any option
-keyword for the corresponding main keyword.</p>
+<p>This keyword specifies an ICC color profile that is used to convert the document colors to the device colorspace. The <tt>ColorModel</tt>, <tt>MediaType</tt>, and <tt>Resolution</tt> option keywords specify a selector for color profiles. If omitted, the color profile will match any option keyword for the corresponding main keyword.</p>
 
-<p>The <tt>Description</tt> specifies human-readable text that
-is associated with the color profile. The <tt>filename</tt>
-portion specifies the ICC color profile to use; if the filename
-is not absolute, it is loaded relative to the
-<var>/usr/share/cups/profiles</var> directory.</p>
+<p>The <tt>Description</tt> specifies human-readable text that is associated with the color profile. The <tt>filename</tt> portion specifies the ICC color profile to use; if the filename is not absolute, it is loaded relative to the <var>/usr/share/cups/profiles</var> directory.</p>
 
 <p>Examples:</p>
 
@@ -244,11 +605,7 @@ is not absolute, it is loaded relative to the
 
 <h4>Customizing the Profile Selection Keywords</h4>
 
-<p>The <tt>MediaType</tt> and <tt>Resolution</tt> keywords can be
-reassigned to different main keywords, allowing drivers to do
-color profile selection based on different parameters. The
-<tt>cupsICCQualifier2</tt> and <tt>cupsICCQualifier3</tt>
-attributes define the mapping from selector to main keyword:</p>
+<p>The <tt>MediaType</tt> and <tt>Resolution</tt> main keywords can be reassigned to different main keywords, allowing drivers to do color profile selection based on different parameters. The <tt>cupsICCQualifier2</tt> and <tt>cupsICCQualifier3</tt> keywords define the mapping from selector to main keyword:</p>
 
 <pre class='command'>
 *cupsICCQualifier2: MainKeyword2
@@ -269,19 +626,11 @@ attributes define the mapping from selector to main keyword:</p>
 *<a href='#APCustomColorMatchingProfile'>APCustomColorMatchingProfile</a>: profile<br>
 *<a href='#APDefaultCustomColorMatchingProfile'>APDefaultCustomColorMatchingProfile</a>: profile</p>
 
-<p>These attributes tell the Mac OS X raster filters that the printer
-driver provides its own custom color matching and that generic color
-profiles should be used when generating 1-, 3-, and 4-component raster
-data as requested by the driver. The <tt>APCustomColorMatchingProfile</tt>
-and <tt>APDefaultColorMatchingProfile</tt> attributes specify alternate
-color profiles (sRGB or AdobeRGB) to use for 3-color (RGB) raster data.</p>
+<p>These keywords tell the Mac OS X raster filters that the printer driver provides its own custom color matching and that generic color profiles should be used when generating 1-, 3-, and 4-component raster data as requested by the driver. The <tt>APCustomColorMatchingProfile</tt> and <tt>APDefaultColorMatchingProfile</tt> keywords specify alternate color profiles (sRGB or AdobeRGB) to use for 3-color (RGB) raster data.</p>
 
 <blockquote><b>Note:</b>
 
-<p>Prior to Mac OS X 10.6, the default RGB color space was Apple's "GenericRGB".
-The new default in Mac OS X 10.6 and later is "sRGB". For more information, see
-<a href="http://support.apple.com/kb/HT3712">"Mac OS X v10.6: About gamma
-2.2"</a> on Apple's support site.</p>
+<p>Prior to Mac OS X 10.6, the default RGB color space was Apple's "GenericRGB". The new default in Mac OS X 10.6 and later is "sRGB". For more information, see <a href="http://support.apple.com/kb/HT3712">"Mac OS X v10.6: About gamma 2.2"</a> on Apple's support site.</p>
 
 </blockquote>
 
@@ -289,10 +638,7 @@ The new default in Mac OS X 10.6 and later is "sRGB". For more information, see
 
 <p class='summary'>*APCustomColorMatchingName name/text: ""</p>
 
-<p>This attribute defines an alternate name for the color matching
-provided by a driver in the <var>Color Matching</var> print panel.
-The default is to use the name "Vendor Matching" or its localized
-equivalent.</p>
+<p>This keyword defines an alternate name for the color matching provided by a driver in the <var>Color Matching</var> print panel. The default is to use the name "Vendor Matching" or its localized equivalent.</p>
 
 <p>Examples:</p>
 
@@ -306,18 +652,11 @@ equivalent.</p>
 
 <p class='summary'>*APCustomColorMatchingProfile: name</p>
 
-<p>This attribute defines a supported RGB color profile that can be used
-when doing custom color matching. Currently only <tt>sRGB</tt>,
-<tt>AdobeRGB</tt>, and <tt>GenericRGB</tt> are supported. If not specified, RGB
-data will use the GenericRGB colorspace.</p>
+<p>This keyword defines a supported RGB color profile that can be used when doing custom color matching. Currently only <tt>sRGB</tt>, <tt>AdobeRGB</tt>, and <tt>GenericRGB</tt> are supported. If not specified, RGB data will use the GenericRGB colorspace.</p>
 
 <blockquote><b>Note:</b>
 
-<p>If you provide multiple <tt>APCustomColorMatchingProfile</tt> attributes,
-you are responsible for providing the necessary user interface controls to
-select the profile in a <a href='#APDialogExtension'>print dialog pane</a>.
-Add the named profile to the print settings using the key
-<tt>kPMCustomColorMatchingProfileKey</tt>.</p>
+<p>If you provide multiple <tt>APCustomColorMatchingProfile</tt> keywords, you are responsible for providing the necessary user interface controls to select the profile in a <a href='#APDialogExtension'>print dialog pane</a>. Add the named profile to the print settings using the key <tt>kPMCustomColorMatchingProfileKey</tt>.</p>
 
 </blockquote>
 
@@ -335,9 +674,7 @@ Add the named profile to the print settings using the key
 
 <p class='summary'>*APDefaultCustomColorMatchingProfile: name</p>
 
-<p>This attribute defines the default RGB color profile that will be used
-when doing custom color matching. Currently only <tt>sRGB</tt>,
-<tt>AdobeRGB</tt>, and <tt>GenericRGB</tt> are supported.</p>
+<p>This keyword defines the default RGB color profile that will be used when doing custom color matching. Currently only <tt>sRGB</tt>, <tt>AdobeRGB</tt>, and <tt>GenericRGB</tt> are supported.</p>
 
 <p>Examples:</p>
 
@@ -351,12 +688,7 @@ when doing custom color matching. Currently only <tt>sRGB</tt>,
 
 <p class='summary'>*APSupportsCustomColorMatching: boolean</p>
 
-<p>This attribute specifies that the driver provides its own custom color
-matching. When <tt>true</tt>, the default hand-off colorspace will be
-GenericGray, GenericRGB, or GenericCMYK depending on the number of
-components the driver requests. The <a
-href='#APDefaultCustomColorMatchingProfile'><tt>APDefaultCustomColorMatchingProfile</tt></a>
-attribute can be used to override the default 3-component (RGB) colorspace.</p>
+<p>This keyword specifies that the driver provides its own custom color matching. When <tt>true</tt>, the default hand-off colorspace will be GenericGray, GenericRGB, or GenericCMYK depending on the number of components the driver requests. The <a href='#APDefaultCustomColorMatchingProfile'><tt>APDefaultCustomColorMatchingProfile</tt></a> keyword can be used to override the default 3-component (RGB) colorspace.</p>
 
 <p>The default for <tt>APSupportsCustomColorMatching</tt> is <tt>false</tt>.</p>
 
@@ -370,11 +702,7 @@ attribute can be used to override the default 3-component (RGB) colorspace.</p>
 
 <h2 class='title'><a name='CONSTRAINTS'>Constraints</a></h2>
 
-<p>Constraints are option choices that are not allowed by the driver or
-device, for example printing 2-sided transparencies. All versions of CUPS
-support constraints defined by the legacy Adobe <tt>UIConstraints</tt> and
-<tt>NonUIConstraints</tt> attributes which support conflicts between any two
-option choices, for example:</p>
+<p>Constraints are option choices that are not allowed by the driver or device, for example printing 2-sided transparencies. All versions of CUPS support constraints defined by the legacy Adobe <tt>UIConstraints</tt> and <tt>NonUIConstraints</tt> keywords which support conflicts between any two option choices, for example:</p>
 
 <pre class='command'>
 *% Do not allow 2-sided printing on transparency media
@@ -382,24 +710,13 @@ option choices, for example:</p>
 *UIConstraints: "*MediaType Transparency *Duplex"
 </pre>
 
-<p>While nearly all constraints can be expressed using these attributes, there
-are valid scenarios requiring constraints between more than two option choices.
-In addition, resolution of constraints is problematic since users and software
-have to guess how a particular constraint is best resolved.</p>
+<p>While nearly all constraints can be expressed using these keywords, there are valid scenarios requiring constraints between more than two option choices. In addition, resolution of constraints is problematic since users and software have to guess how a particular constraint is best resolved.</p>
 
-<p>CUPS 1.4 and higher define two new attributes for constraints,
-<tt>cupsUIConstraints</tt> and <tt>cupsUIResolver</tt>. Each
-<tt>cupsUIConstraints</tt> attribute points to a <tt>cupsUIResolver</tt>
-attribute which specifies alternate options that resolve the conflict condition.
-The same <tt>cupsUIResolver</tt> can be used by multiple
-<tt>cupsUIConstraints</tt>.</p>
+<p>CUPS 1.4 and higher define two new keywords for constraints, <tt>cupsUIConstraints</tt> and <tt>cupsUIResolver</tt>. Each <tt>cupsUIConstraints</tt> keyword points to a <tt>cupsUIResolver</tt> keyword which specifies alternate options that resolve the conflict condition. The same <tt>cupsUIResolver</tt> can be used by multiple <tt>cupsUIConstraints</tt>.</p>
 
 <blockquote><b>Note:</b>
 
-    <p>When developing PPD files that contain constraints, it is very important
-    to use the <a href="man-cupstestppd.html">cupstestppd(1)</a> program to
-    verify that your constraints are accurate and cannot result in unresolvable
-    option selections.</p>
+<p>When developing PPD files that contain constraints, it is very important to use the <a href="man-cupstestppd.html">cupstestppd(1)</a> program to verify that your constraints are accurate and cannot result in unresolvable option selections.</p>
 
 </blockquote>
 
@@ -411,10 +728,7 @@ The same <tt>cupsUIResolver</tt> can be used by multiple
 *cupsUIConstraints resolver: "*Keyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."<br>
 *cupsUIConstraints: "*InstallableKeyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."</p>
 
-<p>Lists two or more options which conflict. The "resolver" string is a
-(possibly unique) keyword which specifies which options to change when the
-constraint exists. When no resolver is provided, CUPS first tries the default
-choice followed by testing each option choice to resolve the conflict.</p>
+<p>Lists two or more options which conflict. The "resolver" string is a (possibly unique) keyword which specifies which options to change when the constraint exists. When no resolver is provided, CUPS first tries the default choice followed by testing each option choice to resolve the conflict.</p>
 
 <p>Examples:</p>
 
@@ -440,16 +754,7 @@ choice followed by testing each option choice to resolve the conflict.</p>
 
 <p class='summary'>*cupsUIResolution resolver: "*Keyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."</p>
 
-<p>Specifies two or more options to mark/select to resolve a constraint. The
-"resolver" string identifies a particular action to take for one or more
-<a href='#cupsUIConstraints'><tt>cupsUIConstraints</tt></a>. The same action
-can be used for multiple constraints. The option keyword pairs are treated as
-an ordered list of option selections to try - only the first N selections will
-be used, where N is the minimum number of selections required. Because
-<a href="api-ppd.html#cupsResolveConflicts"><code>cupsResolveConflicts()</code></a>
-will not change the most recent option selection passed to it, at least two
-options from the constraints must be listed to avoid situations where conflicts
-cannot be resolved.</p>
+<p>Specifies two or more options to mark/select to resolve a constraint. The "resolver" string identifies a particular action to take for one or more <a href='#cupsUIConstraints'><tt>cupsUIConstraints</tt></a>. The same action can be used for multiple constraints. The option keyword pairs are treated as an ordered list of option selections to try - only the first N selections will be used, where N is the minimum number of selections required. Because <a href="api-ppd.html#cupsResolveConflicts"><code>cupsResolveConflicts()</code></a> will not change the most recent option selection passed to it, at least two options from the constraints must be listed to avoid situations where conflicts cannot be resolved.</p>
 
 <p>Examples:</p>
 
@@ -469,8 +774,7 @@ cannot be resolved.</p>
 
 <h2 class='title'><a name='I18N'>Globalized PPD Support</a></h2>
 
-<p>CUPS 1.2 and higher adds support for PPD files containing multiple
-languages by following the following additional rules:</p>
+<p>CUPS 1.2 and higher adds support for PPD files containing multiple languages by following the following additional rules:</p>
 
 <ol>
 
@@ -478,59 +782,36 @@ languages by following the following additional rules:</p>
 
        <li>The <tt>LanguageEncoding</tt> MUST be <tt>ISOLatin1</tt></li>
 
-       <li>The <tt>cupsLanguages</tt> attribute MUST be provided and
-       list each of the supported locales in the PPD file</li>
+       <li>The <tt>cupsLanguages</tt> keyword MUST be provided and list each of the supported locales in the PPD file</li>
 
-       <li>Main and option keywords MUST NOT exceed 34 (instead of 40)
-       characters to allow room for the locale prefixes in translation
-       attributes</li>
+       <li>Main and option keywords MUST NOT exceed 34 (instead of 40) characters to allow room for the locale prefixes in translation keywords</li>
 
        <li>The main keyword "Translation" MUST NOT be used</li>
 
-       <li>Translation strings included with the main and option
-       keywords MUST NOT contain characters outside the ASCII
-       subset of ISOLatin1 and UTF-8; developers wishing to use
-       characters outside ASCII MUST provide a separate set of
-       English localization attributes for the affected keywords.</li>
+       <li>Translation strings included with the main and option keywords MUST NOT contain characters outside the ASCII subset of ISOLatin1 and UTF-8; developers wishing to use characters outside ASCII MUST provide a separate set of English localization keywords for the affected keywords.</li>
 
-       <li>Localizations are specified using a locale prefix of
-       the form "ll" or "ll_CC." where "ll" is the 2-letter ISO
-       language code and "CC" is the 2-letter ISO country
-       code<ul>
+       <li>Localizations are specified using a locale prefix of the form "ll" or "ll_CC." where "ll" is the 2-letter ISO language code and "CC" is the 2-letter ISO country code<ul>
                <li>A generic language translation ("ll") SHOULD be provided with country-specific differences ("ll_CC") provided only as needed</li>
                <li>For historical reasons, the "zh" and "zh_CN" locales map to Simplified Chinese while the "zh_TW" locale maps to Traditional Chinese</li>
        </ul></li>
 
-       <li>Locale-specific translation strings MUST be encoded
-       using UTF-8.</li>
+       <li>Locale-specific translation strings MUST be encoded using UTF-8.</li>
 
-       <li>Main keywords MUST be localized using one of the
-       following forms:
-       <p><tt>*ll.Translation MainKeyword/translation
-       text: ""</tt><br />
-       <tt>*ll_CC.Translation MainKeyword/translation
-       text: ""</tt></p></li>
+       <li>Main keywords MUST be localized using one of the following forms:
+       <p><tt>*ll.Translation MainKeyword/translation text: ""</tt><br />
+       <tt>*ll_CC.Translation MainKeyword/translation text: ""</tt></p></li>
 
-       <li>Option keywords MUST be localized using one of the
-       following forms:
-       <p><tt>*ll.MainKeyword OptionKeyword/translation
-       text: ""</tt><br />
-       <tt>*ll_CC.MainKeyword OptionKeyword/translation
-       text: ""</tt></p></li>
+       <li>Option keywords MUST be localized using one of the following forms:
+       <p><tt>*ll.MainKeyword OptionKeyword/translation text: ""</tt><br>
+       <tt>*ll_CC.MainKeyword OptionKeyword/translation text: ""</tt></p></li>
 
-       <li>Localization attributes MAY appear anywhere after the
-       first line of the PPD file</li>
+       <li>Localization keywords MAY appear anywhere after the first line of the PPD file</li>
 
 </ol>
 
 <blockquote><b>Note:</b>
 
-<p>We use a <tt>LanguageEncoding</tt> value of <tt>ISOLatin1</tt>
-and limit the allowed base translation strings to ASCII to avoid
-character coding issues that would otherwise occur. In addition,
-requiring the base translation strings to be in English allows
-for easier fallback translation when no localization is provided
-in the PPD file for a given locale.</p>
+<p>We use a <tt>LanguageEncoding</tt> value of <tt>ISOLatin1</tt> and limit the allowed base translation strings to ASCII to avoid character coding issues that would otherwise occur. In addition, requiring the base translation strings to be in English allows for easier fallback translation when no localization is provided in the PPD file for a given locale.</p>
 
 </blockquote>
 
@@ -571,11 +852,9 @@ in the PPD file for a given locale.</p>
 </pre>
 
 
-<h2 class='title'><a name='OPTIONS'>Custom Options</a></h2>
+<h2 class='title'><a name='OPTIONS'><span class="info">CUPS 1.3/Mac OS X 10.6</span>Custom Options</a></h2>
 
-<p>CUPS supports custom options using an extension of the
-<tt>CustomPageSize</tt> and <tt>ParamCustomPageSize</tt>
-syntax:</p>
+<p>CUPS supports custom options using an extension of the <tt>CustomPageSize</tt> and <tt>ParamCustomPageSize</tt> syntax:</p>
 
 <pre class='command'>
 *CustomFoo True: "command"
@@ -585,68 +864,33 @@ syntax:</p>
 *ParamCustomFoo NameN/Text N: order type minimum maximum
 </pre>
 
-<p>When the base option is part of the <tt>JCLSetup</tt> section,
-the "command" string contains JCL commands with "\order"
-placeholders for each numbered parameter. The CUPS API handles
-any necessary value quoting for HP-PJL commands. For example, if
-the JCL command string is "@PJL SET PASSCODE=\1" and the first
-option value is "1234" then CUPS will output the string
-"@PJL SET PASSCODE=1234".</p>
-
-<p>For non-<tt>JCLSetup</tt> options, the "order" value is a
-number from 1 to N and specifies the order of values as they are
-placed on the stack before the command. For example, if the
-PostScript command string is
-"&lt;&lt;/cupsReal1 2 1 roll&gt;&gt;setpagedevice" and the
-option value is "2.0" then CUPS will output the string
-"2.0 &lt;&lt;/cupsReal1 2 1 roll&gt;&gt;setpagedevice".</p>
+<p>When the base option is part of the <tt>JCLSetup</tt> section, the "command" string contains JCL commands with "\order" placeholders for each numbered parameter. The CUPS API handles any necessary value quoting for HP-PJL commands. For example, if the JCL command string is "@PJL SET PASSCODE=\1" and the first
+option value is "1234" then CUPS will output the string "@PJL SET PASSCODE=1234".</p>
+
+<p>For non-<tt>JCLSetup</tt> options, the "order" value is a number from 1 to N and specifies the order of values as they are placed on the stack before the command. For example, if the PostScript command string is "&lt;&lt;/cupsReal1 2 1 roll&gt;&gt;setpagedevice" and the option value is "2.0" then CUPS will output the string "2.0 &lt;&lt;/cupsReal1 2 1 roll&gt;&gt;setpagedevice".</p>
 
 <p>The "type" is one of the following keywords:</p>
 
 <ul>
 
-       <li><tt>curve</tt> - a real value from "minimum" to
-       "maximum" representing a gamma correction curve using the
-       function: f(x) = x <sup>value</sup></li>
+       <li><tt>curve</tt> - a real value from "minimum" to "maximum" representing a gamma correction curve using the function: f(x) = x <sup>value</sup></li>
 
-       <li><tt>int</tt> - an integer value from "minimum" to
-       "maximum"</li>
+       <li><tt>int</tt> - an integer value from "minimum" to "maximum"</li>
 
-       <li><tt>invcurve</tt> - a real value from "minimum" to
-       "maximum" representing a gamma correction curve using the
-       function: f(x) = x <sup>1 / value</sup></li>
+       <li><tt>invcurve</tt> - a real value from "minimum" to "maximum" representing a gamma correction curve using the function: f(x) = x <sup>1 / value</sup></li>
 
-       <li><tt>passcode</tt> - a string of numbers value with a
-       minimum of "minimum" numbers and a maximum of "maximum"
-       numbers ("minimum" and "maximum" are numbers and passcode
-       strings are not displayed in the user interface)</li>
+       <li><tt>passcode</tt> - a string of numbers value with a minimum of "minimum" numbers and a maximum of "maximum" numbers ("minimum" and "maximum" are numbers and passcode strings are not displayed in the user interface)</li>
 
-       <li><tt>password</tt> - a string value with a minimum of
-       "minimum" characters and a maximum of "maximum"
-       characters ("minimum" and "maximum" are numbers and password
-       strings are not displayed in the user interface)</li>
+       <li><tt>password</tt> - a string value with a minimum of "minimum" characters and a maximum of "maximum" characters ("minimum" and "maximum" are numbers and password strings are not displayed in the user interface)</li>
 
-       <li><tt>points</tt> - a measurement value in points from
-       "minimum" to "maximum"</li>
+       <li><tt>points</tt> - a measurement value in points from "minimum" to "maximum"</li>
 
-       <li><tt>real</tt> - a real value from "minimum" to
-       "maximum"</li>
+       <li><tt>real</tt> - a real value from "minimum" to "maximum"</li>
 
-       <li><tt>string</tt> - a string value with a minimum of
-       "minimum" characters and a maximum of "maximum"
-       characters ("minimum" and "maximum" are numbers)</li>
+       <li><tt>string</tt> - a string value with a minimum of "minimum" characters and a maximum of "maximum" characters ("minimum" and "maximum" are numbers)</li>
 
 </ul>
 
-<blockquote><b>Note:</b>
-
-<p>Custom options are not directly supported by the Mac OS X Print Dialog
-nor by the CUPS web interface at this time. Vendors that use custom
-options on Mac OS X must provide their own user interface via the
-<a href='#APDialogExtension'><tt>APDialogExtension</tt></a> attribute.</p>
-
-</blockquote>
-
 <p>Examples:</p>
 
 <pre class='command'>
@@ -696,7 +940,7 @@ options on Mac OS X must provide their own user interface via the
 
 <h2 class='title'><a name='RASTERPS'>Writing PostScript Option Commands for Raster Drivers</a></h2>
 
-<p>PPD files are used for both PostScript and non-PostScript printers. For CUPS raster drivers, you use a subset of the PostScript language to set page device attributes such as page size, resolution, and so forth. For example, the following code sets the page size to A4 size:</p>
+<p>PPD files are used for both PostScript and non-PostScript printers. For CUPS raster drivers, you use a subset of the PostScript language to set page device keywords such as page size, resolution, and so forth. For example, the following code sets the page size to A4 size:</p>
 
 <pre class='command'>
 *PageSize A4: "&lt;&lt;/PageSize[595 842]&gt;&gt;setpagedevice"
@@ -1061,16 +1305,16 @@ PRE B {
 </table></div>
 
 
-<h2 class='title'><a name='MEDIA'>Media Attributes</a></h2>
+<h2 class='title'><a name='MEDIA'>Media Keywords</a></h2>
 
-<p>The CUPS media attributes allow drivers to specify alternate custom page
+<p>The CUPS media keywords allow drivers to specify alternate custom page
 size limits based on up to two options.</p>
 
 <h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMediaQualifier2'>cupsMediaQualifier2</a></h3>
 
 <p class='summary'>*cupsMediaQualifier2: MainKeyword</p>
 
-<p>This attribute specifies the second option to use for overriding the
+<p>This keyword specifies the second option to use for overriding the
 custom page size limits.</p>
 
 <p>Example:</p>
@@ -1089,7 +1333,7 @@ custom page size limits.</p>
 
 <p class='summary'>*cupsMediaQualifier3: MainKeyword</p>
 
-<p>This attribute specifies the third option to use for overriding the
+<p>This keyword specifies the third option to use for overriding the
 custom page size limits.</p>
 
 <p>Example:</p>
@@ -1110,9 +1354,9 @@ custom page size limits.</p>
 *cupsMinSize .Qualifier2.: "width length"<br>
 *cupsMinSize ..Qualifier3: "width length"</p>
 
-<p>This attribute specifies alternate minimum custom page sizes in points.
+<p>This keyword specifies alternate minimum custom page sizes in points.
 The <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a> and
-<a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a> attributes
+<a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a> keywords
 are used to identify options to use for matching.</p>
 
 <p>Example:</p>
@@ -1133,9 +1377,9 @@ are used to identify options to use for matching.</p>
 *cupsMaxSize .Qualifier2.: "width length"<br>
 *cupsMaxSize ..Qualifier3: "width length"</p>
 
-<p>This attribute specifies alternate maximum custom page sizes in points.
+<p>This keyword specifies alternate maximum custom page sizes in points.
 The <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a> and
-<a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a> attributes
+<a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a> keywords
 are used to identify options to use for matching.</p>
 
 <p>Example:</p>
@@ -1157,9 +1401,9 @@ are used to identify options to use for matching.</p>
 
 <p class='summary'>*cupsBackSide: keyword</p>
 
-<p>This attribute requests special handling of the back side of pages
+<p>This keyword requests special handling of the back side of pages
 when doing duplexed (2-sided) output. <a href='#TABLE_1'>Table 1</a>
-shows the supported keyword values for this attribute and their effect
+shows the supported keyword values for this keyword and their effect
 on the raster data sent to your driver. For example, when <tt>cupsBackSide</tt>
 is <code>Rotated</code> and <tt>Tumble</tt> is <tt>false</tt>, your driver
 will receive print data starting at the bottom right corner of the page, with
@@ -1169,7 +1413,7 @@ each line going right-to-left instead of left-to-right. The default value is
 <blockquote><b>Note:</b>
 
 <p><tt>cupsBackSide</tt> replaces the older <tt>cupsFlipDuplex</tt>
-attribute - if <tt>cupsBackSide</tt> is specified, <tt>cupsFlipDuplex</tt>
+keyword - if <tt>cupsBackSide</tt> is specified, <tt>cupsFlipDuplex</tt>
 will be ignored.</p>
 
 </blockquote>
@@ -1247,13 +1491,13 @@ will be ignored.</p>
 </pre>
 
 <p>Also see the related <a href='#APDuplexRequiresFlippedMargin'><tt>APDuplexRequiresFlippedMargin</tt></a>
-attribute.</p>
+keyword.</p>
 
 <h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsCommands'>cupsCommands</a></h3>
 
 <p class='summary'>*cupsCommands: "name name2 ... nameN"</p>
 
-<p>This string attribute specifies the commands that are supported by the
+<p>This string keyword specifies the commands that are supported by the
 CUPS command file filter for this device. The command names are separated
 by whitespace.</p>
 
@@ -1269,7 +1513,7 @@ by whitespace.</p>
 
 <p class='summary'>*cupsEvenDuplex: boolean</p>
 
-<p>This boolean attribute notifies the RIP filters that the
+<p>This boolean keyword notifies the RIP filters that the
 destination printer requires an even number of pages when 2-sided
 printing is selected. The default value is <code>false</code>.</p>
 
@@ -1284,7 +1528,7 @@ printing is selected. The default value is <code>false</code>.</p>
 
 <p class='summary'>*cupsFax: boolean</p>
 
-<p>This boolean attribute specifies whether the PPD defines a facsimile device. The default is <tt>false</tt>.</p>
+<p>This boolean keyword specifies whether the PPD defines a facsimile device. The default is <tt>false</tt>.</p>
 
 <p>Examples:</p>
 
@@ -1296,7 +1540,7 @@ printing is selected. The default value is <code>false</code>.</p>
 
 <p class='summary'>*cupsFilter: "source/type cost program"</p>
 
-<p>This string attribute provides a conversion rule from the
+<p>This string keyword provides a conversion rule from the
 given source type to the printer's native format using the
 filter "program". If a printer supports the source type directly,
 the special filter program "-" may be specified.</p>
@@ -1319,8 +1563,8 @@ the special filter program "-" may be specified.</p>
 <p class='summary'>*cupsFlipDuplex: boolean</p>
 
 <p>Due to implementation differences between Mac OS X and Ghostscript,
-the <tt>cupsFlipDuplex</tt> attribute is deprecated. Instead, use
-the <a href='#cupsBackSide'><tt>cupsBackSide</tt></a> attribute to specify
+the <tt>cupsFlipDuplex</tt> keyword is deprecated. Instead, use
+the <a href='#cupsBackSide'><tt>cupsBackSide</tt></a> keyword to specify
 the coordinate system (pixel layout) of the page data on the back side of
 duplex pages.</p>
 
@@ -1334,7 +1578,7 @@ Ghostscript.</p>
 
 <p>Mac OS X drivers that previously used
 <tt>cupsFlipDuplex</tt> may wish to provide both the old and
-new attributes for maximum compatibility, for example:</p>
+new keywords for maximum compatibility, for example:</p>
 
 <pre class='command'>
 *cupsBackSide: Rotated
@@ -1353,7 +1597,7 @@ Ghostscript can use:</p>
 
 <p class='summary'>*cupsIPPFinishings number/text: "*Option Choice ..."</p>
 
-<p>This attribute defines a mapping from IPP <code>finishings</code>
+<p>This keyword defines a mapping from IPP <code>finishings</code>
 values to PPD options and choices.</p>
 
 <p>Examples:</p>
@@ -1369,7 +1613,7 @@ values to PPD options and choices.</p>
 
 <p class='summary'>*cupsIPPReason reason/Reason Text: "optional URIs"</p>
 
-<p>This optional attribute maps custom
+<p>This optional keyword maps custom
 <code>printer-state-reasons</code> keywords that are generated by
 the driver to human readable text. The optional URIs string
 contains zero or more URIs separated by a newline. Each URI can
@@ -1413,7 +1657,7 @@ http://www.vendor.com/help"
 
 <p class='summary'>*cupsLanguages: "locale list"</p>
 
-<p>This attribute describes which language localizations are
+<p>This keyword describes which language localizations are
 included in the PPD. The "locale list" string is a space-delimited
 list of locale names ("en", "en_US", "fr_CA", etc.)</p>
 
@@ -1428,7 +1672,7 @@ list of locale names ("en", "en_US", "fr_CA", etc.)</p>
 
 <p class='summary'>*cupsManualCopies: boolean</p>
 
-<p>This boolean attribute notifies the RIP filters that the
+<p>This boolean keyword notifies the RIP filters that the
 destination printer does not support copy generation in
 hardware. The default value is <code>false</code>.</p>
 
@@ -1443,7 +1687,7 @@ hardware. The default value is <code>false</code>.</p>
 
 <p class='summary'>*cupsMarkerName/Name Text: ""</p>
 
-<p>This optional attribute maps <code>marker-names</code> strings that are
+<p>This optional keyword maps <code>marker-names</code> strings that are
 generated by the driver to human readable text.</p>
 
 <p>Examples:</p>
@@ -1457,7 +1701,7 @@ generated by the driver to human readable text.</p>
 
 <p class='summary'>*cupsMarkerNotice: "disclaimer text"</p>
 
-<p>This optional attribute provides disclaimer text for the supply level
+<p>This optional keyword provides disclaimer text for the supply level
 information provided by the driver, typically something like "supply levels
 are approximate".</p>
 
@@ -1471,7 +1715,7 @@ are approximate".</p>
 
 <p class='summary'>*cupsModelNumber: number</p>
 
-<p>This integer attribute specifies a printer-specific model
+<p>This integer keyword specifies a printer-specific model
 number. This number can be used by a filter program to adjust
 the output for a specific model of printer.</p>
 
@@ -1486,7 +1730,7 @@ the output for a specific model of printer.</p>
 
 <p class='summary'>*cupsPJLCharset: "ISO character set name"</p>
 
-<p>This string attribute specifies the character set that is used
+<p>This string keyword specifies the character set that is used
 for strings in PJL commands. If not specified, US-ASCII is
 assumed.</p>
 
@@ -1501,7 +1745,7 @@ assumed.</p>
 
 <p class='summary'>*cupsPJLDisplay: "what"</p>
 
-<p>This optional attribute specifies which command is used to display the
+<p>This optional keyword specifies which command is used to display the
 job ID, name, and user on the printer's control panel. "What" is either "none"
 to disable this functionality, "job" to use "@PJL JOB DISPLAY", or "rdymsg"
 to use "@PJL RDYMSG DISPLAY". The default is "job".</p>
@@ -1520,15 +1764,15 @@ to use "@PJL RDYMSG DISPLAY". The default is "job".</p>
 
 <p class='summary'>*cupsPortMonitor urischeme/Descriptive Text: "port monitor"</p>
 
-<p>This string attribute specifies printer-specific "port
+<p>This string keyword specifies printer-specific "port
 monitor" filters that may be used with the printer. The CUPS
-scheduler also looks for the <tt>Protocols</tt> attribute to see
+scheduler also looks for the <tt>Protocols</tt> keyword to see
 if the <tt>BCP</tt> or <tt>TBCP</tt> protocols are supported. If
 so, the corresponding port monitor ("bcp" and "tbcp",
 respectively) is listed in the printer's
-<tt>port-monitor-supported</tt> attribute.</p>
+<tt>port-monitor-supported</tt> keyword.</p>
 
-<p>The "urischeme" portion of the attribute specifies the URI scheme
+<p>The "urischeme" portion of the keyword specifies the URI scheme
 that this port monitor should be used for. Typically this is used to
 pre-select a particular port monitor for each type of connection that
 is supported by the printer. The "port monitor" string can be "none"
@@ -1552,7 +1796,7 @@ to disable the port monitor for the given URI scheme.</p>
 
 <p class='summary'>*cupsPreFilter: "source/type cost program"</p>
 
-<p>This string attribute provides a pre-filter rule. The pre-filter
+<p>This string keyword provides a pre-filter rule. The pre-filter
 program will be inserted in the conversion chain immediately 
 before the filter that accepts the given MIME type.</p>
 
@@ -1571,7 +1815,7 @@ before the filter that accepts the given MIME type.</p>
 
 <p class='summary'>*cupsPrintQuality keyword/text: "code"</p>
 
-<p>This UI keyword defines standard print qualities that directly map from the IPP "print-quality" job template attribute. Standard keyword values are "Draft", "Normal", and "High" which are mapped from the IPP "print-quality" values 3, 4, and 5 respectively. Each <code>cupsPrintQuality</code> option typically sets output mode and resolution parameters in the page device dictionary, eliminating the need for separate (and sometimes confusing) output mode and resolution options.</p>
+<p>This UI keyword defines standard print qualities that directly map from the IPP "print-quality" job template keyword. Standard keyword values are "Draft", "Normal", and "High" which are mapped from the IPP "print-quality" values 3, 4, and 5 respectively. Each <code>cupsPrintQuality</code> option typically sets output mode and resolution parameters in the page device dictionary, eliminating the need for separate (and sometimes confusing) output mode and resolution options.</p>
 
 <blockquote><b>Note:</b>
 
@@ -1595,7 +1839,7 @@ before the filter that accepts the given MIME type.</p>
 
 <p class='summary'>*cupsSNMPSupplies: boolean</p>
 
-<p>This attribute tells the standard network backends whether they should query
+<p>This keyword tells the standard network backends whether they should query
 the standard SNMP Printer MIB OIDs for supply levels. The default value is
 <code>True</code>.
 
@@ -1610,7 +1854,7 @@ the standard SNMP Printer MIB OIDs for supply levels. The default value is
 
 <p class='summary'>*cupsVersion: major.minor</p>
 
-<p>This required attribute describes which version of the CUPS
+<p>This required keyword describes which version of the CUPS
 PPD file extensions was used. Currently it must be the string
 "1.0", "1.1", "1.2", or "1.3".</p>
 
@@ -1628,8 +1872,8 @@ PPD file extensions was used. Currently it must be the string
 
 <p class='summary'>*APDialogExtension: "/Library/Printers/vendor/filename.plugin"</p>
 
-<p>This attribute defines additional option panes that are displayed in the
-print dialog. Each attribute adds one or more option panes. See the "OutputBinsPDE"
+<p>This keyword defines additional option panes that are displayed in the
+print dialog. Each keyword adds one or more option panes. See the "OutputBinsPDE"
 example and <a href='http://developer.apple.com/qa/qa2004/qa1352.html'>Apple
 Technical Q&amp;A QA1352</a> for information on writing your own print dialog
 plug-ins.</p>
@@ -1654,7 +1898,7 @@ in order to be usable with all applications.</p>
 
 <p class='summary'>*APDuplexRequiresFlippedMargin: boolean</p>
 
-<p>This boolean attribute notifies the RIP filters that the
+<p>This boolean keyword notifies the RIP filters that the
 destination printer requires the top and bottom margins of the
 <tt>ImageableArea</tt> to be swapped for the back page. The
 default is <tt>true</tt> when <tt>cupsBackSide</tt> is <tt>Flipped</tt>
@@ -1730,15 +1974,15 @@ and the <tt>Tumble</tt> page attribute.</p>
 </pre>
 
 <p>Also see the related <a href='#cupsBackSide'><tt>cupsBackSide</tt></a>
-attribute.</p>
+keyword.</p>
 
 <h3><a name='APHelpBook'>APHelpBook</a></h3>
 
 <p class='summary'>*APHelpBook: "bundle URL"</p>
 
-<p>This string attribute specifies the Apple help book bundle to use when
+<p>This string keyword specifies the Apple help book bundle to use when
 looking up IPP reason codes for this printer driver. The
-<a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> attribute maps
+<a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> keyword maps
 "help" URIs to this file.</p>
 
 <p>Example:</p>
@@ -1751,7 +1995,7 @@ looking up IPP reason codes for this printer driver. The
 
 <p class='summary'>*APICADriver: boolean</p>
 
-<p>This attribute specifies whether the device has a matching Image Capture
+<p>This keyword specifies whether the device has a matching Image Capture
 Architecture (ICA) driver for scanning. The default is <tt>False</tt>.</p>
 
 <p>Examples:</p>
@@ -1765,7 +2009,7 @@ Architecture (ICA) driver for scanning. The default is <tt>False</tt>.</p>
 
 <p class='summary'>*APPrinterIconPath: "/Library/Printers/vendor/filename.icns"</p>
 
-<p>This attribute defines the location of a printer icon file to use when
+<p>This keyword defines the location of a printer icon file to use when
 displaying the printer. The file must be in the Apple icon format.</p>
 
 <p>Examples:</p>
@@ -1779,7 +2023,7 @@ displaying the printer. The file must be in the Apple icon format.</p>
 
 <p class='summary'>*APPrinterLowInkTool: "/Library/Printers/vendor/program"</p>
 
-<p>This attribute defines an program that checks the ink/toner/marker levels
+<p>This keyword defines an program that checks the ink/toner/marker levels
 on a printer, returning an XML document with those levels. See the "InkTool"
 example and
 <a href='http://developer.apple.com/technotes/tn2005/tn2144.html'>Apple
@@ -1796,7 +2040,7 @@ Technical Note TN2144</a> for more information.</p>
 
 <p class='summary'>*APPrinterPreset name/text: "*Option Choice ..."</p>
 
-<p>This attribute defines presets for multiple options that show up
+<p>This keyword defines presets for multiple options that show up
 in the print dialog of applications (such as iPhoto) that set the job
 style hint to <tt>NSPrintPhotoJobStyleHint</tt>. Each preset maps to one or
 more pairs of PPD options and choices as well as providing key/value data for
@@ -1866,7 +2110,7 @@ choice (*MainKeyword OptionKeyword) or a preset identifier and value
 
 <p class='summary'>*APPrinterPrinterUtilityPath: "/Library/Printers/vendor/filename.app"</p>
 
-<p>This attribute defines a GUI application that can be used to do printer
+<p>This keyword defines a GUI application that can be used to do printer
 maintenance functions such as cleaning the print head(s). See ... for more
 information.</p>
 
@@ -1881,7 +2125,7 @@ information.</p>
 
 <p class='summary'>*APScannerOnly: boolean</p>
 
-<p>This attribute specifies whether the device has scanning but no printing
+<p>This keyword specifies whether the device has scanning but no printing
 capabilities. The default is <tt>False</tt>.</p>
 
 <p>Examples:</p>
@@ -1895,7 +2139,7 @@ capabilities. The default is <tt>False</tt>.</p>
 
 <p class='summary'>*APScanAppBundleID: "bundle ID"</p>
 
-<p>This attribute defines the application to use when scanning pages from
+<p>This keyword defines the application to use when scanning pages from
 the device.</p>
 
 <p>Examples:</p>
@@ -1908,6 +2152,15 @@ the device.</p>
 
 <h2 class='title'><a name='HISTORY'>Change History</a></h2>
 
+<h3>Changes in CUPS 1.5</h3>
+
+<ul>
+
+       <li>Changes all instances of PPD attributes to PPD keywords, to be consistent with the parent specification from Adobe.</li>
+
+</ul>
+
+
 <h3>Changes in CUPS 1.4.5</h3>
 
 <ul>
@@ -1924,32 +2177,32 @@ the device.</p>
 <ul>
 
        <li>Added <a href='#APICADriver'><tt>APICADriver</tt></a>
-       attribute.</li>
+       keyword.</li>
 
        <li>Added <a href='#cupsCommands'><tt>cupsCommands</tt></a>
-       attribute.</li>
+       keyword.</li>
 
        <li>Added <a href='#cupsMarkerName'><tt>cupsMarkerName</tt></a>
-       attribute.</li>
+       keyword.</li>
 
        <li>Added <a href='#cupsMarkerNotice'><tt>cupsMarkerNotice</tt></a>
-       attribute.</li>
+       keyword.</li>
 
        <li>Added <a href='#cupsPJLDisplay'><tt>cupsPJLDisplay</tt></a>
-       attribute.</li>
+       keyword.</li>
 
        <li>Added <a href='#cupsSNMPSupplies'><tt>cupsSNMPSupplies</tt></a>
-       attribute.</li>
+       keyword.</li>
 
        <li>Added <a href='#cupsUIResolver'><tt>cupsUIResolver</tt></a> and
        <a href='#cupsUIConstraints'><tt>cupsUIConstraints</tt></a>
-       attributes.</li>
+       keywords.</li>
 
        <li>Added
        <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a>,
        <a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a>,
        <a href='#cupsMinSize'><tt>cupsMinSize</tt></a>, and
-       <a href='#cupsMaxSize'><tt>cupsMaxSize</tt></a> attributes.</li>
+       <a href='#cupsMaxSize'><tt>cupsMaxSize</tt></a> keywords.</li>
 
 </ul>
 
@@ -1958,11 +2211,11 @@ the device.</p>
 
 <ul>
 
-       <li>Added missing Mac OS X <tt>AP</tt> attributes.</li>
+       <li>Added missing Mac OS X <tt>AP</tt> keywords.</li>
 
        <li>Added section on auto-configuration including the
        <tt>OID<i>MainKeyword</i></tt> and <tt>?<i>MainKeyword</i></tt>
-       attributes.</li>
+       keywords.</li>
 
        <li>Minor reorganization.</li>
 
@@ -1981,7 +2234,7 @@ the device.</p>
 
        <li>Added <a href='#APPrinterPreset'><tt>APPrinterPreset</tt></a>,
        <a href='#cupsIPPFinishings'><tt>cupsIPPFinishings</tt></a>, and
-       <a href='#cupsPreFilter'><tt>cupsPreFilter</tt></a> attributes.</li>
+       <a href='#cupsPreFilter'><tt>cupsPreFilter</tt></a> keywords.</li>
 
        <li>Added discussion of custom option code, sample
        <tt>CustomPageSize</tt> code, and "do not use dict and put" note.</li>
@@ -2001,24 +2254,24 @@ the device.</p>
 
 <ul>
 
-       <li>Added globalization support attributes</li>
+       <li>Added globalization support keywords</li>
 
        <li>Added custom option values support</li>
 
-       <li>Added <a href='#APHelpBook'><tt>APHelpBook</tt></a> attribute</li>
+       <li>Added <a href='#APHelpBook'><tt>APHelpBook</tt></a> keyword</li>
 
        <li>Added <a href='#APDuplexRequiresFlippedMargin'><tt>APDuplexRequiresFlippedMargin</tt></a>
-       attribute</li>
+       keyword</li>
 
-       <li>Added <a href='#cupsICCProfile'><tt>cupsICCProfile</tt></a> attribute</li>
+       <li>Added <a href='#cupsICCProfile'><tt>cupsICCProfile</tt></a> keyword</li>
 
-       <li>Added <a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> attribute</li>
+       <li>Added <a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> keyword</li>
 
-       <li>Added <a href='#cupsLanguages'><tt>cupsLanguages</tt></a> attribute</li>
+       <li>Added <a href='#cupsLanguages'><tt>cupsLanguages</tt></a> keyword</li>
 
-       <li>Added <a href='#cupsPortMonitor'><tt>cupsPortMonitor</tt></a> attribute</li>
+       <li>Added <a href='#cupsPortMonitor'><tt>cupsPortMonitor</tt></a> keyword</li>
 
-       <li>Removed <tt>cupsProtocol</tt> attribute</li>
+       <li>Removed <tt>cupsProtocol</tt> keyword</li>
 
 </ul>
 
@@ -2026,11 +2279,11 @@ the device.</p>
 
 <ul>
 
-       <li>Added <a href='#cupsFlipDuplex'><tt>cupsFlipDuplex</tt></a> attribute</li>
+       <li>Added <a href='#cupsFlipDuplex'><tt>cupsFlipDuplex</tt></a> keyword</li>
 
-       <li>Added <tt>cupsProtocol</tt> attribute</li>
+       <li>Added <tt>cupsProtocol</tt> keyword</li>
 
 </ul>
-
+</div>
 </body>
 </html>
index a4b4e4f6759337d0aff802e593c0cd1b8dcdf080..a4d08770a5541e7b4bf90222f4b1ea0a9c97622d 100644 (file)
@@ -245,6 +245,12 @@ apihelp:
                --header raster-driver.header \
                --intro raster-driver.shtml \
                >../doc/help/raster-driver.html
+       mxmldoc --section "Specifications" \
+               --title "CUPS PPD Extensions" \
+               --css ../doc/cups-printable.css \
+               --header spec-ppd.header \
+               --intro spec-ppd.shtml \
+               >../doc/help/spec-ppd.html
 
 framedhelp:
        echo Generating CUPS API help files...
@@ -271,6 +277,12 @@ framedhelp:
                --css ../doc/cups-printable.css \
                --header raster-driver.header \
                --intro raster-driver.shtml
+       mxmldoc --section "Specifications" \
+               --title "CUPS PPD Extensions" \
+               --framed ../cups/spec-ppd \
+               --css ../doc/cups-printable.css \
+               --header spec-ppd.header \
+               --intro spec-ppd.shtml \
 
 
 #
index 8e26fbf3e0c07472f4d3814fffc3e173cc8bfd92..42c11d1ed4a224c5ec0903451d12240810cb00b8 100644 (file)
@@ -1,9 +1,9 @@
 <!--
   "$Id$"
 
-  Raster API header for the Common UNIX Printing System (CUPS).
+  Raster API documentation for CUPS.
 
-  Copyright 2008-2009 by Apple Inc.
+  Copyright 2008-2010 by Apple Inc.
 
   These coded instructions, statements, and computer programs are the
   property of Apple Inc. and are protected by Federal copyright
index 1f717ba098477fb849bc619c87c3139a938bd020..b4fef953e603886ac80ead74ff49ae472ca4fa6d 100644 (file)
@@ -1,3 +1,18 @@
+<!--
+  "$Id$"
+
+  PostScript printer driver documentation for CUPS.
+
+  Copyright 2007-2010 by Apple Inc.
+  Copyright 1997-2007 by Easy Software Products.
+
+  These coded instructions, statements, and computer programs are the
+  property of Apple Inc. and are protected by Federal copyright
+  law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+  which should have been included with this file.  If this file is
+  file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
 <h1 class='title'>Developing PostScript Printer Drivers</h1>
 
 <p>This document describes how to develop printer drivers for PostScript printers. Topics include: <a href='#BASICS'>printer driver basics</a>, <a href='#CREATE'>creating new PPD files</a>, <a href='#IMPORT'>importing existing PPD files</a>, <a href='#FILTERS'>using custom filters</a>, <a href='#COLOR'>implementing color management</a>, and <a href='#MACOSX'>adding Mac OS X features</a>.</p>
index 6afe1b4f04a3be984f02d27578ef2d9aef702ab2..4af7865f86ffbef40b3da732be7d1e8bfc7cca9b 100644 (file)
@@ -1,3 +1,18 @@
+<!--
+  "$Id$"
+
+  PPD compiler documentation for CUPS.
+
+  Copyright 2007-2010 by Apple Inc.
+  Copyright 1997-2007 by Easy Software Products.
+
+  These coded instructions, statements, and computer programs are the
+  property of Apple Inc. and are protected by Federal copyright
+  law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+  which should have been included with this file.  If this file is
+  file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
 <h1 class='title'>Introduction to the PPD Compiler</h1>
 
 <P>This document describes how to use the CUPS PostScript Printer Description
index 5ba1fb6149607758904525c0df922ae75b709660..31fc607223c298f8cff01c990d6cae8615960658 100644 (file)
@@ -1,3 +1,18 @@
+<!--
+  "$Id$"
+
+  Raster printer driver documentation for CUPS.
+
+  Copyright 2007-2010 by Apple Inc.
+  Copyright 1997-2007 by Easy Software Products.
+
+  These coded instructions, statements, and computer programs are the
+  property of Apple Inc. and are protected by Federal copyright
+  law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+  which should have been included with this file.  If this file is
+  file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
 <h1 class='title'>Developing Raster Printer Drivers</h1>
 
 <p>This document describes how to develop printer drivers for raster printers. Topics include: <a href='#BASICS'>printer driver basics</a>, <a href='#CREATE'>creating new PPD files</a>, <a href='#FILTERS'>using filters</a>, <a href='#COLOR'>implementing color management</a>, and <a href='#MACOSX'>adding Mac OS X features</a>.</p>
diff --git a/filter/spec-ppd.header b/filter/spec-ppd.header
new file mode 100644 (file)
index 0000000..8292be8
--- /dev/null
@@ -0,0 +1,32 @@
+<!--
+  "$Id$"
+
+  PPD extension documentation for CUPS.
+
+  Copyright 2007-2010 by Apple Inc.
+  Copyright 1997-2007 by Easy Software Products.
+
+  These coded instructions, statements, and computer programs are the
+  property of Apple Inc. and are protected by Federal copyright
+  law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+  which should have been included with this file.  If this file is
+  file is missing or damaged, see the license at "http://www.cups.org/".
+-->
+
+<H1 CLASS="title">CUPS PPD Extensions</H1>
+
+<p>This specification describes the attributes and extensions that CUPS adds to <a href="http://partners.adobe.com/public/developer/en/ps/5003.PPD_Spec_v4.3.pdf" target="_blank">Adobe TechNote #5003: PostScript Printer Description File Format Specification Version 4.3</a>. PostScript Printer Description ("PPD") files describe the capabilities of each printer and are used by CUPS to support printer-specific features and intelligent filtering.</p>
+
+<div class='summary'><table summary='General Information'>
+<tbody>
+<tr>
+       <th>See Also</th>
+       <td>Programming: <a href='postscript-driver.html'>Developing PostScript Printer Drivers</a><br>
+       Programming: <a href='raster-driver.html'>Developing Raster Printer Drivers</a><br>
+       Programming: <a href='api-filter.html'>Filter and Backend Programming</a><br>
+       Programming: <a href='ppd-compiler.html'>Introduction to the PPD Compiler</a><br>
+       Programming: <a href='api-raster.html'>Raster API</a><br>
+       References: <a href='ref-ppdcfile.html'>PPD Compiler Driver Information File Reference</a></td>
+</tr>
+</tbody>
+</table></div>
diff --git a/filter/spec-ppd.shtml b/filter/spec-ppd.shtml
new file mode 100644 (file)
index 0000000..96fb881
--- /dev/null
@@ -0,0 +1,1851 @@
+<h2 class='title'><a name='SYNTAX'>PPD File Syntax</a></h2>
+
+<p>The PPD format is text-based and uses lines of up to 255 characters terminated by a carriage return, linefeed, or combination of carriage return and line feed. The following ABNF definition [<a href="http://tools.ietf.org/html/rfc5234" target="_blank">RFC5234</a>] defines the general format of lines in a PPD file:</p>
+
+<pre class='command'>
+PPD-FILE = HEADER +(DATA / COMMENT / LINE-END)
+
+HEADER   = "*PPD-Adobe:" *WSP DQUOTE VERSION DQUOTE LINE-END
+
+VERSION  = "4.0" / "4.1" / "4.2" / "4.3"
+
+COMMENT  = "*%" *TCHAR LINE-END
+
+DATA     = "*" 1*KCHAR [ WSP 1*KCHAR [ "/" 1*TCHAR ] ] ":"
+           1*(*WSP VALUE) LINE-END
+
+VALUE    = 1*TCHAR / DQUOTE 1*SCHAR DQUOTE
+
+KCHAR    = ALPHA / DIGIT / "_" / "." / "-"
+
+SCHAR    = LINE-END / WSP / %x21.23-7E.A0-FF
+
+TCHAR    = %x20-7E.A0-FF
+
+LINE-END = CR / LF / CR LF
+</pre>
+
+
+<h2 class='title'><a name='AUTOCONFIG'>Auto-Configuration</a></h2>
+
+<p>CUPS supports several methods of auto-configuration via PPD keywords.</p>
+
+<h3><span class='info'>Deprecated</span><a name='APAutoSetupTool'>APAutoSetupTool</a></h3>
+
+<p class='summary'>*APAutoSetupTool: "/LibraryPrinters/vendor/filename"</p>
+
+<p>This deprecated keyword defines a program that sets the default option choices. It is run when a printer is added from the <var>Add Printer</var> window or the <var>Nearby Printers</var> list in the <var>Print</var> dialog.</p>
+
+<p>The program is provided with two arguments: the printer's device URI and the PPD file to be used for the printer. The program must write an updated PPD file to stdout.</p>
+
+<blockquote><b>Note:</b>
+
+<p>This keyword is deprecated. New printer drivers SHOULD provide a CUPS command filter and support the "AutoConfigure" command. Alternately, drivers MAY use the <a href="#OID">SNMP OID</a> keywords to configure network printers or <a href="#QUERYKEYWORD">PostScript query keywords</a> to configure PostScript printers.</p>
+
+</blockquote>
+<p>Examples:</p>
+
+<pre class='command'>
+*% Use our setup tool when adding a printer
+*APAutoSetupTool: "/Library/Printers/vendor/Tools/autosetuptool"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.2/CUPS 1.4</span><a name='QUERYKEYWORD'>?MainKeyword</a></h3>
+
+<p class='summary'>*?<i>MainKeyword</i>: "<br>
+  PostScript query code that writes a message using the = operator...<br>
+"<br>
+*End</p>
+
+<p>The <tt>?<i>MainKeyword</i></tt> keyword defines PostScript code that determines the currently selected/enabled option keyword (choice) for the main keyword (option). It is typically used when communicating with USB, serial, Appletalk, and AppSocket (port 9100) printers.</p>
+
+<p>The PostScript code typically sends its response back using the <tt>=</tt> operator.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+*OpenUI OptionDuplex/Duplexer Installed: Boolean
+*DuplexOptionDuplex: False
+*OptionDuplex False/Not Installed: ""
+*OptionDuplex True/Installed: ""
+
+<em>*% Query the printer for the presence of the duplexer option...</em>
+*?OptionDuplex: "
+  currentpagedevice /Duplex known
+  {(True)} {(False)} ifelse
+  = flush
+"
+*End
+*CloseUI: OptionDuplex
+</pre>
+
+<h3><span class='info'>Mac OS X 10.4/CUPS 1.5</span><a name='OID'>OIDMainKeyword</a></h3>
+
+<p class='summary'>*?OID<i>MainKeyword</i>: ".n.n.n..."<br>
+*OID<i>MainKeyword</i> <i>OptionKeyword1</i>: "value"<br>
+...<br>
+*OID<i>MainKeyword</i> <i>OptionKeywordN</i>: "value"</p>
+
+<p>The <tt>OID<i>MainKeyword</i></tt> keyword is used to define SNMP OIDs that map to installable options. The first (query) line defines the OID to lookup on the network device. The second and subsequent keywords define a mapping from OID value to option keyword. Since SNMP is an IP-based network protocol, this method is typically only used to configure AppSocket, IPP, and LPD network printers.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Get the installed memory on the printer...
+*?OIDInstalledMemory: ".1.3.6.1.2.1.25.2.2.0"
+*OIDInstalledMemory 16MB: "16384 KBytes"
+*OIDInstalledMemory 32MB: "32768 KBytes"
+*OIDInstalledMemory 48MB: "49152 KBytes"
+*OIDInstalledMemory 72MB: "73728 KBytes"
+</pre>
+
+
+<h2 class='title'><a name='PROFILES'>Color Profiles</a></h2>
+
+<p>CUPS supports three types of color profiles. The first type is based on sRGB and is used by the standard CUPS raster filters and GPL Ghostscript. The second type is based on ICC profiles and is used by the Quartz-based filters on MacOS X. The final type is based on well-known colorspaces such as sRGB and Adobe RGB.</p>
+
+<blockquote><b>Note:</b>
+
+<p>At this time, none of the CUPS raster filters support ICC profiles. This will be addressed as time and resources permit.</p>
+
+</blockquote>
+
+<h3><span class='info'>Deprecated</span><a name='cupsColorProfile'>cupsColorProfile</a></h3>
+
+<p class='summary'>*cupsColorProfile Resolution/MediaType: "density gamma m00 m01 m02 m10 m11 m12 m20 m21 m22"</p>
+
+<p>This string keyword specifies an sRGB-based color profile consisting of gamma and density controls and a 3x3 CMY color transform matrix. <em>This keyword is not supported on Mac OS X.</em></p>
+
+<p>The <i>Resolution</i> and <i>MediaType</i> values may be "-" to act as a wildcard. Otherwise they must match one of the <tt>Resolution</tt> or <tt>MediaType</tt> option keywords defined in the PPD file.</p>
+
+<p>The <i>density</i> and <i>gamma</i> values define gamma and
+density adjustment function such that:</p>
+
+<pre class='command'>
+f(x) = density * x <sup style='font-size: 100%'>gamma</sup>
+</pre>
+
+<p>The <i>m00</i> through <i>m22</i> values define a 3x3 transformation matrix for the CMY color values. The density function is applied <i>after</i> the CMY transformation:</p>
+
+<pre class='command'>
+| m00 m01 m02 |
+| m10 m11 m12 |
+| m20 m21 m22 |
+</pre>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify a profile for printing at 360dpi on all media types</em> 
+*cupsColorProfile 360dpi/-: "1.0 1.5 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
+
+<em>*% Specify a profile for printing at 720dpi on Glossy media</em> 
+*cupsColorProfile 720dpi/Glossy: "1.0 2.5 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
+
+<em>*% Specify a default profile for printing at all other resolutions and media types</em> 
+*cupsColorProfile -/-: "0.9 2.0 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
+</pre>
+
+
+<h3><span class='info'>Mac OS X 10.3/CUPS 1.2</span><a name='cupsICCProfile'>cupsICCProfile</a></h3>
+
+<p class='summary'>*cupsICCProfile ColorModel.MediaType.Resolution/Description: "filename"</p>
+
+<p>This keyword specifies an ICC color profile that is used to convert the document colors to the device colorspace. The <tt>ColorModel</tt>, <tt>MediaType</tt>, and <tt>Resolution</tt> option keywords specify a selector for color profiles. If omitted, the color profile will match any option keyword for the corresponding main keyword.</p>
+
+<p>The <tt>Description</tt> specifies human-readable text that is associated with the color profile. The <tt>filename</tt> portion specifies the ICC color profile to use; if the filename is not absolute, it is loaded relative to the <var>/usr/share/cups/profiles</var> directory.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify a profile for CMYK printing at 360dpi on all media types</em> 
+*cupsICCProfile CMYK..360dpi/360dpi CMYK: "/Library/Printers/vendor/Profiles/foo-360-cmyk.icc"
+
+<em>*% Specify a profile for RGB printing at 720dpi on Glossy media</em> 
+*cupsColorProfile RGB.Glossy.720dpi/720dpi Glossy: "/Library/Printers/vendor/Profiles/foo-720-glossy-rgb.icc"
+
+<em>*% Specify a default profile for printing at all other resolutions and media types</em> 
+*cupsICCProfile ../Default: "/Library/Printers/vendor/Profiles/foo-default.icc"
+</pre>
+
+<h4>Customizing the Profile Selection Keywords</h4>
+
+<p>The <tt>MediaType</tt> and <tt>Resolution</tt> main keywords can be reassigned to different main keywords, allowing drivers to do color profile selection based on different parameters. The <tt>cupsICCQualifier2</tt> and <tt>cupsICCQualifier3</tt> keywords define the mapping from selector to main keyword:</p>
+
+<pre class='command'>
+*cupsICCQualifier2: MainKeyword2
+*cupsICCQualifier3: MainKeyword3
+</pre>
+
+<p>The default mapping is as follows:</p>
+
+<pre class='command'>
+*cupsICCQualifier2: MediaType
+*cupsICCQualifier3: Resolution
+</pre>
+
+<h3><span class='info'>Mac OS X 10.4</span><a name='APCustom'>Custom Color Matching Support</a></h3>
+
+<p class='summary'>*<a href='#APSupportsCustomColorMatching'>APSupportsCustomColorMatching</a>: true<br>
+*<a href='#APCustomColorMatchingName'>APCustomColorMatchingName</a> name/text: ""<br>
+*<a href='#APCustomColorMatchingProfile'>APCustomColorMatchingProfile</a>: profile<br>
+*<a href='#APDefaultCustomColorMatchingProfile'>APDefaultCustomColorMatchingProfile</a>: profile</p>
+
+<p>These keywords tell the Mac OS X raster filters that the printer driver provides its own custom color matching and that generic color profiles should be used when generating 1-, 3-, and 4-component raster data as requested by the driver. The <tt>APCustomColorMatchingProfile</tt> and <tt>APDefaultColorMatchingProfile</tt> keywords specify alternate color profiles (sRGB or AdobeRGB) to use for 3-color (RGB) raster data.</p>
+
+<blockquote><b>Note:</b>
+
+<p>Prior to Mac OS X 10.6, the default RGB color space was Apple's "GenericRGB". The new default in Mac OS X 10.6 and later is "sRGB". For more information, see <a href="http://support.apple.com/kb/HT3712">"Mac OS X v10.6: About gamma 2.2"</a> on Apple's support site.</p>
+
+</blockquote>
+
+<h4><span class='info'>Mac OS X 10.5</span><a name='APCustomColorMatchingName'>APCustomColorMatchingName</a></h4>
+
+<p class='summary'>*APCustomColorMatchingName name/text: ""</p>
+
+<p>This keyword defines an alternate name for the color matching provided by a driver in the <var>Color Matching</var> print panel. The default is to use the name "Vendor Matching" or its localized equivalent.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Define the names for our color matching...
+*APCustomColorMatchingName name/AcmeColor(tm): ""
+*fr.APCustomColorMatchingName name/La AcmeColor(tm): ""
+</pre>
+
+<h4><span class='info'>Mac OS X 10.5</span><a name='APCustomColorMatchingProfile'>APCustomColorMatchingProfile</a></h4>
+
+<p class='summary'>*APCustomColorMatchingProfile: name</p>
+
+<p>This keyword defines a supported RGB color profile that can be used when doing custom color matching. Currently only <tt>sRGB</tt>, <tt>AdobeRGB</tt>, and <tt>GenericRGB</tt> are supported. If not specified, RGB data will use the GenericRGB colorspace.</p>
+
+<blockquote><b>Note:</b>
+
+<p>If you provide multiple <tt>APCustomColorMatchingProfile</tt> keywords, you are responsible for providing the necessary user interface controls to select the profile in a <a href='#APDialogExtension'>print dialog pane</a>. Add the named profile to the print settings using the key <tt>kPMCustomColorMatchingProfileKey</tt>.</p>
+
+</blockquote>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Use sRGB for RGB color by default, but support both sRGB and AdobeRGB
+*APSupportsCustomColorMatching: true
+*APDefaultCustomColorMatchingProfile: sRGB
+*APCustomColorMatchingProfile: sRGB
+*APCustomColorMatchingProfile: AdobeRGB
+</pre>
+
+<h4><span class='info'>Mac OS X 10.5</span><a name='APDefaultCustomColorMatchingProfile'>APDefaultCustomColorMatchingProfile</a></h4>
+
+<p class='summary'>*APDefaultCustomColorMatchingProfile: name</p>
+
+<p>This keyword defines the default RGB color profile that will be used when doing custom color matching. Currently only <tt>sRGB</tt>, <tt>AdobeRGB</tt>, and <tt>GenericRGB</tt> are supported.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Use sRGB for RGB color by default
+*APSupportsCustomColorMatching: true
+*APDefaultCustomColorMatchingProfile: sRGB
+</pre>
+
+<h4><span class='info'>Mac OS X 10.4</span><a name='APSupportsCustomColorMatching'>APSupportsCustomColorMatching</a></h4>
+
+<p class='summary'>*APSupportsCustomColorMatching: boolean</p>
+
+<p>This keyword specifies that the driver provides its own custom color matching. When <tt>true</tt>, the default hand-off colorspace will be GenericGray, GenericRGB, or GenericCMYK depending on the number of components the driver requests. The <a href='#APDefaultCustomColorMatchingProfile'><tt>APDefaultCustomColorMatchingProfile</tt></a> keyword can be used to override the default 3-component (RGB) colorspace.</p>
+
+<p>The default for <tt>APSupportsCustomColorMatching</tt> is <tt>false</tt>.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APSupportsCustomColorMatching: true
+*APDefaultCustomColorMatchingProfile: sRGB
+</pre>
+
+
+<h2 class='title'><a name='CONSTRAINTS'>Constraints</a></h2>
+
+<p>Constraints are option choices that are not allowed by the driver or device, for example printing 2-sided transparencies. All versions of CUPS support constraints defined by the legacy Adobe <tt>UIConstraints</tt> and <tt>NonUIConstraints</tt> keywords which support conflicts between any two option choices, for example:</p>
+
+<pre class='command'>
+*% Do not allow 2-sided printing on transparency media
+*UIConstraints: "*Duplex *MediaType Transparency"
+*UIConstraints: "*MediaType Transparency *Duplex"
+</pre>
+
+<p>While nearly all constraints can be expressed using these keywords, there are valid scenarios requiring constraints between more than two option choices. In addition, resolution of constraints is problematic since users and software have to guess how a particular constraint is best resolved.</p>
+
+<p>CUPS 1.4 and higher define two new keywords for constraints, <tt>cupsUIConstraints</tt> and <tt>cupsUIResolver</tt>. Each <tt>cupsUIConstraints</tt> keyword points to a <tt>cupsUIResolver</tt> keyword which specifies alternate options that resolve the conflict condition. The same <tt>cupsUIResolver</tt> can be used by multiple <tt>cupsUIConstraints</tt>.</p>
+
+<blockquote><b>Note:</b>
+
+<p>When developing PPD files that contain constraints, it is very important to use the <a href="man-cupstestppd.html">cupstestppd(1)</a> program to verify that your constraints are accurate and cannot result in unresolvable option selections.</p>
+
+</blockquote>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsUIConstraints'>cupsUIConstraints</a></h3>
+
+<p class='summary'>*cupsUIConstraints resolver: "*Keyword1 *Keyword2 ..."<br>
+*cupsUIConstraints resolver: "*Keyword1 OptionKeyword1 *Keyword2 ..."<br>
+*cupsUIConstraints resolver: "*Keyword1 *Keyword2 OptionKeyword2 ..."<br>
+*cupsUIConstraints resolver: "*Keyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."<br>
+*cupsUIConstraints: "*InstallableKeyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."</p>
+
+<p>Lists two or more options which conflict. The "resolver" string is a (possibly unique) keyword which specifies which options to change when the constraint exists. When no resolver is provided, CUPS first tries the default choice followed by testing each option choice to resolve the conflict.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify that 2-sided printing cannot happen on transparencies</em> 
+*cupsUIConstraints transparency: "*Duplex *MediaType Transparency"
+
+<em>*% Specify that envelope printing cannot happen from the paper trays</em> 
+*cupsUIConstraints envelope: "*PageSize Env10 *InputSlot Tray1"
+*cupsUIConstraints envelope: "*PageSize Env10 *InputSlot Tray1"
+*cupsUIConstraints envelope: "*PageSize EnvDL *InputSlot Tray2"
+*cupsUIConstraints envelope: "*PageSize EnvDL *InputSlot Tray2"
+
+<em>*% Specify an installable option constraint for the envelope feeder</em>
+*cupsUIConstraints: "*InputSlot EnvFeeder *InstalledEnvFeeder"
+
+<em>*% Specify that photo printing cannot happen on plain paper or transparencies at 1200dpi</em> 
+*cupsUIConstraints photo: "*OutputMode Photo *MediaType Plain *Resolution 1200dpi"
+*cupsUIConstraints photo: "*OutputMode Photo *MediaType Transparency *Resolution 1200dpi"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsUIResolver'>cupsUIResolver</a></h3>
+
+<p class='summary'>*cupsUIResolution resolver: "*Keyword1 OptionKeyword1 *Keyword2 OptionKeyword2 ..."</p>
+
+<p>Specifies two or more options to mark/select to resolve a constraint. The "resolver" string identifies a particular action to take for one or more <a href='#cupsUIConstraints'><tt>cupsUIConstraints</tt></a>. The same action can be used for multiple constraints. The option keyword pairs are treated as an ordered list of option selections to try - only the first N selections will be used, where N is the minimum number of selections required. Because <a href="api-ppd.html#cupsResolveConflicts"><code>cupsResolveConflicts()</code></a> will not change the most recent option selection passed to it, at least two options from the constraints must be listed to avoid situations where conflicts cannot be resolved.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify the options to change for the 2-sided transparency constraint</em> 
+*cupsUIResolver transparency: "*Duplex None *MediaType Plain"
+
+<em>*% Specify the options to change for the envelope printing constraints.  Notice
+*% that we try to change the InputSlot to either the envelope feeder or the
+*% manual feed first, then we change the page size...</em>
+*cupsUIResolver envelope: "*InputSlot EnvFeeder *InputSlot ManualFeed *PageSize Letter"
+
+<em>*% Specify the options to change for the photo printing constraints</em> 
+*cupsUIResolver photo: "*OutputMode Best *Resolution 600dpi"
+</pre>
+
+
+<h2 class='title'><a name='I18N'>Globalized PPD Support</a></h2>
+
+<p>CUPS 1.2 and higher adds support for PPD files containing multiple languages by following the following additional rules:</p>
+
+<ol>
+
+       <li>The <tt>LanguageVersion</tt> MUST be <tt>English</tt></li>
+
+       <li>The <tt>LanguageEncoding</tt> MUST be <tt>ISOLatin1</tt></li>
+
+       <li>The <tt>cupsLanguages</tt> keyword MUST be provided and list each of the supported locales in the PPD file</li>
+
+       <li>Main and option keywords MUST NOT exceed 34 (instead of 40) characters to allow room for the locale prefixes in translation keywords</li>
+
+       <li>The main keyword "Translation" MUST NOT be used</li>
+
+       <li>Translation strings included with the main and option keywords MUST NOT contain characters outside the ASCII subset of ISOLatin1 and UTF-8; developers wishing to use characters outside ASCII MUST provide a separate set of English localization keywords for the affected keywords.</li>
+
+       <li>Localizations are specified using a locale prefix of the form "ll" or "ll_CC." where "ll" is the 2-letter ISO language code and "CC" is the 2-letter ISO country code<ul>
+               <li>A generic language translation ("ll") SHOULD be provided with country-specific differences ("ll_CC") provided only as needed</li>
+               <li>For historical reasons, the "zh" and "zh_CN" locales map to Simplified Chinese while the "zh_TW" locale maps to Traditional Chinese</li>
+       </ul></li>
+
+       <li>Locale-specific translation strings MUST be encoded using UTF-8.</li>
+
+       <li>Main keywords MUST be localized using one of the following forms:
+       <p><tt>*ll.Translation MainKeyword/translation text: ""</tt><br />
+       <tt>*ll_CC.Translation MainKeyword/translation text: ""</tt></p></li>
+
+       <li>Option keywords MUST be localized using one of the following forms:
+       <p><tt>*ll.MainKeyword OptionKeyword/translation text: ""</tt><br>
+       <tt>*ll_CC.MainKeyword OptionKeyword/translation text: ""</tt></p></li>
+
+       <li>Localization keywords MAY appear anywhere after the first line of the PPD file</li>
+
+</ol>
+
+<blockquote><b>Note:</b>
+
+<p>We use a <tt>LanguageEncoding</tt> value of <tt>ISOLatin1</tt> and limit the allowed base translation strings to ASCII to avoid character coding issues that would otherwise occur. In addition, requiring the base translation strings to be in English allows for easier fallback translation when no localization is provided in the PPD file for a given locale.</p>
+
+</blockquote>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*LanguageVersion: English
+*LanguageEncoding: ISOLatin1
+*cupsLanguages: "de fr_CA"
+*ModelName: "Foobar Laser 9999"
+
+<em>*% Localize ModelName for French and German</em>
+*fr_CA.Translation ModelName/La Foobar Laser 9999: ""
+*de.Translation ModelName/Foobar LaserDrucken 9999: ""
+
+*cupsIPPReason com.vendor-error/A serious error occurred: "/help/com.vendor/error.html"
+<em>*% Localize printer-state-reason for French and German</em>
+*fr_CA.cupsIPPReason com.vendor-error/Une erreur s&egrave;rieuse s'est produite: "/help/com.vendor/error.html"
+*de.cupsIPPReason com.vendor-error/Eine ernste St&ouml;rung trat: "/help/com.vendor/error.html"
+
+...
+
+*OpenUI *InputSlot/Paper Source: PickOne
+*OrderDependency: 10 AnySetup *InputSlot
+*DefaultInputSlot: Auto
+<em>*% Localize InputSlot for French and German</em>
+*fr_CA.Translation InputSlot/Papier source: ""
+*de.Translation InputSlot/Papiereinzug: ""
+*InputSlot Auto/Default: "&lt;&lt;/ManualFeed false&gt;&gt;setpagedevice"
+<em>*% Localize InputSlot=Auto for French and German</em>
+*fr_CA.InputSlot Auto/Par Defaut: ""
+*de.InputSlot Auto/Standard: ""
+*InputSlot Manual/Manual Feed: "&lt;&lt;/ManualFeed true&gt;&gt;setpagedevice"
+<em>*% Localize InputSlot=Manual for French and German</em>
+*fr_CA.InputSlot Manual/Manuel mecanisme de alimentation: ""
+*de.InputSlot Manual/Manueller Einzug: ""
+*CloseUI: *InputSlot
+</pre>
+
+
+<h2 class='title'><a name='OPTIONS'><span class="info">CUPS 1.3/Mac OS X 10.6</span>Custom Options</a></h2>
+
+<p>CUPS supports custom options using an extension of the <tt>CustomPageSize</tt> and <tt>ParamCustomPageSize</tt> syntax:</p>
+
+<pre class='command'>
+*CustomFoo True: "command"
+*ParamCustomFoo Name1/Text 1: order type minimum maximum
+*ParamCustomFoo Name2/Text 2: order type minimum maximum
+...
+*ParamCustomFoo NameN/Text N: order type minimum maximum
+</pre>
+
+<p>When the base option is part of the <tt>JCLSetup</tt> section, the "command" string contains JCL commands with "\order" placeholders for each numbered parameter. The CUPS API handles any necessary value quoting for HP-PJL commands. For example, if the JCL command string is "@PJL SET PASSCODE=\1" and the first
+option value is "1234" then CUPS will output the string "@PJL SET PASSCODE=1234".</p>
+
+<p>For non-<tt>JCLSetup</tt> options, the "order" value is a number from 1 to N and specifies the order of values as they are placed on the stack before the command. For example, if the PostScript command string is "&lt;&lt;/cupsReal1 2 1 roll&gt;&gt;setpagedevice" and the option value is "2.0" then CUPS will output the string "2.0 &lt;&lt;/cupsReal1 2 1 roll&gt;&gt;setpagedevice".</p>
+
+<p>The "type" is one of the following keywords:</p>
+
+<ul>
+
+       <li><tt>curve</tt> - a real value from "minimum" to "maximum" representing a gamma correction curve using the function: f(x) = x <sup>value</sup></li>
+
+       <li><tt>int</tt> - an integer value from "minimum" to "maximum"</li>
+
+       <li><tt>invcurve</tt> - a real value from "minimum" to "maximum" representing a gamma correction curve using the function: f(x) = x <sup>1 / value</sup></li>
+
+       <li><tt>passcode</tt> - a string of numbers value with a minimum of "minimum" numbers and a maximum of "maximum" numbers ("minimum" and "maximum" are numbers and passcode strings are not displayed in the user interface)</li>
+
+       <li><tt>password</tt> - a string value with a minimum of "minimum" characters and a maximum of "maximum" characters ("minimum" and "maximum" are numbers and password strings are not displayed in the user interface)</li>
+
+       <li><tt>points</tt> - a measurement value in points from "minimum" to "maximum"</li>
+
+       <li><tt>real</tt> - a real value from "minimum" to "maximum"</li>
+
+       <li><tt>string</tt> - a string value with a minimum of "minimum" characters and a maximum of "maximum" characters ("minimum" and "maximum" are numbers)</li>
+
+</ul>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Base JCL key code option</em> 
+*JCLOpenUI JCLPasscode/Key Code: PickOne
+*OrderDependency: 10 JCLSetup *JCLPasscode
+*DefaultJCLPasscode: None
+*JCLPasscode None/No Code: ""
+*JCLPasscode 1111: "@PJL SET PASSCODE = 1111&lt;0A&gt;"
+*JCLPasscode 2222: "@PJL SET PASSCODE = 2222&lt;0A&gt;"
+*JCLPasscode 3333: "@PJL SET PASSCODE = 3333&lt;0A&gt;"
+*JCLCloseUI: *JCLPasscode
+
+<em>*% Custom JCL key code option</em> 
+*CustomJCLPasscode True: "@PJL SET PASSCODE = \1&lt;0A&gt;"
+*ParamCustomJCLPasscode Code/Key Code: 1 passcode 4 4
+
+
+<em>*% Base PostScript watermark option</em>
+*OpenUI WatermarkText/Watermark Text: PickOne
+*OrderDependency: 10 AnySetup *WatermarkText
+*DefaultWatermarkText: None
+*WatermarkText None: ""
+*WatermarkText Draft: "&lt;&lt;/cupsString1(Draft)&gt;&gt;setpagedevice"
+*CloseUI: *WatermarkText
+
+<em>*% Custom PostScript watermark option</em>
+*CustomWatermarkText True: "&lt;&lt;/cupsString1 3 -1 roll&gt;&gt;setpagedevice"
+*ParamCustomWatermarkText Text: 1 string 0 32
+
+
+<em>*% Base PostScript gamma/density option</em> 
+*OpenUI GammaDensity/Gamma and Density: PickOne
+*OrderDependency: 10 AnySetup *GammaDensity
+*DefaultGammaDensity: Normal
+*GammaDensity Normal/Normal: "&lt;&lt;/cupsReal1 1.0/cupsReal2 1.0&gt;&gt;setpagedevice"
+*GammaDensity Light/Lighter: "&lt;&lt;/cupsReal1 0.9/cupsReal2 0.67&gt;&gt;setpagedevice"
+*GammaDensity Dark/Darker: "&lt;&lt;/cupsReal1 1.1/cupsReal2 1.5&gt;&gt;setpagedevice"
+*CloseUI: *GammaDensity
+
+<em>*% Custom PostScript gamma/density option</em> 
+*CustomGammaDensity True: "&lt;&lt;/cupsReal1 3 -1 roll/cupsReal2 5 -1&gt;&gt;setpagedevice"
+*ParamCustomGammaDensity Gamma: 1 curve 0.1 10
+*ParamCustomGammaDensity Density: 2 real 0 2
+</pre>
+
+
+<h2 class='title'><a name='RASTERPS'>Writing PostScript Option Commands for Raster Drivers</a></h2>
+
+<p>PPD files are used for both PostScript and non-PostScript printers. For CUPS raster drivers, you use a subset of the PostScript language to set page device keywords such as page size, resolution, and so forth. For example, the following code sets the page size to A4 size:</p>
+
+<pre class='command'>
+*PageSize A4: "&lt;&lt;/PageSize[595 842]&gt;&gt;setpagedevice"
+</pre>
+
+<p>Custom options typically use other operators to organize the values into a key/value dictionary for <tt>setpagedevice</tt>. For example, our previous <tt>CustomWatermarkText</tt> option code uses the <tt>roll</tt> operator to move the custom string value into the dictionary for <tt>setpagedevice</tt>:</p>
+
+<pre class='command'>
+*CustomWatermarkText True: "&lt;&lt;/cupsString1 3 -1 roll&gt;&gt;setpagedevice"
+</pre>
+
+<p>For a custom string value of "My Watermark", CUPS will produce the following PostScript code for the option:</p>
+
+<pre class='command'>
+(My Watermark)
+&lt;&lt;/cupsString1 3 -1 roll&gt;&gt;setpagedevice
+</pre>
+
+<p>The code moves the string value ("My Watermark") from the bottom of the stack to the top, creating a dictionary that looks like:</p>
+
+<pre class='command'>
+&lt;&lt;/cupsString1(My Watermark)&gt;&gt;setpagedevice
+</pre>
+
+<p>The resulting dictionary sets the page device attributes that are sent to your raster driver in the page header.</p>
+
+<h3>Custom Page Size Code</a></h3>
+
+<p>There are many possible implementations of the <tt>CustomPageSize</tt> code. For CUPS raster drivers, the following code is recommended:</p>
+
+<pre class='command'>
+*ParamCustomPageSize Width:        1 points <i>min-width max-width</i>
+*ParamCustomPageSize Height:       2 points <i>min-height max-height</i>
+*ParamCustomPageSize WidthOffset:  3 points 0 0
+*ParamCustomPageSize HeightOffset: 4 points 0 0
+*ParamCustomPageSize Orientation:  5 int 0 0
+*CustomPageSize True: "pop pop pop &lt;&lt;/PageSize[5 -2 roll]/ImagingBBox null&gt;&gt;setpagedevice"
+</pre>
+
+<h3>Supported PostScript Operators</a></h3>
+
+<p>CUPS supports the following PostScript operators in addition to the usual PostScript number, string (literal and hex-encoded), boolean, null, and name values:</p>
+
+<ul>
+
+       <li><tt>&lt;&lt;</tt> - Start a dictionary.</li>
+
+       <li><tt>&gt;&gt;</tt> - End a dictionary.</li>
+
+       <li><tt>[</tt> - Start an array.</li>
+
+       <li><tt>]</tt> - End an array.</li>
+
+       <li><tt>copy</tt> - Copy the top N objects on the stack.</li>
+
+       <li><tt>dup</tt> - Copy the top object on the stack.</li>
+
+       <li><tt>index</tt> - Copy the Nth from the top object on the stack.</li>
+
+       <li><tt>pop</tt> - Pop the top object on the stack.</li>
+
+       <li><tt>roll</tt> - Shift the top N objects on the stack.</li>
+
+       <li><tt>setpagedevice</tt> - Set the page header values according to the key/value dictionary on the stack.</li>
+
+</ul>
+
+<blockquote><b>Note:</b>
+
+<p><em>Never</em> use the unsupported <tt>dict</tt> or <tt>put</tt>
+operators in your option code. These operators are typically used in
+option code dating back to Level 1 PostScript printers, which did not
+support the simpler <tt>&lt;&lt;</tt> or <tt>&gt;&gt;</tt> operators.
+If you have old option code using <tt>dict</tt> or <tt>put</tt>, you can
+rewrite it very easily to use the newer <tt>&lt;&lt;</tt> and
+<tt>&gt;&gt;</tt> operators instead. For example, the following code
+to set the page size:</p>
+
+<style type='text/css'><!--
+PRE B {
+  background: #000000;
+  color: #ffffff;
+  padding: 2px 5px;
+}
+--></style>
+
+<pre class='command'>
+<b>1 dict dup</b> /PageSize [612 792] <b>put</b> setpagedevice
+</pre>
+
+<p>can be rewritten as:</p>
+
+<pre class='command'>
+<b>&lt;&lt;</b> /PageSize [612 792] <b>&gt;&gt;</b> setpagedevice
+</pre>
+
+</blockquote>
+
+<h3>Supported Page Device Attributes</a></h3>
+
+<p>Table 2 shows the supported page device attributes along with PostScript code examples.</p>
+
+<div class='table'>
+<table summary='Supported Page Device Attributes'>
+<caption>Table 2: <a name='TABLE_2'>Supported Page Device Attributes</a></caption>
+<thead>
+<tr>
+       <th>Name(s)</th>
+       <th>Type</th>
+       <th>Description</th>
+       <th>Example(s)</th>
+</tr>
+</thead>
+<tbody>
+<tr valign='top'>
+       <td><tt>AdvanceDistance</tt></td>
+       <td>Integer</td>
+       <td>Specifies the number of points to advance roll media after printing.</td>
+       <td><tt>&lt;&lt;/AdvanceDistance 18&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>AdvanceMedia</tt></td>
+       <td>Integer</td>
+       <td>Specifies when to advance the media: 0 = never, 1 = after the file, 2 = after the job, 3 = after the set, and 4 = after the page.</td>
+       <td><tt>&lt;&lt;/AdvanceMedia 4&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>Collate</tt></td>
+       <td>Boolean</td>
+       <td>Specifies whether collated copies are required.</td>
+       <td><tt>&lt;&lt;/Collate true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>CutMedia</tt></td>
+       <td>Integer</td>
+       <td>Specifies when to cut the media: 0 = never, 1 = after the file, 2 = after the job, 3 = after the set, and 4 = after the page.</td>
+       <td><tt>&lt;&lt;/CutMedia 1&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>Duplex</tt></td>
+       <td>Boolean</td>
+       <td>Specifies whether 2-sided printing is required.</td>
+       <td><tt>&lt;&lt;/Duplex true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>HWResolution</tt></td>
+       <td>Integer Array</td>
+       <td>Specifies the resolution of the page image in pixels per inch.</td>
+       <td><tt>&lt;&lt;/HWResolution[1200 1200]&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>InsertSheet</tt></td>
+       <td>Boolean</td>
+       <td>Specifies whether to insert a blank sheet before the job.</td>
+       <td><tt>&lt;&lt;/InsertSheet true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>Jog</tt></td>
+       <td>Integer</td>
+       <td>Specifies when to shift the media in the output bin: 0 = never, 1 = after the file, 2 = after the job, 3 = after the set, and 4 = after the page.</td>
+       <td><tt>&lt;&lt;/Jog 2&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>LeadingEdge</tt></td>
+       <td>Integer</td>
+       <td>Specifies the leading edge of the media: 0 = top, 1 = right, 2 = bottom, 3 = left.</td>
+       <td><tt>&lt;&lt;/LeadingEdge 0&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>ManualFeed</tt></td>
+       <td>Boolean</td>
+       <td>Specifies whether media should be drawn from the manual feed tray. Note: The <tt>MediaPosition</tt> attribute is preferred over the <tt>ManualFeed</tt> attribute.</td>
+       <td><tt>&lt;&lt;/ManualFeed true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>MediaClass</tt></td>
+       <td>String</td>
+       <td>Specifies a named media.</td>
+       <td><tt>&lt;&lt;/MediaClass (Invoices)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>MediaColor</tt></td>
+       <td>String</td>
+       <td>Specifies the color of the media.</td>
+       <td><tt>&lt;&lt;/MediaColor &gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>MediaPosition</tt></td>
+       <td>Integer</td>
+       <td>Specifies the tray or source of the media.</td>
+       <td><tt>&lt;&lt;/MediaPosition 12&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>MediaType</tt></td>
+       <td>String</td>
+       <td>Specifies the general media type.</td>
+       <td><tt>&lt;&lt;/MediaType (Glossy)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>MediaWeight</tt></td>
+       <td>Integer</td>
+       <td>Specifies the media weight in grams per meter<sup>2</sup>.</td>
+       <td><tt>&lt;&lt;/MediaWeight 100&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>MirrorPrint</tt></td>
+       <td>Boolean</td>
+       <td>Specifies whether to flip the output image horizontally.</td>
+       <td><tt>&lt;&lt;/MirrorPrint true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>NegativePrint</tt></td>
+       <td>Boolean</td>
+       <td>Specifies whether to invert the output image.</td>
+       <td><tt>&lt;&lt;/NegativePrint true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>NumCopies</tt></td>
+       <td>Integer</td>
+       <td>Specifies the number of copies to produce of each page.</td>
+       <td><tt>&lt;&lt;/NumCopies 100&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>Orientation</tt></td>
+       <td>Integer</td>
+       <td>Specifies the orientation of the output: 0 = portrait, 1 = landscape rotated counter-clockwise, 2 = upside-down, 3 = landscape rotated clockwise.</td>
+       <td><tt>&lt;&lt;/Orientation 3&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>OutputFaceUp</tt></td>
+       <td>Boolean</td>
+       <td>Specifies whether to place the media face-up in the output bin/tray.</td>
+       <td><tt>&lt;&lt;/OutputFaceUp true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>OutputType</tt></td>
+       <td>String</td>
+       <td>Specifies the output type name.</td>
+       <td><tt>&lt;&lt;/OutputType (Photo)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>PageSize</tt></td>
+       <td>Integer/Real Array</td>
+       <td>Specifies the width and length/height of the page in points.</td>
+       <td><tt>&lt;&lt;/PageSize[595 842]&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>Separations</tt></td>
+       <td>Boolean</td>
+       <td>Specifies whether to produce color separations.</td>
+       <td><tt>&lt;&lt;/Separations true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>TraySwitch</tt></td>
+       <td>Boolean</td>
+       <td>Specifies whether to switch trays automatically.</td>
+       <td><tt>&lt;&lt;/TraySwitch true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>Tumble</tt></td>
+       <td>Boolean</td>
+       <td>Specifies whether the back sides of pages are rotated 180 degrees.</td>
+       <td><tt>&lt;&lt;/Tumble true&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsBorderlessScalingFactor</tt></td>
+       <td>Real</td>
+       <td>Specifies the amount to scale the page image dimensions.</td>
+       <td><tt>&lt;&lt;/cupsBorderlessScalingFactor 1.01&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsColorOrder</tt></td>
+       <td>Integer</td>
+       <td>Specifies the order of colors: 0 = chunked, 1 = banded, 2 = planar.</td>
+       <td><tt>&lt;&lt;/cupsColorOrder 0&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsColorSpace</tt></td>
+       <td>Integer</td>
+       <td>Specifies the page image colorspace: 0 = W, 1 = RGB, 2 = RGBA, 3 = K, 4 = CMY, 5 = YMC, 6 = CMYK, 7 = YMCK, 8 = KCMY, 9 = KCMYcm, 10 = GMCK, 11 = GMCS, 12 = White, 13 = Gold, 14 = Silver, 15 = CIE XYZ, 16 = CIE Lab, 17 = RGBW, 32 to 46 = CIE Lab (1 to 15 inks)</td>
+       <td><tt>&lt;&lt;/cupsColorSpace 1 &gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsCompression</tt></td>
+       <td>Integer</td>
+       <td>Specifies a driver compression type/mode.</td>
+       <td><tt>&lt;&lt;/cupsCompression 2&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsInteger0<br>
+       ...<br>
+       cupsInteger15</tt></td>
+       <td>Integer</td>
+       <td>Specifies driver integer values.</td>
+       <td><tt>&lt;&lt;/cupsInteger11 1234&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsMarkerType</tt></td>
+       <td>String</td>
+       <td>Specifies the type of ink/toner to use.</td>
+       <td><tt>&lt;&lt;/cupsMarkerType (Black+Color)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsMediaType</tt></td>
+       <td>Integer</td>
+       <td>Specifies a numeric media type.</td>
+       <td><tt>&lt;&lt;/cupsMediaType 999&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsPageSizeName</tt></td>
+       <td>String</td>
+       <td>Specifies the name of the page size.</td>
+       <td><tt>&lt;&lt;/cupsPageSizeName (A4.Full)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsPreferredBitsPerColor</tt></td>
+       <td>Integer</td>
+       <td>Specifies the preferred number of bits per color, typically 8 or 16.</td>
+       <td><tt>&lt;&lt;/cupsPreferredBitsPerColor 16&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsReal0<br>
+       ...<br>
+       cupsReal15</tt></td>
+       <td>Real</td>
+       <td>Specifies driver real number values.</td>
+       <td><tt>&lt;&lt;/cupsReal15 1.234&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsRenderingIntent</tt></td>
+       <td>String</td>
+       <td>Specifies the color rendering intent.</td>
+       <td><tt>&lt;&lt;/cupsRenderingIntent (AbsoluteColorimetric)&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsRowCount</tt></td>
+       <td>Integer</td>
+       <td>Specifies the number of rows of raster data to print on each line for some drivers.</td>
+       <td><tt>&lt;&lt;/cupsRowCount 24&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsRowFeed</tt></td>
+       <td>Integer</td>
+       <td>Specifies the number of rows to feed between passes for some drivers.</td>
+       <td><tt>&lt;&lt;/cupsRowFeed 17&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsRowStep</tt></td>
+       <td>Integer</td>
+       <td>Specifies the number of lines between columns/rows on the print head for some drivers.</td>
+       <td><tt>&lt;&lt;/cupsRowStep 2&gt;&gt;setpagedevice</tt></td>
+</tr>
+<tr valign='top'>
+       <td><tt>cupsString0<br>
+       ...<br>
+       cupsString15</tt></td>
+       <td>String</td>
+       <td>Specifies driver string values.</td>
+       <td><tt>&lt;&lt;/cupsString0(String Value)&gt;&gt;setpagedevice</tt></td>
+</tr>
+</tbody>
+</table></div>
+
+
+<h2 class='title'><a name='MEDIA'>Media Keywords</a></h2>
+
+<p>The CUPS media keywords allow drivers to specify alternate custom page
+size limits based on up to two options.</p>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMediaQualifier2'>cupsMediaQualifier2</a></h3>
+
+<p class='summary'>*cupsMediaQualifier2: MainKeyword</p>
+
+<p>This keyword specifies the second option to use for overriding the
+custom page size limits.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMediaQualifier3'>cupsMediaQualifier3</a></h3>
+
+<p class='summary'>*cupsMediaQualifier3: MainKeyword</p>
+
+<p>This keyword specifies the third option to use for overriding the
+custom page size limits.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMinSize'>cupsMinSize</a></h3>
+
+<p class='summary'>*cupsMinSize .Qualifier2.Qualifier3: "width length"<br>
+*cupsMinSize .Qualifier2.: "width length"<br>
+*cupsMinSize ..Qualifier3: "width length"</p>
+
+<p>This keyword specifies alternate minimum custom page sizes in points.
+The <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a> and
+<a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a> keywords
+are used to identify options to use for matching.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMaxSize'>cupsMaxSize</a></h3>
+
+<p class='summary'>*cupsMaxSize .Qualifier2.Qualifier3: "width length"<br>
+*cupsMaxSize .Qualifier2.: "width length"<br>
+*cupsMaxSize ..Qualifier3: "width length"</p>
+
+<p>This keyword specifies alternate maximum custom page sizes in points.
+The <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a> and
+<a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a> keywords
+are used to identify options to use for matching.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify alternate custom page size limits based on InputSlot and Quality</em>
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+</pre>
+
+
+<h2 class='title'><a name='ATTRIBUTES'>General Attributes</a></h2>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsBackSide'>cupsBackSide</a></h3>
+
+<p class='summary'>*cupsBackSide: keyword</p>
+
+<p>This keyword requests special handling of the back side of pages
+when doing duplexed (2-sided) output. <a href='#TABLE_1'>Table 1</a>
+shows the supported keyword values for this keyword and their effect
+on the raster data sent to your driver. For example, when <tt>cupsBackSide</tt>
+is <code>Rotated</code> and <tt>Tumble</tt> is <tt>false</tt>, your driver
+will receive print data starting at the bottom right corner of the page, with
+each line going right-to-left instead of left-to-right. The default value is
+<code>Normal</code>.</p>
+
+<blockquote><b>Note:</b>
+
+<p><tt>cupsBackSide</tt> replaces the older <tt>cupsFlipDuplex</tt>
+keyword - if <tt>cupsBackSide</tt> is specified, <tt>cupsFlipDuplex</tt>
+will be ignored.</p>
+
+</blockquote>
+
+<div class='table'>
+<table width='80%' summary='Back Side Raster Coordinate System'>
+<caption>Table 1: <a name='TABLE_1'>Back Side Raster Coordinate System</a></caption>
+<thead>
+<tr>
+       <th>cupsBackSide</th>
+       <th>Tumble Value</th>
+       <th>Image Presentation</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+       <td><code>Normal</code></td>
+       <td><code>false</code></td>
+       <td>Left-to-right, top-to-bottom</td>
+</tr>
+<tr>
+       <td><code>Normal</code></td>
+       <td><code>true</code></td>
+       <td>Left-to-right, top-to-bottom</td>
+</tr>
+<tr>
+       <td><code>ManualTumble</code></td>
+       <td><code>false</code></td>
+       <td>Left-to-right, top-to-bottom</td>
+</tr>
+<tr>
+       <td><code>ManualTumble</code></td>
+       <td><code>true</code></td>
+       <td>Right-to-left, bottom-to-top</td>
+</tr>
+<tr>
+       <td><code>Rotated</code></td>
+       <td><code>false</code></td>
+       <td>Right-to-left, bottom-to-top</td>
+</tr>
+<tr>
+       <td><code>Rotated</code></td>
+       <td><code>true</code></td>
+       <td>Right-to-left, top-to-bottom</td>
+</tr>
+<tr>
+       <td><code>Flipped</code> *</td>
+       <td><code>false</code></td>
+       <td>Left-to-right, bottom-to-top</td>
+</tr>
+<tr>
+       <td><code>Flipped</code> *</td>
+       <td><code>true</code></td>
+       <td>Right-to-left, top-to-bottom</td>
+</tr>
+</tbody>
+</table>
+</div>
+
+<p><em>* - Not supported in Mac OS X 10.5.x and earlier</em></p>
+
+<div class='figure'><table summary='Back side images'>
+<caption>Figure 1: Back side images</caption>
+<tr><td><img src='../images/raster.png' width='624' height='448' alt='Back side images'></td></tr>
+</table></div>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Flip the page image for the back side of duplexed output</em> 
+*cupsBackSide: Flipped
+
+<em>*% Rotate the page image for the back side of duplexed output</em> 
+*cupsBackSide: Rotated
+</pre>
+
+<p>Also see the related <a href='#APDuplexRequiresFlippedMargin'><tt>APDuplexRequiresFlippedMargin</tt></a>
+keyword.</p>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsCommands'>cupsCommands</a></h3>
+
+<p class='summary'>*cupsCommands: "name name2 ... nameN"</p>
+
+<p>This string keyword specifies the commands that are supported by the
+CUPS command file filter for this device. The command names are separated
+by whitespace.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify the list of commands we support</em> 
+*cupsCommands: "AutoConfigure Clean PrintSelfTestPage ReportLevels com.vendor.foo"
+</pre>
+
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsEvenDuplex'>cupsEvenDuplex</a></h3>
+
+<p class='summary'>*cupsEvenDuplex: boolean</p>
+
+<p>This boolean keyword notifies the RIP filters that the
+destination printer requires an even number of pages when 2-sided
+printing is selected. The default value is <code>false</code>.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Always send an even number of pages when duplexing</em> 
+*cupsEvenDuplex: true
+</pre>
+
+<h3><a name='cupsFax'>cupsFax</a></h3>
+
+<p class='summary'>*cupsFax: boolean</p>
+
+<p>This boolean keyword specifies whether the PPD defines a facsimile device. The default is <tt>false</tt>.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*cupsFax: true
+</pre>
+
+<h3><a name='cupsFilter'>cupsFilter</a></h3>
+
+<p class='summary'>*cupsFilter: "source/type cost program"</p>
+
+<p>This string keyword provides a conversion rule from the
+given source type to the printer's native format using the
+filter "program". If a printer supports the source type directly,
+the special filter program "-" may be specified.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Standard raster printer driver filter</em> 
+*cupsFilter: "application/vnd.cups-raster 100 rastertofoo"
+
+<em>*% Plain text filter</em> 
+*cupsFilter: "text/plain 10 texttofoo"
+
+<em>*% Pass-through filter for PostScript printers</em> 
+*cupsFilter: "application/vnd.cups-postscript 0 -"
+</pre>
+
+<h3><span class='info'>Deprecated</span><a name='cupsFlipDuplex'>cupsFlipDuplex</a></h3>
+
+<p class='summary'>*cupsFlipDuplex: boolean</p>
+
+<p>Due to implementation differences between Mac OS X and Ghostscript,
+the <tt>cupsFlipDuplex</tt> keyword is deprecated. Instead, use
+the <a href='#cupsBackSide'><tt>cupsBackSide</tt></a> keyword to specify
+the coordinate system (pixel layout) of the page data on the back side of
+duplex pages.</p>
+
+<p>The value <code>true</code> maps to a <tt>cupsBackSide</tt> value
+of <code>Rotated</code> on Mac OS X and <code>Flipped</code> with
+Ghostscript.</p>
+
+<p>The default value is <code>false</code>.</p>
+
+<blockquote><b>Note:</b>
+
+<p>Mac OS X drivers that previously used
+<tt>cupsFlipDuplex</tt> may wish to provide both the old and
+new keywords for maximum compatibility, for example:</p>
+
+<pre class='command'>
+*cupsBackSide: Rotated
+*cupsFlipDuplex: true
+</pre>
+
+<p>Similarly, drivers written for other operating systems using
+Ghostscript can use:</p>
+
+<pre class='command'>
+*cupsBackSide: Flipped
+*cupsFlipDuplex: true
+</pre></blockquote>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsIPPFinishings'>cupsIPPFinishings</a></h3>
+
+<p class='summary'>*cupsIPPFinishings number/text: "*Option Choice ..."</p>
+
+<p>This keyword defines a mapping from IPP <code>finishings</code>
+values to PPD options and choices.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*cupsIPPFinishings 4/staple: "*StapleLocation SinglePortrait"
+*cupsIPPFinishings 5/punch: "*PunchMedia Yes *PunchLocation LeftSide"
+*cupsIPPFinishings 20/staple-top-left: "*StapleLocation SinglePortrait"
+*cupsIPPFinishings 21/staple-bottom-left: "*StapleLocation SingleLandscape"
+</pre>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsIPPReason'>cupsIPPReason</a></h3>
+
+<p class='summary'>*cupsIPPReason reason/Reason Text: "optional URIs"</p>
+
+<p>This optional keyword maps custom
+<code>printer-state-reasons</code> keywords that are generated by
+the driver to human readable text. The optional URIs string
+contains zero or more URIs separated by a newline. Each URI can
+be a CUPS server absolute path to a help file under the
+scheduler's <code>DocumentRoot</code> directory, a full HTTP URL
+("http://www.domain.com/path/to/help/page.html"), or any other
+valid URI which directs the user at additional information
+concerning the condition that is being reported.</p>
+
+<p>Since the reason text is limited to 80 characters by the PPD specification,
+longer text strings can be included by URI-encoding the text with the "text"
+scheme, for example "text:some%20text". Multiple <code>text</code> URIs are
+combined (with spaces between each URI) by the <tt>ppdLocalizeIPPReason</tt>
+into a single string that can be displayed to the user.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Map com.vendor-error to text but no page</em>
+*cupsIPPReason com.vendor-error/A serious error occurred: ""
+
+<em>*% Map com.vendor-error to more than 80 characters of text but no page</em>
+*cupsIPPReason com.vendor-error/A serious error occurred: "text:Now%20is%20the%20time
+text:for%20all%20good%20men%20to%20come%20to%20the%20aid%20of%20their%20country."
+
+<em>*% Map com.vendor-error to text and a local page</em>
+*cupsIPPReason com.vendor-error/A serious error occurred: "/help/com.vendor/error.html"
+
+<em>*% Map com.vendor-error to text and a remote page</em>
+*cupsIPPReason com.vendor-error/A serious error occurred: "http://www.vendor.com/help"
+
+<em>*% Map com.vendor-error to text and a local, Apple help book, and remote page</em>
+*APHelpBook: "file:///Library/Printers/vendor/Help.bundle"
+*cupsIPPReason com.vendor-error/A serious error occurred: "/help/com.vendor/error.html
+help:anchor='com.vendor-error'%20bookID=Vendor%20Help
+http://www.vendor.com/help"
+*End
+</pre>
+
+<h3><span class='info'>CUPS 1.2/Mac OS X 10.5</span><a name='cupsLanguages'>cupsLanguages</a></h3>
+
+<p class='summary'>*cupsLanguages: "locale list"</p>
+
+<p>This keyword describes which language localizations are
+included in the PPD. The "locale list" string is a space-delimited
+list of locale names ("en", "en_US", "fr_CA", etc.)</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify Canadian, UK, and US English, and Candian and French French</em> 
+*cupsLanguages: "en_CA en_UK en_US fr_CA fr_FR"
+</pre>
+
+<h3><a name='cupsManualCopies'>cupsManualCopies</a></h3>
+
+<p class='summary'>*cupsManualCopies: boolean</p>
+
+<p>This boolean keyword notifies the RIP filters that the
+destination printer does not support copy generation in
+hardware. The default value is <code>false</code>.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Tell the RIP filters to generate the copies for us</em> 
+*cupsManualCopies: true
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMarkerName'>cupsMarkerName</a></h3>
+
+<p class='summary'>*cupsMarkerName/Name Text: ""</p>
+
+<p>This optional keyword maps <code>marker-names</code> strings that are
+generated by the driver to human readable text.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Map cyanToner to "Cyan Toner"</em>
+*cupsMarkerName cyanToner/Cyan Toner: ""
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsMarkerNotice'>cupsMarkerNotice</a></h3>
+
+<p class='summary'>*cupsMarkerNotice: "disclaimer text"</p>
+
+<p>This optional keyword provides disclaimer text for the supply level
+information provided by the driver, typically something like "supply levels
+are approximate".</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*cupsMarkerNotice: "Supply levels are approximate."
+</pre>
+
+<h3><a name='cupsModelNumber'>cupsModelNumber</a></h3>
+
+<p class='summary'>*cupsModelNumber: number</p>
+
+<p>This integer keyword specifies a printer-specific model
+number. This number can be used by a filter program to adjust
+the output for a specific model of printer.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify an integer for a driver-specific model number</em> 
+*cupsModelNumber: 1234
+</pre>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsPJLCharset'>cupsPJLCharset</a></h3>
+
+<p class='summary'>*cupsPJLCharset: "ISO character set name"</p>
+
+<p>This string keyword specifies the character set that is used
+for strings in PJL commands. If not specified, US-ASCII is
+assumed.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify UTF-8 is used in PJL strings</em>
+*cupsPJLCharset: "UTF-8"
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsPJLDisplay'>cupsPJLDisplay</a></h3>
+
+<p class='summary'>*cupsPJLDisplay: "what"</p>
+
+<p>This optional keyword specifies which command is used to display the
+job ID, name, and user on the printer's control panel. "What" is either "none"
+to disable this functionality, "job" to use "@PJL JOB DISPLAY", or "rdymsg"
+to use "@PJL RDYMSG DISPLAY". The default is "job".</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Display job information using @PJL SET RDYMSG DISPLAY="foo"</em>
+*cupsPJLDisplay: "rdymsg"
+
+<em>*% Display job information display</em>
+*cupsPJLDisplay: "none"
+</pre>
+
+<h3><span class='info'>CUPS 1.2/Mac OS X 10.5</span><a name='cupsPortMonitor'>cupsPortMonitor</a></h3>
+
+<p class='summary'>*cupsPortMonitor urischeme/Descriptive Text: "port monitor"</p>
+
+<p>This string keyword specifies printer-specific "port
+monitor" filters that may be used with the printer. The CUPS
+scheduler also looks for the <tt>Protocols</tt> keyword to see
+if the <tt>BCP</tt> or <tt>TBCP</tt> protocols are supported. If
+so, the corresponding port monitor ("bcp" and "tbcp",
+respectively) is listed in the printer's
+<tt>port-monitor-supported</tt> keyword.</p>
+
+<p>The "urischeme" portion of the keyword specifies the URI scheme
+that this port monitor should be used for. Typically this is used to
+pre-select a particular port monitor for each type of connection that
+is supported by the printer. The "port monitor" string can be "none"
+to disable the port monitor for the given URI scheme.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% Specify a PostScript printer that supports the TBCP protocol</em>
+*Protocols: TBCP PJL
+
+<em>*% Specify that TBCP should be used for socket connections but not USB</em>
+*cupsPortMonitor socket/AppSocket Printing: "tbcp"
+*cupsPortMonitor usb/USB Printing: "none"
+
+<em>*% Specify a printer-specific port monitor for an Epson USB printer</em> 
+*cupsPortMonitor usb/USB Status Monitor: "epson-usb"
+</pre>
+
+<h3><span class='info'>CUPS 1.3/Mac OS X 10.5</span><a name='cupsPreFilter'>cupsPreFilter</a></h3>
+
+<p class='summary'>*cupsPreFilter: "source/type cost program"</p>
+
+<p>This string keyword provides a pre-filter rule. The pre-filter
+program will be inserted in the conversion chain immediately 
+before the filter that accepts the given MIME type.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+<em>*% PDF pre-filter</em>
+*cupsPreFilter: "application/pdf 100 mypdfprefilter"
+
+<em>*% PNG pre-filter</em>
+*cupsPreFilter: "image/png 0 mypngprefilter"
+</pre>
+
+
+<h3><span class='info'>CUPS 1.5</span><a name='cupsPrintQuality'>cupsPrintQuality</a></h3>
+
+<p class='summary'>*cupsPrintQuality keyword/text: "code"</p>
+
+<p>This UI keyword defines standard print qualities that directly map from the IPP "print-quality" job template keyword. Standard keyword values are "Draft", "Normal", and "High" which are mapped from the IPP "print-quality" values 3, 4, and 5 respectively. Each <code>cupsPrintQuality</code> option typically sets output mode and resolution parameters in the page device dictionary, eliminating the need for separate (and sometimes confusing) output mode and resolution options.</p>
+
+<blockquote><b>Note:</b>
+
+<p>Unlike all of the other keywords defined in this document, <code>cupsPrintQuality</code> is a UI keyword that MUST be enclosed inside the PPD <code>OpenUI</code> and <code>CloseUI</code> keywords.</p>
+
+</blockquote>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*OpenUI *cupsPrintQuality/Print Quality: PickOne
+*OrderDependency: 10 AnySetup *cupsPrintQuality
+*DefaultcupsPrintQuality: Normal
+*cupsPrintQuality Draft/Draft: "code"
+*cupsPrintQuality Normal/Normal: "code"
+*cupsPrintQuality High/Photo: "code"
+*CloseUI: *cupsPrintQuality
+</pre>
+
+<h3><span class='info'>CUPS 1.4/Mac OS X 10.6</span><a name='cupsSNMPSupplies'>cupsSNMPSupplies</a></h3>
+
+<p class='summary'>*cupsSNMPSupplies: boolean</p>
+
+<p>This keyword tells the standard network backends whether they should query
+the standard SNMP Printer MIB OIDs for supply levels. The default value is
+<code>True</code>.
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Do not use SNMP queries to report supply levels</em>
+*cupsSNMPSupplies: False
+</pre>
+
+<h3><a name='cupsVersion'>cupsVersion</a></h3>
+
+<p class='summary'>*cupsVersion: major.minor</p>
+
+<p>This required keyword describes which version of the CUPS
+PPD file extensions was used. Currently it must be the string
+"1.0", "1.1", "1.2", or "1.3".</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Specify a CUPS 1.2 driver</em> 
+*cupsVersion: "1.2"
+</pre>
+
+
+<h2 class='title'><a name='MACOSX'>Mac OS X Attributes</a></h2>
+
+<h3><span class='info'>Mac OS X 10.3</span><a name='APDialogExtension'>APDialogExtension</a></h3>
+
+<p class='summary'>*APDialogExtension: "/Library/Printers/vendor/filename.plugin"</p>
+
+<p>This keyword defines additional option panes that are displayed in the
+print dialog. Each keyword adds one or more option panes. See the "OutputBinsPDE"
+example and <a href='http://developer.apple.com/qa/qa2004/qa1352.html'>Apple
+Technical Q&amp;A QA1352</a> for information on writing your own print dialog
+plug-ins.</p>
+
+<blockquote><b>Note:</b>
+
+<p>Starting with Mac OS X 10.5, each plug-in must be compiled "4-way fat"
+(32-bit and 64-bit for both PowerPC and Intel) with garbage collection enabled
+in order to be usable with all applications.</p>
+
+</blockquote>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Add two panes for finishing and driver options
+*APDialogExtension: "/Library/Printers/vendor/finishing.plugin"
+*APDialogExtension: "/Library/Printers/vendor/options.plugin"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.4</span><a name='APDuplexRequiresFlippedMargin'>APDuplexRequiresFlippedMargin</a></h3>
+
+<p class='summary'>*APDuplexRequiresFlippedMargin: boolean</p>
+
+<p>This boolean keyword notifies the RIP filters that the
+destination printer requires the top and bottom margins of the
+<tt>ImageableArea</tt> to be swapped for the back page. The
+default is <tt>true</tt> when <tt>cupsBackSide</tt> is <tt>Flipped</tt>
+and <tt>false</tt> otherwise. <a href='#TABLE_2'>Table 2</a> shows how
+<tt>APDuplexRequiresFlippedMargin</tt> interacts with <tt>cupsBackSide</tt>
+and the <tt>Tumble</tt> page attribute.</p>
+
+<div class='table'>
+<table width='80%' summary='Margin Flipping Modes'>
+<caption>Table 2: <a name='TABLE_2'>Margin Flipping Modes</a></caption>
+<thead>
+<tr>
+       <th>APDuplexRequiresFlippedMargin</th>
+       <th>cupsBackSide</th>
+       <th>Tumble Value</th>
+       <th>Margins</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+       <td>false</td>
+       <td>any</td>
+       <td>any</td>
+       <td>Normal</td>
+</tr>
+<tr>
+       <td>any</td>
+       <td>Normal</td>
+       <td>any</td>
+       <td>Normal</td>
+</tr>
+<tr>
+       <td>true</td>
+       <td>ManualDuplex</td>
+       <td>false</td>
+       <td>Normal</td>
+</tr>
+<tr>
+       <td>true</td>
+       <td>ManualDuplex</td>
+       <td>true</td>
+       <td>Flipped</td>
+</tr>
+<tr>
+       <td>true</td>
+       <td>Rotated</td>
+       <td>false</td>
+       <td>Flipped</td>
+</tr>
+<tr>
+       <td>true</td>
+       <td>Rotated</td>
+       <td>true</td>
+       <td>Normal</td>
+</tr>
+<tr>
+       <td>true or unspecified</td>
+       <td>Flipped</td>
+       <td>any</td>
+       <td>Flipped</td>
+</tr>
+</tbody>
+</table></div>
+
+<p>Example:</p>
+
+<pre class='command'>
+<em>*% Rotate the back side images</em>
+*cupsBackSide: Rotated
+
+<em>*% Don't swap the top and bottom margins for the back side</em> 
+*APDuplexRequiresFlippedMargin: false
+</pre>
+
+<p>Also see the related <a href='#cupsBackSide'><tt>cupsBackSide</tt></a>
+keyword.</p>
+
+<h3><a name='APHelpBook'>APHelpBook</a></h3>
+
+<p class='summary'>*APHelpBook: "bundle URL"</p>
+
+<p>This string keyword specifies the Apple help book bundle to use when
+looking up IPP reason codes for this printer driver. The
+<a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> keyword maps
+"help" URIs to this file.</p>
+
+<p>Example:</p>
+
+<pre class='command'>
+*APHelpBook: "file:///Library/Printers/vendor/Help.bundle"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.6</span><a name='APICADriver'>APICADriver</a></h3>
+
+<p class='summary'>*APICADriver: boolean</p>
+
+<p>This keyword specifies whether the device has a matching Image Capture
+Architecture (ICA) driver for scanning. The default is <tt>False</tt>.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APICADriver: True
+*APScanAppBundleID: "com.apple.ImageCaptureApp"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.3</span><a name='APPrinterIconPath'>APPrinterIconPath</a></h3>
+
+<p class='summary'>*APPrinterIconPath: "/Library/Printers/vendor/filename.icns"</p>
+
+<p>This keyword defines the location of a printer icon file to use when
+displaying the printer. The file must be in the Apple icon format.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Apple icon file
+*APPrinterIconPath: "/Library/Printers/vendor/Icons/filename.icns"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.4</span><a name='APPrinterLowInkTool'>APPrinterLowInkTool</a></h3>
+
+<p class='summary'>*APPrinterLowInkTool: "/Library/Printers/vendor/program"</p>
+
+<p>This keyword defines an program that checks the ink/toner/marker levels
+on a printer, returning an XML document with those levels. See the "InkTool"
+example and
+<a href='http://developer.apple.com/technotes/tn2005/tn2144.html'>Apple
+Technical Note TN2144</a> for more information.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Use a vendor monitoring program
+*APPrinterLowInkTool: "/Library/Printers/vendor/Tools/lowinktool"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.5</span><a name='APPrinterPreset'>APPrinterPreset</a></h3>
+
+<p class='summary'>*APPrinterPreset name/text: "*Option Choice ..."</p>
+
+<p>This keyword defines presets for multiple options that show up
+in the print dialog of applications (such as iPhoto) that set the job
+style hint to <tt>NSPrintPhotoJobStyleHint</tt>. Each preset maps to one or
+more pairs of PPD options and choices as well as providing key/value data for
+the application. The following standard preset names are currently defined:</p>
+
+<ul>
+
+       <li><code>General_with_Paper_Auto-Detect</code>; Normal quality general printing with auto-detected media.</li>
+
+       <li><code>General_with_Paper_Auto-Detect_-_Draft</code>; Draft quality general printing with auto-detected media.</li>
+
+       <li><code>General_on_Plain_Paper</code>; Normal quality general printing on plain paper.</li>
+
+       <li><code>General_on_Plain_Paper_-_Draft</code>; Draft quality general printing on plain paper.</li>
+
+       <li><code>Photo_with_Paper_Auto-Detect</code>; Normal quality photo printing with auto-detected media.</li>
+
+       <li><code>Photo_with_Paper_Auto-Detect_-_Fine</code>; High quality photo printing with auto-detected media.</li>
+
+       <li><code>Photo_on_Plain_Paper</code>; Normal quality photo printing on plain paper.</li>
+
+       <li><code>Photo_on_Plain_Paper_-_Fine</code>; High quality photo printing on plain paper.</li>
+
+       <li><code>Photo_on_Photo_Paper</code>; Normal quality photo printing on glossy photo paper.</li>
+
+       <li><code>Photo_on_Photo_Paper_-_Fine</code>; High quality photo printing on glossy photo paper.</li>
+
+       <li><code>Photo_on_Matte_Paper</code>; Normal quality photo printing on matte paper.</li>
+
+       <li><code>Photo_on_Matte_Paper_-_Fine</code>; High quality photo printing on matte paper.</li>
+
+</ul>
+
+<p>The value string consists of pairs of keywords, either an option name and
+choice (*MainKeyword OptionKeyword) or a preset identifier and value
+(com.apple.print.preset.foo value). The following preset identifiers are currently used:</p>
+
+<ul>
+
+       <li><code>com.apple.print.preset.graphicsType</code>; specifies the type of printing used for this printing - "General" for general purpose printing and "Photo" for photo printing.</li>
+
+       <li><code>com.apple.print.preset.media-front-coating</code>; specifies the media type selected by this preset - "none" (plain paper), "glossy", "high-gloss", "semi-gloss", "satin", "matte", and "autodetect".</li>
+
+       <li><code>com.apple.print.preset.output-mode</code>; specifies the output mode for this preset - "color" (default for color printers) or "monochrome" (grayscale, default for B&amp;W printers).</li>
+
+       <li><code>com.apple.print.preset.quality</code>; specifies the overall print quality selected by this preset - "low" (draft), "mid" (normal), or "high".</li>
+
+</ul>
+
+<p>Presets, like options, can also be localized in multiple languages.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APPrinterPreset Photo_on_Photo_Paper/Photo on Photo Paper: "
+  *MediaType Glossy
+  *ColorModel RGB
+  *Resolution 300dpi
+  com.apple.print.preset.graphicsType Photo
+  com.apple.print.preset.quality mid
+  com.apple.print.preset.media-front-coating glossy"
+*End
+*fr.APPrinterPreset Photo_on_Photo_Paper/Photo sur papier photographique: ""
+</pre>
+
+<h3><span class='info'>Mac OS X 10.3</span><a name='APPrinterUtilityPath'>APPrinterUtilityPath</a></h3>
+
+<p class='summary'>*APPrinterPrinterUtilityPath: "/Library/Printers/vendor/filename.app"</p>
+
+<p>This keyword defines a GUI application that can be used to do printer
+maintenance functions such as cleaning the print head(s). See ... for more
+information.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*% Define the printer utility application
+*APPrinterPrinterUtilityPath: "/Library/Printers/vendor/Tools/utility.app"
+</pre>
+
+<h3><span class='info'>Mac OS X 10.6</span><a name='APScannerOnly'>APScannerOnly</a></h3>
+
+<p class='summary'>*APScannerOnly: boolean</p>
+
+<p>This keyword specifies whether the device has scanning but no printing
+capabilities. The default is <tt>False</tt>.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APICADriver: True
+*APScannerOnly: True
+</pre>
+
+<h3><span class='info'>Mac OS X 10.3</span><a name='APScanAppBundleID'>APScanAppBundleID</a></h3>
+
+<p class='summary'>*APScanAppBundleID: "bundle ID"</p>
+
+<p>This keyword defines the application to use when scanning pages from
+the device.</p>
+
+<p>Examples:</p>
+
+<pre class='command'>
+*APICADriver: True
+*APScanAppBundleID: "com.apple.ImageCaptureApp"
+</pre>
+
+
+<h2 class='title'><a name='HISTORY'>Change History</a></h2>
+
+<h3>Changes in CUPS 1.5</h3>
+
+<ul>
+
+       <li>Changes all instances of PPD attributes to PPD keywords, to be consistent with the parent specification from Adobe.</li>
+
+</ul>
+
+
+<h3>Changes in CUPS 1.4.5</h3>
+
+<ul>
+
+       <li>Added <a href='#cupsPrintQuality'><tt>cupsPrintQuality</tt></a> UI keyword.</li>
+
+       <li>Added new properties and values for the <a href='#APPrinterPreset'><tt>APPrinterPreset</tt></a> keyword.</li>
+
+</ul>
+
+
+<h3>Changes in CUPS 1.4</h3>
+
+<ul>
+
+       <li>Added <a href='#APICADriver'><tt>APICADriver</tt></a>
+       keyword.</li>
+
+       <li>Added <a href='#cupsCommands'><tt>cupsCommands</tt></a>
+       keyword.</li>
+
+       <li>Added <a href='#cupsMarkerName'><tt>cupsMarkerName</tt></a>
+       keyword.</li>
+
+       <li>Added <a href='#cupsMarkerNotice'><tt>cupsMarkerNotice</tt></a>
+       keyword.</li>
+
+       <li>Added <a href='#cupsPJLDisplay'><tt>cupsPJLDisplay</tt></a>
+       keyword.</li>
+
+       <li>Added <a href='#cupsSNMPSupplies'><tt>cupsSNMPSupplies</tt></a>
+       keyword.</li>
+
+       <li>Added <a href='#cupsUIResolver'><tt>cupsUIResolver</tt></a> and
+       <a href='#cupsUIConstraints'><tt>cupsUIConstraints</tt></a>
+       keywords.</li>
+
+       <li>Added
+       <a href='#cupsMediaQualifier2'><tt>cupsMediaQualifier2</tt></a>,
+       <a href='#cupsMediaQualifier3'><tt>cupsMediaQualifier3</tt></a>,
+       <a href='#cupsMinSize'><tt>cupsMinSize</tt></a>, and
+       <a href='#cupsMaxSize'><tt>cupsMaxSize</tt></a> keywords.</li>
+
+</ul>
+
+
+<h3>Changes in CUPS 1.3.1</h3>
+
+<ul>
+
+       <li>Added missing Mac OS X <tt>AP</tt> keywords.</li>
+
+       <li>Added section on auto-configuration including the
+       <tt>OID<i>MainKeyword</i></tt> and <tt>?<i>MainKeyword</i></tt>
+       keywords.</li>
+
+       <li>Minor reorganization.</li>
+
+</ul>
+
+
+<h3>Changes in CUPS 1.3</h3>
+
+<ul>
+
+       <li>Added <a href='#cupsBackSide'><tt>cupsBackSide</tt></a> and
+       deprecated <a href='#cupsFlipDuplex'><tt>cupsFlipDuplex</tt></a>.</li>
+
+       <li>Added text URI information to
+       <a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> documentation.</li>
+
+       <li>Added <a href='#APPrinterPreset'><tt>APPrinterPreset</tt></a>,
+       <a href='#cupsIPPFinishings'><tt>cupsIPPFinishings</tt></a>, and
+       <a href='#cupsPreFilter'><tt>cupsPreFilter</tt></a> keywords.</li>
+
+       <li>Added discussion of custom option code, sample
+       <tt>CustomPageSize</tt> code, and "do not use dict and put" note.</li>
+
+</ul>
+
+<h3>Changes in CUPS 1.2.8</h3>
+
+<ul>
+
+       <li>Added section on supported PostScript commands for raster
+       drivers</li>
+
+</ul>
+
+<h3>Changes in CUPS 1.2</h3>
+
+<ul>
+
+       <li>Added globalization support keywords</li>
+
+       <li>Added custom option values support</li>
+
+       <li>Added <a href='#APHelpBook'><tt>APHelpBook</tt></a> keyword</li>
+
+       <li>Added <a href='#APDuplexRequiresFlippedMargin'><tt>APDuplexRequiresFlippedMargin</tt></a>
+       keyword</li>
+
+       <li>Added <a href='#cupsICCProfile'><tt>cupsICCProfile</tt></a> keyword</li>
+
+       <li>Added <a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> keyword</li>
+
+       <li>Added <a href='#cupsLanguages'><tt>cupsLanguages</tt></a> keyword</li>
+
+       <li>Added <a href='#cupsPortMonitor'><tt>cupsPortMonitor</tt></a> keyword</li>
+
+       <li>Removed <tt>cupsProtocol</tt> keyword</li>
+
+</ul>
+
+<h3>Changes in CUPS 1.1</h3>
+
+<ul>
+
+       <li>Added <a href='#cupsFlipDuplex'><tt>cupsFlipDuplex</tt></a> keyword</li>
+
+       <li>Added <tt>cupsProtocol</tt> keyword</li>
+
+</ul>
index ad4d082b3d173de37524f93a5a9cbd8ac45f872a..d32412110d349c3a6d104e97d6fa30ff9a81f0df 100644 (file)
@@ -12,7 +12,7 @@
 .\"   which should have been included with this file.  If this file is
 .\"   file is missing or damaged, see the license at "http://www.cups.org/".
 .\"
-.TH cupsd.conf 5 "CUPS" "28 January 2010" "Apple Inc."
+.TH cupsd.conf 5 "CUPS" "5 November 2010" "Apple Inc."
 .SH NAME
 cupsd.conf \- server configuration file for cups
 .SH DESCRIPTION
@@ -400,6 +400,26 @@ JobKillDelay seconds
 Specifies the number of seconds to wait before killing the filters and backend
 associated with a canceled or held job.
 .TP 5
+JobPrivateAccess all
+.TP 5
+JobPrivateAccess default
+.TP 5
+JobPrivateAccess {user|@group|@ACL|@OWNER|@SYSTEM}+
+.br
+Specifies an access list for a job's private values. The "default" access list
+is "@OWNER @SYSTEM". "@ACL" maps to the printer's requesting-user-name-allowed
+or requesting-user-name-denied values.
+.TP 5
+JobPrivateValues all
+.TP 5
+JobPrivateValues default
+.TP 5
+JobPrivateValues none
+.TP 5
+JobPrivateValues attribute-name-1 [ ... attribute-name-N ]
+Specifies the list of job values to make private. The "default" values are
+"job-name", "job-originating-host-name", and "job-originating-user-name".
+.TP 5
 JobRetryInterval seconds
 .br
 Specifies the interval between retries of jobs in seconds.
@@ -686,6 +706,27 @@ SSLPort
 .br
 Listens on the specified port for encrypted connections.
 .TP 5
+SubscriptionPrivateAccess all
+.TP 5
+SubscriptionPrivateAccess default
+.TP 5
+SubscriptionPrivateAccess {user|@group|@ACL|@OWNER|@SYSTEM}+
+.br
+Specifies an access list for a subscription's private values. The "default"
+access list is "@OWNER @SYSTEM". "@ACL" maps to the printer's
+requesting-user-name-allowed or requesting-user-name-denied values.
+.TP 5
+SubscriptionPrivateValues all
+.TP 5
+SubscriptionPrivateValues default
+.TP 5
+SubscriptionPrivateValues none
+.TP 5
+SubscriptionPrivateValues attribute-name-1 [ ... attribute-name-N ]
+Specifies the list of job values to make private. The "default" values are
+"notify-events", "notify-pull-method", "notify-recipient-uri",
+"notify-subscriber-user-name", and "notify-user-data".
+.TP 5
 SystemGroup group-name [group-name ...]
 .br
 Specifies the group(s) to use for System class authentication.
@@ -708,7 +749,7 @@ Specifies the user name or ID that is used when running external programs.
 .br
 http://localhost:631/help
 .SH COPYRIGHT
-Copyright 2007-2009 by Apple Inc.
+Copyright 2007-2010 by Apple Inc.
 .\"
 .\" End of "$Id: cupsd.conf.man.in 7935 2008-09-11 01:54:11Z mike $".
 .\"
index 1e9f59b3cc3e54971549858a1c1b950c5b40cf1a..31bd93de63096d3085004363989aaa1187086361 100644 (file)
 .\"   which should have been included with this file.  If this file is
 .\"   file is missing or damaged, see the license at "http://www.cups.org/".
 .\"
-.TH ipptool 1 "CUPS" "2 August 2010" "Apple Inc."
+.TH ipptool 1 "CUPS" "17 October 2010" "Apple Inc."
 .SH NAME
 ipptool - perform internet printing protocol requests
 .SH SYNOPSIS
 .B ipptool
-[ -C ] [ -E ] [ -I ] [ -L ] [ -S ] [ -V
+[ -C ] [ -E ] [ -I ] [ -L ] [ -S ] [ -T
+.I seconds
+] [ -V
 .I version
 ] [ -X ] [ -c ] [ -d
 .I name=value
@@ -52,6 +54,9 @@ Specifies that requests should be sent using the HTTP/1.0 "Content-Length:" head
 -S
 Forces (dedicated) SSL encryption when connecting to the server.
 .TP 5
+-T seconds
+Specifies a timeout for IPP requests in seconds.
+.TP 5
 -V version
 Specifies the default IPP version to use: 1.0, 1.1, 2.0, 2.1, or 2.2. If not specified, version 1.1 is used.
 .TP 5
@@ -68,7 +73,7 @@ Defines the named variable.
 Defines the default request filename for tests.
 .TP 5
 -i seconds
-Specifies that the (last) file should be repeated at the specified interval. This option is incompatible with the \fI-x\fR (XML plist output) option.
+Specifies that the (last) file should be repeated at the specified interval. This option is incompatible with the \fI-X\fR (XML plist output) option.
 .TP 5
 -l
 Specifies that plain text output is desired.
index 497997d6f2e4c912d84131b20728ce7dd5871782..8b3571f298805b44bdfe8ecab40d81316ebcbce4 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: auth.c 7830 2008-08-04 20:38:50Z mike $"
  *
- *   Authorization routines for the Common UNIX Printing System (CUPS).
+ *   Authorization routines for the CUPS scheduler.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   This file contains Kerberos support code, copyright 2006 by
  *
  * Contents:
  *
+ *   cupsdAddIPMask()          - Add an IP address authorization mask.
  *   cupsdAddLocation()        - Add a location for authorization.
  *   cupsdAddName()            - Add a name to a location...
- *   cupsdAllowHost()          - Add a host name that is allowed to access the
- *                               location.
- *   cupsdAllowIP()            - Add an IP address or network that is allowed to
- *                               access the location.
+ *   cupsdAddNameMask()        - Add a host or interface name authorization
+ *                               mask.
  *   cupsdAuthorize()          - Validate any authorization credentials.
  *   cupsdCheckAccess()        - Check whether the given address is allowed to
  *                               access a location.
  *   cupsdCopyLocation()       - Make a copy of a location...
  *   cupsdDeleteAllLocations() - Free all memory used for location
  *                               authorization.
- *   cupsdDeleteLocation()     - Free all memory used by a location.
- *   cupsdDenyHost()           - Add a host name that is not allowed to access
- *                               the location.
- *   cupsdDenyIP()             - Add an IP address or network that is not
- *                               allowed to access the location.
  *   cupsdFindBest()           - Find the location entry that best matches the
  *                               resource.
  *   cupsdFindLocation()       - Find the named location.
+ *   cupsdFreeLocation()       - Free all memory used by a location.
  *   cupsdIsAuthorized()       - Check to see if the user is authorized...
- *   add_allow()               - Add an allow mask to the location.
- *   add_deny()                - Add a deny mask to the location.
+ *   cupsdNewLocation()        - Create a new location for authorization.
  *   check_authref()           - Check if an authorization services reference
  *                               has the supplied right.
  *   compare_locations()       - Compare two locations.
+ *   copy_authmask()           - Copy function for auth masks.
  *   cups_crypt()              - Encrypt the password using the DES or MD5
  *                               algorithms, as needed.
+ *   free_authmask()           - Free function for auth masks.
  *   get_md5_password()        - Get an MD5 password.
  *   pam_func()                - PAM conversation function.
  *   to64()                    - Base64-encode an integer value...
@@ -108,16 +104,16 @@ extern void       krb5_ipc_client_clear_target(void);
  * Local functions...
  */
 
-static cupsd_authmask_t        *add_allow(cupsd_location_t *loc);
-static cupsd_authmask_t        *add_deny(cupsd_location_t *loc);
 #ifdef HAVE_AUTHORIZATION_H
 static int             check_authref(cupsd_client_t *con, const char *right);
 #endif /* HAVE_AUTHORIZATION_H */
 static int             compare_locations(cupsd_location_t *a,
                                          cupsd_location_t *b);
+static cupsd_authmask_t        *copy_authmask(cupsd_authmask_t *am, void *data);
 #if !HAVE_LIBPAM && !defined(HAVE_USERSEC_H)
 static char            *cups_crypt(const char *pw, const char *salt);
 #endif /* !HAVE_LIBPAM && !HAVE_USERSEC_H */
+static void            free_authmask(cupsd_authmask_t *am, void *data);
 static char            *get_md5_password(const char *username,
                                          const char *group, char passwd[33]);
 #if HAVE_LIBPAM
@@ -151,54 +147,66 @@ static cupsd_authdata_t   *auth_data;     /* Current client being authenticated */
 
 
 /*
- * 'cupsdAddLocation()' - Add a location for authorization.
+ * 'cupsdAddIPMask()' - Add an IP address authorization mask.
  */
 
-cupsd_location_t *                     /* O - Pointer to new location record */
-cupsdAddLocation(const char *location) /* I - Location path */
+int                                    /* O  - 1 on success, 0 on failure */
+cupsdAddIPMask(
+    cups_array_t   **masks,            /* IO - Masks array (created as needed) */
+    const unsigned address[4],         /* I  - IP address */
+    const unsigned netmask[4])         /* I  - IP netmask */
 {
-  cupsd_location_t     *temp;          /* New location */
+  cupsd_authmask_t     temp;           /* New host/domain mask */
 
 
- /*
-  * Make sure the locations array is created...
-  */
-
-  if (!Locations)
-    Locations = cupsArrayNew((cups_array_func_t)compare_locations, NULL);
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "cupsdAddIPMask(masks=%p(%p), address=%x:%x:%x:%x, "
+                 "netmask=%x:%x:%x:%x)",
+                 masks, *masks,
+                 address[0], address[1], address[2], address[3],
+                 netmask[0], netmask[1], netmask[2], netmask[3]);
 
-  if (!Locations)
-    return (NULL);
+  temp.type = CUPSD_AUTH_IP;
+  memcpy(temp.mask.ip.address, address, sizeof(temp.mask.ip.address));
+  memcpy(temp.mask.ip.netmask, netmask, sizeof(temp.mask.ip.netmask));
 
  /*
-  * Try to allocate memory for the new location.
+  * Create the masks array as needed and add...
   */
 
-  if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
-    return (NULL);
+  if (!*masks)
+    *masks = cupsArrayNew3(NULL, NULL, NULL, 0,
+                          (cups_acopy_func_t)copy_authmask,
+                          (cups_afree_func_t)free_authmask);
 
- /*
-  * Initialize the record and copy the name over...
-  */
-
-  if ((temp->location = strdup(location)) == NULL)
-  {
-    free(temp);
-    return (NULL);
-  }
-
-  temp->length = strlen(temp->location);
+  return (cupsArrayAdd(*masks, &temp));
+}
 
-  cupsArrayAdd(Locations, temp);
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddLocation: added location \'%s\'",
-                  location);
+/*
+ * 'cupsdAddLocation()' - Add a location for authorization.
+ */
 
+void
+cupsdAddLocation(cupsd_location_t *loc)        /* I - Location to add */
+{
  /*
-  * Return the new record...
+  * Make sure the locations array is created...
   */
 
-  return (temp);
+  if (!Locations)
+    Locations = cupsArrayNew3((cups_array_func_t)compare_locations, NULL,
+                              (cups_ahash_func_t)NULL, 0,
+                             (cups_acopy_func_t)NULL,
+                             (cups_afree_func_t)cupsdFreeLocation);
+
+  if (Locations)
+  {
+    cupsArrayAdd(Locations, loc);
+
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddLocation: Added location \"%s\"",
+                    loc->location ? loc->location : "(null)");
+  }
 }
 
 
@@ -210,126 +218,98 @@ void
 cupsdAddName(cupsd_location_t *loc,    /* I - Location to add to */
              char             *name)   /* I - Name to add */
 {
-  char **temp;                         /* Pointer to names array */
-
-
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddName(loc=%p, name=\"%s\")",
                   loc, name);
 
-  if (loc->num_names == 0)
-    temp = malloc(sizeof(char *));
-  else
-    temp = realloc(loc->names, (loc->num_names + 1) * sizeof(char *));
-
-  if (temp == NULL)
-  {
-    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add name to location %s: %s",
-                    loc->location ? loc->location : "nil", strerror(errno));
-    return;
-  }
-
-  loc->names = temp;
+  if (!loc->names)
+    loc->names = cupsArrayNew3(NULL, NULL, NULL, 0,
+                               (cups_acopy_func_t)_cupsStrAlloc,
+                               (cups_afree_func_t)_cupsStrFree);
 
-  if ((temp[loc->num_names] = strdup(name)) == NULL)
+  if (!cupsArrayAdd(loc->names, name))
   {
     cupsdLogMessage(CUPSD_LOG_ERROR,
                     "Unable to duplicate name for location %s: %s",
                     loc->location ? loc->location : "nil", strerror(errno));
     return;
   }
-
-  loc->num_names ++;
 }
 
 
 /*
- * 'cupsdAllowHost()' - Add a host name that is allowed to access the location.
+ * 'cupsdAddNameMask()' - Add a host or interface name authorization mask.
  */
 
-void
-cupsdAllowHost(cupsd_location_t *loc,  /* I - Location to add to */
-               char             *name) /* I - Name of host or domain to add */
+int                                    /* O  - 1 on success, 0 on failure */
+cupsdAddNameMask(cups_array_t **masks, /* IO - Masks array (created as needed) */
+                 char         *name)   /* I  - Host or interface name */
 {
-  cupsd_authmask_t     *temp;          /* New host/domain mask */
+  cupsd_authmask_t     temp;           /* New host/domain mask */
   char                 ifname[32],     /* Interface name */
                        *ifptr;         /* Pointer to end of name */
 
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAllowHost(loc=%p(%s), name=\"%s\")",
-                  loc, loc->location ? loc->location : "nil", name);
-
-  if ((temp = add_allow(loc)) == NULL)
-    return;
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "cupsdAddNameMask(masks=%p(%p), name=\"%s\")",
+                  masks, *masks, name);
 
   if (!strcasecmp(name, "@LOCAL"))
   {
    /*
-    * Allow *interface*...
+    * Deny *interface*...
     */
 
-    temp->type             = CUPSD_AUTH_INTERFACE;
-    temp->mask.name.name   = strdup("*");
-    temp->mask.name.length = 1;
+    temp.type           = CUPSD_AUTH_INTERFACE;
+    temp.mask.name.name = (char *)"*";
   }
   else if (!strncasecmp(name, "@IF(", 4))
   {
    /*
-    * Allow *interface*...
+    * Deny *interface*...
     */
 
     strlcpy(ifname, name + 4, sizeof(ifname));
 
-    ifptr = ifname + strlen(ifname);
+    ifptr = ifname + strlen(ifname) - 1;
 
-    if (ifptr[-1] == ')')
+    if (ifptr >= ifname && *ifptr == ')')
     {
       ifptr --;
       *ifptr = '\0';
     }
 
-    temp->type             = CUPSD_AUTH_INTERFACE;
-    temp->mask.name.name   = strdup(ifname);
-    temp->mask.name.length = ifptr - ifname;
+    temp.type             = CUPSD_AUTH_INTERFACE;
+    temp.mask.name.name   = ifname;
   }
   else
   {
    /*
-    * Allow name...
+    * Deny name...
     */
 
-    temp->type             = CUPSD_AUTH_NAME;
-    temp->mask.name.name   = strdup(name);
-    temp->mask.name.length = strlen(name);
-  }
-}
-
+    if (*name == '*')
+      name ++;
 
-/*
- * 'cupsdAllowIP()' - Add an IP address or network that is allowed to access
- *                    the location.
- */
+    temp.type             = CUPSD_AUTH_NAME;
+    temp.mask.name.name   = (char *)name;
+  }
 
-void
-cupsdAllowIP(
-    cupsd_location_t *loc,             /* I - Location to add to */
-    const unsigned   address[4],       /* I - IP address to add */
-    const unsigned   netmask[4])       /* I - Netmask of address */
-{
-  cupsd_authmask_t     *temp;          /* New host/domain mask */
+ /*
+  * Set the name length...
+  */
 
+  temp.mask.name.length = strlen(temp.mask.name.name);
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdAllowIP(loc=%p(%s), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)",
-                 loc, loc->location ? loc->location : "nil",
-                 address[0], address[1], address[2], address[3],
-                 netmask[0], netmask[1], netmask[2], netmask[3]);
+ /*
+  * Create the masks array as needed and add...
+  */
 
-  if ((temp = add_allow(loc)) == NULL)
-    return;
+  if (!*masks)
+    *masks = cupsArrayNew3(NULL, NULL, NULL, 0,
+                          (cups_acopy_func_t)copy_authmask,
+                          (cups_afree_func_t)free_authmask);
 
-  temp->type = CUPSD_AUTH_IP;
-  memcpy(temp->mask.ip.address, address, sizeof(temp->mask.ip.address));
-  memcpy(temp->mask.ip.netmask, netmask, sizeof(temp->mask.ip.netmask));
+  return (cupsArrayAdd(*masks, &temp));
 }
 
 
@@ -1232,20 +1212,20 @@ cupsdCheckAccess(
       case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
           allow = 1;
 
-          if (cupsdCheckAuth(ip, name, namelen, loc->num_deny, loc->deny))
+          if (cupsdCheckAuth(ip, name, namelen, loc->deny))
            allow = 0;
 
-          if (cupsdCheckAuth(ip, name, namelen, loc->num_allow, loc->allow))
+          if (cupsdCheckAuth(ip, name, namelen, loc->allow))
            allow = 1;
          break;
 
       case CUPSD_AUTH_DENY : /* Order Allow,Deny */
           allow = 0;
 
-          if (cupsdCheckAuth(ip, name, namelen, loc->num_allow, loc->allow))
+          if (cupsdCheckAuth(ip, name, namelen, loc->allow))
            allow = 1;
 
-          if (cupsdCheckAuth(ip, name, namelen, loc->num_deny, loc->deny))
+          if (cupsdCheckAuth(ip, name, namelen, loc->deny))
            allow = 0;
          break;
     }
@@ -1260,24 +1240,25 @@ cupsdCheckAccess(
  */
 
 int                                    /* O - 1 if mask matches, 0 otherwise */
-cupsdCheckAuth(
-    unsigned         ip[4],            /* I - Client address */
-    char             *name,            /* I - Client hostname */
-    int              name_len,         /* I - Length of hostname */
-    int              num_masks,                /* I - Number of masks */
-    cupsd_authmask_t *masks)           /* I - Masks */
+cupsdCheckAuth(unsigned     ip[4],     /* I - Client address */
+              char         *name,      /* I - Client hostname */
+              int          name_len,   /* I - Length of hostname */
+              cups_array_t *masks)     /* I - Masks */
 {
-  int          i;                      /* Looping var */
-  cupsd_netif_t        *iface;                 /* Network interface */
-  unsigned     netip4;                 /* IPv4 network address */
+  int                  i;              /* Looping var */
+  cupsd_authmask_t     *mask;          /* Current mask */
+  cupsd_netif_t                *iface;         /* Network interface */
+  unsigned             netip4;         /* IPv4 network address */
 #ifdef AF_INET6
-  unsigned     netip6[4];              /* IPv6 network address */
+  unsigned             netip6[4];      /* IPv6 network address */
 #endif /* AF_INET6 */
 
 
-  while (num_masks > 0)
+  for (mask = (cupsd_authmask_t *)cupsArrayFirst(masks);
+       mask;
+       mask = (cupsd_authmask_t *)cupsArrayNext(masks))
   {
-    switch (masks->type)
+    switch (mask->type)
     {
       case CUPSD_AUTH_INTERFACE :
          /*
@@ -1293,7 +1274,7 @@ cupsdCheckAuth(
           netip6[3] = htonl(ip[3]);
 #endif /* AF_INET6 */
 
-          if (!strcmp(masks->mask.name.name, "*"))
+          if (!strcmp(mask->mask.name.name, "*"))
          {
 #ifdef __APPLE__
            /*
@@ -1361,7 +1342,7 @@ cupsdCheckAuth(
                 iface;
                 iface = (cupsd_netif_t *)cupsArrayNext(NetIFList))
            {
-              if (strcmp(masks->mask.name.name, iface->name))
+              if (strcmp(mask->mask.name.name, iface->name))
                 continue;
 
               if (iface->address.addr.sa_family == AF_INET)
@@ -1401,17 +1382,17 @@ cupsdCheckAuth(
          * Check for exact name match...
          */
 
-          if (!strcasecmp(name, masks->mask.name.name))
+          if (!strcasecmp(name, mask->mask.name.name))
            return (1);
 
          /*
          * Check for domain match...
          */
 
-         if (name_len >= masks->mask.name.length &&
-             masks->mask.name.name[0] == '.' &&
-             !strcasecmp(name + name_len - masks->mask.name.length,
-                         masks->mask.name.name))
+         if (name_len >= mask->mask.name.length &&
+             mask->mask.name.name[0] == '.' &&
+             !strcasecmp(name + name_len - mask->mask.name.length,
+                         mask->mask.name.name))
            return (1);
           break;
 
@@ -1421,17 +1402,14 @@ cupsdCheckAuth(
          */
 
           for (i = 0; i < 4; i ++)
-           if ((ip[i] & masks->mask.ip.netmask[i]) !=
-                   masks->mask.ip.address[i])
+           if ((ip[i] & mask->mask.ip.netmask[i]) !=
+                   mask->mask.ip.address[i])
              break;
 
          if (i == 4)
            return (1);
           break;
     }
-
-    masks ++;
-    num_masks --;
   }
 
   return (0);
@@ -1731,137 +1709,78 @@ cupsdCopyKrb5Creds(cupsd_client_t *con)        /* I - Client connection */
 
 cupsd_location_t *                     /* O - New location */
 cupsdCopyLocation(
-    cupsd_location_t **loc)            /* IO - Original location */
+    cupsd_location_t *loc)             /* I - Original location */
 {
-  int                  i;              /* Looping var */
   cupsd_location_t     *temp;          /* New location */
-  char                 location[HTTP_MAX_URI];
-                                       /* Location of resource */
 
 
  /*
-  * Use a local copy of location because cupsdAddLocation may cause
-  * this memory to be moved...
+  * Make a copy of the original location...
   */
 
-  strlcpy(location, (*loc)->location, sizeof(location));
-
-  if ((temp = cupsdAddLocation(location)) == NULL)
+  if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
     return (NULL);
 
  /*
   * Copy the information from the original location to the new one.
   */
 
-  temp->limit      = (*loc)->limit;
-  temp->order_type = (*loc)->order_type;
-  temp->type       = (*loc)->type;
-  temp->level      = (*loc)->level;
-  temp->satisfy    = (*loc)->satisfy;
-  temp->encryption = (*loc)->encryption;
+  if (!loc)
+    return (temp);
 
-  if ((temp->num_names  = (*loc)->num_names) > 0)
-  {
-   /*
-    * Copy the names array...
-    */
+  if (loc->location)
+    temp->location = _cupsStrAlloc(loc->location);
+
+  temp->limit      = loc->limit;
+  temp->order_type = loc->order_type;
+  temp->type       = loc->type;
+  temp->level      = loc->level;
+  temp->satisfy    = loc->satisfy;
+  temp->encryption = loc->encryption;
 
-    if ((temp->names = calloc(temp->num_names, sizeof(char *))) == NULL)
+  if (loc->names)
+  {
+    if ((temp->names = cupsArrayDup(loc->names)) == NULL)
     {
       cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdCopyLocation: Unable to allocate memory for %d names: %s",
-                      temp->num_names, strerror(errno));
+                      "Unable to allocate memory for %d names: %s",
+                     cupsArrayCount(loc->names), strerror(errno));
 
-      cupsdDeleteLocation(temp);
+      cupsdFreeLocation(temp);
       return (NULL);
     }
-
-    for (i = 0; i < temp->num_names; i ++)
-      if ((temp->names[i] = strdup((*loc)->names[i])) == NULL)
-      {
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "cupsdCopyLocation: Unable to copy name \"%s\": %s",
-                        (*loc)->names[i], strerror(errno));
-
-        cupsdDeleteLocation(temp);
-       return (NULL);
-      }
   }
 
-  if ((temp->num_allow  = (*loc)->num_allow) > 0)
+  if (loc->allow)
   {
    /*
     * Copy allow rules...
     */
 
-    if ((temp->allow = calloc(temp->num_allow, sizeof(cupsd_authmask_t))) == NULL)
+    if ((temp->allow = cupsArrayDup(loc->allow)) == NULL)
     {
       cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdCopyLocation: Unable to allocate memory for %d allow rules: %s",
-                      temp->num_allow, strerror(errno));
-      cupsdDeleteLocation(temp);
+                      "Unable to allocate memory for %d allow rules: %s",
+                      cupsArrayCount(loc->allow), strerror(errno));
+      cupsdFreeLocation(temp);
       return (NULL);
     }
-
-    for (i = 0; i < temp->num_allow; i ++)
-      switch (temp->allow[i].type = (*loc)->allow[i].type)
-      {
-        case CUPSD_AUTH_NAME :
-           temp->allow[i].mask.name.length = (*loc)->allow[i].mask.name.length;
-           temp->allow[i].mask.name.name   = strdup((*loc)->allow[i].mask.name.name);
-
-            if (temp->allow[i].mask.name.name == NULL)
-           {
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "cupsdCopyLocation: Unable to copy allow name \"%s\": %s",
-                             (*loc)->allow[i].mask.name.name, strerror(errno));
-              cupsdDeleteLocation(temp);
-             return (NULL);
-           }
-           break;
-       case CUPSD_AUTH_IP :
-           memcpy(&(temp->allow[i].mask.ip), &((*loc)->allow[i].mask.ip),
-                  sizeof(cupsd_ipmask_t));
-           break;
-      }
   }
 
-  if ((temp->num_deny  = (*loc)->num_deny) > 0)
+  if (loc->deny)
   {
    /*
     * Copy deny rules...
     */
 
-    if ((temp->deny = calloc(temp->num_deny, sizeof(cupsd_authmask_t))) == NULL)
+    if ((temp->deny = cupsArrayDup(loc->deny)) == NULL)
     {
       cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdCopyLocation: Unable to allocate memory for %d deny rules: %s",
-                      temp->num_deny, strerror(errno));
-      cupsdDeleteLocation(temp);
+                      "Unable to allocate memory for %d deny rules: %s",
+                      cupsArrayCount(loc->deny), strerror(errno));
+      cupsdFreeLocation(temp);
       return (NULL);
     }
-
-    for (i = 0; i < temp->num_deny; i ++)
-      switch (temp->deny[i].type = (*loc)->deny[i].type)
-      {
-        case CUPSD_AUTH_NAME :
-           temp->deny[i].mask.name.length = (*loc)->deny[i].mask.name.length;
-           temp->deny[i].mask.name.name   = strdup((*loc)->deny[i].mask.name.name);
-
-            if (temp->deny[i].mask.name.name == NULL)
-           {
-             cupsdLogMessage(CUPSD_LOG_ERROR,
-                             "cupsdCopyLocation: Unable to copy deny name \"%s\": %s",
-                             (*loc)->deny[i].mask.name.name, strerror(errno));
-              cupsdDeleteLocation(temp);
-             return (NULL);
-           }
-           break;
-       case CUPSD_AUTH_IP :
-           memcpy(&(temp->deny[i].mask.ip), &((*loc)->deny[i].mask.ip),
-                  sizeof(cupsd_ipmask_t));
-           break;
-      }
   }
 
   return (temp);
@@ -1875,20 +1794,8 @@ cupsdCopyLocation(
 void
 cupsdDeleteAllLocations(void)
 {
-  cupsd_location_t     *loc;           /* Current location */
-
-
  /*
-  * Free all of the allow/deny records first...
-  */
-
-  for (loc = (cupsd_location_t *)cupsArrayFirst(Locations);
-       loc;
-       loc = (cupsd_location_t *)cupsArrayNext(Locations))
-    cupsdDeleteLocation(loc);
-
- /*
-  * Then free the location array...
+  * Free the location array, which will free all of the locations...
   */
 
   cupsArrayDelete(Locations);
@@ -1896,136 +1803,6 @@ cupsdDeleteAllLocations(void)
 }
 
 
-/*
- * 'cupsdDeleteLocation()' - Free all memory used by a location.
- */
-
-void
-cupsdDeleteLocation(
-    cupsd_location_t *loc)             /* I - Location to delete */
-{
-  int                  i;              /* Looping var */
-  cupsd_authmask_t     *mask;          /* Current mask */
-
-
-  cupsArrayRemove(Locations, loc);
-
-  for (i = loc->num_names - 1; i >= 0; i --)
-    free(loc->names[i]);
-
-  if (loc->num_names > 0)
-    free(loc->names);
-
-  for (i = loc->num_allow, mask = loc->allow; i > 0; i --, mask ++)
-    if (mask->type == CUPSD_AUTH_NAME || mask->type == CUPSD_AUTH_INTERFACE)
-      free(mask->mask.name.name);
-
-  if (loc->num_allow > 0)
-    free(loc->allow);
-
-  for (i = loc->num_deny, mask = loc->deny; i > 0; i --, mask ++)
-    if (mask->type == CUPSD_AUTH_NAME || mask->type == CUPSD_AUTH_INTERFACE)
-      free(mask->mask.name.name);
-
-  if (loc->num_deny > 0)
-    free(loc->deny);
-
-  free(loc->location);
-  free(loc);
-}
-
-
-/*
- * 'cupsdDenyHost()' - Add a host name that is not allowed to access the
- *                     location.
- */
-
-void
-cupsdDenyHost(cupsd_location_t *loc,   /* I - Location to add to */
-              char             *name)  /* I - Name of host or domain to add */
-{
-  cupsd_authmask_t     *temp;          /* New host/domain mask */
-  char                 ifname[32],     /* Interface name */
-                       *ifptr;         /* Pointer to end of name */
-
-
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDenyHost(loc=%p(%s), name=\"%s\")",
-                  loc, loc->location ? loc->location : "nil", name);
-
-  if ((temp = add_deny(loc)) == NULL)
-    return;
-
-  if (!strcasecmp(name, "@LOCAL"))
-  {
-   /*
-    * Deny *interface*...
-    */
-
-    temp->type             = CUPSD_AUTH_INTERFACE;
-    temp->mask.name.name   = strdup("*");
-    temp->mask.name.length = 1;
-  }
-  else if (!strncasecmp(name, "@IF(", 4))
-  {
-   /*
-    * Deny *interface*...
-    */
-
-    strlcpy(ifname, name + 4, sizeof(ifname));
-
-    ifptr = ifname + strlen(ifname);
-
-    if (ifptr[-1] == ')')
-    {
-      ifptr --;
-      *ifptr = '\0';
-    }
-
-    temp->type             = CUPSD_AUTH_INTERFACE;
-    temp->mask.name.name   = strdup(ifname);
-    temp->mask.name.length = ifptr - ifname;
-  }
-  else
-  {
-   /*
-    * Deny name...
-    */
-
-    temp->type             = CUPSD_AUTH_NAME;
-    temp->mask.name.name   = strdup(name);
-    temp->mask.name.length = strlen(name);
-  }
-}
-
-
-/*
- * 'cupsdDenyIP()' - Add an IP address or network that is not allowed to
- *                   access the location.
- */
-
-void
-cupsdDenyIP(cupsd_location_t *loc,     /* I - Location to add to */
-           const unsigned   address[4],/* I - IP address to add */
-           const unsigned   netmask[4])/* I - Netmask of address */
-{
-  cupsd_authmask_t     *temp;          /* New host/domain mask */
-
-
-  cupsdLogMessage(CUPSD_LOG_DEBUG,
-                  "cupsdDenyIP(loc=%p(%s), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)",
-                 loc, loc->location ? loc->location : "nil",
-                 address[0], address[1], address[2], address[3],
-                 netmask[0], netmask[1], netmask[2], netmask[3]);
-
-  if ((temp = add_deny(loc)) == NULL)
-    return;
-
-  temp->type = CUPSD_AUTH_IP;
-  memcpy(temp->mask.ip.address, address, sizeof(temp->mask.ip.address));
-  memcpy(temp->mask.ip.netmask, netmask, sizeof(temp->mask.ip.netmask));
-}
-
-
 /*
  * 'cupsdFindBest()' - Find the location entry that best matches the resource.
  */
@@ -2157,6 +1934,22 @@ cupsdFindLocation(const char *location)  /* I - Connection */
 }
 
 
+/*
+ * 'cupsdFreeLocation()' - Free all memory used by a location.
+ */
+
+void
+cupsdFreeLocation(cupsd_location_t *loc)/* I - Location to free */
+{
+  cupsArrayDelete(loc->names);
+  cupsArrayDelete(loc->allow);
+  cupsArrayDelete(loc->deny);
+
+  _cupsStrFree(loc->location);
+  free(loc);
+}
+
+
 /*
  * 'cupsdIsAuthorized()' - Check to see if the user is authorized...
  */
@@ -2165,13 +1958,14 @@ http_status_t                           /* O - HTTP_OK if authorized or error code */
 cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */
                   const char     *owner)/* I - Owner of object */
 {
-  int                  i, j,           /* Looping vars */
+  int                  i,              /* Looping vars */
                        auth,           /* Authorization status */
                        type;           /* Type of authentication */
   unsigned             address[4];     /* Authorization address */
   cupsd_location_t     *best;          /* Best match for location so far */
   int                  hostlen;        /* Length of hostname */
-  char                 username[256],  /* Username to authorize */
+  char                 *name,          /* Current username */
+                       username[256],  /* Username to authorize */
                        ownername[256], /* Owner name to authorize */
                        *ptr;           /* Pointer into username */
   struct passwd                *pw;            /* User password data */
@@ -2223,7 +2017,7 @@ cupsdIsAuthorized(cupsd_client_t *con,    /* I - Connection */
                   "cupsdIsAuthorized: level=CUPSD_AUTH_%s, type=%s, "
                  "satisfy=CUPSD_AUTH_SATISFY_%s, num_names=%d",
                   levels[best->level], types[type],
-                 best->satisfy ? "ANY" : "ALL", best->num_names);
+                 best->satisfy ? "ANY" : "ALL", cupsArrayCount(best->names));
 
   if (best->limit == CUPSD_AUTH_LIMIT_IPP)
     cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: op=%x(%s)",
@@ -2294,7 +2088,7 @@ cupsdIsAuthorized(cupsd_client_t *con,    /* I - Connection */
   */
 
   if (best->level == CUPSD_AUTH_ANON ||        /* Anonymous access - allow it */
-      (type == CUPSD_AUTH_NONE && best->num_names == 0))
+      (type == CUPSD_AUTH_NONE && cupsArrayCount(best->names) == 0))
     return (HTTP_OK);
 
   if (!con->username[0] && type == CUPSD_AUTH_NONE &&
@@ -2393,7 +2187,7 @@ cupsdIsAuthorized(cupsd_client_t *con,    /* I - Connection */
     * any valid user is OK...
     */
 
-    if (best->num_names == 0)
+    if (cupsArrayCount(best->names) == 0)
       return (HTTP_OK);
 
    /*
@@ -2411,13 +2205,13 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
 
     if (con->authref)
     {
-      for (i = 0; i < best->num_names; i ++)
+      for (name = (char *)cupsArrayFirst(best->names);
+           name;
+          name = (char *)cupsArrayNext(best->names))
       {
-       if (!strncasecmp(best->names[i], "@AUTHKEY(", 9) && 
-           check_authref(con, best->names[i] + 9))
+       if (!strncasecmp(name, "@AUTHKEY(", 9) && check_authref(con, name + 9))
          return (HTTP_OK);
-       else if (!strcasecmp(best->names[i], "@SYSTEM") &&
-                SystemGroupAuthKey &&
+       else if (!strcasecmp(name, "@SYSTEM") && SystemGroupAuthKey &&
                 check_authref(con, SystemGroupAuthKey))
          return (HTTP_OK);
       }
@@ -2426,23 +2220,25 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
     }
 #endif /* HAVE_AUTHORIZATION_H */
 
-    for (i = 0; i < best->num_names; i ++)
+    for (name = (char *)cupsArrayFirst(best->names);
+        name;
+        name = (char *)cupsArrayNext(best->names))
     {
-      if (!strcasecmp(best->names[i], "@OWNER") && owner &&
+      if (!strcasecmp(name, "@OWNER") && owner &&
           !strcasecmp(username, ownername))
        return (HTTP_OK);
-      else if (!strcasecmp(best->names[i], "@SYSTEM"))
+      else if (!strcasecmp(name, "@SYSTEM"))
       {
-        for (j = 0; j < NumSystemGroups; j ++)
-         if (cupsdCheckGroup(username, pw, SystemGroups[j]))
+        for (i = 0; i < NumSystemGroups; i ++)
+         if (cupsdCheckGroup(username, pw, SystemGroups[i]))
            return (HTTP_OK);
       }
-      else if (best->names[i][0] == '@')
+      else if (name[0] == '@')
       {
-        if (cupsdCheckGroup(username, pw, best->names[i] + 1))
+        if (cupsdCheckGroup(username, pw, name + 1))
           return (HTTP_OK);
       }
-      else if (!strcasecmp(username, best->names[i]))
+      else if (!strcasecmp(username, name))
         return (HTTP_OK);
     }
 
@@ -2460,19 +2256,21 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
   * Check to see if this user is in any of the named groups...
   */
 
-  for (i = 0; i < best->num_names; i ++)
+  for (name = (char *)cupsArrayFirst(best->names);
+       name;
+       name = (char *)cupsArrayNext(best->names))
   {
     cupsdLogMessage(CUPSD_LOG_DEBUG2,
                     "cupsdIsAuthorized: Checking group \"%s\" membership...",
-                    best->names[i]);
+                    name);
 
-    if (!strcasecmp(best->names[i], "@SYSTEM"))
+    if (!strcasecmp(name, "@SYSTEM"))
     {
-      for (j = 0; j < NumSystemGroups; j ++)
-       if (cupsdCheckGroup(username, pw, SystemGroups[j]))
+      for (i = 0; i < NumSystemGroups; i ++)
+       if (cupsdCheckGroup(username, pw, SystemGroups[i]))
          return (HTTP_OK);
     }
-    else if (cupsdCheckGroup(username, pw, best->names[i]))
+    else if (cupsdCheckGroup(username, pw, name))
       return (HTTP_OK);
   }
 
@@ -2488,85 +2286,41 @@ cupsdIsAuthorized(cupsd_client_t *con,  /* I - Connection */
 
 
 /*
- * 'add_allow()' - Add an allow mask to the location.
- */
-
-static cupsd_authmask_t *              /* O - New mask record */
-add_allow(cupsd_location_t *loc)       /* I - Location to add to */
-{
-  cupsd_authmask_t     *temp;          /* New mask record */
-
-
- /*
-  * Range-check...
-  */
-
-  if (loc == NULL)
-    return (NULL);
-
- /*
-  * Try to allocate memory for the record...
-  */
-
-  if (loc->num_allow == 0)
-    temp = malloc(sizeof(cupsd_authmask_t));
-  else
-    temp = realloc(loc->allow, sizeof(cupsd_authmask_t) * (loc->num_allow + 1));
-
-  if (temp == NULL)
-    return (NULL);
-
-  loc->allow = temp;
-  temp       += loc->num_allow;
-  loc->num_allow ++;
-
- /*
-  * Clear the mask record and return...
-  */
-
-  memset(temp, 0, sizeof(cupsd_authmask_t));
-  return (temp);
-}
-
-
-/*
- * 'add_deny()' - Add a deny mask to the location.
+ * 'cupsdNewLocation()' - Create a new location for authorization.
+ *
+ * Note: Still need to call cupsdAddLocation() to add it to the list of global
+ * locations.
  */
 
-static cupsd_authmask_t *              /* O - New mask record */
-add_deny(cupsd_location_t *loc)                /* I - Location to add to */
+cupsd_location_t *                     /* O - Pointer to new location record */
+cupsdNewLocation(const char *location) /* I - Location path */
 {
-  cupsd_authmask_t     *temp;          /* New mask record */
+  cupsd_location_t     *temp;          /* New location */
 
 
  /*
-  * Range-check...
+  * Try to allocate memory for the new location.
   */
 
-  if (loc == NULL)
+  if ((temp = calloc(1, sizeof(cupsd_location_t))) == NULL)
     return (NULL);
 
  /*
-  * Try to allocate memory for the record...
+  * Initialize the record and copy the name over...
   */
 
-  if (loc->num_deny == 0)
-    temp = malloc(sizeof(cupsd_authmask_t));
-  else
-    temp = realloc(loc->deny, sizeof(cupsd_authmask_t) * (loc->num_deny + 1));
-
-  if (temp == NULL)
+  if ((temp->location = _cupsStrAlloc(location)) == NULL)
+  {
+    free(temp);
     return (NULL);
+  }
 
-  loc->deny = temp;
-  temp      += loc->num_deny;
-  loc->num_deny ++;
+  temp->length = strlen(temp->location);
 
  /*
-  * Clear the mask record and return...
+  * Return the new record...
   */
 
-  memset(temp, 0, sizeof(cupsd_authmask_t));
   return (temp);
 }
 
@@ -2636,6 +2390,45 @@ compare_locations(cupsd_location_t *a,   /* I - First location */
 }
 
 
+/*
+ * 'copy_authmask()' - Copy function for auth masks.
+ */
+
+static cupsd_authmask_t        *               /* O - New auth mask */
+copy_authmask(cupsd_authmask_t *mask,  /* I - Existing auth mask */
+              void             *data)  /* I - User data (unused) */
+{
+  cupsd_authmask_t     *temp;          /* New auth mask */
+
+
+  (void)data;
+
+  if ((temp = malloc(sizeof(cupsd_authmask_t))) != NULL)
+  {
+    memcpy(temp, mask, sizeof(cupsd_authmask_t));
+
+    if (temp->type == CUPSD_AUTH_NAME || temp->type == CUPSD_AUTH_INTERFACE)
+    {
+     /*
+      * Make a copy of the name...
+      */
+
+      if ((temp->mask.name.name = _cupsStrAlloc(temp->mask.name.name)) == NULL)
+      {
+       /*
+        * Failed to make copy...
+       */
+
+        free(temp);
+       temp = NULL;
+      }
+    }
+  }
+
+  return (temp);
+}
+
+
 #if !HAVE_LIBPAM && !defined(HAVE_USERSEC_H)
 /*
  * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms,
@@ -2759,6 +2552,23 @@ cups_crypt(const char *pw,               /* I - Password string */
 #endif /* !HAVE_LIBPAM && !HAVE_USERSEC_H */
 
 
+/*
+ * 'free_authmask()' - Free function for auth masks.
+ */
+
+static void
+free_authmask(cupsd_authmask_t *mask,  /* I - Auth mask to free */
+              void             *data)  /* I - User data (unused) */
+{
+  (void)data;
+
+  if (mask->type == CUPSD_AUTH_NAME || mask->type == CUPSD_AUTH_INTERFACE)
+    _cupsStrFree(mask->mask.name.name);
+
+  free(mask);
+}
+
+
 /*
  * 'get_md5_password()' - Get an MD5 password.
  */
index 189ca2997af45a316a350d5952b9754710a87292..5e7525cbc0e9a4c16d1c251dce42503a25e57a55 100644 (file)
@@ -1,10 +1,9 @@
 /*
  * "$Id: auth.h 7317 2008-02-15 22:29:27Z mike $"
  *
- *   Authorization definitions for the Common UNIX Printing System (CUPS)
- *   scheduler.
+ *   Authorization definitions for the CUPS scheduler.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -98,12 +97,9 @@ typedef struct
                        type,           /* Type of authentication */
                        level,          /* Access level required */
                        satisfy;        /* Satisfy any or all limits? */
-  int                  num_names;      /* Number of names */
-  char                 **names;        /* User or group names */
-  int                  num_allow;      /* Number of Allow lines */
-  cupsd_authmask_t     *allow;         /* Allow lines */
-  int                  num_deny;       /* Number of Deny lines */
-  cupsd_authmask_t     *deny;          /* Deny lines */
+  cups_array_t         *names,         /* User or group names */
+                       *allow,         /* Allow lines */
+                       *deny;          /* Deny lines */
   http_encryption_t    encryption;     /* To encrypt or not to encrypt... */
 } cupsd_location_t;
 
@@ -128,33 +124,30 @@ VAR http_encryption_t     DefaultEncryption VALUE(HTTP_ENCRYPT_REQUIRED);
  * Prototypes...
  */
 
-extern cupsd_location_t        *cupsdAddLocation(const char *location);
+extern int             cupsdAddIPMask(cups_array_t **masks,
+                                      const unsigned address[4],
+                                      const unsigned netmask[4]);
+extern void            cupsdAddLocation(cupsd_location_t *loc);
 extern void            cupsdAddName(cupsd_location_t *loc, char *name);
-extern void            cupsdAllowHost(cupsd_location_t *loc, char *name);
-extern void            cupsdAllowIP(cupsd_location_t *loc, 
-                                    const unsigned address[4],
-                                    const unsigned netmask[4]);
+extern int             cupsdAddNameMask(cups_array_t **masks, char *name);
 extern void            cupsdAuthorize(cupsd_client_t *con);
 extern int             cupsdCheckAccess(unsigned ip[4], char *name,
                                         int namelen, cupsd_location_t *loc);
 extern int             cupsdCheckAuth(unsigned ip[4], char *name, int namelen,
-                                      int num_masks, cupsd_authmask_t *masks);
+                                      cups_array_t *masks);
 extern int             cupsdCheckGroup(const char *username,
                                        struct passwd *user,
                                        const char *groupname);
 #ifdef HAVE_GSSAPI
 extern krb5_ccache     cupsdCopyKrb5Creds(cupsd_client_t *con);
 #endif /* HAVE_GSSAPI */
-extern cupsd_location_t        *cupsdCopyLocation(cupsd_location_t **loc);
+extern cupsd_location_t        *cupsdCopyLocation(cupsd_location_t *loc);
 extern void            cupsdDeleteAllLocations(void);
-extern void            cupsdDeleteLocation(cupsd_location_t *loc);
-extern void            cupsdDenyHost(cupsd_location_t *loc, char *name);
-extern void            cupsdDenyIP(cupsd_location_t *loc, 
-                                   const unsigned address[4],
-                                   const unsigned netmask[4]);
 extern cupsd_location_t        *cupsdFindBest(const char *path, http_state_t state);
 extern cupsd_location_t        *cupsdFindLocation(const char *location);
+extern void            cupsdFreeLocation(cupsd_location_t *loc);
 extern http_status_t   cupsdIsAuthorized(cupsd_client_t *con, const char *owner);
+extern cupsd_location_t        *cupsdNewLocation(const char *location);
 
 
 /*
index ef73d2e7cf5859b722544a28e9776df889ff06f3..968de49116cb98cad5326253988a6d55baeb3d4f 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: banners.c 7221 2008-01-16 22:20:08Z mike $"
  *
- *   Banner routines for the Common UNIX Printing System (CUPS).
+ *   Banner routines for the CUPS scheduler.
  *
- *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2006 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
index 6ae8baa420155d0a088b07ff6024b4b4287aaf39..b215fe6abd328306c3a0248835c71a3535d620d5 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: banners.h 6649 2007-07-11 21:46:42Z mike $"
  *
- *   Banner definitions for the Common UNIX Printing System (CUPS).
+ *   Banner definitions for the CUPS scheduler.
  *
- *   Copyright 2007 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2006 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
index c34efac0c925059c8fe460043ff96db28d2bc575..0e791f8c4dba9fdf4fe3237db037ec3ff2d8bf06 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * "$Id: cert.c 7673 2008-06-18 22:31:26Z mike $"
  *
- *   Authentication certificate routines for CUPS.
+ *   Authentication certificate routines for the CUPS scheduler.
  *
  *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2006 by Easy Software Products.
index 976600146f2b9a5f38f590e4b613c8155853a64c..444897ebd96d51bd099963881e19d57b2dbb0701 100644 (file)
@@ -1,10 +1,9 @@
 /*
  * "$Id: cert.h 7383 2008-03-20 20:58:07Z mike $"
  *
- *   Authentication certificate definitions for the Common UNIX
- *   Printing System (CUPS).
+ *   Authentication certificate definitions for the CUPS scheduler.
  *
- *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2005 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
index 72b5dbff0d50e4f0ed9da594e58270aaccd432c0..92122c0687b079ac7c46c54bd1d6f31164bce9cd 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * "$Id: classes.c 7724 2008-07-14 06:06:06Z mike $"
  *
- *   Printer class routines for the Common UNIX Printing System (CUPS).
+ *   Printer class routines for the CUPS scheduler.
  *
  *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
@@ -584,7 +584,7 @@ cupsdLoadAllClasses(void)
       if (value)
       {
         p->deny_users = 0;
-        cupsdAddPrinterUser(p, value);
+        cupsdAddString(&(p->users), value);
       }
       else
        cupsdLogMessage(CUPSD_LOG_ERROR,
@@ -595,7 +595,7 @@ cupsdLoadAllClasses(void)
       if (value)
       {
         p->deny_users = 1;
-        cupsdAddPrinterUser(p, value);
+        cupsdAddString(&(p->users), value);
       }
       else
        cupsdLogMessage(CUPSD_LOG_ERROR,
@@ -685,7 +685,8 @@ cupsdSaveAllClasses(void)
   cups_file_t          *fp;            /* classes.conf file */
   char                 temp[1024],     /* Temporary string */
                        backup[1024],   /* printers.conf.O file */
-                       value[2048];    /* Value string */
+                       value[2048],    /* Value string */
+                       *name;          /* Current user name */
   cupsd_printer_t      *pclass;        /* Current printer class */
   int                  i;              /* Looping var */
   time_t               curtime;        /* Current time */
@@ -825,9 +826,10 @@ cupsdSaveAllClasses(void)
     cupsFilePrintf(fp, "PageLimit %d\n", pclass->page_limit);
     cupsFilePrintf(fp, "KLimit %d\n", pclass->k_limit);
 
-    for (i = 0; i < pclass->num_users; i ++)
-      cupsFilePutConf(fp, pclass->deny_users ? "DenyUser" : "AllowUser",
-                      pclass->users[i]);
+    for (name = (char *)cupsArrayFirst(pclass->users);
+         name;
+        name = (char *)cupsArrayNext(pclass->users))
+      cupsFilePutConf(fp, pclass->deny_users ? "DenyUser" : "AllowUser", name);
 
      if (pclass->op_policy)
       cupsFilePutConf(fp, "OpPolicy", pclass->op_policy);
index e9940ce2b8e00df4d57b1bbf3dedb1b7e2304434..ef415762ab42d37fa20e90f3401bf005df9b6da8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * "$Id: classes.h 6649 2007-07-11 21:46:42Z mike $"
  *
- *   Printer class definitions for the Common UNIX Printing System (CUPS).
+ *   Printer class definitions for the CUPS scheduler.
  *
  *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2005 by Easy Software Products, all rights reserved.
index 298fdfe301204344e0b2a28684ce0dea66b4e450..f6a446195780de515614224f81426db10de7ea77 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * "$Id: client.c 7950 2008-09-17 00:21:59Z mike $"
  *
- *   Client routines for the Common UNIX Printing System (CUPS) scheduler.
+ *   Client routines for the CUPS scheduler.
  *
  *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
@@ -2545,26 +2545,27 @@ cupsdSendHeader(
       * parameter as needed...
       */
 
-      int      i;                      /* Looping var */
-      char     *auth_key;              /* Auth key buffer */
+      char     *name,                  /* Current user name */
+               *auth_key;              /* Auth key buffer */
       size_t   auth_size;              /* Size of remaining buffer */
 
       auth_key  = auth_str + strlen(auth_str);
       auth_size = sizeof(auth_str) - (auth_key - auth_str);
 
-      for (i = 0; i < con->best->num_names; i ++)
+      for (name = (char *)cupsArrayFirst(con->best->names);
+           name;
+          name = (char *)cupsArrayNext(con->best->names))
       {
 #ifdef HAVE_AUTHORIZATION_H
-       if (!strncasecmp(con->best->names[i], "@AUTHKEY(", 9))
+       if (!strncasecmp(name, "@AUTHKEY(", 9))
        {
-         snprintf(auth_key, auth_size, ", authkey=\"%s\"",
-                  con->best->names[i] + 9);
+         snprintf(auth_key, auth_size, ", authkey=\"%s\"", name + 9);
          /* end parenthesis is stripped in conf.c */
          break;
         }
        else
 #endif /* HAVE_AUTHORIZATION_H */
-       if (!strcasecmp(con->best->names[i], "@SYSTEM"))
+       if (!strcasecmp(name, "@SYSTEM"))
        {
 #ifdef HAVE_AUTHORIZATION_H
          if (SystemGroupAuthKey)
@@ -3513,7 +3514,19 @@ get_cdsa_certificate(
       goto cleanup;
     }
 
+    CFRelease(search);
+    search = NULL;
+    if ((err = SecIdentitySearchCreateWithPolicy(policy, NULL, CSSM_KEYUSE_SIGN,
+                                              keychain, FALSE, &search)))
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                     "Cannot create identity search reference: %s (%d)",
+                     cssmErrorString(err), (int)err);
+      goto cleanup;
+    }
+
     err = SecIdentitySearchCopyNext(search, &identity);
+
   }
 
   if (err)
@@ -4477,11 +4490,21 @@ make_certificate(cupsd_client_t *con)   /* I - Client connection */
                *argv[4],               /* Command-line arguments */
                *envp[MAX_ENV + 1],     /* Environment variables */
                keychain[1024],         /* Keychain argument */
-               infofile[1024];         /* Type-in information for cert */
+               infofile[1024],         /* Type-in information for cert */
+               localname[1024],        /* Local hostname */
+               *servername;            /* Name of server in cert */
   cups_file_t  *fp;                    /* Seed/info file */
   int          infofd;                 /* Info file descriptor */
 
 
+  if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName)
+  {
+    snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName);
+    servername = localname;
+  }
+  else
+    servername = con->servername;
+       
  /*
   * Run the "certtool" command to generate a self-signed certificate...
   */
@@ -4509,7 +4532,7 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
   }
 
   cupsFilePrintf(fp, "%s\nr\n\ny\nb\ns\ny\n%s\n\n\n\n\n%s\ny\n",
-                con->servername, con->servername, ServerAdmin);
+                servername, servername, ServerAdmin);
   cupsFileClose(fp);
 
   cupsdLogMessage(CUPSD_LOG_INFO,
index aa2cee81866cb4b51259a1d1915f239b323f0eb5..a88f9dcefa34a8145d598f41bee6d6ba6d556a63 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: client.h 7935 2008-09-11 01:54:11Z mike $"
  *
- *   Client definitions for the Common UNIX Printing System (CUPS) scheduler.
+ *   Client definitions for the CUPS scheduler.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
index a10f1cdb34ab20d91a4468dc2f8014d0d4241c61..b85c79ce663b05311d17ca0ed62b7ee5919b2c17 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * "$Id: conf.c 7952 2008-09-17 00:56:20Z mike $"
+ * "$Id: conf.c 9352 2010-11-06 04:55:26Z mike $"
  *
- *   Configuration routines for the Common UNIX Printing System (CUPS).
+ *   Configuration routines for the CUPS scheduler.
  *
  *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
@@ -29,6 +29,7 @@
  *   read_configuration()     - Read a configuration file.
  *   read_location()          - Read a <Location path> definition.
  *   read_policy()            - Read a <Policy name> definition.
+ *   set_policy_defaults()    - Set default policy values as needed.
  */
 
 /*
@@ -209,6 +210,7 @@ static int          parse_protocols(const char *s);
 static int             read_configuration(cups_file_t *fp);
 static int             read_location(cups_file_t *fp, char *name, int linenum);
 static int             read_policy(cups_file_t *fp, char *name, int linenum);
+static void            set_policy_defaults(cupsd_policy_t *pol);
 
 
 /*
@@ -462,8 +464,7 @@ cupsdReadConfiguration(void)
   if (NumRelays > 0)
   {
     for (i = 0; i < NumRelays; i ++)
-      if (Relays[i].from.type == CUPSD_AUTH_NAME)
-       free(Relays[i].from.mask.name.name);
+      cupsArrayDelete(Relays[i].from);
 
     free(Relays);
 
@@ -1166,6 +1167,27 @@ cupsdReadConfiguration(void)
       DefaultPolicyPtr = p = cupsdAddPolicy("default");
 
       cupsdLogMessage(CUPSD_LOG_INFO, "<Policy default>");
+
+      cupsdLogMessage(CUPSD_LOG_INFO, "JobPrivateAccess default");
+      cupsdAddString(&(p->job_access), "@OWNER");
+      cupsdAddString(&(p->job_access), "@SYSTEM");
+
+      cupsdLogMessage(CUPSD_LOG_INFO, "JobPrivateValues default");
+      cupsdAddString(&(p->job_attrs), "job-name");
+      cupsdAddString(&(p->job_attrs), "job-originating-host-name");
+      cupsdAddString(&(p->job_attrs), "job-originating-user-name");
+
+      cupsdLogMessage(CUPSD_LOG_INFO, "SubscriptionPrivateAccess default");
+      cupsdAddString(&(p->sub_access), "@OWNER");
+      cupsdAddString(&(p->sub_access), "@SYSTEM");
+
+      cupsdLogMessage(CUPSD_LOG_INFO, "SubscriptionPrivateValues default");
+      cupsdAddString(&(p->job_attrs), "notify-events");
+      cupsdAddString(&(p->job_attrs), "notify-pull-method");
+      cupsdAddString(&(p->job_attrs), "notify-recipient-uri");
+      cupsdAddString(&(p->job_attrs), "notify-subscriber-user-name");
+      cupsdAddString(&(p->job_attrs), "notify-user-data");
+
       cupsdLogMessage(CUPSD_LOG_INFO,
                       "<Limit Create-Job Print-Job Print-URI Validate-Job>");
       cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
@@ -1185,7 +1207,7 @@ cupsdReadConfiguration(void)
                      "Set-Job-Attributes Create-Job-Subscription "
                      "Renew-Subscription Cancel-Subscription "
                      "Get-Notifications Reprocess-Job Cancel-Current-Job "
-                     "Suspend-Current-Job Resume-Job Cancel-Jobs "
+                     "Suspend-Current-Job Resume-Job "
                      "Cancel-My-Jobs Close-Job CUPS-Move-Job "
                      "CUPS-Authenticate-Job CUPS-Get-Document>");
       cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
@@ -1213,7 +1235,6 @@ cupsdReadConfiguration(void)
       cupsdAddPolicyOp(p, po, IPP_CANCEL_CURRENT_JOB);
       cupsdAddPolicyOp(p, po, IPP_SUSPEND_CURRENT_JOB);
       cupsdAddPolicyOp(p, po, IPP_RESUME_JOB);
-      cupsdAddPolicyOp(p, po, IPP_CANCEL_JOBS);
       cupsdAddPolicyOp(p, po, IPP_CANCEL_MY_JOBS);
       cupsdAddPolicyOp(p, po, IPP_CLOSE_JOB);
       cupsdAddPolicyOp(p, po, CUPS_MOVE_JOB);
@@ -1229,7 +1250,7 @@ cupsdReadConfiguration(void)
                      "Hold-New-Jobs Release-Held-New-Jobs "
                      "Deactivate-Printer Activate-Printer Restart-Printer "
                      "Shutdown-Printer Startup-Printer Promote-Job "
-                     "Schedule-Job-After CUPS-Add-Printer "
+                     "Schedule-Job-After Cancel-Jobs CUPS-Add-Printer "
                      "CUPS-Delete-Printer CUPS-Add-Class CUPS-Delete-Class "
                      "CUPS-Accept-Jobs CUPS-Reject-Jobs CUPS-Set-Default>");
       cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
@@ -1257,6 +1278,7 @@ cupsdReadConfiguration(void)
       cupsdAddPolicyOp(p, po, IPP_STARTUP_PRINTER);
       cupsdAddPolicyOp(p, po, IPP_PROMOTE_JOB);
       cupsdAddPolicyOp(p, po, IPP_SCHEDULE_JOB_AFTER);
+      cupsdAddPolicyOp(p, po, IPP_CANCEL_JOBS);
       cupsdAddPolicyOp(p, po, CUPS_ADD_PRINTER);
       cupsdAddPolicyOp(p, po, CUPS_DELETE_PRINTER);
       cupsdAddPolicyOp(p, po, CUPS_ADD_CLASS);
@@ -1888,9 +1910,9 @@ parse_aaa(cupsd_location_t *loc,  /* I - Location */
        */
 
        if (!strcasecmp(line, "Allow"))
-         cupsdAllowIP(loc, zeros, zeros);
+         cupsdAddIPMask(&(loc->allow), zeros, zeros);
        else
-         cupsdDenyIP(loc, zeros, zeros);
+         cupsdAddIPMask(&(loc->deny), zeros, zeros);
       }
       else if (!strcasecmp(value, "none"))
       {
@@ -1899,9 +1921,9 @@ parse_aaa(cupsd_location_t *loc,  /* I - Location */
        */
 
        if (!strcasecmp(line, "Allow"))
-         cupsdAllowIP(loc, ones, zeros);
+         cupsdAddIPMask(&(loc->allow), ones, zeros);
        else
-         cupsdDenyIP(loc, ones, zeros);
+         cupsdAddIPMask(&(loc->deny), ones, zeros);
       }
 #ifdef AF_INET6
       else if (value[0] == '*' || value[0] == '.' ||
@@ -1918,9 +1940,9 @@ parse_aaa(cupsd_location_t *loc,  /* I - Location */
          value ++;
 
        if (!strcasecmp(line, "Allow"))
-         cupsdAllowHost(loc, value);
+         cupsdAddNameMask(&(loc->allow), value);
        else
-         cupsdDenyHost(loc, value);
+         cupsdAddNameMask(&(loc->deny), value);
       }
       else
       {
@@ -1936,9 +1958,9 @@ parse_aaa(cupsd_location_t *loc,  /* I - Location */
        }
 
        if (!strcasecmp(line, "Allow"))
-         cupsdAllowIP(loc, ip, mask);
+         cupsdAddIPMask(&(loc->allow), ip, mask);
        else
-         cupsdDenyIP(loc, ip, mask);
+         cupsdAddIPMask(&(loc->deny), ip, mask);
       }
 
      /*
@@ -2407,8 +2429,6 @@ read_configuration(cups_file_t *fp)       /* I - File to read from */
                                        /* Line from file */
                        temp[HTTP_MAX_BUFFER],
                                        /* Temporary buffer for value */
-                       temp2[HTTP_MAX_BUFFER],
-                                       /* Temporary buffer 2 for value */
                        *ptr,           /* Pointer into line/temp */
                        *value,         /* Pointer to value */
                        *valueptr;      /* Pointer into value */
@@ -2704,7 +2724,8 @@ read_configuration(cups_file_t *fp)       /* I - File to read from */
       */
 
       if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL)
-        location = cupsdAddLocation("CUPS_INTERNAL_BROWSE_ACL");
+        if ((location = cupsdNewLocation("CUPS_INTERNAL_BROWSE_ACL")) != NULL)
+         cupsdAddLocation(location);
 
       if (location == NULL)
         cupsdLogMessage(CUPSD_LOG_ERROR,
@@ -2752,35 +2773,43 @@ read_configuration(cups_file_t *fp)     /* I - File to read from */
       */
 
       if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL)
-        location = cupsdAddLocation("CUPS_INTERNAL_BROWSE_ACL");
+        if ((location = cupsdNewLocation("CUPS_INTERNAL_BROWSE_ACL")) != NULL)
+         cupsdAddLocation(location);
+
 
       if (location == NULL)
         cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Unable to initialize browse access control list!");
       else
       {
-       while (*value)
+       if (!strncasecmp(value, "from", 4))
        {
-         if (!strncasecmp(value, "from", 4))
-         {
-          /*
-           * Strip leading "from"...
-           */
+        /*
+         * Skip leading "from"...
+         */
 
-           value += 4;
+         value += 4;
+       }
 
-           while (isspace(*value & 255))
-             value ++;
+       while (*value)
+       {
+        /*
+         * Skip leading whitespace...
+         */
 
-           if (!*value)
-             break;
-         }
+         while (isspace(*value & 255))
+           value ++;
+
+         if (!*value)
+           break;
 
         /*
          * Find the end of the value...
          */
 
-         for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
+         for (valueptr = value;
+              *valueptr && !isspace(*valueptr & 255);
+              valueptr ++);
 
          while (isspace(*valueptr & 255))
            *valueptr++ = '\0';
@@ -2808,9 +2837,9 @@ read_configuration(cups_file_t *fp)       /* I - File to read from */
            */
 
            if (!strcasecmp(line, "BrowseAllow"))
-             cupsdAllowIP(location, zeros, zeros);
+             cupsdAddIPMask(&(location->allow), zeros, zeros);
            else
-             cupsdDenyIP(location, zeros, zeros);
+             cupsdAddIPMask(&(location->deny), zeros, zeros);
          }
          else if (!strcasecmp(value, "none"))
          {
@@ -2819,28 +2848,26 @@ read_configuration(cups_file_t *fp)     /* I - File to read from */
            */
 
            if (!strcasecmp(line, "BrowseAllow"))
-             cupsdAllowIP(location, ones, zeros);
+             cupsdAddIPMask(&(location->allow), ones, zeros);
            else
-             cupsdDenyIP(location, ones, zeros);
+             cupsdAddIPMask(&(location->deny), ones, zeros);
          }
 #ifdef AF_INET6
          else if (value[0] == '*' || value[0] == '.' ||
                   (!isdigit(value[0] & 255) && value[0] != '['))
 #else
-         else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0] & 255))
+         else if (value[0] == '*' || value[0] == '.' ||
+                  !isdigit(value[0] & 255))
 #endif /* AF_INET6 */
          {
           /*
            * Host or domain name...
            */
 
-           if (value[0] == '*')
-             value ++;
-
            if (!strcasecmp(line, "BrowseAllow"))
-             cupsdAllowHost(location, value);
+             cupsdAddNameMask(&(location->allow), value);
            else
-             cupsdDenyHost(location, value);
+             cupsdAddNameMask(&(location->deny), value);
          }
          else
          {
@@ -2856,9 +2883,9 @@ read_configuration(cups_file_t *fp)       /* I - File to read from */
            }
 
            if (!strcasecmp(line, "BrowseAllow"))
-             cupsdAllowIP(location, ip, mask);
+             cupsdAddIPMask(&(location->allow), ip, mask);
            else
-             cupsdDenyIP(location, ip, mask);
+             cupsdAddIPMask(&(location->deny), ip, mask);
          }
 
         /*
@@ -2896,15 +2923,30 @@ read_configuration(cups_file_t *fp)     /* I - File to read from */
       if (!strncasecmp(value, "from ", 5))
       {
        /*
-        * Strip leading "from"...
+       * Skip leading "from"...
        */
 
        value += 5;
 
+       /*
+        * Skip leading whitespace...
+       */
+
        while (isspace(*value))
          value ++;
       }
 
+     /*
+      * Find the end of the from value...
+      */
+
+      for (valueptr = value;
+          *valueptr && !isspace(*valueptr & 255);
+          valueptr ++);
+
+      while (isspace(*valueptr & 255))
+       *valueptr++ = '\0';
+
      /*
       * Figure out what form the from address takes:
       *
@@ -2930,24 +2972,13 @@ read_configuration(cups_file_t *fp)     /* I - File to read from */
         * Host or domain name...
        */
 
-       if (value[0] == '*')
-         value ++;
-
-        strlcpy(temp, value, sizeof(temp));
-       if ((ptr = strchr(temp, ' ')) != NULL)
-         *ptr = '\0';
-
-        relay->from.type = CUPSD_AUTH_NAME;
-
-       if ((relay->from.mask.name.name = strdup(temp)) == NULL)
+        if (!cupsdAddNameMask(&(relay->from), value))
        {
          cupsdLogMessage(CUPSD_LOG_ERROR,
                          "Unable to allocate BrowseRelay name at line %d - %s.",
                          linenum, strerror(errno));
          continue;
        }
-
-       relay->from.mask.name.length = strlen(temp);
       }
       else
       {
@@ -2962,41 +2993,32 @@ read_configuration(cups_file_t *fp)     /* I - File to read from */
          break;
        }
 
-        relay->from.type = CUPSD_AUTH_IP;
-       memcpy(relay->from.mask.ip.address, ip,
-              sizeof(relay->from.mask.ip.address));
-       memcpy(relay->from.mask.ip.netmask, mask,
-              sizeof(relay->from.mask.ip.netmask));
+        if (!cupsdAddIPMask(&(relay->from), ip, mask))
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Unable to allocate BrowseRelay IP at line %d - %s.",
+                         linenum, strerror(errno));
+         continue;
+       }
       }
 
      /*
-      * Skip value and trailing whitespace...
+      * Get "to" address and port...
       */
 
-      for (; *value; value ++)
-       if (isspace(*value))
-         break;
-
-      while (isspace(*value))
-        value ++;
-
-      if (!strncasecmp(value, "to ", 3))
+      if (!strncasecmp(valueptr, "to ", 3))
       {
        /*
         * Strip leading "to"...
        */
 
-       value += 3;
+       valueptr += 3;
 
-       while (isspace(*value))
-         value ++;
+       while (isspace(*valueptr))
+         valueptr ++;
       }
 
-     /*
-      * Get "to" address and port...
-      */
-
-      if ((addrlist = get_address(value, BrowsePort)) != NULL)
+      if ((addrlist = get_address(valueptr, BrowsePort)) != NULL)
       {
        /*
         * Only IPv4 addresses are supported...
@@ -3012,37 +3034,29 @@ read_configuration(cups_file_t *fp)     /* I - File to read from */
 
          httpAddrString(&(relay->to), temp, sizeof(temp));
 
-         if (relay->from.type == CUPSD_AUTH_IP)
-           snprintf(temp2, sizeof(temp2), "%u.%u.%u.%u/%u.%u.%u.%u",
-                    relay->from.mask.ip.address[0] >> 24,
-                    (relay->from.mask.ip.address[0] >> 16) & 255,
-                    (relay->from.mask.ip.address[0] >> 8) & 255,
-                    relay->from.mask.ip.address[0] & 255,
-                    relay->from.mask.ip.netmask[0] >> 24,
-                    (relay->from.mask.ip.netmask[0] >> 16) & 255,
-                    (relay->from.mask.ip.netmask[0] >> 8) & 255,
-                    relay->from.mask.ip.netmask[0] & 255);
-         else
-           strlcpy(temp2, relay->from.mask.name.name, sizeof(temp2));
-
          cupsdLogMessage(CUPSD_LOG_INFO, "Relaying from %s to %s:%d (IPv4)",
-                         temp2, temp, ntohs(relay->to.ipv4.sin_port));
+                         value, temp, ntohs(relay->to.ipv4.sin_port));
 
          NumRelays ++;
        }
        else
+       {
+         cupsArrayDelete(relay->from);
+         relay->from = NULL;
+
          cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.",
-                         value, linenum);
+                         valueptr, linenum);
+       }
 
        httpAddrFreeList(addrlist);
       }
       else
       {
-        if (relay->from.type == CUPSD_AUTH_NAME)
-         free(relay->from.mask.name.name);
+       cupsArrayDelete(relay->from);
+       relay->from = NULL;
 
         cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.",
-                       value, linenum);
+                       valueptr, linenum);
       }
     }
     else if (!strcasecmp(line, "BrowsePoll") && value)
@@ -3563,9 +3577,11 @@ read_location(cups_file_t *fp,           /* I - Configuration file */
                        *valptr;        /* Pointer into value */
 
 
-  if ((parent = cupsdAddLocation(location)) == NULL)
+  if ((parent = cupsdNewLocation(location)) == NULL)
     return (0);
 
+  cupsdAddLocation(parent);
+
   parent->limit = CUPSD_AUTH_LIMIT_ALL;
   loc           = parent;
 
@@ -3589,9 +3605,11 @@ read_location(cups_file_t *fp,           /* I - Configuration file */
          continue;
       }
 
-      if ((loc = cupsdCopyLocation(&parent)) == NULL)
+      if ((loc = cupsdCopyLocation(parent)) == NULL)
         return (0);
 
+      cupsdAddLocation(loc);
+
       loc->limit = 0;
       while (*value)
       {
@@ -3694,106 +3712,7 @@ read_policy(cups_file_t *fp,            /* I - Configuration file */
                        "Missing </Limit> before </Policy> on line %d!",
                        linenum);
 
-     /*
-      * Verify that we have an explicit policy for Validate-Job, Cancel-Jobs,
-      * Cancel-My-Jobs, Close-Job, and CUPS-Get-Document, which ensures that
-      * upgrades do not introduce new security issues...
-      */
-
-      if ((op = cupsdFindPolicyOp(pol, IPP_VALIDATE_JOB)) == NULL ||
-          op->op == IPP_ANY_OPERATION)
-      {
-        if ((op = cupsdFindPolicyOp(pol, IPP_PRINT_JOB)) != NULL &&
-            op->op != IPP_ANY_OPERATION)
-       {
-        /*
-         * Add a new limit for Validate-Job using the Print-Job limit as a
-         * template...
-         */
-
-          cupsdLogMessage(CUPSD_LOG_WARN,
-                         "No limit for Validate-Job defined in policy %s "
-                         "- using Print-Job's policy", pol->name);
-
-          cupsdAddPolicyOp(pol, op, IPP_VALIDATE_JOB);
-       }
-      }
-
-      if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_JOBS)) == NULL ||
-          op->op == IPP_ANY_OPERATION)
-      {
-        if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_JOB)) != NULL &&
-            op->op != IPP_ANY_OPERATION)
-       {
-        /*
-         * Add a new limit for Cancel-Jobs using the Cancel-Job limit as a
-         * template...
-         */
-
-          cupsdLogMessage(CUPSD_LOG_WARN,
-                         "No limit for Cancel-Jobs defined in policy %s "
-                         "- using Cancel-Job's policy", pol->name);
-
-          cupsdAddPolicyOp(pol, op, IPP_CANCEL_JOBS);
-       }
-      }
-
-      if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_MY_JOBS)) == NULL ||
-          op->op == IPP_ANY_OPERATION)
-      {
-        if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
-            op->op != IPP_ANY_OPERATION)
-       {
-        /*
-         * Add a new limit for Cancel-My-Jobs using the Send-Document limit as
-         * a template...
-         */
-
-          cupsdLogMessage(CUPSD_LOG_WARN,
-                         "No limit for Cancel-My-Jobs defined in policy %s "
-                         "- using Send-Document's policy", pol->name);
-
-          cupsdAddPolicyOp(pol, op, IPP_CANCEL_MY_JOBS);
-       }
-      }
-
-      if ((op = cupsdFindPolicyOp(pol, IPP_CLOSE_JOB)) == NULL ||
-          op->op == IPP_ANY_OPERATION)
-      {
-        if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
-            op->op != IPP_ANY_OPERATION)
-       {
-        /*
-         * Add a new limit for Close-Job using the Send-Document limit as a
-         * template...
-         */
-
-          cupsdLogMessage(CUPSD_LOG_WARN,
-                         "No limit for Close-Job defined in policy %s "
-                         "- using Send-Document's policy", pol->name);
-
-          cupsdAddPolicyOp(pol, op, IPP_CLOSE_JOB);
-       }
-      }
-
-      if ((op = cupsdFindPolicyOp(pol, CUPS_GET_DOCUMENT)) == NULL ||
-          op->op == IPP_ANY_OPERATION)
-      {
-        if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
-            op->op != IPP_ANY_OPERATION)
-       {
-        /*
-         * Add a new limit for CUPS-Get-Document using the Send-Document
-         * limit as a template...
-         */
-
-          cupsdLogMessage(CUPSD_LOG_WARN,
-                         "No limit for CUPS-Get-Document defined in policy %s "
-                         "- using Send-Document's policy", pol->name);
-
-          cupsdAddPolicyOp(pol, op, CUPS_GET_DOCUMENT);
-       }
-      }
+      set_policy_defaults(pol);
 
       return (linenum);
     }
@@ -3874,6 +3793,109 @@ read_policy(cups_file_t *fp,            /* I - Configuration file */
 
       op = NULL;
     }
+    else if (!strcasecmp(line, "JobPrivateAccess") ||
+            !strcasecmp(line, "JobPrivateValues") ||
+            !strcasecmp(line, "SubscriptionPrivateAccess") ||
+            !strcasecmp(line, "SubscriptionPrivateValues"))
+    {
+      if (op)
+      {
+        cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "%s directive must appear outside <Limit>...</Limit> "
+                       "on line %d.", line, linenum);
+       if (FatalErrors & CUPSD_FATAL_CONFIG)
+         return (0);
+      }
+      else
+      {
+       /*
+        * Pull out whitespace-delimited values...
+       */
+
+       while (*value)
+       {
+        /*
+         * Find the end of the current value...
+         */
+
+         for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
+
+         if (*valptr)
+           *valptr++ = '\0';
+
+         /*
+         * Save it appropriately...
+         */
+
+         if (!strcasecmp(line, "JobPrivateAccess"))
+         {
+          /*
+           * JobPrivateAccess {all|default|user/group list|@@ACL}
+           */
+
+            if (!strcasecmp(value, "default"))
+           {
+             cupsdAddString(&(pol->job_access), "@OWNER");
+             cupsdAddString(&(pol->job_access), "@SYSTEM");
+           }
+           else
+             cupsdAddString(&(pol->job_access), value);
+         }
+         else if (!strcasecmp(line, "JobPrivateValues"))
+         {
+          /*
+           * JobPrivateValues {all|none|default|attribute list}
+           */
+
+           if (!strcasecmp(value, "default"))
+           {
+             cupsdAddString(&(pol->job_attrs), "job-name");
+             cupsdAddString(&(pol->job_attrs), "job-originating-host-name");
+             cupsdAddString(&(pol->job_attrs), "job-originating-user-name");
+           }
+           else
+             cupsdAddString(&(pol->job_attrs), value);
+         }
+         else if (!strcasecmp(line, "SubscriptionPrivateAccess"))
+         {
+          /*
+           * SubscriptionPrivateAccess {all|default|user/group list|@@ACL}
+           */
+
+            if (!strcasecmp(value, "default"))
+           {
+             cupsdAddString(&(pol->sub_access), "@OWNER");
+             cupsdAddString(&(pol->sub_access), "@SYSTEM");
+           }
+           else
+             cupsdAddString(&(pol->sub_access), value);
+         }
+         else /* if (!strcasecmp(line, "SubscriptionPrivateValues")) */
+         {
+          /*
+           * SubscriptionPrivateValues {all|none|default|attribute list}
+           */
+
+           if (!strcasecmp(value, "default"))
+           {
+             cupsdAddString(&(pol->sub_attrs), "notify-events");
+             cupsdAddString(&(pol->sub_attrs), "notify-pull-method");
+             cupsdAddString(&(pol->sub_attrs), "notify-recipient-uri");
+             cupsdAddString(&(pol->sub_attrs), "notify-subscriber-user-name");
+             cupsdAddString(&(pol->sub_attrs), "notify-user-data");
+           }
+           else
+             cupsdAddString(&(pol->sub_attrs), value);
+         }
+
+        /*
+         * Find the next string on the line...
+         */
+
+         for (value = valptr; isspace(*value & 255); value ++);
+       }
+      }
+    }
     else if (!op)
     {
       cupsdLogMessage(CUPSD_LOG_ERROR,
@@ -3907,5 +3929,183 @@ read_policy(cups_file_t *fp,            /* I - Configuration file */
 
 
 /*
- * End of "$Id: conf.c 7952 2008-09-17 00:56:20Z mike $".
+ * 'set_policy_defaults()' - Set default policy values as needed.
+ */
+
+static void
+set_policy_defaults(cupsd_policy_t *pol)/* I - Policy */
+{
+  cupsd_location_t     *op;            /* Policy operation */
+
+
+ /*
+  * Verify that we have an explicit policy for Validate-Job, Cancel-Jobs,
+  * Cancel-My-Jobs, Close-Job, and CUPS-Get-Document, which ensures that
+  * upgrades do not introduce new security issues...
+  */
+
+  if ((op = cupsdFindPolicyOp(pol, IPP_VALIDATE_JOB)) == NULL ||
+      op->op == IPP_ANY_OPERATION)
+  {
+    if ((op = cupsdFindPolicyOp(pol, IPP_PRINT_JOB)) != NULL &&
+       op->op != IPP_ANY_OPERATION)
+    {
+     /*
+      * Add a new limit for Validate-Job using the Print-Job limit as a
+      * template...
+      */
+
+      cupsdLogMessage(CUPSD_LOG_WARN,
+                     "No limit for Validate-Job defined in policy %s "
+                     "- using Print-Job's policy.", pol->name);
+
+      cupsdAddPolicyOp(pol, op, IPP_VALIDATE_JOB);
+    }
+    else
+      cupsdLogMessage(CUPSD_LOG_WARN,
+                     "No limit for Validate-Job defined in policy %s "
+                     "and no suitable template found.", pol->name);
+  }
+
+  if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_JOBS)) == NULL ||
+      op->op == IPP_ANY_OPERATION)
+  {
+    if ((op = cupsdFindPolicyOp(pol, IPP_PAUSE_PRINTER)) != NULL &&
+       op->op != IPP_ANY_OPERATION)
+    {
+     /*
+      * Add a new limit for Cancel-Jobs using the Pause-Printer limit as a
+      * template...
+      */
+
+      cupsdLogMessage(CUPSD_LOG_WARN,
+                     "No limit for Cancel-Jobs defined in policy %s "
+                     "- using Pause-Printer's policy.", pol->name);
+
+      cupsdAddPolicyOp(pol, op, IPP_CANCEL_JOBS);
+    }
+    else
+      cupsdLogMessage(CUPSD_LOG_WARN,
+                     "No limit for Cancel-Jobs defined in policy %s "
+                     "and no suitable template found.", pol->name);
+  }
+
+  if ((op = cupsdFindPolicyOp(pol, IPP_CANCEL_MY_JOBS)) == NULL ||
+      op->op == IPP_ANY_OPERATION)
+  {
+    if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
+       op->op != IPP_ANY_OPERATION)
+    {
+     /*
+      * Add a new limit for Cancel-My-Jobs using the Send-Document limit as
+      * a template...
+      */
+
+      cupsdLogMessage(CUPSD_LOG_WARN,
+                     "No limit for Cancel-My-Jobs defined in policy %s "
+                     "- using Send-Document's policy.", pol->name);
+
+      cupsdAddPolicyOp(pol, op, IPP_CANCEL_MY_JOBS);
+    }
+    else
+      cupsdLogMessage(CUPSD_LOG_WARN,
+                     "No limit for Cancel-My-Jobs defined in policy %s "
+                     "and no suitable template found.", pol->name);
+  }
+
+  if ((op = cupsdFindPolicyOp(pol, IPP_CLOSE_JOB)) == NULL ||
+      op->op == IPP_ANY_OPERATION)
+  {
+    if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
+       op->op != IPP_ANY_OPERATION)
+    {
+     /*
+      * Add a new limit for Close-Job using the Send-Document limit as a
+      * template...
+      */
+
+      cupsdLogMessage(CUPSD_LOG_WARN,
+                     "No limit for Close-Job defined in policy %s "
+                     "- using Send-Document's policy.", pol->name);
+
+      cupsdAddPolicyOp(pol, op, IPP_CLOSE_JOB);
+    }
+    else
+      cupsdLogMessage(CUPSD_LOG_WARN,
+                     "No limit for Close-Job defined in policy %s "
+                     "and no suitable template found.", pol->name);
+  }
+
+  if ((op = cupsdFindPolicyOp(pol, CUPS_GET_DOCUMENT)) == NULL ||
+      op->op == IPP_ANY_OPERATION)
+  {
+    if ((op = cupsdFindPolicyOp(pol, IPP_SEND_DOCUMENT)) != NULL &&
+       op->op != IPP_ANY_OPERATION)
+    {
+     /*
+      * Add a new limit for CUPS-Get-Document using the Send-Document
+      * limit as a template...
+      */
+
+      cupsdLogMessage(CUPSD_LOG_WARN,
+                     "No limit for CUPS-Get-Document defined in policy %s "
+                     "- using Send-Document's policy.", pol->name);
+
+      cupsdAddPolicyOp(pol, op, CUPS_GET_DOCUMENT);
+    }
+    else
+      cupsdLogMessage(CUPSD_LOG_WARN,
+                     "No limit for CUPS-Get-Document defined in policy %s "
+                     "and no suitable template found.", pol->name);
+  }
+
+ /*
+  * Verify we have JobPrivateAccess, JobPrivateValues,
+  * SubscriptionPrivateAccess, and SubscriptionPrivateValues in the policy.
+  */
+
+  if (!pol->job_access)
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                   "No JobPrivateAccess defined in policy %s "
+                   "- using defaults.", pol->name);
+    cupsdAddString(&(pol->job_access), "@OWNER");
+    cupsdAddString(&(pol->job_access), "@SYSTEM");
+  }
+
+  if (!pol->job_attrs)
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                   "No JobPrivateValues defined in policy %s "
+                   "- using defaults.", pol->name);
+    cupsdAddString(&(pol->job_attrs), "job-name");
+    cupsdAddString(&(pol->job_attrs), "job-originating-host-name");
+    cupsdAddString(&(pol->job_attrs), "job-originating-user-name");
+  }
+
+  if (!pol->sub_access)
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                   "No SubscriptionPrivateAccess defined in policy %s "
+                   "- using defaults.", pol->name);
+    cupsdAddString(&(pol->sub_access), "@OWNER");
+    cupsdAddString(&(pol->sub_access), "@SYSTEM");
+  }
+
+  if (!pol->sub_attrs)
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                   "No SubscriptionPrivateValues defined in policy %s "
+                   "- using defaults.", pol->name);
+    cupsdAddString(&(pol->sub_attrs), "notify-events");
+    cupsdAddString(&(pol->sub_attrs), "notify-pull-method");
+    cupsdAddString(&(pol->sub_attrs), "notify-recipient-uri");
+    cupsdAddString(&(pol->sub_attrs), "notify-subscriber-user-name");
+    cupsdAddString(&(pol->sub_attrs), "notify-user-data");
+  }
+}
+
+
+/*
+ * End of "$Id: conf.c 9352 2010-11-06 04:55:26Z mike $".
  */
index d1cab69a1b0388812a60ca8f4abee0cd6ca371f2..c98e89a009fca60c457818059960b90b8192f89a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * "$Id: conf.h 7935 2008-09-11 01:54:11Z mike $"
  *
- *   Configuration file definitions for CUPS.
+ *   Configuration file definitions for the CUPS scheduler.
  *
  *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
index 547a032d0680f10da5aa5c5439631adbb51587a4..a7195985d26f653e2c759185eb902893720cb262 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: cups-deviced.c 7816 2008-07-30 20:53:31Z mike $"
  *
- *   Device scanning mini-daemon for the Common UNIX Printing System (CUPS).
+ *   Device scanning mini-daemon for CUPS.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2006 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
index 1c5ce2560f2c744aa1a8ea9d9a33a8eaba60d543..f1ba5cc7c2144c6cf57ae5a313338aea158dc24c 100644 (file)
@@ -177,8 +177,10 @@ VAR int                    Launchd         VALUE(0);
  * Prototypes...
  */
 
+extern int     cupsdAddString(cups_array_t **a, const char *s);
 extern void    cupsdCheckProcess(void);
 extern void    cupsdClearString(char **s);
+extern void    cupsdFreeStrings(cups_array_t **a);
 extern void    cupsdHoldSignals(void);
 extern void    cupsdReleaseSignals(void);
 extern void    cupsdSetString(char **s, const char *v);
index b40cc55647fb33e7d28ce026d27049ced28cd878..e2e7bee8418894a3f072b432cacc4e9256f7c294 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * "$Id: cupsfilter.c 7952 2008-09-17 00:56:20Z mike $"
  *
- *   CUPS filtering program for CUPS.
+ *   Filtering program for CUPS.
  *
  *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
index 581ab6763ef9579be5b48f0b7830b8d60718dd32..2f7f0e6c4dbc2dae6044f50140265dab2236534d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * "$Id: dirsvc.c 7933 2008-09-11 00:44:58Z mike $"
  *
- *   Directory services routines for the Common UNIX Printing System (CUPS).
+ *   Directory services routines for the CUPS scheduler.
  *
  *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
@@ -634,7 +634,7 @@ cupsdLoadRemoteCache(void)
       if (value)
       {
         p->deny_users = 0;
-        cupsdAddPrinterUser(p, value);
+        cupsdAddString(&(p->users), value);
       }
       else
        cupsdLogMessage(CUPSD_LOG_ERROR,
@@ -645,7 +645,7 @@ cupsdLoadRemoteCache(void)
       if (value)
       {
         p->deny_users = 1;
-        cupsdAddPrinterUser(p, value);
+        cupsdAddString(&(p->users), value);
       }
       else
        cupsdLogMessage(CUPSD_LOG_ERROR,
@@ -728,7 +728,8 @@ cupsdSaveRemoteCache(void)
   int                  i;              /* Looping var */
   cups_file_t          *fp;            /* printers.conf file */
   char                 temp[1024],     /* Temporary string */
-                       value[2048];    /* Value string */
+                       value[2048],    /* Value string */
+                       *name;          /* Current user name */
   cupsd_printer_t      *printer;       /* Current printer class */
   time_t               curtime;        /* Current time */
   struct tm            *curdate;       /* Current date */
@@ -829,9 +830,10 @@ cupsdSaveRemoteCache(void)
              printer->job_sheets[1]);
     cupsFilePutConf(fp, "JobSheets", value);
 
-    for (i = 0; i < printer->num_users; i ++)
-      cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser",
-                      printer->users[i]);
+    for (name = (char *)cupsArrayFirst(printer->users);
+        name;
+        name = (char *)cupsArrayNext(printer->users))
+      cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", name);
 
     for (i = printer->num_options, option = printer->options;
          i > 0;
@@ -5194,24 +5196,20 @@ update_cups_browse(void)
        case CUPSD_AUTH_ALLOW : /* Order Deny,Allow */
             auth = CUPSD_AUTH_ALLOW;
 
-            if (cupsdCheckAuth(address, srcname, len,
-                         BrowseACL->num_deny, BrowseACL->deny))
+            if (cupsdCheckAuth(address, srcname, len, BrowseACL->deny))
              auth = CUPSD_AUTH_DENY;
 
-            if (cupsdCheckAuth(address, srcname, len,
-                         BrowseACL->num_allow, BrowseACL->allow))
+            if (cupsdCheckAuth(address, srcname, len, BrowseACL->allow))
              auth = CUPSD_AUTH_ALLOW;
            break;
 
        case CUPSD_AUTH_DENY : /* Order Allow,Deny */
             auth = CUPSD_AUTH_DENY;
 
-            if (cupsdCheckAuth(address, srcname, len,
-                         BrowseACL->num_allow, BrowseACL->allow))
+            if (cupsdCheckAuth(address, srcname, len, BrowseACL->allow))
              auth = CUPSD_AUTH_ALLOW;
 
-            if (cupsdCheckAuth(address, srcname, len,
-                         BrowseACL->num_deny, BrowseACL->deny))
+            if (cupsdCheckAuth(address, srcname, len, BrowseACL->deny))
              auth = CUPSD_AUTH_DENY;
            break;
       }
@@ -5323,7 +5321,7 @@ update_cups_browse(void)
   */
 
   for (i = 0; i < NumRelays; i ++)
-    if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
+    if (cupsdCheckAuth(address, srcname, len, Relays[i].from))
       if (sendto(BrowseSocket, packet, bytes, 0,
                  (struct sockaddr *)&(Relays[i].to),
                 httpAddrLength(&(Relays[i].to))) <= 0)
index c17a2540671187a979826f2967edfa4bd0f08e5d..cc4eb20476cc2988069fe3831068476b71f2d89a 100644 (file)
@@ -1,10 +1,9 @@
 /*
  * "$Id: dirsvc.h 7933 2008-09-11 00:44:58Z mike $"
  *
- *   Directory services definitions for the Common UNIX Printing System
- *   (CUPS) scheduler.
+ *   Directory services definitions for the CUPS scheduler.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -62,7 +61,7 @@ typedef struct
 
 typedef struct
 {
-  cupsd_authmask_t     from;           /* Source address/name mask */
+  cups_array_t         *from;          /* Source address/name mask(s) */
   http_addr_t          to;             /* Destination address */
 } cupsd_dirsvc_relay_t;
 
index 94d7c355b97e8a8b62639ad7077e435306b85786..9cf6ff26f647f94a65e9aa3017a68443c81a2c78 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: env.c 7673 2008-06-18 22:31:26Z mike $"
  *
- *   Environment management routines for the Common UNIX Printing System (CUPS).
+ *   Environment management routines for the CUPS scheduler.
  *
- *   Copyright 2007 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
index b1049b1ff03ca6da06ded0b91318e31ed84d8093..207596c0859564677453633f6ca956dfea8532be 100644 (file)
@@ -167,7 +167,8 @@ static ipp_attribute_t      *copy_attribute(ipp_t *to, ipp_attribute_t *attr,
                                        int quickcopy);
 static void    close_job(cupsd_client_t *con, ipp_attribute_t *uri);
 static void    copy_attrs(ipp_t *to, ipp_t *from, cups_array_t *ra,
-                          ipp_tag_t group, int quickcopy);
+                          ipp_tag_t group, int quickcopy,
+                          cups_array_t *exclude);
 static int     copy_banner(cupsd_client_t *con, cupsd_job_t *job,
                            const char *name);
 static int     copy_file(const char *from, const char *to);
@@ -175,13 +176,14 @@ static int        copy_model(cupsd_client_t *con, const char *from,
                           const char *to);
 static void    copy_job_attrs(cupsd_client_t *con,
                               cupsd_job_t *job,
-                              cups_array_t *ra);
+                              cups_array_t *ra, cups_array_t *exclude);
 static void    copy_printer_attrs(cupsd_client_t *con,
                                   cupsd_printer_t *printer,
                                   cups_array_t *ra);
 static void    copy_subscription_attrs(cupsd_client_t *con,
                                        cupsd_subscription_t *sub,
-                                       cups_array_t *ra);
+                                       cups_array_t *ra,
+                                       cups_array_t *exclude);
 static void    create_job(cupsd_client_t *con, ipp_attribute_t *uri);
 static cups_array_t *create_requested_array(ipp_t *request);
 static void    create_subscription(cupsd_client_t *con, ipp_attribute_t *uri);
@@ -4396,8 +4398,8 @@ static int                                /* O - 1 if OK, 0 if forbidden,
 check_quotas(cupsd_client_t  *con,     /* I - Client connection */
              cupsd_printer_t *p)       /* I - Printer or class */
 {
-  int          i;                      /* Looping var */
-  char         username[33];           /* Username */
+  char         username[33],           /* Username */
+               *name;                  /* Current user name */
   cupsd_quota_t        *q;                     /* Quota data */
 #ifdef HAVE_MBR_UID_TO_UUID
  /*
@@ -4464,10 +4466,10 @@ check_quotas(cupsd_client_t  *con,      /* I - Client connection */
   * Check against users...
   */
 
-  if (p->num_users == 0 && p->k_limit == 0 && p->page_limit == 0)
+  if (cupsArrayCount(p->users) == 0 && p->k_limit == 0 && p->page_limit == 0)
     return (1);
 
-  if (p->num_users)
+  if (cupsArrayCount(p->users))
   {
 #ifdef HAVE_MBR_UID_TO_UUID
    /*
@@ -4498,21 +4500,22 @@ check_quotas(cupsd_client_t  *con,      /* I - Client connection */
     endpwent();
 #endif /* HAVE_MBR_UID_TO_UUID */
 
-    for (i = 0; i < p->num_users; i ++)
-      if (p->users[i][0] == '@')
+    for (name = (char *)cupsArrayFirst(p->users);
+         name;
+        name = (char *)cupsArrayNext(p->users))
+      if (name[0] == '@')
       {
        /*
         * Check group membership...
        */
 
 #ifdef HAVE_MBR_UID_TO_UUID
-        if (p->users[i][1] == '#')
+        if (name[1] == '#')
        {
-         if (uuid_parse((char *)p->users[i] + 2, grp_uuid))
+         if (uuid_parse(name + 2, grp_uuid))
            uuid_clear(grp_uuid);
        }
-       else if ((mbr_err = mbr_group_name_to_uuid((char *)p->users[i] + 1,
-                                                  grp_uuid)) != 0)
+       else if ((mbr_err = mbr_group_name_to_uuid(name + 1, grp_uuid)) != 0)
        {
         /*
          * Invalid ACL entries are ignored for matching; just record a
@@ -4521,10 +4524,10 @@ check_quotas(cupsd_client_t  *con,      /* I - Client connection */
 
          cupsdLogMessage(CUPSD_LOG_DEBUG,
                          "check_quotas: UUID lookup failed for ACL entry "
-                         "\"%s\" (err=%d)", p->users[i], mbr_err);
+                         "\"%s\" (err=%d)", name, mbr_err);
          cupsdLogMessage(CUPSD_LOG_WARN,
                          "Access control entry \"%s\" not a valid group name; "
-                         "entry ignored", p->users[i]);
+                         "entry ignored", name);
        }
 
        if ((mbr_err = mbr_check_membership(usr_uuid, grp_uuid,
@@ -4536,7 +4539,7 @@ check_quotas(cupsd_client_t  *con,        /* I - Client connection */
 
          cupsdLogMessage(CUPSD_LOG_DEBUG,
                          "check_quotas: group \"%s\" membership check "
-                         "failed (err=%d)", p->users[i] + 1, mbr_err);
+                         "failed (err=%d)", name + 1, mbr_err);
          is_member = 0;
        }
 
@@ -4548,20 +4551,19 @@ check_quotas(cupsd_client_t  *con,      /* I - Client connection */
          break;
 
 #else
-        if (cupsdCheckGroup(username, pw, p->users[i] + 1))
+        if (cupsdCheckGroup(username, pw, name + 1))
          break;
 #endif /* HAVE_MBR_UID_TO_UUID */
       }
 #ifdef HAVE_MBR_UID_TO_UUID
       else
       {
-        if (p->users[i][0] == '#')
+        if (name[0] == '#')
        {
-         if (uuid_parse((char *)p->users[i] + 1, usr2_uuid))
+         if (uuid_parse(name + 1, usr2_uuid))
            uuid_clear(usr2_uuid);
         }
-        else if ((mbr_err = mbr_user_name_to_uuid((char *)p->users[i],
-                                                 usr2_uuid)) != 0)
+        else if ((mbr_err = mbr_user_name_to_uuid(name, usr2_uuid)) != 0)
        {
         /*
          * Invalid ACL entries are ignored for matching; just record a
@@ -4570,21 +4572,21 @@ check_quotas(cupsd_client_t  *con,      /* I - Client connection */
 
           cupsdLogMessage(CUPSD_LOG_DEBUG,
                          "check_quotas: UUID lookup failed for ACL entry "
-                         "\"%s\" (err=%d)", p->users[i], mbr_err);
+                         "\"%s\" (err=%d)", name, mbr_err);
           cupsdLogMessage(CUPSD_LOG_WARN,
                          "Access control entry \"%s\" not a valid user name; "
-                         "entry ignored", p->users[i]);
+                         "entry ignored", name);
        }
 
        if (!uuid_compare(usr_uuid, usr2_uuid))
          break;
       }
 #else
-      else if (!strcasecmp(username, p->users[i]))
+      else if (!strcasecmp(username, name))
        break;
 #endif /* HAVE_MBR_UID_TO_UUID */
 
-    if ((i < p->num_users) == p->deny_users)
+    if ((name != NULL) == p->deny_users)
     {
       cupsdLogMessage(CUPSD_LOG_INFO,
                       "Denying user \"%s\" access to printer \"%s\"...",
@@ -4940,7 +4942,8 @@ copy_attrs(ipp_t        *to,              /* I - Destination request */
            ipp_t        *from,         /* I - Source request */
            cups_array_t *ra,           /* I - Requested attributes */
           ipp_tag_t    group,          /* I - Group to copy */
-          int          quickcopy)      /* I - Do a quick copy? */
+          int          quickcopy,      /* I - Do a quick copy? */
+          cups_array_t *exclude)       /* I - Attributes to exclude? */
 {
   ipp_attribute_t      *fromattr;      /* Source attribute */
 
@@ -4962,6 +4965,23 @@ copy_attrs(ipp_t        *to,             /* I - Destination request */
          fromattr->group_tag != IPP_TAG_ZERO) || !fromattr->name)
       continue;
 
+    if (exclude && 
+        (cupsArrayFind(exclude, fromattr->name) ||
+        cupsArrayFind(exclude, "all")))
+    {
+     /*
+      * We need to exclude this attribute for security reasons; we require the
+      * job-id and job-printer-uri attributes regardless of the security
+      * settings for IPP conformance.
+      *
+      * Subscription attribute security is handled by copy_subscription_attrs().
+      */
+
+      if (strcmp(fromattr->name, "job-id") &&
+         strcmp(fromattr->name, "job-printer-uri"))
+        continue;
+    }
+
     if (!ra || cupsArrayFind(ra, fromattr->name))
     {
      /*
@@ -5608,7 +5628,8 @@ copy_model(cupsd_client_t *con,           /* I - Client connection */
 static void
 copy_job_attrs(cupsd_client_t *con,    /* I - Client connection */
               cupsd_job_t    *job,     /* I - Job */
-              cups_array_t   *ra)      /* I - Requested attributes array */
+              cups_array_t   *ra,      /* I - Requested attributes array */
+              cups_array_t   *exclude) /* I - Private attributes array */
 {
   char job_uri[HTTP_MAX_URI];          /* Job URI */
 
@@ -5621,26 +5642,34 @@ copy_job_attrs(cupsd_client_t *con,     /* I - Client connection */
                    con->servername, con->serverport, "/jobs/%d",
                   job->id);
 
-  if (!ra || cupsArrayFind(ra, "document-count"))
-    ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
-                 "document-count", job->num_files);
+  if (!cupsArrayFind(exclude, "all"))
+  {
+    if ((!exclude || !cupsArrayFind(exclude, "document-count")) &&
+        (!ra || cupsArrayFind(ra, "document-count")))
+      ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
+                   "document-count", job->num_files);
 
-  if (!ra || cupsArrayFind(ra, "job-media-progress"))
-    ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
-                 "job-media-progress", job->progress);
+    if ((!exclude || !cupsArrayFind(exclude, "job-media-progress")) &&
+        (!ra || cupsArrayFind(ra, "job-media-progress")))
+      ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
+                   "job-media-progress", job->progress);
 
-  if (!ra || cupsArrayFind(ra, "job-more-info"))
-    ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
-                "job-more-info", NULL, job_uri);
+    if ((!exclude || !cupsArrayFind(exclude, "job-more-info")) &&
+        (!ra || cupsArrayFind(ra, "job-more-info")))
+      ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
+                  "job-more-info", NULL, job_uri);
 
-  if (job->state_value > IPP_JOB_PROCESSING &&
-      (!ra || cupsArrayFind(ra, "job-preserved")))
-    ippAddBoolean(con->response, IPP_TAG_JOB, "job-preserved",
-                  job->num_files > 0);
+    if (job->state_value > IPP_JOB_PROCESSING &&
+       (!exclude || !cupsArrayFind(exclude, "job-preserved")) &&
+        (!ra || cupsArrayFind(ra, "job-preserved")))
+      ippAddBoolean(con->response, IPP_TAG_JOB, "job-preserved",
+                   job->num_files > 0);
 
-  if (!ra || cupsArrayFind(ra, "job-printer-up-time"))
-    ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
-                  "job-printer-up-time", time(NULL));
+    if ((!exclude || !cupsArrayFind(exclude, "job-printer-up-time")) &&
+        (!ra || cupsArrayFind(ra, "job-printer-up-time")))
+      ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
+                   "job-printer-up-time", time(NULL));
+  }
 
   if (!ra || cupsArrayFind(ra, "job-state-reasons"))
     add_job_state_reasons(con, job);
@@ -5649,7 +5678,7 @@ copy_job_attrs(cupsd_client_t *con,       /* I - Client connection */
     ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
                 "job-uri", NULL, job_uri);
 
-  copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0);
+  copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0, exclude);
 }
 
 
@@ -5821,7 +5850,7 @@ copy_printer_attrs(
 
     for (i = 0; i < printer->num_history; i ++)
       copy_attrs(history->values[i].collection = ippNew(), printer->history[i],
-                 NULL, IPP_TAG_ZERO, 0);
+                 NULL, IPP_TAG_ZERO, 0, NULL);
   }
 
   if (!ra || cupsArrayFind(ra, "printer-state-message"))
@@ -5875,10 +5904,10 @@ copy_printer_attrs(
   if (!ra || cupsArrayFind(ra, "queued-job-count"))
     add_queued_job_count(con, printer);
 
-  copy_attrs(con->response, printer->attrs, ra, IPP_TAG_ZERO, 0);
+  copy_attrs(con->response, printer->attrs, ra, IPP_TAG_ZERO, 0, NULL);
   if (printer->ppd_attrs)
-    copy_attrs(con->response, printer->ppd_attrs, ra, IPP_TAG_ZERO, 0);
-  copy_attrs(con->response, CommonData, ra, IPP_TAG_ZERO, IPP_TAG_COPY);
+    copy_attrs(con->response, printer->ppd_attrs, ra, IPP_TAG_ZERO, 0, NULL);
+  copy_attrs(con->response, CommonData, ra, IPP_TAG_ZERO, IPP_TAG_COPY, NULL);
 }
 
 
@@ -5890,7 +5919,8 @@ static void
 copy_subscription_attrs(
     cupsd_client_t       *con,         /* I - Client connection */
     cupsd_subscription_t *sub,         /* I - Subscription */
-    cups_array_t         *ra)          /* I - Requested attributes array */
+    cups_array_t         *ra,          /* I - Requested attributes array */
+    cups_array_t         *exclude)     /* I - Private attributes array */
 {
   ipp_attribute_t      *attr;          /* Current attribute */
   char                 printer_uri[HTTP_MAX_URI];
@@ -5900,56 +5930,92 @@ copy_subscription_attrs(
   const char           *name;          /* Current event name */
 
 
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "copy_subscription_attrs(con=%p, sub=%p, ra=%p, exclude=%p)",
+                 con, sub, ra, exclude);
+
  /*
   * Copy the subscription attributes to the response using the
   * requested-attributes attribute that may be provided by the client.
   */
 
-  if (!ra || cupsArrayFind(ra, "notify-events"))
+  if (!exclude || !cupsArrayFind(exclude, "all"))
   {
-    if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL)
+    if ((!exclude || !cupsArrayFind(exclude, "notify-events")) &&
+        (!ra || cupsArrayFind(ra, "notify-events")))
     {
-     /*
-      * Simple event list...
-      */
+      cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_subscription_attrs: notify-events");
 
-      ippAddString(con->response, IPP_TAG_SUBSCRIPTION,
-                   (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY),
-                   "notify-events", NULL, name);
-    }
-    else
-    {
-     /*
-      * Complex event list...
-      */
+      if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL)
+      {
+       /*
+       * Simple event list...
+       */
+
+       ippAddString(con->response, IPP_TAG_SUBSCRIPTION,
+                    (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY),
+                    "notify-events", NULL, name);
+      }
+      else
+      {
+       /*
+       * Complex event list...
+       */
 
-      for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1)
-       if (sub->mask & mask)
-          count ++;
+       for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1)
+         if (sub->mask & mask)
+           count ++;
 
-      attr = ippAddStrings(con->response, IPP_TAG_SUBSCRIPTION,
-                           (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY),
-                           "notify-events", count, NULL, NULL);
+       attr = ippAddStrings(con->response, IPP_TAG_SUBSCRIPTION,
+                            (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY),
+                            "notify-events", count, NULL, NULL);
 
-      for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1)
-       if (sub->mask & mask)
-       {
-          attr->values[count].string.text =
-             (char *)cupsdEventName((cupsd_eventmask_t)mask);
+       for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1)
+         if (sub->mask & mask)
+         {
+           attr->values[count].string.text =
+               (char *)cupsdEventName((cupsd_eventmask_t)mask);
 
-          count ++;
-       }
+           count ++;
+         }
+      }
     }
+
+    if ((!exclude || !cupsArrayFind(exclude, "notify-lease-duration")) &&
+        (!sub->job && (!ra || cupsArrayFind(ra, "notify-lease-duration"))))
+      ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+                   "notify-lease-duration", sub->lease);
+
+    if ((!exclude || !cupsArrayFind(exclude, "notify-recipient-uri")) &&
+        (sub->recipient && (!ra || cupsArrayFind(ra, "notify-recipient-uri"))))
+      ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
+                  "notify-recipient-uri", NULL, sub->recipient);
+    else if ((!exclude || !cupsArrayFind(exclude, "notify-pull-method")) &&
+             (!ra || cupsArrayFind(ra, "notify-pull-method")))
+      ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
+                  "notify-pull-method", NULL, "ippget");
+
+    if ((!exclude || !cupsArrayFind(exclude, "notify-subscriber-user-name")) &&
+        (!ra || cupsArrayFind(ra, "notify-subscriber-user-name")))
+      ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_NAME,
+                  "notify-subscriber-user-name", NULL, sub->owner);
+
+    if ((!exclude || !cupsArrayFind(exclude, "notify-time-interval")) &&
+        (!ra || cupsArrayFind(ra, "notify-time-interval")))
+      ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+                   "notify-time-interval", sub->interval);
+
+    if (sub->user_data_len > 0 &&
+       (!exclude || !cupsArrayFind(exclude, "notify-user-data")) &&
+        (!ra || cupsArrayFind(ra, "notify-user-data")))
+      ippAddOctetString(con->response, IPP_TAG_SUBSCRIPTION, "notify-user-data",
+                       sub->user_data, sub->user_data_len);
   }
 
   if (sub->job && (!ra || cupsArrayFind(ra, "notify-job-id")))
     ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
                   "notify-job-id", sub->job->id);
 
-  if (!sub->job && (!ra || cupsArrayFind(ra, "notify-lease-duration")))
-    ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
-                  "notify-lease-duration", sub->lease);
-
   if (sub->dest && (!ra || cupsArrayFind(ra, "notify-printer-uri")))
   {
     httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
@@ -5959,28 +6025,9 @@ copy_subscription_attrs(
                 "notify-printer-uri", NULL, printer_uri);
   }
 
-  if (sub->recipient && (!ra || cupsArrayFind(ra, "notify-recipient-uri")))
-    ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI,
-                "notify-recipient-uri", NULL, sub->recipient);
-  else if (!ra || cupsArrayFind(ra, "notify-pull-method"))
-    ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD,
-                 "notify-pull-method", NULL, "ippget");
-
-  if (!ra || cupsArrayFind(ra, "notify-subscriber-user-name"))
-    ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_NAME,
-                "notify-subscriber-user-name", NULL, sub->owner);
-
   if (!ra || cupsArrayFind(ra, "notify-subscription-id"))
     ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
                   "notify-subscription-id", sub->id);
-
-  if (!ra || cupsArrayFind(ra, "notify-time-interval"))
-    ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
-                  "notify-time-interval", sub->interval);
-
-  if (sub->user_data_len > 0 && (!ra || cupsArrayFind(ra, "notify-user-data")))
-    ippAddOctetString(con->response, IPP_TAG_SUBSCRIPTION, "notify-user-data",
-                      sub->user_data, sub->user_data_len);
 }
 
 
@@ -7004,12 +7051,14 @@ get_job_attrs(cupsd_client_t  *con,     /* I - Client connection */
   int          jobid;                  /* Job ID */
   cupsd_job_t  *job;                   /* Current job */
   cupsd_printer_t *printer;            /* Current printer */
-  char         scheme[HTTP_MAX_URI],   /* Method portion of URI */
+  cupsd_policy_t *policy;              /* Current security policy */
+  char         scheme[HTTP_MAX_URI],   /* Scheme portion of URI */
                username[HTTP_MAX_URI], /* Username portion of URI */
                host[HTTP_MAX_URI],     /* Host portion of URI */
                resource[HTTP_MAX_URI]; /* Resource portion of URI */
   int          port;                   /* Port portion of URI */
-  cups_array_t *ra;                    /* Requested attributes array */
+  cups_array_t *ra,                    /* Requested attributes array */
+               *exclude;               /* Private attributes array */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_job_attrs(%p[%d], %s)", con,
@@ -7082,20 +7131,18 @@ get_job_attrs(cupsd_client_t  *con,     /* I - Client connection */
     printer = cupsdFindDest(job->dest);
 
   if (printer)
-  {
-    if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
-                                   NULL)) != HTTP_OK)
-    {
-      send_http_error(con, status, printer);
-      return;
-    }
-  }
-  else if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+    policy = printer->op_policy_ptr;
+  else
+    policy = DefaultPolicyPtr;
+
+  if ((status = cupsdCheckPolicy(policy, con, job->username)) != HTTP_OK)
   {
     send_http_error(con, status, NULL);
     return;
   }
 
+  exclude = cupsdGetPrivateAttrs(policy, con, printer, job->username);
+
  /*
   * Copy attributes...
   */
@@ -7103,7 +7150,7 @@ get_job_attrs(cupsd_client_t  *con,       /* I - Client connection */
   cupsdLoadJob(job);
 
   ra = create_requested_array(con->request);
-  copy_job_attrs(con, job, ra);
+  copy_job_attrs(con, job, ra, exclude);
   cupsArrayDelete(ra);
 
   con->response->request.status.status_code = IPP_OK;
@@ -7137,7 +7184,9 @@ get_jobs(cupsd_client_t  *con,            /* I - Client connection */
   cupsd_job_t  *job;                   /* Current job pointer */
   cupsd_printer_t *printer;            /* Printer */
   cups_array_t *list;                  /* Which job list... */
-  cups_array_t *ra;                    /* Requested attributes array */
+  cups_array_t *ra,                    /* Requested attributes array */
+               *exclude;               /* Private attributes array */
+  cupsd_policy_t *policy;              /* Current policy */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs(%p[%d], %s)", con, con->http.fd,
@@ -7200,15 +7249,11 @@ get_jobs(cupsd_client_t  *con,          /* I - Client connection */
   */
 
   if (printer)
-  {
-    if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con,
-                                   NULL)) != HTTP_OK)
-    {
-      send_http_error(con, status, printer);
-      return;
-    }
-  }
-  else if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+    policy = printer->op_policy_ptr;
+  else
+    policy = DefaultPolicyPtr;
+
+  if ((status = cupsdCheckPolicy(policy, con, NULL)) != HTTP_OK)
   {
     send_http_error(con, status, NULL);
     return;
@@ -7395,7 +7440,12 @@ get_jobs(cupsd_client_t  *con,           /* I - Client connection */
       if (i > 0)
        ippAddSeparator(con->response);
 
-      copy_job_attrs(con, job, ra);
+      exclude = cupsdGetPrivateAttrs(job->printer ?
+                                         job->printer->op_policy_ptr :
+                                        policy, con, job->printer,
+                                        job->username);
+
+      copy_job_attrs(con, job, ra, exclude);
     }
   }
   else
@@ -7451,7 +7501,12 @@ get_jobs(cupsd_client_t  *con,           /* I - Client connection */
 
       count ++;
 
-      copy_job_attrs(con, job, ra);
+      exclude = cupsdGetPrivateAttrs(job->printer ?
+                                         job->printer->op_policy_ptr :
+                                        policy, con, job->printer,
+                                        job->username);
+
+      copy_job_attrs(con, job, ra, exclude);
     }
 
     cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: count=%d", count);
@@ -7577,7 +7632,7 @@ get_notifications(cupsd_client_t *con)    /* I - Client connection */
     * If we don't have any new events, nothing to do here...
     */
 
-    if (min_seq > (sub->first_event_id + sub->num_events))
+    if (min_seq > (sub->first_event_id + cupsArrayCount(sub->events)))
       continue;
 
    /*
@@ -7589,12 +7644,13 @@ get_notifications(cupsd_client_t *con)  /* I - Client connection */
     else
       j = min_seq - sub->first_event_id;
 
-    for (; j < sub->num_events; j ++)
+    for (; j < cupsArrayCount(sub->events); j ++)
     {
       ippAddSeparator(con->response);
 
-      copy_attrs(con->response, sub->events[j]->attrs, NULL,
-                IPP_TAG_EVENT_NOTIFICATION, 0);
+      copy_attrs(con->response,
+                 ((cupsd_event_t *)cupsArrayIndex(sub->events, j))->attrs, NULL,
+                IPP_TAG_EVENT_NOTIFICATION, 0, NULL);
     }
   }
 }
@@ -8162,7 +8218,8 @@ get_printers(cupsd_client_t *con, /* I - Client connection */
       * access...
       */
 
-      if (printer->num_users && username && !user_allowed(printer, username))
+      if (cupsArrayCount(printer->users) && username &&
+         !user_allowed(printer, username))
         continue;
 
      /*
@@ -8199,7 +8256,9 @@ get_subscription_attrs(
 {
   http_status_t                status;         /* Policy status */
   cupsd_subscription_t *sub;           /* Subscription */
-  cups_array_t         *ra;            /* Requested attributes array */
+  cupsd_policy_t       *policy;        /* Current security policy */
+  cups_array_t         *ra,            /* Requested attributes array */
+                       *exclude;       /* Private attributes array */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2,
@@ -8225,14 +8284,19 @@ get_subscription_attrs(
   * Check policy...
   */
 
-  if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr :
-                                             DefaultPolicyPtr,
-                                 con, sub->owner)) != HTTP_OK)
+  if (sub->dest)
+    policy = sub->dest->op_policy_ptr;
+  else
+    policy = DefaultPolicyPtr;
+
+  if ((status = cupsdCheckPolicy(policy, con, sub->owner)) != HTTP_OK)
   {
     send_http_error(con, status, sub->dest);
     return;
   }
 
+  exclude = cupsdGetPrivateAttrs(policy, con, sub->dest, sub->owner);
+
  /*
   * Copy the subscription attributes to the response using the
   * requested-attributes attribute that may be provided by the client.
@@ -8240,7 +8304,7 @@ get_subscription_attrs(
 
   ra = create_requested_array(con->request);
 
-  copy_subscription_attrs(con, sub, ra);
+  copy_subscription_attrs(con, sub, ra, exclude);
 
   cupsArrayDelete(ra);
 
@@ -8274,6 +8338,8 @@ get_subscriptions(cupsd_client_t  *con,   /* I - Client connection */
   int                  port;           /* Port portion of URI */
   cupsd_job_t          *job;           /* Job pointer */
   cupsd_printer_t      *printer;       /* Printer */
+  cupsd_policy_t       *policy;        /* Policy */
+  cups_array_t         *exclude;       /* Private attributes array */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2,
@@ -8337,9 +8403,12 @@ get_subscriptions(cupsd_client_t  *con,  /* I - Client connection */
   * Check policy...
   */
 
-  if ((status = cupsdCheckPolicy(printer ? printer->op_policy_ptr :
-                                           DefaultPolicyPtr,
-                                 con, NULL)) != HTTP_OK)
+  if (printer)
+    policy = printer->op_policy_ptr;
+  else
+    policy = DefaultPolicyPtr;
+
+  if ((status = cupsdCheckPolicy(policy, con, NULL)) != HTTP_OK)
   {
     send_http_error(con, status, printer);
     return;
@@ -8376,7 +8445,12 @@ get_subscriptions(cupsd_client_t  *con,  /* I - Client connection */
         (!username[0] || !strcasecmp(username, sub->owner)))
     {
       ippAddSeparator(con->response);
-      copy_subscription_attrs(con, sub, ra);
+
+      exclude = cupsdGetPrivateAttrs(sub->dest ? sub->dest->op_policy_ptr :
+                                                policy, con, sub->dest,
+                                                sub->owner);
+
+      copy_subscription_attrs(con, sub, ra, exclude);
 
       count ++;
       if (limit && count >= limit)
@@ -11198,7 +11272,7 @@ set_printer_defaults(
     }
     else if (!strcmp(attr->name, "requesting-user-name-allowed"))
     {
-      cupsdFreePrinterUsers(printer);
+      cupsdFreeStrings(&(printer->users));
 
       printer->deny_users = 0;
 
@@ -11207,12 +11281,12 @@ set_printer_defaults(
           strcmp(attr->values[0].string.text, "all")))
       {
        for (i = 0; i < attr->num_values; i ++)
-         cupsdAddPrinterUser(printer, attr->values[i].string.text);
+         cupsdAddString(&(printer->users), attr->values[i].string.text);
       }
     }
     else if (!strcmp(attr->name, "requesting-user-name-denied"))
     {
-      cupsdFreePrinterUsers(printer);
+      cupsdFreeStrings(&(printer->users));
 
       printer->deny_users = 1;
 
@@ -11221,7 +11295,7 @@ set_printer_defaults(
           strcmp(attr->values[0].string.text, "none")))
       {
        for (i = 0; i < attr->num_values; i ++)
-         cupsdAddPrinterUser(printer, attr->values[i].string.text);
+         cupsdAddString(&(printer->users), attr->values[i].string.text);
       }
     }
     else if (!strcmp(attr->name, "job-quota-period"))
@@ -11401,6 +11475,7 @@ static void
 start_printer(cupsd_client_t  *con,    /* I - Client connection */
               ipp_attribute_t *uri)    /* I - Printer URI */
 {
+  int                  i;              /* Temporary variable */
   http_status_t                status;         /* Policy status */
   cups_ptype_t         dtype;          /* Destination type (printer/class) */
   cupsd_printer_t      *printer;       /* Printer data */
@@ -11451,6 +11526,21 @@ start_printer(cupsd_client_t  *con,    /* I - Client connection */
 
   cupsdCheckJobs();
 
+ /*
+  * Check quotas...
+  */
+
+  if ((i = check_quotas(con, printer)) < 0)
+  {
+    send_ipp_status(con, IPP_NOT_POSSIBLE, _("Quota limit reached."));
+    return;
+  }
+  else if (i == 0)
+  {
+    send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Not allowed to print."));
+    return;
+  }
+
  /*
   * Everything was ok, so return OK status...
   */
@@ -11634,13 +11724,13 @@ static int                            /* O - 0 if not allowed, 1 if allowed */
 user_allowed(cupsd_printer_t *p,       /* I - Printer or class */
              const char      *username)        /* I - Username */
 {
-  int          i;                      /* Looping var */
   struct passwd        *pw;                    /* User password data */
   char         baseuser[256],          /* Base username */
-               *baseptr;               /* Pointer to "@" in base username */
+               *baseptr,               /* Pointer to "@" in base username */
+               *name;                  /* Current user name */
 
 
-  if (p->num_users == 0)
+  if (cupsArrayCount(p->users) == 0)
     return (1);
 
   if (!strcmp(username, "root"))
@@ -11663,31 +11753,33 @@ user_allowed(cupsd_printer_t *p,      /* I - Printer or class */
   pw = getpwnam(username);
   endpwent();
 
-  for (i = 0; i < p->num_users; i ++)
+  for (name = (char *)cupsArrayFirst(p->users);
+       name;
+       name = (char *)cupsArrayNext(p->users))
   {
-    if (p->users[i][0] == '@')
+    if (name[0] == '@')
     {
      /*
       * Check group membership...
       */
 
-      if (cupsdCheckGroup(username, pw, p->users[i] + 1))
+      if (cupsdCheckGroup(username, pw, name + 1))
         break;
     }
-    else if (p->users[i][0] == '#')
+    else if (name[0] == '#')
     {
      /*
       * Check UUID...
       */
 
-      if (cupsdCheckGroup(username, pw, p->users[i]))
+      if (cupsdCheckGroup(username, pw, name))
         break;
     }
-    else if (!strcasecmp(username, p->users[i]))
+    else if (!strcasecmp(username, name))
       break;
   }
 
-  return ((i < p->num_users) != p->deny_users);
+  return ((name != NULL) != p->deny_users);
 }
 
 
index cc395d3111ea91b64f049c01111d6db6eeda6d3f..a58ab311df99952c811a5b17196a64c0358a86b8 100644 (file)
@@ -294,6 +294,9 @@ cupsdCheckJobs(void)
 
     if (job->kill_time && job->kill_time <= curtime)
     {
+      cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Stopping unresponsive job!", 
+                     job->id);
+
       stop_job(job, CUPSD_JOB_FORCE);
       continue;
     }
@@ -2721,6 +2724,12 @@ finalize_job(cupsd_job_t *job,           /* I - Job */
   cupsdDestroyProfile(job->profile);
   job->profile = NULL;
 
+ /*
+  * Clear the unresponsive job watchdog timer...
+  */
+
+  job->kill_time = 0;
+
  /*
   * Close pipes and status buffer...
   */
@@ -3068,7 +3077,7 @@ get_options(cupsd_job_t *job,             /* I - Job */
       output_mode = _PWG_OUTPUT_MODE_COLOR;
 
     if ((attr = ippFindAttribute(job->attrs, "print-quality",
-                                IPP_TAG_INTEGER)) != NULL &&
+                                IPP_TAG_ENUM)) != NULL &&
        attr->values[0].integer >= IPP_QUALITY_DRAFT &&
        attr->values[0].integer <= IPP_QUALITY_HIGH)
       print_quality = attr->values[0].integer - IPP_QUALITY_DRAFT;
index 16dd09ff7cfc587fe25f852bdc01c47ae9dab516..2268886b04ccb3ffdb0cff20a69a6482438e4b15 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: job.h 7883 2008-08-28 20:38:13Z mike $"
  *
- *   Print job definitions for the Common UNIX Printing System (CUPS) scheduler.
+ *   Print job definitions for the CUPS scheduler.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -40,6 +40,7 @@ struct cupsd_job_s                    /**** Job request ****/
   char                 *username;      /* Printing user */
   char                 *dest;          /* Destination printer or class */
   cups_ptype_t         dtype;          /* Destination type */
+  cupsd_printer_t      *printer;       /* Printer this job is assigned to */
   int                  num_files;      /* Number of files in job */
   mime_type_t          **filetypes;    /* File types */
   int                  *compressions;  /* Compression status of each file */
@@ -68,7 +69,6 @@ struct cupsd_job_s                    /**** Job request ****/
                                        /* Filter process IDs, 0 terminated */
   int                  backend;        /* Backend process ID */
   int                  status;         /* Status code from filters */
-  cupsd_printer_t      *printer;       /* Printer this job is assigned to */
   int                  tries;          /* Number of tries for this job */
   char                 *auth_username, /* AUTH_USERNAME environment variable,
                                          * if any */
index 85c8071668000a9c1fecb346dc79dcf4335210ac..15af46f06d8c83d9f352ea257eecf7b3e1c4965a 100644 (file)
@@ -1,10 +1,9 @@
 /*
  * "$Id: listen.c 7918 2008-09-08 22:03:01Z mike $"
  *
- *   Server listening routines for the Common UNIX Printing System (CUPS)
- *   scheduler.
+ *   Server listening routines for the CUPS scheduler.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
index 09bb273e9b923271affec2eafe9fd44ffb15a2b8..80ee8e077b41782ba8b39cc0791d69d3681bcf9d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * "$Id: log.c 7918 2008-09-08 22:03:01Z mike $"
  *
- *   Log file routines for the Common UNIX Printing System (CUPS).
+ *   Log file routines for the CUPS scheduler.
  *
  *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
index 1c0bdf4f88c78660fdc172b609acf76addfd6f57..cbd6732d6f079e064f5160d3caae93d3df580615 100644 (file)
  *
  * Contents:
  *
- *   main()                    - Main entry for the CUPS scheduler.
- *   cupsdClosePipe()          - Close a pipe as necessary.
- *   cupsdOpenPipe()           - Create a pipe which is closed on exec.
- *   cupsdHoldSignals()        - Hold child and termination signals.
- *   cupsdReleaseSignals()     - Release signals for delivery.
- *   cupsdSetString()          - Set a string value.
- *   cupsdSetStringf()         - Set a formatted string value.
- *   cupsd_clean_files()       - Clean out old files.
- *   launchd_checkin()         - Check-in with launchd and collect the
- *                               listening fds.
- *   launchd_checkout()        - Check-out with launchd.
- *   parent_handler()          - Catch USR1/CHLD signals...
- *   process_children()        - Process all dead children...
- *   select_timeout()          - Calculate the select timeout value.
- *   sigchld_handler()         - Handle 'child' signals from old processes.
- *   sighup_handler()          - Handle 'hangup' signals to reconfigure the
- *                               scheduler.
- *   sigterm_handler()         - Handle 'terminate' signals that stop the
- *                               scheduler.
- *   usage()                   - Show scheduler usage.
+ *   main()                - Main entry for the CUPS scheduler.
+ *   cupsdAddString()      - Copy and add a string to an array.
+ *   cupsdCheckProcess()   - Tell the main loop to check for dead children.
+ *   cupsdClearString()    - Clear a string.
+ *   cupsdClosePipe()      - Close a pipe as necessary.
+ *   cupsdFreeStrings()    - Free an array of strings.
+ *   cupsdHoldSignals()    - Hold child and termination signals.
+ *   cupsdOpenPipe()       - Create a pipe which is closed on exec.
+ *   cupsdReleaseSignals() - Release signals for delivery.
+ *   cupsdSetString()      - Set a string value.
+ *   cupsdSetStringf()     - Set a formatted string value.
+ *   cupsd_clean_files()   - Clean out old files.
+ *   launchd_checkin()     - Check-in with launchd and collect the listening
+ *                           fds.
+ *   launchd_checkout()    - Update the launchd KeepAlive file as needed.
+ *   parent_handler()      - Catch USR1/CHLD signals...
+ *   process_children()    - Process all dead children...
+ *   select_timeout()      - Calculate the select timeout value.
+ *   sigchld_handler()     - Handle 'child' signals from old processes.
+ *   sighup_handler()      - Handle 'hangup' signals to reconfigure the
+ *                           scheduler.
+ *   sigterm_handler()     - Handle 'terminate' signals that stop the scheduler.
+ *   usage()               - Show scheduler usage.
  */
 
 /*
@@ -1178,6 +1181,24 @@ main(int  argc,                          /* I - Number of command-line args */
 }
 
 
+/*
+ * 'cupsdAddString()' - Copy and add a string to an array.
+ */
+
+int                                    /* O  - 1 on success, 0 on failure */
+cupsdAddString(cups_array_t **a,       /* IO - String array */
+               const char   *s)                /* I  - String to copy and add */
+{
+  if (!*a)
+    *a = cupsArrayNew3((cups_array_func_t)strcmp, NULL,
+                      (cups_ahash_func_t)NULL, 0,
+                      (cups_acopy_func_t)_cupsStrAlloc,
+                      (cups_afree_func_t)_cupsStrFree);
+
+  return (cupsArrayAdd(*a, (char *)s));
+}
+
+
 /*
  * 'cupsdCheckProcess()' - Tell the main loop to check for dead children.
  */
@@ -1193,6 +1214,21 @@ cupsdCheckProcess(void)
 }
 
 
+/*
+ * 'cupsdClearString()' - Clear a string.
+ */
+
+void
+cupsdClearString(char **s)             /* O - String value */
+{
+  if (s && *s)
+  {
+    _cupsStrFree(*s);
+    *s = NULL;
+  }
+}
+
+
 /*
  * 'cupsdClosePipe()' - Close a pipe as necessary.
  */
@@ -1218,6 +1254,49 @@ cupsdClosePipe(int *fds)         /* I - Pipe file descriptors (2) */
 }
 
 
+/*
+ * 'cupsdFreeStrings()' - Free an array of strings.
+ */
+
+void
+cupsdFreeStrings(cups_array_t **a)     /* IO - String array */
+{
+  if (*a)
+  {
+    cupsArrayDelete(*a);
+    *a = NULL;
+  }
+}
+
+
+/*
+ * 'cupsdHoldSignals()' - Hold child and termination signals.
+ */
+
+void
+cupsdHoldSignals(void)
+{
+#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
+  sigset_t             newmask;        /* New POSIX signal mask */
+#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
+
+
+  holdcount ++;
+  if (holdcount > 1)
+    return;
+
+#ifdef HAVE_SIGSET
+  sighold(SIGTERM);
+  sighold(SIGCHLD);
+#elif defined(HAVE_SIGACTION)
+  sigemptyset(&newmask);
+  sigaddset(&newmask, SIGTERM);
+  sigaddset(&newmask, SIGCHLD);
+  sigprocmask(SIG_BLOCK, &newmask, &holdmask);
+#endif /* HAVE_SIGSET */
+}
+
+
 /*
  * 'cupsdOpenPipe()' - Create a pipe which is closed on exec.
  */
@@ -1271,49 +1350,6 @@ cupsdOpenPipe(int *fds)                  /* O - Pipe file descriptors (2) */
 }
 
 
-/*
- * 'cupsdClearString()' - Clear a string.
- */
-
-void
-cupsdClearString(char **s)             /* O - String value */
-{
-  if (s && *s)
-  {
-    _cupsStrFree(*s);
-    *s = NULL;
-  }
-}
-
-
-/*
- * 'cupsdHoldSignals()' - Hold child and termination signals.
- */
-
-void
-cupsdHoldSignals(void)
-{
-#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
-  sigset_t             newmask;        /* New POSIX signal mask */
-#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
-
-
-  holdcount ++;
-  if (holdcount > 1)
-    return;
-
-#ifdef HAVE_SIGSET
-  sighold(SIGTERM);
-  sighold(SIGCHLD);
-#elif defined(HAVE_SIGACTION)
-  sigemptyset(&newmask);
-  sigaddset(&newmask, SIGTERM);
-  sigaddset(&newmask, SIGCHLD);
-  sigprocmask(SIG_BLOCK, &newmask, &holdmask);
-#endif /* HAVE_SIGSET */
-}
-
-
 /*
  * 'cupsdReleaseSignals()' - Release signals for delivery.
  */
@@ -2159,9 +2195,10 @@ usage(int status)                        /* O - Exit status */
                  "\n"
                  "-c config-file      Load alternate configuration file\n"
                  "-f                  Run in the foreground\n"
-                 "-F                  Run in the foreground but detach\n"
+                 "-F                  Run in the foreground but detach from console\n"
                  "-h                  Show this usage message\n"
-                 "-l                  Run cupsd from launchd(8)\n"));
+                 "-l                  Run cupsd from launchd(8)\n"
+                 "-t                  Test the configuration file\n"));
   exit(status);
 }
 
index a6eb515dd8ab4da670cb8754cac758c3eb73a398..630b2d763441538a44b7c404e20c61bd8f6d3fce 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: mime.h 7694 2008-06-26 00:23:20Z mike $"
  *
- *   MIME type/conversion database definitions for the Common UNIX Printing System (CUPS).
+ *   MIME type/conversion database definitions for CUPS.
  *
- *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
index bbb081ade257dc38da89d3b571fcaf9f27f1cba1..95b6badc17c8b539d48ca55bb415f1abc208139f 100644 (file)
@@ -1,10 +1,9 @@
 /*
  * "$Id: network.h 6649 2007-07-11 21:46:42Z mike $"
  *
- *   Network interface definitions for the Common UNIX Printing System
- *   (CUPS) scheduler.
+ *   Network interface definitions for the CUPS scheduler.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
index b7deab72ab809512b07523b2db566af983b99b33..bdca28728aff608ec6b6c6c4e3058e4ebc4abe84 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: policy.c 7673 2008-06-18 22:31:26Z mike $"
  *
- *   Policy routines for the Common UNIX Printing System (CUPS).
+ *   Policy routines for the CUPS scheduler.
  *
- *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
  *
  * Contents:
  *
- *   cupsdAddPolicy()         - Add a policy to the system.
+ *   AddPolicy()              - Add a policy to the system.
  *   cupsdAddPolicyOp()       - Add an operation to a policy.
- *   cupsdCheckPolicy()       - Check the IPP operation and username against
- *                              policy.
+ *   cupsdCheckPolicy()       - Check the IPP operation and username against a
+ *                              policy.
  *   cupsdDeleteAllPolicies() - Delete all policies in memory.
  *   cupsdFindPolicy()        - Find a named policy.
  *   cupsdFindPolicyOp()      - Find a policy operation.
+ *   cupsdGetPrivateAttrs()   - Get the private attributes for the current
+ *                              request.
+ *   compare_ops()            - Compare two operations.
+ *   compare_policies()       - Compare two policies.
+ *   free_policy()            - Free the memory used by a policy.
+ *   hash_op()                - Generate a lookup hash for the operation.
  */
 
 /*
@@ -28,6 +34,7 @@
  */
 
 #include "cupsd.h"
+#include <pwd.h>
 
 
 /*
@@ -36,6 +43,7 @@
 
 static int     compare_ops(cupsd_location_t *a, cupsd_location_t *b);
 static int     compare_policies(cupsd_policy_t *a, cupsd_policy_t *b);
+static void    free_policy(cupsd_policy_t *p);
 static int     hash_op(cupsd_location_t *op);
 
 
@@ -53,7 +61,10 @@ cupsdAddPolicy(const char *policy)   /* I - Name of policy */
     return (NULL);
 
   if (!Policies)
-    Policies = cupsArrayNew((cups_array_func_t)compare_policies, NULL);
+    Policies = cupsArrayNew3((cups_array_func_t)compare_policies, NULL,
+                            (cups_ahash_func_t)NULL, 0,
+                            (cups_acopy_func_t)NULL,
+                            (cups_afree_func_t)free_policy);
 
   if (!Policies)
     return (NULL);
@@ -77,9 +88,7 @@ cupsdAddPolicyOp(cupsd_policy_t   *p, /* I - Policy */
                  cupsd_location_t *po, /* I - Policy operation to copy */
                  ipp_op_t         op)  /* I - IPP operation code */
 {
-  int                  i;              /* Looping var */
   cupsd_location_t     *temp;          /* New policy operation */
-  char                 name[1024];     /* Interface name */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPolicyOp(p=%p, po=%p, op=%x(%s))",
@@ -89,72 +98,20 @@ cupsdAddPolicyOp(cupsd_policy_t   *p,       /* I - Policy */
     return (NULL);
 
   if (!p->ops)
-    p->ops = cupsArrayNew2((cups_array_func_t)compare_ops, NULL,
-                           (cups_ahash_func_t)hash_op, 128);
+    p->ops = cupsArrayNew3((cups_array_func_t)compare_ops, NULL,
+                           (cups_ahash_func_t)hash_op, 128,
+                          (cups_acopy_func_t)NULL,
+                          (cups_afree_func_t)cupsdFreeLocation);
 
   if (!p->ops)
     return (NULL);
 
-  if ((temp = calloc(1, sizeof(cupsd_location_t))) != NULL)
+  if ((temp = cupsdCopyLocation(po)) != NULL)
   {
     temp->op    = op;
     temp->limit = CUPSD_AUTH_LIMIT_IPP;
 
     cupsArrayAdd(p->ops, temp);
-
-    if (po)
-    {
-     /*
-      * Copy the specified policy to the new one...
-      */
-
-      temp->order_type = po->order_type;
-      temp->type       = po->type;
-      temp->level      = po->level;
-      temp->satisfy    = po->satisfy;
-      temp->encryption = po->encryption;
-
-      for (i = 0; i < po->num_names; i ++)
-        cupsdAddName(temp, po->names[i]);
-
-      for (i = 0; i < po->num_allow; i ++)
-        switch (po->allow[i].type)
-       {
-         case CUPSD_AUTH_IP :
-             cupsdAllowIP(temp, po->allow[i].mask.ip.address,
-                          po->allow[i].mask.ip.netmask);
-             break;
-
-          case CUPSD_AUTH_INTERFACE :
-             snprintf(name, sizeof(name), "@IF(%s)",
-                      po->allow[i].mask.name.name);
-              cupsdAllowHost(temp, name);
-             break;
-
-          default :
-              cupsdAllowHost(temp, po->allow[i].mask.name.name);
-             break;
-        }
-
-      for (i = 0; i < po->num_deny; i ++)
-        switch (po->deny[i].type)
-       {
-         case CUPSD_AUTH_IP :
-             cupsdDenyIP(temp, po->deny[i].mask.ip.address,
-                         po->deny[i].mask.ip.netmask);
-             break;
-
-          case CUPSD_AUTH_INTERFACE :
-             snprintf(name, sizeof(name), "@IF(%s)",
-                      po->deny[i].mask.name.name);
-              cupsdDenyHost(temp, name);
-             break;
-
-          default :
-              cupsdDenyHost(temp, po->deny[i].mask.name.name);
-             break;
-        }
-    }
   }
 
   return (temp);
@@ -211,8 +168,6 @@ cupsdCheckPolicy(cupsd_policy_t *p, /* I - Policy */
 void
 cupsdDeleteAllPolicies(void)
 {
-  cupsd_policy_t       *p;             /* Current policy */
-  cupsd_location_t     *po;            /* Current policy op */
   cupsd_printer_t      *printer;       /* Current printer */
 
 
@@ -228,24 +183,12 @@ cupsdDeleteAllPolicies(void)
        printer = (cupsd_printer_t *)cupsArrayNext(Printers))
     printer->op_policy_ptr = NULL;
 
+  DefaultPolicyPtr = NULL;
+
  /*
   * Then free all of the policies...
   */
 
-  for (p = (cupsd_policy_t *)cupsArrayFirst(Policies);
-       p;
-       p = (cupsd_policy_t *)cupsArrayNext(Policies))
-  {
-    for (po = (cupsd_location_t *)cupsArrayFirst(p->ops);
-         po;
-        po = (cupsd_location_t *)cupsArrayNext(p->ops))
-      cupsdDeleteLocation(po);
-
-    cupsArrayDelete(p->ops);
-    cupsdClearString(&p->name);
-    free(p);
-  }
-
   cupsArrayDelete(Policies);
 
   Policies = NULL;
@@ -326,6 +269,197 @@ cupsdFindPolicyOp(cupsd_policy_t *p,      /* I - Policy */
 }
 
 
+/*
+ * 'cupsdGetPrivateAttrs()' - Get the private attributes for the current
+ *                            request.
+ */
+
+cups_array_t *                         /* O - Array or NULL for no restrictions */
+cupsdGetPrivateAttrs(
+    cupsd_policy_t  *policy,           /* I - Policy */
+    cupsd_client_t  *con,              /* I - Client connection */
+    cupsd_printer_t *printer,          /* I - Printer, if any */
+    const char      *owner)            /* I - Owner of object */
+{
+  char         *name;                  /* Current name in access list */
+  cups_array_t *access_ptr,            /* Access array */
+               *attrs_ptr;             /* Attributes array */
+  const char   *username;              /* Username associated with request */
+  ipp_attribute_t *attr;               /* Attribute from request */
+  struct passwd        *pw;                    /* User info */
+
+
+#ifdef DEBUG
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "cupsdGetPrivateAttrs(policy=%p(%s), con=%p(%d), "
+                 "printer=%p(%s), owner=\"%s\")", policy, policy->name, con,
+                 con->http.fd, printer, printer ? printer->name : "", owner);
+#endif /* DEBUG */
+
+ /*
+  * Get the access and attributes lists that correspond to the request...
+  */
+
+#ifdef DEBUG
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: %s",
+                  ippOpString(con->request->request.op.operation_id));
+#endif /* DEBUG */
+
+  switch (con->request->request.op.operation_id)
+  {
+    case IPP_GET_SUBSCRIPTIONS :
+    case IPP_GET_SUBSCRIPTION_ATTRIBUTES :
+    case IPP_GET_NOTIFICATIONS :
+        access_ptr = policy->sub_access;
+       attrs_ptr  = policy->sub_attrs;
+       break;
+
+    default :
+        access_ptr = policy->job_access;
+       attrs_ptr  = policy->job_attrs;
+        break;
+  }
+
+ /*
+  * If none of the attributes are private, return NULL now...
+  */
+
+  if ((name = (char *)cupsArrayFirst(attrs_ptr)) != NULL &&
+      !strcasecmp(name, "none"))
+  {
+#ifdef DEBUG
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
+
+    return (NULL);
+  }
+
+ /*
+  * Otherwise check the user against the access list...
+  */
+
+  if (con->username[0])
+    username = con->username;
+  else if ((attr = ippFindAttribute(con->request, "requesting-user-name",
+                                    IPP_TAG_NAME)) != NULL)
+    username = attr->values[0].string.text;
+  else
+    username = "anonymous";
+
+  if (username[0])
+  {
+    pw = getpwnam(username);
+    endpwent();
+  }
+  else
+    pw = NULL;
+
+#ifdef DEBUG
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: username=\"%s\"",
+                  username);
+#endif /* DEBUG */
+
+ /*
+  * Otherwise check the user against the access list...
+  */
+
+  for (name = (char *)cupsArrayFirst(access_ptr);
+       name;
+       name = (char *)cupsArrayNext(access_ptr))
+  {
+#ifdef DEBUG
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: name=%s", name);
+#endif /* DEBUG */
+
+    if (printer && !strcasecmp(name, "@ACL"))
+    {
+      char     *acl;                   /* Current ACL user/group */
+
+      for (acl = (char *)cupsArrayFirst(printer->users);
+          acl;
+          acl = (char *)cupsArrayNext(printer->users))
+      {
+       if (acl[0] == '@')
+       {
+        /*
+         * Check group membership...
+         */
+
+         if (cupsdCheckGroup(username, pw, acl + 1))
+           break;
+       }
+       else if (acl[0] == '#')
+       {
+        /*
+         * Check UUID...
+         */
+
+         if (cupsdCheckGroup(username, pw, acl))
+           break;
+       }
+       else if (!strcasecmp(username, acl))
+         break;
+      }
+    }
+    else if (owner && !strcasecmp(name, "@OWNER") &&
+             !strcasecmp(username, owner))
+    {
+#ifdef DEBUG
+      cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                     "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
+
+      return (NULL);
+    }
+    else if (!strcasecmp(name, "@SYSTEM"))
+    {
+      int i;                           /* Looping var */
+
+      for (i = 0; i < NumSystemGroups; i ++)
+       if (cupsdCheckGroup(username, pw, SystemGroups[i]))
+       {
+#ifdef DEBUG
+         cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                         "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
+
+         return (NULL);
+       }
+    }
+    else if (name[0] == '@')
+    {
+      if (cupsdCheckGroup(username, pw, name + 1))
+      {
+#ifdef DEBUG
+        cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                       "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
+
+       return (NULL);
+      }
+    }
+    else if (!strcasecmp(username, name))
+    {
+#ifdef DEBUG
+      cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning NULL.");
+#endif /* DEBUG */
+
+      return (NULL);
+    }
+  }
+
+ /*
+  * No direct access, so return private attributes list...
+  */
+
+#ifdef DEBUG
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdGetPrivateAttrs: Returning list.");
+#endif /* DEBUG */
+
+  return (attrs_ptr);
+}
+
+
 /*
  * 'compare_ops()' - Compare two operations.
  */
@@ -350,6 +484,23 @@ compare_policies(cupsd_policy_t *a,        /* I - First policy */
 }
 
 
+/*
+ * 'free_policy()' - Free the memory used by a policy.
+ */
+
+static void
+free_policy(cupsd_policy_t *p)         /* I - Policy to free */
+{
+  cupsArrayDelete(p->job_access);
+  cupsArrayDelete(p->job_attrs);
+  cupsArrayDelete(p->sub_access);
+  cupsArrayDelete(p->sub_attrs);
+  cupsArrayDelete(p->ops);
+  cupsdClearString(&p->name);
+  free(p);
+}
+
+
 /*
  * 'hash_op()' - Generate a lookup hash for the operation.
  */
index d3c0c34b293249d86c395006367f213ee030e336..897b011f5219b66a09f4c248120086bd473fb7c2 100644 (file)
@@ -1,10 +1,9 @@
 /*
  * "$Id: policy.h 6895 2007-08-30 00:09:27Z mike $"
  *
- *   Policy definitions for the Common UNIX Printing System (CUPS)
- *   scheduler.
+ *   Policy definitions for the CUPS scheduler.
  *
- *   Copyright 2007 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2005 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
 typedef struct
 {
   char                 *name;          /* Policy name */
-  cups_array_t         *ops;           /* Operations */
+  cups_array_t         *job_access,    /* Private users/groups for jobs */
+                       *job_attrs,     /* Private attributes for jobs */
+                       *sub_access,    /* Private users/groups for subscriptions */
+                       *sub_attrs,     /* Private attributes for subscriptions */
+                       *ops;           /* Operations */
 } cupsd_policy_t;
 
+typedef struct cupsd_printer_s cupsd_printer_t;
+
 
 /*
  * Globals...
@@ -47,6 +52,10 @@ extern http_status_t cupsdCheckPolicy(cupsd_policy_t *p, cupsd_client_t *con,
 extern void            cupsdDeleteAllPolicies(void);
 extern cupsd_policy_t  *cupsdFindPolicy(const char *policy);
 extern cupsd_location_t        *cupsdFindPolicyOp(cupsd_policy_t *p, ipp_op_t op);
+extern cups_array_t    *cupsdGetPrivateAttrs(cupsd_policy_t *p,
+                                             cupsd_client_t *con,
+                                             cupsd_printer_t *printer,
+                                             const char *owner);
 
 
 /*
index 537d6e4f4121d8fa7ed19d25f0ea0b57162ea484..8d2de325a0db1a0cc0ca005ab3ab79201fb89e47 100644 (file)
  *
  *   cupsdAddPrinter()          - Add a printer to the system.
  *   cupsdAddPrinterHistory()   - Add the current printer state to the history.
- *   cupsdAddPrinterUser()      - Add a user to the ACL.
  *   cupsdCreateCommonData()    - Create the common printer data.
  *   cupsdDeleteAllPrinters()   - Delete all printers from the system.
  *   cupsdDeletePrinter()       - Delete a printer from the system.
  *   cupsdFindDest()            - Find a destination in the list.
  *   cupsdFindPrinter()         - Find a printer in the list.
- *   cupsdFreePrinterUsers()    - Free allow/deny users.
  *   cupsdLoadAllPrinters()     - Load printers from the printers.conf file.
  *   cupsdRenamePrinter()       - Rename a printer.
  *   cupsdSaveAllPrinters()     - Save all printer definitions to the
@@ -241,37 +239,6 @@ cupsdAddPrinterHistory(
 }
 
 
-/*
- * 'cupsdAddPrinterUser()' - Add a user to the ACL.
- */
-
-void
-cupsdAddPrinterUser(
-    cupsd_printer_t *p,                        /* I - Printer */
-    const char      *username)         /* I - User */
-{
-  const char   **temp;                 /* Temporary array pointer */
-
-
-  if (!p || !username)
-    return;
-
-  if (p->num_users == 0)
-    temp = malloc(sizeof(char **));
-  else
-    temp = realloc(p->users, sizeof(char **) * (p->num_users + 1));
-
-  if (!temp)
-    return;
-
-  p->users = temp;
-  temp     += p->num_users;
-
-  if ((*temp = strdup(username)) != NULL)
-    p->num_users ++;
-}
-
-
 /*
  * 'cupsdCreateCommonData()' - Create the common printer data.
  */
@@ -931,7 +898,7 @@ cupsdDeletePrinter(
   delete_string_array(&(p->filters));
   delete_string_array(&(p->pre_filters));
 
-  cupsdFreePrinterUsers(p);
+  cupsdFreeStrings(&(p->users));
   cupsdFreeQuotas(p);
 
   cupsdClearString(&p->uri);
@@ -1007,30 +974,6 @@ cupsdFindPrinter(const char *name)        /* I - Name of printer to find */
 }
 
 
-/*
- * 'cupsdFreePrinterUsers()' - Free allow/deny users.
- */
-
-void
-cupsdFreePrinterUsers(
-    cupsd_printer_t *p)                        /* I - Printer */
-{
-  int  i;                              /* Looping var */
-
-
-  if (!p || !p->num_users)
-    return;
-
-  for (i = 0; i < p->num_users; i ++)
-    free((void *)p->users[i]);
-
-  free(p->users);
-
-  p->num_users = 0;
-  p->users     = NULL;
-}
-
-
 /*
  * 'cupsdLoadAllPrinters()' - Load printers from the printers.conf file.
  */
@@ -1399,7 +1342,7 @@ cupsdLoadAllPrinters(void)
       if (value)
       {
         p->deny_users = 0;
-        cupsdAddPrinterUser(p, value);
+        cupsdAddString(&(p->users), value);
       }
       else
        cupsdLogMessage(CUPSD_LOG_ERROR,
@@ -1410,7 +1353,7 @@ cupsdLoadAllPrinters(void)
       if (value)
       {
         p->deny_users = 1;
-        cupsdAddPrinterUser(p, value);
+        cupsdAddString(&(p->users), value);
       }
       else
        cupsdLogMessage(CUPSD_LOG_ERROR,
@@ -1583,7 +1526,8 @@ cupsdSaveAllPrinters(void)
   char                 temp[1024],     /* Temporary string */
                        backup[1024],   /* printers.conf.O file */
                        value[2048],    /* Value string */
-                       *ptr;           /* Pointer into value */
+                       *ptr,           /* Pointer into value */
+                       *name;          /* Current user/group name */
   cupsd_printer_t      *printer;       /* Current printer class */
   time_t               curtime;        /* Current time */
   struct tm            *curdate;       /* Current date */
@@ -1756,9 +1700,10 @@ cupsdSaveAllPrinters(void)
     cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit);
     cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit);
 
-    for (i = 0; i < printer->num_users; i ++)
-      cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser",
-                      printer->users[i]);
+    for (name = (char *)cupsArrayFirst(printer->users);
+         name;
+        name = (char *)cupsArrayNext(printer->users))
+      cupsFilePutConf(fp, printer->deny_users ? "DenyUser" : "AllowUser", name);
 
     if (printer->op_policy)
       cupsFilePutConf(fp, "OpPolicy", printer->op_policy);
@@ -2263,7 +2208,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
   ipp_t                *oldattrs;              /* Old printer attributes */
   ipp_attribute_t *attr;               /* Attribute data */
   cups_option_t        *option;                /* Current printer option */
-  char         *filter;                /* Current filter */
+  char         *name,                  /* Current user/group name */
+               *filter;                /* Current filter */
   static const char * const air_none[] =
                {                       /* No authentication */
                  "none"
@@ -2366,16 +2312,21 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
   ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
                NULL, p->info ? p->info : "");
 
-  if (p->num_users)
+  if (cupsArrayCount(p->users) > 0)
   {
     if (p->deny_users)
-      ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
-                    "requesting-user-name-denied", p->num_users, NULL,
-                   p->users);
+      attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+                           "requesting-user-name-denied",
+                          cupsArrayCount(p->users), NULL, NULL);
     else
-      ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
-                    "requesting-user-name-allowed", p->num_users, NULL,
-                   p->users);
+      attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+                           "requesting-user-name-allowed",
+                          cupsArrayCount(p->users), NULL, NULL);
+
+    for (i = 0, name = (char *)cupsArrayFirst(p->users);
+         name;
+        i ++, name = (char *)cupsArrayNext(p->users))
+      attr->values[i].string.text = _cupsStrRetain(name);
   }
 
   ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
index f594a2492c76f899e7f6ad955540c3e2baa56596..5a62a5da982abea336ed940cca0b904831c9ec2a 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: printers.h 7564 2008-05-15 00:57:43Z mike $"
  *
- *   Printer definitions for the Common UNIX Printing System (CUPS) scheduler.
+ *   Printer definitions for the CUPS scheduler.
  *
- *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -38,7 +38,7 @@ typedef struct
 
 typedef struct cupsd_job_s cupsd_job_t;
 
-typedef struct cupsd_printer_s
+struct cupsd_printer_s
 {
   char         *uri,                   /* Printer URI */
                *hostname,              /* Host printer resides on */
@@ -81,9 +81,8 @@ typedef struct cupsd_printer_s
                page_limit,             /* Maximum number of pages */
                k_limit;                /* Maximum number of kilobytes */
   cups_array_t *quotas;                /* Quota records */
-  int          deny_users,             /* 1 = deny, 0 = allow */
-               num_users;              /* Number of allowed/denied users */
-  const char   **users;                /* Allowed/denied users */
+  int          deny_users;             /* 1 = deny, 0 = allow */
+  cups_array_t *users;                 /* Allowed/denied users */
   int          num_history;            /* Number of history collections */
   ipp_t                **history;              /* History data */
   int          sequence_number;        /* Increasing sequence number */
@@ -109,7 +108,7 @@ typedef struct cupsd_printer_s
   DNSServiceRef        ipp_ref,                /* Reference for _ipp._tcp,_cups */
                printer_ref;            /* Reference for _printer._tcp */
 #endif /* HAVE_DNSSD */
-} cupsd_printer_t;
+};
 
 
 /*
@@ -139,8 +138,6 @@ VAR cupsd_policy_t  *DefaultPolicyPtr
 
 extern cupsd_printer_t *cupsdAddPrinter(const char *name);
 extern void            cupsdAddPrinterHistory(cupsd_printer_t *p);
-extern void            cupsdAddPrinterUser(cupsd_printer_t *p,
-                                           const char *username);
 extern void            cupsdCreateCommonData(void);
 extern void            cupsdDeleteAllPrinters(void);
 extern int             cupsdDeletePrinter(cupsd_printer_t *p, int update);
@@ -148,7 +145,6 @@ extern cupsd_printer_t      *cupsdFindDest(const char *name);
 extern cupsd_printer_t *cupsdFindPrinter(const char *name);
 extern cupsd_quota_t   *cupsdFindQuota(cupsd_printer_t *p,
                                        const char *username);
-extern void            cupsdFreePrinterUsers(cupsd_printer_t *p);
 extern void            cupsdFreeQuotas(cupsd_printer_t *p);
 extern void            cupsdLoadAllPrinters(void);
 extern void            cupsdRenamePrinter(cupsd_printer_t *p,
index eb62771025e77639849dfb64d95167489669c6ae..15f1b37b37213d2257ccf8a4a012efc45148cb69 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * "$Id: quotas.c 6947 2007-09-12 21:09:49Z mike $"
  *
- *   Quota routines for the Common UNIX Printing System (CUPS).
+ *   Quota routines for the CUPS scheduler.
  *
  *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products.
index 213d795eadef51b9078c9edf0b824867de2722f5..756912e9952a1ef993b142a27fa3614d1e70f74e 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: removefile.c 7720 2008-07-11 22:46:21Z mike $"
  *
- *   "Secure" file removal function for the Common UNIX Printing System (CUPS).
+ *   "Secure" file removal function for the CUPS scheduler.
  *
- *   Copyright 2007 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -107,8 +107,10 @@ cupsdRemoveFile(const char *filename)      /* I - File to remove */
     return (-1);
   }
 
+  CUPS_SRAND(time(NULL));
+
   for (i = 0; i < sizeof(buffer); i ++)
-    buffer[i] = rand();
+    buffer[i] = CUPS_RAND();
   if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
   {
     close(fd);
@@ -130,7 +132,7 @@ cupsdRemoveFile(const char *filename)       /* I - File to remove */
   }
 
   for (i = 0; i < sizeof(buffer); i ++)
-    buffer[i] = rand();
+    buffer[i] = CUPS_RAND();
   if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
   {
     close(fd);
index 03e47437a7881de2c3698cf67b53521591dceb05..2965c6cb01443414fe14862ce0ac7a44eabc20b3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * "$Id: select.c 7720 2008-07-11 22:46:21Z mike $"
  *
- *   Select abstraction functions for the Common UNIX Printing System (CUPS).
+ *   Select abstraction functions for the CUPS scheduler.
  *
  *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 2006-2007 by Easy Software Products.
index 6da11175afc6a31b1285cdf64250b8087a498cc8..e719aebdba29b3fb89ae1f246189eeffce450063 100644 (file)
@@ -1,10 +1,9 @@
 /*
  * "$Id: statbuf.c 7674 2008-06-18 23:18:32Z mike $"
  *
- *   Status buffer routines for the Common UNIX Printing System (CUPS)
- *   scheduler.
+ *   Status buffer routines for the CUPS scheduler.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
index c42c6fdb7088dcc43845ee775ed73fc1d934246e..1ca227213756fe607ae8bc13fb9f3ce3fba99c36 100644 (file)
@@ -1,10 +1,9 @@
 /*
  * "$Id: statbuf.h 7674 2008-06-18 23:18:32Z mike $"
  *
- *   Status buffer definitions for the Common UNIX Printing System (CUPS)
- *   scheduler.
+ *   Status buffer definitions for the CUPS scheduler.
  *
- *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2005 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -19,7 +18,7 @@
  * Constants...
  */
 
-#define CUPSD_SB_BUFFER_SIZE   1024    /* Bytes or job status buffer */
+#define CUPSD_SB_BUFFER_SIZE   2048    /* Bytes for job status buffer */
 
 
 /*
index 4781ac14758a4132d21209bcbf5acee71c452b87..92dffe6423aa9c1ad11baf00a785815cd7703054 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: subscriptions.c 7824 2008-08-01 21:11:55Z mike $"
  *
- *   Subscription routines for the Common UNIX Printing System (CUPS) scheduler.
+ *   Subscription routines for the CUPS scheduler.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -480,9 +480,6 @@ cupsdDeleteSubscription(
     cupsd_subscription_t *sub,         /* I - Subscription object */
     int                  update)       /* I - 1 = update subscriptions.conf */
 {
-  int  i;                              /* Looping var */
-
-
  /*
   * Close the pipe to the notifier as needed...
   */
@@ -503,13 +500,7 @@ cupsdDeleteSubscription(
   cupsdClearString(&(sub->owner));
   cupsdClearString(&(sub->recipient));
 
-  if (sub->events)
-  {
-    for (i = 0; i < sub->num_events; i ++)
-      cupsd_delete_event(sub->events[i]);
-
-    free(sub->events);
-  }
+  cupsArrayDelete(sub->events);
 
   free(sub);
 
@@ -1426,7 +1417,10 @@ cupsd_send_notification(
 
   if (!sub->events)
   {
-    sub->events = calloc(MaxEvents, sizeof(cupsd_event_t *));
+    sub->events = cupsArrayNew3((cups_array_func_t)NULL, NULL,
+                                (cups_ahash_func_t)NULL, 0,
+                               (cups_acopy_func_t)NULL,
+                               (cups_afree_func_t)cupsd_delete_event);
 
     if (!sub->events)
     {
@@ -1441,19 +1435,15 @@ cupsd_send_notification(
   * Purge an old event as needed...
   */
 
-  if (sub->num_events >= MaxEvents)
+  if (cupsArrayCount(sub->events) >= MaxEvents)
   {
    /*
     * Purge the oldest event in the cache...
     */
 
-    cupsd_delete_event(sub->events[0]);
+    cupsArrayRemove(sub->events, cupsArrayFirst(sub->events));
 
-    sub->num_events --;
     sub->first_event_id ++;
-
-    memmove(sub->events, sub->events + 1,
-           sub->num_events * sizeof(cupsd_event_t *));
   }
 
  /*
@@ -1463,8 +1453,7 @@ cupsd_send_notification(
   * event cache limit, we don't need to check for overflow here...
   */
 
-  sub->events[sub->num_events] = event;
-  sub->num_events ++;
+  cupsArrayAdd(sub->events, event);
 
  /*
   * Deliver the event...
index b807ac2150147d4ca5c6ed2237887833cb914790..2a2714ec1f701c98d3eb28aabc580d9c5a1f2574 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: subscriptions.h 7824 2008-08-01 21:11:55Z mike $"
  *
- *   Subscription definitions for the Common UNIX Printing System (CUPS) scheduler.
+ *   Subscription definitions for the CUPS scheduler.
  *
- *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -100,9 +100,8 @@ typedef struct cupsd_subscription_s /**** Subscription structure ****/
   time_t               last;           /* Time of last notification */
   time_t               expire;         /* Lease expiration time */
   int                  first_event_id, /* First event-id in cache */
-                       next_event_id,  /* Next event-id to use */
-                       num_events;     /* Number of cached events */
-  cupsd_event_t                **events;       /* Cached events */
+                       next_event_id;  /* Next event-id to use */
+  cups_array_t         *events;        /* Cached events */
 } cupsd_subscription_t;
 
 
index 1c548b6caeed76f48911ba7050b80498a881e766..e5c138e2898e38deb241a89c6050a157b108b67c 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: sysman.c 7928 2008-09-10 22:14:22Z mike $"
  *
- *   System management definitions for the Common UNIX Printing System (CUPS).
+ *   System management functions for the CUPS scheduler.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 2006 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -52,7 +52,7 @@
  *
  * Power management support is currently only implemented on MacOS X, but
  * essentially we use four functions to let the OS know when it is OK to
- * put the system to idle sleep, typically when we are not in the middle of
+ * put the system to sleep, typically when we are not in the middle of
  * printing a job.
  *
  * Once put to sleep, we invalidate all remote printers since it is common
index 231fc2c54c63dd3efcc884c0e8a81f7a530007eb..0983f109dcde0a0555e830d2413a651953e0580a 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: sysman.h 7928 2008-09-10 22:14:22Z mike $"
  *
- *   System management definitions for the Common UNIX Printing System (CUPS).
+ *   System management definitions for the CUPS scheduler.
  *
- *   Copyright 2007-2008 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 2006 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
index db920c225e28572fe7326ab9d9f5afbb1d09ed92..b170f805275267d8c5c8f14571aae5b0818c84a1 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: util.c 7621 2008-06-06 18:55:35Z mike $"
  *
- *   Mini-daemon utility functions for the Common UNIX Printing System (CUPS).
+ *   Mini-daemon utility functions for CUPS.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2005 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -163,13 +163,16 @@ cupsdCreateStringsArray(const char *s)    /* I - Comma-delimited strings */
   cups_array_t *a;                     /* CUPS array */
   const char   *start,                 /* Start of string */
                *end;                   /* End of string */
-  char         *ptr;                   /* New string */
+  char         buffer[8192];           /* New string */
 
 
   if (!s)
     return (NULL);
 
-  if ((a = cupsArrayNew((cups_array_func_t)strcmp, NULL)) != NULL)
+  if ((a = cupsArrayNew3((cups_array_func_t)strcmp, NULL,
+                         (cups_ahash_func_t)NULL, 0,
+                        (cups_acopy_func_t)_cupsStrAlloc,
+                        (cups_afree_func_t)_cupsStrFree)) != NULL)
   {
     for (start = end = s; *end; start = end + 1)
     {
@@ -178,17 +181,26 @@ cupsdCreateStringsArray(const char *s)    /* I - Comma-delimited strings */
       */
 
       if ((end = strchr(start, ',')) == NULL)
-        end = start + strlen(start);
+      {
+       /*
+        * Last delimited string...
+       */
+
+        cupsArrayAdd(a, (char *)start);
+       break;
+      }
 
      /*
-      * Duplicate the string and add it to the array...
+      * Copy the string and add it to the array...
       */
 
-      if ((ptr = calloc(1, end - start + 1)) == NULL)
+      if ((end - start + 1) > sizeof(buffer))
         break;
 
-      memcpy(ptr, start, end - start);
-      cupsArrayAdd(a, ptr);
+      memcpy(buffer, start, end - start);
+      buffer[end - start] = '\0';
+
+      cupsArrayAdd(a, buffer);
     }
   }
 
index fab50eee5b7c3b5be0092b5b818cb142a37a3315..ecf7645a4a8a222c971c52d35f97ef3fe306e192 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * "$Id: util.h 7711 2008-07-02 04:39:27Z mike $"
  *
- *   Mini-daemon utility definitions for the Common UNIX Printing System (CUPS).
+ *   Mini-daemon utility definitions for CUPS.
  *
- *   Copyright 2007-2009 by Apple Inc.
+ *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2005 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
index f63cfcbd2236b7551cebc8071518469b7d8e8cc0..f6cf820f1a7b6b843d6e17d059d9841975401cce 100644 (file)
@@ -16,6 +16,7 @@
        ATTR charset attributes-charset utf-8
        ATTR language attributes-natural-language en
        ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1
+       ATTR name requesting-user-name $user
 
         GROUP subscription
        ATTR uri notify-recipient-uri testnotify://
@@ -48,6 +49,7 @@
        ATTR language attributes-natural-language en
        ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1
        ATTR integer notify-subscription-id $notify-subscription-id
+       ATTR name requesting-user-name $user
 
        # What statuses are OK?
        STATUS client-error-not-found
@@ -69,6 +71,7 @@
        ATTR charset attributes-charset utf-8
        ATTR language attributes-natural-language en
        ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1
+       ATTR name requesting-user-name $user
 
         GROUP subscription
        ATTR uri notify-recipient-uri testnotify://
        ATTR charset attributes-charset utf-8
        ATTR language attributes-natural-language en
        ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1
+       ATTR name requesting-user-name $user
 
        # What statuses are OK?
        STATUS successful-ok
        ATTR charset attributes-charset utf-8
        ATTR language attributes-natural-language en
        ATTR uri printer-uri $scheme://$hostname:$port/printers/Test1
+       ATTR name requesting-user-name $user
 
         GROUP subscription
        ATTR uri notify-recipient-uri testnotify://
index 54ce778b29fefc59882ccf9c9f660d0bd230927b..5940017a02640b0303bceaa8b499cb594b781f4b 100644 (file)
@@ -1,16 +1,13 @@
 # Get printer attributes using get-printer-attributes
 {
        # The name of the test...
-       NAME "Get printer attributes using get-printer-attributes"
-
-       # The resource to use for the POST
-       # RESOURCE /admin
+       NAME "Get printer attributes using Get-Printer-Attributes"
 
        # The operation to use
-       OPERATION get-printer-attributes
+       OPERATION Get-Printer-Attributes
 
        # Attributes, starting in the operation group...
-       GROUP operation
+       GROUP operation-attributes-tag
        ATTR charset attributes-charset utf-8
        ATTR language attributes-natural-language en
        ATTR uri printer-uri $uri
index eb547fb0162c9c1c177dcf34719ecb0ad6e40e19..dc3147090aafbbbe4968543bd3c8d85653209962 100644 (file)
        EXPECT ipp-versions-supported OF-TYPE keyword IN-GROUP printer-attributes-tag WITH-VALUE 1.1
        EXPECT natural-language-configured OF-TYPE naturalLanguage IN-GROUP printer-attributes-tag COUNT 1
        EXPECT operations-supported OF-TYPE enum IN-GROUP printer-attributes-tag WITH-VALUE 0x0002 # Print-Job
-       # Not requiring 0x0004 Validate-Job since it is deprecated
+       EXPECT operations-supported WITH-VALUE 0x0004 # Validate-Job
        EXPECT operations-supported WITH-VALUE 0x0008 # Cancel-Job
        EXPECT operations-supported WITH-VALUE 0x0009 # Get-Job-Attributes
        EXPECT operations-supported WITH-VALUE 0x000a # Get-Jobs
index 330c5212de33846345f6242723b56d48a8f6c7d1..6832f9d34931a104e8c1a53d2285478d15dc4b83 100644 (file)
@@ -36,6 +36,7 @@
  *   print_xml_string()  - Print an XML string with escaping.
  *   print_xml_trailer() - Print the XML trailer with success/fail value.
  *   set_variable()      - Set a variable value.
+ *   timeout_cb()        - Handle HTTP timeouts.
  *   usage()             - Show program usage.
  *   validate_attr()     - Determine whether an attribute is valid.
  *   with_value()        - Test a WITH-VALUE predicate.
@@ -115,6 +116,7 @@ typedef struct _cups_vars_s         /**** Set of variables ****/
                resource[1024];         /* Resource path from URI */
   int          port;                   /* Port number from URI */
   http_encryption_t encryption;                /* Encryption for connection? */
+  double       timeout;                /* Timeout for connection */
   cups_array_t *vars;                  /* Array of variables */
 } _cups_vars_t;
 
@@ -191,6 +193,7 @@ static void print_xml_string(const char *element, const char *s);
 static void    print_xml_trailer(int success, const char *message);
 static void    set_variable(_cups_vars_t *vars, const char *name,
                             const char *value);
+static int     timeout_cb(http_t *http, void *user_data);
 static void    usage(void);
 static int     validate_attr(ipp_attribute_t *attr, int print);
 static int      with_value(char *value, int regex, ipp_attribute_t *attr,
@@ -213,7 +216,7 @@ main(int  argc,                             /* I - Number of command-line args */
                        filename[1024], /* Real filename */
                        testname[1024]; /* Real test filename */
   const char           *testfile;      /* Test file to use */
-  int                  interval,       /* Test interval */
+  int                  interval,       /* Test interval in microseconds */
                        repeat;         /* Repeat count */
   _cups_vars_t         vars;           /* Variables */
   http_uri_status_t    uri_status;     /* URI separation status */
@@ -282,6 +285,19 @@ main(int  argc,                            /* I - Number of command-line args */
 #endif /* HAVE_SSL */
              break;
 
+         case 'T' : /* Set timeout */
+             i ++;
+
+             if (i >= argc)
+             {
+               _cupsLangPuts(stderr,
+                             _("ipptool: Missing timeout for \"-T\".\n"));
+               usage();
+              }
+
+             vars.timeout = _cupsStrScand(argv[i], NULL, localeconv());
+             break;
+
          case 'V' : /* Set IPP version */
              i ++;
 
@@ -378,7 +394,16 @@ main(int  argc,                            /* I - Number of command-line args */
                usage();
               }
              else
-               interval = atoi(argv[i]);
+             {
+               interval = (int)(_cupsStrScand(argv[i], NULL, localeconv()) *
+                                1000000.0);
+               if (interval <= 0)
+               {
+                 _cupsLangPuts(stderr,
+                               _("ipptool: Invalid seconds for \"-i\".\n"));
+                 usage();
+               }
+              }
 
               if (Output == _CUPS_OUTPUT_PLIST && interval)
              {
@@ -517,20 +542,20 @@ main(int  argc,                           /* I - Number of command-line args */
 
   if (Output == _CUPS_OUTPUT_PLIST)
     print_xml_trailer(!status, NULL);
-  else if (interval && repeat > 0)
+  else if (interval > 0 && repeat > 0)
   {
     while (repeat > 1)
     {
-      sleep(interval);
+      usleep(interval);
       do_tests(&vars, testfile);
       repeat --;
     }
   }
-  else if (interval)
+  else if (interval > 0)
   {
     for (;;)
     {
-      sleep(interval);
+      usleep(interval);
       do_tests(&vars, testfile);
     }
   }
@@ -628,6 +653,9 @@ do_tests(_cups_vars_t *vars,                /* I - Variables */
     goto test_exit;
   }
 
+  if (vars->timeout > 0.0)
+    _httpSetTimeout(http, vars->timeout, timeout_cb, NULL);
+
  /*
   * Loop on tests...
   */
@@ -1194,7 +1222,7 @@ do_tests(_cups_vars_t *vars,              /* I - Variables */
         * Delay before operation...
        */
 
-        int delay;
+        double delay;
 
        if (!get_token(fp, token, sizeof(token), &linenum))
        {
@@ -1203,7 +1231,7 @@ do_tests(_cups_vars_t *vars,              /* I - Variables */
          goto test_exit;
        }
 
-       if ((delay = atoi(token)) <= 0)
+       if ((delay = _cupsStrScand(token, NULL, localeconv())) <= 0.0)
        {
          print_fatal_error("Bad DELAY value \"%s\" on line %d.", token,
                            linenum);
@@ -1213,9 +1241,9 @@ do_tests(_cups_vars_t *vars,              /* I - Variables */
        else
        {
          if (Output == _CUPS_OUTPUT_TEST)
-           printf("    [%d second delay]\n", delay);
+           printf("    [%g second delay]\n", delay);
 
-         sleep(delay);
+         usleep((int)(1000000.0 * delay));
        }
       }
       else if (!strcasecmp(token, "ATTR"))
@@ -3687,6 +3715,21 @@ set_variable(_cups_vars_t *vars, /* I - Variables */
 }
 
 
+/*
+ * 'timeout_cb()' - Handle HTTP timeouts.
+ */
+
+static int                             /* O - 1 to continue, 0 to cancel */
+timeout_cb(http_t *http,               /* I - Connection to server (unused) */
+           void   *user_data)          /* I - User data (unused) */
+{
+  (void)http;
+  (void)user_data;
+
+  return (0);
+}
+
+
 /*
  * 'usage()' - Show program usage.
  */
@@ -3705,6 +3748,7 @@ usage(void)
                  "-I             Ignore errors\n"
                  "-L             Send requests using content-length\n"
                  "-S             Test with SSL encryption.\n"
+                 "-T             Set the receive/send timeout in seconds.\n"
                  "-V version     Set default IPP version.\n"
                  "-X             Produce XML plist instead of plain text.\n"
                  "-d name=value  Define variable.\n"
@@ -4526,6 +4570,65 @@ with_value(char            *value,       /* I - Value string */
        }
        break;
 
+    case IPP_TAG_RANGE :
+        for (i = 0; i < attr->num_values; i ++)
+        {
+         char  op,                     /* Comparison operator */
+               *nextptr;               /* Next pointer */
+         int   intvalue;               /* Integer value */
+
+
+          valptr = value;
+         if (!strncmp(valptr, "no-value,", 9))
+           valptr += 9;
+
+         while (isspace(*valptr & 255) || isdigit(*valptr & 255) ||
+                *valptr == '-' || *valptr == ',' || *valptr == '<' ||
+                *valptr == '=' || *valptr == '>')
+         {
+           op = '=';
+           while (*valptr && !isdigit(*valptr & 255) && *valptr != '-')
+           {
+             if (*valptr == '<' || *valptr == '>' || *valptr == '=')
+               op = *valptr;
+             valptr ++;
+           }
+
+            if (!*valptr)
+             break;
+
+           intvalue = strtol(valptr, &nextptr, 0);
+           if (nextptr == valptr)
+             break;
+           valptr = nextptr;
+
+           switch (op)
+           {
+             case '=' :
+                 if (attr->values[i].range.upper == intvalue)
+                   return (1);
+                 break;
+             case '<' :
+                 if (attr->values[i].range.upper < intvalue)
+                   return (1);
+                 break;
+             case '>' :
+                 if (attr->values[i].range.upper > intvalue)
+                   return (1);
+                 break;
+           }
+         }
+        }
+
+       if (report)
+       {
+         for (i = 0; i < attr->num_values; i ++)
+           print_test_error("GOT: %s=%d-%d", attr->name,
+                            attr->values[i].range.lower,
+                            attr->values[i].range.upper);
+       }
+       break;
+
     case IPP_TAG_BOOLEAN :
        for (i = 0; i < attr->num_values; i ++)
        {
index ed4f73b5d1c442fe7d5ae0099a25dcc3daafe2e3..cafd291fbfbb83ed1c0fd93721656c2dcd633c72 100644 (file)
@@ -32,6 +32,7 @@
                MEMBER integer media-top-margin 0
                MEMBER integer media-bottom-margin 0
        }
+       ATTR enum print-quality 5
 
        FILE $filename
 
index 1d0973b9dc16dfd4c0714024ac24adf52aa8aca1..a1a3536e51f59638e4d47c6027080359a3968807 100755 (executable)
@@ -736,10 +736,10 @@ fi
 
 # Warning log messages
 count=`grep '^W ' /tmp/cups-$user/log/error_log | wc -l | awk '{print $1}'`
-if test $count != 0; then
-       echo "FAIL: $count warning messages, expected 0."
+if test $count != 9; then
+       echo "FAIL: $count warning messages, expected 9."
        grep '^W ' /tmp/cups-$user/log/error_log
-       echo "<P>FAIL: $count warning messages, expected 0.</P>" >>$strfile
+       echo "<P>FAIL: $count warning messages, expected 9.</P>" >>$strfile
        echo "<PRE>" >>$strfile
        grep '^W ' /tmp/cups-$user/log/error_log | sed -e '1,$s/&/&amp;/g' -e '1,$s/</&lt;/g' >>$strfile
        echo "</PRE>" >>$strfile