]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Implement BrowseDomains, FilterLocation, and FilterType directives in client.conf...
authorMichael R Sweet <msweet@msweet.org>
Fri, 28 Feb 2025 20:13:50 +0000 (15:13 -0500)
committerMichael R Sweet <msweet@msweet.org>
Fri, 28 Feb 2025 20:13:50 +0000 (15:13 -0500)
CHANGES.md
cups/cups-private.h
cups/dest.c
cups/globals.c
cups/ipp-support.c
cups/ipp.c
cups/tls-gnutls.c
cups/tls-openssl.c
cups/usersys.c
doc/help/man-client.conf.html
man/client.conf.5

index 8d06497031d4f4d71ed6e196c5c6c377fbfde943..afe7a30b6165f66777bc4f3a4a3324562723a046 100644 (file)
@@ -66,6 +66,8 @@ Changes in CUPS v2.5b1 (YYYY-MM-DD)
   `cupsRasterGetErrorString`.
 - Updated the `ipptool` utility to support the `--bearer-token` and
   `--client-name` options.
+- Updated `cupsEnumDests` and `cupsGetDests` to support printer browsing and
+  filtering options in client.conf (Issue #1180)
 - Deprecated the "page-border" Job Template attribute (Issue #1020)
 - Removed the `cups-config` utility (use `pkg-config` instead)
 - Fixed use-after-free in `cupsdAcceptClient()` when we log warning during error
index ec5f0f602a55c82d4f424deca9a10ae2fe2fc9d8..e67800957da4a1d03049c7bc6fdeac0a002a9a6b 100644 (file)
@@ -1,7 +1,7 @@
 //
 // Private definitions for CUPS.
 //
-// Copyright © 2020-2024 by OpenPrinting.
+// Copyright © 2020-2025 by OpenPrinting.
 // Copyright © 2007-2019 by Apple Inc.
 // Copyright © 1997-2007 by Easy Software Products, all rights reserved.
 //
@@ -29,6 +29,7 @@ extern "C" {
 #  ifdef _WIN32
 typedef int mode_t;                    // Windows doesn't support mode_t type @private@
 #  endif // _WIN32
+#  include <regex.h>
 
 
 //
@@ -191,6 +192,17 @@ typedef struct _cups_globals_s             // CUPS global state data
   char                 pw_buf[PW_BUF_SIZE];
                                        // Big buffer for struct passwd buffers
 #  endif // !_WIN32
+
+  bool                 client_conf_loaded;
+                                       // Has client.conf been loaded?
+  cups_array_t         *browse_domains;// BrowseDomains list
+  cups_array_t         *filter_location_array;
+                                       // FilterLocation list
+  regex_t              *filter_location_regex;
+                                       // FilterLocation regular expression
+  cups_ptype_t         filter_type;    // FilterType values from client.conf
+  cups_ptype_t         filter_type_mask;
+                                       // FilterType mask
 } _cups_globals_t;
 
 typedef struct _cups_media_db_s                // Media database
index 3659f5f75fc1647ea59a2348662f607f89845381..9dbb9c86278338b6892165cceef2b42b408ad3db 100644 (file)
@@ -1265,7 +1265,8 @@ _cupsGetDests(http_t       *http, /* I  - Connection to server or
   ipp_t                *request,               // IPP Request
                *response;              // IPP Response
   ipp_attribute_t *attr;               // Current attribute
-  const char   *printer_name;          // printer-name attribute
+  const char   *printer_name,          // printer-name attribute
+               *printer_location;      // printer-location attribute
   char         uri[1024];              // printer-uri value
   int          num_options;            // Number of options
   cups_option_t        *options;               // Options
@@ -1275,6 +1276,7 @@ _cupsGetDests(http_t       *http, /* I  - Connection to server or
   char         optname[1024],          // Option name
                value[2048],            // Option value
                *ptr;                   // Pointer into name/value
+  _cups_globals_t *cg = _cupsGlobals();        // Pointer to library globals
   static const char * const pattrs[] = // Attributes we're interested in
                {
                  "auth-info-required",
@@ -1374,9 +1376,10 @@ _cupsGetDests(http_t       *http,        /* I  - Connection to server or
       * Pull the needed attributes from this printer...
       */
 
-      printer_name = NULL;
-      num_options  = 0;
-      options      = NULL;
+      printer_name     = NULL;
+      printer_location = NULL;
+      num_options      = 0;
+      options          = NULL;
 
       for (; attr && attr->group_tag == IPP_TAG_PRINTER; attr = attr->next)
       {
@@ -1410,20 +1413,20 @@ _cupsGetDests(http_t       *http,       /* I  - Connection to server or
            !strcmp(attr->name, "printer-mandatory-job-attributes") ||
            !strcmp(attr->name, "printer-state") ||
            !strcmp(attr->name, "printer-state-change-time") ||
+            !strcmp(attr->name, "printer-state-reasons") ||
            !strcmp(attr->name, "printer-type") ||
             !strcmp(attr->name, "printer-is-accepting-jobs") ||
-            !strcmp(attr->name, "printer-location") ||
-            !strcmp(attr->name, "printer-state-reasons") ||
            !strcmp(attr->name, "printer-uri-supported"))
         {
-        /*
-         * Add a printer description attribute...
-         */
+         // Add a printer description attribute...
+          num_options = cupsAddOption(attr->name, cups_make_string(attr, value, sizeof(value)), num_options, &options);
+       }
+       else if (!strcmp(attr->name, "printer-location"))
+        {
+         // Add a printer description attribute...
+         printer_location = ippGetString(attr, 0, NULL);
 
-          num_options = cupsAddOption(attr->name,
-                                     cups_make_string(attr, value,
-                                                      sizeof(value)),
-                                     num_options, &options);
+          num_options = cupsAddOption(attr->name, printer_location, num_options, &options);
        }
 #ifdef __APPLE__
        else if (!strcmp(attr->name, "media-supported") && media_default[0])
@@ -1468,11 +1471,21 @@ _cupsGetDests(http_t       *http,       /* I  - Connection to server or
        }
       }
 
-     /*
-      * See if we have everything needed...
-      */
+      // See if we have everything needed...
+      if (printer_location && cg->filter_location_array != NULL)
+      {
+        // Look for a matching printer location...
+        if (!cupsArrayFind(cg->filter_location_array, (void *)printer_location))
+          printer_location = NULL;
+      }
+      else if (printer_location && cg->filter_location_regex != NULL)
+      {
+        // Match the printer location against a regular expression...
+        if (regexec(cg->filter_location_regex, printer_location, 0, NULL, 0))
+          printer_location = NULL;
+      }
 
-      if (!printer_name)
+      if (!printer_name || !printer_location)
       {
         cupsFreeOptions(num_options, options);
 
@@ -3089,19 +3102,20 @@ cups_enum_dests(
   cups_dest_cb_t cb,                    // I - Callback function
   void           *user_data)            // I - User data
 {
-  int           i, j, k,               // Looping vars
-                num_dests,              // Number of destinations
+  int          i, j, k,                // Looping vars
+               num_dests,              // Number of destinations
                num_devices;            // Number of devices
-  cups_dest_t   *dests = NULL,          // Destinations
-                *dest;                 // Current destination
+  const char   *domain;                // Current domain
+  cups_dest_t  *dests = NULL,          // Destinations
+               *dest;                  // Current destination
   cups_option_t        *option;                // Current option
   const char   *user_default;          // Default printer from environment
-  int           count,                  // Number of queries started
-                completed,              // Number of completed queries
-                remaining;              // Remainder of timeout
-  struct timeval curtime;               // Current time
+  int          count,                  // Number of queries started
+               completed,              // Number of completed queries
+               remaining;              // Remainder of timeout
+  struct timeval curtime;              // Current time
   _cups_dnssd_data_t data;             // Data for callback
-  _cups_dnssd_device_t *device;         // Current device
+  _cups_dnssd_device_t *device;                // Current device
   cups_dnssd_t *dnssd = NULL;          // DNS-SD context
   char         filename[1024];         // Local lpoptions file
   _cups_globals_t *cg = _cupsGlobals();        // Pointer to library globals
@@ -3118,6 +3132,10 @@ cups_enum_dests(
     return (0);
   }
 
+  // Load the client.conf files...
+  if (!cg->client_conf_loaded)
+    _cupsSetDefaults();
+
   // Load the /etc/cups/lpoptions and ~/.cups/lpoptions files...
   memset(&data, 0, sizeof(data));
 
@@ -3159,8 +3177,10 @@ cups_enum_dests(
   DEBUG_printf("1cups_enum_dests: def_name=\"%s\", def_instance=\"%s\"", data.def_name, data.def_instance);
 
   // Get ready to enumerate...
-  data.type      = type;
-  data.mask      = mask;
+  cupsRWInit(&data.rwlock);
+
+  data.type      = type | cg->filter_type;
+  data.mask      = mask | cg->filter_type_mask;
   data.cb        = cb;
   data.user_data = user_data;
   data.devices   = cupsArrayNew3((cups_array_func_t)cups_dnssd_compare_devices, NULL, NULL, 0, NULL, (cups_afree_func_t)cups_dnssd_free_device);
@@ -3168,7 +3188,7 @@ cups_enum_dests(
   if (!(mask & CUPS_PTYPE_DISCOVERED) || !(type & CUPS_PTYPE_DISCOVERED))
   {
     // Get the list of local printers and pass them to the callback function...
-    num_dests = _cupsGetDests(http, IPP_OP_CUPS_GET_PRINTERS, NULL, &dests, type, mask);
+    num_dests = _cupsGetDests(http, IPP_OP_CUPS_GET_PRINTERS, NULL, &dests, data.type, data.mask);
 
     if (data.def_name[0])
     {
@@ -3254,6 +3274,9 @@ cups_enum_dests(
   if ((mask & CUPS_PTYPE_DISCOVERED) && !(type & CUPS_PTYPE_DISCOVERED))
     goto enum_finished;
 
+  if (cg->browse_domains && cupsArrayGetCount(cg->browse_domains) == 0)
+    goto enum_finished;
+
   // Get DNS-SD printers...
   if ((dnssd = cupsDNSSDNew(dnssd_error_cb, NULL)) == NULL)
   {
@@ -3265,26 +3288,62 @@ cups_enum_dests(
     return (false);
   }
 
-  if (!cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_ipp._tcp", /*domain*/NULL, cups_dest_browse_cb, &data))
+  if (cg->browse_domains)
   {
-    DEBUG_puts("1cups_enum_dests: Unable to create IPP browser, returning 0.");
-    cupsDNSSDDelete(dnssd);
+    // Browse listed domains
+    for (domain = (char *)cupsArrayGetFirst(cg->browse_domains); domain; domain = (char *)cupsArrayGetNext(cg->browse_domains))
+    {
+      // Drop leading '.' in domain name...
+      if (*domain == '.')
+        domain ++;
 
-    cupsFreeDests(data.num_dests, data.dests);
-    cupsArrayDelete(data.devices);
+      if (!cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_ipp._tcp", domain, cups_dest_browse_cb, &data))
+      {
+       DEBUG_puts("1cups_enum_dests: Unable to create IPP browser, returning 0.");
+       cupsDNSSDDelete(dnssd);
 
-    return (false);
-  }
+       cupsFreeDests(data.num_dests, data.dests);
+       cupsArrayDelete(data.devices);
+
+       return (false);
+      }
+
+      if (!cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_ipps._tcp", domain, cups_dest_browse_cb, &data))
+      {
+       DEBUG_puts("1cups_enum_dests: Unable to create IPPS browser, returning 0.");
+       cupsDNSSDDelete(dnssd);
+
+       cupsFreeDests(data.num_dests, data.dests);
+       cupsArrayDelete(data.devices);
 
-  if (!cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_ipps._tcp", /*domain*/NULL, cups_dest_browse_cb, &data))
+       return (false);
+      }
+    }
+  }
+  else
   {
-    DEBUG_puts("1cups_enum_dests: Unable to create IPPS browser, returning 0.");
-    cupsDNSSDDelete(dnssd);
+    // Browse all domains...
+    if (!cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_ipp._tcp", /*domain*/NULL, cups_dest_browse_cb, &data))
+    {
+      DEBUG_puts("1cups_enum_dests: Unable to create IPP browser, returning 0.");
+      cupsDNSSDDelete(dnssd);
 
-    cupsFreeDests(data.num_dests, data.dests);
-    cupsArrayDelete(data.devices);
+      cupsFreeDests(data.num_dests, data.dests);
+      cupsArrayDelete(data.devices);
 
-    return (false);
+      return (false);
+    }
+
+    if (!cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_ipps._tcp", /*domain*/NULL, cups_dest_browse_cb, &data))
+    {
+      DEBUG_puts("1cups_enum_dests: Unable to create IPPS browser, returning 0.");
+      cupsDNSSDDelete(dnssd);
+
+      cupsFreeDests(data.num_dests, data.dests);
+      cupsArrayDelete(data.devices);
+
+      return (false);
+    }
   }
 
   if (msec < 0)
@@ -3328,14 +3387,34 @@ cups_enum_dests(
       }
       else if (device->query && device->state == _CUPS_DNSSD_PENDING)
       {
+        const char *location = cupsGetOption("printer-location", device->dest.num_options, device->dest.options);
+                                       // Printer location, if any
+
         completed ++;
 
         DEBUG_printf("1cups_enum_dests: Query for \"%s\" is complete.", device->fullname);
 
-        if ((device->type & mask) == type)
+        if (location && cg->filter_location_array)
+        {
+          if (!cupsArrayFind(cg->filter_location_array, (void *)location))
+            device->state = _CUPS_DNSSD_INCOMPATIBLE;
+       }
+       else if (location && cg->filter_location_regex)
+       {
+         if (regexec(cg->filter_location_regex, location, 0, NULL, 0))
+           device->state = _CUPS_DNSSD_INCOMPATIBLE;
+       }
+
+        if ((device->type & mask) != type)
+          device->state = _CUPS_DNSSD_INCOMPATIBLE;
+
+        if (device->state == _CUPS_DNSSD_PENDING)
         {
+          // Device is OK...
           cups_dest_t  *user_dest;     // Destination from lpoptions
 
+          DEBUG_printf("2cups_enum_dests: Doing callback for '%s'.", device->fullname);
+
           dest = &device->dest;
 
          if ((user_dest = cupsGetDest(dest->name, dest->instance, data.num_dests, data.dests)) != NULL)
@@ -3377,9 +3456,14 @@ cups_enum_dests(
              break;
            }
          }
-        }
 
-        device->state = _CUPS_DNSSD_ACTIVE;
+          device->state = _CUPS_DNSSD_ACTIVE;
+        }
+        else
+        {
+          // Filter this one out...
+          DEBUG_printf("2cups_enum_dests: Filtered out '%s'.", device->fullname);
+       }
       }
     }
 
index dbeae44d8f6cf4513f5ebfbf4022aec6b0609450..572603ea21e568e208ddc810b1a32a9513cc5caf 100644 (file)
@@ -1,13 +1,13 @@
-/*
- * Global variable access routines for CUPS.
- *
- * Copyright © 2020-2025 by OpenPrinting.
- * Copyright © 2007-2019 by Apple Inc.
- * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
- *
- * Licensed under Apache License v2.0.  See the file "LICENSE" for more
- * information.
- */
+//
+// Global variable access routines for CUPS.
+//
+// Copyright © 2021-2025 by OpenPrinting.
+// Copyright © 2007-2019 by Apple Inc.
+// Copyright © 1997-2007 by Easy Software Products, all rights reserved.
+//
+// Licensed under Apache License v2.0.  See the file "LICENSE" for more
+// information.
+//
 
 #include "cups-private.h"
 #include "debug-internal.h"
@@ -436,11 +436,18 @@ cups_globals_free(_cups_globals_t *cg)    /* I - Pointer to global data */
   cupsFileClose(cg->stdio_files[1]);
   cupsFileClose(cg->stdio_files[2]);
 
+  cupsArrayDelete(cg->browse_domains);
+  cupsArrayDelete(cg->filter_location_array);
+  if (cg->filter_location_regex)
+  {
+    regfree(cg->filter_location_regex);
+    free(cg->filter_location_regex);
+  }
+
   cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings);
 
   free(cg->userconfig);
   free(cg->raster_error.start);
-
   free(cg);
 }
 #endif /* HAVE_PTHREAD_H || _WIN32 */
index daa895856f2e48712efa815bc4cdd721c3115981..a75ab871b54c2f96f9e10290ab055bb7f8c58ce2 100644 (file)
@@ -2327,7 +2327,7 @@ ippGetPort(void)
 
   DEBUG_puts("ippPort()");
 
-  if (!cg->ipp_port)
+  if (!cg->client_conf_loaded)
     _cupsSetDefaults();
 
   DEBUG_printf("1ippPort: Returning %d...", cg->ipp_port);
index 70052849c9f4707ead1014b41f18f4fd2005ae0e..5e30bf00e8d713cbfab383d3fae7b16c9f0f2035 100644 (file)
@@ -2448,7 +2448,7 @@ ippNew(void)
     // Set default version - usually 2.0...
     DEBUG_printf("4debug_alloc: %p IPP message", (void *)temp);
 
-    if (cg->server_version == 0)
+    if (!cg->client_conf_loaded)
       _cupsSetDefaults();
 
     temp->request.any.version[0] = (ipp_uchar_t)(cg->server_version / 10);
@@ -5712,7 +5712,7 @@ ipp_read_io(void        *src,             // I - Data source
 
                buffer[n] = '\0';
                value->string.text = _cupsStrAlloc((char *)buffer);
-               DEBUG_printf("2ipp_read_io: value=\"%s\"(%p)", value->string.text, value->string.text);
+               DEBUG_printf("2ipp_read_io: value=\"%s\"(%p)", value->string.text, (void *)value->string.text);
                break;
 
            case IPP_TAG_DATE :
index 753327ffaccb23b0038042893836482c6ef39aca..3dd25c1384afe853008d4011c5fdeffec95760a2 100644 (file)
@@ -901,7 +901,7 @@ cupsGetCredentialsTrust(
     return (HTTP_TRUST_UNKNOWN);
   }
 
-  if (cg->any_root < 0)
+  if (!cg->client_conf_loaded)
   {
     _cupsSetDefaults();
     gnutls_load_crl();
@@ -1616,9 +1616,7 @@ _httpTLSStart(http_t *http)               // I - Connection to server
 
   DEBUG_printf("3_httpTLSStart(http=%p)", http);
 
-  priority_string[0] = '\0';
-
-  if (tls_options < 0)
+  if (!cg->client_conf_loaded)
   {
     DEBUG_puts("4_httpTLSStart: Setting defaults.");
     _cupsSetDefaults();
@@ -1821,7 +1819,9 @@ _httpTLSStart(http_t *http)               // I - Connection to server
     return (false);
   }
 
-  if (!(tls_options & _HTTP_TLS_NO_SYSTEM))
+  if (tls_options & _HTTP_TLS_NO_SYSTEM)
+    priority_string[0] = '\0';
+  else
     cupsCopyString(priority_string, "@SYSTEM,", sizeof(priority_string));
 
   cupsConcatString(priority_string, "NORMAL", sizeof(priority_string));
index ba2bac37b786b44a51217a346758c62898ae095b..48a5ab8a26757776c3ad7199a248f793f5ea1d52 100644 (file)
@@ -832,9 +832,7 @@ cupsGetCredentialsTrust(
 
   cert = sk_X509_value(certs, 0);
 
-  DEBUG_printf("1cupsGetCredentialsGetTrust: certs=%p, sk_X509_num(certs)=%d", (void *)certs, sk_X509_num(certs));
-
-  if (cg->any_root < 0)
+  if (!cg->client_conf_loaded)
   {
     _cupsSetDefaults();
 //    openssl_load_crl();
@@ -1589,6 +1587,7 @@ _httpTLSStart(http_t *http)               // I - Connection to server
   char         hostname[256],          // Hostname
                cipherlist[256];        // List of cipher suites
   unsigned long        error;                  // Error code, if any
+  _cups_globals_t *cg = _cupsGlobals();        // Per-thread globals
   static const uint16_t versions[] =   // SSL/TLS versions
   {
     TLS1_VERSION,                      // No more SSL support in OpenSSL
@@ -1607,7 +1606,7 @@ _httpTLSStart(http_t *http)               // I - Connection to server
 
   DEBUG_printf("3_httpTLSStart(http=%p)", (void *)http);
 
-  if (tls_options < 0)
+  if (!cg->client_conf_loaded)
   {
     DEBUG_puts("4_httpTLSStart: Setting defaults.");
     _cupsSetDefaults();
index 4f4a186fb5f281c71ec8e3b16ef95ecd368d6960..705ba8ff4206971c6c57c6ee09f2ad4bef271e13 100644 (file)
@@ -1,13 +1,13 @@
-/*
- * User, system, and password routines for CUPS.
- *
- * Copyright © 2020-2025 by OpenPrinting.
- * Copyright © 2007-2019 by Apple Inc.
- * Copyright © 1997-2006 by Easy Software Products.
- *
- * Licensed under Apache License v2.0.  See the file "LICENSE" for more
- * information.
- */
+//
+// User, system, and password routines for CUPS.
+//
+// Copyright © 2021-2025 by OpenPrinting.
+// Copyright © 2007-2019 by Apple Inc.
+// Copyright © 1997-2006 by Easy Software Products.
+//
+// Licensed under Apache License v2.0.  See the file "LICENSE" for more
+// information.
+//
 
 #include "cups-private.h"
 #include "debug-internal.h"
 #  include <pwd.h>
 #  include <termios.h>
 #  include <sys/utsname.h>
-#endif /* _WIN32 */
+#endif // _WIN32
 #ifdef __APPLE__
 #  include <sys/sysctl.h>
-#endif /* __APPLE__ */
+#endif // __APPLE__
 
 
-/*
- * Local constants...
- */
+//
+// Local constants...
+//
 
 #ifdef __APPLE__
 #  if TARGET_OS_OSX
@@ -36,7 +36,7 @@
 #  else
 #    define kCUPSPrintingPrefs CFSTR(".GlobalPreferences")
 #    define kPREFIX            "AirPrint"
-#  endif /* TARGET_OS_OSX */
+#  endif // TARGET_OS_OSX
 #  define kDigestOptionsKey    CFSTR(kPREFIX "DigestOptions")
 #  define kUserKey             CFSTR(kPREFIX "User")
 #  define kUserAgentTokensKey  CFSTR(kPREFIX "UserAgentTokens")
 #  define kSSLOptionsKey       CFSTR(kPREFIX "SSLOptions")
 #  define kTrustOnFirstUseKey  CFSTR(kPREFIX "TrustOnFirstUse")
 #  define kValidateCertsKey    CFSTR(kPREFIX "ValidateCerts")
-/* Deprecated */
+// Deprecated */
 #  define kAllowRC4            CFSTR(kPREFIX "AllowRC4")
 #  define kAllowSSL3           CFSTR(kPREFIX "AllowSSL3")
 #  define kAllowDH             CFSTR(kPREFIX "AllowDH")
-#endif /* __APPLE__ */
+#endif // __APPLE__
 
-#define _CUPS_PASSCHAR '*'             /* Character that is echoed for password */
+#define _CUPS_PASSCHAR '*'             // Character that is echoed for password
 
 
-/*
- * Local types...
- */
+//
+// Local types...
+//
 
-typedef struct _cups_client_conf_s     /**** client.conf config data ****/
+typedef struct _cups_client_conf_s     // client.conf config data
 {
-  _cups_digestoptions_t        digestoptions;  /* DigestOptions values */
-  _cups_uatokens_t     uatokens;       /* UserAgentTokens values */
-  int                  ssl_options,    /* SSLOptions values */
-                       ssl_min_version,/* Minimum SSL/TLS version */
-                       ssl_max_version;/* Maximum SSL/TLS version */
-  int                  trust_first,    /* Trust on first use? */
-                       any_root,       /* Allow any (e.g., self-signed) root */
-                       expired_certs,  /* Allow expired certs */
-                       validate_certs; /* Validate certificates */
-  http_encryption_t    encryption;     /* Encryption setting */
-  char                 user[65],       /* User name */
-                       server_name[256];
-                                       /* Server hostname */
+  _cups_digestoptions_t        digestoptions;  // DigestOptions values
+  _cups_uatokens_t     uatokens;       // UserAgentTokens values
+  int                  ssl_options,    // SSLOptions values
+                       ssl_min_version,// Minimum SSL/TLS version
+                       ssl_max_version;// Maximum SSL/TLS version
+  int                  trust_first,    // Trust on first use?
+                       any_root,       // Allow any (e.g., self-signed) root
+                       expired_certs,  // Allow expired certs
+                       validate_certs; // Validate certificates
+  http_encryption_t    encryption;     // Encryption setting
+  char                 user[65],       // User name
+                       server_name[256],
+                                       // Server hostname
+                       browse_domains[1024],
+                                       // Browse domains
+                       filter_location[1024],
+                                       // Filter location(s)
+                       filter_type[256];
+                                       // Filter type(s)
 #ifdef HAVE_GSSAPI
   char                 gss_service_name[32];
-                                       /* Kerberos service name */
-#endif /* HAVE_GSSAPI */
+                                       // Kerberos service name
+#endif // HAVE_GSSAPI
 } _cups_client_conf_t;
 
 
-/*
- * Local functions...
- */
+//
+// Local functions...
+//
 
 #ifdef __APPLE__
 static int     cups_apple_get_boolean(CFStringRef key, int *value);
 static int     cups_apple_get_string(CFStringRef key, char *value, size_t valsize);
-#endif /* __APPLE__ */
+#endif // __APPLE__
 static int     cups_boolean_value(const char *value);
 static void    cups_finalize_client_conf(_cups_client_conf_t *cc);
 static void    cups_init_client_conf(_cups_client_conf_t *cc);
 static void    cups_read_client_conf(cups_file_t *fp, _cups_client_conf_t *cc);
 static void    cups_set_default_ipp_port(_cups_globals_t *cg);
+static void    cups_set_browse_domains(_cups_client_conf_t *cc, const char *value);
 static void    cups_set_digestoptions(_cups_client_conf_t *cc, const char *value);
 static void    cups_set_encryption(_cups_client_conf_t *cc, const char *value);
+static void    cups_set_filter_location(_cups_client_conf_t *cc, const char *value);
+static void    cups_set_filter_type(_cups_client_conf_t *cc, const char *value);
 #ifdef HAVE_GSSAPI
 static void    cups_set_gss_service_name(_cups_client_conf_t *cc, const char *value);
-#endif /* HAVE_GSSAPI */
+#endif // HAVE_GSSAPI
 static void    cups_set_server_name(_cups_client_conf_t *cc, const char *value);
 static void    cups_set_ssl_options(_cups_client_conf_t *cc, const char *value);
 static void    cups_set_uatokens(_cups_client_conf_t *cc, const char *value);
 static void    cups_set_user(_cups_client_conf_t *cc, const char *value);
 
 
-/*
- * 'cupsEncryption()' - Get the current encryption settings.
- *
- * @deprecated@
- */
+//
+// Local globals...
+//
+
+static const char * const uatokens[] =// UserAgentTokens values
+{
+  "None",
+  "ProductOnly",
+  "Major",
+  "Minor",
+  "Minimal",
+  "OS",
+  "Full"
+};
+#ifdef DEBUG
+static const char * const tls_versions[] =
+{                                      // TLS/SSL version numbers
+  "SSL3.0",
+  "TLS1.0",
+  "TLS1.1",
+  "TLS1.2",
+  "TLS1.3",
+  "TLS1.3"
+};
+#endif // DEBUG
+
+
+//
+// 'cupsEncryption()' - Get the current encryption settings.
+//
+// @deprecated@
+//
 
-http_encryption_t                      /* O - Encryption settings */
+http_encryption_t                      // O - Encryption settings
 cupsEncryption(void)
 {
   return (cupsGetEncryption());
 }
 
 
-/*
- * 'cupsGetEncryption()' - Get the current encryption settings.
- *
- * The default encryption setting comes from the CUPS_ENCRYPTION
- * environment variable, then the ~/.cups/client.conf file, and finally the
- * /etc/cups/client.conf file. If not set, the default is
- * @code HTTP_ENCRYPTION_IF_REQUESTED@.
- *
- * Note: The current encryption setting is tracked separately for each thread
- * in a program. Multi-threaded programs that override the setting via the
- * @link cupsSetEncryption@ function need to do so in each thread for the same
- * setting to be used.
- *
- * @since CUPS 2.5@
- */
-
-http_encryption_t                      /* O - Encryption settings */
+//
+// 'cupsGetEncryption()' - Get the current encryption settings.
+//
+// The default encryption setting comes from the CUPS_ENCRYPTION
+// environment variable, then the ~/.cups/client.conf file, and finally the
+// /etc/cups/client.conf file. If not set, the default is
+// @code HTTP_ENCRYPTION_IF_REQUESTED@.
+//
+// Note: The current encryption setting is tracked separately for each thread
+// in a program. Multi-threaded programs that override the setting via the
+// @link cupsSetEncryption@ function need to do so in each thread for the same
+// setting to be used.
+//
+// @since CUPS 2.5@
+//
+
+http_encryption_t                      // O - Encryption settings
 cupsGetEncryption(void)
 {
-  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
+  _cups_globals_t *cg = _cupsGlobals();        // Pointer to library globals
 
 
-  if (cg->encryption == (http_encryption_t)-1)
+  if (!cg->client_conf_loaded)
     _cupsSetDefaults();
 
   return (cg->encryption);
 }
 
 
-/*
- * 'cupsGetPassword()' - Get a password from the user.
- *
- * Uses the current password callback function. Returns @code NULL@ if the
- * user does not provide a password.
- *
- * Note: The current password callback function is tracked separately for each
- * thread in a program. Multi-threaded programs that override the setting via
- * the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
- * do so in each thread for the same function to be used.
- *
- * @exclude all@
- */
-
-const char *                           /* O - Password */
-cupsGetPassword(const char *prompt)    /* I - Prompt string */
+//
+// 'cupsGetPassword()' - Get a password from the user.
+//
+// Uses the current password callback function. Returns @code NULL@ if the
+// user does not provide a password.
+//
+// Note: The current password callback function is tracked separately for each
+// thread in a program. Multi-threaded programs that override the setting via
+// the @link cupsSetPasswordCB@ or @link cupsSetPasswordCB2@ functions need to
+// do so in each thread for the same function to be used.
+//
+// @exclude all@
+//
+
+const char *                           // O - Password
+cupsGetPassword(const char *prompt)    // I - Prompt string
 {
-  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
+  _cups_globals_t *cg = _cupsGlobals();        // Pointer to library globals
 
 
   return ((cg->password_cb)(prompt, NULL, NULL, NULL, cg->password_data));
 }
 
 
-/*
- * 'cupsGetPassword2()' - Get a password from the user using the current
- *                        password callback.
- *
- * Uses the current password callback function. Returns @code NULL@ if the
- * user does not provide a password.
- *
- * Note: The current password callback function is tracked separately for each
- * thread in a program. Multi-threaded programs that override the setting via
- * the @link cupsSetPasswordCB2@ function need to do so in each thread for the
- * same function to be used.
- *
- * @since CUPS 1.4@
- */
-
-const char *                           /* O - Password */
-cupsGetPassword2(const char *prompt,   /* I - Prompt string */
-                http_t     *http,      /* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
-                const char *method,    /* I - Request method ("GET", "POST", "PUT") */
-                const char *resource)  /* I - Resource path */
+//
+// 'cupsGetPassword2()' - Get a password from the user using the current
+//                        password callback.
+//
+// Uses the current password callback function. Returns @code NULL@ if the
+// user does not provide a password.
+//
+// Note: The current password callback function is tracked separately for each
+// thread in a program. Multi-threaded programs that override the setting via
+// the @link cupsSetPasswordCB2@ function need to do so in each thread for the
+// same function to be used.
+//
+// @since CUPS 1.4@
+//
+
+const char *                           // O - Password
+cupsGetPassword2(const char *prompt,   // I - Prompt string
+                http_t     *http,      // I - Connection to server or @code CUPS_HTTP_DEFAULT@
+                const char *method,    // I - Request method ("GET", "POST", "PUT")
+                const char *resource)  // I - Resource path
 {
-  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
+  _cups_globals_t *cg = _cupsGlobals();        // Pointer to library globals
 
 
   if (!http)
@@ -203,72 +239,72 @@ cupsGetPassword2(const char *prompt,      /* I - Prompt string */
 }
 
 
-/*
- * 'cupsGetServer()' - Return the hostname/address of the current server.
- *
- * The default server comes from the CUPS_SERVER environment variable, then the
- * ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not
- * set, the default is the local system - either "localhost" or a domain socket
- * path.
- *
- * The returned value can be a fully-qualified hostname, a numeric IPv4 or IPv6
- * address, or a domain socket pathname.
- *
- * Note: The current server is tracked separately for each thread in a program.
- * Multi-threaded programs that override the server via the
- * @link cupsSetServer@ function need to do so in each thread for the same
- * server to be used.
- *
- * @since CUPS 2.5@
- */
-
-const char *                           /* O - Server name */
+//
+// 'cupsGetServer()' - Return the hostname/address of the current server.
+//
+// The default server comes from the CUPS_SERVER environment variable, then the
+// ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not
+// set, the default is the local system - either "localhost" or a domain socket
+// path.
+//
+// The returned value can be a fully-qualified hostname, a numeric IPv4 or IPv6
+// address, or a domain socket pathname.
+//
+// Note: The current server is tracked separately for each thread in a program.
+// Multi-threaded programs that override the server via the
+// @link cupsSetServer@ function need to do so in each thread for the same
+// server to be used.
+//
+// @since CUPS 2.5@
+//
+
+const char *                           // O - Server name
 cupsGetServer(void)
 {
-  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
+  _cups_globals_t *cg = _cupsGlobals();        // Pointer to library globals
 
 
-  if (!cg->server[0])
+  if (!cg->client_conf_loaded)
     _cupsSetDefaults();
 
   return (cg->server);
 }
 
 
-/*
- * 'cupsGetUser()' - Return the current user's name.
- *
- * Note: The current user name is tracked separately for each thread in a
- * program. Multi-threaded programs that override the user name with the
- * @link cupsSetUser@ function need to do so in each thread for the same user
- * name to be used.
- *
- * @since CUPS 2.5@
- */
+//
+// 'cupsGetUser()' - Return the current user's name.
+//
+// Note: The current user name is tracked separately for each thread in a
+// program. Multi-threaded programs that override the user name with the
+// @link cupsSetUser@ function need to do so in each thread for the same user
+// name to be used.
+//
+// @since CUPS 2.5@
+//
 
-const char *                           /* O - User name */
+const char *                           // O - User name
 cupsGetUser(void)
 {
-  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
+  _cups_globals_t *cg = _cupsGlobals();        // Pointer to library globals
 
 
-  if (!cg->user[0])
+  if (!cg->client_conf_loaded)
     _cupsSetDefaults();
 
   return (cg->user);
 }
 
 
-/*
- * 'cupsGetUserAgent()' - Return the default HTTP User-Agent string.
- *
- * @since CUPS 2.5@
- */
+//
+// 'cupsGetUserAgent()' - Return the default HTTP User-Agent string.
+//
+// @since CUPS 2.5@
+//
 
-const char *                           /* O - User-Agent string */
+const char *                           // O - User-Agent string
 cupsGetUserAgent(void)
 {
-  _cups_globals_t *cg = _cupsGlobals();        /* Thread globals */
+  _cups_globals_t *cg = _cupsGlobals();        // Thread globals
 
 
   if (!cg->user_agent[0])
@@ -278,48 +314,48 @@ cupsGetUserAgent(void)
 }
 
 
-/*
- * 'cupsServer()' - Return the hostname/address of the current server.
- *
- * The default server comes from the CUPS_SERVER environment variable, then the
- * ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not
- * set, the default is the local system - either "localhost" or a domain socket
- * path.
- *
- * The returned value can be a fully-qualified hostname, a numeric IPv4 or IPv6
- * address, or a domain socket pathname.
- *
- * Note: The current server is tracked separately for each thread in a program.
- * Multi-threaded programs that override the server via the
- * @link cupsSetServer@ function need to do so in each thread for the same
- * server to be used.
- *
- * @deprecated@
- */
-
-const char *                           /* O - Server name */
+//
+// 'cupsServer()' - Return the hostname/address of the current server.
+//
+// The default server comes from the CUPS_SERVER environment variable, then the
+// ~/.cups/client.conf file, and finally the /etc/cups/client.conf file. If not
+// set, the default is the local system - either "localhost" or a domain socket
+// path.
+//
+// The returned value can be a fully-qualified hostname, a numeric IPv4 or IPv6
+// address, or a domain socket pathname.
+//
+// Note: The current server is tracked separately for each thread in a program.
+// Multi-threaded programs that override the server via the
+// @link cupsSetServer@ function need to do so in each thread for the same
+// server to be used.
+//
+// @deprecated@
+//
+
+const char *                           // O - Server name
 cupsServer(void)
 {
   return (cupsGetServer());
 }
 
 
-/*
- * 'cupsSetClientCertCB()' - Set the client certificate callback.
- *
- * Pass @code NULL@ to restore the default callback.
- *
- * Note: The current certificate callback is tracked separately for each thread
- * in a program. Multi-threaded programs that override the callback need to do
- * so in each thread for the same callback to be used.
- *
- * @deprecated@
- */
+//
+// 'cupsSetClientCertCB()' - Set the client certificate callback.
+//
+// Pass @code NULL@ to restore the default callback.
+//
+// Note: The current certificate callback is tracked separately for each thread
+// in a program. Multi-threaded programs that override the callback need to do
+// so in each thread for the same callback to be used.
+//
+// @deprecated@
+//
 
 void
 cupsSetClientCertCB(
-    cups_client_cert_cb_t cb,          /* I - Callback function */
-    void                  *user_data)  /* I - User data pointer */
+    cups_client_cert_cb_t cb,          // I - Callback function
+    void                  *user_data)  // I - User data pointer
 {
   (void)cb;
   (void)user_data;
@@ -354,16 +390,16 @@ cupsSetClientCredentials(
 }
 
 
-/*
- * 'cupsSetCredentials()' - Set the default credentials to be used for SSL/TLS
- *                         connections.
- *
- * @deprecated@
- */
+//
+// 'cupsSetCredentials()' - Set the default credentials to be used for SSL/TLS
+//                         connections.
+//
+// @deprecated@
+//
 
-int                                    /* O - Status of call (0 = success) */
+int                                    // O - Status of call (0 = success)
 cupsSetCredentials(
-    cups_array_t *credentials)         /* I - Array of credentials */
+    cups_array_t *credentials)         // I - Array of credentials
 {
   (void)credentials;
 
@@ -371,23 +407,23 @@ cupsSetCredentials(
 }
 
 
-/*
- * 'cupsSetEncryption()' - Set the encryption preference.
- *
- * The default encryption setting comes from the CUPS_ENCRYPTION
- * environment variable, then the ~/.cups/client.conf file, and finally the
- * /etc/cups/client.conf file. If not set, the default is
- * @code HTTP_ENCRYPTION_IF_REQUESTED@.
- *
- * Note: The current encryption setting is tracked separately for each thread
- * in a program. Multi-threaded programs that override the setting need to do
- * so in each thread for the same setting to be used.
- */
+//
+// 'cupsSetEncryption()' - Set the encryption preference.
+//
+// The default encryption setting comes from the CUPS_ENCRYPTION
+// environment variable, then the ~/.cups/client.conf file, and finally the
+// /etc/cups/client.conf file. If not set, the default is
+// @code HTTP_ENCRYPTION_IF_REQUESTED@.
+//
+// Note: The current encryption setting is tracked separately for each thread
+// in a program. Multi-threaded programs that override the setting need to do
+// so in each thread for the same setting to be used.
+//
 
 void
-cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */
+cupsSetEncryption(http_encryption_t e) // I - New encryption preference
 {
-  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
+  _cups_globals_t *cg = _cupsGlobals();        // Pointer to library globals
 
 
   cg->encryption = e;
@@ -397,36 +433,36 @@ cupsSetEncryption(http_encryption_t e)    /* I - New encryption preference */
 }
 
 
-/*
- * 'cupsSetOAuthCB()' - Set the OAuth 2.0 callback for CUPS.
- *
- * This function sets the OAuth 2.0 callback for the various CUPS APIs that
- * send HTTP requests. Pass @code NULL@ to restore the default (console-based)
- * callback.
- *
- * The OAuth callback receives the HTTP connection, realm name, scope name (if
- * any), resource path, and the "user_data" pointer for each request that
- * requires an OAuth access token. The function then returns either the Bearer
- * token string or `NULL` if no authorization could be obtained.
- *
- * Beyond reusing the Bearer token for subsequent requests on the same HTTP
- * connection, no caching of the token is done by the CUPS library.  The
- * callback can determine whether to refresh a cached token by examining any
- * existing token returned by the @link httpGetAuthString@ function.
- *
- * Note: The current OAuth callback is tracked separately for each thread in a
- * program. Multi-threaded programs that override the callback need to do so in
- * each thread for the same callback to be used.
- *
- * @since CUPS 2.4@
- */
+//
+// 'cupsSetOAuthCB()' - Set the OAuth 2.0 callback for CUPS.
+//
+// This function sets the OAuth 2.0 callback for the various CUPS APIs that
+// send HTTP requests. Pass @code NULL@ to restore the default (console-based)
+// callback.
+//
+// The OAuth callback receives the HTTP connection, realm name, scope name (if
+// any), resource path, and the "user_data" pointer for each request that
+// requires an OAuth access token. The function then returns either the Bearer
+// token string or `NULL` if no authorization could be obtained.
+//
+// Beyond reusing the Bearer token for subsequent requests on the same HTTP
+// connection, no caching of the token is done by the CUPS library.  The
+// callback can determine whether to refresh a cached token by examining any
+// existing token returned by the @link httpGetAuthString@ function.
+//
+// Note: The current OAuth callback is tracked separately for each thread in a
+// program. Multi-threaded programs that override the callback need to do so in
+// each thread for the same callback to be used.
+//
+// @since CUPS 2.4@
+//
 
 void
 cupsSetOAuthCB(
-    cups_oauth_cb_t cb,                        /* I - Callback function */
-    void            *user_data)                /* I - User data pointer */
+    cups_oauth_cb_t cb,                        // I - Callback function
+    void            *user_data)                // I - User data pointer
 {
-  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
+  _cups_globals_t *cg = _cupsGlobals();        // Pointer to library globals
 
 
   cg->oauth_cb   = cb;
@@ -434,25 +470,25 @@ cupsSetOAuthCB(
 }
 
 
-/*
- * 'cupsSetPasswordCB()' - Set the password callback for CUPS.
- *
- * Pass @code NULL@ to restore the default (console) password callback, which
- * reads the password from the console. Programs should call either this
- * function or @link cupsSetPasswordCB2@, as only one callback can be registered
- * by a program per thread.
- *
- * Note: The current password callback is tracked separately for each thread
- * in a program. Multi-threaded programs that override the callback need to do
- * so in each thread for the same callback to be used.
- *
- * @exclude all@
- */
+//
+// 'cupsSetPasswordCB()' - Set the password callback for CUPS.
+//
+// Pass @code NULL@ to restore the default (console) password callback, which
+// reads the password from the console. Programs should call either this
+// function or @link cupsSetPasswordCB2@, as only one callback can be registered
+// by a program per thread.
+//
+// Note: The current password callback is tracked separately for each thread
+// in a program. Multi-threaded programs that override the callback need to do
+// so in each thread for the same callback to be used.
+//
+// @exclude all@
+//
 
 void
-cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */
+cupsSetPasswordCB(cups_password_cb_t cb)// I - Callback function
 {
-  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
+  _cups_globals_t *cg = _cupsGlobals();        // Pointer to library globals
 
 
   if (cb == (cups_password_cb_t)0)
@@ -464,27 +500,27 @@ cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */
 }
 
 
-/*
- * 'cupsSetPasswordCB2()' - Set the advanced password callback for CUPS.
- *
- * Pass @code NULL@ to restore the default (console) password callback, which
- * reads the password from the console. Programs should call either this
- * function or @link cupsSetPasswordCB2@, as only one callback can be registered
- * by a program per thread.
- *
- * Note: The current password callback is tracked separately for each thread
- * in a program. Multi-threaded programs that override the callback need to do
- * so in each thread for the same callback to be used.
- *
- * @since CUPS 1.4@
- */
+//
+// 'cupsSetPasswordCB2()' - Set the advanced password callback for CUPS.
+//
+// Pass @code NULL@ to restore the default (console) password callback, which
+// reads the password from the console. Programs should call either this
+// function or @link cupsSetPasswordCB2@, as only one callback can be registered
+// by a program per thread.
+//
+// Note: The current password callback is tracked separately for each thread
+// in a program. Multi-threaded programs that override the callback need to do
+// so in each thread for the same callback to be used.
+//
+// @since CUPS 1.4@
+//
 
 void
 cupsSetPasswordCB2(
-    cups_password_cb2_t cb,            /* I - Callback function */
-    void                *user_data)    /* I - User data pointer */
+    cups_password_cb2_t cb,            // I - Callback function
+    void                *user_data)    // I - User data pointer
 {
-  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
+  _cups_globals_t *cg = _cupsGlobals();        // Pointer to library globals
 
 
   if (cb == (cups_password_cb2_t)0)
@@ -496,26 +532,26 @@ cupsSetPasswordCB2(
 }
 
 
-/*
- * 'cupsSetServer()' - Set the default server name and port.
- *
- * The "server" string can be a fully-qualified hostname, a numeric
- * IPv4 or IPv6 address, or a domain socket pathname. Hostnames and numeric IP
- * addresses can be optionally followed by a colon and port number to override
- * the default port 631, e.g. "hostname:8631". Pass @code NULL@ to restore the
- * default server name and port.
- *
- * Note: The current server is tracked separately for each thread in a program.
- * Multi-threaded programs that override the server need to do so in each
- * thread for the same server to be used.
- */
+//
+// 'cupsSetServer()' - Set the default server name and port.
+//
+// The "server" string can be a fully-qualified hostname, a numeric
+// IPv4 or IPv6 address, or a domain socket pathname. Hostnames and numeric IP
+// addresses can be optionally followed by a colon and port number to override
+// the default port 631, e.g. "hostname:8631". Pass @code NULL@ to restore the
+// default server name and port.
+//
+// Note: The current server is tracked separately for each thread in a program.
+// Multi-threaded programs that override the server need to do so in each
+// thread for the same server to be used.
+//
 
 void
-cupsSetServer(const char *server)      /* I - Server name */
+cupsSetServer(const char *server)      // I - Server name
 {
-  char         *options,               /* Options */
-               *port;                  /* Pointer to port */
-  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
+  char         *options,               // Options
+               *port;                  // Pointer to port
+  _cups_globals_t *cg = _cupsGlobals();        // Pointer to library globals
 
 
   if (server)
@@ -572,42 +608,42 @@ cupsSetServer(const char *server) /* I - Server name */
 }
 
 
-/*
- * 'cupsSetServerCertCB()' - Set the server certificate callback.
- *
- * Pass @code NULL@ to restore the default callback.
- *
- * Note: The current credentials callback is tracked separately for each thread
- * in a program. Multi-threaded programs that override the callback need to do
- * so in each thread for the same callback to be used.
- *
- * @deprecated@
- */
+//
+// 'cupsSetServerCertCB()' - Set the server certificate callback.
+//
+// Pass @code NULL@ to restore the default callback.
+//
+// Note: The current credentials callback is tracked separately for each thread
+// in a program. Multi-threaded programs that override the callback need to do
+// so in each thread for the same callback to be used.
+//
+// @deprecated@
+//
 
 void
 cupsSetServerCertCB(
-    cups_server_cert_cb_t cb,          /* I - Callback function */
-    void                 *user_data)   /* I - User data pointer */
+    cups_server_cert_cb_t cb,          // I - Callback function
+    void                 *user_data)   // I - User data pointer
 {
   (void)cb;
   (void)user_data;
 }
 
 
-/*
- * 'cupsSetUser()' - Set the default user name.
- *
- * Pass @code NULL@ to restore the default user name.
- *
- * Note: The current user name is tracked separately for each thread in a
- * program. Multi-threaded programs that override the user name need to do so
- * in each thread for the same user name to be used.
- */
+//
+// 'cupsSetUser()' - Set the default user name.
+//
+// Pass @code NULL@ to restore the default user name.
+//
+// Note: The current user name is tracked separately for each thread in a
+// program. Multi-threaded programs that override the user name need to do so
+// in each thread for the same user name to be used.
+//
 
 void
-cupsSetUser(const char *user)          /* I - User name */
+cupsSetUser(const char *user)          // I - User name
 {
-  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
+  _cups_globals_t *cg = _cupsGlobals();        // Pointer to library globals
 
 
   if (user)
@@ -617,31 +653,31 @@ cupsSetUser(const char *user)             /* I - User name */
 }
 
 
-/*
- * 'cupsSetUserAgent()' - Set the default HTTP User-Agent string.
- *
- * Setting the string to NULL forces the default value containing the CUPS
- * version, IPP version, and operating system version and architecture.
- *
- * @since CUPS 1.7@
- */
+//
+// 'cupsSetUserAgent()' - Set the default HTTP User-Agent string.
+//
+// Setting the string to NULL forces the default value containing the CUPS
+// version, IPP version, and operating system version and architecture.
+//
+// @since CUPS 1.7@
+//
 
 void
-cupsSetUserAgent(const char *user_agent)/* I - User-Agent string or @code NULL@ */
+cupsSetUserAgent(const char *user_agent)// I - User-Agent string or @code NULL@
 {
   _cups_globals_t      *cg = _cupsGlobals();
-                                       /* Thread globals */
+                                       // Thread globals
 #ifdef _WIN32
-  SYSTEM_INFO          sysinfo;        /* System information */
-  OSVERSIONINFOW       version;        /* OS version info */
-  const char           *machine;       /* Hardware/machine name */
+  SYSTEM_INFO          sysinfo;        // System information
+  OSVERSIONINFOW       version;        // OS version info
+  const char           *machine;       // Hardware/machine name
 #elif defined(__APPLE__)
-  struct utsname       name;           /* uname info */
-  char                 version[256];   /* macOS/iOS version */
-  size_t               len;            /* Length of value */
+  struct utsname       name;           // uname info
+  char                 version[256];   // macOS/iOS version
+  size_t               len;            // Length of value
 #else
-  struct utsname       name;           /* uname info */
-#endif /* _WIN32 */
+  struct utsname       name;           // uname info
+#endif // _WIN32
 
 
   if (user_agent)
@@ -675,16 +711,13 @@ cupsSetUserAgent(const char *user_agent)/* I - User-Agent string or @code NULL@
   }
 
 #ifdef _WIN32
- /*
-  * Gather Windows version information for the User-Agent string...
-  */
-
+  // Gather Windows version information for the User-Agent string...
   typedef NTSTATUS(WINAPI * RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
 
   memset(&version, 0, sizeof(version));
   version.dwOSVersionInfoSize = sizeof(version);
 
-  /* RtlGetVersion gets the current native version of Windows, even when running in compatibility mode */
+  // RtlGetVersion gets the current native version of Windows, even when running in compatibility mode
   RtlGetVersionPtr RtlGetVersionInternal = (RtlGetVersionPtr)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlGetVersion");
   if (RtlGetVersionInternal)
   {
@@ -692,7 +725,7 @@ cupsSetUserAgent(const char *user_agent)/* I - User-Agent string or @code NULL@
   }
   else
   {
-    /* Should not happen, but just in case, fallback to deprecated GetVersionExW */
+    // Should not happen, but just in case, fallback to deprecated GetVersionExW
     GetVersionExW(&version);
   }
   GetNativeSystemInfo(&sysinfo);
@@ -726,10 +759,7 @@ cupsSetUserAgent(const char *user_agent)/* I - User-Agent string or @code NULL@
     snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (Windows %lu.%lu; %s) IPP/2.0", version.dwMajorVersion, version.dwMinorVersion, machine);
 
 #elif defined(__APPLE__)
- /*
-  * Gather macOS/iOS version information for the User-Agent string...
-  */
-
+  // Gather macOS/iOS version information for the User-Agent string...
   uname(&name);
 
   len = sizeof(version) - 1;
@@ -749,76 +779,70 @@ cupsSetUserAgent(const char *user_agent)/* I - User-Agent string or @code NULL@
     snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (iOS %s) IPP/2.0", version);
   else
     snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (iOS %s; %s) IPP/2.0", version, name.machine);
-#  endif /* TARGET_OS_OSX */
+#  endif // TARGET_OS_OSX
 
 #else
- /*
-  * Gather generic UNIX version information for the User-Agent string...
-  */
-
+  // Gather generic UNIX version information for the User-Agent string...
   uname(&name);
 
   if (cg->uatokens == _CUPS_UATOKENS_OS)
     snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (%s %s) IPP/2.0", name.sysname, name.release);
   else
     snprintf(cg->user_agent, sizeof(cg->user_agent), CUPS_MINIMAL " (%s %s; %s) IPP/2.0", name.sysname, name.release, name.machine);
-#endif /* _WIN32 */
+#endif // _WIN32
 }
 
 
-/*
- * 'cupsUser()' - Return the current user's name.
- *
- * Note: The current user name is tracked separately for each thread in a
- * program. Multi-threaded programs that override the user name with the
- * @link cupsSetUser@ function need to do so in each thread for the same user
- * name to be used.
- *
- * @deprecated@
- */
+//
+// 'cupsUser()' - Return the current user's name.
+//
+// Note: The current user name is tracked separately for each thread in a
+// program. Multi-threaded programs that override the user name with the
+// @link cupsSetUser@ function need to do so in each thread for the same user
+// name to be used.
+//
+// @deprecated@
+//
 
-const char *                           /* O - User name */
+const char *                           // O - User name
 cupsUser(void)
 {
   return (cupsGetUser());
 }
 
 
-/*
- * 'cupsUserAgent()' - Return the default HTTP User-Agent string.
- *
- * @deprecated@
- */
+//
+// 'cupsUserAgent()' - Return the default HTTP User-Agent string.
+//
+// @deprecated@
+//
 
-const char *                           /* O - User-Agent string */
+const char *                           // O - User-Agent string
 cupsUserAgent(void)
 {
   return (cupsGetUserAgent());
 }
 
 
-/*
- * '_cupsGetPassword()' - Get a password from the user.
- */
+//
+// '_cupsGetPassword()' - Get a password from the user.
+//
 
-const char *                           /* O - Password or @code NULL@ if none */
-_cupsGetPassword(const char *prompt)   /* I - Prompt string */
+const char *                           // O - Password or @code NULL@ if none
+_cupsGetPassword(const char *prompt)   // I - Prompt string
 {
 #ifdef _WIN32
-  HANDLE               tty;            /* Console handle */
-  DWORD                        mode;           /* Console mode */
-  char                 passch,         /* Current key press */
-                       *passptr,       /* Pointer into password string */
-                       *passend;       /* End of password string */
-  DWORD                        passbytes;      /* Bytes read */
+  HANDLE               tty;            // Console handle
+  DWORD                        mode;           // Console mode
+  char                 passch,         // Current key press
+                       *passptr,       // Pointer into password string
+                       *passend;       // End of password string
+  DWORD                        passbytes;      // Bytes read
   _cups_globals_t      *cg = _cupsGlobals();
-                                       /* Thread globals */
-
+                                       // Thread globals
 
- /*
-  * Disable input echo and set raw input...
-  */
 
+  // Disable input echo and set raw input...
   if ((tty = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE)
     return (NULL);
 
@@ -828,18 +852,12 @@ _cupsGetPassword(const char *prompt)      /* I - Prompt string */
   if (!SetConsoleMode(tty, 0))
     return (NULL);
 
- /*
-  * Display the prompt...
-  */
-
+  // Display the prompt...
   printf("%s ", prompt);
   fflush(stdout);
 
- /*
-  * Read the password string from /dev/tty until we get interrupted or get a
-  * carriage return or newline...
-  */
-
+  // Read the password string from /dev/tty until we get interrupted or get a
+  // carriage return or newline...
   passptr = cg->password;
   passend = cg->password + sizeof(cg->password) - 1;
 
@@ -847,18 +865,12 @@ _cupsGetPassword(const char *prompt)      /* I - Prompt string */
   {
     if (passch == 0x0A || passch == 0x0D)
     {
-     /*
-      * Enter/return...
-      */
-
+      // Enter/return...
       break;
     }
     else if (passch == 0x08 || passch == 0x7F)
     {
-     /*
-      * Backspace/delete (erase character)...
-      */
-
+      // Backspace/delete (erase character)...
       if (passptr > cg->password)
       {
         passptr --;
@@ -869,10 +881,7 @@ _cupsGetPassword(const char *prompt)       /* I - Prompt string */
     }
     else if (passch == 0x15)
     {
-     /*
-      * CTRL+U (erase line)
-      */
-
+      // CTRL+U (erase line)
       if (passptr > cg->password)
       {
        while (passptr > cg->password)
@@ -886,10 +895,7 @@ _cupsGetPassword(const char *prompt)       /* I - Prompt string */
     }
     else if (passch == 0x03)
     {
-     /*
-      * CTRL+C...
-      */
-
+      // CTRL+C...
       passptr = cg->password;
       break;
     }
@@ -907,16 +913,11 @@ _cupsGetPassword(const char *prompt)      /* I - Prompt string */
   putchar('\n');
   fflush(stdout);
 
- /*
-  * Cleanup...
-  */
+  // Cleanup...
 
   SetConsoleMode(tty, mode);
 
- /*
-  * Return the proper value...
-  */
-
+  // Return the proper value...
   if (passbytes == 1 && passptr > cg->password)
   {
     *passptr = '\0';
@@ -929,21 +930,18 @@ _cupsGetPassword(const char *prompt)      /* I - Prompt string */
   }
 
 #else
-  int                  tty;            /* /dev/tty - never read from stdin */
-  struct termios       original,       /* Original input mode */
-                       noecho;         /* No echo input mode */
-  char                 passch,         /* Current key press */
-                       *passptr,       /* Pointer into password string */
-                       *passend;       /* End of password string */
-  ssize_t              passbytes;      /* Bytes read */
+  int                  tty;            // /dev/tty - never read from stdin
+  struct termios       original,       // Original input mode
+                       noecho;         // No echo input mode
+  char                 passch,         // Current key press
+                       *passptr,       // Pointer into password string
+                       *passend;       // End of password string
+  ssize_t              passbytes;      // Bytes read
   _cups_globals_t      *cg = _cupsGlobals();
-                                       /* Thread globals */
-
+                                       // Thread globals
 
- /*
-  * Disable input echo and set raw input...
-  */
 
+  // Disable input echo and set raw input...
   if ((tty = open("/dev/tty", O_RDONLY)) < 0)
     return (NULL);
 
@@ -964,18 +962,12 @@ _cupsGetPassword(const char *prompt)      /* I - Prompt string */
     return (NULL);
   }
 
- /*
-  * Display the prompt...
-  */
-
+  // Display the prompt...
   printf("%s ", prompt);
   fflush(stdout);
 
- /*
-  * Read the password string from /dev/tty until we get interrupted or get a
-  * carriage return or newline...
-  */
-
+  // Read the password string from /dev/tty until we get interrupted or get a
+  // carriage return or newline...
   passptr = cg->password;
   passend = cg->password + sizeof(cg->password) - 1;
 
@@ -984,22 +976,16 @@ _cupsGetPassword(const char *prompt)      /* I - Prompt string */
     if (passch == noecho.c_cc[VEOL] ||
 #  ifdef VEOL2
         passch == noecho.c_cc[VEOL2] ||
-#  endif /* VEOL2 */
+#  endif // VEOL2
         passch == 0x0A || passch == 0x0D)
     {
-     /*
-      * Enter/return...
-      */
-
+      // Enter/return...
       break;
     }
     else if (passch == noecho.c_cc[VERASE] ||
              passch == 0x08 || passch == 0x7F)
     {
-     /*
-      * Backspace/delete (erase character)...
-      */
-
+      // Backspace/delete (erase character)...
       if (passptr > cg->password)
       {
         passptr --;
@@ -1010,10 +996,7 @@ _cupsGetPassword(const char *prompt)      /* I - Prompt string */
     }
     else if (passch == noecho.c_cc[VKILL])
     {
-     /*
-      * CTRL+U (erase line)
-      */
-
+      // CTRL+U (erase line)
       if (passptr > cg->password)
       {
        while (passptr > cg->password)
@@ -1028,10 +1011,7 @@ _cupsGetPassword(const char *prompt)     /* I - Prompt string */
     else if (passch == noecho.c_cc[VINTR] || passch == noecho.c_cc[VQUIT] ||
              passch == noecho.c_cc[VEOF])
     {
-     /*
-      * CTRL+C, CTRL+D, or CTRL+Z...
-      */
-
+      // CTRL+C, CTRL+D, or CTRL+Z...
       passptr = cg->password;
       break;
     }
@@ -1049,17 +1029,11 @@ _cupsGetPassword(const char *prompt)    /* I - Prompt string */
   putchar('\n');
   fflush(stdout);
 
- /*
-  * Cleanup...
-  */
-
+  // Cleanup...
   tcsetattr(tty, TCSAFLUSH, &original);
   close(tty);
 
- /*
-  * Return the proper value...
-  */
-
+  // Return the proper value...
   if (passbytes == 1 && passptr > cg->password)
   {
     *passptr = '\0';
@@ -1070,19 +1044,19 @@ _cupsGetPassword(const char *prompt)    /* I - Prompt string */
     memset(cg->password, 0, sizeof(cg->password));
     return (NULL);
   }
-#endif /* _WIN32 */
+#endif // _WIN32
 }
 
 
 #ifdef HAVE_GSSAPI
-/*
- * '_cupsGSSServiceName()' - Get the GSS (Kerberos) service name.
- */
+//
+// '_cupsGSSServiceName()' - Get the GSS (Kerberos) service name.
+//
 
 const char *
 _cupsGSSServiceName(void)
 {
-  _cups_globals_t *cg = _cupsGlobals();        /* Thread globals */
+  _cups_globals_t *cg = _cupsGlobals();        // Thread globals
 
 
   if (!cg->gss_service_name[0])
@@ -1090,35 +1064,38 @@ _cupsGSSServiceName(void)
 
   return (cg->gss_service_name);
 }
-#endif /* HAVE_GSSAPI */
+#endif // HAVE_GSSAPI
 
 
-/*
- * '_cupsSetDefaults()' - Set the default server, port, and encryption.
- */
+//
+// '_cupsSetDefaults()' - Set the default server, port, and encryption.
+//
 
 void
 _cupsSetDefaults(void)
 {
-  cups_file_t  *fp;                    /* File */
-  char         filename[1024];         /* Filename */
-  _cups_client_conf_t cc;              /* client.conf values */
-  _cups_globals_t *cg = _cupsGlobals();        /* Pointer to library globals */
+  cups_file_t  *fp;                    // File
+  char         filename[1024];         // Filename
+  _cups_client_conf_t cc;              // client.conf values
+  _cups_globals_t *cg = _cupsGlobals();        // Pointer to library globals
+#ifdef DEBUG
+  static const char * const encryptions[] =
+  {                                    // Encryption values
+    "IfRequested",
+    "Never",
+    "Required",
+    "Always"
+  };
+#endif // DEBUG
 
 
   DEBUG_puts("_cupsSetDefaults()");
 
- /*
-  * Load initial client.conf values...
-  */
-
+  // Load initial client.conf values...
   cups_init_client_conf(&cc);
 
- /*
-  * Read the /etc/cups/client.conf and ~/.cups/client.conf files, if
-  * present.
-  */
-
+  // Read the /etc/cups/client.conf and ~/.cups/client.conf files, if
+  // present.
   snprintf(filename, sizeof(filename), "%s/client.conf", cg->sysconfig);
   if ((fp = cupsFileOpen(filename, "r")) != NULL)
   {
@@ -1128,10 +1105,7 @@ _cupsSetDefaults(void)
 
   if (cg->userconfig)
   {
-   /*
-    * Look for ~/.cups/client.conf...
-    */
-
+    // Look for ~/.cups/client.conf...
     snprintf(filename, sizeof(filename), "%s/client.conf", cg->userconfig);
 
     if ((fp = cupsFileOpen(filename, "r")) != NULL)
@@ -1141,10 +1115,7 @@ _cupsSetDefaults(void)
     }
   }
 
- /*
-  * Finalize things so every client.conf value is set...
-  */
-
+  // Finalize things so every client.conf value is set...
   cups_finalize_client_conf(&cc);
 
   cg->uatokens = cc.uatokens;
@@ -1164,7 +1135,7 @@ _cupsSetDefaults(void)
 #ifdef HAVE_GSSAPI
   if (!cg->gss_service_name[0])
     cupsCopyString(cg->gss_service_name, cc.gss_service_name, sizeof(cg->gss_service_name));
-#endif /* HAVE_GSSAPI */
+#endif // HAVE_GSSAPI
 
   if (cg->trust_first < 0)
     cg->trust_first = cc.trust_first;
@@ -1178,22 +1149,208 @@ _cupsSetDefaults(void)
   if (cg->validate_certs < 0)
     cg->validate_certs = cc.validate_certs;
 
+  DEBUG_printf("1_cupsSetDefaults: BrowseDomains %s", cc.browse_domains);
+
+  if (!strcmp(cc.browse_domains, "none"))
+    cg->browse_domains = cupsArrayNewStrings(/*s*/NULL, /*delim*/'\0');
+  else if (strcmp(cc.browse_domains, "all") && cc.browse_domains[0])
+    cg->browse_domains = cupsArrayNewStrings(cc.browse_domains, /*delim*/',');
+
+  DEBUG_printf("1_cupsSetDefaults: FilterLocation %s", cc.filter_location);
+
+  if (cc.filter_location[0] == '/')
+  {
+    // FilterLocation /regex/
+    if ((cg->filter_location_regex = (regex_t *)calloc(1, sizeof(regex_t))) != NULL)
+    {
+      char     *ptr = cc.filter_location + strlen(cc.filter_location) - 1;
+                                       // Pointer into FilterLocation value
+
+      if (*ptr == '/')
+        *ptr = '\0';                   // Strip trailing '/'
+
+      if (regcomp(cg->filter_location_regex, cc.filter_location + 1, REG_EXTENDED | REG_ICASE))
+      {
+        DEBUG_puts("1_cupsSetDefaults: Bad regular expression in FilterLocation - results not filtered.");
+        free(cg->filter_location_regex);
+        cg->filter_location_regex = NULL;
+      }
+    }
+  }
+  else if (cc.filter_location[0])
+  {
+    // FilterLocation "string"[,...,"string"]
+    // FilterLocation 'string'[,...,'string']
+    // FilterLocation string[,...,string]
+    char       quote,                  // Quote character, if any
+               *start,                 // Start of value
+               *ptr;                   // Pointer into string
+
+    cg->filter_location_array = cupsArrayNewStrings(/*s*/NULL, /*delim*/'\0');
+
+    // Scan for strings...
+    for (ptr = cc.filter_location; *ptr;)
+    {
+      // Handle quotes...
+      if (*ptr == '\'' || *ptr == '\"')
+        quote = *ptr++;
+      else
+        quote = '\0';
+
+      // Find the end of the string...
+      for (start = ptr; *ptr; ptr ++)
+      {
+        if (quote && *ptr == quote)
+        {
+          *ptr++ = '\0';
+          if (*ptr == ',')
+            *ptr++ = '\0';
+          break;
+       }
+       else if (!quote && *ptr == ',')
+       {
+         *ptr++ = '\0';
+         break;
+       }
+      }
+
+      if (*start)
+        cupsArrayAdd(cg->filter_location_array, start);
+    }
+  }
+
+  DEBUG_printf("1_cupsSetDefaults: FilterType %s", cc.filter_type);
+  if (cc.filter_type[0] && strcmp(cc.filter_type, "any"))
+  {
+    char       *ptr,                   // Pointer into type value
+               *next;                  // Pointer to next value
+
+    for (ptr = cc.filter_type; ptr && *ptr; ptr = next)
+    {
+      if ((next = strchr(ptr, ',')) != NULL)
+        *next++ = '\0';
+
+      if (!_cups_strcasecmp(ptr, "mono"))
+      {
+        cg->filter_type      |= CUPS_PTYPE_BW;
+        cg->filter_type_mask |= CUPS_PTYPE_BW;
+      }
+      else if (!_cups_strcasecmp(ptr, "color"))
+      {
+        cg->filter_type      |= CUPS_PTYPE_COLOR;
+        cg->filter_type_mask |= CUPS_PTYPE_COLOR;
+      }
+      else if (!_cups_strcasecmp(ptr, "duplex"))
+      {
+        if (cg->filter_type_mask & CUPS_PTYPE_DUPLEX)
+        {
+          // Both simplex and duplex
+          cg->filter_type_mask &= (cups_ptype_t)~CUPS_PTYPE_DUPLEX;
+       }
+       else
+       {
+         // Just duplex
+         cg->filter_type      |= CUPS_PTYPE_DUPLEX;
+         cg->filter_type_mask |= CUPS_PTYPE_DUPLEX;
+       }
+      }
+      else if (!_cups_strcasecmp(ptr, "simplex"))
+      {
+        if (cg->filter_type & CUPS_PTYPE_DUPLEX)
+        {
+          // Both simplex and duplex
+          cg->filter_type_mask &= (cups_ptype_t)~CUPS_PTYPE_DUPLEX;
+        }
+        else
+        {
+          // Just simplex
+          cg->filter_type_mask |= CUPS_PTYPE_DUPLEX;
+       }
+      }
+      else if (!_cups_strcasecmp(ptr, "staple"))
+      {
+        cg->filter_type      |= CUPS_PTYPE_STAPLE;
+        cg->filter_type_mask |= CUPS_PTYPE_STAPLE;
+      }
+      else if (!_cups_strcasecmp(ptr, "punch"))
+      {
+        cg->filter_type      |= CUPS_PTYPE_PUNCH;
+        cg->filter_type_mask |= CUPS_PTYPE_PUNCH;
+      }
+      else if (!_cups_strcasecmp(ptr, "cover"))
+      {
+        cg->filter_type      |= CUPS_PTYPE_COVER;
+        cg->filter_type_mask |= CUPS_PTYPE_COVER;
+      }
+      else if (!_cups_strcasecmp(ptr, "bind"))
+      {
+        cg->filter_type      |= CUPS_PTYPE_BIND;
+        cg->filter_type_mask |= CUPS_PTYPE_BIND;
+      }
+      else if (!_cups_strcasecmp(ptr, "sort"))
+      {
+        cg->filter_type      |= CUPS_PTYPE_SORT;
+        cg->filter_type_mask |= CUPS_PTYPE_SORT;
+      }
+      else if (!_cups_strcasecmp(ptr, "small"))
+      {
+        cg->filter_type      |= CUPS_PTYPE_SMALL;
+        cg->filter_type_mask |= CUPS_PTYPE_SMALL;
+      }
+      else if (!_cups_strcasecmp(ptr, "medium"))
+      {
+        cg->filter_type      |= CUPS_PTYPE_MEDIUM;
+        cg->filter_type_mask |= CUPS_PTYPE_MEDIUM;
+      }
+      else if (!_cups_strcasecmp(ptr, "large"))
+      {
+        cg->filter_type      |= CUPS_PTYPE_LARGE;
+        cg->filter_type_mask |= CUPS_PTYPE_LARGE;
+      }
+      else if (!_cups_strcasecmp(ptr, "variable"))
+      {
+        cg->filter_type      |= CUPS_PTYPE_VARIABLE;
+        cg->filter_type_mask |= CUPS_PTYPE_VARIABLE;
+      }
+      else
+      {
+        // Something we don't understand...
+        DEBUG_printf("2_cupsSetDefaults: Unknown FilterType '%s'.", ptr);
+      }
+    }
+  }
+
+  DEBUG_printf("1_cupsSetDefaults: FilterType value 0x%x mask 0x%x", cg->filter_type, cg->filter_type_mask);
+
+  DEBUG_printf("1_cupsSetDefaults: AllowAnyRoot %s", cg->any_root ? "Yes" : "No");
+  DEBUG_printf("1_cupsSetDefaults: AllowExpiredCerts %s", cg->expired_certs ? "Yes" : "No");
+  DEBUG_printf("1_cupsSetDefaults: DigestOptions %s", cg->digestoptions == _CUPS_DIGESTOPTIONS_DENYMD5 ? "DenyMD5" : "None");
+  DEBUG_printf("1_cupsSetDefaults: Encryption %s", encryptions[cg->encryption]);
+  DEBUG_printf("1_cupsSetDefaults: ServerName %s", cg->servername);
+  DEBUG_printf("1_cupsSetDefaults: SSLOptions%s%s%s%s Min%s Max%s", cc.ssl_options == _HTTP_TLS_NONE ? " none" : "", (cc.ssl_options & _HTTP_TLS_ALLOW_RC4) ? " AllowRC4" : "", (cc.ssl_options & _HTTP_TLS_ALLOW_DH) ? " AllowDH" : "", (cc.ssl_options & _HTTP_TLS_DENY_CBC) ? " DenyCBC" : "", tls_versions[cc.ssl_min_version], tls_versions[cc.ssl_max_version]);
+  DEBUG_printf("1_cupsSetDefaults: TrustOnFirstUse %s", cg->trust_first ? "Yes" : "No");
+  DEBUG_printf("1_cupsSetDefaults: User %s", cg->user);
+  DEBUG_printf("1_cupsSetDefaults: UserAgentTokens %s", uatokens[cg->uatokens]);
+  DEBUG_printf("1_cupsSetDefaults: ValidateCerts %s", cg->validate_certs ? "Yes" : "No");
+
   _httpTLSSetOptions(cc.ssl_options | _HTTP_TLS_SET_DEFAULT, cc.ssl_min_version, cc.ssl_max_version);
+
+  cg->client_conf_loaded = true;
 }
 
 
 #ifdef __APPLE__
-/*
- * 'cups_apple_get_boolean()' - Get a boolean setting from the CUPS preferences.
- */
+//
+// 'cups_apple_get_boolean()' - Get a boolean setting from the CUPS preferences.
+//
 
-static int                             /* O - 1 if set, 0 otherwise */
+static int                             // O - 1 if set, 0 otherwise
 cups_apple_get_boolean(
-    CFStringRef key,                   /* I - Key (name) */
-    int         *value)                        /* O - Boolean value */
+    CFStringRef key,                   // I - Key (name)
+    int         *value)                        // O - Boolean value
 {
-  Boolean      bval,                   /* Preference value */
-               bval_set;               /* Value is set? */
+  Boolean      bval,                   // Preference value
+               bval_set;               // Value is set?
 
 
   bval = CFPreferencesGetAppBooleanValue(key, kCUPSPrintingPrefs, &bval_set);
@@ -1205,17 +1362,17 @@ cups_apple_get_boolean(
 }
 
 
-/*
- * 'cups_apple_get_string()' - Get a string setting from the CUPS preferences.
- */
+//
+// 'cups_apple_get_string()' - Get a string setting from the CUPS preferences.
+//
 
-static int                             /* O - 1 if set, 0 otherwise */
+static int                             // O - 1 if set, 0 otherwise
 cups_apple_get_string(
-    CFStringRef key,                   /* I - Key (name) */
-    char        *value,                        /* O - String value */
-    size_t      valsize)               /* I - Size of value buffer */
+    CFStringRef key,                   // I - Key (name)
+    char        *value,                        // O - String value
+    size_t      valsize)               // I - Size of value buffer
 {
-  CFStringRef  sval;                   /* String value */
+  CFStringRef  sval;                   // String value
 
 
   if ((sval = CFPreferencesCopyAppValue(key, kCUPSPrintingPrefs)) != NULL)
@@ -1230,31 +1387,40 @@ cups_apple_get_string(
 
   return (0);
 }
-#endif /* __APPLE__ */
+#endif // __APPLE__
 
 
-/*
- * 'cups_boolean_value()' - Convert a string to a boolean value.
- */
+//
+// 'cups_boolean_value()' - Convert a string to a boolean value.
+//
 
-static int                             /* O - Boolean value */
-cups_boolean_value(const char *value)  /* I - String value */
+static int                             // O - Boolean value
+cups_boolean_value(const char *value)  // I - String value
 {
   return (!_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "on") || !_cups_strcasecmp(value, "true"));
 }
 
 
-/*
- * 'cups_finalize_client_conf()' - Finalize client.conf values.
- */
+//
+// 'cups_finalize_client_conf()' - Finalize client.conf values.
+//
 
 static void
 cups_finalize_client_conf(
-    _cups_client_conf_t *cc)           /* I - client.conf values */
+    _cups_client_conf_t *cc)           // I - client.conf values
 {
-  const char   *value;                 /* Environment variable */
+  const char   *value;                 // Environment variable
 
 
+  if ((value = getenv("CUPS_BROWSE_DOMAINS")) != NULL)
+    cups_set_browse_domains(cc, value);
+
+  if ((value = getenv("CUPS_FILTER_LOCATION")) != NULL)
+    cups_set_filter_location(cc, value);
+
+  if ((value = getenv("CUPS_FILTER_TYPE")) != NULL)
+    cups_set_filter_type(cc, value);
+
   if ((value = getenv("CUPS_TRUSTFIRST")) != NULL)
     cc->trust_first = cups_boolean_value(value);
 
@@ -1270,7 +1436,7 @@ cups_finalize_client_conf(
 #ifdef HAVE_GSSAPI
   if ((value = getenv("CUPS_GSSSERVICENAME")) != NULL)
     cups_set_gss_service_name(cc, value);
-#endif /* HAVE_GSSAPI */
+#endif // HAVE_GSSAPI
 
   if ((value = getenv("CUPS_SERVER")) != NULL)
     cups_set_server_name(cc, value);
@@ -1281,10 +1447,7 @@ cups_finalize_client_conf(
   if ((value = getenv("CUPS_VALIDATECERTS")) != NULL)
     cc->validate_certs = cups_boolean_value(value);
 
- /*
-  * Then apply defaults for those values that haven't been set...
-  */
-
+  // Then apply defaults for those values that haven't been set...
   if (cc->trust_first < 0)
     cc->trust_first = 1;
 
@@ -1300,15 +1463,12 @@ cups_finalize_client_conf(
 #ifdef HAVE_GSSAPI
   if (!cc->gss_service_name[0])
     cups_set_gss_service_name(cc, CUPS_DEFAULT_GSSSERVICENAME);
-#endif /* HAVE_GSSAPI */
+#endif // HAVE_GSSAPI
 
   if (!cc->server_name[0])
   {
-   /*
-    * If we are compiled with domain socket support, only use the
-    * domain socket if it exists and has the right permissions...
-    */
-
+    // If we are compiled with domain socket support, only use the
+    // domain socket if it exists and has the right permissions...
 #if defined(__APPLE__) && !TARGET_OS_OSX
     cups_set_server_name(cc, "/private/var/run/printd");
 
@@ -1317,39 +1477,31 @@ cups_finalize_client_conf(
     if (!access(CUPS_DEFAULT_DOMAINSOCKET, R_OK))
       cups_set_server_name(cc, CUPS_DEFAULT_DOMAINSOCKET);
     else
-#  endif /* CUPS_DEFAULT_DOMAINSOCKET */
+#  endif // CUPS_DEFAULT_DOMAINSOCKET
     cups_set_server_name(cc, "localhost");
-#endif /* __APPLE__ && !TARGET_OS_OSX */
+#endif // __APPLE__ && !TARGET_OS_OSX
   }
 
   if (!cc->user[0])
   {
 #ifdef _WIN32
-   /*
-    * Get the current user name from the OS...
-    */
-
-    DWORD      size;                   /* Size of string */
+    // Get the current user name from the OS...
+    DWORD      size;                           // Size of string
 
     size = sizeof(cc->user);
     if (!GetUserNameA(cc->user, &size))
 #else
-   /*
-    * Try the USER environment variable as the default username...
-    */
-
-    const char *envuser = getenv("USER");      /* Default username */
-    struct passwd pw;                          /* Account information */
-    struct passwd *result = NULL;              /* Auxiliary pointer */
-    _cups_globals_t *cg = _cupsGlobals();      /* Pointer to library globals */
+    // Try the USER environment variable as the default username...
+    const char *envuser = getenv("USER");      // Default username
+    struct passwd pw;                          // Account information
+    struct passwd *result = NULL;              // Auxiliary pointer
+    _cups_globals_t *cg = _cupsGlobals();      // Pointer to library globals
 
     if (envuser)
     {
-     /*
-      * Validate USER matches the current UID, otherwise don't allow it to
-      * override things...  This makes sure that printing after doing su
-      * or sudo records the correct username.
-      */
+      // Validate USER matches the current UID, otherwise don't allow it to
+      // override things...  This makes sure that printing after doing su
+      // or sudo records the correct username.
       getpwnam_r(envuser, &pw, cg->pw_buf, PW_BUF_SIZE, &result);
       if (result && pw.pw_uid != getuid())
         result = NULL;
@@ -1361,12 +1513,9 @@ cups_finalize_client_conf(
     if (result)
       cupsCopyString(cc->user, pw.pw_name, sizeof(cc->user));
     else
-#endif /* _WIN32 */
+#endif // _WIN32
     {
-     /*
-      * Use the default "unknown" user name...
-      */
-
+      // Use the default "unknown" user name...
       cupsCopyString(cc->user, "unknown", sizeof(cc->user));
     }
   }
@@ -1376,25 +1525,22 @@ cups_finalize_client_conf(
 }
 
 
-/*
- * 'cups_init_client_conf()' - Initialize client.conf values.
- */
+//
+// 'cups_init_client_conf()' - Initialize client.conf values.
+//
 
 static void
 cups_init_client_conf(
-    _cups_client_conf_t *cc)           /* I - client.conf values */
+    _cups_client_conf_t *cc)           // I - client.conf values
 {
- /*
-  * Clear all values to "not set"...
-  */
-
+  // Clear all values to "not set"...
   memset(cc, 0, sizeof(_cups_client_conf_t));
 
   cc->uatokens = _CUPS_UATOKENS_MINIMAL;
 
 #if defined(__APPLE__) && !TARGET_OS_OSX
   cups_set_user(cc, "mobile");
-#endif /* __APPLE__ && !TARGET_OS_OSX */
+#endif // __APPLE__ && !TARGET_OS_OSX
 
   cc->ssl_min_version = _HTTP_TLS_1_0;
   cc->ssl_max_version = _HTTP_TLS_MAX;
@@ -1404,14 +1550,11 @@ cups_init_client_conf(
   cc->expired_certs   = -1;
   cc->validate_certs  = -1;
 
- /*
-  * Load settings from the org.cups.PrintingPrefs plist (which trump
-  * everything...)
-  */
-
+  // Load settings from the org.cups.PrintingPrefs plist (which trump
+  // everything...)
 #if defined(__APPLE__)
-  char sval[1024];                     /* String value */
-  int  bval;                           /* Boolean value */
+  char sval[1024];                     // String value
+  int  bval;                           // Boolean value
 
   if (cups_apple_get_boolean(kAllowAnyRootKey, &bval))
     cc->any_root = bval;
@@ -1455,43 +1598,44 @@ cups_init_client_conf(
 
   if (cups_apple_get_string(kUserAgentTokensKey, sval, sizeof(sval)))
     cups_set_uatokens(cc, sval);
-#endif /* __APPLE__ */
+#endif // __APPLE__
 }
 
 
-/*
- * 'cups_read_client_conf()' - Read a client.conf file.
- */
+//
+// 'cups_read_client_conf()' - Read a client.conf file.
+//
 
 static void
 cups_read_client_conf(
-    cups_file_t         *fp,           /* I - File to read */
-    _cups_client_conf_t *cc)           /* I - client.conf values */
+    cups_file_t         *fp,           // I - File to read
+    _cups_client_conf_t *cc)           // I - client.conf values
 {
-  int  linenum;                        /* Current line number */
-  char line[1024],                     /* Line from file */
-        *value;                                /* Pointer into line */
+  int  linenum;                        // Current line number
+  char line[1024],                     // Line from file
+        *value;                                // Pointer into line
 
 
- /*
-  * Read from the file...
-  */
-
+  // Read from the file...
   linenum = 0;
   while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
   {
-    if (!_cups_strcasecmp(line, "DigestOptions") && value)
+    if (!_cups_strcasecmp(line, "BrowseDomains"))
+      cups_set_browse_domains(cc, value);
+    else if (!_cups_strcasecmp(line, "DigestOptions") && value)
       cups_set_digestoptions(cc, value);
     else if (!_cups_strcasecmp(line, "Encryption") && value)
       cups_set_encryption(cc, value);
+    else if (!_cups_strcasecmp(line, "FilterLocation"))
+      cups_set_filter_location(cc, value);
+    else if (!_cups_strcasecmp(line, "FilterType"))
+      cups_set_filter_type(cc, value);
 #ifndef __APPLE__
-   /*
-    * The ServerName directive is not supported on macOS due to app
-    * sandboxing restrictions, i.e. not all apps request network access.
-    */
+    // The ServerName directive is not supported on macOS due to app
+    // sandboxing restrictions, i.e. not all apps request network access.
     else if (!_cups_strcasecmp(line, "ServerName") && value)
       cups_set_server_name(cc, value);
-#endif /* !__APPLE__ */
+#endif // !__APPLE__
     else if (!_cups_strcasecmp(line, "User") && value)
       cups_set_user(cc, value);
     else if (!_cups_strcasecmp(line, "UserAgentTokens") && value)
@@ -1508,22 +1652,38 @@ cups_read_client_conf(
 #ifdef HAVE_GSSAPI
     else if (!_cups_strcasecmp(line, "GSSServiceName") && value)
       cups_set_gss_service_name(cc, value);
-#endif /* HAVE_GSSAPI */
+#endif // HAVE_GSSAPI
     else if (!_cups_strcasecmp(line, "SSLOptions") && value)
       cups_set_ssl_options(cc, value);
   }
 }
 
 
-/*
- * 'cups_set_default_ipp_port()' - Set the default IPP port value.
- */
+//
+// 'cups_set_browse_domains()' - Set the BrowseDomains value.
+//
+
+static void
+cups_set_browse_domains(
+    _cups_client_conf_t *cc,           // I - client.conf values
+    const char          *value)                // I - Value
+{
+  if (value)
+    cupsCopyString(cc->browse_domains, value, sizeof(cc->browse_domains));
+  else
+    cc->browse_domains[0] = '\0';
+}
+
+
+//
+// 'cups_set_default_ipp_port()' - Set the default IPP port value.
+//
 
 static void
 cups_set_default_ipp_port(
-    _cups_globals_t *cg)               /* I - Global data */
+    _cups_globals_t *cg)               // I - Global data
 {
-  const char   *ipp_port;              /* IPP_PORT environment variable */
+  const char   *ipp_port;              // IPP_PORT environment variable
 
 
   if ((ipp_port = getenv("IPP_PORT")) != NULL)
@@ -1536,14 +1696,14 @@ cups_set_default_ipp_port(
 }
 
 
-/*
- * 'cups_set_digestoptions()' - Set the DigestOptions value.
- */
+//
+// 'cups_set_digestoptions()' - Set the DigestOptions value.
+//
 
 static void
 cups_set_digestoptions(
-    _cups_client_conf_t *cc,           /* I - client.conf values */
-    const char          *value)                /* I - Value */
+    _cups_client_conf_t *cc,           // I - client.conf values
+    const char          *value)                // I - Value
 {
   if (!_cups_strcasecmp(value, "DenyMD5"))
     cc->digestoptions = _CUPS_DIGESTOPTIONS_DENYMD5;
@@ -1552,14 +1712,14 @@ cups_set_digestoptions(
 }
 
 
-/*
- * 'cups_set_encryption()' - Set the Encryption value.
- */
+//
+// 'cups_set_encryption()' - Set the Encryption value.
+//
 
 static void
 cups_set_encryption(
-    _cups_client_conf_t *cc,           /* I - client.conf values */
-    const char          *value)                /* I - Value */
+    _cups_client_conf_t *cc,           // I - client.conf values
+    const char          *value)                // I - Value
 {
   if (!_cups_strcasecmp(value, "never"))
     cc->encryption = HTTP_ENCRYPTION_NEVER;
@@ -1572,63 +1732,89 @@ cups_set_encryption(
 }
 
 
-/*
- * 'cups_set_gss_service_name()' - Set the GSSServiceName value.
- */
+//
+// 'cups_set_gss_service_name()' - Set the GSSServiceName value.
+//
 
 #ifdef HAVE_GSSAPI
 static void
 cups_set_gss_service_name(
-    _cups_client_conf_t *cc,           /* I - client.conf values */
-    const char          *value)                /* I - Value */
+    _cups_client_conf_t *cc,           // I - client.conf values
+    const char          *value)                // I - Value
 {
   cupsCopyString(cc->gss_service_name, value, sizeof(cc->gss_service_name));
 }
-#endif /* HAVE_GSSAPI */
+#endif // HAVE_GSSAPI
 
 
-/*
- * 'cups_set_server_name()' - Set the ServerName value.
- */
+//
+// 'cups_set_filter_location()' - Set the FilterLocation value.
+//
+
+static void
+cups_set_filter_location(
+    _cups_client_conf_t *cc,           // I - client.conf values
+    const char          *value)                // I - Value
+{
+  if (value)
+    cupsCopyString(cc->filter_location, value, sizeof(cc->filter_location));
+  else
+    cc->filter_location[0] = '\0';
+}
+
+
+//
+// 'cups_set_filter_type()' - Set the FilterType value.
+//
+
+static void
+cups_set_filter_type(
+    _cups_client_conf_t *cc,           // I - client.conf values
+    const char          *value)                // I - Value
+{
+  if (value)
+    cupsCopyString(cc->filter_type, value, sizeof(cc->filter_type));
+  else
+    cc->filter_type[0] = '\0';
+}
+
+
+//
+// 'cups_set_server_name()' - Set the ServerName value.
+//
 
 static void
 cups_set_server_name(
-    _cups_client_conf_t *cc,           /* I - client.conf values */
-    const char          *value)                /* I - Value */
+    _cups_client_conf_t *cc,           // I - client.conf values
+    const char          *value)                // I - Value
 {
   cupsCopyString(cc->server_name, value, sizeof(cc->server_name));
 }
 
 
-/*
- * 'cups_set_ssl_options()' - Set the SSLOptions value.
- */
+//
+// 'cups_set_ssl_options()' - Set the SSLOptions value.
+//
 
 static void
 cups_set_ssl_options(
-    _cups_client_conf_t *cc,           /* I - client.conf values */
-    const char          *value)                /* I - Value */
+    _cups_client_conf_t *cc,           // I - client.conf values
+    const char          *value)                // I - Value
 {
- /*
-  * SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyTLS1.0] [None]
-  */
-
-  int  options = _HTTP_TLS_NONE,       /* SSL/TLS options */
-       min_version = _HTTP_TLS_1_0,    /* Minimum SSL/TLS version */
-       max_version = _HTTP_TLS_MAX;    /* Maximum SSL/TLS version */
-  char temp[256],                      /* Copy of value */
-       *start,                         /* Start of option */
-       *end;                           /* End of option */
+  // SSLOptions [AllowRC4] [AllowSSL3] [AllowDH] [DenyTLS1.0] [None]
+  int  options = _HTTP_TLS_NONE,       // SSL/TLS options
+       min_version = _HTTP_TLS_1_0,    // Minimum SSL/TLS version
+       max_version = _HTTP_TLS_MAX;    // Maximum SSL/TLS version
+  char temp[256],                      // Copy of value
+       *start,                         // Start of option
+       *end;                           // End of option
 
 
   cupsCopyString(temp, value, sizeof(temp));
 
   for (start = temp; *start; start = end)
   {
-   /*
-    * Find end of keyword...
-    */
-
+    // Find end of keyword...
     end = start;
     while (*end && !_cups_isspace(*end))
       end ++;
@@ -1636,10 +1822,7 @@ cups_set_ssl_options(
     if (*end)
       *end++ = '\0';
 
-   /*
-    * Compare...
-    */
-
+    // Compare...
     if (!_cups_strcasecmp(start, "AllowRC4"))
       options |= _HTTP_TLS_ALLOW_RC4;
     else if (!_cups_strcasecmp(start, "AllowSSL3"))
@@ -1680,26 +1863,17 @@ cups_set_ssl_options(
 }
 
 
-/*
- * 'cups_set_uatokens()' - Set the UserAgentTokens value.
- */
+//
+// 'cups_set_uatokens()' - Set the UserAgentTokens value.
+//
 
 static void
 cups_set_uatokens(
-    _cups_client_conf_t *cc,           /* I - client.conf values */
-    const char          *value)                /* I - Value */
+    _cups_client_conf_t *cc,           // I - client.conf values
+    const char          *value)                // I - Value
 {
-  int  i;                              /* Looping var */
-  static const char * const uatokens[] =/* UserAgentTokens values */
-  {
-    "NONE",
-    "PRODUCTONLY",
-    "MAJOR",
-    "MINOR",
-    "MINIMAL",
-    "OS",
-    "FULL"
-  };
+  int  i;                              // Looping var
+
 
   for (i = 0; i < (int)(sizeof(uatokens) / sizeof(uatokens[0])); i ++)
   {
@@ -1712,14 +1886,14 @@ cups_set_uatokens(
 }
 
 
-/*
- * 'cups_set_user()' - Set the User value.
- */
+//
+// 'cups_set_user()' - Set the User value.
+//
 
 static void
 cups_set_user(
-    _cups_client_conf_t *cc,           /* I - client.conf values */
-    const char          *value)                /* I - Value */
+    _cups_client_conf_t *cc,           // I - client.conf values
+    const char          *value)                // I - Value
 {
   cupsCopyString(cc->user, value, sizeof(cc->user));
 }
index 50a3913ce319a128c9e637f9e7eba75a73df6750..7ab8bf1bf249b09a5e1bce6c95993cb63ab5a704 100644 (file)
 <p>The <strong>client.conf</strong> file configures the CUPS client and is normally located in the <em>/etc/cups</em> and/or <em>~/.cups</em> directories.
 Each line in the file can be a configuration directive, a blank line, or a comment. Comment lines start with the # character.
 </p>
-    <p><strong>Note:</strong> Starting with macOS 10.7, this file is only used by command-line and X11 applications plus the IPP backend.
-The <strong>ServerName</strong> directive is not supported on macOS at all.
-Starting with macOS 10.12, all applications can access these settings in the <em>/Library/Preferences/org.cups.PrintingPrefs.plist</em> file instead.
+    <p><strong>Note:</strong> macOS applications can access many of these settings in the <em>/Library/Preferences/org.cups.PrintingPrefs.plist</em> file instead.
+macOS also does not support the
+<strong>ServerName</strong>
+directive.
 See the NOTES section below for more information.
 </p>
     <h3 id="client.conf-5.description.directives">Directives</h3>
@@ -32,6 +33,15 @@ The default is &quot;Yes&quot;.
     <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>AllowExpiredCerts No</strong><br>
 Specifies whether to allow TLS with expired certificates.
 The default is &quot;No&quot;.
+</p>
+    <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>BrowseDomains all</strong><br>
+</p>
+    <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>BrowseDomains none</strong><br>
+</p>
+    <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>BrowseDomains </strong><em>DOMAIN[,...,DOMAIN]</em><br>
+Specifies the DNS-SD domains to browse for IPP printers.
+The value &quot;all&quot; browses the &quot;.local&quot; domain (mDNS) and all registered DNS domains on the local system.
+The value &quot;none&quot; disables browsing for network printers.
 </p>
     <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>DigestOptions DenyMD5</strong><br>
 </p>
@@ -45,6 +55,22 @@ Specifies HTTP Digest authentication options.
 </p>
     <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>Encryption Required</strong><br>
 Specifies the level of encryption that should be used.
+</p>
+    <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>FilterLocation </strong><em>LOCATION[,...,LOCATION]</em><br>
+</p>
+    <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>FilterLocation </strong><em>'LOCATION'[,...,'LOCATION']</em><br>
+</p>
+    <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>FilterLocation </strong><em>&quot;LOCATION&quot;[,...,&quot;LOCATION&quot;]</em><br>
+Specifies a list of locations to use for destinations.
+</p>
+    <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>FilterLocation </strong><em>/REGULAR-EXPRESSION/</em><br>
+Specifies a regular expression for matching locations to use for destinations.
+</p>
+    <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>FilterType any</strong><br>
+</p>
+    <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>FilterType </strong><em>TYPE[,...,TYPE]</em><br>
+Specifies the type of destinations to use.
+The TYPE values are &quot;mono&quot; for B&amp;W printers, &quot;color&quot; for color printers, &quot;duplex&quot; for printers with 2-sided printing capabilities, &quot;simplex&quot; for printers with 1-sided printing capabilities, &quot;bind&quot; for printers that can bind output, &quot;cover&quot; for printers that can cover output, &quot;punch&quot; for printers that can punch output, &quot;sort&quot; for printers that can sort output, &quot;staple&quot; for printers with a stapler, &quot;small&quot; for printers that support media up to US Legal/ISO A4, &quot;medium&quot; for printers that support media up to US Tabloid/ISO A3, and &quot;large&quot; for printers that support media larger than US Tabloid/ISO A3.
 </p>
     <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>GSSServiceName </strong><em>name</em><br>
 Specifies the Kerberos service name that is used for authentication, typically &quot;host&quot;, &quot;http&quot;, or &quot;ipp&quot;.
@@ -59,7 +85,7 @@ Specifies the address and optionally the port to use when connecting to the serv
     <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>ServerName </strong><em>hostname-or-ip-address</em>[<em>:port</em>]<strong>/version=1.1</strong><br>
 Specifies the address and optionally the port to use when connecting to a server running CUPS 1.3.12 and earlier.
 </p>
-    <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>SSLOptions </strong>[<em>AllowDH</em>] [<em>AllowRC4</em>] [<em>AllowSSL3</em>] [<em>DenyCBC</em>] [<em>DenyTLS1.0</em>] [<em>MaxTLS1.0</em>] [<em>MaxTLS1.1</em>] [<em>MaxTLS1.2</em>] [<em>MaxTLS1.3</em>] [<em>MinTLS1.0</em>] [<em>MinTLS1.1</em>] [<em>MinTLS1.2</em>] [<em>MinTLS1.3</em>] [<em>NoSystem</em>]<br>
+    <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>SSLOptions </strong>[<em>AllowDH</em>] [<em>AllowRC4</em>] [<em>AllowSSL3</em>] [<em>DenyCBC</em>] [<em>DenyTLS1.0</em>] [<em>MaxTLS1.0</em>] [<em>MaxTLS1.1</em>] [<em>MaxTLS1.2</em>] [<em>MaxTLS1.3</em>] [<em>MinTLS1.0</em>] [<em>MinTLS1.1</em>] [<em>MinTLS1.2</em>] [<em>MinTLS1.3</em>]<br>
 </p>
     <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>SSLOptions None</strong><br>
 Sets encryption options (only in /etc/cups/client.conf).
@@ -73,7 +99,6 @@ The <em>DenyCBC</em> option disables all CBC cipher suites.
 The <em>DenyTLS1.0</em> option disables TLS v1.0 support - this sets the minimum protocol version to TLS v1.1.
 The <em>MinTLS</em> options set the minimum TLS version to support.
 The <em>MaxTLS</em> options set the maximum TLS version to support.
-The <em>NoSystem</em> option disables applying system cryptographic policy.
 Not all operating systems support TLS 1.3 at this time.
 </p>
     <p style="margin-left: 2.5em; text-indent: -2.5em;"><strong>TrustOnFirstUse Yes</strong><br>
@@ -115,7 +140,7 @@ Specifies whether to only allow TLS with certificates whose common name matches
 The default is &quot;No&quot;.
 </p>
     <h2 id="client.conf-5.notes">Notes</h2>
-<p>The <strong>client.conf</strong> file is deprecated on macOS and will no longer be supported in a future version of CUPS.
+<p>Because of sandboxing, the <strong>client.conf</strong> file is not generally accessible to applications on macOS.
 Configuration settings can instead be viewed or changed using the
 <strong>defaults</strong>(1)
 
@@ -129,13 +154,10 @@ defaults read /Library/Preferences/org.cups.PrintingPrefs.plist Encryption
 <p>On Linux and other systems using GNU TLS, the <em>/etc/cups/ssl/site.crl</em> file, if present, provides a list of revoked X.509 certificates and is used when validating certificates.
 </p>
     <h2 id="client.conf-5.see-also">See Also</h2>
-<a href="cups.html"><p><strong>cups</strong>(1),</a>
-
-<strong>default</strong>(1),
+<a href="cups.html"><p><strong>cups</strong>(1)</a>
 
-CUPS Online Help (<a href="http://localhost:631/help">http://localhost:631/help</a>)
 </p>
     <h2 id="client.conf-5.copyright">Copyright</h2>
-<p>Copyright &copy; 2020-2024 by OpenPrinting.
+<p>Copyright &copy; 2021-2025 by OpenPrinting.
   </body>
 </html>
index e84fab2e3699a835a20510c32c5dfe03f547d0c4..ce52d22d311ee2ed93720bf9e5d5cab2fe03ece3 100644 (file)
@@ -1,23 +1,24 @@
 .\"
 .\" client.conf man page for CUPS.
 .\"
-.\" Copyright © 2020-2025 by OpenPrinting.
+.\" Copyright © 2021-2025 by OpenPrinting.
 .\" Copyright © 2007-2019 by Apple Inc.
 .\" Copyright © 2006 by Easy Software Products.
 .\"
 .\" Licensed under Apache License v2.0.  See the file "LICENSE" for more
 .\" information.
 .\"
-.TH client.conf 5 "CUPS" "2021-02-28" "OpenPrinting"
+.TH client.conf 5 "CUPS" "2025-02-28" "OpenPrinting"
 .SH NAME
 client.conf \- client configuration file for cups (deprecated on macos)
 .SH DESCRIPTION
 The \fBclient.conf\fR file configures the CUPS client and is normally located in the \fI/etc/cups\fR and/or \fI~/.cups\fR directories.
 Each line in the file can be a configuration directive, a blank line, or a comment. Comment lines start with the # character.
 .LP
-\fBNote:\fR Starting with macOS 10.7, this file is only used by command-line and X11 applications plus the IPP backend.
-The \fBServerName\fR directive is not supported on macOS at all.
-Starting with macOS 10.12, all applications can access these settings in the \fI/Library/Preferences/org.cups.PrintingPrefs.plist\fR file instead.
+\fBNote:\fR macOS applications can access many of these settings in the \fI/Library/Preferences/org.cups.PrintingPrefs.plist\fR file instead.
+macOS also does not support the
+.B ServerName
+directive.
 See the NOTES section below for more information.
 .SS DIRECTIVES
 The following directives are understood by the client. Consult the online help for detailed descriptions:
@@ -35,6 +36,16 @@ The default is "Yes".
 \fBAllowExpiredCerts No\fR
 Specifies whether to allow TLS with expired certificates.
 The default is "No".
+.\"#BrowseDomains
+.TP 5
+\fBBrowseDomains all\fR
+.TP 5
+\fBBrowseDomains none\fR
+.TP 5
+\fBBrowseDomains \fIDOMAIN[,...,DOMAIN]\fR
+Specifies the DNS-SD domains to browse for IPP printers.
+The value "all" browses the ".local" domain (mDNS) and all registered DNS domains on the local system.
+The value "none" disables browsing for network printers.
 .\"#DigestOptions
 .TP 5
 \fBDigestOptions DenyMD5\fR
@@ -50,6 +61,24 @@ Specifies HTTP Digest authentication options.
 .TP 5
 \fBEncryption Required\fR
 Specifies the level of encryption that should be used.
+.\"#FilterLocation
+.TP 5
+\fBFilterLocation \fILOCATION[,...,LOCATION]\fR
+.TP 5
+\fBFilterLocation \fI'LOCATION'[,...,'LOCATION']\fR
+.TP 5
+\fBFilterLocation \fI"LOCATION"[,...,"LOCATION"]\fR
+Specifies a list of locations to use for destinations.
+.TP 5
+\fBFilterLocation \fI/REGULAR-EXPRESSION/\fR
+Specifies a regular expression for matching locations to use for destinations.
+.\"#FilterType
+.TP 5
+\fBFilterType any\fR
+.TP 5
+\fBFilterType \fITYPE[,...,TYPE]\fR
+Specifies the type of destinations to use.
+The TYPE values are "mono" for B&W printers, "color" for color printers, "duplex" for printers with 2-sided printing capabilities, "simplex" for printers with 1-sided printing capabilities, "bind" for printers that can bind output, "cover" for printers that can cover output, "punch" for printers that can punch output, "sort" for printers that can sort output, "staple" for printers with a stapler, "small" for printers that support media up to US Legal/ISO A4, "medium" for printers that support media up to US Tabloid/ISO A3, and "large" for printers that support media larger than US Tabloid/ISO A3.
 .\"#GSSServiceName
 .TP 5
 \fBGSSServiceName \fIname\fR
@@ -67,7 +96,7 @@ Specifies the address and optionally the port to use when connecting to the serv
 Specifies the address and optionally the port to use when connecting to a server running CUPS 1.3.12 and earlier.
 .\"#SSLOptions
 .TP 5
-\fBSSLOptions \fR[\fIAllowDH\fR] [\fIAllowRC4\fR] [\fIAllowSSL3\fR] [\fIDenyCBC\fR] [\fIDenyTLS1.0\fR] [\fIMaxTLS1.0\fR] [\fIMaxTLS1.1\fR] [\fIMaxTLS1.2\fR] [\fIMaxTLS1.3\fR] [\fIMinTLS1.0\fR] [\fIMinTLS1.1\fR] [\fIMinTLS1.2\fR] [\fIMinTLS1.3\fR] [\fINoSystem\fR]
+\fBSSLOptions \fR[\fIAllowDH\fR] [\fIAllowRC4\fR] [\fIAllowSSL3\fR] [\fIDenyCBC\fR] [\fIDenyTLS1.0\fR] [\fIMaxTLS1.0\fR] [\fIMaxTLS1.1\fR] [\fIMaxTLS1.2\fR] [\fIMaxTLS1.3\fR] [\fIMinTLS1.0\fR] [\fIMinTLS1.1\fR] [\fIMinTLS1.2\fR] [\fIMinTLS1.3\fR]
 .TP 5
 \fBSSLOptions None\fR
 Sets encryption options (only in /etc/cups/client.conf).
@@ -81,7 +110,6 @@ The \fIDenyCBC\fR option disables all CBC cipher suites.
 The \fIDenyTLS1.0\fR option disables TLS v1.0 support - this sets the minimum protocol version to TLS v1.1.
 The \fIMinTLS\fR options set the minimum TLS version to support.
 The \fIMaxTLS\fR options set the maximum TLS version to support.
-The \fINoSystem\fR option disables applying system cryptographic policy.
 Not all operating systems support TLS 1.3 at this time.
 .\"#TrustOnFirstUse
 .TP 5
@@ -126,7 +154,7 @@ The default is "Minimal".
 Specifies whether to only allow TLS with certificates whose common name matches the hostname.
 The default is "No".
 .SH NOTES
-The \fBclient.conf\fR file is deprecated on macOS and will no longer be supported in a future version of CUPS.
+Because of sandboxing, the \fBclient.conf\fR file is not generally accessible to applications on macOS.
 Configuration settings can instead be viewed or changed using the
 .BR defaults (1)
 command:
@@ -138,8 +166,6 @@ defaults read /Library/Preferences/org.cups.PrintingPrefs.plist Encryption
 .fi
 On Linux and other systems using GNU TLS, the \fI/etc/cups/ssl/site.crl\fR file, if present, provides a list of revoked X.509 certificates and is used when validating certificates.
 .SH SEE ALSO
-.BR cups (1),
-.BR default (1),
-CUPS Online Help (http://localhost:631/help)
+.BR cups (1)
 .SH COPYRIGHT
-Copyright \[co] 2020-2024 by OpenPrinting.
+Copyright \[co] 2021-2025 by OpenPrinting.