]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/dirsvc.c
Import CUPS trunk (1.4svn) r7116.
[thirdparty/cups.git] / scheduler / dirsvc.c
index 73abd7bfce43792f2708c905ce30399e38c03639..5303bf898ff7ba60486815475af9df503f3f6ff8 100644 (file)
@@ -1,25 +1,16 @@
 /*
- * "$Id: dirsvc.c 6309 2007-02-24 03:11:56Z mike $"
+ * "$Id: dirsvc.c 7003 2007-10-01 23:10:13Z mike $"
  *
  *   Directory services routines for the Common UNIX Printing System (CUPS).
  *
+ *   Copyright 2007 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products and are protected by Federal
- *   copyright law.  Distribution and use rights are outlined in the file
- *   "LICENSE.txt" which should have been included with this file.  If this
- *   file is missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
  *
  * Contents:
  *
  *   cupsdStopBrowsing()           - Stop sending and receiving broadcast
  *                                   information.
  *   cupsdStopPolling()            - Stop polling servers as needed.
- *   cupsdUpdateCUPSBrowse()       - Update the browse lists using the CUPS
- *                                   protocol.
  *   cupsdUpdateDNSSDBrowse()      - Handle DNS-SD queries.
  *   cupsdUpdateLDAPBrowse()       - Scan for new printers via LDAP...
- *   cupsdUpdatePolling()          - Read status messages from the poll daemons.
  *   cupsdUpdateSLPBrowse()        - Get browsing information via SLP.
  *   dnssdBuildTxtRecord()         - Build a TXT record from printer info.
  *   dnssdDeregisterPrinter()      - Stop sending broadcast information for a
  *   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.
  */
 
 /*
 
 #ifdef HAVE_DNSSD
 #  include <dns_sd.h>
-#  include <nameser.h>
-#  include <nameser.h>
-#  ifdef HAVE_COREFOUNDATION
-#    include <CoreFoundation/CoreFoundation.h>
-#  endif /* HAVE_COREFOUNDATION */
-#  ifdef HAVE_SYSTEMCONFIGURATION
-#    include <SystemConfiguration/SystemConfiguration.h>
-#  endif /* HAVE_SYSTEMCONFIGURATION */
+#  ifdef __APPLE__
+#    include <nameser.h>
+#    ifdef HAVE_COREFOUNDATION
+#      include <CoreFoundation/CoreFoundation.h>
+#    endif /* HAVE_COREFOUNDATION */
+#    ifdef HAVE_SYSTEMCONFIGURATION
+#      include <SystemConfiguration/SystemConfiguration.h>
+#    endif /* HAVE_SYSTEMCONFIGURATION */
+#  endif /* __APPLE__ */
 #endif /* HAVE_DNSSD */
 
 
@@ -97,7 +91,7 @@ static void   process_browse_data(const char *uri, const char *host,
                                    ipp_pstate_t state, const char *location,
                                    const char *info, const char *make_model,
                                    int num_attrs, cups_option_t *attrs);
-static void    process_implicit_classes(void);
+static void    process_implicit_classes(int *write_printcap);
 static void    send_cups_browse(cupsd_printer_t *p);
 #ifdef HAVE_LDAP
 static void    send_ldap_browse(cupsd_printer_t *p);
@@ -105,6 +99,11 @@ static void send_ldap_browse(cupsd_printer_t *p);
 #ifdef HAVE_LIBSLP
 static void    send_slp_browse(cupsd_printer_t *p);
 #endif /* HAVE_LIBSLP */
+static void    update_cups_browse(void);
+static void    update_lpd(int onoff);
+static void    update_polling(void);
+static void    update_smb(int onoff);
+
 
 #ifdef HAVE_OPENLDAP
 static const char * const ldap_attrs[] =/* CUPS LDAP attributes */
@@ -203,7 +202,7 @@ cupsdDeregisterPrinter(
   * Announce the deletion...
   */
 
-  if ((BrowseLocalProtocols & BROWSE_CUPS))
+  if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
   {
     cups_ptype_t savedtype = p->type;  /* Saved printer type */
 
@@ -315,7 +314,7 @@ cupsdLoadRemoteCache(void)
 
        p->accepting     = 1;
        p->state         = IPP_PRINTER_IDLE;
-       p->type          |= CUPS_PRINTER_REMOTE;
+       p->type          |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
        p->browse_time   = now;
        p->browse_expire = now + BrowseTimeout;
 
@@ -356,7 +355,7 @@ cupsdLoadRemoteCache(void)
 
        p->accepting     = 1;
        p->state         = IPP_PRINTER_IDLE;
-       p->type          |= CUPS_PRINTER_REMOTE;
+       p->type          |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
        p->browse_time   = now;
        p->browse_expire = now + BrowseTimeout;
 
@@ -610,7 +609,7 @@ cupsdLoadRemoteCache(void)
   * Do auto-classing if needed...
   */
 
-  process_implicit_classes();
+  process_implicit_classes(NULL);
 }
 
 
@@ -716,7 +715,7 @@ cupsdSaveRemoteCache(void)
     * Skip local destinations...
     */
 
-    if (!(printer->type & CUPS_PRINTER_REMOTE))
+    if (!(printer->type & CUPS_PRINTER_DISCOVERED))
       continue;
 
    /*
@@ -795,6 +794,7 @@ cupsdSendBrowseList(void)
   cupsd_printer_t      *p;             /* Current printer */
   time_t               ut,             /* Minimum update time */
                        to;             /* Timeout time */
+  int                  write_printcap; /* Write the printcap file? */
 
 
   if (!Browsing || !BrowseLocalProtocols || !Printers)
@@ -866,7 +866,7 @@ cupsdSendBrowseList(void)
 
        p->browse_time = time(NULL);
 
-       if (BrowseLocalProtocols & BROWSE_CUPS)
+       if ((BrowseLocalProtocols & BROWSE_CUPS) && BrowseSocket >= 0)
           send_cups_browse(p);
 
 #ifdef HAVE_LIBSLP
@@ -892,7 +892,7 @@ cupsdSendBrowseList(void)
   * Loop through all of the printers and send local updates as needed...
   */
 
-  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), write_printcap = 0;
        p;
        p = (cupsd_printer_t *)cupsArrayNext(Printers))
   {
@@ -900,7 +900,7 @@ cupsdSendBrowseList(void)
     * If this is a remote queue, see if it needs to be timed out...
     */
 
-    if (p->type & CUPS_PRINTER_REMOTE)
+    if (p->type & CUPS_PRINTER_DISCOVERED)
     {
       if (p->browse_expire < to)
       {
@@ -917,9 +917,13 @@ cupsdSendBrowseList(void)
         cupsArraySave(Printers);
         cupsdDeletePrinter(p, 1);
         cupsArrayRestore(Printers);
+       write_printcap = 1;
       }
     }
   }
+
+  if (write_printcap)
+    cupsdWritePrintcap();
 }
 
 
@@ -951,8 +955,8 @@ cupsdStartBrowsing(void)
       if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
       {
        cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "cupsdStartBrowsing: Unable to create broadcast "
-                       "socket - %s.", strerror(errno));
+                       "Unable to create broadcast socket - %s.",
+                       strerror(errno));
        BrowseLocalProtocols &= ~BROWSE_CUPS;
        BrowseRemoteProtocols &= ~BROWSE_CUPS;
        return;
@@ -970,8 +974,8 @@ cupsdStartBrowsing(void)
       if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
       {
        cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "cupsdStartBrowsing: Unable to bind broadcast "
-                       "socket - %s.", strerror(errno));
+                       "Unable to bind broadcast socket - %s.",
+                       strerror(errno));
 
 #ifdef WIN32
        closesocket(BrowseSocket);
@@ -993,8 +997,7 @@ cupsdStartBrowsing(void)
     val = 1;
     if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "cupsdStartBrowsing: Unable to set broadcast mode - %s.",
+      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to set broadcast mode - %s.",
                      strerror(errno));
 
 #ifdef WIN32
@@ -1025,7 +1028,7 @@ cupsdStartBrowsing(void)
       * We only listen if we want remote printers...
       */
 
-      cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)cupsdUpdateCUPSBrowse,
+      cupsdAddSelect(BrowseSocket, (cupsd_selfunc_t)update_cups_browse,
                      NULL, NULL);
     }
   }
@@ -1074,6 +1077,24 @@ cupsdStartBrowsing(void)
       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...
       */
@@ -1126,6 +1147,16 @@ cupsdStartBrowsing(void)
   }
 #endif /* HAVE_OPENLDAP */
 
+ /*
+  * Enable LPD and SMB printer sharing as needed through external programs...
+  */
+
+  if (BrowseLocalProtocols & BROWSE_LPD)
+    update_lpd(1);
+
+  if (BrowseLocalProtocols & BROWSE_SMB)
+    update_smb(1);
+
  /*
   * Register the individual printers
   */
@@ -1237,7 +1268,7 @@ cupsdStartPolling(void)
   * Finally, add the pipe to the input selection set...
   */
 
-  cupsdAddSelect(PollPipe, (cupsd_selfunc_t)cupsdUpdatePolling, NULL, NULL);
+  cupsdAddSelect(PollPipe, (cupsd_selfunc_t)update_polling, NULL, NULL);
 }
 
 
@@ -1306,6 +1337,16 @@ cupsdStopBrowsing(void)
     BrowseLDAPHandle = NULL;
   }
 #endif /* HAVE_OPENLDAP */
+
+ /*
+  * Disable LPD and SMB printer sharing as needed through external programs...
+  */
+
+  if (BrowseLocalProtocols & BROWSE_LPD)
+    update_lpd(0);
+
+  if (BrowseLocalProtocols & BROWSE_SMB)
+    update_smb(0);
 }
 
 
@@ -1337,442 +1378,139 @@ cupsdStopPolling(void)
 }
 
 
+#ifdef HAVE_DNSSD
 /*
- * 'cupsdUpdateCUPSBrowse()' - Update the browse lists using the CUPS protocol.
+ * 'cupsdUpdateDNSSDBrowse()' - Handle DNS-SD queries.
  */
 
 void
-cupsdUpdateCUPSBrowse(void)
+cupsdUpdateDNSSDBrowse(
+    cupsd_printer_t *p)                        /* I - Printer being queried */
 {
-  int          i;                      /* Looping var */
-  int          auth;                   /* Authorization status */
-  int          len;                    /* Length of name string */
-  int          bytes;                  /* Number of bytes left */
-  char         packet[1541],           /* Broadcast packet */
-               *pptr;                  /* Pointer into packet */
-  socklen_t    srclen;                 /* Length of source address */
-  http_addr_t  srcaddr;                /* Source address */
-  char         srcname[1024];          /* Source hostname */
-  unsigned     address[4];             /* Source address */
-  unsigned     type;                   /* Printer type */
-  unsigned     state;                  /* Printer state */
-  char         uri[HTTP_MAX_URI],      /* Printer URI */
-               host[HTTP_MAX_URI],     /* Host portion of URI */
-               resource[HTTP_MAX_URI], /* Resource portion of URI */
-               info[IPP_MAX_NAME],     /* Information string */
-               location[IPP_MAX_NAME], /* Location string */
-               make_model[IPP_MAX_NAME];/* Make and model string */
-  int          num_attrs;              /* Number of attributes */
-  cups_option_t        *attrs;                 /* Attributes */
-
+  DNSServiceErrorType  sdErr;          /* Service discovery error */
 
- /*
-  * Read a packet from the browse socket...
-  */
 
-  srclen = sizeof(srcaddr);
-  if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0, 
-                        (struct sockaddr *)&srcaddr, &srclen)) < 0)
+  if ((sdErr = DNSServiceProcessResult(p->dnssd_ipp_ref))
+          != kDNSServiceErr_NoError)
   {
-   /*
-    * "Connection refused" is returned under Linux if the destination port
-    * or address is unreachable from a previous sendto(); check for the
-    * error here and ignore it for now...
-    */
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                    "DNS Service Discovery registration error %d for \"%s\"!",
+                   sdErr, p->name);
+    cupsdRemoveSelect(p->dnssd_ipp_fd);
+    DNSServiceRefDeallocate(p->dnssd_ipp_ref);
 
-    if (errno != ECONNREFUSED && errno != EAGAIN)
-    {
-      cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
-                      strerror(errno));
-      cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off.");
+    p->dnssd_ipp_ref = NULL;
+    p->dnssd_ipp_fd  = -1;
+  }
+}
+#endif /* HAVE_DNSSD */
 
-      cupsdStopBrowsing();
-      Browsing = 0;
-    }
 
-    return;
-  }
+#ifdef HAVE_OPENLDAP
+/*
+ * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
+ */
+
+void
+cupsdUpdateLDAPBrowse(void)
+{
+  char         uri[HTTP_MAX_URI],      /* Printer URI */
+               host[HTTP_MAX_URI],     /* Hostname */
+               resource[HTTP_MAX_URI], /* Resource path */
+               location[1024],         /* Printer location */
+               info[1024],             /* Printer information */
+               make_model[1024],       /* Printer make and model */
+               **value;                /* Holds the returned data from LDAP */
+  int          type;                   /* Printer type */
+  int          rc;                     /* LDAP status */
+  int          limit;                  /* Size limit */
+  LDAPMessage  *res,                   /* LDAP search results */
+                 *e;                   /* Current entry from search */
 
-  packet[bytes] = '\0';
 
  /*
-  * If we're about to sleep, ignore incoming browse packets.
+  * Search for printers...
   */
 
-  if (Sleeping)
-    return;
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "UpdateLDAPBrowse: %s", ServerName);
 
- /*
-  * Figure out where it came from...
-  */
+  BrowseLDAPRefresh = time(NULL) + BrowseInterval;
 
-#ifdef AF_INET6
-  if (srcaddr.addr.sa_family == AF_INET6)
-  {
-    address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
-    address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
-    address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
-    address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
-  }
-  else
-#endif /* AF_INET6 */
+  rc = ldap_search_s(BrowseLDAPHandle, BrowseLDAPDN, LDAP_SCOPE_SUBTREE,
+                     "(objectclass=cupsPrinter)", (char **)ldap_attrs, 0, &res);
+  if (rc != LDAP_SUCCESS) 
   {
-    address[0] = 0;
-    address[1] = 0;
-    address[2] = 0;
-    address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                    "LDAP search returned error %d: %s", rc,
+                   ldap_err2string(rc));
+    return;
   }
 
-  if (HostNameLookups)
-    httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
-  else
-    httpAddrString(&srcaddr, srcname, sizeof(srcname));
-
-  len = strlen(srcname);
+  limit = ldap_count_entries(BrowseLDAPHandle, res);
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
+  if (limit < 1)
+    return;
 
  /*
-  * Do ACL stuff...
+  * Loop through the available printers...
   */
 
-  if (BrowseACL)
+  for (e = ldap_first_entry(BrowseLDAPHandle, res);
+       e;
+       e = ldap_next_entry(BrowseLDAPHandle, e))
   {
-    if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
-    {
-     /*
-      * Access from localhost (127.0.0.1) is always allowed...
-      */
-
-      auth = AUTH_ALLOW;
-    }
-    else
-    {
-     /*
-      * Do authorization checks on the domain/address...
-      */
-
-      switch (BrowseACL->order_type)
-      {
-        default :
-           auth = AUTH_DENY;   /* anti-compiler-warning-code */
-           break;
-
-       case AUTH_ALLOW : /* Order Deny,Allow */
-            auth = AUTH_ALLOW;
+   /*
+    * Get the required values from this entry...
+    */
 
-            if (cupsdCheckAuth(address, srcname, len,
-                         BrowseACL->num_deny, BrowseACL->deny))
-             auth = AUTH_DENY;
+    if ((value = ldap_get_values(BrowseLDAPHandle, e,
+                                 "printerDescription")) == NULL)
+      continue;
 
-            if (cupsdCheckAuth(address, srcname, len,
-                         BrowseACL->num_allow, BrowseACL->allow))
-             auth = AUTH_ALLOW;
-           break;
+    strlcpy(info, *value, sizeof(info));
+    ldap_value_free(value);
 
-       case AUTH_DENY : /* Order Allow,Deny */
-            auth = AUTH_DENY;
+    if ((value = ldap_get_values(BrowseLDAPHandle, e,
+                                 "printerLocation")) == NULL)
+      continue;
 
-            if (cupsdCheckAuth(address, srcname, len,
-                         BrowseACL->num_allow, BrowseACL->allow))
-             auth = AUTH_ALLOW;
+    strlcpy(location, *value, sizeof(location));
+    ldap_value_free(value);
 
-            if (cupsdCheckAuth(address, srcname, len,
-                         BrowseACL->num_deny, BrowseACL->deny))
-             auth = AUTH_DENY;
-           break;
-      }
-    }
-  }
-  else
-    auth = AUTH_ALLOW;
+    if ((value = ldap_get_values(BrowseLDAPHandle, e,
+                                 "printerMakeAndModel")) == NULL)
+      continue;
 
-  if (auth == AUTH_DENY)
-  {
-    cupsdLogMessage(CUPSD_LOG_DEBUG,
-                    "cupsdUpdateCUPSBrowse: Refused %d bytes from %s", bytes,
-                    srcname);
-    return;
-  }
+    strlcpy(make_model, *value, sizeof(make_model));
+    ldap_value_free(value);
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdUpdateCUPSBrowse: (%d bytes from %s) %s", bytes,
-                 srcname, packet);
+    if ((value = ldap_get_values(BrowseLDAPHandle, e,
+                                 "printerType")) == NULL)
+      continue;
 
- /*
-  * Parse packet...
-  */
+    type = atoi(*value);
+    ldap_value_free(value);
 
-  if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
-  {
-    cupsdLogMessage(CUPSD_LOG_WARN,
-                    "cupsdUpdateCUPSBrowse: Garbled browse packet - %s", packet);
-    return;
-  }
+    if ((value = ldap_get_values(BrowseLDAPHandle, e,
+                                 "printerURI")) == NULL)
+      continue;
 
-  strcpy(location, "Location Unknown");
-  strcpy(info, "No Information Available");
-  make_model[0] = '\0';
-  num_attrs     = 0;
-  attrs         = NULL;
+    strlcpy(uri, *value, sizeof(uri));
+    ldap_value_free(value);
 
-  if ((pptr = strchr(packet, '\"')) != NULL)
-  {
    /*
-    * Have extended information; can't use sscanf for it because not all
-    * sscanf's allow empty strings with %[^\"]...
+    * Process the entry as browse data...
     */
 
-    for (i = 0, pptr ++;
-         i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
-         i ++, pptr ++)
-      location[i] = *pptr;
-
-    if (i)
-      location[i] = '\0';
-
-    if (*pptr == '\"')
-      pptr ++;
-
-    while (*pptr && isspace(*pptr & 255))
-      pptr ++;
-
-    if (*pptr == '\"')
-    {
-      for (i = 0, pptr ++;
-           i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
-           i ++, pptr ++)
-       info[i] = *pptr;
-
-      info[i] = '\0';
-
-      if (*pptr == '\"')
-       pptr ++;
-
-      while (*pptr && isspace(*pptr & 255))
-       pptr ++;
-
-      if (*pptr == '\"')
-      {
-       for (i = 0, pptr ++;
-             i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
-             i ++, pptr ++)
-         make_model[i] = *pptr;
-
-       if (*pptr == '\"')
-         pptr ++;
-
-       make_model[i] = '\0';
-
-        if (*pptr)
-         num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
-      }
-    }
-  }
-
-  DEBUG_puts(packet);
-  DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
-                "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
-               type, state, uri, location, info, make_model));
-
- /*
-  * Pull the URI apart to see if this is a local or remote printer...
-  */
-
-  if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
-  {
-    cupsFreeOptions(num_attrs, attrs);
-    return;
-  }
-
- /*
-  * Do relaying...
-  */
-
-  for (i = 0; i < NumRelays; i ++)
-    if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
-      if (sendto(BrowseSocket, packet, bytes, 0,
-                 (struct sockaddr *)&(Relays[i].to),
-                httpAddrLength(&(Relays[i].to))) <= 0)
-      {
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "cupsdUpdateCUPSBrowse: sendto failed for relay %d - %s.",
-                       i + 1, strerror(errno));
-       cupsFreeOptions(num_attrs, attrs);
-       return;
-      }
-
- /*
-  * Process the browse data...
-  */
-
-  process_browse_data(uri, host, resource, (cups_ptype_t)type,
-                      (ipp_pstate_t)state, location, info, make_model,
-                     num_attrs, attrs);
-}
-
-
-#ifdef HAVE_DNSSD
-/*
- * 'cupsdUpdateDNSSDBrowse()' - Handle DNS-SD queries.
- */
-
-void
-cupsdUpdateDNSSDBrowse(
-    cupsd_printer_t *p)                        /* I - Printer being queried */
-{
-  DNSServiceErrorType  sdErr;          /* Service discovery error */
-
-
-  if ((sdErr = DNSServiceProcessResult(p->dnssd_ipp_ref))
-          != kDNSServiceErr_NoError)
-  {
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                    "DNS Service Discovery registration error %d for \"%s\"!",
-                   sdErr, p->name);
-    cupsdRemoveSelect(p->dnssd_ipp_fd);
-    DNSServiceRefDeallocate(p->dnssd_ipp_ref);
-
-    p->dnssd_ipp_ref = NULL;
-    p->dnssd_ipp_fd  = -1;
-  }
-}
-#endif /* HAVE_DNSSD */
-
-
-#ifdef HAVE_OPENLDAP
-/*
- * 'cupsdUpdateLDAPBrowse()' - Scan for new printers via LDAP...
- */
-
-void
-cupsdUpdateLDAPBrowse(void)
-{
-  char         uri[HTTP_MAX_URI],      /* Printer URI */
-               host[HTTP_MAX_URI],     /* Hostname */
-               resource[HTTP_MAX_URI], /* Resource path */
-               location[1024],         /* Printer location */
-               info[1024],             /* Printer information */
-               make_model[1024],       /* Printer make and model */
-               **value;                /* Holds the returned data from LDAP */
-  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) 
-  {
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                    "LDAP search returned error %d: %s", rc,
-                   ldap_err2string(rc));
-    return;
-  }
-
-  limit = ldap_count_entries(BrowseLDAPHandle, res);
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "LDAP search returned %d entries", limit);
-  if (limit < 1)
-    return;
-
- /*
-  * Loop through the available printers...
-  */
-
-  for (e = ldap_first_entry(BrowseLDAPHandle, res);
-       e;
-       e = ldap_next_entry(BrowseLDAPHandle, e))
-  {
-   /*
-    * Get the required values from this entry...
-    */
-
-    if ((value = ldap_get_values(BrowseLDAPHandle, e,
-                                 "printerDescription")) == NULL)
-      continue;
-
-    strlcpy(info, *value, sizeof(info));
-    ldap_value_free(value);
-
-    if ((value = ldap_get_values(BrowseLDAPHandle, e,
-                                 "printerLocation")) == NULL)
-      continue;
-
-    strlcpy(location, *value, sizeof(location));
-    ldap_value_free(value);
-
-    if ((value = ldap_get_values(BrowseLDAPHandle, e,
-                                 "printerMakeAndModel")) == NULL)
-      continue;
-
-    strlcpy(make_model, *value, sizeof(make_model));
-    ldap_value_free(value);
-
-    if ((value = ldap_get_values(BrowseLDAPHandle, e,
-                                 "printerType")) == NULL)
-      continue;
-
-    type = atoi(*value);
-    ldap_value_free(value);
-
-    if ((value = ldap_get_values(BrowseLDAPHandle, e,
-                                 "printerURI")) == NULL)
-      continue;
-
-    strlcpy(uri, *value, sizeof(uri));
-    ldap_value_free(value);
-
-   /*
-    * Process the entry as browse data...
-    */
-
-    if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
-      process_browse_data(uri, host, resource, type, IPP_PRINTER_IDLE,
-                          location, info, make_model, 0, NULL);
+    if (!is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
+      process_browse_data(uri, host, resource, type, IPP_PRINTER_IDLE,
+                          location, info, make_model, 0, NULL);
 
   }
 }
 #endif /* HAVE_OPENLDAP */
 
 
-/*
- * 'cupsdUpdatePolling()' - Read status messages from the poll daemons.
- */
-
-void
-cupsdUpdatePolling(void)
-{
-  char         *ptr,                   /* Pointer to end of line in buffer */
-               message[1024];          /* Pointer to message text */
-  int          loglevel;               /* Log level for message */
-
-
-  while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
-                                   message, sizeof(message))) != NULL)
-    if (!strchr(PollStatusBuffer->buffer, '\n'))
-      break;
-
-  if (ptr == NULL && !PollStatusBuffer->bufused)
-  {
-   /*
-    * All polling processes have died; stop polling...
-    */
-
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                    "cupsdUpdatePolling: all polling processes have exited!");
-    cupsdStopPolling();
-  }
-}
-
-
 #ifdef HAVE_LIBSLP 
 /*
  * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP.
@@ -1952,7 +1690,8 @@ process_browse_data(
     cups_option_t *attrs)              /* I - Attributes */
 {
   int          i;                      /* Looping var */
-  int          update;                 /* Update printer attributes? */
+  int          update,                 /* Update printer attributes? */
+               write_printcap;         /* Write the printcap file? */
   char         finaluri[HTTP_MAX_URI], /* Final URI for printer */
                name[IPP_MAX_NAME],     /* Name of printer */
                newname[IPP_MAX_NAME],  /* New name of printer */
@@ -2039,11 +1778,12 @@ process_browse_data(
   * See if we already have it listed in the Printers list, and add it if not...
   */
 
-  type   |= CUPS_PRINTER_REMOTE;
-  type   &= ~CUPS_PRINTER_IMPLICIT;
-  update = 0;
-  hptr   = strchr(host, '.');
-  sptr   = strchr(ServerName, '.');
+  type           |= CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED;
+  type           &= ~CUPS_PRINTER_IMPLICIT;
+  update         = 0;
+  write_printcap = 0;
+  hptr           = strchr(host, '.');
+  sptr           = strchr(ServerName, '.');
 
   if (!ServerNameIsIP && sptr != NULL && hptr != NULL)
   {
@@ -2166,7 +1906,8 @@ process_browse_data(
       cupsdSetString(&p->device_uri, uri);
       cupsdSetString(&p->hostname, host);
 
-      update = 1;
+      update         = 1;
+      write_printcap = 1;
     }
   }
   else
@@ -2272,7 +2013,8 @@ process_browse_data(
       cupsdSetString(&p->uri, uri);
       cupsdSetString(&p->device_uri, uri);
 
-      update = 1;
+      write_printcap = 1;
+      update         = 1;
     }
   }
 
@@ -2331,7 +2073,8 @@ process_browse_data(
   if (info && (!p->info || strcmp(p->info, info)))
   {
     cupsdSetString(&p->info, info);
-    update = 1;
+    update         = 1;
+    write_printcap = 1;
   }
 
   if (!make_model || !make_model[0])
@@ -2396,6 +2139,7 @@ process_browse_data(
  
     cupsdDeletePrinter(p, 1);
     cupsdUpdateImplicitClasses();
+    write_printcap = 1;
   }
   else if (update)
   {
@@ -2420,6 +2164,7 @@ process_browse_data(
       if (p->type & CUPS_PRINTER_DEFAULT)
       {
         DefaultPrinter = p;
+       write_printcap = 1;
        break;
       }
   }
@@ -2428,13 +2173,14 @@ process_browse_data(
   * Do auto-classing if needed...
   */
 
-  process_implicit_classes();
+  process_implicit_classes(&write_printcap);
 
  /*
   * Update the printcap file...
   */
 
-  cupsdWritePrintcap();
+  if (write_printcap)
+    cupsdWritePrintcap();
 }
 
 
@@ -2448,10 +2194,11 @@ dnssdBuildTxtRecord(
     int             *txt_len,          /* O - TXT record length */
     cupsd_printer_t *p)                        /* I - Printer information */
 {
-  int          i;                      /* Looping var */
+  int          i, j;                   /* Looping vars */
   char         type_str[32],           /* Type to string buffer */
                state_str[32],          /* State to string buffer */
                rp_str[1024],           /* Queue name string buffer */
+               air_str[1024],          /* auth-info-required string buffer */
                *keyvalue[32][2];       /* Table of key/value pairs */
 
 
@@ -2556,6 +2303,27 @@ dnssdBuildTxtRecord(
   keyvalue[i  ][0] = "pdl";
   keyvalue[i++][1] = p->pdl ? p->pdl : "application/postscript";
 
+  if (p->num_auth_info_required)
+  {
+    char       *air = air_str;         /* Pointer into string */
+
+
+    for (j = 0; j < p->num_auth_info_required; j ++)
+    {
+      if (air >= (air_str + sizeof(air_str) - 2))
+        break;
+
+      if (j)
+        *air++ = ',';
+
+      strlcpy(air, p->auth_info_required[j], sizeof(air_str) - (air - air_str));
+      air += strlen(air);
+    }
+
+    keyvalue[i  ][0] = "air";
+    keyvalue[i++][1] = air;
+  }
+
  /*
   * Then pack them into a proper txt record...
   */
@@ -2902,7 +2670,8 @@ dnssdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
  */
 
 static void
-process_implicit_classes(void)
+process_implicit_classes(
+    int *write_printcap)               /* O - Write printcap file? */
 {
   int          i;                      /* Looping var */
   int          update;                 /* Update printer attributes? */
@@ -2978,8 +2747,14 @@ process_implicit_classes(void)
         cupsdSetString(&pclass->location, p->location);
         cupsdSetString(&pclass->info, p->info);
 
+        cupsdSetString(&pclass->job_sheets[0], p->job_sheets[0]);
+        cupsdSetString(&pclass->job_sheets[1], p->job_sheets[1]);
+
         update = 1;
 
+       if (write_printcap)
+         *write_printcap = 1;
+
         cupsdLogMessage(CUPSD_LOG_DEBUG, "Added implicit class \"%s\"...",
                        name);
        cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL,
@@ -3079,7 +2854,7 @@ process_implicit_classes(void)
 
 /*
  * 'send_cups_browse()' - Send new browsing information using the CUPS
- *                           protocol.
+ *                        protocol.
  */
 
 static void
@@ -3206,7 +2981,7 @@ send_cups_browse(cupsd_printer_t *p)      /* I - Printer to send */
        {
          httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
                           iface->hostname, iface->port,
-                          (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s%s" :
+                          (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
                                                            "/printers/%s",
                           p->name);
          snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
@@ -3774,5 +3549,477 @@ slp_url_callback(
 
 
 /*
- * End of "$Id: dirsvc.c 6309 2007-02-24 03:11:56Z mike $".
+ * 'update_cups_browse()' - Update the browse lists using the CUPS protocol.
+ */
+
+static void
+update_cups_browse(void)
+{
+  int          i;                      /* Looping var */
+  int          auth;                   /* Authorization status */
+  int          len;                    /* Length of name string */
+  int          bytes;                  /* Number of bytes left */
+  char         packet[1541],           /* Broadcast packet */
+               *pptr;                  /* Pointer into packet */
+  socklen_t    srclen;                 /* Length of source address */
+  http_addr_t  srcaddr;                /* Source address */
+  char         srcname[1024];          /* Source hostname */
+  unsigned     address[4];             /* Source address */
+  unsigned     type;                   /* Printer type */
+  unsigned     state;                  /* Printer state */
+  char         uri[HTTP_MAX_URI],      /* Printer URI */
+               host[HTTP_MAX_URI],     /* Host portion of URI */
+               resource[HTTP_MAX_URI], /* Resource portion of URI */
+               info[IPP_MAX_NAME],     /* Information string */
+               location[IPP_MAX_NAME], /* Location string */
+               make_model[IPP_MAX_NAME];/* Make and model string */
+  int          num_attrs;              /* Number of attributes */
+  cups_option_t        *attrs;                 /* Attributes */
+
+
+ /*
+  * Read a packet from the browse socket...
+  */
+
+  srclen = sizeof(srcaddr);
+  if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0, 
+                        (struct sockaddr *)&srcaddr, &srclen)) < 0)
+  {
+   /*
+    * "Connection refused" is returned under Linux if the destination port
+    * or address is unreachable from a previous sendto(); check for the
+    * error here and ignore it for now...
+    */
+
+    if (errno != ECONNREFUSED && errno != EAGAIN)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.",
+                      strerror(errno));
+      cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off.");
+
+      cupsdStopBrowsing();
+      Browsing = 0;
+    }
+
+    return;
+  }
+
+  packet[bytes] = '\0';
+
+ /*
+  * If we're about to sleep, ignore incoming browse packets.
+  */
+
+  if (Sleeping)
+    return;
+
+ /*
+  * Figure out where it came from...
+  */
+
+#ifdef AF_INET6
+  if (srcaddr.addr.sa_family == AF_INET6)
+  {
+    address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]);
+    address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]);
+    address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]);
+    address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]);
+  }
+  else
+#endif /* AF_INET6 */
+  {
+    address[0] = 0;
+    address[1] = 0;
+    address[2] = 0;
+    address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr);
+  }
+
+  if (HostNameLookups)
+    httpAddrLookup(&srcaddr, srcname, sizeof(srcname));
+  else
+    httpAddrString(&srcaddr, srcname, sizeof(srcname));
+
+  len = strlen(srcname);
+
+ /*
+  * Do ACL stuff...
+  */
+
+  if (BrowseACL)
+  {
+    if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost"))
+    {
+     /*
+      * Access from localhost (127.0.0.1) is always allowed...
+      */
+
+      auth = AUTH_ALLOW;
+    }
+    else
+    {
+     /*
+      * Do authorization checks on the domain/address...
+      */
+
+      switch (BrowseACL->order_type)
+      {
+        default :
+           auth = AUTH_DENY;   /* anti-compiler-warning-code */
+           break;
+
+       case AUTH_ALLOW : /* Order Deny,Allow */
+            auth = AUTH_ALLOW;
+
+            if (cupsdCheckAuth(address, srcname, len,
+                         BrowseACL->num_deny, BrowseACL->deny))
+             auth = AUTH_DENY;
+
+            if (cupsdCheckAuth(address, srcname, len,
+                         BrowseACL->num_allow, BrowseACL->allow))
+             auth = AUTH_ALLOW;
+           break;
+
+       case AUTH_DENY : /* Order Allow,Deny */
+            auth = AUTH_DENY;
+
+            if (cupsdCheckAuth(address, srcname, len,
+                         BrowseACL->num_allow, BrowseACL->allow))
+             auth = AUTH_ALLOW;
+
+            if (cupsdCheckAuth(address, srcname, len,
+                         BrowseACL->num_deny, BrowseACL->deny))
+             auth = AUTH_DENY;
+           break;
+      }
+    }
+  }
+  else
+    auth = AUTH_ALLOW;
+
+  if (auth == AUTH_DENY)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG,
+                    "update_cups_browse: Refused %d bytes from %s", bytes,
+                    srcname);
+    return;
+  }
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "update_cups_browse: (%d bytes from %s) %s", bytes,
+                 srcname, packet);
+
+ /*
+  * Parse packet...
+  */
+
+  if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3)
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                    "update_cups_browse: Garbled browse packet - %s", packet);
+    return;
+  }
+
+  strcpy(location, "Location Unknown");
+  strcpy(info, "No Information Available");
+  make_model[0] = '\0';
+  num_attrs     = 0;
+  attrs         = NULL;
+
+  if ((pptr = strchr(packet, '\"')) != NULL)
+  {
+   /*
+    * Have extended information; can't use sscanf for it because not all
+    * sscanf's allow empty strings with %[^\"]...
+    */
+
+    for (i = 0, pptr ++;
+         i < (sizeof(location) - 1) && *pptr && *pptr != '\"';
+         i ++, pptr ++)
+      location[i] = *pptr;
+
+    if (i)
+      location[i] = '\0';
+
+    if (*pptr == '\"')
+      pptr ++;
+
+    while (*pptr && isspace(*pptr & 255))
+      pptr ++;
+
+    if (*pptr == '\"')
+    {
+      for (i = 0, pptr ++;
+           i < (sizeof(info) - 1) && *pptr && *pptr != '\"';
+           i ++, pptr ++)
+       info[i] = *pptr;
+
+      info[i] = '\0';
+
+      if (*pptr == '\"')
+       pptr ++;
+
+      while (*pptr && isspace(*pptr & 255))
+       pptr ++;
+
+      if (*pptr == '\"')
+      {
+       for (i = 0, pptr ++;
+             i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"';
+             i ++, pptr ++)
+         make_model[i] = *pptr;
+
+       if (*pptr == '\"')
+         pptr ++;
+
+       make_model[i] = '\0';
+
+        if (*pptr)
+         num_attrs = cupsParseOptions(pptr, num_attrs, &attrs);
+      }
+    }
+  }
+
+  DEBUG_puts(packet);
+  DEBUG_printf(("type=%x, state=%x, uri=\"%s\"\n"
+                "location=\"%s\", info=\"%s\", make_model=\"%s\"\n",
+               type, state, uri, location, info, make_model));
+
+ /*
+  * Pull the URI apart to see if this is a local or remote printer...
+  */
+
+  if (is_local_queue(uri, host, sizeof(host), resource, sizeof(resource)))
+  {
+    cupsFreeOptions(num_attrs, attrs);
+    return;
+  }
+
+ /*
+  * Do relaying...
+  */
+
+  for (i = 0; i < NumRelays; i ++)
+    if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from)))
+      if (sendto(BrowseSocket, packet, bytes, 0,
+                 (struct sockaddr *)&(Relays[i].to),
+                httpAddrLength(&(Relays[i].to))) <= 0)
+      {
+       cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "update_cups_browse: sendto failed for relay %d - %s.",
+                       i + 1, strerror(errno));
+       cupsFreeOptions(num_attrs, attrs);
+       return;
+      }
+
+ /*
+  * Process the browse data...
+  */
+
+  process_browse_data(uri, host, resource, (cups_ptype_t)type,
+                      (ipp_pstate_t)state, location, info, make_model,
+                     num_attrs, attrs);
+}
+
+
+/*
+ * 'update_lpd()' - Update the LPD configuration as needed.
+ */
+
+static void
+update_lpd(int onoff)                  /* - 1 = turn on, 0 = turn off */
+{
+  if (!LPDConfigFile)
+    return;
+
+  if (!strncmp(LPDConfigFile, "xinetd:///", 10))
+  {
+   /*
+    * Enable/disable LPD via the xinetd.d config file for cups-lpd...
+    */
+
+    char       newfile[1024];          /* New cups-lpd.N file */
+    cups_file_t        *ofp,                   /* Original file pointer */
+               *nfp;                   /* New file pointer */
+    char       line[1024];             /* Line from file */
+
+
+    snprintf(newfile, sizeof(newfile), "%s.N", LPDConfigFile + 9);
+
+    if ((ofp = cupsFileOpen(LPDConfigFile + 9, "r")) == NULL)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
+                      LPDConfigFile + 9, strerror(errno));
+      return;
+    }
+
+    if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
+                      newfile, strerror(errno));
+      cupsFileClose(ofp);
+      return;
+    }
+
+   /*
+    * Copy all of the lines from the cups-lpd file...
+    */
+
+    while (cupsFileGets(ofp, line, sizeof(line)))
+    {
+      if (line[0] == '{')
+      {
+        cupsFilePrintf(nfp, "%s\n", line);
+        snprintf(line, sizeof(line), "\tdisable = %s",
+                onoff ? "no" : "yes");
+      }
+      else if (strstr(line, "disable ="))
+        continue;
+
+      cupsFilePrintf(nfp, "%s\n", line);
+    }
+
+    cupsFileClose(nfp);
+    cupsFileClose(ofp);
+    rename(newfile, LPDConfigFile + 9);
+  }
+  else if (!strncmp(LPDConfigFile, "launchd:///", 11))
+  {
+   /*
+    * Enable/disable LPD via the launchctl command...
+    */
+
+    char       *argv[5],               /* Arguments for command */
+               *envp[MAX_ENV];         /* Environment for command */
+    int                pid;                    /* Process ID */
+
+
+    cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
+    argv[0] = (char *)"launchctl";
+    argv[1] = (char *)(onoff ? "load" : "unload");
+    argv[2] = (char *)"-w";
+    argv[3] = LPDConfigFile + 10;
+    argv[4] = NULL;
+
+    cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1, &pid);
+  }
+}
+
+
+/*
+ * 'update_polling()' - Read status messages from the poll daemons.
+ */
+
+static void
+update_polling(void)
+{
+  char         *ptr,                   /* Pointer to end of line in buffer */
+               message[1024];          /* Pointer to message text */
+  int          loglevel;               /* Log level for message */
+
+
+  while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel,
+                                   message, sizeof(message))) != NULL)
+    if (!strchr(PollStatusBuffer->buffer, '\n'))
+      break;
+
+  if (ptr == NULL && !PollStatusBuffer->bufused)
+  {
+   /*
+    * All polling processes have died; stop polling...
+    */
+
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                    "update_polling: all polling processes have exited!");
+    cupsdStopPolling();
+  }
+}
+
+
+/*
+ * 'update_smb()' - Update the SMB configuration as needed.
+ */
+
+static void
+update_smb(int onoff)                  /* I - 1 = turn on, 0 = turn off */
+{
+  if (!SMBConfigFile)
+    return;
+
+  if (!strncmp(SMBConfigFile, "samba:///", 9))
+  {
+   /*
+    * Enable/disable SMB via the specified smb.conf config file...
+    */
+
+    char       newfile[1024];          /* New smb.conf.N file */
+    cups_file_t        *ofp,                   /* Original file pointer */
+               *nfp;                   /* New file pointer */
+    char       line[1024];             /* Line from file */
+    int                in_printers;            /* In [printers] section? */
+
+
+    snprintf(newfile, sizeof(newfile), "%s.N", SMBConfigFile + 8);
+
+    if ((ofp = cupsFileOpen(SMBConfigFile + 8, "r")) == NULL)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\" - %s",
+                      SMBConfigFile + 8, strerror(errno));
+      return;
+    }
+
+    if ((nfp = cupsFileOpen(newfile, "w")) == NULL)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\" - %s",
+                      newfile, strerror(errno));
+      cupsFileClose(ofp);
+      return;
+    }
+
+   /*
+    * Copy all of the lines from the smb.conf file...
+    */
+
+    in_printers = 0;
+
+    while (cupsFileGets(ofp, line, sizeof(line)))
+    {
+      if (in_printers && strstr(line, "printable ="))
+        snprintf(line, sizeof(line), "    printable = %s",
+                onoff ? "yes" : "no");
+
+      cupsFilePrintf(nfp, "%s\n", line);
+
+      if (line[0] == '[')
+        in_printers = !strcmp(line, "[printers]");
+    }
+
+    cupsFileClose(nfp);
+    cupsFileClose(ofp);
+    rename(newfile, SMBConfigFile + 8);
+  }
+  else if (!strncmp(SMBConfigFile, "launchd:///", 11))
+  {
+   /*
+    * Enable/disable SMB via the launchctl command...
+    */
+
+    char       *argv[5],               /* Arguments for command */
+               *envp[MAX_ENV];         /* Environment for command */
+    int                pid;                    /* Process ID */
+
+
+    cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
+    argv[0] = (char *)"launchctl";
+    argv[1] = (char *)(onoff ? "load" : "unload");
+    argv[2] = (char *)"-w";
+    argv[3] = SMBConfigFile + 10;
+    argv[4] = NULL;
+
+    cupsdStartProcess("/bin/launchctl", argv, envp, -1, -1, -1, -1, -1, 1, &pid);
+  }
+}
+
+
+/*
+ * End of "$Id: dirsvc.c 7003 2007-10-01 23:10:13Z mike $".
  */