]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Merge changes from CUPS 1.4svn-r7817.
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Wed, 30 Jul 2008 23:42:12 +0000 (23:42 +0000)
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Wed, 30 Jul 2008 23:42:12 +0000 (23:42 +0000)
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@901 a1ca3aef-8c08-0410-bb20-df032aa958be

54 files changed:
CHANGES-1.3.txt
CHANGES.txt
Makedefs.in
Makefile
backend/backend-private.h
backend/mdns.c
backend/parallel.c
backend/snmp.c
backend/usb-darwin.c
backend/usb-libusb.c
backend/usb-unix.c
cgi-bin/admin.c
config-scripts/cups-common.m4
config-scripts/cups-compiler.m4
config-scripts/cups-directories.m4
config-scripts/cups-ldap.m4
config.h.in
configure.in
cups/adminutil.c
cups/backend.c
cups/backend.h
cups/cups.h
cups/dest.c
cups/getdevices.c
cups/globals.h
cups/langprintf.c
cups/libcups.exp
cups/ppd.c
cups/request.c
cups/testppd.c
cups/util.c
cups/versioning.h
doc/cups.css
doc/help/kerberos.html
doc/help/options.html
doc/help/ref-cupsd-conf.html.in
doc/help/spec-ipp.html
doc/help/spec-ppd.html
init/cups.xml.in [new file with mode: 0644]
man/backend.man
man/cupsd.conf.man.in
notifier/Makefile
scheduler/Makefile
scheduler/client.c
scheduler/cups-deviced.c
scheduler/cups-driverd.cxx
scheduler/dirsvc.c
scheduler/dirsvc.h
scheduler/main.c
systemv/cupstestppd.c
systemv/lpinfo.c
templates/option-pickone.tmpl
templates/set-printer-options-header.tmpl
templates/set-printer-options-trailer.tmpl

index fca0738fa26c89c989e4a87068c1a2fe079c02ea..ea573a92464260d0073221fc3dc02592abe61245 100644 (file)
@@ -3,6 +3,7 @@ CHANGES-1.3.txt
 
 CHANGES IN CUPS V1.3.9
 
+       - Refined the cupstestppd utility.
        - ppdEmit*() did not support custom JCL options (STR #2889)
        - The cupstestppd utility incorrectly reported missing
          "en" base translations (STR #2887)
index f3f407183e98d663a1d586e83a8245623ddbfae8..8a1984e9a28571d72650560f999f08b7ff7155e0 100644 (file)
@@ -1,8 +1,19 @@
-CHANGES.txt - 2008-07-23
+CHANGES.txt - 2008-07-28
 ------------------------
 
 CHANGES IN CUPS V1.4b1
 
+       - Added support for a device-location attribute which provides
+         the physical location of a printer device.
+       - Added a cupsBackendReport() API which handles quoting of the
+         device data by a backend.
+       - Added support for custom options in the web interface
+         (STR #1729)
+       - Added support for Mozilla LDAP, reconnection to LDAP servers,
+         and improved LDAP performance (STR #1962)
+       - Added Solaris SMF support (STR #1477)
+       - Added optional support for using TCP wrappers to limit access
+         to CUPS (STR #263)
        - Added ppdPageSizeLimits API.
        - Added support for new cupsMediaQualifier2, cupsMediaQualifier3,
          cupsMinSize, and cupsMaxSize attributes.
index 0e5068553f47a9744079fe6eb39af5a0f10422bf..b34c7ae0e97231134faf1c0adda6cb8b94a1b0ca 100644 (file)
@@ -92,6 +92,7 @@ LIBSLP                =       @LIBSLP@
 LIBGSSAPI      =       @LIBGSSAPI@
 LIBTIFF                =       @LIBTIFF@
 LIBUSB         =       @LIBUSB@
+LIBWRAP                =       @LIBWRAP@
 LIBZ           =       @LIBZ@
 
 #
@@ -229,6 +230,7 @@ REQUESTS    =       $(BUILDROOT)@CUPS_REQUESTS@
 SBINDIR                =       $(BUILDROOT)@sbindir@
 SERVERBIN      =       $(BUILDROOT)@CUPS_SERVERBIN@
 SERVERROOT     =       $(BUILDROOT)@CUPS_SERVERROOT@
+SMFMANIFESTDIR =       @SMFMANIFESTDIR@
 STATEDIR       =       $(BUILDROOT)@CUPS_STATEDIR@
 XINETD         =       @XINETD@
 
index 9074d67315942b2853a44829c8f1e48e1d87581e..017378db38ebe07fcda3809e38c2d7146bf03a56 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -182,6 +182,11 @@ install-data:
                        $(INSTALL_SCRIPT) init/cups.sh $(BUILDROOT)$(INITDDIR)/cups; \
                fi \
        fi
+       if test "x$(SMFMANIFESTDIR)" != x; then \
+               echo Installing SMF manifest in $(SMFMANIFESTDIR)...;\
+               $(INSTALL_DIR) $(BUILDROOT)/$(SMFMANIFESTDIR); \
+               $(INSTALL_SCRIPT) init/cups.xml $(BUILDROOT)$(SMFMANIFESTDIR)/cups.xml; \
+       fi
        if test "x$(DBUSDIR)" != x; then \
                echo Installing cups.conf in $(DBUSDIR)...;\
                $(INSTALL_DIR) -m 755 $(BUILDROOT)$(DBUSDIR)/system.d; \
index b7912d59dab17604c9201a8c377eaec19f932916..c124274a9d879f5baed2502258f2a675058c4fcb 100644 (file)
@@ -51,6 +51,9 @@ extern "C" {
 /* Host MIB */
 #define CUPS_OID_mib2                          1,3,6,1,2,1
 
+#define CUPS_OID_system                                CUPS_OID_mib2,1
+#define CUPS_OID_sysLocation                   CUPS_OID_system,6
+
 #define CUPS_OID_host                          CUPS_OID_mib2,25
 
 #define CUPS_OID_hrSystem                      CUPS_OID_host,1
index 4ae2c8121d6cf6e1c5fb21b23f8577a0f2bc5f16..419b12dc3c72572b5e578b648287266e5123a430 100644 (file)
@@ -280,11 +280,8 @@ main(int  argc,                            /* I - Number of command-line args */
                            schemes[best->type], NULL, best->fullName, 0,
                            best->cups_shared ? "/cups" : "/");
 
-           printf("network %s \"%s\" \"%s\"\n", device_uri,
-                  best->make_and_model ? best->make_and_model : "Unknown",
-                  best->name);
-           fflush(stdout);
-
+           cupsBackendReport("network", device_uri, best->make_and_model,
+                             best->name, NULL, NULL);
            best->sent = 1;
            best       = device;
          }
@@ -305,11 +302,8 @@ main(int  argc,                            /* I - Number of command-line args */
                        schemes[best->type], NULL, best->fullName, 0,
                        best->cups_shared ? "/cups" : "/");
 
-       printf("network %s \"%s\" \"%s\"\n", device_uri,
-              best->make_and_model ? best->make_and_model : "Unknown",
-              best->name);
-       fflush(stdout);
-
+       cupsBackendReport("network", device_uri, best->make_and_model,
+                         best->name, NULL, NULL);
        best->sent = 1;
       }
     }
index bba472095a6ee38a4f83ef5a65e5e1095a6bc5fd..e2049954552eb7c34d36519183560fb7e68abe25 100644 (file)
@@ -328,6 +328,7 @@ list_devices(void)
        basedevice[255],        /* Base device filename for ports */
        device_id[1024],        /* Device ID string */
        make_model[1024],       /* Make and model */
+       info[1024],             /* Info string */
        uri[1024];              /* Device URI */
 
 
@@ -359,10 +360,15 @@ list_devices(void)
       if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
                               make_model, sizeof(make_model),
                              NULL, uri, sizeof(uri)))
-       printf("direct %s \"%s\" \"%s LPT #%d\" \"%s\"\n", uri,
-              make_model, make_model, i + 1, device_id);
+      {
+        snprintf(info, sizeof(info), "%s LPT #%d", make_model, i + 1);
+       cupsBackendReport("direct", uri, make_model, info, device_id, NULL);
+      }
       else
-       printf("direct %s \"Unknown\" \"LPT #%d\"\n", uri, i + 1);
+      {
+        snprintf(info, sizeof(info), "LPT #%d", i + 1);
+       cupsBackendReport("direct", uri, NULL, info, NULL, NULL);
+      }
 
       close(fd);
     }
index b7bafbf5619ea5ef46148eb0cc7ed9c3b5db4cf1..712981cfd48a235cbb385f6cc9eb9d279f10ab80 100644 (file)
  * Types...
  */
 
+enum                                   /**** Request IDs for each field ****/
+{
+  DEVICE_TYPE = 1,
+  DEVICE_DESCRIPTION,
+  DEVICE_LOCATION,
+  DEVICE_ID,
+  DEVICE_URI,
+  DEVICE_PRODUCT
+};
+
 typedef struct device_uri_s            /**** DeviceURI values ****/
 {
   regex_t      re;                     /* Regular expression to match */
@@ -124,7 +134,9 @@ typedef struct snmp_cache_s         /**** SNMP scan cache ****/
                *uri,                   /* device-uri */
                *id,                    /* device-id */
                *info,                  /* device-info */
+               *location,              /* device-location */
                *make_and_model;        /* device-make-and-model */
+  int          sent;                   /* Has this device been listed? */
 } snmp_cache_t;
 
 
@@ -174,14 +186,15 @@ static cups_array_t       *Addresses = NULL;
 static cups_array_t    *Communities = NULL;
 static cups_array_t    *Devices = NULL;
 static int             DebugLevel = 0;
-static const int       DeviceDescOID[] = { CUPS_OID_hrDeviceDescr, 1, -1 };
-static unsigned                DeviceDescRequest;
+static const int       DescriptionOID[] = { CUPS_OID_hrDeviceDescr, 1, -1 };
+static const int       LocationOID[] = { CUPS_OID_sysLocation, 0, -1 };
 static const int       DeviceTypeOID[] = { CUPS_OID_hrDeviceType, 1, -1 };
-static unsigned                DeviceTypeRequest;
 static const int       DeviceIdOID[] = { CUPS_OID_ppmPrinterIEEE1284DeviceId, 1, -1 };
-static unsigned                DeviceIdRequest;
-static const int       DeviceUriOID[] = { CUPS_OID_ppmPortServiceNameOrURI, 1, 1, -1 };
-static unsigned                DeviceUriRequest;
+static const int       UriOID[] = { CUPS_OID_ppmPortServiceNameOrURI, 1, 1, -1 };
+static const int       LexmarkProductOID[] = { 1,3,6,1,4,1,641,2,1,2,1,2,1,-1 };
+static const int       LexmarkProductOID2[] = { 1,3,6,1,4,1,674,10898,100,2,1,2,1,2,1,-1 };
+static const int       LexmarkDeviceIdOID[] = { 1,3,6,1,4,1,641,2,1,2,1,3,1,-1 };
+static const int       XeroxProductOID[] = { 1,3,6,1,4,1,128,2,1,3,1,2,0,-1 };
 static cups_array_t    *DeviceURIs = NULL;
 static int             HostNameLookups = 0;
 static int             MaxRunTime = 120;
@@ -660,15 +673,8 @@ static void
 list_device(snmp_cache_t *cache)       /* I - Cached device */
 {
   if (cache->uri)
-  {
-    printf("network %s \"%s\" \"%s %s\" \"%s\"\n",
-           cache->uri,
-          cache->make_and_model ? cache->make_and_model : "Unknown",
-          cache->info ? cache->info : "Unknown",
-          cache->addrname,
-          cache->id ? cache->id : "");
-    fflush(stdout);
-  }
+    cupsBackendReport("network", cache->uri, cache->make_and_model,
+                      cache->info, cache->id, cache->location);
 }
 
 
@@ -953,156 +959,172 @@ read_snmp_response(int fd)              /* I - SNMP socket file descriptor */
   * Process the message...
   */
 
-  if (packet.request_id == DeviceTypeRequest)
+  switch (packet.request_id)
   {
-   /*
-    * Got the device type response...
-    */
-
-    if (device)
-    {
-      debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n",
-                  addrname);
-      return;
-    }
-
-   /*
-    * Add the device and request the device description...
-    */
-
-    add_cache(&(packet.address), addrname, NULL, NULL, NULL);
+    case DEVICE_TYPE :
+       /*
+       * Got the device type response...
+       */
+
+       if (device)
+       {
+         debug_printf("DEBUG: Discarding duplicate device type for \"%s\"...\n",
+                      addrname);
+         return;
+       }
+
+       /*
+       * Add the device and request the device data...
+       */
+
+       add_cache(&(packet.address), addrname, NULL, NULL, NULL);
+
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_DESCRIPTION, DescriptionOID);
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_ID, DeviceIdOID);
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_URI, UriOID);
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_LOCATION, LocationOID);
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_PRODUCT, LexmarkProductOID);
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_PRODUCT, LexmarkProductOID2);
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_URI, LexmarkDeviceIdOID);
+       _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1,
+                      packet.community, CUPS_ASN1_GET_REQUEST,
+                      DEVICE_PRODUCT, XeroxProductOID);
+        break;
+
+    case DEVICE_DESCRIPTION :
+       if (device && packet.object_type == CUPS_ASN1_OCTET_STRING)
+       {
+        /*
+         * Update an existing cache entry...
+         */
+
+         char  make_model[256];        /* Make and model */
+
+
+         if (strchr(packet.object_value.string, ':') &&
+             strchr(packet.object_value.string, ';'))
+         {
+          /*
+           * Description is the IEEE-1284 device ID...
+           */
 
-    _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community,
-                  CUPS_ASN1_GET_REQUEST, DeviceDescRequest, DeviceDescOID);
-    _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community,
-                  CUPS_ASN1_GET_REQUEST, DeviceIdRequest, DeviceIdOID);
-    _cupsSNMPWrite(fd, &(packet.address), CUPS_SNMP_VERSION_1, packet.community,
-                  CUPS_ASN1_GET_REQUEST, DeviceUriRequest, DeviceUriOID);
-  }
-  else if (packet.request_id == DeviceDescRequest &&
-           packet.object_type == CUPS_ASN1_OCTET_STRING)
-  {
-   /*
-    * Update an existing cache entry...
-    */
+           if (!device->id)
+             device->id = strdup(packet.object_value.string);
 
-    char       make_model[256];        /* Make and model */
+           backendGetMakeModel(packet.object_value.string, make_model,
+                               sizeof(make_model));
 
+            if (device->info)
+             free(device->info);
 
-    if (!device)
-    {
-      debug_printf("DEBUG: Discarding device description for \"%s\"...\n",
-                  addrname);
-      return;
-    }
-
-    if (strchr(packet.object_value.string, ':') &&
-       strchr(packet.object_value.string, ';'))
-    {
-     /*
-      * Description is the IEEE-1284 device ID...
-      */
-
-      if (!device->id)
-       device->id = strdup(packet.object_value.string);
-
-      backendGetMakeModel(packet.object_value.string, make_model,
-                         sizeof(make_model));
-      device->info = strdup(make_model);
-    }
-    else
-    {
-     /*
-      * Description is plain text...
-      */
+           device->info = strdup(make_model);
+         }
+         else
+         {
+          /*
+           * Description is plain text...
+           */
 
-      fix_make_model(make_model, packet.object_value.string,
-                    sizeof(make_model));
+           fix_make_model(make_model, packet.object_value.string,
+                          sizeof(make_model));
 
-      device->info = strdup(packet.object_value.string);
-    }
+            if (device->info)
+             free(device->info);
 
-    if (!device->make_and_model)
-      device->make_and_model = strdup(make_model);
+           device->info = strdup(packet.object_value.string);
+         }
 
-   /*
-    * List the device now if we have all the info...
-    */
+         if (!device->make_and_model)
+           device->make_and_model = strdup(make_model);
+        }
+       break;
 
-    if (device->id && device->info && device->make_and_model && device->uri)
-      list_device(device);
-  }
-  else if (packet.request_id == DeviceIdRequest &&
-           packet.object_type == CUPS_ASN1_OCTET_STRING)
-  {
-   /*
-    * Update an existing cache entry...
-    */
+    case DEVICE_ID :
+       if (device && packet.object_type == CUPS_ASN1_OCTET_STRING)
+       {
+        /*
+         * Update an existing cache entry...
+         */
 
-    char       make_model[256];        /* Make and model */
+         char  make_model[256];        /* Make and model */
 
 
-    if (!device)
-    {
-      debug_printf("DEBUG: Discarding device ID for \"%s\"...\n",
-                  addrname);
-      return;
-    }
+         if (device->id)
+           free(device->id);
 
-    if (device->id)
-      free(device->id);
+         device->id = strdup(packet.object_value.string);
 
-    device->id = strdup(packet.object_value.string);
+        /*
+         * Convert the ID to a make and model string...
+         */
 
-   /*
-    * Convert the ID to a make and model string...
-    */
+         backendGetMakeModel(packet.object_value.string, make_model,
+                             sizeof(make_model));
+         if (device->make_and_model)
+           free(device->make_and_model);
 
-    backendGetMakeModel(packet.object_value.string, make_model,
-                       sizeof(make_model));
-    if (device->make_and_model)
-      free(device->make_and_model);
+         device->make_and_model = strdup(make_model);
+       }
+       break;
 
-    device->make_and_model = strdup(make_model);
+    case DEVICE_LOCATION :
+       if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+           !device->location)
+         device->location = strdup(packet.object_value.string);
+       break;
 
-   /*
-    * List the device now if we have all the info...
-    */
+    case DEVICE_PRODUCT :
+       if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+           !device->id)
+       {
+        /*
+         * Update an existing cache entry...
+         */
 
-    if (device->id && device->info && device->make_and_model && device->uri)
-      list_device(device);
-  }
-  else if (packet.request_id == DeviceUriRequest &&
-           packet.object_type == CUPS_ASN1_OCTET_STRING)
-  {
-   /*
-    * Update an existing cache entry...
-    */
+          if (!device->info)
+           device->info = strdup(packet.object_value.string);
 
-    if (!device)
-    {
-      debug_printf("DEBUG: Discarding device URI for \"%s\"...\n",
-                  addrname);
-      return;
-    }
+          if (device->make_and_model)
+           free(device->make_and_model);
 
-    if (!strncmp(packet.object_value.string, "lpr:", 4))
-    {
-     /*
-      * We want "lpd://..." for the URI...
-      */
+         device->make_and_model = strdup(packet.object_value.string);
+       }
+       break;
 
-      packet.object_value.string[2] = 'd';
-    }
+    case DEVICE_URI :
+       if (device && packet.object_type == CUPS_ASN1_OCTET_STRING &&
+           !device->uri)
+       {
+        /*
+         * Update an existing cache entry...
+         */
 
-    device->uri = strdup(packet.object_value.string);
+         if (!strncmp(packet.object_value.string, "lpr:", 4))
+         {
+          /*
+           * We want "lpd://..." for the URI...
+           */
 
-   /*
-    * List the device now if we have all the info...
-    */
+           packet.object_value.string[2] = 'd';
+         }
 
-    if (device->id && device->info && device->make_and_model && device->uri)
-      list_device(device);
+         device->uri = strdup(packet.object_value.string);
+       }
+       break;
   }
 }
 
@@ -1141,15 +1163,8 @@ scan_devices(int fd)                     /* I - SNMP socket */
   snmp_cache_t         *device;        /* Current device */
 
 
- /*
-  * Setup the request IDs...
-  */
-
   gettimeofday(&StartTime, NULL);
 
-  DeviceTypeRequest = StartTime.tv_sec;
-  DeviceDescRequest = StartTime.tv_sec + 1;
-
  /*
   * First send all of the broadcast queries...
   */
@@ -1189,7 +1204,7 @@ scan_devices(int fd)                      /* I - SNMP socket */
 
       for (addr = addrs; addr; addr = addr->next)
         _cupsSNMPWrite(fd, &(addr->addr), CUPS_SNMP_VERSION_1, community,
-                     CUPS_ASN1_GET_REQUEST, DeviceTypeRequest, DeviceTypeOID);
+                      CUPS_ASN1_GET_REQUEST, DEVICE_TYPE, DeviceTypeOID);
     }
 
     httpAddrFreeList(addrs);
@@ -1219,21 +1234,30 @@ scan_devices(int fd)                    /* I - SNMP socket */
     if (FD_ISSET(fd, &input))
       read_snmp_response(fd);
     else
-      break;
-  }
+    {
+     /*
+      * List devices with complete information...
+      */
 
- /*
-  * Finally, probe all of the printers we discovered to see how they are
-  * connected...
-  */
+      int sent_something = 0;
 
-  for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
-       device;
-       device = (snmp_cache_t *)cupsArrayNext(Devices))
-    if (MaxRunTime > 0 && run_time() >= MaxRunTime)
-      break;
-    else if (!device->uri)
-      probe_device(device);
+      for (device = (snmp_cache_t *)cupsArrayFirst(Devices);
+           device;
+          device = (snmp_cache_t *)cupsArrayNext(Devices))
+        if (!device->sent && device->info && device->make_and_model)
+       {
+         if (device->uri)
+           list_device(device);
+         else
+           probe_device(device);
+
+         device->sent = sent_something = 1;
+       }
+
+      if (!sent_something)
+        break;
+    }
+  }
 
   debug_printf("DEBUG: %.3f Scan complete!\n", run_time());
 }
index d0371378b163a425f1e6f3ccfad6870a6a9227d4..d333795646e53b83f568069ed94eedb0b7610ae3 100644 (file)
@@ -65,7 +65,7 @@
 *  cfstr_create_trim() - Create CFString and trim whitespace characters.
 *  parse_options()     - Parse uri options.
 *  setup_cfLanguage()  - Create AppleLanguages array from LANG environment var.
-*  run_ppc_backend()   - Re-exec i386 backend as ppc.
+*  run_legacy_backend()        - Re-exec backend as ppc or i386.
 *  sigterm_handler()   - SIGTERM handler.
 *  next_line()         - Find the next line in a buffer.
 *  parse_pserror()     - Scan the backchannel data for postscript errors.
 #include <IOKit/usb/IOUSBLib.h>
 #include <IOKit/IOCFPlugIn.h>
 
+#include <spawn.h>
 #include <pthread.h>
 
+extern char **environ;
+
 
 /*
  * WAIT_EOF_DELAY is number of seconds we'll wait for responses from
@@ -275,11 +278,11 @@ static void setup_cfLanguage(void);
 static void soft_reset();
 static void status_timer_cb(CFRunLoopTimerRef timer, void *info);
 
-#if defined(__i386__)
+#if defined(__i386__) || defined(__x86_64__)
 static pid_t   child_pid;                                      /* Child PID */
-static void run_ppc_backend(int argc, char *argv[], int fd);   /* Starts child backend process running as a ppc executable */
+static void run_legacy_backend(int argc, char *argv[], int fd);        /* Starts child backend process running as a ppc executable */
 static void sigterm_handler(int sig);                          /* SIGTERM handler */
-#endif /* __i386__ */
+#endif /* __i386__ || __x86_64__ */
 
 #ifdef PARSE_PS_ERRORS
 static const char *next_line (const char *buffer);
@@ -392,17 +395,18 @@ print_device(const char *uri,             /* I - Device URI */
 
     status = registry_open(&driverBundlePath);
 
-#if defined(__i386__)
+#if defined(__i386__) || defined(__x86_64__)
     /*
-     * If we were unable to load the class drivers for this printer it's probably because they're ppc-only.
-     * In this case try to fork & exec this backend as a ppc executable so we can use them...
+     * If we were unable to load the class drivers for this printer it's
+     * probably because they're ppc or i386. In this case try to run this
+     * backend as i386 or ppc executables so we can use them...
      */
     if (status == -2)
     {
-      run_ppc_backend(argc, argv, print_fd);
+      run_legacy_backend(argc, argv, print_fd);
       /* Never returns here */
     }
-#endif /* __i386__ */
+#endif /* __i386__ || __x86_64__ */
 
     if (status ==  -2)
     {
@@ -518,7 +522,7 @@ print_device(const char *uri,               /* I - Device URI */
 
     if (print_fd != STDIN_FILENO)
     {
-      fputs("PAGE: 1 1", stderr);
+      fputs("PAGE: 1 1\n", stderr);
       lseek(print_fd, 0, SEEK_SET);
     }
 
@@ -1052,8 +1056,8 @@ static Boolean list_device_cb(void *refcon,
       httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
       strncat(uristr, optionsstr, sizeof(uristr));
 
-      printf("direct %s \"%s\" \"%s USB\" \"%s\"\n", uristr, make_modelstr,
-             make_modelstr, idstr);
+      cupsBackendReport("direct", uristr, make_modelstr, make_modelstr, idstr,
+                        NULL);
 
       release_deviceinfo(&make, &model, &serial);
       CFRelease(deviceIDString);
@@ -1154,7 +1158,7 @@ static void status_timer_cb(CFRunLoopTimerRef timer,
                            void *info)
 {
   fputs("STATE: +offline-error\n", stderr);
-  _cupsLangPuts(stderr, _("INFO: Printer is currently offline.\n"));
+  _cupsLangPuts(stderr, _("INFO: Printer is offline.\n"));
 
   if (getenv("CLASS") != NULL)
   {
@@ -1729,36 +1733,42 @@ static void setup_cfLanguage(void)
 }
 
 #pragma mark -
-#if defined(__i386__)
+#if defined(__i386__) || defined(__x86_64__)
 /*!
- * @function   run_ppc_backend
+ * @function   run_legacy_backend
  *
- * @abstract   Starts child backend process running as a ppc executable.
+ * @abstract   Starts child backend process running as a ppc or i386 executable.
  *
  * @result     Never returns; always calls exit().
  *
  * @discussion
  */
-static void run_ppc_backend(int argc,
-                           char *argv[],
-                           int fd)
+static void run_legacy_backend(int argc,
+                              char *argv[],
+                              int fd)
 {
   int  i;
   int  exitstatus = 0;
   int  childstatus;
   pid_t        waitpid_status;
   char *my_argv[32];
-  char *usb_ppc_status;
+  char *usb_legacy_status;
 
 /*
-   * If we're running as i386 and couldn't load the class driver (because they'it's
-   * ppc-only) then try to re-exec ourselves in ppc mode to try again. If we don't have
-   * a ppc architecture we may be running i386 again so guard against this by setting
-   * and testing an environment variable...
-   */
-  usb_ppc_status = getenv("USB_PPC_STATUS");
+ /*
+  * If we're running as x86_64 or i386 and couldn't load the class driver
+  * (because it's ppc or i386), then try to re-exec ourselves in ppc or i386
+  * mode to try again. If we don't have a ppc or i386 architecture we may be
+  * running with the same architecture again so guard against this by setting
+  * and testing an environment variable...
+  */
 
-  if (usb_ppc_status == NULL)
+#  ifdef __x86_64__
+  usb_legacy_status = getenv("USB_I386_STATUS");
+#  else
+  usb_legacy_status = getenv("USB_PPC_STATUS");
+#  endif /* __x86_64__ */
+
+  if (!usb_legacy_status)
   {
    /*
     * Setup a SIGTERM handler then block it before forking...
@@ -1777,57 +1787,49 @@ static void run_ppc_backend(int argc,
     sigaddset(&newmask, SIGTERM);
     sigprocmask(SIG_BLOCK, &newmask, &oldmask);
 
-    if ((child_pid = fork()) == 0)
-    {
-     /*
-      * Child comes here...
-      */
-
-      setenv("USB_PPC_STATUS", "1", false);
-
-     /*
-      * Unblock signals before doing the exec...
-      */
-
-      memset(&action, 0, sizeof(action));
-      sigemptyset(&action.sa_mask);
-      action.sa_handler = SIG_DFL;
-      sigaction(SIGTERM, &action, NULL);
+   /*
+    * Set the environment variable...
+    */
 
-      sigprocmask(SIG_SETMASK, &oldmask, NULL);
+#  ifdef __x86_64__
+    setenv("USB_I386_STATUS", "1", false);
+#  else
+    setenv("USB_PPC_STATUS", "1", false);
+#  endif /* __x86_64__ */
 
-     /*
-      * Tell the kernel the next exec call should favor the ppc architecture...
-      */
+   /*
+    * Tell the kernel to use the specified CPU architecture...
+    */
 
-      int mib[] = { CTL_KERN, KERN_AFFINITY, 1, 1 };
-      int namelen = 4;
-      sysctl(mib, namelen, NULL, NULL, NULL, 0);
+#  ifdef __x86_64__
+    cpu_type_t cpu = CPU_TYPE_I386;
+#  else
+    cpu_type_t cpu = CPU_TYPE_POWERPC;
+#  endif /* __x86_64__ */
+    size_t ocount = 0;
+    posix_spawnattr_t attrs;
 
-     /*
-      * Set up the arguments and call exec...
-      */
+    if (!posix_spawnattr_init(&attrs))
+    {
+      posix_spawnattr_setsigdefault(attrs, &oldmask);
+      posix_spawnattr_setbinpref_np(attrs, 1, &cpu, &ocount);
+    }
 
-      for (i = 0; i < argc && i < (sizeof(my_argv)/sizeof(my_argv[0])) - 1; i++)
-       my_argv[i] = argv[i];
+   /*
+    * Set up the arguments and call posix_spawn...
+    */
 
-      my_argv[i] = NULL;
+    for (i = 0; i < argc && i < (sizeof(my_argv) / sizeof(my_argv[0])) - 1; i ++)
+      my_argv[i] = argv[i];
 
-      execv("/usr/libexec/cups/backend/usb", my_argv);
+    my_argv[i] = NULL;
 
-      _cupsLangPrintf(stderr, _("Unable to use legacy USB class driver!\n"));
-      perror("DEBUG: Unable to exec /usr/libexec/cups/backend/usb");
-      exit(errno);
-    }
-    else if (child_pid < 0)
+    if (posix_spawn(&child_pid, "/usr/libexec/cups/backend/usb", NULL, &attrs,
+                    my_argv, environ))
     {
-     /*
-      * Error - couldn't fork a new process!
-      */
-
       _cupsLangPrintf(stderr, _("Unable to use legacy USB class driver!\n"));
-      perror("DEBUG: Unable to fork");
-      exit(errno);
+      perror("DEBUG: Unable to exec /usr/libexec/cups/backend/usb");
+      exit(CUPS_BACKEND_STOP);
     }
 
    /*
@@ -1851,9 +1853,9 @@ static void run_ppc_backend(int argc,
 
     if (WIFSIGNALED(childstatus))
     {
-      exitstatus = WTERMSIG(childstatus);
+      exitstatus = CUPS_BACKEND_STOP;
       fprintf(stderr, "DEBUG: usb(legacy) backend %d crashed on signal %d!\n",
-              child_pid, exitstatus);
+              child_pid, WTERMSIG(childstatus));
     }
     else
     {
@@ -1869,7 +1871,7 @@ static void run_ppc_backend(int argc,
   else
   {
     fputs("DEBUG: usb(legacy) backend running native again\n", stderr);
-    exitstatus = ENOENT;
+    exitstatus = CUPS_BACKEND_STOP;
   }
 
   exit(exitstatus);
@@ -1889,7 +1891,7 @@ static void sigterm_handler(int sig)
   exit(1);
 }
 
-#endif /* __i386__ */
+#endif /* __i386__ || __x86_64__ */
 
 
 #ifdef PARSE_PS_ERRORS
index 4a7716ec30d02de5f049a5914ee136edba43e9d0..cad8d87ca6be0c232b0d9245f4383a802c01706b 100644 (file)
@@ -447,9 +447,8 @@ list_cb(usb_printer_t *printer,             /* I - Printer */
   * Report the printer...
   */
 
-  printf("direct %s \"%s\" \"%s USB\" \"%s\"\n", device_uri, make_model,
-         make_model, device_id);
-  fflush(stdout);
+  cupsBackendReport("direct", device_uri, make_model, make_model, device_id,
+                    NULL);
 
  /*
   * Keep going...
index 5fbed6ecd95edeaea9ec702cc21071370ed9d4ec..de4ab4e29b2c6f0c23c8a58716f1451320d029f4 100644 (file)
@@ -210,6 +210,7 @@ list_devices(void)
        device_uri[1024],               /* Device URI string */
        make_model[1024];               /* Make and model */
 
+
  /*
   * Try to open each USB device...
   */
@@ -245,8 +246,8 @@ list_devices(void)
     if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
                             make_model, sizeof(make_model),
                            "usb", device_uri, sizeof(device_uri)))
-      printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
-            make_model, make_model, i + 1, device_id);
+      cupsBackendReport("direct", device_uri, make_model, make_model,
+                        device_id, NULL);
 
     close(fd);
   }
@@ -273,8 +274,8 @@ list_devices(void)
       if (!backendGetDeviceID(fd, device_id, sizeof(device_id),
                               make_model, sizeof(make_model),
                              "usb", device_uri, sizeof(device_uri)))
-       printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri,
-              make_model, make_model, i + 1, device_id);
+       cupsBackendReport("direct", device_uri, make_model, make_model,
+                         device_id, NULL);
 
       close(fd);
     }
index e67582d0202435d81fe437a75376d5a81696dd27..bddc2d03841ea948b988f6de705d7bac972c8dc1 100644 (file)
  *   do_am_printer()           - Add or modify a printer.
  *   do_cancel_subscription()  - Cancel a subscription.
  *   do_config_server()        - Configure server settings.
- *   do_delete_class()         - Delete a class...
- *   do_delete_printer()       - Delete a printer...
- *   do_export()               - Export printers to Samba...
- *   do_list_printers()        - List available printers...
- *   do_menu()                 - Show the main menu...
+ *   do_delete_class()         - Delete a class.
+ *   do_delete_printer()       - Delete a printer.
+ *   do_export()               - Export printers to Samba.
+ *   do_list_printers()        - List available printers.
+ *   do_menu()                 - Show the main menu.
  *   do_printer_op()           - Do a printer operation.
  *   do_set_allowed_users()    - Set the allowed/denied users for a queue.
  *   do_set_options()          - Configure the default options for a queue.
- *   do_set_sharing()          - Set printer-is-shared value...
+ *   do_set_sharing()          - Set printer-is-shared value.
+ *   get_option_value()        - Return the value of an option.
+ *   get_points()              - Get a value in points.
  *   match_string()            - Return the number of matching characters.
  */
 
@@ -43,6 +45,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/wait.h>
+#include <limits.h>
 
 
 /*
@@ -64,6 +67,9 @@ static void   do_printer_op(http_t *http,
                              ipp_op_t op, const char *title);
 static void    do_set_allowed_users(http_t *http);
 static void    do_set_sharing(http_t *http);
+static char    *get_option_value(ppd_file_t *ppd, const char *name,
+                                 char *buffer, size_t bufsize);
+static double  get_points(double number, const char *uval);
 static int     match_string(const char *a, const char *b);
 
 
@@ -177,7 +183,7 @@ main(int  argc,                             /* I - Number of command-line arguments */
     else
     {
      /*
-      * Bad operation code...  Display an error...
+      * Bad operation code - display an error...
       */
 
       cgiStartHTML(cgiText(_("Administration")));
@@ -206,7 +212,7 @@ main(int  argc,                             /* I - Number of command-line arguments */
   else
   {
    /*
-    * Form data but no operation code...  Display an error...
+    * Form data but no operation code - display an error...
     */
 
     cgiStartHTML(cgiText(_("Administration")));
@@ -1769,7 +1775,7 @@ do_config_server(http_t *http)            /* I - HTTP connection */
 
 
 /*
- * 'do_delete_class()' - Delete a class...
+ * 'do_delete_class()' - Delete a class.
  */
 
 static void
@@ -1854,7 +1860,7 @@ do_delete_class(http_t *http)             /* I - HTTP connection */
 
 
 /*
- * 'do_delete_printer()' - Delete a printer...
+ * 'do_delete_printer()' - Delete a printer.
  */
 
 static void
@@ -1939,7 +1945,7 @@ do_delete_printer(http_t *http)           /* I - HTTP connection */
 
 
 /*
- * 'do_export()' - Export printers to Samba...
+ * 'do_export()' - Export printers to Samba.
  */
 
 static void
@@ -2075,7 +2081,7 @@ do_export(http_t *http)                   /* I - HTTP connection */
 
 
 /*
- * 'do_list_printers()' - List available printers...
+ * 'do_list_printers()' - List available printers.
  */
 
 static void
@@ -2278,7 +2284,7 @@ do_list_printers(http_t *http)            /* I - HTTP connection */
 
 
 /*
- * 'do_menu()' - Show the main menu...
+ * 'do_menu()' - Show the main menu.
  */
 
 static void
@@ -2774,12 +2780,15 @@ do_set_options(http_t *http,            /* I - HTTP connection */
   char         tempfile[1024];         /* Temporary filename */
   cups_file_t  *in,                    /* Input file */
                *out;                   /* Output file */
-  char         line[1024];             /* Line from PPD file */
-  char         keyword[1024],          /* Keyword from Default line */
+  char         line[1024],             /* Line from PPD file */
+               value[1024],            /* Option value */
+               keyword[1024],          /* Keyword from Default line */
                *keyptr;                /* Pointer into keyword... */
   ppd_file_t   *ppd;                   /* PPD file */
   ppd_group_t  *group;                 /* Option group */
   ppd_option_t *option;                /* Option */
+  ppd_coption_t        *coption;               /* Custom option */
+  ppd_cparam_t *cparam;                /* Custom parameter */
   ppd_attr_t   *protocol;              /* cupsProtocol attribute */
   const char   *title;                 /* Page title */
 
@@ -2847,32 +2856,14 @@ do_set_options(http_t *http,            /* I - HTTP connection */
   {
     ppdMarkDefaults(ppd);
 
-    DEBUG_printf(("<P>ppd->num_groups = %d\n"
-                 "<UL>\n", ppd->num_groups));
-
-    for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
-    {
-      DEBUG_printf(("<LI>%s<UL>\n", group->text));
-
-      for (j = group->num_options, option = group->options;
-          j > 0;
-          j --, option ++)
-       if ((var = cgiGetVariable(option->keyword)) != NULL)
-       {
-         DEBUG_printf(("<LI>%s = \"%s\"</LI>\n", option->keyword, var));
-         have_options = 1;
-         ppdMarkOption(ppd, option->keyword, var);
-       }
-#ifdef DEBUG
-       else
-         printf("<LI>%s not defined!</LI>\n", option->keyword);
-#endif /* DEBUG */
-
-      DEBUG_puts("</UL></LI>");
-    }
-
-    DEBUG_printf(("</UL>\n"
-                 "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd)));
+    for (option = ppdFirstOption(ppd);
+         option;
+        option = ppdNextOption(ppd))
+      if ((var = cgiGetVariable(option->keyword)) != NULL)
+      {
+       have_options = 1;
+       ppdMarkOption(ppd, option->keyword, var);
+      }
   }
 
   if (!have_options || ppdConflicts(ppd))
@@ -2928,7 +2919,7 @@ do_set_options(http_t *http,              /* I - HTTP connection */
 
          cgiSetVariable("KEYWORD", option->keyword);
          cgiSetVariable("KEYTEXT", option->text);
-             
+
          if (option->conflicted)
            cgiSetVariable("CONFLICTED", "1");
          else
@@ -2938,13 +2929,6 @@ do_set_options(http_t *http,             /* I - HTTP connection */
          cgiSetSize("TEXT", 0);
          for (k = 0, m = 0; k < option->num_choices; k ++)
          {
-          /*
-           * Hide custom option values...
-           */
-
-           if (!strcmp(option->choices[k].choice, "Custom"))
-             continue;
-
            cgiSetArray("CHOICES", m, option->choices[k].choice);
            cgiSetArray("TEXT", m, option->choices[k].text);
 
@@ -2954,6 +2938,118 @@ do_set_options(http_t *http,            /* I - HTTP connection */
              cgiSetVariable("DEFCHOICE", option->choices[k].choice);
          }
 
+         cgiSetSize("PARAMS", 0);
+         cgiSetSize("PARAMTEXT", 0);
+         cgiSetSize("PARAMVALUE", 0);
+         cgiSetSize("INPUTTYPE", 0);
+
+         if ((coption = ppdFindCustomOption(ppd, option->keyword)))
+         {
+            const char *units = NULL;  /* Units value, if any */
+
+
+           cgiSetVariable("ISCUSTOM", "1");
+
+           for (cparam = ppdFirstCustomParam(coption), m = 0;
+                cparam;
+                cparam = ppdNextCustomParam(coption), m ++)
+           {
+             if (!strcasecmp(option->keyword, "PageSize") &&
+                 strcasecmp(cparam->name, "Width") &&
+                 strcasecmp(cparam->name, "Height"))
+              {
+               m --;
+               continue;
+              }
+
+             cgiSetArray("PARAMS", m, cparam->name);
+             cgiSetArray("PARAMTEXT", m, cparam->text);
+             cgiSetArray("INPUTTYPE", m, "text");
+
+             switch (cparam->type)
+             {
+               case PPD_CUSTOM_POINTS :
+                   if (!strncasecmp(option->defchoice, "Custom.", 7))
+                   {
+                     units = option->defchoice + strlen(option->defchoice) - 2;
+
+                     if (strcmp(units, "mm") && strcmp(units, "cm") &&
+                         strcmp(units, "in") && strcmp(units, "ft"))
+                     {
+                       if (units[1] == 'm')
+                         units ++;
+                       else
+                         units = "pt";
+                     }
+                   }
+                   else
+                     units = "pt";
+
+                    if (!strcmp(units, "mm"))
+                     snprintf(value, sizeof(value), "%g",
+                              cparam->current.custom_points / 72.0 * 25.4);
+                    else if (!strcmp(units, "cm"))
+                     snprintf(value, sizeof(value), "%g",
+                              cparam->current.custom_points / 72.0 * 2.54);
+                    else if (!strcmp(units, "in"))
+                     snprintf(value, sizeof(value), "%g",
+                              cparam->current.custom_points / 72.0);
+                    else if (!strcmp(units, "ft"))
+                     snprintf(value, sizeof(value), "%g",
+                              cparam->current.custom_points / 72.0 / 12.0);
+                    else if (!strcmp(units, "m"))
+                     snprintf(value, sizeof(value), "%g",
+                              cparam->current.custom_points / 72.0 * 0.0254);
+                    else
+                     snprintf(value, sizeof(value), "%g",
+                              cparam->current.custom_points);
+                   cgiSetArray("PARAMVALUE", m, value);
+                   break;
+
+               case PPD_CUSTOM_CURVE :
+               case PPD_CUSTOM_INVCURVE :
+               case PPD_CUSTOM_REAL :
+                   snprintf(value, sizeof(value), "%g",
+                            cparam->current.custom_real);
+                   cgiSetArray("PARAMVALUE", m, value);
+                   break;
+
+               case PPD_CUSTOM_INT:
+                   snprintf(value, sizeof(value), "%d",
+                            cparam->current.custom_int);
+                   cgiSetArray("PARAMVALUE", m, value);
+                   break;
+
+               case PPD_CUSTOM_PASSCODE:
+               case PPD_CUSTOM_PASSWORD:
+                   if (cparam->current.custom_password)
+                     cgiSetArray("PARAMVALUE", m,
+                                 cparam->current.custom_password);
+                   else
+                     cgiSetArray("PARAMVALUE", m, "");
+                   cgiSetArray("INPUTTYPE", m, "password");
+                   break;
+
+               case PPD_CUSTOM_STRING:
+                   if (cparam->current.custom_string)
+                     cgiSetArray("PARAMVALUE", m,
+                                 cparam->current.custom_string);
+                   else
+                     cgiSetArray("PARAMVALUE", m, "");
+                   break;
+             }
+           }
+
+            if (units)
+           {
+             cgiSetArray("PARAMS", m, "Units");
+             cgiSetArray("PARAMTEXT", m, cgiText(_("Units")));
+             cgiSetArray("PARAMVALUE", m, units);
+           }
+         }
+         else
+           cgiSetVariable("ISCUSTOM", "0");
+
          switch (option->ui)
          {
            case PPD_UI_BOOLEAN :
@@ -3199,17 +3295,21 @@ do_set_options(http_t *http,            /* I - HTTP connection */
          if (!strcmp(keyword, "PageRegion") ||
              !strcmp(keyword, "PaperDimension") ||
              !strcmp(keyword, "ImageableArea"))
-           var = cgiGetVariable("PageSize");
+           var = get_option_value(ppd, "PageSize", value, sizeof(value));
          else
-           var = cgiGetVariable(keyword);
+           var = get_option_value(ppd, keyword, value, sizeof(value));
 
-         if (var != NULL)
-           cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
-         else
+         if (!var)
            cupsFilePrintf(out, "%s\n", line);
+         else
+           cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
        }
       }
 
+     /*
+      * TODO: We need to set the port-monitor attribute!
+      */
+
       if ((var = cgiGetVariable("protocol")) != NULL)
        cupsFilePrintf(out, "*cupsProtocol: %s\n", var);
 
@@ -3307,7 +3407,7 @@ do_set_options(http_t *http,              /* I - HTTP connection */
 
 
 /*
- * 'do_set_sharing()' - Set printer-is-shared value...
+ * 'do_set_sharing()' - Set printer-is-shared value.
  */
 
 static void
@@ -3399,6 +3499,294 @@ do_set_sharing(http_t *http)            /* I - HTTP connection */
 }
 
 
+/*
+ * 'get_option_value()' - Return the value of an option.
+ *
+ * This function also handles generation of custom option values.
+ */
+
+static char *                          /* O - Value string or NULL on error */
+get_option_value(
+    ppd_file_t    *ppd,                        /* I - PPD file */
+    const char    *name,               /* I - Option name */
+    char          *buffer,             /* I - String buffer */
+    size_t        bufsize)             /* I - Size of buffer */
+{
+  char         *bufptr,                /* Pointer into buffer */
+               *bufend;                /* End of buffer */
+  ppd_coption_t *coption;              /* Custom option */
+  ppd_cparam_t *cparam;                /* Current custom parameter */
+  char         keyword[256];           /* Parameter name */
+  const char   *val,                   /* Parameter value */
+               *uval;                  /* Units value */
+  long         integer;                /* Integer value */
+  double       number,                 /* Number value */
+               number_points;          /* Number in points */
+
+
+ /*
+  * See if we have a custom option choice...
+  */
+
+  if ((val = cgiGetVariable(name)) == NULL)
+  {
+   /*
+    * Option not found!
+    */
+
+    return (NULL);
+  }
+  else if (strcasecmp(val, "Custom") ||
+           (coption = ppdFindCustomOption(ppd, name)) == NULL)
+  {
+   /*
+    * Not a custom choice...
+    */
+
+    strlcpy(buffer, val, bufsize);
+    return (buffer);
+  }
+
+ /*
+  * OK, we have a custom option choice, format it...
+  */
+
+  *buffer = '\0';
+
+  if (!strcmp(coption->keyword, "PageSize"))
+  {
+    const char *lval;                  /* Length string value */
+    double     width,                  /* Width value */
+               width_points,           /* Width in points */
+               length,                 /* Length value */
+               length_points;          /* Length in points */
+
+
+    val  = cgiGetVariable("PageSize.Width");
+    lval = cgiGetVariable("PageSize.Height");
+    uval = cgiGetVariable("PageSize.Units");
+
+    if (!val || !lval || !uval ||
+        (width = strtod(val, NULL)) == 0.0 ||
+        (length = strtod(lval, NULL)) == 0.0 ||
+        (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
+        strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
+      return (NULL);
+
+    width_points  = get_points(width, uval);
+    length_points = get_points(length, uval);
+
+    if (width_points < ppd->custom_min[0] ||
+        width_points > ppd->custom_max[0] ||
+        length_points < ppd->custom_min[1] ||
+       length_points > ppd->custom_max[1])
+      return (NULL);
+
+    snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval);
+  }
+  else if (cupsArrayCount(coption->params) == 1) 
+  {
+    cparam = ppdFirstCustomParam(coption);
+    snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name);
+
+    if ((val = cgiGetVariable(keyword)) == NULL)
+      return (NULL);
+
+    switch (cparam->type)
+    {
+      case PPD_CUSTOM_CURVE :
+      case PPD_CUSTOM_INVCURVE :
+      case PPD_CUSTOM_REAL :
+         if ((number = strtod(val, NULL)) == 0.0 ||
+             number < cparam->minimum.custom_real ||
+             number > cparam->maximum.custom_real)
+           return (NULL);
+
+          snprintf(buffer, bufsize, "Custom.%g", number);
+          break;
+
+      case PPD_CUSTOM_INT :
+          if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
+             integer == LONG_MAX ||
+             integer < cparam->minimum.custom_int ||
+             integer > cparam->maximum.custom_int)
+            return (NULL);
+
+          snprintf(buffer, bufsize, "Custom.%ld", integer);
+          break;
+
+      case PPD_CUSTOM_POINTS :
+          snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
+
+         if ((number = strtod(val, NULL)) == 0.0 ||
+             (uval = cgiGetVariable(keyword)) == NULL ||
+             (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
+              strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
+           return (NULL);
+
+         number_points = get_points(number, uval);
+         if (number_points < cparam->minimum.custom_points ||
+             number_points > cparam->maximum.custom_points)
+           return (NULL);
+
+         snprintf(buffer, bufsize, "Custom.%g%s", number, uval);
+          break;
+
+      case PPD_CUSTOM_PASSCODE :
+          for (uval = val; *uval; uval ++)
+           if (!isdigit(*uval & 255))
+             return (NULL);
+
+      case PPD_CUSTOM_PASSWORD :
+      case PPD_CUSTOM_STRING :
+          integer = (long)strlen(val);
+         if (integer < cparam->minimum.custom_string ||
+             integer > cparam->maximum.custom_string)
+           return (NULL);
+
+          snprintf(buffer, bufsize, "Custom.%s", val);
+         break;
+    }
+  }
+  else
+  {
+    const char *prefix = "{";          /* Prefix string */
+
+
+    bufptr = buffer;
+    bufend = buffer + bufsize;
+
+    for (cparam = ppdFirstCustomParam(coption);
+        cparam;
+        cparam = ppdNextCustomParam(coption))
+    {
+      snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword,
+               cparam->name);
+
+      if ((val = cgiGetVariable(keyword)) == NULL)
+       return (NULL);
+
+      snprintf(bufptr, bufend - bufptr, "%s%s=", prefix, cparam->name);
+      bufptr += strlen(bufptr);
+      prefix = " ";
+
+      switch (cparam->type)
+      {
+       case PPD_CUSTOM_CURVE :
+       case PPD_CUSTOM_INVCURVE :
+       case PPD_CUSTOM_REAL :
+           if ((number = strtod(val, NULL)) == 0.0 ||
+               number < cparam->minimum.custom_real ||
+               number > cparam->maximum.custom_real)
+             return (NULL);
+
+           snprintf(bufptr, bufend - bufptr, "%g", number);
+           break;
+
+       case PPD_CUSTOM_INT :
+           if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
+               integer == LONG_MAX ||
+               integer < cparam->minimum.custom_int ||
+               integer > cparam->maximum.custom_int)
+             return (NULL);
+
+           snprintf(bufptr, bufend - bufptr, "%ld", integer);
+           break;
+
+       case PPD_CUSTOM_POINTS :
+           snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
+
+           if ((number = strtod(val, NULL)) == 0.0 ||
+               (uval = cgiGetVariable(keyword)) == NULL ||
+               (strcmp(uval, "pt") && strcmp(uval, "in") &&
+                strcmp(uval, "ft") && strcmp(uval, "cm") &&
+                strcmp(uval, "mm") && strcmp(uval, "m")))
+             return (NULL);
+
+           number_points = get_points(number, uval);
+           if (number_points < cparam->minimum.custom_points ||
+               number_points > cparam->maximum.custom_points)
+             return (NULL);
+
+           snprintf(bufptr, bufend - bufptr, "%g%s", number, uval);
+           break;
+
+       case PPD_CUSTOM_PASSCODE :
+           for (uval = val; *uval; uval ++)
+             if (!isdigit(*uval & 255))
+               return (NULL);
+
+       case PPD_CUSTOM_PASSWORD :
+       case PPD_CUSTOM_STRING :
+           integer = (long)strlen(val);
+           if (integer < cparam->minimum.custom_string ||
+               integer > cparam->maximum.custom_string)
+             return (NULL);
+
+           if ((bufptr + 2) > bufend)
+             return (NULL);
+
+           bufend --;
+           *bufptr++ = '\"';
+
+           while (*val && bufptr < bufend)
+           {
+             if (*val == '\\' || *val == '\"')
+             {
+               if ((bufptr + 1) >= bufend)
+                 return (NULL);
+
+               *bufptr++ = '\\';
+             }
+
+             *bufptr++ = *val++;
+           }
+
+           if (bufptr >= bufend)
+             return (NULL);
+
+           *bufptr++ = '\"';
+           *bufptr   = '\0';
+           bufend ++;
+           break;
+      }
+
+      bufptr += strlen(bufptr);
+    }
+
+    if (bufptr == buffer || (bufend - bufptr) < 2)
+      return (NULL);
+
+    strcpy(bufptr, "}");
+  }
+
+  return (buffer);
+}
+
+
+/*
+ * 'get_points()' - Get a value in points.
+ */
+
+static double                          /* O - Number in points */
+get_points(double     number,          /* I - Original number */
+           const char *uval)           /* I - Units */
+{
+  if (!strcmp(uval, "mm"))             /* Millimeters */
+    return (number * 72.0 / 25.4);
+  else if (!strcmp(uval, "cm"))                /* Centimeters */
+    return (number * 72.0 / 2.54);
+  else if (!strcmp(uval, "in"))                /* Inches */
+    return (number * 72.0);
+  else if (!strcmp(uval, "ft"))                /* Feet */
+    return (number * 72.0 * 12.0);
+  else if (!strcmp(uval, "m"))         /* Meters */
+    return (number * 72.0 / 0.0254);
+  else                                 /* Points */
+    return (number);
+}
+
+
 /*
  * 'match_string()' - Return the number of matching characters.
  */
index e48fc0fe4f21514bb2ef80d7fcc52d6c30ac4720..16e6b2b0e6732d563021012da580afab239b29bf 100644 (file)
@@ -188,6 +188,19 @@ if test $check_libusb = yes; then
                        LIBUSB="-lusb")])
 fi
 
+dnl See if we have libwrap for TCP wrappers support...
+AC_ARG_ENABLE(tcp_wrappers, [  --enable-tcp-wrappers   use libwrap for TCP wrappers support, default=no])
+
+LIBWRAP=""
+AC_SUBST(LIBWRAP)
+
+if test x$enable_tcp_wrappers = xyes; then
+       AC_CHECK_LIB(wrap, hosts_access,[
+               AC_CHECK_HEADER(tcpd.h,
+                       AC_DEFINE(HAVE_TCPD_H)
+                       LIBWRAP="-lwrap")])
+fi
+
 dnl Flags for "ar" command...
 case $uname in
         Darwin* | *BSD*)
index 8598aebb97a7a5351a38b2ee401eafcb7fdc0a7b..8d30df79c110f762e45be06a390a864cc7035e37 100644 (file)
@@ -145,6 +145,7 @@ if test -n "$GCC"; then
                # Additional warning options for development testing...
                if test -d .svn; then
                        OPTIM="-Wshadow -Wunused $OPTIM"
+                       CFLAGS="-Werror-implicit-function-declaration $CFLAGS"
                        PHPOPTIONS="-Wno-shadow"
                fi
        fi
index 4105ba17f2ff585371a1bc1fb3dc1c04c19f20a7..16d414d229601ba1e0b1cdf4ded1d982fe8c2916 100644 (file)
@@ -123,12 +123,14 @@ AC_ARG_WITH(rcdir, [  --with-rcdir            set path for rc scripts],rcdir="$w
 AC_ARG_WITH(rclevels, [  --with-rclevels         set run levels for rc scripts],rclevels="$withval",rclevels="2 3 5")
 AC_ARG_WITH(rcstart, [  --with-rcstart          set start number for rc scripts],rcstart="$withval",rcstart="99")
 AC_ARG_WITH(rcstop, [  --with-rcstop           set stop number for rc scripts],rcstop="$withval",rcstop="00")
+AC_ARG_WITH(smfmanifestdir, [  --with-smfmanifestdir   set path for Solaris SMF manifest],smfmanifestdir="$withval",smfmanifestdir="")
 
 INITDIR=""
 INITDDIR=""
 RCLEVELS="$rclevels"
 RCSTART="$rcstart"
 RCSTOP="$rcstop"
+SMFMANIFESTDIR=""
 
 if test x$rcdir = x; then
        case "$uname" in
@@ -192,8 +194,12 @@ if test x$rcdir = x; then
 
                SunOS*)
                        # Solaris
-                       INITDIR="/etc"
-                       RCSTART="81"
+                       if test "x$smfmanifestdir" != x; then
+                               SMFMANIFESTDIR=$smfmanifestdir
+                       else
+                               INITDIR="/etc"
+                               RCSTART="81"
+                       fi
                        ;;
 
                *)
@@ -214,6 +220,7 @@ AC_SUBST(INITDDIR)
 AC_SUBST(RCLEVELS)
 AC_SUBST(RCSTART)
 AC_SUBST(RCSTOP)
+AC_SUBST(SMFMANIFESTDIR)
 
 dnl Xinetd support...
 AC_ARG_WITH(xinetd, [  --with-xinetd           set path for xinetd config files],XINETD="$withval",XINETD="")
index 3f5adec2351ed19e94fa32090a398d5b15d1abfb..1c5f516bc9b75a48c96f3d0b4c0e0ac960818145 100644 (file)
@@ -14,22 +14,34 @@ dnl   file is missing or damaged, see the license at "http://www.cups.org/".
 dnl
 
 AC_ARG_ENABLE(ldap, [  --enable-ldap           turn on LDAP support, default=yes])
-AC_ARG_WITH(openldap-libs, [  --with-openldap-libs    set directory for OpenLDAP library],
+AC_ARG_WITH(ldap-libs, [  --with-ldap-libs        set directory for LDAP library],
     LDFLAGS="-L$withval $LDFLAGS"
     DSOFLAGS="-L$withval $DSOFLAGS",)
-AC_ARG_WITH(openldap-includes, [  --with-openldap-includes
-                          set directory for OpenLDAP includes],
+AC_ARG_WITH(ldap-includes, [  --with-ldap-includes    set directory for LDAP includes],
     CFLAGS="-I$withval $CFLAGS"
     CPPFLAGS="-I$withval $CPPFLAGS",)
 
 LIBLDAP=""
 
 if test x$enable_ldap != xno; then
-    AC_CHECK_HEADER(ldap.h,
+    AC_CHECK_HEADER(ldap.h, [
        AC_CHECK_LIB(ldap, ldap_initialize,
-            AC_DEFINE(HAVE_LDAP)
-            AC_DEFINE(HAVE_OPENLDAP)
-           LIBLDAP="-lldap"))
+           AC_DEFINE(HAVE_LDAP)
+           AC_DEFINE(HAVE_OPENLDAP)
+           LIBLDAP="-lldap"
+           AC_CHECK_LIB(ldap, ldap_start_tls,
+               AC_DEFINE(HAVE_LDAP_SSL)),
+
+           AC_CHECK_LIB(ldap, ldap_init,
+               AC_DEFINE(HAVE_LDAP)
+               AC_DEFINE(HAVE_MOZILLA_LDAP)
+               LIBLDAP="-lldap"
+               AC_CHECK_HEADER(ldap_ssl.h, AC_DEFINE(HAVE_LDAP_SSL_H),,[#include <ldap.h>])
+               AC_CHECK_LIB(ldap, ldapssl_init,
+                   AC_DEFINE(HAVE_LDAP_SSL)))
+       )
+       AC_CHECK_LIB(ldap, ldap_set_rebind_proc, AC_DEFINE(HAVE_LDAP_REBIND_PROC))
+    ])
 fi
 
 AC_SUBST(LIBLDAP)
index cd801f72e1bd5ee76c6d3bc6365b3e8bc83afd0d..9a95a084fa11279cf7285f3d3547c1940a14df20 100644 (file)
 
 #undef HAVE_LDAP
 #undef HAVE_OPENLDAP
+#undef HAVE_MOZILLA_LDAP
+#undef HAVE_LDAP_SSL_H
+#undef HAVE_LDAP_SSL
+#undef HAVE_LDAP_REBIND_PROC
 
 
 /*
 #undef HAVE_USB_H
 
 
+/*
+ * Do we have libwrap and tcpd.h?
+ */
+
+#undef HAVE_TCPD_H
+
+
 #endif /* !_CUPS_CONFIG_H_ */
 
 /*
index 0425660be99c53886d129ffb7973c4e225b05fc4..8ff9a0e0caafbee7b3baf7eaf96d88da7fd44817 100644 (file)
@@ -65,7 +65,7 @@ AC_SUBST(UNINSTALL_LANGUAGES)
 AC_OUTPUT(Makedefs packaging/cups.list init/cups.sh init/cups-lpd cups-config
          conf/cupsd.conf conf/mime.convs conf/pam.std conf/snmp.conf
          doc/index.html doc/help/ref-cupsd-conf.html doc/help/standard.html
-         init/org.cups.cups-lpd.plist
+         init/org.cups.cups-lpd.plist init/cups.xml
          man/client.conf.man man/cups-deviced.man man/cups-driverd.man
          man/cups-lpd.man man/cupsaddsmb.man man/cupsd.man
          man/cupsd.conf.man man/drv.man man/lpoptions.man
index 87ff36fd791745302a6764a812dee17f67950bd3..3ea7e81af5fe3d5e31bdf398ea5cb165aa8d8d7f 100644 (file)
@@ -260,9 +260,9 @@ cupsAdminCreateWindowsPPD(
       if ((ptr = strchr(line, ':')) == NULL)
       {
         snprintf(line, sizeof(line),
-                 _cupsLangString(language, _("Missing value on line %d!")),
-                 linenum);
-        _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line);
+                _cupsLangString(language, _("Missing value on line %d!")),
+                linenum);
+        _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line, 0);
 
         cupsFileClose(srcfp);
         cupsFileClose(dstfp);
@@ -281,7 +281,7 @@ cupsAdminCreateWindowsPPD(
                 _cupsLangString(language,
                                 _("Missing double quote on line %d!")),
                 linenum);
-        _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line);
+        _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line, 0);
 
         cupsFileClose(srcfp);
         cupsFileClose(dstfp);
@@ -300,7 +300,7 @@ cupsAdminCreateWindowsPPD(
                 _cupsLangString(language,
                                 _("Bad option + choice on line %d!")),
                 linenum);
-        _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line);
+        _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line, 0);
 
         cupsFileClose(srcfp);
         cupsFileClose(dstfp);
@@ -343,10 +343,7 @@ cupsAdminCreateWindowsPPD(
 
   if (linenum == 0)
   {
-    snprintf(line, sizeof(line),
-             _cupsLangString(language, _("Empty PPD file!")),
-             linenum);
-    _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, line);
+    _cupsSetError(IPP_DOCUMENT_FORMAT_ERROR, _("Empty PPD file!"), 1);
 
     cupsFileClose(dstfp);
     unlink(buffer);
@@ -434,7 +431,7 @@ cupsAdminExportSamba(
 
   if (!dest || !ppd || !samba_server || !samba_user || !samba_password)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
     return (0);
   }
 
@@ -444,7 +441,7 @@ cupsAdminExportSamba(
 
   if ((fp = cupsTempFile2(authfile, sizeof(authfile))) == NULL)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+    _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
     return (0);
   }
 
@@ -497,7 +494,7 @@ cupsAdminExportSamba(
                               _("Unable to copy Windows 2000 printer "
                                 "driver files (%d)!")), status);
 
-      _cupsSetError(IPP_INTERNAL_ERROR, message);
+      _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
 
       if (logfile)
        _cupsLangPrintf(logfile, "%s\n", message);
@@ -532,7 +529,7 @@ cupsAdminExportSamba(
                                 _("Unable to copy CUPS printer driver "
                                   "files (%d)!")), status);
 
-       _cupsSetError(IPP_INTERNAL_ERROR, message);
+       _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
 
        if (logfile)
          _cupsLangPrintf(logfile, "%s\n", message);
@@ -575,7 +572,7 @@ cupsAdminExportSamba(
                               _("Unable to install Windows 2000 printer "
                                 "driver files (%d)!")), status);
 
-      _cupsSetError(IPP_INTERNAL_ERROR, message);
+      _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
 
       if (logfile)
        _cupsLangPrintf(logfile, "%s\n", message);
@@ -620,7 +617,7 @@ cupsAdminExportSamba(
                               _("Unable to copy Windows 9x printer "
                                 "driver files (%d)!")), status);
 
-      _cupsSetError(IPP_INTERNAL_ERROR, message);
+      _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
 
       if (logfile)
        _cupsLangPrintf(logfile, "%s\n", message);
@@ -649,7 +646,7 @@ cupsAdminExportSamba(
                               _("Unable to install Windows 9x printer "
                                 "driver files (%d)!")), status);
 
-      _cupsSetError(IPP_INTERNAL_ERROR, message);
+      _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
 
       if (logfile)
        _cupsLangPrintf(logfile, "%s\n", message);
@@ -701,7 +698,7 @@ cupsAdminExportSamba(
                               _("Unable to copy 64-bit Windows printer "
                                 "driver files (%d)!")), status);
 
-      _cupsSetError(IPP_INTERNAL_ERROR, message);
+      _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
 
       if (logfile)
        _cupsLangPrintf(logfile, "%s\n", message);
@@ -736,7 +733,7 @@ cupsAdminExportSamba(
                                 _("Unable to copy 64-bit CUPS printer driver "
                                   "files (%d)!")), status);
 
-       _cupsSetError(IPP_INTERNAL_ERROR, message);
+       _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
 
        if (logfile)
          _cupsLangPrintf(logfile, "%s\n", message);
@@ -779,7 +776,7 @@ cupsAdminExportSamba(
                               _("Unable to install Windows 2000 printer "
                                 "driver files (%d)!")), status);
 
-      _cupsSetError(IPP_INTERNAL_ERROR, message);
+      _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
 
       if (logfile)
        _cupsLangPrintf(logfile, "%s\n", message);
@@ -804,13 +801,13 @@ cupsAdminExportSamba(
                                "are installed!")),
               sizeof(message));
 
-    _cupsSetError(IPP_NOT_FOUND, message);
+    _cupsSetError(IPP_NOT_FOUND, message, 0);
     _cupsLangPrintf(logfile, "%s\n", message);
   }
 
   if (have_drivers == 0)
   {
-    _cupsSetError(IPP_NOT_FOUND, message);
+    _cupsSetError(IPP_NOT_FOUND, message, 0);
 
     unlink(authfile);
 
@@ -831,7 +828,7 @@ cupsAdminExportSamba(
                             _("Unable to set Windows printer driver (%d)!")),
                             status);
 
-    _cupsSetError(IPP_INTERNAL_ERROR, message);
+    _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
 
     if (logfile)
       _cupsLangPrintf(logfile, "%s\n", message);
@@ -901,7 +898,7 @@ _cupsAdminGetServerSettings(
 
   if (!http || !num_settings || !settings)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
 
     if (num_settings)
       *num_settings = 0;
@@ -928,9 +925,9 @@ _cupsAdminGetServerSettings(
 
 
       snprintf(message, sizeof(message),
-               _cupsLangString(cupsLangDefault(), _("open of %s failed: %s")),
+               _cupsLangString(cupsLangDefault(), _("Open of %s failed: %s")),
                cupsdconf, strerror(errno));
-      _cupsSetError(IPP_INTERNAL_ERROR, message);
+      _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
     }
   }
   else
@@ -1224,7 +1221,7 @@ _cupsAdminSetServerSettings(
 
   if (!http || !num_settings || !settings)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
 
     return (0);
   }
@@ -1238,7 +1235,7 @@ _cupsAdminSetServerSettings(
   {
     if ((cupsd = cupsFileOpen(cupsdconf, "r")) == NULL)
     {
-      _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+      _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
       return (0);
     }
   }
@@ -1395,7 +1392,7 @@ _cupsAdminSetServerSettings(
     if (remote)
       unlink(cupsdconf);
 
-    _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+    _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
     return (0);
   }
 
@@ -2203,7 +2200,7 @@ get_cupsd_conf(
       snprintf(message, sizeof(message),
                _cupsLangString(cupsLangDefault(), _("stat of %s failed: %s")),
                name, strerror(errno));
-      _cupsSetError(IPP_INTERNAL_ERROR, message);
+      _cupsSetError(IPP_INTERNAL_ERROR, message, 0);
 
       *name = '\0';
 
@@ -2225,7 +2222,7 @@ get_cupsd_conf(
     {
       *name = '\0';
 
-      _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+      _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
 
       invalidate_cupsd_cache(cg);
 
index 021dad2e21ce3adfb72f7c2f85516ee76592a1da..ca4fad2f3cb3076c13cb7fd7f1c3d2d77e650090 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: backend.c 7583 2008-05-16 17:47:16Z mike $"
+ * "$Id: backend.c 7810 2008-07-29 01:11:15Z mike $"
  *
  *   Backend functions for the Common UNIX Printing System (CUPS).
  *
@@ -17,6 +17,8 @@
  * Contents:
  *
  *   cupsBackendDeviceURI() - Get the device URI for a backend.
+ *   cupsBackendReport()    - Write a device line from a backend.
+ *   quote_string()         - Write a quoted string to stdout, escaping \ and ".
  */
 
 /*
 #include "globals.h"
 
 
+/*
+ * Local functions...
+ */
+
+static void    quote_string(const char *s);
+
+
 /*
  * 'cupsBackendDeviceURI()' - Get the device URI for a backend.
  *
@@ -58,5 +67,64 @@ cupsBackendDeviceURI(char **argv)    /* I - Command-line arguments */
 
 
 /*
- * End of "$Id: backend.c 7583 2008-05-16 17:47:16Z mike $".
+ * 'cupsBackendReport()' - Write a device line from a backend.
+ *
+ * This function writes a single device line to stdout for a backend.
+ * It handles quoting of special characters in the device-make-and-model,
+ * device-info, device-id, and device-location strings.
+ */
+
+void
+cupsBackendReport(
+    const char *device_scheme,         /* I - device-scheme string */
+    const char *device_uri,            /* I - device-uri string */
+    const char *device_make_and_model, /* I - device-make-and-model string or @code NULL@ */
+    const char *device_info,           /* I - device-info string or @code NULL@ */
+    const char *device_id,             /* I - device-id string or @code NULL@ */
+    const char *device_location)       /* I - device-location string or @code NULL@ */
+{
+  if (!device_scheme || !device_uri)
+    return;
+
+  printf("%s %s", device_scheme, device_uri);
+  if (device_make_and_model && *device_make_and_model)
+    quote_string(device_make_and_model);
+  else
+    quote_string("unknown");
+  quote_string(device_info);
+  quote_string(device_id);
+  quote_string(device_location);
+  putchar('\n');
+  fflush(stdout);
+}
+
+
+/*
+ * 'quote_string()' - Write a quoted string to stdout, escaping \ and ".
+ */
+
+static void
+quote_string(const char *s)            /* I - String to write */
+{
+  fputs(" \"", stdout);
+
+  if (s)
+  {
+    while (*s)
+    {
+      if (*s == '\\' || *s == '\"')
+       putchar('\\');
+
+      putchar(*s);
+
+      s ++;
+    }
+  }
+
+  putchar('\"');
+}
+
+
+/*
+ * End of "$Id: backend.c 7810 2008-07-29 01:11:15Z mike $".
  */
index 77bf5756973495f79b2aa46e4ea02ac119b0be9b..f128895da4a95792e5dc1213770122fa1cef2265 100644 (file)
@@ -48,7 +48,14 @@ typedef enum cups_backend_e cups_backend_t;
  */
 
 extern const char      *cupsBackendDeviceURI(char **argv) _CUPS_API_1_2;
-
+extern void            cupsBackendReport(const char *device_scheme,
+                                         const char *device_uri,
+                                         const char *device_make_and_model,
+                                         const char *device_info,
+                                         const char *device_id,
+                                         const char *device_location)
+                                         _CUPS_API_1_4;
+                                         
 
 #endif /* !_CUPS_BACKEND_H_ */
 
index 1038c8313d613e8e2360616f5c9b0db3f8029744..08aaf3479a7d928417f1ad450f09ab58b795e27a 100644 (file)
@@ -124,7 +124,8 @@ typedef const char *(*cups_password_cb_t)(const char *prompt);
 typedef void (*cups_device_cb_t)(const char *device_class,
                                  const char *device_id, const char *device_info,
                                  const char *device_make_and_model,
-                                 const char *device_uri, void *user_data);
+                                 const char *device_uri,
+                                const char *device_location, void *user_data);
                                        /**** Device callback @since CUPS 1.4@ ****/
 
 typedef struct cups_option_s           /**** Printer Options ****/
index 66289b2c7c687773922bd2ee1e261e2b74b1e0fe..d2a9b346238089e85aa00f815f10fb7d15cfaf59 100644 (file)
@@ -31,9 +31,9 @@
  *                           server.
  *   cupsSetDests2()       - Save the list of destinations for the specified
  *                           server.
+ *   appleCopyNetwork()    - Get the network ID for the current location.
  *   appleGetDefault()     - Get the default printer for this location.
  *   appleGetLocations()   - Get the location history array.
- *   appleGetNetwork()     - Get the network ID for the current location.
  *   appleGetPrinter()     - Get a printer from the history array.
  *   appleSetDefault()     - Set the default printer for this location.
  *   appleUseLastPrinter() - Get the default printer preference value.
@@ -73,9 +73,9 @@
  */
 
 #ifdef __APPLE__
+static CFStringRef appleCopyNetwork(void);
 static char    *appleGetDefault(char *name, int namesize);
 static CFArrayRef appleGetLocations(void);
-static CFStringRef appleGetNetwork(void);
 static CFStringRef appleGetPrinter(CFArrayRef locations, CFStringRef network,
                                   CFIndex *locindex);
 static void    appleSetDefault(const char *name);
@@ -929,6 +929,44 @@ cupsSetDests2(http_t      *http,   /* I - Connection to server or @code CUPS_HTTP_
 
 
 #ifdef __APPLE__
+/*
+ * 'appleCopyNetwork()' - Get the network ID for the current location.
+ */
+
+static CFStringRef                     /* O - Network ID */
+appleCopyNetwork(void)
+{
+  SCDynamicStoreRef    dynamicStore;   /* System configuration data */
+  CFStringRef          key;            /* Current network configuration key */
+  CFDictionaryRef      ip_dict;        /* Network configuration data */
+  CFStringRef          network = NULL; /* Current network ID */
+  
+
+  if ((dynamicStore = SCDynamicStoreCreate(NULL, CFSTR("Printing"), NULL,
+                                           NULL)) != NULL)
+  {
+    if ((key = SCDynamicStoreKeyCreateNetworkGlobalEntity(
+                   NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4)) != NULL)
+    {
+      if ((ip_dict = SCDynamicStoreCopyValue(dynamicStore, key)) != NULL)
+      {
+       if ((network = CFDictionaryGetValue(ip_dict,
+                                           kSCPropNetIPv4Router)) != NULL)
+          CFRetain(network);
+
+        CFRelease(ip_dict);
+      }
+
+      CFRelease(key);
+    }
+
+    CFRelease(dynamicStore);
+  }
+
+  return (network);
+}
+
+
 /*
  * 'appleGetDefault()' - Get the default printer for this location.
  */
@@ -957,7 +995,7 @@ appleGetDefault(char *name,         /* I - Name buffer */
   * Get the current location...
   */
 
-  if ((network = appleGetNetwork()) == NULL)
+  if ((network = appleCopyNetwork()) == NULL)
   {
     DEBUG_puts("appleGetDefault: Unable to get current network...");
     return (NULL);
@@ -980,6 +1018,8 @@ appleGetDefault(char *name,                /* I - Name buffer */
 
     DEBUG_puts("appleGetDefault: Missing or bad location history array...");
 
+    CFRelease(network);
+
     return (NULL);
   }
   
@@ -991,6 +1031,8 @@ appleGetDefault(char *name,                /* I - Name buffer */
   else
     name[0] = '\0';
 
+  CFRelease(network);
+
   DEBUG_printf(("appleGetDefault: Returning \"%s\"...\n", name));
 
   return (*name ? name : NULL);
@@ -1025,44 +1067,6 @@ appleGetLocations(void)
 }
 
 
-/*
- * 'appleGetNetwork()' - Get the network ID for the current location.
- */
-
-static CFStringRef                     /* O - Network ID */
-appleGetNetwork(void)
-{
-  SCDynamicStoreRef    dynamicStore;   /* System configuration data */
-  CFStringRef          key;            /* Current network configuration key */
-  CFDictionaryRef      ip_dict;        /* Network configuration data */
-  CFStringRef          network = NULL; /* Current network ID */
-  
-
-  if ((dynamicStore = SCDynamicStoreCreate(NULL, CFSTR("Printing"), NULL,
-                                           NULL)) != NULL)
-  {
-    if ((key = SCDynamicStoreKeyCreateNetworkGlobalEntity(
-                   NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4)) != NULL)
-    {
-      if ((ip_dict = SCDynamicStoreCopyValue(dynamicStore, key)) != NULL)
-      {
-       if ((network = CFDictionaryGetValue(ip_dict,
-                                           kSCPropNetIPv4Router)) != NULL)
-          CFRetain(network);
-
-        CFRelease(ip_dict);
-      }
-
-      CFRelease(key);
-    }
-
-    CFRelease(dynamicStore);
-  }
-
-  return (network);
-}
-
-
 /*
  * 'appleGetPrinter()' - Get a printer from the history array.
  */
@@ -1122,7 +1126,7 @@ appleSetDefault(const char *name) /* I - Default printer/class name */
   * Get the current location...
   */
 
-  if ((network = appleGetNetwork()) == NULL)
+  if ((network = appleCopyNetwork()) == NULL)
   {
     DEBUG_puts("appleSetDefault: Unable to get current network...");
     return;
@@ -1202,6 +1206,7 @@ appleSetDefault(const char *name) /* I - Default printer/class name */
       CFRelease(newlocation);
   }
 
+  CFRelease(network);
   CFRelease(newprinter);
 }
 
index d0e1cf2fa6061fc12c34f310a440484b20d5559b..c6f7ddac3e0af5c37985584cfae6018b3c59fec1 100644 (file)
@@ -15,6 +15,7 @@
  *
  * Contents:
  *
+ *   cupsGetDevices() - Get available printer devices.
  */
 
 /*
@@ -50,6 +51,7 @@ cupsGetDevices(
   const char   *device_class,          /* device-class value */
                *device_id,             /* device-id value */
                *device_info,           /* device-info value */
+               *device_location,       /* device-location value */
                *device_make_and_model, /* device-make-and-model value */
                *device_uri;            /* device-uri value */
   int          blocking;               /* Current blocking-IO mode */
@@ -160,6 +162,7 @@ cupsGetDevices(
   device_class          = NULL;
   device_id             = NULL;
   device_info           = NULL;
+  device_location       = "";
   device_make_and_model = NULL;
   device_uri            = NULL;
   attr                  = NULL;
@@ -192,11 +195,13 @@ cupsGetDevices(
         if (device_class && device_id && device_info && device_make_and_model &&
            device_uri)
           (*callback)(device_class, device_id, device_info,
-                     device_make_and_model, device_uri, user_data);
+                     device_make_and_model, device_uri, device_location,
+                     user_data);
 
        device_class          = NULL;
        device_id             = NULL;
        device_info           = NULL;
+       device_location       = "";
        device_make_and_model = NULL;
        device_uri            = NULL;
       }
@@ -209,6 +214,9 @@ cupsGetDevices(
       else if (!strcmp(attr->name, "device-info") &&
                attr->value_tag == IPP_TAG_TEXT)
         device_info = attr->values[0].string.text;
+      else if (!strcmp(attr->name, "device-location") &&
+               attr->value_tag == IPP_TAG_TEXT)
+        device_location = attr->values[0].string.text;
       else if (!strcmp(attr->name, "device-make-and-model") &&
                attr->value_tag == IPP_TAG_TEXT)
         device_make_and_model = attr->values[0].string.text;
@@ -225,7 +233,7 @@ cupsGetDevices(
   if (device_class && device_id && device_info && device_make_and_model &&
       device_uri)
     (*callback)(device_class, device_id, device_info,
-               device_make_and_model, device_uri, user_data);
+               device_make_and_model, device_uri, device_location, user_data);
 
  /*
   * Set the IPP status and return...
@@ -235,7 +243,7 @@ cupsGetDevices(
   httpFlush(http);
 
   if (status == IPP_ERROR)
-    _cupsSetError(IPP_ERROR, NULL);
+    _cupsSetError(IPP_ERROR, NULL, 0);
   else
   {
     attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
@@ -245,8 +253,8 @@ cupsGetDevices(
                  attr ? attr->values[0].string.text : ""));
 
     _cupsSetError(response->request.status.status_code,
-                  attr ? attr->values[0].string.text :
-                      ippErrorString(response->request.status.status_code));
+                 attr ? attr->values[0].string.text :
+                     ippErrorString(response->request.status.status_code), 0);
   }
 
   ippDelete(response);
index d098e868e6ba88047ca0cbc975eaa77dde03ff68..f2ae63b972cf42d1c6800b13529ee0c1bdda7884 100644 (file)
@@ -136,7 +136,8 @@ typedef struct _cups_globals_s              /**** CUPS global state data ****/
 extern http_t          *_cupsConnect(void);
 extern const char      *_cupsGetPassword(const char *prompt);
 extern _cups_globals_t *_cupsGlobals(void);
-extern void            _cupsSetError(ipp_status_t status, const char *message);
+extern void            _cupsSetError(ipp_status_t status, const char *message,
+                                     int localize);
 extern void            _cupsSetHTTPError(http_status_t status);
 
 
index 84956888c2283db51809ad9effdf727aede0c0cb..059e9983f19c3e0c5a8c80b7f8cdc3682b921648 100644 (file)
  *
  * Contents:
  *
- *   _cupsLangPrintf() - Print a formatted message string to a file.
- *   _cupsLangPuts()   - Print a static message string to a file.
- *   _cupsSetLocale()  - Set the current locale and transcode the command-line.
+ *   _cupsLangPrintError() - Print a message followed by a standard error.
+ *   _cupsLangPrintf()     - Print a formatted message string to a file.
+ *   _cupsLangPuts()       - Print a static message string to a file.
+ *   _cupsSetLocale()      - Set the current locale and transcode the
+ *                           command-line.
  */
 
 /*
index 8f34b3ccc157a3dfafbfbdc4a04c6640877040d2..3da3642b039362ca0b18852a68ceb3710c23a858 100644 (file)
@@ -86,6 +86,7 @@ _cupsArrayUserData
 _cupsBackChannelRead
 _cupsBackChannelWrite
 _cupsBackendDeviceURI
+_cupsBackendReport
 _cupsCancelJob
 _cupsCancelJob2
 _cupsCharsetToUTF8
index 75db5c5acf87912018119ef9ed80f8b6de818cd7..e88dad15b7f78b1289596fa543ea152a7d10e8af 100644 (file)
@@ -1050,14 +1050,15 @@ ppdOpen2(cups_file_t *fp)               /* I - File to read from */
        * Add the "custom" option...
        */
 
-       if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
-       {
-         DEBUG_puts("Unable to add Custom choice!");
+        if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
+         if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
+         {
+           DEBUG_puts("Unable to add Custom choice!");
 
-         cg->ppd_status = PPD_ALLOC_ERROR;
+           cg->ppd_status = PPD_ALLOC_ERROR;
 
-         goto error;
-       }
+           goto error;
+         }
 
        strlcpy(choice->text, text[0] ? text : _("Custom"),
                sizeof(choice->text));
@@ -1089,14 +1090,15 @@ ppdOpen2(cups_file_t *fp)               /* I - File to read from */
 
         if (custom_option)
        {
-         if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
-         {
-           DEBUG_puts("Unable to add Custom choice!");
+         if ((choice = ppdFindChoice(custom_option, "Custom")) == NULL)
+           if ((choice = ppd_add_choice(custom_option, "Custom")) == NULL)
+           {
+             DEBUG_puts("Unable to add Custom choice!");
 
-           cg->ppd_status = PPD_ALLOC_ERROR;
+             cg->ppd_status = PPD_ALLOC_ERROR;
 
-           goto error;
-         }
+             goto error;
+           }
 
          strlcpy(choice->text, text[0] ? text : _("Custom"),
                  sizeof(choice->text));
@@ -1301,14 +1303,15 @@ ppdOpen2(cups_file_t *fp)               /* I - File to read from */
 
       if ((custom_attr = ppdFindAttr(ppd, custom_name, "True")) != NULL)
       {
-       if ((choice = ppd_add_choice(option, "Custom")) == NULL)
-       {
-         DEBUG_puts("Unable to add Custom choice!");
+        if ((choice = ppdFindChoice(option, "Custom")) == NULL)
+         if ((choice = ppd_add_choice(option, "Custom")) == NULL)
+         {
+           DEBUG_puts("Unable to add Custom choice!");
 
-         cg->ppd_status = PPD_ALLOC_ERROR;
+           cg->ppd_status = PPD_ALLOC_ERROR;
 
-         goto error;
-       }
+           goto error;
+         }
 
        strlcpy(choice->text,
                custom_attr->text[0] ? custom_attr->text : _("Custom"),
index f8978a6278a6490c0a434c9a0f047912f510f54f..fc6a7fa1822849addd0e3e8f51c3e20ffa1d7580 100644 (file)
@@ -80,7 +80,7 @@ cupsDoFileRequest(http_t     *http,   /* I - Connection to server or @code CUPS_HT
       */
 
       _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
-                    strerror(errno));
+                    NULL, 0);
 
       ippDelete(request);
 
@@ -143,7 +143,7 @@ cupsDoIORequest(http_t     *http,   /* I - Connection to server or @code CUPS_HTTP
   {
     ippDelete(request);
 
-    _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL));
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
 
     return (NULL);
   }
@@ -169,7 +169,7 @@ cupsDoIORequest(http_t     *http,   /* I - Connection to server or @code CUPS_HTTP
       */
 
       _cupsSetError(errno == EBADF ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
-                    strerror(errno));
+                    NULL, 0);
 
       ippDelete(request);
 
@@ -188,7 +188,7 @@ cupsDoIORequest(http_t     *http,   /* I - Connection to server or @code CUPS_HTTP
 
       ippDelete(request);
 
-      _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR));
+      _cupsSetError(IPP_NOT_POSSIBLE, strerror(EISDIR), 0);
 
       return (NULL);
     }
@@ -395,7 +395,7 @@ cupsGetResponse(http_t     *http,   /* I - Connection to server or @code CUPS_HTTP
       ippDelete(response);
       response = NULL;
 
-      _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno));
+      _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
     }
   }
   else if (status != HTTP_ERROR)
@@ -453,8 +453,8 @@ cupsGetResponse(http_t     *http,   /* I - Connection to server or @code CUPS_HTTP
                   attr ? attr->values[0].string.text : ""));
 
     _cupsSetError(response->request.status.status_code,
-                   attr ? attr->values[0].string.text :
-                      ippErrorString(response->request.status.status_code));
+                  attr ? attr->values[0].string.text :
+                     ippErrorString(response->request.status.status_code), 0);
   }
   else if (status != HTTP_OK)
     _cupsSetHTTPError(status);
@@ -492,7 +492,7 @@ cupsReadResponseData(
 
     if ((http = cg->http) == NULL)
     {
-      _cupsSetError(IPP_INTERNAL_ERROR, "No active connection");
+      _cupsSetError(IPP_INTERNAL_ERROR, _("No active connection"), 1);
       return (-1);
     }
   }
@@ -542,7 +542,7 @@ cupsSendRequest(http_t     *http,   /* I - Connection to server or @code CUPS_HTTP
 
   if (!request || !resource)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL));
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
 
     return (HTTP_ERROR);
   }
@@ -724,7 +724,7 @@ cupsWriteRequestData(
 
     if ((http = cg->http) == NULL)
     {
-      _cupsSetError(IPP_INTERNAL_ERROR, "No active connection");
+      _cupsSetError(IPP_INTERNAL_ERROR, _("No active connection"), 1);
       return (HTTP_ERROR);
     }
   }
@@ -753,26 +753,49 @@ cupsWriteRequestData(
 
 void
 _cupsSetError(ipp_status_t status,     /* I - IPP status code */
-               const char   *message)  /* I - status-message value */
+              const char   *message,   /* I - status-message value */
+             int          localize)    /* I - Localize the message? */
 {
   _cups_globals_t      *cg;            /* Global data */
 
 
+  if (!message && errno)
+  {
+    message  = strerror(errno);
+    localize = 0;
+  }
+
   cg             = _cupsGlobals();
   cg->last_error = status;
 
   if (cg->last_status_message)
   {
-    free(cg->last_status_message);
+    _cupsStrFree(cg->last_status_message);
 
     cg->last_status_message = NULL;
   }
 
   if (message)
-    cg->last_status_message = strdup(message);
+  {
+    if (localize)
+    {
+     /*
+      * Get the message catalog...
+      */
+
+      if (!cg->lang_default)
+       cg->lang_default = cupsLangDefault();
+
+      cg->last_status_message = _cupsStrAlloc(_cupsLangString(cg->lang_default,
+                                                              message));
+    }
+    else
+      cg->last_status_message = _cupsStrAlloc(message);
+  }
 
   DEBUG_printf(("_cupsSetError: last_error=%s, last_status_message=\"%s\"\n",
-                ippErrorString(cg->last_error), message ? message : ""));
+                ippErrorString(cg->last_error),
+               cg->last_status_message ? cg->last_status_message : ""));
 }
 
 
@@ -786,37 +809,37 @@ _cupsSetHTTPError(http_status_t status)   /* I - HTTP status code */
   switch (status)
   {
     case HTTP_NOT_FOUND :
-       _cupsSetError(IPP_NOT_FOUND, httpStatus(status));
+       _cupsSetError(IPP_NOT_FOUND, httpStatus(status), 0);
        break;
 
     case HTTP_UNAUTHORIZED :
-       _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status));
+       _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status), 0);
        break;
 
     case HTTP_FORBIDDEN :
-       _cupsSetError(IPP_FORBIDDEN, httpStatus(status));
+       _cupsSetError(IPP_FORBIDDEN, httpStatus(status), 0);
        break;
 
     case HTTP_BAD_REQUEST :
-       _cupsSetError(IPP_BAD_REQUEST, httpStatus(status));
+       _cupsSetError(IPP_BAD_REQUEST, httpStatus(status), 0);
        break;
 
     case HTTP_REQUEST_TOO_LARGE :
-       _cupsSetError(IPP_REQUEST_VALUE, httpStatus(status));
+       _cupsSetError(IPP_REQUEST_VALUE, httpStatus(status), 0);
        break;
 
     case HTTP_NOT_IMPLEMENTED :
-       _cupsSetError(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status));
+       _cupsSetError(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status), 0);
        break;
 
     case HTTP_NOT_SUPPORTED :
-       _cupsSetError(IPP_VERSION_NOT_SUPPORTED, httpStatus(status));
+       _cupsSetError(IPP_VERSION_NOT_SUPPORTED, httpStatus(status), 0);
        break;
 
     default :
        DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
                      status));
-       _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
+       _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status), 0);
        break;
   }
 }
index 943e390e17a84deb9b3e768df96e2ebd84a3246e..cfd872d2910074e9d2fe8a57735644b8963c40e3 100644 (file)
@@ -602,7 +602,14 @@ main(int  argc,                            /* I - Number of command-line arguments */
 
 
     if (!strncmp(argv[1], "-d", 2))
+    {
       filename = cupsGetPPD(argv[1] + 2);
+      if (!filename)
+      {
+        printf("%s: %s\n", argv[1], cupsLastErrorString());
+        return (1);
+      }
+    }
     else
       filename = argv[1];
 
index 605cd89e80555fa406e2f34b2d98f2815de94d54..f52bbe7f081e843a94b286fb47f822b750428db3 100644 (file)
@@ -131,7 +131,7 @@ cupsCancelJob2(http_t     *http,    /* I - Connection to server or @code CUPS_HTTP_
 
   if (job_id < -1 || (!name && job_id == 0))
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL));
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
     return (0);
   }
 
@@ -229,7 +229,7 @@ cupsCreateJob(
 
   if (!name)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
     return (0);
   }
 
@@ -239,7 +239,7 @@ cupsCreateJob(
 
   if ((request = ippNewRequest(IPP_CREATE_JOB)) == NULL)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(ENOMEM), 0);
     return (0);
   }
 
@@ -346,7 +346,7 @@ cupsGetClasses(char ***classes)             /* O - Classes */
 
   if (!classes)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
 
     return (0);
   }
@@ -596,7 +596,7 @@ cupsGetJobs2(http_t     *http,              /* I - Connection to server or @code CUPS_HTTP_D
 
   if (!jobs)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
 
     return (-1);
   }
@@ -610,7 +610,7 @@ cupsGetJobs2(http_t     *http,              /* I - Connection to server or @code CUPS_HTTP_D
     if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
                          "localhost", 0, "/printers/%s", name) != HTTP_URI_OK)
     {
-      _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+      _cupsSetError(IPP_INTERNAL_ERROR, _("Unable to create printer-uri!"), 1);
 
       return (-1);
     }
@@ -764,7 +764,7 @@ cupsGetJobs2(http_t     *http,              /* I - Connection to server or @code CUPS_HTTP_D
         * Ran out of memory!
         */
 
-        _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+        _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
 
        cupsFreeJobs(n, *jobs);
        *jobs = NULL;
@@ -921,19 +921,19 @@ cupsGetPPD3(http_t     *http,             /* I  - HTTP connection or @code CUPS_HTTP_DEFAUL
 
   if (!name)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, "No printer name!");
+    _cupsSetError(IPP_INTERNAL_ERROR, _("No printer name!"), 1);
     return (HTTP_NOT_ACCEPTABLE);
   }
 
   if (!modtime)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, "No modification time!");
+    _cupsSetError(IPP_INTERNAL_ERROR, _("No modification time!"), 1);
     return (HTTP_NOT_ACCEPTABLE);
   }
 
   if (!buffer || bufsize <= 1)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, "Bad filename buffer!");
+    _cupsSetError(IPP_INTERNAL_ERROR, _("Bad filename buffer!"), 1);
     return (HTTP_NOT_ACCEPTABLE);
   }
 
@@ -1010,7 +1010,7 @@ cupsGetPPD3(http_t     *http,             /* I  - HTTP connection or @code CUPS_HTTP_DEFAUL
     * Can't open file; close the server connection and return NULL...
     */
 
-    _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+    _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
 
     if (http2 != http)
       httpClose(http2);
@@ -1043,17 +1043,17 @@ cupsGetPPD3(http_t     *http,           /* I  - HTTP connection or @code CUPS_HTTP_DEFAUL
     switch (status)
     {
       case HTTP_NOT_FOUND :
-          _cupsSetError(IPP_NOT_FOUND, httpStatus(status));
+          _cupsSetError(IPP_NOT_FOUND, httpStatus(status), 0);
          break;
 
       case HTTP_UNAUTHORIZED :
-          _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status));
+          _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status), 0);
          break;
 
       default :
          DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n",
                        status));
-         _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
+         _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status), 0);
          break;
     }
 
@@ -1096,7 +1096,7 @@ cupsGetPrinters(char ***printers) /* O - Printers */
 
   if (!printers)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
 
     return (0);
   }
@@ -1208,7 +1208,7 @@ cupsGetServerPPD(http_t     *http,        /* I - Connection to server or @code CUPS_HTT
 
   if (!name)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, "No PPD name!");
+    _cupsSetError(IPP_INTERNAL_ERROR, _("No PPD name!"), 1);
 
     return (NULL);
   }
@@ -1227,7 +1227,7 @@ cupsGetServerPPD(http_t     *http,        /* I - Connection to server or @code CUPS_HTT
     * Can't open file; close the server connection and return NULL...
     */
 
-    _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+    _cupsSetError(IPP_INTERNAL_ERROR, NULL, 0);
 
     return (NULL);
   }
@@ -1388,7 +1388,7 @@ cupsPrintFiles2(
 
   if (!name || num_files < 1 || !files)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(EINVAL), 0);
 
     return (0);
   }
@@ -1490,7 +1490,7 @@ cupsStartDocument(
 
   if ((request = ippNewRequest(IPP_SEND_DOCUMENT)) == NULL)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, NULL);
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(ENOMEM), 0);
     return (0);
   }
 
@@ -1583,8 +1583,13 @@ _cupsConnect(void)
   {
     if ((cg->http = httpConnectEncrypt(cupsServer(), ippPort(),
                                        cupsEncryption())) == NULL)
-      _cupsSetError(IPP_SERVICE_UNAVAILABLE,
-                    errno ? strerror(errno) : "Unable to connect to host.");
+    {
+      if (errno)
+        _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
+      else
+        _cupsSetError(IPP_SERVICE_UNAVAILABLE,
+                     _("Unable to connect to host."), 1);
+    }
   }
 
  /*
@@ -1642,7 +1647,7 @@ cups_get_printer_uri(
   if (httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
                        "localhost", 0, "/printers/%s", name) != HTTP_URI_OK)
   {
-    _cupsSetError(IPP_INTERNAL_ERROR, "Unable to create printer-uri!");
+    _cupsSetError(IPP_INTERNAL_ERROR, _("Unable to create printer-uri!"), 1);
 
     *host     = '\0';
     *resource = '\0';
@@ -1777,7 +1782,8 @@ cups_get_printer_uri(
 
       if (!strncmp(resource, "/classes/", 9))
       {
-        _cupsSetError(IPP_INTERNAL_ERROR, _("No printer-uri found for class!"));
+        _cupsSetError(IPP_INTERNAL_ERROR,
+                     _("No printer-uri found for class!"), 1);
 
        *host     = '\0';
        *resource = '\0';
@@ -1792,7 +1798,7 @@ cups_get_printer_uri(
   }
 
   if (cupsLastError() != IPP_NOT_FOUND)
-    _cupsSetError(IPP_INTERNAL_ERROR, _("No printer-uri found!"));
+    _cupsSetError(IPP_INTERNAL_ERROR, _("No printer-uri found!"), 1);
 
   *host     = '\0';
   *resource = '\0';
index 659d55bef6835ae98e33f8f65acc80a95a301922..96972ee747c118d8b7e1ad441bd52b0400f14925 100644 (file)
@@ -3,7 +3,7 @@
  *
  *   API versioning definitions for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 2007 by Apple Inc.
+ *   Copyright 2007-2008 by Apple Inc.
  *
  *   These coded instructions, statements, and computer programs are the
  *   property of Apple Inc. and are protected by Federal copyright
  * _CUPS_API_1_1, _CUPS_API_1_1_19, _CUPS_API_1_1_20, _CUPS_API_1_1_21,
  * _CUPS_API_1_2, _CUPS_API_1_3, _CUPS_API_1_4 - which add compiler-
  * specific attributes that flag functions that are deprecated or added
- * in particular releases.  On Mac OS X, the _CUPS_API_* constants are
- * defined based on the value of the MAC_OS_X_VERSION_MAX_ALLOWED constant
+ * in particular releases.
+ *
+ * On Mac OS X, the _CUPS_API_* constants are defined based on the values of
+ * the MAC_OS_X_VERSION_MIN_ALLOWED and MAC_OS_X_VERSION_MAX_ALLOWED constants
  * provided by the compiler.
  */
 
 #  if defined(__APPLE__) && !defined(_CUPS_SOURCE)
-#    if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_3
-#      define _CUPS_API_1_1_19 __attribute__((unavailable))
-#      define _CUPS_API_1_1_20 __attribute__((unavailable))
-#      define _CUPS_API_1_1_21 __attribute__((unavailable))
-#      define _CUPS_API_1_2 __attribute__((unavailable))
-#      define _CUPS_API_1_3 __attribute__((unavailable))
-#      define _CUPS_API_1_4 __attribute__((unavailable))
-#    elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_4
-#      define _CUPS_API_1_1_19
-#      define _CUPS_API_1_1_20 __attribute__((unavailable))
-#      define _CUPS_API_1_1_21 __attribute__((unavailable))
-#      define _CUPS_API_1_2 __attribute__((unavailable))
-#      define _CUPS_API_1_3 __attribute__((unavailable))
-#      define _CUPS_API_1_4 __attribute__((unavailable))
-#    elif MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
-#      define _CUPS_API_1_1_19
-#      define _CUPS_API_1_1_20
-#      define _CUPS_API_1_1_21
-#      define _CUPS_API_1_2 __attribute__((unavailable))
-#      define _CUPS_API_1_3 __attribute__((unavailable))
-#      define _CUPS_API_1_4 __attribute__((unavailable))
-#    elif MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5
-#      define _CUPS_API_1_1_19
-#      define _CUPS_API_1_1_20
-#      define _CUPS_API_1_1_21
-#      define _CUPS_API_1_2
-#      define _CUPS_API_1_3
-#      define _CUPS_API_1_4 __attribute__((unavailable))
-#    else
-#      define _CUPS_API_1_1_19
-#      define _CUPS_API_1_1_20
-#      define _CUPS_API_1_1_21
-#      define _CUPS_API_1_2
-#      define _CUPS_API_1_3
-#      define _CUPS_API_1_4
-#    endif /* MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_x */
+#    include <AvailabilityMacros.h>
+#    ifndef AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#      define AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER __attribute__((unavailable))
+#    endif /* !AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER */
+#    ifndef AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#      define AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER __attribute__((unavailable))
+#    endif /* !AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER */
+#    ifndef AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#      define AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER __attribute__((unavailable))
+#    endif /* !AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER */
+#    ifndef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+#      define AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER __attribute__((unavailable))
+#    endif /* !AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER */
+#    define _CUPS_API_1_1_19 AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER
+#    define _CUPS_API_1_1_20 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#    define _CUPS_API_1_1_21 AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER
+#    define _CUPS_API_1_2 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#    define _CUPS_API_1_3 AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER
+#    define _CUPS_API_1_4 AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
 #  else
 #    define _CUPS_API_1_1_19
 #    define _CUPS_API_1_1_20
index 637f3d885beacd4d24e9ad6af405e756e069877e..7588d11496ac2f0408bf87e0c2caa522bbe5c629 100644 (file)
@@ -204,6 +204,12 @@ TH.label {
   vertical-align: top;
 }
 
+TH.sublabel {
+  padding-top: 0pt;
+  text-align: right;
+  font-weight: normal;
+}
+
 HR {
   border: solid thin;
 }
index 83c5fe8f08ac02813d026e24e87f4d4799314165..d3075811842869413415a36bc54399fc2a9a9e5c 100644 (file)
@@ -5,20 +5,43 @@
 </HEAD>
 <BODY>
 
-<P>CUPS 1.3 adds Kerberos support which allows you to use a Key Distribution
-Center (KDC) for authentication on your local CUPS server and when printing
-to a remote authenticated queue. This document describes how to configure
-CUPS to use Kerberos authentication and provides helpful links to the MIT
-help pages for configuring Kerberos on your systems and network.</P>
+<P>CUPS allows you to use a Key Distribution Center (KDC) for authentication
+on your local CUPS server and when printing to a remote authenticated queue.
+This document describes how to configure CUPS to use Kerberos authentication
+and provides links to the MIT help pages for configuring Kerberos on your
+systems and network.</P>
 
-<BLOCKQUOTE><B>Note:</B>
 
-<P>In order to use Kerberos-authenticated shared printers, you <EM>must</EM> be
-running a version of MIT Kerberos with the <TT>krb5_cc_new_unique()</TT>
-function or Heimdal Kerberos. Otherwise, only local Kerberos authentication
-is supported.</P>
+<H2 CLASS="title"><A NAME="REQUIREMENTS">System Requirements</A></H2>
 
-</BLOCKQUOTE>
+<p>The following are required to use Kerberos with CUPS:</p>
+
+<ol>
+
+       <li>Heimdal Kerberos (any version) or MIT Kerberos (1.6.3 or newer)</li>
+
+       <li>Properly configured Domain Name System (DNS)
+       infrastructure:<ol type='a'>
+               <li>DNS server(s) with static IP addresses for all CUPS clients
+               and servers or configured to allow DHCP updates to the host
+               addresses</li>
+               <li>All CUPS clients and servers configured to use the same
+               DNS server(s)</li>
+       </ol></li>
+
+       <li>Properly configured Kerberos infrastructure:<ol type='a'>
+               <li>KDC configured to allow CUPS clients and servers to obtain
+               Service Granting Tickets (SGTs) for the "ipp" service</li>
+               <li>LDAP-based user accounts - both OpenDirectory and
+               ActiveDirectory provide this with the KDC</li>
+               <li>CUPS clients and servers bound to the KDC and LDAP
+               server(s)</li>
+       </ol></li>
+
+       <li>An "ipp" Service Granting Ticket (SGT) for every CUPS client and
+       server</li>
+
+</ol>
 
 
 <H2 CLASS="title"><A NAME="KRB5">Configuring Kerberos on Your System</A></H2>
@@ -68,80 +91,29 @@ Settings</VAR>:</P>
 http://localhost:631/admin
 </PRE>
 
-<P>After you have enabled Kerberos authentication, add <tt>AuthType Default</tt>
-lines to the policies you want to protect with authentication, for example:</P>
-
-<PRE CLASS="command">
-<EM>Listing 1: <A NAME="LISTING01">Remote Printer Operation Policy</A></EM>
-
- 1    &lt;Policy remote>
- 2      # Job-related operations must be done by the owner or an
-      administrator...
- 3      &lt;Limit Send-Document Send-URI Hold-Job Release-Job
-      Restart-Job Purge-Jobs Set-Job-Attributes
-      Create-Job-Subscription Renew-Subscription
-      Cancel-Subscription Get-Notifications Reprocess-Job
-      Cancel-Current-Job Suspend-Current-Job Resume-Job
-      CUPS-Move-Job>
- 4        AuthType Default
- 5        Require user @OWNER @SYSTEM
- 6        Order deny,allow
- 7      &lt;/Limit>
- 8
- 9      # Require authentication when creating jobs
-10      &lt;Limit Create-Job Print-Job Print-URI>
-11        AuthType Default
-12        Require valid-user
-13        Order deny,allow
-14      &lt;/Limit>
-15
-16      # All administration operations require an administrator
-      to authenticate...
-17      &lt;Limit CUPS-Add-Printer CUPS-Delete-Printer
-      CUPS-Add-Class CUPS-Delete-Class CUPS-Set-Default>
-18        AuthType Default
-19        Require user @SYSTEM
-20        Order deny,allow
-21      &lt;/Limit>
-22    
-23      # All printer operations require a printer operator
-      to authenticate...
-24      &lt;Limit Pause-Printer Resume-Printer
-      Set-Printer-Attributes 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>
-25        AuthType Default
-26        Require user <em>varies by OS</em>
-27        Order deny,allow
-28      &lt;/Limit>
-29    
-30      # Only the owner or an administrator can cancel or
-      authenticate a job...
-31      &lt;Limit Cancel-Job CUPS-Authenticate-Job>
-32        Require user @OWNER @SYSTEM
-33        Order deny,allow
-34      &lt;/Limit>
-35    
-36      &lt;Limit All>
-37        Order deny,allow
-38      &lt;/Limit>
-39    &lt;/Policy>
-</PRE>
+<P>After you have enabled Kerberos authentication, use the built-in
+"authenticated" policy or your own custom policies with the printers you
+will be sharing. See <a href="policies.html">Managing Operation Policies</a>
+for more information.</P>
 
 
 <H2 CLASS="title"><A NAME="IMPLEMENT">Implementation Information</A></H2>
 
-<P>CUPS implements Kerberos over HTTP using GSS API and the service name
-"ipp". Delegation of credentials, which is needed when printing to a
-remote/shared printer with Kerberos authentication, is currently only supported
-when using a single KDC on your network.</P>
-
-<P>After getting a user's Kerberos credentials, CUPS strips the "@KDC"
-portion of the username so that it can check the group membership locally,
-effectively treating the Kerberos account as a local user account.</P>
+<P>CUPS implements Kerberos over HTTP using GSSAPI and the service name
+"ipp". Because of limitations in the HTTP GSSAPI protocol extension, only
+a single domain/KDC is supported for authentication.</P>
+
+<P>When doing printing tasks that require authentication, CUPS requests a
+single-use "ticket" from your login session to authenticate who you are.
+This ticket gives CUPS a username of the form "user@REALM", which is then
+converted to just "user" for purposes of user and group checks.</P>
+
+<P>In order to support printing to a shared printer, CUPS has to ask the KDC
+for a copy of your credentials (this is called delegation) that can be sent to
+the remote server for authenticatation. Delegation only works when the system
+has a stable hostname which maps to the current address of the system, which
+is why you need a static IP address or DHCP that updates the DNS entry for your
+system.</P>
 
 </BODY>
 </HTML>
index 8ad4ffada25605a991bc1ab44714cd54bdb9a512..c2d37220c2e6c12a30fa62b44cd5e40e34d28f2f 100644 (file)
@@ -720,76 +720,6 @@ at half its natural size. If the specified scaling makes the
 image larger than the page, multiple pages will be printed to
 satisfy the request.
 
-<H3><A NAME="hue">Adjusting Image Hue (Tint)</A></H3>
-
-<P>The <CODE>-o hue=value</CODE> option will adjust the hue of the
-printed image, much like the tint control on your television:
-
-<PRE CLASS="command">
-lp -o hue=<EM>value</EM> filename
-lpr -o hue=<EM>value</EM> filename
-</PRE>
-
-<P>The <CODE>value</CODE> argument is a number from -360 to 360 and represents
-the color hue rotation. The following table summarizes the change you'll see
-with different colors:</P>
-
-<DIV CLASS="table"><TABLE SUMMARY="Hue Values">
-<TR>
-       <TH>Original</TH>
-       <TH>hue=-45</TH>
-       <TH>hue=45</TH>
-</TR>
-<TR>
-       <TD>Red</TD>
-       <TD>Purple</TD>
-       <TD>Yellow-orange</TD>
-</TR>
-<TR>
-       <TD>Green</TD>
-       <TD>Yellow-green</TD>
-       <TD>Blue-green</TD>
-</TR>
-<TR>
-       <TD>Yellow</TD>
-       <TD>Orange</TD>
-       <TD>Green-yellow</TD>
-</TR>
-<TR>
-       <TD>Blue</TD>
-       <TD>Sky-blue</TD>
-       <TD>Purple</TD>
-</TR>
-<TR>
-       <TD>Magenta</TD>
-       <TD>Indigo</TD>
-       <TD>Crimson</TD>
-</TR>
-<TR>
-       <TD>Cyan</TD>
-       <TD>Blue-green</TD>
-       <TD>Light-navy-blue</TD>
-</TR>
-</TABLE></DIV>
-
-<P>The default hue adjustment is 0.
-
-<H3><A NAME="saturation">Adjusting Image Saturation (Color)</A></H3>
-
-<P>The <CODE>-o saturation=percent</CODE> option adjusts the saturation
-of the colors in an image, much like the color control on your television:</P>
-
-<PRE CLASS="command">
-lp -o saturation=<EM>percent</EM> filename
-lpr -o saturation=<EM>percent</EM> filename
-</PRE>
-
-<P>The <CODE>percent</CODE> argument specifies the color saturation
-from 0 to 200. A color saturation of 0 produces a black-and-white
-print, while a value of 200 will make the colors extremely intense.</P>
-
-<P>The default saturation is 100.</P>
-
 
 <H2 CLASS="title"><A NAME="HPGL2OPTIONS">HP-GL/2 Options</A></H2>
 
index 37ddc448a1dd9c36f768fbcd5a3095be5f6476af..9d5ca0e5ba65c6e46f0211712dcfe0b47394d1b8 100644 (file)
@@ -474,6 +474,20 @@ domain name to use when listening for printer registrations. The
 default is undefined.</P>
 
 
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.4</SPAN><A NAME="BrowseLDAPCACertFile">BrowseLDAPCACertFile</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+BrowseLDAPCACertFile /etc/cups/ssl/certs
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>BrowseLDAPCACertFile</CODE> directive specifies the SSL certificate
+authority file to use for LDAP + SSL. The default is undefined.</P>
+
+
 <H2 CLASS="title"><SPAN CLASS="info">CUPS 1.2</SPAN><A NAME="BrowseLDAPDN">BrowseLDAPDN</A></H2>
 
 <H3>Examples</H3>
index a1c85a82538e206e1a13ec59c4b9b40e40937d38..63a5fe5a642ed48376695a45d6dce0aecbbb5b4b 100644 (file)
@@ -2043,9 +2043,14 @@ string for the device.</p>
 <p>The device-info attribute specifies a human-readable string describing
 the device, e.g. "Parallel Port #1".
 
+<h4><a name="device-location">device-location (text(127))</a><span class="info">CUPS 1.4</span></h4>
+
+<p>The device-location attribute specifies the physical location of the
+printer.
+
 <h4><a name="device-make-and-model">device-make-and-model (text(127))</a></h4>
 
-<p>The device-makr-and-model attribute specifies a device
+<p>The device-make-and-model attribute specifies a device
 identification string provided by the printer connected to the device.
 If the device or printer does not support identification then this
 attribute contains the string "unknown".
@@ -2108,7 +2113,7 @@ of the device-class attribute:
 rendered entirely in black ink (blackplot=true) or using the colors and shades
 specified in the file (blackplot=false). The default value is false.
 
-<h4><a name="brightness">brightness (integer(0:200))</a></h4>
+<h4><a name="brightness">brightness (integer(0:200))</a><span class="info">Deprecated</span></h4>
 
 <p>The brightness attribute specifies the overall brightness of the printed
 output in percent. A brightness of 100 is normal, while 200 is twice as
@@ -2117,6 +2122,13 @@ bright and 50 is half as bright. The default value is 100.
 <p>Brightness is applied to the Cyan, Magenta, Yellow, and Black values using
 the function "f(x) = brightness / 100 * x".
 
+<blockquote><b>Note:</b>
+
+<p>This attribute is deprecated and will be removed from a future CUPS
+release.</p>
+
+</blockquote>
+
 <h4><a name="columns">columns (integer(1:4))</a></h4>
 
 <p>The columns attribute specifies the number of columns to generate when
@@ -2139,7 +2151,7 @@ are present in the job.
 fit on the selected media (fitplot=true) or use the physical scale specified
 in the plot file (fitplot=false). The default value is false.
 
-<h4><a name="gamma">gamma (integer(1:10000))</a></h4>
+<h4><a name="gamma">gamma (integer(1:10000))</a><span class="info">Deprecated</span></h4>
 
 <p>The gamma attribute specifies the luminance correction for the output.
 A value of 1000 specifies no correction, while values of 2000 and 500 will
@@ -2147,13 +2159,27 @@ generate lighter and darker output, respectively. The default value is
 1000.
 
 <p>Gamma is applied to the Red, Green, and Blue values (or luminance for
-grayscale output) using the function "f(x) = x<SUp>(1000/gamma)</SUp>".
+grayscale output) using the function "f(x) = x<sup>(1000/gamma)</sup>".
+
+<blockquote><b>Note:</b>
+
+<p>This attribute is deprecated and will be removed from a future CUPS
+release.</p>
 
-<h4><a name="hue">hue (integer(-180:180))</a></h4>
+</blockquote>
+
+<h4><a name="hue">hue (integer(-180:180))</a><span class="info">Deprecated</span></h4>
 
 <p>The hue attribute specifies a color hue rotation when printing image
 files. The default value is 0.
 
+<blockquote><b>Note:</b>
+
+<p>This attribute is deprecated and will be removed from a future CUPS
+release.</p>
+
+</blockquote>
+
 <h4><a name="job-billing">job-billing (text(MAX))</a><span class='info'>CUPS 1.1</span></h4>
 
 <p>The job-billing attribute provides a text value to associate with a job
@@ -2344,13 +2370,20 @@ per inch. The default value is the resolution included with the file or
 with a shaded header and keyword highlighting (prettyprint=true) or without
 additional formatting (prettyprint=false). The default value is false.
 
-<h4><a name="saturation">saturation (integer(0:200))</a></h4>
+<h4><a name="saturation">saturation (integer(0:200))</a><span class="info">Deprecated</span></h4>
 
 <p>The saturation attribute specifies the color saturation when
 printing image files. A saturation of 100 is normal, while values of 50
 and 200 will be half and twice as colorful, respectively. The default
 value is 100.
 
+<blockquote><b>Note:</b>
+
+<p>This attribute is deprecated and will be removed from a future CUPS
+release.</p>
+
+</blockquote>
+
 <h4><a name="scaling">scaling (integer(1:1000))</a></h4>
 
 <p>The scaling attribute specifies the scaling of image files with
index 5a9865090c0fdfa52a80ba3802ec86a77efc3bb3..33254bd1428766b99e10c60431f27a6abe2587e1 100644 (file)
@@ -1022,6 +1022,96 @@ PRE B {
 </table></div>
 
 
+<h2 class='title'><a name='MEDIA'>Media Attributes</a></h2>
+
+<p>The CUPS media attributes allow drivers to specify alternate custom page
+size limits based on up to two options.</p>
+
+<h3><span class='info'>CUPS 1.4</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
+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</span><a name='cupsMediaQualifier3'>cupsMediaQualifier3</a></h3>
+
+<p class='summary'>*cupsMediaQualifier3: MainKeyword</p>
+
+<p>This attribute 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</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 attribute 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
+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</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 attribute 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
+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</span><a name='cupsBackSide'>cupsBackSide</a></h3>
@@ -1711,17 +1801,28 @@ the device.</p>
 
 <ul>
 
-       <li>Added <tt>cupsCommands</tt> attribute.</li>
+       <li>Added <a href='#cupsCommands'><tt>cupsCommands</tt></a>
+       attribute.</li>
 
-       <li>Added <tt>cupsMarkerName</tt> attribute.</li>
+       <li>Added <a href='#cupsMarkerName'><tt>cupsMarkerName</tt></a>
+       attribute.</li>
 
-       <li>Added <tt>cupsMarkerNotice</tt> attribute.</li>
+       <li>Added <a href='#cupsMarkerNotice'><tt>cupsMarkerNotice</tt></a>
+       attribute.</li>
 
-       <li>Added <tt>cupsPJLDisplay</tt> attribute.</li>
+       <li>Added <a href='#cupsPJLDisplay'><tt>cupsPJLDisplay</tt></a>
+       attribute.</li>
 
-       <li>Added <tt>cupsUIResolver</tt> and <tt>cupsUIConstraints</tt>
+       <li>Added <a href='#cupsUIResolver'><tt>cupsUIResolver</tt></a> and
+       <a href='#cupsUIConstraints'><tt>cupsUIConstraints</tt></a>
        attributes.</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>
+
 </ul>
 
 
@@ -1744,13 +1845,18 @@ the device.</p>
 
 <ul>
 
-       <li>Added <tt>cupsBackSide</tt> and deprecated <tt>cupsFlipDuplex</tt>.</li>
+       <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 <tt>cupsIPPReason</tt> documentation.</li>
+       <li>Added text URI information to
+       <a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> documentation.</li>
 
-       <li>Added <tt>APPrinterPreset</tt>, <tt>cupsIPPFinishings</tt>, and <tt>cupsPreFilter</tt> attributes.</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> attributes.</li>
 
-       <li>Added discussion of custom option code, sample <tt>CustomPageSize</tt> code, and "do not use dict and put" note.</li>
+       <li>Added discussion of custom option code, sample
+       <tt>CustomPageSize</tt> code, and "do not use dict and put" note.</li>
 
 </ul>
 
@@ -1771,17 +1877,18 @@ the device.</p>
 
        <li>Added custom option values support</li>
 
-       <li>Added <tt>APHelpBook</tt> attribute</li>
+       <li>Added <a href='#APHelpBook'><tt>APHelpBook</tt></a> attribute</li>
 
-       <li>Added <tt>APDuplexRequiresFlippedMargin</tt> attribute</li>
+       <li>Added <a href='#APDuplexRequiresFlippedMargin'><tt>APDuplexRequiresFlippedMargin</tt></a>
+       attribute</li>
 
-       <li>Added <tt>cupsICCProfile</tt> attribute</li>
+       <li>Added <a href='#cupsICCProfile'><tt>cupsICCProfile</tt></a> attribute</li>
 
-       <li>Added <tt>cupsIPPReason</tt> attribute</li>
+       <li>Added <a href='#cupsIPPReason'><tt>cupsIPPReason</tt></a> attribute</li>
 
-       <li>Added <tt>cupsLanguages</tt> attribute</li>
+       <li>Added <a href='#cupsLanguages'><tt>cupsLanguages</tt></a> attribute</li>
 
-       <li>Added <tt>cupsPortMonitor</tt> attribute</li>
+       <li>Added <a href='#cupsPortMonitor'><tt>cupsPortMonitor</tt></a> attribute</li>
 
        <li>Removed <tt>cupsProtocol</tt> attribute</li>
 
@@ -1791,7 +1898,7 @@ the device.</p>
 
 <ul>
 
-       <li>Added <tt>cupsFlipDuplex</tt> attribute</li>
+       <li>Added <a href='#cupsFlipDuplex'><tt>cupsFlipDuplex</tt></a> attribute</li>
 
        <li>Added <tt>cupsProtocol</tt> attribute</li>
 
diff --git a/init/cups.xml.in b/init/cups.xml.in
new file mode 100644 (file)
index 0000000..e47398a
--- /dev/null
@@ -0,0 +1,212 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+    Service manifest for CUPS.
+
+    This service manifest introduces smf(5) services for CUPS.  The services
+    described in this file are as follows:
+
+       svc:/application/cups/scheduler:default
+       svc:/application/cups/in-lpd:default
+
+    NOTE:  This service manifest is not editable; its contents will be
+    overwritten by package or patch operations, including operating system
+    upgrade.  Make customizations in a different file.
+
+    Norm.Jacobs@Sun.COM
+
+    $Id$
+-->
+
+<service_bundle type='manifest' name='SUNWcups:services'>
+
+<service
+    name='application/cups/scheduler'
+    type='service'
+    version='1'>
+
+    <dependency
+        name='filesystem_minimal'
+        grouping='require_all'
+        restart_on='none'
+        type='service'>
+        <service_fmri value='svc:/system/filesystem/minimal' />
+    </dependency>
+
+    <dependency
+        name='loopback'
+        grouping='optional_all'
+        restart_on='error'
+        type='service'>
+        <service_fmri value='svc:/network/loopback' />
+    </dependency>
+
+
+    <dependency
+        name='network'
+        grouping='optional_all'
+        restart_on='error'
+        type='service'>
+        <service_fmri value='svc:/milestone/network' />
+    </dependency>
+
+    <dependency
+        name='lpsched'
+        grouping='exclude_all'
+        restart_on='none'
+        type='service'>
+        <service_fmri value='svc:/application/print/server' />
+    </dependency>
+
+    <exec_method
+        type='method'
+        name='stop'
+        exec=':kill'
+        timeout_seconds='60' />
+
+    <instance name='default' enabled='false' >
+
+        <dependency
+            name='config_data'
+            grouping='require_all'
+            restart_on='none'
+            type='path'>
+            <service_fmri value='file://localhost@sysconfdir@/cups/cupsd.conf' />
+        </dependency>
+
+        <exec_method
+            type='method'
+            name='start'
+            exec='@sbindir@/cupsd'
+            timeout_seconds='60' >
+            <method_context>
+                <method_credential user='root' group='@CUPS_GROUP@' />
+            </method_context>
+        </exec_method>
+
+        <property_group name='general' type='framework'>
+            <propval name='action_authorization' type='astring'
+                value='solaris.smf.manage.cups' />
+            <propval name='value_authorization' type='astring'
+                value='solaris.smf.value.cups' />
+        </property_group>
+
+        <template>
+            <common_name>
+                <loctext xml:lang='C'>
+                    CUPS Print Spooler
+                </loctext>
+            </common_name>
+            <documentation>
+                <manpage title='cupsd' section='8'
+                    manpath='@mandir@' />
+            </documentation>
+        </template>
+
+    </instance>
+
+    <stability value='Stable' />
+
+</service>
+
+<service
+    name='application/cups/in-lpd'
+    type='service'
+    version='1'>
+
+    <dependency
+        name='filesystem_minimal'
+        grouping='require_all'
+        restart_on='none'
+        type='service'>
+        <service_fmri value='svc:/system/filesystem/minimal' />
+    </dependency>
+
+    <dependency
+        name='loopback'
+        grouping='require_any'
+        restart_on='error'
+        type='service'>
+        <service_fmri value='svc:/network/loopback' />
+    </dependency>
+
+    <dependency
+        name='network'
+        grouping='optional_all'
+        restart_on='error'
+        type='service'>
+        <service_fmri value='svc:/milestone/network' />
+    </dependency>
+
+    <dependency
+        name='in-lpd'
+        grouping='exclude_all'
+        restart_on='none'
+        type='service'>
+        <service_fmri value='svc:/application/print/rfc1179' />
+    </dependency>
+
+    <exec_method
+        type='method'
+        name='stop'
+        exec=':kill'
+        timeout_seconds='60' />
+
+    <instance name='default' enabled='false' >
+        <restarter>
+            <service_fmri value='svc:/network/inetd:default' />
+        </restarter>
+
+        <dependency
+            name='cupsd'
+            grouping='require_all'
+            restart_on='none'
+            type='service'>
+            <service_fmri value='svc:/application/cups/scheduler' />
+        </dependency>
+
+        <exec_method
+            type='method'
+            name='inetd_start'
+            exec='@CUPS_SERVERBIN@/daemon/cups-lpd -o document-format=application/octet-stream'
+            timeout_seconds='0'>
+            <method_context>
+                <method_credential user='@CUPS_USER@' group='@CUPS_GROUP@' />
+            </method_context>
+        </exec_method>
+
+        <property_group name='inetd' type='framework'>
+            <stability value='Evolving' />
+            <propval name='endpoint_type' type='astring' value='stream' />
+            <propval name='name' type='astring' value='printer' />
+            <propval name='wait' type='boolean' value='false' />
+            <propval name='isrpc' type='boolean' value='false' />
+            <propval name='proto' type='astring' value='tcp6' />
+        </property_group>
+
+        <property_group name='general' type='framework'>
+            <propval name='action_authorization' type='astring'
+                value='solaris.smf.manage.cups' />
+            <propval name='value_authorization' type='astring'
+                value='solaris.smf.value.cups' />
+        </property_group>
+
+        <template>
+            <common_name>
+                <loctext xml:lang='C'>
+                    CUPS Line Printer Daemon mini-server
+                </loctext>
+            </common_name>
+            <documentation>
+                <manpage title='cups-lpd' section='8'
+                    manpath='@mandir@' />
+            </documentation>
+        </template>
+
+    </instance>
+
+    <stability value='Stable' />
+
+</service>
+
+</service_bundle>
index b8a52d9ba99d2f89bf2236de8e6fa1cc63f8b170..b4ba4251636579632491f2554687b7cc05e7a87c 100644 (file)
@@ -3,7 +3,7 @@
 .\"
 .\"   Backend man page for the Common UNIX Printing System (CUPS).
 .\"
-.\"   Copyright 2007 by Apple Inc.
+.\"   Copyright 2007-2008 by Apple Inc.
 .\"   Copyright 1997-2006 by Easy Software Products.
 .\"
 .\"   These coded instructions, statements, and computer programs are the
@@ -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 backend 7 "Common UNIX Printing System" "20 March 2006" "Apple Inc."
+.TH backend 7 "Common UNIX Printing System" "28 July 2008" "Apple Inc."
 
 .SH NAME
 backend \- cups backend transmission interfaces
@@ -59,6 +59,7 @@ forms:
     device-class scheme "Unknown" "device-info"
     device-class device-uri "device-make-and-model" "device-info"
     device-class device-uri "device-make-and-model" "device-info" "device-id"
+    device-class device-uri "device-make-and-model" "device-info" "device-id" "device-location"
 .fi
 
 .LP
@@ -111,6 +112,11 @@ The optional \fIdevice-id\fR field specifies the IEEE-1284 device
 ID string for the device, which is used to select a matching
 driver.
 
+.LP
+The optional \fIdevice-location\fR field specifies the physical location of
+the device, which is often used to pre-populate the printer-location attribute
+when adding a printer.
+
 .SH PERMISSIONS
 Backends without world execute permissions are run as the root
 user. Otherwise, the backend is run using the unprivileged user
@@ -173,7 +179,7 @@ All other exit code values are reserved.
 http://localhost:631/help
 
 .SH COPYRIGHT
-Copyright 2007 by Apple Inc.
+Copyright 2007-2008 by Apple Inc.
 .\"
 .\" End of "$Id: backend.man 7600 2008-05-20 21:06:23Z mike $".
 .\"
index 6fbdd31bb377ec5634ee579f1c33de788c44a73d..4421c1df482decf1e540d3d7d6aeb02e29a43cee 100644 (file)
@@ -146,6 +146,26 @@ BrowseInterval seconds
 .br
 Specifies the maximum interval between printer information broadcasts.
 .TP 5
+BrowseLDAPBindDN
+.br
+Specifies the LDAP domain name to use when registering printers.
+.TP 5
+BrowseLDAPCACertFile
+.br
+Specifies the SSL certificate authority file to use.
+.TP 5
+BrowseLDAPDN
+.br
+Specifies the LDAP domain name to use when discovering printers.
+.TP 5
+BrowseLDAPPassword
+.br
+Specifies the password to use when accessing the LDAP server.
+.TP 5
+BrowseLDAPServer
+.br
+Specifies the LDAP server to use.
+.TP 5
 BrowseOrder allow,deny
 .TP 5
 BrowseOrder deny,allow
index 4f05e374f7cbd6a58a6d162dcdae4adebc7a7d53..90b51b4d7f2d5bf0bf5259bda26c1d738c476219 100644 (file)
@@ -58,9 +58,7 @@ install-data:
        -chgrp $(CUPS_GROUP) $(CACHEDIR)/rss
        if test "x$(SYMROOT)" != "x"; then \
                $(INSTALL_DIR) $(SYMROOT); \
-               for file in $(TARGETS); do \
-                       cp $$file $(SYMROOT); \
-               done \
+               cp mailto rss $(SYMROOT); \
        fi
 
 
@@ -70,9 +68,8 @@ install-data:
 
 install-exec:
        $(INSTALL_DIR) -m 755 $(SERVERBIN)/notifier
-       for file in $(TARGETS); do \
-               $(INSTALL_BIN) $$file $(SERVERBIN)/notifier; \
-       done
+       $(INSTALL_BIN) mailto $(SERVERBIN)/notifier
+       $(INSTALL_BIN) rss $(SERVERBIN)/notifier
 
 
 #
index c199e697c4cde924b0f5a3e244df559ba7d7335d..e580c2ddcea6ee89c52562a2df8e0a7aeda6ba7f 100644 (file)
@@ -333,14 +333,15 @@ cupsd:    $(CUPSDOBJS) $(LIBCUPSMIME) ../cups/$(LIBCUPS)
        $(CC) $(LDFLAGS) -o cupsd $(CUPSDOBJS) -L. -lcupsmime \
                $(LIBZ) $(SSLLIBS) $(LIBSLP) $(LIBLDAP) $(PAMLIBS) \
                $(LIBPAPER) $(LIBMALLOC) $(CUPSDLIBS) $(DNSSDLIBS) $(LIBS) \
-               $(LIBGSSAPI)
+               $(LIBGSSAPI) $(LIBWRAP)
 
 cupsd-static:  $(CUPSDOBJS) libcupsmime.a ../cups/libcups.a
        echo Linking $@...
        $(CC) $(LDFLAGS) -o cupsd-static $(CUPSDOBJS) libcupsmime.a \
                $(LIBZ) $(SSLLIBS) $(LIBSLP) $(LIBLDAP) $(PAMLIBS) \
                ../cups/libcups.a $(COMMONLIBS) $(LIBZ) $(LIBPAPER) \
-               $(LIBMALLOC) $(CUPSDLIBS) $(DNSSDLIBS) $(LIBGSSAPI)
+               $(LIBMALLOC) $(CUPSDLIBS) $(DNSSDLIBS) $(LIBGSSAPI) \
+               $(LIBWRAP)
 
 
 #
index 25be7a491b0ff4f52f6b1871b9d83b145c01872b..ac52bd99efa2ecca5dad5a2182e0e9bf9cb684c8 100644 (file)
@@ -76,6 +76,10 @@ extern const char *cssmErrorString(int error);
 #  include <gnutls/x509.h>
 #endif /* HAVE_GNUTLS */
 
+#ifdef HAVE_TCPD_H
+#  include <tcpd.h>
+#endif /* HAVE_TCPD_H */
+
 
 /*
  * Local functions...
@@ -125,6 +129,9 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
   char                 *hostname;      /* Hostname for address */
   http_addr_t          temp;           /* Temporary address variable */
   static time_t                last_dos = 0;   /* Time of last DoS attack */
+#ifdef HAVE_TCPD_H
+  struct request_info  wrap_req;       /* TCP wrappers request information */
+#endif /* HAVE_TCPD_H */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2,
@@ -240,7 +247,9 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
       cupsdLogMessage(CUPSD_LOG_WARN,
                       "Possible DoS attack - more than %d clients connecting "
                      "from %s!",
-                     MaxClientsPerHost, con->http.hostname);
+                     MaxClientsPerHost,
+                     httpAddrString(con->http.hostaddr, con->http.hostname,
+                                    sizeof(con->http.hostname)));
     }
 
 #ifdef WIN32
@@ -322,7 +331,8 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
     * Do double lookups as needed...
     */
 
-    if ((addrlist = httpAddrGetList(con->http.hostname, AF_UNSPEC, NULL)) != NULL)
+    if ((addrlist = httpAddrGetList(con->http.hostname, AF_UNSPEC, NULL))
+            != NULL)
     {
      /*
       * See if the hostname maps to the same IP address...
@@ -362,6 +372,34 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */
     }
   }
 
+#ifdef HAVE_TCPD_H
+ /*
+  * See if the connection is denied by TCP wrappers...
+  */
+
+  request_init(&wrap_req, RQ_DAEMON, "cupsd", RQ_FILE, con->http.fd, NULL);
+  fromhost(&wrap_req);
+
+  if (!hosts_access(&wrap_req))
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                    "cupsdAcceptClient: Closing connection %d...",
+                    con->http.fd);
+
+#ifdef WIN32
+    closesocket(con->http.fd);
+#else
+    close(con->http.fd);
+#endif /* WIN32 */
+
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                    "Connection from %s refused by /etc/hosts.allow and "
+                   "/etc/hosts.deny rules.", con->http.hostname);
+    free(con);
+    return;
+  }
+#endif /* HAVE_TCPD_H */
+
 #ifdef AF_INET6
   if (con->http.hostaddr->addr.sa_family == AF_INET6)
     cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s:%d (IPv6)",
index 3fb619e1eb2b469502ba502c01047c4a4993af30..8b634a27cb8cf9a9f77c1e7b2aa12dd336d281d3 100644 (file)
@@ -65,10 +65,8 @@ typedef struct
 typedef struct
 {
   char device_class[128],              /* Device class */
-       device_make_and_model[128],     /* Make and model, if known */
        device_info[128],               /* Device info/description */
-       device_uri[1024],               /* Device URI */
-       device_id[1024];                /* 1284 Device ID */
+       device_uri[1024];               /* Device URI */
 } cupsd_device_t;
 
 
@@ -92,7 +90,8 @@ static int            send_class,     /* Send device-class attribute? */
                        send_make_and_model,
                                        /* Send device-make-and-model attribute? */
                        send_uri,       /* Send device-uri attribute? */
-                       send_id;        /* Send device-id attribute? */
+                       send_id,        /* Send device-id attribute? */
+                       send_location;  /* Send device-location attribute? */
 static int             dead_children = 0;
                                        /* Dead children? */
 
@@ -105,7 +104,8 @@ static int          add_device(const char *device_class,
                                   const char *device_make_and_model,
                                   const char *device_info,
                                   const char *device_uri,
-                                  const char *device_id);
+                                  const char *device_id,
+                                  const char *device_location);
 static int             compare_devices(cupsd_device_t *p0,
                                        cupsd_device_t *p1);
 static cups_array_t    *create_strings_array(const char *s);
@@ -198,7 +198,10 @@ main(int  argc,                            /* I - Number of command-line args */
                                                    num_options, options));
 
   if (!requested || cupsArrayFind(requested, "all") != NULL)
-    send_class = send_info = send_make_and_model = send_uri = send_id = 1;
+  {
+    send_class = send_info = send_make_and_model = send_uri = send_id =
+        send_location = 1;
+  }
   else
   {
     send_class          = cupsArrayFind(requested, "device-class") != NULL;
@@ -206,6 +209,7 @@ main(int  argc,                             /* I - Number of command-line args */
     send_make_and_model = cupsArrayFind(requested, "device-make-and-model") != NULL;
     send_uri            = cupsArrayFind(requested, "device-uri") != NULL;
     send_id             = cupsArrayFind(requested, "device-id") != NULL;
+    send_location       = cupsArrayFind(requested, "device-location") != NULL;
   }
 
  /*
@@ -345,7 +349,8 @@ add_device(
     const char *device_make_and_model, /* I - Device make and model */
     const char *device_info,           /* I - Device information */
     const char *device_uri,            /* I - Device URI */
-    const char *device_id)             /* I - 1284 device ID */
+    const char *device_id,             /* I - 1284 device ID */
+    const char *device_location)       /* I - Physical location */
 {
   cupsd_device_t       *device;        /* New device */
 
@@ -366,11 +371,8 @@ add_device(
   */
 
   strlcpy(device->device_class, device_class, sizeof(device->device_class));
-  strlcpy(device->device_make_and_model, device_make_and_model,
-          sizeof(device->device_make_and_model));
   strlcpy(device->device_info, device_info, sizeof(device->device_info));
   strlcpy(device->device_uri, device_uri, sizeof(device->device_uri));
-  strlcpy(device->device_id, device_id, sizeof(device->device_id));
 
  /*
   * Add the device to the array and return...
@@ -397,16 +399,20 @@ add_device(
       cupsdSendIPPGroup(IPP_TAG_PRINTER);
       if (send_class)
        cupsdSendIPPString(IPP_TAG_KEYWORD, "device-class",
-                          device->device_class);
+                          device_class);
       if (send_info)
-       cupsdSendIPPString(IPP_TAG_TEXT, "device-info", device->device_info);
+       cupsdSendIPPString(IPP_TAG_TEXT, "device-info", device_info);
       if (send_make_and_model)
        cupsdSendIPPString(IPP_TAG_TEXT, "device-make-and-model",
-                          device->device_make_and_model);
+                          device_make_and_model);
       if (send_uri)
-       cupsdSendIPPString(IPP_TAG_URI, "device-uri", device->device_uri);
+       cupsdSendIPPString(IPP_TAG_URI, "device-uri", device_uri);
       if (send_id)
-       cupsdSendIPPString(IPP_TAG_TEXT, "device-id", device->device_id);
+       cupsdSendIPPString(IPP_TAG_TEXT, "device-id",
+                          device_id ? device_id : "");
+      if (send_location)
+       cupsdSendIPPString(IPP_TAG_TEXT, "device-location",
+                          device_location ? device_location : "");
 
       fflush(stdout);
       fputs("DEBUG: Flushed attributes...\n", stderr);
@@ -508,11 +514,14 @@ static int                                /* O - 0 on success, -1 on error */
 get_device(cupsd_backend_t *backend)   /* I - Backend to read from */
 {
   char line[2048],                     /* Line from backend */
-       dclass[64],                     /* Device class */
-       uri[1024],                      /* Device URI */
-       info[128],                      /* Device info */
-       make_model[256],                /* Make and model */
-       device_id[1024];                /* 1284 device ID */
+       temp[2048],                     /* Copy of line */
+       *ptr,                           /* Pointer into line */
+       *dclass,                        /* Device class */
+       *uri,                           /* Device URI */
+       *make_model,                    /* Make and model */
+       *info,                          /* Device info */
+       *device_id,                     /* 1284 device ID */
+       *location;                      /* Physical location */
 
 
   if (cupsFileGets(backend->pipe, line, sizeof(line)))
@@ -520,35 +529,123 @@ get_device(cupsd_backend_t *backend)     /* I - Backend to read from */
    /*
     * Each line is of the form:
     *
-    *   class URI "make model" "name" ["1284 device ID"]
+    *   class URI "make model" "name" ["1284 device ID"] ["location"]
+    */
+
+    strlcpy(temp, line, sizeof(temp));
+
+   /*
+    * device-class
+    */
+
+    dclass = temp;
+
+    for (ptr = temp; *ptr; ptr ++)
+      if (isspace(*ptr & 255))
+        break;
+
+    while (isspace(*ptr & 255))
+      *ptr++ = '\0';
+
+   /*
+    * device-uri
+    */
+
+    if (!*ptr)
+      goto error;
+
+    for (uri = ptr; *ptr; ptr ++)
+      if (isspace(*ptr & 255))
+        break;
+
+    while (isspace(*ptr & 255))
+      *ptr++ = '\0';
+
+   /*
+    * device-make-and-model
     */
 
-    device_id[0] = '\0';
+    if (*ptr != '\"')
+      goto error;
 
-    if (sscanf(line,
-              "%63s%1023s%*[ \t]\"%255[^\"]\"%*[ \t]\"%127[^\"]\""
-              "%*[ \t]\"%1023[^\"]",
-              dclass, uri, make_model, info, device_id) < 4)
+    for (ptr ++, make_model = ptr; *ptr && *ptr != '\"'; ptr ++)
     {
-     /*
-      * Bad format; strip trailing newline and write an error message.
-      */
+      if (*ptr == '\\' && ptr[1])
+        _cups_strcpy(ptr, ptr + 1);
+    }
+
+    if (*ptr != '\"')
+      goto error;
+
+    for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
+
+   /*
+    * device-info
+    */
 
-      if (line[strlen(line) - 1] == '\n')
-       line[strlen(line) - 1] = '\0';
+    if (*ptr != '\"')
+      goto error;
 
-      fprintf(stderr, "ERROR: [cups-deviced] Bad line from \"%s\": %s\n",
-             backend->name, line);
+    for (ptr ++, info = ptr; *ptr && *ptr != '\"'; ptr ++)
+    {
+      if (*ptr == '\\' && ptr[1])
+        _cups_strcpy(ptr, ptr + 1);
     }
-    else
+
+    if (*ptr != '\"')
+      goto error;
+
+    for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
+
+   /*
+    * device-id
+    */
+
+    if (*ptr == '\"')
     {
+      for (ptr ++, device_id = ptr; *ptr && *ptr != '\"'; ptr ++)
+      {
+       if (*ptr == '\\' && ptr[1])
+         _cups_strcpy(ptr, ptr + 1);
+      }
+
+      if (*ptr != '\"')
+       goto error;
+
+      for (*ptr++ = '\0'; isspace(*ptr & 255); *ptr++ = '\0');
+
      /*
-      * Add the device to the array of available devices...
+      * device-location
       */
 
-      if (!add_device(dclass, make_model, info, uri, device_id))
-        fprintf(stderr, "DEBUG: [cups-deviced] Found device \"%s\"...\n", uri);
+      if (*ptr == '\"')
+      {
+       for (ptr ++, location = ptr; *ptr && *ptr != '\"'; ptr ++)
+       {
+         if (*ptr == '\\' && ptr[1])
+           _cups_strcpy(ptr, ptr + 1);
+       }
+
+       if (*ptr != '\"')
+         goto error;
+
+       *ptr = '\0';
+      }
+      else
+        location = NULL;
     }
+    else
+    {
+      device_id = NULL;
+      location  = NULL;
+    }
+
+   /*
+    * Add the device to the array of available devices...
+    */
+
+    if (!add_device(dclass, make_model, info, uri, device_id, location))
+      fprintf(stderr, "DEBUG: [cups-deviced] Found device \"%s\"...\n", uri);
 
     return (0);
   }
@@ -561,6 +658,19 @@ get_device(cupsd_backend_t *backend)       /* I - Backend to read from */
   backend->pipe = NULL;
 
   return (-1);
+
+ /*
+  * Bad format; strip trailing newline and write an error message.
+  */
+
+  error:
+
+  if (line[strlen(line) - 1] == '\n')
+    line[strlen(line) - 1] = '\0';
+
+  fprintf(stderr, "ERROR: [cups-deviced] Bad line from \"%s\": %s\n",
+         backend->name, line);
+  return (0);
 }
 
 
index bed393eae5f3a248cbee88899cac7dc2e5c581dd..7742abc9304c7bfa6063d6819b52332e3e92f19f 100644 (file)
@@ -76,7 +76,7 @@ static const char * const ppd_types[] =       /* ppd-type values */
 typedef struct                         /**** PPD record ****/
 {
   time_t       mtime;                  /* Modification time */
-  size_t       size;                   /* Size in bytes */
+  off_t                size;                   /* Size in bytes */
   int          model_number;           /* cupsModelNumber */
   int          type;                   /* ppd-type */
   char         filename[512],          /* Filename */
index b2960d65dbb5effc890ee323094333adb6b13948..27efd0d00018aabd468b42701452dd37e1c7ff46 100644 (file)
  *
  * Contents:
  *
- *   cupsdDeregisterPrinter()   - Stop sending broadcast information for a local
- *                                printer and remove any pending references to
- *                                remote printers.
- *   cupsdLoadRemoteCache()     - Load the remote printer cache.
- *   cupsdRegisterPrinter()     - Start sending broadcast information for a
- *                                printer or update the broadcast contents.
- *   cupsdRestartPolling()      - Restart polling servers as needed.
- *   cupsdSaveRemoteCache()     - Save the remote printer cache.
- *   cupsdSendBrowseList()      - Send new browsing information as necessary.
- *   cupsdStartBrowsing()       - Start sending and receiving broadcast
- *                                information.
- *   cupsdStartPolling()        - Start polling servers as needed.
- *   cupsdStopBrowsing()        - Stop sending and receiving broadcast
- *                                information.
- *   cupsdStopPolling()         - Stop polling servers as needed.
- *   cupsdUpdateDNSSDName()     - Update the computer name we use for
- *                                browsing...
- *   cupsdUpdateLDAPBrowse()    - Scan for new printers via LDAP...
- *   cupsdUpdateSLPBrowse()     - Get browsing information via SLP.
- *   dequote()                  - Remote quotes from a string.
- *   dnssdBuildTxtRecord()      - Build a TXT record from printer info.
- *   dnssdComparePrinters()     - Compare the registered names of two printers.
- *   dnssdDeregisterPrinter()   - Stop sending broadcast information for a
- *                                printer.
- *   dnssdPackTxtRecord()       - Pack an array of key/value pairs into the TXT
- *                                record format.
- *   dnssdRegisterCallback()    - DNSServiceRegister callback.
- *   dnssdRegisterPrinter()     - Start sending broadcast information for a
- *                                printer or update the broadcast contents.
- *   dnssdUpdate()              - Handle DNS-SD queries.
- *   get_hostconfig()           - Get an /etc/hostconfig service setting.
- *   is_local_queue()           - Determine whether the URI points at a local
- *                                queue.
- *   process_browse_data()      - Process new browse data.
- *   process_implicit_classes() - Create/update implicit classes as needed.
- *   send_cups_browse()         - Send new browsing information using the CUPS
- *                                protocol.
- *   send_ldap_browse()         - Send LDAP printer registrations.
- *   send_slp_browse()          - Register the specified printer with SLP.
- *   slp_attr_callback()        - SLP attribute callback
- *   slp_dereg_printer()        - SLPDereg() the specified printer
- *   slp_get_attr()             - Get an attribute from an SLP registration.
- *   slp_reg_callback()         - Empty SLPRegReport.
- *   slp_url_callback()         - SLP service url callback
- *   update_cups_browse()       - Update the browse lists using the CUPS
- *                                protocol.
- *   update_lpd()               - Update the LPD configuration as needed.
- *   update_polling()           - Read status messages from the poll daemons.
- *   update_smb()               - Update the SMB configuration as needed.
  */
 
 /*
@@ -104,7 +55,36 @@ static void process_browse_data(const char *uri, const char *host,
 static void    process_implicit_classes(void);
 static void    send_cups_browse(cupsd_printer_t *p);
 #ifdef HAVE_LDAP
+static LDAP    *ldap_connect(void);
+static void    ldap_reconnect(void);
+static void    ldap_disconnect(LDAP *ld);
+static int     ldap_search_rec(LDAP *ld, char *base, int scope,
+                                char *filter, char *attrs[],
+                                int attrsonly, LDAPMessage **res);
+static int     ldap_getval_firststring(LDAP *ld, LDAPMessage *entry,
+                                        char *attr, char *retval,
+                                        unsigned long maxsize);
+static void    ldap_freeres(LDAPMessage *entry);
+static void    send_ldap_ou(char *ou, char *basedn, char *descstring);
 static void    send_ldap_browse(cupsd_printer_t *p);
+static void    ldap_dereg_printer(cupsd_printer_t *p);
+static void    ldap_dereg_ou(char *ou, char *basedn);
+#  ifdef HAVE_LDAP_REBIND_PROC
+#    if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+static int     ldap_rebind_proc(LDAP *RebindLDAPHandle,
+                                 LDAP_CONST char *refsp,
+                                 ber_tag_t request,
+                                 ber_int_t msgid,
+                                 void *params);
+#    else
+static int     ldap_rebind_proc(LDAP *RebindLDAPHandle,
+                                 char **dnp,
+                                 char **passwdp,
+                                 int *authmethodp,
+                                 int freeit,
+                                 void *arg);
+#    endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
+#  endif /* HAVE_LDAP_REBIND_PROC */
 #endif /* HAVE_LDAP */
 #ifdef HAVE_LIBSLP
 static void    send_slp_browse(cupsd_printer_t *p);
@@ -131,7 +111,7 @@ static void dnssdRegisterPrinter(cupsd_printer_t *p);
 static void    dnssdUpdate(void);
 #endif /* HAVE_DNSSD */
 
-#ifdef HAVE_OPENLDAP
+#ifdef HAVE_LDAP
 static const char * const ldap_attrs[] =/* CUPS LDAP attributes */
                {
                  "printerDescription",
@@ -141,7 +121,7 @@ static const char * const ldap_attrs[] =/* CUPS LDAP attributes */
                  "printerURI",
                  NULL
                };
-#endif /* HAVE_OPENLDAP */
+#endif /* HAVE_LDAP */
 
 #ifdef HAVE_LIBSLP 
 /*
@@ -224,6 +204,11 @@ cupsdDeregisterPrinter(
     slp_dereg_printer(p);
 #endif /* HAVE_LIBSLP */
 
+#ifdef HAVE_LDAP
+  if (BrowseLocalProtocols & BROWSE_LDAP)
+    ldap_dereg_printer(p);
+#endif /* HAVE_LDAP */
+
 #ifdef HAVE_DNSSD
   if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDRef)
     dnssdDeregisterPrinter(p);
@@ -928,6 +913,425 @@ cupsdSendBrowseList(void)
 }
 
 
+#ifdef HAVE_LDAP_REBIND_PROC
+#  if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+/*
+ * 'ldap_rebind_proc()' - Callback function for LDAP rebind
+ */
+
+static int
+ldap_rebind_proc (LDAP *RebindLDAPHandle,
+                  LDAP_CONST char *refsp,
+                  ber_tag_t request,
+                  ber_int_t msgid,
+                  void *params)
+{
+  int               rc;
+
+ /*
+  * Bind to new LDAP server...
+  */
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "ldap_rebind_proc: Rebind to %s", refsp);
+
+#    if LDAP_API_VERSION > 3000
+  struct berval bval;
+  bval.bv_val = BrowseLDAPPassword;
+  bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword);
+
+  rc = ldap_sasl_bind_s(RebindLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL);
+#    else
+  rc = ldap_bind_s(RebindLDAPHandle, BrowseLDAPBindDN,
+                   BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
+#    endif /* LDAP_API_VERSION > 3000 */
+
+  return (rc);
+}
+
+#  else /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
+
+/*
+ * 'ldap_rebind_proc()' - Callback function for LDAP rebind
+ */
+
+static int
+ldap_rebind_proc (LDAP *RebindLDAPHandle,
+                  char **dnp,
+                  char **passwdp,
+                  int *authmethodp,
+                  int freeit,
+                  void *arg)
+{
+  switch ( freeit ) {
+
+  case 1:
+
+     /*
+      * Free current values...
+      */
+
+      cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                     "ldap_rebind_proc: Free values...");
+
+      if ( dnp && *dnp ) {
+        free( *dnp );
+      }
+      if ( passwdp && *passwdp ) {
+        free( *passwdp );
+      }
+      break;
+
+  case 0:
+
+     /*
+      * Return credentials for LDAP referal...
+      */
+
+      cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                     "ldap_rebind_proc: Return necessary values...");
+
+      *dnp = strdup(BrowseLDAPBindDN);
+      *passwdp = strdup(BrowseLDAPPassword);
+      *authmethodp = LDAP_AUTH_SIMPLE;
+      break;
+
+  default:
+
+     /*
+      * Should never happen...
+      */
+
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                      "LDAP rebind has been called with wrong freeit value!");
+      break;
+
+  }
+
+  return (LDAP_SUCCESS);
+}
+#  endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
+#endif /* HAVE_LDAP_REBIND_PROC */
+
+
+#ifdef HAVE_LDAP
+/*
+ * 'ldap_connect()' - Start new LDAP connection
+ */
+
+static LDAP *
+ldap_connect(void)
+{
+ /* 
+  * Open LDAP handle...
+  */
+
+  int          rc;                             /* LDAP API status */
+  int          version = 3;                    /* LDAP version */
+  struct berval        bv = {0, ""};                   /* SASL bind value */
+  LDAP         *TempBrowseLDAPHandle=NULL;     /* Temporary LDAP Handle */
+#  if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
+  int          ldap_ssl = 0;                   /* LDAP SSL indicator */
+  int          ssl_err = 0;                    /* LDAP SSL error value */
+#  endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
+
+#  ifdef HAVE_OPENLDAP
+#    ifdef HAVE_LDAP_SSL
+
+ /*
+  * Set the certificate file to use for encrypted LDAP sessions...
+  */
+
+  if (BrowseLDAPCACertFile)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG,
+                   "cupsdStartBrowsing: Setting CA certificate file \"%s\"",
+                    BrowseLDAPCACertFile);
+
+    if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
+                             (void *)BrowseLDAPCACertFile)) != LDAP_SUCCESS)
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                      "Unable to set CA certificate file for LDAP "
+                      "connections: %d - %s", rc, ldap_err2string(rc));
+  }
+
+#    endif /* HAVE_LDAP_SSL */
+ /*
+  * Initialize OPENLDAP connection...
+  * LDAP stuff currently only supports ldapi EXTERNAL SASL binds...
+  */
+
+  if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost")) 
+    rc = ldap_initialize(&TempBrowseLDAPHandle, "ldapi:///");
+  else 
+    rc = ldap_initialize(&TempBrowseLDAPHandle, BrowseLDAPServer);
+
+#  else /* HAVE_OPENLDAP */
+
+  int          ldap_port = 0;                  /* LDAP port */
+  char         ldap_protocol[11],              /* LDAP protocol */
+               ldap_host[255];                 /* LDAP host */
+
+ /*
+  * Split LDAP URI into its components...
+  */
+
+  if (! BrowseLDAPServer)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                    "BrowseLDAPServer not configured! Disable LDAP browsing!");
+    BrowseLocalProtocols &= ~BROWSE_LDAP;
+    BrowseRemoteProtocols &= ~BROWSE_LDAP;
+    return (NULL);
+  }
+
+  sscanf(BrowseLDAPServer, "%10[^:]://%254[^:/]:%d", ldap_protocol, ldap_host, &ldap_port);
+
+  if (strcmp(ldap_protocol, "ldap") == 0) {
+    ldap_ssl = 0;
+  } else if (strcmp(ldap_protocol, "ldaps") == 0) {
+    ldap_ssl = 1;
+  } else {
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                    "unrecognised ldap protocol (%s)!", ldap_protocol);
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                    "Disable LDAP browsing!");
+    BrowseLocalProtocols &= ~BROWSE_LDAP;
+    BrowseRemoteProtocols &= ~BROWSE_LDAP;
+    return (NULL);
+  }
+
+  if (ldap_port == 0)
+  {
+    if (ldap_ssl)
+      ldap_port = LDAPS_PORT;
+    else
+      ldap_port = LDAP_PORT;
+  }
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG,
+                  "LDAP Connection Details: PROT:%s HOST:%s PORT:%d",
+                  ldap_protocol, ldap_host, ldap_port);
+
+ /*
+  * Initialize LDAP connection...
+  */
+
+  if (! ldap_ssl)
+  {
+    if ((TempBrowseLDAPHandle = ldap_init(ldap_host, ldap_port)) == NULL)
+      rc = LDAP_OPERATIONS_ERROR;
+    else
+      rc = LDAP_SUCCESS;
+
+#    ifdef HAVE_LDAP_SSL
+  }
+  else
+  {
+
+   /*
+    * Initialize SSL LDAP connection...
+    */
+    if (BrowseLDAPCACertFile)
+    {
+      rc = ldapssl_client_init(BrowseLDAPCACertFile, (void *)NULL);
+      if (rc != LDAP_SUCCESS) {
+        cupsdLogMessage(CUPSD_LOG_ERROR,
+                        "Failed to initialize LDAP SSL client!");
+        rc = LDAP_OPERATIONS_ERROR;
+      } else {
+        if ((TempBrowseLDAPHandle = ldapssl_init(ldap_host, ldap_port, 1)) == NULL)
+          rc = LDAP_OPERATIONS_ERROR;
+        else
+          rc = LDAP_SUCCESS;
+      }
+    }
+    else
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                      "LDAP SSL certificate file/database not configured!");
+      rc = LDAP_OPERATIONS_ERROR;
+    }
+
+#    else /* HAVE_LDAP_SSL */
+
+   /*
+    * Return error, because client libraries doesn't support SSL
+    */
+
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                    "LDAP client libraries does not support TLS");
+    rc = LDAP_OPERATIONS_ERROR;
+
+#    endif /* HAVE_LDAP_SSL */
+  }
+#  endif /* HAVE_OPENLDAP */
+
+ /*
+  * Check return code from LDAP initialize...
+  */
+
+  if (rc != LDAP_SUCCESS)
+  {
+    if ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR))
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                      "Unable to initialize LDAP! Temporary disable LDAP browsing...");
+    }
+    else
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                      "Unable to initialize LDAP! Disable LDAP browsing!");
+      BrowseLocalProtocols &= ~BROWSE_LDAP;
+      BrowseRemoteProtocols &= ~BROWSE_LDAP;
+    }
+
+    ldap_disconnect(TempBrowseLDAPHandle);
+    TempBrowseLDAPHandle = NULL;
+  }
+
+ /*
+  * Upgrade LDAP version...
+  */
+
+  else if (ldap_set_option(TempBrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION,
+                           (const void *)&version) != LDAP_SUCCESS)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                   "Unable to set LDAP protocol version %d! Disable LDAP browsing!",
+                   version);
+    BrowseLocalProtocols &= ~BROWSE_LDAP;
+    BrowseRemoteProtocols &= ~BROWSE_LDAP;
+    ldap_disconnect(TempBrowseLDAPHandle);
+    TempBrowseLDAPHandle = NULL;
+  }
+  else
+  {
+
+   /*
+    * Register LDAP rebind procedure...
+    */
+
+#  ifdef HAVE_LDAP_REBIND_PROC
+#    if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
+
+    rc = ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc, (void *)NULL);
+    if ( rc != LDAP_SUCCESS )
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                      "Setting LDAP rebind function failed with status %d: %s",
+                      rc, ldap_err2string(rc));
+
+#    else
+
+    ldap_set_rebind_proc(TempBrowseLDAPHandle, &ldap_rebind_proc, (void *)NULL);
+
+#    endif /* defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000) */
+#  endif /* HAVE_LDAP_REBIND_PROC */
+
+   /*
+    * Start LDAP bind...
+    */
+
+#  if LDAP_API_VERSION > 3000
+    struct berval bval;
+    bval.bv_val = BrowseLDAPPassword;
+    bval.bv_len = (BrowseLDAPPassword == NULL) ? 0 : strlen(BrowseLDAPPassword);
+
+    if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
+      rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, NULL, "EXTERNAL", &bv, NULL,
+                            NULL, NULL);
+    else
+      rc = ldap_sasl_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN, LDAP_SASL_SIMPLE, &bval, NULL, NULL, NULL);
+#  else
+      rc = ldap_bind_s(TempBrowseLDAPHandle, BrowseLDAPBindDN,
+                       BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
+#  endif /* LDAP_API_VERSION > 3000 */
+
+    if (rc != LDAP_SUCCESS)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                     "LDAP bind failed with error %d: %s",
+                      rc, ldap_err2string(rc));
+#  if defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP)
+      if (ldap_ssl && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR)))
+      {
+        ssl_err = PORT_GetError();
+        if (ssl_err != 0)
+          cupsdLogMessage(CUPSD_LOG_ERROR,
+                          "LDAP SSL error %d: %s",
+                          ssl_err, ldapssl_err2string(ssl_err));
+      }
+#  endif /* defined(HAVE_LDAP_SSL) && defined (HAVE_MOZILLA_LDAP) */
+      ldap_disconnect(TempBrowseLDAPHandle);
+      TempBrowseLDAPHandle = NULL;
+    }
+    else
+    {
+      cupsdLogMessage(CUPSD_LOG_INFO,
+                     "LDAP connection established");
+    }
+
+  }
+  return (TempBrowseLDAPHandle);
+}
+
+
+/*
+ * 'ldap_reconnect()' - Reconnect to LDAP Server
+ */
+
+static void
+ldap_reconnect(void)
+{
+  LDAP         *TempBrowseLDAPHandle = NULL;   /* Temp Handle to LDAP server */
+
+  cupsdLogMessage(CUPSD_LOG_INFO,
+                  "Try LDAP reconnect...");
+
+ /*
+  * Get a new LDAP Handle and replace the global Handle
+  * if the new connection was successful
+  */
+
+  TempBrowseLDAPHandle = ldap_connect();
+
+  if (TempBrowseLDAPHandle != NULL)
+  {
+    if (BrowseLDAPHandle != NULL)
+    {
+      ldap_disconnect(BrowseLDAPHandle);
+    }
+    BrowseLDAPHandle = TempBrowseLDAPHandle;
+  }
+}
+
+
+/*
+ * 'ldap_disconnect()' - Disconnect from LDAP Server
+ */
+
+static void
+ldap_disconnect(LDAP *ld)      /* I - LDAP handle */
+{
+  int  rc;     /* return code */
+
+ /*
+  * Close LDAP handle...
+  */
+
+#  if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+  rc = ldap_unbind_ext_s(ld, NULL, NULL);
+#  else
+  rc = ldap_unbind_s(ld);
+#  endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+  if (rc != LDAP_SUCCESS)
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                    "Unbind from LDAP server failed with status %d: %s",
+                    rc, ldap_err2string(rc));
+}
+#endif /* HAVE_LDAP */
+
+
 /*
  * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information.
  */
@@ -1125,7 +1529,7 @@ cupsdStartBrowsing(void)
     BrowseSLPHandle = NULL;
 #endif /* HAVE_LIBSLP */
 
-#ifdef HAVE_OPENLDAP
+#ifdef HAVE_LDAP
   if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP)
   {
     if (!BrowseLDAPDN)
@@ -1137,84 +1541,13 @@ cupsdStartBrowsing(void)
     }
     else
     {
-     /* 
-      * Open LDAP handle...
-      */
-
-      int              rc;             /* LDAP API status */
-      int              version = 3;    /* LDAP version */
-      struct berval    bv = {0, ""};   /* SASL bind value */
-
-
-     /*
-      * Set the certificate file to use for encrypted LDAP sessions...
-      */
-
-      if (BrowseLDAPCACertFile)
-      {
-       cupsdLogMessage(CUPSD_LOG_DEBUG,
-                       "cupsdStartBrowsing: Setting CA certificate file \"%s\"",
-                       BrowseLDAPCACertFile);
-
-        if ((rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
-                                 (void *)BrowseLDAPCACertFile))
-               != LDAP_SUCCESS)
-          cupsdLogMessage(CUPSD_LOG_ERROR,
-                          "Unable to set CA certificate file for LDAP "
-                         "connections: %d - %s", rc, ldap_err2string(rc));
-      }
-
-     /*
-      * LDAP stuff currently only supports ldapi EXTERNAL SASL binds...
-      */
-
-      if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost")) 
-        rc = ldap_initialize(&BrowseLDAPHandle, "ldapi:///");
-      else     
-       rc = ldap_initialize(&BrowseLDAPHandle, BrowseLDAPServer);
-
-      if (rc != LDAP_SUCCESS)
-      {
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "Unable to initialize LDAP; disabling LDAP browsing!");
-       BrowseLocalProtocols &= ~BROWSE_LDAP;
-       BrowseRemoteProtocols &= ~BROWSE_LDAP;
-      }
-      else if (ldap_set_option(BrowseLDAPHandle, LDAP_OPT_PROTOCOL_VERSION,
-                               (const void *)&version) != LDAP_SUCCESS)
-      {
-       ldap_unbind_ext(BrowseLDAPHandle, NULL, NULL);
-       BrowseLDAPHandle = NULL;
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "Unable to set LDAP protocol version; "
-                       "disabling LDAP browsing!");
-       BrowseLocalProtocols &= ~BROWSE_LDAP;
-       BrowseRemoteProtocols &= ~BROWSE_LDAP;
-      }
-      else
-      {
-       if (!BrowseLDAPServer || !strcasecmp(BrowseLDAPServer, "localhost"))
-         rc = ldap_sasl_bind_s(BrowseLDAPHandle, NULL, "EXTERNAL", &bv, NULL,
-                               NULL, NULL);
-       else
-         rc = ldap_bind_s(BrowseLDAPHandle, BrowseLDAPBindDN,
-                          BrowseLDAPPassword, LDAP_AUTH_SIMPLE);
-
-       if (rc != LDAP_SUCCESS)
-       {
-         cupsdLogMessage(CUPSD_LOG_ERROR,
-                         "Unable to bind to LDAP server; "
-                         "disabling LDAP browsing!");
-         ldap_unbind_ext(BrowseLDAPHandle, NULL, NULL);
-         BrowseLocalProtocols &= ~BROWSE_LDAP;
-         BrowseRemoteProtocols &= ~BROWSE_LDAP;
-       }
-      }
+      /* Open LDAP handle... */
+      BrowseLDAPHandle = ldap_connect();
     }
 
     BrowseLDAPRefresh = 0;
   }
-#endif /* HAVE_OPENLDAP */
+#endif /* HAVE_LDAP */
 
  /*
   * Enable LPD and SMB printer sharing as needed through external programs...
@@ -1425,11 +1758,12 @@ cupsdStopBrowsing(void)
   }
 #endif /* HAVE_LIBSLP */
 
-#ifdef HAVE_OPENLDAP
+#ifdef HAVE_LDAP
   if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_LDAP) &&
       BrowseLDAPHandle)
   {
-    ldap_unbind(BrowseLDAPHandle);
+    ldap_dereg_ou(ServerName, BrowseLDAPDN);
+    ldap_disconnect(BrowseLDAPHandle);
     BrowseLDAPHandle = NULL;
   }
 #endif /* HAVE_OPENLDAP */
@@ -1545,7 +1879,7 @@ cupsdUpdateDNSSDName(void)
 #endif /* HAVE_DNSSD */
 
 
-#ifdef HAVE_OPENLDAP
+#ifdef HAVE_LDAP
 /*
  * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
  */
@@ -1559,36 +1893,72 @@ cupsdUpdateLDAPBrowse(void)
                location[1024],         /* Printer location */
                info[1024],             /* Printer information */
                make_model[1024],       /* Printer make and model */
-               **value;                /* Holds the returned data from LDAP */
+               type_num[30];           /* Printer type number */
   int          type;                   /* Printer type */
   int          rc;                     /* LDAP status */
   int          limit;                  /* Size limit */
   LDAPMessage  *res,                   /* LDAP search results */
                  *e;                   /* Current entry from search */
 
-
- /*
-  * Search for printers...
-  */
-
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
 
   BrowseLDAPRefresh = time(NULL) + BrowseInterval;
 
-  rc = ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
-                     "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
-  if (rc != LDAP_SUCCESS) 
+ /*
+  * Reconnect if LDAP Handle is invalid...
+  */
+
+  if (! BrowseLDAPHandle)
   {
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                    "LDAP search returned error %d: %s", rc,
-                   ldap_err2string(rc));
+    ldap_reconnect();
     return;
   }
 
+ /*
+  * Search for cups printers in LDAP directory...
+  */
+
+  rc = ldap_search_rec(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
+                       "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
+
+ /*
+  * If ldap search was successfull then exit function
+  * and temporary disable LDAP updates...
+  */
+
+  if (rc != LDAP_SUCCESS) 
+  {
+    if (BrowseLDAPUpdate && ((rc == LDAP_SERVER_DOWN) || (rc == LDAP_CONNECT_ERROR)))
+    {
+      BrowseLDAPUpdate = FALSE;
+      cupsdLogMessage(CUPSD_LOG_INFO,
+                      "LDAP update temporary disabled");
+    }
+    return;
+  }
+
+ /*
+  * If LDAP updates were disabled, we will reenable them...
+  */
+
+  if (! BrowseLDAPUpdate)
+  {
+    BrowseLDAPUpdate = TRUE;
+    cupsdLogMessage(CUPSD_LOG_INFO,
+                    "LDAP update enabled");
+  }
+
+ /*
+  * Count LDAP entries and return if no entry exist...
+  */
+
   limit = ldap_count_entries(BrowseLDAPHandle, res);
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
   if (limit < 1)
+  {
+    ldap_freeres(res);
     return;
+  }
 
  /*
   * Loop through the available printers...
@@ -1602,41 +1972,28 @@ cupsdUpdateLDAPBrowse(void)
     * Get the required values from this entry...
     */
 
-    if ((value = ldap_get_values(BrowseLDAPHandle, e,
-                                 "printerDescription")) == NULL)
+    if (ldap_getval_firststring(BrowseLDAPHandle, e,
+                                "printerDescription", info, sizeof(info)) == -1)
       continue;
 
-    strlcpy(info, *value, sizeof(info));
-    ldap_value_free(value);
-
-    if ((value = ldap_get_values(BrowseLDAPHandle, e,
-                                 "printerLocation")) == NULL)
+    if (ldap_getval_firststring(BrowseLDAPHandle, e,
+                                "printerLocation", location, sizeof(location)) == -1)
       continue;
 
-    strlcpy(location, *value, sizeof(location));
-    ldap_value_free(value);
-
-    if ((value = ldap_get_values(BrowseLDAPHandle, e,
-                                 "printerMakeAndModel")) == NULL)
+    if (ldap_getval_firststring(BrowseLDAPHandle, e,
+                                "printerMakeAndModel", make_model, sizeof(make_model)) == -1)
       continue;
 
-    strlcpy(make_model, *value, sizeof(make_model));
-    ldap_value_free(value);
-
-    if ((value = ldap_get_values(BrowseLDAPHandle, e,
-                                 "printerType")) == NULL)
+    if (ldap_getval_firststring(BrowseLDAPHandle, e,
+                                "printerType", type_num, sizeof(type_num)) == -1)
       continue;
 
-    type = atoi(*value);
-    ldap_value_free(value);
+    type = atoi(type_num);
 
-    if ((value = ldap_get_values(BrowseLDAPHandle, e,
-                                 "printerURI")) == NULL)
+    if (ldap_getval_firststring(BrowseLDAPHandle, e,
+                                "printerURI", uri, sizeof(uri)) == -1)
       continue;
 
-    strlcpy(uri, *value, sizeof(uri));
-    ldap_value_free(value);
-
    /*
     * Process the entry as browse data...
     */
@@ -1646,8 +2003,10 @@ cupsdUpdateLDAPBrowse(void)
                           location, info, make_model, 0, NULL);
 
   }
+
+  ldap_freeres(res);
 }
-#endif /* HAVE_OPENLDAP */
+#endif /* HAVE_LDAP */
 
 
 #ifdef HAVE_LIBSLP 
@@ -3232,7 +3591,346 @@ send_cups_browse(cupsd_printer_t *p)    /* I - Printer to send */
 }
 
 
-#ifdef HAVE_OPENLDAP
+#ifdef HAVE_LDAP
+/*
+ * 'ldap_search_rec()' - LDAP Search with reconnect
+ */
+
+static int
+ldap_search_rec(LDAP        *ld,       /* I - LDAP handler */
+                char        *base,     /* I - Base dn */
+                int         scope,     /* I - LDAP search scope */
+                char        *filter,   /* I - Filter string */
+                char        *attrs[],  /* I - Requested attributes */
+                int         attrsonly, /* I - Return only attributes? */
+                LDAPMessage **res)     /* I - LDAP handler */
+{
+  int  rc;                             /* Return code */
+
+
+#  if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+  rc = ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly, NULL, NULL,
+                         NULL, LDAP_NO_LIMIT, res);
+#  else
+  rc = ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res);
+#  endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+
+ /*
+  * If we have a connection problem try again...
+  */
+
+  if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                    "LDAP search failed with status %d: %s",
+                     rc, ldap_err2string(rc));
+    cupsdLogMessage(CUPSD_LOG_INFO,
+                    "We try the LDAP search once again after reconnecting to "
+                   "the server");
+    ldap_freeres(*res);
+    ldap_reconnect();
+
+#  if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+    rc = ldap_search_ext_s(ld, base, scope, filter, attrs, attrsonly, NULL,
+                           NULL, NULL, LDAP_NO_LIMIT, res);
+#  else
+    rc = ldap_search_s(ld, base, scope, filter, attrs, attrsonly, res);
+#  endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+  }
+
+  if (rc == LDAP_NO_SUCH_OBJECT)
+    cupsdLogMessage(CUPSD_LOG_DEBUG,
+                    "ldap_search_rec: LDAP entry/object not found");
+  else if (rc != LDAP_SUCCESS)
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                    "ldap_search_rec: LDAP search failed with status %d: %s",
+                     rc, ldap_err2string(rc));
+
+  if (rc != LDAP_SUCCESS)
+    ldap_freeres(*res);
+
+  return (rc);
+}
+
+
+/*
+ * 'ldap_freeres()' - Free LDAPMessage
+ */
+
+static void
+ldap_freeres(LDAPMessage *entry)       /* I - LDAP handler */
+{
+  int  rc;                             /* Return value */
+
+
+  rc = ldap_msgfree(entry);
+  if (rc == -1)
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                    "Can't free LDAPMessage!");
+  else if (rc == 0)
+    cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                    "Freeing LDAPMessage was unnecessary");
+}
+
+
+/*
+ * 'ldap_getval_char()' - Get first LDAP value and convert to string
+ */
+
+static int
+ldap_getval_firststring(
+    LDAP          *ld,                 /* I - LDAP handler */
+    LDAPMessage   *entry,              /* I - LDAP message or search result */
+    char          *attr,               /* I - the wanted attribute  */
+    char          *retval,             /* O - String to return */
+    unsigned long maxsize)             /* I - Max string size */
+{
+  char                 *dn;            /* LDAP DN */
+  int                  rc = 0;         /* Return code */
+#  if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+  struct berval                **bval;         /* LDAP value array */
+  unsigned long                size;           /* String size */
+
+
+ /*
+  * Get value from LDAPMessage...
+  */
+
+  if ((bval = ldap_get_values_len(ld, entry, attr)) == NULL)
+  {
+    rc = -1;
+    dn = ldap_get_dn(ld, entry);
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                    "Failed to get LDAP value %s for %s!",
+                    attr, dn);
+    ldap_memfree(dn);
+  }
+  else
+  {
+
+   /*
+    * Check size and copy value into our string...
+    */
+
+    size = maxsize;
+    if (size < bval[0]->bv_len)
+    {
+      rc = -1;
+      dn = ldap_get_dn(ld, entry);
+      cupsdLogMessage(CUPSD_LOG_WARN,
+                      "Attribute %s is too big! (dn: %s)",
+                      attr, dn);
+      ldap_memfree(dn);
+    }
+    else
+      size = bval[0]->bv_len;
+
+    strlcpy(retval, bval[0]->bv_val, size);
+    ldap_value_free_len(bval);
+  }
+#  else
+  char                 **value;        /* LDAP value */
+
+ /*
+  * Get value from LDAPMessage...
+  */
+
+  if ((value = (char **)ldap_get_values(ld, entry, attr)) == NULL)
+  {
+    rc = -1;
+    dn = ldap_get_dn(ld, entry);
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                    "Failed to get LDAP value %s for %s!",
+                    attr, dn);
+    ldap_memfree(dn);
+  }
+  else
+  {
+    strlcpy(retval, *value, maxsize);
+    ldap_value_free(value);
+  }
+#  endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+
+  return (rc);
+}
+
+
+/*
+ * 'send_ldap_ou()' - Send LDAP ou registrations.
+ */
+
+static void
+send_ldap_ou(char *ou,                 /* I - Servername/ou to register */
+             char *basedn,             /* I - Our base dn */
+             char *descstring)         /* I - Description for ou */
+{
+  int           i;                      /* Looping var... */
+  LDAPMod       mods[3];                /* The 3 attributes we will be adding */
+  LDAPMod       *pmods[4];              /* Pointers to the 3 attributes + NULL */
+  LDAPMessage   *res,                   /* Search result token */
+               *e;                     /* Current entry from search */
+  int           rc;                     /* LDAP status */
+  char          dn[1024],               /* DN of the organizational unit we are adding */
+                *desc[2],               /* Change records */
+                *ou_value[2];
+  char         old_desc[1024];         /* Old description */
+  static const char * const objectClass_values[] =
+               {                       /* The 2 objectClass's we use in */
+                 "top",                /* our LDAP entries              */
+                 "organizationalUnit",
+                 NULL
+               };
+  static const char * const ou_attrs[] =/* CUPS LDAP attributes */
+               {
+                 "description",
+                 NULL
+               };
+
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: %s", ou);
+
+ /*
+  * Reconnect if LDAP Handle is invalid...
+  */
+
+  if (! BrowseLDAPHandle)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                    "send_ldap_ou: LDAP Handle is invalid. Try "
+                   "reconnecting...");
+    ldap_reconnect();
+    return;
+  }
+
+ /*
+  * Prepare ldap search...
+  */
+
+  snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_ou: dn=\"%s\"", dn);
+
+  ou_value[0] = ou;
+  ou_value[1] = NULL;
+  desc[0]     = descstring;
+  desc[1]     = NULL;
+  
+  mods[0].mod_type   = "ou";
+  mods[0].mod_values = ou_value;
+  mods[1].mod_type   = "description";
+  mods[1].mod_values = desc;
+  mods[2].mod_type   = "objectClass";
+  mods[2].mod_values = (char **)objectClass_values;
+
+  rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
+                       (char **)ou_attrs, 0, &res);
+
+ /*
+  * If ldap search was not successfull then exit function...
+  */
+
+  if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
+    return;
+
+ /*
+  * Check if we need to insert or update the LDAP entry...
+  */
+
+  if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
+      rc != LDAP_NO_SUCH_OBJECT)
+  {
+   /*
+    * Printserver has already been registered, check if
+    * modification is required...
+    */
+
+    e = ldap_first_entry(BrowseLDAPHandle, res);
+
+   /*
+    * Get the required values from this entry...
+    */
+
+    if (ldap_getval_firststring(BrowseLDAPHandle, e, "description", old_desc,
+                                sizeof(old_desc)) == -1)
+      old_desc[0] = '\0';
+
+   /*
+    * Check if modification is required...
+    */
+
+    if ( strcmp(desc[0], old_desc) == 0 )
+    {
+     /*
+      * LDAP entry for the printer exists.
+      * Printer has already been registered,
+      * no modifications required...
+      */
+      cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                      "send_ldap_ou: No updates required for %s", ou);
+    }
+    else
+    {
+
+      cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                      "send_ldap_ou: Replace entry for %s", ou);
+
+      for (i = 0; i < 3; i ++)
+      {
+        pmods[i]         = mods + i;
+        pmods[i]->mod_op = LDAP_MOD_REPLACE;
+      }
+      pmods[i] = NULL;
+
+#  if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+      if ((rc = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+                                  NULL)) != LDAP_SUCCESS)
+#  else
+      if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+#  endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+      {
+        cupsdLogMessage(CUPSD_LOG_ERROR,
+                        "LDAP modify for %s failed with status %d: %s",
+                        ou, rc, ldap_err2string(rc));
+        if ( LDAP_SERVER_DOWN == rc )
+          ldap_reconnect();
+      }
+    }
+  }
+  else
+  {
+   /*
+    * Printserver has never been registered,
+    * add registration...
+    */
+
+    cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                    "send_ldap_ou: Add entry for %s", ou);
+
+    for (i = 0; i < 3; i ++)
+    {
+      pmods[i]         = mods + i;
+      pmods[i]->mod_op = LDAP_MOD_ADD;
+    }
+    pmods[i] = NULL;
+
+#  if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+    if ((rc = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+                             NULL)) != LDAP_SUCCESS)
+#  else
+    if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+#  endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                      "LDAP add for %s failed with status %d: %s",
+                      ou, rc, ldap_err2string(rc));
+      if ( LDAP_SERVER_DOWN == rc )
+        ldap_reconnect();
+    }
+  }
+
+  ldap_freeres(res);
+}
+
+
 /*
  * 'send_ldap_browse()' - Send LDAP printer registrations.
  */
@@ -3243,7 +3941,8 @@ send_ldap_browse(cupsd_printer_t *p)      /* I - Printer to register */
   int          i;                      /* Looping var... */
   LDAPMod      mods[7];                /* The 7 attributes we will be adding */
   LDAPMod      *pmods[8];              /* Pointers to the 7 attributes + NULL */
-  LDAPMessage  *res;                   /* Search result token */
+  LDAPMessage  *res,                   /* Search result token */
+               *e;                     /* Current entry from search */
   char         *cn_value[2],           /* Change records */
                *uri[2],
                *info[2],
@@ -3251,9 +3950,14 @@ send_ldap_browse(cupsd_printer_t *p)     /* I - Printer to register */
                *make_model[2],
                *type[2],
                typestring[255],        /* String to hold printer-type */
-               filter[256],            /* Search filter for possible UPDATEs */
                dn[1024];               /* DN of the printer we are adding */
   int          rc;                     /* LDAP status */
+  char         old_uri[HTTP_MAX_URI],  /* Printer URI */
+               old_location[1024],     /* Printer location */
+               old_info[1024],         /* Printer information */
+               old_make_model[1024],   /* Printer make and model */
+               old_type_string[30];    /* Temporary type number */
+  int          old_type;               /* Printer type */
   static const char * const objectClass_values[] =
                {                       /* The 3 objectClass's we use in */
                  "top",                /* our LDAP entries              */
@@ -3262,8 +3966,34 @@ send_ldap_browse(cupsd_printer_t *p)     /* I - Printer to register */
                  NULL
                };
 
+
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: %s", p->name);
 
+ /*
+  * Exit function if LDAP updates has been disabled...
+  */
+
+  if (!BrowseLDAPUpdate)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                    "send_ldap_browse: Updates temporary disabled; "
+                   "skipping...");
+    return;
+  }
+
+ /*
+  * Reconnect if LDAP Handle is invalid...
+  */
+
+  if (!BrowseLDAPHandle)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                    "send_ldap_browse: LDAP Handle is invalid. Try "
+                   "reconnecting...");
+    ldap_reconnect();
+    return;
+  }
+
  /*
   * Everything in ldap is ** so we fudge around it...
   */
@@ -3283,63 +4013,153 @@ send_ldap_browse(cupsd_printer_t *p)   /* I - Printer to register */
   uri[0]        = p->uri;
   uri[1]        = NULL;
 
-  snprintf(filter, sizeof(filter),
-           "(&(objectclass=cupsPrinter)(printerURI=%s))", p->uri);
+ /*
+  * Get ldap entry for printer ...
+  */
 
-  ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
-                filter, (char **)ldap_attrs, 0, &res);
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: Searching \"%s\"",
-                  filter);
+  snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
+           BrowseLDAPDN);
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
 
-  mods[0].mod_type = "cn";
+  rc = ldap_search_rec(BrowseLDAPHandle, dn, LDAP_SCOPE_BASE, NULL,
+                       (char **)ldap_attrs, 0, &res);
+
+ /*
+  * If ldap search was not successfull then exit function
+  * and temporary disable LDAP updates...
+  */
+
+  if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
+  {
+    if (BrowseLDAPUpdate &&
+        (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR))
+    {
+      BrowseLDAPUpdate = FALSE;
+      cupsdLogMessage(CUPSD_LOG_INFO,
+                      "LDAP update temporary disabled");
+    }
+
+    return;
+  }
+
+ /*
+  * Fill modification array...
+  */
+
+  mods[0].mod_type   = "cn";
   mods[0].mod_values = cn_value;
-  mods[1].mod_type = "printerDescription";
+  mods[1].mod_type   = "printerDescription";
   mods[1].mod_values = info;
-  mods[2].mod_type = "printerURI";
+  mods[2].mod_type   = "printerURI";
   mods[2].mod_values = uri;
-  mods[3].mod_type = "printerLocation";
+  mods[3].mod_type   = "printerLocation";
   mods[3].mod_values = location;
-  mods[4].mod_type = "printerMakeAndModel";
+  mods[4].mod_type   = "printerMakeAndModel";
   mods[4].mod_values = make_model;
-  mods[5].mod_type = "printerType";
+  mods[5].mod_type   = "printerType";
   mods[5].mod_values = type;
-  mods[6].mod_type = "objectClass";
+  mods[6].mod_type   = "objectClass";
   mods[6].mod_values = (char **)objectClass_values;
 
-  snprintf(dn, sizeof(dn), "cn=%s,ou=printers,%s", p->name, BrowseLDAPDN);
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_ldap_browse: dn=\"%s\"", dn);
+ /*
+  * Check if we need to insert or update the LDAP entry...
+  */
 
-  if (ldap_count_entries(BrowseLDAPHandle, res) > 0)
+  if (ldap_count_entries(BrowseLDAPHandle, res) > 0 &&
+      rc != LDAP_NO_SUCH_OBJECT)
   {
    /*
-    * Printer has already been registered, modify the current
-    * registration...
+    * Printer has already been registered, check if
+    * modification is required...
     */
 
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "send_ldap_browse: Replacing entry...");
+    e = ldap_first_entry(BrowseLDAPHandle, res);
 
-    for (i = 0; i < 7; i ++)
+   /*
+    * Get the required values from this entry...
+    */
+
+    if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerDescription",
+                                old_info, sizeof(old_info)) == -1)
+      old_info[0] = '\0';
+
+    if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerLocation",
+                                old_location, sizeof(old_location)) == -1)
+      old_info[0] = '\0';
+
+    if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerMakeAndModel",
+                                old_make_model, sizeof(old_make_model)) == -1)
+      old_info[0] = '\0';
+
+    if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerType",
+                                old_type_string, sizeof(old_type_string)) == -1)
+      old_info[0] = '\0';
+
+    old_type = atoi(old_type_string);
+
+    if (ldap_getval_firststring(BrowseLDAPHandle, e, "printerURI", old_uri,
+                                sizeof(old_uri)) == -1)
+      old_info[0] = '\0';
+
+   /*
+    * Check if modification is required...
+    */
+
+    if (!strcmp(info[0], old_info) && !strcmp(uri[0], old_uri) &&
+        !strcmp(location[0], old_location) &&
+       !strcmp(make_model[0], old_make_model) && p->type == old_type)
     {
-      pmods[i]         = mods + i;
-      pmods[i]->mod_op = LDAP_MOD_REPLACE;
+     /*
+      * LDAP entry for the printer exists. Printer has already been registered,
+      * no modifications required...
+      */
+
+      cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                       "send_ldap_browse: No updates required for %s", p->name);
     }
-    pmods[i] = NULL;
+    else
+    {
+     /*
+      * LDAP entry for the printer exists.  Printer has already been registered,
+      * modify the current registration...
+      */
 
-    if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "LDAP modify for %s failed with status %d: %s",
-                      p->name, rc, ldap_err2string(rc));
+      cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                      "send_ldap_browse: Replace entry for %s", p->name);
+
+      for (i = 0; i < 7; i ++)
+      {
+        pmods[i]         = mods + i;
+        pmods[i]->mod_op = LDAP_MOD_REPLACE;
+      }
+      pmods[i] = NULL;
+
+#  if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+      if ((rc = ldap_modify_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+                                  NULL)) != LDAP_SUCCESS)
+#  else
+      if ((rc = ldap_modify_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+#  endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+      {
+        cupsdLogMessage(CUPSD_LOG_ERROR,
+                        "LDAP modify for %s failed with status %d: %s",
+                        p->name, rc, ldap_err2string(rc));
+        if (rc == LDAP_SERVER_DOWN)
+          ldap_reconnect();
+      }
+    }
   }
   else 
   {
    /*
-    * Printer has never been registered, add the current
-    * registration...
+    * No LDAP entry exists for the printer.  Printer has never been registered,
+    * add the current registration...
     */
 
+    send_ldap_ou(ServerName, BrowseLDAPDN, "CUPS Server");
+
     cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "send_ldap_browse: Adding entry...");
+                    "send_ldap_browse: Add entry for %s", p->name);
 
     for (i = 0; i < 7; i ++)
     {
@@ -3348,13 +4168,155 @@ send_ldap_browse(cupsd_printer_t *p)   /* I - Printer to register */
     }
     pmods[i] = NULL;
 
+#  if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+    if ((rc = ldap_add_ext_s(BrowseLDAPHandle, dn, pmods, NULL,
+                             NULL)) != LDAP_SUCCESS)
+#  else
     if ((rc = ldap_add_s(BrowseLDAPHandle, dn, pmods)) != LDAP_SUCCESS)
+#  endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+    {
       cupsdLogMessage(CUPSD_LOG_ERROR,
                       "LDAP add for %s failed with status %d: %s",
                       p->name, rc, ldap_err2string(rc));
+      if (rc == LDAP_SERVER_DOWN)
+        ldap_reconnect();
+    }
   }
+
+  ldap_freeres(res);
 }
-#endif /* HAVE_OPENLDAP */
+
+
+/*
+ * 'ldap_dereg_printer()' - Delete printer from directory
+ */
+
+static void
+ldap_dereg_printer(cupsd_printer_t *p) /* I - Printer to deregister */
+{
+  char         dn[1024];               /* DN of the printer */
+  int          rc;                     /* LDAP status */
+
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: Remove entry for %s",
+                  p->name);
+
+ /*
+  * Reconnect if LDAP Handle is invalid...
+  */
+
+  if (!BrowseLDAPHandle)
+  {
+    ldap_reconnect();
+    return;
+  }
+
+ /*
+  * Get dn for printer and delete LDAP entry...
+  */
+
+  snprintf(dn, sizeof(dn), "cn=%s, ou=%s, %s", p->name, ServerName,
+           BrowseLDAPDN);
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_printer: dn=\"%s\"", dn);
+
+#  if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+  if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+                              NULL)) != LDAP_SUCCESS)
+#  else
+  if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+#  endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                    "LDAP delete for %s failed with status %d: %s",
+                    p->name, rc, ldap_err2string(rc));
+
+   /*
+    * If we had a connection problem (connection timed out, etc.)
+    * we should reconnect and try again to delete the entry...
+    */
+
+    if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
+    {
+      cupsdLogMessage(CUPSD_LOG_INFO,
+                      "Retry deleting LDAP entry for %s after a reconnect...", p->name);
+      ldap_reconnect();
+
+#  if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+      if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+                                  NULL)) != LDAP_SUCCESS)
+#  else
+      if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+#  endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+        cupsdLogMessage(CUPSD_LOG_WARN,
+                        "LDAP delete for %s failed with status %d: %s",
+                        p->name, rc, ldap_err2string(rc));
+    }
+  }
+}
+
+
+static void
+ldap_dereg_ou(char *ou,                        /* I - Organizational unit (servername) */
+              char *basedn)            /* I - Dase dn */
+{
+  char         dn[1024];               /* DN of the printer */
+  int          rc;                     /* LDAP status */
+
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: Remove entry for %s", ou);
+
+ /*
+  * Reconnect if LDAP Handle is invalid...
+  */
+
+  if (!BrowseLDAPHandle)
+  {
+    ldap_reconnect();
+    return;
+  }
+
+ /*
+  * Get dn for printer and delete LDAP entry...
+  */
+
+  snprintf(dn, sizeof(dn), "ou=%s, %s", ou, basedn);
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "ldap_dereg_ou: dn=\"%s\"", dn);
+
+#  if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+  if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+                              NULL)) != LDAP_SUCCESS)
+#  else
+  if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+#  endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                    "LDAP delete for %s failed with status %d: %s",
+                    ou, rc, ldap_err2string(rc));
+
+   /*
+    * If we had a connection problem (connection timed out, etc.)
+    * we should reconnect and try again to delete the entry...
+    */
+
+    if (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR)
+    {
+      cupsdLogMessage(CUPSD_LOG_INFO,
+                      "Retry deleting LDAP entry for %s after a reconnect...", ou);
+      ldap_reconnect();
+#  if defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000
+      if ((rc = ldap_delete_ext_s(BrowseLDAPHandle, dn, NULL,
+                                  NULL)) != LDAP_SUCCESS)
+#  else
+      if ((rc = ldap_delete_s(BrowseLDAPHandle, dn)) != LDAP_SUCCESS)
+#  endif /* defined(HAVE_OPENLDAP) && LDAP_API_VERSION > 3000 */
+        cupsdLogMessage(CUPSD_LOG_WARN,
+                        "LDAP delete for %s failed with status %d: %s",
+                        ou, rc, ldap_err2string(rc));
+    }
+
+  }
+}
+#endif /* HAVE_LDAP */
 
 
 #ifdef HAVE_LIBSLP
index 60c22c3bd0ccbb66bf76770c7bb273b8922196ff..7de4e2d56eecad7876302709e0be0cae6bdec2e8 100644 (file)
 #  include <slp.h>
 #endif /* HAVE_LIBSLP */
 
-#ifdef HAVE_OPENLDAP
+#ifdef HAVE_LDAP
 #  ifdef __sun
 #    include <lber.h>
 #  endif /* __sun */
 #  include <ldap.h>
-#endif /* HAVE_OPENLDAP */
+#  ifdef HAVE_LDAP_SSL_H
+#    include <ldap_ssl.h>
+#  endif /* HAVE_LDAP_SSL_H */
+#endif /* HAVE_LDAP */
 
 /*
  * Browse protocols...
@@ -150,22 +153,26 @@ VAR time_t                BrowseSLPRefresh VALUE(0);
 #endif /* HAVE_LIBSLP */
 
 #ifdef HAVE_LDAP
-#  ifdef HAVE_OPENLDAP
 VAR LDAP               *BrowseLDAPHandle VALUE(NULL);
                                        /* Handle to LDAP server */
-#  endif /* HAVE_OPENLDAP */
 VAR time_t             BrowseLDAPRefresh VALUE(0);
                                        /* Next LDAP refresh time */
 VAR char               *BrowseLDAPBindDN VALUE(NULL),
                                        /* LDAP login DN */
+                       *BrowseLDAPCACertFile VALUE(NULL),
+                                       /* LDAP CA cert file */
                        *BrowseLDAPDN   VALUE(NULL),
                                        /* LDAP search DN */
                        *BrowseLDAPPassword VALUE(NULL),
                                        /* LDAP login password */
-                       *BrowseLDAPServer VALUE(NULL),
+                       *BrowseLDAPServer VALUE(NULL);
                                        /* LDAP server to use */
-                       *BrowseLDAPCACertFile VALUE(NULL);
+VAR int                        BrowseLDAPUpdate VALUE(TRUE);
+                                       /* enables LDAP updates */
+#  ifdef HAVE_LDAP_SSL
+VAR char               *BrowseLDAPCACertFile VALUE(NULL);
                                        /* LDAP CA CERT file to use */
+#  endif /* HAVE_LDAP_SSL */
 #endif /* HAVE_LDAP */
 VAR char               *LPDConfigFile  VALUE(NULL),
                                        /* LPD configuration file */
index b6beb3ee0424122c156d7e35ffafb94d53e1bb67..571b3a7fcb64822a03af0801867dcbf07fe79ff8 100644 (file)
@@ -1418,6 +1418,7 @@ launchd_checkin(void)
                    "launchd_checkin: launch_msg(\"" LAUNCH_KEY_CHECKIN
                    "\") IPC failure");
     exit(EXIT_FAILURE);
+    return; /* anti-compiler-warning */
   }
 
   if (launch_data_get_type(ld_resp) == LAUNCH_DATA_ERRNO)
@@ -1426,28 +1427,32 @@ launchd_checkin(void)
     cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_checkin: Check-in failed: %s",
                     strerror(errno));
     exit(EXIT_FAILURE);
+    return; /* anti-compiler-warning */
   }
 
  /*
   * Get the sockets dictionary...
   */
 
-  if (!(ld_sockets = launch_data_dict_lookup(ld_resp, LAUNCH_JOBKEY_SOCKETS)))
+  if ((ld_sockets = launch_data_dict_lookup(ld_resp, LAUNCH_JOBKEY_SOCKETS))
+          == NULL)
   {
     cupsdLogMessage(CUPSD_LOG_ERROR,
                     "launchd_checkin: No sockets found to answer requests on!");
     exit(EXIT_FAILURE);
+    return; /* anti-compiler-warning */
   }
 
  /*
   * Get the array of listener sockets...
   */
 
-  if (!(ld_array = launch_data_dict_lookup(ld_sockets, "Listeners")))
+  if ((ld_array = launch_data_dict_lookup(ld_sockets, "Listeners")) == NULL)
   {
     cupsdLogMessage(CUPSD_LOG_ERROR,
                     "launchd_checkin: No sockets found to answer requests on!");
     exit(EXIT_FAILURE);
+    return; /* anti-compiler-warning */
   }
 
  /*
@@ -1464,73 +1469,75 @@ launchd_checkin(void)
       * Get the launchd file descriptor and address...
       */
 
-      tmp     = launch_data_array_get_index(ld_array, i);
-      fd      = launch_data_get_fd(tmp);
-      addrlen = sizeof(addr);
-
-      if (getsockname(fd, (struct sockaddr *)&addr, &addrlen))
+      if ((tmp = launch_data_array_get_index(ld_array, i)) != NULL)
       {
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "launchd_checkin: Unable to get local address - %s",
-                       strerror(errno));
-       continue;
-      }
+       fd      = launch_data_get_fd(tmp);
+       addrlen = sizeof(addr);
 
-     /*
-      * Try to match the launchd socket address to one of the listeners...
-      */
+       if (getsockname(fd, (struct sockaddr *)&addr, &addrlen))
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "launchd_checkin: Unable to get local address - %s",
+                         strerror(errno));
+         continue;
+       }
 
-      for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
-          lis;
-          lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
-       if (httpAddrEqual(&lis->address, &addr))
-         break;
+       /*
+       * Try to match the launchd socket address to one of the listeners...
+       */
 
-     /*
-      * Add a new listener If there's no match...
-      */
+       for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
+            lis;
+            lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
+         if (httpAddrEqual(&lis->address, &addr))
+           break;
 
-      if (lis)
-      {
-       cupsdLogMessage(CUPSD_LOG_DEBUG, 
-               "launchd_checkin: Matched existing listener %s with fd %d...",
-               httpAddrString(&(lis->address), s, sizeof(s)), fd);
-      }
-      else
-      {
-       cupsdLogMessage(CUPSD_LOG_DEBUG, 
-               "launchd_checkin: Adding new listener %s with fd %d...",
-               httpAddrString(&addr, s, sizeof(s)), fd);
+       /*
+       * Add a new listener If there's no match...
+       */
 
-        if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
-        {
-         cupsdLogMessage(CUPSD_LOG_ERROR,
-                                 "launchd_checkin: Unable to allocate listener - %s.",
-                         strerror(errno));
-         exit(EXIT_FAILURE);
-        }
+       if (lis)
+       {
+         cupsdLogMessage(CUPSD_LOG_DEBUG, 
+                 "launchd_checkin: Matched existing listener %s with fd %d...",
+                 httpAddrString(&(lis->address), s, sizeof(s)), fd);
+       }
+       else
+       {
+         cupsdLogMessage(CUPSD_LOG_DEBUG, 
+                 "launchd_checkin: Adding new listener %s with fd %d...",
+                 httpAddrString(&addr, s, sizeof(s)), fd);
 
-        cupsArrayAdd(Listeners, lis);
+         if ((lis = calloc(1, sizeof(cupsd_listener_t))) == NULL)
+         {
+           cupsdLogMessage(CUPSD_LOG_ERROR,
+                           "launchd_checkin: Unable to allocate listener - %s.",
+                           strerror(errno));
+           exit(EXIT_FAILURE);
+         }
 
-       memcpy(&lis->address, &addr, sizeof(lis->address));
-      }
+         cupsArrayAdd(Listeners, lis);
 
-      lis->fd = fd;
+         memcpy(&lis->address, &addr, sizeof(lis->address));
+       }
+
+       lis->fd = fd;
 
 #  ifdef HAVE_SSL
-      portnum = 0;
+       portnum = 0;
 
 #    ifdef AF_INET6
-      if (lis->address.addr.sa_family == AF_INET6)
-       portnum = ntohs(lis->address.ipv6.sin6_port);
-      else
+       if (lis->address.addr.sa_family == AF_INET6)
+         portnum = ntohs(lis->address.ipv6.sin6_port);
+       else
 #    endif /* AF_INET6 */
-      if (lis->address.addr.sa_family == AF_INET)
-       portnum = ntohs(lis->address.ipv4.sin_port);
+       if (lis->address.addr.sa_family == AF_INET)
+         portnum = ntohs(lis->address.ipv4.sin_port);
 
-      if (portnum == 443)
-       lis->encryption = HTTP_ENCRYPT_ALWAYS;
+       if (portnum == 443)
+         lis->encryption = HTTP_ENCRYPT_ALWAYS;
 #  endif /* HAVE_SSL */
+      }
     }
   }
 
index b8052b3b588ae4114d2d761819e40ea8b101c185..e398d3f4ca94a5f626282519f4d11d7399a08f21 100644 (file)
  *   main()               - Main entry for test program.
  *   check_basics()       - Check for CR LF, mixed line endings, and blank
  *                          lines.
+ *   check_case()         - Check that there are no duplicate groups, options,
+ *                          or choices that differ only by case.
  *   check_constraints()  - Check UIConstraints in the PPD file.
  *   check_defaults()     - Check default option keywords in the PPD file.
+ *   check_duplex()       - Check duplex keywords in the PPD file.
  *   check_filters()      - Check filters in the PPD file.
  *   check_profiles()     - Check ICC color profiles in the PPD file.
  *   check_translations() - Check translations in the PPD file.
@@ -58,7 +61,8 @@ enum
   WARN_FILTERS = 4,
   WARN_PROFILES = 8,
   WARN_TRANSLATIONS = 16,
-  WARN_ALL = 31
+  WARN_DUPLEX = 32,
+  WARN_ALL = 63
 };
 
 
@@ -96,8 +100,11 @@ enum
 static void    check_basics(const char *filename);
 static int     check_constraints(ppd_file_t *ppd, int errors, int verbose,
                                  int warn);
+static int     check_case(ppd_file_t *ppd, int errors, int verbose);
 static int     check_defaults(ppd_file_t *ppd, int errors, int verbose,
                               int warn);
+static int     check_duplex(ppd_file_t *ppd, int errors, int verbose,
+                            int warn);
 static int     check_filters(ppd_file_t *ppd, const char *root, int errors,
                              int verbose, int warn);
 static int     check_profiles(ppd_file_t *ppd, const char *root, int errors,
@@ -190,6 +197,8 @@ main(int  argc,                             /* I - Number of command-line args */
                warn |= WARN_CONSTRAINTS;
              else if (!strcmp(argv[i], "defaults"))
                warn |= WARN_DEFAULTS;
+             else if (!strcmp(argv[i], "duplex"))
+               warn |= WARN_DUPLEX;
              else if (!strcmp(argv[i], "filters"))
                warn |= WARN_FILTERS;
              else if (!strcmp(argv[i], "profiles"))
@@ -1008,55 +1017,6 @@ main(int  argc,                          /* I - Number of command-line args */
        }
       }
 
-     /*
-      * Check for a duplex option, and for standard values...
-      */
-
-      if ((option = ppdFindOption(ppd, "Duplex")) == NULL)
-       if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL)
-         if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
-            option = ppdFindOption(ppd, "KD03Duplex");
-
-      if (option != NULL)
-      {
-        if (ppdFindChoice(option, "None") == NULL)
-       {
-         if (verbose >= 0)
-         {
-           if (!errors && !verbose)
-             _cupsLangPuts(stdout, _(" FAIL\n"));
-
-           _cupsLangPrintf(stdout,
-                           _("      **FAIL**  REQUIRED %s does not define "
-                             "choice None!\n"
-                             "                REF: Page 122, section 5.17\n"),
-                           option->keyword);
-          }
-
-         errors ++;
-       }
-
-        for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++)
-          if (strcmp(choice->choice, "None") &&
-             strcmp(choice->choice, "DuplexNoTumble") &&
-             strcmp(choice->choice, "DuplexTumble") &&
-             strcmp(choice->choice, "SimplexTumble"))
-         {
-           if (verbose >= 0)
-           {
-             if (!errors && !verbose)
-               _cupsLangPuts(stdout, _(" FAIL\n"));
-
-             _cupsLangPrintf(stdout,
-                             _("      **FAIL**  Bad %s choice %s!\n"
-                               "                REF: Page 122, section 5.17\n"),
-                             option->keyword, choice->choice);
-            }
-
-           errors ++;
-         }
-      }
-
       if ((attr = ppdFindAttr(ppd, "1284DeviceID", NULL)) &&
           strcmp(attr->name, "1284DeviceID"))
       {
@@ -1074,6 +1034,8 @@ main(int  argc,                           /* I - Number of command-line args */
        errors ++;
       }
 
+      errors = check_case(ppd, errors, verbose);
+
       if (!(warn & WARN_CONSTRAINTS))
         errors = check_constraints(ppd, errors, verbose, 0);
 
@@ -1086,6 +1048,9 @@ main(int  argc,                           /* I - Number of command-line args */
       if (!(warn & WARN_TRANSLATIONS))
         errors = check_translations(ppd, errors, verbose, 0);
 
+      if (!(warn & WARN_DUPLEX))
+        errors = check_duplex(ppd, errors, verbose, 0);
+
       if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL &&
          attr->value)
       {
@@ -1217,6 +1182,24 @@ main(int  argc,                          /* I - Number of command-line args */
        if (warn & WARN_TRANSLATIONS)
          errors = check_translations(ppd, errors, verbose, 1);
 
+       if (warn & WARN_DUPLEX)
+         errors = check_duplex(ppd, errors, verbose, 1);
+
+       /*
+        * Look for legacy duplex keywords...
+       */
+
+       if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL)
+         if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
+           option = ppdFindOption(ppd, "KD03Duplex");
+
+       if (option)
+         _cupsLangPrintf(stdout,
+                         _("        WARN    Duplex option keyword %s may not "
+                           "work as expected and should be named Duplex!\n"
+                           "                REF: Page 122, section 5.17\n"),
+                         option->keyword);
+
        /*
        * Look for default keywords with no corresponding option...
        */
@@ -1246,22 +1229,6 @@ main(int  argc,                          /* I - Number of command-line args */
                            attr->name);
        }
 
-       /*
-        * Check for old Duplex option names...
-       */
-
-       if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
-          option = ppdFindOption(ppd, "KD03Duplex");
-
-        if (option)
-       {
-         _cupsLangPrintf(stdout,
-                         _("        WARN    Duplex option keyword %s "
-                           "should be named Duplex or JCLDuplex!\n"
-                           "                REF: Page 122, section 5.17\n"),
-                         option->keyword);
-       }
-
         ppdMarkDefaults(ppd);
        if (ppdConflicts(ppd))
        {
@@ -1964,6 +1931,116 @@ check_constraints(ppd_file_t *ppd,      /* I - PPD file */
 }
 
 
+/*
+ * 'check_case()' - Check that there are no duplicate groups, options,
+ *                  or choices that differ only by case.
+ */
+
+static int                             /* O - Errors found */
+check_case(ppd_file_t *ppd,            /* I - PPD file */
+           int        errors,          /* I - Errors found */
+          int        verbose)          /* I - Verbosity level */
+{
+  int          i, j;                   /* Looping vars */
+  ppd_group_t  *groupa,                /* First group */
+               *groupb;                /* Second group */
+  ppd_option_t *optiona,               /* First option */
+               *optionb;               /* Second option */
+  ppd_choice_t *choicea,               /* First choice */
+               *choiceb;               /* Second choice */
+
+
+ /*
+  * Check that the groups do not have any duplicate names...
+  */
+
+  for (i = ppd->num_groups, groupa = ppd->groups; i > 1; i --, groupa ++)
+    for (j = i - 1, groupb = groupa + 1; j > 0; j --, groupb ++)
+      if (!strcasecmp(groupa->name, groupb->name))
+      {
+       if (!errors && !verbose)
+         _cupsLangPuts(stdout, _(" FAIL\n"));
+
+       if (verbose >= 0)
+         _cupsLangPrintf(stdout,
+                         _("      **FAIL**  Group names %s and %s differ only "
+                           "by case!\n"),
+                         groupa->name, groupb->name);
+
+       errors ++;
+      }
+
+ /*
+  * Check that the options do not have any duplicate names...
+  */
+
+  for (optiona = ppdFirstOption(ppd); optiona; optiona = ppdNextOption(ppd))
+  {
+    cupsArraySave(ppd->options);
+    for (optionb = ppdNextOption(ppd); optionb; optionb = ppdNextOption(ppd))
+      if (!strcasecmp(optiona->keyword, optionb->keyword))
+      {
+       if (!errors && !verbose)
+         _cupsLangPuts(stdout, _(" FAIL\n"));
+
+       if (verbose >= 0)
+         _cupsLangPrintf(stdout,
+                         _("      **FAIL**  Option names %s and %s differ only "
+                           "by case!\n"),
+                         optiona->keyword, optionb->keyword);
+
+       errors ++;
+      }
+    cupsArrayRestore(ppd->options);
+
+   /*
+    * Then the choices...
+    */
+
+    for (i = optiona->num_choices, choicea = optiona->choices;
+         i > 1;
+        i --, choicea ++)
+      for (j = i - 1, choiceb = choicea + 1; j > 0; j --, choiceb ++)
+        if (!strcmp(choicea->choice, choiceb->choice))
+       {
+         if (!errors && !verbose)
+           _cupsLangPuts(stdout, _(" FAIL\n"));
+
+         if (verbose >= 0)
+           _cupsLangPrintf(stdout,
+                           _("      **FAIL**  Multiple occurrences of %s "
+                             "choice name %s!\n"),
+                           optiona->keyword, choicea->choice);
+
+         errors ++;
+
+         choicea ++;
+         i --;
+         break;
+       }
+        else if (!strcasecmp(choicea->choice, choiceb->choice))
+       {
+         if (!errors && !verbose)
+           _cupsLangPuts(stdout, _(" FAIL\n"));
+
+         if (verbose >= 0)
+           _cupsLangPrintf(stdout,
+                           _("      **FAIL**  %s choice names %s and %s "
+                             "differ only by case!\n"),
+                           optiona->keyword, choicea->choice, choiceb->choice);
+
+         errors ++;
+       }
+  }
+
+ /*
+  * Return the number of errors found...
+  */
+
+  return (errors);
+}
+
+
 /*
  * 'check_defaults()' - Check default option keywords in the PPD file.
  */
@@ -2031,6 +2108,76 @@ check_defaults(ppd_file_t *ppd,          /* I - PPD file */
 }
 
 
+/*
+ * 'check_duplex()' - Check duplex keywords in the PPD file.
+ */
+
+static int                             /* O - Errors found */
+check_duplex(ppd_file_t *ppd,          /* I - PPD file */
+             int        errors,                /* I - Error found */
+            int        verbose,        /* I - Verbosity level */
+             int        warn)          /* I - Warnings only? */
+{
+  int          i;                      /* Looping var */
+  ppd_option_t *option;                /* PPD option */
+  ppd_choice_t *choice;                /* Current choice */
+  const char   *prefix;                /* Message prefix */
+
+
+  prefix = warn ? "  WARN  " : "**FAIL**";
+
+ /*
+  * Check for a duplex option, and for standard values...
+  */
+
+  if ((option = ppdFindOption(ppd, "Duplex")) != NULL)
+  {
+    if (!ppdFindChoice(option, "None"))
+    {
+      if (verbose >= 0)
+      {
+       if (!warn && !errors && !verbose)
+         _cupsLangPuts(stdout, _(" FAIL\n"));
+
+       _cupsLangPrintf(stdout,
+                       _("      %s  REQUIRED %s does not define "
+                         "choice None!\n"
+                         "                REF: Page 122, section 5.17\n"),
+                       prefix, option->keyword);
+      }
+
+      if (!warn)
+       errors ++;
+    }
+
+    for (i = option->num_choices, choice = option->choices;
+        i > 0;
+        i --, choice ++)
+      if (strcmp(choice->choice, "None") &&
+         strcmp(choice->choice, "DuplexNoTumble") &&
+         strcmp(choice->choice, "DuplexTumble") &&
+         strcmp(choice->choice, "SimplexTumble"))
+      {
+       if (verbose >= 0)
+       {
+         if (!warn && !errors && !verbose)
+           _cupsLangPuts(stdout, _(" FAIL\n"));
+
+         _cupsLangPrintf(stdout,
+                         _("      %s  Bad %s choice %s!\n"
+                           "                REF: Page 122, section 5.17\n"),
+                         prefix, option->keyword, choice->choice);
+       }
+
+       if (!warn)
+         errors ++;
+      }
+  }
+
+  return (errors);
+}
+
+
 /*
  * 'check_filters()' - Check filters in the PPD file.
  */
@@ -2071,7 +2218,7 @@ check_filters(ppd_file_t *ppd,            /* I - PPD file */
       if (!warn)
         errors ++;
     }
-    else
+    else if (strcmp(program, "-"))
     {
       if (program[0] == '/')
        snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
@@ -2122,7 +2269,7 @@ check_filters(ppd_file_t *ppd,            /* I - PPD file */
       if (!warn)
         errors ++;
     }
-    else
+    else if (strcmp(program, "-"))
     {
       if (program[0] == '/')
        snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
@@ -2310,6 +2457,7 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
   ppd_cparam_t *cparam;                /* Custom parameter */
   char         ll[3];                  /* Base language */
   const char   *prefix;                /* WARN/FAIL prefix */
+  const char   *text;                  /* Pointer into UI text */
 
 
   prefix = warn ? "  WARN  " : "**FAIL**";
@@ -2397,6 +2545,22 @@ check_translations(ppd_file_t *ppd,      /* I - PPD file */
 
        for (j = 0; j < option->num_choices; j ++)
        {
+         /*
+         * First see if this choice is a number; if so, don't require
+         * translation...
+         */
+
+          for (text = option->choices[j].text; *text; text ++)
+           if (!strchr("0123456789-+.", *text))
+             break;
+
+          if (!*text)
+           continue;
+
+        /*
+         * Check custom choices differently...
+         */
+
          if (!strcasecmp(option->choices[j].choice, "Custom") &&
              (coption = ppdFindCustomOption(ppd,
                                             option->keyword)) != NULL)
@@ -2725,7 +2889,8 @@ usage(void)
                  "Options:\n"
                  "\n"
                  "    -R root-directory    Set alternate root\n"
-                 "    -W {all,none,constraints,defaults,filters,translations}\n"
+                 "    -W {all,none,constraints,defaults,duplex,filters,"
+                 "translations}\n"
                  "                         Issue warnings instead of errors\n"
                  "    -q                   Run silently\n"
                  "    -r                   Use 'relaxed' open mode\n"
index bd7fb0311b07faaf9f0fd4e4e04e15bddc2237ea..3e7cc1c6e3b59d50fb0ac73963001e20eedfe41b 100644 (file)
@@ -40,7 +40,8 @@
 static void    device_cb(const char *device_clas, const char *device_id,
                          const char *device_info,
                          const char *device_make_and_model,
-                         const char *device_uri, void *user_data);
+                         const char *device_uri, const char *device_location,
+                         void *user_data);
 static int     show_devices(http_t *, int);
 static int     show_models(http_t *, int);
 
@@ -173,6 +174,7 @@ device_cb(
     const char *device_info,           /* I - device-info string */
     const char *device_make_and_model, /* I - device-make-and-model string */
     const char *device_uri,            /* I - device-uri string */
+    const char *device_location,       /* I - device-location string */
     void       *user_data)             /* I - User data */
 {
   int  *long_status;                   /* Show verbose info? */
@@ -191,9 +193,10 @@ device_cb(
                      "        class = %s\n"
                      "        info = %s\n"
                      "        make-and-model = %s\n"
-                     "        device-id = %s\n"),
+                     "        device-id = %s\n"
+                     "        location = %s\n"),
                    device_uri, device_class, device_info,
-                   device_make_and_model, device_id);
+                   device_make_and_model, device_id, device_location);
   }
   else
     _cupsLangPrintf(stdout, "%s %s\n", device_class, device_uri);
index 08342d06e4fb9ff0a772d1cbce3f9caa10324d98..a2ce9d8c8cdd3869130da9fd0d58e843597a3075 100644 (file)
@@ -1,6 +1,18 @@
 <TR>
 <TH CLASS="label"{conflicted=1? CLASS="conflict":}><A NAME="{keyword}">{keytext}</A>:</TH>
-<TD><SELECT NAME="{keyword}">
+<TD><SELECT NAME="{keyword}" ID="select-{keyword}" ONCHANGE="update_paramtable('{keyword}')">
 {[choices]<OPTION {choices={defchoice}?SELECTED:} VALUE="{choices}">{text}}
-</SELECT></TD>
+</SELECT>
+{iscustom=1?<TABLE NAME="paramtable" id="{keyword}-params">{[params]
+<TR><TH CLASS="sublabel">{paramtext}:</TH>
+<TD>{params=Units?<SELECT NAME="{keyword}.{params}">
+<OPTION VALUE="pt"{paramvalue=pt? SELECTED:}>Points</OPTION>
+<OPTION VALUE="mm"{paramvalue=mm? SELECTED:}>Millimeters</OPTION>
+<OPTION VALUE="cm"{paramvalue=cm? SELECTED:}>Centimeters</OPTION>
+<OPTION VALUE="in"{paramvalue=in? SELECTED:}>Inches</OPTION>
+<OPTION VALUE="ft"{paramvalue=ft? SELECTED:}>Feet</OPTION>
+<OPTION VALUE="m"{paramvalue=m? SELECTED:}>Meters</OPTION>
+</SELECT>:<INPUT TYPE="{inputtype}" NAME="{keyword}.{params}" VALUE="{paramvalue}">}</TD></TR>
+}</TABLE>
+</TD>:}
 </TR>
index 864f9f0ced9bf5455d0dbbff27101b4ad137a216..56d2bb766acce812deffbdb459317c0ef546a7cf 100644 (file)
@@ -1,3 +1,16 @@
 <FORM METHOD="POST" ACTION="/admin">
 <INPUT TYPE="HIDDEN" NAME="PRINTER_NAME" VALUE="{printer_name}">
 <INPUT TYPE="HIDDEN" NAME="OP" VALUE="{op}">
+
+<SCRIPT TYPE="text/javascript"><!--
+function update_paramtable(option)
+{
+  var cb = document.getElementById("select-" + option)
+  var paramstable = document.getElementById(option + "-params");
+  if (cb.value == "Custom")
+    paramstable.style.display = "table";
+  else
+    paramstable.style.display = "none";
+}
+--></SCRIPT>
+
index a3d1e1ffaa67982f21baa9adb4e1866af29f1793..ac07cc9e13f5d9f30875c6f1d886da864b3526d2 100644 (file)
@@ -1 +1,12 @@
+<SCRIPT TYPE="text/javascript"><!--
+// Hide custom options parameters for browsers that understand Javascript
+var paramtables = document.getElementsByName("paramtable");
+for (var i = 0; i < paramtables.length; i++)
+{
+  var opt = paramtables[i].id.substr(0, paramtables[i].id.lastIndexOf("-"));
+  var cb = document.getElementById("select-" + opt);
+  if (cb.value != "Custom")
+    paramtables[i].style.display = "none";
+}
+--></SCRIPT>
 </FORM>